vesant-sdk 1.7.0-dev.ac305d8 → 1.7.0-dev.b4284ca
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-DoMSYMMR.d.ts → client-0NOPDnT0.d.ts} +29 -26
- package/dist/{client-DMIRx7Tu.d.mts → client-CvWNRwwg.d.mts} +29 -26
- package/dist/{client-ZNdnpWe7.d.mts → client-Dps40EtF.d.mts} +2 -2
- package/dist/{client-C3DCmGe9.d.ts → client-SMxqod4j.d.ts} +2 -2
- package/dist/{client-BolQlL5e.d.mts → client-q9fN8Hhf.d.mts} +103 -1
- package/dist/{client-BolQlL5e.d.ts → client-q9fN8Hhf.d.ts} +103 -1
- package/dist/compliance/index.d.mts +3 -3
- package/dist/compliance/index.d.ts +3 -3
- package/dist/compliance/index.js +133 -22
- package/dist/compliance/index.js.map +1 -1
- package/dist/compliance/index.mjs +133 -22
- 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 +68 -7
- package/dist/decisions/index.js.map +1 -1
- package/dist/decisions/index.mjs +68 -7
- package/dist/decisions/index.mjs.map +1 -1
- package/dist/geolocation/index.d.mts +59 -4
- package/dist/geolocation/index.d.ts +59 -4
- package/dist/geolocation/index.js +136 -19
- package/dist/geolocation/index.js.map +1 -1
- package/dist/geolocation/index.mjs +134 -20
- package/dist/geolocation/index.mjs.map +1 -1
- package/dist/index-CPOrMRaH.d.ts +264 -0
- package/dist/index-CimDmgZb.d.mts +264 -0
- package/dist/index.d.mts +27 -10
- package/dist/index.d.ts +27 -10
- package/dist/index.js +325 -67
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +318 -68
- package/dist/index.mjs.map +1 -1
- package/dist/kyc/core.d.mts +2 -2
- package/dist/kyc/core.d.ts +2 -2
- package/dist/kyc/core.js +94 -19
- package/dist/kyc/core.js.map +1 -1
- package/dist/kyc/core.mjs +94 -19
- package/dist/kyc/core.mjs.map +1 -1
- package/dist/kyc/index.d.mts +110 -13
- package/dist/kyc/index.d.ts +110 -13
- package/dist/kyc/index.js +94 -19
- package/dist/kyc/index.js.map +1 -1
- package/dist/kyc/index.mjs +94 -19
- package/dist/kyc/index.mjs.map +1 -1
- package/dist/react.d.mts +9 -3
- package/dist/react.d.ts +9 -3
- package/dist/react.js +180 -77
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +180 -77
- 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 +68 -7
- package/dist/risk-profile/index.js.map +1 -1
- package/dist/risk-profile/index.mjs +68 -7
- 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 +68 -7
- package/dist/scores/index.js.map +1 -1
- package/dist/scores/index.mjs +68 -7
- package/dist/scores/index.mjs.map +1 -1
- package/dist/tax/index.d.mts +3 -26
- package/dist/tax/index.d.ts +3 -26
- package/dist/tax/index.js +74 -19
- package/dist/tax/index.js.map +1 -1
- package/dist/tax/index.mjs +74 -19
- package/dist/tax/index.mjs.map +1 -1
- package/dist/webhooks/index.d.mts +2 -189
- package/dist/webhooks/index.d.ts +2 -189
- package/dist/webhooks/index.js +85 -21
- package/dist/webhooks/index.js.map +1 -1
- package/dist/webhooks/index.mjs +85 -22
- package/dist/webhooks/index.mjs.map +1 -1
- package/package.json +4 -1
package/dist/compliance/index.js
CHANGED
|
@@ -75,6 +75,19 @@ var sdkReasons = {
|
|
|
75
75
|
})
|
|
76
76
|
};
|
|
77
77
|
|
|
78
|
+
// src/core/auth.ts
|
|
79
|
+
var StaticApiKeyProvider = class {
|
|
80
|
+
constructor(apiKey) {
|
|
81
|
+
this.apiKey = apiKey;
|
|
82
|
+
}
|
|
83
|
+
async getCredential() {
|
|
84
|
+
return this.apiKey ? { scheme: "Bearer", token: this.apiKey } : null;
|
|
85
|
+
}
|
|
86
|
+
canRefresh() {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
78
91
|
// src/core/errors.ts
|
|
79
92
|
var VesantError = class _VesantError extends Error {
|
|
80
93
|
constructor(message, code, statusCode, details) {
|
|
@@ -381,6 +394,12 @@ var BaseClient = class {
|
|
|
381
394
|
if (!config.tenantId?.trim()) {
|
|
382
395
|
throw new ValidationError("tenantId is required and must be a non-empty string", ["tenantId"]);
|
|
383
396
|
}
|
|
397
|
+
if (typeof fetch === "undefined") {
|
|
398
|
+
throw new VesantError(
|
|
399
|
+
"The Vesant SDK requires a global fetch (Node.js >= 18). Upgrade Node or provide a fetch polyfill.",
|
|
400
|
+
"RUNTIME_UNSUPPORTED"
|
|
401
|
+
);
|
|
402
|
+
}
|
|
384
403
|
this.interceptors = config.interceptors || [];
|
|
385
404
|
this.logger = config.logger || createConsoleLogger();
|
|
386
405
|
let environment = config.environment;
|
|
@@ -399,11 +418,12 @@ var BaseClient = class {
|
|
|
399
418
|
environment,
|
|
400
419
|
headers: config.headers || {},
|
|
401
420
|
timeout: config.timeout || 1e4,
|
|
402
|
-
retries: config.retries
|
|
421
|
+
retries: config.retries ?? 3,
|
|
403
422
|
debug: config.debug || false,
|
|
404
423
|
interceptors: this.interceptors,
|
|
405
424
|
logger: this.logger
|
|
406
425
|
};
|
|
426
|
+
this.authProvider = config.authProvider ?? (apiKey ? new StaticApiKeyProvider(apiKey) : void 0);
|
|
407
427
|
if (config.circuitBreaker) {
|
|
408
428
|
this.circuitBreaker = new CircuitBreaker(config.circuitBreaker);
|
|
409
429
|
}
|
|
@@ -411,6 +431,19 @@ var BaseClient = class {
|
|
|
411
431
|
this.rateLimitTracker = new RateLimitTracker();
|
|
412
432
|
}
|
|
413
433
|
}
|
|
434
|
+
/**
|
|
435
|
+
* Resolve the Idempotency-Key for a request. Mutating methods (POST/PUT/PATCH)
|
|
436
|
+
* get the caller-supplied key or a freshly minted UUID; non-mutating methods get
|
|
437
|
+
* none. requestWithRetry resolves this once and injects it so every retry reuses
|
|
438
|
+
* one key (letting the server dedup replays); a direct request() resolves per call.
|
|
439
|
+
*/
|
|
440
|
+
resolveIdempotencyKey(method, requestOptions) {
|
|
441
|
+
const isMutating = ["POST", "PUT", "PATCH"].includes((method || "GET").toUpperCase());
|
|
442
|
+
if (!isMutating) {
|
|
443
|
+
return void 0;
|
|
444
|
+
}
|
|
445
|
+
return requestOptions?.idempotencyKey ?? generateUUID();
|
|
446
|
+
}
|
|
414
447
|
/**
|
|
415
448
|
* Make an HTTP request with timeout and error handling
|
|
416
449
|
*/
|
|
@@ -436,15 +469,20 @@ var BaseClient = class {
|
|
|
436
469
|
...this.config.headers,
|
|
437
470
|
...options.headers || {}
|
|
438
471
|
};
|
|
439
|
-
|
|
440
|
-
|
|
472
|
+
const credential = await this.authProvider?.getCredential({
|
|
473
|
+
tenantId: this.config.tenantId,
|
|
474
|
+
requestId
|
|
475
|
+
});
|
|
476
|
+
if (credential) {
|
|
477
|
+
headers["Authorization"] = `${credential.scheme ?? "Bearer"} ${credential.token}`;
|
|
441
478
|
}
|
|
442
479
|
if (this.config.environment === "sandbox") {
|
|
443
480
|
headers["X-Sandbox"] = "true";
|
|
444
481
|
}
|
|
445
482
|
const method = (options.method || "GET").toUpperCase();
|
|
446
|
-
|
|
447
|
-
|
|
483
|
+
const idempotencyKey = this.resolveIdempotencyKey(method, requestOptions);
|
|
484
|
+
if (idempotencyKey) {
|
|
485
|
+
headers["Idempotency-Key"] = idempotencyKey;
|
|
448
486
|
}
|
|
449
487
|
const controller = new AbortController();
|
|
450
488
|
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
@@ -465,10 +503,28 @@ var BaseClient = class {
|
|
|
465
503
|
if (this.config.debug) {
|
|
466
504
|
this.logger.debug(`${finalOptions.method || "GET"} ${endpoint}`);
|
|
467
505
|
}
|
|
468
|
-
|
|
506
|
+
let response = await fetch(url, {
|
|
469
507
|
...finalOptions,
|
|
470
508
|
signal: controller.signal
|
|
471
509
|
});
|
|
510
|
+
if (response.status === 401 && this.authProvider?.canRefresh?.()) {
|
|
511
|
+
const refreshed = await this.authProvider.getCredential({
|
|
512
|
+
tenantId: this.config.tenantId,
|
|
513
|
+
requestId,
|
|
514
|
+
forceRefresh: true
|
|
515
|
+
});
|
|
516
|
+
if (refreshed) {
|
|
517
|
+
this.config.onCredentialRotated?.({ reason: "unauthorized" });
|
|
518
|
+
finalOptions = {
|
|
519
|
+
...finalOptions,
|
|
520
|
+
headers: {
|
|
521
|
+
...finalOptions.headers,
|
|
522
|
+
Authorization: `${refreshed.scheme ?? "Bearer"} ${refreshed.token}`
|
|
523
|
+
}
|
|
524
|
+
};
|
|
525
|
+
response = await fetch(url, { ...finalOptions, signal: controller.signal });
|
|
526
|
+
}
|
|
527
|
+
}
|
|
472
528
|
clearTimeout(timeoutId);
|
|
473
529
|
if (this.rateLimitTracker) {
|
|
474
530
|
this.rateLimitTracker.updateFromHeaders(response.headers);
|
|
@@ -557,9 +613,11 @@ var BaseClient = class {
|
|
|
557
613
|
*/
|
|
558
614
|
async requestWithRetry(endpoint, options = {}, serviceURL, retries = this.config.retries, requestOptions) {
|
|
559
615
|
let lastError;
|
|
616
|
+
const idempotencyKey = this.resolveIdempotencyKey(options.method || "GET", requestOptions);
|
|
617
|
+
const attemptOptions = idempotencyKey ? { ...requestOptions, idempotencyKey } : requestOptions;
|
|
560
618
|
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
561
619
|
try {
|
|
562
|
-
return await this.request(endpoint, options, serviceURL,
|
|
620
|
+
return await this.request(endpoint, options, serviceURL, attemptOptions);
|
|
563
621
|
} catch (error) {
|
|
564
622
|
lastError = error instanceof Error ? error : new Error("Unknown error");
|
|
565
623
|
if (requestOptions?.signal?.aborted) {
|
|
@@ -656,6 +714,9 @@ var BaseClient = class {
|
|
|
656
714
|
if (config.interceptors) {
|
|
657
715
|
this.interceptors = config.interceptors;
|
|
658
716
|
}
|
|
717
|
+
if (config.authProvider !== void 0 || config.apiKey !== void 0) {
|
|
718
|
+
this.authProvider = this.config.authProvider ?? (this.config.apiKey ? new StaticApiKeyProvider(this.config.apiKey) : void 0);
|
|
719
|
+
}
|
|
659
720
|
}
|
|
660
721
|
/**
|
|
661
722
|
* Get current configuration (readonly)
|
|
@@ -683,6 +744,61 @@ var BaseClient = class {
|
|
|
683
744
|
}
|
|
684
745
|
};
|
|
685
746
|
|
|
747
|
+
// src/geolocation/integrity.ts
|
|
748
|
+
var isNil = (v) => v === null || v === void 0;
|
|
749
|
+
function assessGpsIntegrity(input, opts = {}) {
|
|
750
|
+
const flags = [];
|
|
751
|
+
const now = opts.now ?? (() => Date.now());
|
|
752
|
+
const maxAgeMs = opts.maxAgeMs ?? 6e4;
|
|
753
|
+
const minAccuracy = opts.minAccuracyMeters ?? 1;
|
|
754
|
+
const { accuracy, altitude, altitudeAccuracy, heading, speed, timestamp } = input;
|
|
755
|
+
if (isNil(accuracy)) {
|
|
756
|
+
flags.push("accuracy_missing");
|
|
757
|
+
} else if (accuracy === 0) {
|
|
758
|
+
flags.push("accuracy_zero");
|
|
759
|
+
} else if (accuracy < minAccuracy) {
|
|
760
|
+
flags.push("accuracy_implausibly_small");
|
|
761
|
+
}
|
|
762
|
+
const hasMotion = !isNil(heading) || !isNil(speed);
|
|
763
|
+
if (hasMotion && (isNil(accuracy) || accuracy === 0)) {
|
|
764
|
+
flags.push("motion_without_accuracy");
|
|
765
|
+
}
|
|
766
|
+
if (!isNil(altitude) && isNil(altitudeAccuracy)) {
|
|
767
|
+
flags.push("altitude_without_accuracy");
|
|
768
|
+
}
|
|
769
|
+
if (timestamp !== void 0 && now() - timestamp > maxAgeMs) {
|
|
770
|
+
flags.push("stale_timestamp");
|
|
771
|
+
}
|
|
772
|
+
if (opts.permissionState === "denied" || opts.permissionState === "prompt") {
|
|
773
|
+
flags.push(`permission_${opts.permissionState}`);
|
|
774
|
+
}
|
|
775
|
+
return { suspicious: flags.length > 0, flags };
|
|
776
|
+
}
|
|
777
|
+
function gpsIntegrityInputFromPosition(position) {
|
|
778
|
+
const c = position.coords;
|
|
779
|
+
return {
|
|
780
|
+
latitude: c.latitude,
|
|
781
|
+
longitude: c.longitude,
|
|
782
|
+
accuracy: c.accuracy,
|
|
783
|
+
altitude: c.altitude,
|
|
784
|
+
altitudeAccuracy: c.altitudeAccuracy,
|
|
785
|
+
heading: c.heading,
|
|
786
|
+
speed: c.speed,
|
|
787
|
+
timestamp: position.timestamp
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
async function probeGeolocationPermission() {
|
|
791
|
+
try {
|
|
792
|
+
if (typeof navigator === "undefined" || !navigator.permissions?.query) {
|
|
793
|
+
return "unavailable";
|
|
794
|
+
}
|
|
795
|
+
const status = await navigator.permissions.query({ name: "geolocation" });
|
|
796
|
+
return status.state;
|
|
797
|
+
} catch {
|
|
798
|
+
return "unavailable";
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
|
|
686
802
|
// src/geolocation/ciphertext.ts
|
|
687
803
|
var CIPHER_TEXT_EXPIRY_MINUTES = 5;
|
|
688
804
|
async function computeHMAC(key, message) {
|
|
@@ -735,6 +851,7 @@ async function requestGPSLocation(timeout = 1e4, highAccuracy = true) {
|
|
|
735
851
|
if (typeof navigator === "undefined" || !navigator.geolocation) {
|
|
736
852
|
return null;
|
|
737
853
|
}
|
|
854
|
+
const permissionState = await probeGeolocationPermission();
|
|
738
855
|
return new Promise((resolve) => {
|
|
739
856
|
navigator.geolocation.getCurrentPosition(
|
|
740
857
|
(position) => {
|
|
@@ -751,6 +868,7 @@ async function requestGPSLocation(timeout = 1e4, highAccuracy = true) {
|
|
|
751
868
|
resolve(null);
|
|
752
869
|
return;
|
|
753
870
|
}
|
|
871
|
+
const { flags } = assessGpsIntegrity(gpsIntegrityInputFromPosition(position), { permissionState });
|
|
754
872
|
resolve({
|
|
755
873
|
latitude,
|
|
756
874
|
longitude,
|
|
@@ -759,7 +877,8 @@ async function requestGPSLocation(timeout = 1e4, highAccuracy = true) {
|
|
|
759
877
|
altitude_accuracy: position.coords.altitudeAccuracy ?? void 0,
|
|
760
878
|
heading: position.coords.heading ?? void 0,
|
|
761
879
|
speed: position.coords.speed ?? void 0,
|
|
762
|
-
timestamp: position.timestamp
|
|
880
|
+
timestamp: position.timestamp,
|
|
881
|
+
integrity_flags: flags.length ? flags : void 0
|
|
763
882
|
});
|
|
764
883
|
},
|
|
765
884
|
() => {
|
|
@@ -826,6 +945,9 @@ async function generateCipherText(options, config) {
|
|
|
826
945
|
);
|
|
827
946
|
if (location) {
|
|
828
947
|
locationData = location;
|
|
948
|
+
if (location.integrity_flags?.length) {
|
|
949
|
+
warnings.push(`GPS integrity flags (advisory): ${location.integrity_flags.join(", ")}`);
|
|
950
|
+
}
|
|
829
951
|
} else if (gpsRequiredByConfig) {
|
|
830
952
|
throw new VesantError(
|
|
831
953
|
`GPS location is required for ${options.reason} by tenant configuration, but GPS was not available or permission was denied`,
|
|
@@ -920,8 +1042,8 @@ var GeolocationClient = class extends BaseClient {
|
|
|
920
1042
|
* ```
|
|
921
1043
|
*/
|
|
922
1044
|
async verifyIP(request, requestOptions) {
|
|
923
|
-
if (!request.ip_address
|
|
924
|
-
throw new ValidationError("ip_address
|
|
1045
|
+
if (request.ip_address !== void 0 && !request.ip_address.trim()) {
|
|
1046
|
+
throw new ValidationError("ip_address, when provided, must be a non-empty string", ["ip_address"]);
|
|
925
1047
|
}
|
|
926
1048
|
return this.requestWithRetry("/api/v1/geo/verify", {
|
|
927
1049
|
method: "POST",
|
|
@@ -1271,20 +1393,12 @@ var GeolocationClient = class extends BaseClient {
|
|
|
1271
1393
|
*
|
|
1272
1394
|
* @example
|
|
1273
1395
|
* ```typescript
|
|
1274
|
-
* //
|
|
1396
|
+
* // GPS (the web SDK is GPS + IP only; the server handles the IP fallback)
|
|
1275
1397
|
* const result = await client.captureLocation(token, {
|
|
1276
1398
|
* latitude: 37.7749,
|
|
1277
1399
|
* longitude: -122.4194,
|
|
1278
1400
|
* accuracy: 10
|
|
1279
1401
|
* });
|
|
1280
|
-
*
|
|
1281
|
-
* // Using WiFi positioning (fallback)
|
|
1282
|
-
* const result = await client.captureLocation(token, {
|
|
1283
|
-
* wifi_networks: [
|
|
1284
|
-
* { macAddress: "00:11:22:33:44:55", signalStrength: -50 },
|
|
1285
|
-
* { macAddress: "AA:BB:CC:DD:EE:FF", signalStrength: -70 }
|
|
1286
|
-
* ]
|
|
1287
|
-
* });
|
|
1288
1402
|
* ```
|
|
1289
1403
|
*/
|
|
1290
1404
|
async captureLocation(token, capture, requestOptions) {
|
|
@@ -1714,9 +1828,6 @@ var ComplianceClient = class {
|
|
|
1714
1828
|
if (cipherTextResult.risk?.is_blocked) {
|
|
1715
1829
|
blockReasons.push(...cipherTextResult.risk.block_reasons_structured ?? []);
|
|
1716
1830
|
}
|
|
1717
|
-
if (cipherTextResult.risk?.location_mismatch) {
|
|
1718
|
-
blockReasons.push(sdkReasons.gpsIPMismatch());
|
|
1719
|
-
}
|
|
1720
1831
|
}
|
|
1721
1832
|
if (geoVerification.gps_required && !cipherTextResult) {
|
|
1722
1833
|
blockReasons.push(sdkReasons.gpsRequired());
|