@laranex/myanmar-payments 0.0.0-stage → 4.0.0-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/LICENSE.md +21 -0
  3. package/README.md +10 -2
  4. package/dist/cjs/aya-pay/aya-pay.d.ts +122 -0
  5. package/dist/cjs/aya-pay/aya-pay.js +301 -0
  6. package/dist/cjs/aya-pay/index.d.ts +1 -0
  7. package/dist/cjs/aya-pay/index.js +8 -0
  8. package/dist/cjs/core/amount.d.ts +57 -0
  9. package/dist/cjs/core/amount.js +107 -0
  10. package/dist/cjs/core/cache.d.ts +26 -0
  11. package/dist/cjs/core/cache.js +35 -0
  12. package/dist/cjs/core/callback.d.ts +180 -0
  13. package/dist/cjs/core/callback.js +304 -0
  14. package/dist/cjs/core/crypto.d.ts +19 -0
  15. package/dist/cjs/core/crypto.js +50 -0
  16. package/dist/cjs/core/env.d.ts +21 -0
  17. package/dist/cjs/core/env.js +54 -0
  18. package/dist/cjs/core/errors.d.ts +56 -0
  19. package/dist/cjs/core/errors.js +78 -0
  20. package/dist/cjs/core/http.d.ts +81 -0
  21. package/dist/cjs/core/http.js +128 -0
  22. package/dist/cjs/core/index.d.ts +8 -0
  23. package/dist/cjs/core/index.js +30 -0
  24. package/dist/cjs/core/json.d.ts +44 -0
  25. package/dist/cjs/core/json.js +254 -0
  26. package/dist/cjs/core/results.d.ts +122 -0
  27. package/dist/cjs/core/results.js +147 -0
  28. package/dist/cjs/core/status.d.ts +50 -0
  29. package/dist/cjs/core/status.js +60 -0
  30. package/dist/cjs/core/validate.d.ts +46 -0
  31. package/dist/cjs/core/validate.js +148 -0
  32. package/dist/cjs/core/values.d.ts +16 -0
  33. package/dist/cjs/core/values.js +45 -0
  34. package/dist/cjs/cyber-source/cyber-source.d.ts +95 -0
  35. package/dist/cjs/cyber-source/cyber-source.js +188 -0
  36. package/dist/cjs/cyber-source/index.d.ts +1 -0
  37. package/dist/cjs/cyber-source/index.js +7 -0
  38. package/dist/cjs/index.d.ts +7 -0
  39. package/dist/cjs/index.js +25 -0
  40. package/dist/cjs/kbz-pay/index.d.ts +2 -0
  41. package/dist/cjs/kbz-pay/index.js +8 -0
  42. package/dist/cjs/kbz-pay/kbz-pay.d.ts +102 -0
  43. package/dist/cjs/kbz-pay/kbz-pay.js +266 -0
  44. package/dist/cjs/kbz-pay/signer.d.ts +15 -0
  45. package/dist/cjs/kbz-pay/signer.js +36 -0
  46. package/dist/cjs/myanmar-payments.d.ts +50 -0
  47. package/dist/cjs/myanmar-payments.js +73 -0
  48. package/dist/cjs/package.json +3 -0
  49. package/dist/cjs/wave-money/index.d.ts +1 -0
  50. package/dist/cjs/wave-money/index.js +6 -0
  51. package/dist/cjs/wave-money/wave-money.d.ts +111 -0
  52. package/dist/cjs/wave-money/wave-money.js +251 -0
  53. package/dist/cjs/yoma-mmqr/index.d.ts +1 -0
  54. package/dist/cjs/yoma-mmqr/index.js +6 -0
  55. package/dist/cjs/yoma-mmqr/yoma-mmqr.d.ts +105 -0
  56. package/dist/cjs/yoma-mmqr/yoma-mmqr.js +233 -0
  57. package/dist/esm/aya-pay/aya-pay.d.ts +122 -0
  58. package/dist/esm/aya-pay/aya-pay.js +296 -0
  59. package/dist/esm/aya-pay/index.d.ts +1 -0
  60. package/dist/esm/aya-pay/index.js +1 -0
  61. package/dist/esm/core/amount.d.ts +57 -0
  62. package/dist/esm/core/amount.js +103 -0
  63. package/dist/esm/core/cache.d.ts +26 -0
  64. package/dist/esm/core/cache.js +31 -0
  65. package/dist/esm/core/callback.d.ts +180 -0
  66. package/dist/esm/core/callback.js +294 -0
  67. package/dist/esm/core/crypto.d.ts +19 -0
  68. package/dist/esm/core/crypto.js +41 -0
  69. package/dist/esm/core/env.d.ts +21 -0
  70. package/dist/esm/core/env.js +45 -0
  71. package/dist/esm/core/errors.d.ts +56 -0
  72. package/dist/esm/core/errors.js +70 -0
  73. package/dist/esm/core/http.d.ts +81 -0
  74. package/dist/esm/core/http.js +121 -0
  75. package/dist/esm/core/index.d.ts +8 -0
  76. package/dist/esm/core/index.js +7 -0
  77. package/dist/esm/core/json.d.ts +44 -0
  78. package/dist/esm/core/json.js +244 -0
  79. package/dist/esm/core/results.d.ts +122 -0
  80. package/dist/esm/core/results.js +139 -0
  81. package/dist/esm/core/status.d.ts +50 -0
  82. package/dist/esm/core/status.js +56 -0
  83. package/dist/esm/core/validate.d.ts +46 -0
  84. package/dist/esm/core/validate.js +142 -0
  85. package/dist/esm/core/values.d.ts +16 -0
  86. package/dist/esm/core/values.js +38 -0
  87. package/dist/esm/cyber-source/cyber-source.d.ts +95 -0
  88. package/dist/esm/cyber-source/cyber-source.js +184 -0
  89. package/dist/esm/cyber-source/index.d.ts +1 -0
  90. package/dist/esm/cyber-source/index.js +1 -0
  91. package/dist/esm/index.d.ts +7 -0
  92. package/dist/esm/index.js +7 -0
  93. package/dist/esm/kbz-pay/index.d.ts +2 -0
  94. package/dist/esm/kbz-pay/index.js +2 -0
  95. package/dist/esm/kbz-pay/kbz-pay.d.ts +102 -0
  96. package/dist/esm/kbz-pay/kbz-pay.js +262 -0
  97. package/dist/esm/kbz-pay/signer.d.ts +15 -0
  98. package/dist/esm/kbz-pay/signer.js +32 -0
  99. package/dist/esm/myanmar-payments.d.ts +50 -0
  100. package/dist/esm/myanmar-payments.js +69 -0
  101. package/dist/esm/wave-money/index.d.ts +1 -0
  102. package/dist/esm/wave-money/index.js +1 -0
  103. package/dist/esm/wave-money/wave-money.d.ts +111 -0
  104. package/dist/esm/wave-money/wave-money.js +246 -0
  105. package/dist/esm/yoma-mmqr/index.d.ts +1 -0
  106. package/dist/esm/yoma-mmqr/index.js +1 -0
  107. package/dist/esm/yoma-mmqr/yoma-mmqr.d.ts +105 -0
  108. package/dist/esm/yoma-mmqr/yoma-mmqr.js +229 -0
  109. package/package.json +151 -4
  110. package/skills/node-myanmar-payments/SKILL.md +109 -0
