paybridge 0.1.2 → 0.2.1

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 (48) hide show
  1. package/README.md +87 -7
  2. package/dist/circuit-breaker-store.d.ts +27 -0
  3. package/dist/circuit-breaker-store.js +25 -0
  4. package/dist/circuit-breaker.d.ts +30 -0
  5. package/dist/circuit-breaker.js +86 -0
  6. package/dist/crypto/base.d.ts +15 -0
  7. package/dist/crypto/base.js +24 -0
  8. package/dist/crypto/index.d.ts +35 -0
  9. package/dist/crypto/index.js +95 -0
  10. package/dist/crypto/mock.d.ts +15 -0
  11. package/dist/crypto/mock.js +112 -0
  12. package/dist/crypto/moonpay.d.ts +33 -0
  13. package/dist/crypto/moonpay.js +251 -0
  14. package/dist/crypto/router.d.ts +36 -0
  15. package/dist/crypto/router.js +287 -0
  16. package/dist/crypto/types.d.ts +89 -0
  17. package/dist/crypto/types.js +5 -0
  18. package/dist/crypto/yellowcard.d.ts +56 -0
  19. package/dist/crypto/yellowcard.js +310 -0
  20. package/dist/index.d.ts +9 -1
  21. package/dist/index.js +59 -3
  22. package/dist/providers/base.d.ts +5 -0
  23. package/dist/providers/flutterwave.d.ts +36 -0
  24. package/dist/providers/flutterwave.js +338 -0
  25. package/dist/providers/ozow.d.ts +20 -2
  26. package/dist/providers/ozow.js +161 -114
  27. package/dist/providers/payfast.d.ts +40 -0
  28. package/dist/providers/payfast.js +355 -0
  29. package/dist/providers/paystack.d.ts +37 -0
  30. package/dist/providers/paystack.js +335 -0
  31. package/dist/providers/peach.d.ts +50 -0
  32. package/dist/providers/peach.js +305 -0
  33. package/dist/providers/softycomp.d.ts +106 -0
  34. package/dist/providers/softycomp.js +234 -10
  35. package/dist/providers/stripe.d.ts +38 -0
  36. package/dist/providers/stripe.js +370 -0
  37. package/dist/providers/yoco.d.ts +12 -0
  38. package/dist/providers/yoco.js +159 -61
  39. package/dist/router.d.ts +33 -0
  40. package/dist/router.js +247 -0
  41. package/dist/routing-types.d.ts +39 -0
  42. package/dist/routing-types.js +14 -0
  43. package/dist/stores/redis.d.ts +30 -0
  44. package/dist/stores/redis.js +42 -0
  45. package/dist/strategies.d.ts +18 -0
  46. package/dist/strategies.js +44 -0
  47. package/dist/types.d.ts +4 -2
  48. package/package.json +7 -4
