@laranex/myanmar-payments 4.0.0-dev.4 → 4.0.0-dev.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +4 -4
  2. package/dist/cjs/aya-pay/aya-pay.d.ts +10 -10
  3. package/dist/cjs/aya-pay/aya-pay.js +10 -11
  4. package/dist/cjs/core/env.d.ts +5 -12
  5. package/dist/cjs/core/env.js +20 -23
  6. package/dist/cjs/core/errors.d.ts +8 -3
  7. package/dist/cjs/core/errors.js +11 -4
  8. package/dist/cjs/core/http.d.ts +10 -11
  9. package/dist/cjs/core/http.js +7 -9
  10. package/dist/cjs/core/index.d.ts +1 -1
  11. package/dist/cjs/core/index.js +1 -2
  12. package/dist/cjs/cyber-source/cyber-source.d.ts +10 -16
  13. package/dist/cjs/cyber-source/cyber-source.js +13 -14
  14. package/dist/cjs/kbz-pay/kbz-pay.d.ts +10 -11
  15. package/dist/cjs/kbz-pay/kbz-pay.js +11 -13
  16. package/dist/cjs/wave-money/wave-money.d.ts +12 -13
  17. package/dist/cjs/wave-money/wave-money.js +14 -23
  18. package/dist/cjs/yoma-mmqr/yoma-mmqr.d.ts +14 -14
  19. package/dist/cjs/yoma-mmqr/yoma-mmqr.js +14 -15
  20. package/dist/esm/aya-pay/aya-pay.d.ts +10 -10
  21. package/dist/esm/aya-pay/aya-pay.js +11 -12
  22. package/dist/esm/core/env.d.ts +5 -12
  23. package/dist/esm/core/env.js +18 -20
  24. package/dist/esm/core/errors.d.ts +8 -3
  25. package/dist/esm/core/errors.js +11 -4
  26. package/dist/esm/core/http.d.ts +10 -11
  27. package/dist/esm/core/http.js +6 -8
  28. package/dist/esm/core/index.d.ts +1 -1
  29. package/dist/esm/core/index.js +1 -1
  30. package/dist/esm/cyber-source/cyber-source.d.ts +10 -16
  31. package/dist/esm/cyber-source/cyber-source.js +14 -15
  32. package/dist/esm/kbz-pay/kbz-pay.d.ts +10 -11
  33. package/dist/esm/kbz-pay/kbz-pay.js +12 -14
  34. package/dist/esm/wave-money/wave-money.d.ts +12 -13
  35. package/dist/esm/wave-money/wave-money.js +15 -24
  36. package/dist/esm/yoma-mmqr/yoma-mmqr.d.ts +14 -14
  37. package/dist/esm/yoma-mmqr/yoma-mmqr.js +15 -16
  38. package/package.json +1 -1
  39. package/skills/node-myanmar-payments/SKILL.md +7 -5
package/CHANGELOG.md CHANGED
@@ -10,19 +10,20 @@ Initial release. The version number matches the other Laranex Myanmar payments p
10
10
  - Gateways: KBZ Pay (`pwa`, `qr`, `app`, `status`), Wave Money (`initiate`), AYA Payment Gateway (`services`, `initiate`, `status`, `verifyRedirect`), Yoma MMQR (`initiate`, `renewQr`, `status`, `forgetToken`) and CyberSource Secure Acceptance (`initiate`); every gateway validates its payment data (`KbzPay.validate()` and so on) and verifies callbacks with `handleCallback`.
11
11
  - Subpath exports per gateway (`@laranex/myanmar-payments/kbz-pay`, `/wave-money`, `/aya-pay`, `/yoma-mmqr`, `/cyber-source`) next to the root export, as ES modules and CommonJS with type declarations.
12
12
  - Exact `Amount` type (`Amount.kyat()`, `Amount.parse()`) kept as decimal text, so amounts never pass through a float; payment data also takes a whole-number `number` or `bigint` and rejects fractions. Decimals are accepted only where the gateway documents them (KBZ Pay up to 2 places, CyberSource any); every gateway except CyberSource is MMK only.
13
- - A config class per gateway with `fromEnv(process.env)`, reading the same `*_SANDBOX`, credential and URL variables as the PHP, Laravel and Go packages; a missing credential throws `ConfigurationError`. `MyanmarPayments` builds every gateway lazily from one config object or the environment.
13
+ - A config class per gateway with `fromEnv(process.env)`, reading the same credential, setting and URL variables as the PHP, Laravel and Go packages; a missing setting throws `ConfigurationError`. `MyanmarPayments` builds every gateway lazily from one config object or the environment.
14
14
  - Result classes: `RedirectPayment`, `FormPayment` (with `toHtml()`), `QrPayment` (with `qrImageDataUri()`) and `AppPayment`; `PaymentCallback` (with a gateway-independent `PaymentStatus` and the `Acknowledgement` each gateway expects, sent with `send(res)` or `toResponse()`) and `PaymentStatusResult`.
15
15
  - `CallbackRequest.fromNodeRequest()` (node:http, Express), `CallbackRequest.fromWebRequest()` (Fetch API servers such as Next.js, Hono and Bun), `CallbackRequest.from()` and `CallbackRequest.fromJson()`. JSON numbers in callbacks are read without a float conversion, so signatures and amounts keep the gateway's exact text.
16
16
  - Errors: `PaymentError` and its subclasses `InvalidPaymentDataError` (per-field `errors`), `ApiError` (`gatewayCode`, `gatewayMessage`, `httpStatus`, `raw`, `cause`), `SignatureVerificationError` and `ConfigurationError`.
17
- - No runtime dependencies: the global `fetch` (or an injected `fetch` / `HttpClient`, 30 second default timeout, `AbortSignal` per call) and `node:crypto`; an injectable `TokenCache` with an in-memory default for Yoma's access token.
17
+ - No runtime dependencies: the global `fetch` (or an injected `fetch` / `HttpClient`, the configured `timeoutSeconds`, `AbortSignal` per call) and `node:crypto`; an injectable `TokenCache` with an in-memory default for Yoma's access token.
18
18
  - CyberSource callbacks trust only the fields listed in `signed_field_names`: `decision` and `req_reference_number` must be signed, and unsigned fields are left out of the result and `raw`.