@@ -0,0 +1,254 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JsonNumber = void 0;
4
+ exports.parseJson = parseJson;
5
+ exports.parseJsonObject = parseJsonObject;
6
+ exports.isLosslessObject = isLosslessObject;
7
+ exports.toPlain = toPlain;
8
+ exports.toPlainObject = toPlainObject;
9
+ exports.setKey = setKey;
10
+ /**
11
+ * A JSON number kept as the exact text the gateway sent, so `1000.50` stays `1000.50` and large
12
+ * integers keep every digit. Only used internally while verifying signatures and reading values.
13
+ *
14
+ * @internal
15
+ */
16
+ class JsonNumber {
17
+ text;
18
+ constructor(text) {
19
+ this.text = text;
20
+ }
21
+ }
22
+ exports.JsonNumber = JsonNumber;
23
+ const NUMBER = /-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/y;
24
+ /**
25
+ * Parses strict JSON (RFC 8259) without passing numbers through a float. Returns `undefined` when
26
+ * the text is not valid JSON.
27
+ *
28
+ * @internal
29
+ */
30
+ function parseJson(text) {
31
+ const parser = new Parser(text);
32
+ try {
33
+ parser.skipWhitespace();
34
+ const value = parser.value();
35
+ parser.skipWhitespace();
36
+ return parser.done() ? value : undefined;
37
+ }
38
+ catch {
39
+ return undefined;
40
+ }
41
+ }
42
+ /**
43
+ * Parses JSON and returns it only when it is an object (not an array, string or null).
44
+ *
45
+ * @internal
46
+ */
47
+ function parseJsonObject(text) {
48
+ const value = parseJson(text);
49
+ return isLosslessObject(value) ? value : undefined;
50
+ }
51
+ /** @internal */
52
+ function isLosslessObject(value) {
53
+ return (typeof value === 'object' &&
54
+ value !== null &&
55
+ !Array.isArray(value) &&
56
+ !(value instanceof JsonNumber));
57
+ }
58
+ /**
59
+ * Converts a lossless value to plain JavaScript values (numbers become `number`), for the `raw`
60
+ * fields of results.
61
+ *
62
+ * @internal
63
+ */
64
+ function toPlain(value) {
65
+ if (value instanceof JsonNumber) {
66
+ return Number(value.text);
67
+ }
68
+ if (Array.isArray(value)) {
69
+ return value.map(toPlain);
70
+ }
71
+ if (value !== null && typeof value === 'object') {
72
+ return toPlainObject(value);
73
+ }
74
+ return value;
75
+ }
76
+ /** @internal */
77
+ function toPlainObject(value) {
78
+ const result = {};
79
+ for (const key of Object.keys(value)) {
80
+ setKey(result, key, toPlain(value[key]));
81
+ }
82
+ return result;
83
+ }
84
+ /** Sets a key without letting `__proto__` change the object's prototype. @internal */
85
+ function setKey(target, key, value) {
86
+ Object.defineProperty(target, key, {
87
+ value,
88
+ enumerable: true,
89
+ writable: true,
90
+ configurable: true,
91
+ });
92
+ }
93
+ class Parser {
94
+ text;
95
+ index = 0;
96
+ constructor(text) {
97
+ this.text = text;
98
+ }
99
+ done() {
100
+ return this.index === this.text.length;
101
+ }
102
+ skipWhitespace() {
103
+ while (this.index < this.text.length) {
104
+ const char = this.text[this.index];
105
+ if (char !== ' ' && char !== '\t' && char !== '\n' && char !== '\r') {
106
+ return;
107
+ }
108
+ this.index++;
109
+ }
110
+ }
111
+ value() {
112
+ const char = this.text[this.index];
113
+ switch (char) {
114
+ case '{':
115
+ return this.object();
116
+ case '[':
117
+ return this.array();
118
+ case '"':
119
+ return this.string();
120
+ case 't':
121
+ return this.literal('true', true);
122
+ case 'f':
123
+ return this.literal('false', false);
124
+ case 'n':
125
+ return this.literal('null', null);
126
+ default:
127
+ return this.number();
128
+ }
129
+ }
130
+ object() {
131
+ this.index++;
132
+ const result = {};
133
+ this.skipWhitespace();
134
+ if (this.text[this.index] === '}') {
135
+ this.index++;
136
+ return result;
137
+ }
138
+ for (;;) {
139
+ this.skipWhitespace();
140
+ if (this.text[this.index] !== '"') {
141
+ throw new SyntaxError('Expected a string key');
142
+ }
143
+ const key = this.string();
144
+ this.skipWhitespace();
145
+ this.expect(':');
146
+ this.skipWhitespace();
147
+ setKey(result, key, this.value());
148
+ this.skipWhitespace();
149
+ if (this.text[this.index] === ',') {
150
+ this.index++;
151
+ continue;
152
+ }
153
+ this.expect('}');
154
+ return result;
155
+ }
156
+ }
157
+ array() {
158
+ this.index++;
159
+ const result = [];
160
+ this.skipWhitespace();
161
+ if (this.text[this.index] === ']') {
162
+ this.index++;
163
+ return result;
164
+ }
165
+ for (;;) {
166
+ this.skipWhitespace();
167
+ result.push(this.value());
168
+ this.skipWhitespace();
169
+ if (this.text[this.index] === ',') {
170
+ this.index++;
171
+ continue;
172
+ }
173
+ this.expect(']');
174
+ return result;
175
+ }
176
+ }
177
+ string() {
178
+ this.index++;
179
+ let result = '';
180
+ for (;;) {
181
+ if (this.index >= this.text.length) {
182
+ throw new SyntaxError('Unterminated string');
183
+ }
184
+ const char = this.text[this.index];
185
+ if (char === '"') {
186
+ this.index++;
187
+ return result;
188
+ }
189
+ if (char === '\\') {
190
+ result += this.escape();
191
+ continue;
192
+ }
193
+ if (char < ' ') {
194
+ throw new SyntaxError('Control character in string');
195
+ }
196
+ result += char;
197
+ this.index++;
198
+ }
199
+ }
200
+ escape() {
201
+ const char = this.text[this.index + 1];
202
+ this.index += 2;
203
+ switch (char) {
204
+ case '"':
205
+ return '"';
206
+ case '\\':
207
+ return '\\';
208
+ case '/':
209
+ return '/';
210
+ case 'b':
211
+ return '\b';
212
+ case 'f':
213
+ return '\f';
214
+ case 'n':
215
+ return '\n';
216
+ case 'r':
217
+ return '\r';
218
+ case 't':
219
+ return '\t';
220
+ case 'u': {
221
+ const hex = this.text.slice(this.index, this.index + 4);
222
+ if (!/^[0-9a-fA-F]{4}$/.test(hex)) {
223
+ throw new SyntaxError('Invalid unicode escape');
224
+ }
225
+ this.index += 4;
226
+ return String.fromCharCode(parseInt(hex, 16));
227
+ }
228
+ default:
229
+ throw new SyntaxError('Invalid escape');
230
+ }
231
+ }
232
+ literal(word, value) {
233
+ if (!this.text.startsWith(word, this.index)) {
234
+ throw new SyntaxError(`Expected ${word}`);
235
+ }
236
+ this.index += word.length;
237
+ return value;
238
+ }
239
+ number() {
240
+ NUMBER.lastIndex = this.index;
241
+ const match = NUMBER.exec(this.text);
242
+ if (match === null) {
243
+ throw new SyntaxError('Unexpected token');
244
+ }
245
+ this.index += match[0].length;
246
+ return new JsonNumber(match[0]);
247
+ }
248
+ expect(char) {
249
+ if (this.text[this.index] !== char) {
250
+ throw new SyntaxError(`Expected ${char}`);
251
+ }
252
+ this.index++;
253
+ }
254
+ }
@@ -0,0 +1,122 @@
1
+ type Raw = Readonly<Record<string, unknown>>;
2
+ /** Returned when a payment is initiated. Each flow has its own class; switch on `flow`. */
3
+ export type PaymentResult = RedirectPayment | FormPayment | QrPayment | AppPayment;
4
+ /**
5
+ * Send the customer's browser to `url` to complete the payment.
6
+ */
7
+ export declare class RedirectPayment {
8
+ /** Always `redirect`. */
9
+ readonly flow: 'redirect';
10
+ /** Your order id, as sent to the gateway. */
11
+ readonly orderId: string;
12
+ /** The gateway page to redirect the customer to. */
13
+ readonly url: string;
14
+ /** The gateway's id for this attempt (KBZ `prepay_id`, Wave `transaction_id`). */
15
+ readonly gatewayReference: string | undefined;
16
+ /** The gateway's response, for logging. */
17
+ readonly raw: Raw;
18
+ constructor(init: {
19
+ orderId: string;
20
+ url: string;
21
+ gatewayReference?: string | undefined;
22
+ raw?: Raw;
23
+ });
24
+ }
25
+ /** One signed hidden field of a {@link FormPayment}. */
26
+ export interface FormField {
27
+ readonly name: string;
28
+ readonly value: string;
29
+ }
30
+ /**
31
+ * POST `fields` to `action` from the customer's browser. {@link FormPayment.toHtml} renders a page
32
+ * that does this automatically.
33
+ */
34
+ export declare class FormPayment {
35
+ /** Always `form`. */
36
+ readonly flow: 'form';
37
+ /** Your order id, as sent to the gateway. */
38
+ readonly orderId: string;
39
+ /** The gateway URL the form posts to. */
40
+ readonly action: string;
41
+ /** The signed hidden fields, in signing order. Post them unchanged. */
42
+ readonly fields: readonly FormField[];
43
+ /** The encoding the gateway expects for the form. */
44
+ readonly enctype: string;
45
+ constructor(init: {
46
+ orderId: string;
47
+ action: string;
48
+ fields: readonly FormField[];
49
+ enctype?: string | undefined;
50
+ });
51
+ /** The value of the named field, or `undefined`. */
52
+ field(name: string): string | undefined;
53
+ /** The fields as an object, e.g. to render the form with your own template. */
54
+ values(): Record<string, string>;
55
+ /** A complete HTML page that posts the form as soon as it loads. Every value is escaped. */
56
+ toHtml(): string;
57
+ }
58
+ /**
59
+ * Show a QR code for the customer to scan. Gateways return either a payload to encode
60
+ * (`qrString`) or a ready-made image (`qrImage`).
61
+ */
62
+ export declare class QrPayment {
63
+ /** Always `qr`. */
64
+ readonly flow: 'qr';
65
+ /** Your order id, as sent to the gateway. */
66
+ readonly orderId: string;
67
+ /** A QR payload to encode into an image yourself (KBZ Pay). */
68
+ readonly qrString: string | undefined;
69
+ /** A base64 encoded image to display as is (Yoma MMQR). */
70
+ readonly qrImage: string | undefined;
71
+ /** When the QR stops being payable, when the gateway limits it. */
72
+ readonly expiresAt: Date | undefined;
73
+ /** The gateway's id for this QR, used to check its status (Yoma `refLabel`, KBZ `prepay_id`). */
74
+ readonly reference: string | undefined;
75
+ /** The gateway's response, for logging. */
76
+ readonly raw: Raw;
77
+ constructor(init: {
78
+ orderId: string;
79
+ qrString?: string | undefined;
80
+ qrImage?: string | undefined;
81
+ expiresAt?: Date | undefined;
82
+ reference?: string | undefined;
83
+ raw?: Raw;
84
+ });
85
+ /** The image as a data URI for an `<img src>`, or `undefined` when there is no image. */
86
+ qrImageDataUri(mimeType?: string): string | undefined;
87
+ }
88
+ /**
89
+ * Pass these values to your mobile app, which hands them to the wallet's SDK.
90
+ * `JSON.stringify(payment)` writes `orderId`, `orderInfo`, `sign` and `signType`.
91
+ */
92
+ export declare class AppPayment {
93
+ /** Always `app`. */
94
+ readonly flow: 'app';
95
+ /** Your order id, as sent to the gateway. */
96
+ readonly orderId: string;
97
+ /** The signed order string the SDK expects. */
98
+ readonly orderInfo: string;
99
+ /** The signature of `orderInfo`. */
100
+ readonly sign: string;
101
+ /** The signature algorithm, e.g. `SHA256`. */
102
+ readonly signType: string;
103
+ /** The gateway's response, for logging. Left out of `toJSON()`. */
104
+ readonly raw: Raw;
105
+ constructor(init: {
106
+ orderId: string;
107
+ orderInfo: string;
108
+ sign: string;
109
+ signType: string;
110
+ raw?: Raw;
111
+ });
112
+ /** The values your app needs: `orderId`, `orderInfo`, `sign` and `signType`. */
113
+ toJSON(): {
114
+ orderId: string;
115
+ orderInfo: string;
116
+ sign: string;
117
+ signType: string;
118
+ };
119
+ }
120
+ /** Escapes text for HTML content and attribute values. @internal */
121
+ export declare function escapeHtml(value: string): string;
122
+ export {};
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AppPayment = exports.QrPayment = exports.FormPayment = exports.RedirectPayment = void 0;
4
+ exports.escapeHtml = escapeHtml;
5
+ /**
6
+ * Send the customer's browser to `url` to complete the payment.
7
+ */
8
+ class RedirectPayment {
9
+ /** Always `redirect`. */
10
+ flow = 'redirect';
11
+ /** Your order id, as sent to the gateway. */
12
+ orderId;
13
+ /** The gateway page to redirect the customer to. */
14
+ url;
15
+ /** The gateway's id for this attempt (KBZ `prepay_id`, Wave `transaction_id`). */
16
+ gatewayReference;
17
+ /** The gateway's response, for logging. */
18
+ raw;
19
+ constructor(init) {
20
+ this.orderId = init.orderId;
21
+ this.url = init.url;
22
+ this.gatewayReference = init.gatewayReference;
23
+ this.raw = init.raw ?? {};
24
+ }
25
+ }
26
+ exports.RedirectPayment = RedirectPayment;
27
+ /**
28
+ * POST `fields` to `action` from the customer's browser. {@link FormPayment.toHtml} renders a page
29
+ * that does this automatically.
30
+ */
31
+ class FormPayment {
32
+ /** Always `form`. */
33
+ flow = 'form';
34
+ /** Your order id, as sent to the gateway. */
35
+ orderId;
36
+ /** The gateway URL the form posts to. */
37
+ action;
38
+ /** The signed hidden fields, in signing order. Post them unchanged. */
39
+ fields;
40
+ /** The encoding the gateway expects for the form. */
41
+ enctype;
42
+ constructor(init) {
43
+ this.orderId = init.orderId;
44
+ this.action = init.action;
45
+ this.fields = Object.freeze(init.fields.map((field) => Object.freeze({ ...field })));
46
+ this.enctype = init.enctype ?? 'application/x-www-form-urlencoded';
47
+ }
48
+ /** The value of the named field, or `undefined`. */
49
+ field(name) {
50
+ return this.fields.find((field) => field.name === name)?.value;
51
+ }
52
+ /** The fields as an object, e.g. to render the form with your own template. */
53
+ values() {
54
+ return Object.fromEntries(this.fields.map((field) => [field.name, field.value]));
55
+ }
56
+ /** A complete HTML page that posts the form as soon as it loads. Every value is escaped. */
57
+ toHtml() {
58
+ const inputs = this.fields
59
+ .map((field) => `<input type="hidden" name="${escapeHtml(field.name)}" value="${escapeHtml(field.value)}">`)
60
+ .join('');
61
+ return ('<!DOCTYPE html><html><head><meta charset="utf-8"><title>Redirecting to payment</title></head><body>' +
62
+ `<form id="payment-form" method="POST" action="${escapeHtml(this.action)}" enctype="${escapeHtml(this.enctype)}">` +
63
+ inputs +
64
+ '<noscript><button type="submit">Continue to payment</button></noscript></form>' +
65
+ '<script>document.getElementById("payment-form").submit();</script></body></html>');
66
+ }
67
+ }
68
+ exports.FormPayment = FormPayment;
69
+ /**
70
+ * Show a QR code for the customer to scan. Gateways return either a payload to encode
71
+ * (`qrString`) or a ready-made image (`qrImage`).
72
+ */
73
+ class QrPayment {
74
+ /** Always `qr`. */
75
+ flow = 'qr';
76
+ /** Your order id, as sent to the gateway. */
77
+ orderId;
78
+ /** A QR payload to encode into an image yourself (KBZ Pay). */
79
+ qrString;
80
+ /** A base64 encoded image to display as is (Yoma MMQR). */
81
+ qrImage;
82
+ /** When the QR stops being payable, when the gateway limits it. */
83
+ expiresAt;
84
+ /** The gateway's id for this QR, used to check its status (Yoma `refLabel`, KBZ `prepay_id`). */
85
+ reference;
86
+ /** The gateway's response, for logging. */
87
+ raw;
88
+ constructor(init) {
89
+ this.orderId = init.orderId;
90
+ this.qrString = init.qrString;
91
+ this.qrImage = init.qrImage;
92
+ this.expiresAt = init.expiresAt;
93
+ this.reference = init.reference;
94
+ this.raw = init.raw ?? {};
95
+ }
96
+ /** The image as a data URI for an `<img src>`, or `undefined` when there is no image. */
97
+ qrImageDataUri(mimeType = 'image/png') {
98
+ return this.qrImage === undefined ? undefined : `data:${mimeType};base64,${this.qrImage}`;
99
+ }
100
+ }
101
+ exports.QrPayment = QrPayment;
102
+ /**
103
+ * Pass these values to your mobile app, which hands them to the wallet's SDK.
104
+ * `JSON.stringify(payment)` writes `orderId`, `orderInfo`, `sign` and `signType`.
105
+ */
106
+ class AppPayment {
107
+ /** Always `app`. */
108
+ flow = 'app';
109
+ /** Your order id, as sent to the gateway. */
110
+ orderId;
111
+ /** The signed order string the SDK expects. */
112
+ orderInfo;
113
+ /** The signature of `orderInfo`. */
114
+ sign;
115
+ /** The signature algorithm, e.g. `SHA256`. */
116
+ signType;
117
+ /** The gateway's response, for logging. Left out of `toJSON()`. */
118
+ raw;
119
+ constructor(init) {
120
+ this.orderId = init.orderId;
121
+ this.orderInfo = init.orderInfo;
122
+ this.sign = init.sign;
123
+ this.signType = init.signType;
124
+ this.raw = init.raw ?? {};
125
+ }
126
+ /** The values your app needs: `orderId`, `orderInfo`, `sign` and `signType`. */
127
+ toJSON() {
128
+ return {
129
+ orderId: this.orderId,
130
+ orderInfo: this.orderInfo,
131
+ sign: this.sign,
132
+ signType: this.signType,
133
+ };
134
+ }
135
+ }
136
+ exports.AppPayment = AppPayment;
137
+ const HTML_ESCAPES = {
138
+ '&': '&amp;',
139
+ '<': '&lt;',
140
+ '>': '&gt;',
141
+ '"': '&#34;',
142
+ "'": '&#39;',
143
+ };
144
+ /** Escapes text for HTML content and attribute values. @internal */
145
+ function escapeHtml(value) {
146
+ return value.replace(/[&<>"']/g, (char) => HTML_ESCAPES[char]);
147
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * A gateway-independent payment status. Every gateway's own status values are mapped onto these.
3
+ */
4
+ export type PaymentStatus = 'successful' | 'pending' | 'failed' | 'cancelled' | 'expired' | 'unknown';
5
+ /**
6
+ * The payment statuses, plus helpers.
7
+ *
8
+ * ```ts
9
+ * if (callback.status === PaymentStatus.Successful) { ... }
10
+ * PaymentStatus.isFinal(result.status)
11
+ * ```
12
+ */
13
+ export declare const PaymentStatus: Readonly<{
14
+ /** The customer paid. The only status that means money was collected. */
15
+ Successful: "successful";
16
+ /** The payment is still in progress or waiting on the customer. */
17
+ Pending: "pending";
18
+ /** The payment was attempted and failed or was rejected. */
19
+ Failed: "failed";
20
+ /** The payment or order was canceled or closed before completing. */
21
+ Cancelled: "cancelled";
22
+ /** The payment window ran out before the customer paid. */
23
+ Expired: "expired";
24
+ /** The gateway sent a status this package does not recognize. Inspect `gatewayStatus`. */
25
+ Unknown: "unknown";
26
+ /** Every status, in the order above. */
27
+ values: readonly ["successful", "pending", "failed", "cancelled", "expired", "unknown"];
28
+ /** Whether the status will not change any more: `false` for `pending` and `unknown`. */
29
+ isFinal(status: PaymentStatus): boolean;
30
+ }>;
31
+ /**
32
+ * Maps a gateway status onto a {@link PaymentStatus}, trimming whitespace. Statuses missing from
33
+ * the map resolve to `unknown`.
34
+ */
35
+ export declare function resolveStatus(statuses: Readonly<Record<string, PaymentStatus>>, gatewayStatus: string | null | undefined): PaymentStatus;
36
+ /**
37
+ * How the customer completes a payment after it has been initiated.
38
+ */
39
+ export type PaymentFlow = 'redirect' | 'form' | 'qr' | 'app';
40
+ /** The payment flows. */
41
+ export declare const PaymentFlow: Readonly<{
42
+ /** Send the customer's browser to a gateway-hosted URL. */
43
+ readonly Redirect: "redirect";
44
+ /** POST a signed form from the customer's browser to the gateway. */
45
+ readonly Form: "form";
46
+ /** Show a QR code the customer scans with their wallet app. */
47
+ readonly Qr: "qr";
48
+ /** Hand a signed payload to your mobile app, which opens the wallet SDK. */
49
+ readonly App: "app";
50
+ }>;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PaymentFlow = exports.PaymentStatus = void 0;
4
+ exports.resolveStatus = resolveStatus;
5
+ /**
6
+ * The payment statuses, plus helpers.
7
+ *
8
+ * ```ts
9
+ * if (callback.status === PaymentStatus.Successful) { ... }
10
+ * PaymentStatus.isFinal(result.status)
11
+ * ```
12
+ */
13
+ exports.PaymentStatus = Object.freeze({
14
+ /** The customer paid. The only status that means money was collected. */
15
+ Successful: 'successful',
16
+ /** The payment is still in progress or waiting on the customer. */
17
+ Pending: 'pending',
18
+ /** The payment was attempted and failed or was rejected. */
19
+ Failed: 'failed',
20
+ /** The payment or order was canceled or closed before completing. */
21
+ Cancelled: 'cancelled',
22
+ /** The payment window ran out before the customer paid. */
23
+ Expired: 'expired',
24
+ /** The gateway sent a status this package does not recognize. Inspect `gatewayStatus`. */
25
+ Unknown: 'unknown',
26
+ /** Every status, in the order above. */
27
+ values: Object.freeze([
28
+ 'successful',
29
+ 'pending',
30
+ 'failed',
31
+ 'cancelled',
32
+ 'expired',
33
+ 'unknown',
34
+ ]),
35
+ /** Whether the status will not change any more: `false` for `pending` and `unknown`. */
36
+ isFinal(status) {
37
+ return status !== 'pending' && status !== 'unknown';
38
+ },
39
+ });
40
+ /**
41
+ * Maps a gateway status onto a {@link PaymentStatus}, trimming whitespace. Statuses missing from
42
+ * the map resolve to `unknown`.
43
+ */
44
+ function resolveStatus(statuses, gatewayStatus) {
45
+ const key = (gatewayStatus ?? '').trim();
46
+ return Object.prototype.hasOwnProperty.call(statuses, key)
47
+ ? statuses[key]
48
+ : 'unknown';
49
+ }
50
+ /** The payment flows. */
51
+ exports.PaymentFlow = Object.freeze({
52
+ /** Send the customer's browser to a gateway-hosted URL. */
53
+ Redirect: 'redirect',
54
+ /** POST a signed form from the customer's browser to the gateway. */
55
+ Form: 'form',
56
+ /** Show a QR code the customer scans with their wallet app. */
57
+ Qr: 'qr',
58
+ /** Hand a signed payload to your mobile app, which opens the wallet SDK. */
59
+ App: 'app',
60
+ });
@@ -0,0 +1,46 @@
1
+ import { Amount } from './amount.js';
2
+ /** What a gateway's documentation allows for an amount. @internal */
3
+ export interface AmountRule {
4
+ /** The gateway's display name, used in error messages. */
5
+ gateway: string;
6
+ /** The most fractional digits allowed: 0 means whole amounts only, `null` means no limit. */
7
+ maxDecimals: number | null;
8
+ /** Limits the amount's text length. */
9
+ maxLength?: number;
10
+ /** Accepts an amount of 0. */
11
+ allowZero?: boolean;
12
+ }
13
+ /**
14
+ * Converts an amount input to an {@link Amount}, or `undefined` when it is missing or not a valid
15
+ * non-negative amount. Validation reports why.
16
+ *
17
+ * @internal
18
+ */
19
+ export declare function toAmount(value: unknown): Amount | undefined;
20
+ /** UTF-8 byte length, matching the byte limits in the gateway documentation. @internal */
21
+ export declare function byteLength(value: string): number;
22
+ /**
23
+ * Collects one error per field (the first one wins) and throws them together.
24
+ *
25
+ * @internal
26
+ */
27
+ export declare class Validator {
28
+ private readonly errors;
29
+ required(field: string, value: unknown): this;
30
+ /** Fails when the value is set but not a string. */
31
+ string(field: string, value: unknown): this;
32
+ length(field: string, value: string | undefined, min: number, max: number): this;
33
+ max(field: string, value: string | undefined, max: number): this;
34
+ pattern(field: string, value: string | undefined, pattern: RegExp, description: string): this;
35
+ /** Fails when a set value is not an integer within [min, max]. */
36
+ between(field: string, value: unknown, min: number, max: number): this;
37
+ amount(field: string, value: unknown, rule: AmountRule): this;
38
+ /** Fails when a set value is not an absolute http or https URL. */
39
+ url(field: string, value: string | undefined): this;
40
+ when(condition: boolean, field: string, message: string): this;
41
+ /** Whether any check failed so far. */
42
+ failed(): boolean;
43
+ /** Throws an {@link InvalidPaymentDataError} when any check failed. */
44
+ validate(): void;
45
+ private fail;
46
+ }