Conversation
- Switch base URLs to APIv4 (`https://{region}.api.fpjs.io/v4`) and add
`apiVersion` handling in URL builder.
- Use `Authorization: Bearer <secret-api-key>` only. Remove custom
header and query api authorization.
- Event API renamed and updated. Use `event_id` instead of `request_id`.
Also use `PATCH` for event update instead of `PUT` method.
- Add new examples, mocked responses, and update `sync.sh` script.
- README reworked for v4
- Package renamed to `@fingerprint/fingerprint-server-sdk`. Updated
description and subpackages (example).
- Regenerated types and OpenAPI schema.
- Updated unit and mock tests for v4 URLs.
BREAKING CHANGES:
- Only **Bearer auth** is supported; query and custom-header API-key
modes are removed. `AuthenticationMode` option is deleted.
- Event endpoint and signatures changes:
- Use `client.getEvent(eventId)` instead of `requestId`
Related-Task: INTER-1488
Remove `Accept: application/json` testing header for `updateEvent` function. Related-Task: INTER-1488
Fix updateEventTests test expected method to `PATCH`. Related-Task: INTER-1488
Removed unnecessary commented line. Related-Task: INTER-1488
Expands `searchEvents` JSDoc with new filters. Also its align parameter names.
Removes `example/getVisitorHistory.mjs` file because it's not a different endpoint anymore. Related-Task: INTER-1488
Add `fingerprint-server-sdk-smoke-tests` to changeset ignore list. Related-Task: INTER-1488
Explicitly mention about package name change in changeset file. Related-Task: INTER-1488
Use correct `patch` method instead of `put` for updating an event. Related-Task: INTER-1488
Replace strict `response.status === 200` checks with `response.ok` in fetch handlers. Related-Task: INTER-1488
Added a new `callApi()` function to handle request building and `fetch` usage in one place. Replaced all direct `fetch` calls with `callApi`. Introduced `defaultHeaders` options to the client, it's include `Authorization` header and allow extra headers and override of `Authorization` header. Made `region` optional in `GetRequestPathOptions` and it's default to `Region.Global` in `getRequestPath` function. Related-Task: INTER-1488
Remove `isEmptyValue` helper function and use direct `== null` checks to skip `undefined` or `null` values. Related-Task: INTER-1488
Use correct `EVENT_ID` placeholder for the example `.env.example` dotenv file. Related-Task: INTER-1488
Add `IsNever` and `NonNeverKeys` utility types to filter out `never` type keys. Introduce and export `AllowedMethod` that excludes specific `parameters` and any `never` type methods. Use this `AllowedMethod` type for `GetRequestPathOptions` type and `getRequestPath` functions. Update related signatures. Related-Task: INTER-1488
Use `options.method.toUpperCase()` when calling `fetch` to ensure standard HTTP method casing and avoid test fails. Change `AllowedMethod` to make a string literal union. Related-Task: INTER-1488
Extend `callApi` to accept an optional `body?: BodyInit` and forward it to `fetch`. Fix `updateEvent` to send `body`. Related-Task: INTER-1488
Removed unnecessary visitor detail tests. Related-Task: INTER-1488
Fix missing quote for `linked_id` in `searchEvents.mjs` example file. Related-Task: INTER-1488
Removed redundant `await` keyword in `callApi` function. Related-Task: INTER-1488
Centralize response parsing and error handling in `callApi` function. Throw consistent `SdkError`, `RequestError`, or `TooManyRequestsError` depends on the case. Added `SuccessJsonOrVoid<Path, Method>` to automatically resolve the potential/correct return type for success responses. Simplify all public methods. Related-Task: INTER-1488
Removed `handleErrorResponse` and moved all error logic into `callApi`. Exported `isErrorResponse` to detect valid error payloads. Added `createResponse` helper for creating mock Response object with headers. Related-Task: INTER-1488
Fixes webhook example and description in the `readme.md` file. Related-Task: INTER-1488
Use `Event` type instead of duplicated `EventsGetResponse` type. Update sealedResults snapshot and example base64 sealed result value. Fix reference links. Related-Task: INTER-1488
Removes unnecessary `ErrorJson` type from the project. Related-Task: INTER-1488
Fix inconsistent error message casing in the `deleteVisitorData` function. Related-Task: INTER-1488
TheUnderScorer
left a comment
There was a problem hiding this comment.
Nice work! Left some comments, thanks!
|
|
||
| if (response.ok) { | ||
| if (!isJson || response.status === 204) { | ||
| return undefined as SuccessJsonOrVoid<Path, Method> |
There was a problem hiding this comment.
I’m afraid this type of assertion could potentially break the contract in some edge cases.
I suggest creating a separate method for operations that don't return anything, such as callApiVoid.
|
|
||
| handleErrorResponse(jsonResponse, response) | ||
| if (response.status === 429) { | ||
| throw new TooManyRequestsError(errPayload, response) |
There was a problem hiding this comment.
We can get rid of the TooManyRequestsError, in V4 the Retry-After header is no longer being sent, so it doesn't make sense to have a separate error instance for this status code.
There was a problem hiding this comment.
According to the OpenAPI schema, it appears we return a 429 Too Many Requests response. We might have forgotten to remove these from the schema if the server definitely doesn't return a 429
There was a problem hiding this comment.
Can it be that it returns 429 Response, just without the Retry-After header? Best to test practically to confirm
There was a problem hiding this comment.
In local testing, I saw that it does throw a 429 error, but without retry-after header. I'm thinking of keeping the TooManyRequestsError but removing the retryAfter handling inside it. Is there any objection to not removing the TooManyRequestsError?
There was a problem hiding this comment.
Removed retryAfter handling with commit #4677ab6
Move `region` parameter passing to inside of the `callApi`. Related-Task: INTER-1488
Extract `toError` function of `serverApiClient` to `errors` module. Related-Task: INTER-1488
Add a second `@example` block showing how to handle the `rule_action` response when calling `getEvent` with a `rulesetId` parameter. Related-Task: INTER-1488
Co-authored-by: Przemysław Żydek <przemyslawzydek@gmail.com>
JuroUhlar
left a comment
There was a problem hiding this comment.
Thanks for working on this, left some suggestions!
|
|
||
| handleErrorResponse(jsonResponse, response) | ||
| if (response.status === 429) { | ||
| throw new TooManyRequestsError(errPayload, response) |
There was a problem hiding this comment.
Can it be that it returns 429 Response, just without the Retry-After header? Best to test practically to confirm
| throw TypeError('VisitorId is not set') | ||
| } | ||
|
|
||
| private async callApi<Path extends keyof paths, Method extends AllowedMethod<Path>>( |
There was a problem hiding this comment.
I want the challenge the need for a generic callApi method. It seem to require a lot of generic type gymnastics to make it work and it might not be worth it. You only have 4 API endpoints. It might be easier typing out their interfaces individually and extracting common code into helper methods.
There was a problem hiding this comment.
My main goal with this approach was to minimize errors during usage (in callApi calls within new function/operation implementations). For example, with the current type definition, when calling callApi, you can only specify acceptable method, pathParams, and queryParams specific to the given path. With usages like below, TS errors are immediately visible.
return this.callApi({
path: '/events/{event_id}',
pathParams: [eventId],
method: 'put', // TS2322: Type "put" is not assignable to type "get" | "patch"
queryParams: rulesetId ? { ruleset_id: rulesetId } : undefined,
})return this.callApi({
path: '/non-exists', // TS2322: Type "/non-exists" is not assignable to type keyof paths
pathParams: [eventId],
method: 'get',
queryParams: rulesetId ? { ruleset_id: rulesetId } : undefined,
})return this.callApi({
path: '/events/{event_id}',
pathParams: [eventId],
method: 'get',
queryParams: { nonQueryParam: 'ok' }, // TS2353: Object literal may only specify known properties, and nonQueryParam does not exist in type { ruleset_id?: string | undefined; }
})return this.callApi({
path: '/events/{event_id}',
pathParams: [eventId],
method: 'get',
queryParams: rulesetId ? { ruleset_id: 1 } : undefined, // TS2322: Type { ruleset_id: number; } | undefined is not assignable to type
})But we could achieve a similar benefit manually, as you suggested, rather than doing it automatically like this
There was a problem hiding this comment.
I am all for maximum type safety, but the mistakes these types catch are unlikely to happen and would be immediately caught by smoke/e2e tests. Consider how much complexity you can remove by relaxing the callApi types and keeping strong type safety just on the user-level methods. Both approach are fine, just different trade-offs, happy to hear more opinions cc @TheUnderScorer @mcnulty-fp
diff --git a/src/serverApiClient.ts b/src/serverApiClient.ts
index 7ba0514..f954fc7 100644
--- a/src/serverApiClient.ts
+++ b/src/serverApiClient.ts
@@ -1,10 +1,15 @@
-import { AllowedMethod, getRequestPath, GetRequestPathOptions, SuccessJsonOrVoid } from './urlUtils'
+import { getRequestPath, GetRequestPathOptions } from './urlUtils'
import { Event, EventUpdate, FingerprintApi, Options, Region, SearchEventsFilter, SearchEventsResponse } from './types'
-import { paths } from './generatedApiTypes'
import { RequestError, SdkError, TooManyRequestsError } from './errors/apiErrors'
import { isErrorResponse } from './errors/handleErrorResponse'
import { toError } from './errors/toError'
+type CallApiOptions = GetRequestPathOptions & {
+ headers?: Record<string, string>
+ body?: BodyInit
+ expect: 'json' | 'void'
+}
+
export class FingerprintJsServerApiClient implements FingerprintApi {
public readonly region: Region
@@ -87,6 +92,7 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
pathParams: [eventId],
method: 'get',
queryParams: rulesetId ? { ruleset_id: rulesetId } : undefined,
+ expect: 'json',
})
}
@@ -142,6 +148,7 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
pathParams: [eventId],
method: 'patch',
body: JSON.stringify(body),
+ expect: 'void',
})
}
@@ -184,6 +191,7 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
path: '/visitors/{visitor_id}',
pathParams: [visitorId],
method: 'delete',
+ expect: 'void',
})
}
@@ -250,12 +258,13 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
path: '/events',
method: 'get',
queryParams: filter,
+ expect: 'json',
})
}
- private async callApi<Path extends keyof paths, Method extends AllowedMethod<Path>>(
- options: GetRequestPathOptions<Path, Method> & { headers?: Record<string, string>; body?: BodyInit }
- ): Promise<SuccessJsonOrVoid<Path, Method>> {
+ private async callApi<T>(options: CallApiOptions & { expect: 'json' }): Promise<T>
+ private async callApi(options: CallApiOptions & { expect: 'void' }): Promise<void>
+ private async callApi<T>(options: CallApiOptions): Promise<T | void> {
const url = getRequestPath({
...options,
region: this.region,
@@ -272,37 +281,39 @@ export class FingerprintJsServerApiClient implements FingerprintApi {
body: options.body,
})
} catch (e) {
- throw new SdkError('Network or fetch error', undefined, e as Error)
+ throw new SdkError('Network or fetch error', undefined, toError(e))
}
- const contentType = response.headers.get('content-type') ?? ''
- const isJson = contentType.includes('application/json')
-
if (response.ok) {
- if (!isJson || response.status === 204) {
- return undefined as SuccessJsonOrVoid<Path, Method>
- }
- let data
- try {
- data = await response.clone().json()
- } catch (e) {
- throw new SdkError('Failed to parse JSON response', response, toError(e))
+ if (options.expect === 'void') {
+ return
}
- return data as SuccessJsonOrVoid<Path, Method>
+ return this.parseJson(response)
+ }
+
+ const errorPayload = await this.parseJson<unknown>(response)
+
+ if (response.status === 429 && isErrorResponse(errorPayload)) {
+ throw new TooManyRequestsError(errorPayload, response)
}
+ if (isErrorResponse(errorPayload)) {
+ throw new RequestError(
+ errorPayload.error.message,
+ errorPayload,
+ response.status,
+ errorPayload.error.code,
+ response
+ )
+ }
+
+ throw RequestError.unknown(response)
+ }
- let errPayload
+ private async parseJson<T>(response: Response): Promise<T> {
try {
- errPayload = await response.clone().json()
+ return (await response.clone().json()) as T
} catch (e) {
throw new SdkError('Failed to parse JSON response', response, toError(e))
}
- if (response.status === 429) {
- throw new TooManyRequestsError(errPayload, response)
- }
- if (isErrorResponse(errPayload)) {
- throw new RequestError(errPayload.error.message, errPayload, response.status, errPayload.error.code, response)
- }
- throw RequestError.unknown(response)
}
}
diff --git a/src/types.ts b/src/types.ts
index c51ef28..3a7ed32 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -1,4 +1,4 @@
-import { components, operations, paths } from './generatedApiTypes'
+import { components, paths } from './generatedApiTypes'
export enum Region {
EU = 'EU',
@@ -47,56 +47,9 @@ export type EventUpdate = components['schemas']['EventUpdate']
export type EventRuleAction = components['schemas']['EventRuleAction']
-// Extract just the `path` parameters as a tuple of strings
-type ExtractPathParamStrings<Path> = Path extends { parameters: { path: infer P } }
- ? P extends Record<string, any>
- ? [P[keyof P]] // We extract the path parameter values as a tuple of strings
- : []
- : []
-
-// Utility type to extract query parameters from an operation and differentiate required/optional
-export type ExtractQueryParams<Path> = Path extends { parameters: { query?: infer Q } }
- ? undefined extends Q // Check if Q can be undefined (meaning it's optional)
- ? Q | undefined // If so, it's optional
- : Q // Otherwise, it's required
- : never // If no query parameters, return never
-
-// Utility type to extract request body from an operation (for POST, PUT, etc.)
-type ExtractRequestBody<Path> = Path extends { requestBody: { content: { 'application/json': infer B } } } ? B : never
-
-// Utility type to extract the response type for 200 status code
-type ExtractResponse<Path> = Path extends { responses: { 200: { content: { 'application/json': infer R } } } }
- ? R
- : void
-
-// Utility type to check union
-type IsUnion<T, U = T> = T extends U ? ([U] extends [T] ? false : true) : never
-
-// When query params have a single key, flatten it into an optional arg(`getEvent`) else keep as object(`searchEvents`)
-// WARN: This type only affects the public FingerprintApi interface (`serverApiClient`).
-// For internal request building (`urlUtils`), use `ExtractQueryParams` which preserves the object form.
-type QueryParamArgs<Q> = [Q] extends [never]
- ? []
- : [Exclude<Q, undefined>] extends [never]
- ? []
- : IsUnion<keyof Exclude<Q, undefined>> extends false
- ? [param?: Exclude<Q, undefined>[keyof Exclude<Q, undefined>]]
- : [params: Q]
-
-// Extracts args to given API method
-type ApiMethodArgs<Path extends keyof operations> = [
- // If method has body, extract it as first parameter
- ...(ExtractRequestBody<operations[Path]> extends never ? [] : [body: ExtractRequestBody<operations[Path]>]),
- // Next are path params, e.g. for path "/events/{event_id}" it will be one string parameter,
- ...ExtractPathParamStrings<operations[Path]>,
- // Last parameter will be the query params, if any
- ...QueryParamArgs<ExtractQueryParams<operations[Path]>>,
-]
-
-type ApiMethod<Path extends keyof operations> = (
- ...args: ApiMethodArgs<Path>
-) => Promise<ExtractResponse<operations[Path]>>
-
-export type FingerprintApi = {
- [Operation in keyof operations]: ApiMethod<Operation>
+export interface FingerprintApi {
+ getEvent(eventId: string, rulesetId?: string): Promise<Event>
+ updateEvent(body: EventUpdate, eventId: string): Promise<void>
+ searchEvents(filter: SearchEventsFilter): Promise<SearchEventsResponse>
+ deleteVisitorData(visitorId: string): Promise<void>
}
diff --git a/src/urlUtils.ts b/src/urlUtils.ts
index 27f53d7..042e6ef 100644
--- a/src/urlUtils.ts
+++ b/src/urlUtils.ts
@@ -1,4 +1,4 @@
-import { ExtractQueryParams, Region } from './types'
+import { Region } from './types'
import { version } from '../package.json'
import { paths } from './generatedApiTypes'
@@ -10,8 +10,7 @@ const globalRegionUrl = 'https://api.fpjs.io/'
type QueryStringScalar = string | number | boolean | null | undefined
-type QueryStringParameters = Record<string, QueryStringScalar | string[]> & {
- api_key?: string
+type QueryStringParameters = Record<string, QueryStringScalar | QueryStringScalar[]> & {
ii: string
}
@@ -57,67 +56,15 @@ function getServerApiUrl(region: Region): string {
}
}
-/**
- * Extracts parameter placeholders into a literal union type.
- * For example `extractPathParams<'/users/{userId}/posts/{postId}'>` resolves to `"userId" | "postId"
- */
-type ExtractPathParams<T extends string> = T extends `${string}{${infer Param}}${infer Rest}`
- ? Param | ExtractPathParams<Rest>
- : never
-
-type PathParams<Path extends keyof paths> =
- ExtractPathParams<Path> extends never
- ? { pathParams?: never }
- : {
- pathParams: ExtractPathParams<Path> extends never ? never : string[]
- }
-
-type QueryParams<Path extends keyof paths, Method extends keyof paths[Path]> =
- ExtractQueryParams<paths[Path][Method]> extends never
- ? { queryParams?: any } // No query params
- : {
- queryParams?: ExtractQueryParams<paths[Path][Method]> // Optional query params
- }
-
-type IsNever<Type> = [Exclude<Type, undefined>] extends [never] ? true : false
-export type NonNeverKeys<Type> = {
- [Key in keyof Type]-?: IsNever<Type[Key]> extends true ? never : Key
-}[keyof Type]
-export type AllowedMethod<Path extends keyof paths> = Extract<Exclude<NonNeverKeys<paths[Path]>, 'parameters'>, string>
-
-type JsonContentOf<Response> = Response extends { content: { 'application/json': infer T } } ? T : never
-
-type UnionJsonFromResponses<Response> = {
- [StatusCode in keyof Response]: JsonContentOf<Response[StatusCode]>
-}[keyof Response]
+export type HttpMethod = 'get' | 'put' | 'post' | 'delete' | 'options' | 'head' | 'patch' | 'trace'
-type StartingWithSuccessCode<Response> = {
- [StatusCode in keyof Response]: `${StatusCode & number}` extends `2${number}${number}` ? StatusCode : never
-}[keyof Response]
-
-type SuccessResponses<Response> = Pick<Response, Extract<StartingWithSuccessCode<Response>, keyof Response>>
-
-type OperationOf<Path extends keyof paths, Method extends AllowedMethod<Path>> = paths[Path][Method]
-
-type ResponsesOf<Path extends keyof paths, Method extends AllowedMethod<Path>> =
- OperationOf<Path, Method> extends { responses: infer Response } ? Response : never
-
-type SuccessJson<Path extends keyof paths, Method extends AllowedMethod<Path>> = UnionJsonFromResponses<
- SuccessResponses<ResponsesOf<Path, Method>>
->
-
-export type SuccessJsonOrVoid<Path extends keyof paths, Method extends AllowedMethod<Path>> = [
- SuccessJson<Path, Method>,
-] extends [never]
- ? void
- : SuccessJson<Path, Method>
-
-export type GetRequestPathOptions<Path extends keyof paths, Method extends AllowedMethod<Path>> = {
- path: Path
- method: Method
+export interface GetRequestPathOptions {
+ path: keyof paths
+ method: HttpMethod
+ pathParams?: string[]
+ queryParams?: Record<string, QueryStringScalar | QueryStringScalar[]>
region?: Region
-} & PathParams<Path> &
- QueryParams<Path, Method>
+}
/**
* 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
*
* @internal
*
- * @param {GetRequestPathOptions<Path, Method>} options
- * @param {Path} options.path - The path of the API endpoint
+ * @param {GetRequestPathOptions} options
+ * @param {keyof paths} options.path - The path of the API endpoint
* @param {string[]} [options.pathParams] - Path parameters to be replaced in the path
- * @param {QueryParams<Path, Method>["queryParams"]} [options.queryParams] - Query string
+ * @param {GetRequestPathOptions["queryParams"]} [options.queryParams] - Query string
* parameters to be appended to the URL
* @param {Region} options.region - The region of the API endpoint
- * @param {Method} options.method - The method of the API endpoint
+ * @param {HttpMethod} options.method - The method of the API endpoint
*
* @returns {string} The formatted URL with parameters replaced and query string
* parameters appended
*/
-export function getRequestPath<Path extends keyof paths, Method extends AllowedMethod<Path>>({
+export function getRequestPath({
path,
pathParams,
queryParams,
@@ -144,7 +91,7 @@ export function getRequestPath<Path extends keyof paths, Method extends AllowedM
// method mention here so that it can be referenced in JSDoc
// eslint-disable-next-line @typescript-eslint/no-unused-vars
method: _,
-}: GetRequestPathOptions<Path, Method>): string {
+}: GetRequestPathOptions): string {
// Step 1: Extract the path parameters (placeholders) from the path
const placeholders = Array.from(path.matchAll(/{(.*?)}/g)).map((match) => match[1])
There was a problem hiding this comment.
But in this form, it doesn't show the operations that need to be implemented/updated. It won't show any errors when a new operation or a new parameter is added. We'll need to remember to update this interface and functions whenever a new parameter or operation is added.
export interface FingerprintApi {
getEvent(eventId: string, { rulesetId?: string }): Promise<Event>
updateEvent(body: EventUpdate, eventId: string): Promise<void>
searchEvents(filter: SearchEventsFilter): Promise<SearchEventsResponse>
deleteVisitorData(visitorId: string): Promise<void>
}This will not show an error when a new parameter is introduced in the OpenAPI schema. But the one below will show an error about a missing operation/argument when running lint & test workflow
export type FingerprintApi = {
[Operation in keyof operations]: ApiMethod<Operation>
}
There was a problem hiding this comment.
In the absence of more input, let's stick with your approach then :)
Fixes `Handling an event with rule_action` example of the `getEvent` function. Related-Task: INTER-1488
Replace the standalone `rulesetId` string parameter with a `GetEventOptions` object to support future query parameters without breaking changes. Remove the `QueryParamArgs` utility type and its support types that is no longer needed. Related-Task: INTER-1488
be7fcb9 to
8b30052
Compare
Removes `Endpoints and method signatures changed.` breaking change note because it no longer true. There are no named parameters in JS and all functions keep similar signature. Related-Task: INTER-1488
Remove the `retryAfter` property from the `TooManyRequestsError`. Related-Task: INTER-1488
Make `curl` silent unless `TRACE` or `ACTIONS_STEP_DEBUG` is set. Related-Task: INTER-1488
Rename the test helper to better reflect that it creates a JSON response. Related-Task: INTER-1488
Co-authored-by: Juraj Uhlar <juro.uhlar@gmail.com>
Updates OpenAPI schema to latest version. Related-Task: INTER-1488
Validate rule_action response for events matched by a ruleset. Related-Task: INTER-1488
src/serverApiClient.ts
Outdated
| * | ||
| * When an event is created, it is assigned `linkedId` and `tag` submitted through the JS agent parameters. This information might not be available on the client so the Server API allows for updating the attributes after the fact. | ||
| * | ||
| * **Warning** It's not possible to update events older than 10 days. |
There was a problem hiding this comment.
Schema says: Warning It’s not possible to update events older than one month. I guess it improved and we need to update the description here?
| @@ -200,38 +187,14 @@ export class FingerprintJsServerApiClient implements FingerprintApi { | |||
| */ | |||
| public async deleteVisitorData(visitorId: string): Promise<void> { | |||
There was a problem hiding this comment.
JS doc still references retryAfter
|
|
||
| console.log('All tests passed') | ||
| return 0 | ||
| } catch (error) { |
There was a problem hiding this comment.
retryAfter below no longer exists. Consider adding @ts-check to start of all mjs files to catch these kinds of errors in the editor/during
There was a problem hiding this comment.
Updated with commit #167e25c.
We can consider adding a tsconfig.json and using JSDoc for type checking in a separate PR instead of // @ts-check. Let's handle the type checking in .mjsfiles in its own PR
Update updateEvent JSDoc to reflect the new one month retention limit. Remove TooManyRequestsError.retryAfter usage from docs and tests. Related-Task: INTER-1488
Serialize array query parameters as `key=a&key=b`. Related-Task: INTER-1488
🚀 Following releases will be created using changesets from this PR:@fingerprint/fingerprint-server-sdk@7.0.0-test.0Major Changes
Minor Changes
|
| import { isErrorResponse } from './errors/handleErrorResponse' | ||
| import { toError } from './errors/toError' | ||
|
|
||
| export class FingerprintJsServerApiClient implements FingerprintApi { |
There was a problem hiding this comment.
now is a good chance to remove js and call this
| export class FingerprintJsServerApiClient implements FingerprintApi { | |
| export class FingerprintServerApiClient implements FingerprintApi { |
Wdyt @ilfa ?
This PR upgrades the Server SDK to the Server API v4. It removes Server APIv3 specific behavior and aligns the SDK with the new events format shared by Server API and Webhooks.
❓ Why?
data/products/resultnesting), switches to Bearer auth, unifies Webhooks & Server APIeventformats, and deprecates/visitorsin favor of/v4/events.⚙️ What Changed?
GET /events/search->GET /v4/eventsGET /visitors-> removed, migrate toGET /v4/events/v4/*URLs.Auth-Api-Keycustom header andapiKeyquery param withAuthorization: Bearer <secret_api_key>.AuthenticationModeoption.request_id->event_idlinked_id,pagination_key)GET /v4/eventswith filters.object) withruleset_idkey to evaluate the event against a ruleset.EventRuleActiontype exported for package consumers.PUT /events->PATCH /v4/event/:event_id@fingerprint/fingerprint-server-sdkfingerprintjs/node-sdkAuthenticationModeoption are removed.updateEvent(body, eventId)now use snake_case fields forbody📦 Migration Guide (SDK Consumers)
@fingerprint/fingerprint-server-sdkauthenticationModeoption when initializingFingerprintJsServerApiClient.const client = new FingerprintJsServerApiClient({ apiKey: '<SECRET_API_KEY>', region: Region.Global, - authenticationMode: AuthenticationMode.AuthHeader })client.updateEvent({ - linkedId: "linkedId" + linked_id: "linkedId" }, "<event-id>")tagsinstead oftagfor updating an event.client.updateEvent({ - tag: { + tags: { key: 'value', }, }, "<event-id>")getVisitorHistory()function and usesearchEventsfunction.getVisits()function. UsesearchEvents()function.getRelatedVisitors()function.VisitorHistoryFilter,ErrorPlainResponse,VisitorsResponse,RelatedVisitorsResponse,RelatedVisitorsFilter,Webhook,EventsUpdateRequesttype usages.