@bayarkit/testing 0.0.0 → 0.2.0

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 (138) hide show
  1. package/README.md +26 -1
  2. package/dist/cli/2c2p.d.ts +4 -0
  3. package/dist/cli/2c2p.d.ts.map +1 -0
  4. package/dist/cli/2c2p.js +7 -0
  5. package/dist/cli/2c2p.js.map +1 -0
  6. package/dist/cli/bayarcash.d.ts +4 -0
  7. package/dist/cli/bayarcash.d.ts.map +1 -0
  8. package/dist/cli/bayarcash.js +11 -0
  9. package/dist/cli/bayarcash.js.map +1 -0
  10. package/dist/cli/billplz.d.ts +4 -0
  11. package/dist/cli/billplz.d.ts.map +1 -0
  12. package/dist/cli/billplz.js +11 -0
  13. package/dist/cli/billplz.js.map +1 -0
  14. package/dist/cli/chip.d.ts +4 -0
  15. package/dist/cli/chip.d.ts.map +1 -0
  16. package/dist/cli/chip.js +7 -0
  17. package/dist/cli/chip.js.map +1 -0
  18. package/dist/cli/curlec.d.ts +4 -0
  19. package/dist/cli/curlec.d.ts.map +1 -0
  20. package/dist/cli/curlec.js +11 -0
  21. package/dist/cli/curlec.js.map +1 -0
  22. package/dist/cli/eghl.d.ts +4 -0
  23. package/dist/cli/eghl.d.ts.map +1 -0
  24. package/dist/cli/eghl.js +7 -0
  25. package/dist/cli/eghl.js.map +1 -0
  26. package/dist/cli/fiuu.d.ts +4 -0
  27. package/dist/cli/fiuu.d.ts.map +1 -0
  28. package/dist/cli/fiuu.js +17 -0
  29. package/dist/cli/fiuu.js.map +1 -0
  30. package/dist/cli/gkash.d.ts +4 -0
  31. package/dist/cli/gkash.d.ts.map +1 -0
  32. package/dist/cli/gkash.js +7 -0
  33. package/dist/cli/gkash.js.map +1 -0
  34. package/dist/cli/hitpay.d.ts +4 -0
  35. package/dist/cli/hitpay.d.ts.map +1 -0
  36. package/dist/cli/hitpay.js +7 -0
  37. package/dist/cli/hitpay.js.map +1 -0
  38. package/dist/cli/ipay88.d.ts +4 -0
  39. package/dist/cli/ipay88.d.ts.map +1 -0
  40. package/dist/cli/ipay88.js +7 -0
  41. package/dist/cli/ipay88.js.map +1 -0
  42. package/dist/cli/senangpay.d.ts +4 -0
  43. package/dist/cli/senangpay.d.ts.map +1 -0
  44. package/dist/cli/senangpay.js +17 -0
  45. package/dist/cli/senangpay.js.map +1 -0
  46. package/dist/cli/stripe.d.ts +4 -0
  47. package/dist/cli/stripe.d.ts.map +1 -0
  48. package/dist/cli/stripe.js +7 -0
  49. package/dist/cli/stripe.js.map +1 -0
  50. package/dist/cli/toyyibpay.d.ts +4 -0
  51. package/dist/cli/toyyibpay.d.ts.map +1 -0
  52. package/dist/cli/toyyibpay.js +7 -0
  53. package/dist/cli/toyyibpay.js.map +1 -0
  54. package/dist/cli/types.d.ts +7 -0
  55. package/dist/cli/types.d.ts.map +1 -0
  56. package/dist/cli/types.js +2 -0
  57. package/dist/cli/types.js.map +1 -0
  58. package/dist/cli/xendit.d.ts +4 -0
  59. package/dist/cli/xendit.d.ts.map +1 -0
  60. package/dist/cli/xendit.js +7 -0
  61. package/dist/cli/xendit.js.map +1 -0
  62. package/dist/cli.d.ts +3 -0
  63. package/dist/cli.d.ts.map +1 -0
  64. package/dist/cli.js +46 -0
  65. package/dist/cli.js.map +1 -0
  66. package/dist/conformance.d.ts +13 -0
  67. package/dist/conformance.d.ts.map +1 -0
  68. package/dist/conformance.js +166 -0
  69. package/dist/conformance.js.map +1 -0
  70. package/dist/control.d.ts +6 -0
  71. package/dist/control.d.ts.map +1 -0
  72. package/dist/control.js +46 -0
  73. package/dist/control.js.map +1 -0
  74. package/dist/fakes/2c2p.d.ts +21 -0
  75. package/dist/fakes/2c2p.d.ts.map +1 -0
  76. package/dist/fakes/2c2p.js +287 -0
  77. package/dist/fakes/2c2p.js.map +1 -0
  78. package/dist/fakes/bayarcash.d.ts +17 -0
  79. package/dist/fakes/bayarcash.d.ts.map +1 -0
  80. package/dist/fakes/bayarcash.js +183 -0
  81. package/dist/fakes/bayarcash.js.map +1 -0
  82. package/dist/fakes/billplz.d.ts +20 -0
  83. package/dist/fakes/billplz.d.ts.map +1 -0
  84. package/dist/fakes/billplz.js +233 -0
  85. package/dist/fakes/billplz.js.map +1 -0
  86. package/dist/fakes/chip.d.ts +18 -0
  87. package/dist/fakes/chip.d.ts.map +1 -0
  88. package/dist/fakes/chip.js +227 -0
  89. package/dist/fakes/chip.js.map +1 -0
  90. package/dist/fakes/curlec.d.ts +30 -0
  91. package/dist/fakes/curlec.d.ts.map +1 -0
  92. package/dist/fakes/curlec.js +396 -0
  93. package/dist/fakes/curlec.js.map +1 -0
  94. package/dist/fakes/eghl.d.ts +36 -0
  95. package/dist/fakes/eghl.d.ts.map +1 -0
  96. package/dist/fakes/eghl.js +267 -0
  97. package/dist/fakes/eghl.js.map +1 -0
  98. package/dist/fakes/fiuu.d.ts +27 -0
  99. package/dist/fakes/fiuu.d.ts.map +1 -0
  100. package/dist/fakes/fiuu.js +230 -0
  101. package/dist/fakes/fiuu.js.map +1 -0
  102. package/dist/fakes/gkash.d.ts +18 -0
  103. package/dist/fakes/gkash.d.ts.map +1 -0
  104. package/dist/fakes/gkash.js +193 -0
  105. package/dist/fakes/gkash.js.map +1 -0
  106. package/dist/fakes/hitpay.d.ts +36 -0
  107. package/dist/fakes/hitpay.d.ts.map +1 -0
  108. package/dist/fakes/hitpay.js +233 -0
  109. package/dist/fakes/hitpay.js.map +1 -0
  110. package/dist/fakes/ipay88.d.ts +16 -0
  111. package/dist/fakes/ipay88.d.ts.map +1 -0
  112. package/dist/fakes/ipay88.js +195 -0
  113. package/dist/fakes/ipay88.js.map +1 -0
  114. package/dist/fakes/senangpay.d.ts +51 -0
  115. package/dist/fakes/senangpay.d.ts.map +1 -0
  116. package/dist/fakes/senangpay.js +255 -0
  117. package/dist/fakes/senangpay.js.map +1 -0
  118. package/dist/fakes/stripe.d.ts +26 -0
  119. package/dist/fakes/stripe.d.ts.map +1 -0
  120. package/dist/fakes/stripe.js +243 -0
  121. package/dist/fakes/stripe.js.map +1 -0
  122. package/dist/fakes/toyyibpay.d.ts +14 -0
  123. package/dist/fakes/toyyibpay.d.ts.map +1 -0
  124. package/dist/fakes/toyyibpay.js +130 -0
  125. package/dist/fakes/toyyibpay.js.map +1 -0
  126. package/dist/fakes/types.d.ts +19 -0
  127. package/dist/fakes/types.d.ts.map +1 -0
  128. package/dist/fakes/types.js +3 -0
  129. package/dist/fakes/types.js.map +1 -0
  130. package/dist/fakes/xendit.d.ts +36 -0
  131. package/dist/fakes/xendit.d.ts.map +1 -0
  132. package/dist/fakes/xendit.js +300 -0
  133. package/dist/fakes/xendit.js.map +1 -0
  134. package/dist/index.d.ts +18 -0
  135. package/dist/index.d.ts.map +1 -0
  136. package/dist/index.js +18 -0
  137. package/dist/index.js.map +1 -0
  138. package/package.json +66 -2
