vesant-sdk 1.7.0 → 1.7.1-dev.0520b46

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-B0qhE2kr.d.mts → client-5q4whhGu.d.mts} +2 -2
  2. package/dist/{client-DF7hlMEz.d.ts → client-BaUekQT8.d.ts} +96 -52
  3. package/dist/{client-DtH2RLuy.d.ts → client-DUHC-68_.d.ts} +2 -2
  4. package/dist/{client-DrjgZoH_.d.mts → client-XDEhh9VN.d.mts} +96 -52
  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 +218 -90
  10. package/dist/compliance/index.js.map +1 -1
  11. package/dist/compliance/index.mjs +218 -90
  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 +69 -8
  16. package/dist/decisions/index.js.map +1 -1
  17. package/dist/decisions/index.mjs +69 -8
  18. package/dist/decisions/index.mjs.map +1 -1
  19. package/dist/geolocation/index.d.mts +68 -7
  20. package/dist/geolocation/index.d.ts +68 -7
  21. package/dist/geolocation/index.js +223 -90
  22. package/dist/geolocation/index.js.map +1 -1
  23. package/dist/geolocation/index.mjs +220 -91
  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 +27 -10
  28. package/dist/index.d.ts +27 -10
  29. package/dist/index.js +418 -126
  30. package/dist/index.js.map +1 -1
  31. package/dist/index.mjs +409 -127
  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 +102 -21
  36. package/dist/kyc/core.js.map +1 -1
  37. package/dist/kyc/core.mjs +102 -22
  38. package/dist/kyc/core.mjs.map +1 -1
  39. package/dist/kyc/index.d.mts +154 -30
  40. package/dist/kyc/index.d.ts +154 -30
  41. package/dist/kyc/index.js +102 -21
  42. package/dist/kyc/index.js.map +1 -1
  43. package/dist/kyc/index.mjs +102 -22
  44. package/dist/kyc/index.mjs.map +1 -1
  45. package/dist/react.d.mts +14 -3
  46. package/dist/react.d.ts +14 -3
  47. package/dist/react.js +317 -68
  48. package/dist/react.js.map +1 -1
  49. package/dist/react.mjs +317 -68
  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 +69 -8
  54. package/dist/risk-profile/index.js.map +1 -1
  55. package/dist/risk-profile/index.mjs +69 -8
  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 +69 -8
  60. package/dist/scores/index.js.map +1 -1
  61. package/dist/scores/index.mjs +69 -8
  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 +74 -10
  66. package/dist/tax/index.js.map +1 -1
  67. package/dist/tax/index.mjs +74 -10
  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
@@ -73,6 +73,19 @@ var sdkReasons = {
73
73
  })
74
74
  };
75
75
 
76
+ // src/core/auth.ts
77
+ var StaticApiKeyProvider = class {
78
+ constructor(apiKey) {
79
+ this.apiKey = apiKey;
80
+ }
81
+ async getCredential() {
82
+ return this.apiKey ? { scheme: "Bearer", token: this.apiKey } : null;
83
+ }
84
+ canRefresh() {
85
+ return false;
86
+ }
87
+ };
88
+
76
89
  // src/core/errors.ts
