@dryinov8/zumbopay-ts 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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Salvador Matavele
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,375 @@
1
+ # @salvamatavele/zumbopay-ts
2
+
3
+ [![NPM Version](https://img.shields.io/npm/v/@salvamatavele/zumbopay-ts?color=blue)](https://www.npmjs.com/package/@salvamatavele/zumbopay-ts)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT)
5
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
6
+
7
+ SDK oficial em **TypeScript / JavaScript** e componentes **React** para integração do gateway de pagamentos **[ZumboPay](https://zumbopay.com)** em Moçambique.
8
+
9
+ Compatível com **Node.js**, **Next.js** (App Router & Pages), **React**, **Vite**, **Remix** e **Express**.
10
+
11
+ ---
12
+
13
+ ## 🚀 Funcionalidades
14
+
15
+ * 🇲🇿 **Suporte a Carteiras Móveis Moçambicanas:**
16
+ * **Vodacom M-Pesa** (prefixos `84`, `85`)
17
+ * **Movitel e-Mola** (prefixos `86`, `87`)
18
+ * **Tmcel mKesh** (prefixos `82`, `83`)
19
+ * 💳 **Cartões Bancários:** Checkout hospedado com suporte a cartões **Visa** e **Mastercard** (nacionais e internacionais).
20
+ * 🎛️ **Interruptor Global / Kill-Switch (`enabled: boolean`):** Ative ou silencie o gateway dinamicamente via código (`enabled: false`) ou variável de ambiente (`ZUMBOPAY_ENABLED=false`).
21
+ * ⚛️ **Componentes & Hooks React Prontos:** Componente `<ZumboPayModal />` acessível com abas e deteção visual de operadora, e hook `useZumboPay()`.
22
+ * 🛡️ **Segurança & Webhooks:** Validação criptográfica de assinaturas HMAC-SHA256 em tempo constante contra *timing attacks*.
23
+ * 📦 **Dual Build:** Suporta módulos **ESM** (`import`) e **CommonJS** (`require`), com tipos TypeScript completos (`.d.ts`).
24
+
25
+ ---
26
+
27
+ ## 📦 Instalação
28
+
29
+ ```bash
30
+ # npm
31
+ npm install @salvamatavele/zumbopay-ts
32
+
33
+ # pnpm
34
+ pnpm add @salvamatavele/zumbopay-ts
35
+
36
+ # yarn
37
+ yarn add @salvamatavele/zumbopay-ts
38
+ ```
39
+
40
+ *(Se pretender utilizar os componentes React, certifique-se de que tem `react` e `react-dom` instalados no seu projeto).*
41
+
42
+ ---
43
+
44
+ ## ⚙️ Configuração e Variáveis de Ambiente
45
+
46
+ Crie ou adicione ao seu ficheiro `.env`:
47
+
48
+ ```env
49
+ # Credenciais Principais
50
+ ZUMBOPAY_API_KEY=sua_chave_secreta_aqui
51
+ ZUMBOPAY_MERCHANT_ID=seu_merchant_id_aqui
52
+ ZUMBOPAY_WEBHOOK_SECRET=seu_webhook_secret_aqui
53
+
54
+ # Carteiras Pré-configuradas (UUIDs) - Opcional
55
+ # (Se deixar vazio, o SDK descobre automaticamente os UUIDs via GET /wallets)
56
+ ZUMBOPAY_WALLET_MPESA=uuid-carteira-mpesa
57
+ ZUMBOPAY_WALLET_EMOLA=uuid-carteira-emola
58
+ ZUMBOPAY_WALLET_MKESH=uuid-carteira-mkesh
59
+ ZUMBOPAY_WALLET_CARD=uuid-carteira-cartao
60
+
61
+ # Gatilho de silenciamento global / Kill-Switch (Opcional - padrão: true)
62
+ ZUMBOPAY_ENABLED=true
63
+ ```
64
+
65
+ ---
66
+
67
+ ## 💼 Como Configurar e Passar as Carteiras (Wallets)
68
+
69
+ O `zumbopay-ts` oferece total flexibilidade para passar os UUIDs das suas carteiras do painel ZumboPay:
70
+
71
+ ### Forma 1: Automática via `.env` (Recomendado para Node.js / Next.js)
72
+ Basta definir as variáveis no `.env` como mostrado acima. O cliente lê-as automaticamente:
73
+ ```typescript
74
+ const zumboPay = new ZumboPayClient({
75
+ apiKey: process.env.ZUMBOPAY_API_KEY!,
76
+ merchantId: process.env.ZUMBOPAY_MERCHANT_ID!,
77
+ // As carteiras MPESA, EMOLA, MKESH e CARD são lidas automaticamente do .env!
78
+ });
79
+ ```
80
+
81
+ ### Forma 2: No Construtor do Cliente
82
+ Pode passar o objeto `wallets` explicitamente no código:
83
+ ```typescript
84
+ const zumboPay = new ZumboPayClient({
85
+ apiKey: '...',
86
+ merchantId: '...',
87
+ wallets: {
88
+ mpesa: 'd1a2b3c4-....', // UUID carteira Vodacom M-Pesa
89
+ emola: 'e5f6a7b8-....', // UUID carteira Movitel e-Mola
90
+ mkesh: 'c9d0e1f2-....', // UUID carteira Tmcel mKesh
91
+ card: 'a3b4c5d6-....', // UUID carteira Cartão Bancário
92
+ },
93
+ });
94
+ ```
95
+
96
+ ### Forma 3: No Componente React (`<ZumboPayModal />`)
97
+ ```tsx
98
+ <ZumboPayModal
99
+ isOpen={isOpen}
100
+ onClose={() => setIsOpen(false)}
101
+ config={{
102
+ apiKey: 'pk_live_...',
103
+ merchantId: 'mer_...',
104
+ wallets: {
105
+ mpesa: 'uuid-mpesa',
106
+ emola: 'uuid-emola',
107
+ mkesh: 'uuid-mkesh',
108
+ card: 'uuid-card',
109
+ },
110
+ }}
111
+ amount={1500}
112
+ />
113
+ ```
114
+
115
+ ### Forma 4: Por Transação Pontual (Sobrescrita Ad-hoc)
116
+ ```typescript
117
+ await zumboPay.stkPush({
118
+ amount: 250,
119
+ phone: '841234567',
120
+ walletId: 'uuid-especifico-desta-transacao', // Força este UUID
121
+ });
122
+ ```
123
+
124
+ ### Forma 5: Auto-descoberta Dinâmica
125
+ Se **não** passar nenhum UUID de carteira, o SDK consulta automaticamente a rota `GET /wallets` da sua conta ZumboPay e mapeia a carteira correta para M-Pesa, e-Mola, mKesh ou Cartão (com cache em memória de 10 minutos).
126
+
127
+
128
+ ---
129
+
130
+ ## 📖 Guia de Utilização Rápida
131
+
132
+ ### 1. Iniciar STK Push (M-Pesa, e-Mola ou mKesh) no Backend
133
+
134
+ ```typescript
135
+ import { ZumboPayClient } from 'zumbopay-ts';
136
+
137
+ const zumboPay = new ZumboPayClient({
138
+ apiKey: process.env.ZUMBOPAY_API_KEY!,
139
+ merchantId: process.env.ZUMBOPAY_MERCHANT_ID!,
140
+ // Ativação / Kill-Switch (lê automaticamente process.env.ZUMBOPAY_ENABLED)
141
+ enabled: process.env.ZUMBOPAY_ENABLED !== 'false',
142
+ });
143
+
144
+ // Envia prompt STK para o telemóvel do cliente
145
+ const response = await zumboPay.stkPush({
146
+ amount: 250.00,
147
+ phone: '841234567', // Detecta automaticamente Vodacom M-Pesa
148
+ reference: 'PROP-2026-001',
149
+ customerName: 'Manuel Cossa',
150
+ description: 'Pagamento de Propina Escolar',
151
+ });
152
+
153
+ if (response.success) {
154
+ console.log('Status:', response.status); // 'pending' | 'success'
155
+ console.log('Mensagem:', response.message);
156
+ } else {
157
+ console.error('Falha:', response.message);
158
+ }
159
+ ```
160
+
161
+ ---
162
+
163
+ ### 2. Criar Checkout Hospedado (Cartão Visa/Mastercard)
164
+
165
+ ```typescript
166
+ const checkout = await zumboPay.createCheckout({
167
+ amount: 1500.00,
168
+ title: 'Matrícula Anual',
169
+ reference: 'MAT-2026-890',
170
+ returnUrl: 'https://seu-sistema.ac.mz/pagamento/sucesso',
171
+ cancelUrl: 'https://seu-sistema.ac.mz/pagamento/cancelado',
172
+ channels: ['card', 'mpesa', 'emola', 'mkesh'],
173
+ });
174
+
175
+ if (checkout.success && checkout.checkoutUrl) {
176
+ // Redirecionar o cliente para a página de pagamento
177
+ console.log('URL de pagamento:', checkout.checkoutUrl);
178
+ }
179
+ ```
180
+
181
+ ---
182
+
183
+ ### 3. Consultar Estado da Transação
184
+
185
+ ```typescript
186
+ const status = await zumboPay.getStatus('PROP-2026-001');
187
+
188
+ console.log('Está pago?', status.paid); // true | false
189
+ console.log('Estado:', status.status); // 'success' | 'pending' | 'failed'
190
+ ```
191
+
192
+ ---
193
+
194
+ ## 🎛️ Gatilho de Silenciamento / Kill-Switch
195
+
196
+ Pode desativar ou suspender o gateway a qualquer momento sem necessidade de alterar o código dos seus endpoints:
197
+
198
+ ```typescript
199
+ // 1. Via variável de ambiente:
200
+ // ZUMBOPAY_ENABLED=false
201
+
202
+ // 2. Via inicialização:
203
+ const client = new ZumboPayClient({
204
+ apiKey: '...',
205
+ merchantId: '...',
206
+ enabled: false, // Silencia STK e checkouts
207
+ });
208
+
209
+ // 3. Via controlo dinâmico em tempo de execução:
210
+ client.setEnabled(false);
211
+
212
+ const res = await client.stkPush({ amount: 100, phone: '841234567' });
213
+ // Retorna imediatamente:
214
+ // { success: false, status: 'disabled', message: 'O gateway de pagamento ZumboPay está temporariamente desativado.' }
215
+ // Nenhuma chamada externa é feita!
216
+ ```
217
+
218
+ ---
219
+
220
+ ## ⚛️ Utilização com React / Next.js
221
+
222
+ Importe o componente ou o hook através do submódulo `zumbopay-ts/react`:
223
+
224
+ ### Opção A: Modal Completo (`<ZumboPayModal />`)
225
+
226
+ ```tsx
227
+ import React, { useState } from 'react';
228
+ import { ZumboPayModal } from 'zumbopay-ts/react';
229
+
230
+ export function CheckoutButton() {
231
+ const [isOpen, setIsOpen] = useState(false);
232
+
233
+ return (
234
+ <>
235
+ <button
236
+ onClick={() => setIsOpen(true)}
237
+ className="px-4 py-2 bg-blue-600 text-white rounded-lg font-bold"
238
+ >
239
+ Pagar com ZumboPay
240
+ </button>
241
+
242
+ <ZumboPayModal
243
+ isOpen={isOpen}
244
+ onClose={() => setIsOpen(false)}
245
+ config={{
246
+ apiKey: 'pk_live_...',
247
+ merchantId: 'mer_...',
248
+ enabled: true,
249
+ }}
250
+ amount={1500}
251
+ reference="PEDIDO-994"
252
+ title="Inscrição em Exame"
253
+ onPaymentSuccess={(payment) => {
254
+ alert('Pagamento recebido com sucesso!');
255
+ setIsOpen(false);
256
+ }}
257
+ />
258
+ </>
259
+ );
260
+ }
261
+ ```
262
+
263
+ ### Opção B: Hook Personalizado (`useZumboPay`)
264
+
265
+ ```tsx
266
+ import { useZumboPay } from 'zumbopay-ts/react';
267
+
268
+ export function CustomPaymentForm() {
269
+ const {
270
+ phone,
271
+ setPhone,
272
+ operator,
273
+ isLoading,
274
+ status,
275
+ errorMessage,
276
+ initiateStk,
277
+ } = useZumboPay({
278
+ config: {
279
+ apiKey: '...',
280
+ merchantId: '...',
281
+ },
282
+ onSuccess: (res) => console.log('Sucesso!', res),
283
+ });
284
+
285
+ return (
286
+ <div>
287
+ <input
288
+ type="tel"
289
+ value={phone}
290
+ onChange={(e) => setPhone(e.target.value)}
291
+ placeholder="84 / 86 / 82..."
292
+ />
293
+ <span>Operadora detectada: {operator}</span>
294
+
295
+ <button
296
+ disabled={isLoading}
297
+ onClick={() => initiateStk({ amount: 500 })}
298
+ >
299
+ {isLoading ? 'A processar...' : 'Pagar 500 MZN'}
300
+ </button>
301
+
302
+ {errorMessage && <p className="text-red-500">{errorMessage}</p>}
303
+ </div>
304
+ );
305
+ }
306
+ ```
307
+
308
+ ---
309
+
310
+ ## 🔐 Validação de Webhook (Node.js / Express / Next.js)
311
+
312
+ Para garantir que as notificações de pagamento recebidas no seu servidor provêm legitimamente do ZumboPay:
313
+
314
+ ### Exemplo em Next.js (App Router: `app/api/webhooks/zumbopay/route.ts`)
315
+
316
+ ```typescript
317
+ import { NextRequest, NextResponse } from 'next/server';
318
+ import { verifyWebhookSignature } from 'zumbopay-ts';
319
+
320
+ export async function POST(req: NextRequest) {
321
+ const rawBody = await req.text();
322
+ const signature = req.headers.get('x-signature') || req.headers.get('x-zumbopay-signature') || '';
323
+ const secret = process.env.ZUMBOPAY_WEBHOOK_SECRET!;
324
+
325
+ // Validação criptográfica HMAC-SHA256
326
+ const isValid = verifyWebhookSignature(rawBody, signature, secret);
327
+
328
+ if (!isValid) {
329
+ return NextResponse.json({ error: 'Assinatura inválida' }, { status: 401 });
330
+ }
331
+
332
+ const event = JSON.parse(rawBody);
333
+
334
+ if (event.event === 'payment.succeeded') {
335
+ const { reference, amount } = event.data;
336
+ // Liquidar fatura na base de dados
337
+ }
338
+
339
+ return NextResponse.json({ received: true });
340
+ }
341
+ ```
342
+
343
+ ---
344
+
345
+ ## 🛠️ Utilitários de Telefonia de Moçambique
346
+
347
+ ```typescript
348
+ import { normalizePhone, detectOperator, isValidMozPhone } from 'zumbopay-ts';
349
+
350
+ normalizePhone('+258 (84) 123-4567'); // '258841234567'
351
+ detectOperator('841234567'); // 'mpesa'
352
+ detectOperator('861234567'); // 'emola'
353
+ detectOperator('821234567'); // 'mkesh'
354
+ isValidMozPhone('841234567'); // true
355
+ isValidMozPhone('12345'); // false
356
+ ```
357
+
358
+ ---
359
+
360
+ ## 🏷️ Versionamento e Política de Releases
361
+
362
+ Este projeto segue rigorosamente o padrão **[Semantic Versioning (SemVer)](https://semver.org/)**:
363
+ - **MAJOR (`X.0.0`)**: Mudanças incompatíveis na API.
364
+ - **MINOR (`0.X.0`)**: Adição de novas funcionalidades retrocompatíveis (ex: novos canais ou carteiras).
365
+ - **PATCH (`0.0.X`)**: Correções de bugs e otimizações retrocompatíveis.
366
+
367
+ Consulte o histórico de alterações em `CHANGELOG.md`.
368
+
369
+ ---
370
+
371
+ ## 📄 Licença
372
+
373
+ Distribuído sob a licença MIT. Consulte `LICENSE` para mais detalhes.
374
+
375
+ Desenvolvido por **[Salvador Matavele](https://github.com/salvamatavele)**.