user-analytics-tracker 4.5.0 → 4.6.0

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/index.d.cts CHANGED
@@ -138,6 +138,8 @@ interface AnalyticsConfig {
138
138
  baseUrl?: string;
139
139
  timeout?: number;
140
140
  ip?: string;
141
+ /** Proxy URL for paid users in browser: client calls this; your backend calls ipwho.is with API key (key never in browser). */
142
+ proxyUrl?: string;
141
143
  };
142
144
  fieldStorage?: {
143
145
  ipLocation?: FieldStorageConfig$1;
@@ -266,17 +268,28 @@ declare class DeviceDetector {
266
268
  * 3) Paid subscription (e.g. ipwhois.pro):
267
269
  * - URL format: https://ipwhois.pro/{IP}?key=YOUR_API_KEY
268
270
  * - Pass baseUrl: 'https://ipwhois.pro', apiKey, and ip when you have the IP.
271
+ *
272
+ * 4) Paid users in the browser (recommended): use a proxy so API key and IP are not exposed.
273
+ * - Set ipGeolocation.proxyUrl to your backend route (e.g. '/api/ip-geolocation').
274
+ * - Browser calls the proxy; proxy calls ipwho.is/ipwhois.pro with API key from env and request IP.
275
+ * - See docs for proxy contract and example backend implementation.
269
276
  */
270
277
  /**
271
278
  * IP Geolocation configuration interface
272
- * Supports ipwho.is (free/paid) and ipwhois.pro (paid: baseUrl/{IP}?key=API_KEY)
279
+ * Supports ipwho.is (free/paid), ipwhois.pro (paid), and proxy (paid users in browser - no key in client).
273
280
  */
274
281
  interface IPGeolocationConfig {
275
282
  apiKey?: string;
276
283
  baseUrl?: string;
277
284
  timeout?: number;
278
- /** When provided (e.g. server-side or paid flow), lookup this IP. URL becomes baseUrl/{ip}?key=API_KEY */
285
+ /** When provided (server-side), lookup this IP. Ignored when proxyUrl is set. */
279
286
  ip?: string;
287
+ /**
288
+ * When set, the client calls this URL instead of ipwho.is. Your backend holds the API key and
289
+ * calls ipwho.is/ipwhois.pro server-side. Use for paid users in the browser so key and IP are not exposed.
290
+ * Contract: GET proxyUrl → auto-detect IP; GET proxyUrl?ip=1.2.3.4 → lookup that IP. Response = same JSON as ipwho.is.
291
+ */
292
+ proxyUrl?: string;
280
293
  }
281
294
  /**
282
295
  * Get complete IP location data from ipwho.is API (HIGH PRIORITY)
@@ -299,6 +312,9 @@ interface IPGeolocationConfig {
299
312
  * apiKey: '<key>',
300
313
  * ip: '203.0.113.42',
301
314
  * });
315
+ *
316
+ * // Paid users in browser: use proxy so API key is not exposed (GET proxyUrl → same JSON)
317
+ * const location = await getCompleteIPLocation({ proxyUrl: '/api/ip-geolocation', timeout: 5000 });
302
318
  * ```
303
319
  */
304
320
  declare function getCompleteIPLocation(config?: IPGeolocationConfig): Promise<IPLocation | null>;
package/dist/index.d.ts CHANGED
@@ -138,6 +138,8 @@ interface AnalyticsConfig {
138
138
  baseUrl?: string;
139
139
  timeout?: number;
140
140
  ip?: string;
141
+ /** Proxy URL for paid users in browser: client calls this; your backend calls ipwho.is with API key (key never in browser). */
142
+ proxyUrl?: string;
141
143
  };
