@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,26 @@
1
+ type MaybePromise<T> = T | Promise<T>;
2
+ /**
3
+ * Stores access tokens between calls (used by Yoma MMQR). Implement it on top of Redis or similar
4
+ * to share tokens between processes; every method may return a promise.
5
+ */
6
+ export interface TokenCache {
7
+ /** The cached value, or `undefined` when it is missing or expired. */
8
+ get(key: string): MaybePromise<string | undefined | null>;
9
+ /** Stores `value` for `ttlSeconds`; `0` or less never expires. */
10
+ set(key: string, value: string, ttlSeconds: number): MaybePromise<unknown>;
11
+ /** Removes `key`. */
12
+ delete(key: string): MaybePromise<unknown>;
13
+ }
14
+ /**
15
+ * The default {@link TokenCache}: a `Map` that lives as long as the process. Share one gateway (or
16
+ * one cache) across requests so the token is reused.
17
+ */
18
+ export declare class MemoryTokenCache implements TokenCache {
19
+ private readonly items;
20
+ get(key: string): string | undefined;
21
+ set(key: string, value: string, ttlSeconds: number): void;
22
+ delete(key: string): void;
23
+ /** Removes every entry. */
24
+ clear(): void;
25
+ }
26
+ export {};
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MemoryTokenCache = void 0;
4
+ /**
5
+ * The default {@link TokenCache}: a `Map` that lives as long as the process. Share one gateway (or
6
+ * one cache) across requests so the token is reused.
7
+ */
8
+ class MemoryTokenCache {
9
+ items = new Map();
10
+ get(key) {
11
+ const item = this.items.get(key);
12
+ if (item === undefined) {
13
+ return undefined;
14
+ }
15
+ if (item.expiresAt !== undefined && Date.now() >= item.expiresAt) {
16
+ this.items.delete(key);
17
+ return undefined;
18
+ }
19
+ return item.value;
20
+ }
21
+ set(key, value, ttlSeconds) {
22
+ this.items.set(key, {
23
+ value,
24
+ expiresAt: ttlSeconds > 0 ? Date.now() + ttlSeconds * 1000 : undefined,
25
+ });
26
+ }
27
+ delete(key) {
28
+ this.items.delete(key);
29
+ }
30
+ /** Removes every entry. */
31
+ clear() {
32
+ this.items.clear();
33
+ }
34
+ }
35
+ exports.MemoryTokenCache = MemoryTokenCache;
@@ -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,304 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PaymentStatusResult = exports.PaymentCallback = exports.Acknowledgement = exports.CallbackRequest = void 0;
4
+ exports.losslessBody = losslessBody;
5
+ exports.losslessInput = losslessInput;
6
+ exports.losslessQueryInput = losslessQueryInput;
7
+ const json_js_1 = require("./json.js");
8
+ /**
9
+ * An incoming request from a gateway (a server callback or a browser return). Signatures are
10
+ * verified against what the gateway actually sent, so build it from the real request with
11
+ * {@link CallbackRequest.fromNodeRequest} or {@link CallbackRequest.fromWebRequest}.
12
+ */
13
+ class CallbackRequest {
14
+ /** The raw request body, decoded as UTF-8. */
15
+ body;
16
+ /** The request headers, with lowercase names. Repeated headers are joined with `, `. */
17
+ headers;
18
+ /** The query string parameters (the first value of each). */
19
+ query;
20
+ constructor(init = {}) {
21
+ this.body = bodyText(init.body);
22
+ this.headers = Object.freeze(normalizeHeaders(init.headers));
23
+ this.query = Object.freeze(normalizeQuery(init.query));
24
+ }
25
+ /** Builds a request from its parts, e.g. to replay a stored callback. */
26
+ static from(init) {
27
+ return new CallbackRequest(init);
28
+ }
29
+ /**
30
+ * Builds a request from a decoded payload, encoded as a JSON body, e.g. to replay a callback
31
+ * stored as JSON.
32
+ */
33
+ static fromJson(payload, headers) {
34
+ return new CallbackRequest({
35
+ body: JSON.stringify(payload),
36
+ headers: { ...normalizeHeaders(headers), 'content-type': 'application/json' },
37
+ });
38
+ }
39
+ /**
40
+ * Reads a Node `http.IncomingMessage` (also Express `req`, Fastify `request.raw`, Koa `ctx.req`).
41
+ * Reads the raw body from the stream, or from `rawBody`/`body` when middleware captured it as
42
+ * text or bytes. When a body parser already consumed the stream, the parsed `body` is encoded
43
+ * again as JSON or a form.
44
+ */
45
+ static async fromNodeRequest(request) {
46
+ const headers = normalizeHeaders(request.headers);
47
+ const query = new URL(request.url ?? '/', 'http://localhost').searchParams;
48
+ let body = rawBody(request.rawBody) ?? rawBody(request.body);
49
+ if (body === undefined) {
50
+ const chunks = [];
51
+ for await (const chunk of request) {
52
+ chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk);
53
+ }
54
+ body = Buffer.concat(chunks);
55
+ if (body.length === 0 && isPlainObject(request.body)) {
56
+ body = encodeParsedBody(request.body, headers['content-type'] ?? '');
57
+ }
58
+ }
59
+ return new CallbackRequest({ body, headers, query });
60
+ }
61
+ /**
62
+ * Reads a Fetch API `Request` (Next.js route handlers, Hono, Bun, Deno, Cloudflare Workers). The
63
+ * body is read from a clone, so the request stays readable.
64
+ */
65
+ static async fromWebRequest(request) {
66
+ return new CallbackRequest({
67
+ body: request.bodyUsed ? '' : await request.clone().text(),
68
+ headers: request.headers,
69
+ query: new URL(request.url).searchParams,
70
+ });
71
+ }
72
+ /** The named header, matched case-insensitively, or `undefined`. */
73
+ header(name) {
74
+ return this.headers[name.toLowerCase()];
75
+ }
76
+ /** The body decoded as JSON or as a urlencoded form. */
77
+ parsedBody() {
78
+ return (0, json_js_1.toPlainObject)(losslessBody(this));
79
+ }
80
+ /** The parsed body merged over the query string. */
81
+ input() {
82
+ return (0, json_js_1.toPlainObject)(losslessInput(this));
83
+ }
84
+ /** The query string merged over the parsed body. */
85
+ queryInput() {
86
+ return (0, json_js_1.toPlainObject)(losslessQueryInput(this));
87
+ }
88
+ }
89
+ exports.CallbackRequest = CallbackRequest;
90
+ /** The body as JSON (numbers kept exact) or a form, or `{}`. @internal */
91
+ function losslessBody(request) {
92
+ const body = request.body.trim();
93
+ if (body === '') {
94
+ return {};
95
+ }
96
+ const json = (0, json_js_1.parseJsonObject)(body);
97
+ if (json !== undefined) {
98
+ return json;
99
+ }
100
+ return firstValues(new URLSearchParams(body));
101
+ }
102
+ /** @internal */
103
+ function losslessInput(request) {
104
+ return merge({ ...request.query }, losslessBody(request));
105
+ }
106
+ /** @internal */
107
+ function losslessQueryInput(request) {
108
+ return merge(losslessBody(request), request.query);
109
+ }
110
+ function merge(target, source) {
111
+ const result = {};
112
+ for (const object of [target, source]) {
113
+ for (const key of Object.keys(object)) {
114
+ (0, json_js_1.setKey)(result, key, object[key]);
115
+ }
116
+ }
117
+ return result;
118
+ }
119
+ /**
120
+ * The HTTP response a gateway expects after it delivers a callback. Gateways retry until they
121
+ * receive it.
122
+ */
123
+ class Acknowledgement {
124
+ /** The HTTP status, 200 unless a gateway documents another. */
125
+ status;
126
+ /** The response body, e.g. KBZ Pay's plain `success`. */
127
+ body;
128
+ /** The response headers. */
129
+ headers;
130
+ constructor(init = {}) {
131
+ this.status = init.status ?? 200;
132
+ this.body = init.body ?? '';
133
+ this.headers = Object.freeze({ ...(init.headers ?? { 'Content-Type': 'text/plain' }) });
134
+ }
135
+ /** An empty `200 text/plain` response, which most gateways expect. */
136
+ static default() {
137
+ return new Acknowledgement();
138
+ }
139
+ /** Writes the acknowledgement to a Node `http.ServerResponse` (or Express `res`) and ends it. */
140
+ send(response) {
141
+ response.statusCode = this.status;
142
+ for (const [name, value] of Object.entries(this.headers)) {
143
+ response.setHeader(name, value);
144
+ }
145
+ response.end(this.body);
146
+ }
147
+ /** The acknowledgement as a Fetch API `Response`, for Next.js, Hono, Bun and other Fetch servers. */
148
+ toResponse() {
149
+ return new Response(this.body, { status: this.status, headers: { ...this.headers } });
150
+ }
151
+ }
152
+ exports.Acknowledgement = Acknowledgement;
153
+ /**
154
+ * A gateway notification whose signature has been verified.
155
+ *
156
+ * Always compare `amount` with your order before fulfilling it, and handle duplicates: gateways
157
+ * retry.
158
+ */
159
+ class PaymentCallback {
160
+ /** Your order id. */
161
+ orderId;
162
+ /** The status mapped onto this package's statuses. */
163
+ status;
164
+ /** The gateway's own status value, unmapped. */
165
+ gatewayStatus;
166
+ /** The gateway's id for the payment, when it sends one. */
167
+ gatewayReference;
168
+ /** The amount the gateway reports, exactly as it sent it, when it sends one. */
169
+ amount;
170
+ /** The verified payload. */
171
+ raw;
172
+ /** The response to send so the gateway stops retrying. */
173
+ acknowledgement;
174
+ constructor(init) {
175
+ this.orderId = init.orderId;
176
+ this.status = init.status;
177
+ this.gatewayStatus = init.gatewayStatus;
178
+ this.gatewayReference = init.gatewayReference;
179
+ this.amount = init.amount;
180
+ this.raw = init.raw ?? {};
181
+ this.acknowledgement = init.acknowledgement ?? Acknowledgement.default();
182
+ }
183
+ /** Whether the customer paid. */
184
+ isSuccessful() {
185
+ return this.status === 'successful';
186
+ }
187
+ }
188
+ exports.PaymentCallback = PaymentCallback;
189
+ /**
190
+ * The state of a payment as reported by a gateway's status API.
191
+ */
192
+ class PaymentStatusResult {
193
+ /** Your order id, when the gateway returns it. */
194
+ orderId;
195
+ /** The status mapped onto this package's statuses. */
196
+ status;
197
+ /** The gateway's own status value, unmapped. */
198
+ gatewayStatus;
199
+ /** The gateway's id for the payment, when it sends one. */
200
+ gatewayReference;
201
+ /** The amount the gateway reports, exactly as it sent it, when it sends one. */
202
+ amount;
203
+ /** The gateway's response, for logging. */
204
+ raw;
205
+ constructor(init) {
206
+ this.orderId = init.orderId;
207
+ this.status = init.status;
208
+ this.gatewayStatus = init.gatewayStatus;
209
+ this.gatewayReference = init.gatewayReference;
210
+ this.amount = init.amount;
211
+ this.raw = init.raw ?? {};
212
+ }
213
+ /** Whether the customer paid. */
214
+ isSuccessful() {
215
+ return this.status === 'successful';
216
+ }
217
+ }
218
+ exports.PaymentStatusResult = PaymentStatusResult;
219
+ function bodyText(body) {
220
+ if (body === undefined || body === null) {
221
+ return '';
222
+ }
223
+ if (typeof body === 'string') {
224
+ return body;
225
+ }
226
+ return new TextDecoder().decode(body);
227
+ }
228
+ function rawBody(value) {
229
+ if (typeof value === 'string' || value instanceof Uint8Array || value instanceof ArrayBuffer) {
230
+ return value;
231
+ }
232
+ return undefined;
233
+ }
234
+ function isPlainObject(value) {
235
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
236
+ }
237
+ function encodeParsedBody(body, contentType) {
238
+ if (!contentType.toLowerCase().includes('urlencoded')) {
239
+ return JSON.stringify(body);
240
+ }
241
+ const form = new URLSearchParams();
242
+ for (const [key, value] of Object.entries(body)) {
243
+ for (const item of Array.isArray(value) ? value : [value]) {
244
+ form.append(key, String(item));
245
+ }
246
+ }
247
+ return form.toString();
248
+ }
249
+ function normalizeHeaders(headers) {
250
+ const result = {};
251
+ if (headers === undefined || headers === null) {
252
+ return result;
253
+ }
254
+ const add = (name, value) => {
255
+ if (value === undefined) {
256
+ return;
257
+ }
258
+ const text = typeof value === 'string' ? value : value.join(', ');
259
+ const key = name.toLowerCase();
260
+ (0, json_js_1.setKey)(result, key, result[key] === undefined ? text : `${result[key]}, ${text}`);
261
+ };
262
+ if (typeof headers.forEach === 'function' &&
263
+ typeof headers.get === 'function') {
264
+ headers.forEach((value, name) => {
265
+ add(name, value);
266
+ });
267
+ }
268
+ else if (Symbol.iterator in headers) {
269
+ for (const [name, value] of headers) {
270
+ add(name, value);
271
+ }
272
+ }
273
+ else {
274
+ for (const [name, value] of Object.entries(headers)) {
275
+ add(name, value);
276
+ }
277
+ }
278
+ return result;
279
+ }
280
+ function normalizeQuery(query) {
281
+ if (query === undefined || query === null) {
282
+ return {};
283
+ }
284
+ if (typeof query === 'string' || query instanceof URLSearchParams) {
285
+ return firstValues(new URLSearchParams(query));
286
+ }
287
+ const result = {};
288
+ for (const [key, value] of Object.entries(query)) {
289
+ const first = typeof value === 'string' ? value : value?.[0];
290
+ if (first !== undefined) {
291
+ (0, json_js_1.setKey)(result, key, first);
292
+ }
293
+ }
294
+ return result;
295
+ }
296
+ function firstValues(params) {
297
+ const result = {};
298
+ for (const [key, value] of params) {
299
+ if (!Object.prototype.hasOwnProperty.call(result, key)) {
300
+ (0, json_js_1.setKey)(result, key, value);
301
+ }
302
+ }
303
+ return result;
304
+ }
@@ -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,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.hmacSha256Hex = hmacSha256Hex;
4
+ exports.hmacSha256Base64 = hmacSha256Base64;
5
+ exports.sha256Hex = sha256Hex;
6
+ exports.safeEqual = safeEqual;
7
+ exports.randomHex = randomHex;
8
+ exports.queryEscape = queryEscape;
9
+ exports.decodeBase64 = decodeBase64;
10
+ const node_crypto_1 = require("node:crypto");
11
+ /** HMAC-SHA256 of `message`, hex encoded. @internal */
12
+ function hmacSha256Hex(key, message) {
13
+ return (0, node_crypto_1.createHmac)('sha256', key).update(message, 'utf8').digest('hex');
14
+ }
15
+ /** HMAC-SHA256 of `message`, base64 encoded. @internal */
16
+ function hmacSha256Base64(key, message) {
17
+ return (0, node_crypto_1.createHmac)('sha256', key).update(message, 'utf8').digest('base64');
18
+ }
19
+ /** SHA-256 of `message`, hex encoded. @internal */
20
+ function sha256Hex(message) {
21
+ return (0, node_crypto_1.createHash)('sha256').update(message, 'utf8').digest('hex');
22
+ }
23
+ /** Compares two strings in constant time (for equal lengths). @internal */
24
+ function safeEqual(expected, actual) {
25
+ const a = Buffer.from(expected, 'utf8');
26
+ const b = Buffer.from(actual, 'utf8');
27
+ return a.length === b.length && (0, node_crypto_1.timingSafeEqual)(a, b);
28
+ }
29
+ /** `bytes` random bytes, hex encoded. @internal */
30
+ function randomHex(bytes = 16) {
31
+ return (0, node_crypto_1.randomBytes)(bytes).toString('hex');
32
+ }
33
+ /**
34
+ * Escapes text like Go's `url.QueryEscape` and PHP's `urlencode`: everything except letters,
35
+ * digits and `-_.~` is percent-encoded and spaces become `+`.
36
+ *
37
+ * @internal
38
+ */
39
+ function queryEscape(value) {
40
+ return encodeURIComponent(value)
41
+ .replace(/[!'()*]/g, (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`)
42
+ .replace(/%20/g, '+');
43
+ }
44
+ /** Decodes strict standard base64 (with padding), or `undefined`. @internal */
45
+ function decodeBase64(value) {
46
+ if (value === '' || value.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(value)) {
47
+ return undefined;
48
+ }
49
+ return Buffer.from(value, 'base64').toString('utf8');
50
+ }
@@ -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;