19
19
  - AYA Pay reads a `payload` whose `+` signs became spaces in an unencoded return query string.
20
20
  - Callback, return and cancel URLs only need to be valid absolute http or https URLs; there is no HTTPS-only rule (gateways may still require HTTPS in production).
21
- - Wave Money's sandbox is `https://preprodpayments.wavemoney.io:8107`, with checkout at `https://preprodpayments.wavemoney.io/authenticate`.
22
21
  - Agent skill in `skills/node-myanmar-payments` so coding agents use the package correctly; install it with `npx skills add laranex/node-myanmar-payments`.
23
22
  - Requires Node.js 20 or higher.
24
23
 
25
24
  ### Changed since the pre-releases
25
+ - No sandbox switch: the sandbox setting (`sandbox`) and the `*_SANDBOX` variables are removed, and every gateway defaults to its production endpoints. Every other setting is required: the HTTP timeout (`timeout_in_seconds`, `MYANMAR_PAYMENTS_HTTP_TIMEOUT`) for every gateway that calls an API, Wave Money's `time_to_live_in_seconds` and `merchant_name` (no `APP_NAME` fallback), Yoma MMQR's `api_version`, and CyberSource's `currency`, `locale` and `transactionType` on each payment. A missing setting throws the configuration error naming it; a time setting that is not a whole number greater than 0 throws `The <gateway> configuration [<key>] must be a whole number greater than 0.` Upgrading: delete `*_SANDBOX`; to keep testing against UAT, set the URL overrides to the UAT URLs listed in the docs; set the newly required settings.
26
+ - In Node: config options `timeoutSeconds` (KBZ Pay, Wave Money, AYA Pay, Yoma MMQR), `timeToLiveSeconds` and `apiVersion` are required and take a whole number or its text; the `SANDBOX_*`, `DEFAULT_TIME_TO_LIVE_SECONDS` and `DEFAULT_API_VERSION` constants are removed. `GatewayOptions.timeoutMs` (so also the `MyanmarPayments` option) and `DEFAULT_TIMEOUT_MS` are removed; `FetchHttpClient` requires `timeoutMs`. `ConfigurationError` takes a third `invalid` argument for the whole-number message.
26
27
  - `PaymentStatus.Cancelled` is renamed to `PaymentStatus.Canceled` and its value from `'cancelled'` to `'canceled'` (American English), with no alias. Code or stored statuses from the `v4.0.0-dev` pre-releases need the new name; gateway status literals such as Wave Money's `PAYMENT_REQUEST_CANCELLED` are unchanged.
27
28
  - Callback values that are JSON numbers are kept as their exact text, as strings, in `raw`, `parsedBody()`, `input()`, `queryInput()` and the `raw` of errors (`1000.50` is `'1000.50'`, not `1000.5`), like the PHP SDK.
28
29
  - A nested value (object or array) in a signed or hashed callback field now fails verification: KBZ Pay (any callback field), Wave Money (the hashed fields), AYA Pay (the signed payload fields) and Yoma MMQR (`status`). Before, KBZ Pay skipped it, Wave Money hashed it as `null` and AYA Pay signed it as empty.
@@ -30,4 +31,3 @@ Initial release. The version number matches the other Laranex Myanmar payments p
30
31
  - Yoma MMQR caches its access token under `myanmar-payments.yoma-mmqr.token.<sha256 of base URL and client id>` (was `node-myanmar-payments.…`), the same key as the PHP, Go and Python SDKs, and reads `expires_in` from its leading digits.
31
32
  - `Amount.equals()` compares by value, ignoring leading zeros too (`'01000'` equals `Amount.kyat(1000)`); text that is not plain digits with an optional fraction is never equal.
32
33
  - `CallbackRequest.rawBody` holds the exact bytes received (a string body is encoded as UTF-8), next to `body` as text, like Python's `raw_body` and Go's `Body`.
33
- - A config's `sandbox` option also takes a string, read like the `*_SANDBOX` variable (`false`, `0`, `f`, `no` or `off` select production).
@@ -10,29 +10,29 @@ export interface AyaPayConfigOptions {
10
10
  /** The secret that signs requests and verifies callbacks. */
11
11
  appSecret: string;
12
12
  /**
13
- * Use the UAT environment (default `true`).
14
- * Text is read like a `*_SANDBOX` variable: `false`, `0`, `f`, `no` or `off` select production.
13
+ * Seconds before the default HTTP client gives up on a request, a whole number greater than 0
14
+ * (or its text). A client you pass keeps its own timeout.
15
15
  */
16
- sandbox?: boolean | string | undefined;
17
- /** Overrides the gateway base URL. */
16
+ timeoutSeconds: number | string;
17
+ /** Overrides the gateway base URL, e.g. to point at UAT. */
18
18
  baseUrl?: string | undefined;
19
19
  }
20
20
  /**
21
- * AYA Payment Gateway (APG) credentials and endpoints. A missing credential throws a
22
- * `ConfigurationError`.
21
+ * AYA Payment Gateway (APG) credentials and endpoints. A missing setting throws a
22
+ * `ConfigurationError`. The URL defaults to production.
23
23
  */
24
24
  export declare class AyaPayConfig {
25
- static readonly SANDBOX_URL = "https://uat-pgw.ayainnovation.com";
26
25
  static readonly PRODUCTION_URL = "https://pgw.ayainnovation.com";
27
26
  readonly appKey: string;
28
27
  readonly appSecret: string;
29
- readonly sandbox: boolean;
28
+ /** Seconds before the default HTTP client gives up on a request. */
29
+ readonly timeoutSeconds: number;
30
30
  /** The base URL in use. */
31
31
  readonly baseUrl: string;
32
32
  constructor(options: AyaPayConfigOptions);
33
33
  /**
34
- * Reads `AYA_PAY_APP_KEY`, `AYA_PAY_APP_SECRET`, `AYA_PAY_SANDBOX` and `AYA_PAY_BASE_URL`, falling
35
- * back to the `AYA_PGW_*` names.
34
+ * Reads `AYA_PAY_APP_KEY`, `AYA_PAY_APP_SECRET`, `MYANMAR_PAYMENTS_HTTP_TIMEOUT` and
35
+ * `AYA_PAY_BASE_URL`, falling back to the `AYA_PGW_*` names.
36
36
  */
37
37
  static fromEnv(env?: EnvSource): AyaPayConfig;
38
38
  }
