@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,180 @@
1
+ import { type LosslessObject } from './json.js';
2
+ import type { PaymentStatus } from './status.js';
3
+ /** Headers as a Fetch `Headers`, a Node-style object or `[name, value]` pairs. */
4
+ export type HeadersInput = Headers | Readonly<Record<string, string | readonly string[] | undefined>> | Iterable<readonly [string, string]>;
5
+ /** A query string, `URLSearchParams` or an object of values. */
6
+ export type QueryInput = string | URLSearchParams | Readonly<Record<string, string | readonly string[] | undefined>>;
7
+ /** A request body: text or raw bytes (a `Buffer` works). */
8
+ export type BodyInput = string | Uint8Array | ArrayBuffer;
9
+ /** The parts of a gateway request. */
10
+ export interface CallbackRequestInit {
11
+ /** The raw request body exactly as received. */
12
+ body?: BodyInput | null | undefined;
13
+ /** The request headers. */
14
+ headers?: HeadersInput | null | undefined;
15
+ /** The query string parameters. */
16
+ query?: QueryInput | null | undefined;
17
+ }
18
+ /**
19
+ * The parts of a Node `http.IncomingMessage` this package reads, so Express, Fastify (`request.raw`)
20
+ * and Koa (`ctx.req`) requests work too.
21
+ */
22
+ export interface NodeRequestLike extends AsyncIterable<unknown> {
23
+ headers: Readonly<Record<string, string | readonly string[] | undefined>>;
24
+ url?: string | undefined;
25
+ /** A raw body captured by middleware, e.g. `express.raw()` or a `verify` hook. */
26
+ rawBody?: unknown;
27
+ /** A body parsed by middleware. Used only when the stream was already consumed. */
28
+ body?: unknown;
29
+ }
30
+ /** The parts of a Fetch API `Request` this package reads. */
31
+ export interface WebRequestLike {
32
+ readonly url: string;
33
+ readonly headers: Headers;
34
+ readonly bodyUsed: boolean;
35
+ clone(): {
36
+ text(): Promise<string>;
37
+ };
38
+ }
39
+ /**
40
+ * An incoming request from a gateway (a server callback or a browser return). Signatures are
41
+ * verified against what the gateway actually sent, so build it from the real request with
42
+ * {@link CallbackRequest.fromNodeRequest} or {@link CallbackRequest.fromWebRequest}.
43
+ */
44
+ export declare class CallbackRequest {
45
+ /** The raw request body, decoded as UTF-8. */
46
+ readonly body: string;
47
+ /** The request headers, with lowercase names. Repeated headers are joined with `, `. */
48
+ readonly headers: Readonly<Record<string, string>>;
49
+ /** The query string parameters (the first value of each). */
50
+ readonly query: Readonly<Record<string, string>>;
51
+ constructor(init?: CallbackRequestInit);
52
+ /** Builds a request from its parts, e.g. to replay a stored callback. */
53
+ static from(init: CallbackRequestInit): CallbackRequest;
54
+ /**
55
+ * Builds a request from a decoded payload, encoded as a JSON body, e.g. to replay a callback
56
+ * stored as JSON.
57
+ */
58
+ static fromJson(payload: unknown, headers?: HeadersInput | null): CallbackRequest;
59
+ /**
60
+ * Reads a Node `http.IncomingMessage` (also Express `req`, Fastify `request.raw`, Koa `ctx.req`).
61
+ * Reads the raw body from the stream, or from `rawBody`/`body` when middleware captured it as
62
+ * text or bytes. When a body parser already consumed the stream, the parsed `body` is encoded
63
+ * again as JSON or a form.
64
+ */
65
+ static fromNodeRequest(request: NodeRequestLike): Promise<CallbackRequest>;
66
+ /**
67
+ * Reads a Fetch API `Request` (Next.js route handlers, Hono, Bun, Deno, Cloudflare Workers). The
68
+ * body is read from a clone, so the request stays readable.
69
+ */
70
+ static fromWebRequest(request: WebRequestLike): Promise<CallbackRequest>;
71
+ /** The named header, matched case-insensitively, or `undefined`. */
72
+ header(name: string): string | undefined;
73
+ /** The body decoded as JSON or as a urlencoded form. */
74
+ parsedBody(): Record<string, unknown>;
75
+ /** The parsed body merged over the query string. */
76
+ input(): Record<string, unknown>;
77
+ /** The query string merged over the parsed body. */
78
+ queryInput(): Record<string, unknown>;
79
+ }
80
+ /** The body as JSON (numbers kept exact) or a form, or `{}`. @internal */
81
+ export declare function losslessBody(request: CallbackRequest): LosslessObject;
82
+ /** @internal */
83
+ export declare function losslessInput(request: CallbackRequest): LosslessObject;
84
+ /** @internal */
85
+ export declare function losslessQueryInput(request: CallbackRequest): LosslessObject;
86
+ /** The headers, a status and a body a gateway expects after it delivers a callback. */
87
+ export interface AcknowledgementInit {
88
+ status?: number | undefined;
89
+ body?: string | undefined;
90
+ headers?: Readonly<Record<string, string>> | undefined;
91
+ }
92
+ /** The parts of a Node `http.ServerResponse` (or Express `res`) {@link Acknowledgement.send} uses. */
93
+ export interface ServerResponseLike {
94
+ statusCode: number;
95
+ setHeader(name: string, value: string): unknown;
96
+ end(body?: string): unknown;
97
+ }
98
+ /**
99
+ * The HTTP response a gateway expects after it delivers a callback. Gateways retry until they
100
+ * receive it.
101
+ */
102
+ export declare class Acknowledgement {
103
+ /** The HTTP status, 200 unless a gateway documents another. */
104
+ readonly status: number;
105
+ /** The response body, e.g. KBZ Pay's plain `success`. */
106
+ readonly body: string;
107
+ /** The response headers. */
108
+ readonly headers: Readonly<Record<string, string>>;
109
+ constructor(init?: AcknowledgementInit);
110
+ /** An empty `200 text/plain` response, which most gateways expect. */
111
+ static default(): Acknowledgement;
112
+ /** Writes the acknowledgement to a Node `http.ServerResponse` (or Express `res`) and ends it. */
113
+ send(response: ServerResponseLike): void;
114
+ /** The acknowledgement as a Fetch API `Response`, for Next.js, Hono, Bun and other Fetch servers. */
115
+ toResponse(): Response;
116
+ }
117
+ /** The fields of a {@link PaymentCallback}. */
118
+ export interface PaymentCallbackInit {
119
+ orderId: string;
120
+ status: PaymentStatus;
121
+ gatewayStatus: string;
122
+ gatewayReference?: string | undefined;
123
+ amount?: string | undefined;
124
+ raw?: Readonly<Record<string, unknown>> | undefined;
125
+ acknowledgement?: Acknowledgement | undefined;
126
+ }
127
+ /**
128
+ * A gateway notification whose signature has been verified.
129
+ *
130
+ * Always compare `amount` with your order before fulfilling it, and handle duplicates: gateways
131
+ * retry.
132
+ */
133
+ export declare class PaymentCallback {
134
+ /** Your order id. */
135
+ readonly orderId: string;
136
+ /** The status mapped onto this package's statuses. */
137
+ readonly status: PaymentStatus;
138
+ /** The gateway's own status value, unmapped. */
139
+ readonly gatewayStatus: string;
140
+ /** The gateway's id for the payment, when it sends one. */
141
+ readonly gatewayReference: string | undefined;
142
+ /** The amount the gateway reports, exactly as it sent it, when it sends one. */
143
+ readonly amount: string | undefined;
144
+ /** The verified payload. */
145
+ readonly raw: Readonly<Record<string, unknown>>;
146
+ /** The response to send so the gateway stops retrying. */
147
+ readonly acknowledgement: Acknowledgement;
148
+ constructor(init: PaymentCallbackInit);
149
+ /** Whether the customer paid. */
150
+ isSuccessful(): boolean;
151
+ }
152
+ /** The fields of a {@link PaymentStatusResult}. */
153
+ export interface PaymentStatusResultInit {
154
+ orderId?: string | undefined;
155
+ status: PaymentStatus;
156
+ gatewayStatus: string;
157
+ gatewayReference?: string | undefined;
158
+ amount?: string | undefined;
159
+ raw?: Readonly<Record<string, unknown>> | undefined;
160
+ }
161
+ /**
162
+ * The state of a payment as reported by a gateway's status API.
163
+ */
164
+ export declare class PaymentStatusResult {
165
+ /** Your order id, when the gateway returns it. */
166
+ readonly orderId: string | undefined;
167
+ /** The status mapped onto this package's statuses. */
168
+ readonly status: PaymentStatus;
169
+ /** The gateway's own status value, unmapped. */
170
+ readonly gatewayStatus: string;
171
+ /** The gateway's id for the payment, when it sends one. */
172
+ readonly gatewayReference: string | undefined;
173
+ /** The amount the gateway reports, exactly as it sent it, when it sends one. */
174
+ readonly amount: string | undefined;
175
+ /** The gateway's response, for logging. */
176
+ readonly raw: Readonly<Record<string, unknown>>;
177
+ constructor(init: PaymentStatusResultInit);
178
+ /** Whether the customer paid. */
179
+ isSuccessful(): boolean;
180
+ }
@@ -0,0 +1,294 @@
1
+ import { parseJsonObject, setKey, toPlainObject } from './json.js';
2
+ /**
3
+ * An incoming request from a gateway (a server callback or a browser return). Signatures are
4
+ * verified against what the gateway actually sent, so build it from the real request with
5
+ * {@link CallbackRequest.fromNodeRequest} or {@link CallbackRequest.fromWebRequest}.
6
+ */
7
+ export class CallbackRequest {
8
+ /** The raw request body, decoded as UTF-8. */
9
+ body;
10
+ /** The request headers, with lowercase names. Repeated headers are joined with `, `. */
11
+ headers;
12
+ /** The query string parameters (the first value of each). */
13
+ query;
14
+ constructor(init = {}) {
15
+ this.body = bodyText(init.body);
16
+ this.headers = Object.freeze(normalizeHeaders(init.headers));
17
+ this.query = Object.freeze(normalizeQuery(init.query));
18
+ }
19
+ /** Builds a request from its parts, e.g. to replay a stored callback. */
20
+ static from(init) {
21
+ return new CallbackRequest(init);
22
+ }
23
+ /**
24
+ * Builds a request from a decoded payload, encoded as a JSON body, e.g. to replay a callback
25
+ * stored as JSON.
26
+ */
27
+ static fromJson(payload, headers) {
28
+ return new CallbackRequest({
29
+ body: JSON.stringify(payload),
30
+ headers: { ...normalizeHeaders(headers), 'content-type': 'application/json' },
31
+ });
32
+ }
33
+ /**
34
+ * Reads a Node `http.IncomingMessage` (also Express `req`, Fastify `request.raw`, Koa `ctx.req`).
35
+ * Reads the raw body from the stream, or from `rawBody`/`body` when middleware captured it as
36
+ * text or bytes. When a body parser already consumed the stream, the parsed `body` is encoded
37
+ * again as JSON or a form.
38
+ */
39
+ static async fromNodeRequest(request) {
40
+ const headers = normalizeHeaders(request.headers);
41
+ const query = new URL(request.url ?? '/', 'http://localhost').searchParams;
42
+ let body = rawBody(request.rawBody) ?? rawBody(request.body);
43
+ if (body === undefined) {
44
+ const chunks = [];
45
+ for await (const chunk of request) {
46
+ chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk);
47
+ }
48
+ body = Buffer.concat(chunks);
49
+ if (body.length === 0 && isPlainObject(request.body)) {
50
+ body = encodeParsedBody(request.body, headers['content-type'] ?? '');
51
+ }
52
+ }
53
+ return new CallbackRequest({ body, headers, query });
54
+ }
55
+ /**
56
+ * Reads a Fetch API `Request` (Next.js route handlers, Hono, Bun, Deno, Cloudflare Workers). The
57
+ * body is read from a clone, so the request stays readable.
58
+ */
59
+ static async fromWebRequest(request) {
60
+ return new CallbackRequest({
61
+ body: request.bodyUsed ? '' : await request.clone().text(),
62
+ headers: request.headers,
63
+ query: new URL(request.url).searchParams,
64
+ });
65
+ }
66
+ /** The named header, matched case-insensitively, or `undefined`. */
67
+ header(name) {
68
+ return this.headers[name.toLowerCase()];
69
+ }
70
+ /** The body decoded as JSON or as a urlencoded form. */
71
+ parsedBody() {
72
+ return toPlainObject(losslessBody(this));
73
+ }
74
+ /** The parsed body merged over the query string. */
75
+ input() {
76
+ return toPlainObject(losslessInput(this));
77
+ }
78
+ /** The query string merged over the parsed body. */
79
+ queryInput() {
80
+ return toPlainObject(losslessQueryInput(this));
81
+ }
82
+ }
83
+ /** The body as JSON (numbers kept exact) or a form, or `{}`. @internal */
84
+ export function losslessBody(request) {
85
+ const body = request.body.trim();
86
+ if (body === '') {
87
+ return {};
88
+ }
89
+ const json = parseJsonObject(body);
90
+ if (json !== undefined) {
91
+ return json;
92
+ }
93
+ return firstValues(new URLSearchParams(body));
94
+ }
95
+ /** @internal */
96
+ export function losslessInput(request) {
97
+ return merge({ ...request.query }, losslessBody(request));
98
+ }
99
+ /** @internal */
100
+ export function losslessQueryInput(request) {
101
+ return merge(losslessBody(request), request.query);
102
+ }
103
+ function merge(target, source) {
104
+ const result = {};
105
+ for (const object of [target, source]) {
106
+ for (const key of Object.keys(object)) {
107
+ setKey(result, key, object[key]);
108
+ }
109
+ }
110
+ return result;
111
+ }
112
+ /**
113
+ * The HTTP response a gateway expects after it delivers a callback. Gateways retry until they
114
+ * receive it.
115
+ */
116
+ export class Acknowledgement {
117
+ /** The HTTP status, 200 unless a gateway documents another. */
118
+ status;
119
+ /** The response body, e.g. KBZ Pay's plain `success`. */
120
+ body;
121
+ /** The response headers. */
122
+ headers;
123
+ constructor(init = {}) {
124
+ this.status = init.status ?? 200;
125
+ this.body = init.body ?? '';
126
+ this.headers = Object.freeze({ ...(init.headers ?? { 'Content-Type': 'text/plain' }) });
127
+ }
128
+ /** An empty `200 text/plain` response, which most gateways expect. */
129
+ static default() {
130
+ return new Acknowledgement();
131
+ }
132
+ /** Writes the acknowledgement to a Node `http.ServerResponse` (or Express `res`) and ends it. */
133
+ send(response) {
134
+ response.statusCode = this.status;
135
+ for (const [name, value] of Object.entries(this.headers)) {
136
+ response.setHeader(name, value);
137
+ }
138
+ response.end(this.body);
139
+ }
140
+ /** The acknowledgement as a Fetch API `Response`, for Next.js, Hono, Bun and other Fetch servers. */
141
+ toResponse() {
142
+ return new Response(this.body, { status: this.status, headers: { ...this.headers } });
143
+ }
144
+ }
145
+ /**
146
+ * A gateway notification whose signature has been verified.
147
+ *
148
+ * Always compare `amount` with your order before fulfilling it, and handle duplicates: gateways
149
+ * retry.
150
+ */
151
+ export class PaymentCallback {
152
+ /** Your order id. */
153
+ orderId;
154
+ /** The status mapped onto this package's statuses. */
155
+ status;
156
+ /** The gateway's own status value, unmapped. */
157
+ gatewayStatus;
158
+ /** The gateway's id for the payment, when it sends one. */
159
+ gatewayReference;
160
+ /** The amount the gateway reports, exactly as it sent it, when it sends one. */
161
+ amount;
162
+ /** The verified payload. */
163
+ raw;
164
+ /** The response to send so the gateway stops retrying. */
165
+ acknowledgement;
166
+ constructor(init) {
167
+ this.orderId = init.orderId;
168
+ this.status = init.status;
169
+ this.gatewayStatus = init.gatewayStatus;
170
+ this.gatewayReference = init.gatewayReference;
171
+ this.amount = init.amount;
172
+ this.raw = init.raw ?? {};
173
+ this.acknowledgement = init.acknowledgement ?? Acknowledgement.default();
174
+ }
175
+ /** Whether the customer paid. */
176
+ isSuccessful() {
177
+ return this.status === 'successful';
178
+ }
179
+ }
180
+ /**
181
+ * The state of a payment as reported by a gateway's status API.
182
+ */
183
+ export class PaymentStatusResult {
184
+ /** Your order id, when the gateway returns it. */
185
+ orderId;
186
+ /** The status mapped onto this package's statuses. */
187
+ status;
188
+ /** The gateway's own status value, unmapped. */
189
+ gatewayStatus;
190
+ /** The gateway's id for the payment, when it sends one. */
191
+ gatewayReference;
192
+ /** The amount the gateway reports, exactly as it sent it, when it sends one. */
193
+ amount;
194
+ /** The gateway's response, for logging. */
195
+ raw;
196
+ constructor(init) {
197
+ this.orderId = init.orderId;
198
+ this.status = init.status;
199
+ this.gatewayStatus = init.gatewayStatus;
200
+ this.gatewayReference = init.gatewayReference;
201
+ this.amount = init.amount;
202
+ this.raw = init.raw ?? {};
203
+ }
204
+ /** Whether the customer paid. */
205
+ isSuccessful() {
206
+ return this.status === 'successful';
207
+ }
208
+ }
209
+ function bodyText(body) {
210
+ if (body === undefined || body === null) {
211
+ return '';
212
+ }
213
+ if (typeof body === 'string') {
214
+ return body;
215
+ }
216
+ return new TextDecoder().decode(body);
217
+ }
218
+ function rawBody(value) {
219
+ if (typeof value === 'string' || value instanceof Uint8Array || value instanceof ArrayBuffer) {
220
+ return value;
221
+ }
222
+ return undefined;
223
+ }
224
+ function isPlainObject(value) {
225
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
226
+ }
227
+ function encodeParsedBody(body, contentType) {
228
+ if (!contentType.toLowerCase().includes('urlencoded')) {
229
+ return JSON.stringify(body);
230
+ }
231
+ const form = new URLSearchParams();
232
+ for (const [key, value] of Object.entries(body)) {
233
+ for (const item of Array.isArray(value) ? value : [value]) {
234
+ form.append(key, String(item));
235
+ }
236
+ }
237
+ return form.toString();
238
+ }
239
+ function normalizeHeaders(headers) {
240
+ const result = {};
241
+ if (headers === undefined || headers === null) {
242
+ return result;
243
+ }
244
+ const add = (name, value) => {
245
+ if (value === undefined) {
246
+ return;
247
+ }
248
+ const text = typeof value === 'string' ? value : value.join(', ');
249
+ const key = name.toLowerCase();
250
+ setKey(result, key, result[key] === undefined ? text : `${result[key]}, ${text}`);
251
+ };
252
+ if (typeof headers.forEach === 'function' &&
253
+ typeof headers.get === 'function') {
254
+ headers.forEach((value, name) => {
255
+ add(name, value);
256
+ });
257
+ }
258
+ else if (Symbol.iterator in headers) {
259
+ for (const [name, value] of headers) {
260
+ add(name, value);
261
+ }
262
+ }
263
+ else {
264
+ for (const [name, value] of Object.entries(headers)) {
265
+ add(name, value);
266
+ }
267
+ }
268
+ return result;
269
+ }
270
+ function normalizeQuery(query) {
271
+ if (query === undefined || query === null) {
272
+ return {};
273
+ }
274
+ if (typeof query === 'string' || query instanceof URLSearchParams) {
275
+ return firstValues(new URLSearchParams(query));
276
+ }
277
+ const result = {};
278
+ for (const [key, value] of Object.entries(query)) {
279
+ const first = typeof value === 'string' ? value : value?.[0];
280
+ if (first !== undefined) {
281
+ setKey(result, key, first);
282
+ }
283
+ }
284
+ return result;
285
+ }
286
+ function firstValues(params) {
287
+ const result = {};
288
+ for (const [key, value] of params) {
289
+ if (!Object.prototype.hasOwnProperty.call(result, key)) {
290
+ setKey(result, key, value);
291
+ }
292
+ }
293
+ return result;
294
+ }
@@ -0,0 +1,19 @@
1
+ /** HMAC-SHA256 of `message`, hex encoded. @internal */
2
+ export declare function hmacSha256Hex(key: string, message: string): string;
3
+ /** HMAC-SHA256 of `message`, base64 encoded. @internal */
4
+ export declare function hmacSha256Base64(key: string, message: string): string;
5
+ /** SHA-256 of `message`, hex encoded. @internal */
6
+ export declare function sha256Hex(message: string): string;
7
+ /** Compares two strings in constant time (for equal lengths). @internal */
8
+ export declare function safeEqual(expected: string, actual: string): boolean;
9
+ /** `bytes` random bytes, hex encoded. @internal */
10
+ export declare function randomHex(bytes?: number): string;
11
+ /**
12
+ * Escapes text like Go's `url.QueryEscape` and PHP's `urlencode`: everything except letters,
13
+ * digits and `-_.~` is percent-encoded and spaces become `+`.
14
+ *
15
+ * @internal
16
+ */
17
+ export declare function queryEscape(value: string): string;
18
+ /** Decodes strict standard base64 (with padding), or `undefined`. @internal */
19
+ export declare function decodeBase64(value: string): string | undefined;
@@ -0,0 +1,41 @@
1
+ import { createHash, createHmac, randomBytes, timingSafeEqual } from 'node:crypto';
2
+ /** HMAC-SHA256 of `message`, hex encoded. @internal */
3
+ export function hmacSha256Hex(key, message) {
4
+ return createHmac('sha256', key).update(message, 'utf8').digest('hex');
5
+ }
6
+ /** HMAC-SHA256 of `message`, base64 encoded. @internal */
7
+ export function hmacSha256Base64(key, message) {
8
+ return createHmac('sha256', key).update(message, 'utf8').digest('base64');
9
+ }
10
+ /** SHA-256 of `message`, hex encoded. @internal */
11
+ export function sha256Hex(message) {
12
+ return createHash('sha256').update(message, 'utf8').digest('hex');
13
+ }
14
+ /** Compares two strings in constant time (for equal lengths). @internal */
15
+ export function safeEqual(expected, actual) {
16
+ const a = Buffer.from(expected, 'utf8');
17
+ const b = Buffer.from(actual, 'utf8');
18
+ return a.length === b.length && timingSafeEqual(a, b);
19
+ }
20
+ /** `bytes` random bytes, hex encoded. @internal */
21
+ export function randomHex(bytes = 16) {
22
+ return randomBytes(bytes).toString('hex');
23
+ }
24
+ /**
25
+ * Escapes text like Go's `url.QueryEscape` and PHP's `urlencode`: everything except letters,
26
+ * digits and `-_.~` is percent-encoded and spaces become `+`.
27
+ *
28
+ * @internal
29
+ */
30
+ export function queryEscape(value) {
31
+ return encodeURIComponent(value)
32
+ .replace(/[!'()*]/g, (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`)
33
+ .replace(/%20/g, '+');
34
+ }
35
+ /** Decodes strict standard base64 (with padding), or `undefined`. @internal */
36
+ export function decodeBase64(value) {
37
+ if (value === '' || value.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(value)) {
38
+ return undefined;
39
+ }
40
+ return Buffer.from(value, 'base64').toString('utf8');
41
+ }
@@ -0,0 +1,21 @@
1
+ /** Environment variables, e.g. `process.env`. */
2
+ export type EnvSource = Readonly<Record<string, string | undefined>>;
3
+ /** The first non-empty value among `keys`, trimmed, or `''`. @internal */
4
+ export declare function envFirst(env: EnvSource, ...keys: string[]): string;
5
+ /**
6
+ * Reads a `*_SANDBOX` variable. Only `false`, `0`, `f`, `no` and `off` (any case) select
7
+ * production; unset or unrecognized values mean sandbox.
8
+ *
9
+ * @internal
10
+ */
11
+ export declare function envSandbox(env: EnvSource, key: string): boolean;
12
+ /** An integer variable, or `undefined` when unset or not an integer. @internal */
13
+ export declare function envInt(env: EnvSource, key: string): number | undefined;
14
+ /** The trimmed value, or throws a {@link ConfigurationError} naming `key`. @internal */
15
+ export declare function requireSetting(gateway: string, key: string, value: unknown): string;
16
+ /** A trimmed optional string, `undefined` when blank. @internal */
17
+ export declare function optionalSetting(value: unknown): string | undefined;
18
+ /** Removes trailing slashes. @internal */
19
+ export declare function trimUrl(url: string): string;
20
+ /** The default environment: `process.env`. @internal */
21
+ export declare function defaultEnv(): EnvSource;
@@ -0,0 +1,45 @@
1
+ import { ConfigurationError } from './errors.js';
2
+ /** The first non-empty value among `keys`, trimmed, or `''`. @internal */
3
+ export function envFirst(env, ...keys) {
4
+ for (const key of keys) {
5
+ const value = env[key]?.trim();
6
+ if (value) {
7
+ return value;
8
+ }
9
+ }
10
+ return '';
11
+ }
12
+ /**
13
+ * Reads a `*_SANDBOX` variable. Only `false`, `0`, `f`, `no` and `off` (any case) select
14
+ * production; unset or unrecognized values mean sandbox.
15
+ *
16
+ * @internal
17
+ */
18
+ export function envSandbox(env, key) {
19
+ const value = env[key]?.trim().toLowerCase() ?? '';
20
+ return !['false', '0', 'f', 'no', 'off'].includes(value);
21
+ }
22
+ /** An integer variable, or `undefined` when unset or not an integer. @internal */
23
+ export function envInt(env, key) {
24
+ const value = env[key]?.trim() ?? '';
25
+ return /^[+-]?\d+$/.test(value) ? Number.parseInt(value, 10) : undefined;
26
+ }
27
+ /** The trimmed value, or throws a {@link ConfigurationError} naming `key`. @internal */
28
+ export function requireSetting(gateway, key, value) {
29
+ if (typeof value !== 'string' || value.trim() === '') {
30
+ throw new ConfigurationError(gateway, key);
31
+ }
32
+ return value;
33
+ }
34
+ /** A trimmed optional string, `undefined` when blank. @internal */
35
+ export function optionalSetting(value) {
36
+ return typeof value === 'string' && value.trim() !== '' ? value : undefined;
37
+ }
38
+ /** Removes trailing slashes. @internal */
39
+ export function trimUrl(url) {
40
+ return url.replace(/\/+$/, '');
41
+ }
42
+ /** The default environment: `process.env`. @internal */
43
+ export function defaultEnv() {
44
+ return process.env;
45
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Base class of every error thrown by this package.
3
+ */
4
+ export declare class PaymentError extends Error {
5
+ constructor(message: string, options?: {
6
+ cause?: unknown;
7
+ });
8
+ }
9
+ /**
10
+ * Thrown when payment data has values the gateway would reject. Thrown before any request is sent.
11
+ */
12
+ export declare class InvalidPaymentDataError extends PaymentError {
13
+ /** Field name to error message, e.g. `{ amount: 'The amount field is required.' }`. */
14
+ readonly errors: Readonly<Record<string, string>>;
15
+ constructor(errors: Record<string, string>);
16
+ }
17
+ /**
18
+ * Thrown when a gateway rejects a request or answers with an error, including errors sent with
19
+ * HTTP 200, or when it cannot be reached (the network error is the `cause`).
20
+ */
21
+ export declare class ApiError extends PaymentError {
22
+ /** The gateway's own error code, e.g. `ORDER_ID_USED` or `09`. */
23
+ readonly gatewayCode: string | undefined;
24
+ /** The gateway's own error message. */
25
+ readonly gatewayMessage: string | undefined;
26
+ /** The HTTP status of the response, or `0` when no response was received. */
27
+ readonly httpStatus: number;
28
+ /** The decoded response body. */
29
+ readonly raw: Readonly<Record<string, unknown>>;
30
+ constructor(message: string, details?: {
31
+ gatewayCode?: string | undefined;
32
+ gatewayMessage?: string | undefined;
33
+ httpStatus?: number;
34
+ raw?: Record<string, unknown>;
35
+ cause?: unknown;
36
+ });
37
+ }
38
+ /**
39
+ * Thrown when a callback, return redirect or gateway response fails signature verification.
40
+ * Never act on its payload.
41
+ */
42
+ export declare class SignatureVerificationError extends PaymentError {
43
+ /** The unverified payload, for logging only. */
44
+ readonly raw: Readonly<Record<string, unknown>>;
45
+ constructor(message: string, raw?: Record<string, unknown>);
46
+ }
47
+ /**
48
+ * Thrown when a gateway is missing a credential or setting it needs.
49
+ */
50
+ export declare class ConfigurationError extends PaymentError {
51
+ /** The gateway, e.g. `kbz_pay`. */
52
+ readonly gateway: string;
53
+ /** The missing setting, e.g. `app_key`. */
54
+ readonly key: string;
55
+ constructor(gateway: string, key: string);
56
+ }