142
144
  fieldStorage?: {
143
145
  ipLocation?: FieldStorageConfig$1;
@@ -266,17 +268,28 @@ declare class DeviceDetector {
266
268
  * 3) Paid subscription (e.g. ipwhois.pro):
267
269
  * - URL format: https://ipwhois.pro/{IP}?key=YOUR_API_KEY
268
270
  * - Pass baseUrl: 'https://ipwhois.pro', apiKey, and ip when you have the IP.
271
+ *
272
+ * 4) Paid users in the browser (recommended): use a proxy so API key and IP are not exposed.
273
+ * - Set ipGeolocation.proxyUrl to your backend route (e.g. '/api/ip-geolocation').
274
+ * - Browser calls the proxy; proxy calls ipwho.is/ipwhois.pro with API key from env and request IP.
275
+ * - See docs for proxy contract and example backend implementation.
269
276
  */
270
277
  /**
271
278
  * IP Geolocation configuration interface
272
- * Supports ipwho.is (free/paid) and ipwhois.pro (paid: baseUrl/{IP}?key=API_KEY)
279
+ * Supports ipwho.is (free/paid), ipwhois.pro (paid), and proxy (paid users in browser - no key in client).
273
280
  */
274
281
  interface IPGeolocationConfig {
275
282
  apiKey?: string;
276
283
  baseUrl?: string;
277
284
  timeout?: number;
278
- /** When provided (e.g. server-side or paid flow), lookup this IP. URL becomes baseUrl/{ip}?key=API_KEY */
285
+ /** When provided (server-side), lookup this IP. Ignored when proxyUrl is set. */
279
286
  ip?: string;
287
+ /**
288
+ * When set, the client calls this URL instead of ipwho.is. Your backend holds the API key and
289
+ * calls ipwho.is/ipwhois.pro server-side. Use for paid users in the browser so key and IP are not exposed.
290
+ * Contract: GET proxyUrl → auto-detect IP; GET proxyUrl?ip=1.2.3.4 → lookup that IP. Response = same JSON as ipwho.is.
291
+ */
292
+ proxyUrl?: string;
280
293
  }
281
294
  /**
282
295
  * Get complete IP location data from ipwho.is API (HIGH PRIORITY)
@@ -299,6 +312,9 @@ interface IPGeolocationConfig {
299
312
  * apiKey: '<key>',
300
313
  * ip: '203.0.113.42',
301
314
  * });
315
+ *
316
+ * // Paid users in browser: use proxy so API key is not exposed (GET proxyUrl → same JSON)
317
+ * const location = await getCompleteIPLocation({ proxyUrl: '/api/ip-geolocation', timeout: 5000 });
302
318
  * ```
303
319
  */
304
320
  declare function getCompleteIPLocation(config?: IPGeolocationConfig): Promise<IPLocation | null>;
package/dist/index.esm.js CHANGED
@@ -633,6 +633,9 @@ function checkAndSetLocationConsent(msisdn) {
633
633
  * apiKey: '<key>',
634
634
  * ip: '203.0.113.42',
635
635
  * });
