paybridge 0.10.0 → 0.11.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 CHANGED
@@ -101,6 +101,46 @@ Exit code 1 if drift detected, 0 if clean. Perfect for CI/CD pipelines or cron j
101
101
 
102
102
  The Square `/checkout/payment-links → /online-checkout/payment-links` endpoint change would have shipped silently to production. With `drift-check` running daily, you get a Slack alert the moment it happens.
103
103
 
104
+ ## Reconciliation
105
+
106
+ Webhooks can fail. Networks blip. Your server hiccups. Provider retries don't reach you. Without reconciliation, you discover missed webhooks when a customer complains their account wasn't credited.
107
+
108
+ PayBridge's **reconcile** command diffs your database against each provider's current state, catching payments where your local status doesn't match reality.
109
+
110
+ ### Quick Start
111
+
112
+ ```bash
113
+ # From JSONL file
114
+ echo '{"provider":"stripe","reference":"pay_001","expectedStatus":"pending"}' > expected.jsonl
115
+ npx paybridge reconcile --input expected.jsonl
116
+
117
+ # From SQL query (Postgres example)
118
+ psql -t -c "SELECT provider, reference, status AS \"expectedStatus\" FROM payments WHERE status='pending' AND created_at > now() - interval '24 hours'" \
119
+ | npx paybridge reconcile
120
+
121
+ # CSV format
122
+ cat payments.csv | npx paybridge reconcile
123
+ ```
124
+
125
+ ### Example Output
126
+
127
+ ```
128
+ [✓] stripe:pay_001 — completed (match)
129
+ [!] stripe:pay_002 — expected pending, actual completed (MISSED WEBHOOK)
130
+ [?] paystack:pay_003 — not-found (no provider record)
131
+ [✗] stripe:pay_004 — error (HTTP 503)
132
+ [ ] adyen:pay_005 — skipped (missing ADYEN_API_KEY)
133
+
134
+ Reconciled: 5
135
+ Match: 1
136
+ Mismatch (missed webhook): 1
137
+ Not found: 1
138
+ Error: 1
139
+ Skipped: 1
140
+ ```
141
+
142
+ Exit code 1 if any mismatch, 0 if clean. Add `--webhook-url` to POST mismatch reports to Slack/Discord/your ops channel. Use `--json` for pipeline integration.
143
+
104
144
  ## Quick Start
105
145
 
106
146
  > **Upgrading from 0.1 or 0.2?** See [docs/migration.md](docs/migration.md).
