@youidian/sdk 3.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.
@@ -0,0 +1,385 @@
1
+ /**
2
+ * Youidian Payment SDK - Server Module
3
+ * 用于服务端集成,包含签名、订单创建、回调解密等功能
4
+ */
5
+ /**
6
+ * Order status response
7
+ */
8
+ interface OrderStatus {
9
+ orderId: string;
10
+ status: "PENDING" | "PAID" | "CANCELLED" | "REFUNDED" | "FAILED";
11
+ paidAt?: string;
12
+ channelTransactionId?: string;
13
+ }
14
+ /**
15
+ * Order details response (full order information)
16
+ */
17
+ interface OrderDetails {
18
+ orderId: string;
19
+ internalId: string;
20
+ status: "PENDING" | "PAID" | "CANCELLED" | "REFUNDED" | "FAILED";
21
+ amount: number;
22
+ currency: string;
23
+ description?: string;
24
+ paidAt?: string;
25
+ createdAt: string;
26
+ channel?: string;
27
+ product?: {
28
+ code: string;
29
+ type: string;
30
+ name: string;
31
+ description?: string;
32
+ entitlements: ProductEntitlements;
33
+ metadata?: ProductMetadata | null;
34
+ };
35
+ }
36
+ /**
37
+ * Product Entitlements
38
+ */
39
+ interface ProductEntitlements {
40
+ [key: string]: any;
41
+ }
42
+ /**
43
+ * Product Price
44
+ */
45
+ interface ProductPrice {
46
+ id: string;
47
+ currency: string;
48
+ amount: number;
49
+ displayAmount: string;
50
+ locale: string | null;
51
+ isDefault: boolean;
52
+ }
53
+ interface ProductSubscriptionPeriod {
54
+ value: number;
55
+ unit: "days" | "months" | "years";
56
+ }
57
+ interface ProductResetRule {
58
+ resetInterval: "month";
59
+ }
60
+ interface ProductMetadata {
61
+ subscriptionPeriod?: ProductSubscriptionPeriod;
62
+ expiringEntitlements?: string[];
63
+ resetEntitlements?: Record<string, ProductResetRule>;
64
+ autoAssignOnNewUser?: boolean;
65
+ trialDurationDays?: number;
66
+ }
67
+ /**
68
+ * Product Data
69
+ */
70
+ interface Product {
71
+ id: string;
72
+ code: string;
73
+ type: string;
74
+ name: string;
75
+ description?: string;
76
+ entitlements: ProductEntitlements;
77
+ prices: ProductPrice[];
78
+ metadata?: ProductMetadata | null;
79
+ }
80
+ /**
81
+ * WeChat JSAPI Payment Parameters (for wx.requestPayment)
82
+ */
83
+ interface WechatJsapiPayParams {
84
+ appId: string;
85
+ timeStamp: string;
86
+ nonceStr: string;
87
+ package: string;
88
+ signType: "RSA";
89
+ paySign: string;
90
+ }
91
+ /**
92
+ * Verified hosted login token payload.
93
+ */
94
+ interface VerifiedLoginToken {
95
+ appId: string;
96
+ userId: string;
97
+ legacyCasdoorId?: string | null;
98
+ channel: string;
99
+ email?: string | null;
100
+ name?: string | null;
101
+ avatar?: string | null;
102
+ wechatOpenId?: string | null;
103
+ wechatUnionId?: string | null;
104
+ expiresAt: string;
105
+ }
106
+ /**
107
+ * SDK Client Options
108
+ */
109
+ interface PaymentClientOptions {
110
+ /** Application ID (Required) */
111
+ appId: string;
112
+ /** Application Secret (Required for server-side operations) */
113
+ appSecret: string;
114
+ /**
115
+ * @deprecated Use apiUrl and checkoutUrl instead
116
+ * API Base URL (e.g. https://pay.youidian.com)
117
+ * If apiUrl or checkoutUrl is not provided, this will be used as fallback
118
+ * Default: https://pay.imgto.link
119
+ */
120
+ baseUrl?: string;
121
+ /**
122
+ * API server URL for backend requests (e.g. https://api.youidian.com)
123
+ * Default: https://pay-api.imgto.link
124
+ */
125
+ apiUrl?: string;
126
+ /**
127
+ * Checkout page URL for client-side payment (e.g. https://pay.youidian.com)
128
+ * Default: https://pay.imgto.link
129
+ */
130
+ checkoutUrl?: string;
131
+ }
132
+ /**
133
+ * Create Order Parameters
134
+ */
135
+ interface CreateOrderParams {
136
+ productId?: string;
137
+ priceId?: string;
138
+ channel?: string;
139
+ userId: string;
140
+ returnUrl?: string;
141
+ metadata?: Record<string, any>;
142
+ merchantOrderId?: string;
143
+ openid?: string;
144
+ locale?: string;
145
+ }
146
+ /**
147
+ * Create WeChat Mini Program Order Parameters
148
+ */
149
+ type CreateMiniProgramOrderParams = {
150
+ userId: string;
151
+ openid: string;
152
+ merchantOrderId?: string;
153
+ priceId: string;
154
+ };
155
+ /**
156
+ * Create Order Response
157
+ */
158
+ interface CreateOrderResponse {
159
+ orderId: string;
160
+ internalId: string;
161
+ amount: number;
162
+ currency: string;
163
+ payParams: any;
164
+ }
165
+ /**
166
+ * Payment Callback Notification
167
+ */
168
+ interface PaymentNotification {
169
+ iv: string;
170
+ encryptedData: string;
171
+ authTag: string;
172
+ }
173
+ /**
174
+ * Decrypted Payment Callback Data
175
+ */
176
+ interface PaymentCallbackData {
177
+ orderId: string;
178
+ merchantOrderId?: string;
179
+ status: "PAID" | "CANCELLED" | "REFUNDED" | "FAILED";
180
+ amount: number;
181
+ currency: string;
182
+ paidAt: string;
183
+ channelTransactionId?: string;
184
+ metadata?: Record<string, any>;
185
+ }
186
+ /**
187
+ * Get Orders Parameters
188
+ */
189
+ interface GetOrdersParams {
190
+ page?: number;
191
+ pageSize?: number;
192
+ userId?: string;
193
+ status?: "PENDING" | "PAID" | "CANCELLED" | "REFUNDED" | "FAILED";
194
+ startDate?: string;
195
+ endDate?: string;
196
+ }
197
+ /**
198
+ * Order List Item
199
+ */
200
+ interface OrderListItem {
201
+ orderId: string;
202
+ internalId: string;
203
+ merchantUserId: string;
204
+ status: "PENDING" | "PAID" | "CANCELLED" | "REFUNDED" | "FAILED";
205
+ amount: number;
206
+ currency: string;
207
+ channel?: string;
208
+ paidAt?: string;
209
+ createdAt: string;
210
+ }
211
+ /**
212
+ * Get Orders Response
213
+ */
214
+ interface GetOrdersResponse {
215
+ orders: OrderListItem[];
216
+ pagination: {
217
+ total: number;
218
+ page: number;
219
+ pageSize: number;
220
+ totalPages: number;
221
+ };
222
+ }
223
+ /**
224
+ * Entitlement Detail Item
225
+ */
226
+ interface EntitlementDetailItem {
227
+ type: string;
228
+ current: number | boolean;
229
+ limit?: number;
230
+ expiresAt?: string | null;
231
+ resetInterval?: string | null;
232
+ nextResetAt?: string | null;
233
+ sourceKind?: string | null;
234
+ }
235
+ /**
236
+ * Entitlement Detail - returned by getEntitlementsDetail
237
+ */
238
+ type EntitlementDetail = Record<string, EntitlementDetailItem>;
239
+ /**
240
+ * Ensure User With Trial Response
241
+ */
242
+ interface EnsureUserWithTrialResponse {
243
+ isNew: boolean;
244
+ trialAssigned: boolean;
245
+ trialProductCode?: string;
246
+ entitlements: EntitlementDetail;
247
+ }
248
+ /**
249
+ * Server-side Payment Client
250
+ * 服务端支付客户端,用于创建订单、查询状态、解密回调
251
+ */
252
+ declare class PaymentClient {
253
+ private readonly appId;
254
+ private readonly appSecret;
255
+ private readonly apiUrl;
256
+ private readonly checkoutUrl;
257
+ constructor(options: PaymentClientOptions);
258
+ /**
259
+ * Generate SHA256 signature for the request
260
+ * Logic: SHA256(appId + appSecret + timestamp)
261
+ */
262
+ private generateSignature;
263
+ /**
264
+ * Internal request helper for Gateway API
265
+ */
266
+ private request;
267
+ /**
268
+ * Decrypts the callback notification payload using AES-256-GCM.
269
+ * @param notification - The encrypted notification from payment webhook
270
+ * @returns Decrypted payment callback data
271
+ */
272
+ decryptCallback(notification: PaymentNotification): PaymentCallbackData;
273
+ /**
274
+ * Fetch products for the configured app.
275
+ */
276
+ getProducts(options?: {
277
+ locale?: string;
278
+ currency?: string;
279
+ }): Promise<Product[]>;
280
+ /**
281
+ * Create a new order
282
+ * @param params - Order creation parameters
283
+ * @returns Order details with payment parameters
284
+ */
285
+ createOrder(params: CreateOrderParams): Promise<CreateOrderResponse>;
286
+ /**
287
+ * Create a WeChat Mini Program order (channel fixed to WECHAT_MINI)
288
+ * @param params - Mini program order parameters
289
+ * @returns Order details with payment parameters
290
+ */
291
+ createMiniProgramOrder(params: CreateMiniProgramOrderParams): Promise<CreateOrderResponse>;
292
+ /**
293
+ * Pay for an existing order
294
+ * @param orderId - The order ID to pay
295
+ * @param params - Payment parameters including channel
296
+ */
297
+ payOrder(orderId: string, params: {
298
+ channel: string;
299
+ returnUrl?: string;
300
+ openid?: string;
301
+ [key: string]: any;
302
+ }): Promise<CreateOrderResponse>;
303
+ /**
304
+ * Query order status
305
+ * @param orderId - The order ID to query
306
+ */
307
+ getOrderStatus(orderId: string): Promise<OrderStatus>;
308
+ /**
309
+ * Get order details (full order information)
310
+ * @param orderId - The order ID to query
311
+ */
312
+ getOrderDetails(orderId: string): Promise<OrderDetails>;
313
+ /**
314
+ * Get orders list with pagination
315
+ * @param params - Query parameters (pagination, filters)
316
+ * @returns Orders list and pagination info
317
+ */
318
+ getOrders(params?: GetOrdersParams): Promise<GetOrdersResponse>;
319
+ /**
320
+ * Get user entitlements in the legacy flat shape.
321
+ * @param userId - User ID
322
+ */
323
+ getEntitlements(userId: string): Promise<Record<string, any>>;
324
+ /**
325
+ * Get user entitlements with full details (type, expiry, reset config, source)
326
+ * @param userId - User ID
327
+ */
328
+ getEntitlementsDetail(userId: string): Promise<EntitlementDetail>;
329
+ /**
330
+ * Ensure user exists and auto-assign trial product if new user
331
+ * This should be called when user first logs in or registers
332
+ * @param userId - User ID
333
+ */
334
+ ensureUserWithTrial(userId: string): Promise<EnsureUserWithTrialResponse>;
335
+ /**
336
+ * Get a single entitlement value
337
+ * @param userId - User ID
338
+ * @param key - Entitlement key
339
+ */
340
+ getEntitlementValue(userId: string, key: string): Promise<any>;
341
+ /**
342
+ * Consume numeric entitlement
343
+ * @param userId - User ID
344
+ * @param key - Entitlement key
345
+ * @param amount - Amount to consume
346
+ */
347
+ consumeEntitlement(userId: string, key: string, amount: number, options?: {
348
+ idempotencyKey?: string;
349
+ metadata?: Record<string, any>;
350
+ }): Promise<{
351
+ balance: number;
352
+ }>;
353
+ /**
354
+ * Add numeric entitlement (e.g. refund)
355
+ * @param userId - User ID
356
+ * @param key - Entitlement key
357
+ * @param amount - Amount to add
358
+ */
359
+ addEntitlement(userId: string, key: string, amount: number): Promise<{
360
+ balance: number;
361
+ }>;
362
+ /**
363
+ * Toggle boolean entitlement
364
+ * @param userId - User ID
365
+ * @param key - Entitlement key
366
+ * @param enabled - Whether to enable
367
+ */
368
+ toggleEntitlement(userId: string, key: string, enabled: boolean): Promise<{
369
+ isEnabled: boolean;
370
+ }>;
371
+ /**
372
+ * Generate checkout URL for client-side payment
373
+ * @param productId - Product ID
374
+ * @param priceId - Price ID
375
+ * @returns Checkout page URL
376
+ */
377
+ getCheckoutUrl(productId: string, priceId: string): string;
378
+ /**
379
+ * Verify a hosted login token and return the normalized login profile.
380
+ * This request is signed with your app credentials and routed through the worker API.
381
+ */
382
+ verifyLoginToken(token: string): Promise<VerifiedLoginToken>;
383
+ }
384
+
385
+ export { type CreateMiniProgramOrderParams, type CreateOrderParams, type CreateOrderResponse, type EnsureUserWithTrialResponse, type EntitlementDetail, type EntitlementDetailItem, type GetOrdersParams, type GetOrdersResponse, type OrderDetails, type OrderListItem, type OrderStatus, type PaymentCallbackData, PaymentClient, type PaymentClientOptions, type PaymentNotification, type Product, type ProductEntitlements, type ProductMetadata, type ProductPrice, type ProductResetRule, type ProductSubscriptionPeriod, type VerifiedLoginToken, type WechatJsapiPayParams };
package/dist/server.js ADDED
@@ -0,0 +1,246 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+
5
+ // src/server.ts
6
+ import crypto from "crypto";
7
+ var PaymentClient = class {
8
+ // 用于生成 checkout URL
9
+ constructor(options) {
10
+ __publicField(this, "appId");
11
+ __publicField(this, "appSecret");
12
+ __publicField(this, "apiUrl");
13
+ // 用于 API 调用
14
+ __publicField(this, "checkoutUrl");
15
+ if (!options.appId) throw new Error("appId is required");
16
+ if (!options.appSecret) throw new Error("appSecret is required");
17
+ this.appId = options.appId;
18
+ this.appSecret = options.appSecret;
19
+ const apiUrl = options.apiUrl || options.baseUrl || "https://pay-api.imgto.link";
20
+ this.apiUrl = apiUrl.replace(/\/$/, "");
21
+ const checkoutUrl = options.checkoutUrl || options.baseUrl || "https://pay.imgto.link";
22
+ this.checkoutUrl = checkoutUrl.replace(/\/$/, "");
23
+ }
24
+ /**
25
+ * Generate SHA256 signature for the request
26
+ * Logic: SHA256(appId + appSecret + timestamp)
27
+ */
28
+ generateSignature(timestamp) {
29
+ const str = `${this.appId}${this.appSecret}${timestamp}`;
30
+ return crypto.createHash("sha256").update(str).digest("hex");
31
+ }
32
+ /**
33
+ * Internal request helper for Gateway API
34
+ */
35
+ async request(method, path, body) {
36
+ const timestamp = Date.now();
37
+ const signature = this.generateSignature(timestamp);
38
+ const url = `${this.apiUrl}/api/v1/gateway/${this.appId}${path}`;
39
+ const headers = {
40
+ "Content-Type": "application/json",
41
+ "X-Pay-Timestamp": timestamp.toString(),
42
+ "X-Pay-Sign": signature
43
+ };
44
+ const options = {
45
+ method,
46
+ headers,
47
+ body: body ? JSON.stringify(body) : void 0
48
+ };
49
+ const response = await fetch(url, options);
50
+ if (!response.ok) {
51
+ const errorText = await response.text();
52
+ throw new Error(`Payment SDK Error (${response.status}): ${errorText}`);
53
+ }
54
+ const json = await response.json();
55
+ if (json.error) {
56
+ throw new Error(`Payment API Error: ${json.error}`);
57
+ }
58
+ return json.data;
59
+ }
60
+ /**
61
+ * Decrypts the callback notification payload using AES-256-GCM.
62
+ * @param notification - The encrypted notification from payment webhook
63
+ * @returns Decrypted payment callback data
64
+ */
65
+ decryptCallback(notification) {
66
+ try {
67
+ const { iv, encryptedData, authTag } = notification;
68
+ const key = crypto.createHash("sha256").update(this.appSecret).digest();
69
+ const decipher = crypto.createDecipheriv(
70
+ "aes-256-gcm",
71
+ key,
72
+ Buffer.from(iv, "hex")
73
+ );
74
+ decipher.setAuthTag(Buffer.from(authTag, "hex"));
75
+ let decrypted = decipher.update(encryptedData, "hex", "utf8");
76
+ decrypted += decipher.final("utf8");
77
+ return JSON.parse(decrypted);
78
+ } catch (error) {
79
+ throw new Error(
80
+ "Failed to decrypt payment callback: Invalid secret or tampered data."
81
+ );
82
+ }
83
+ }
84
+ /**
85
+ * Fetch products for the configured app.
86
+ */
87
+ async getProducts(options) {
88
+ const params = new URLSearchParams();
89
+ if (options?.locale) params.append("locale", options.locale);
90
+ if (options?.currency) params.append("currency", options.currency);
91
+ const path = params.toString() ? `/products?${params.toString()}` : "/products";
92
+ return this.request("GET", path);
93
+ }
94
+ /**
95
+ * Create a new order
96
+ * @param params - Order creation parameters
97
+ * @returns Order details with payment parameters
98
+ */
99
+ async createOrder(params) {
100
+ return this.request("POST", "/orders", params);
101
+ }
102
+ /**
103
+ * Create a WeChat Mini Program order (channel fixed to WECHAT_MINI)
104
+ * @param params - Mini program order parameters
105
+ * @returns Order details with payment parameters
106
+ */
107
+ async createMiniProgramOrder(params) {
108
+ const { openid, ...rest } = params;
109
+ return this.request("POST", "/orders", {
110
+ ...rest,
111
+ channel: "WECHAT_MINI",
112
+ openid,
113
+ metadata: { openid }
114
+ });
115
+ }
116
+ /**
117
+ * Pay for an existing order
118
+ * @param orderId - The order ID to pay
119
+ * @param params - Payment parameters including channel
120
+ */
121
+ async payOrder(orderId, params) {
122
+ return this.request("POST", `/orders/${orderId}/pay`, params);
123
+ }
124
+ /**
125
+ * Query order status
126
+ * @param orderId - The order ID to query
127
+ */
128
+ async getOrderStatus(orderId) {
129
+ return this.request("GET", `/orders/${orderId}`);
130
+ }
131
+ /**
132
+ * Get order details (full order information)
133
+ * @param orderId - The order ID to query
134
+ */
135
+ async getOrderDetails(orderId) {
136
+ return this.request("GET", `/orders/${orderId}/details`);
137
+ }
138
+ /**
139
+ * Get orders list with pagination
140
+ * @param params - Query parameters (pagination, filters)
141
+ * @returns Orders list and pagination info
142
+ */
143
+ async getOrders(params) {
144
+ const queryParams = new URLSearchParams();
145
+ if (params?.page) queryParams.append("page", params.page.toString());
146
+ if (params?.pageSize)
147
+ queryParams.append("pageSize", params.pageSize.toString());
148
+ if (params?.userId) queryParams.append("userId", params.userId);
149
+ if (params?.status) queryParams.append("status", params.status);
150
+ if (params?.startDate) queryParams.append("startDate", params.startDate);
151
+ if (params?.endDate) queryParams.append("endDate", params.endDate);
152
+ const path = queryParams.toString() ? `/orders?${queryParams.toString()}` : "/orders";
153
+ return this.request("GET", path);
154
+ }
155
+ /**
156
+ * Get user entitlements in the legacy flat shape.
157
+ * @param userId - User ID
158
+ */
159
+ async getEntitlements(userId) {
160
+ return this.request("GET", `/users/${userId}/entitlements`);
161
+ }
162
+ /**
163
+ * Get user entitlements with full details (type, expiry, reset config, source)
164
+ * @param userId - User ID
165
+ */
166
+ async getEntitlementsDetail(userId) {
167
+ return this.request("GET", `/users/${userId}/entitlements/detail`);
168
+ }
169
+ /**
170
+ * Ensure user exists and auto-assign trial product if new user
171
+ * This should be called when user first logs in or registers
172
+ * @param userId - User ID
173
+ */
174
+ async ensureUserWithTrial(userId) {
175
+ return this.request("POST", `/users/${userId}/entitlements/bootstrap`, {});
176
+ }
177
+ /**
178
+ * Get a single entitlement value
179
+ * @param userId - User ID
180
+ * @param key - Entitlement key
181
+ */
182
+ async getEntitlementValue(userId, key) {
183
+ const entitlements = await this.getEntitlements(userId);
184
+ return entitlements[key] ?? null;
185
+ }
186
+ /**
187
+ * Consume numeric entitlement
188
+ * @param userId - User ID
189
+ * @param key - Entitlement key
190
+ * @param amount - Amount to consume
191
+ */
192
+ async consumeEntitlement(userId, key, amount, options) {
193
+ return this.request("POST", `/users/${userId}/entitlements/consume`, {
194
+ key,
195
+ amount,
196
+ ...options
197
+ });
198
+ }
199
+ /**
200
+ * Add numeric entitlement (e.g. refund)
201
+ * @param userId - User ID
202
+ * @param key - Entitlement key
203
+ * @param amount - Amount to add
204
+ */
205
+ async addEntitlement(userId, key, amount) {
206
+ return this.request("POST", `/users/${userId}/entitlements/add`, {
207
+ key,
208
+ amount
209
+ });
210
+ }
211
+ /**
212
+ * Toggle boolean entitlement
213
+ * @param userId - User ID
214
+ * @param key - Entitlement key
215
+ * @param enabled - Whether to enable
216
+ */
217
+ async toggleEntitlement(userId, key, enabled) {
218
+ return this.request("POST", `/users/${userId}/entitlements/toggle`, {
219
+ key,
220
+ enabled
221
+ });
222
+ }
223
+ /**
224
+ * Generate checkout URL for client-side payment
225
+ * @param productId - Product ID
226
+ * @param priceId - Price ID
227
+ * @returns Checkout page URL
228
+ */
229
+ getCheckoutUrl(productId, priceId) {
230
+ return `${this.checkoutUrl}/checkout/${this.appId}/${productId}/${priceId}`;
231
+ }
232
+ /**
233
+ * Verify a hosted login token and return the normalized login profile.
234
+ * This request is signed with your app credentials and routed through the worker API.
235
+ */
236
+ async verifyLoginToken(token) {
237
+ if (!token?.trim()) {
238
+ throw new Error("login token is required");
239
+ }
240
+ return this.request("POST", "/login/tokens/verify", { token: token.trim() });
241
+ }
242
+ };
243
+ export {
244
+ PaymentClient
245
+ };
246
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server.ts"],"sourcesContent":["/**\n * Youidian Payment SDK - Server Module\n * 用于服务端集成,包含签名、订单创建、回调解密等功能\n */\n\nimport crypto from \"crypto\"\n\n/**\n * Order status response\n */\nexport interface OrderStatus {\n\torderId: string\n\tstatus: \"PENDING\" | \"PAID\" | \"CANCELLED\" | \"REFUNDED\" | \"FAILED\"\n\tpaidAt?: string\n\tchannelTransactionId?: string\n}\n\n/**\n * Order details response (full order information)\n */\nexport interface OrderDetails {\n\torderId: string\n\tinternalId: string\n\tstatus: \"PENDING\" | \"PAID\" | \"CANCELLED\" | \"REFUNDED\" | \"FAILED\"\n\tamount: number\n\tcurrency: string\n\tdescription?: string\n\tpaidAt?: string\n\tcreatedAt: string\n\tchannel?: string\n\tproduct?: {\n\t\tcode: string\n\t\ttype: string\n\t\tname: string\n\t\tdescription?: string\n\t\tentitlements: ProductEntitlements\n\t\tmetadata?: ProductMetadata | null\n\t}\n}\n\n/**\n * Product Entitlements\n */\nexport interface ProductEntitlements {\n\t[key: string]: any\n}\n\n/**\n * Product Price\n */\nexport interface ProductPrice {\n\tid: string\n\tcurrency: string\n\tamount: number\n\tdisplayAmount: string\n\tlocale: string | null\n\tisDefault: boolean\n}\n\nexport interface ProductSubscriptionPeriod {\n\tvalue: number\n\tunit: \"days\" | \"months\" | \"years\"\n}\n\nexport interface ProductResetRule {\n\tresetInterval: \"month\"\n}\n\nexport interface ProductMetadata {\n\tsubscriptionPeriod?: ProductSubscriptionPeriod\n\texpiringEntitlements?: string[]\n\tresetEntitlements?: Record<string, ProductResetRule>\n\tautoAssignOnNewUser?: boolean\n\ttrialDurationDays?: number\n}\n\n/**\n * Product Data\n */\nexport interface Product {\n\tid: string\n\tcode: string\n\ttype: string\n\tname: string\n\tdescription?: string\n\tentitlements: ProductEntitlements\n\tprices: ProductPrice[]\n\tmetadata?: ProductMetadata | null\n}\n\n/**\n * WeChat JSAPI Payment Parameters (for wx.requestPayment)\n */\nexport interface WechatJsapiPayParams {\n\tappId: string\n\ttimeStamp: string\n\tnonceStr: string\n\tpackage: string\n\tsignType: \"RSA\"\n\tpaySign: string\n}\n\n/**\n * Verified hosted login token payload.\n */\nexport interface VerifiedLoginToken {\n\tappId: string\n\tuserId: string\n\tlegacyCasdoorId?: string | null\n\tchannel: string\n\temail?: string | null\n\tname?: string | null\n\tavatar?: string | null\n\twechatOpenId?: string | null\n\twechatUnionId?: string | null\n\texpiresAt: string\n}\n\n/**\n * SDK Client Options\n */\nexport interface PaymentClientOptions {\n\t/** Application ID (Required) */\n\tappId: string\n\t/** Application Secret (Required for server-side operations) */\n\tappSecret: string\n\n\t/**\n\t * @deprecated Use apiUrl and checkoutUrl instead\n\t * API Base URL (e.g. https://pay.youidian.com)\n\t * If apiUrl or checkoutUrl is not provided, this will be used as fallback\n\t * Default: https://pay.imgto.link\n\t */\n\tbaseUrl?: string\n\n\t/**\n\t * API server URL for backend requests (e.g. https://api.youidian.com)\n\t * Default: https://pay-api.imgto.link\n\t */\n\tapiUrl?: string\n\n\t/**\n\t * Checkout page URL for client-side payment (e.g. https://pay.youidian.com)\n\t * Default: https://pay.imgto.link\n\t */\n\tcheckoutUrl?: string\n}\n\n/**\n * Create Order Parameters\n */\nexport interface CreateOrderParams {\n\tproductId?: string\n\tpriceId?: string\n\tchannel?: string\n\tuserId: string\n\treturnUrl?: string\n\tmetadata?: Record<string, any>\n\tmerchantOrderId?: string\n\topenid?: string\n\tlocale?: string\n}\n\n/**\n * Create WeChat Mini Program Order Parameters\n */\nexport type CreateMiniProgramOrderParams = {\n\tuserId: string\n\topenid: string\n\tmerchantOrderId?: string\n\tpriceId: string\n}\n\n/**\n * Create Order Response\n */\nexport interface CreateOrderResponse {\n\torderId: string\n\tinternalId: string\n\tamount: number\n\tcurrency: string\n\tpayParams: any\n}\n\n/**\n * Payment Callback Notification\n */\nexport interface PaymentNotification {\n\tiv: string\n\tencryptedData: string\n\tauthTag: string\n}\n\n/**\n * Decrypted Payment Callback Data\n */\nexport interface PaymentCallbackData {\n\torderId: string\n\tmerchantOrderId?: string\n\tstatus: \"PAID\" | \"CANCELLED\" | \"REFUNDED\" | \"FAILED\"\n\tamount: number\n\tcurrency: string\n\tpaidAt: string\n\tchannelTransactionId?: string\n\tmetadata?: Record<string, any>\n}\n\n/**\n * Get Orders Parameters\n */\nexport interface GetOrdersParams {\n\tpage?: number\n\tpageSize?: number\n\tuserId?: string\n\tstatus?: \"PENDING\" | \"PAID\" | \"CANCELLED\" | \"REFUNDED\" | \"FAILED\"\n\tstartDate?: string\n\tendDate?: string\n}\n\n/**\n * Order List Item\n */\nexport interface OrderListItem {\n\torderId: string\n\tinternalId: string\n\tmerchantUserId: string\n\tstatus: \"PENDING\" | \"PAID\" | \"CANCELLED\" | \"REFUNDED\" | \"FAILED\"\n\tamount: number\n\tcurrency: string\n\tchannel?: string\n\tpaidAt?: string\n\tcreatedAt: string\n}\n\n/**\n * Get Orders Response\n */\nexport interface GetOrdersResponse {\n\torders: OrderListItem[]\n\tpagination: {\n\t\ttotal: number\n\t\tpage: number\n\t\tpageSize: number\n\t\ttotalPages: number\n\t}\n}\n\n/**\n * Entitlement Detail Item\n */\nexport interface EntitlementDetailItem {\n\ttype: string\n\tcurrent: number | boolean\n\tlimit?: number\n\texpiresAt?: string | null\n\tresetInterval?: string | null\n\tnextResetAt?: string | null\n\tsourceKind?: string | null\n}\n\n/**\n * Entitlement Detail - returned by getEntitlementsDetail\n */\nexport type EntitlementDetail = Record<string, EntitlementDetailItem>\n\n/**\n * Ensure User With Trial Response\n */\nexport interface EnsureUserWithTrialResponse {\n\tisNew: boolean\n\ttrialAssigned: boolean\n\ttrialProductCode?: string\n\tentitlements: EntitlementDetail\n}\n\n/**\n * Server-side Payment Client\n * 服务端支付客户端,用于创建订单、查询状态、解密回调\n */\nexport class PaymentClient {\n\tprivate readonly appId: string\n\tprivate readonly appSecret: string\n\tprivate readonly apiUrl: string // 用于 API 调用\n\tprivate readonly checkoutUrl: string // 用于生成 checkout URL\n\n\tconstructor(options: PaymentClientOptions) {\n\t\tif (!options.appId) throw new Error(\"appId is required\")\n\t\tif (!options.appSecret) throw new Error(\"appSecret is required\")\n\n\t\tthis.appId = options.appId\n\t\tthis.appSecret = options.appSecret\n\n\t\t// apiUrl: 优先使用 apiUrl,其次 baseUrl,默认 https://pay-api.imgto.link\n\t\tconst apiUrl =\n\t\t\toptions.apiUrl || options.baseUrl || \"https://pay-api.imgto.link\"\n\t\tthis.apiUrl = apiUrl.replace(/\\/$/, \"\") // Remove trailing slash\n\n\t\t// checkoutUrl: 优先使用 checkoutUrl,其次 baseUrl,默认 https://pay.imgto.link\n\t\tconst checkoutUrl =\n\t\t\toptions.checkoutUrl || options.baseUrl || \"https://pay.imgto.link\"\n\t\tthis.checkoutUrl = checkoutUrl.replace(/\\/$/, \"\") // Remove trailing slash\n\t}\n\n\t/**\n\t * Generate SHA256 signature for the request\n\t * Logic: SHA256(appId + appSecret + timestamp)\n\t */\n\tprivate generateSignature(timestamp: number): string {\n\t\tconst str = `${this.appId}${this.appSecret}${timestamp}`\n\t\treturn crypto.createHash(\"sha256\").update(str).digest(\"hex\")\n\t}\n\n\t/**\n\t * Internal request helper for Gateway API\n\t */\n\tprivate async request<T>(\n\t\tmethod: string,\n\t\tpath: string,\n\t\tbody?: any,\n\t): Promise<T> {\n\t\tconst timestamp = Date.now()\n\t\tconst signature = this.generateSignature(timestamp)\n\n\t\tconst url = `${this.apiUrl}/api/v1/gateway/${this.appId}${path}`\n\n\t\tconst headers: HeadersInit = {\n\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\"X-Pay-Timestamp\": timestamp.toString(),\n\t\t\t\"X-Pay-Sign\": signature,\n\t\t}\n\n\t\tconst options: RequestInit = {\n\t\t\tmethod,\n\t\t\theaders,\n\t\t\tbody: body ? JSON.stringify(body) : undefined,\n\t\t}\n\n\t\tconst response = await fetch(url, options)\n\n\t\tif (!response.ok) {\n\t\t\tconst errorText = await response.text()\n\t\t\tthrow new Error(`Payment SDK Error (${response.status}): ${errorText}`)\n\t\t}\n\n\t\tconst json = await response.json()\n\t\tif (json.error) {\n\t\t\tthrow new Error(`Payment API Error: ${json.error}`)\n\t\t}\n\n\t\treturn json.data as T\n\t}\n\n\t/**\n\t * Decrypts the callback notification payload using AES-256-GCM.\n\t * @param notification - The encrypted notification from payment webhook\n\t * @returns Decrypted payment callback data\n\t */\n\tdecryptCallback(notification: PaymentNotification): PaymentCallbackData {\n\t\ttry {\n\t\t\tconst { iv, encryptedData, authTag } = notification\n\t\t\tconst key = crypto.createHash(\"sha256\").update(this.appSecret).digest()\n\t\t\tconst decipher = crypto.createDecipheriv(\n\t\t\t\t\"aes-256-gcm\",\n\t\t\t\tkey,\n\t\t\t\tBuffer.from(iv, \"hex\"),\n\t\t\t)\n\n\t\t\tdecipher.setAuthTag(Buffer.from(authTag, \"hex\"))\n\n\t\t\tlet decrypted = decipher.update(encryptedData, \"hex\", \"utf8\")\n\t\t\tdecrypted += decipher.final(\"utf8\")\n\n\t\t\treturn JSON.parse(decrypted)\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Failed to decrypt payment callback: Invalid secret or tampered data.\",\n\t\t\t)\n\t\t}\n\t}\n\n\t/**\n\t * Fetch products for the configured app.\n\t */\n\tasync getProducts(options?: {\n\t\tlocale?: string\n\t\tcurrency?: string\n\t}): Promise<Product[]> {\n\t\tconst params = new URLSearchParams()\n\t\tif (options?.locale) params.append(\"locale\", options.locale)\n\t\tif (options?.currency) params.append(\"currency\", options.currency)\n\n\t\tconst path = params.toString()\n\t\t\t? `/products?${params.toString()}`\n\t\t\t: \"/products\"\n\t\treturn this.request(\"GET\", path)\n\t}\n\n\t/**\n\t * Create a new order\n\t * @param params - Order creation parameters\n\t * @returns Order details with payment parameters\n\t */\n\tasync createOrder(params: CreateOrderParams): Promise<CreateOrderResponse> {\n\t\treturn this.request(\"POST\", \"/orders\", params)\n\t}\n\n\t/**\n\t * Create a WeChat Mini Program order (channel fixed to WECHAT_MINI)\n\t * @param params - Mini program order parameters\n\t * @returns Order details with payment parameters\n\t */\n\tasync createMiniProgramOrder(\n\t\tparams: CreateMiniProgramOrderParams,\n\t): Promise<CreateOrderResponse> {\n\t\tconst { openid, ...rest } = params\n\t\treturn this.request(\"POST\", \"/orders\", {\n\t\t\t...rest,\n\t\t\tchannel: \"WECHAT_MINI\",\n\t\t\topenid,\n\t\t\tmetadata: { openid },\n\t\t} satisfies CreateOrderParams)\n\t}\n\n\t/**\n\t * Pay for an existing order\n\t * @param orderId - The order ID to pay\n\t * @param params - Payment parameters including channel\n\t */\n\tasync payOrder(\n\t\torderId: string,\n\t\tparams: {\n\t\t\tchannel: string\n\t\t\treturnUrl?: string\n\t\t\topenid?: string\n\t\t\t[key: string]: any\n\t\t},\n\t): Promise<CreateOrderResponse> {\n\t\treturn this.request(\"POST\", `/orders/${orderId}/pay`, params)\n\t}\n\n\t/**\n\t * Query order status\n\t * @param orderId - The order ID to query\n\t */\n\tasync getOrderStatus(orderId: string): Promise<OrderStatus> {\n\t\treturn this.request(\"GET\", `/orders/${orderId}`)\n\t}\n\n\t/**\n\t * Get order details (full order information)\n\t * @param orderId - The order ID to query\n\t */\n\tasync getOrderDetails(orderId: string): Promise<OrderDetails> {\n\t\treturn this.request(\"GET\", `/orders/${orderId}/details`)\n\t}\n\n\t/**\n\t * Get orders list with pagination\n\t * @param params - Query parameters (pagination, filters)\n\t * @returns Orders list and pagination info\n\t */\n\tasync getOrders(params?: GetOrdersParams): Promise<GetOrdersResponse> {\n\t\tconst queryParams = new URLSearchParams()\n\t\tif (params?.page) queryParams.append(\"page\", params.page.toString())\n\t\tif (params?.pageSize)\n\t\t\tqueryParams.append(\"pageSize\", params.pageSize.toString())\n\t\tif (params?.userId) queryParams.append(\"userId\", params.userId)\n\t\tif (params?.status) queryParams.append(\"status\", params.status)\n\t\tif (params?.startDate) queryParams.append(\"startDate\", params.startDate)\n\t\tif (params?.endDate) queryParams.append(\"endDate\", params.endDate)\n\n\t\tconst path = queryParams.toString()\n\t\t\t? `/orders?${queryParams.toString()}`\n\t\t\t: \"/orders\"\n\t\treturn this.request<GetOrdersResponse>(\"GET\", path)\n\t}\n\n\t/**\n\t * Get user entitlements in the legacy flat shape.\n\t * @param userId - User ID\n\t */\n\tasync getEntitlements(userId: string): Promise<Record<string, any>> {\n\t\treturn this.request(\"GET\", `/users/${userId}/entitlements`)\n\t}\n\n\t/**\n\t * Get user entitlements with full details (type, expiry, reset config, source)\n\t * @param userId - User ID\n\t */\n\tasync getEntitlementsDetail(userId: string): Promise<EntitlementDetail> {\n\t\treturn this.request(\"GET\", `/users/${userId}/entitlements/detail`)\n\t}\n\n\t/**\n\t * Ensure user exists and auto-assign trial product if new user\n\t * This should be called when user first logs in or registers\n\t * @param userId - User ID\n\t */\n\tasync ensureUserWithTrial(\n\t\tuserId: string,\n\t): Promise<EnsureUserWithTrialResponse> {\n\t\treturn this.request(\"POST\", `/users/${userId}/entitlements/bootstrap`, {})\n\t}\n\n\t/**\n\t * Get a single entitlement value\n\t * @param userId - User ID\n\t * @param key - Entitlement key\n\t */\n\tasync getEntitlementValue(userId: string, key: string): Promise<any> {\n\t\tconst entitlements = await this.getEntitlements(userId)\n\t\treturn entitlements[key] ?? null\n\t}\n\n\t/**\n\t * Consume numeric entitlement\n\t * @param userId - User ID\n\t * @param key - Entitlement key\n\t * @param amount - Amount to consume\n\t */\n\tasync consumeEntitlement(\n\t\tuserId: string,\n\t\tkey: string,\n\t\tamount: number,\n\t\toptions?: {\n\t\t\tidempotencyKey?: string\n\t\t\tmetadata?: Record<string, any>\n\t\t},\n\t): Promise<{ balance: number }> {\n\t\treturn this.request(\"POST\", `/users/${userId}/entitlements/consume`, {\n\t\t\tkey,\n\t\t\tamount,\n\t\t\t...options,\n\t\t})\n\t}\n\n\t/**\n\t * Add numeric entitlement (e.g. refund)\n\t * @param userId - User ID\n\t * @param key - Entitlement key\n\t * @param amount - Amount to add\n\t */\n\tasync addEntitlement(\n\t\tuserId: string,\n\t\tkey: string,\n\t\tamount: number,\n\t): Promise<{ balance: number }> {\n\t\treturn this.request(\"POST\", `/users/${userId}/entitlements/add`, {\n\t\t\tkey,\n\t\t\tamount,\n\t\t})\n\t}\n\n\t/**\n\t * Toggle boolean entitlement\n\t * @param userId - User ID\n\t * @param key - Entitlement key\n\t * @param enabled - Whether to enable\n\t */\n\tasync toggleEntitlement(\n\t\tuserId: string,\n\t\tkey: string,\n\t\tenabled: boolean,\n\t): Promise<{ isEnabled: boolean }> {\n\t\t// Toggle endpoint expects POST with enabled flag\n\t\t// However, looking at list_dir, we have toggle/route.ts\n\t\t// I should verify its contract, but assuming standard toggle pattern:\n\t\treturn this.request(\"POST\", `/users/${userId}/entitlements/toggle`, {\n\t\t\tkey,\n\t\t\tenabled,\n\t\t})\n\t}\n\n\t/**\n\t * Generate checkout URL for client-side payment\n\t * @param productId - Product ID\n\t * @param priceId - Price ID\n\t * @returns Checkout page URL\n\t */\n\tgetCheckoutUrl(productId: string, priceId: string): string {\n\t\treturn `${this.checkoutUrl}/checkout/${this.appId}/${productId}/${priceId}`\n\t}\n\n\t/**\n\t * Verify a hosted login token and return the normalized login profile.\n\t * This request is signed with your app credentials and routed through the worker API.\n\t */\n\tasync verifyLoginToken(token: string): Promise<VerifiedLoginToken> {\n\t\tif (!token?.trim()) {\n\t\t\tthrow new Error(\"login token is required\")\n\t\t}\n\t\treturn this.request(\"POST\", \"/login/tokens/verify\", { token: token.trim() })\n\t}\n}\n"],"mappings":"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","names":[]}