@laranex/myanmar-payments 4.0.0-dev.3 → 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 (63) hide show
  1. package/CHANGELOG.md +10 -3
  2. package/dist/cjs/aya-pay/aya-pay.d.ts +12 -9
  3. package/dist/cjs/aya-pay/aya-pay.js +14 -11
  4. package/dist/cjs/core/amount.d.ts +4 -3
  5. package/dist/cjs/core/amount.js +13 -4
  6. package/dist/cjs/core/callback.d.ts +7 -2
  7. package/dist/cjs/core/callback.js +14 -7
  8. package/dist/cjs/core/crypto.d.ts +6 -1
  9. package/dist/cjs/core/crypto.js +17 -3
  10. package/dist/cjs/core/env.d.ts +5 -5
  11. package/dist/cjs/core/env.js +21 -12
  12. package/dist/cjs/core/errors.d.ts +8 -3
  13. package/dist/cjs/core/errors.js +11 -4
  14. package/dist/cjs/core/http.d.ts +10 -11
  15. package/dist/cjs/core/http.js +7 -9
  16. package/dist/cjs/core/index.d.ts +1 -1
  17. package/dist/cjs/core/index.js +1 -2
  18. package/dist/cjs/core/json.d.ts +2 -2
  19. package/dist/cjs/core/json.js +3 -3
  20. package/dist/cjs/core/values.d.ts +2 -0
  21. package/dist/cjs/core/values.js +5 -0
  22. package/dist/cjs/cyber-source/cyber-source.d.ts +10 -13
  23. package/dist/cjs/cyber-source/cyber-source.js +13 -14
  24. package/dist/cjs/kbz-pay/kbz-pay.d.ts +12 -9
  25. package/dist/cjs/kbz-pay/kbz-pay.js +11 -13
  26. package/dist/cjs/kbz-pay/signer.d.ts +4 -1
  27. package/dist/cjs/kbz-pay/signer.js +7 -2
  28. package/dist/cjs/wave-money/wave-money.d.ts +15 -13
  29. package/dist/cjs/wave-money/wave-money.js +18 -25
  30. package/dist/cjs/yoma-mmqr/yoma-mmqr.d.ts +16 -13
  31. package/dist/cjs/yoma-mmqr/yoma-mmqr.js +21 -19
  32. package/dist/esm/aya-pay/aya-pay.d.ts +12 -9
  33. package/dist/esm/aya-pay/aya-pay.js +16 -13
  34. package/dist/esm/core/amount.d.ts +4 -3
  35. package/dist/esm/core/amount.js +13 -4
  36. package/dist/esm/core/callback.d.ts +7 -2
  37. package/dist/esm/core/callback.js +14 -7
  38. package/dist/esm/core/crypto.d.ts +6 -1
  39. package/dist/esm/core/crypto.js +17 -3
  40. package/dist/esm/core/env.d.ts +5 -5
  41. package/dist/esm/core/env.js +19 -10
  42. package/dist/esm/core/errors.d.ts +8 -3
  43. package/dist/esm/core/errors.js +11 -4
  44. package/dist/esm/core/http.d.ts +10 -11
  45. package/dist/esm/core/http.js +6 -8
  46. package/dist/esm/core/index.d.ts +1 -1
  47. package/dist/esm/core/index.js +1 -1
  48. package/dist/esm/core/json.d.ts +2 -2
  49. package/dist/esm/core/json.js +3 -3
  50. package/dist/esm/core/values.d.ts +2 -0
  51. package/dist/esm/core/values.js +4 -0
  52. package/dist/esm/cyber-source/cyber-source.d.ts +10 -13
  53. package/dist/esm/cyber-source/cyber-source.js +14 -15
  54. package/dist/esm/kbz-pay/kbz-pay.d.ts +12 -9
  55. package/dist/esm/kbz-pay/kbz-pay.js +12 -14
  56. package/dist/esm/kbz-pay/signer.d.ts +4 -1
  57. package/dist/esm/kbz-pay/signer.js +8 -3
  58. package/dist/esm/wave-money/wave-money.d.ts +15 -13
  59. package/dist/esm/wave-money/wave-money.js +20 -27
  60. package/dist/esm/yoma-mmqr/yoma-mmqr.d.ts +16 -13
  61. package/dist/esm/yoma-mmqr/yoma-mmqr.js +23 -21
  62. package/package.json +1 -1
  63. package/skills/node-myanmar-payments/SKILL.md +24 -21