@@ -0,0 +1 @@
1
+ export declare function runReconcileCommand(args: string[]): Promise<void>;
@@ -0,0 +1,341 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.runReconcileCommand = runReconcileCommand;
37
+ const fs = __importStar(require("node:fs"));
38
+ const readline = __importStar(require("node:readline"));
39
+ const index_1 = require("../../index");
40
+ const runners_1 = require("../runners");
41
+ const reconcile_1 = require("../reconcile");
42
+ const utils_1 = require("../utils");
43
+ function parseOptions(args) {
44
+ const opts = {};
45
+ for (let i = 0; i < args.length; i++) {
46
+ if (args[i] === '--input' && args[i + 1]) {
47
+ opts.input = args[i + 1];
48
+ i++;
49
+ }
50
+ else if (args[i] === '--json') {
51
+ opts.json = true;
52
+ }
53
+ else if (args[i] === '--webhook-url' && args[i + 1]) {
54
+ opts.webhookUrl = args[i + 1];
55
+ i++;
56
+ }
57
+ }
58
+ return opts;
59
+ }
60
+ async function parseInput(input) {
61
+ const lines = [];
62
+ if (input) {
63
+ const content = fs.readFileSync(input, 'utf8');
64
+ lines.push(...content.split('\n').filter((l) => l.trim()));
65
+ }
66
+ else {
67
+ const rl = readline.createInterface({
68
+ input: process.stdin,
69
+ output: process.stdout,
70
+ terminal: false,
71
+ });
72
+ for await (const line of rl) {
73
+ if (line.trim()) {
74
+ lines.push(line.trim());
75
+ }
76
+ }
77
+ }
78
+ if (lines.length === 0) {
79
+ return [];
80
+ }
81
+ const firstLine = lines[0];
82
+ const isCsv = /^provider\s*,\s*reference\s*,\s*expectedStatus/i.test(firstLine);
83
+ const records = [];
84
+ if (isCsv) {
85
+ for (let i = 1; i < lines.length; i++) {
86
+ const parts = lines[i].split(',').map((s) => s.trim());
87
+ if (parts.length >= 3) {
88
+ records.push({
89
+ provider: parts[0],
90
+ reference: parts[1],
91
+ expectedStatus: parts[2],
92
+ });
93
+ }
94
+ }
95
+ }
96
+ else {
97
+ for (const line of lines) {
98
+ try {
99
+ const obj = JSON.parse(line);
100
+ if (obj.provider && obj.reference && obj.expectedStatus) {
101
+ records.push({
102
+ provider: obj.provider,
103
+ reference: obj.reference,
104
+ expectedStatus: obj.expectedStatus,
105
+ });
106
+ }
107
+ }
108
+ catch (e) {
109
+ console.error(`${(0, utils_1.colorize)('[!]', 'yellow')} Skipping invalid JSON line: ${line}`);
110
+ }
111
+ }
112
+ }
113
+ return records;
114
+ }
115
+ function buildProvider(providerName) {
116
+ const runner = runners_1.runners.find((r) => r.name === providerName);
117
+ if (!runner) {
118
+ throw new Error(`Unknown provider: ${providerName}`);
119
+ }
120
+ const missing = runner.envRequired.filter((key) => !process.env[key]);
121
+ if (missing.length > 0) {
122
+ throw new Error(`Missing: ${missing.join(', ')}`);
123
+ }
124
+ switch (providerName) {
125
+ case 'stripe':
126
+ return new index_1.PayBridge({
127
+ provider: 'stripe',
128
+ credentials: { apiKey: process.env.STRIPE_API_KEY },
129
+ sandbox: true,
130
+ });
131
+ case 'paystack':
132
+ return new index_1.PayBridge({
133
+ provider: 'paystack',
134
+ credentials: { apiKey: process.env.PAYSTACK_API_KEY },
135
+ sandbox: true,
136
+ });
137
+ case 'flutterwave':
138
+ return new index_1.PayBridge({
139
+ provider: 'flutterwave',
140
+ credentials: { apiKey: process.env.FLUTTERWAVE_API_KEY },
141
+ sandbox: true,
142
+ });
143
+ case 'adyen':
144
+ return new index_1.PayBridge({
145
+ provider: 'adyen',
146
+ credentials: {
147
+ apiKey: process.env.ADYEN_API_KEY,
148
+ merchantAccount: process.env.ADYEN_MERCHANT_ACCOUNT,
149
+ },
150
+ sandbox: true,
151
+ });
152
+ case 'softycomp':
153
+ return new index_1.PayBridge({
154
+ provider: 'softycomp',
155
+ credentials: {
156
+ apiKey: process.env.SOFTYCOMP_API_KEY,
157
+ secretKey: process.env.SOFTYCOMP_SECRET_KEY,
158
+ },
159
+ sandbox: true,
160
+ });
161
+ case 'yoco':
162
+ return new index_1.PayBridge({
163
+ provider: 'yoco',
164
+ credentials: { apiKey: process.env.YOCO_API_KEY },
165
+ sandbox: true,
166
+ });
167
+ case 'ozow':
168
+ return new index_1.PayBridge({
169
+ provider: 'ozow',
170
+ credentials: {
171
+ apiKey: process.env.OZOW_API_KEY,
172
+ siteCode: process.env.OZOW_SITE_CODE,
173
+ privateKey: process.env.OZOW_PRIVATE_KEY,
174
+ },
175
+ sandbox: true,
176
+ });
177
+ case 'payfast':
178
+ return new index_1.PayBridge({
179
+ provider: 'payfast',
180
+ credentials: {
181
+ merchantId: process.env.PAYFAST_MERCHANT_ID,
182
+ merchantKey: process.env.PAYFAST_MERCHANT_KEY,
183
+ passphrase: process.env.PAYFAST_PASSPHRASE,
184
+ },
185
+ sandbox: true,
186
+ });
187
+ case 'peach':
188
+ return new index_1.PayBridge({
189
+ provider: 'peach',
190
+ credentials: {
191
+ apiKey: process.env.PEACH_ACCESS_TOKEN,
192
+ secretKey: process.env.PEACH_ENTITY_ID,
193
+ },
194
+ sandbox: true,
195
+ });
196
+ case 'mercadopago':
197
+ return new index_1.PayBridge({
198
+ provider: 'mercadopago',
199
+ credentials: { apiKey: process.env.MERCADOPAGO_ACCESS_TOKEN },
200
+ sandbox: true,
201
+ });
202
+ case 'razorpay':
203
+ return new index_1.PayBridge({
204
+ provider: 'razorpay',
205
+ credentials: {
206
+ apiKey: process.env.RAZORPAY_KEY_ID,
207
+ secretKey: process.env.RAZORPAY_KEY_SECRET,
208
+ },
209
+ sandbox: true,
210
+ });
211
+ case 'mollie':
212
+ return new index_1.PayBridge({
213
+ provider: 'mollie',
214
+ credentials: { apiKey: process.env.MOLLIE_API_KEY },
215
+ sandbox: true,
216
+ });
217
+ case 'square':
218
+ return new index_1.PayBridge({
219
+ provider: 'square',
220
+ credentials: {
221
+ apiKey: process.env.SQUARE_ACCESS_TOKEN,
222
+ locationId: process.env.SQUARE_LOCATION_ID,
223
+ },
224
+ sandbox: true,
225
+ });
226
+ case 'pesapal':
227
+ return new index_1.PayBridge({
228
+ provider: 'pesapal',
229
+ credentials: {
230
+ apiKey: process.env.PESAPAL_CONSUMER_KEY,
231
+ secretKey: process.env.PESAPAL_CONSUMER_SECRET,
232
+ notificationId: process.env.PESAPAL_NOTIFICATION_ID,
233
+ },
234
+ sandbox: true,
235
+ });
236
+ default:
237
+ throw new Error(`Provider ${providerName} not implemented in reconcile`);
238
+ }
239
+ }
240
+ function hasCredsFor(providerName) {
241
+ const runner = runners_1.runners.find((r) => r.name === providerName);
242
+ if (!runner) {
243
+ return false;
244
+ }
245
+ return runner.envRequired.every((key) => !!process.env[key]);
246
+ }
247
+ function printResult(result) {
248
+ const { provider, reference, classification, expectedStatus, actualStatus, errorMessage } = result;
249
+ let icon;
250
+ let message;
251
+ switch (classification) {
252
+ case 'match':
253
+ icon = (0, utils_1.colorize)('[✓]', 'green');
254
+ message = `${provider}:${reference} — ${actualStatus} (match)`;
255
+ break;
256
+ case 'mismatch':
257
+ icon = (0, utils_1.colorize)('[!]', 'yellow');
258
+ message = `${provider}:${reference} — expected ${expectedStatus}, actual ${actualStatus} (MISSED WEBHOOK)`;
259
+ break;
260
+ case 'not-found':
261
+ icon = (0, utils_1.colorize)('[?]', 'yellow');
262
+ message = `${provider}:${reference} — not-found (no provider record)`;
263
+ break;
264
+ case 'error':
265
+ icon = (0, utils_1.colorize)('[✗]', 'red');
266
+ message = `${provider}:${reference} — error (${errorMessage})`;
267
+ break;
268
+ case 'skipped':
269
+ icon = (0, utils_1.colorize)('[ ]', 'dim');
270
+ message = `${provider}:${reference} — skipped (${errorMessage})`;
271
+ break;
272
+ }
273
+ console.log(`${icon} ${message}`);
274
+ }
275
+ async function postWebhook(url, payload) {
276
+ const res = await fetch(url, {
277
+ method: 'POST',
278
+ headers: { 'Content-Type': 'application/json' },
279
+ body: JSON.stringify(payload),
280
+ });
281
+ if (!res.ok) {
282
+ throw new Error(`Webhook POST failed: ${res.status} ${res.statusText}`);
283
+ }
284
+ }
285
+ async function runReconcileCommand(args) {
286
+ const opts = parseOptions(args);
287
+ const records = await parseInput(opts.input);
288
+ if (records.length === 0) {
289
+ console.error('No records to reconcile. Provide input via stdin or --input <file>.');
290
+ process.exit(1);
291
+ }
292
+ const { results, summary } = await (0, reconcile_1.runReconcile)(records, { buildProvider, hasCredsFor }, {
293
+ onResult: opts.json ? undefined : printResult,
294
+ });
295
+ if (opts.json) {
296
+ for (const result of results) {
297
+ console.log(JSON.stringify(result));
298
+ }
299
+ console.log(JSON.stringify({ summary }));
300
+ }
301
+ else {
302
+ console.log(`\nReconciled: ${summary.total}`);
303
+ console.log(` Match: ${summary.match}`);
304
+ console.log(` Mismatch (missed webhook): ${summary.mismatch}`);
305
+ console.log(` Not found: ${summary.notFound}`);
306
+ console.log(` Error: ${summary.error}`);
307
+ console.log(` Skipped: ${summary.skipped}`);
308
+ }
309
+ if (opts.webhookUrl && summary.mismatch > 0) {
310
+ const mismatches = results.filter((r) => r.classification === 'mismatch');
311
+ const payload = {
312
+ totalReconciled: summary.total,
313
+ missed: summary.mismatch,
314
+ mismatches: mismatches.map((r) => ({
315
+ provider: r.provider,
316
+ reference: r.reference,
317
+ expected: r.expectedStatus,
318
+ actual: r.actualStatus,
319
+ })),
320
+ libVersion: '0.11.0',
321
+ };
322
+ try {
323
+ await postWebhook(opts.webhookUrl, payload);
324
+ if (!opts.json) {
325
+ console.log(`\n${(0, utils_1.colorize)('[webhook]', 'cyan')} Posted mismatch report to ${opts.webhookUrl}`);
326
+ }
327
+ }
328
+ catch (err) {
329
+ console.error(`${(0, utils_1.colorize)('[!]', 'yellow')} Webhook POST failed: ${err.message}`);
330
+ }
331
+ }
332
+ if (summary.mismatch > 0) {
333
+ process.exit(1);
334
+ }
335
+ else if (summary.error > 0 && summary.match === 0) {
336
+ process.exit(2);
337
+ }
338
+ else {
339
+ process.exit(0);
340
+ }
341
+ }
package/dist/cli/index.js CHANGED
@@ -7,6 +7,7 @@ const webhook_1 = require("./commands/webhook");
7
7
  const quote_1 = require("./commands/quote");
