ucpify 1.1.0 → 1.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/package.json +18 -18
- package/src/cli.ts +30 -1
- package/src/db.ts +35 -0
- package/src/express-app.ts +206 -1
- package/src/oauth.ts +270 -0
- package/src/schema.ts +18 -0
- package/src/ucp-server-db.ts +10 -5
- package/src/ucp-server.ts +8 -0
- package/dist/__tests__/api.test.d.ts +0 -1
- package/dist/__tests__/api.test.js +0 -121
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +0 -208
- package/dist/config.d.ts +0 -14
- package/dist/config.js +0 -22
- package/dist/db.d.ts +0 -4
- package/dist/db.js +0 -129
- package/dist/express-app.d.ts +0 -5
- package/dist/express-app.js +0 -320
- package/dist/index.d.ts +0 -4
- package/dist/index.js +0 -12
- package/dist/logger.d.ts +0 -3
- package/dist/logger.js +0 -15
- package/dist/paypal.d.ts +0 -20
- package/dist/paypal.js +0 -111
- package/dist/schema.d.ts +0 -266
- package/dist/schema.js +0 -98
- package/dist/stripe.d.ts +0 -14
- package/dist/stripe.js +0 -103
- package/dist/ucp-server-db.d.ts +0 -72
- package/dist/ucp-server-db.js +0 -364
- package/dist/ucp-server.d.ts +0 -79
- package/dist/ucp-server.js +0 -373
package/dist/express-app.js
DELETED
|
@@ -1,320 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.createExpressApp = createExpressApp;
|
|
7
|
-
const express_1 = __importDefault(require("express"));
|
|
8
|
-
const express_rate_limit_1 = __importDefault(require("express-rate-limit"));
|
|
9
|
-
const ucp_server_1 = require("./ucp-server");
|
|
10
|
-
const ucp_server_db_1 = require("./ucp-server-db");
|
|
11
|
-
const schema_1 = require("./schema");
|
|
12
|
-
const db_1 = require("./db");
|
|
13
|
-
const logger_1 = require("./logger");
|
|
14
|
-
const stripe_1 = require("./stripe");
|
|
15
|
-
const paypal_1 = require("./paypal");
|
|
16
|
-
// Rate limiters
|
|
17
|
-
const apiLimiter = (0, express_rate_limit_1.default)({
|
|
18
|
-
windowMs: 60 * 1000, // 1 minute
|
|
19
|
-
max: 100, // 100 requests per minute
|
|
20
|
-
standardHeaders: true,
|
|
21
|
-
legacyHeaders: false,
|
|
22
|
-
message: { error: 'Too many requests, please try again later' },
|
|
23
|
-
});
|
|
24
|
-
const checkoutLimiter = (0, express_rate_limit_1.default)({
|
|
25
|
-
windowMs: 60 * 1000,
|
|
26
|
-
max: 20, // 20 checkout creates per minute
|
|
27
|
-
standardHeaders: true,
|
|
28
|
-
legacyHeaders: false,
|
|
29
|
-
message: { error: 'Too many checkout requests' },
|
|
30
|
-
});
|
|
31
|
-
function createExpressApp(config, options) {
|
|
32
|
-
const app = (0, express_1.default)();
|
|
33
|
-
const ucpServer = options?.useDb
|
|
34
|
-
? new ucp_server_db_1.UCPServerDB(config)
|
|
35
|
-
: new ucp_server_1.UCPServer(config);
|
|
36
|
-
const useDb = options?.useDb ?? false;
|
|
37
|
-
// Apply rate limiting to API routes
|
|
38
|
-
app.use('/ucp/v1/', apiLimiter);
|
|
39
|
-
// Stripe webhook needs raw body - must come before json parser
|
|
40
|
-
app.post('/webhooks/stripe', express_1.default.raw({ type: 'application/json' }), (req, res) => {
|
|
41
|
-
const signature = req.headers['stripe-signature'];
|
|
42
|
-
if (!signature) {
|
|
43
|
-
res.status(400).json({ error: 'Missing stripe-signature header' });
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
const event = (0, stripe_1.constructWebhookEvent)(req.body, signature);
|
|
47
|
-
if (!event) {
|
|
48
|
-
res.status(400).json({ error: 'Invalid webhook signature' });
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
logger_1.logger.info({ eventType: event.type, eventId: event.id }, 'Stripe webhook received');
|
|
52
|
-
switch (event.type) {
|
|
53
|
-
case 'payment_intent.succeeded': {
|
|
54
|
-
const paymentIntent = event.data.object;
|
|
55
|
-
const checkoutId = paymentIntent.metadata?.checkout_id;
|
|
56
|
-
const orderId = paymentIntent.metadata?.order_id;
|
|
57
|
-
if (checkoutId && useDb) {
|
|
58
|
-
db_1.db.prepare(`UPDATE checkouts SET payment_status = 'succeeded', updated_at = ? WHERE id = ?`)
|
|
59
|
-
.run(new Date().toISOString(), checkoutId);
|
|
60
|
-
if (orderId) {
|
|
61
|
-
db_1.db.prepare(`UPDATE orders SET payment_status = 'succeeded' WHERE id = ?`).run(orderId);
|
|
62
|
-
}
|
|
63
|
-
logger_1.logger.info({ checkoutId, orderId, paymentIntentId: paymentIntent.id }, 'Payment succeeded');
|
|
64
|
-
}
|
|
65
|
-
break;
|
|
66
|
-
}
|
|
67
|
-
case 'payment_intent.payment_failed': {
|
|
68
|
-
const paymentIntent = event.data.object;
|
|
69
|
-
const checkoutId = paymentIntent.metadata?.checkout_id;
|
|
70
|
-
const orderId = paymentIntent.metadata?.order_id;
|
|
71
|
-
if (checkoutId && useDb) {
|
|
72
|
-
db_1.db.prepare(`UPDATE checkouts SET payment_status = 'failed', updated_at = ? WHERE id = ?`)
|
|
73
|
-
.run(new Date().toISOString(), checkoutId);
|
|
74
|
-
if (orderId) {
|
|
75
|
-
db_1.db.prepare(`UPDATE orders SET payment_status = 'failed' WHERE id = ?`).run(orderId);
|
|
76
|
-
}
|
|
77
|
-
logger_1.logger.error({
|
|
78
|
-
checkoutId, orderId, paymentIntentId: paymentIntent.id,
|
|
79
|
-
error: paymentIntent.last_payment_error?.message
|
|
80
|
-
}, 'Payment failed');
|
|
81
|
-
}
|
|
82
|
-
break;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
res.json({ received: true });
|
|
86
|
-
});
|
|
87
|
-
// PayPal webhook - capture completed orders
|
|
88
|
-
app.post('/webhooks/paypal', express_1.default.json(), async (req, res) => {
|
|
89
|
-
const eventType = req.body.event_type;
|
|
90
|
-
const resource = req.body.resource;
|
|
91
|
-
logger_1.logger.info({ eventType, resourceId: resource?.id }, 'PayPal webhook received');
|
|
92
|
-
if (eventType === 'CHECKOUT.ORDER.APPROVED' && resource?.id) {
|
|
93
|
-
try {
|
|
94
|
-
// Capture the payment
|
|
95
|
-
const capturedOrder = await (0, paypal_1.capturePayPalOrder)(resource.id);
|
|
96
|
-
if (capturedOrder && capturedOrder.status === 'COMPLETED') {
|
|
97
|
-
// Get the checkout ID from the order
|
|
98
|
-
const orderDetails = await (0, paypal_1.getPayPalOrder)(resource.id);
|
|
99
|
-
const checkoutId = orderDetails?.customId;
|
|
100
|
-
if (checkoutId && useDb) {
|
|
101
|
-
const now = new Date().toISOString();
|
|
102
|
-
db_1.db.prepare(`UPDATE checkouts SET payment_status = 'succeeded', updated_at = ? WHERE paypal_order_id = ?`)
|
|
103
|
-
.run(now, resource.id);
|
|
104
|
-
db_1.db.prepare(`UPDATE orders SET payment_status = 'succeeded' WHERE paypal_order_id = ?`)
|
|
105
|
-
.run(resource.id);
|
|
106
|
-
logger_1.logger.info({ checkoutId, paypalOrderId: resource.id }, 'PayPal payment captured and succeeded');
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
catch (error) {
|
|
111
|
-
logger_1.logger.error({ error, paypalOrderId: resource.id }, 'Failed to capture PayPal order');
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
else if (eventType === 'PAYMENT.CAPTURE.DENIED' && resource?.id) {
|
|
115
|
-
if (useDb) {
|
|
116
|
-
const now = new Date().toISOString();
|
|
117
|
-
db_1.db.prepare(`UPDATE checkouts SET payment_status = 'failed', updated_at = ? WHERE paypal_order_id = ?`)
|
|
118
|
-
.run(now, resource.supplementary_data?.related_ids?.order_id);
|
|
119
|
-
db_1.db.prepare(`UPDATE orders SET payment_status = 'failed' WHERE paypal_order_id = ?`)
|
|
120
|
-
.run(resource.supplementary_data?.related_ids?.order_id);
|
|
121
|
-
logger_1.logger.error({ paypalOrderId: resource.id }, 'PayPal payment denied');
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
res.json({ received: true });
|
|
125
|
-
});
|
|
126
|
-
app.use(express_1.default.json());
|
|
127
|
-
// Request logging middleware
|
|
128
|
-
app.use((req, res, next) => {
|
|
129
|
-
const start = Date.now();
|
|
130
|
-
res.on('finish', () => {
|
|
131
|
-
logger_1.logger.info({
|
|
132
|
-
method: req.method,
|
|
133
|
-
path: req.path,
|
|
134
|
-
status: res.statusCode,
|
|
135
|
-
duration: Date.now() - start,
|
|
136
|
-
}, 'Request completed');
|
|
137
|
-
});
|
|
138
|
-
next();
|
|
139
|
-
});
|
|
140
|
-
// CORS middleware
|
|
141
|
-
app.use((_req, res, next) => {
|
|
142
|
-
res.header('Access-Control-Allow-Origin', '*');
|
|
143
|
-
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
|
|
144
|
-
res.header('Access-Control-Allow-Headers', 'Content-Type, UCP-Agent, Authorization');
|
|
145
|
-
next();
|
|
146
|
-
});
|
|
147
|
-
// UCP Discovery endpoint
|
|
148
|
-
app.get('/.well-known/ucp', (_req, res) => {
|
|
149
|
-
res.json(ucpServer.getProfile());
|
|
150
|
-
});
|
|
151
|
-
// Create Checkout Session
|
|
152
|
-
app.post('/ucp/v1/checkout-sessions', checkoutLimiter, (req, res) => {
|
|
153
|
-
const parsed = schema_1.CreateCheckoutRequestSchema.safeParse(req.body);
|
|
154
|
-
if (!parsed.success) {
|
|
155
|
-
res.status(400).json({ error: 'Validation failed', details: parsed.error.issues });
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
try {
|
|
159
|
-
const session = ucpServer.createCheckout(parsed.data);
|
|
160
|
-
res.status(201).json(session);
|
|
161
|
-
}
|
|
162
|
-
catch (error) {
|
|
163
|
-
res.status(400).json({ error: 'Invalid request', details: String(error) });
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
// Get Checkout Session
|
|
167
|
-
app.get('/ucp/v1/checkout-sessions/:id', (req, res) => {
|
|
168
|
-
const id = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
|
|
169
|
-
const session = ucpServer.getCheckout(id);
|
|
170
|
-
if (!session) {
|
|
171
|
-
res.status(404).json({ error: 'Checkout session not found' });
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
res.json(session);
|
|
175
|
-
});
|
|
176
|
-
// Update Checkout Session
|
|
177
|
-
app.put('/ucp/v1/checkout-sessions/:id', (req, res) => {
|
|
178
|
-
const parsed = schema_1.UpdateCheckoutRequestSchema.safeParse(req.body);
|
|
179
|
-
if (!parsed.success) {
|
|
180
|
-
res.status(400).json({ error: 'Validation failed', details: parsed.error.issues });
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
try {
|
|
184
|
-
const id = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
|
|
185
|
-
const session = ucpServer.updateCheckout(id, parsed.data);
|
|
186
|
-
if (!session) {
|
|
187
|
-
res.status(404).json({ error: 'Checkout session not found' });
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
res.json(session);
|
|
191
|
-
}
|
|
192
|
-
catch (error) {
|
|
193
|
-
res.status(400).json({ error: 'Invalid request', details: String(error) });
|
|
194
|
-
}
|
|
195
|
-
});
|
|
196
|
-
// Complete Checkout
|
|
197
|
-
app.post('/ucp/v1/checkout-sessions/:id/complete', async (req, res) => {
|
|
198
|
-
const id = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
|
|
199
|
-
try {
|
|
200
|
-
const result = await ucpServer.completeCheckout(id);
|
|
201
|
-
if ('error' in result) {
|
|
202
|
-
res.status(400).json(result);
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
res.status(201).json(result);
|
|
206
|
-
}
|
|
207
|
-
catch (error) {
|
|
208
|
-
logger_1.logger.error({ error, checkoutId: id }, 'Failed to complete checkout');
|
|
209
|
-
res.status(500).json({ error: 'Internal server error' });
|
|
210
|
-
}
|
|
211
|
-
});
|
|
212
|
-
// Cancel Checkout
|
|
213
|
-
app.post('/ucp/v1/checkout-sessions/:id/cancel', (req, res) => {
|
|
214
|
-
const id = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
|
|
215
|
-
const session = ucpServer.cancelCheckout(id);
|
|
216
|
-
if (!session) {
|
|
217
|
-
res.status(404).json({ error: 'Checkout session not found' });
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
220
|
-
res.json(session);
|
|
221
|
-
});
|
|
222
|
-
// Get Order
|
|
223
|
-
app.get('/ucp/v1/orders/:id', (req, res) => {
|
|
224
|
-
const id = Array.isArray(req.params.id) ? req.params.id[0] : req.params.id;
|
|
225
|
-
const order = ucpServer.getOrder(id);
|
|
226
|
-
if (!order) {
|
|
227
|
-
res.status(404).json({ error: 'Order not found' });
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
res.json(order);
|
|
231
|
-
});
|
|
232
|
-
// List Orders
|
|
233
|
-
app.get('/ucp/v1/orders', (_req, res) => {
|
|
234
|
-
res.json(ucpServer.listOrders());
|
|
235
|
-
});
|
|
236
|
-
// Product catalog (convenience endpoint)
|
|
237
|
-
app.get('/ucp/v1/items', (_req, res) => {
|
|
238
|
-
res.json(ucpServer.getConfig().items);
|
|
239
|
-
});
|
|
240
|
-
// Admin stats endpoint
|
|
241
|
-
app.get('/admin/stats', (_req, res) => {
|
|
242
|
-
if (!useDb) {
|
|
243
|
-
res.status(501).json({ error: 'Stats require database mode' });
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
try {
|
|
247
|
-
const checkoutStats = db_1.db.prepare(`
|
|
248
|
-
SELECT status, COUNT(*) as count FROM checkouts GROUP BY status
|
|
249
|
-
`).all();
|
|
250
|
-
const orderStats = db_1.db.prepare(`
|
|
251
|
-
SELECT payment_status, payment_provider, COUNT(*) as count
|
|
252
|
-
FROM orders GROUP BY payment_status, payment_provider
|
|
253
|
-
`).all();
|
|
254
|
-
const revenueResult = db_1.db.prepare(`
|
|
255
|
-
SELECT SUM(json_extract(totals_json, '$[?(@.type=="total")].amount')) as total
|
|
256
|
-
FROM orders WHERE payment_status = 'succeeded'
|
|
257
|
-
`).get();
|
|
258
|
-
const todayOrders = db_1.db.prepare(`
|
|
259
|
-
SELECT COUNT(*) as count FROM orders
|
|
260
|
-
WHERE date(created_at) = date('now')
|
|
261
|
-
`).get();
|
|
262
|
-
res.json({
|
|
263
|
-
checkouts: Object.fromEntries(checkoutStats.map(s => [s.status, s.count])),
|
|
264
|
-
orders: {
|
|
265
|
-
by_payment_status: Object.fromEntries(orderStats.map(s => [`${s.payment_provider || 'none'}_${s.payment_status}`, s.count])),
|
|
266
|
-
today: todayOrders.count,
|
|
267
|
-
},
|
|
268
|
-
revenue: {
|
|
269
|
-
total_succeeded: revenueResult.total || 0,
|
|
270
|
-
},
|
|
271
|
-
timestamp: new Date().toISOString(),
|
|
272
|
-
});
|
|
273
|
-
}
|
|
274
|
-
catch (error) {
|
|
275
|
-
logger_1.logger.error({ error }, 'Failed to get admin stats');
|
|
276
|
-
res.status(500).json({ error: 'Failed to get stats' });
|
|
277
|
-
}
|
|
278
|
-
});
|
|
279
|
-
// Admin dashboard HTML
|
|
280
|
-
app.get('/admin', (_req, res) => {
|
|
281
|
-
const statsScript = useDb
|
|
282
|
-
? `fetch('/admin/stats').then(r=>r.json()).then(d=>{
|
|
283
|
-
document.getElementById('stats').innerHTML = \`
|
|
284
|
-
<div class="card"><div class="stat">\${Object.values(d.checkouts).reduce((a,b)=>a+b,0)}</div><div class="label">Total Checkouts</div></div>
|
|
285
|
-
<div class="card"><div class="stat">\${d.checkouts.completed||0}</div><div class="label">Completed</div></div>
|
|
286
|
-
<div class="card"><div class="stat">\${d.orders.today||0}</div><div class="label">Orders Today</div></div>
|
|
287
|
-
<div class="card"><div class="stat">$\${(d.revenue.total_succeeded/100).toFixed(2)}</div><div class="label">Revenue</div></div>
|
|
288
|
-
\`;
|
|
289
|
-
}).catch(e=>document.getElementById('stats').innerHTML='Error loading stats');`
|
|
290
|
-
: `document.getElementById('stats').innerHTML = '<div class="card" style="grid-column:1/-1"><div class="label">Running in <strong>in-memory mode</strong>. Stats require <code>--db</code> mode.</div><div style="margin-top:8px;font-size:0.85em;color:#999">Restart with: <code>ucpify serve config.json</code> (DB is on by default)</div></div>';`;
|
|
291
|
-
res.send(`<!DOCTYPE html>
|
|
292
|
-
<html><head><title>UCP Admin</title>
|
|
293
|
-
<style>
|
|
294
|
-
body { font-family: system-ui; max-width: 800px; margin: 40px auto; padding: 20px; }
|
|
295
|
-
.card { background: #f5f5f5; padding: 20px; border-radius: 8px; margin: 10px 0; }
|
|
296
|
-
.stat { font-size: 2em; font-weight: bold; color: #333; }
|
|
297
|
-
.label { color: #666; font-size: 0.9em; }
|
|
298
|
-
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; }
|
|
299
|
-
h1 { color: #333; }
|
|
300
|
-
code { background: #e5e5e5; padding: 2px 6px; border-radius: 3px; font-size: 0.85em; }
|
|
301
|
-
</style>
|
|
302
|
-
</head><body>
|
|
303
|
-
<h1>🛒 UCP Server Admin</h1>
|
|
304
|
-
<div class="grid" id="stats">Loading...</div>
|
|
305
|
-
<script>${statsScript}</script>
|
|
306
|
-
</body></html>`);
|
|
307
|
-
});
|
|
308
|
-
// Health check
|
|
309
|
-
app.get('/health', (_req, res) => {
|
|
310
|
-
const dbHealthy = (0, db_1.isDbHealthy)();
|
|
311
|
-
const status = dbHealthy ? 'ok' : 'degraded';
|
|
312
|
-
res.status(dbHealthy ? 200 : 503).json({
|
|
313
|
-
status,
|
|
314
|
-
ucp_version: schema_1.UCP_VERSION,
|
|
315
|
-
database: dbHealthy ? 'connected' : 'disconnected',
|
|
316
|
-
timestamp: new Date().toISOString(),
|
|
317
|
-
});
|
|
318
|
-
});
|
|
319
|
-
return app;
|
|
320
|
-
}
|
package/dist/index.d.ts
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
export { MerchantConfigSchema, ItemSchema, ShippingOptionSchema, PaymentHandlerSchema } from './schema';
|
|
2
|
-
export type { MerchantConfig, Item, ShippingOption, PaymentHandler, CheckoutSession, Order } from './schema';
|
|
3
|
-
export { UCPServer } from './ucp-server';
|
|
4
|
-
export { createExpressApp } from './express-app';
|
package/dist/index.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createExpressApp = exports.UCPServer = exports.PaymentHandlerSchema = exports.ShippingOptionSchema = exports.ItemSchema = exports.MerchantConfigSchema = void 0;
|
|
4
|
-
var schema_1 = require("./schema");
|
|
5
|
-
Object.defineProperty(exports, "MerchantConfigSchema", { enumerable: true, get: function () { return schema_1.MerchantConfigSchema; } });
|
|
6
|
-
Object.defineProperty(exports, "ItemSchema", { enumerable: true, get: function () { return schema_1.ItemSchema; } });
|
|
7
|
-
Object.defineProperty(exports, "ShippingOptionSchema", { enumerable: true, get: function () { return schema_1.ShippingOptionSchema; } });
|
|
8
|
-
Object.defineProperty(exports, "PaymentHandlerSchema", { enumerable: true, get: function () { return schema_1.PaymentHandlerSchema; } });
|
|
9
|
-
var ucp_server_1 = require("./ucp-server");
|
|
10
|
-
Object.defineProperty(exports, "UCPServer", { enumerable: true, get: function () { return ucp_server_1.UCPServer; } });
|
|
11
|
-
var express_app_1 = require("./express-app");
|
|
12
|
-
Object.defineProperty(exports, "createExpressApp", { enumerable: true, get: function () { return express_app_1.createExpressApp; } });
|
package/dist/logger.d.ts
DELETED
package/dist/logger.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.logger = void 0;
|
|
7
|
-
const pino_1 = __importDefault(require("pino"));
|
|
8
|
-
const config_1 = require("./config");
|
|
9
|
-
exports.logger = (0, pino_1.default)({
|
|
10
|
-
level: config_1.config.logLevel,
|
|
11
|
-
transport: config_1.config.nodeEnv === 'development'
|
|
12
|
-
? { target: 'pino-pretty', options: { colorize: true } }
|
|
13
|
-
: undefined,
|
|
14
|
-
base: { service: 'ucpify' },
|
|
15
|
-
});
|
package/dist/paypal.d.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export declare function isPayPalConfigured(): boolean;
|
|
2
|
-
export interface CreatePayPalOrderParams {
|
|
3
|
-
amount: number;
|
|
4
|
-
currency: string;
|
|
5
|
-
checkoutId: string;
|
|
6
|
-
description?: string;
|
|
7
|
-
}
|
|
8
|
-
export declare function createPayPalOrder(params: CreatePayPalOrderParams): Promise<{
|
|
9
|
-
id: string;
|
|
10
|
-
status: string;
|
|
11
|
-
} | null>;
|
|
12
|
-
export declare function capturePayPalOrder(orderId: string): Promise<{
|
|
13
|
-
id: string;
|
|
14
|
-
status: string;
|
|
15
|
-
} | null>;
|
|
16
|
-
export declare function getPayPalOrder(orderId: string): Promise<{
|
|
17
|
-
id: string;
|
|
18
|
-
status: string;
|
|
19
|
-
customId?: string;
|
|
20
|
-
} | null>;
|
package/dist/paypal.js
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isPayPalConfigured = isPayPalConfigured;
|
|
4
|
-
exports.createPayPalOrder = createPayPalOrder;
|
|
5
|
-
exports.capturePayPalOrder = capturePayPalOrder;
|
|
6
|
-
exports.getPayPalOrder = getPayPalOrder;
|
|
7
|
-
const paypal_server_sdk_1 = require("@paypal/paypal-server-sdk");
|
|
8
|
-
const config_1 = require("./config");
|
|
9
|
-
const logger_1 = require("./logger");
|
|
10
|
-
let paypalClient = null;
|
|
11
|
-
let ordersController = null;
|
|
12
|
-
function getPayPalClient() {
|
|
13
|
-
if (!config_1.config.paypalClientId || !config_1.config.paypalClientSecret) {
|
|
14
|
-
return null;
|
|
15
|
-
}
|
|
16
|
-
if (!paypalClient) {
|
|
17
|
-
paypalClient = new paypal_server_sdk_1.Client({
|
|
18
|
-
clientCredentialsAuthCredentials: {
|
|
19
|
-
oAuthClientId: config_1.config.paypalClientId,
|
|
20
|
-
oAuthClientSecret: config_1.config.paypalClientSecret,
|
|
21
|
-
},
|
|
22
|
-
environment: config_1.config.paypalMode === 'live' ? paypal_server_sdk_1.Environment.Production : paypal_server_sdk_1.Environment.Sandbox,
|
|
23
|
-
});
|
|
24
|
-
ordersController = new paypal_server_sdk_1.OrdersController(paypalClient);
|
|
25
|
-
logger_1.logger.info('PayPal client initialized');
|
|
26
|
-
}
|
|
27
|
-
return paypalClient;
|
|
28
|
-
}
|
|
29
|
-
function isPayPalConfigured() {
|
|
30
|
-
return !!(config_1.config.paypalClientId && config_1.config.paypalClientSecret);
|
|
31
|
-
}
|
|
32
|
-
async function createPayPalOrder(params) {
|
|
33
|
-
const client = getPayPalClient();
|
|
34
|
-
if (!client || !ordersController) {
|
|
35
|
-
logger_1.logger.warn('PayPal not configured, skipping order creation');
|
|
36
|
-
return null;
|
|
37
|
-
}
|
|
38
|
-
// Convert cents to dollars with 2 decimal places
|
|
39
|
-
const amountValue = (params.amount / 100).toFixed(2);
|
|
40
|
-
try {
|
|
41
|
-
const response = await ordersController.createOrder({
|
|
42
|
-
body: {
|
|
43
|
-
intent: paypal_server_sdk_1.CheckoutPaymentIntent.Capture,
|
|
44
|
-
purchaseUnits: [
|
|
45
|
-
{
|
|
46
|
-
amount: {
|
|
47
|
-
currencyCode: params.currency.toUpperCase(),
|
|
48
|
-
value: amountValue,
|
|
49
|
-
},
|
|
50
|
-
description: params.description || `Checkout ${params.checkoutId}`,
|
|
51
|
-
customId: params.checkoutId,
|
|
52
|
-
},
|
|
53
|
-
],
|
|
54
|
-
},
|
|
55
|
-
prefer: 'return=representation',
|
|
56
|
-
});
|
|
57
|
-
const order = response.result;
|
|
58
|
-
logger_1.logger.info({
|
|
59
|
-
paypalOrderId: order.id,
|
|
60
|
-
checkoutId: params.checkoutId,
|
|
61
|
-
amount: params.amount,
|
|
62
|
-
}, 'PayPal order created');
|
|
63
|
-
return { id: order.id, status: order.status };
|
|
64
|
-
}
|
|
65
|
-
catch (error) {
|
|
66
|
-
if (error instanceof paypal_server_sdk_1.ApiError) {
|
|
67
|
-
logger_1.logger.error({ error: error.message, checkoutId: params.checkoutId }, 'Failed to create PayPal order');
|
|
68
|
-
}
|
|
69
|
-
throw error;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
async function capturePayPalOrder(orderId) {
|
|
73
|
-
const client = getPayPalClient();
|
|
74
|
-
if (!client || !ordersController)
|
|
75
|
-
return null;
|
|
76
|
-
try {
|
|
77
|
-
const response = await ordersController.captureOrder({
|
|
78
|
-
id: orderId,
|
|
79
|
-
prefer: 'return=representation',
|
|
80
|
-
});
|
|
81
|
-
const order = response.result;
|
|
82
|
-
logger_1.logger.info({ paypalOrderId: orderId, status: order.status }, 'PayPal order captured');
|
|
83
|
-
return { id: order.id, status: order.status };
|
|
84
|
-
}
|
|
85
|
-
catch (error) {
|
|
86
|
-
if (error instanceof paypal_server_sdk_1.ApiError) {
|
|
87
|
-
logger_1.logger.error({ error: error.message, paypalOrderId: orderId }, 'Failed to capture PayPal order');
|
|
88
|
-
}
|
|
89
|
-
throw error;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
async function getPayPalOrder(orderId) {
|
|
93
|
-
const client = getPayPalClient();
|
|
94
|
-
if (!client || !ordersController)
|
|
95
|
-
return null;
|
|
96
|
-
try {
|
|
97
|
-
const response = await ordersController.getOrder({ id: orderId });
|
|
98
|
-
const order = response.result;
|
|
99
|
-
return {
|
|
100
|
-
id: order.id,
|
|
101
|
-
status: order.status,
|
|
102
|
-
customId: order.purchaseUnits?.[0]?.customId,
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
catch (error) {
|
|
106
|
-
if (error instanceof paypal_server_sdk_1.ApiError) {
|
|
107
|
-
logger_1.logger.error({ error: error.message, paypalOrderId: orderId }, 'Failed to get PayPal order');
|
|
108
|
-
}
|
|
109
|
-
throw error;
|
|
110
|
-
}
|
|
111
|
-
}
|