@@ -10,27 +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
- /** Use the test environment (default `true`). */
14
- sandbox?: boolean | undefined;
15
- /** Overrides the Secure Acceptance base URL. */
13
+ /** Overrides the Secure Acceptance base URL, e.g. to point at the test environment. */
16
14
  baseUrl?: string | undefined;
17
15
  }
18
16
  /**
19
- * 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.
20
19
  */
21
20
  export declare class CyberSourceConfig {
22
- static readonly SANDBOX_URL = "https://testsecureacceptance.cybersource.com";
23
21
  static readonly PRODUCTION_URL = "https://secureacceptance.cybersource.com";
24
22
  readonly profileId: string;
25
23
  readonly accessKey: string;
26
24
  readonly secretKey: string;
27
- readonly sandbox: boolean;
28
25
  /** The base URL in use. */
29
26
  readonly baseUrl: string;
30
27
  constructor(options: CyberSourceConfigOptions);
31
28
  /**
32
29
  * Reads `CYBER_SOURCE_PROFILE_ID`, `CYBER_SOURCE_ACCESS_KEY`, `CYBER_SOURCE_SECRET_KEY`,
33
- * `CYBER_SOURCE_SANDBOX` and `CYBER_SOURCE_BASE_URL`.
30
+ * and `CYBER_SOURCE_BASE_URL`.
34
31
  */
35
32
  static fromEnv(env?: EnvSource): CyberSourceConfig;
36
33
  }
@@ -61,12 +58,12 @@ export interface CyberSourcePaymentData {
61
58
  returnUrl?: string | undefined;
62
59
  /** The page shown on cancel (`override_custom_cancel_page`), at most 255 characters. */
63
60
  cancelUrl?: string | undefined;
64
- /** An ISO 4217 code (default `MMK`). */
65
- currency?: string | undefined;
66
- /** What to do with the card (default `sale`). */
67
- transactionType?: CyberSourceTransactionType | undefined;
68
- /** The hosted page language, e.g. `en-us` (the default). */
69
- 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;
70
67
  }
71
68
  /**
72
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 = options.sandbox ?? true;
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 ?? '',
@@ -12,33 +12,36 @@ export interface KbzPayConfigOptions {
12
12
  appKey: string;
13
13
  /** The `merch_code` KBZ issued. */
14
14
  merchantCode: string;
15
- /** Use the UAT endpoints (default `true`). UAT and production issue separate credentials. */
16
- sandbox?: boolean | undefined;
17
- /** Overrides the API base URL, e.g. to go through a proxy. */
15
+ /**
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.
18
+ */
19
+ timeoutSeconds: number | string;
20
+ /** Overrides the API base URL, e.g. to point at UAT or go through a proxy. */
18
21
  apiUrl?: string | undefined;
19
22
  /** Overrides the PWA checkout URL. A trailing `#` or `#/` is normalized to `#/`. */
20
23
  pwaUrl?: string | undefined;
21
24
  }
22
25
  /**
23
- * 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.
24
28
  */
