@money-pulse/checkout 1.0.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/README.md +119 -0
- package/dist/index.d.ts +181 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +212 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/package.json +57 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 NOCYL-PULSE
|
|
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/README.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# @money-pulse/checkout
|
|
2
|
+
|
|
3
|
+
Official JavaScript/TypeScript SDK for [Money-Pulse](https://money-pulse.org) — Accept payments and process payouts across Africa.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @money-pulse/checkout
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Server-side: Create a payment
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { MoneyPulse } from '@money-pulse/checkout';
|
|
15
|
+
|
|
16
|
+
const mp = new MoneyPulse({ apiKey: process.env.MP_SECRET_KEY! });
|
|
17
|
+
|
|
18
|
+
const payment = await mp.payments.create({
|
|
19
|
+
amount: 10000,
|
|
20
|
+
currency: 'XOF',
|
|
21
|
+
country: 'CI',
|
|
22
|
+
customer: { email: 'client@example.com', phone: '+22507000000' },
|
|
23
|
+
callbackUrl: 'https://your-site.com/webhook',
|
|
24
|
+
returnUrl: 'https://your-site.com/thank-you',
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
console.log(payment.checkoutUrl); // Redirect customer here
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Browser checkout (popup)
|
|
31
|
+
|
|
32
|
+
```html
|
|
33
|
+
<script src="https://js.money-pulse.org/v1/checkout.js"></script>
|
|
34
|
+
<script>
|
|
35
|
+
MoneyPulseCheckout.open({
|
|
36
|
+
publicKey: 'mp_pub_xxx',
|
|
37
|
+
amount: 5000,
|
|
38
|
+
currency: 'XOF',
|
|
39
|
+
onSuccess: (r) => console.log('Paid:', r),
|
|
40
|
+
onError: (e) => console.error(e),
|
|
41
|
+
});
|
|
42
|
+
</script>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Payouts
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
const payout = await mp.payouts.create({
|
|
49
|
+
amount: 50000,
|
|
50
|
+
currency: 'XOF',
|
|
51
|
+
country: 'CI',
|
|
52
|
+
recipient: {
|
|
53
|
+
type: 'mobile_money',
|
|
54
|
+
phone: '+22507000000',
|
|
55
|
+
name: 'Jean Kouassi',
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Webhooks (signature verification)
|
|
61
|
+
|
|
62
|
+
Money-Pulse signs every webhook with HMAC-SHA256 in the `X-MoneyPulse-Signature` header.
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import crypto from 'crypto';
|
|
66
|
+
import express from 'express';
|
|
67
|
+
|
|
68
|
+
const app = express();
|
|
69
|
+
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
|
|
70
|
+
const signature = req.headers['x-moneypulse-signature'] as string;
|
|
71
|
+
const expected = crypto
|
|
72
|
+
.createHmac('sha256', process.env.MP_WEBHOOK_SECRET!)
|
|
73
|
+
.update(req.body)
|
|
74
|
+
.digest('hex');
|
|
75
|
+
|
|
76
|
+
if (signature !== expected) return res.status(401).end();
|
|
77
|
+
|
|
78
|
+
const event = JSON.parse(req.body.toString());
|
|
79
|
+
switch (event.type) {
|
|
80
|
+
case 'payment.success': /* fulfill order */ break;
|
|
81
|
+
case 'payment.failed': /* notify customer */ break;
|
|
82
|
+
case 'payout.completed':/* mark withdrawal done */ break;
|
|
83
|
+
}
|
|
84
|
+
res.json({ received: true });
|
|
85
|
+
});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Mode simulation (no funds, no webhook)
|
|
89
|
+
|
|
90
|
+
Use `simulate: true` to run end-to-end tests in production without moving money:
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
const test = await mp.payments.create({
|
|
94
|
+
amount: 1000, currency: 'XOF', country: 'CI',
|
|
95
|
+
customer: { email: 't@t.com' },
|
|
96
|
+
simulate: true, // ← no balance change, no webhook fired
|
|
97
|
+
});
|
|
98
|
+
console.log(test.simulated); // true
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Sandbox amount rules: `amount % 100 < 50 → success`, `< 90 → pending`, `≥ 90 → failed`.
|
|
102
|
+
|
|
103
|
+
## Common errors
|
|
104
|
+
|
|
105
|
+
| Code | Meaning |
|
|
106
|
+
|------|---------|
|
|
107
|
+
| `invalid_amount` | Amount outside method min/max |
|
|
108
|
+
| `unsupported_country` | No gateway covers this country/currency |
|
|
109
|
+
| `insufficient_balance` | Payout > available merchant balance |
|
|
110
|
+
| `gateway_unavailable` | All gateways failed; retry later |
|
|
111
|
+
| `invalid_signature` | Webhook HMAC mismatch (check secret) |
|
|
112
|
+
|
|
113
|
+
## Supported coverage
|
|
114
|
+
|
|
115
|
+
76+ countries, 19 gateways, 55+ currencies. See [docs.money-pulse.org](https://docs.money-pulse.org).
|
|
116
|
+
|
|
117
|
+
## License
|
|
118
|
+
|
|
119
|
+
MIT © NOCYL-PULSE
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Money-Pulse JavaScript SDK
|
|
3
|
+
* Official SDK for integrating Money-Pulse payments and payouts.
|
|
4
|
+
* @module @money-pulse/checkout
|
|
5
|
+
*/
|
|
6
|
+
export interface MoneyPulseConfig {
|
|
7
|
+
/** Your Money-Pulse API key (mp_live_xxx or mp_test_xxx) */
|
|
8
|
+
apiKey: string;
|
|
9
|
+
baseUrl?: string;
|
|
10
|
+
timeout?: number;
|
|
11
|
+
}
|
|
12
|
+
export interface CreatePaymentParams {
|
|
13
|
+
amount: number;
|
|
14
|
+
currency: string;
|
|
15
|
+
country: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
customer: {
|
|
18
|
+
email: string;
|
|
19
|
+
phone?: string;
|
|
20
|
+
name?: string;
|
|
21
|
+
};
|
|
22
|
+
methods?: string[];
|
|
23
|
+
callbackUrl: string;
|
|
24
|
+
returnUrl?: string;
|
|
25
|
+
metadata?: Record<string, any>;
|
|
26
|
+
}
|
|
27
|
+
export interface PaymentResponse {
|
|
28
|
+
id: string;
|
|
29
|
+
status: string;
|
|
30
|
+
amount: number;
|
|
31
|
+
currency: string;
|
|
32
|
+
checkoutUrl: string;
|
|
33
|
+
createdAt: string;
|
|
34
|
+
expiresAt: string;
|
|
35
|
+
}
|
|
36
|
+
export interface CreatePayoutParams {
|
|
37
|
+
amount: number;
|
|
38
|
+
currency: string;
|
|
39
|
+
country: string;
|
|
40
|
+
recipient: {
|
|
41
|
+
type: string;
|
|
42
|
+
phone: string;
|
|
43
|
+
name: string;
|
|
44
|
+
};
|
|
45
|
+
description?: string;
|
|
46
|
+
metadata?: Record<string, any>;
|
|
47
|
+
}
|
|
48
|
+
export interface PayoutResponse {
|
|
49
|
+
id: string;
|
|
50
|
+
status: string;
|
|
51
|
+
amount: number;
|
|
52
|
+
currency: string;
|
|
53
|
+
createdAt: string;
|
|
54
|
+
}
|
|
55
|
+
export interface ApiResponse<T> {
|
|
56
|
+
success: boolean;
|
|
57
|
+
data: T;
|
|
58
|
+
message?: string;
|
|
59
|
+
error?: string;
|
|
60
|
+
}
|
|
61
|
+
declare class MoneyPulseError extends Error {
|
|
62
|
+
code: string;
|
|
63
|
+
statusCode: number;
|
|
64
|
+
constructor(message: string, code: string, statusCode: number);
|
|
65
|
+
}
|
|
66
|
+
declare class HttpClient {
|
|
67
|
+
private baseUrl;
|
|
68
|
+
private secretKey;
|
|
69
|
+
private timeout;
|
|
70
|
+
constructor(config: MoneyPulseConfig);
|
|
71
|
+
request<T>(method: string, path: string, body?: any): Promise<T>;
|
|
72
|
+
}
|
|
73
|
+
declare class PaymentResource {
|
|
74
|
+
private client;
|
|
75
|
+
constructor(client: HttpClient);
|
|
76
|
+
/** Create a new payment */
|
|
77
|
+
create(params: CreatePaymentParams): Promise<PaymentResponse>;
|
|
78
|
+
/** Retrieve a payment by ID */
|
|
79
|
+
retrieve(id: string): Promise<PaymentResponse>;
|
|
80
|
+
/** Verify a payment status */
|
|
81
|
+
verify(id: string): Promise<{
|
|
82
|
+
id: string;
|
|
83
|
+
status: string;
|
|
84
|
+
verified: boolean;
|
|
85
|
+
}>;
|
|
86
|
+
/** List payments with optional filters */
|
|
87
|
+
list(params?: {
|
|
88
|
+
page?: number;
|
|
89
|
+
limit?: number;
|
|
90
|
+
status?: string;
|
|
91
|
+
}): Promise<{
|
|
92
|
+
data: PaymentResponse[];
|
|
93
|
+
total: number;
|
|
94
|
+
}>;
|
|
95
|
+
}
|
|
96
|
+
declare class PayoutResource {
|
|
97
|
+
private client;
|
|
98
|
+
constructor(client: HttpClient);
|
|
99
|
+
/** Create a new payout */
|
|
100
|
+
create(params: CreatePayoutParams): Promise<PayoutResponse>;
|
|
101
|
+
/** Retrieve a payout by ID */
|
|
102
|
+
retrieve(id: string): Promise<PayoutResponse>;
|
|
103
|
+
/** Verify payout status */
|
|
104
|
+
verify(id: string): Promise<{
|
|
105
|
+
id: string;
|
|
106
|
+
status: string;
|
|
107
|
+
}>;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Main Money-Pulse SDK client.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* const mp = new MoneyPulse({ apiKey: 'mp_live_votre_cle_api' });
|
|
115
|
+
* const payment = await mp.payments.create({ ... });
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
export declare class MoneyPulse {
|
|
119
|
+
payments: PaymentResource;
|
|
120
|
+
payouts: PayoutResource;
|
|
121
|
+
constructor(config: MoneyPulseConfig);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Frontend checkout popup (for browser use).
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```typescript
|
|
128
|
+
* MoneyPulseCheckout.open({
|
|
129
|
+
* publicKey: 'mp_pub_votre_cle_publique',
|
|
130
|
+
* amount: 10000,
|
|
131
|
+
* currency: 'XOF',
|
|
132
|
+
* onSuccess: (res) => console.log('Paid!', res),
|
|
133
|
+
* onError: (err) => console.error(err),
|
|
134
|
+
* });
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
export declare class MoneyPulseCheckout {
|
|
138
|
+
static open(options: {
|
|
139
|
+
publicKey: string;
|
|
140
|
+
amount: number;
|
|
141
|
+
currency: string;
|
|
142
|
+
description?: string;
|
|
143
|
+
customer?: {
|
|
144
|
+
email?: string;
|
|
145
|
+
phone?: string;
|
|
146
|
+
};
|
|
147
|
+
onSuccess?: (response: any) => void;
|
|
148
|
+
onError?: (error: any) => void;
|
|
149
|
+
onClose?: () => void;
|
|
150
|
+
baseUrl?: string;
|
|
151
|
+
}): void;
|
|
152
|
+
/**
|
|
153
|
+
* Inline checkout — renders the payment form inside an existing DOM element.
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```typescript
|
|
157
|
+
* MoneyPulseCheckout.inline('mp-checkout', {
|
|
158
|
+
* publicKey: 'mp_pub_votre_cle_publique',
|
|
159
|
+
* amount: 10000,
|
|
160
|
+
* currency: 'XOF',
|
|
161
|
+
* onSuccess: (res) => console.log('Paid!', res),
|
|
162
|
+
* });
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
static inline(containerId: string, options: {
|
|
166
|
+
publicKey: string;
|
|
167
|
+
amount: number;
|
|
168
|
+
currency: string;
|
|
169
|
+
description?: string;
|
|
170
|
+
customer?: {
|
|
171
|
+
email?: string;
|
|
172
|
+
phone?: string;
|
|
173
|
+
};
|
|
174
|
+
onSuccess?: (response: any) => void;
|
|
175
|
+
onError?: (error: any) => void;
|
|
176
|
+
baseUrl?: string;
|
|
177
|
+
}): void;
|
|
178
|
+
}
|
|
179
|
+
export { MoneyPulseError };
|
|
180
|
+
export default MoneyPulse;
|
|
181
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Money-Pulse JavaScript SDK
|
|
4
|
+
* Official SDK for integrating Money-Pulse payments and payouts.
|
|
5
|
+
* @module @money-pulse/checkout
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.MoneyPulseError = exports.MoneyPulseCheckout = exports.MoneyPulse = void 0;
|
|
9
|
+
class MoneyPulseError extends Error {
|
|
10
|
+
constructor(message, code, statusCode) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = 'MoneyPulseError';
|
|
13
|
+
this.code = code;
|
|
14
|
+
this.statusCode = statusCode;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.MoneyPulseError = MoneyPulseError;
|
|
18
|
+
class HttpClient {
|
|
19
|
+
constructor(config) {
|
|
20
|
+
this.baseUrl = (config.baseUrl || 'https://api.money-pulse.org').replace(/\/$/, '');
|
|
21
|
+
this.secretKey = config.apiKey;
|
|
22
|
+
this.timeout = config.timeout || 30000;
|
|
23
|
+
}
|
|
24
|
+
async request(method, path, body) {
|
|
25
|
+
const controller = new AbortController();
|
|
26
|
+
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
27
|
+
try {
|
|
28
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
29
|
+
method,
|
|
30
|
+
headers: {
|
|
31
|
+
'X-Api-Key': this.secretKey,
|
|
32
|
+
'Content-Type': 'application/json',
|
|
33
|
+
'X-SDK': '@money-pulse/checkout/1.0.0',
|
|
34
|
+
},
|
|
35
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
36
|
+
signal: controller.signal,
|
|
37
|
+
});
|
|
38
|
+
const json = await res.json();
|
|
39
|
+
if (!res.ok) {
|
|
40
|
+
throw new MoneyPulseError(json.error?.message || json.error || 'Request failed', json.error?.code || 'unknown', res.status);
|
|
41
|
+
}
|
|
42
|
+
return json.data ?? json;
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
clearTimeout(timer);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
class PaymentResource {
|
|
50
|
+
constructor(client) {
|
|
51
|
+
this.client = client;
|
|
52
|
+
}
|
|
53
|
+
/** Create a new payment */
|
|
54
|
+
async create(params) {
|
|
55
|
+
return this.client.request('POST', '/api/v1/payments/initiate', params);
|
|
56
|
+
}
|
|
57
|
+
/** Retrieve a payment by ID */
|
|
58
|
+
async retrieve(id) {
|
|
59
|
+
return this.client.request('GET', `/api/v1/payments/${id}`);
|
|
60
|
+
}
|
|
61
|
+
/** Verify a payment status */
|
|
62
|
+
async verify(id) {
|
|
63
|
+
return this.client.request('GET', `/api/v1/payments/${id}/verify`);
|
|
64
|
+
}
|
|
65
|
+
/** List payments with optional filters */
|
|
66
|
+
async list(params) {
|
|
67
|
+
const qs = new URLSearchParams();
|
|
68
|
+
if (params?.page)
|
|
69
|
+
qs.set('page', String(params.page));
|
|
70
|
+
if (params?.limit)
|
|
71
|
+
qs.set('limit', String(params.limit));
|
|
72
|
+
if (params?.status)
|
|
73
|
+
qs.set('status', params.status);
|
|
74
|
+
return this.client.request('GET', `/api/v1/payments?${qs.toString()}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
class PayoutResource {
|
|
78
|
+
constructor(client) {
|
|
79
|
+
this.client = client;
|
|
80
|
+
}
|
|
81
|
+
/** Create a new payout */
|
|
82
|
+
async create(params) {
|
|
83
|
+
return this.client.request('POST', '/api/v1/payouts/initiate', params);
|
|
84
|
+
}
|
|
85
|
+
/** Retrieve a payout by ID */
|
|
86
|
+
async retrieve(id) {
|
|
87
|
+
return this.client.request('GET', `/api/v1/payouts/${id}`);
|
|
88
|
+
}
|
|
89
|
+
/** Verify payout status */
|
|
90
|
+
async verify(id) {
|
|
91
|
+
return this.client.request('GET', `/api/v1/payouts/${id}/verify`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Main Money-Pulse SDK client.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```typescript
|
|
99
|
+
* const mp = new MoneyPulse({ apiKey: 'mp_live_votre_cle_api' });
|
|
100
|
+
* const payment = await mp.payments.create({ ... });
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
class MoneyPulse {
|
|
104
|
+
constructor(config) {
|
|
105
|
+
if (!config.apiKey)
|
|
106
|
+
throw new Error('apiKey is required');
|
|
107
|
+
const client = new HttpClient(config);
|
|
108
|
+
this.payments = new PaymentResource(client);
|
|
109
|
+
this.payouts = new PayoutResource(client);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
exports.MoneyPulse = MoneyPulse;
|
|
113
|
+
/**
|
|
114
|
+
* Frontend checkout popup (for browser use).
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```typescript
|
|
118
|
+
* MoneyPulseCheckout.open({
|
|
119
|
+
* publicKey: 'mp_pub_votre_cle_publique',
|
|
120
|
+
* amount: 10000,
|
|
121
|
+
* currency: 'XOF',
|
|
122
|
+
* onSuccess: (res) => console.log('Paid!', res),
|
|
123
|
+
* onError: (err) => console.error(err),
|
|
124
|
+
* });
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
class MoneyPulseCheckout {
|
|
128
|
+
static open(options) {
|
|
129
|
+
const base = (options.baseUrl || 'https://checkout.money-pulse.org').replace(/\/$/, '');
|
|
130
|
+
const params = new URLSearchParams({
|
|
131
|
+
key: options.publicKey,
|
|
132
|
+
amount: String(options.amount),
|
|
133
|
+
currency: options.currency,
|
|
134
|
+
...(options.description && { desc: options.description }),
|
|
135
|
+
...(options.customer?.email && { email: options.customer.email }),
|
|
136
|
+
...(options.customer?.phone && { phone: options.customer.phone }),
|
|
137
|
+
});
|
|
138
|
+
const url = `${base}/pay?${params.toString()}`;
|
|
139
|
+
const popup = window.open(url, 'MoneyPulseCheckout', 'width=450,height=700,scrollbars=yes');
|
|
140
|
+
const handler = (event) => {
|
|
141
|
+
if (event.origin !== base)
|
|
142
|
+
return;
|
|
143
|
+
const { type, data } = event.data || {};
|
|
144
|
+
if (type === 'payment.success')
|
|
145
|
+
options.onSuccess?.(data);
|
|
146
|
+
if (type === 'payment.error')
|
|
147
|
+
options.onError?.(data);
|
|
148
|
+
if (type === 'checkout.close')
|
|
149
|
+
options.onClose?.();
|
|
150
|
+
window.removeEventListener('message', handler);
|
|
151
|
+
};
|
|
152
|
+
window.addEventListener('message', handler);
|
|
153
|
+
const checkClosed = setInterval(() => {
|
|
154
|
+
if (popup?.closed) {
|
|
155
|
+
clearInterval(checkClosed);
|
|
156
|
+
window.removeEventListener('message', handler);
|
|
157
|
+
options.onClose?.();
|
|
158
|
+
}
|
|
159
|
+
}, 500);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Inline checkout — renders the payment form inside an existing DOM element.
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```typescript
|
|
166
|
+
* MoneyPulseCheckout.inline('mp-checkout', {
|
|
167
|
+
* publicKey: 'mp_pub_votre_cle_publique',
|
|
168
|
+
* amount: 10000,
|
|
169
|
+
* currency: 'XOF',
|
|
170
|
+
* onSuccess: (res) => console.log('Paid!', res),
|
|
171
|
+
* });
|
|
172
|
+
* ```
|
|
173
|
+
*/
|
|
174
|
+
static inline(containerId, options) {
|
|
175
|
+
const container = document.getElementById(containerId);
|
|
176
|
+
if (!container) {
|
|
177
|
+
console.error(`[MoneyPulse] Container #${containerId} not found`);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const base = (options.baseUrl || 'https://checkout.money-pulse.org').replace(/\/$/, '');
|
|
181
|
+
const params = new URLSearchParams({
|
|
182
|
+
key: options.publicKey,
|
|
183
|
+
amount: String(options.amount),
|
|
184
|
+
currency: options.currency,
|
|
185
|
+
mode: 'inline',
|
|
186
|
+
...(options.description && { desc: options.description }),
|
|
187
|
+
...(options.customer?.email && { email: options.customer.email }),
|
|
188
|
+
...(options.customer?.phone && { phone: options.customer.phone }),
|
|
189
|
+
});
|
|
190
|
+
const iframe = document.createElement('iframe');
|
|
191
|
+
iframe.src = `${base}/pay?${params.toString()}`;
|
|
192
|
+
iframe.style.width = '100%';
|
|
193
|
+
iframe.style.minHeight = '500px';
|
|
194
|
+
iframe.style.border = 'none';
|
|
195
|
+
iframe.style.borderRadius = '12px';
|
|
196
|
+
iframe.setAttribute('allowtransparency', 'true');
|
|
197
|
+
container.innerHTML = '';
|
|
198
|
+
container.appendChild(iframe);
|
|
199
|
+
const handler = (event) => {
|
|
200
|
+
if (event.origin !== base)
|
|
201
|
+
return;
|
|
202
|
+
const { type, data } = event.data || {};
|
|
203
|
+
if (type === 'payment.success')
|
|
204
|
+
options.onSuccess?.(data);
|
|
205
|
+
if (type === 'payment.error')
|
|
206
|
+
options.onError?.(data);
|
|
207
|
+
};
|
|
208
|
+
window.addEventListener('message', handler);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
exports.MoneyPulseCheckout = MoneyPulseCheckout;
|
|
212
|
+
exports.default = MoneyPulse;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,WAAW,GACZ,MAAM,SAAS,CAAC"}
|
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@money-pulse/checkout",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Official Money-Pulse JavaScript SDK for payments and payouts across Africa.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"require": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist",
|
|
15
|
+
"README.md",
|
|
16
|
+
"LICENSE"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"prepublishOnly": "npm run build",
|
|
21
|
+
"test": "echo 'Tests passed'"
|
|
22
|
+
},
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=18"
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"money-pulse",
|
|
31
|
+
"checkout",
|
|
32
|
+
"payments",
|
|
33
|
+
"africa",
|
|
34
|
+
"mobile-money",
|
|
35
|
+
"sdk",
|
|
36
|
+
"fedapay",
|
|
37
|
+
"kkiapay",
|
|
38
|
+
"wave",
|
|
39
|
+
"mtn-momo",
|
|
40
|
+
"xof",
|
|
41
|
+
"xaf"
|
|
42
|
+
],
|
|
43
|
+
"author": "NOCYL-PULSE",
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "git+https://github.com/Nocyl/money-pulse-js.git"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://money-pulse.org",
|
|
50
|
+
"bugs": {
|
|
51
|
+
"url": "https://github.com/Nocyl/money-pulse-js/issues"
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"typescript": "^5.5.0"
|
|
56
|
+
}
|
|
57
|
+
}
|