package/README.md CHANGED
@@ -5,6 +5,7 @@
5
5
  [![npm version](https://img.shields.io/npm/v/paybridge.svg)](https://www.npmjs.com/package/paybridge)
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
7
7
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue)](https://www.typescriptlang.org/)
8
+ [![Discord](https://img.shields.io/badge/Discord-Join%20Chat-5865F2?logo=discord&logoColor=white)](https://discord.gg/Y2jCXNGgE)
8
9
 
9
10
  Unified payment SDK for Node.js that works with multiple payment providers through a single, consistent API. Focus on South African providers first, with support for international gateways.
10
11
 
@@ -178,17 +179,32 @@ app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
178
179
 
179
180
  ## Supported Providers
180
181
 
182
+ ### Fiat providers
183
+
181
184
  | Provider | One-time | Subscriptions | Refunds | Webhooks | Status |
182
185
  |----------|----------|---------------|---------|----------|--------|
183
186
  | **SoftyComp** | ✅ | ✅ | ✅ | ✅ | **Production** |
184
- | **Yoco** | 🚧 | 🚧 | 🚧 | 🚧 | Coming soon |
185
- | **Ozow** | 🚧 | 🚧 | 🚧 | 🚧 | Coming soon |
186
- | **PayFast** | 📋 | 📋 | 📋 | 📋 | Planned |
187
- | **PayStack** | 📋 | 📋 | 📋 | 📋 | Planned |
188
- | **Stripe** | 📋 | 📋 | 📋 | 📋 | Planned |
189
- | **Peach Payments** | 📋 | 📋 | 📋 | 📋 | Planned |
187
+ | **Yoco** | | | | | **Production** |
188
+ | **Ozow** | | | | | **Production** |
189
+ | **PayFast** | | | | | **Production** |
190
+ | **PayStack** | | | | | **Production** |
191
+ | **Stripe** | | | | | **Production** |
192
+ | **Peach Payments** | | | | | **Production** |
193
+ | **Flutterwave** | ✅ | ✅ | ✅ | ✅ | **Production** |
194
+
195
+ ### Crypto on/off-ramp providers
196
+
197
+ | Provider | On-ramp | Off-ramp | Quote | Webhooks | Status |
198
+ |----------|---------|----------|-------|----------|--------|
199
+ | **MoonPay** | ✅ | ✅ | ✅ | ✅ | **Production** |
200
+ | **Yellow Card** | ⚠️ | ⚠️ | ⚠️ | ⚠️ | **Experimental** |
190
201
 
191
- **Legend:** ✅ Production ready | 🚧 In development | 📋 Planned
202
+ **Legend:** ✅ Supported | Not supported by upstream API | ⚠️ Experimental (spec unverified)
203
+
204
+ **Notes:**
205
+ - `⛔` marks features the underlying provider's API doesn't support — those methods throw a clear error explaining the limitation. Use a different provider for that capability or use `PayBridgeRouter` to route accordingly.
206
+ - **Yellow Card** is gated behind `@experimental` until partner API documentation is verified — it logs a warning on instantiation. Do not use in production without partner-confirmed spec.
207
+ - **Sandbox testing.** PayFast / PayStack / Stripe / Peach / Flutterwave are wired and unit-tested, but have not yet been validated against live sandbox credentials. Run a sandbox transaction before going live.
192
208
 
193
209
  ## Provider Configuration
194
210
 
@@ -326,6 +342,64 @@ new PayBridge(config: PayBridgeConfig)
326
342
 
327
343
  See [src/types.ts](src/types.ts) for full type definitions.
328
344
 
345
+ ## Multi-Provider Routing
346
+
347
+ PayBridge supports multi-provider routing with automatic failover and circuit breakers. Use `PayBridgeRouter` to route requests across multiple providers based on cost, priority, or round-robin.
348
+
349
+ ```typescript
350
+ import { PayBridge, PayBridgeRouter } from 'paybridge';
351
+
352
+ const softycomp = new PayBridge({ provider: 'softycomp', credentials: {...}, sandbox: true });
353
+ const yoco = new PayBridge({ provider: 'yoco', credentials: {...}, sandbox: true });
354
+
355
+ const router = new PayBridgeRouter({
356
+ providers: [
357
+ { provider: softycomp, weight: 1 },
358
+ { provider: yoco, weight: 2 }
359
+ ],
360
+ strategy: 'cheapest',
361
+ fallback: {
362
+ enabled: true,
363
+ maxAttempts: 3,
364
+ retryDelayMs: 250
365
+ }
366
+ });
367
+
368
+ const payment = await router.createPayment({
369
+ amount: 299.00,
370
+ currency: 'ZAR',
371
+ reference: 'INV-001',
372
+ customer: { name: 'John Doe', email: 'john@example.com' },
373
+ urls: {
374
+ success: 'https://myapp.com/success',
375
+ cancel: 'https://myapp.com/cancel',
376
+ webhook: 'https://myapp.com/webhook'
377
+ }
378
+ });
379
+
380
+ console.log(payment.routingMeta.chosenProvider);
381
+ console.log(payment.routingMeta.attempts);
382
+ ```
383
+
384
+ ### Multi-instance deployments (Redis circuit-breaker)
385
+
386
+ By default, each Node process has its own in-memory circuit breaker. To share circuit breaker state across multiple instances (e.g., behind a load balancer), use a Redis-backed store:
387
+
388
+ ```typescript
389
+ import Redis from 'ioredis';
390
+ import { PayBridgeRouter, createRedisCircuitBreakerStore } from 'paybridge';
391
+
392
+ const redis = new Redis(process.env.REDIS_URL!);
393
+ const store = createRedisCircuitBreakerStore(redis, { prefix: 'app:cb:' });
394
+
395
+ const router = new PayBridgeRouter({
396
+ providers: [...],
397
+ circuitBreakerStore: store,
398
+ });
399
+ ```
400
+
401
+ The Redis adapter works with both `ioredis` and `redis` (node-redis v4+) clients. State is eventually consistent across instances — race conditions during state transitions may cause a few extra failures, but correctness is preserved.
402
+
329
403
  ## Currency Handling
330
404
 
331
405
  PayBridge **always uses major currency units** (rands, dollars) in the API:
@@ -394,6 +468,12 @@ We welcome contributions! To add a new payment provider:
394
468
 
395
469
  See [src/providers/softycomp.ts](src/providers/softycomp.ts) for reference implementation.
396
470
 
471
+ ## Community
472
+
473
+ Join our Discord for support, feature discussions, and updates:
474
+
475
+ - **Discord:** [https://discord.gg/Y2jCXNGgE](https://discord.gg/Y2jCXNGgE)
476
+
397
477
  ## License
398
478
 
399
479
  MIT © [Kobie Wentzel](https://github.com/kobie3717)
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Circuit breaker storage abstraction
3
+ */
4
+ export interface CircuitBreakerSnapshot {
5
+ state: 'CLOSED' | 'OPEN' | 'HALF_OPEN';
6
+ failureCount: number;
7
+ nextAttemptTime: number;
8
+ }
9
+ /**
10
+ * Storage interface for circuit breaker state.
11
+ * TTL is advisory — in-memory stores may ignore it, Redis-backed stores use it for expiry.
12
+ */
13
+ export interface CircuitBreakerStore {
14
+ get(key: string): Promise<CircuitBreakerSnapshot | null>;
15
+ set(key: string, snapshot: CircuitBreakerSnapshot, ttlMs?: number): Promise<void>;
16
+ delete(key: string): Promise<void>;
17
+ }
18
+ /**
19
+ * In-memory circuit breaker store.
20
+ * Each process instance has its own isolated state.
21
+ */
22
+ export declare class MemoryStore implements CircuitBreakerStore {
23
+ private map;
24
+ get(key: string): Promise<CircuitBreakerSnapshot | null>;
25
+ set(key: string, snapshot: CircuitBreakerSnapshot): Promise<void>;
26
+ delete(key: string): Promise<void>;
27
+ }
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ /**
3
+ * Circuit breaker storage abstraction
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.MemoryStore = void 0;
7
+ /**
8
+ * In-memory circuit breaker store.
9
+ * Each process instance has its own isolated state.
10
+ */
11
+ class MemoryStore {
12
+ constructor() {
13
+ this.map = new Map();
14
+ }
15
+ async get(key) {
16
+ return this.map.get(key) ?? null;
17
+ }
18
+ async set(key, snapshot) {
19
+ this.map.set(key, snapshot);
20
+ }
21
+ async delete(key) {
22
+ this.map.delete(key);
23
+ }
24
+ }
25
+ exports.MemoryStore = MemoryStore;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Circuit breaker for provider failure management.
3
+ * Supports pluggable storage for multi-instance deployments.
4
+ * Not atomic across processes — eventual consistency accepted.
5
+ */
6
+ import { CircuitBreakerStore } from './circuit-breaker-store';
7
+ export declare enum CircuitState {
8
+ CLOSED = "CLOSED",
9
+ OPEN = "OPEN",
10
+ HALF_OPEN = "HALF_OPEN"
11
+ }
12
+ export interface CircuitBreakerConfig {
13
+ failureThreshold?: number;
14
+ resetTimeoutMs?: number;
15
+ store?: CircuitBreakerStore;
16
+ }
17
+ export declare class CircuitBreaker {
18
+ private readonly key;
19
+ private readonly failureThreshold;
20
+ private readonly resetTimeoutMs;
21
+ private readonly store;
22
+ constructor(key?: string, config?: CircuitBreakerConfig);
23
+ isOpen(): Promise<boolean>;
24
+ recordSuccess(): Promise<void>;
25
+ recordFailure(): Promise<void>;
26
+ getState(): Promise<CircuitState>;
27
+ reset(): Promise<void>;
28
+ private getSnapshot;
29
+ private saveSnapshot;
30
+ }
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ /**
3
+ * Circuit breaker for provider failure management.
4
+ * Supports pluggable storage for multi-instance deployments.
5
+ * Not atomic across processes — eventual consistency accepted.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.CircuitBreaker = exports.CircuitState = void 0;
9
+ const circuit_breaker_store_1 = require("./circuit-breaker-store");
10
+ var CircuitState;
11
+ (function (CircuitState) {
12
+ CircuitState["CLOSED"] = "CLOSED";
13
+ CircuitState["OPEN"] = "OPEN";
14
+ CircuitState["HALF_OPEN"] = "HALF_OPEN";
15
+ })(CircuitState || (exports.CircuitState = CircuitState = {}));
16
+ class CircuitBreaker {
17
+ constructor(key = 'default', config = {}) {
18
+ this.key = key;
19
+ this.failureThreshold = config.failureThreshold ?? 5;
20
+ this.resetTimeoutMs = config.resetTimeoutMs ?? 30000;
21
+ this.store = config.store ?? new circuit_breaker_store_1.MemoryStore();
22
+ }
23
+ async isOpen() {
24
+ const snapshot = await this.getSnapshot();
25
+ if (snapshot.state === CircuitState.OPEN) {
26
+ if (Date.now() >= snapshot.nextAttemptTime) {
27
+ snapshot.state = CircuitState.HALF_OPEN;
28
+ await this.saveSnapshot(snapshot);
29
+ return false;
30
+ }
31
+ return true;
32
+ }
33
+ return false;
34
+ }
35
+ async recordSuccess() {
36
+ const snapshot = {
37
+ state: CircuitState.CLOSED,
38
+ failureCount: 0,
39
+ nextAttemptTime: 0,
40
+ };
41
+ await this.saveSnapshot(snapshot);
42
+ }
43
+ async recordFailure() {
44
+ const snapshot = await this.getSnapshot();
45
+ snapshot.failureCount++;
46
+ if (snapshot.state === CircuitState.HALF_OPEN) {
47
+ snapshot.state = CircuitState.OPEN;
48
+ snapshot.nextAttemptTime = Date.now() + this.resetTimeoutMs;
49
+ await this.saveSnapshot(snapshot, this.resetTimeoutMs + 5000);
50
+ }
51
+ else if (snapshot.failureCount >= this.failureThreshold) {
52
+ snapshot.state = CircuitState.OPEN;
53
+ snapshot.nextAttemptTime = Date.now() + this.resetTimeoutMs;
54
+ await this.saveSnapshot(snapshot, this.resetTimeoutMs + 5000);
55
+ }
56
+ else {
57
+ await this.saveSnapshot(snapshot);
58
+ }
59
+ }
60
+ async getState() {
61
+ const snapshot = await this.getSnapshot();
62
+ return snapshot.state;
63
+ }
64
+ async reset() {
65
+ const snapshot = {
66
+ state: CircuitState.CLOSED,
67
+ failureCount: 0,
68
+ nextAttemptTime: 0,
69
+ };
70
+ await this.saveSnapshot(snapshot);
71
+ }
72
+ async getSnapshot() {
73
+ const snapshot = await this.store.get(this.key);
74
+ if (snapshot)
75
+ return snapshot;
76
+ return {
77
+ state: CircuitState.CLOSED,
78
+ failureCount: 0,
79
+ nextAttemptTime: 0,
80
+ };
81
+ }
82
+ async saveSnapshot(snapshot, ttlMs) {
83
+ await this.store.set(this.key, snapshot, ttlMs);
84
+ }
85
+ }
86
+ exports.CircuitBreaker = CircuitBreaker;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Base crypto ramp provider abstract class
3
+ */
4
+ import { OnRampParams, OffRampParams, RampQuote, RampResult, CryptoRampCapabilities, CryptoNetwork } from './types';
5
+ export declare function validateWalletAddress(address: string, network: CryptoNetwork): void;
6
+ export declare abstract class CryptoRampProvider {
7
+ abstract readonly name: string;
8
+ abstract getQuote(direction: 'on' | 'off', fiatAmount: number, fiatCurrency: string, cryptoAsset: string, network: string): Promise<RampQuote>;
9
+ abstract createOnRamp(params: OnRampParams): Promise<RampResult>;
10
+ abstract createOffRamp(params: OffRampParams): Promise<RampResult>;
11
+ abstract getRamp(id: string): Promise<RampResult>;
12
+ abstract parseWebhook(body: any, headers?: any): any;
13
+ abstract verifyWebhook(body: any, headers?: any): boolean;
14
+ abstract getCapabilities(): CryptoRampCapabilities;
15
+ }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ /**
3
+ * Base crypto ramp provider abstract class
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.CryptoRampProvider = void 0;
7
+ exports.validateWalletAddress = validateWalletAddress;
8
+ function validateWalletAddress(address, network) {
9
+ const patterns = {
10
+ BTC: /^([13][a-km-zA-HJ-NP-Z1-9]{25,34}|bc1[a-z0-9]{39,59})$/,
11
+ ETH: /^0x[a-fA-F0-9]{40}$/,
12
+ POLYGON: /^0x[a-fA-F0-9]{40}$/,
13
+ BSC: /^0x[a-fA-F0-9]{40}$/,
14
+ TRON: /^T[A-Za-z1-9]{33}$/,
15
+ };
16
+ const re = patterns[network];
17
+ if (!re)
18
+ throw new Error(`Unsupported network: ${network}`);
19
+ if (!re.test(address))
20
+ throw new Error(`Invalid ${network} wallet address`);
21
+ }
22
+ class CryptoRampProvider {
23
+ }
24
+ exports.CryptoRampProvider = CryptoRampProvider;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * CryptoRamp — Unified crypto on/off-ramp SDK
3
+ */
4
+ import { OnRampParams, OffRampParams, RampQuote, RampResult, CryptoRampCapabilities } from './types';
5
+ export * from './types';
6
+ export * from './base';
7
+ export * from './moonpay';
8
+ export * from './yellowcard';
9
+ export * from './mock';
10
+ export * from './router';
11
+ export type CryptoProvider = 'moonpay' | 'yellowcard' | 'mock';
12
+ export interface CryptoRampConfig {
13
+ provider: CryptoProvider;
14
+ credentials: {
15
+ apiKey?: string;
16
+ secretKey?: string;
17
+ [key: string]: any;
18
+ };
19
+ sandbox?: boolean;
20
+ webhookSecret?: string;
21
+ }
22
+ export declare class CryptoRamp {
23
+ private provider;
24
+ constructor(config: CryptoRampConfig);
25
+ private createProvider;
26
+ getQuote(direction: 'on' | 'off', fiatAmount: number, fiatCurrency: string, cryptoAsset: string, network: string): Promise<RampQuote>;
27
+ createOnRamp(params: OnRampParams): Promise<RampResult>;
28
+ createOffRamp(params: OffRampParams): Promise<RampResult>;
29
+ getRamp(id: string): Promise<RampResult>;
30
+ parseWebhook(body: any, headers?: any): any;
31
+ verifyWebhook(body: any, headers?: any): boolean;
32
+ getCapabilities(): CryptoRampCapabilities;
33
+ getProviderName(): string;
34
+ }
35
+ export default CryptoRamp;
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ /**
3
+ * CryptoRamp — Unified crypto on/off-ramp SDK
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
17
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.CryptoRamp = void 0;
21
+ const moonpay_1 = require("./moonpay");
22
+ const yellowcard_1 = require("./yellowcard");
23
+ const mock_1 = require("./mock");
24
+ __exportStar(require("./types"), exports);
25
+ __exportStar(require("./base"), exports);
26
+ __exportStar(require("./moonpay"), exports);
27
+ __exportStar(require("./yellowcard"), exports);
28
+ __exportStar(require("./mock"), exports);
29
+ __exportStar(require("./router"), exports);
30
+ class CryptoRamp {
31
+ constructor(config) {
32
+ this.provider = this.createProvider(config);
33
+ }
34
+ createProvider(config) {
35
+ const { provider, credentials, sandbox = true, webhookSecret } = config;
36
+ switch (provider) {
37
+ case 'moonpay':
38
+ if (!credentials.apiKey || !credentials.secretKey) {
39
+ throw new Error('MoonPay requires apiKey and secretKey');
40
+ }
41
+ return new moonpay_1.MoonPayProvider({
42
+ apiKey: credentials.apiKey,
43
+ secretKey: credentials.secretKey,
44
+ sandbox,
45
+ webhookSecret,
46
+ });
47
+ case 'yellowcard':
48
+ if (!credentials.apiKey || !credentials.secretKey) {
49
+ throw new Error('Yellow Card requires apiKey and secretKey');
50
+ }
51
+ return new yellowcard_1.YellowCardProvider({
52
+ apiKey: credentials.apiKey,
53
+ secretKey: credentials.secretKey,
54
+ sandbox,
55
+ webhookSecret,
56
+ });
57
+ case 'mock':
58
+ return new mock_1.MockCryptoRampProvider();
59
+ default:
60
+ throw new Error(`Unknown crypto provider: ${provider}`);
61
+ }
62
+ }
63
+ async getQuote(direction, fiatAmount, fiatCurrency, cryptoAsset, network) {
64
+ return this.provider.getQuote(direction, fiatAmount, fiatCurrency, cryptoAsset, network);
65
+ }
66
+ async createOnRamp(params) {
67
+ if (!Number.isFinite(params.fiatAmount) || params.fiatAmount <= 0) {
68
+ throw new Error('Invalid amount: must be a positive finite number');
69
+ }
70
+ return this.provider.createOnRamp(params);
71
+ }
72
+ async createOffRamp(params) {
73
+ if (!Number.isFinite(params.cryptoAmount) || params.cryptoAmount <= 0) {
74
+ throw new Error('Invalid amount: must be a positive finite number');
75
+ }
76
+ return this.provider.createOffRamp(params);
77
+ }
78
+ async getRamp(id) {
79
+ return this.provider.getRamp(id);
80
+ }
81
+ parseWebhook(body, headers) {
82
+ return this.provider.parseWebhook(body, headers);
83
+ }
84
+ verifyWebhook(body, headers) {
85
+ return this.provider.verifyWebhook(body, headers);
86
+ }
87
+ getCapabilities() {
88
+ return this.provider.getCapabilities();
89
+ }
90
+ getProviderName() {
91
+ return this.provider.name;
92
+ }
93
+ }
94
+ exports.CryptoRamp = CryptoRamp;
95
+ exports.default = CryptoRamp;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Mock crypto ramp provider for testing
3
+ */
4
+ import { CryptoRampProvider } from './base';
5
+ import { OnRampParams, OffRampParams, RampQuote, RampResult, CryptoRampCapabilities } from './types';
6
+ export declare class MockCryptoRampProvider extends CryptoRampProvider {
7
+ readonly name = "mock";
8
+ getQuote(direction: 'on' | 'off', fiatAmount: number, fiatCurrency: string, cryptoAsset: string, _network: string): Promise<RampQuote>;
9
+ createOnRamp(params: OnRampParams): Promise<RampResult>;
10
+ createOffRamp(params: OffRampParams): Promise<RampResult>;
11
+ getRamp(id: string): Promise<RampResult>;
12
+ parseWebhook(body: any, _headers?: any): any;
13
+ verifyWebhook(_body: any, _headers?: any): boolean;
14
+ getCapabilities(): CryptoRampCapabilities;
15
+ }
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ /**
3
+ * Mock crypto ramp provider for testing
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.MockCryptoRampProvider = void 0;
7
+ const base_1 = require("./base");
8
+ class MockCryptoRampProvider extends base_1.CryptoRampProvider {
9
+ constructor() {
10
+ super(...arguments);
11
+ this.name = 'mock';
12
+ }
13
+ async getQuote(direction, fiatAmount, fiatCurrency, cryptoAsset, _network) {
14
+ const mockRate = cryptoAsset === 'BTC' ? 50000 : cryptoAsset === 'ETH' ? 3000 : 1;
15
+ const cryptoAmount = fiatAmount / mockRate;
16
+ const feePercent = direction === 'on' ? 3.5 : 2.0;
17
+ const feeTotal = fiatAmount * (feePercent / 100);
18
+ return {
19
+ fiatAmount,
20
+ cryptoAmount,
21
+ rate: mockRate,
22
+ feeFixed: 0,
23
+ feePercent,
24
+ feeTotal,
25
+ expiresAt: new Date(Date.now() + 5 * 60 * 1000).toISOString(),
26
+ };
27
+ }
28
+ async createOnRamp(params) {
29
+ (0, base_1.validateWalletAddress)(params.destinationWallet, params.network);
30
+ const quote = await this.getQuote('on', params.fiatAmount, params.fiatCurrency, params.asset, params.network);
31
+ return {
32
+ id: `mock_on_${Date.now()}`,
33
+ direction: 'on',
34
+ status: 'pending',
35
+ quote,
36
+ checkoutUrl: `https://mock-ramp.example.com/checkout/${params.reference}`,
37
+ createdAt: new Date().toISOString(),
38
+ expiresAt: quote.expiresAt,
39
+ };
40
+ }
41
+ async createOffRamp(params) {
42
+ if (params.sourceWallet) {
43
+ (0, base_1.validateWalletAddress)(params.sourceWallet, params.network);
44
+ }
45
+ const mockRate = params.asset === 'BTC' ? 50000 : params.asset === 'ETH' ? 3000 : 1;
46
+ const fiatAmount = params.cryptoAmount * mockRate;
47
+ const quote = await this.getQuote('off', fiatAmount, params.fiatCurrency, params.asset, params.network);
48
+ return {
49
+ id: `mock_off_${Date.now()}`,
50
+ direction: 'off',
51
+ status: 'pending',
52
+ quote,
53
+ depositAddress: '0xMOCK1234567890ABCDEF',
54
+ depositTag: 'MOCK123',
55
+ createdAt: new Date().toISOString(),
56
+ expiresAt: quote.expiresAt,
57
+ };
58
+ }
59
+ async getRamp(id) {
60
+ const direction = id.includes('_on_') ? 'on' : 'off';
61
+ const quote = {
62
+ fiatAmount: 1000,
63
+ cryptoAmount: 0.02,
64
+ rate: 50000,
65
+ feeFixed: 0,
66
+ feePercent: 3.5,
67
+ feeTotal: 35,
68
+ expiresAt: new Date(Date.now() + 5 * 60 * 1000).toISOString(),
69
+ };
70
+ return {
71
+ id,
72
+ direction,
73
+ status: 'completed',
74
+ quote,
75
+ txHash: '0xMOCKTXHASH123456',
76
+ createdAt: new Date(Date.now() - 10 * 60 * 1000).toISOString(),
77
+ };
78
+ }
79
+ parseWebhook(body, _headers) {
80
+ const event = typeof body === 'string' ? JSON.parse(body) : body;
81
+ return {
82
+ type: 'transaction.completed',
83
+ data: event,
84
+ raw: event,
85
+ };
86
+ }
87
+ verifyWebhook(_body, _headers) {
88
+ return true;
89
+ }
90
+ getCapabilities() {
91
+ return {
92
+ supportedAssets: ['BTC', 'ETH', 'USDT', 'USDC'],
93
+ supportedNetworks: ['BTC', 'ETH', 'TRON', 'POLYGON', 'BSC'],
94
+ supportedFiat: ['ZAR', 'USD', 'EUR', 'GBP'],
95
+ country: 'GLOBAL',
96
+ kycRequired: false,
97
+ onRampLimits: {
98
+ min: 10,
99
+ max: 100000,
100
+ },
101
+ offRampLimits: {
102
+ min: 10,
103
+ max: 100000,
104
+ },
105
+ fees: {
106
+ onRampPercent: 3.5,
107
+ offRampPercent: 2.0,
108
+ },
109
+ };
110
+ }
111
+ }
112
+ exports.MockCryptoRampProvider = MockCryptoRampProvider;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * MoonPay crypto on/off-ramp provider
3
+ * @see https://dev.moonpay.com
4
+ */
5
+ import { CryptoRampProvider } from './base';
6
+ import { OnRampParams, OffRampParams, RampQuote, RampResult, CryptoRampCapabilities } from './types';
7
+ interface MoonPayConfig {
8
+ apiKey: string;
9
+ secretKey: string;
10
+ sandbox: boolean;
11
+ webhookSecret?: string;
12
+ }
13
+ export declare class MoonPayProvider extends CryptoRampProvider {
14
+ readonly name = "moonpay";
15
+ private apiKey;
16
+ private secretKey;
17
+ private sandbox;
18
+ private baseUrl;
19
+ private widgetUrl;
20
+ private webhookSecret?;
21
+ constructor(config: MoonPayConfig);
22
+ getQuote(direction: 'on' | 'off', fiatAmount: number, fiatCurrency: string, cryptoAsset: string, _network: string): Promise<RampQuote>;
23
+ createOnRamp(params: OnRampParams): Promise<RampResult>;
24
+ createOffRamp(params: OffRampParams): Promise<RampResult>;
25
+ getRamp(id: string): Promise<RampResult>;
26
+ parseWebhook(body: any, _headers?: any): any;
27
+ verifyWebhook(body: string | Buffer, headers?: any): boolean;
28
+ private verifyWebhookV2;
29
+ getCapabilities(): CryptoRampCapabilities;
30
+ private signWidgetUrl;
31
+ private mapMoonPayStatus;
32
+ }
33
+ export {};