vesant-sdk 1.7.0-dev.f9faca4 → 1.7.0-dev.fe84882
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-C3zUKydT.d.mts +264 -0
- package/dist/index-DSDgS09k.d.ts +264 -0
- package/dist/index.d.mts +26 -9
- package/dist/index.d.ts +26 -9
- package/dist/index.js +325 -58
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +318 -59
- 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 +2 -2
- package/dist/tax/index.d.ts +2 -2
- package/dist/tax/index.js +74 -10
- package/dist/tax/index.js.map +1 -1
- package/dist/tax/index.mjs +74 -10
- 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
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
// src/core/auth.ts
|
|
2
|
+
var StaticApiKeyProvider = class {
|
|
3
|
+
constructor(apiKey) {
|
|
4
|
+
this.apiKey = apiKey;
|
|
5
|
+
}
|
|
6
|
+
async getCredential() {
|
|
7
|
+
return this.apiKey ? { scheme: "Bearer", token: this.apiKey } : null;
|
|
8
|
+
}
|
|
9
|
+
canRefresh() {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
|
|
1
14
|
// src/core/errors.ts
|
|
2
15
|
var VesantError = class _VesantError extends Error {
|
|
3
16
|
constructor(message, code, statusCode, details) {
|
|
@@ -296,6 +309,12 @@ var BaseClient = class {
|
|
|
296
309
|
if (!config.tenantId?.trim()) {
|
|
297
310
|
throw new ValidationError("tenantId is required and must be a non-empty string", ["tenantId"]);
|
|
298
311
|
}
|
|
312
|
+
if (typeof fetch === "undefined") {
|
|
313
|
+
throw new VesantError(
|
|
314
|
+
"The Vesant SDK requires a global fetch (Node.js >= 18). Upgrade Node or provide a fetch polyfill.",
|
|
315
|
+
"RUNTIME_UNSUPPORTED"
|
|
316
|
+
);
|
|
317
|
+
}
|
|
299
318
|
this.interceptors = config.interceptors || [];
|
|
300
319
|
this.logger = config.logger || createConsoleLogger();
|
|
301
320
|
let environment = config.environment;
|
|
@@ -314,11 +333,12 @@ var BaseClient = class {
|
|
|
314
333
|
environment,
|
|
315
334
|
headers: config.headers || {},
|
|
316
335
|
timeout: config.timeout || 1e4,
|
|
317
|
-
retries: config.retries
|
|
336
|
+
retries: config.retries ?? 3,
|
|
318
337
|
debug: config.debug || false,
|
|
319
338
|
interceptors: this.interceptors,
|
|
320
339
|
logger: this.logger
|
|
321
340
|
};
|
|
341
|
+
this.authProvider = config.authProvider ?? (apiKey ? new StaticApiKeyProvider(apiKey) : void 0);
|
|
322
342
|
if (config.circuitBreaker) {
|
|
323
343
|
this.circuitBreaker = new CircuitBreaker(config.circuitBreaker);
|
|
324
344
|
}
|
|
@@ -326,6 +346,19 @@ var BaseClient = class {
|
|
|
326
346
|
this.rateLimitTracker = new RateLimitTracker();
|
|
327
347
|
}
|
|
328
348
|
}
|
|
349
|
+
/**
|
|
350
|
+
* Resolve the Idempotency-Key for a request. Mutating methods (POST/PUT/PATCH)
|
|
351
|
+
* get the caller-supplied key or a freshly minted UUID; non-mutating methods get
|
|
352
|
+
* none. requestWithRetry resolves this once and injects it so every retry reuses
|
|
353
|
+
* one key (letting the server dedup replays); a direct request() resolves per call.
|
|
354
|
+
*/
|
|
355
|
+
resolveIdempotencyKey(method, requestOptions) {
|
|
356
|
+
const isMutating = ["POST", "PUT", "PATCH"].includes((method || "GET").toUpperCase());
|
|
357
|
+
if (!isMutating) {
|
|
358
|
+
return void 0;
|
|
359
|
+
}
|
|
360
|
+
return requestOptions?.idempotencyKey ?? generateUUID();
|
|
361
|
+
}
|
|
329
362
|
/**
|
|
330
363
|
* Make an HTTP request with timeout and error handling
|
|
331
364
|
*/
|
|
@@ -351,15 +384,20 @@ var BaseClient = class {
|
|
|
351
384
|
...this.config.headers,
|
|
352
385
|
...options.headers || {}
|
|
353
386
|
};
|
|
354
|
-
|
|
355
|
-
|
|
387
|
+
const credential = await this.authProvider?.getCredential({
|
|
388
|
+
tenantId: this.config.tenantId,
|
|
389
|
+
requestId
|
|
390
|
+
});
|
|
391
|
+
if (credential) {
|
|
392
|
+
headers["Authorization"] = `${credential.scheme ?? "Bearer"} ${credential.token}`;
|
|
356
393
|
}
|
|
357
394
|
if (this.config.environment === "sandbox") {
|
|
358
395
|
headers["X-Sandbox"] = "true";
|
|
359
396
|
}
|
|
360
397
|
const method = (options.method || "GET").toUpperCase();
|
|
361
|
-
|
|
362
|
-
|
|
398
|
+
const idempotencyKey = this.resolveIdempotencyKey(method, requestOptions);
|
|
399
|
+
if (idempotencyKey) {
|
|
400
|
+
headers["Idempotency-Key"] = idempotencyKey;
|
|
363
401
|
}
|
|
364
402
|
const controller = new AbortController();
|
|
365
403
|
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
@@ -380,10 +418,28 @@ var BaseClient = class {
|
|
|
380
418
|
if (this.config.debug) {
|
|
381
419
|
this.logger.debug(`${finalOptions.method || "GET"} ${endpoint}`);
|
|
382
420
|
}
|
|
383
|
-
|
|
421
|
+
let response = await fetch(url, {
|
|
384
422
|
...finalOptions,
|
|
385
423
|
signal: controller.signal
|
|
386
424
|
});
|
|
425
|
+
if (response.status === 401 && this.authProvider?.canRefresh?.()) {
|
|
426
|
+
const refreshed = await this.authProvider.getCredential({
|
|
427
|
+
tenantId: this.config.tenantId,
|
|
428
|
+
requestId,
|
|
429
|
+
forceRefresh: true
|
|
430
|
+
});
|
|
431
|
+
if (refreshed) {
|
|
432
|
+
this.config.onCredentialRotated?.({ reason: "unauthorized" });
|
|
433
|
+
finalOptions = {
|
|
434
|
+
...finalOptions,
|
|
435
|
+
headers: {
|
|
436
|
+
...finalOptions.headers,
|
|
437
|
+
Authorization: `${refreshed.scheme ?? "Bearer"} ${refreshed.token}`
|
|
438
|
+
}
|
|
439
|
+
};
|
|
440
|
+
response = await fetch(url, { ...finalOptions, signal: controller.signal });
|
|
441
|
+
}
|
|
442
|
+
}
|
|
387
443
|
clearTimeout(timeoutId);
|
|
388
444
|
if (this.rateLimitTracker) {
|
|
389
445
|
this.rateLimitTracker.updateFromHeaders(response.headers);
|
|
@@ -472,9 +528,11 @@ var BaseClient = class {
|
|
|
472
528
|
*/
|
|
473
529
|
async requestWithRetry(endpoint, options = {}, serviceURL, retries = this.config.retries, requestOptions) {
|
|
474
530
|
let lastError;
|
|
531
|
+
const idempotencyKey = this.resolveIdempotencyKey(options.method || "GET", requestOptions);
|
|
532
|
+
const attemptOptions = idempotencyKey ? { ...requestOptions, idempotencyKey } : requestOptions;
|
|
475
533
|
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
476
534
|
try {
|
|
477
|
-
return await this.request(endpoint, options, serviceURL,
|
|
535
|
+
return await this.request(endpoint, options, serviceURL, attemptOptions);
|
|
478
536
|
} catch (error) {
|
|
479
537
|
lastError = error instanceof Error ? error : new Error("Unknown error");
|
|
480
538
|
if (requestOptions?.signal?.aborted) {
|
|
@@ -571,6 +629,9 @@ var BaseClient = class {
|
|
|
571
629
|
if (config.interceptors) {
|
|
572
630
|
this.interceptors = config.interceptors;
|
|
573
631
|
}
|
|
632
|
+
if (config.authProvider !== void 0 || config.apiKey !== void 0) {
|
|
633
|
+
this.authProvider = this.config.authProvider ?? (this.config.apiKey ? new StaticApiKeyProvider(this.config.apiKey) : void 0);
|
|
634
|
+
}
|
|
574
635
|
}
|
|
575
636
|
/**
|
|
576
637
|
* Get current configuration (readonly)
|
|
@@ -598,6 +659,61 @@ var BaseClient = class {
|
|
|
598
659
|
}
|
|
599
660
|
};
|
|
600
661
|
|
|
662
|
+
// src/geolocation/integrity.ts
|
|
663
|
+
var isNil = (v) => v === null || v === void 0;
|
|
664
|
+
function assessGpsIntegrity(input, opts = {}) {
|
|
665
|
+
const flags = [];
|
|
666
|
+
const now = opts.now ?? (() => Date.now());
|
|
667
|
+
const maxAgeMs = opts.maxAgeMs ?? 6e4;
|
|
668
|
+
const minAccuracy = opts.minAccuracyMeters ?? 1;
|
|
669
|
+
const { accuracy, altitude, altitudeAccuracy, heading, speed, timestamp } = input;
|
|
670
|
+
if (isNil(accuracy)) {
|
|
671
|
+
flags.push("accuracy_missing");
|
|
672
|
+
} else if (accuracy === 0) {
|
|
673
|
+
flags.push("accuracy_zero");
|
|
674
|
+
} else if (accuracy < minAccuracy) {
|
|
675
|
+
flags.push("accuracy_implausibly_small");
|
|
676
|
+
}
|
|
677
|
+
const hasMotion = !isNil(heading) || !isNil(speed);
|
|
678
|
+
if (hasMotion && (isNil(accuracy) || accuracy === 0)) {
|
|
679
|
+
flags.push("motion_without_accuracy");
|
|
680
|
+
}
|
|
681
|
+
if (!isNil(altitude) && isNil(altitudeAccuracy)) {
|
|
682
|
+
flags.push("altitude_without_accuracy");
|
|
683
|
+
}
|
|
684
|
+
if (timestamp !== void 0 && now() - timestamp > maxAgeMs) {
|
|
685
|
+
flags.push("stale_timestamp");
|
|
686
|
+
}
|
|
687
|
+
if (opts.permissionState === "denied" || opts.permissionState === "prompt") {
|
|
688
|
+
flags.push(`permission_${opts.permissionState}`);
|
|
689
|
+
}
|
|
690
|
+
return { suspicious: flags.length > 0, flags };
|
|
691
|
+
}
|
|
692
|
+
function gpsIntegrityInputFromPosition(position) {
|
|
693
|
+
const c = position.coords;
|
|
694
|
+
return {
|
|
695
|
+
latitude: c.latitude,
|
|
696
|
+
longitude: c.longitude,
|
|
697
|
+
accuracy: c.accuracy,
|
|
698
|
+
altitude: c.altitude,
|
|
699
|
+
altitudeAccuracy: c.altitudeAccuracy,
|
|
700
|
+
heading: c.heading,
|
|
701
|
+
speed: c.speed,
|
|
702
|
+
timestamp: position.timestamp
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
async function probeGeolocationPermission() {
|
|
706
|
+
try {
|
|
707
|
+
if (typeof navigator === "undefined" || !navigator.permissions?.query) {
|
|
708
|
+
return "unavailable";
|
|
709
|
+
}
|
|
710
|
+
const status = await navigator.permissions.query({ name: "geolocation" });
|
|
711
|
+
return status.state;
|
|
712
|
+
} catch {
|
|
713
|
+
return "unavailable";
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
|
|
601
717
|
// src/geolocation/ciphertext.ts
|
|
602
718
|
var CIPHER_TEXT_EXPIRY_MINUTES = 5;
|
|
603
719
|
async function computeHMAC(key, message) {
|
|
@@ -650,6 +766,7 @@ async function requestGPSLocation(timeout = 1e4, highAccuracy = true) {
|
|
|
650
766
|
if (typeof navigator === "undefined" || !navigator.geolocation) {
|
|
651
767
|
return null;
|
|
652
768
|
}
|
|
769
|
+
const permissionState = await probeGeolocationPermission();
|
|
653
770
|
return new Promise((resolve) => {
|
|
654
771
|
navigator.geolocation.getCurrentPosition(
|
|
655
772
|
(position) => {
|
|
@@ -666,6 +783,7 @@ async function requestGPSLocation(timeout = 1e4, highAccuracy = true) {
|
|
|
666
783
|
resolve(null);
|
|
667
784
|
return;
|
|
668
785
|
}
|
|
786
|
+
const { flags } = assessGpsIntegrity(gpsIntegrityInputFromPosition(position), { permissionState });
|
|
669
787
|
resolve({
|
|
670
788
|
latitude,
|
|
671
789
|
longitude,
|
|
@@ -674,7 +792,8 @@ async function requestGPSLocation(timeout = 1e4, highAccuracy = true) {
|
|
|
674
792
|
altitude_accuracy: position.coords.altitudeAccuracy ?? void 0,
|
|
675
793
|
heading: position.coords.heading ?? void 0,
|
|
676
794
|
speed: position.coords.speed ?? void 0,
|
|
677
|
-
timestamp: position.timestamp
|
|
795
|
+
timestamp: position.timestamp,
|
|
796
|
+
integrity_flags: flags.length ? flags : void 0
|
|
678
797
|
});
|
|
679
798
|
},
|
|
680
799
|
() => {
|
|
@@ -741,6 +860,9 @@ async function generateCipherText(options, config) {
|
|
|
741
860
|
);
|
|
742
861
|
if (location) {
|
|
743
862
|
locationData = location;
|
|
863
|
+
if (location.integrity_flags?.length) {
|
|
864
|
+
warnings.push(`GPS integrity flags (advisory): ${location.integrity_flags.join(", ")}`);
|
|
865
|
+
}
|
|
744
866
|
} else if (gpsRequiredByConfig) {
|
|
745
867
|
throw new VesantError(
|
|
746
868
|
`GPS location is required for ${options.reason} by tenant configuration, but GPS was not available or permission was denied`,
|
|
@@ -860,8 +982,8 @@ var GeolocationClient = class extends BaseClient {
|
|
|
860
982
|
* ```
|
|
861
983
|
*/
|
|
862
984
|
async verifyIP(request, requestOptions) {
|
|
863
|
-
if (!request.ip_address
|
|
864
|
-
throw new ValidationError("ip_address
|
|
985
|
+
if (request.ip_address !== void 0 && !request.ip_address.trim()) {
|
|
986
|
+
throw new ValidationError("ip_address, when provided, must be a non-empty string", ["ip_address"]);
|
|
865
987
|
}
|
|
866
988
|
return this.requestWithRetry("/api/v1/geo/verify", {
|
|
867
989
|
method: "POST",
|
|
@@ -1211,20 +1333,12 @@ var GeolocationClient = class extends BaseClient {
|
|
|
1211
1333
|
*
|
|
1212
1334
|
* @example
|
|
1213
1335
|
* ```typescript
|
|
1214
|
-
* //
|
|
1336
|
+
* // GPS (the web SDK is GPS + IP only; the server handles the IP fallback)
|
|
1215
1337
|
* const result = await client.captureLocation(token, {
|
|
1216
1338
|
* latitude: 37.7749,
|
|
1217
1339
|
* longitude: -122.4194,
|
|
1218
1340
|
* accuracy: 10
|
|
1219
1341
|
* });
|
|
1220
|
-
*
|
|
1221
|
-
* // Using WiFi positioning (fallback)
|
|
1222
|
-
* const result = await client.captureLocation(token, {
|
|
1223
|
-
* wifi_networks: [
|
|
1224
|
-
* { macAddress: "00:11:22:33:44:55", signalStrength: -50 },
|
|
1225
|
-
* { macAddress: "AA:BB:CC:DD:EE:FF", signalStrength: -70 }
|
|
1226
|
-
* ]
|
|
1227
|
-
* });
|
|
1228
1342
|
* ```
|
|
1229
1343
|
*/
|
|
1230
1344
|
async captureLocation(token, capture, requestOptions) {
|
|
@@ -1271,6 +1385,6 @@ var GeolocationClient = class extends BaseClient {
|
|
|
1271
1385
|
// ============================================================================
|
|
1272
1386
|
};
|
|
1273
1387
|
|
|
1274
|
-
export { GeolocationClient, decodeCipherText, generateCipherText, isCipherTextExpired };
|
|
1388
|
+
export { GeolocationClient, assessGpsIntegrity, decodeCipherText, generateCipherText, gpsIntegrityInputFromPosition, isCipherTextExpired, probeGeolocationPermission };
|
|
1275
1389
|
//# sourceMappingURL=index.mjs.map
|
|
1276
1390
|
//# sourceMappingURL=index.mjs.map
|