paybridge 0.5.0 → 0.6.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 +61 -0
- package/dist/crypto/index.d.ts +3 -1
- package/dist/crypto/index.js +23 -0
- package/dist/crypto/ramp.d.ts +36 -0
- package/dist/crypto/ramp.js +179 -0
- package/dist/crypto/transak.d.ts +32 -0
- package/dist/crypto/transak.js +212 -0
- package/dist/index.js +35 -0
- package/dist/providers/mollie.d.ts +39 -0
- package/dist/providers/mollie.js +178 -0
- package/dist/providers/pesapal.d.ts +47 -0
- package/dist/providers/pesapal.js +236 -0
- package/dist/providers/square.d.ts +41 -0
- package/dist/providers/square.js +278 -0
- package/dist/types.d.ts +1 -1
- package/package.json +8 -2
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Square payment provider
|
|
4
|
+
* Payment Links API supporting USD, CAD, GBP, AUD, EUR, JPY
|
|
5
|
+
* @see https://developer.squareup.com/reference/square
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.SquareProvider = void 0;
|
|
42
|
+
const crypto = __importStar(require("crypto"));
|
|
43
|
+
const base_1 = require("./base");
|
|
44
|
+
const currency_1 = require("../utils/currency");
|
|
45
|
+
const fetch_1 = require("../utils/fetch");
|
|
46
|
+
class SquareProvider extends base_1.PaymentProvider {
|
|
47
|
+
constructor(config) {
|
|
48
|
+
super();
|
|
49
|
+
this.name = 'square';
|
|
50
|
+
this.supportedCurrencies = ['USD', 'CAD', 'GBP', 'AUD', 'EUR', 'JPY'];
|
|
51
|
+
this.accessToken = config.accessToken;
|
|
52
|
+
this.locationId = config.locationId;
|
|
53
|
+
this.notificationUrl = config.notificationUrl;
|
|
54
|
+
this.webhookSecret = config.webhookSecret;
|
|
55
|
+
this.sandbox = config.sandbox ?? false;
|
|
56
|
+
this.baseUrl = this.sandbox
|
|
57
|
+
? 'https://connect.squareupsandbox.com/v2'
|
|
58
|
+
: 'https://connect.squareup.com/v2';
|
|
59
|
+
}
|
|
60
|
+
async apiRequest(method, path, data) {
|
|
61
|
+
const url = `${this.baseUrl}${path}`;
|
|
62
|
+
const response = await (0, fetch_1.timedFetchOrThrow)(url, {
|
|
63
|
+
method,
|
|
64
|
+
headers: {
|
|
65
|
+
Authorization: `Bearer ${this.accessToken}`,
|
|
66
|
+
'Content-Type': 'application/json',
|
|
67
|
+
'Square-Version': '2024-09-19',
|
|
68
|
+
},
|
|
69
|
+
body: data ? JSON.stringify(data) : undefined,
|
|
70
|
+
});
|
|
71
|
+
return (await response.json());
|
|
72
|
+
}
|
|
73
|
+
async createPayment(params) {
|
|
74
|
+
this.validateCurrency(params.currency);
|
|
75
|
+
const amountInMinorUnits = (0, currency_1.toMinorUnit)(params.amount, params.currency);
|
|
76
|
+
const requestBody = {
|
|
77
|
+
idempotency_key: crypto.randomUUID(),
|
|
78
|
+
quick_pay: {
|
|
79
|
+
name: params.description || params.reference,
|
|
80
|
+
price_money: {
|
|
81
|
+
amount: amountInMinorUnits,
|
|
82
|
+
currency: params.currency,
|
|
83
|
+
},
|
|
84
|
+
location_id: this.locationId,
|
|
85
|
+
},
|
|
86
|
+
checkout_options: {
|
|
87
|
+
redirect_url: params.urls.success,
|
|
88
|
+
ask_for_shipping_address: false,
|
|
89
|
+
},
|
|
90
|
+
pre_populated_data: {
|
|
91
|
+
buyer_email: params.customer.email,
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
const response = await this.apiRequest('POST', '/checkout/payment-links', requestBody);
|
|
95
|
+
const link = response.payment_link;
|
|
96
|
+
return {
|
|
97
|
+
id: link.id,
|
|
98
|
+
checkoutUrl: link.url,
|
|
99
|
+
status: 'pending',
|
|
100
|
+
amount: params.amount,
|
|
101
|
+
currency: params.currency.toUpperCase(),
|
|
102
|
+
reference: params.reference,
|
|
103
|
+
provider: 'square',
|
|
104
|
+
createdAt: link.created_at || new Date().toISOString(),
|
|
105
|
+
raw: response,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
async createSubscription(_params) {
|
|
109
|
+
throw new Error('Square subscriptions require multi-step Catalog + Customer + Plan setup; not yet supported by paybridge. Use the Square Subscriptions API directly or choose another provider.');
|
|
110
|
+
}
|
|
111
|
+
async getPayment(id) {
|
|
112
|
+
const linkResponse = await this.apiRequest('GET', `/online-checkout/payment-links/${id}`);
|
|
113
|
+
const link = linkResponse.payment_link;
|
|
114
|
+
const orderId = link.order_id;
|
|
115
|
+
const orderResponse = await this.apiRequest('GET', `/orders/${orderId}`);
|
|
116
|
+
const order = orderResponse.order;
|
|
117
|
+
let status = 'pending';
|
|
118
|
+
if (order.state === 'COMPLETED') {
|
|
119
|
+
status = 'completed';
|
|
120
|
+
}
|
|
121
|
+
else if (order.state === 'CANCELED') {
|
|
122
|
+
status = 'cancelled';
|
|
123
|
+
}
|
|
124
|
+
else if (order.state === 'OPEN') {
|
|
125
|
+
status = 'pending';
|
|
126
|
+
}
|
|
127
|
+
const currency = order.total_money?.currency || 'USD';
|
|
128
|
+
const amount = order.total_money?.amount ? (0, currency_1.toMajorUnit)(order.total_money.amount, currency) : 0;
|
|
129
|
+
return {
|
|
130
|
+
id: link.id,
|
|
131
|
+
checkoutUrl: link.url || '',
|
|
132
|
+
status,
|
|
133
|
+
amount,
|
|
134
|
+
currency: currency.toUpperCase(),
|
|
135
|
+
reference: link.id,
|
|
136
|
+
provider: 'square',
|
|
137
|
+
createdAt: link.created_at || new Date().toISOString(),
|
|
138
|
+
raw: { link, order },
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
async refund(params) {
|
|
142
|
+
const currency = 'USD';
|
|
143
|
+
const amountInMinorUnits = params.amount ? (0, currency_1.toMinorUnit)(params.amount, currency) : undefined;
|
|
144
|
+
const refundData = {
|
|
145
|
+
idempotency_key: crypto.randomUUID(),
|
|
146
|
+
payment_id: params.paymentId,
|
|
147
|
+
reason: params.reason || 'Refund',
|
|
148
|
+
};
|
|
149
|
+
if (amountInMinorUnits !== undefined) {
|
|
150
|
+
refundData.amount_money = {
|
|
151
|
+
amount: amountInMinorUnits,
|
|
152
|
+
currency,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
const response = await this.apiRequest('POST', '/refunds', refundData);
|
|
156
|
+
const refund = response.refund;
|
|
157
|
+
const refundCurrency = refund.amount_money?.currency || currency;
|
|
158
|
+
const refundAmount = refund.amount_money?.amount
|
|
159
|
+
? (0, currency_1.toMajorUnit)(refund.amount_money.amount, refundCurrency)
|
|
160
|
+
: 0;
|
|
161
|
+
return {
|
|
162
|
+
id: refund.id,
|
|
163
|
+
status: refund.status === 'COMPLETED' ? 'completed' : 'pending',
|
|
164
|
+
amount: refundAmount,
|
|
165
|
+
currency: refundCurrency.toUpperCase(),
|
|
166
|
+
paymentId: params.paymentId,
|
|
167
|
+
createdAt: refund.created_at || new Date().toISOString(),
|
|
168
|
+
raw: response,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
parseWebhook(body, _headers) {
|
|
172
|
+
const event = typeof body === 'string' ? JSON.parse(body) : body;
|
|
173
|
+
const typeMap = {
|
|
174
|
+
'payment.created': 'payment.completed',
|
|
175
|
+
'payment.updated': 'payment.pending',
|
|
176
|
+
'refund.created': 'refund.completed',
|
|
177
|
+
'refund.updated': 'refund.completed',
|
|
178
|
+
};
|
|
179
|
+
let eventType = typeMap[event.type] || 'payment.pending';
|
|
180
|
+
const data = event.data?.object?.payment || event.data?.object?.refund || {};
|
|
181
|
+
if (event.type === 'payment.updated' && data.status === 'COMPLETED') {
|
|
182
|
+
eventType = 'payment.completed';
|
|
183
|
+
}
|
|
184
|
+
else if (event.type === 'payment.updated' && data.status === 'FAILED') {
|
|
185
|
+
eventType = 'payment.failed';
|
|
186
|
+
}
|
|
187
|
+
else if (event.type === 'payment.updated' && data.status === 'CANCELED') {
|
|
188
|
+
eventType = 'payment.cancelled';
|
|
189
|
+
}
|
|
190
|
+
let payment;
|
|
191
|
+
let refund;
|
|
192
|
+
if (event.type.startsWith('payment.')) {
|
|
193
|
+
const currency = data.amount_money?.currency || 'USD';
|
|
194
|
+
let status = 'pending';
|
|
195
|
+
if (data.status === 'COMPLETED') {
|
|
196
|
+
status = 'completed';
|
|
197
|
+
}
|
|
198
|
+
else if (data.status === 'FAILED') {
|
|
199
|
+
status = 'failed';
|
|
200
|
+
}
|
|
201
|
+
else if (data.status === 'CANCELED') {
|
|
202
|
+
status = 'cancelled';
|
|
203
|
+
}
|
|
204
|
+
payment = {
|
|
205
|
+
id: data.id,
|
|
206
|
+
checkoutUrl: '',
|
|
207
|
+
status,
|
|
208
|
+
amount: data.amount_money?.amount ? (0, currency_1.toMajorUnit)(data.amount_money.amount, currency) : 0,
|
|
209
|
+
currency: currency.toUpperCase(),
|
|
210
|
+
reference: data.id,
|
|
211
|
+
provider: 'square',
|
|
212
|
+
createdAt: data.created_at || new Date().toISOString(),
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
else if (event.type.startsWith('refund.')) {
|
|
216
|
+
const currency = data.amount_money?.currency || 'USD';
|
|
217
|
+
refund = {
|
|
218
|
+
id: data.id,
|
|
219
|
+
status: data.status === 'COMPLETED' ? 'completed' : 'pending',
|
|
220
|
+
amount: data.amount_money?.amount ? (0, currency_1.toMajorUnit)(data.amount_money.amount, currency) : 0,
|
|
221
|
+
currency: currency.toUpperCase(),
|
|
222
|
+
paymentId: data.payment_id || '',
|
|
223
|
+
createdAt: data.created_at || new Date().toISOString(),
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
return {
|
|
227
|
+
type: eventType,
|
|
228
|
+
payment,
|
|
229
|
+
refund,
|
|
230
|
+
raw: event,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Verify webhook signature using Square's HMAC-SHA256 scheme.
|
|
235
|
+
*
|
|
236
|
+
* Square signs the concatenation of: notificationUrl + rawBody
|
|
237
|
+
* TODO(verify): Confirm Square's current signing scheme matches this implementation.
|
|
238
|
+
*/
|
|
239
|
+
verifyWebhook(body, headers) {
|
|
240
|
+
if (!this.webhookSecret || !this.notificationUrl) {
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
const signature = headers?.['x-square-hmacsha256-signature'];
|
|
244
|
+
if (!signature) {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
const rawBody = typeof body === 'string' ? body : body.toString('utf8');
|
|
248
|
+
const signedString = `${this.notificationUrl}${rawBody}`;
|
|
249
|
+
const computedSig = crypto
|
|
250
|
+
.createHmac('sha256', this.webhookSecret)
|
|
251
|
+
.update(signedString)
|
|
252
|
+
.digest('base64');
|
|
253
|
+
try {
|
|
254
|
+
const computedBuffer = Buffer.from(computedSig, 'base64');
|
|
255
|
+
const expectedBuffer = Buffer.from(signature, 'base64');
|
|
256
|
+
if (computedBuffer.length !== expectedBuffer.length) {
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
return crypto.timingSafeEqual(computedBuffer, expectedBuffer);
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
getCapabilities() {
|
|
266
|
+
return {
|
|
267
|
+
fees: {
|
|
268
|
+
fixed: 0.10,
|
|
269
|
+
percent: 2.6,
|
|
270
|
+
currency: 'USD',
|
|
271
|
+
},
|
|
272
|
+
currencies: this.supportedCurrencies,
|
|
273
|
+
country: 'US',
|
|
274
|
+
avgLatencyMs: 400,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
exports.SquareProvider = SquareProvider;
|
package/dist/types.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* PayBridge — Unified payment SDK types
|
|
3
3
|
*/
|
|
4
|
-
export type Provider = 'softycomp' | 'yoco' | 'ozow' | 'payfast' | 'paystack' | 'stripe' | 'peach' | 'flutterwave' | 'adyen' | 'mercadopago' | 'razorpay';
|
|
4
|
+
export type Provider = 'softycomp' | 'yoco' | 'ozow' | 'payfast' | 'paystack' | 'stripe' | 'peach' | 'flutterwave' | 'adyen' | 'mercadopago' | 'razorpay' | 'mollie' | 'square' | 'pesapal';
|
|
5
5
|
export type PaymentStatus = 'pending' | 'completed' | 'failed' | 'cancelled' | 'refunded';
|
|
6
6
|
export type SubscriptionInterval = 'weekly' | 'monthly' | 'yearly';
|
|
7
7
|
export type Currency = 'ZAR' | 'USD' | 'EUR' | 'GBP' | 'NGN' | 'KES' | 'UGX' | 'GHS' | string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "paybridge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.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",
|
|
@@ -33,7 +33,13 @@
|
|
|
33
33
|
"mercadopago",
|
|
34
34
|
"razorpay",
|
|
35
35
|
"india",
|
|
36
|
-
"latam"
|
|
36
|
+
"latam",
|
|
37
|
+
"mollie",
|
|
38
|
+
"square",
|
|
39
|
+
"pesapal",
|
|
40
|
+
"transak",
|
|
41
|
+
"ramp",
|
|
42
|
+
"east-africa"
|
|
37
43
|
],
|
|
38
44
|
"author": "Kobie Wentzel",
|
|
39
45
|
"license": "MIT",
|