vesant-sdk 1.7.0-dev.a85efc5 → 1.7.0-dev.ab635a0

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.
Files changed (75) hide show
  1. package/dist/{client-DF7hlMEz.d.ts → client-0NOPDnT0.d.ts} +16 -26
  2. package/dist/{client-DrjgZoH_.d.mts → client-CvWNRwwg.d.mts} +16 -26
  3. package/dist/{client-B0qhE2kr.d.mts → client-Dps40EtF.d.mts} +2 -2
  4. package/dist/{client-DtH2RLuy.d.ts → client-SMxqod4j.d.ts} +2 -2
  5. package/dist/{client-BolQlL5e.d.mts → client-q9fN8Hhf.d.mts} +103 -1
  6. package/dist/{client-BolQlL5e.d.ts → client-q9fN8Hhf.d.ts} +103 -1
  7. package/dist/compliance/index.d.mts +3 -3
  8. package/dist/compliance/index.d.ts +3 -3
  9. package/dist/compliance/index.js +133 -19
  10. package/dist/compliance/index.js.map +1 -1
  11. package/dist/compliance/index.mjs +133 -19
  12. package/dist/compliance/index.mjs.map +1 -1
  13. package/dist/decisions/index.d.mts +1 -1
  14. package/dist/decisions/index.d.ts +1 -1
  15. package/dist/decisions/index.js +68 -7
  16. package/dist/decisions/index.js.map +1 -1
  17. package/dist/decisions/index.mjs +68 -7
  18. package/dist/decisions/index.mjs.map +1 -1
  19. package/dist/geolocation/index.d.mts +59 -4
  20. package/dist/geolocation/index.d.ts +59 -4
  21. package/dist/geolocation/index.js +136 -19
  22. package/dist/geolocation/index.js.map +1 -1
  23. package/dist/geolocation/index.mjs +134 -20
  24. package/dist/geolocation/index.mjs.map +1 -1
  25. package/dist/index-C3zUKydT.d.mts +264 -0
  26. package/dist/index-DSDgS09k.d.ts +264 -0
  27. package/dist/index.d.mts +26 -9
  28. package/dist/index.d.ts +26 -9
  29. package/dist/index.js +320 -50
  30. package/dist/index.js.map +1 -1
  31. package/dist/index.mjs +313 -51
  32. package/dist/index.mjs.map +1 -1
  33. package/dist/kyc/core.d.mts +2 -2
  34. package/dist/kyc/core.d.ts +2 -2
  35. package/dist/kyc/core.js +90 -15
  36. package/dist/kyc/core.js.map +1 -1
  37. package/dist/kyc/core.mjs +90 -15
  38. package/dist/kyc/core.mjs.map +1 -1
  39. package/dist/kyc/index.d.mts +56 -8
  40. package/dist/kyc/index.d.ts +56 -8
  41. package/dist/kyc/index.js +90 -15
  42. package/dist/kyc/index.js.map +1 -1
  43. package/dist/kyc/index.mjs +90 -15
  44. package/dist/kyc/index.mjs.map +1 -1
  45. package/dist/react.d.mts +7 -3
  46. package/dist/react.d.ts +7 -3
  47. package/dist/react.js +68 -4
  48. package/dist/react.js.map +1 -1
  49. package/dist/react.mjs +68 -4
  50. package/dist/react.mjs.map +1 -1
  51. package/dist/risk-profile/index.d.mts +1 -1
  52. package/dist/risk-profile/index.d.ts +1 -1
  53. package/dist/risk-profile/index.js +68 -7
  54. package/dist/risk-profile/index.js.map +1 -1
  55. package/dist/risk-profile/index.mjs +68 -7
  56. package/dist/risk-profile/index.mjs.map +1 -1
  57. package/dist/scores/index.d.mts +1 -1
  58. package/dist/scores/index.d.ts +1 -1
  59. package/dist/scores/index.js +68 -7
  60. package/dist/scores/index.js.map +1 -1
  61. package/dist/scores/index.mjs +68 -7
  62. package/dist/scores/index.mjs.map +1 -1
  63. package/dist/tax/index.d.mts +2 -2
  64. package/dist/tax/index.d.ts +2 -2
  65. package/dist/tax/index.js +73 -9
  66. package/dist/tax/index.js.map +1 -1
  67. package/dist/tax/index.mjs +73 -9
  68. package/dist/tax/index.mjs.map +1 -1
  69. package/dist/webhooks/index.d.mts +2 -189
  70. package/dist/webhooks/index.d.ts +2 -189
  71. package/dist/webhooks/index.js +85 -21
  72. package/dist/webhooks/index.js.map +1 -1
  73. package/dist/webhooks/index.mjs +85 -22
  74. package/dist/webhooks/index.mjs.map +1 -1
  75. package/package.json +4 -1
@@ -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 || 3,
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
- if (this.config.apiKey) {
440
- headers["Authorization"] = `Bearer ${this.config.apiKey}`;
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
- if (["POST", "PUT", "PATCH"].includes(method)) {
447
- headers["Idempotency-Key"] = requestOptions?.idempotencyKey || generateUUID();
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
- const response = await fetch(url, {
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, requestOptions);
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?.trim()) {
924
- throw new ValidationError("ip_address is required and must be a non-empty string", ["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
- * // Using GPS (preferred)
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) {