25
29
  export declare class KbzPayConfig {
26
- static readonly SANDBOX_API_URL = "http://api-uat.kbzpay.com/payment/gateway/uat";
27
30
  static readonly PRODUCTION_API_URL = "https://api.kbzpay.com/payment/gateway";
28
- static readonly SANDBOX_PWA_URL = "https://static.kbzpay.com/pgw/uat/pwa/#/";
29
31
  static readonly PRODUCTION_PWA_URL = "https://wap.kbzpay.com/pgw/pwa/#/";
30
32
  readonly appId: string;
31
33
  readonly appKey: string;
32
34
  readonly merchantCode: string;
33
- readonly sandbox: boolean;
35
+ /** Seconds before the default HTTP client gives up on a request. */
36
+ readonly timeoutSeconds: number;
34
37
  /** The API base URL in use. */
35
38
  readonly apiUrl: string;
36
39
  /** The PWA checkout URL in use, always ending in `/`. */
37
40
  readonly pwaUrl: string;
38
41
  constructor(options: KbzPayConfigOptions);
39
42
  /**
40
- * Reads `KBZ_PAY_APP_ID`, `KBZ_PAY_APP_KEY`, `KBZ_PAY_MERCHANT_CODE`, `KBZ_PAY_SANDBOX`,
41
- * `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`.
42
45
  */
43
46
  static fromEnv(env?: EnvSource): KbzPayConfig;
44
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 = options.sandbox ?? true;
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 = {}) {
@@ -10,6 +10,9 @@ export declare class KbzPaySigner {
10
10
  signString(fields: Readonly<Record<string, unknown>>): string;
11
11
  /** The uppercase SHA-256 signature of `fields`. */
12
12
  sign(fields: Readonly<Record<string, unknown>>): string;
13
- /** Whether `fields.sign` matches, compared in constant time. */
13
+ /**
14
+ * Whether `fields.sign` matches, compared in constant time. Nested values are never signed, so
15
+ * fields holding an object or array fail rather than being partly trusted.
16
+ */
14
17
  verify(fields: Readonly<Record<string, unknown>>): boolean;
15
18
  }
@@ -27,10 +27,15 @@ class KbzPaySigner {
27
27
  sign(fields) {
28
28
  return (0, crypto_js_1.sha256Hex)(`${this.signString(fields)}&key=${this.appKey}`).toUpperCase();
29
29
  }
30
- /** Whether `fields.sign` matches, compared in constant time. */
30
+ /**
31
+ * Whether `fields.sign` matches, compared in constant time. Nested values are never signed, so
32
+ * fields holding an object or array fail rather than being partly trusted.
33
+ */
31
34
  verify(fields) {
32
35
  const sign = fields.sign;
33
- return typeof sign === 'string' && (0, crypto_js_1.safeEqual)(this.sign(fields), sign.toUpperCase());
36
+ return (typeof sign === 'string' &&
37
+ !Object.values(fields).some(values_js_1.isNested) &&
38
+ (0, crypto_js_1.safeEqual)(this.sign(fields), sign.toUpperCase()));
34
39
  }
35
40
  }
36
41
  exports.KbzPaySigner = KbzPaySigner;
@@ -11,38 +11,40 @@ export interface WaveMoneyConfigOptions {
11
11
  secretKey: string;
12
12
  /** Your business name, shown on Wave's payment page. */
13
13
  merchantName: string;
14
- /** How long the customer has to pay, in seconds (default 300). */
15
- timeToLiveSeconds?: number | undefined;
16
- /** Use the test environment (default `true`). */
17
- sandbox?: boolean | undefined;
18
- /** Overrides the API base URL. */
14
+ /** How long the customer has to pay, in seconds: a whole number greater than 0 (or its text). */
15
+ timeToLiveSeconds: number | string;
16
+ /**
17
+ * Seconds before the default HTTP client gives up on a request, a whole number greater than 0
18
+ * (or its text). A client you pass keeps its own timeout.
19
+ */
20
+ timeoutSeconds: number | string;
21
+ /** Overrides the API base URL, e.g. to point at UAT. */
19
22
  baseUrl?: string | undefined;
20
23
  /** Overrides the host the customer is redirected to. Wave serves it without the API port. */
21
24
  authenticateUrl?: string | undefined;
22
25
  }
23
26
  /**
24
- * Wave Money credentials and endpoints. A missing credential throws a `ConfigurationError`.
27
+ * Wave Money credentials and endpoints. A missing setting throws a `ConfigurationError`. The URLs
28
+ * default to production.
25
29
  */
26
30
  export declare class WaveMoneyConfig {
27
- static readonly SANDBOX_URL = "https://preprodpayments.wavemoney.io:8107";
28
31
  static readonly PRODUCTION_URL = "https://payments.wavemoney.io";
29
- static readonly SANDBOX_AUTHENTICATE_URL = "https://preprodpayments.wavemoney.io";
30
32
  static readonly PRODUCTION_AUTHENTICATE_URL = "https://payments.wavemoney.io";
31
- static readonly DEFAULT_TIME_TO_LIVE_SECONDS = 300;
32
33
  readonly merchantId: string;
33
34
  readonly secretKey: string;
34
35
  readonly merchantName: string;
35
36
  /** Seconds the customer has to pay. */
36
37
  readonly timeToLiveSeconds: number;
37
- readonly sandbox: boolean;
38
+ /** Seconds before the default HTTP client gives up on a request. */
39
+ readonly timeoutSeconds: number;
38
40
  /** The API base URL in use. */
39
41
  readonly baseUrl: string;
40
42
  /** The host the customer is redirected to. */
41
43
  readonly authenticateUrl: string;
42
44
  constructor(options: WaveMoneyConfigOptions);
43
45
  /**
44
- * Reads `WAVE_MONEY_MERCHANT_ID`, `WAVE_MONEY_SECRET_KEY`, `WAVE_MONEY_MERCHANT_NAME` (falling back
45
- * to `APP_NAME`), `WAVE_MONEY_TIME_TO_LIVE_IN_SECONDS`, `WAVE_MONEY_SANDBOX`, `WAVE_MONEY_BASE_URL`
46
+ * Reads `WAVE_MONEY_MERCHANT_ID`, `WAVE_MONEY_SECRET_KEY`, `WAVE_MONEY_MERCHANT_NAME`,
47
+ * `WAVE_MONEY_TIME_TO_LIVE_IN_SECONDS`, `MYANMAR_PAYMENTS_HTTP_TIMEOUT`, `WAVE_MONEY_BASE_URL`
46
48
  * and `WAVE_MONEY_AUTHENTICATE_URL`.
47
49
  */
48
50
  static fromEnv(env?: EnvSource): WaveMoneyConfig;
@@ -104,7 +106,7 @@ export declare class WaveMoney {
104
106
  /**
105
107
  * Verifies Wave's callback. Only `PAYMENT_CONFIRMED` means the customer paid. `orderId` falls
106
108
  * back to `merchantReferenceId` when it is missing, null or empty, because Wave marks `orderId` as
107
- * optional.
109
+ * optional. A hashed field holding an object or array fails verification.
108
110
  */
109
111
  handleCallback(request: CallbackRequest): PaymentCallback;
110
112
  private hash;
@@ -13,20 +13,19 @@ const status_js_1 = require("../core/status.js");
13
13
  const validate_js_1 = require("../core/validate.js");
14
14
  const values_js_1 = require("../core/values.js");
15
15
  /**
16
- * Wave Money credentials and endpoints. A missing credential throws a `ConfigurationError`.
16
+ * Wave Money credentials and endpoints. A missing setting throws a `ConfigurationError`. The URLs
17
+ * default to production.
17
18
  */
18
19
  class WaveMoneyConfig {
19
- static SANDBOX_URL = 'https://preprodpayments.wavemoney.io:8107';
20
20
  static PRODUCTION_URL = 'https://payments.wavemoney.io';
21
- static SANDBOX_AUTHENTICATE_URL = 'https://preprodpayments.wavemoney.io';
22
21
  static PRODUCTION_AUTHENTICATE_URL = 'https://payments.wavemoney.io';
23
- static DEFAULT_TIME_TO_LIVE_SECONDS = 300;
24
22
  merchantId;
25
23
  secretKey;
26
24
  merchantName;
27
25
  /** Seconds the customer has to pay. */
28
26
  timeToLiveSeconds;
29
- sandbox;
27
+ /** Seconds before the default HTTP client gives up on a request. */
28
+ timeoutSeconds;
30
29
  /** The API base URL in use. */
31
30
  baseUrl;
32
31
  /** The host the customer is redirected to. */
@@ -35,31 +34,23 @@ class WaveMoneyConfig {
35
34
  this.merchantId = (0, env_js_1.requireSetting)('wave_money', 'merchant_id', options.merchantId);
36
35
  this.secretKey = (0, env_js_1.requireSetting)('wave_money', 'secret_key', options.secretKey);
37
36
  this.merchantName = (0, env_js_1.requireSetting)('wave_money', 'merchant_name', options.merchantName);
38
- const ttl = options.timeToLiveSeconds;
39
- this.timeToLiveSeconds =
40
- ttl !== undefined && Number.isInteger(ttl) && ttl > 0
41
- ? ttl
42
- : WaveMoneyConfig.DEFAULT_TIME_TO_LIVE_SECONDS;
43
- this.sandbox = options.sandbox ?? true;
44
- this.baseUrl = (0, env_js_1.trimUrl)((0, env_js_1.optionalSetting)(options.baseUrl) ??
45
- (this.sandbox ? WaveMoneyConfig.SANDBOX_URL : WaveMoneyConfig.PRODUCTION_URL));
46
- this.authenticateUrl = (0, env_js_1.trimUrl)((0, env_js_1.optionalSetting)(options.authenticateUrl) ??
47
- (this.sandbox
48
- ? WaveMoneyConfig.SANDBOX_AUTHENTICATE_URL
49
- : WaveMoneyConfig.PRODUCTION_AUTHENTICATE_URL));
37
+ this.timeToLiveSeconds = (0, env_js_1.requireSeconds)('wave_money', 'time_to_live_in_seconds', options.timeToLiveSeconds);
38
+ this.timeoutSeconds = (0, env_js_1.requireSeconds)('wave_money', 'timeout_in_seconds', options.timeoutSeconds);
39
+ this.baseUrl = (0, env_js_1.trimUrl)((0, env_js_1.optionalSetting)(options.baseUrl) ?? WaveMoneyConfig.PRODUCTION_URL);
40
+ this.authenticateUrl = (0, env_js_1.trimUrl)((0, env_js_1.optionalSetting)(options.authenticateUrl) ?? WaveMoneyConfig.PRODUCTION_AUTHENTICATE_URL);
50
41
  }
51
42
  /**
52
- * Reads `WAVE_MONEY_MERCHANT_ID`, `WAVE_MONEY_SECRET_KEY`, `WAVE_MONEY_MERCHANT_NAME` (falling back
53
- * to `APP_NAME`), `WAVE_MONEY_TIME_TO_LIVE_IN_SECONDS`, `WAVE_MONEY_SANDBOX`, `WAVE_MONEY_BASE_URL`
43
+ * Reads `WAVE_MONEY_MERCHANT_ID`, `WAVE_MONEY_SECRET_KEY`, `WAVE_MONEY_MERCHANT_NAME`,
44
+ * `WAVE_MONEY_TIME_TO_LIVE_IN_SECONDS`, `MYANMAR_PAYMENTS_HTTP_TIMEOUT`, `WAVE_MONEY_BASE_URL`
54
45
  * and `WAVE_MONEY_AUTHENTICATE_URL`.
55
46
  */
56
47
  static fromEnv(env = (0, env_js_1.defaultEnv)()) {
57
48
  return new WaveMoneyConfig({
58
49
  merchantId: (0, env_js_1.envFirst)(env, 'WAVE_MONEY_MERCHANT_ID'),
59
50
  secretKey: (0, env_js_1.envFirst)(env, 'WAVE_MONEY_SECRET_KEY'),
60
- merchantName: (0, env_js_1.envFirst)(env, 'WAVE_MONEY_MERCHANT_NAME', 'APP_NAME'),
61
- timeToLiveSeconds: (0, env_js_1.envInt)(env, 'WAVE_MONEY_TIME_TO_LIVE_IN_SECONDS'),
62
- sandbox: (0, env_js_1.envSandbox)(env, 'WAVE_MONEY_SANDBOX'),
51
+ merchantName: (0, env_js_1.envFirst)(env, 'WAVE_MONEY_MERCHANT_NAME'),
52
+ timeToLiveSeconds: (0, env_js_1.envFirst)(env, 'WAVE_MONEY_TIME_TO_LIVE_IN_SECONDS'),
53
+ timeoutSeconds: (0, env_js_1.envFirst)(env, env_js_1.HTTP_TIMEOUT_VARIABLE),
63
54
  baseUrl: (0, env_js_1.envFirst)(env, 'WAVE_MONEY_BASE_URL'),
64
55
  authenticateUrl: (0, env_js_1.envFirst)(env, 'WAVE_MONEY_AUTHENTICATE_URL'),
65
56
  });
@@ -98,7 +89,7 @@ class WaveMoney {
98
89
  transport;
99
90
  constructor(config, options = {}) {
100
91
  this.config = config instanceof WaveMoneyConfig ? config : new WaveMoneyConfig(config);
101
- this.transport = new http_js_1.Transport((0, http_js_1.httpClientFrom)(options));
92
+ this.transport = new http_js_1.Transport((0, http_js_1.httpClientFrom)(options, this.config.timeoutSeconds));
102
93
  }
103
94
  /** A gateway configured from the `WAVE_MONEY_*` environment variables. */
104
95
  static fromEnv(env = (0, env_js_1.defaultEnv)(), options = {}) {
@@ -209,13 +200,15 @@ class WaveMoney {
209
200
  /**
210
201
  * Verifies Wave's callback. Only `PAYMENT_CONFIRMED` means the customer paid. `orderId` falls
211
202
  * back to `merchantReferenceId` when it is missing, null or empty, because Wave marks `orderId` as
212
- * optional.
203
+ * optional. A hashed field holding an object or array fails verification.
213
204
  */
214
205
  handleCallback(request) {
215
206
  const payload = (0, callback_js_1.losslessBody)(request);
216
207
  const expected = this.hash(CALLBACK_FIELDS.map((field) => (0, values_js_1.scalarString)(payload[field]) ?? 'null'));
217
208
  const hashValue = payload.hashValue;
218
- if (typeof hashValue !== 'string' || !(0, crypto_js_1.safeEqual)(expected, hashValue.toLowerCase())) {
209
+ if (typeof hashValue !== 'string' ||
210
+ CALLBACK_FIELDS.some((field) => (0, values_js_1.isNested)(payload[field])) ||
211
+ !(0, crypto_js_1.safeEqual)(expected, hashValue.toLowerCase())) {
219
212
  throw new errors_js_1.SignatureVerificationError('Wave Money callback hash verification failed.', (0, json_js_1.toPlainObject)(payload));
220
213
  }
221
214
  const gatewayStatus = (0, values_js_1.trimmed)(payload, 'status');
@@ -16,35 +16,38 @@ export interface YomaMmqrConfigOptions {
16
16
  webhookHashKey: string;
17
17
  /** The secret you shared with Yoma; when set, callbacks must carry it in `X-Webhook-Secret`. */
18
18
  webhookSecret?: string | undefined;
19
- /** Use the UAT payment hub (default `true`). */
20
- sandbox?: boolean | undefined;
21
- /** Overrides the API base URL. */
19
+ /** The `{version}` segment of the API paths, e.g. `v1rc`. */
20
+ apiVersion: string;
21
+ /**
22
+ * Seconds before the default HTTP client gives up on a request, a whole number greater than 0
23
+ * (or its text). A client you pass keeps its own timeout.
24
+ */
25
+ timeoutSeconds: number | string;
26
+ /** Overrides the API base URL, e.g. to point at UAT. */
22
27
  baseUrl?: string | undefined;
23
- /** The `{version}` segment of the API paths (default `v1rc`). */
24
- apiVersion?: string | undefined;
25
28
  }
26
29
  /**
27
- * Yoma MMQR credentials and endpoints. A missing credential throws a `ConfigurationError`.
30
+ * Yoma MMQR credentials and endpoints. A missing setting throws a `ConfigurationError`. The URL
31
+ * defaults to production.
28
32
  */
29
33
  export declare class YomaMmqrConfig {
30
- static readonly SANDBOX_URL = "https://devapi.yomabank.net";
31
34
  static readonly PRODUCTION_URL = "https://paymenthubapi.yomabank.com";
32
- static readonly DEFAULT_API_VERSION = "v1rc";
33
35
  readonly merchantId: string;
34
36
  readonly clientId: string;
35
37
  readonly clientSecret: string;
36
38
  readonly webhookHashKey: string;
37
39
  readonly webhookSecret: string | undefined;
38
- readonly sandbox: boolean;
40
+ /** The `{version}` segment of the API paths. */
41
+ readonly apiVersion: string;
42
+ /** Seconds before the default HTTP client gives up on a request. */
43
+ readonly timeoutSeconds: number;
39
44
  /** The base URL in use. */
40
45
  readonly baseUrl: string;
41
- /** The API version in use. */
42
- readonly apiVersion: string;
43
46
  constructor(options: YomaMmqrConfigOptions);
44
47
  /**
45
48
  * Reads `YOMA_MMQR_MERCHANT_ID`, `YOMA_MMQR_CLIENT_ID`, `YOMA_MMQR_CLIENT_SECRET`,
46
- * `YOMA_MMQR_WEBHOOK_HASHKEY`, `YOMA_MMQR_WEBHOOK_SECRET`, `YOMA_MMQR_SANDBOX`,
47
- * `YOMA_MMQR_BASE_URL` and `YOMA_MMQR_API_VERSION`.
49
+ * `YOMA_MMQR_WEBHOOK_HASHKEY`, `YOMA_MMQR_API_VERSION`, `MYANMAR_PAYMENTS_HTTP_TIMEOUT`,
50
+ * `YOMA_MMQR_WEBHOOK_SECRET` and `YOMA_MMQR_BASE_URL`.
48
51
  */
49
52
  static fromEnv(env?: EnvSource): YomaMmqrConfig;
50
53
  }
@@ -13,37 +13,36 @@ const status_js_1 = require("../core/status.js");
13
13
  const validate_js_1 = require("../core/validate.js");
14
14
  const values_js_1 = require("../core/values.js");
15
15
  /**
16
- * Yoma MMQR credentials and endpoints. A missing credential throws a `ConfigurationError`.
16
+ * Yoma MMQR credentials and endpoints. A missing setting throws a `ConfigurationError`. The URL
17
+ * defaults to production.
17
18
  */
18
19
  class YomaMmqrConfig {
19
- static SANDBOX_URL = 'https://devapi.yomabank.net';
20
20
  static PRODUCTION_URL = 'https://paymenthubapi.yomabank.com';
21
- static DEFAULT_API_VERSION = 'v1rc';
22
21
  merchantId;
23
22
  clientId;
24
23
  clientSecret;
25
24
  webhookHashKey;
26
25
  webhookSecret;
27
- sandbox;
26
+ /** The `{version}` segment of the API paths. */
27
+ apiVersion;
28
+ /** Seconds before the default HTTP client gives up on a request. */
29
+ timeoutSeconds;
28
30
  /** The base URL in use. */
29
31
  baseUrl;
30
- /** The API version in use. */
31
- apiVersion;
32
32
  constructor(options) {
33
33
  this.merchantId = (0, env_js_1.requireSetting)('yoma_mmqr', 'merchant_id', options.merchantId);
34
34
  this.clientId = (0, env_js_1.requireSetting)('yoma_mmqr', 'client_id', options.clientId);
35
35
  this.clientSecret = (0, env_js_1.requireSetting)('yoma_mmqr', 'client_secret', options.clientSecret);
36
36
  this.webhookHashKey = (0, env_js_1.requireSetting)('yoma_mmqr', 'webhook_hashkey', options.webhookHashKey);
37
+ this.apiVersion = (0, env_js_1.requireSetting)('yoma_mmqr', 'api_version', options.apiVersion);
38
+ this.timeoutSeconds = (0, env_js_1.requireSeconds)('yoma_mmqr', 'timeout_in_seconds', options.timeoutSeconds);
37
39
  this.webhookSecret = (0, env_js_1.optionalSetting)(options.webhookSecret);
38
- this.sandbox = options.sandbox ?? true;
39
- this.baseUrl = (0, env_js_1.trimUrl)((0, env_js_1.optionalSetting)(options.baseUrl) ??
40
- (this.sandbox ? YomaMmqrConfig.SANDBOX_URL : YomaMmqrConfig.PRODUCTION_URL));
41
- this.apiVersion = (0, env_js_1.optionalSetting)(options.apiVersion) ?? YomaMmqrConfig.DEFAULT_API_VERSION;
40
+ this.baseUrl = (0, env_js_1.trimUrl)((0, env_js_1.optionalSetting)(options.baseUrl) ?? YomaMmqrConfig.PRODUCTION_URL);
42
41
  }
43
42
  /**
44
43
  * Reads `YOMA_MMQR_MERCHANT_ID`, `YOMA_MMQR_CLIENT_ID`, `YOMA_MMQR_CLIENT_SECRET`,
45
- * `YOMA_MMQR_WEBHOOK_HASHKEY`, `YOMA_MMQR_WEBHOOK_SECRET`, `YOMA_MMQR_SANDBOX`,
46
- * `YOMA_MMQR_BASE_URL` and `YOMA_MMQR_API_VERSION`.
44
+ * `YOMA_MMQR_WEBHOOK_HASHKEY`, `YOMA_MMQR_API_VERSION`, `MYANMAR_PAYMENTS_HTTP_TIMEOUT`,
45
+ * `YOMA_MMQR_WEBHOOK_SECRET` and `YOMA_MMQR_BASE_URL`.
47
46
  */
48
47
  static fromEnv(env = (0, env_js_1.defaultEnv)()) {
49
48
  return new YomaMmqrConfig({
@@ -51,10 +50,10 @@ class YomaMmqrConfig {
51
50
  clientId: (0, env_js_1.envFirst)(env, 'YOMA_MMQR_CLIENT_ID'),
52
51
  clientSecret: (0, env_js_1.envFirst)(env, 'YOMA_MMQR_CLIENT_SECRET'),
53
52
  webhookHashKey: (0, env_js_1.envFirst)(env, 'YOMA_MMQR_WEBHOOK_HASHKEY'),
53
+ apiVersion: (0, env_js_1.envFirst)(env, 'YOMA_MMQR_API_VERSION'),
54
+ timeoutSeconds: (0, env_js_1.envFirst)(env, env_js_1.HTTP_TIMEOUT_VARIABLE),
54
55
  webhookSecret: (0, env_js_1.envFirst)(env, 'YOMA_MMQR_WEBHOOK_SECRET'),
55
- sandbox: (0, env_js_1.envSandbox)(env, 'YOMA_MMQR_SANDBOX'),
56
56
  baseUrl: (0, env_js_1.envFirst)(env, 'YOMA_MMQR_BASE_URL'),
57
- apiVersion: (0, env_js_1.envFirst)(env, 'YOMA_MMQR_API_VERSION'),
58
57
  });
59
58
  }
60
59
  }
@@ -79,7 +78,7 @@ class YomaMmqr {
79
78
  pendingToken;
80
79
  constructor(config, options = {}) {
81
80
  this.config = config instanceof YomaMmqrConfig ? config : new YomaMmqrConfig(config);
82
- this.transport = new http_js_1.Transport((0, http_js_1.httpClientFrom)(options));
81
+ this.transport = new http_js_1.Transport((0, http_js_1.httpClientFrom)(options, this.config.timeoutSeconds));
83
82
  this.cache = options.tokenCache ?? new cache_js_1.MemoryTokenCache();
84
83
  }
85
84
  /** A gateway configured from the `YOMA_MMQR_*` environment variables. */
@@ -161,7 +160,9 @@ class YomaMmqr {
161
160
  const orderNumber = (0, values_js_1.get)(payload, 'orderNumber');
162
161
  const status = (0, values_js_1.trimmed)(payload, 'status');
163
162
  const expected = (0, crypto_js_1.hmacSha256Hex)(orderNumber + this.config.webhookHashKey, `orderNumber=${orderNumber}&status=${status}`);
164
- if (orderNumber === '' || !(0, crypto_js_1.safeEqual)(expected, (0, values_js_1.get)(payload, 'hashValue').toLowerCase())) {
163
+ if (orderNumber === '' ||
164
+ (0, values_js_1.isNested)(payload.status) ||
165
+ !(0, crypto_js_1.safeEqual)(expected, (0, values_js_1.get)(payload, 'hashValue').toLowerCase())) {
165
166
  throw new errors_js_1.SignatureVerificationError('Yoma MMQR callback hash verification failed.', (0, json_js_1.toPlainObject)(payload));
166
167
  }
167
168
  return new callback_js_1.PaymentCallback({
@@ -210,13 +211,14 @@ class YomaMmqr {
210
211
  if (!response.successful() || token === '') {
211
212
  throw apiError('token', response.status, body, (0, values_js_1.get)(body, 'error'));
212
213
  }
213
- const expiresIn = Number.parseInt((0, values_js_1.get)(body, 'expires_in'), 10);
214
- const ttl = Math.max(60, (Number.isFinite(expiresIn) && expiresIn > 0 ? expiresIn : 3600) - 60);
214
+ // The leading digits of `expires_in`; missing, non-numeric or 0 means an hour.
215
+ const expiresIn = Number(/^\d+/.exec((0, values_js_1.get)(body, 'expires_in'))?.[0] ?? 0);
216
+ const ttl = Math.max(60, (expiresIn > 0 ? expiresIn : 3600) - 60);
215
217
  await this.cache.set(this.tokenCacheKey(), token, ttl);
216
218
  return token;
217
219
  }
218
220
  tokenCacheKey() {
219
- return `node-myanmar-payments.yoma-mmqr.token.${(0, crypto_js_1.sha256Hex)(`${this.config.baseUrl}|${this.config.clientId}`)}`;
221
+ return `myanmar-payments.yoma-mmqr.token.${(0, crypto_js_1.sha256Hex)(`${this.config.baseUrl}|${this.config.clientId}`)}`;
220
222
  }
221
223
  }
222
224
  exports.YomaMmqr = YomaMmqr;
@@ -9,27 +9,30 @@ export interface AyaPayConfigOptions {
9
9
  appKey: string;
10
10
  /** The secret that signs requests and verifies callbacks. */
11
11
  appSecret: string;
12
- /** Use the UAT environment (default `true`). */
13
- sandbox?: boolean | undefined;
14
- /** Overrides the gateway base URL. */
12
+ /**
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
+ */
16
+ timeoutSeconds: number | string;
17
+ /** Overrides the gateway base URL, e.g. to point at UAT. */
15
18
  baseUrl?: string | undefined;
16
19
  }
17
20
  /**
18
- * AYA Payment Gateway (APG) credentials and endpoints. A missing credential throws a
19
- * `ConfigurationError`.
21
+ * AYA Payment Gateway (APG) credentials and endpoints. A missing setting throws a
22
+ * `ConfigurationError`. The URL defaults to production.
20
23
  */
21
24
  export declare class AyaPayConfig {
22
- static readonly SANDBOX_URL = "https://uat-pgw.ayainnovation.com";
23
25
  static readonly PRODUCTION_URL = "https://pgw.ayainnovation.com";
24
26
  readonly appKey: string;
25
27
  readonly appSecret: string;
26
- readonly sandbox: boolean;
28
+ /** Seconds before the default HTTP client gives up on a request. */
29
+ readonly timeoutSeconds: number;
27
30
  /** The base URL in use. */
28
31
  readonly baseUrl: string;
29
32
  constructor(options: AyaPayConfigOptions);
30
33
  /**
31
- * Reads `AYA_PAY_APP_KEY`, `AYA_PAY_APP_SECRET`, `AYA_PAY_SANDBOX` and `AYA_PAY_BASE_URL`, falling
32
- * 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.
33
36
  */
34
37
  static fromEnv(env?: EnvSource): AyaPayConfig;
35
38
  }