mirror of
https://github.com/Such-Software/wownerogue.git
synced 2026-10-18 22:58:32 +02:00
feat(payments): provider-registry bootstrap from env (single wiring seam)
buildProviderRegistry({env, walletService}) assembles the registry:
- native Monero/Wownero provider registered whenever a walletService exists;
- BTCPay auto-registers when BTCPAY_URL/STORE_ID/API_KEY are set;
- default routing sends BTC/LTC/GRIN to BTCPay and keeps XMR/WOW on native;
- PAYMENT_ROUTING (JSON or CHAIN:provider,... ) overrides any mapping.
Behavior-preserving: with no BTCPAY_* env (prod today) only the native
provider registers and all chains route to it — identical to the current
flow. Inert until index.js calls it; this just makes P3 instantiable behind
one factory. parseRouting + bootstrap covered by 5 tests.
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
const { PaymentProvider, PaymentProviderRegistry } = require('./paymentProvider');
|
||||
const BTCPayProvider = require('./btcpayProvider');
|
||||
const NativeMoneroProvider = require('./nativeMoneroProvider');
|
||||
|
||||
/**
|
||||
* Parse an operator routing override. Accepts JSON ({"BTC":"btcpay","XMR":"native-monero"})
|
||||
* or a compact "CHAIN:provider,CHAIN:provider" string. Returns {} on empty/garbage.
|
||||
*/
|
||||
function parseRouting(raw) {
|
||||
if (!raw) return {};
|
||||
const s = String(raw).trim();
|
||||
if (!s) return {};
|
||||
if (s[0] === '{') {
|
||||
try {
|
||||
const obj = JSON.parse(s);
|
||||
const out = {};
|
||||
for (const k of Object.keys(obj)) out[String(k).toUpperCase()] = String(obj[k]);
|
||||
return out;
|
||||
} catch (_) { return {}; }
|
||||
}
|
||||
const out = {};
|
||||
for (const pair of s.split(',')) {
|
||||
const [chain, prov] = pair.split(':').map(x => (x || '').trim());
|
||||
if (chain && prov) out[chain.toUpperCase()] = prov;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assemble the payment-provider registry from environment/config. Single wiring seam for Pillar 3.
|
||||
*
|
||||
* Behavior-preserving: with no BTCPAY_* env set (prod today), only the native Monero/Wownero
|
||||
* provider is registered and every chain routes to it — identical to the current flow. Set
|
||||
* BTCPAY_URL/BTCPAY_STORE_ID/BTCPAY_API_KEY and BTC/LTC/GRIN route to BTCPay automatically, while
|
||||
* XMR/WOW stay on the native wallet-RPC. PAYMENT_ROUTING overrides any chain->provider mapping.
|
||||
*/
|
||||
function buildProviderRegistry({ env = process.env, walletService = null } = {}) {
|
||||
const registry = new PaymentProviderRegistry();
|
||||
let hasNative = false, hasBtcpay = false;
|
||||
|
||||
if (walletService) {
|
||||
registry.register(new NativeMoneroProvider({ walletService }));
|
||||
hasNative = true;
|
||||
}
|
||||
|
||||
const baseUrl = env.BTCPAY_URL, storeId = env.BTCPAY_STORE_ID, apiKey = env.BTCPAY_API_KEY;
|
||||
if (baseUrl && storeId && apiKey) {
|
||||
registry.register(new BTCPayProvider({ baseUrl, storeId, apiKey }));
|
||||
hasBtcpay = true;
|
||||
}
|
||||
|
||||
// Sensible defaults, only for providers that are actually present.
|
||||
const routing = {};
|
||||
if (hasBtcpay) { routing.BTC = 'btcpay'; routing.LTC = 'btcpay'; routing.GRIN = 'btcpay'; }
|
||||
if (hasNative) { routing.XMR = 'native-monero'; routing.WOW = 'native-monero'; }
|
||||
else if (hasBtcpay) { routing.XMR = 'btcpay'; routing.WOW = 'btcpay'; }
|
||||
|
||||
Object.assign(routing, parseRouting(env.PAYMENT_ROUTING)); // operator override wins
|
||||
registry.setRouting(routing);
|
||||
registry.setDefault(hasNative ? 'native-monero' : (hasBtcpay ? 'btcpay' : null));
|
||||
|
||||
return registry;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
PaymentProvider,
|
||||
PaymentProviderRegistry,
|
||||
BTCPayProvider,
|
||||
NativeMoneroProvider,
|
||||
buildProviderRegistry,
|
||||
parseRouting
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
const { buildProviderRegistry, parseRouting } = require('../src/payments/providers');
|
||||
|
||||
const fakeWallet = { createPaymentRequest: async () => ({}), checkPaymentStatus: async () => ({}), processBatchPayout: async () => ({}) };
|
||||
|
||||
describe('parseRouting', () => {
|
||||
test('parses JSON and compact forms, ignores garbage', () => {
|
||||
expect(parseRouting('{"btc":"btcpay","xmr":"native-monero"}')).toEqual({ BTC: 'btcpay', XMR: 'native-monero' });
|
||||
expect(parseRouting('BTC:btcpay, XMR:native-monero')).toEqual({ BTC: 'btcpay', XMR: 'native-monero' });
|
||||
expect(parseRouting('')).toEqual({});
|
||||
expect(parseRouting('{not json')).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('buildProviderRegistry', () => {
|
||||
test('native-only (no BTCPay env): every chain routes to native — behavior-preserving', () => {
|
||||
const reg = buildProviderRegistry({ env: {}, walletService: fakeWallet });
|
||||
expect(reg.getProvider('WOW').id).toBe('native-monero');
|
||||
expect(reg.getProvider('XMR').id).toBe('native-monero');
|
||||
expect(reg.getProvider('BTC').id).toBe('native-monero'); // default provider, no routing entry
|
||||
});
|
||||
|
||||
test('with BTCPay env: BTC/LTC/GRIN -> btcpay, XMR/WOW stay native', () => {
|
||||
const reg = buildProviderRegistry({
|
||||
env: { BTCPAY_URL: 'https://btcpay.lan', BTCPAY_STORE_ID: 's', BTCPAY_API_KEY: 'k' },
|
||||
walletService: fakeWallet
|
||||
});
|
||||
expect(reg.getProvider('BTC').id).toBe('btcpay');
|
||||
expect(reg.getProvider('LTC').id).toBe('btcpay');
|
||||
expect(reg.getProvider('GRIN').id).toBe('btcpay');
|
||||
expect(reg.getProvider('XMR').id).toBe('native-monero');
|
||||
expect(reg.getProvider('WOW').id).toBe('native-monero');
|
||||
});
|
||||
|
||||
test('BTCPay-only (no wallet): all five chains route to btcpay', () => {
|
||||
const reg = buildProviderRegistry({
|
||||
env: { BTCPAY_URL: 'https://btcpay.lan', BTCPAY_STORE_ID: 's', BTCPAY_API_KEY: 'k' },
|
||||
walletService: null
|
||||
});
|
||||
expect(reg.getProvider('XMR').id).toBe('btcpay');
|
||||
expect(reg.getProvider('WOW').id).toBe('btcpay');
|
||||
expect(reg.getProvider('BTC').id).toBe('btcpay');
|
||||
});
|
||||
|
||||
test('PAYMENT_ROUTING override wins', () => {
|
||||
const reg = buildProviderRegistry({
|
||||
env: { BTCPAY_URL: 'u', BTCPAY_STORE_ID: 's', BTCPAY_API_KEY: 'k', PAYMENT_ROUTING: 'WOW:btcpay' },
|
||||
walletService: fakeWallet
|
||||
});
|
||||
expect(reg.getProvider('WOW').id).toBe('btcpay'); // overrode the native default
|
||||
expect(reg.getProvider('XMR').id).toBe('native-monero'); // untouched
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user