ucpify 1.0.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/.env.example +23 -0
- package/Dockerfile +35 -0
- package/README.md +320 -0
- package/dist/__tests__/api.test.d.ts +1 -0
- package/dist/__tests__/api.test.js +121 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +207 -0
- package/dist/config.d.ts +14 -0
- package/dist/config.js +22 -0
- package/dist/db.d.ts +4 -0
- package/dist/db.js +129 -0
- package/dist/express-app.d.ts +5 -0
- package/dist/express-app.js +318 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +12 -0
- package/dist/logger.d.ts +3 -0
- package/dist/logger.js +15 -0
- package/dist/paypal.d.ts +20 -0
- package/dist/paypal.js +111 -0
- package/dist/schema.d.ts +266 -0
- package/dist/schema.js +98 -0
- package/dist/stripe.d.ts +14 -0
- package/dist/stripe.js +103 -0
- package/dist/ucp-server-db.d.ts +72 -0
- package/dist/ucp-server-db.js +364 -0
- package/dist/ucp-server.d.ts +77 -0
- package/dist/ucp-server.js +331 -0
- package/merchant-config.json +64 -0
- package/package.json +53 -0
- package/src/__tests__/api.test.ts +129 -0
- package/src/cli.ts +184 -0
- package/src/config.ts +27 -0
- package/src/db.ts +94 -0
- package/src/express-app.ts +344 -0
- package/src/index.ts +4 -0
- package/src/logger.ts +12 -0
- package/src/paypal.ts +120 -0
- package/src/schema.ts +244 -0
- package/src/stripe.ts +106 -0
- package/src/ucp-server-db.ts +412 -0
- package/src/ucp-server.ts +380 -0
- package/tsconfig.json +17 -0
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const UCP_VERSION = "2026-01-11";
|
|
3
|
+
export declare const ItemSchema: z.ZodObject<{
|
|
4
|
+
id: z.ZodString;
|
|
5
|
+
title: z.ZodString;
|
|
6
|
+
description: z.ZodOptional<z.ZodString>;
|
|
7
|
+
price: z.ZodNumber;
|
|
8
|
+
image_url: z.ZodOptional<z.ZodString>;
|
|
9
|
+
sku: z.ZodOptional<z.ZodString>;
|
|
10
|
+
stock: z.ZodOptional<z.ZodNumber>;
|
|
11
|
+
}, z.core.$strip>;
|
|
12
|
+
export declare const ShippingOptionSchema: z.ZodObject<{
|
|
13
|
+
id: z.ZodString;
|
|
14
|
+
title: z.ZodString;
|
|
15
|
+
description: z.ZodOptional<z.ZodString>;
|
|
16
|
+
price: z.ZodNumber;
|
|
17
|
+
estimated_days: z.ZodOptional<z.ZodString>;
|
|
18
|
+
}, z.core.$strip>;
|
|
19
|
+
export declare const PaymentHandlerSchema: z.ZodObject<{
|
|
20
|
+
namespace: z.ZodString;
|
|
21
|
+
id: z.ZodString;
|
|
22
|
+
config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
23
|
+
}, z.core.$strip>;
|
|
24
|
+
export declare const MerchantConfigSchema: z.ZodObject<{
|
|
25
|
+
name: z.ZodString;
|
|
26
|
+
domain: z.ZodString;
|
|
27
|
+
currency: z.ZodDefault<z.ZodString>;
|
|
28
|
+
terms_url: z.ZodOptional<z.ZodString>;
|
|
29
|
+
privacy_url: z.ZodOptional<z.ZodString>;
|
|
30
|
+
items: z.ZodArray<z.ZodObject<{
|
|
31
|
+
id: z.ZodString;
|
|
32
|
+
title: z.ZodString;
|
|
33
|
+
description: z.ZodOptional<z.ZodString>;
|
|
34
|
+
price: z.ZodNumber;
|
|
35
|
+
image_url: z.ZodOptional<z.ZodString>;
|
|
36
|
+
sku: z.ZodOptional<z.ZodString>;
|
|
37
|
+
stock: z.ZodOptional<z.ZodNumber>;
|
|
38
|
+
}, z.core.$strip>>;
|
|
39
|
+
shipping_options: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
40
|
+
id: z.ZodString;
|
|
41
|
+
title: z.ZodString;
|
|
42
|
+
description: z.ZodOptional<z.ZodString>;
|
|
43
|
+
price: z.ZodNumber;
|
|
44
|
+
estimated_days: z.ZodOptional<z.ZodString>;
|
|
45
|
+
}, z.core.$strip>>>;
|
|
46
|
+
payment_handlers: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
47
|
+
namespace: z.ZodString;
|
|
48
|
+
id: z.ZodString;
|
|
49
|
+
config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
50
|
+
}, z.core.$strip>>>;
|
|
51
|
+
tax_rate: z.ZodDefault<z.ZodNumber>;
|
|
52
|
+
port: z.ZodDefault<z.ZodNumber>;
|
|
53
|
+
}, z.core.$strip>;
|
|
54
|
+
export type Item = z.infer<typeof ItemSchema>;
|
|
55
|
+
export type ShippingOption = z.infer<typeof ShippingOptionSchema>;
|
|
56
|
+
export type PaymentHandler = z.infer<typeof PaymentHandlerSchema>;
|
|
57
|
+
export type MerchantConfig = z.infer<typeof MerchantConfigSchema>;
|
|
58
|
+
export type CheckoutStatus = 'incomplete' | 'requires_escalation' | 'ready_for_complete' | 'complete_in_progress' | 'completed' | 'canceled';
|
|
59
|
+
export interface Buyer {
|
|
60
|
+
email?: string;
|
|
61
|
+
first_name?: string;
|
|
62
|
+
last_name?: string;
|
|
63
|
+
phone?: string;
|
|
64
|
+
}
|
|
65
|
+
export interface Address {
|
|
66
|
+
id?: string;
|
|
67
|
+
first_name?: string;
|
|
68
|
+
last_name?: string;
|
|
69
|
+
street_address: string;
|
|
70
|
+
address_locality: string;
|
|
71
|
+
address_region: string;
|
|
72
|
+
postal_code: string;
|
|
73
|
+
address_country: string;
|
|
74
|
+
}
|
|
75
|
+
export interface LineItem {
|
|
76
|
+
id: string;
|
|
77
|
+
item: Item;
|
|
78
|
+
quantity: number;
|
|
79
|
+
totals?: {
|
|
80
|
+
type: string;
|
|
81
|
+
amount: number;
|
|
82
|
+
}[];
|
|
83
|
+
}
|
|
84
|
+
export interface FulfillmentOption {
|
|
85
|
+
id: string;
|
|
86
|
+
title: string;
|
|
87
|
+
description?: string;
|
|
88
|
+
totals: {
|
|
89
|
+
type: string;
|
|
90
|
+
amount: number;
|
|
91
|
+
}[];
|
|
92
|
+
}
|
|
93
|
+
export interface FulfillmentGroup {
|
|
94
|
+
id: string;
|
|
95
|
+
line_item_ids: string[];
|
|
96
|
+
selected_option_id?: string;
|
|
97
|
+
options: FulfillmentOption[];
|
|
98
|
+
}
|
|
99
|
+
export interface FulfillmentMethod {
|
|
100
|
+
id: string;
|
|
101
|
+
type: 'shipping' | 'pickup' | 'digital';
|
|
102
|
+
line_item_ids: string[];
|
|
103
|
+
selected_destination_id?: string;
|
|
104
|
+
destinations: Address[];
|
|
105
|
+
groups: FulfillmentGroup[];
|
|
106
|
+
}
|
|
107
|
+
export interface Fulfillment {
|
|
108
|
+
methods: FulfillmentMethod[];
|
|
109
|
+
}
|
|
110
|
+
export interface PaymentInstrument {
|
|
111
|
+
id: string;
|
|
112
|
+
handler_id: string;
|
|
113
|
+
type: string;
|
|
114
|
+
selected?: boolean;
|
|
115
|
+
display?: Record<string, unknown>;
|
|
116
|
+
}
|
|
117
|
+
export interface Payment {
|
|
118
|
+
instruments: PaymentInstrument[];
|
|
119
|
+
}
|
|
120
|
+
export interface CheckoutMessage {
|
|
121
|
+
type: 'error' | 'warning' | 'info';
|
|
122
|
+
code: string;
|
|
123
|
+
path?: string;
|
|
124
|
+
content: string;
|
|
125
|
+
severity: 'recoverable' | 'requires_buyer_input' | 'requires_buyer_review';
|
|
126
|
+
}
|
|
127
|
+
export interface OrderConfirmation {
|
|
128
|
+
id: string;
|
|
129
|
+
permalink_url?: string;
|
|
130
|
+
}
|
|
131
|
+
export interface CheckoutSession {
|
|
132
|
+
ucp: {
|
|
133
|
+
version: string;
|
|
134
|
+
capabilities: Record<string, {
|
|
135
|
+
version: string;
|
|
136
|
+
}[]>;
|
|
137
|
+
payment_handlers?: Record<string, {
|
|
138
|
+
id: string;
|
|
139
|
+
version: string;
|
|
140
|
+
config?: Record<string, unknown>;
|
|
141
|
+
}[]>;
|
|
142
|
+
};
|
|
143
|
+
id: string;
|
|
144
|
+
status: CheckoutStatus;
|
|
145
|
+
messages?: CheckoutMessage[];
|
|
146
|
+
currency: string;
|
|
147
|
+
buyer?: Buyer;
|
|
148
|
+
line_items: LineItem[];
|
|
149
|
+
totals: {
|
|
150
|
+
type: string;
|
|
151
|
+
amount: number;
|
|
152
|
+
}[];
|
|
153
|
+
links: {
|
|
154
|
+
type: string;
|
|
155
|
+
url: string;
|
|
156
|
+
title?: string;
|
|
157
|
+
}[];
|
|
158
|
+
fulfillment?: Fulfillment;
|
|
159
|
+
payment?: Payment;
|
|
160
|
+
continue_url?: string;
|
|
161
|
+
expires_at?: string;
|
|
162
|
+
order?: OrderConfirmation;
|
|
163
|
+
}
|
|
164
|
+
export interface Order {
|
|
165
|
+
ucp: {
|
|
166
|
+
version: string;
|
|
167
|
+
capabilities: Record<string, {
|
|
168
|
+
version: string;
|
|
169
|
+
}[]>;
|
|
170
|
+
};
|
|
171
|
+
id: string;
|
|
172
|
+
checkout_id: string;
|
|
173
|
+
permalink_url?: string;
|
|
174
|
+
line_items: LineItem[];
|
|
175
|
+
buyer?: Buyer;
|
|
176
|
+
totals: {
|
|
177
|
+
type: string;
|
|
178
|
+
amount: number;
|
|
179
|
+
}[];
|
|
180
|
+
fulfillment?: {
|
|
181
|
+
expectations: {
|
|
182
|
+
id: string;
|
|
183
|
+
line_items: {
|
|
184
|
+
id: string;
|
|
185
|
+
quantity: number;
|
|
186
|
+
}[];
|
|
187
|
+
method_type: string;
|
|
188
|
+
destination?: Address;
|
|
189
|
+
description?: string;
|
|
190
|
+
fulfillable_on?: string;
|
|
191
|
+
}[];
|
|
192
|
+
events: {
|
|
193
|
+
id: string;
|
|
194
|
+
occurred_at: string;
|
|
195
|
+
type: string;
|
|
196
|
+
line_items: {
|
|
197
|
+
id: string;
|
|
198
|
+
quantity: number;
|
|
199
|
+
}[];
|
|
200
|
+
tracking_number?: string;
|
|
201
|
+
tracking_url?: string;
|
|
202
|
+
description?: string;
|
|
203
|
+
}[];
|
|
204
|
+
};
|
|
205
|
+
created_at: string;
|
|
206
|
+
}
|
|
207
|
+
export declare const CreateCheckoutRequestSchema: z.ZodObject<{
|
|
208
|
+
line_items: z.ZodArray<z.ZodObject<{
|
|
209
|
+
id: z.ZodOptional<z.ZodString>;
|
|
210
|
+
item: z.ZodObject<{
|
|
211
|
+
id: z.ZodString;
|
|
212
|
+
title: z.ZodOptional<z.ZodString>;
|
|
213
|
+
price: z.ZodOptional<z.ZodNumber>;
|
|
214
|
+
}, z.core.$strip>;
|
|
215
|
+
quantity: z.ZodNumber;
|
|
216
|
+
}, z.core.$strip>>;
|
|
217
|
+
buyer: z.ZodOptional<z.ZodObject<{
|
|
218
|
+
email: z.ZodOptional<z.ZodString>;
|
|
219
|
+
first_name: z.ZodOptional<z.ZodString>;
|
|
220
|
+
last_name: z.ZodOptional<z.ZodString>;
|
|
221
|
+
phone: z.ZodOptional<z.ZodString>;
|
|
222
|
+
}, z.core.$strip>>;
|
|
223
|
+
fulfillment: z.ZodOptional<z.ZodObject<{
|
|
224
|
+
methods: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
225
|
+
id: z.ZodOptional<z.ZodString>;
|
|
226
|
+
type: z.ZodEnum<{
|
|
227
|
+
shipping: "shipping";
|
|
228
|
+
pickup: "pickup";
|
|
229
|
+
digital: "digital";
|
|
230
|
+
}>;
|
|
231
|
+
line_item_ids: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
232
|
+
selected_destination_id: z.ZodOptional<z.ZodString>;
|
|
233
|
+
destinations: z.ZodArray<z.ZodObject<{
|
|
234
|
+
id: z.ZodOptional<z.ZodString>;
|
|
235
|
+
first_name: z.ZodOptional<z.ZodString>;
|
|
236
|
+
last_name: z.ZodOptional<z.ZodString>;
|
|
237
|
+
street_address: z.ZodString;
|
|
238
|
+
address_locality: z.ZodString;
|
|
239
|
+
address_region: z.ZodString;
|
|
240
|
+
postal_code: z.ZodString;
|
|
241
|
+
address_country: z.ZodString;
|
|
242
|
+
}, z.core.$strip>>;
|
|
243
|
+
groups: z.ZodOptional<z.ZodArray<z.ZodAny>>;
|
|
244
|
+
}, z.core.$strip>>>;
|
|
245
|
+
}, z.core.$strip>>;
|
|
246
|
+
}, z.core.$strip>;
|
|
247
|
+
export declare const UpdateCheckoutRequestSchema: z.ZodObject<{
|
|
248
|
+
buyer: z.ZodOptional<z.ZodObject<{
|
|
249
|
+
email: z.ZodOptional<z.ZodString>;
|
|
250
|
+
first_name: z.ZodOptional<z.ZodString>;
|
|
251
|
+
last_name: z.ZodOptional<z.ZodString>;
|
|
252
|
+
phone: z.ZodOptional<z.ZodString>;
|
|
253
|
+
}, z.core.$strip>>;
|
|
254
|
+
line_items: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
255
|
+
id: z.ZodOptional<z.ZodString>;
|
|
256
|
+
item: z.ZodObject<{
|
|
257
|
+
id: z.ZodString;
|
|
258
|
+
title: z.ZodOptional<z.ZodString>;
|
|
259
|
+
price: z.ZodOptional<z.ZodNumber>;
|
|
260
|
+
}, z.core.$strip>;
|
|
261
|
+
quantity: z.ZodNumber;
|
|
262
|
+
}, z.core.$strip>>>;
|
|
263
|
+
fulfillment: z.ZodOptional<z.ZodAny>;
|
|
264
|
+
}, z.core.$strip>;
|
|
265
|
+
export type CreateCheckoutRequest = z.infer<typeof CreateCheckoutRequestSchema>;
|
|
266
|
+
export type UpdateCheckoutRequest = z.infer<typeof UpdateCheckoutRequestSchema>;
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UpdateCheckoutRequestSchema = exports.CreateCheckoutRequestSchema = exports.MerchantConfigSchema = exports.PaymentHandlerSchema = exports.ShippingOptionSchema = exports.ItemSchema = exports.UCP_VERSION = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
// UCP Version
|
|
6
|
+
exports.UCP_VERSION = '2026-01-11';
|
|
7
|
+
// Product/Item Schema
|
|
8
|
+
exports.ItemSchema = zod_1.z.object({
|
|
9
|
+
id: zod_1.z.string(),
|
|
10
|
+
title: zod_1.z.string(),
|
|
11
|
+
description: zod_1.z.string().optional(),
|
|
12
|
+
price: zod_1.z.number().int().min(0), // Minor units (cents)
|
|
13
|
+
image_url: zod_1.z.string().url().optional(),
|
|
14
|
+
sku: zod_1.z.string().optional(),
|
|
15
|
+
stock: zod_1.z.number().int().min(0).optional(), // Inventory tracking
|
|
16
|
+
});
|
|
17
|
+
// Shipping Option Schema
|
|
18
|
+
exports.ShippingOptionSchema = zod_1.z.object({
|
|
19
|
+
id: zod_1.z.string(),
|
|
20
|
+
title: zod_1.z.string(),
|
|
21
|
+
description: zod_1.z.string().optional(),
|
|
22
|
+
price: zod_1.z.number().int().min(0), // Minor units
|
|
23
|
+
estimated_days: zod_1.z.string().optional(),
|
|
24
|
+
});
|
|
25
|
+
// Payment Handler Schema
|
|
26
|
+
exports.PaymentHandlerSchema = zod_1.z.object({
|
|
27
|
+
namespace: zod_1.z.string(), // e.g., "com.stripe", "com.google.pay"
|
|
28
|
+
id: zod_1.z.string(),
|
|
29
|
+
config: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).optional(),
|
|
30
|
+
});
|
|
31
|
+
// Merchant Configuration Schema
|
|
32
|
+
exports.MerchantConfigSchema = zod_1.z.object({
|
|
33
|
+
name: zod_1.z.string(),
|
|
34
|
+
domain: zod_1.z.string().url(),
|
|
35
|
+
currency: zod_1.z.string().default('USD'),
|
|
36
|
+
terms_url: zod_1.z.string().url().optional(),
|
|
37
|
+
privacy_url: zod_1.z.string().url().optional(),
|
|
38
|
+
items: zod_1.z.array(exports.ItemSchema),
|
|
39
|
+
shipping_options: zod_1.z.array(exports.ShippingOptionSchema).default([]),
|
|
40
|
+
payment_handlers: zod_1.z.array(exports.PaymentHandlerSchema).default([]),
|
|
41
|
+
tax_rate: zod_1.z.number().min(0).max(1).default(0), // e.g., 0.08 for 8%
|
|
42
|
+
port: zod_1.z.number().default(3000),
|
|
43
|
+
});
|
|
44
|
+
// Request validation schemas
|
|
45
|
+
exports.CreateCheckoutRequestSchema = zod_1.z.object({
|
|
46
|
+
line_items: zod_1.z.array(zod_1.z.object({
|
|
47
|
+
id: zod_1.z.string().optional(),
|
|
48
|
+
item: zod_1.z.object({
|
|
49
|
+
id: zod_1.z.string(),
|
|
50
|
+
title: zod_1.z.string().optional(),
|
|
51
|
+
price: zod_1.z.number().int().min(0).optional(),
|
|
52
|
+
}),
|
|
53
|
+
quantity: zod_1.z.number().int().min(1).max(100),
|
|
54
|
+
})).min(1).max(50),
|
|
55
|
+
buyer: zod_1.z.object({
|
|
56
|
+
email: zod_1.z.string().email().optional(),
|
|
57
|
+
first_name: zod_1.z.string().max(100).optional(),
|
|
58
|
+
last_name: zod_1.z.string().max(100).optional(),
|
|
59
|
+
phone: zod_1.z.string().max(30).optional(),
|
|
60
|
+
}).optional(),
|
|
61
|
+
fulfillment: zod_1.z.object({
|
|
62
|
+
methods: zod_1.z.array(zod_1.z.object({
|
|
63
|
+
id: zod_1.z.string().optional(),
|
|
64
|
+
type: zod_1.z.enum(['shipping', 'pickup', 'digital']),
|
|
65
|
+
line_item_ids: zod_1.z.array(zod_1.z.string()).optional(),
|
|
66
|
+
selected_destination_id: zod_1.z.string().optional(),
|
|
67
|
+
destinations: zod_1.z.array(zod_1.z.object({
|
|
68
|
+
id: zod_1.z.string().optional(),
|
|
69
|
+
first_name: zod_1.z.string().max(100).optional(),
|
|
70
|
+
last_name: zod_1.z.string().max(100).optional(),
|
|
71
|
+
street_address: zod_1.z.string().max(200),
|
|
72
|
+
address_locality: zod_1.z.string().max(100),
|
|
73
|
+
address_region: zod_1.z.string().max(100),
|
|
74
|
+
postal_code: zod_1.z.string().max(20),
|
|
75
|
+
address_country: zod_1.z.string().length(2),
|
|
76
|
+
})),
|
|
77
|
+
groups: zod_1.z.array(zod_1.z.any()).optional(),
|
|
78
|
+
})).optional(),
|
|
79
|
+
}).optional(),
|
|
80
|
+
});
|
|
81
|
+
exports.UpdateCheckoutRequestSchema = zod_1.z.object({
|
|
82
|
+
buyer: zod_1.z.object({
|
|
83
|
+
email: zod_1.z.string().email().optional(),
|
|
84
|
+
first_name: zod_1.z.string().max(100).optional(),
|
|
85
|
+
last_name: zod_1.z.string().max(100).optional(),
|
|
86
|
+
phone: zod_1.z.string().max(30).optional(),
|
|
87
|
+
}).optional(),
|
|
88
|
+
line_items: zod_1.z.array(zod_1.z.object({
|
|
89
|
+
id: zod_1.z.string().optional(),
|
|
90
|
+
item: zod_1.z.object({
|
|
91
|
+
id: zod_1.z.string(),
|
|
92
|
+
title: zod_1.z.string().optional(),
|
|
93
|
+
price: zod_1.z.number().int().min(0).optional(),
|
|
94
|
+
}),
|
|
95
|
+
quantity: zod_1.z.number().int().min(1).max(100),
|
|
96
|
+
})).optional(),
|
|
97
|
+
fulfillment: zod_1.z.any().optional(),
|
|
98
|
+
});
|
package/dist/stripe.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import Stripe from 'stripe';
|
|
2
|
+
export declare function getStripe(): Stripe | null;
|
|
3
|
+
export declare function isStripeConfigured(): boolean;
|
|
4
|
+
export interface CreatePaymentIntentParams {
|
|
5
|
+
amount: number;
|
|
6
|
+
currency: string;
|
|
7
|
+
checkoutId: string;
|
|
8
|
+
customerEmail?: string;
|
|
9
|
+
metadata?: Record<string, string>;
|
|
10
|
+
}
|
|
11
|
+
export declare function createPaymentIntent(params: CreatePaymentIntentParams): Promise<Stripe.PaymentIntent | null>;
|
|
12
|
+
export declare function confirmPaymentIntent(paymentIntentId: string): Promise<Stripe.PaymentIntent | null>;
|
|
13
|
+
export declare function cancelPaymentIntent(paymentIntentId: string): Promise<Stripe.PaymentIntent | null>;
|
|
14
|
+
export declare function constructWebhookEvent(payload: string | Buffer, signature: string): Stripe.Event | null;
|
package/dist/stripe.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
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.getStripe = getStripe;
|
|
7
|
+
exports.isStripeConfigured = isStripeConfigured;
|
|
8
|
+
exports.createPaymentIntent = createPaymentIntent;
|
|
9
|
+
exports.confirmPaymentIntent = confirmPaymentIntent;
|
|
10
|
+
exports.cancelPaymentIntent = cancelPaymentIntent;
|
|
11
|
+
exports.constructWebhookEvent = constructWebhookEvent;
|
|
12
|
+
const stripe_1 = __importDefault(require("stripe"));
|
|
13
|
+
const config_1 = require("./config");
|
|
14
|
+
const logger_1 = require("./logger");
|
|
15
|
+
let stripeClient = null;
|
|
16
|
+
function getStripe() {
|
|
17
|
+
if (!config_1.config.stripeSecretKey) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
if (!stripeClient) {
|
|
21
|
+
stripeClient = new stripe_1.default(config_1.config.stripeSecretKey, {
|
|
22
|
+
apiVersion: '2026-01-28.clover',
|
|
23
|
+
});
|
|
24
|
+
logger_1.logger.info('Stripe client initialized');
|
|
25
|
+
}
|
|
26
|
+
return stripeClient;
|
|
27
|
+
}
|
|
28
|
+
function isStripeConfigured() {
|
|
29
|
+
return !!config_1.config.stripeSecretKey;
|
|
30
|
+
}
|
|
31
|
+
async function createPaymentIntent(params) {
|
|
32
|
+
const stripe = getStripe();
|
|
33
|
+
if (!stripe) {
|
|
34
|
+
logger_1.logger.warn('Stripe not configured, skipping payment intent creation');
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
const paymentIntent = await stripe.paymentIntents.create({
|
|
39
|
+
amount: params.amount,
|
|
40
|
+
currency: params.currency.toLowerCase(),
|
|
41
|
+
metadata: {
|
|
42
|
+
checkout_id: params.checkoutId,
|
|
43
|
+
...params.metadata,
|
|
44
|
+
},
|
|
45
|
+
receipt_email: params.customerEmail,
|
|
46
|
+
automatic_payment_methods: {
|
|
47
|
+
enabled: true,
|
|
48
|
+
},
|
|
49
|
+
}, {
|
|
50
|
+
idempotencyKey: `checkout_${params.checkoutId}`,
|
|
51
|
+
});
|
|
52
|
+
logger_1.logger.info({
|
|
53
|
+
paymentIntentId: paymentIntent.id,
|
|
54
|
+
checkoutId: params.checkoutId,
|
|
55
|
+
amount: params.amount,
|
|
56
|
+
}, 'Payment intent created');
|
|
57
|
+
return paymentIntent;
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
logger_1.logger.error({ error, checkoutId: params.checkoutId }, 'Failed to create payment intent');
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async function confirmPaymentIntent(paymentIntentId) {
|
|
65
|
+
const stripe = getStripe();
|
|
66
|
+
if (!stripe)
|
|
67
|
+
return null;
|
|
68
|
+
try {
|
|
69
|
+
const paymentIntent = await stripe.paymentIntents.retrieve(paymentIntentId);
|
|
70
|
+
logger_1.logger.info({ paymentIntentId, status: paymentIntent.status }, 'Payment intent retrieved');
|
|
71
|
+
return paymentIntent;
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
logger_1.logger.error({ error, paymentIntentId }, 'Failed to retrieve payment intent');
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async function cancelPaymentIntent(paymentIntentId) {
|
|
79
|
+
const stripe = getStripe();
|
|
80
|
+
if (!stripe)
|
|
81
|
+
return null;
|
|
82
|
+
try {
|
|
83
|
+
const paymentIntent = await stripe.paymentIntents.cancel(paymentIntentId);
|
|
84
|
+
logger_1.logger.info({ paymentIntentId }, 'Payment intent canceled');
|
|
85
|
+
return paymentIntent;
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
logger_1.logger.error({ error, paymentIntentId }, 'Failed to cancel payment intent');
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function constructWebhookEvent(payload, signature) {
|
|
93
|
+
const stripe = getStripe();
|
|
94
|
+
if (!stripe || !config_1.config.stripeWebhookSecret)
|
|
95
|
+
return null;
|
|
96
|
+
try {
|
|
97
|
+
return stripe.webhooks.constructEvent(payload, signature, config_1.config.stripeWebhookSecret);
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
logger_1.logger.error({ error }, 'Webhook signature verification failed');
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { MerchantConfig, CheckoutSession, Order, Buyer, Fulfillment } from './schema';
|
|
2
|
+
export declare class UCPServerDB {
|
|
3
|
+
private config;
|
|
4
|
+
private itemsMap;
|
|
5
|
+
constructor(config: MerchantConfig);
|
|
6
|
+
getProfile(): {
|
|
7
|
+
ucp: {
|
|
8
|
+
version: string;
|
|
9
|
+
services: {
|
|
10
|
+
'dev.ucp.shopping': {
|
|
11
|
+
version: string;
|
|
12
|
+
spec: string;
|
|
13
|
+
transport: string;
|
|
14
|
+
endpoint: string;
|
|
15
|
+
schema: string;
|
|
16
|
+
}[];
|
|
17
|
+
};
|
|
18
|
+
capabilities: {
|
|
19
|
+
'dev.ucp.shopping.checkout': {
|
|
20
|
+
version: string;
|
|
21
|
+
spec: string;
|
|
22
|
+
schema: string;
|
|
23
|
+
}[];
|
|
24
|
+
'dev.ucp.shopping.fulfillment': {
|
|
25
|
+
version: string;
|
|
26
|
+
spec: string;
|
|
27
|
+
schema: string;
|
|
28
|
+
extends: string;
|
|
29
|
+
}[];
|
|
30
|
+
'dev.ucp.shopping.order': {
|
|
31
|
+
version: string;
|
|
32
|
+
spec: string;
|
|
33
|
+
schema: string;
|
|
34
|
+
}[];
|
|
35
|
+
};
|
|
36
|
+
payment_handlers: Record<string, {
|
|
37
|
+
id: string;
|
|
38
|
+
version: string;
|
|
39
|
+
config?: Record<string, unknown>;
|
|
40
|
+
}[]>;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
private buildLinks;
|
|
44
|
+
private buildPaymentHandlers;
|
|
45
|
+
private validateCheckout;
|
|
46
|
+
private calculateTotals;
|
|
47
|
+
private sessionFromRow;
|
|
48
|
+
createCheckout(data: {
|
|
49
|
+
line_items: {
|
|
50
|
+
id?: string;
|
|
51
|
+
item: {
|
|
52
|
+
id: string;
|
|
53
|
+
title?: string;
|
|
54
|
+
price?: number;
|
|
55
|
+
};
|
|
56
|
+
quantity: number;
|
|
57
|
+
}[];
|
|
58
|
+
}): CheckoutSession;
|
|
59
|
+
getCheckout(id: string): CheckoutSession | undefined;
|
|
60
|
+
updateCheckout(id: string, data: {
|
|
61
|
+
buyer?: Buyer;
|
|
62
|
+
line_items?: any[];
|
|
63
|
+
fulfillment?: Fulfillment;
|
|
64
|
+
}): CheckoutSession | undefined;
|
|
65
|
+
completeCheckout(id: string): Promise<CheckoutSession | {
|
|
66
|
+
error: string;
|
|
67
|
+
}>;
|
|
68
|
+
cancelCheckout(id: string): CheckoutSession | undefined;
|
|
69
|
+
getOrder(id: string): Order | undefined;
|
|
70
|
+
listOrders(): Order[];
|
|
71
|
+
getConfig(): MerchantConfig;
|
|
72
|
+
}
|