77
90
  var VesantError = class _VesantError extends Error {
78
91
  constructor(message, code, statusCode, details) {
@@ -297,7 +310,7 @@ function createConsoleLogger() {
297
310
  }
298
311
 
299
312
  // src/core/version.ts
300
- var SDK_VERSION = "1.7.0";
313
+ var SDK_VERSION = "1.7.1";
301
314
 
302
315
  // src/shared/browser-utils.ts
303
316
  function generateUUID() {
@@ -379,6 +392,12 @@ var BaseClient = class {
379
392
  if (!config.tenantId?.trim()) {
380
393
  throw new ValidationError("tenantId is required and must be a non-empty string", ["tenantId"]);
381
394
  }
395
+ if (typeof fetch === "undefined") {
396
+ throw new VesantError(
397
+ "The Vesant SDK requires a global fetch (Node.js >= 18). Upgrade Node or provide a fetch polyfill.",
398
+ "RUNTIME_UNSUPPORTED"
399
+ );
400
+ }
382
401
  this.interceptors = config.interceptors || [];
383
402
  this.logger = config.logger || createConsoleLogger();
384
403
  let environment = config.environment;
@@ -397,11 +416,12 @@ var BaseClient = class {
397
416
  environment,
398
417
  headers: config.headers || {},
399
418
  timeout: config.timeout || 1e4,
400
- retries: config.retries || 3,
419
+ retries: config.retries ?? 3,
401
420
  debug: config.debug || false,
402
421
  interceptors: this.interceptors,
403
422
  logger: this.logger
404
423
  };
424
+ this.authProvider = config.authProvider ?? (apiKey ? new StaticApiKeyProvider(apiKey) : void 0);
405
425
  if (config.circuitBreaker) {
406
426
  this.circuitBreaker = new CircuitBreaker(config.circuitBreaker);
407
427
  }
@@ -409,6 +429,19 @@ var BaseClient = class {
409
429
  this.rateLimitTracker = new RateLimitTracker();
410
430
  }
411
431
  }
432
+ /**
433
+ * Resolve the Idempotency-Key for a request. Mutating methods (POST/PUT/PATCH)
434
+ * get the caller-supplied key or a freshly minted UUID; non-mutating methods get
435
+ * none. requestWithRetry resolves this once and injects it so every retry reuses
436
+ * one key (letting the server dedup replays); a direct request() resolves per call.
437
+ */
438
+ resolveIdempotencyKey(method, requestOptions) {
439
+ const isMutating = ["POST", "PUT", "PATCH"].includes((method || "GET").toUpperCase());
440
+ if (!isMutating) {
441
+ return void 0;
442
+ }
443
+ return requestOptions?.idempotencyKey ?? generateUUID();
444
+ }
412
445
  /**
413
446
  * Make an HTTP request with timeout and error handling
414
447
  */
@@ -434,15 +467,20 @@ var BaseClient = class {
434
467
  ...this.config.headers,
435
468
  ...options.headers || {}
436
469
  };
437
- if (this.config.apiKey) {
438
- headers["Authorization"] = `Bearer ${this.config.apiKey}`;
470
+ const credential = await this.authProvider?.getCredential({
471
+ tenantId: this.config.tenantId,
472
+ requestId
473
+ });
474
+ if (credential) {
475
+ headers["Authorization"] = `${credential.scheme ?? "Bearer"} ${credential.token}`;
439
476
  }
440
477
  if (this.config.environment === "sandbox") {
441
478
  headers["X-Sandbox"] = "true";
442
479
  }
443
480
  const method = (options.method || "GET").toUpperCase();
444
- if (["POST", "PUT", "PATCH"].includes(method)) {
445
- headers["Idempotency-Key"] = requestOptions?.idempotencyKey || generateUUID();
481
+ const idempotencyKey = this.resolveIdempotencyKey(method, requestOptions);
482
+ if (idempotencyKey) {
483
+ headers["Idempotency-Key"] = idempotencyKey;
446
484
  }
447
485
  const controller = new AbortController();
448
486
  const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
@@ -463,10 +501,28 @@ var BaseClient = class {
463
501
  if (this.config.debug) {
464
502
  this.logger.debug(`${finalOptions.method || "GET"} ${endpoint}`);
465
503
  }
466
- const response = await fetch(url, {
504
+ let response = await fetch(url, {
467
505
  ...finalOptions,
468
506
  signal: controller.signal
469
507
  });
508
+ if (response.status === 401 && this.authProvider?.canRefresh?.()) {
509
+ const refreshed = await this.authProvider.getCredential({
510
+ tenantId: this.config.tenantId,
511
+ requestId,
512
+ forceRefresh: true
513
+ });
514
+ if (refreshed) {
515
+ this.config.onCredentialRotated?.({ reason: "unauthorized" });
516
+ finalOptions = {
517
+ ...finalOptions,
518
+ headers: {
519
+ ...finalOptions.headers,
520
+ Authorization: `${refreshed.scheme ?? "Bearer"} ${refreshed.token}`
521
+ }
522
+ };
523
+ response = await fetch(url, { ...finalOptions, signal: controller.signal });
524
+ }
525
+ }
470
526
  clearTimeout(timeoutId);
471
527
  if (this.rateLimitTracker) {
472
528
  this.rateLimitTracker.updateFromHeaders(response.headers);
@@ -555,9 +611,11 @@ var BaseClient = class {
555
611
  */
556
612
  async requestWithRetry(endpoint, options = {}, serviceURL, retries = this.config.retries, requestOptions) {
557
613
  let lastError;
614
+ const idempotencyKey = this.resolveIdempotencyKey(options.method || "GET", requestOptions);
615
+ const attemptOptions = idempotencyKey ? { ...requestOptions, idempotencyKey } : requestOptions;
558
616
  for (let attempt = 0; attempt <= retries; attempt++) {
559
617
  try {
560
- return await this.request(endpoint, options, serviceURL, requestOptions);
618
+ return await this.request(endpoint, options, serviceURL, attemptOptions);
561
619
  } catch (error) {
562
620
  lastError = error instanceof Error ? error : new Error("Unknown error");
563
621
  if (requestOptions?.signal?.aborted) {
@@ -654,6 +712,9 @@ var BaseClient = class {
654
712
  if (config.interceptors) {
655
713
  this.interceptors = config.interceptors;
656
714
  }
715
+ if (config.authProvider !== void 0 || config.apiKey !== void 0) {
716
+ this.authProvider = this.config.authProvider ?? (this.config.apiKey ? new StaticApiKeyProvider(this.config.apiKey) : void 0);
717
+ }
657
718
  }
658
719
  /**
659
720
  * Get current configuration (readonly)
@@ -681,27 +742,63 @@ var BaseClient = class {
681
742
  }
682
743
  };
683
744
 
684
- // src/geolocation/ciphertext.ts
685
- var CIPHER_TEXT_EXPIRY_MINUTES = 5;
686
- async function computeHMAC(key, message) {
687
- if (typeof globalThis.crypto !== "undefined" && globalThis.crypto.subtle) {
688
- const encoder = new TextEncoder();
689
- const keyData = encoder.encode(key);
690
- const msgData = encoder.encode(message);
691
- const cryptoKey = await globalThis.crypto.subtle.importKey(
692
- "raw",
693
- keyData,
694
- { name: "HMAC", hash: "SHA-256" },
695
- false,
696
- ["sign"]
697
- );
698
- const signature = await globalThis.crypto.subtle.sign("HMAC", cryptoKey, msgData);
699
- const bytes = new Uint8Array(signature);
700
- return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
745
+ // src/geolocation/integrity.ts
746
+ var isNil = (v) => v === null || v === void 0;
747
+ function assessGpsIntegrity(input, opts = {}) {
748
+ const flags = [];
749
+ const now = opts.now ?? (() => Date.now());
750
+ const maxAgeMs = opts.maxAgeMs ?? 6e4;
751
+ const minAccuracy = opts.minAccuracyMeters ?? 1;
752
+ const { accuracy, altitude, altitudeAccuracy, heading, speed, timestamp } = input;
753
+ if (isNil(accuracy)) {
754
+ flags.push("accuracy_missing");
755
+ } else if (accuracy === 0) {
756
+ flags.push("accuracy_zero");
757
+ } else if (accuracy < minAccuracy) {
758
+ flags.push("accuracy_implausibly_small");
759
+ }
760
+ const hasMotion = !isNil(heading) || !isNil(speed);
761
+ if (hasMotion && (isNil(accuracy) || accuracy === 0)) {
762
+ flags.push("motion_without_accuracy");
763
+ }
764
+ if (!isNil(altitude) && isNil(altitudeAccuracy)) {
765
+ flags.push("altitude_without_accuracy");
766
+ }
767
+ if (timestamp !== void 0 && now() - timestamp > maxAgeMs) {
768
+ flags.push("stale_timestamp");
769
+ }
770
+ if (opts.permissionState === "denied" || opts.permissionState === "prompt") {
771
+ flags.push(`permission_${opts.permissionState}`);
772
+ }
773
+ return { suspicious: flags.length > 0, flags };
774
+ }
775
+ function gpsIntegrityInputFromPosition(position) {
776
+ const c = position.coords;
777
+ return {
778
+ latitude: c.latitude,
779
+ longitude: c.longitude,
780
+ accuracy: c.accuracy,
781
+ altitude: c.altitude,
782
+ altitudeAccuracy: c.altitudeAccuracy,
783
+ heading: c.heading,
784
+ speed: c.speed,
785
+ timestamp: position.timestamp
786
+ };
787
+ }
788
+ async function probeGeolocationPermission() {
789
+ try {
790
+ if (typeof navigator === "undefined" || !navigator.permissions?.query) {
791
+ return "unavailable";
792
+ }
793
+ const status = await navigator.permissions.query({ name: "geolocation" });
794
+ return status.state;
795
+ } catch {
796
+ return "unavailable";
701
797
  }
702
- const { createHmac } = await import('crypto');
703
- return createHmac("sha256", key).update(message).digest("hex");
704
798
  }
799
+
800
+ // src/geolocation/ciphertext.ts
801
+ var CIPHER_TEXT_EXPIRY_MINUTES = 5;
705
802
  function getWebGLInfo() {
706
803
  if (typeof document === "undefined") return null;
707
804
  try {
@@ -733,6 +830,7 @@ async function requestGPSLocation(timeout = 1e4, highAccuracy = true) {
733
830
  if (typeof navigator === "undefined" || !navigator.geolocation) {
734
831
  return null;
735
832
  }
833
+ const permissionState = await probeGeolocationPermission();
736
834
  return new Promise((resolve) => {
737
835
  navigator.geolocation.getCurrentPosition(
738
836
  (position) => {
@@ -749,6 +847,7 @@ async function requestGPSLocation(timeout = 1e4, highAccuracy = true) {
749
847
  resolve(null);
750
848
  return;
751
849
  }
850
+ const { flags } = assessGpsIntegrity(gpsIntegrityInputFromPosition(position), { permissionState });
752
851
  resolve({
753
852
  latitude,
754
853
  longitude,
@@ -757,7 +856,8 @@ async function requestGPSLocation(timeout = 1e4, highAccuracy = true) {
757
856
  altitude_accuracy: position.coords.altitudeAccuracy ?? void 0,
758
857
  heading: position.coords.heading ?? void 0,
759
858
  speed: position.coords.speed ?? void 0,
760
- timestamp: position.timestamp
859
+ timestamp: position.timestamp,
860
+ integrity_flags: flags.length ? flags : void 0
761
861
  });
762
862
  },
763
863
  () => {
@@ -824,6 +924,9 @@ async function generateCipherText(options, config) {
824
924
  );
825
925
  if (location) {
826
926
  locationData = location;
927
+ if (location.integrity_flags?.length) {
928
+ warnings.push(`GPS integrity flags (advisory): ${location.integrity_flags.join(", ")}`);
929
+ }
827
930
  } else if (gpsRequiredByConfig) {
828
931
  throw new VesantError(
829
932
  `GPS location is required for ${options.reason} by tenant configuration, but GPS was not available or permission was denied`,
@@ -853,15 +956,7 @@ async function generateCipherText(options, config) {
853
956
  };
854
957
  const encoded = encodePayload(payload);
855
958
  const timestamp = now.getTime().toString(36);
856
- let cipherText;
857
- const hmacKey = options.signingKey || options.apiKey;
858
- if (hmacKey) {
859
- const message = `02.${timestamp}.${encoded}`;
860
- const hmac = await computeHMAC(hmacKey, message);
861
- cipherText = `${message}.${hmac}`;
862
- } else {
863
- cipherText = `01.${timestamp}.${encoded}`;
864
- }
959
+ const cipherText = `01.${timestamp}.${encoded}`;
865
960
  return {
866
961
  cipherText,
867
962
  locationCaptured: !!locationData,
@@ -872,6 +967,7 @@ async function generateCipherText(options, config) {
872
967
  }
873
968
 
874
969
  // src/geolocation/client.ts
970
+ var DEFAULT_GPS_CONFIG_TTL_MS = 5 * 60 * 1e3;
875
971
  var GeolocationClient = class extends BaseClient {
876
972
  constructor(config) {
877
973
  const baseConfig = {
@@ -887,6 +983,8 @@ var GeolocationClient = class extends BaseClient {
887
983
  environment: config.environment
888
984
  };
889
985
  super(baseConfig);
986
+ this.gpsConfigCache = null;
987
+ this.gpsConfigTtlMs = config.gpsConfigTtlMs ?? DEFAULT_GPS_CONFIG_TTL_MS;
890
988
  }
891
989
  // ============================================================================
892
990
  // IP Verification & Compliance
@@ -918,8 +1016,8 @@ var GeolocationClient = class extends BaseClient {
918
1016
  * ```
919
1017
  */
920
1018
  async verifyIP(request, requestOptions) {
921
- if (!request.ip_address?.trim()) {
922
- throw new ValidationError("ip_address is required and must be a non-empty string", ["ip_address"]);
1019
+ if (request.ip_address !== void 0 && !request.ip_address.trim()) {
1020
+ throw new ValidationError("ip_address, when provided, must be a non-empty string", ["ip_address"]);
923
1021
  }
924
1022
  return this.requestWithRetry("/api/v1/geo/verify", {
925
1023
  method: "POST",
@@ -972,37 +1070,85 @@ var GeolocationClient = class extends BaseClient {
972
1070
  * ```
973
1071
  */
974
1072
  async getGPSConfig(requestOptions) {
975
- const config = await this.requestWithRetry("/api/v1/geo/config", void 0, void 0, void 0, requestOptions);
976
- if (config.signing_key) {
977
- this.cachedSigningKey = config.signing_key;
1073
+ const cached = this.gpsConfigCache;
1074
+ if (cached && cached.expiresAt > Date.now()) {
1075
+ return cached.value;
978
1076
  }
979
- return config;
1077
+ return this.refreshGPSConfig(requestOptions);
980
1078
  }
981
1079
  /**
982
- * Fetch the signing key from the dedicated authenticated endpoint.
1080
+ * Re-read the tenant's GPS requirement configuration, ignoring any copy held
1081
+ * from an earlier read.
983
1082
  *
984
- * Falls back to getGPSConfig() for backward compatibility with older servers
985
- * that don't expose `/api/v1/geo/signing-key`.
1083
+ * These requirements are edited in the compliance console while your
1084
+ * application is running. `getGPSConfig` reuses a fetched copy for a short
1085
+ * period so a long-lived session does not call the API on every event; call
1086
+ * this when you need a change to take effect immediately — for example right
1087
+ * after an administrator saves new settings.
986
1088
  *
987
- * @returns The signing key string, or undefined if unavailable
1089
+ * @returns The current GPS requirement config per event type
1090
+ *
1091
+ * @example
1092
+ * ```typescript
1093
+ * const config = await client.refreshGPSConfig();
1094
+ * if (config.require_gps.login) {
1095
+ * // GPS is now required for login
1096
+ * }
1097
+ * ```
1098
+ */
1099
+ async refreshGPSConfig(requestOptions) {
1100
+ const value = await this.requestWithRetry(
1101
+ "/api/v1/geo/config",
1102
+ void 0,
1103
+ void 0,
1104
+ void 0,
1105
+ requestOptions
1106
+ );
1107
+ this.gpsConfigCache = { value, expiresAt: Date.now() + this.gpsConfigTtlMs };
1108
+ return value;
1109
+ }
1110
+ /**
1111
+ * Mint a short-lived, single-use device-signals nonce.
1112
+ *
1113
+ * The nonce is bound to the tenant, user, and event type and is consumed
1114
+ * server-side during validation, so a captured device-signals envelope cannot
1115
+ * be replayed. `validateCipherText` mints and attaches one automatically; call
1116
+ * this directly only if you manage the nonce yourself.
1117
+ *
1118
+ * @param userId - User ID the nonce is bound to
1119
+ * @param eventType - Event type the nonce is bound to (login, registration, ...)
1120
+ * @returns The nonce and its expiry
1121
+ */
1122
+ async fetchSignalsNonce(userId, eventType, requestOptions) {
1123
+ if (!userId?.trim()) {
1124
+ throw new ValidationError("userId is required and must be a non-empty string", ["userId"]);
1125
+ }
1126
+ const request = { user_id: userId, event_type: eventType };
1127
+ return this.request(
1128
+ "/api/v1/geo/signals-token",
1129
+ {
1130
+ method: "POST",
1131
+ body: JSON.stringify(request)
1132
+ },
1133
+ void 0,
1134
+ requestOptions
1135
+ );
1136
+ }
1137
+ /**
1138
+ * Best-effort nonce mint for validation. Returns undefined if minting fails —
1139
+ * the server is the sole authority and blocks when a nonce is required, so this
1140
+ * never downgrades security on the client's say-so.
988
1141
  */
989
- async fetchSigningKey(requestOptions) {
1142
+ async resolveSignalsNonce(userId, eventType, requestOptions) {
990
1143
  try {
991
- const response = await this.requestWithRetry(
992
- "/api/v1/geo/signing-key",
993
- void 0,
994
- void 0,
995
- void 0,
996
- requestOptions
1144
+ const { nonce } = await this.fetchSignalsNonce(userId, eventType, requestOptions);
1145
+ return nonce;
1146
+ } catch (err) {
1147
+ this.logger.warn(
1148
+ `Failed to mint device-signals nonce; proceeding without it: ${err instanceof Error ? err.message : String(err)}`
997
1149
  );
998
- if (response.signing_key) {
999
- this.cachedSigningKey = response.signing_key;
1000
- return response.signing_key;
1001
- }
1002
- } catch {
1150
+ return void 0;
1003
1151
  }
1004
- const config = await this.getGPSConfig(requestOptions);
1005
- return config.signing_key;
1006
1152
  }
1007
1153
  // ============================================================================
1008
1154
  // CipherText Validation
@@ -1055,12 +1201,14 @@ var GeolocationClient = class extends BaseClient {
1055
1201
  if (!userId?.trim()) {
1056
1202
  throw new ValidationError("userId is required and must be a non-empty string", ["userId"]);
1057
1203
  }
1204
+ const nonce = await this.resolveSignalsNonce(userId, eventType, requestOptions);
1058
1205
  const request = {
1059
1206
  cipher_text: cipherText,
1060
1207
  user_id: userId,
1061
1208
  event_type: eventType,
1062
1209
  expected_ip: expectedIP,
1063
- customer_data: customerData
1210
+ customer_data: customerData,
1211
+ nonce
1064
1212
  };
1065
1213
  return this.requestWithRetry(
1066
1214
  "/api/v1/geo/validate-ciphertext",
@@ -1269,20 +1417,12 @@ var GeolocationClient = class extends BaseClient {
1269
1417
  *
1270
1418
  * @example
1271
1419
  * ```typescript
1272
- * // Using GPS (preferred)
1420
+ * // GPS (the web SDK is GPS + IP only; the server handles the IP fallback)
1273
1421
  * const result = await client.captureLocation(token, {
1274
1422
  * latitude: 37.7749,
1275
1423
  * longitude: -122.4194,
1276
1424
  * accuracy: 10
1277
1425
  * });
1278
- *
1279
- * // Using WiFi positioning (fallback)
1280
- * const result = await client.captureLocation(token, {
1281
- * wifi_networks: [
1282
- * { macAddress: "00:11:22:33:44:55", signalStrength: -50 },
1283
- * { macAddress: "AA:BB:CC:DD:EE:FF", signalStrength: -70 }
1284
- * ]
1285
- * });
1286
1426
  * ```
1287
1427
  */
1288
1428
  async captureLocation(token, capture, requestOptions) {
@@ -1295,34 +1435,22 @@ var GeolocationClient = class extends BaseClient {
1295
1435
  // CipherText Generation
1296
1436
  // ============================================================================
1297
1437
  /**
1298
- * Generate a signed cipherText containing device and location data.
1299
- *
1300
- * Automatically passes the client's API key for HMAC signing (v02 format).
1301
- * If no API key is configured, falls back to unsigned v01 format.
1438
+ * Generate a device-signals envelope containing device and location data,
1439
+ * validated by the server.
1302
1440
  *
1303
- * @param options - Options for cipherText generation
1441
+ * @param options - Options for envelope generation
1304
1442
  * @param gpsConfig - Optional GPS config (from getGPSConfig)
1305
- * @returns CipherText result with the signed string
1443
+ * @returns The device-signals envelope result
1306
1444
  *
1307
1445
  * @example
1308
1446
  * ```typescript
1309
1447
  * const result = await client.generateCipherText({ reason: 'login' });
1310
- * console.log(result.cipherText); // v02 signed cipherText
1448
+ * console.log(result.cipherText); // device-signals envelope
1311
1449
  * ```
1312
1450
  */
1313
1451
  async generateCipherText(options, gpsConfig) {
1314
- let signingKey = this.cachedSigningKey;
1315
- let resolvedGpsConfig = gpsConfig;
1316
- if (!signingKey) {
1317
- signingKey = await this.fetchSigningKey();
1318
- }
1319
- if (!resolvedGpsConfig) {
1320
- resolvedGpsConfig = await this.getGPSConfig();
1321
- }
1322
- return generateCipherText(
1323
- { ...options, signingKey: signingKey || void 0 },
1324
- resolvedGpsConfig
1325
- );
1452
+ const resolvedGpsConfig = gpsConfig ?? await this.getGPSConfig();
1453
+ return generateCipherText(options, resolvedGpsConfig);
1326
1454
  }
1327
1455
  // ============================================================================
1328
1456
  // Utility Methods (inherited from BaseClient: healthCheck, updateConfig, getConfig, buildQueryString)