pesafy 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/README.md ADDED
@@ -0,0 +1,177 @@
1
+ # Pesafy ๐Ÿ’ณ
2
+
3
+ > A powerful, type-safe payment gateway library for African payment systems, starting with M-Pesa Daraja API
4
+
5
+ [![npm version](https://img.shields.io/npm/v/pesafy.svg)](https://www.npmjs.com/package/pesafy)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.7-blue.svg)](https://www.typescriptlang.org/)
8
+
9
+ Pesafy simplifies payment processing for Kenyan merchants by providing a clean, well-documented, and easy-to-use interface for M-Pesa transactions. Built with TypeScript, following industry best practices inspired by Stripe.
10
+
11
+ ## โœจ Features
12
+
13
+ - ๐Ÿš€ **Easy Integration**: Simple, intuitive API design
14
+ - ๐Ÿ”’ **Type-Safe**: Full TypeScript support with comprehensive types
15
+ - ๐ŸŽฏ **Complete M-Pesa Coverage**: STK Push, B2C, B2B, C2B, QR Codes, and more
16
+ - ๐Ÿ” **Secure**: Built-in security credential encryption and webhook verification
17
+ - ๐ŸŽจ **Dashboard Ready**: Payment monitoring and webhook management dashboard
18
+ - ๐Ÿงฉ **Component Library**: Reusable payment components for React/Vue
19
+ - ๐Ÿ“š **Well Documented**: Comprehensive documentation and examples
20
+ - โšก **Fast**: Built with Bun for optimal performance
21
+
22
+ ## ๐Ÿ“ฆ Installation
23
+
24
+ ```bash
25
+ # Using npm
26
+ npm install pesafy
27
+
28
+ # Using yarn
29
+ yarn add pesafy
30
+
31
+ # Using pnpm
32
+ pnpm add pesafy
33
+
34
+ # Using bun
35
+ bun add pesafy
36
+ ```
37
+
38
+ ## ๐Ÿš€ Quick Start
39
+
40
+ ```typescript
41
+ import { Mpesa } from "pesafy";
42
+
43
+ const mpesa = new Mpesa({
44
+ consumerKey: "your-consumer-key",
45
+ consumerSecret: "your-consumer-secret",
46
+ environment: "sandbox",
47
+ lipaNaMpesaShortCode: "174379",
48
+ lipaNaMpesaPassKey: "your-passkey",
49
+ });
50
+
51
+ // STK Push (M-Pesa Express)
52
+ const result = await mpesa.stkPush({
53
+ amount: 100,
54
+ phoneNumber: "254712345678",
55
+ callbackUrl: "https://yoursite.com/callback",
56
+ accountReference: "ORDER-123",
57
+ transactionDesc: "Payment for order",
58
+ });
59
+ ```
60
+
61
+ ## ๐Ÿ“š Documentation
62
+
63
+ - **[Getting Started Guide](./docs/guides/getting-started.md)** - Learn how to set up Pesafy
64
+ - **[API Reference](./docs/api/)** - Complete API documentation
65
+ - **[Examples](./docs/examples/)** - Code examples for different frameworks
66
+ - **[Architecture](./ARCHITECTURE.md)** - System architecture overview
67
+ - **[Project Plan](./PROJECT_PLAN.md)** - Development roadmap
68
+
69
+ ## ๐ŸŽฏ Supported APIs
70
+
71
+ ### โœ… Available
72
+
73
+ - **STK Push (M-Pesa Express)** - Initiate payments via STK Push
74
+ - **STK Query** - Check STK Push transaction status
75
+ - **B2C** - Business to Customer payments
76
+ - **B2B** - Business to Business payments
77
+ - **C2B** - Register URLs & simulate (sandbox)
78
+ - **Dynamic QR Codes** - Generate LIPA NA M-PESA QR codes
79
+ - **Transaction Status** - Query transaction status
80
+ - **Reversal** - Reverse transactions
81
+
82
+ ### ๐Ÿ“ฆ Components
83
+
84
+ - **PaymentButton** - Simple button to trigger payments
85
+ - **PaymentForm** - Complete form for collecting payment details
86
+ - **QRCode** - Display M-Pesa dynamic QR codes
87
+ - **PaymentStatus** - Show payment status with visual feedback
88
+
89
+ ## ๐Ÿ—๏ธ Project Structure
90
+
91
+ ```
92
+ pesafy/
93
+ โ”œโ”€โ”€ src/ # Source code
94
+ โ”œโ”€โ”€ docs/ # Documentation
95
+ โ”œโ”€โ”€ tests/ # Test files
96
+ โ”œโ”€โ”€ examples/ # Example projects
97
+ โ””โ”€โ”€ components/ # Payment components (coming soon)
98
+ ```
99
+
100
+ See [FOLDER_STRUCTURE.md](./FOLDER_STRUCTURE.md) for detailed structure.
101
+
102
+ ## ๐Ÿงช Development
103
+
104
+ ```bash
105
+ # Install dependencies
106
+ bun install
107
+
108
+ # Run tests
109
+ bun test
110
+
111
+ # Build the library
112
+ bun run build
113
+
114
+ # Run type checking
115
+ bun run typecheck
116
+
117
+ # Format code
118
+ bun run format
119
+
120
+ # Lint code
121
+ bun run lint
122
+ ```
123
+
124
+ ## ๐Ÿ“Š Dashboard (SaaS)
125
+
126
+ Run the payment monitoring dashboard:
127
+
128
+ ```bash
129
+ cd dashboard
130
+ bun install
131
+ bun run dev
132
+ ```
133
+
134
+ Open http://localhost:3000 to view the dashboard. See [RUNNING.md](./RUNNING.md) for full instructions.
135
+
136
+ ## ๐Ÿ“ Contributing
137
+
138
+ Contributions are welcome! Please read our contributing guidelines before submitting PRs.
139
+
140
+ 1. Fork the repository
141
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
142
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
143
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
144
+ 5. Open a Pull Request
145
+
146
+ ## ๐Ÿ” Security
147
+
148
+ For security concerns, please email [lewisodero27@gmail.com](mailto:lewisodero27@gmail.com) instead of using the issue tracker.
149
+
150
+ ## ๐Ÿ“„ License
151
+
152
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
153
+
154
+ ## ๐Ÿ™ Acknowledgments
155
+
156
+ - [Safaricom Daraja API](https://developer.safaricom.co.ke/) - For providing the M-Pesa API
157
+ - Inspired by payment gateway patterns from Stripe and other industry leaders
158
+
159
+ ## ๐Ÿ“ž Support
160
+
161
+ - ๐Ÿ“ง Email: [lewisodero27@gmail.com](mailto:lewisodero27@gmail.com)
162
+ - ๐Ÿ› Issues: [GitHub Issues](https://github.com/levos-snr/pesafy/issues)
163
+ - ๐Ÿ“– Documentation: [Full Documentation](./docs/)
164
+
165
+ ## ๐Ÿ—บ๏ธ Roadmap
166
+
167
+ See [PROJECT_PLAN.md](./PROJECT_PLAN.md) for the complete development roadmap.
168
+
169
+ **Phase 1** (Current): Core library foundation โœ…
170
+ **Phase 2**: Payment processing implementation ๐Ÿšง
171
+ **Phase 3**: Webhook management system ๐Ÿ“…
172
+ **Phase 4**: Dashboard development ๐Ÿ“…
173
+ **Phase 5**: Payment components ๐Ÿ“…
174
+
175
+ ---
176
+
177
+ Made with โค๏ธ for the African developer community
@@ -0,0 +1,230 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/components/react/index.tsx
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ PaymentButton: () => PaymentButton,
24
+ PaymentForm: () => PaymentForm,
25
+ PaymentStatus: () => PaymentStatus,
26
+ QRCode: () => QRCode
27
+ });
28
+ module.exports = __toCommonJS(index_exports);
29
+
30
+ // src/components/react/PaymentButton.tsx
31
+ var import_jsx_runtime = require("react/jsx-runtime");
32
+ function PaymentButton({
33
+ amount,
34
+ onPay,
35
+ disabled = false,
36
+ loading = false,
37
+ children,
38
+ className = ""
39
+ }) {
40
+ const handleClick = async () => {
41
+ if (disabled || loading) return;
42
+ await onPay({ amount });
43
+ };
44
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
45
+ "button",
46
+ {
47
+ type: "button",
48
+ onClick: handleClick,
49
+ disabled: disabled || loading,
50
+ className: `pesafy-payment-btn ${className}`,
51
+ "aria-busy": loading,
52
+ children: loading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "pesafy-payment-btn-loading", children: "Processing..." }) : children ?? `Pay KES ${amount.toLocaleString()}`
53
+ }
54
+ );
55
+ }
56
+
57
+ // src/components/react/PaymentForm.tsx
58
+ var import_react = require("react");
59
+ var import_jsx_runtime2 = require("react/jsx-runtime");
60
+ function PaymentForm({
61
+ onSubmit,
62
+ defaultAmount = 0,
63
+ defaultReference = "",
64
+ disabled = false,
65
+ loading = false,
66
+ className = ""
67
+ }) {
68
+ const [amount, setAmount] = (0, import_react.useState)(defaultAmount.toString());
69
+ const [phone, setPhone] = (0, import_react.useState)("");
70
+ const [reference, setReference] = (0, import_react.useState)(defaultReference);
71
+ const [desc, setDesc] = (0, import_react.useState)("Payment");
72
+ const handleSubmit = async (e) => {
73
+ e.preventDefault();
74
+ if (disabled || loading) return;
75
+ const amt = Number.parseFloat(amount);
76
+ if (Number.isNaN(amt) || amt <= 0) return;
77
+ const cleaned = phone.replace(/\D/g, "");
78
+ if (cleaned.length < 9) return;
79
+ await onSubmit({
80
+ amount: amt,
81
+ phoneNumber: phone,
82
+ accountReference: reference || `REF-${Date.now()}`,
83
+ transactionDesc: desc
84
+ });
85
+ };
86
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
87
+ "form",
88
+ {
89
+ onSubmit: handleSubmit,
90
+ className: `pesafy-payment-form ${className}`,
91
+ children: [
92
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "pesafy-payment-form-field", children: [
93
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { htmlFor: "pesafy-amount", children: "Amount (KES)" }),
94
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
95
+ "input",
96
+ {
97
+ id: "pesafy-amount",
98
+ type: "number",
99
+ min: "1",
100
+ step: "0.01",
101
+ value: amount,
102
+ onChange: (e) => setAmount(e.target.value),
103
+ placeholder: "100",
104
+ disabled,
105
+ required: true
106
+ }
107
+ )
108
+ ] }),
109
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "pesafy-payment-form-field", children: [
110
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { htmlFor: "pesafy-phone", children: "M-Pesa Phone Number" }),
111
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
112
+ "input",
113
+ {
114
+ id: "pesafy-phone",
115
+ type: "tel",
116
+ value: phone,
117
+ onChange: (e) => setPhone(e.target.value),
118
+ placeholder: "07XX XXX XXX or 2547XX XXX XXX",
119
+ disabled,
120
+ required: true
121
+ }
122
+ )
123
+ ] }),
124
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "pesafy-payment-form-field", children: [
125
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { htmlFor: "pesafy-reference", children: "Reference" }),
126
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
127
+ "input",
128
+ {
129
+ id: "pesafy-reference",
130
+ type: "text",
131
+ value: reference,
132
+ onChange: (e) => setReference(e.target.value),
133
+ placeholder: "ORDER-123",
134
+ disabled,
135
+ maxLength: 12
136
+ }
137
+ )
138
+ ] }),
139
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "pesafy-payment-form-field", children: [
140
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { htmlFor: "pesafy-desc", children: "Description" }),
141
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
142
+ "input",
143
+ {
144
+ id: "pesafy-desc",
145
+ type: "text",
146
+ value: desc,
147
+ onChange: (e) => setDesc(e.target.value),
148
+ placeholder: "Payment",
149
+ disabled,
150
+ maxLength: 13
151
+ }
152
+ )
153
+ ] }),
154
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
155
+ "button",
156
+ {
157
+ type: "submit",
158
+ disabled: disabled || loading,
159
+ className: "pesafy-payment-form-submit",
160
+ "aria-busy": loading,
161
+ children: loading ? "Processing..." : "Pay with M-Pesa"
162
+ }
163
+ )
164
+ ]
165
+ }
166
+ );
167
+ }
168
+
169
+ // src/components/react/PaymentStatus.tsx
170
+ var import_jsx_runtime3 = require("react/jsx-runtime");
171
+ function PaymentStatus({
172
+ status,
173
+ message,
174
+ transactionId,
175
+ children,
176
+ className = ""
177
+ }) {
178
+ if (status === "idle" && !children) return null;
179
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
180
+ "div",
181
+ {
182
+ className: `pesafy-payment-status pesafy-payment-status--${status} ${className}`,
183
+ role: "status",
184
+ "aria-live": "polite",
185
+ children: [
186
+ status === "pending" && (children ?? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: "Waiting for payment..." })),
187
+ status === "success" && (children ?? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { children: [
188
+ "Payment successful",
189
+ transactionId && ` (${transactionId})`,
190
+ message && ` - ${message}`
191
+ ] })),
192
+ status === "error" && (children ?? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { children: [
193
+ "Payment failed",
194
+ message && ` - ${message}`
195
+ ] })),
196
+ status === "idle" && children
197
+ ]
198
+ }
199
+ );
200
+ }
201
+
202
+ // src/components/react/QRCode.tsx
203
+ var import_jsx_runtime4 = require("react/jsx-runtime");
204
+ function QRCode({
205
+ base64,
206
+ alt = "M-Pesa QR Code",
207
+ size = 300,
208
+ className = ""
209
+ }) {
210
+ const src = base64.startsWith("data:") ? base64 : `data:image/png;base64,${base64}`;
211
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
212
+ "img",
213
+ {
214
+ src,
215
+ alt,
216
+ width: size,
217
+ height: size,
218
+ className: `pesafy-qrcode ${className}`,
219
+ loading: "lazy"
220
+ }
221
+ );
222
+ }
223
+ // Annotate the CommonJS export names for ESM import in node:
224
+ 0 && (module.exports = {
225
+ PaymentButton,
226
+ PaymentForm,
227
+ PaymentStatus,
228
+ QRCode
229
+ });
230
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/react/index.tsx","../../../src/components/react/PaymentButton.tsx","../../../src/components/react/PaymentForm.tsx","../../../src/components/react/PaymentStatus.tsx","../../../src/components/react/QRCode.tsx"],"sourcesContent":["/**\n * Pesafy React Components\n * Use with your backend API - never expose Daraja credentials in the browser\n *\n * Import styles: import \"pesafy/components/react/styles.css\"\n */\n\nexport type { PaymentButtonProps } from \"./PaymentButton\";\nexport { PaymentButton } from \"./PaymentButton\";\nexport type { PaymentFormData, PaymentFormProps } from \"./PaymentForm\";\nexport { PaymentForm } from \"./PaymentForm\";\nexport type { PaymentStatusProps, PaymentStatusState } from \"./PaymentStatus\";\nexport { PaymentStatus } from \"./PaymentStatus\";\nexport type { QRCodeProps } from \"./QRCode\";\nexport { QRCode } from \"./QRCode\";\n","/**\n * PaymentButton - Trigger M-Pesa STK Push payment\n * Call onPay with payment details; parent handles API call (credentials stay server-side)\n */\n\nimport type { ReactNode } from \"react\";\n\nexport interface PaymentButtonProps {\n amount: number;\n /** Called when user clicks pay. Parent should call your backend which uses Pesafy */\n onPay: (params: { amount: number }) => void | Promise<void>;\n disabled?: boolean;\n loading?: boolean;\n children?: ReactNode;\n className?: string;\n}\n\nexport function PaymentButton({\n amount,\n onPay,\n disabled = false,\n loading = false,\n children,\n className = \"\",\n}: PaymentButtonProps) {\n const handleClick = async () => {\n if (disabled || loading) return;\n await onPay({ amount });\n };\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n disabled={disabled || loading}\n className={`pesafy-payment-btn ${className}`}\n aria-busy={loading}\n >\n {loading ? (\n <span className=\"pesafy-payment-btn-loading\">Processing...</span>\n ) : (\n (children ?? `Pay KES ${amount.toLocaleString()}`)\n )}\n </button>\n );\n}\n","/**\n * PaymentForm - Collect payment details for M-Pesa STK Push\n * Parent receives form data and handles API call (credentials stay server-side)\n */\n\nimport { type FormEvent, useState } from \"react\";\n\nexport interface PaymentFormData {\n amount: number;\n phoneNumber: string;\n accountReference: string;\n transactionDesc: string;\n}\n\nexport interface PaymentFormProps {\n /** Called on submit. Parent should call your backend which uses Pesafy stkPush */\n onSubmit: (data: PaymentFormData) => void | Promise<void>;\n defaultAmount?: number;\n defaultReference?: string;\n disabled?: boolean;\n loading?: boolean;\n className?: string;\n}\n\nexport function PaymentForm({\n onSubmit,\n defaultAmount = 0,\n defaultReference = \"\",\n disabled = false,\n loading = false,\n className = \"\",\n}: PaymentFormProps) {\n const [amount, setAmount] = useState(defaultAmount.toString());\n const [phone, setPhone] = useState(\"\");\n const [reference, setReference] = useState(defaultReference);\n const [desc, setDesc] = useState(\"Payment\");\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault();\n if (disabled || loading) return;\n\n const amt = Number.parseFloat(amount);\n if (Number.isNaN(amt) || amt <= 0) return;\n\n const cleaned = phone.replace(/\\D/g, \"\");\n if (cleaned.length < 9) return;\n\n await onSubmit({\n amount: amt,\n phoneNumber: phone,\n accountReference: reference || `REF-${Date.now()}`,\n transactionDesc: desc,\n });\n };\n\n return (\n <form\n onSubmit={handleSubmit}\n className={`pesafy-payment-form ${className}`}\n >\n <div className=\"pesafy-payment-form-field\">\n <label htmlFor=\"pesafy-amount\">Amount (KES)</label>\n <input\n id=\"pesafy-amount\"\n type=\"number\"\n min=\"1\"\n step=\"0.01\"\n value={amount}\n onChange={(e) => setAmount((e.target as HTMLInputElement).value)}\n placeholder=\"100\"\n disabled={disabled}\n required\n />\n </div>\n <div className=\"pesafy-payment-form-field\">\n <label htmlFor=\"pesafy-phone\">M-Pesa Phone Number</label>\n <input\n id=\"pesafy-phone\"\n type=\"tel\"\n value={phone}\n onChange={(e) => setPhone((e.target as HTMLInputElement).value)}\n placeholder=\"07XX XXX XXX or 2547XX XXX XXX\"\n disabled={disabled}\n required\n />\n </div>\n <div className=\"pesafy-payment-form-field\">\n <label htmlFor=\"pesafy-reference\">Reference</label>\n <input\n id=\"pesafy-reference\"\n type=\"text\"\n value={reference}\n onChange={(e) => setReference((e.target as HTMLInputElement).value)}\n placeholder=\"ORDER-123\"\n disabled={disabled}\n maxLength={12}\n />\n </div>\n <div className=\"pesafy-payment-form-field\">\n <label htmlFor=\"pesafy-desc\">Description</label>\n <input\n id=\"pesafy-desc\"\n type=\"text\"\n value={desc}\n onChange={(e) => setDesc((e.target as HTMLInputElement).value)}\n placeholder=\"Payment\"\n disabled={disabled}\n maxLength={13}\n />\n </div>\n <button\n type=\"submit\"\n disabled={disabled || loading}\n className=\"pesafy-payment-form-submit\"\n aria-busy={loading}\n >\n {loading ? \"Processing...\" : \"Pay with M-Pesa\"}\n </button>\n </form>\n );\n}\n","/**\n * PaymentStatus - Display payment state (pending, success, failed)\n */\n\nimport type { ReactNode } from \"react\";\n\nexport type PaymentStatusState = \"idle\" | \"pending\" | \"success\" | \"error\";\n\nexport interface PaymentStatusProps {\n status: PaymentStatusState;\n /** Optional message for success/error states */\n message?: string;\n /** Optional transaction/callback data */\n transactionId?: string;\n children?: ReactNode;\n className?: string;\n}\n\nexport function PaymentStatus({\n status,\n message,\n transactionId,\n children,\n className = \"\",\n}: PaymentStatusProps) {\n if (status === \"idle\" && !children) return null;\n\n return (\n <div\n className={`pesafy-payment-status pesafy-payment-status--${status} ${className}`}\n role=\"status\"\n aria-live=\"polite\"\n >\n {status === \"pending\" &&\n (children ?? <span>Waiting for payment...</span>)}\n {status === \"success\" &&\n (children ?? (\n <span>\n Payment successful\n {transactionId && ` (${transactionId})`}\n {message && ` - ${message}`}\n </span>\n ))}\n {status === \"error\" &&\n (children ?? (\n <span>\n Payment failed\n {message && ` - ${message}`}\n </span>\n ))}\n {status === \"idle\" && children}\n </div>\n );\n}\n","/**\n * QRCode - Display M-Pesa Dynamic QR code\n * Pass base64 image from mpesa.qrCode() response\n */\n\nexport interface QRCodeProps {\n /** Base64 QR code image from Dynamic QR API */\n base64: string;\n alt?: string;\n size?: number;\n className?: string;\n}\n\nexport function QRCode({\n base64,\n alt = \"M-Pesa QR Code\",\n size = 300,\n className = \"\",\n}: QRCodeProps) {\n const src = base64.startsWith(\"data:\")\n ? base64\n : `data:image/png;base64,${base64}`;\n\n return (\n <img\n src={src}\n alt={alt}\n width={size}\n height={size}\n className={`pesafy-qrcode ${className}`}\n loading=\"lazy\"\n />\n );\n}\n"],"mappings":"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","names":["import_jsx_runtime","import_jsx_runtime","import_jsx_runtime"]}
@@ -0,0 +1,63 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+
4
+ interface PaymentButtonProps {
5
+ amount: number;
6
+ /** Called when user clicks pay. Parent should call your backend which uses Pesafy */
7
+ onPay: (params: {
8
+ amount: number;
9
+ }) => void | Promise<void>;
10
+ disabled?: boolean;
11
+ loading?: boolean;
12
+ children?: ReactNode;
13
+ className?: string;
14
+ }
15
+ declare function PaymentButton({ amount, onPay, disabled, loading, children, className, }: PaymentButtonProps): react_jsx_runtime.JSX.Element;
16
+
17
+ /**
18
+ * PaymentForm - Collect payment details for M-Pesa STK Push
19
+ * Parent receives form data and handles API call (credentials stay server-side)
20
+ */
21
+ interface PaymentFormData {
22
+ amount: number;
23
+ phoneNumber: string;
24
+ accountReference: string;
25
+ transactionDesc: string;
26
+ }
27
+ interface PaymentFormProps {
28
+ /** Called on submit. Parent should call your backend which uses Pesafy stkPush */
29
+ onSubmit: (data: PaymentFormData) => void | Promise<void>;
30
+ defaultAmount?: number;
31
+ defaultReference?: string;
32
+ disabled?: boolean;
33
+ loading?: boolean;
34
+ className?: string;
35
+ }
36
+ declare function PaymentForm({ onSubmit, defaultAmount, defaultReference, disabled, loading, className, }: PaymentFormProps): react_jsx_runtime.JSX.Element;
37
+
38
+ type PaymentStatusState = "idle" | "pending" | "success" | "error";
39
+ interface PaymentStatusProps {
40
+ status: PaymentStatusState;
41
+ /** Optional message for success/error states */
42
+ message?: string;
43
+ /** Optional transaction/callback data */
44
+ transactionId?: string;
45
+ children?: ReactNode;
46
+ className?: string;
47
+ }
48
+ declare function PaymentStatus({ status, message, transactionId, children, className, }: PaymentStatusProps): react_jsx_runtime.JSX.Element | null;
49
+
50
+ /**
51
+ * QRCode - Display M-Pesa Dynamic QR code
52
+ * Pass base64 image from mpesa.qrCode() response
53
+ */
54
+ interface QRCodeProps {
55
+ /** Base64 QR code image from Dynamic QR API */
56
+ base64: string;
57
+ alt?: string;
58
+ size?: number;
59
+ className?: string;
60
+ }
61
+ declare function QRCode({ base64, alt, size, className, }: QRCodeProps): react_jsx_runtime.JSX.Element;
62
+
63
+ export { PaymentButton, type PaymentButtonProps, PaymentForm, type PaymentFormData, type PaymentFormProps, PaymentStatus, type PaymentStatusProps, type PaymentStatusState, QRCode, type QRCodeProps };
@@ -0,0 +1,63 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+
4
+ interface PaymentButtonProps {
5
+ amount: number;
6
+ /** Called when user clicks pay. Parent should call your backend which uses Pesafy */
7
+ onPay: (params: {
8
+ amount: number;
9
+ }) => void | Promise<void>;
10
+ disabled?: boolean;
11
+ loading?: boolean;
12
+ children?: ReactNode;
13
+ className?: string;
14
+ }
15
+ declare function PaymentButton({ amount, onPay, disabled, loading, children, className, }: PaymentButtonProps): react_jsx_runtime.JSX.Element;
16
+
17
+ /**
18
+ * PaymentForm - Collect payment details for M-Pesa STK Push
19
+ * Parent receives form data and handles API call (credentials stay server-side)
20
+ */
21
+ interface PaymentFormData {
22
+ amount: number;
23
+ phoneNumber: string;
24
+ accountReference: string;
25
+ transactionDesc: string;
26
+ }
27
+ interface PaymentFormProps {
28
+ /** Called on submit. Parent should call your backend which uses Pesafy stkPush */
29
+ onSubmit: (data: PaymentFormData) => void | Promise<void>;
30
+ defaultAmount?: number;
31
+ defaultReference?: string;
32
+ disabled?: boolean;
33
+ loading?: boolean;
34
+ className?: string;
35
+ }
36
+ declare function PaymentForm({ onSubmit, defaultAmount, defaultReference, disabled, loading, className, }: PaymentFormProps): react_jsx_runtime.JSX.Element;
37
+
38
+ type PaymentStatusState = "idle" | "pending" | "success" | "error";
39
+ interface PaymentStatusProps {
40
+ status: PaymentStatusState;
41
+ /** Optional message for success/error states */
42
+ message?: string;
43
+ /** Optional transaction/callback data */
44
+ transactionId?: string;
45
+ children?: ReactNode;
46
+ className?: string;
47
+ }
48
+ declare function PaymentStatus({ status, message, transactionId, children, className, }: PaymentStatusProps): react_jsx_runtime.JSX.Element | null;
49
+
50
+ /**
51
+ * QRCode - Display M-Pesa Dynamic QR code
52
+ * Pass base64 image from mpesa.qrCode() response
53
+ */
54
+ interface QRCodeProps {
55
+ /** Base64 QR code image from Dynamic QR API */
56
+ base64: string;
57
+ alt?: string;
58
+ size?: number;
59
+ className?: string;
60
+ }
61
+ declare function QRCode({ base64, alt, size, className, }: QRCodeProps): react_jsx_runtime.JSX.Element;
62
+
63
+ export { PaymentButton, type PaymentButtonProps, PaymentForm, type PaymentFormData, type PaymentFormProps, PaymentStatus, type PaymentStatusProps, type PaymentStatusState, QRCode, type QRCodeProps };