@@ -0,0 +1,183 @@
1
+ /**
2
+ * A fake Bayarcash API v3. Shapes MEASURED on the sandbox 27 Oct 2026 (api.console.bayarcash-sandbox.com, FPX mock bank,
3
+ * one paid and one failed payment): creating an intent answers 201 with `amount` as a number and one `payment_channel`;
4
+ * `GET /payment-intents/{id}` answers 201 (a read, still 201) with `status` "unpaid"/"paid" and its `attempts`;
5
+ * `/transactions/{intent id}` is 404 (an intent is not a transaction); a transaction names its portal by NAME (`portal`),
6
+ * not by key. Callback field lists still come from the official PHP SDK: the sandbox sent no server callback.
7
+ */
8
+ import { createHmac } from 'node:crypto';
9
+ import { createServer } from 'node:http';
10
+ import { flip } from './types.js';
11
+ const sign = (secret, fields) => createHmac('sha256', secret)
12
+ .update(Object.keys(fields)
13
+ .sort()
14
+ .map((k) => fields[k] ?? '')
15
+ .join('|'))
16
+ .digest('hex');
17
+ export async function startFakeBayarcash(opts) {
18
+ const portalName = opts.portalName ?? 'Fake portal';
19
+ let n = 0;
20
+ const intents = new Map();
21
+ const transactions = new Map();
22
+ const requests = [];
23
+ const server = createServer((req, res) => {
24
+ let raw = '';
25
+ req.on('data', (d) => {
26
+ raw += d;
27
+ });
28
+ req.on('end', () => {
29
+ let body = {};
30
+ try {
31
+ body = raw ? JSON.parse(raw) : {};
32
+ }
33
+ catch { }
34
+ const path = req.url ?? '';
35
+ requests.push({ method: req.method ?? '', path, body, headers: req.headers });
36
+ const send = (status, o) => {
37
+ res.writeHead(status, { 'content-type': 'application/json' });
38
+ res.end(JSON.stringify(o));
39
+ };
40
+ if (req.headers.authorization !== `Bearer ${opts.token}`)
41
+ return send(401, { message: 'Unauthenticated.' });
42
+ if (req.method === 'POST' && path === '/payment-intents') {
43
+ const channels = Array.isArray(body.payment_channel)
44
+ ? body.payment_channel.join(',')
45
+ : String(body.payment_channel);
46
+ const expected = sign(opts.secretKey, {
47
+ payment_channel: channels,
48
+ order_number: String(body.order_number ?? ''),
49
+ amount: String(body.amount ?? ''),
50
+ payer_name: String(body.payer_name ?? ''),
51
+ payer_email: String(body.payer_email ?? ''),
52
+ });
53
+ if (body.checksum !== expected)
54
+ return send(422, { message: 'Invalid checksum.' });
55
+ if (body.portal_key !== opts.portalKey)
56
+ return send(422, { message: 'Invalid portal key.' });
57
+ const id = `pi_fake${++n}`;
58
+ intents.set(id, { id, body });
59
+ return send(201, {
60
+ type: 'payment_intent',
61
+ id,
62
+ payer_name: body.payer_name,
63
+ payer_email: body.payer_email,
64
+ payer_telephone_number: '',
65
+ order_number: body.order_number,
66
+ amount: Number(body.amount),
67
+ payment_channel: Number(String(channels).split(',')[0]),
68
+ url: `https://fake.bayarcash.test/payment-intent/${id}`,
69
+ });
70
+ }
71
+ const pi = /^\/payment-intents\/([A-Za-z0-9_-]+)$/.exec(path);
72
+ if (req.method === 'GET' && pi) {
73
+ const i = intents.get(pi[1] ?? '');
74
+ if (!i)
75
+ return send(404, { code: 404, message: 'Resource not found.' });
76
+ const t = i.transactionId ? transactions.get(i.transactionId) : undefined;
77
+ const paid = t?.status === '3';
78
+ return send(201, {
79
+ type: 'payment_intent',
80
+ id: i.id,
81
+ status: paid ? 'paid' : 'unpaid',
82
+ last_attempt: t ? t.datetime : null,
83
+ paid_at: paid ? t?.datetime : '',
84
+ order_number: i.body.order_number,
85
+ amount: Number(i.body.amount),
86
+ currency: 'MYR',
87
+ attempts: t
88
+ ? [
89
+ {
90
+ transaction_id: t.transaction_id,
91
+ order_number: t.order_number,
92
+ amount: Number(t.amount),
93
+ status: Number(t.status),
94
+ },
95
+ ]
96
+ : [],
97
+ });
98
+ }
99
+ const tx = /^\/transactions\/([A-Za-z0-9_-]+)$/.exec(path);
100
+ if (req.method === 'GET' && tx) {
101
+ const t = transactions.get(tx[1] ?? '');
102
+ if (!t)
103
+ return send(404, { code: 404, message: 'Resource not found.' });
104
+ const { record_type: _, transaction_id, ...rest } = t;
105
+ return send(200, {
106
+ ...rest,
107
+ id: transaction_id,
108
+ amount: Number(t.amount),
109
+ status: Number(t.status),
110
+ portal: portalName,
111
+ payment_intent_id: [...intents.values()].find((i) => i.transactionId === transaction_id)?.id,
112
+ });
113
+ }
114
+ if (req.method === 'GET' && path === '/portals') {
115
+ return send(200, {
116
+ data: [
117
+ {
118
+ portal_key: opts.portalKey,
119
+ portal_name: portalName,
120
+ payment_channels: [{ id: 1, name: 'FPX' }],
121
+ },
122
+ ],
123
+ });
124
+ }
125
+ send(404, { message: 'Not found.' });
126
+ });
127
+ });
128
+ await new Promise((r) => server.listen(0, '127.0.0.1', r));
129
+ const url = `http://127.0.0.1:${server.address().port}`;
130
+ const intent = (id) => {
131
+ const i = intents.get(id);
132
+ if (!i)
133
+ throw new Error(`fake Bayarcash: no payment intent ${id}`);
134
+ return i;
135
+ };
136
+ const transaction = (i, status) => {
137
+ i.transactionId ??= `trx_${i.id}`;
138
+ const t = {
139
+ record_type: 'transaction',
140
+ transaction_id: i.transactionId,
141
+ exchange_reference_number: `1-${i.id}`,
142
+ exchange_transaction_id: `FPX${i.id}`,
143
+ order_number: String(i.body.order_number ?? ''),
144
+ currency: 'MYR',
145
+ amount: String(i.body.amount ?? ''),
146
+ payer_name: String(i.body.payer_name ?? ''),
147
+ payer_email: String(i.body.payer_email ?? ''),
148
+ payer_bank_name: 'Test Bank',
149
+ status,
150
+ status_description: status === '3' ? 'Approved' : 'Pending',
151
+ datetime: '2026-10-23 10:00:00',
152
+ };
153
+ transactions.set(i.transactionId, t);
154
+ return t;
155
+ };
156
+ return {
157
+ url,
158
+ requests,
159
+ markPaid(id) {
160
+ transaction(intent(id), '3');
161
+ },
162
+ callbackFor(id, override = {}) {
163
+ const i = intent(id);
164
+ // A callback before payment: the gateway's own record stays pending, the callback still claims success.
165
+ const base = transactions.get(i.transactionId ?? '') ?? transaction(i, '1');
166
+ const fields = {
167
+ ...base,
168
+ status: '3',
169
+ status_description: 'Approved',
170
+ ...override,
171
+ };
172
+ const { checksum, ...signed } = fields;
173
+ return {
174
+ fields: { ...signed, checksum: checksum ?? sign(opts.secretKey, signed) },
175
+ rawBody: '',
176
+ headers: {},
177
+ };
178
+ },
179
+ tamper: (cb) => ({ ...cb, fields: { ...cb.fields, checksum: flip(cb.fields.checksum ?? '') } }),
180
+ close: () => new Promise((r) => server.close(() => r())),
181
+ };
182
+ }
183
+ //# sourceMappingURL=bayarcash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bayarcash.js","sourceRoot":"","sources":["../../src/fakes/bayarcash.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { CallbackInput } from '@bayarkit/core';
2
+ import { type FakeGateway } from './types.js';
3
+ export interface FakeBillplz extends FakeGateway {
4
+ /** Every request received: body fields as posted (form or JSON), and headers. */
5
+ requests: {
6
+ method: string;
7
+ path: string;
8
+ body: Record<string, unknown>;
9
+ contentType: string | undefined;
10
+ headers: Record<string, string | string[] | undefined>;
11
+ }[];
12
+ /** The redirect query (`billplz[id]`, `billplz[paid]`, `billplz[paid_at]`, `billplz[x_signature]`) as decoded fields. */
13
+ redirectFor(id: string, override?: Record<string, string>): CallbackInput;
14
+ }
15
+ export declare function startFakeBillplz(opts: {
16
+ secretKey: string;
17
+ xSignatureKey: string;
18
+ collectionId: string;
19
+ }): Promise<FakeBillplz>;
20
+ //# sourceMappingURL=billplz.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billplz.d.ts","sourceRoot":"","sources":["../../src/fakes/billplz.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,EAAE,KAAK,WAAW,EAAQ,MAAM,YAAY,CAAA;AA4CnD,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC9C,iFAAiF;IACjF,QAAQ,EAAE;QACR,MAAM,EAAE,MAAM,CAAA;QACd,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAC7B,WAAW,EAAE,MAAM,GAAG,SAAS,CAAA;QAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAA;KACvD,EAAE,CAAA;IACH,yHAAyH;IACzH,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,aAAa,CAAA;CAC1E;AAgBD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;CACrB,GAAG,OAAO,CAAC,WAAW,CAAC,CAiLvB"}
@@ -0,0 +1,233 @@
1
+ /**
2
+ * A fake Billplz API (V3 Bills), built from the official documentation (support.billplz.com/api) and the official
3
+ * WooCommerce plugin's signing code — see gateways/billplz/spec.md. NOT yet measured against the sandbox: when someone
4
+ * does, change this file first so it answers like the real thing, then the adapter.
5
+ *
6
+ * Where the docs are silent this fake picks one shape and says so (marked ASSUMED below); the adapter must not depend on
7
+ * those shapes beyond "an error is an error".
8
+ */
9
+ import { createHmac } from 'node:crypto';
10
+ import { createServer } from 'node:http';
11
+ import { flip } from './types.js';
12
+ /**
13
+ * X Signature, written independently of the adapter (spec §5.1): one `key+value` string per parameter except
14
+ * `x_signature` (nested keys flattened, `billplz[id]` → `billplzid`), sort those STRINGS ascending case-insensitively,
15
+ * join with `|`, HMAC-SHA256 with the X Signature key, lowercase hex.
16
+ */
17
+ const sign = (key, fields) => {
18
+ const parts = [];
19
+ for (const [k, v] of Object.entries(fields)) {
20
+ const flat = k.replaceAll('[', '').replaceAll(']', '');
21
+ if (flat === 'x_signature' || flat === 'billplzx_signature')
22
+ continue;
23
+ parts.push(`${flat}${v}`);
24
+ }
25
+ parts.sort((a, b) => {
26
+ const x = a.toLowerCase();
27
+ const y = b.toLowerCase();
28
+ return x < y ? -1 : x > y ? 1 : a < b ? -1 : a > b ? 1 : 0;
29
+ });
30
+ return createHmac('sha256', key).update(parts.join('|')).digest('hex');
31
+ };
32
+ const MY_OFFSET_MS = 8 * 3600_000;
33
+ const pad = (n) => String(n).padStart(2, '0');
34
+ const myNow = () => new Date(Date.now() + MY_OFFSET_MS);
35
+ /** Doc examples show due_at NOT zero-padded ("2018-9-27"). */
36
+ const dueToday = () => {
37
+ const d = myNow();
38
+ return `${d.getUTCFullYear()}-${d.getUTCMonth() + 1}-${d.getUTCDate()}`;
39
+ };
40
+ /** Callback/redirect format: "2018-09-27 15:15:09 +0800". */
41
+ const paidNow = () => {
42
+ const d = myNow();
43
+ return `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())} ${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}:${pad(d.getUTCSeconds())} +0800`;
44
+ };
45
+ export async function startFakeBillplz(opts) {
46
+ let n = 0;
47
+ const bills = new Map();
48
+ const requests = [];
49
+ const expectedAuth = `Basic ${Buffer.from(`${opts.secretKey}:`).toString('base64')}`;
50
+ let origin = '';
51
+ const server = createServer((req, res) => {
52
+ let raw = '';
53
+ req.on('data', (d) => {
54
+ raw += d;
55
+ });
56
+ req.on('end', () => {
57
+ const contentType = req.headers['content-type'];
58
+ let body = {};
59
+ if (contentType?.includes('application/json')) {
60
+ try {
61
+ const j = raw ? JSON.parse(raw) : {};
62
+ if (j && typeof j === 'object' && !Array.isArray(j))
63
+ body = j;
64
+ }
65
+ catch { }
66
+ }
67
+ else {
68
+ body = Object.fromEntries(new URLSearchParams(raw));
69
+ }
70
+ const path = req.url ?? '';
71
+ requests.push({ method: req.method ?? '', path, body, contentType, headers: req.headers });
72
+ const send = (status, o) => {
73
+ res.writeHead(status, { 'content-type': 'application/json' });
74
+ res.end(JSON.stringify(o));
75
+ };
76
+ // ASSUMED: the docs give the error body only for 429 (`{"error":{"type","message":[…]}}`); other codes reuse it.
77
+ const error = (status, type, message) => send(status, { error: { type, message: [message] } });
78
+ // Docs: HTTP Basic, secret key as username, empty password; a wrong key (or the other environment's) → 401.
79
+ if (req.headers.authorization !== expectedAuth)
80
+ return error(401, 'Unauthorized', 'Invalid access token');
81
+ if (req.method === 'POST' && path === '/api/v3/bills') {
82
+ const s = (k) => (body[k] == null ? '' : String(body[k]).trim());
83
+ const problems = [];
84
+ if (!s('collection_id'))
85
+ problems.push('Collection is required');
86
+ else if (s('collection_id') !== opts.collectionId)
87
+ problems.push('Collection not found'); // ASSUMED code 422
88
+ if (!s('email') && !s('mobile'))
89
+ problems.push('Email or mobile is required');
90
+ if (s('mobile') && !/^\+?\d+$/.test(s('mobile')))
91
+ problems.push('Mobile is invalid');
92
+ if (!s('name'))
93
+ problems.push('Name is required');
94
+ else if ([...s('name')].length > 255)
95
+ problems.push('Name is too long (maximum is 255 characters)');
96
+ const amount = body.amount;
97
+ const amountOk = (typeof amount === 'number' && Number.isInteger(amount) && amount > 0) ||
98
+ (typeof amount === 'string' && /^[1-9]\d*$/.test(amount));
99
+ if (!amountOk)
100
+ problems.push('Amount must be a positive integer');
101
+ if (!s('callback_url'))
102
+ problems.push('Callback url is required');
103
+ if (!s('description'))
104
+ problems.push('Description is required');
105
+ else if ([...s('description')].length > 200)
106
+ problems.push('Description is too long (maximum is 200 characters)');
107
+ for (const k of ['reference_1_label', 'reference_2_label'])
108
+ if ([...s(k)].length > 20)
109
+ problems.push(`${k} is too long (maximum is 20 characters)`);
110
+ for (const k of ['reference_1', 'reference_2'])
111
+ if ([...s(k)].length > 120)
112
+ problems.push(`${k} is too long (maximum is 120 characters)`);
113
+ if (problems.length)
114
+ return send(422, { error: { type: 'Unprocessable', message: problems } });
115
+ n += 1;
116
+ const id = `fk${String(n).padStart(6, '0')}`;
117
+ const bill = {
118
+ id,
119
+ collection_id: s('collection_id'),
120
+ paid: false,
121
+ state: 'due',
122
+ amount: Number(amount),
123
+ paid_amount: 0,
124
+ due_at: s('due_at') || dueToday(),
125
+ email: s('email') || null,
126
+ mobile: s('mobile') || null,
127
+ name: s('name'),
128
+ url: `${origin}/bills/${id}`,
129
+ reference_1_label: s('reference_1_label') || 'Reference 1',
130
+ reference_1: s('reference_1') || null,
131
+ reference_2_label: s('reference_2_label') || 'Reference 2',
132
+ reference_2: s('reference_2') || null,
133
+ redirect_url: s('redirect_url') || null,
134
+ callback_url: s('callback_url'),
135
+ description: s('description'),
136
+ paid_at: null,
137
+ };
138
+ bills.set(id, bill);
139
+ const { paid_at: _omit, ...created } = bill;
140
+ return send(200, created);
141
+ }
142
+ const one = /^\/api\/v3\/bills\/([A-Za-z0-9]+)$/.exec(path);
143
+ if (one) {
144
+ const bill = bills.get(one[1] ?? '');
145
+ if (!bill)
146
+ return error(404, 'RecordNotFound', 'The requested bill does not exist');
147
+ if (req.method === 'GET') {
148
+ // Doc examples: the name comes back upper-cased; `paid_at` is absent from Get-a-Bill examples (UNCONFIRMED).
149
+ const { paid_at: _omit, ...shown } = bill;
150
+ return send(200, { ...shown, name: bill.name.toUpperCase() });
151
+ }
152
+ if (req.method === 'DELETE') {
153
+ // Docs: only due bills can be deleted; a paid bill → 422. ASSUMED: deleting a deleted bill is also 422.
154
+ if (bill.state !== 'due')
155
+ return error(422, 'Unprocessable', `Bill is ${bill.state}`);
156
+ bill.state = 'deleted';
157
+ return send(200, {});
158
+ }
159
+ }
160
+ error(404, 'RecordNotFound', 'Not found');
161
+ });
162
+ });
163
+ await new Promise((r) => server.listen(0, '127.0.0.1', r));
164
+ origin = `http://127.0.0.1:${server.address().port}`;
165
+ const bill = (id) => {
166
+ const b = bills.get(id);
167
+ if (!b)
168
+ throw new Error(`fake Billplz: no bill ${id}`);
169
+ return b;
170
+ };
171
+ return {
172
+ url: `${origin}/api`,
173
+ requests,
174
+ markPaid(id) {
175
+ // Docs: a deleted bill comes back when a payment already in flight completes.
176
+ const b = bill(id);
177
+ b.paid = true;
178
+ b.state = 'paid';
179
+ b.paid_amount = b.amount;
180
+ b.paid_at = paidNow();
181
+ },
182
+ callbackFor(id, override = {}) {
183
+ const b = bill(id);
184
+ // Flat fields exactly as Billplz posts them (spec §5.2), form-encoded; null becomes "". It claims a successful
185
+ // payment even before markPaid (a replayed or forged-with-a-leaked-key callback).
186
+ const fields = {
187
+ id: b.id,
188
+ collection_id: b.collection_id,
189
+ paid: 'true',
190
+ state: 'paid',
191
+ amount: String(b.amount),
192
+ paid_amount: String(b.amount),
193
+ due_at: b.due_at,
194
+ email: b.email ?? '',
195
+ mobile: b.mobile ?? '',
196
+ name: b.name.toUpperCase(),
197
+ url: b.url,
198
+ paid_at: b.paid_at ?? paidNow(),
199
+ ...override,
200
+ };
201
+ const { x_signature, ...signed } = fields;
202
+ const posted = { ...signed, x_signature: x_signature ?? sign(opts.xSignatureKey, signed) };
203
+ return {
204
+ fields: posted,
205
+ rawBody: new URLSearchParams(posted).toString(),
206
+ headers: { 'content-type': 'application/x-www-form-urlencoded' },
207
+ };
208
+ },
209
+ redirectFor(id, override = {}) {
210
+ const b = bill(id);
211
+ const fields = {
212
+ 'billplz[id]': b.id,
213
+ 'billplz[paid]': 'true',
214
+ 'billplz[paid_at]': b.paid_at ?? paidNow(),
215
+ ...override,
216
+ };
217
+ const { 'billplz[x_signature]': given, ...signed } = fields;
218
+ return {
219
+ fields: { ...signed, 'billplz[x_signature]': given ?? sign(opts.xSignatureKey, signed) },
220
+ rawBody: '',
221
+ headers: {},
222
+ };
223
+ },
224
+ tamper: (cb) => {
225
+ const k = 'billplz[x_signature]' in cb.fields ? 'billplz[x_signature]' : 'x_signature';
226
+ const fields = { ...cb.fields, [k]: flip(cb.fields[k] ?? '') };
227
+ // The body must say what the fields say: a real tampered POST carries the altered value in its bytes too.
228
+ return { ...cb, fields, rawBody: cb.rawBody ? new URLSearchParams(fields).toString() : '' };
229
+ },
230
+ close: () => new Promise((r) => server.close(() => r())),
231
+ };
232
+ }
233
+ //# sourceMappingURL=billplz.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billplz.js","sourceRoot":"","sources":["../../src/fakes/billplz.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { type FakeGateway } from './types.js';
2
+ export interface FakeChip extends FakeGateway {
3
+ /** The PEM public key that signs this fake's callbacks (what `GET /public_key/` returns, JSON-decoded). */
4
+ publicKey: string;
5
+ requests: {
6
+ method: string;
7
+ path: string;
8
+ body: unknown;
9
+ headers: Record<string, string | string[] | undefined>;
10
+ }[];
11
+ }
12
+ export declare function startFakeChip(opts: {
13
+ secretKey: string;
14
+ brandId: string;
15
+ /** `is_test` on every purchase; CHIP sets it from the key's mode. Default true (test keys). */
16
+ isTest?: boolean;
17
+ }): Promise<FakeChip>;
18
+ //# sourceMappingURL=chip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chip.d.ts","sourceRoot":"","sources":["../../src/fakes/chip.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,KAAK,WAAW,EAAQ,MAAM,YAAY,CAAA;AAuBnD,MAAM,WAAW,QAAS,SAAQ,WAAW;IAC3C,2GAA2G;IAC3G,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE;QACR,MAAM,EAAE,MAAM,CAAA;QACd,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,EAAE,OAAO,CAAA;QACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAA;KACvD,EAAE,CAAA;CACJ;AAKD,wBAAsB,aAAa,CAAC,IAAI,EAAE;IACxC,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,+FAA+F;IAC/F,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA8LpB"}