@fingerprint/node-sdk 7.0.0-test.0 → 7.0.0-test.1
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.cjs +43 -39
- package/dist/index.d.ts +11 -39
- package/dist/index.mjs +43 -39
- package/package.json +5 -1
- package/src/serverApiClient.ts +59 -39
- package/src/types.ts +6 -39
- package/src/urlUtils.ts +15 -68
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Fingerprint Server Node.js SDK v7.0.0-test.
|
|
2
|
+
* Fingerprint Server Node.js SDK v7.0.0-test.1 - Copyright (c) FingerprintJS, Inc, 2026 (https://fingerprint.com)
|
|
3
3
|
* Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
|
|
4
4
|
*/
|
|
5
5
|
|
|
@@ -17,7 +17,7 @@ exports.Region = void 0;
|
|
|
17
17
|
Region["Global"] = "Global";
|
|
18
18
|
})(exports.Region || (exports.Region = {}));
|
|
19
19
|
|
|
20
|
-
var version = "7.0.0-test.
|
|
20
|
+
var version = "7.0.0-test.1";
|
|
21
21
|
|
|
22
22
|
const apiVersion = 'v4';
|
|
23
23
|
const euRegionUrl = 'https://eu.api.fpjs.io/';
|
|
@@ -65,13 +65,13 @@ function getServerApiUrl(region) {
|
|
|
65
65
|
*
|
|
66
66
|
* @internal
|
|
67
67
|
*
|
|
68
|
-
* @param {GetRequestPathOptions
|
|
69
|
-
* @param {
|
|
68
|
+
* @param {GetRequestPathOptions} options
|
|
69
|
+
* @param {keyof paths} options.path - The path of the API endpoint
|
|
70
70
|
* @param {string[]} [options.pathParams] - Path parameters to be replaced in the path
|
|
71
|
-
* @param {
|
|
71
|
+
* @param {GetRequestPathOptions["queryParams"]} [options.queryParams] - Query string
|
|
72
72
|
* parameters to be appended to the URL
|
|
73
73
|
* @param {Region} options.region - The region of the API endpoint
|
|
74
|
-
* @param {
|
|
74
|
+
* @param {HttpMethod} options.method - The method of the API endpoint
|
|
75
75
|
*
|
|
76
76
|
* @returns {string} The formatted URL with parameters replaced and query string
|
|
77
77
|
* parameters appended
|
|
@@ -233,6 +233,7 @@ class FingerprintServerApiClient {
|
|
|
233
233
|
pathParams: [eventId],
|
|
234
234
|
method: 'get',
|
|
235
235
|
queryParams: options,
|
|
236
|
+
expect: 'json',
|
|
236
237
|
});
|
|
237
238
|
}
|
|
238
239
|
/**
|
|
@@ -243,8 +244,8 @@ class FingerprintServerApiClient {
|
|
|
243
244
|
*
|
|
244
245
|
* **Warning** It's not possible to update events older than one month.
|
|
245
246
|
*
|
|
246
|
-
* @param body - Data to update the event with.
|
|
247
247
|
* @param eventId The unique event [identifier](https://docs.fingerprint.com/reference/js-agent-v4-get-function#event_id).
|
|
248
|
+
* @param body - Data to update the event with.
|
|
248
249
|
*
|
|
249
250
|
* @return {Promise<void>}
|
|
250
251
|
*
|
|
@@ -256,7 +257,7 @@ class FingerprintServerApiClient {
|
|
|
256
257
|
* }
|
|
257
258
|
*
|
|
258
259
|
* client
|
|
259
|
-
* .updateEvent(
|
|
260
|
+
* .updateEvent('<eventId>', body)
|
|
260
261
|
* .then(() => {
|
|
261
262
|
* // Event was successfully updated
|
|
262
263
|
* })
|
|
@@ -273,7 +274,7 @@ class FingerprintServerApiClient {
|
|
|
273
274
|
* })
|
|
274
275
|
* ```
|
|
275
276
|
*/
|
|
276
|
-
async updateEvent(
|
|
277
|
+
async updateEvent(eventId, body) {
|
|
277
278
|
if (!body) {
|
|
278
279
|
throw new TypeError('body is not set');
|
|
279
280
|
}
|
|
@@ -285,6 +286,7 @@ class FingerprintServerApiClient {
|
|
|
285
286
|
pathParams: [eventId],
|
|
286
287
|
method: 'patch',
|
|
287
288
|
body: JSON.stringify(body),
|
|
289
|
+
expect: 'void',
|
|
288
290
|
});
|
|
289
291
|
}
|
|
290
292
|
/**
|
|
@@ -321,6 +323,7 @@ class FingerprintServerApiClient {
|
|
|
321
323
|
path: '/visitors/{visitor_id}',
|
|
322
324
|
pathParams: [visitorId],
|
|
323
325
|
method: 'delete',
|
|
326
|
+
expect: 'void',
|
|
324
327
|
});
|
|
325
328
|
}
|
|
326
329
|
/**
|
|
@@ -386,6 +389,7 @@ class FingerprintServerApiClient {
|
|
|
386
389
|
path: '/events',
|
|
387
390
|
method: 'get',
|
|
388
391
|
queryParams: filter,
|
|
392
|
+
expect: 'json',
|
|
389
393
|
});
|
|
390
394
|
}
|
|
391
395
|
async callApi(options) {
|
|
@@ -393,53 +397,53 @@ class FingerprintServerApiClient {
|
|
|
393
397
|
...options,
|
|
394
398
|
region: this.region,
|
|
395
399
|
});
|
|
400
|
+
const requestInit = {
|
|
401
|
+
method: options.method.toUpperCase(),
|
|
402
|
+
headers: {
|
|
403
|
+
...this.defaultHeaders,
|
|
404
|
+
...options.headers,
|
|
405
|
+
},
|
|
406
|
+
};
|
|
407
|
+
if (options.body !== undefined) {
|
|
408
|
+
requestInit.body = options.body;
|
|
409
|
+
}
|
|
396
410
|
let response;
|
|
397
411
|
try {
|
|
398
|
-
response = await this.fetch(url,
|
|
399
|
-
method: options.method.toUpperCase(),
|
|
400
|
-
headers: {
|
|
401
|
-
...this.defaultHeaders,
|
|
402
|
-
...options.headers,
|
|
403
|
-
},
|
|
404
|
-
body: options.body,
|
|
405
|
-
});
|
|
412
|
+
response = await this.fetch(url, requestInit);
|
|
406
413
|
}
|
|
407
414
|
catch (e) {
|
|
408
|
-
throw new SdkError('Network or fetch error', undefined, e);
|
|
415
|
+
throw new SdkError('Network or fetch error', undefined, toError(e));
|
|
409
416
|
}
|
|
410
|
-
const contentType = response.headers.get('content-type') ?? '';
|
|
411
|
-
const isJson = contentType.includes('application/json');
|
|
412
417
|
if (response.ok) {
|
|
418
|
+
if (options.expect === 'void') {
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
413
421
|
const hasNoBody = response.status === 204 || response.headers.get('content-length') === '0';
|
|
414
422
|
if (hasNoBody) {
|
|
415
|
-
|
|
423
|
+
throw new SdkError('Expected JSON response but response body is empty', response);
|
|
416
424
|
}
|
|
417
|
-
|
|
425
|
+
const contentType = response.headers.get('content-type') ?? '';
|
|
426
|
+
if (!contentType.includes('application/json')) {
|
|
418
427
|
throw new SdkError('Expected JSON response but received non-JSON content type', response);
|
|
419
428
|
}
|
|
420
|
-
|
|
421
|
-
try {
|
|
422
|
-
data = await response.clone().json();
|
|
423
|
-
}
|
|
424
|
-
catch (e) {
|
|
425
|
-
throw new SdkError('Failed to parse JSON response', response, toError(e));
|
|
426
|
-
}
|
|
427
|
-
return data;
|
|
429
|
+
return this.parseJson(response);
|
|
428
430
|
}
|
|
429
|
-
|
|
431
|
+
const errorPayload = await this.parseJson(response.clone());
|
|
432
|
+
if (response.status === 429 && isErrorResponse(errorPayload)) {
|
|
433
|
+
throw new TooManyRequestsError(errorPayload, response);
|
|
434
|
+
}
|
|
435
|
+
if (isErrorResponse(errorPayload)) {
|
|
436
|
+
throw new RequestError(errorPayload.error.message, errorPayload, response.status, errorPayload.error.code, response);
|
|
437
|
+
}
|
|
438
|
+
throw RequestError.unknown(response);
|
|
439
|
+
}
|
|
440
|
+
async parseJson(response) {
|
|
430
441
|
try {
|
|
431
|
-
|
|
442
|
+
return (await response.json());
|
|
432
443
|
}
|
|
433
444
|
catch (e) {
|
|
434
445
|
throw new SdkError('Failed to parse JSON response', response, toError(e));
|
|
435
446
|
}
|
|
436
|
-
if (isErrorResponse(errPayload)) {
|
|
437
|
-
if (response.status === 429) {
|
|
438
|
-
throw new TooManyRequestsError(errPayload, response);
|
|
439
|
-
}
|
|
440
|
-
throw new RequestError(errPayload.error.message, errPayload, response.status, errPayload.error.code, response);
|
|
441
|
-
}
|
|
442
|
-
throw RequestError.unknown(response);
|
|
443
447
|
}
|
|
444
448
|
}
|
|
445
449
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Fingerprint Server Node.js SDK v7.0.0-test.
|
|
2
|
+
* Fingerprint Server Node.js SDK v7.0.0-test.1 - Copyright (c) FingerprintJS, Inc, 2026 (https://fingerprint.com)
|
|
3
3
|
* Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
|
|
4
4
|
*/
|
|
5
5
|
|
|
@@ -1542,41 +1542,12 @@ type Event = components['schemas']['Event'];
|
|
|
1542
1542
|
type GetEventOptions = paths['/events/{event_id}']['get']['parameters']['query'];
|
|
1543
1543
|
type EventUpdate = components['schemas']['EventUpdate'];
|
|
1544
1544
|
type EventRuleAction = components['schemas']['EventRuleAction'];
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
parameters: {
|
|
1552
|
-
query?: infer Q;
|
|
1553
|
-
};
|
|
1554
|
-
} ? undefined extends Q ? Q | undefined : Q : never;
|
|
1555
|
-
type ExtractRequestBody<Path> = Path extends {
|
|
1556
|
-
requestBody: {
|
|
1557
|
-
content: {
|
|
1558
|
-
'application/json': infer B;
|
|
1559
|
-
};
|
|
1560
|
-
};
|
|
1561
|
-
} ? B : never;
|
|
1562
|
-
type ExtractResponse<Path> = Path extends {
|
|
1563
|
-
responses: {
|
|
1564
|
-
200: {
|
|
1565
|
-
content: {
|
|
1566
|
-
'application/json': infer R;
|
|
1567
|
-
};
|
|
1568
|
-
};
|
|
1569
|
-
};
|
|
1570
|
-
} ? R : void;
|
|
1571
|
-
type ApiMethodArgs<Path extends keyof operations> = [
|
|
1572
|
-
...(ExtractRequestBody<operations[Path]> extends never ? [] : [body: ExtractRequestBody<operations[Path]>]),
|
|
1573
|
-
...ExtractPathParamStrings<operations[Path]>,
|
|
1574
|
-
...(ExtractQueryParams<operations[Path]> extends never ? [] : [params: ExtractQueryParams<operations[Path]>])
|
|
1575
|
-
];
|
|
1576
|
-
type ApiMethod<Path extends keyof operations> = (...args: ApiMethodArgs<Path>) => Promise<ExtractResponse<operations[Path]>>;
|
|
1577
|
-
type FingerprintApi = {
|
|
1578
|
-
[Operation in keyof operations]: ApiMethod<Operation>;
|
|
1579
|
-
};
|
|
1545
|
+
interface FingerprintApi {
|
|
1546
|
+
getEvent(eventId: string, options?: GetEventOptions): Promise<Event>;
|
|
1547
|
+
updateEvent(eventId: string, body: EventUpdate): Promise<void>;
|
|
1548
|
+
searchEvents(filter: SearchEventsFilter): Promise<SearchEventsResponse>;
|
|
1549
|
+
deleteVisitorData(visitorId: string): Promise<void>;
|
|
1550
|
+
}
|
|
1580
1551
|
|
|
1581
1552
|
declare class FingerprintServerApiClient implements FingerprintApi {
|
|
1582
1553
|
readonly region: Region;
|
|
@@ -1638,8 +1609,8 @@ declare class FingerprintServerApiClient implements FingerprintApi {
|
|
|
1638
1609
|
*
|
|
1639
1610
|
* **Warning** It's not possible to update events older than one month.
|
|
1640
1611
|
*
|
|
1641
|
-
* @param body - Data to update the event with.
|
|
1642
1612
|
* @param eventId The unique event [identifier](https://docs.fingerprint.com/reference/js-agent-v4-get-function#event_id).
|
|
1613
|
+
* @param body - Data to update the event with.
|
|
1643
1614
|
*
|
|
1644
1615
|
* @return {Promise<void>}
|
|
1645
1616
|
*
|
|
@@ -1651,7 +1622,7 @@ declare class FingerprintServerApiClient implements FingerprintApi {
|
|
|
1651
1622
|
* }
|
|
1652
1623
|
*
|
|
1653
1624
|
* client
|
|
1654
|
-
* .updateEvent(
|
|
1625
|
+
* .updateEvent('<eventId>', body)
|
|
1655
1626
|
* .then(() => {
|
|
1656
1627
|
* // Event was successfully updated
|
|
1657
1628
|
* })
|
|
@@ -1668,7 +1639,7 @@ declare class FingerprintServerApiClient implements FingerprintApi {
|
|
|
1668
1639
|
* })
|
|
1669
1640
|
* ```
|
|
1670
1641
|
*/
|
|
1671
|
-
updateEvent(
|
|
1642
|
+
updateEvent(eventId: string, body: EventUpdate): Promise<void>;
|
|
1672
1643
|
/**
|
|
1673
1644
|
* Delete data by visitor ID
|
|
1674
1645
|
* Request deleting all data associated with the specified visitor ID. This API is useful for compliance with privacy regulations. All delete requests are queued:
|
|
@@ -1756,6 +1727,7 @@ declare class FingerprintServerApiClient implements FingerprintApi {
|
|
|
1756
1727
|
* */
|
|
1757
1728
|
searchEvents(filter: SearchEventsFilter): Promise<SearchEventsResponse>;
|
|
1758
1729
|
private callApi;
|
|
1730
|
+
private parseJson;
|
|
1759
1731
|
}
|
|
1760
1732
|
|
|
1761
1733
|
declare enum DecryptionAlgorithm {
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Fingerprint Server Node.js SDK v7.0.0-test.
|
|
2
|
+
* Fingerprint Server Node.js SDK v7.0.0-test.1 - Copyright (c) FingerprintJS, Inc, 2026 (https://fingerprint.com)
|
|
3
3
|
* Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
|
|
4
4
|
*/
|
|
5
5
|
|
|
@@ -15,7 +15,7 @@ var Region;
|
|
|
15
15
|
Region["Global"] = "Global";
|
|
16
16
|
})(Region || (Region = {}));
|
|
17
17
|
|
|
18
|
-
var version = "7.0.0-test.
|
|
18
|
+
var version = "7.0.0-test.1";
|
|
19
19
|
|
|
20
20
|
const apiVersion = 'v4';
|
|
21
21
|
const euRegionUrl = 'https://eu.api.fpjs.io/';
|
|
@@ -63,13 +63,13 @@ function getServerApiUrl(region) {
|
|
|
63
63
|
*
|
|
64
64
|
* @internal
|
|
65
65
|
*
|
|
66
|
-
* @param {GetRequestPathOptions
|
|
67
|
-
* @param {
|
|
66
|
+
* @param {GetRequestPathOptions} options
|
|
67
|
+
* @param {keyof paths} options.path - The path of the API endpoint
|
|
68
68
|
* @param {string[]} [options.pathParams] - Path parameters to be replaced in the path
|
|
69
|
-
* @param {
|
|
69
|
+
* @param {GetRequestPathOptions["queryParams"]} [options.queryParams] - Query string
|
|
70
70
|
* parameters to be appended to the URL
|
|
71
71
|
* @param {Region} options.region - The region of the API endpoint
|
|
72
|
-
* @param {
|
|
72
|
+
* @param {HttpMethod} options.method - The method of the API endpoint
|
|
73
73
|
*
|
|
74
74
|
* @returns {string} The formatted URL with parameters replaced and query string
|
|
75
75
|
* parameters appended
|
|
@@ -231,6 +231,7 @@ class FingerprintServerApiClient {
|
|
|
231
231
|
pathParams: [eventId],
|
|
232
232
|
method: 'get',
|
|
233
233
|
queryParams: options,
|
|
234
|
+
expect: 'json',
|
|
234
235
|
});
|
|
235
236
|
}
|
|
236
237
|
/**
|
|
@@ -241,8 +242,8 @@ class FingerprintServerApiClient {
|
|
|
241
242
|
*
|
|
242
243
|
* **Warning** It's not possible to update events older than one month.
|
|
243
244
|
*
|
|
244
|
-
* @param body - Data to update the event with.
|
|
245
245
|
* @param eventId The unique event [identifier](https://docs.fingerprint.com/reference/js-agent-v4-get-function#event_id).
|
|
246
|
+
* @param body - Data to update the event with.
|
|
246
247
|
*
|
|
247
248
|
* @return {Promise<void>}
|
|
248
249
|
*
|
|
@@ -254,7 +255,7 @@ class FingerprintServerApiClient {
|
|
|
254
255
|
* }
|
|
255
256
|
*
|
|
256
257
|
* client
|
|
257
|
-
* .updateEvent(
|
|
258
|
+
* .updateEvent('<eventId>', body)
|
|
258
259
|
* .then(() => {
|
|
259
260
|
* // Event was successfully updated
|
|
260
261
|
* })
|
|
@@ -271,7 +272,7 @@ class FingerprintServerApiClient {
|
|
|
271
272
|
* })
|
|
272
273
|
* ```
|
|
273
274
|
*/
|
|
274
|
-
async updateEvent(
|
|
275
|
+
async updateEvent(eventId, body) {
|
|
275
276
|
if (!body) {
|
|
276
277
|
throw new TypeError('body is not set');
|
|
277
278
|
}
|
|
@@ -283,6 +284,7 @@ class FingerprintServerApiClient {
|
|
|
283
284
|
pathParams: [eventId],
|
|
284
285
|
method: 'patch',
|
|
285
286
|
body: JSON.stringify(body),
|
|
287
|
+
expect: 'void',
|
|
286
288
|
});
|
|
287
289
|
}
|
|
288
290
|
/**
|
|
@@ -319,6 +321,7 @@ class FingerprintServerApiClient {
|
|
|
319
321
|
path: '/visitors/{visitor_id}',
|
|
320
322
|
pathParams: [visitorId],
|
|
321
323
|
method: 'delete',
|
|
324
|
+
expect: 'void',
|
|
322
325
|
});
|
|
323
326
|
}
|
|
324
327
|
/**
|
|
@@ -384,6 +387,7 @@ class FingerprintServerApiClient {
|
|
|
384
387
|
path: '/events',
|
|
385
388
|
method: 'get',
|
|
386
389
|
queryParams: filter,
|
|
390
|
+
expect: 'json',
|
|
387
391
|
});
|
|
388
392
|
}
|
|
389
393
|
async callApi(options) {
|
|
@@ -391,53 +395,53 @@ class FingerprintServerApiClient {
|
|
|
391
395
|
...options,
|
|
392
396
|
region: this.region,
|
|
393
397
|
});
|
|
398
|
+
const requestInit = {
|
|
399
|
+
method: options.method.toUpperCase(),
|
|
400
|
+
headers: {
|
|
401
|
+
...this.defaultHeaders,
|
|
402
|
+
...options.headers,
|
|
403
|
+
},
|
|
404
|
+
};
|
|
405
|
+
if (options.body !== undefined) {
|
|
406
|
+
requestInit.body = options.body;
|
|
407
|
+
}
|
|
394
408
|
let response;
|
|
395
409
|
try {
|
|
396
|
-
response = await this.fetch(url,
|
|
397
|
-
method: options.method.toUpperCase(),
|
|
398
|
-
headers: {
|
|
399
|
-
...this.defaultHeaders,
|
|
400
|
-
...options.headers,
|
|
401
|
-
},
|
|
402
|
-
body: options.body,
|
|
403
|
-
});
|
|
410
|
+
response = await this.fetch(url, requestInit);
|
|
404
411
|
}
|
|
405
412
|
catch (e) {
|
|
406
|
-
throw new SdkError('Network or fetch error', undefined, e);
|
|
413
|
+
throw new SdkError('Network or fetch error', undefined, toError(e));
|
|
407
414
|
}
|
|
408
|
-
const contentType = response.headers.get('content-type') ?? '';
|
|
409
|
-
const isJson = contentType.includes('application/json');
|
|
410
415
|
if (response.ok) {
|
|
416
|
+
if (options.expect === 'void') {
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
411
419
|
const hasNoBody = response.status === 204 || response.headers.get('content-length') === '0';
|
|
412
420
|
if (hasNoBody) {
|
|
413
|
-
|
|
421
|
+
throw new SdkError('Expected JSON response but response body is empty', response);
|
|
414
422
|
}
|
|
415
|
-
|
|
423
|
+
const contentType = response.headers.get('content-type') ?? '';
|
|
424
|
+
if (!contentType.includes('application/json')) {
|
|
416
425
|
throw new SdkError('Expected JSON response but received non-JSON content type', response);
|
|
417
426
|
}
|
|
418
|
-
|
|
419
|
-
try {
|
|
420
|
-
data = await response.clone().json();
|
|
421
|
-
}
|
|
422
|
-
catch (e) {
|
|
423
|
-
throw new SdkError('Failed to parse JSON response', response, toError(e));
|
|
424
|
-
}
|
|
425
|
-
return data;
|
|
427
|
+
return this.parseJson(response);
|
|
426
428
|
}
|
|
427
|
-
|
|
429
|
+
const errorPayload = await this.parseJson(response.clone());
|
|
430
|
+
if (response.status === 429 && isErrorResponse(errorPayload)) {
|
|
431
|
+
throw new TooManyRequestsError(errorPayload, response);
|
|
432
|
+
}
|
|
433
|
+
if (isErrorResponse(errorPayload)) {
|
|
434
|
+
throw new RequestError(errorPayload.error.message, errorPayload, response.status, errorPayload.error.code, response);
|
|
435
|
+
}
|
|
436
|
+
throw RequestError.unknown(response);
|
|
437
|
+
}
|
|
438
|
+
async parseJson(response) {
|
|
428
439
|
try {
|
|
429
|
-
|
|
440
|
+
return (await response.json());
|
|
430
441
|
}
|
|
431
442
|
catch (e) {
|
|
432
443
|
throw new SdkError('Failed to parse JSON response', response, toError(e));
|
|
433
444
|
}
|
|
434
|
-
if (isErrorResponse(errPayload)) {
|
|
435
|
-
if (response.status === 429) {
|
|
436
|
-
throw new TooManyRequestsError(errPayload, response);
|
|
437
|
-
}
|
|
438
|
-
throw new RequestError(errPayload.error.message, errPayload, response.status, errPayload.error.code, response);
|
|
439
|
-
}
|
|
440
|
-
throw RequestError.unknown(response);
|
|
441
445
|
}
|
|
442
446
|
}
|
|
443
447
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fingerprint/node-sdk",
|
|
3
|
-
"version": "7.0.0-test.
|
|
3
|
+
"version": "7.0.0-test.1",
|
|
4
4
|
"description": "Node.js wrapper for Fingerprint Server API",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
"type": "git",
|
|
18
18
|
"url": "https://github.com/fingerprintjs/node-sdk"
|
|
19
19
|
},
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public",
|
|
22
|
+
"provenance": true
|
|
23
|
+
},
|
|
20
24
|
"engines": {
|
|
21
25
|
"node": ">=18.17.0"
|
|
22
26
|
},
|
package/src/serverApiClient.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getRequestPath, GetRequestPathOptions } from './urlUtils'
|
|
2
2
|
import {
|
|
3
3
|
Event,
|
|
4
4
|
EventUpdate,
|
|
@@ -9,11 +9,16 @@ import {
|
|
|
9
9
|
SearchEventsFilter,
|
|
10
10
|
SearchEventsResponse,
|
|
11
11
|
} from './types'
|
|
12
|
-
import { paths } from './generatedApiTypes'
|
|
13
12
|
import { RequestError, SdkError, TooManyRequestsError } from './errors/apiErrors'
|
|
14
13
|
import { isErrorResponse } from './errors/handleErrorResponse'
|
|
15
14
|
import { toError } from './errors/toError'
|
|
16
15
|
|
|
16
|
+
type CallApiOptions = GetRequestPathOptions & {
|
|
17
|
+
headers?: Record<string, string>
|
|
18
|
+
body?: BodyInit
|
|
19
|
+
expect: 'json' | 'void'
|
|
20
|
+
}
|
|
21
|
+
|
|
17
22
|
export class FingerprintServerApiClient implements FingerprintApi {
|
|
18
23
|
public readonly region: Region
|
|
19
24
|
|
|
@@ -97,6 +102,7 @@ export class FingerprintServerApiClient implements FingerprintApi {
|
|
|
97
102
|
pathParams: [eventId],
|
|
98
103
|
method: 'get',
|
|
99
104
|
queryParams: options,
|
|
105
|
+
expect: 'json',
|
|
100
106
|
})
|
|
101
107
|
}
|
|
102
108
|
|
|
@@ -108,8 +114,8 @@ export class FingerprintServerApiClient implements FingerprintApi {
|
|
|
108
114
|
*
|
|
109
115
|
* **Warning** It's not possible to update events older than one month.
|
|
110
116
|
*
|
|
111
|
-
* @param body - Data to update the event with.
|
|
112
117
|
* @param eventId The unique event [identifier](https://docs.fingerprint.com/reference/js-agent-v4-get-function#event_id).
|
|
118
|
+
* @param body - Data to update the event with.
|
|
113
119
|
*
|
|
114
120
|
* @return {Promise<void>}
|
|
115
121
|
*
|
|
@@ -121,7 +127,7 @@ export class FingerprintServerApiClient implements FingerprintApi {
|
|
|
121
127
|
* }
|
|
122
128
|
*
|
|
123
129
|
* client
|
|
124
|
-
* .updateEvent(
|
|
130
|
+
* .updateEvent('<eventId>', body)
|
|
125
131
|
* .then(() => {
|
|
126
132
|
* // Event was successfully updated
|
|
127
133
|
* })
|
|
@@ -138,7 +144,7 @@ export class FingerprintServerApiClient implements FingerprintApi {
|
|
|
138
144
|
* })
|
|
139
145
|
* ```
|
|
140
146
|
*/
|
|
141
|
-
public async updateEvent(
|
|
147
|
+
public async updateEvent(eventId: string, body: EventUpdate): Promise<void> {
|
|
142
148
|
if (!body) {
|
|
143
149
|
throw new TypeError('body is not set')
|
|
144
150
|
}
|
|
@@ -152,6 +158,7 @@ export class FingerprintServerApiClient implements FingerprintApi {
|
|
|
152
158
|
pathParams: [eventId],
|
|
153
159
|
method: 'patch',
|
|
154
160
|
body: JSON.stringify(body),
|
|
161
|
+
expect: 'void',
|
|
155
162
|
})
|
|
156
163
|
}
|
|
157
164
|
|
|
@@ -190,6 +197,7 @@ export class FingerprintServerApiClient implements FingerprintApi {
|
|
|
190
197
|
path: '/visitors/{visitor_id}',
|
|
191
198
|
pathParams: [visitorId],
|
|
192
199
|
method: 'delete',
|
|
200
|
+
expect: 'void',
|
|
193
201
|
})
|
|
194
202
|
}
|
|
195
203
|
|
|
@@ -256,66 +264,78 @@ export class FingerprintServerApiClient implements FingerprintApi {
|
|
|
256
264
|
path: '/events',
|
|
257
265
|
method: 'get',
|
|
258
266
|
queryParams: filter,
|
|
267
|
+
expect: 'json',
|
|
259
268
|
})
|
|
260
269
|
}
|
|
261
270
|
|
|
262
|
-
private async callApi<
|
|
263
|
-
|
|
264
|
-
): Promise<
|
|
271
|
+
private async callApi<T>(options: CallApiOptions & { expect: 'json' }): Promise<T>
|
|
272
|
+
private async callApi(options: CallApiOptions & { expect: 'void' }): Promise<void>
|
|
273
|
+
private async callApi<T>(options: CallApiOptions): Promise<T | void> {
|
|
265
274
|
const url = getRequestPath({
|
|
266
275
|
...options,
|
|
267
276
|
region: this.region,
|
|
268
277
|
})
|
|
269
278
|
|
|
279
|
+
const requestInit: RequestInit = {
|
|
280
|
+
method: options.method.toUpperCase(),
|
|
281
|
+
headers: {
|
|
282
|
+
...this.defaultHeaders,
|
|
283
|
+
...options.headers,
|
|
284
|
+
},
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (options.body !== undefined) {
|
|
288
|
+
requestInit.body = options.body
|
|
289
|
+
}
|
|
290
|
+
|
|
270
291
|
let response: Response
|
|
271
292
|
try {
|
|
272
|
-
response = await this.fetch(url,
|
|
273
|
-
method: options.method.toUpperCase(),
|
|
274
|
-
headers: {
|
|
275
|
-
...this.defaultHeaders,
|
|
276
|
-
...options.headers,
|
|
277
|
-
},
|
|
278
|
-
body: options.body,
|
|
279
|
-
})
|
|
293
|
+
response = await this.fetch(url, requestInit)
|
|
280
294
|
} catch (e) {
|
|
281
|
-
throw new SdkError('Network or fetch error', undefined, e
|
|
295
|
+
throw new SdkError('Network or fetch error', undefined, toError(e))
|
|
282
296
|
}
|
|
283
297
|
|
|
284
|
-
const contentType = response.headers.get('content-type') ?? ''
|
|
285
|
-
const isJson = contentType.includes('application/json')
|
|
286
|
-
|
|
287
298
|
if (response.ok) {
|
|
288
|
-
|
|
299
|
+
if (options.expect === 'void') {
|
|
300
|
+
return
|
|
301
|
+
}
|
|
289
302
|
|
|
303
|
+
const hasNoBody = response.status === 204 || response.headers.get('content-length') === '0'
|
|
290
304
|
if (hasNoBody) {
|
|
291
|
-
|
|
305
|
+
throw new SdkError('Expected JSON response but response body is empty', response)
|
|
292
306
|
}
|
|
293
307
|
|
|
294
|
-
|
|
308
|
+
const contentType = response.headers.get('content-type') ?? ''
|
|
309
|
+
if (!contentType.includes('application/json')) {
|
|
295
310
|
throw new SdkError('Expected JSON response but received non-JSON content type', response)
|
|
296
311
|
}
|
|
297
312
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
313
|
+
return this.parseJson(response)
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const errorPayload = await this.parseJson<unknown>(response.clone())
|
|
317
|
+
|
|
318
|
+
if (response.status === 429 && isErrorResponse(errorPayload)) {
|
|
319
|
+
throw new TooManyRequestsError(errorPayload, response)
|
|
320
|
+
}
|
|
321
|
+
if (isErrorResponse(errorPayload)) {
|
|
322
|
+
throw new RequestError(
|
|
323
|
+
errorPayload.error.message,
|
|
324
|
+
errorPayload,
|
|
325
|
+
response.status,
|
|
326
|
+
errorPayload.error.code,
|
|
327
|
+
response
|
|
328
|
+
)
|
|
305
329
|
}
|
|
306
330
|
|
|
307
|
-
|
|
331
|
+
throw RequestError.unknown(response)
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
private async parseJson<T>(response: Response): Promise<T> {
|
|
308
335
|
try {
|
|
309
|
-
|
|
336
|
+
return (await response.json()) as T
|
|
310
337
|
} catch (e) {
|
|
311
338
|
throw new SdkError('Failed to parse JSON response', response, toError(e))
|
|
312
339
|
}
|
|
313
|
-
if (isErrorResponse(errPayload)) {
|
|
314
|
-
if (response.status === 429) {
|
|
315
|
-
throw new TooManyRequestsError(errPayload, response)
|
|
316
|
-
}
|
|
317
|
-
throw new RequestError(errPayload.error.message, errPayload, response.status, errPayload.error.code, response)
|
|
318
|
-
}
|
|
319
|
-
throw RequestError.unknown(response)
|
|
320
340
|
}
|
|
321
341
|
}
|
package/src/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { components,
|
|
1
|
+
import { components, paths } from './generatedApiTypes'
|
|
2
2
|
|
|
3
3
|
export enum Region {
|
|
4
4
|
EU = 'EU',
|
|
@@ -49,42 +49,9 @@ export type EventUpdate = components['schemas']['EventUpdate']
|
|
|
49
49
|
|
|
50
50
|
export type EventRuleAction = components['schemas']['EventRuleAction']
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
: []
|
|
58
|
-
|
|
59
|
-
// Utility type to extract query parameters from an operation and differentiate required/optional
|
|
60
|
-
export type ExtractQueryParams<Path> = Path extends { parameters: { query?: infer Q } }
|
|
61
|
-
? undefined extends Q // Check if Q can be undefined (meaning it's optional)
|
|
62
|
-
? Q | undefined // If so, it's optional
|
|
63
|
-
: Q // Otherwise, it's required
|
|
64
|
-
: never // If no query parameters, return never
|
|
65
|
-
|
|
66
|
-
// Utility type to extract request body from an operation (for POST, PUT, etc.)
|
|
67
|
-
type ExtractRequestBody<Path> = Path extends { requestBody: { content: { 'application/json': infer B } } } ? B : never
|
|
68
|
-
|
|
69
|
-
// Utility type to extract the response type for 200 status code
|
|
70
|
-
type ExtractResponse<Path> = Path extends { responses: { 200: { content: { 'application/json': infer R } } } }
|
|
71
|
-
? R
|
|
72
|
-
: void
|
|
73
|
-
|
|
74
|
-
// Extracts args to given API method
|
|
75
|
-
type ApiMethodArgs<Path extends keyof operations> = [
|
|
76
|
-
// If method has body, extract it as first parameter
|
|
77
|
-
...(ExtractRequestBody<operations[Path]> extends never ? [] : [body: ExtractRequestBody<operations[Path]>]),
|
|
78
|
-
// Next are path params, e.g. for path "/events/{event_id}" it will be one string parameter,
|
|
79
|
-
...ExtractPathParamStrings<operations[Path]>,
|
|
80
|
-
// Last parameter will be the query params, if any
|
|
81
|
-
...(ExtractQueryParams<operations[Path]> extends never ? [] : [params: ExtractQueryParams<operations[Path]>]),
|
|
82
|
-
]
|
|
83
|
-
|
|
84
|
-
type ApiMethod<Path extends keyof operations> = (
|
|
85
|
-
...args: ApiMethodArgs<Path>
|
|
86
|
-
) => Promise<ExtractResponse<operations[Path]>>
|
|
87
|
-
|
|
88
|
-
export type FingerprintApi = {
|
|
89
|
-
[Operation in keyof operations]: ApiMethod<Operation>
|
|
52
|
+
export interface FingerprintApi {
|
|
53
|
+
getEvent(eventId: string, options?: GetEventOptions): Promise<Event>
|
|
54
|
+
updateEvent(eventId: string, body: EventUpdate): Promise<void>
|
|
55
|
+
searchEvents(filter: SearchEventsFilter): Promise<SearchEventsResponse>
|
|
56
|
+
deleteVisitorData(visitorId: string): Promise<void>
|
|
90
57
|
}
|
package/src/urlUtils.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Region } from './types'
|
|
2
2
|
import { version } from '../package.json'
|
|
3
3
|
import { paths } from './generatedApiTypes'
|
|
4
4
|
|
|
@@ -10,8 +10,7 @@ const globalRegionUrl = 'https://api.fpjs.io/'
|
|
|
10
10
|
|
|
11
11
|
type QueryStringScalar = string | number | boolean | null | undefined
|
|
12
12
|
|
|
13
|
-
type QueryStringParameters = Record<string, QueryStringScalar |
|
|
14
|
-
api_key?: string
|
|
13
|
+
type QueryStringParameters = Record<string, QueryStringScalar | QueryStringScalar[]> & {
|
|
15
14
|
ii: string
|
|
16
15
|
}
|
|
17
16
|
|
|
@@ -57,67 +56,15 @@ function getServerApiUrl(region: Region): string {
|
|
|
57
56
|
}
|
|
58
57
|
}
|
|
59
58
|
|
|
60
|
-
|
|
61
|
-
* Extracts parameter placeholders into a literal union type.
|
|
62
|
-
* For example `extractPathParams<'/users/{userId}/posts/{postId}'>` resolves to `"userId" | "postId"
|
|
63
|
-
*/
|
|
64
|
-
type ExtractPathParams<T extends string> = T extends `${string}{${infer Param}}${infer Rest}`
|
|
65
|
-
? Param | ExtractPathParams<Rest>
|
|
66
|
-
: never
|
|
67
|
-
|
|
68
|
-
type PathParams<Path extends keyof paths> =
|
|
69
|
-
ExtractPathParams<Path> extends never
|
|
70
|
-
? { pathParams?: never }
|
|
71
|
-
: {
|
|
72
|
-
pathParams: ExtractPathParams<Path> extends never ? never : string[]
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
type QueryParams<Path extends keyof paths, Method extends keyof paths[Path]> =
|
|
76
|
-
ExtractQueryParams<paths[Path][Method]> extends never
|
|
77
|
-
? { queryParams?: any } // No query params
|
|
78
|
-
: {
|
|
79
|
-
queryParams?: ExtractQueryParams<paths[Path][Method]> // Optional query params
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
type IsNever<Type> = [Exclude<Type, undefined>] extends [never] ? true : false
|
|
83
|
-
export type NonNeverKeys<Type> = {
|
|
84
|
-
[Key in keyof Type]-?: IsNever<Type[Key]> extends true ? never : Key
|
|
85
|
-
}[keyof Type]
|
|
86
|
-
export type AllowedMethod<Path extends keyof paths> = Extract<Exclude<NonNeverKeys<paths[Path]>, 'parameters'>, string>
|
|
87
|
-
|
|
88
|
-
type JsonContentOf<Response> = Response extends { content: { 'application/json': infer T } } ? T : never
|
|
89
|
-
|
|
90
|
-
type UnionJsonFromResponses<Response> = {
|
|
91
|
-
[StatusCode in keyof Response]: JsonContentOf<Response[StatusCode]>
|
|
92
|
-
}[keyof Response]
|
|
59
|
+
export type HttpMethod = 'get' | 'put' | 'post' | 'delete' | 'options' | 'head' | 'patch' | 'trace'
|
|
93
60
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
type OperationOf<Path extends keyof paths, Method extends AllowedMethod<Path>> = paths[Path][Method]
|
|
101
|
-
|
|
102
|
-
type ResponsesOf<Path extends keyof paths, Method extends AllowedMethod<Path>> =
|
|
103
|
-
OperationOf<Path, Method> extends { responses: infer Response } ? Response : never
|
|
104
|
-
|
|
105
|
-
type SuccessJson<Path extends keyof paths, Method extends AllowedMethod<Path>> = UnionJsonFromResponses<
|
|
106
|
-
SuccessResponses<ResponsesOf<Path, Method>>
|
|
107
|
-
>
|
|
108
|
-
|
|
109
|
-
export type SuccessJsonOrVoid<Path extends keyof paths, Method extends AllowedMethod<Path>> = [
|
|
110
|
-
SuccessJson<Path, Method>,
|
|
111
|
-
] extends [never]
|
|
112
|
-
? void
|
|
113
|
-
: SuccessJson<Path, Method>
|
|
114
|
-
|
|
115
|
-
export type GetRequestPathOptions<Path extends keyof paths, Method extends AllowedMethod<Path>> = {
|
|
116
|
-
path: Path
|
|
117
|
-
method: Method
|
|
61
|
+
export interface GetRequestPathOptions {
|
|
62
|
+
path: keyof paths
|
|
63
|
+
method: HttpMethod
|
|
64
|
+
pathParams?: string[]
|
|
65
|
+
queryParams?: Record<string, QueryStringScalar | QueryStringScalar[]>
|
|
118
66
|
region?: Region
|
|
119
|
-
}
|
|
120
|
-
QueryParams<Path, Method>
|
|
67
|
+
}
|
|
121
68
|
|
|
122
69
|
/**
|
|
123
70
|
* Formats a URL for the FingerprintJS server API by replacing placeholders and
|
|
@@ -125,18 +72,18 @@ export type GetRequestPathOptions<Path extends keyof paths, Method extends Allow
|
|
|
125
72
|
*
|
|
126
73
|
* @internal
|
|
127
74
|
*
|
|
128
|
-
* @param {GetRequestPathOptions
|
|
129
|
-
* @param {
|
|
75
|
+
* @param {GetRequestPathOptions} options
|
|
76
|
+
* @param {keyof paths} options.path - The path of the API endpoint
|
|
130
77
|
* @param {string[]} [options.pathParams] - Path parameters to be replaced in the path
|
|
131
|
-
* @param {
|
|
78
|
+
* @param {GetRequestPathOptions["queryParams"]} [options.queryParams] - Query string
|
|
132
79
|
* parameters to be appended to the URL
|
|
133
80
|
* @param {Region} options.region - The region of the API endpoint
|
|
134
|
-
* @param {
|
|
81
|
+
* @param {HttpMethod} options.method - The method of the API endpoint
|
|
135
82
|
*
|
|
136
83
|
* @returns {string} The formatted URL with parameters replaced and query string
|
|
137
84
|
* parameters appended
|
|
138
85
|
*/
|
|
139
|
-
export function getRequestPath
|
|
86
|
+
export function getRequestPath({
|
|
140
87
|
path,
|
|
141
88
|
pathParams,
|
|
142
89
|
queryParams,
|
|
@@ -144,7 +91,7 @@ export function getRequestPath<Path extends keyof paths, Method extends AllowedM
|
|
|
144
91
|
// method mention here so that it can be referenced in JSDoc
|
|
145
92
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
146
93
|
method: _,
|
|
147
|
-
}: GetRequestPathOptions
|
|
94
|
+
}: GetRequestPathOptions): string {
|
|
148
95
|
// Step 1: Extract the path parameters (placeholders) from the path
|
|
149
96
|
const placeholders = Array.from(path.matchAll(/{(.*?)}/g)).map((match) => match[1])
|
|
150
97
|
|