@everestan/protocolbanks-sdk 0.0.0-stage → 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.
- package/README.md +45 -2
- package/dist/index.d.mts +555 -0
- package/dist/index.d.ts +555 -0
- package/dist/index.js +708 -0
- package/dist/index.mjs +683 -0
- package/package.json +43 -4
package/dist/index.js
ADDED
|
@@ -0,0 +1,708 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
Agent: () => Agent,
|
|
24
|
+
Checkout: () => Checkout,
|
|
25
|
+
Invoice: () => Invoice,
|
|
26
|
+
PaymentLink: () => PaymentLink,
|
|
27
|
+
ProtocolBanks: () => ProtocolBanks,
|
|
28
|
+
Webhook: () => Webhook
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(index_exports);
|
|
31
|
+
|
|
32
|
+
// src/payment-link.ts
|
|
33
|
+
var PaymentLink = class {
|
|
34
|
+
constructor(config) {
|
|
35
|
+
this.config = config;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Create a new payment link
|
|
39
|
+
*/
|
|
40
|
+
async create(options) {
|
|
41
|
+
const baseUrl = this.config.baseUrl || "https://protocol-banks.vercel.app";
|
|
42
|
+
const response = await fetch(`${baseUrl}/api/acquiring/payment-links`, {
|
|
43
|
+
method: "POST",
|
|
44
|
+
headers: {
|
|
45
|
+
"Content-Type": "application/json",
|
|
46
|
+
"X-API-Key": this.config.apiKey
|
|
47
|
+
},
|
|
48
|
+
body: JSON.stringify({
|
|
49
|
+
title: options.title,
|
|
50
|
+
description: options.description,
|
|
51
|
+
amount: options.amount,
|
|
52
|
+
token: options.token || this.config.defaultToken || "USDC",
|
|
53
|
+
recipientAddress: options.recipientAddress,
|
|
54
|
+
amountType: options.amount ? "fixed" : "customer_input",
|
|
55
|
+
redirectUrl: options.redirectUrl,
|
|
56
|
+
expiresAt: options.expiresIn ? new Date(Date.now() + options.expiresIn * 1e3).toISOString() : void 0,
|
|
57
|
+
brandColor: options.branding?.color,
|
|
58
|
+
logoUrl: options.branding?.logoUrl,
|
|
59
|
+
distributeAsset: !!options.assetDistribution,
|
|
60
|
+
assetType: options.assetDistribution?.type,
|
|
61
|
+
assetContractAddress: options.assetDistribution?.contractAddress,
|
|
62
|
+
assetTokenId: options.assetDistribution?.tokenId,
|
|
63
|
+
assetAmount: options.assetDistribution?.amount,
|
|
64
|
+
metadata: options.metadata
|
|
65
|
+
})
|
|
66
|
+
});
|
|
67
|
+
const data = await response.json();
|
|
68
|
+
if (!response.ok || !data.success) {
|
|
69
|
+
return {
|
|
70
|
+
success: false,
|
|
71
|
+
id: "",
|
|
72
|
+
paymentUrl: "",
|
|
73
|
+
status: "failed",
|
|
74
|
+
error: data.error || "Failed to create payment link"
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
success: true,
|
|
79
|
+
id: data.link.link_id,
|
|
80
|
+
paymentUrl: data.paymentUrl,
|
|
81
|
+
shortUrl: data.shortUrl,
|
|
82
|
+
qrCodeData: data.paymentUrl,
|
|
83
|
+
status: "pending"
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Get payment link details
|
|
88
|
+
*/
|
|
89
|
+
async get(linkId) {
|
|
90
|
+
const baseUrl = this.config.baseUrl || "https://protocol-banks.vercel.app";
|
|
91
|
+
const response = await fetch(
|
|
92
|
+
`${baseUrl}/api/acquiring/payment-links?linkId=${linkId}`,
|
|
93
|
+
{
|
|
94
|
+
headers: {
|
|
95
|
+
"X-API-Key": this.config.apiKey
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
return response.json();
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* List all payment links
|
|
103
|
+
*/
|
|
104
|
+
async list(merchantId) {
|
|
105
|
+
const baseUrl = this.config.baseUrl || "https://protocol-banks.vercel.app";
|
|
106
|
+
const params = merchantId ? `?merchantId=${merchantId}` : "";
|
|
107
|
+
const response = await fetch(
|
|
108
|
+
`${baseUrl}/api/acquiring/payment-links${params}`,
|
|
109
|
+
{
|
|
110
|
+
headers: {
|
|
111
|
+
"X-API-Key": this.config.apiKey
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
return response.json();
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Update a payment link
|
|
119
|
+
*/
|
|
120
|
+
async update(linkId, updates) {
|
|
121
|
+
const baseUrl = this.config.baseUrl || "https://protocol-banks.vercel.app";
|
|
122
|
+
const response = await fetch(`${baseUrl}/api/acquiring/payment-links`, {
|
|
123
|
+
method: "PATCH",
|
|
124
|
+
headers: {
|
|
125
|
+
"Content-Type": "application/json",
|
|
126
|
+
"X-API-Key": this.config.apiKey
|
|
127
|
+
},
|
|
128
|
+
body: JSON.stringify({ linkId, ...updates })
|
|
129
|
+
});
|
|
130
|
+
return response.json();
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Delete a payment link
|
|
134
|
+
*/
|
|
135
|
+
async delete(linkId) {
|
|
136
|
+
const baseUrl = this.config.baseUrl || "https://protocol-banks.vercel.app";
|
|
137
|
+
const response = await fetch(
|
|
138
|
+
`${baseUrl}/api/acquiring/payment-links?linkId=${linkId}`,
|
|
139
|
+
{
|
|
140
|
+
method: "DELETE",
|
|
141
|
+
headers: {
|
|
142
|
+
"X-API-Key": this.config.apiKey
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
return response.json();
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
// src/invoice.ts
|
|
151
|
+
var Invoice = class {
|
|
152
|
+
constructor(config) {
|
|
153
|
+
this.config = config;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Create a new invoice
|
|
157
|
+
*/
|
|
158
|
+
async create(options) {
|
|
159
|
+
const baseUrl = this.config.baseUrl || "https://protocol-banks.vercel.app";
|
|
160
|
+
const response = await fetch(`${baseUrl}/api/invoice`, {
|
|
161
|
+
method: "POST",
|
|
162
|
+
headers: {
|
|
163
|
+
"Content-Type": "application/json",
|
|
164
|
+
"X-API-Key": this.config.apiKey
|
|
165
|
+
},
|
|
166
|
+
body: JSON.stringify({
|
|
167
|
+
recipientAddress: options.recipientAddress,
|
|
168
|
+
amount: options.amount,
|
|
169
|
+
token: options.token || this.config.defaultToken || "USDC",
|
|
170
|
+
description: options.description,
|
|
171
|
+
merchantName: options.merchantName,
|
|
172
|
+
amountFiat: options.amountFiat,
|
|
173
|
+
fiatCurrency: options.fiatCurrency,
|
|
174
|
+
expiresIn: (options.expiresInHours || 24) * 60 * 60 * 1e3,
|
|
175
|
+
metadata: {
|
|
176
|
+
...options.metadata,
|
|
177
|
+
customerName: options.customer?.name,
|
|
178
|
+
customerEmail: options.customer?.email
|
|
179
|
+
}
|
|
180
|
+
})
|
|
181
|
+
});
|
|
182
|
+
const data = await response.json();
|
|
183
|
+
if (!response.ok || !data.success && !data.invoice) {
|
|
184
|
+
return {
|
|
185
|
+
success: false,
|
|
186
|
+
id: "",
|
|
187
|
+
paymentUrl: "",
|
|
188
|
+
status: "failed",
|
|
189
|
+
error: data.error || "Failed to create invoice"
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
success: true,
|
|
194
|
+
id: data.invoice.invoice_id,
|
|
195
|
+
paymentUrl: data.paymentLink,
|
|
196
|
+
qrCodeData: data.qrCodeData,
|
|
197
|
+
status: "pending"
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Get invoice details
|
|
202
|
+
*/
|
|
203
|
+
async get(invoiceId, signature) {
|
|
204
|
+
const baseUrl = this.config.baseUrl || "https://protocol-banks.vercel.app";
|
|
205
|
+
const params = new URLSearchParams({ id: invoiceId });
|
|
206
|
+
if (signature) params.set("sig", signature);
|
|
207
|
+
const response = await fetch(`${baseUrl}/api/invoice?${params.toString()}`, {
|
|
208
|
+
headers: {
|
|
209
|
+
"X-API-Key": this.config.apiKey
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
return response.json();
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Update invoice status (e.g., after payment)
|
|
216
|
+
*/
|
|
217
|
+
async updateStatus(invoiceId, status, txHash, paidBy) {
|
|
218
|
+
const baseUrl = this.config.baseUrl || "https://protocol-banks.vercel.app";
|
|
219
|
+
const response = await fetch(`${baseUrl}/api/invoice`, {
|
|
220
|
+
method: "PATCH",
|
|
221
|
+
headers: {
|
|
222
|
+
"Content-Type": "application/json",
|
|
223
|
+
"X-API-Key": this.config.apiKey
|
|
224
|
+
},
|
|
225
|
+
body: JSON.stringify({ invoiceId, status, txHash, paidBy })
|
|
226
|
+
});
|
|
227
|
+
return response.json();
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Get printable invoice export URL
|
|
231
|
+
*/
|
|
232
|
+
getExportUrl(invoiceId, signature) {
|
|
233
|
+
const baseUrl = this.config.baseUrl || "https://protocol-banks.vercel.app";
|
|
234
|
+
const params = new URLSearchParams({ id: invoiceId });
|
|
235
|
+
if (signature) params.set("sig", signature);
|
|
236
|
+
return `${baseUrl}/api/invoice/export?${params.toString()}`;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* List invoices for a merchant
|
|
240
|
+
*/
|
|
241
|
+
async list(options) {
|
|
242
|
+
const baseUrl = this.config.baseUrl || "https://protocol-banks.vercel.app";
|
|
243
|
+
const params = new URLSearchParams();
|
|
244
|
+
if (options?.status) params.set("status", options.status);
|
|
245
|
+
if (options?.limit) params.set("limit", options.limit.toString());
|
|
246
|
+
if (options?.offset) params.set("offset", options.offset.toString());
|
|
247
|
+
const response = await fetch(`${baseUrl}/api/invoice/list?${params.toString()}`, {
|
|
248
|
+
headers: {
|
|
249
|
+
"X-API-Key": this.config.apiKey
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
return response.json();
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
// src/checkout.ts
|
|
257
|
+
var Checkout = class {
|
|
258
|
+
constructor(config) {
|
|
259
|
+
this.config = config;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Create a new checkout order
|
|
263
|
+
*/
|
|
264
|
+
async create(options) {
|
|
265
|
+
const baseUrl = this.config.baseUrl || "https://protocol-banks.vercel.app";
|
|
266
|
+
const response = await fetch(`${baseUrl}/api/acquiring/orders`, {
|
|
267
|
+
method: "POST",
|
|
268
|
+
headers: {
|
|
269
|
+
"Content-Type": "application/json",
|
|
270
|
+
"X-API-Key": this.config.apiKey
|
|
271
|
+
},
|
|
272
|
+
body: JSON.stringify({
|
|
273
|
+
merchant_id: options.merchantId,
|
|
274
|
+
amount: parseFloat(options.amount),
|
|
275
|
+
currency: options.currency || "USD",
|
|
276
|
+
token: options.token || this.config.defaultToken || "USDC",
|
|
277
|
+
notify_url: options.notifyUrl,
|
|
278
|
+
return_url: options.returnUrl,
|
|
279
|
+
metadata: options.metadata
|
|
280
|
+
})
|
|
281
|
+
});
|
|
282
|
+
const data = await response.json();
|
|
283
|
+
if (!response.ok || !data.success) {
|
|
284
|
+
return {
|
|
285
|
+
success: false,
|
|
286
|
+
id: "",
|
|
287
|
+
paymentUrl: "",
|
|
288
|
+
status: "failed",
|
|
289
|
+
error: data.error || "Failed to create checkout"
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
const checkoutUrl = `${baseUrl}/checkout?order=${data.order.order_no}`;
|
|
293
|
+
return {
|
|
294
|
+
success: true,
|
|
295
|
+
id: data.order.order_no,
|
|
296
|
+
paymentUrl: checkoutUrl,
|
|
297
|
+
qrCodeData: checkoutUrl,
|
|
298
|
+
status: "pending"
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Get order status
|
|
303
|
+
*/
|
|
304
|
+
async getStatus(orderNo) {
|
|
305
|
+
const baseUrl = this.config.baseUrl || "https://protocol-banks.vercel.app";
|
|
306
|
+
const response = await fetch(`${baseUrl}/api/acquiring/orders/${orderNo}`, {
|
|
307
|
+
headers: {
|
|
308
|
+
"X-API-Key": this.config.apiKey
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
return response.json();
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* List orders for a merchant
|
|
315
|
+
*/
|
|
316
|
+
async listOrders(merchantId, options) {
|
|
317
|
+
const baseUrl = this.config.baseUrl || "https://protocol-banks.vercel.app";
|
|
318
|
+
const params = new URLSearchParams();
|
|
319
|
+
if (merchantId) params.set("merchantId", merchantId);
|
|
320
|
+
if (options?.limit) params.set("limit", options.limit.toString());
|
|
321
|
+
if (options?.offset) params.set("offset", options.offset.toString());
|
|
322
|
+
const response = await fetch(
|
|
323
|
+
`${baseUrl}/api/acquiring/orders?${params.toString()}`,
|
|
324
|
+
{
|
|
325
|
+
headers: {
|
|
326
|
+
"X-API-Key": this.config.apiKey
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
);
|
|
330
|
+
return response.json();
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Open checkout in a popup window
|
|
334
|
+
*/
|
|
335
|
+
openPopup(options) {
|
|
336
|
+
return new Promise(async (resolve, reject) => {
|
|
337
|
+
try {
|
|
338
|
+
const result = await this.create(options);
|
|
339
|
+
if (!result.success) {
|
|
340
|
+
reject(new Error(result.error || "Failed to create checkout"));
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
const width = 450;
|
|
344
|
+
const height = 700;
|
|
345
|
+
const left = window.screenX + (window.outerWidth - width) / 2;
|
|
346
|
+
const top = window.screenY + (window.outerHeight - height) / 2;
|
|
347
|
+
const popup = window.open(
|
|
348
|
+
result.paymentUrl,
|
|
349
|
+
"protocol-banks-checkout",
|
|
350
|
+
`width=${width},height=${height},left=${left},top=${top},resizable=yes,scrollbars=yes`
|
|
351
|
+
);
|
|
352
|
+
if (!popup) {
|
|
353
|
+
reject(new Error("Popup blocked. Please allow popups for this site."));
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
const interval = setInterval(() => {
|
|
357
|
+
if (popup.closed) {
|
|
358
|
+
clearInterval(interval);
|
|
359
|
+
this.getStatus(result.id).then((status) => {
|
|
360
|
+
if (status.order?.status === "paid") {
|
|
361
|
+
resolve({
|
|
362
|
+
...result,
|
|
363
|
+
status: "paid",
|
|
364
|
+
txHash: status.order.tx_hash
|
|
365
|
+
});
|
|
366
|
+
} else {
|
|
367
|
+
resolve({
|
|
368
|
+
...result,
|
|
369
|
+
status: "cancelled"
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
}).catch(() => {
|
|
373
|
+
resolve({ ...result, status: "cancelled" });
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
}, 500);
|
|
377
|
+
} catch (error) {
|
|
378
|
+
reject(error);
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
// src/webhook.ts
|
|
385
|
+
var Webhook = class {
|
|
386
|
+
constructor(config) {
|
|
387
|
+
this.config = config;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Verify an incoming webhook signature (server-side only).
|
|
391
|
+
*
|
|
392
|
+
* Use this in your webhook handler to validate that the request
|
|
393
|
+
* came from Protocol Banks.
|
|
394
|
+
*
|
|
395
|
+
* @example
|
|
396
|
+
* ```ts
|
|
397
|
+
* const pb = new ProtocolBanks({ apiKey: 'pk_...' });
|
|
398
|
+
*
|
|
399
|
+
* app.post('/webhook', (req, res) => {
|
|
400
|
+
* const signature = req.headers['x-webhook-signature'];
|
|
401
|
+
* const timestamp = req.headers['x-webhook-timestamp'];
|
|
402
|
+
* const body = JSON.stringify(req.body);
|
|
403
|
+
*
|
|
404
|
+
* if (!pb.webhooks.verify(body, signature, 'whsec_...')) {
|
|
405
|
+
* return res.status(401).send('Invalid signature');
|
|
406
|
+
* }
|
|
407
|
+
*
|
|
408
|
+
* // Process event
|
|
409
|
+
* const event = req.body;
|
|
410
|
+
* console.log('Received event:', event.event);
|
|
411
|
+
* res.status(200).send('OK');
|
|
412
|
+
* });
|
|
413
|
+
* ```
|
|
414
|
+
*/
|
|
415
|
+
verify(payload, signature, secret) {
|
|
416
|
+
try {
|
|
417
|
+
const crypto2 = require("crypto");
|
|
418
|
+
const expectedSignature = crypto2.createHmac("sha256", secret).update(payload).digest("hex");
|
|
419
|
+
if (signature.length !== expectedSignature.length) {
|
|
420
|
+
return false;
|
|
421
|
+
}
|
|
422
|
+
const sigBuffer = Buffer.from(signature, "hex");
|
|
423
|
+
const expectedBuffer = Buffer.from(expectedSignature, "hex");
|
|
424
|
+
if (sigBuffer.length !== expectedBuffer.length) {
|
|
425
|
+
return false;
|
|
426
|
+
}
|
|
427
|
+
return crypto2.timingSafeEqual(sigBuffer, expectedBuffer);
|
|
428
|
+
} catch {
|
|
429
|
+
return this.verifyBrowser(payload, signature, secret);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Browser-compatible signature verification using Web Crypto API
|
|
434
|
+
*/
|
|
435
|
+
verifyBrowser(payload, signature, secret) {
|
|
436
|
+
console.warn(
|
|
437
|
+
"Webhook verification in browser is not recommended. Use server-side verification."
|
|
438
|
+
);
|
|
439
|
+
return false;
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Async signature verification using Web Crypto API (works in browser and Node.js)
|
|
443
|
+
*/
|
|
444
|
+
async verifyAsync(payload, signature, secret) {
|
|
445
|
+
try {
|
|
446
|
+
const crypto2 = require("crypto");
|
|
447
|
+
const expectedSignature = crypto2.createHmac("sha256", secret).update(payload).digest("hex");
|
|
448
|
+
const sigBuffer = Buffer.from(signature, "hex");
|
|
449
|
+
const expectedBuffer = Buffer.from(expectedSignature, "hex");
|
|
450
|
+
if (sigBuffer.length !== expectedBuffer.length) {
|
|
451
|
+
return false;
|
|
452
|
+
}
|
|
453
|
+
return crypto2.timingSafeEqual(sigBuffer, expectedBuffer);
|
|
454
|
+
} catch {
|
|
455
|
+
const encoder = new TextEncoder();
|
|
456
|
+
const keyData = encoder.encode(secret);
|
|
457
|
+
const payloadData = encoder.encode(payload);
|
|
458
|
+
const key = await crypto.subtle.importKey(
|
|
459
|
+
"raw",
|
|
460
|
+
keyData,
|
|
461
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
462
|
+
false,
|
|
463
|
+
["sign"]
|
|
464
|
+
);
|
|
465
|
+
const signatureBuffer = await crypto.subtle.sign(
|
|
466
|
+
"HMAC",
|
|
467
|
+
key,
|
|
468
|
+
payloadData
|
|
469
|
+
);
|
|
470
|
+
const expectedHex = Array.from(new Uint8Array(signatureBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
471
|
+
if (signature.length !== expectedHex.length) {
|
|
472
|
+
return false;
|
|
473
|
+
}
|
|
474
|
+
let result = 0;
|
|
475
|
+
for (let i = 0; i < signature.length; i++) {
|
|
476
|
+
result |= signature.charCodeAt(i) ^ expectedHex.charCodeAt(i);
|
|
477
|
+
}
|
|
478
|
+
return result === 0;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Construct a webhook event from a raw request
|
|
483
|
+
*/
|
|
484
|
+
constructEvent(payload, signature, secret) {
|
|
485
|
+
if (!this.verify(payload, signature, secret)) {
|
|
486
|
+
throw new Error("Invalid webhook signature");
|
|
487
|
+
}
|
|
488
|
+
const event = JSON.parse(payload);
|
|
489
|
+
return event;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Create a new webhook subscription
|
|
493
|
+
*/
|
|
494
|
+
async create(options) {
|
|
495
|
+
const baseUrl = this.config.baseUrl || "https://protocol-banks.vercel.app";
|
|
496
|
+
const response = await fetch(`${baseUrl}/api/webhooks`, {
|
|
497
|
+
method: "POST",
|
|
498
|
+
headers: {
|
|
499
|
+
"Content-Type": "application/json",
|
|
500
|
+
"X-API-Key": this.config.apiKey
|
|
501
|
+
},
|
|
502
|
+
body: JSON.stringify(options)
|
|
503
|
+
});
|
|
504
|
+
return response.json();
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* List webhook subscriptions
|
|
508
|
+
*/
|
|
509
|
+
async list() {
|
|
510
|
+
const baseUrl = this.config.baseUrl || "https://protocol-banks.vercel.app";
|
|
511
|
+
const response = await fetch(`${baseUrl}/api/webhooks`, {
|
|
512
|
+
headers: {
|
|
513
|
+
"X-API-Key": this.config.apiKey
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
return response.json();
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Delete a webhook subscription
|
|
520
|
+
*/
|
|
521
|
+
async delete(webhookId) {
|
|
522
|
+
const baseUrl = this.config.baseUrl || "https://protocol-banks.vercel.app";
|
|
523
|
+
const response = await fetch(`${baseUrl}/api/webhooks/${webhookId}`, {
|
|
524
|
+
method: "DELETE",
|
|
525
|
+
headers: {
|
|
526
|
+
"X-API-Key": this.config.apiKey
|
|
527
|
+
}
|
|
528
|
+
});
|
|
529
|
+
return response.json();
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Get recent webhook deliveries
|
|
533
|
+
*/
|
|
534
|
+
async getDeliveries(webhookId) {
|
|
535
|
+
const baseUrl = this.config.baseUrl || "https://protocol-banks.vercel.app";
|
|
536
|
+
const response = await fetch(
|
|
537
|
+
`${baseUrl}/api/webhooks/${webhookId}/deliveries`,
|
|
538
|
+
{
|
|
539
|
+
headers: {
|
|
540
|
+
"X-API-Key": this.config.apiKey
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
);
|
|
544
|
+
return response.json();
|
|
545
|
+
}
|
|
546
|
+
};
|
|
547
|
+
|
|
548
|
+
// src/agent.ts
|
|
549
|
+
var Agent = class {
|
|
550
|
+
constructor(config) {
|
|
551
|
+
this.config = config;
|
|
552
|
+
}
|
|
553
|
+
baseUrl() {
|
|
554
|
+
return this.config.baseUrl || "https://protocolbanks.com";
|
|
555
|
+
}
|
|
556
|
+
async call(method, path, body) {
|
|
557
|
+
const res = await fetch(`${this.baseUrl()}/api/v1/agent${path}`, {
|
|
558
|
+
method,
|
|
559
|
+
headers: {
|
|
560
|
+
...body === void 0 ? {} : { "Content-Type": "application/json" },
|
|
561
|
+
Authorization: `Bearer ${this.config.apiKey}`
|
|
562
|
+
},
|
|
563
|
+
...body === void 0 ? {} : { body: JSON.stringify(body) }
|
|
564
|
+
});
|
|
565
|
+
const json = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
|
|
566
|
+
return { ...json, status: res.status };
|
|
567
|
+
}
|
|
568
|
+
/** Mode, equity, positions, activity and the key's policy with spentTodayUsd. */
|
|
569
|
+
async state() {
|
|
570
|
+
return this.call("GET", "/state");
|
|
571
|
+
}
|
|
572
|
+
/** Place one order. Executes through the trading-only agent wallet. */
|
|
573
|
+
async order(request) {
|
|
574
|
+
return this.call("POST", "/orders", request);
|
|
575
|
+
}
|
|
576
|
+
/** Validate a payment and return the intent the agent signs itself. */
|
|
577
|
+
async pay(request) {
|
|
578
|
+
return this.call("POST", "/pay", request);
|
|
579
|
+
}
|
|
580
|
+
/** Quote a swap; the agent signs and submits the returned transaction. */
|
|
581
|
+
async swap(request) {
|
|
582
|
+
return this.call("POST", "/swap", request);
|
|
583
|
+
}
|
|
584
|
+
/** Create a pending invoice and get the payer's paymentLink. */
|
|
585
|
+
async invoice(request) {
|
|
586
|
+
return this.call("POST", "/invoice", request);
|
|
587
|
+
}
|
|
588
|
+
/**
|
|
589
|
+
* Read an invoice back with the id and signature from its paymentLink
|
|
590
|
+
* (`/pay?invoice=<id>&sig=<sig>`). A signed invoice answers 403 without sig.
|
|
591
|
+
*/
|
|
592
|
+
async invoiceStatus(invoiceId, sig) {
|
|
593
|
+
const query = new URLSearchParams({ id: invoiceId });
|
|
594
|
+
if (sig) query.set("sig", sig);
|
|
595
|
+
const res = await fetch(`${this.baseUrl()}/api/invoice?${query.toString()}`);
|
|
596
|
+
const json = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));
|
|
597
|
+
return { ok: Boolean(json.success), status: res.status, invoice: json.invoice, error: json.error };
|
|
598
|
+
}
|
|
599
|
+
};
|
|
600
|
+
|
|
601
|
+
// src/client.ts
|
|
602
|
+
var ProtocolBanks = class {
|
|
603
|
+
constructor(config) {
|
|
604
|
+
this.config = {
|
|
605
|
+
...config,
|
|
606
|
+
baseUrl: config.baseUrl || "https://protocolbanks.com",
|
|
607
|
+
defaultToken: config.defaultToken || "USDC"
|
|
608
|
+
};
|
|
609
|
+
this.paymentLinks = new PaymentLink(this.config);
|
|
610
|
+
this.invoices = new Invoice(this.config);
|
|
611
|
+
this.checkout = new Checkout(this.config);
|
|
612
|
+
this.webhooks = new Webhook(this.config);
|
|
613
|
+
this.agent = new Agent(this.config);
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* Create an embeddable payment iframe
|
|
617
|
+
*/
|
|
618
|
+
embed(options) {
|
|
619
|
+
const container = typeof options.container === "string" ? document.querySelector(options.container) : options.container;
|
|
620
|
+
if (!container) {
|
|
621
|
+
throw new Error("Container element not found");
|
|
622
|
+
}
|
|
623
|
+
const params = new URLSearchParams({
|
|
624
|
+
to: options.to,
|
|
625
|
+
token: options.token || this.config.defaultToken
|
|
626
|
+
});
|
|
627
|
+
if (options.amount) params.set("amount", options.amount);
|
|
628
|
+
if (options.merchantName) params.set("merchant", options.merchantName);
|
|
629
|
+
if (options.theme) params.set("theme", options.theme);
|
|
630
|
+
const iframe = document.createElement("iframe");
|
|
631
|
+
iframe.src = `${this.config.baseUrl}/embed/pay?${params.toString()}`;
|
|
632
|
+
iframe.style.width = "100%";
|
|
633
|
+
iframe.style.height = "500px";
|
|
634
|
+
iframe.style.border = "none";
|
|
635
|
+
iframe.style.borderRadius = "12px";
|
|
636
|
+
iframe.allow = "payment";
|
|
637
|
+
const handleMessage = (event) => {
|
|
638
|
+
if (event.origin !== new URL(this.config.baseUrl).origin) return;
|
|
639
|
+
const data = event.data;
|
|
640
|
+
if (data.type === "payment_success" && options.onSuccess) {
|
|
641
|
+
options.onSuccess({
|
|
642
|
+
success: true,
|
|
643
|
+
id: data.txHash || "",
|
|
644
|
+
paymentUrl: "",
|
|
645
|
+
status: "paid",
|
|
646
|
+
txHash: data.txHash
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
if (data.type === "payment_error" && options.onError) {
|
|
650
|
+
options.onError(new Error(data.error || "Payment failed"));
|
|
651
|
+
}
|
|
652
|
+
};
|
|
653
|
+
window.addEventListener("message", handleMessage);
|
|
654
|
+
container.appendChild(iframe);
|
|
655
|
+
return {
|
|
656
|
+
destroy: () => {
|
|
657
|
+
window.removeEventListener("message", handleMessage);
|
|
658
|
+
iframe.remove();
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Generate a payment URL for direct redirect
|
|
664
|
+
*/
|
|
665
|
+
getPaymentUrl(options) {
|
|
666
|
+
const params = new URLSearchParams({
|
|
667
|
+
to: options.to,
|
|
668
|
+
amount: options.amount,
|
|
669
|
+
token: options.token || this.config.defaultToken
|
|
670
|
+
});
|
|
671
|
+
if (options.merchantName) params.set("merchant", options.merchantName);
|
|
672
|
+
return `${this.config.baseUrl}/pay?${params.toString()}`;
|
|
673
|
+
}
|
|
674
|
+
/**
|
|
675
|
+
* Make an authenticated API request
|
|
676
|
+
*/
|
|
677
|
+
async request(path, options = {}) {
|
|
678
|
+
const url = `${this.config.baseUrl}/api${path}`;
|
|
679
|
+
const headers = {
|
|
680
|
+
"Content-Type": "application/json",
|
|
681
|
+
"X-API-Key": this.config.apiKey
|
|
682
|
+
};
|
|
683
|
+
if (this.config.apiSecret) {
|
|
684
|
+
headers["X-API-Secret"] = this.config.apiSecret;
|
|
685
|
+
}
|
|
686
|
+
const response = await fetch(url, {
|
|
687
|
+
...options,
|
|
688
|
+
headers: {
|
|
689
|
+
...headers,
|
|
690
|
+
...options.headers
|
|
691
|
+
}
|
|
692
|
+
});
|
|
693
|
+
if (!response.ok) {
|
|
694
|
+
const error = await response.json().catch(() => ({ error: "Request failed" }));
|
|
695
|
+
throw new Error(error.error || `API request failed: ${response.status}`);
|
|
696
|
+
}
|
|
697
|
+
return response.json();
|
|
698
|
+
}
|
|
699
|
+
};
|
|
700
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
701
|
+
0 && (module.exports = {
|
|
702
|
+
Agent,
|
|
703
|
+
Checkout,
|
|
704
|
+
Invoice,
|
|
705
|
+
PaymentLink,
|
|
706
|
+
ProtocolBanks,
|
|
707
|
+
Webhook
|
|
708
|
+
});
|