@@ -12,33 +12,32 @@ const status_js_1 = require("../core/status.js");
12
12
  const validate_js_1 = require("../core/validate.js");
13
13
  const values_js_1 = require("../core/values.js");
14
14
  /**
15
- * AYA Payment Gateway (APG) credentials and endpoints. A missing credential throws a
16
- * `ConfigurationError`.
15
+ * AYA Payment Gateway (APG) credentials and endpoints. A missing setting throws a
16
+ * `ConfigurationError`. The URL defaults to production.
17
17
  */
18
18
  class AyaPayConfig {
19
- static SANDBOX_URL = 'https://uat-pgw.ayainnovation.com';
20
19
  static PRODUCTION_URL = 'https://pgw.ayainnovation.com';
21
20
  appKey;
22
21
  appSecret;
23
- sandbox;
22
+ /** Seconds before the default HTTP client gives up on a request. */
23
+ timeoutSeconds;
24
24
  /** The base URL in use. */
25
25
  baseUrl;
26
26
  constructor(options) {
27
27
  this.appKey = (0, env_js_1.requireSetting)('aya_pay', 'app_key', options.appKey);
28
28
  this.appSecret = (0, env_js_1.requireSetting)('aya_pay', 'app_secret', options.appSecret);
29
- this.sandbox = (0, env_js_1.parseSandbox)(options.sandbox);
30
- this.baseUrl = (0, env_js_1.trimUrl)((0, env_js_1.optionalSetting)(options.baseUrl) ??
31
- (this.sandbox ? AyaPayConfig.SANDBOX_URL : AyaPayConfig.PRODUCTION_URL));
29
+ this.timeoutSeconds = (0, env_js_1.requireSeconds)('aya_pay', 'timeout_in_seconds', options.timeoutSeconds);
30
+ this.baseUrl = (0, env_js_1.trimUrl)((0, env_js_1.optionalSetting)(options.baseUrl) ?? AyaPayConfig.PRODUCTION_URL);
32
31
  }
33
32
  /**
34
- * Reads `AYA_PAY_APP_KEY`, `AYA_PAY_APP_SECRET`, `AYA_PAY_SANDBOX` and `AYA_PAY_BASE_URL`, falling
35
- * back to the `AYA_PGW_*` names.
33
+ * Reads `AYA_PAY_APP_KEY`, `AYA_PAY_APP_SECRET`, `MYANMAR_PAYMENTS_HTTP_TIMEOUT` and
34
+ * `AYA_PAY_BASE_URL`, falling back to the `AYA_PGW_*` names.
36
35
  */
37
36
  static fromEnv(env = (0, env_js_1.defaultEnv)()) {
38
37
  return new AyaPayConfig({
39
38
  appKey: (0, env_js_1.envFirst)(env, 'AYA_PAY_APP_KEY', 'AYA_PGW_APP_KEY'),
40
39
  appSecret: (0, env_js_1.envFirst)(env, 'AYA_PAY_APP_SECRET', 'AYA_PGW_APP_SECRET'),
41
- sandbox: (0, env_js_1.envSandbox)(env, 'AYA_PAY_SANDBOX'),
40
+ timeoutSeconds: (0, env_js_1.envFirst)(env, env_js_1.HTTP_TIMEOUT_VARIABLE),
42
41
  baseUrl: (0, env_js_1.envFirst)(env, 'AYA_PAY_BASE_URL', 'AYA_PGW_BASE_URL'),
43
42
  });
44
43
  }
@@ -123,7 +122,7 @@ class AyaPay {
123
122
  transport;
124
123
  constructor(config, options = {}) {
125
124
  this.config = config instanceof AyaPayConfig ? config : new AyaPayConfig(config);
126
- this.transport = new http_js_1.Transport((0, http_js_1.httpClientFrom)(options));
125
+ this.transport = new http_js_1.Transport((0, http_js_1.httpClientFrom)(options, this.config.timeoutSeconds));
127
126
  }
128
127
  /** A gateway configured from the `AYA_PAY_*` (or `AYA_PGW_*`) environment variables. */
129
128
  static fromEnv(env = (0, env_js_1.defaultEnv)(), options = {}) {
@@ -3,21 +3,14 @@ export type EnvSource = Readonly<Record<string, string | undefined>>;
3
3
  /** The first non-empty value among `keys`, trimmed, or `''`. @internal */
4
4
  export declare function envFirst(env: EnvSource, ...keys: string[]): string;
5
5
  /**
6
- * Reads a `*_SANDBOX` variable. Only `false`, `0`, `f`, `no` and `off` (any case) select
7
- * production; unset or unrecognized values mean sandbox.
6
+ * A required whole number of seconds: an integer greater than 0, or text such as `'300'`. Unset
7
+ * or blank throws the missing {@link ConfigurationError}; anything else throws the invalid one.
8
8
  *
9
9
  * @internal
10
10
  */
11
- export declare function envSandbox(env: EnvSource, key: string): boolean;
12
- /**
13
- * A `sandbox` setting: booleans as is, text parsed like a `*_SANDBOX` variable (`false`, `0`, `f`,
14
- * `no` and `off` in any case select production; anything else means sandbox), unset means sandbox.
15
- *
16
- * @internal
17
- */
18
- export declare function parseSandbox(value: boolean | string | undefined | null): boolean;
19
- /** An integer variable, or `undefined` when unset or not an integer. @internal */
20
- export declare function envInt(env: EnvSource, key: string): number | undefined;
11
+ export declare function requireSeconds(gateway: string, key: string, value: unknown): number;
12
+ /** The variable holding the HTTP timeout of every gateway that calls an API. @internal */
13
+ export declare const HTTP_TIMEOUT_VARIABLE = "MYANMAR_PAYMENTS_HTTP_TIMEOUT";
21
14
  /** The trimmed value, or throws a {@link ConfigurationError} naming `key`. @internal */
22
15
  export declare function requireSetting(gateway: string, key: string, value: unknown): string;
23
16
  /** A trimmed optional string, `undefined` when blank. @internal */
@@ -1,9 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HTTP_TIMEOUT_VARIABLE = void 0;
3
4
  exports.envFirst = envFirst;
4
- exports.envSandbox = envSandbox;
5
- exports.parseSandbox = parseSandbox;
6
- exports.envInt = envInt;
5
+ exports.requireSeconds = requireSeconds;
7
6
  exports.requireSetting = requireSetting;
8
7
  exports.optionalSetting = optionalSetting;
9
8
  exports.trimUrl = trimUrl;
@@ -20,31 +19,29 @@ function envFirst(env, ...keys) {
20
19
  return '';
21
20
  }
22
21
  /**
23
- * Reads a `*_SANDBOX` variable. Only `false`, `0`, `f`, `no` and `off` (any case) select
24
- * production; unset or unrecognized values mean sandbox.
22
+ * A required whole number of seconds: an integer greater than 0, or text such as `'300'`. Unset
23
+ * or blank throws the missing {@link ConfigurationError}; anything else throws the invalid one.
25
24
  *
26
25
  * @internal
27
26
  */
28
- function envSandbox(env, key) {
29
- return parseSandbox(env[key] ?? '');
30
- }
31
- /**
32
- * A `sandbox` setting: booleans as is, text parsed like a `*_SANDBOX` variable (`false`, `0`, `f`,
33
- * `no` and `off` in any case select production; anything else means sandbox), unset means sandbox.
34
- *
35
- * @internal
36
- */
37
- function parseSandbox(value) {
38
- if (typeof value === 'boolean') {
39
- return value;
27
+ function requireSeconds(gateway, key, value) {
28
+ if (value === undefined || value === null || (typeof value === 'string' && value.trim() === '')) {
29
+ throw new errors_js_1.ConfigurationError(gateway, key);
40
30
  }
41
- return !['false', '0', 'f', 'no', 'off'].includes((value ?? '').trim().toLowerCase());
42
- }
43
- /** An integer variable, or `undefined` when unset or not an integer. @internal */
44
- function envInt(env, key) {
45
- const value = env[key]?.trim() ?? '';
46
- return /^[+-]?\d+$/.test(value) ? Number.parseInt(value, 10) : undefined;
31
+ let seconds;
32
+ if (typeof value === 'number' && Number.isSafeInteger(value)) {
33
+ seconds = value;
34
+ }
35
+ else if (typeof value === 'string' && /^[+-]?\d+$/.test(value.trim())) {
36
+ seconds = Number.parseInt(value.trim(), 10);
37
+ }
38
+ if (seconds === undefined || !Number.isSafeInteger(seconds) || seconds <= 0) {
39
+ throw new errors_js_1.ConfigurationError(gateway, key, true);
40
+ }
41
+ return seconds;
47
42
  }
43
+ /** The variable holding the HTTP timeout of every gateway that calls an API. @internal */
44
+ exports.HTTP_TIMEOUT_VARIABLE = 'MYANMAR_PAYMENTS_HTTP_TIMEOUT';
48
45
  /** The trimmed value, or throws a {@link ConfigurationError} naming `key`. @internal */
49
46
  function requireSetting(gateway, key, value) {
50
47
  if (typeof value !== 'string' || value.trim() === '') {
@@ -45,12 +45,17 @@ export declare class SignatureVerificationError extends PaymentError {
45
45
  constructor(message: string, raw?: Record<string, unknown>);
46
46
  }
47
47
  /**
48
- * Thrown when a gateway is missing a credential or setting it needs.
48
+ * Thrown when a gateway is missing a credential or setting it needs, or a whole-number setting
49
+ * is not a whole number greater than 0.
49
50
  */
50
51
  export declare class ConfigurationError extends PaymentError {
51
52
  /** The gateway, e.g. `kbz_pay`. */
52
53
  readonly gateway: string;
53
- /** The missing setting, e.g. `app_key`. */
54
+ /** The missing or invalid setting, e.g. `app_key`. */
54
55
  readonly key: string;
55
- constructor(gateway: string, key: string);
56
+ /**
57
+ * @param invalid `true` when the setting is set but is not a whole number greater than 0;
58
+ * `false` (the default) when it is missing.
59
+ */
60
+ constructor(gateway: string, key: string, invalid?: boolean);
56
61
  }
@@ -62,15 +62,22 @@ class SignatureVerificationError extends PaymentError {
62
62
  }
63
63
  exports.SignatureVerificationError = SignatureVerificationError;
64
64
  /**
65
- * Thrown when a gateway is missing a credential or setting it needs.
65
+ * Thrown when a gateway is missing a credential or setting it needs, or a whole-number setting
66
+ * is not a whole number greater than 0.
66
67
  */
67
68
  class ConfigurationError extends PaymentError {
68
69
  /** The gateway, e.g. `kbz_pay`. */
69
70
  gateway;
70
- /** The missing setting, e.g. `app_key`. */
71
+ /** The missing or invalid setting, e.g. `app_key`. */
71
72
  key;
72
- constructor(gateway, key) {
73
- super(`The ${gateway} configuration is missing [${key}].`);
73
+ /**
74
+ * @param invalid `true` when the setting is set but is not a whole number greater than 0;
75
+ * `false` (the default) when it is missing.
76
+ */
77
+ constructor(gateway, key, invalid = false) {
78
+ super(invalid
79
+ ? `The ${gateway} configuration [${key}] must be a whole number greater than 0.`
80
+ : `The ${gateway} configuration is missing [${key}].`);
74
81
  this.gateway = gateway;
75
82
  this.key = key;
76
83
  }
@@ -27,29 +27,28 @@ export type FetchFunction = (input: string, init: RequestInit) => Promise<Respon
27
27
  export interface FetchHttpClientOptions {
28
28
  /** The `fetch` to call; defaults to the global `fetch`. */
29
29
  fetch?: FetchFunction | undefined;
30
- /** Milliseconds before a request is aborted; defaults to 30000. `0` disables the timeout. */
31
- timeoutMs?: number | undefined;
30
+ /** Milliseconds before a request is aborted. `0` disables the timeout. */
31
+ timeoutMs: number;
32
32
  }
33
- /** The default request timeout: 30 seconds. */
34
- export declare const DEFAULT_TIMEOUT_MS = 30000;
35
33
  /**
36
- * The default {@link HttpClient}: the global `fetch` (or the one you pass) with a 30 second
37
- * timeout.
34
+ * The default {@link HttpClient}: the global `fetch` (or the one you pass) with the timeout you
35
+ * give it. Gateways build one with their `timeoutSeconds` setting when you pass no client.
38
36
  */
39
37
  export declare class FetchHttpClient implements HttpClient {
40
38
  private readonly fetchFunction;
41
39
  private readonly timeoutMs;
42
- constructor(options?: FetchHttpClientOptions);
40
+ constructor(options: FetchHttpClientOptions);
43
41
  send(request: HttpRequest): Promise<HttpResponse>;
44
42
  }
45
43
  /** Options every gateway that calls an API accepts. */
46
44
  export interface GatewayOptions {
47
- /** Sends the requests. Takes precedence over `fetch` and `timeoutMs`. */
45
+ /**
46
+ * Sends the requests, with its own timeout. Takes precedence over `fetch`. Without one, the
47
+ * gateway uses a {@link FetchHttpClient} with the config's `timeoutSeconds`.
48
+ */
48
49
  httpClient?: HttpClient | undefined;
49
50
  /** The `fetch` the default client calls, e.g. a mocked one in tests. */
50
51
  fetch?: FetchFunction | undefined;
51
- /** Milliseconds before the default client aborts a request; defaults to 30000. */
52
- timeoutMs?: number | undefined;
53
52
  }
54
53
  /** Per-call options of every network method. */
55
54
  export interface RequestOptions {
@@ -57,7 +56,7 @@ export interface RequestOptions {
57
56
  signal?: AbortSignal | undefined;
58
57
  }
59
58
  /** @internal */
60
- export declare function httpClientFrom(options?: GatewayOptions): HttpClient;
59
+ export declare function httpClientFrom(options: GatewayOptions, timeoutSeconds: number): HttpClient;
61
60
  /** A decoded gateway response. @internal */
62
61
  export declare class GatewayResponse {
63
62
  readonly status: number;
@@ -1,21 +1,19 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Transport = exports.GatewayResponse = exports.FetchHttpClient = exports.DEFAULT_TIMEOUT_MS = void 0;
3
+ exports.Transport = exports.GatewayResponse = exports.FetchHttpClient = void 0;
4
4
  exports.httpClientFrom = httpClientFrom;
5
5
  const errors_js_1 = require("./errors.js");
6
6
  const json_js_1 = require("./json.js");
7
- /** The default request timeout: 30 seconds. */
8
- exports.DEFAULT_TIMEOUT_MS = 30_000;
9
7
  /**
10
- * The default {@link HttpClient}: the global `fetch` (or the one you pass) with a 30 second
11
- * timeout.
8
+ * The default {@link HttpClient}: the global `fetch` (or the one you pass) with the timeout you
9
+ * give it. Gateways build one with their `timeoutSeconds` setting when you pass no client.
12
10
  */
13
11
  class FetchHttpClient {
14
12
  fetchFunction;
15
13
  timeoutMs;
16
- constructor(options = {}) {
14
+ constructor(options) {
17
15
  this.fetchFunction = options.fetch;
18
- this.timeoutMs = options.timeoutMs ?? exports.DEFAULT_TIMEOUT_MS;
16
+ this.timeoutMs = options.timeoutMs;
19
17
  }
20
18
  async send(request) {
21
19
  const fetchFunction = this.fetchFunction ?? globalThis.fetch;
@@ -43,9 +41,9 @@ class FetchHttpClient {
43
41
  }
44
42
  exports.FetchHttpClient = FetchHttpClient;
45
43
  /** @internal */
46
- function httpClientFrom(options = {}) {
44
+ function httpClientFrom(options, timeoutSeconds) {
47
45
  return (options.httpClient ??
48
- new FetchHttpClient({ fetch: options.fetch, timeoutMs: options.timeoutMs }));
46
+ new FetchHttpClient({ fetch: options.fetch, timeoutMs: timeoutSeconds * 1000 }));
49
47
  }
50
48
  /** A decoded gateway response. @internal */
51
49
  class GatewayResponse {
@@ -3,6 +3,6 @@ export { MemoryTokenCache, type TokenCache } from './cache.js';
3
3
  export { Acknowledgement, CallbackRequest, PaymentCallback, PaymentStatusResult, type AcknowledgementInit, type BodyInput, type CallbackRequestInit, type HeadersInput, type NodeRequestLike, type PaymentCallbackInit, type PaymentStatusResultInit, type QueryInput, type ServerResponseLike, type WebRequestLike, } from './callback.js';
4
4
  export type { EnvSource } from './env.js';
5
5
  export { ApiError, ConfigurationError, InvalidPaymentDataError, PaymentError, SignatureVerificationError, } from './errors.js';
6
- export { DEFAULT_TIMEOUT_MS, FetchHttpClient, type FetchFunction, type FetchHttpClientOptions, type GatewayOptions, type HttpClient, type HttpRequest, type HttpResponse, type RequestOptions, } from './http.js';
6
+ export { FetchHttpClient, type FetchFunction, type FetchHttpClientOptions, type GatewayOptions, type HttpClient, type HttpRequest, type HttpResponse, type RequestOptions, } from './http.js';
7
7
  export { AppPayment, FormPayment, QrPayment, RedirectPayment, type FormField, type PaymentResult, } from './results.js';
8
8
  export { PaymentFlow, PaymentStatus, resolveStatus } from './status.js';
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resolveStatus = exports.PaymentStatus = exports.PaymentFlow = exports.RedirectPayment = exports.QrPayment = exports.FormPayment = exports.AppPayment = exports.FetchHttpClient = exports.DEFAULT_TIMEOUT_MS = exports.SignatureVerificationError = exports.PaymentError = exports.InvalidPaymentDataError = exports.ConfigurationError = exports.ApiError = exports.PaymentStatusResult = exports.PaymentCallback = exports.CallbackRequest = exports.Acknowledgement = exports.MemoryTokenCache = exports.Amount = void 0;
3
+ exports.resolveStatus = exports.PaymentStatus = exports.PaymentFlow = exports.RedirectPayment = exports.QrPayment = exports.FormPayment = exports.AppPayment = exports.FetchHttpClient = exports.SignatureVerificationError = exports.PaymentError = exports.InvalidPaymentDataError = exports.ConfigurationError = exports.ApiError = exports.PaymentStatusResult = exports.PaymentCallback = exports.CallbackRequest = exports.Acknowledgement = exports.MemoryTokenCache = exports.Amount = void 0;
4
4
  var amount_js_1 = require("./amount.js");
5
5
  Object.defineProperty(exports, "Amount", { enumerable: true, get: function () { return amount_js_1.Amount; } });
6
6
  var cache_js_1 = require("./cache.js");
@@ -17,7 +17,6 @@ Object.defineProperty(exports, "InvalidPaymentDataError", { enumerable: true, ge
17
17
  Object.defineProperty(exports, "PaymentError", { enumerable: true, get: function () { return errors_js_1.PaymentError; } });
18
18
  Object.defineProperty(exports, "SignatureVerificationError", { enumerable: true, get: function () { return errors_js_1.SignatureVerificationError; } });
19
19
  var http_js_1 = require("./http.js");
20
- Object.defineProperty(exports, "DEFAULT_TIMEOUT_MS", { enumerable: true, get: function () { return http_js_1.DEFAULT_TIMEOUT_MS; } });
21
20
  Object.defineProperty(exports, "FetchHttpClient", { enumerable: true, get: function () { return http_js_1.FetchHttpClient; } });
22
21
  var results_js_1 = require("./results.js");
23
22
  Object.defineProperty(exports, "AppPayment", { enumerable: true, get: function () { return results_js_1.AppPayment; } });
@@ -10,30 +10,24 @@ export interface CyberSourceConfigOptions {
10
10
  accessKey: string;
11
11
  /** The profile's secret key, which signs the fields. */
12
12
  secretKey: string;
13
- /**
14
- * Use the test environment (default `true`).
15
- * Text is read like a `*_SANDBOX` variable: `false`, `0`, `f`, `no` or `off` select production.
16
- */
17
- sandbox?: boolean | string | undefined;
18
- /** Overrides the Secure Acceptance base URL. */
13
+ /** Overrides the Secure Acceptance base URL, e.g. to point at the test environment. */
19
14
  baseUrl?: string | undefined;
20
15
  }
21
16
  /**
22
- * A CyberSource Secure Acceptance profile. A missing credential throws a `ConfigurationError`.
17
+ * A CyberSource Secure Acceptance profile. A missing credential throws a `ConfigurationError`. The
18
+ * URL defaults to production.
23
19
  */
24
20
  export declare class CyberSourceConfig {
25
- static readonly SANDBOX_URL = "https://testsecureacceptance.cybersource.com";
26
21
  static readonly PRODUCTION_URL = "https://secureacceptance.cybersource.com";
27
22
  readonly profileId: string;
28
23
  readonly accessKey: string;
29
24
  readonly secretKey: string;
30
- readonly sandbox: boolean;
31
25
  /** The base URL in use. */
32
26
  readonly baseUrl: string;
33
27
  constructor(options: CyberSourceConfigOptions);
34
28
  /**
35
29
  * Reads `CYBER_SOURCE_PROFILE_ID`, `CYBER_SOURCE_ACCESS_KEY`, `CYBER_SOURCE_SECRET_KEY`,
36
- * `CYBER_SOURCE_SANDBOX` and `CYBER_SOURCE_BASE_URL`.
30
+ * and `CYBER_SOURCE_BASE_URL`.
37
31
  */
38
32
  static fromEnv(env?: EnvSource): CyberSourceConfig;
39
33
  }
@@ -64,12 +58,12 @@ export interface CyberSourcePaymentData {
64
58
  returnUrl?: string | undefined;
65
59
  /** The page shown on cancel (`override_custom_cancel_page`), at most 255 characters. */
66
60
  cancelUrl?: string | undefined;
67
- /** An ISO 4217 code (default `MMK`). */
68
- currency?: string | undefined;
69
- /** What to do with the card (default `sale`). */
70
- transactionType?: CyberSourceTransactionType | undefined;
71
- /** The hosted page language, e.g. `en-us` (the default). */
72
- locale?: string | undefined;
61
+ /** An ISO 4217 code, e.g. `MMK`. */
62
+ currency: string;
63
+ /** What to do with the card, e.g. `sale`. */
64
+ transactionType: CyberSourceTransactionType;
65
+ /** The hosted page language, e.g. `en-us`. */
66
+ locale: string;
73
67
  }
74
68
  /**
75
69
  * CyberSource Secure Acceptance hosted checkout for card payments: signs the form and verifies the
@@ -11,35 +11,31 @@ const status_js_1 = require("../core/status.js");
11
11
  const validate_js_1 = require("../core/validate.js");
12
12
  const values_js_1 = require("../core/values.js");
13
13
  /**
14
- * A CyberSource Secure Acceptance profile. A missing credential throws a `ConfigurationError`.
14
+ * A CyberSource Secure Acceptance profile. A missing credential throws a `ConfigurationError`. The
15
+ * URL defaults to production.
15
16
  */
16
17
  class CyberSourceConfig {
17
- static SANDBOX_URL = 'https://testsecureacceptance.cybersource.com';
18
18
  static PRODUCTION_URL = 'https://secureacceptance.cybersource.com';
19
19
  profileId;
20
20
  accessKey;
21
21
  secretKey;
22
- sandbox;
23
22
  /** The base URL in use. */
24
23
  baseUrl;
25
24
  constructor(options) {
26
25
  this.profileId = (0, env_js_1.requireSetting)('cyber_source', 'profile_id', options.profileId);
27
26
  this.accessKey = (0, env_js_1.requireSetting)('cyber_source', 'access_key', options.accessKey);
28
27
  this.secretKey = (0, env_js_1.requireSetting)('cyber_source', 'secret_key', options.secretKey);
29
- this.sandbox = (0, env_js_1.parseSandbox)(options.sandbox);
30
- this.baseUrl = (0, env_js_1.trimUrl)((0, env_js_1.optionalSetting)(options.baseUrl) ??
31
- (this.sandbox ? CyberSourceConfig.SANDBOX_URL : CyberSourceConfig.PRODUCTION_URL));
28
+ this.baseUrl = (0, env_js_1.trimUrl)((0, env_js_1.optionalSetting)(options.baseUrl) ?? CyberSourceConfig.PRODUCTION_URL);
32
29
  }
33
30
  /**
34
31
  * Reads `CYBER_SOURCE_PROFILE_ID`, `CYBER_SOURCE_ACCESS_KEY`, `CYBER_SOURCE_SECRET_KEY`,
35
- * `CYBER_SOURCE_SANDBOX` and `CYBER_SOURCE_BASE_URL`.
32
+ * and `CYBER_SOURCE_BASE_URL`.
36
33
  */
37
34
  static fromEnv(env = (0, env_js_1.defaultEnv)()) {
38
35
  return new CyberSourceConfig({
39
36
  profileId: (0, env_js_1.envFirst)(env, 'CYBER_SOURCE_PROFILE_ID'),
40
37
  accessKey: (0, env_js_1.envFirst)(env, 'CYBER_SOURCE_ACCESS_KEY'),
41
38
  secretKey: (0, env_js_1.envFirst)(env, 'CYBER_SOURCE_SECRET_KEY'),
42
- sandbox: (0, env_js_1.envSandbox)(env, 'CYBER_SOURCE_SANDBOX'),
43
39
  baseUrl: (0, env_js_1.envFirst)(env, 'CYBER_SOURCE_BASE_URL'),
44
40
  });
45
41
  }
@@ -113,9 +109,12 @@ class CyberSource {
113
109
  .string('cancelUrl', data.cancelUrl)
114
110
  .url('cancelUrl', data.cancelUrl)
115
111
  .max('cancelUrl', data.cancelUrl, 255)
116
- .pattern('currency', String(data.currency || 'MMK'), /^[A-Z]{3}$/, 'a three letter ISO 4217 code')
117
- .pattern('locale', String(data.locale || 'en-us'), /^[a-z]{2}-[a-z]{2}$/, 'a locale code such as en-us')
118
- .when(!TRANSACTION_TYPES.includes(String(data.transactionType || 'sale')), 'transactionType', 'The transactionType field is not a supported transaction type.')
112
+ .required('currency', data.currency)
113
+ .pattern('currency', data.currency, /^[A-Z]{3}$/, 'a three letter ISO 4217 code')
114
+ .required('transactionType', data.transactionType)
115
+ .when(!TRANSACTION_TYPES.includes(String(data.transactionType)), 'transactionType', 'The transactionType field is not a supported transaction type.')
116
+ .required('locale', data.locale)
117
+ .pattern('locale', data.locale, /^[a-z]{2}-[a-z]{2}$/, 'a locale code such as en-us')
119
118
  .validate();
120
119
  }
121
120
  /**
@@ -130,11 +129,11 @@ class CyberSource {
130
129
  transaction_uuid: (0, crypto_js_1.randomHex)(),
131
130
  signed_field_names: SIGNED_FIELDS.join(','),
132
131
  signed_date_time: new Date().toISOString().replace(/\.\d{3}Z$/, 'Z'),
133
- locale: data.locale || 'en-us',
134
- transaction_type: data.transactionType || 'sale',
132
+ locale: data.locale,
133
+ transaction_type: data.transactionType,
135
134
  reference_number: data.orderId,
136
135
  amount: String((0, validate_js_1.toAmount)(data.amount)),
137
- currency: data.currency || 'MMK',
136
+ currency: data.currency,
138
137
  override_custom_receipt_page: data.returnUrl ?? '',
139
138
  override_backoffice_post_url: data.callbackUrl,
140
139
  override_custom_cancel_page: data.cancelUrl ?? '',
@@ -13,36 +13,35 @@ export interface KbzPayConfigOptions {
13
13
  /** The `merch_code` KBZ issued. */
14
14
  merchantCode: string;
15
15
  /**
16
- * Use the UAT endpoints (default `true`). UAT and production issue separate
17
- * credentials. Text is read like a `*_SANDBOX` variable: `false`, `0`, `f`, `no` or `off`
18
- * select production.
16
+ * Seconds before the default HTTP client gives up on a request, a whole number greater than 0
17
+ * (or its text). A client you pass keeps its own timeout.
19
18
  */
20
- sandbox?: boolean | string | undefined;
21
- /** Overrides the API base URL, e.g. to go through a proxy. */
19
+ timeoutSeconds: number | string;
20
+ /** Overrides the API base URL, e.g. to point at UAT or go through a proxy. */
22
21
  apiUrl?: string | undefined;
23
22
  /** Overrides the PWA checkout URL. A trailing `#` or `#/` is normalized to `#/`. */
24
23
  pwaUrl?: string | undefined;
25
24
  }
26
25
  /**
27
- * KBZ Pay credentials and endpoints. A missing credential throws a `ConfigurationError`.
26
+ * KBZ Pay credentials and endpoints. A missing setting throws a `ConfigurationError`. The URLs
27
+ * default to production; UAT and production issue separate credentials.
28
28
  */
29
29
  export declare class KbzPayConfig {
30
- static readonly SANDBOX_API_URL = "http://api-uat.kbzpay.com/payment/gateway/uat";
31
30
  static readonly PRODUCTION_API_URL = "https://api.kbzpay.com/payment/gateway";
32
- static readonly SANDBOX_PWA_URL = "https://static.kbzpay.com/pgw/uat/pwa/#/";
33
31
  static readonly PRODUCTION_PWA_URL = "https://wap.kbzpay.com/pgw/pwa/#/";
34
32
  readonly appId: string;
35
33
  readonly appKey: string;
36
34
  readonly merchantCode: string;
37
- readonly sandbox: boolean;
35
+ /** Seconds before the default HTTP client gives up on a request. */
36
+ readonly timeoutSeconds: number;
38
37
  /** The API base URL in use. */
39
38
  readonly apiUrl: string;
40
39
  /** The PWA checkout URL in use, always ending in `/`. */
41
40
  readonly pwaUrl: string;
42
41
  constructor(options: KbzPayConfigOptions);
43
42
  /**
44
- * Reads `KBZ_PAY_APP_ID`, `KBZ_PAY_APP_KEY`, `KBZ_PAY_MERCHANT_CODE`, `KBZ_PAY_SANDBOX`,
45
- * `KBZ_PAY_BASE_URL` and `KBZ_PAY_PWA_BASE_REDIRECT_URL`.
43
+ * Reads `KBZ_PAY_APP_ID`, `KBZ_PAY_APP_KEY`, `KBZ_PAY_MERCHANT_CODE`,
44
+ * `MYANMAR_PAYMENTS_HTTP_TIMEOUT`, `KBZ_PAY_BASE_URL` and `KBZ_PAY_PWA_BASE_REDIRECT_URL`.
46
45
  */
47
46
  static fromEnv(env?: EnvSource): KbzPayConfig;
48
47
  }
@@ -13,17 +13,17 @@ const validate_js_1 = require("../core/validate.js");
13
13
  const values_js_1 = require("../core/values.js");
14
14
  const signer_js_1 = require("./signer.js");
15
15
  /**
16
- * KBZ Pay credentials and endpoints. A missing credential throws a `ConfigurationError`.
16
+ * KBZ Pay credentials and endpoints. A missing setting throws a `ConfigurationError`. The URLs
17
+ * default to production; UAT and production issue separate credentials.
17
18
  */
18
19
  class KbzPayConfig {
19
- static SANDBOX_API_URL = 'http://api-uat.kbzpay.com/payment/gateway/uat';
20
20
  static PRODUCTION_API_URL = 'https://api.kbzpay.com/payment/gateway';
21
- static SANDBOX_PWA_URL = 'https://static.kbzpay.com/pgw/uat/pwa/#/';
22
21
  static PRODUCTION_PWA_URL = 'https://wap.kbzpay.com/pgw/pwa/#/';
23
22
  appId;
24
23
  appKey;
25
24
  merchantCode;
26
- sandbox;
25
+ /** Seconds before the default HTTP client gives up on a request. */
26
+ timeoutSeconds;
27
27
  /** The API base URL in use. */
28
28
  apiUrl;
29
29
  /** The PWA checkout URL in use, always ending in `/`. */
@@ -32,22 +32,20 @@ class KbzPayConfig {
32
32
  this.appId = (0, env_js_1.requireSetting)('kbz_pay', 'app_id', options.appId);
33
33
  this.appKey = (0, env_js_1.requireSetting)('kbz_pay', 'app_key', options.appKey);
34
34
  this.merchantCode = (0, env_js_1.requireSetting)('kbz_pay', 'merchant_code', options.merchantCode);
35
- this.sandbox = (0, env_js_1.parseSandbox)(options.sandbox);
36
- this.apiUrl = (0, env_js_1.trimUrl)((0, env_js_1.optionalSetting)(options.apiUrl) ??
37
- (this.sandbox ? KbzPayConfig.SANDBOX_API_URL : KbzPayConfig.PRODUCTION_API_URL));
38
- this.pwaUrl = `${(0, env_js_1.trimUrl)((0, env_js_1.optionalSetting)(options.pwaUrl) ??
39
- (this.sandbox ? KbzPayConfig.SANDBOX_PWA_URL : KbzPayConfig.PRODUCTION_PWA_URL))}/`;
35
+ this.timeoutSeconds = (0, env_js_1.requireSeconds)('kbz_pay', 'timeout_in_seconds', options.timeoutSeconds);
36
+ this.apiUrl = (0, env_js_1.trimUrl)((0, env_js_1.optionalSetting)(options.apiUrl) ?? KbzPayConfig.PRODUCTION_API_URL);
37
+ this.pwaUrl = `${(0, env_js_1.trimUrl)((0, env_js_1.optionalSetting)(options.pwaUrl) ?? KbzPayConfig.PRODUCTION_PWA_URL)}/`;
40
38
  }
41
39
  /**
42
- * Reads `KBZ_PAY_APP_ID`, `KBZ_PAY_APP_KEY`, `KBZ_PAY_MERCHANT_CODE`, `KBZ_PAY_SANDBOX`,
43
- * `KBZ_PAY_BASE_URL` and `KBZ_PAY_PWA_BASE_REDIRECT_URL`.
40
+ * Reads `KBZ_PAY_APP_ID`, `KBZ_PAY_APP_KEY`, `KBZ_PAY_MERCHANT_CODE`,
41
+ * `MYANMAR_PAYMENTS_HTTP_TIMEOUT`, `KBZ_PAY_BASE_URL` and `KBZ_PAY_PWA_BASE_REDIRECT_URL`.
44
42
  */
45
43
  static fromEnv(env = (0, env_js_1.defaultEnv)()) {
46
44
  return new KbzPayConfig({
47
45
  appId: (0, env_js_1.envFirst)(env, 'KBZ_PAY_APP_ID'),
48
46
  appKey: (0, env_js_1.envFirst)(env, 'KBZ_PAY_APP_KEY'),
49
47
  merchantCode: (0, env_js_1.envFirst)(env, 'KBZ_PAY_MERCHANT_CODE'),
50
- sandbox: (0, env_js_1.envSandbox)(env, 'KBZ_PAY_SANDBOX'),
48
+ timeoutSeconds: (0, env_js_1.envFirst)(env, env_js_1.HTTP_TIMEOUT_VARIABLE),
51
49
  apiUrl: (0, env_js_1.envFirst)(env, 'KBZ_PAY_BASE_URL'),
52
50
  pwaUrl: (0, env_js_1.envFirst)(env, 'KBZ_PAY_PWA_BASE_REDIRECT_URL'),
53
51
  });
@@ -76,7 +74,7 @@ class KbzPay {
76
74
  constructor(config, options = {}) {
77
75
  this.config = config instanceof KbzPayConfig ? config : new KbzPayConfig(config);
78
76
  this.signer = new signer_js_1.KbzPaySigner(this.config.appKey);
79
- this.transport = new http_js_1.Transport((0, http_js_1.httpClientFrom)(options));
77
+ this.transport = new http_js_1.Transport((0, http_js_1.httpClientFrom)(options, this.config.timeoutSeconds));
80
78
  }
81
79
  /** A gateway configured from the `KBZ_PAY_*` environment variables. */
82
80
  static fromEnv(env = (0, env_js_1.defaultEnv)(), options = {}) {