8
8
  const drift_1 = require("./commands/drift");
9
9
  const drift_watch_1 = require("./commands/drift-watch");
10
+ const reconcile_1 = require("./commands/reconcile");
10
11
  const utils_1 = require("./utils");
11
12
  async function main() {
12
13
  const [, , command, ...args] = process.argv;
@@ -29,6 +30,9 @@ async function main() {
29
30
  case 'drift-watch':
30
31
  await (0, drift_watch_1.runDriftWatch)(args);
31
32
  break;
33
+ case 'reconcile':
34
+ await (0, reconcile_1.runReconcileCommand)(args);
35
+ break;
32
36
  case '-h':
33
37
  case '--help':
34
38
  case 'help':
@@ -0,0 +1,22 @@
1
+ export type CanonicalStatus = 'completed' | 'pending' | 'failed' | 'cancelled' | 'refunded' | 'unknown';
2
+ export interface ReconcileRecord {
3
+ provider: string;
4
+ reference: string;
5
+ expectedStatus: CanonicalStatus | string;
6
+ }
7
+ export interface ReconcileResult {
8
+ provider: string;
9
+ reference: string;
10
+ expectedStatus: string;
11
+ actualStatus?: string;
12
+ classification: 'match' | 'mismatch' | 'not-found' | 'error' | 'skipped';
13
+ errorMessage?: string;
14
+ }
15
+ export interface ReconcileSummary {
16
+ total: number;
17
+ match: number;
18
+ mismatch: number;
19
+ notFound: number;
20
+ error: number;
21
+ skipped: number;
22
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,12 @@
1
+ import { PayBridge } from '../index';
2
+ import { ReconcileRecord, ReconcileResult, ReconcileSummary } from './reconcile-types';
3
+ export interface ReconcileDeps {
4
+ buildProvider: (providerName: string) => PayBridge;
5
+ hasCredsFor: (providerName: string) => boolean;
6
+ }
7
+ export declare function runReconcile(records: ReconcileRecord[], deps: ReconcileDeps, opts?: {
8
+ onResult?: (r: ReconcileResult) => void;
9
+ }): Promise<{
10
+ results: ReconcileResult[];
11
+ summary: ReconcileSummary;
12
+ }>;
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runReconcile = runReconcile;
4
+ async function runReconcile(records, deps, opts = {}) {
5
+ const providerCache = new Map();
6
+ const results = [];
7
+ const summary = {
8
+ total: records.length,
9
+ match: 0,
10
+ mismatch: 0,
11
+ notFound: 0,
12
+ error: 0,
13
+ skipped: 0,
14
+ };
15
+ for (const record of records) {
16
+ if (!deps.hasCredsFor(record.provider)) {
17
+ const result = {
18
+ provider: record.provider,
19
+ reference: record.reference,
20
+ expectedStatus: record.expectedStatus,
21
+ classification: 'skipped',
22
+ errorMessage: 'missing credentials',
23
+ };
24
+ results.push(result);
25
+ summary.skipped++;
26
+ opts.onResult?.(result);
27
+ continue;
28
+ }
29
+ let pay;
30
+ if (providerCache.has(record.provider)) {
31
+ pay = providerCache.get(record.provider);
32
+ }
33
+ else {
34
+ try {
35
+ pay = deps.buildProvider(record.provider);
36
+ providerCache.set(record.provider, pay);
37
+ }
38
+ catch (err) {
39
+ const result = {
40
+ provider: record.provider,
41
+ reference: record.reference,
42
+ expectedStatus: record.expectedStatus,
43
+ classification: 'error',
44
+ errorMessage: err.message || String(err),
45
+ };
46
+ results.push(result);
47
+ summary.error++;
48
+ opts.onResult?.(result);
49
+ continue;
50
+ }
51
+ }
52
+ try {
53
+ const payment = await pay.getPayment(record.reference);
54
+ const actualStatus = payment.status;
55
+ const normalized = normalizeStatus(record.expectedStatus);
56
+ const match = normalized === actualStatus;
57
+ const result = {
58
+ provider: record.provider,
59
+ reference: record.reference,
60
+ expectedStatus: record.expectedStatus,
61
+ actualStatus,
62
+ classification: match ? 'match' : 'mismatch',
63
+ };
64
+ results.push(result);
65
+ if (match) {
66
+ summary.match++;
67
+ }
68
+ else {
69
+ summary.mismatch++;
70
+ }
71
+ opts.onResult?.(result);
72
+ }
73
+ catch (err) {
74
+ const isNotFound = err.message?.includes('not found') ||
75
+ err.message?.includes('404') ||
76
+ err.message?.includes('No payment found');
77
+ const result = {
78
+ provider: record.provider,
79
+ reference: record.reference,
80
+ expectedStatus: record.expectedStatus,
81
+ classification: isNotFound ? 'not-found' : 'error',
82
+ errorMessage: err.message || String(err),
83
+ };
84
+ results.push(result);
85
+ if (isNotFound) {
86
+ summary.notFound++;
87
+ }
88
+ else {
89
+ summary.error++;
90
+ }
91
+ opts.onResult?.(result);
92
+ }
93
+ }
94
+ return { results, summary };
95
+ }
96
+ function normalizeStatus(status) {
97
+ const lower = status.toLowerCase();
98
+ if (['completed', 'pending', 'failed', 'cancelled', 'refunded'].includes(lower)) {
99
+ return lower;
100
+ }
101
+ return 'unknown';
102
+ }
package/dist/cli/utils.js CHANGED
@@ -72,6 +72,7 @@ COMMANDS
72
72
  quote <p> [opts] Get a crypto on/off-ramp quote
73
73
  drift-check [opts] Capture/compare provider response shapes (drift detection)
74
74
  drift-watch [opts] Run drift-check on a loop (long-running monitor)
75
+ reconcile [opts] Reconcile your DB against provider state (detects missed webhooks)
75
76
  help, -h, --help Print this help
76
77
  version, -v Print version
77
78
 
@@ -96,6 +97,8 @@ EXAMPLES
96
97
  paybridge drift-check --capture
97
98
  paybridge drift-check stripe
98
99
  paybridge drift-watch --interval 1h --webhook-url https://hooks.slack.com/...
100
+ paybridge reconcile --input expected.jsonl
101
+ psql -t -c "SELECT provider, reference, status FROM payments" | paybridge reconcile
99
102
 
100
103
  Docs: https://github.com/kobie3717/paybridge
101
104
  `.trim();
package/dist/index.d.ts CHANGED
@@ -22,6 +22,8 @@ export * from './tracer';
22
22
  export { createRedisCircuitBreakerStore, type RedisLike, type RedisStoreOptions } from './stores/redis';
23
23
  export { createRedisIdempotencyStore, type RedisIdempotencyStoreOptions } from './stores/redis-idempotency';
24
24
  export { createRedisLedgerStore, type RedisLedgerStoreOptions } from './stores/redis-ledger';
25
+ export { runReconcile, type ReconcileDeps } from './cli/reconcile';
26
+ export * from './cli/reconcile-types';
25
27
  export declare class PayBridge {
26
28
  readonly provider: PaymentProvider;
27
29
  constructor(config: PayBridgeConfig);
package/dist/index.js CHANGED
@@ -20,7 +20,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
20
20
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
21
21
  };
22
22
  Object.defineProperty(exports, "__esModule", { value: true });
23
- exports.PayBridge = exports.createRedisLedgerStore = exports.createRedisIdempotencyStore = exports.createRedisCircuitBreakerStore = void 0;
23
+ exports.PayBridge = exports.runReconcile = exports.createRedisLedgerStore = exports.createRedisIdempotencyStore = exports.createRedisCircuitBreakerStore = void 0;
24
24
  const softycomp_1 = require("./providers/softycomp");
25
25
  const yoco_1 = require("./providers/yoco");
26
26
  const ozow_1 = require("./providers/ozow");
@@ -54,6 +54,9 @@ var redis_idempotency_1 = require("./stores/redis-idempotency");
54
54
  Object.defineProperty(exports, "createRedisIdempotencyStore", { enumerable: true, get: function () { return redis_idempotency_1.createRedisIdempotencyStore; } });
55
55
  var redis_ledger_1 = require("./stores/redis-ledger");
56
56
  Object.defineProperty(exports, "createRedisLedgerStore", { enumerable: true, get: function () { return redis_ledger_1.createRedisLedgerStore; } });
57
+ var reconcile_1 = require("./cli/reconcile");
58
+ Object.defineProperty(exports, "runReconcile", { enumerable: true, get: function () { return reconcile_1.runReconcile; } });
59
+ __exportStar(require("./cli/reconcile-types"), exports);
57
60
  class PayBridge {
58
61
  constructor(config) {
59
62
  this.provider = this.createProvider(config);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "paybridge",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "One API for fiat + crypto payments. Multi-provider routing, automatic failover, MoonPay on/off-ramp. SA-first, global-ready.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",