@momorail/conformance 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.
- package/LICENSE +21 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +137 -0
- package/dist/index.js.map +1 -0
- package/package.json +57 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Momorail contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { PaymentProvider, CollectionInput, DisbursementInput } from '@momorail/core';
|
|
2
|
+
|
|
3
|
+
interface ConformanceOptions {
|
|
4
|
+
/** A fresh adapter whose next transaction settles to `succeeded`. */
|
|
5
|
+
makeProvider: () => PaymentProvider | Promise<PaymentProvider>;
|
|
6
|
+
/** A fresh adapter whose next transaction settles to `failed`. Optional. */
|
|
7
|
+
makeFailingProvider?: () => PaymentProvider | Promise<PaymentProvider>;
|
|
8
|
+
/** A fresh adapter configured with invalid credentials. Optional. */
|
|
9
|
+
makeUnauthenticatedProvider?: () => PaymentProvider | Promise<PaymentProvider>;
|
|
10
|
+
/** A valid collection input for this adapter; call it for a fresh reference each time. */
|
|
11
|
+
sampleCollection: () => CollectionInput;
|
|
12
|
+
/**
|
|
13
|
+
* A valid disbursement input. Provide it for adapters that advertise
|
|
14
|
+
* `capabilities().disbursement`; the suite then drives a payout to a terminal
|
|
15
|
+
* status. Omit it and the suite instead asserts `disbursement()` rejects with
|
|
16
|
+
* a `not_supported` error.
|
|
17
|
+
*/
|
|
18
|
+
sampleDisbursement?: () => DisbursementInput;
|
|
19
|
+
/** Max polls the suite will do while waiting for a transaction to settle. Default 15. */
|
|
20
|
+
maxPolls?: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Register the shared adapter contract as a Vitest `describe` block. Call this at
|
|
24
|
+
* the top level of an adapter's own `*.test.ts` file.
|
|
25
|
+
*/
|
|
26
|
+
declare function runProviderConformance(suiteName: string, options: ConformanceOptions): void;
|
|
27
|
+
|
|
28
|
+
export { type ConformanceOptions, runProviderConformance };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import {
|
|
3
|
+
AuthError,
|
|
4
|
+
MomorailError,
|
|
5
|
+
TransactionNotFoundError,
|
|
6
|
+
ValidationError,
|
|
7
|
+
isTerminal
|
|
8
|
+
} from "@momorail/core";
|
|
9
|
+
import { describe, expect, it } from "vitest";
|
|
10
|
+
async function settle(provider, id, maxPolls) {
|
|
11
|
+
let current = await provider.getTransaction({ id });
|
|
12
|
+
for (let i = 0; i < maxPolls && !isTerminal(current.status); i++) {
|
|
13
|
+
current = await provider.getTransaction({ id });
|
|
14
|
+
}
|
|
15
|
+
return current;
|
|
16
|
+
}
|
|
17
|
+
function runProviderConformance(suiteName, options) {
|
|
18
|
+
const maxPolls = options.maxPolls ?? 15;
|
|
19
|
+
describe(`conformance: ${suiteName}`, () => {
|
|
20
|
+
it("exposes a lowercase string id", async () => {
|
|
21
|
+
const provider = await options.makeProvider();
|
|
22
|
+
expect(provider.id).toMatch(/^[a-z0-9_-]+$/);
|
|
23
|
+
});
|
|
24
|
+
it("reports capabilities with non-empty operator and currency lists", async () => {
|
|
25
|
+
const provider = await options.makeProvider();
|
|
26
|
+
const caps = provider.capabilities();
|
|
27
|
+
expect(typeof caps.collection).toBe("boolean");
|
|
28
|
+
expect(typeof caps.disbursement).toBe("boolean");
|
|
29
|
+
expect(caps.operators.length).toBeGreaterThan(0);
|
|
30
|
+
expect(caps.currencies.length).toBeGreaterThan(0);
|
|
31
|
+
});
|
|
32
|
+
it("creates a collection and echoes the caller reference", async () => {
|
|
33
|
+
const provider = await options.makeProvider();
|
|
34
|
+
const input = options.sampleCollection();
|
|
35
|
+
const txn = await provider.collection(input);
|
|
36
|
+
expect(txn.provider).toBe(provider.id);
|
|
37
|
+
expect(txn.reference).toBe(input.reference);
|
|
38
|
+
expect(txn.type).toBe("collection");
|
|
39
|
+
expect(txn.amount).toEqual(input.amount);
|
|
40
|
+
expect(txn.providerRaw).toBeDefined();
|
|
41
|
+
expect(Number.isNaN(Date.parse(txn.createdAt))).toBe(false);
|
|
42
|
+
expect(Number.isNaN(Date.parse(txn.updatedAt))).toBe(false);
|
|
43
|
+
});
|
|
44
|
+
it("is idempotent for a repeated reference", async () => {
|
|
45
|
+
const provider = await options.makeProvider();
|
|
46
|
+
const input = options.sampleCollection();
|
|
47
|
+
const first = await provider.collection(input);
|
|
48
|
+
const second = await provider.collection(input);
|
|
49
|
+
expect(second.id).toBe(first.id);
|
|
50
|
+
});
|
|
51
|
+
it("looks a transaction back up by id", async () => {
|
|
52
|
+
const provider = await options.makeProvider();
|
|
53
|
+
const created = await provider.collection(options.sampleCollection());
|
|
54
|
+
const fetched = await provider.getTransaction({ id: created.id });
|
|
55
|
+
expect(fetched.id).toBe(created.id);
|
|
56
|
+
});
|
|
57
|
+
it("looks a transaction back up by reference when advertised", async () => {
|
|
58
|
+
const provider = await options.makeProvider();
|
|
59
|
+
if (!provider.capabilities().lookupByReference) return;
|
|
60
|
+
const input = options.sampleCollection();
|
|
61
|
+
const created = await provider.collection(input);
|
|
62
|
+
const fetched = await provider.getTransaction({ reference: input.reference });
|
|
63
|
+
expect(fetched.id).toBe(created.id);
|
|
64
|
+
});
|
|
65
|
+
it("drives a successful transaction to a terminal status", async () => {
|
|
66
|
+
const provider = await options.makeProvider();
|
|
67
|
+
const created = await provider.collection(options.sampleCollection());
|
|
68
|
+
const final = isTerminal(created.status) ? created : await settle(provider, created.id, maxPolls);
|
|
69
|
+
expect(isTerminal(final.status)).toBe(true);
|
|
70
|
+
expect(final.status).toBe("succeeded");
|
|
71
|
+
});
|
|
72
|
+
it("rejects an unknown transaction ref with TransactionNotFoundError", async () => {
|
|
73
|
+
const provider = await options.makeProvider();
|
|
74
|
+
await expect(
|
|
75
|
+
provider.getTransaction({ id: "momorail-conformance-missing" })
|
|
76
|
+
).rejects.toBeInstanceOf(TransactionNotFoundError);
|
|
77
|
+
});
|
|
78
|
+
it("rejects an unknown operator with a ValidationError", async () => {
|
|
79
|
+
const provider = await options.makeProvider();
|
|
80
|
+
const input = options.sampleCollection();
|
|
81
|
+
await expect(
|
|
82
|
+
provider.collection({
|
|
83
|
+
...input,
|
|
84
|
+
customer: { ...input.customer, operator: "momorail_bogus" }
|
|
85
|
+
})
|
|
86
|
+
).rejects.toBeInstanceOf(ValidationError);
|
|
87
|
+
});
|
|
88
|
+
it("surfaces a failed transaction with a reason", async () => {
|
|
89
|
+
if (!options.makeFailingProvider) return;
|
|
90
|
+
const provider = await options.makeFailingProvider();
|
|
91
|
+
const created = await provider.collection(options.sampleCollection());
|
|
92
|
+
const final = isTerminal(created.status) ? created : await settle(provider, created.id, maxPolls);
|
|
93
|
+
expect(final.status).toBe("failed");
|
|
94
|
+
expect(final.failureReason).toBeDefined();
|
|
95
|
+
});
|
|
96
|
+
it("throws AuthError when credentials are invalid", async () => {
|
|
97
|
+
if (!options.makeUnauthenticatedProvider) return;
|
|
98
|
+
const provider = await options.makeUnauthenticatedProvider();
|
|
99
|
+
await expect(provider.collection(options.sampleCollection())).rejects.toBeInstanceOf(
|
|
100
|
+
AuthError
|
|
101
|
+
);
|
|
102
|
+
});
|
|
103
|
+
if (options.sampleDisbursement) {
|
|
104
|
+
it("creates a disbursement and drives it to a terminal status", async () => {
|
|
105
|
+
const provider = await options.makeProvider();
|
|
106
|
+
if (!provider.capabilities().disbursement) {
|
|
107
|
+
throw new Error(
|
|
108
|
+
"sampleDisbursement was provided but capabilities().disbursement is false"
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
const input = options.sampleDisbursement();
|
|
112
|
+
const created = await provider.disbursement(input);
|
|
113
|
+
expect(created.type).toBe("disbursement");
|
|
114
|
+
expect(created.reference).toBe(input.reference);
|
|
115
|
+
expect(created.amount).toEqual(input.amount);
|
|
116
|
+
const final = isTerminal(created.status) ? created : await settle(provider, created.id, maxPolls);
|
|
117
|
+
expect(isTerminal(final.status)).toBe(true);
|
|
118
|
+
});
|
|
119
|
+
} else {
|
|
120
|
+
it("rejects disbursement with a not_supported error when the capability is off", async () => {
|
|
121
|
+
const provider = await options.makeProvider();
|
|
122
|
+
if (provider.capabilities().disbursement) return;
|
|
123
|
+
const err = await provider.disbursement({
|
|
124
|
+
amount: { amount: 1e3, currency: "XOF" },
|
|
125
|
+
recipient: { phone: "+22500000000" },
|
|
126
|
+
reference: "momorail-conformance-disb"
|
|
127
|
+
}).catch((e) => e);
|
|
128
|
+
expect(err).toBeInstanceOf(MomorailError);
|
|
129
|
+
expect(err.code).toBe("not_supported");
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
export {
|
|
135
|
+
runProviderConformance
|
|
136
|
+
};
|
|
137
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import {\n AuthError,\n type CollectionInput,\n type DisbursementInput,\n MomorailError,\n type PaymentProvider,\n TransactionNotFoundError,\n ValidationError,\n isTerminal,\n} from '@momorail/core';\nimport { describe, expect, it } from 'vitest';\n\nexport interface ConformanceOptions {\n /** A fresh adapter whose next transaction settles to `succeeded`. */\n makeProvider: () => PaymentProvider | Promise<PaymentProvider>;\n /** A fresh adapter whose next transaction settles to `failed`. Optional. */\n makeFailingProvider?: () => PaymentProvider | Promise<PaymentProvider>;\n /** A fresh adapter configured with invalid credentials. Optional. */\n makeUnauthenticatedProvider?: () => PaymentProvider | Promise<PaymentProvider>;\n /** A valid collection input for this adapter; call it for a fresh reference each time. */\n sampleCollection: () => CollectionInput;\n /**\n * A valid disbursement input. Provide it for adapters that advertise\n * `capabilities().disbursement`; the suite then drives a payout to a terminal\n * status. Omit it and the suite instead asserts `disbursement()` rejects with\n * a `not_supported` error.\n */\n sampleDisbursement?: () => DisbursementInput;\n /** Max polls the suite will do while waiting for a transaction to settle. Default 15. */\n maxPolls?: number;\n}\n\nasync function settle(\n provider: PaymentProvider,\n id: string,\n maxPolls: number,\n): Promise<Awaited<ReturnType<PaymentProvider['getTransaction']>>> {\n let current = await provider.getTransaction({ id });\n for (let i = 0; i < maxPolls && !isTerminal(current.status); i++) {\n current = await provider.getTransaction({ id });\n }\n return current;\n}\n\n/**\n * Register the shared adapter contract as a Vitest `describe` block. Call this at\n * the top level of an adapter's own `*.test.ts` file.\n */\nexport function runProviderConformance(suiteName: string, options: ConformanceOptions): void {\n const maxPolls = options.maxPolls ?? 15;\n\n describe(`conformance: ${suiteName}`, () => {\n it('exposes a lowercase string id', async () => {\n const provider = await options.makeProvider();\n expect(provider.id).toMatch(/^[a-z0-9_-]+$/);\n });\n\n it('reports capabilities with non-empty operator and currency lists', async () => {\n const provider = await options.makeProvider();\n const caps = provider.capabilities();\n expect(typeof caps.collection).toBe('boolean');\n expect(typeof caps.disbursement).toBe('boolean');\n expect(caps.operators.length).toBeGreaterThan(0);\n expect(caps.currencies.length).toBeGreaterThan(0);\n });\n\n it('creates a collection and echoes the caller reference', async () => {\n const provider = await options.makeProvider();\n const input = options.sampleCollection();\n const txn = await provider.collection(input);\n expect(txn.provider).toBe(provider.id);\n expect(txn.reference).toBe(input.reference);\n expect(txn.type).toBe('collection');\n expect(txn.amount).toEqual(input.amount);\n expect(txn.providerRaw).toBeDefined();\n expect(Number.isNaN(Date.parse(txn.createdAt))).toBe(false);\n expect(Number.isNaN(Date.parse(txn.updatedAt))).toBe(false);\n });\n\n it('is idempotent for a repeated reference', async () => {\n const provider = await options.makeProvider();\n const input = options.sampleCollection();\n const first = await provider.collection(input);\n const second = await provider.collection(input);\n expect(second.id).toBe(first.id);\n });\n\n it('looks a transaction back up by id', async () => {\n const provider = await options.makeProvider();\n const created = await provider.collection(options.sampleCollection());\n const fetched = await provider.getTransaction({ id: created.id });\n expect(fetched.id).toBe(created.id);\n });\n\n it('looks a transaction back up by reference when advertised', async () => {\n const provider = await options.makeProvider();\n if (!provider.capabilities().lookupByReference) return;\n const input = options.sampleCollection();\n const created = await provider.collection(input);\n const fetched = await provider.getTransaction({ reference: input.reference });\n expect(fetched.id).toBe(created.id);\n });\n\n it('drives a successful transaction to a terminal status', async () => {\n const provider = await options.makeProvider();\n const created = await provider.collection(options.sampleCollection());\n const final = isTerminal(created.status)\n ? created\n : await settle(provider, created.id, maxPolls);\n expect(isTerminal(final.status)).toBe(true);\n expect(final.status).toBe('succeeded');\n });\n\n it('rejects an unknown transaction ref with TransactionNotFoundError', async () => {\n const provider = await options.makeProvider();\n await expect(\n provider.getTransaction({ id: 'momorail-conformance-missing' }),\n ).rejects.toBeInstanceOf(TransactionNotFoundError);\n });\n\n it('rejects an unknown operator with a ValidationError', async () => {\n const provider = await options.makeProvider();\n const input = options.sampleCollection();\n await expect(\n provider.collection({\n ...input,\n customer: { ...input.customer, operator: 'momorail_bogus' as never },\n }),\n ).rejects.toBeInstanceOf(ValidationError);\n });\n\n it('surfaces a failed transaction with a reason', async () => {\n if (!options.makeFailingProvider) return;\n const provider = await options.makeFailingProvider();\n const created = await provider.collection(options.sampleCollection());\n const final = isTerminal(created.status)\n ? created\n : await settle(provider, created.id, maxPolls);\n expect(final.status).toBe('failed');\n expect(final.failureReason).toBeDefined();\n });\n\n it('throws AuthError when credentials are invalid', async () => {\n if (!options.makeUnauthenticatedProvider) return;\n const provider = await options.makeUnauthenticatedProvider();\n await expect(provider.collection(options.sampleCollection())).rejects.toBeInstanceOf(\n AuthError,\n );\n });\n\n if (options.sampleDisbursement) {\n it('creates a disbursement and drives it to a terminal status', async () => {\n const provider = await options.makeProvider();\n if (!provider.capabilities().disbursement) {\n throw new Error(\n 'sampleDisbursement was provided but capabilities().disbursement is false',\n );\n }\n const input = options.sampleDisbursement!();\n const created = await provider.disbursement(input);\n expect(created.type).toBe('disbursement');\n expect(created.reference).toBe(input.reference);\n expect(created.amount).toEqual(input.amount);\n const final = isTerminal(created.status)\n ? created\n : await settle(provider, created.id, maxPolls);\n expect(isTerminal(final.status)).toBe(true);\n });\n } else {\n it('rejects disbursement with a not_supported error when the capability is off', async () => {\n const provider = await options.makeProvider();\n if (provider.capabilities().disbursement) return;\n const err = await provider\n .disbursement({\n amount: { amount: 1_000, currency: 'XOF' },\n recipient: { phone: '+22500000000' },\n reference: 'momorail-conformance-disb',\n })\n .catch((e: unknown) => e);\n expect(err).toBeInstanceOf(MomorailError);\n expect((err as MomorailError).code).toBe('not_supported');\n });\n }\n });\n}\n"],"mappings":";AAAA;AAAA,EACE;AAAA,EAGA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,UAAU,QAAQ,UAAU;AAsBrC,eAAe,OACb,UACA,IACA,UACiE;AACjE,MAAI,UAAU,MAAM,SAAS,eAAe,EAAE,GAAG,CAAC;AAClD,WAAS,IAAI,GAAG,IAAI,YAAY,CAAC,WAAW,QAAQ,MAAM,GAAG,KAAK;AAChE,cAAU,MAAM,SAAS,eAAe,EAAE,GAAG,CAAC;AAAA,EAChD;AACA,SAAO;AACT;AAMO,SAAS,uBAAuB,WAAmB,SAAmC;AAC3F,QAAM,WAAW,QAAQ,YAAY;AAErC,WAAS,gBAAgB,SAAS,IAAI,MAAM;AAC1C,OAAG,iCAAiC,YAAY;AAC9C,YAAM,WAAW,MAAM,QAAQ,aAAa;AAC5C,aAAO,SAAS,EAAE,EAAE,QAAQ,eAAe;AAAA,IAC7C,CAAC;AAED,OAAG,mEAAmE,YAAY;AAChF,YAAM,WAAW,MAAM,QAAQ,aAAa;AAC5C,YAAM,OAAO,SAAS,aAAa;AACnC,aAAO,OAAO,KAAK,UAAU,EAAE,KAAK,SAAS;AAC7C,aAAO,OAAO,KAAK,YAAY,EAAE,KAAK,SAAS;AAC/C,aAAO,KAAK,UAAU,MAAM,EAAE,gBAAgB,CAAC;AAC/C,aAAO,KAAK,WAAW,MAAM,EAAE,gBAAgB,CAAC;AAAA,IAClD,CAAC;AAED,OAAG,wDAAwD,YAAY;AACrE,YAAM,WAAW,MAAM,QAAQ,aAAa;AAC5C,YAAM,QAAQ,QAAQ,iBAAiB;AACvC,YAAM,MAAM,MAAM,SAAS,WAAW,KAAK;AAC3C,aAAO,IAAI,QAAQ,EAAE,KAAK,SAAS,EAAE;AACrC,aAAO,IAAI,SAAS,EAAE,KAAK,MAAM,SAAS;AAC1C,aAAO,IAAI,IAAI,EAAE,KAAK,YAAY;AAClC,aAAO,IAAI,MAAM,EAAE,QAAQ,MAAM,MAAM;AACvC,aAAO,IAAI,WAAW,EAAE,YAAY;AACpC,aAAO,OAAO,MAAM,KAAK,MAAM,IAAI,SAAS,CAAC,CAAC,EAAE,KAAK,KAAK;AAC1D,aAAO,OAAO,MAAM,KAAK,MAAM,IAAI,SAAS,CAAC,CAAC,EAAE,KAAK,KAAK;AAAA,IAC5D,CAAC;AAED,OAAG,0CAA0C,YAAY;AACvD,YAAM,WAAW,MAAM,QAAQ,aAAa;AAC5C,YAAM,QAAQ,QAAQ,iBAAiB;AACvC,YAAM,QAAQ,MAAM,SAAS,WAAW,KAAK;AAC7C,YAAM,SAAS,MAAM,SAAS,WAAW,KAAK;AAC9C,aAAO,OAAO,EAAE,EAAE,KAAK,MAAM,EAAE;AAAA,IACjC,CAAC;AAED,OAAG,qCAAqC,YAAY;AAClD,YAAM,WAAW,MAAM,QAAQ,aAAa;AAC5C,YAAM,UAAU,MAAM,SAAS,WAAW,QAAQ,iBAAiB,CAAC;AACpE,YAAM,UAAU,MAAM,SAAS,eAAe,EAAE,IAAI,QAAQ,GAAG,CAAC;AAChE,aAAO,QAAQ,EAAE,EAAE,KAAK,QAAQ,EAAE;AAAA,IACpC,CAAC;AAED,OAAG,4DAA4D,YAAY;AACzE,YAAM,WAAW,MAAM,QAAQ,aAAa;AAC5C,UAAI,CAAC,SAAS,aAAa,EAAE,kBAAmB;AAChD,YAAM,QAAQ,QAAQ,iBAAiB;AACvC,YAAM,UAAU,MAAM,SAAS,WAAW,KAAK;AAC/C,YAAM,UAAU,MAAM,SAAS,eAAe,EAAE,WAAW,MAAM,UAAU,CAAC;AAC5E,aAAO,QAAQ,EAAE,EAAE,KAAK,QAAQ,EAAE;AAAA,IACpC,CAAC;AAED,OAAG,wDAAwD,YAAY;AACrE,YAAM,WAAW,MAAM,QAAQ,aAAa;AAC5C,YAAM,UAAU,MAAM,SAAS,WAAW,QAAQ,iBAAiB,CAAC;AACpE,YAAM,QAAQ,WAAW,QAAQ,MAAM,IACnC,UACA,MAAM,OAAO,UAAU,QAAQ,IAAI,QAAQ;AAC/C,aAAO,WAAW,MAAM,MAAM,CAAC,EAAE,KAAK,IAAI;AAC1C,aAAO,MAAM,MAAM,EAAE,KAAK,WAAW;AAAA,IACvC,CAAC;AAED,OAAG,oEAAoE,YAAY;AACjF,YAAM,WAAW,MAAM,QAAQ,aAAa;AAC5C,YAAM;AAAA,QACJ,SAAS,eAAe,EAAE,IAAI,+BAA+B,CAAC;AAAA,MAChE,EAAE,QAAQ,eAAe,wBAAwB;AAAA,IACnD,CAAC;AAED,OAAG,sDAAsD,YAAY;AACnE,YAAM,WAAW,MAAM,QAAQ,aAAa;AAC5C,YAAM,QAAQ,QAAQ,iBAAiB;AACvC,YAAM;AAAA,QACJ,SAAS,WAAW;AAAA,UAClB,GAAG;AAAA,UACH,UAAU,EAAE,GAAG,MAAM,UAAU,UAAU,iBAA0B;AAAA,QACrE,CAAC;AAAA,MACH,EAAE,QAAQ,eAAe,eAAe;AAAA,IAC1C,CAAC;AAED,OAAG,+CAA+C,YAAY;AAC5D,UAAI,CAAC,QAAQ,oBAAqB;AAClC,YAAM,WAAW,MAAM,QAAQ,oBAAoB;AACnD,YAAM,UAAU,MAAM,SAAS,WAAW,QAAQ,iBAAiB,CAAC;AACpE,YAAM,QAAQ,WAAW,QAAQ,MAAM,IACnC,UACA,MAAM,OAAO,UAAU,QAAQ,IAAI,QAAQ;AAC/C,aAAO,MAAM,MAAM,EAAE,KAAK,QAAQ;AAClC,aAAO,MAAM,aAAa,EAAE,YAAY;AAAA,IAC1C,CAAC;AAED,OAAG,iDAAiD,YAAY;AAC9D,UAAI,CAAC,QAAQ,4BAA6B;AAC1C,YAAM,WAAW,MAAM,QAAQ,4BAA4B;AAC3D,YAAM,OAAO,SAAS,WAAW,QAAQ,iBAAiB,CAAC,CAAC,EAAE,QAAQ;AAAA,QACpE;AAAA,MACF;AAAA,IACF,CAAC;AAED,QAAI,QAAQ,oBAAoB;AAC9B,SAAG,6DAA6D,YAAY;AAC1E,cAAM,WAAW,MAAM,QAAQ,aAAa;AAC5C,YAAI,CAAC,SAAS,aAAa,EAAE,cAAc;AACzC,gBAAM,IAAI;AAAA,YACR;AAAA,UACF;AAAA,QACF;AACA,cAAM,QAAQ,QAAQ,mBAAoB;AAC1C,cAAM,UAAU,MAAM,SAAS,aAAa,KAAK;AACjD,eAAO,QAAQ,IAAI,EAAE,KAAK,cAAc;AACxC,eAAO,QAAQ,SAAS,EAAE,KAAK,MAAM,SAAS;AAC9C,eAAO,QAAQ,MAAM,EAAE,QAAQ,MAAM,MAAM;AAC3C,cAAM,QAAQ,WAAW,QAAQ,MAAM,IACnC,UACA,MAAM,OAAO,UAAU,QAAQ,IAAI,QAAQ;AAC/C,eAAO,WAAW,MAAM,MAAM,CAAC,EAAE,KAAK,IAAI;AAAA,MAC5C,CAAC;AAAA,IACH,OAAO;AACL,SAAG,8EAA8E,YAAY;AAC3F,cAAM,WAAW,MAAM,QAAQ,aAAa;AAC5C,YAAI,SAAS,aAAa,EAAE,aAAc;AAC1C,cAAM,MAAM,MAAM,SACf,aAAa;AAAA,UACZ,QAAQ,EAAE,QAAQ,KAAO,UAAU,MAAM;AAAA,UACzC,WAAW,EAAE,OAAO,eAAe;AAAA,UACnC,WAAW;AAAA,QACb,CAAC,EACA,MAAM,CAAC,MAAe,CAAC;AAC1B,eAAO,GAAG,EAAE,eAAe,aAAa;AACxC,eAAQ,IAAsB,IAAI,EAAE,KAAK,eAAe;AAAA,MAC1D,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AACH;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@momorail/conformance",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Shared Vitest suite every Momorail adapter must pass",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"mobile-money",
|
|
8
|
+
"payments",
|
|
9
|
+
"west-africa",
|
|
10
|
+
"africa",
|
|
11
|
+
"orange-money",
|
|
12
|
+
"mtn-momo",
|
|
13
|
+
"wave",
|
|
14
|
+
"xof",
|
|
15
|
+
"byo-keys",
|
|
16
|
+
"typescript",
|
|
17
|
+
"conformance"
|
|
18
|
+
],
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"author": "Boukymen <boukymen@gmail.com>",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/Boukymen/momorail.git",
|
|
24
|
+
"directory": "packages/conformance"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://github.com/Boukymen/momorail/tree/main/packages/conformance#readme",
|
|
27
|
+
"bugs": "https://github.com/Boukymen/momorail/issues",
|
|
28
|
+
"main": "./dist/index.js",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"import": "./dist/index.js"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist"
|
|
38
|
+
],
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@momorail/core": "0.1.0"
|
|
44
|
+
},
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"vitest": ">=2"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"tsup": "^8.3.5",
|
|
50
|
+
"typescript": "^5.7.2",
|
|
51
|
+
"vitest": "^2.1.8"
|
|
52
|
+
},
|
|
53
|
+
"scripts": {
|
|
54
|
+
"build": "tsup",
|
|
55
|
+
"typecheck": "tsc --noEmit"
|
|
56
|
+
}
|
|
57
|
+
}
|