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/CHANGELOG.md +7 -0
- package/README.md +8 -8
- package/dist/index.cjs.js +44 -32
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.cts +18 -2
- package/dist/index.d.ts +18 -2
- package/dist/index.esm.js +44 -32
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
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)
|
|
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 (
|
|
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)
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
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
|
-
//
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
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
|
|
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 (
|
|
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
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
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) {
|