@bayarkit/testing 0.0.0 → 0.1.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 +15 -0
  79. package/dist/fakes/bayarcash.d.ts.map +1 -0
  80. package/dist/fakes/bayarcash.js +133 -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 +138 -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,166 @@
1
+ /**
2
+ * The conformance suite. Every adapter runs it against its fake (always) and against the real sandbox (when keys are
3
+ * present, which is what turns `evidence.kind` into "measured"). Adding a gateway = an adapter + a fake that pass this.
4
+ */
5
+ import { confirmPayment, GatewayError, } from '@bayarkit/core';
6
+ import { afterAll, beforeAll, describe, expect, it } from 'vitest';
7
+ let counter = 0;
8
+ export function sampleInput(overrides = {}) {
9
+ counter += 1;
10
+ return {
11
+ reference: `ORDER${Date.now()}${counter}`,
12
+ amount: 1050,
13
+ description: 'Conformance test order',
14
+ customer: { name: 'Ali bin Abu', email: 'ali@example.com', phone: '0123456789' },
15
+ returnUrl: 'https://shop.example/return',
16
+ callbackUrl: 'https://shop.example/callback',
17
+ ...overrides,
18
+ };
19
+ }
20
+ export function gatewayConformance(name, setup) {
21
+ describe(`${name}: bayarkit conformance`, () => {
22
+ let gateway;
23
+ let fake;
24
+ beforeAll(async () => {
25
+ ;
26
+ ({ gateway, fake } = await setup());
27
+ });
28
+ afterAll(async () => {
29
+ await fake?.close();
30
+ });
31
+ it('declares where its behaviour comes from', () => {
32
+ expect(gateway.info.name).toMatch(/^[a-z0-9-]+$/);
33
+ expect(gateway.info.minimumAmount).toBeGreaterThan(0);
34
+ expect(['measured', 'docs']).toContain(gateway.info.evidence.kind);
35
+ expect(gateway.info.evidence.date).toMatch(/^\d{4}-\d{2}-\d{2}$/);
36
+ });
37
+ it('creates a payment with an id and a redirect URL', async () => {
38
+ const created = await gateway.createPayment(sampleInput());
39
+ expect(created.id).not.toBe('');
40
+ expect(created.url).toMatch(/^https?:\/\//);
41
+ // A gateway that wants a POST says so with `form`; checkoutResponse then serves a page that submits it.
42
+ if (created.form) {
43
+ expect(created.form.method).toBe('POST');
44
+ expect(created.form.action).toMatch(/^https?:\/\//);
45
+ expect(Object.keys(created.form.fields).length).toBeGreaterThan(0);
46
+ for (const v of Object.values(created.form.fields))
47
+ expect(typeof v).toBe('string');
48
+ }
49
+ });
50
+ it('rejects an amount below its minimum before calling the gateway', async () => {
51
+ const amount = gateway.info.minimumAmount - 1;
52
+ await expect(gateway.createPayment(sampleInput({ amount }))).rejects.toBeInstanceOf(GatewayError);
53
+ });
54
+ it('rejects a non-integer amount', async () => {
55
+ await expect(gateway.createPayment(sampleInput({ amount: 10.5 }))).rejects.toBeInstanceOf(GatewayError);
56
+ });
57
+ it('reports an unpaid payment as not paid', async () => {
58
+ const input = sampleInput();
59
+ const created = await gateway.createPayment(input);
60
+ const cb = gateway.verifyCallback(fake.callbackFor(created.id));
61
+ expect(cb).not.toBeNull();
62
+ const record = await gateway.getPayment(cb?.id ?? '');
63
+ expect(record.status).not.toBe('paid');
64
+ });
65
+ it('confirms a paid payment from its callback', async () => {
66
+ const input = sampleInput();
67
+ const created = await gateway.createPayment(input);
68
+ fake.markPaid(created.id);
69
+ const result = await confirmPayment(gateway, fake.callbackFor(created.id), input);
70
+ expect(result).toMatchObject({ ok: true });
71
+ if (result.ok) {
72
+ expect(result.payment.reference).toBe(input.reference);
73
+ expect(result.payment.amount).toBe(input.amount);
74
+ expect(result.payment.currency).toBe('MYR');
75
+ }
76
+ });
77
+ it('refuses a callback whose signature was tampered with', async () => {
78
+ const input = sampleInput();
79
+ const created = await gateway.createPayment(input);
80
+ fake.markPaid(created.id);
81
+ const forged = fake.tamper(fake.callbackFor(created.id));
82
+ expect(await confirmPayment(gateway, forged, input)).toMatchObject({
83
+ ok: false,
84
+ reason: 'invalid_signature',
85
+ });
86
+ });
87
+ it('refuses a correctly signed callback when the gateway says it is not paid (replay / leaked key)', async () => {
88
+ const input = sampleInput();
89
+ const created = await gateway.createPayment(input);
90
+ expect(await confirmPayment(gateway, fake.callbackFor(created.id), input)).toMatchObject({
91
+ ok: false,
92
+ reason: 'not_paid',
93
+ });
94
+ });
95
+ it('refuses a paid payment whose amount differs from what you charged', async () => {
96
+ const input = sampleInput();
97
+ const created = await gateway.createPayment(input);
98
+ fake.markPaid(created.id);
99
+ const result = await confirmPayment(gateway, fake.callbackFor(created.id), {
100
+ ...input,
101
+ amount: input.amount + 1,
102
+ });
103
+ expect(result).toMatchObject({ ok: false, reason: 'mismatch' });
104
+ });
105
+ it('refuses a paid payment that belongs to a different order', async () => {
106
+ const input = sampleInput();
107
+ const created = await gateway.createPayment(input);
108
+ fake.markPaid(created.id);
109
+ const result = await confirmPayment(gateway, fake.callbackFor(created.id), {
110
+ ...input,
111
+ reference: 'SOMEONE-ELSE',
112
+ });
113
+ expect(result).toMatchObject({ ok: false, reason: 'mismatch' });
114
+ });
115
+ it("the fake's callbacks are self-consistent (a form body says what its fields say, tampered or not)", async () => {
116
+ const created = await gateway.createPayment(sampleInput());
117
+ const cb = fake.callbackFor(created.id);
118
+ for (const c of [cb, fake.tamper(cb)]) {
119
+ const type = c.headers['content-type'] ?? '';
120
+ if (c.rawBody && type.includes('application/x-www-form-urlencoded')) {
121
+ expect(Object.fromEntries(new URLSearchParams(c.rawBody))).toEqual(c.fields);
122
+ }
123
+ if (c.rawBody && type.includes('application/json')) {
124
+ const json = JSON.parse(c.rawBody);
125
+ for (const [k, v] of Object.entries(c.fields))
126
+ expect(String(json[k]), k).toBe(v);
127
+ }
128
+ }
129
+ // And tampering changes something an adapter reads.
130
+ expect(fake.tamper(cb)).not.toEqual(cb);
131
+ });
132
+ it('never throws on a malformed callback body', () => {
133
+ const junk = [
134
+ { fields: {}, rawBody: '', headers: {} },
135
+ { fields: { hash: 'x' }, rawBody: '{', headers: { 'content-type': 'application/json' } },
136
+ { fields: { checksum: 'zz', transaction_id: '1' }, rawBody: '', headers: {} },
137
+ {
138
+ fields: { billcode: '../../etc' },
139
+ rawBody: 'not json',
140
+ headers: { 'x-signature': '!!', 'stripe-signature': 't=1,v1=zz' },
141
+ },
142
+ ];
143
+ // Shapes a framework can hand over when a body is missing or was parsed by something else.
144
+ const broken = [
145
+ {},
146
+ { fields: null, rawBody: null, headers: null },
147
+ { fields: { hash: ['x'] }, rawBody: '', headers: {} },
148
+ { fields: {}, rawBody: '{}', headers: { 'content-type': 'application/json', 'x-signature': '' } },
149
+ ];
150
+ for (const cb of [...junk, ...broken]) {
151
+ expect(() => gateway.verifyCallback(cb)).not.toThrow();
152
+ expect(gateway.verifyCallback(cb)).toBeNull();
153
+ }
154
+ });
155
+ it('confirming the same callback twice gives the same answer (gateways retry callbacks)', async () => {
156
+ const input = sampleInput();
157
+ const created = await gateway.createPayment(input);
158
+ fake.markPaid(created.id);
159
+ const body = fake.callbackFor(created.id);
160
+ const first = await confirmPayment(gateway, body, input);
161
+ const second = await confirmPayment(gateway, body, input);
162
+ expect(second).toEqual(first);
163
+ });
164
+ });
165
+ }
166
+ //# sourceMappingURL=conformance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conformance.js","sourceRoot":"","sources":["../src/conformance.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAGL,cAAc,EAEd,YAAY,GACb,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAQlE,IAAI,OAAO,GAAG,CAAC,CAAA;AACf,MAAM,UAAU,WAAW,CAAC,SAAS,GAAgC,EAAE;IACrE,OAAO,IAAI,CAAC,CAAA;IACZ,OAAO;QACL,SAAS,EAAE,QAAQ,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,EAAE;QACzC,MAAM,EAAE,IAAI;QACZ,WAAW,EAAE,wBAAwB;QACrC,QAAQ,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAE,YAAY,EAAE;QAChF,SAAS,EAAE,6BAA6B;QACxC,WAAW,EAAE,+BAA+B;QAC5C,GAAG,SAAS;KACb,CAAA;AACH,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,KAAsC;IACrF,QAAQ,CAAC,GAAG,IAAI,wBAAwB,EAAE,GAAG,EAAE;QAC7C,IAAI,OAAgB,CAAA;QACpB,IAAI,IAAiB,CAAA;QAErB,SAAS,CAAC,KAAK,IAAI,EAAE;YACnB,CAAC;YAAA,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,MAAM,KAAK,EAAE,CAAC,CAAA;QACtC,CAAC,CAAC,CAAA;QACF,QAAQ,CAAC,KAAK,IAAI,EAAE;YAClB,MAAM,IAAI,EAAE,KAAK,EAAE,CAAA;QACrB,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;YACjD,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAA;YACjD,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAA;YACrD,MAAM,CAAC,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;YAClE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAA;QACnE,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;YAC/D,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC,CAAA;YAC1D,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;YAC/B,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAA;YAC3C,wGAAwG;YACxG,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;gBACjB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;gBACxC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAA;gBACnD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAA;gBAClE,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;oBAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YACrF,CAAC;QACH,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;YAC9E,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,aAAa,GAAG,CAAC,CAAA;YAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,YAAY,CAAC,CAAA;QACnG,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,8BAA8B,EAAE,KAAK,IAAI,EAAE;YAC5C,MAAM,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,YAAY,CAAC,CAAA;QACzG,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;YACrD,MAAM,KAAK,GAAG,WAAW,EAAE,CAAA;YAC3B,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;YAClD,MAAM,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAA;YAC/D,MAAM,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAA;YACzB,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;YACrD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QACxC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;YACzD,MAAM,KAAK,GAAG,WAAW,EAAE,CAAA;YAC3B,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;YAClD,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;YACzB,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAA;YACjF,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;YAC1C,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;gBACd,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;gBACtD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;gBAChD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YAC7C,CAAC;QACH,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,sDAAsD,EAAE,KAAK,IAAI,EAAE;YACpE,MAAM,KAAK,GAAG,WAAW,EAAE,CAAA;YAC3B,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;YAClD,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;YACzB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAA;YACxD,MAAM,CAAC,MAAM,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC;gBACjE,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,mBAAmB;aAC5B,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,gGAAgG,EAAE,KAAK,IAAI,EAAE;YAC9G,MAAM,KAAK,GAAG,WAAW,EAAE,CAAA;YAC3B,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;YAClD,MAAM,CAAC,MAAM,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC;gBACvF,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,UAAU;aACnB,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;YACjF,MAAM,KAAK,GAAG,WAAW,EAAE,CAAA;YAC3B,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;YAClD,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;YACzB,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE;gBACzE,GAAG,KAAK;gBACR,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC;aACzB,CAAC,CAAA;YACF,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAA;QACjE,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;YACxE,MAAM,KAAK,GAAG,WAAW,EAAE,CAAA;YAC3B,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;YAClD,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;YACzB,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE;gBACzE,GAAG,KAAK;gBACR,SAAS,EAAE,cAAc;aAC1B,CAAC,CAAA;YACF,MAAM,CAAC,MAAM,CAAC,CAAC,aAAa,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAA;QACjE,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,kGAAkG,EAAE,KAAK,IAAI,EAAE;YAChH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC,CAAA;YAC1D,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;YACvC,KAAK,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;gBACtC,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,EAAE,CAAA;gBAC5C,IAAI,CAAC,CAAC,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,mCAAmC,CAAC,EAAE,CAAC;oBACpE,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,eAAe,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;gBAC9E,CAAC;gBACD,IAAI,CAAC,CAAC,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;oBACnD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAA4B,CAAA;oBAC7D,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;wBAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;gBACnF,CAAC;YACH,CAAC;YACD,oDAAoD;YACpD,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QACzC,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;YACnD,MAAM,IAAI,GAAoB;gBAC5B,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;gBACxC,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,EAAE;gBACxF,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,cAAc,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;gBAC7E;oBACE,MAAM,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE;oBACjC,OAAO,EAAE,UAAU;oBACnB,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,kBAAkB,EAAE,WAAW,EAAE;iBAClE;aACF,CAAA;YACD,2FAA2F;YAC3F,MAAM,MAAM,GAAG;gBACb,EAAE;gBACF,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE;gBAC9C,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,GAAG,CAAsB,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;gBAC1E,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,aAAa,EAAE,EAAE,EAAE,EAAE;aACpE,CAAA;YAC/B,KAAK,MAAM,EAAE,IAAI,CAAC,GAAG,IAAI,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC;gBACtC,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAA;gBACtD,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;YAC/C,CAAC;QACH,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,qFAAqF,EAAE,KAAK,IAAI,EAAE;YACnG,MAAM,KAAK,GAAG,WAAW,EAAE,CAAA;YAC3B,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;YAClD,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;YACzB,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;YACzC,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAA;YACxD,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAA;YACzD,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QAC/B,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { FakeGateway } from './fakes/types.js';
2
+ export declare function startControlServer(gateway: string, fake: FakeGateway, port?: number): Promise<{
3
+ url: string;
4
+ close(): Promise<void>;
5
+ }>;
6
+ //# sourceMappingURL=control.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control.d.ts","sourceRoot":"","sources":["../src/control.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAEnD,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,WAAW,EACjB,IAAI,SAAI,GACP,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAAC,CA6BlD"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * A tiny HTTP control API in front of any fake gateway, so tests written in other languages (PHP/Laravel, Python, Go)
3
+ * can drive it: mark a payment paid, and fetch the exact signed callback the real gateway would send.
4
+ *
5
+ * GET /health → { ok, gateway, url }
6
+ * POST /paid/<id> → 204 (markPaid)
7
+ * GET /callback/<id> → CallbackInput JSON { fields, rawBody, headers }
8
+ * GET /callback/<id>/tampered → the same callback with its signature altered
9
+ *
10
+ * Deliver the callback to your app as-is: POST `rawBody` with `headers` when `rawBody` is set (Stripe, CHIP), otherwise
11
+ * POST `fields` as a form.
12
+ */
13
+ import { createServer } from 'node:http';
14
+ export async function startControlServer(gateway, fake, port = 0) {
15
+ const server = createServer((req, res) => {
16
+ const send = (status, body) => {
17
+ res.writeHead(status, body === undefined ? {} : { 'content-type': 'application/json' });
18
+ res.end(body === undefined ? undefined : JSON.stringify(body));
19
+ };
20
+ const path = decodeURIComponent((req.url ?? '').split('?')[0] ?? '');
21
+ try {
22
+ if (req.method === 'GET' && path === '/health')
23
+ return send(200, { ok: true, gateway, url: fake.url });
24
+ const paid = /^\/paid\/([^/]+)$/.exec(path);
25
+ if (req.method === 'POST' && paid?.[1]) {
26
+ fake.markPaid(paid[1]);
27
+ return send(204);
28
+ }
29
+ const cb = /^\/callback\/([^/]+)(\/tampered)?$/.exec(path);
30
+ if (req.method === 'GET' && cb?.[1]) {
31
+ const callback = fake.callbackFor(cb[1]);
32
+ return send(200, cb[2] ? fake.tamper(callback) : callback);
33
+ }
34
+ send(404, { error: 'unknown control route' });
35
+ }
36
+ catch (e) {
37
+ send(404, { error: e instanceof Error ? e.message : String(e) });
38
+ }
39
+ });
40
+ await new Promise((r) => server.listen(port, '127.0.0.1', r));
41
+ return {
42
+ url: `http://127.0.0.1:${server.address().port}`,
43
+ close: () => new Promise((r) => server.close(() => r())),
44
+ };
45
+ }
46
+ //# sourceMappingURL=control.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control.js","sourceRoot":"","sources":["../src/control.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAIxC,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAe,EACf,IAAiB,EACjB,IAAI,GAAG,CAAC;IAER,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QACvC,MAAM,IAAI,GAAG,CAAC,MAAc,EAAE,IAAc,EAAE,EAAE;YAC9C,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAA;YACvF,GAAG,CAAC,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;QAChE,CAAC,CAAA;QACD,MAAM,IAAI,GAAG,kBAAkB,CAAC,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;QACpE,IAAI,CAAC;YACH,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,IAAI,KAAK,SAAS;gBAAE,OAAO,IAAI,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;YACtG,MAAM,IAAI,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAC3C,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;gBACtB,OAAO,IAAI,CAAC,GAAG,CAAC,CAAA;YAClB,CAAC;YACD,MAAM,EAAE,GAAG,oCAAoC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAC1D,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;gBACxC,OAAO,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAA;YAC5D,CAAC;YACD,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAA;QAC/C,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;QAClE,CAAC;IACH,CAAC,CAAC,CAAA;IACF,MAAM,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,CAAA;IACnE,OAAO;QACL,GAAG,EAAE,oBAAqB,MAAM,CAAC,OAAO,EAAkB,CAAC,IAAI,EAAE;QACjE,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;KAC/D,CAAA;AACH,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { CallbackInput } from '@bayarkit/core';
2
+ import { type FakeGateway } from './types.js';
3
+ /** HS256 JWT exactly as 2C2P builds it (written independently of the adapter): compact JSON, base64url, no padding. */
4
+ export declare function sign2C2PJwt(claims: Record<string, unknown>, secretKey: string): string;
5
+ export interface Fake2C2P extends FakeGateway {
6
+ /** Every request: path, the outer JSON body, the decoded JWT claims (null when the JWT did not verify). */
7
+ requests: {
8
+ path: string;
9
+ body: unknown;
10
+ claims: Record<string, unknown> | null;
11
+ }[];
12
+ /** Put a payment in any documented state (`0001` pending, `0003` cancelled, `4005` declined, `9020` expired…). */
13
+ setStatus(invoiceNo: string, respCode: string, respDesc?: string): void;
14
+ /** The browser's frontend return (`paymentResponse=<base64 JSON>`), UNSIGNED exactly as documented [§4b]. */
15
+ frontendFor(invoiceNo: string): CallbackInput;
16
+ }
17
+ export declare function startFake2C2P(opts: {
18
+ merchantId: string;
19
+ secretKey: string;
20
+ }): Promise<Fake2C2P>;
21
+ //# sourceMappingURL=2c2p.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"2c2p.d.ts","sourceRoot":"","sources":["../../src/fakes/2c2p.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,EAAE,KAAK,WAAW,EAAQ,MAAM,YAAY,CAAA;AAInD,uHAAuH;AACvH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAOtF;AAoCD,MAAM,WAAW,QAAS,SAAQ,WAAW;IAC3C,2GAA2G;IAC3G,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;KAAE,EAAE,CAAA;IACnF,kHAAkH;IAClH,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACvE,6GAA6G;IAC7G,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,CAAA;CAC9C;AAoBD,wBAAsB,aAAa,CAAC,IAAI,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAkNtG"}
@@ -0,0 +1,287 @@
1
+ /**
2
+ * A fake 2C2P PGW Payment API (v4.x Payment Token + Payment Inquiry + backend notification), built from the official
3
+ * documentation in `gateways/2c2p/spec.md` (developer.2c2p.com, read 23 October 2026). NOT yet measured against the
4
+ * sandbox (sandbox-pgw.2c2p.com): when someone does, change this file first so it answers like the real thing, then
5
+ * the adapter.
6
+ *
7
+ * What it does, and where each rule comes from (spec sections in brackets):
8
+ * - `POST /payment/<4.3|4.5>/paymentToken` and `/paymentInquiry`, both versions answer; other versions → plain
9
+ * `UnsupportedApiVersion` [§1, observed probe];
10
+ * - request and response bodies are `{"payload":"<JWT>"}`, HS256, the merchant secret key's hex STRING used as ASCII
11
+ * bytes (not hex-decoded) [§1, §4a, TV1/TV2];
12
+ * - a request whose JWT does not verify → plain unsigned `{"respCode":"9042","respDesc":"Hash value mismatch"}`; an
13
+ * unreadable body → plain `{"respCode":"9040",…}` [§1 observed probe; §3 table]. ASSUMED: HTTP 200 for both, and
14
+ * errors unsigned (whether error responses are signed is UNCONFIRMED);
15
+ * - `amount` is decimal MAJOR units (ringgit), D(12,5) [§2]; `invoiceNo` AN 50, unique (9015) [§2, §6];
16
+ * `idempotencyID` repeats the first answer (ASSUMED: the docs only say it "recognises retries") [§6];
17
+ * - Payment Inquiry by `invoiceNo` or `paymentToken`; respCode 0000 paid, 2002 not found [§3]. ASSUMED: a token that
18
+ * exists but has no payment yet answers 0001 "Transaction is pending" (the docs do not say);
19
+ * - inquiry `amount` is a JSON number (inquiry sample), the backend notification's is a STRING "230.87" (backend
20
+ * sample) [§9 C6]; `transactionDateTime` is `yyyyMMddHHmmss` [§3];
21
+ * - backend notification: `{"payload":"<JWT>"}` JSON posted to backendReturnUrl [§4a].
22
+ */
23
+ import { createHmac, randomBytes } from 'node:crypto';
24
+ import { createServer } from 'node:http';
25
+ import { flip } from './types.js';
26
+ const VERSIONS = new Set(['4.3', '4.5']);
27
+ /** HS256 JWT exactly as 2C2P builds it (written independently of the adapter): compact JSON, base64url, no padding. */
28
+ export function sign2C2PJwt(claims, secretKey) {
29
+ const head = Buffer.from(JSON.stringify({ alg: 'HS256', typ: 'JWT' })).toString('base64url');
30
+ const body = Buffer.from(JSON.stringify(claims)).toString('base64url');
31
+ const sig = createHmac('sha256', Buffer.from(secretKey, 'utf8'))
32
+ .update(`${head}.${body}`)
33
+ .digest('base64url');
34
+ return `${head}.${body}.${sig}`;
35
+ }
36
+ function readJwt(token, secretKey) {
37
+ const parts = token.split('.');
38
+ if (parts.length !== 3)
39
+ return null;
40
+ const [head = '', body = '', sig = ''] = parts;
41
+ try {
42
+ const header = JSON.parse(Buffer.from(head, 'base64url').toString('utf8'));
43
+ if (header?.alg !== 'HS256')
44
+ return null;
45
+ const want = createHmac('sha256', Buffer.from(secretKey, 'utf8'))
46
+ .update(`${head}.${body}`)
47
+ .digest('base64url');
48
+ if (want !== sig)
49
+ return null;
50
+ const claims = JSON.parse(Buffer.from(body, 'base64url').toString('utf8'));
51
+ return claims && typeof claims === 'object' && !Array.isArray(claims) ? claims : null;
52
+ }
53
+ catch {
54
+ return null;
55
+ }
56
+ }
57
+ const pad = (n) => String(n).padStart(2, '0');
58
+ /** `yyyyMMddHHmmss`. ASSUMED Malaysia time; the docs do not give the timezone. */
59
+ const stamp = () => {
60
+ const d = new Date(Date.now() + 8 * 3600_000);
61
+ return `${d.getUTCFullYear()}${pad(d.getUTCMonth() + 1)}${pad(d.getUTCDate())}${pad(d.getUTCHours())}${pad(d.getUTCMinutes())}${pad(d.getUTCSeconds())}`;
62
+ };
63
+ /** D(12,5), major units, positive: a JSON number or a decimal string. Returns two-decimal text or null. */
64
+ function amountOf(v) {
65
+ const text = typeof v === 'number' ? String(v) : typeof v === 'string' ? v.trim() : '';
66
+ const m = /^(\d{1,7})(?:\.(\d{1,5}))?$/.exec(text);
67
+ if (!m)
68
+ return null;
69
+ const frac = (m[2] ?? '').padEnd(5, '0');
70
+ if (/[1-9]/.test(frac.slice(2)))
71
+ return null; // MYR has two decimals (ISO 4217)
72
+ const out = `${Number(m[1])}.${frac.slice(0, 2)}`;
73
+ return Number(out) > 0 ? out : null;
74
+ }
75
+ export async function startFake2C2P(opts) {
76
+ const txns = new Map();
77
+ const byToken = new Map();
78
+ const byIdempotency = new Map();
79
+ const requests = [];
80
+ let origin = '';
81
+ const server = createServer((req, res) => {
82
+ let raw = '';
83
+ req.on('data', (d) => {
84
+ raw += d;
85
+ });
86
+ req.on('end', () => {
87
+ const plain = (o) => {
88
+ res.writeHead(200, { 'content-type': 'application/json; charset=utf-8' });
89
+ res.end(JSON.stringify(o));
90
+ };
91
+ const signed = (claims) => plain({ payload: sign2C2PJwt(claims, opts.secretKey) });
92
+ const path = (req.url ?? '').split('?')[0] ?? '';
93
+ const m = /^\/payment\/([0-9.]+)\/(paymentToken|paymentInquiry)$/.exec(path);
94
+ let body = null;
95
+ try {
96
+ body = JSON.parse(raw);
97
+ }
98
+ catch { }
99
+ const token = body?.payload;
100
+ const claims = typeof token === 'string' ? readJwt(token, opts.secretKey) : null;
101
+ requests.push({ path, body, claims });
102
+ if (req.method !== 'POST' || !m) {
103
+ res.writeHead(404, { 'content-type': 'application/json' });
104
+ return res.end(JSON.stringify({ respCode: '9040', respDesc: 'Invalid Request (9040)' }));
105
+ }
106
+ if (!VERSIONS.has(m[1] ?? ''))
107
+ return plain({ respCode: '9040', respDesc: 'UnsupportedApiVersion' });
108
+ if (!(req.headers['content-type'] ?? '').includes('json') || typeof token !== 'string') {
109
+ return plain({ respCode: '9040', respDesc: 'Invalid Request (9040)' });
110
+ }
111
+ if (!claims)
112
+ return plain({ respCode: '9042', respDesc: 'Hash value mismatch' });
113
+ if (claims.merchantID !== opts.merchantId)
114
+ return signed({ respCode: '9007', respDesc: 'Invalid merchant' });
115
+ if (m[2] === 'paymentToken') {
116
+ const s = (k) => (claims[k] == null ? '' : String(claims[k]));
117
+ if (!s('invoiceNo') || !s('description') || claims.amount === undefined) {
118
+ return signed({ respCode: '9005', respDesc: 'Some mandatory fields are missing' });
119
+ }
120
+ if (!/^[A-Za-z0-9]{1,50}$/.test(s('invoiceNo')) || [...s('description')].length > 250) {
121
+ return signed({ respCode: '9006', respDesc: 'This field exceeded its authorized length' });
122
+ }
123
+ const amount = amountOf(claims.amount);
124
+ if (!amount)
125
+ return signed({ respCode: '9009', respDesc: 'Amount is invalid' });
126
+ if (s('currencyCode') && s('currencyCode') !== 'MYR')
127
+ return signed({ respCode: '9010', respDesc: 'Invalid Currency Code' });
128
+ if (s('paymentExpiry') && !/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(s('paymentExpiry')))
129
+ return signed({ respCode: '9008', respDesc: 'Invalid payment expiry' });
130
+ const idem = s('idempotencyID');
131
+ const again = idem ? byIdempotency.get(idem) : undefined;
132
+ if (again) {
133
+ const t = txns.get(again);
134
+ if (t)
135
+ return signed(tokenResponse(m[1] ?? '4.3', t));
136
+ }
137
+ if (txns.has(s('invoiceNo')))
138
+ return signed({ respCode: '9015', respDesc: 'Existing Invoice Number' });
139
+ const paymentToken = randomBytes(48).toString('base64');
140
+ const t = {
141
+ invoiceNo: s('invoiceNo'),
142
+ paymentToken,
143
+ amount,
144
+ currencyCode: s('currencyCode') || 'MYR',
145
+ description: s('description'),
146
+ idempotencyID: idem,
147
+ respCode: '0001',
148
+ respDesc: 'Transaction is pending',
149
+ transactionDateTime: '',
150
+ tranRef: '',
151
+ referenceNo: '',
152
+ approvalCode: '',
153
+ };
154
+ txns.set(t.invoiceNo, t);
155
+ byToken.set(paymentToken, t.invoiceNo);
156
+ if (idem)
157
+ byIdempotency.set(idem, t.invoiceNo);
158
+ return signed(tokenResponse(m[1] ?? '4.3', t));
159
+ }
160
+ // paymentInquiry: merchantID + (paymentToken | invoiceNo) [§3].
161
+ const invoiceNo = typeof claims.paymentToken === 'string' && claims.paymentToken
162
+ ? byToken.get(claims.paymentToken)
163
+ : typeof claims.invoiceNo === 'string'
164
+ ? claims.invoiceNo
165
+ : undefined;
166
+ const t = invoiceNo ? txns.get(invoiceNo) : undefined;
167
+ if (!t)
168
+ return signed({ respCode: '2002', respDesc: 'Transaction not found' });
169
+ return signed({
170
+ merchantID: opts.merchantId,
171
+ invoiceNo: t.invoiceNo,
172
+ amount: Number(t.amount), // inquiry sample: a JSON number (1000.00 → 1000)
173
+ currencyCode: t.currencyCode,
174
+ transactionDateTime: t.transactionDateTime,
175
+ agentCode: '',
176
+ channelCode: t.respCode === '0000' ? 'VI' : '',
177
+ approvalCode: t.approvalCode,
178
+ referenceNo: t.referenceNo,
179
+ tranRef: t.tranRef,
180
+ accountNo: t.respCode === '0000' ? '411111XXXXXX1111' : '',
181
+ idempotencyID: t.idempotencyID,
182
+ userDefined1: '',
183
+ respCode: t.respCode,
184
+ respDesc: t.respDesc,
185
+ });
186
+ });
187
+ });
188
+ function tokenResponse(version, t) {
189
+ return {
190
+ webPaymentUrl: `${origin}/payment/${version}/#/token/${encodeURIComponent(t.paymentToken)}`,
191
+ paymentToken: t.paymentToken,
192
+ respCode: '0000',
193
+ respDesc: 'Success',
194
+ };
195
+ }
196
+ await new Promise((r) => server.listen(0, '127.0.0.1', r));
197
+ origin = `http://127.0.0.1:${server.address().port}`;
198
+ const txn = (id) => {
199
+ const t = txns.get(id);
200
+ if (!t)
201
+ throw new Error(`fake 2C2P: no invoice ${id}`);
202
+ return t;
203
+ };
204
+ return {
205
+ url: origin,
206
+ requests,
207
+ markPaid(id) {
208
+ const t = txn(id);
209
+ Object.assign(t, {
210
+ respCode: '0000',
211
+ respDesc: 'Success',
212
+ transactionDateTime: stamp(),
213
+ tranRef: String(Math.floor(Math.random() * 1e7)),
214
+ referenceNo: String(Math.floor(Math.random() * 1e7)),
215
+ approvalCode: String(Math.floor(Math.random() * 1e6)).padStart(6, '0'),
216
+ });
217
+ },
218
+ setStatus(id, respCode, respDesc = `status ${respCode}`) {
219
+ Object.assign(txn(id), { respCode, respDesc });
220
+ },
221
+ /**
222
+ * The backend notification claiming success (even before markPaid; the fake's record stays unpaid). Field set and
223
+ * types follow the backend sample: `amount` a STRING, `cardNo` (C6). `override` changes claims before signing.
224
+ */
225
+ callbackFor(id, override = {}) {
226
+ const t = txn(id);
227
+ const claims = {
228
+ merchantID: opts.merchantId,
229
+ invoiceNo: t.invoiceNo,
230
+ cardNo: '411111XXXXXX1111',
231
+ amount: t.amount,
232
+ currencyCode: t.currencyCode,
233
+ tranRef: t.tranRef || '2868821',
234
+ referenceNo: t.referenceNo || '2785703',
235
+ approvalCode: t.approvalCode || '531484',
236
+ eci: '05',
237
+ transactionDateTime: t.transactionDateTime || stamp(),
238
+ respCode: '0000',
239
+ respDesc: 'Success',
240
+ ...override,
241
+ };
242
+ // The outer JSON is indented: what is signed is the JWT inside it, not these bytes (spec §4a).
243
+ const rawBody = JSON.stringify({ payload: sign2C2PJwt(claims, opts.secretKey) }, null, '\t');
244
+ return {
245
+ fields: { payload: JSON.parse(rawBody).payload },
246
+ rawBody,
247
+ headers: { 'content-type': 'application/json; charset=utf-8' },
248
+ };
249
+ },
250
+ frontendFor(id) {
251
+ const t = txn(id);
252
+ const json = JSON.stringify({
253
+ locale: null,
254
+ invoiceNo: t.invoiceNo,
255
+ channelCode: 'CC',
256
+ respCode: '2000',
257
+ respDesc: 'Transaction is completed, please do payment inquiry request for full payment information.',
258
+ });
259
+ const paymentResponse = Buffer.from(json).toString('base64');
260
+ return {
261
+ fields: { paymentResponse },
262
+ rawBody: new URLSearchParams({ paymentResponse }).toString(),
263
+ headers: { 'content-type': 'application/x-www-form-urlencoded' },
264
+ };
265
+ },
266
+ tamper(cb) {
267
+ const swap = (jwt) => {
268
+ const [h = '', p = '', s = ''] = jwt.split('.');
269
+ return `${h}.${p}.${flip(s)}`;
270
+ };
271
+ let body = {};
272
+ try {
273
+ body = JSON.parse(cb.rawBody);
274
+ }
275
+ catch { }
276
+ const jwt = typeof body.payload === 'string' ? body.payload : (cb.fields.payload ?? '');
277
+ const forged = swap(jwt);
278
+ return {
279
+ ...cb,
280
+ fields: { ...cb.fields, payload: forged },
281
+ rawBody: JSON.stringify({ payload: forged }, null, '\t'),
282
+ };
283
+ },
284
+ close: () => new Promise((r) => server.close(() => r())),
285
+ };
286
+ }
287
+ //# sourceMappingURL=2c2p.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"2c2p.js","sourceRoot":"","sources":["../../src/fakes/2c2p.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,EAAE,YAAY,EAA6C,MAAM,WAAW,CAAA;AAGnF,OAAO,EAAoB,IAAI,EAAE,MAAM,YAAY,CAAA;AAEnD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAA;AAExC,uHAAuH;AACvH,MAAM,UAAU,WAAW,CAAC,MAA+B,EAAE,SAAiB;IAC5E,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAA;IAC5F,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAA;IACtE,MAAM,GAAG,GAAG,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;SAC7D,MAAM,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;SACzB,MAAM,CAAC,WAAW,CAAC,CAAA;IACtB,OAAO,GAAG,IAAI,IAAI,IAAI,IAAI,GAAG,EAAE,CAAA;AACjC,CAAC;AAED,SAAS,OAAO,CAAC,KAAa,EAAE,SAAiB;IAC/C,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAC9B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACnC,MAAM,CAAC,IAAI,GAAG,EAAE,EAAE,IAAI,GAAG,EAAE,EAAE,GAAG,GAAG,EAAE,CAAC,GAAG,KAAK,CAAA;IAC9C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAA;QAC1E,IAAI,MAAM,EAAE,GAAG,KAAK,OAAO;YAAE,OAAO,IAAI,CAAA;QACxC,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;aAC9D,MAAM,CAAC,GAAG,IAAI,IAAI,IAAI,EAAE,CAAC;aACzB,MAAM,CAAC,WAAW,CAAC,CAAA;QACtB,IAAI,IAAI,KAAK,GAAG;YAAE,OAAO,IAAI,CAAA;QAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAA;QAC1E,OAAO,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAA;IACvF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AA2BD,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;AACrD,kFAAkF;AAClF,MAAM,KAAK,GAAG,GAAG,EAAE;IACjB,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAA;IAC7C,OAAO,GAAG,CAAC,CAAC,cAAc,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,EAAE,CAAA;AAC1J,CAAC,CAAA;AAED,2GAA2G;AAC3G,SAAS,QAAQ,CAAC,CAAU;IAC1B,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IACtF,MAAM,CAAC,GAAG,6BAA6B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAClD,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAA;IACnB,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;IACxC,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAA,CAAC,kCAAkC;IAC/E,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAA;IACjD,OAAO,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAA;AACrC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAA+C;IACjF,MAAM,IAAI,GAAG,IAAI,GAAG,EAAe,CAAA;IACnC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAA;IACzC,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAA;IAC/C,MAAM,QAAQ,GAAyB,EAAE,CAAA;IACzC,IAAI,MAAM,GAAG,EAAE,CAAA;IAEf,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,GAAoB,EAAE,GAAmB,EAAE,EAAE;QACxE,IAAI,GAAG,GAAG,EAAE,CAAA;QACZ,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE;YACnB,GAAG,IAAI,CAAC,CAAA;QACV,CAAC,CAAC,CAAA;QACF,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACjB,MAAM,KAAK,GAAG,CAAC,CAAU,EAAE,EAAE;gBAC3B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,iCAAiC,EAAE,CAAC,CAAA;gBACzE,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAA;YAC5B,CAAC,CAAA;YACD,MAAM,MAAM,GAAG,CAAC,MAA+B,EAAE,EAAE,CACjD,KAAK,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,CAAA;YACzD,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;YAChD,MAAM,CAAC,GAAG,uDAAuD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAC5E,IAAI,IAAI,GAAY,IAAI,CAAA;YACxB,IAAI,CAAC;gBACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;YACxB,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;YACV,MAAM,KAAK,GAAI,IAAqC,EAAE,OAAO,CAAA;YAC7D,MAAM,MAAM,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;YAChF,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA;YACrC,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,EAAE,CAAC;gBAChC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAA;gBAC1D,OAAO,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,wBAAwB,EAAE,CAAC,CAAC,CAAA;YAC1F,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBAAE,OAAO,KAAK,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,uBAAuB,EAAE,CAAC,CAAA;YACpG,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBACvF,OAAO,KAAK,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,wBAAwB,EAAE,CAAC,CAAA;YACxE,CAAC;YACD,IAAI,CAAC,MAAM;gBAAE,OAAO,KAAK,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,qBAAqB,EAAE,CAAC,CAAA;YAChF,IAAI,MAAM,CAAC,UAAU,KAAK,IAAI,CAAC,UAAU;gBACvC,OAAO,MAAM,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,kBAAkB,EAAE,CAAC,CAAA;YAEnE,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,cAAc,EAAE,CAAC;gBAC5B,MAAM,CAAC,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;gBACrE,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;oBACxE,OAAO,MAAM,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,mCAAmC,EAAE,CAAC,CAAA;gBACpF,CAAC;gBACD,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;oBACtF,OAAO,MAAM,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,2CAA2C,EAAE,CAAC,CAAA;gBAC5F,CAAC;gBACD,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;gBACtC,IAAI,CAAC,MAAM;oBAAE,OAAO,MAAM,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,mBAAmB,EAAE,CAAC,CAAA;gBAC/E,IAAI,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,cAAc,CAAC,KAAK,KAAK;oBAClD,OAAO,MAAM,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,uBAAuB,EAAE,CAAC,CAAA;gBACxE,IAAI,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,uCAAuC,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC;oBACzF,OAAO,MAAM,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,wBAAwB,EAAE,CAAC,CAAA;gBACzE,MAAM,IAAI,GAAG,CAAC,CAAC,eAAe,CAAC,CAAA;gBAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;gBACxD,IAAI,KAAK,EAAE,CAAC;oBACV,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;oBACzB,IAAI,CAAC;wBAAE,OAAO,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,CAAA;gBACvD,CAAC;gBACD,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;oBAAE,OAAO,MAAM,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,yBAAyB,EAAE,CAAC,CAAA;gBACtG,MAAM,YAAY,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;gBACvD,MAAM,CAAC,GAAQ;oBACb,SAAS,EAAE,CAAC,CAAC,WAAW,CAAC;oBACzB,YAAY;oBACZ,MAAM;oBACN,YAAY,EAAE,CAAC,CAAC,cAAc,CAAC,IAAI,KAAK;oBACxC,WAAW,EAAE,CAAC,CAAC,aAAa,CAAC;oBAC7B,aAAa,EAAE,IAAI;oBACnB,QAAQ,EAAE,MAAM;oBAChB,QAAQ,EAAE,wBAAwB;oBAClC,mBAAmB,EAAE,EAAE;oBACvB,OAAO,EAAE,EAAE;oBACX,WAAW,EAAE,EAAE;oBACf,YAAY,EAAE,EAAE;iBACjB,CAAA;gBACD,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAA;gBACxB,OAAO,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC,SAAS,CAAC,CAAA;gBACtC,IAAI,IAAI;oBAAE,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,SAAS,CAAC,CAAA;gBAC9C,OAAO,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,CAAA;YAChD,CAAC;YAED,gEAAgE;YAChE,MAAM,SAAS,GACb,OAAO,MAAM,CAAC,YAAY,KAAK,QAAQ,IAAI,MAAM,CAAC,YAAY;gBAC5D,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC;gBAClC,CAAC,CAAC,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ;oBACpC,CAAC,CAAC,MAAM,CAAC,SAAS;oBAClB,CAAC,CAAC,SAAS,CAAA;YACjB,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;YACrD,IAAI,CAAC,CAAC;gBAAE,OAAO,MAAM,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,uBAAuB,EAAE,CAAC,CAAA;YAC9E,OAAO,MAAM,CAAC;gBACZ,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,SAAS,EAAE,CAAC,CAAC,SAAS;gBACtB,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,iDAAiD;gBAC3E,YAAY,EAAE,CAAC,CAAC,YAAY;gBAC5B,mBAAmB,EAAE,CAAC,CAAC,mBAAmB;gBAC1C,SAAS,EAAE,EAAE;gBACb,WAAW,EAAE,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;gBAC9C,YAAY,EAAE,CAAC,CAAC,YAAY;gBAC5B,WAAW,EAAE,CAAC,CAAC,WAAW;gBAC1B,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,SAAS,EAAE,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE;gBAC1D,aAAa,EAAE,CAAC,CAAC,aAAa;gBAC9B,YAAY,EAAE,EAAE;gBAChB,QAAQ,EAAE,CAAC,CAAC,QAAQ;gBACpB,QAAQ,EAAE,CAAC,CAAC,QAAQ;aACrB,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,SAAS,aAAa,CAAC,OAAe,EAAE,CAAM;QAC5C,OAAO;YACL,aAAa,EAAE,GAAG,MAAM,YAAY,OAAO,YAAY,kBAAkB,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE;YAC3F,YAAY,EAAE,CAAC,CAAC,YAAY;YAC5B,QAAQ,EAAE,MAAM;YAChB,QAAQ,EAAE,SAAS;SACpB,CAAA;IACH,CAAC;IAED,MAAM,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,CAAA;IAChE,MAAM,GAAG,oBAAqB,MAAM,CAAC,OAAO,EAAkB,CAAC,IAAI,EAAE,CAAA;IAErE,MAAM,GAAG,GAAG,CAAC,EAAU,EAAE,EAAE;QACzB,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACtB,IAAI,CAAC,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,EAAE,EAAE,CAAC,CAAA;QACtD,OAAO,CAAC,CAAA;IACV,CAAC,CAAA;IAED,OAAO;QACL,GAAG,EAAE,MAAM;QACX,QAAQ;QACR,QAAQ,CAAC,EAAE;YACT,MAAM,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC,CAAA;YACjB,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE;gBACf,QAAQ,EAAE,MAAM;gBAChB,QAAQ,EAAE,SAAS;gBACnB,mBAAmB,EAAE,KAAK,EAAE;gBAC5B,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC;gBAChD,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC;gBACpD,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC;aACvE,CAAC,CAAA;QACJ,CAAC;QACD,SAAS,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,GAAG,UAAU,QAAQ,EAAE;YACrD,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAA;QAChD,CAAC;QACD;;;WAGG;QACH,WAAW,CAAC,EAAE,EAAE,QAAQ,GAAG,EAAE;YAC3B,MAAM,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC,CAAA;YACjB,MAAM,MAAM,GAA4B;gBACtC,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,SAAS,EAAE,CAAC,CAAC,SAAS;gBACtB,MAAM,EAAE,kBAAkB;gBAC1B,MAAM,EAAE,CAAC,CAAC,MAAM;gBAChB,YAAY,EAAE,CAAC,CAAC,YAAY;gBAC5B,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,SAAS;gBAC/B,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,SAAS;gBACvC,YAAY,EAAE,CAAC,CAAC,YAAY,IAAI,QAAQ;gBACxC,GAAG,EAAE,IAAI;gBACT,mBAAmB,EAAE,CAAC,CAAC,mBAAmB,IAAI,KAAK,EAAE;gBACrD,QAAQ,EAAE,MAAM;gBAChB,QAAQ,EAAE,SAAS;gBACnB,GAAG,QAAQ;aACZ,CAAA;YACD,+FAA+F;YAC/F,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;YAC5F,OAAO;gBACL,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE;gBAChD,OAAO;gBACP,OAAO,EAAE,EAAE,cAAc,EAAE,iCAAiC,EAAE;aAC/D,CAAA;QACH,CAAC;QACD,WAAW,CAAC,EAAE;YACZ,MAAM,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC,CAAA;YACjB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC;gBAC1B,MAAM,EAAE,IAAI;gBACZ,SAAS,EAAE,CAAC,CAAC,SAAS;gBACtB,WAAW,EAAE,IAAI;gBACjB,QAAQ,EAAE,MAAM;gBAChB,QAAQ,EAAE,2FAA2F;aACtG,CAAC,CAAA;YACF,MAAM,eAAe,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;YAC5D,OAAO;gBACL,MAAM,EAAE,EAAE,eAAe,EAAE;gBAC3B,OAAO,EAAE,IAAI,eAAe,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC,QAAQ,EAAE;gBAC5D,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;aACjE,CAAA;QACH,CAAC;QACD,MAAM,CAAC,EAAE;YACP,MAAM,IAAI,GAAG,CAAC,GAAW,EAAE,EAAE;gBAC3B,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;gBAC/C,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAA;YAC/B,CAAC,CAAA;YACD,IAAI,IAAI,GAA0B,EAAE,CAAA;YACpC,IAAI,CAAC;gBACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,CAAA;YAC/B,CAAC;YAAC,MAAM,CAAC,CAAA,CAAC;YACV,MAAM,GAAG,GAAG,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,CAAA;YACvF,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAA;YACxB,OAAO;gBACL,GAAG,EAAE;gBACL,MAAM,EAAE,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE;gBACzC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC;aACzD,CAAA;QACH,CAAC;QACD,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;KAC/D,CAAA;AACH,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { type FakeGateway } from './types.js';
2
+ export interface FakeBayarcash extends FakeGateway {
3
+ requests: {
4
+ method: string;
5
+ path: string;
6
+ body: unknown;
7
+ headers: Record<string, string | string[] | undefined>;
8
+ }[];
9
+ }
10
+ export declare function startFakeBayarcash(opts: {
11
+ token: string;
12
+ secretKey: string;
13
+ portalKey: string;
14
+ }): Promise<FakeBayarcash>;
15
+ //# sourceMappingURL=bayarcash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bayarcash.d.ts","sourceRoot":"","sources":["../../src/fakes/bayarcash.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,WAAW,EAAQ,MAAM,YAAY,CAAA;AAkBnD,MAAM,WAAW,aAAc,SAAQ,WAAW;IAChD,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;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC7C,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB,GAAG,OAAO,CAAC,aAAa,CAAC,CAqHzB"}