@finteqhub/sdk-js 0.12.0-beta.3 → 0.12.0-beta.5

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/README.md CHANGED
@@ -6,6 +6,8 @@ Use `new FinteqHubProcessing(apiUrl: string, fingerprintVisitorId: string, merch
6
6
  const processing = new FinteqHubProcessing('api-url', 'fingerprint-visitor-id', 'merchant-id', 'session-id');
7
7
  ```
8
8
 
9
+ The constructor validates its arguments and throws a `TypeError` when `apiUrl`, `fingerprintVisitorId`, `merchantId` or `sessionId` is missing, empty or not a string, when `isSecure` is not a boolean, or when `retryOptions` is malformed (see [Retries and error diagnostics](#retries-and-error-diagnostics)).
10
+
9
11
  ## Retries and error diagnostics
10
12
 
11
13
  Failed HTTP requests are retried automatically with exponential backoff (`100ms → 200ms → 500ms → 1000ms → 2000ms`; every retry after the fifth waits 2000ms). Retries can be configured via the optional `retryOptions` constructor argument (the sixth one, after `isSecure`):
@@ -21,6 +23,8 @@ const processing = new FinteqHubProcessing('api-url', 'fingerprint-visitor-id',
21
23
  });
22
24
  ```
23
25
 
26
+ The constructor throws a `TypeError` when `retryOptions` is not an object, `retryCount` is not a non-negative integer, or `retryStatusCode` is not a function.
27
+
24
28
  Network errors (the browser could not reach the server at all, e.g. `TypeError: Failed to fetch`, or the connection dropped while the response body was being read) are always retried too.
25
29
 
26
30
  Every retry attempt is reported with `console.warn`. When a request finally fails, the SDK logs `console.error` (`sdk-js: request failed: <message>`) with a full diagnostic dump and rejects with a `RequestError` whose `diagnostics` field carries the same payload — include it in your error reporting. `diagnostics.kind` tells the failure class apart:
@@ -59,6 +59,6 @@ export declare class FinteqHubProcessing {
59
59
  private sendPost;
60
60
  private request;
61
61
  private fetchWithRetry;
62
- private responseError;
62
+ private requestError;
63
63
  private collectDiagnostics;
64
64
  }
@@ -7,7 +7,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { getDeviceData, uuid } from "./utils";
10
+ import { getDeviceData, uuid, validateArguments } from "./utils";
11
11
  import { SDK_HEADER_NAME, SDK_HEADER_VALUE, SDK_VERSION } from "./version";
12
12
  export class RequestError extends Error {
13
13
  constructor(message, diagnostics) {
@@ -26,6 +26,7 @@ const sanitizeBody = (body) => body.slice(0, MAX_BODY_SNIPPET_LENGTH).replace(/\
26
26
  const defaultRetryStatusCode = (statusCode) => statusCode < 200 || statusCode === 408 || statusCode >= 500;
27
27
  export class FinteqHubProcessing {
28
28
  constructor(apiUrl, fingerprintVisitorId, merchantId, sessionId, isSecure = false, retryOptions = {}) {
29
+ validateArguments({ apiUrl, fingerprintVisitorId, merchantId, sessionId, isSecure, retryOptions });
29
30
  this.apiUrl = apiUrl;
30
31
  this.fingerprintVisitorId = fingerprintVisitorId;
31
32
  this.merchantId = merchantId;
@@ -134,10 +135,10 @@ export class FinteqHubProcessing {
134
135
  ? sanitizeBody(e.message)
135
136
  : "parse error message omitted (200 response body may carry credentials)",
136
137
  };
137
- throw this.responseError("invalid_json", `request to ${url} returned invalid JSON (status ${response.status})`, url, options, attempts, { status: response.status, body }, parseError);
138
+ throw this.requestError("invalid_json", `request to ${url} returned invalid JSON (status ${response.status})`, url, options, attempts, { status: response.status, body }, parseError);
138
139
  }
139
140
  if ((result === null || result === void 0 ? void 0 : result.error) || response.status !== 200) {
140
- throw this.responseError("http_error", (result === null || result === void 0 ? void 0 : result.error) || `unexpected response status ${response.status}`, url, options, attempts, { status: response.status, body, error: result === null || result === void 0 ? void 0 : result.error });
141
+ throw this.requestError("http_error", (result === null || result === void 0 ? void 0 : result.error) || `unexpected response status ${response.status}`, url, options, attempts, { status: response.status, body, error: result === null || result === void 0 ? void 0 : result.error });
141
142
  }
142
143
  return result;
143
144
  });
@@ -164,10 +165,7 @@ export class FinteqHubProcessing {
164
165
  // status is known when the failure happened while reading the body of a received response
165
166
  attempts.push({ durationMs: Date.now() - startedAt, status: response === null || response === void 0 ? void 0 : response.status, error: e.message });
166
167
  if (attempt > retryCount) {
167
- const message = `request to ${url} failed after ${attempt} attempt(s): ${e.message}`;
168
- const diagnostics = this.collectDiagnostics("network", url, options, attempts, e, response ? { status: response.status } : undefined);
169
- console.error(`sdk-js: request failed: ${message}`, diagnostics);
170
- throw new RequestError(message, diagnostics);
168
+ throw this.requestError("network", `request to ${url} failed after ${attempt} attempt(s): ${e.message}`, url, options, attempts, response ? { status: response.status } : undefined, e);
171
169
  }
172
170
  reason = e.message;
173
171
  }
@@ -187,7 +185,7 @@ export class FinteqHubProcessing {
187
185
  }
188
186
  });
189
187
  }
190
- responseError(kind, message, url, options, attempts, response, error) {
188
+ requestError(kind, message, url, options, attempts, response, error) {
191
189
  const diagnostics = this.collectDiagnostics(kind, url, options, attempts, error, response);
192
190
  console.error(`sdk-js: request failed: ${message}`, diagnostics);
193
191
  return new RequestError(message, diagnostics);
@@ -1,3 +1,4 @@
1
+ import type { RetryOptions } from "./processing";
1
2
  export declare const DeviceType: {
2
3
  Unknown: string;
3
4
  Computer: string;
@@ -9,6 +10,15 @@ export declare const DeviceType: {
9
10
  };
10
11
  export declare function uuid(): string;
11
12
  export declare function getDeviceType(): string;
13
+ declare type ConstructorArguments = {
14
+ apiUrl: string;
15
+ fingerprintVisitorId: string;
16
+ merchantId: string;
17
+ sessionId: string;
18
+ isSecure: boolean;
19
+ retryOptions: RetryOptions;
20
+ };
21
+ export declare function validateArguments(args: ConstructorArguments): void;
12
22
  export declare function getDeviceData(): {
13
23
  device: {
14
24
  type: string;
@@ -31,3 +41,4 @@ export declare function getDeviceData(): {
31
41
  };
32
42
  };
33
43
  };
44
+ export {};
package/dist/src/utils.js CHANGED
@@ -40,6 +40,28 @@ export function getDeviceType() {
40
40
  }
41
41
  return DeviceType.Unknown;
42
42
  }
43
+ const REQUIRED_STRINGS = ["apiUrl", "fingerprintVisitorId", "merchantId", "sessionId"];
44
+ export function validateArguments(args) {
45
+ for (const key of REQUIRED_STRINGS) {
46
+ if (typeof args[key] !== "string" || args[key] === "") {
47
+ throw new TypeError(`sdk-js: ${key} must be a non-empty string`);
48
+ }
49
+ }
50
+ if (typeof args.isSecure !== "boolean") {
51
+ throw new TypeError("sdk-js: isSecure must be a boolean");
52
+ }
53
+ const { retryOptions } = args;
54
+ if (typeof retryOptions !== "object" || retryOptions === null) {
55
+ throw new TypeError("sdk-js: retryOptions must be an object");
56
+ }
57
+ const { retryCount, retryStatusCode } = retryOptions;
58
+ if (retryCount !== undefined && (!Number.isInteger(retryCount) || retryCount < 0)) {
59
+ throw new TypeError("sdk-js: retryOptions.retryCount must be a non-negative integer");
60
+ }
61
+ if (retryStatusCode !== undefined && typeof retryStatusCode !== "function") {
62
+ throw new TypeError("sdk-js: retryOptions.retryStatusCode must be a function");
63
+ }
64
+ }
43
65
  export function getDeviceData() {
44
66
  var _a, _b, _c;
45
67
  return {
@@ -1,3 +1,3 @@
1
1
  export declare const SDK_HEADER_NAME = "X-Finteqhub-SDK";
2
- export declare const SDK_VERSION = "0.12.0-beta.3";
2
+ export declare const SDK_VERSION = "0.12.0-beta.5";
3
3
  export declare const SDK_HEADER_VALUE: string;
@@ -1,3 +1,3 @@
1
1
  export const SDK_HEADER_NAME = "X-Finteqhub-SDK";
2
- export const SDK_VERSION = "0.12.0-beta.3";
2
+ export const SDK_VERSION = "0.12.0-beta.5";
3
3
  export const SDK_HEADER_VALUE = `sdk-js/${SDK_VERSION}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@finteqhub/sdk-js",
3
- "version": "0.12.0-beta.3",
3
+ "version": "0.12.0-beta.5",
4
4
  "description": "SDK for interacting with FinteqHub processing API",
5
5
  "main": "./dist/index.js",
6
6
  "typings": "./dist/index.d.ts",