636
+ *
637
+ * // Paid users in browser: use proxy so API key is not exposed (GET proxyUrl → same JSON)
638
+ * const location = await getCompleteIPLocation({ proxyUrl: '/api/ip-geolocation', timeout: 5000 });
636
639
  * ```
637
640
  */
638
641
  async function getCompleteIPLocation(config) {
@@ -640,30 +643,33 @@ async function getCompleteIPLocation(config) {
640
643
  if (typeof fetch === 'undefined') {
641
644
  return null;
642
645
  }
643
- // Use provided config or defaults
644
- const baseUrl = config?.baseUrl || 'https://ipwho.is';
645
- const timeout = config?.timeout || 5000;
646
- const apiKey = config?.apiKey;
647
- const configIp = config?.ip?.trim();
646
+ const timeout = config?.timeout ?? 5000;
648
647
  try {
649
- // Build URL: baseUrl/{IP}?key=API_KEY when IP provided (paid/server-side); else baseUrl/ or baseUrl?key=...
650
- let url = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
651
- if (configIp) {
652
- // Paid / server-side: lookup specific IP. Format: https://ipwhois.pro/{IP}?key=YOUR_API_KEY
653
- url += `/${encodeURIComponent(configIp)}`;
654
- if (apiKey) {
655
- url += `?key=${encodeURIComponent(apiKey)}`;
656
- }
648
+ let url;
649
+ if (config?.proxyUrl?.trim()) {
650
+ // Paid users in browser: call proxy; proxy holds API key and calls ipwho.is server-side (no key/IP exposed)
651
+ url = config.proxyUrl.trim();
657
652
  }
658
653
  else {
659
- // Auto-detect requestor IP (root path + optional key)
660
- url += '/';
661
- if (apiKey) {
662
- url += `?key=${encodeURIComponent(apiKey)}`;
654
+ // Direct call to ipwho.is / ipwhois.pro
655
+ const baseUrl = config?.baseUrl || 'https://ipwho.is';
656
+ const apiKey = config?.apiKey;
657
+ const configIp = config?.ip?.trim();
658
+ url = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
659
+ if (configIp) {
660
+ url += `/${encodeURIComponent(configIp)}`;
661
+ if (apiKey) {
662
+ url += `?key=${encodeURIComponent(apiKey)}`;
663
+ }
664
+ }
665
+ else {
666
+ url += '/';
667
+ if (apiKey) {
668
+ url += `?key=${encodeURIComponent(apiKey)}`;
669
+ }
663
670
  }
664
671
  }
665
- // Call API: with IP path it returns that IP's location; without path it returns requestor's IP
666
- // This is the HIGH PRIORITY source - gets IP, location, connection, timezone, flag, etc. in one call
672
+ // Call API or proxy: same response shape (ipwho.is JSON)
667
673
  const response = await fetch(url, {
668
674
  method: 'GET',
669
675
  headers: {
@@ -751,12 +757,14 @@ async function getPublicIP(config) {
751
757
  if (completeLocation?.ip) {
752
758
  return completeLocation.ip;
753
759
  }
754
- // Fallback: try direct IP fetch (less efficient, lower priority)
760
+ // Fallback: try direct IP fetch (only when not using proxy)
761
+ if (config?.proxyUrl?.trim()) {
762
+ return null;
763
+ }
755
764
  try {
756
765
  const baseUrl = config?.baseUrl || 'https://ipwho.is';
757
766
  const timeout = config?.timeout || 5000;
758
767
  const apiKey = config?.apiKey;
759
- // Build URL with optional API key (auto-detect requestor IP)
760
768
  let url = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
761
769
  if (apiKey) {
762
770
  url += `?key=${encodeURIComponent(apiKey)}`;
@@ -828,23 +836,27 @@ async function getIPLocation(ip, config) {
828
836
  return null;
829
837
  }
830
838
  try {
831
- // Use provided config or defaults
832
- const baseUrl = config?.baseUrl || 'https://ipwho.is';
833
- const timeout = config?.timeout || 5000;
834
- const apiKey = config?.apiKey;
835
- // Build URL: baseUrl/{IP}?key=API_KEY (same format as ipwhois.pro paid: https://ipwhois.pro/{IP}?key=YOUR_API_KEY)
836
- let url = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
837
- url += `/${encodeURIComponent(ip)}`;
838
- if (apiKey) {
839
- url += `?key=${encodeURIComponent(apiKey)}`;
839
+ const timeout = config?.timeout ?? 5000;
840
+ let url;
841
+ if (config?.proxyUrl?.trim()) {
842
+ const proxy = config.proxyUrl.trim();
843
+ const sep = proxy.includes('?') ? '&' : '?';
844
+ url = `${proxy}${sep}ip=${encodeURIComponent(ip)}`;
845
+ }
846
+ else {
847
+ const baseUrl = config?.baseUrl || 'https://ipwho.is';
848
+ const apiKey = config?.apiKey;
849
+ url = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
850
+ url += `/${encodeURIComponent(ip)}`;
851
+ if (apiKey) {
852
+ url += `?key=${encodeURIComponent(apiKey)}`;
853
+ }
840
854
  }
841
- // Using ipwho.is / ipwhois.pro API
842
855
  const response = await fetch(url, {
843
856
  method: 'GET',
844
857
  headers: {
845
858
  Accept: 'application/json',
846
859
  },
847
- // Add timeout to prevent hanging
848
860
  signal: AbortSignal.timeout(timeout),
849
861
  });
850
862
  if (!response.ok) {