@youidian/sdk 3.3.6 → 3.3.10
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/dist/client.cjs +80 -8
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +12 -4
- package/dist/client.d.ts +12 -4
- package/dist/client.js +80 -8
- package/dist/client.js.map +1 -1
- package/dist/index.cjs +163 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +163 -8
- package/dist/index.js.map +1 -1
- package/dist/{login-C-fF3Bw1.d.cts → login-DerOcXcH.d.cts} +3 -2
- package/dist/{login-C-fF3Bw1.d.ts → login-DerOcXcH.d.ts} +3 -2
- package/dist/login.cjs +2 -2
- package/dist/login.cjs.map +1 -1
- package/dist/login.d.cts +1 -1
- package/dist/login.d.ts +1 -1
- package/dist/login.js +2 -2
- package/dist/login.js.map +1 -1
- package/dist/server.cjs +83 -0
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +97 -1
- package/dist/server.d.ts +97 -1
- package/dist/server.js +83 -0
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
package/dist/server.d.cts
CHANGED
|
@@ -24,6 +24,7 @@ interface OrderDetails {
|
|
|
24
24
|
paidAt?: string;
|
|
25
25
|
createdAt: string;
|
|
26
26
|
channel?: string;
|
|
27
|
+
merchantPricing?: MerchantPricingSnapshot;
|
|
27
28
|
pricingBreakdown?: PricingBreakdown;
|
|
28
29
|
upgrade?: {
|
|
29
30
|
isUpgrade: boolean;
|
|
@@ -87,6 +88,11 @@ interface ProductCustomAmount {
|
|
|
87
88
|
entitlementKey: string;
|
|
88
89
|
currencies: Record<string, ProductCustomAmountCurrency>;
|
|
89
90
|
}
|
|
91
|
+
interface ProductInventory {
|
|
92
|
+
enabled: boolean;
|
|
93
|
+
totalQuantity: number;
|
|
94
|
+
reserveTimeoutSeconds?: number;
|
|
95
|
+
}
|
|
90
96
|
interface ProductMetadata {
|
|
91
97
|
subscriptionPeriod?: ProductSubscriptionPeriod;
|
|
92
98
|
expiringEntitlements?: string[];
|
|
@@ -94,6 +100,28 @@ interface ProductMetadata {
|
|
|
94
100
|
autoAssignOnNewUser?: boolean;
|
|
95
101
|
trialDurationDays?: number;
|
|
96
102
|
customAmount?: ProductCustomAmount;
|
|
103
|
+
inventory?: ProductInventory;
|
|
104
|
+
}
|
|
105
|
+
type ProductStockLookupMode = "auto" | "id" | "code";
|
|
106
|
+
interface ProductStock {
|
|
107
|
+
productId: string;
|
|
108
|
+
productCode: string;
|
|
109
|
+
limited: boolean;
|
|
110
|
+
total: number | null;
|
|
111
|
+
reserved: number;
|
|
112
|
+
sold: number;
|
|
113
|
+
available: number | null;
|
|
114
|
+
updatedAt: string;
|
|
115
|
+
reserveTimeoutSeconds: number | null;
|
|
116
|
+
}
|
|
117
|
+
interface ProductStockQueryOptions {
|
|
118
|
+
lookupBy?: ProductStockLookupMode;
|
|
119
|
+
locale?: string;
|
|
120
|
+
currency?: string;
|
|
121
|
+
}
|
|
122
|
+
interface ProductStocksQueryParams {
|
|
123
|
+
productIds?: string[];
|
|
124
|
+
productCodes?: string[];
|
|
97
125
|
}
|
|
98
126
|
interface PricingBreakdown {
|
|
99
127
|
isUpgrade: boolean;
|
|
@@ -251,6 +279,28 @@ interface PaymentClientOptions {
|
|
|
251
279
|
*/
|
|
252
280
|
checkoutUrl?: string;
|
|
253
281
|
}
|
|
282
|
+
interface MerchantPricingBreakdownItem {
|
|
283
|
+
type: "coupon" | "promotion" | "membership" | "manual" | "other";
|
|
284
|
+
amount: number;
|
|
285
|
+
label?: string;
|
|
286
|
+
code?: string;
|
|
287
|
+
}
|
|
288
|
+
interface MerchantPricing {
|
|
289
|
+
amount: number;
|
|
290
|
+
currency: string;
|
|
291
|
+
originalAmount?: number;
|
|
292
|
+
discountAmount?: number;
|
|
293
|
+
discountReason?: string;
|
|
294
|
+
discountCode?: string;
|
|
295
|
+
breakdown?: MerchantPricingBreakdownItem[];
|
|
296
|
+
}
|
|
297
|
+
interface MerchantPricingSnapshot extends MerchantPricing {
|
|
298
|
+
originalAmount: number;
|
|
299
|
+
discountAmount: number;
|
|
300
|
+
priceId: string;
|
|
301
|
+
productId: string;
|
|
302
|
+
productCode: string;
|
|
303
|
+
}
|
|
254
304
|
/**
|
|
255
305
|
* Create Order Parameters
|
|
256
306
|
*/
|
|
@@ -269,7 +319,9 @@ interface CreateOrderParams {
|
|
|
269
319
|
amount: number;
|
|
270
320
|
currency: string;
|
|
271
321
|
};
|
|
322
|
+
merchantPricing?: MerchantPricing;
|
|
272
323
|
}
|
|
324
|
+
type CreateBankTransferOrderParams = Omit<CreateOrderParams, "channel">;
|
|
273
325
|
/**
|
|
274
326
|
* Create WeChat Mini Program Order Parameters
|
|
275
327
|
*/
|
|
@@ -289,6 +341,23 @@ interface CreateOrderResponse {
|
|
|
289
341
|
currency: string;
|
|
290
342
|
payParams: any;
|
|
291
343
|
pricingBreakdown?: PricingBreakdown;
|
|
344
|
+
status?: "PENDING" | "PAID" | "CANCELLED" | "REFUNDED" | "FAILED";
|
|
345
|
+
paidAt?: string | null;
|
|
346
|
+
channel?: string;
|
|
347
|
+
isSandbox?: boolean;
|
|
348
|
+
merchantPricing?: MerchantPricingSnapshot;
|
|
349
|
+
}
|
|
350
|
+
interface CancelOrderResponse {
|
|
351
|
+
cancelled: boolean;
|
|
352
|
+
status: "PENDING" | "PAID" | "CANCELLED" | "REFUNDED" | "FAILED";
|
|
353
|
+
orderId: string;
|
|
354
|
+
internalId?: string | null;
|
|
355
|
+
}
|
|
356
|
+
interface CompleteFreeOrderResponse {
|
|
357
|
+
completed: boolean;
|
|
358
|
+
status: "paid" | "pending" | "cancelled" | "refunded" | "failed" | "unknown";
|
|
359
|
+
orderId: string;
|
|
360
|
+
internalId?: string | null;
|
|
292
361
|
}
|
|
293
362
|
/**
|
|
294
363
|
* Payment Callback Notification
|
|
@@ -405,12 +474,27 @@ declare class PaymentClient {
|
|
|
405
474
|
locale?: string;
|
|
406
475
|
currency?: string;
|
|
407
476
|
}): Promise<Product[]>;
|
|
477
|
+
/**
|
|
478
|
+
* Fetch the realtime stock snapshot for a single product.
|
|
479
|
+
*/
|
|
480
|
+
getProductStock(productIdOrCode: string, options?: ProductStockQueryOptions): Promise<ProductStock>;
|
|
481
|
+
/**
|
|
482
|
+
* Fetch realtime stock snapshots for multiple products.
|
|
483
|
+
*/
|
|
484
|
+
getProductStocks(params: ProductStocksQueryParams, options?: ProductStockQueryOptions): Promise<ProductStock[]>;
|
|
485
|
+
getProductStocks(params: ProductStocksQueryParams & ProductStockQueryOptions): Promise<ProductStock[]>;
|
|
408
486
|
/**
|
|
409
487
|
* Create a new order
|
|
410
488
|
* @param params - Order creation parameters
|
|
411
489
|
* @returns Order details with payment parameters
|
|
412
490
|
*/
|
|
413
491
|
createOrder(params: CreateOrderParams): Promise<CreateOrderResponse>;
|
|
492
|
+
/**
|
|
493
|
+
* Create a paid manual bank transfer order.
|
|
494
|
+
* @param params - Order creation parameters without channel
|
|
495
|
+
* @returns Paid order details
|
|
496
|
+
*/
|
|
497
|
+
createBankTransferOrder(params: CreateBankTransferOrderParams): Promise<CreateOrderResponse>;
|
|
414
498
|
/**
|
|
415
499
|
* Create a WeChat Mini Program order (channel fixed to WECHAT_MINI)
|
|
416
500
|
* @param params - Mini program order parameters
|
|
@@ -428,6 +512,18 @@ declare class PaymentClient {
|
|
|
428
512
|
openid?: string;
|
|
429
513
|
[key: string]: any;
|
|
430
514
|
}): Promise<CreateOrderResponse>;
|
|
515
|
+
/**
|
|
516
|
+
* Cancel a pending order and release its inventory reservation.
|
|
517
|
+
* Paid/refunded/failed orders are returned unchanged by the gateway.
|
|
518
|
+
*/
|
|
519
|
+
cancelOrder(orderId: string, params?: {
|
|
520
|
+
reason?: string;
|
|
521
|
+
}): Promise<CancelOrderResponse>;
|
|
522
|
+
/**
|
|
523
|
+
* Complete a zero-amount FREE order.
|
|
524
|
+
* This marks the pending order as paid and triggers normal paid-order side effects.
|
|
525
|
+
*/
|
|
526
|
+
completeFreeOrder(orderId: string): Promise<CompleteFreeOrderResponse>;
|
|
431
527
|
/**
|
|
432
528
|
* Query order status
|
|
433
529
|
* @param orderId - The order ID to query
|
|
@@ -519,4 +615,4 @@ declare class PaymentClient {
|
|
|
519
615
|
bindPhoneNumber(params: BindPhoneNumberParams): Promise<BindPhoneNumberResponse>;
|
|
520
616
|
}
|
|
521
617
|
|
|
522
|
-
export { type ActiveSubscriptionInfo, type BindPhoneNumberParams, type BindPhoneNumberResponse, type CreateMiniProgramOrderParams, type CreateOrderParams, type CreateOrderResponse, type CustomAmountRechargeRule, type CustomAmountRechargeValidationResult, type EnsureUserWithTrialResponse, type EntitlementDetail, type EntitlementDetailItem, type GetOrdersParams, type GetOrdersResponse, type OrderDetails, type OrderListItem, type OrderStatus, type PaymentCallbackData, PaymentClient, type PaymentClientOptions, type PaymentNotification, type PricingBreakdown, type Product, type ProductCustomAmount, type ProductCustomAmountCurrency, type ProductEntitlements, type ProductMetadata, type ProductPrice, type ProductResetRule, type ProductSubscriptionPeriod, type SendPhoneVerificationCodeParams, type SendPhoneVerificationCodeResponse, type VerifiedLoginToken, type WechatJsapiPayParams, getCustomAmountRechargeRule, validateCustomAmountRecharge };
|
|
618
|
+
export { type ActiveSubscriptionInfo, type BindPhoneNumberParams, type BindPhoneNumberResponse, type CancelOrderResponse, type CompleteFreeOrderResponse, type CreateBankTransferOrderParams, type CreateMiniProgramOrderParams, type CreateOrderParams, type CreateOrderResponse, type CustomAmountRechargeRule, type CustomAmountRechargeValidationResult, type EnsureUserWithTrialResponse, type EntitlementDetail, type EntitlementDetailItem, type GetOrdersParams, type GetOrdersResponse, type MerchantPricing, type MerchantPricingBreakdownItem, type MerchantPricingSnapshot, type OrderDetails, type OrderListItem, type OrderStatus, type PaymentCallbackData, PaymentClient, type PaymentClientOptions, type PaymentNotification, type PricingBreakdown, type Product, type ProductCustomAmount, type ProductCustomAmountCurrency, type ProductEntitlements, type ProductInventory, type ProductMetadata, type ProductPrice, type ProductResetRule, type ProductStock, type ProductStockLookupMode, type ProductStockQueryOptions, type ProductStocksQueryParams, type ProductSubscriptionPeriod, type SendPhoneVerificationCodeParams, type SendPhoneVerificationCodeResponse, type VerifiedLoginToken, type WechatJsapiPayParams, getCustomAmountRechargeRule, validateCustomAmountRecharge };
|
package/dist/server.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ interface OrderDetails {
|
|
|
24
24
|
paidAt?: string;
|
|
25
25
|
createdAt: string;
|
|
26
26
|
channel?: string;
|
|
27
|
+
merchantPricing?: MerchantPricingSnapshot;
|
|
27
28
|
pricingBreakdown?: PricingBreakdown;
|
|
28
29
|
upgrade?: {
|
|
29
30
|
isUpgrade: boolean;
|
|
@@ -87,6 +88,11 @@ interface ProductCustomAmount {
|
|
|
87
88
|
entitlementKey: string;
|
|
88
89
|
currencies: Record<string, ProductCustomAmountCurrency>;
|
|
89
90
|
}
|
|
91
|
+
interface ProductInventory {
|
|
92
|
+
enabled: boolean;
|
|
93
|
+
totalQuantity: number;
|
|
94
|
+
reserveTimeoutSeconds?: number;
|
|
95
|
+
}
|
|
90
96
|
interface ProductMetadata {
|
|
91
97
|
subscriptionPeriod?: ProductSubscriptionPeriod;
|
|
92
98
|
expiringEntitlements?: string[];
|
|
@@ -94,6 +100,28 @@ interface ProductMetadata {
|
|
|
94
100
|
autoAssignOnNewUser?: boolean;
|
|
95
101
|
trialDurationDays?: number;
|
|
96
102
|
customAmount?: ProductCustomAmount;
|
|
103
|
+
inventory?: ProductInventory;
|
|
104
|
+
}
|
|
105
|
+
type ProductStockLookupMode = "auto" | "id" | "code";
|
|
106
|
+
interface ProductStock {
|
|
107
|
+
productId: string;
|
|
108
|
+
productCode: string;
|
|
109
|
+
limited: boolean;
|
|
110
|
+
total: number | null;
|
|
111
|
+
reserved: number;
|
|
112
|
+
sold: number;
|
|
113
|
+
available: number | null;
|
|
114
|
+
updatedAt: string;
|
|
115
|
+
reserveTimeoutSeconds: number | null;
|
|
116
|
+
}
|
|
117
|
+
interface ProductStockQueryOptions {
|
|
118
|
+
lookupBy?: ProductStockLookupMode;
|
|
119
|
+
locale?: string;
|
|
120
|
+
currency?: string;
|
|
121
|
+
}
|
|
122
|
+
interface ProductStocksQueryParams {
|
|
123
|
+
productIds?: string[];
|
|
124
|
+
productCodes?: string[];
|
|
97
125
|
}
|
|
98
126
|
interface PricingBreakdown {
|
|
99
127
|
isUpgrade: boolean;
|
|
@@ -251,6 +279,28 @@ interface PaymentClientOptions {
|
|
|
251
279
|
*/
|
|
252
280
|
checkoutUrl?: string;
|
|
253
281
|
}
|
|
282
|
+
interface MerchantPricingBreakdownItem {
|
|
283
|
+
type: "coupon" | "promotion" | "membership" | "manual" | "other";
|
|
284
|
+
amount: number;
|
|
285
|
+
label?: string;
|
|
286
|
+
code?: string;
|
|
287
|
+
}
|
|
288
|
+
interface MerchantPricing {
|
|
289
|
+
amount: number;
|
|
290
|
+
currency: string;
|
|
291
|
+
originalAmount?: number;
|
|
292
|
+
discountAmount?: number;
|
|
293
|
+
discountReason?: string;
|
|
294
|
+
discountCode?: string;
|
|
295
|
+
breakdown?: MerchantPricingBreakdownItem[];
|
|
296
|
+
}
|
|
297
|
+
interface MerchantPricingSnapshot extends MerchantPricing {
|
|
298
|
+
originalAmount: number;
|
|
299
|
+
discountAmount: number;
|
|
300
|
+
priceId: string;
|
|
301
|
+
productId: string;
|
|
302
|
+
productCode: string;
|
|
303
|
+
}
|
|
254
304
|
/**
|
|
255
305
|
* Create Order Parameters
|
|
256
306
|
*/
|
|
@@ -269,7 +319,9 @@ interface CreateOrderParams {
|
|
|
269
319
|
amount: number;
|
|
270
320
|
currency: string;
|
|
271
321
|
};
|
|
322
|
+
merchantPricing?: MerchantPricing;
|
|
272
323
|
}
|
|
324
|
+
type CreateBankTransferOrderParams = Omit<CreateOrderParams, "channel">;
|
|
273
325
|
/**
|
|
274
326
|
* Create WeChat Mini Program Order Parameters
|
|
275
327
|
*/
|
|
@@ -289,6 +341,23 @@ interface CreateOrderResponse {
|
|
|
289
341
|
currency: string;
|
|
290
342
|
payParams: any;
|
|
291
343
|
pricingBreakdown?: PricingBreakdown;
|
|
344
|
+
status?: "PENDING" | "PAID" | "CANCELLED" | "REFUNDED" | "FAILED";
|
|
345
|
+
paidAt?: string | null;
|
|
346
|
+
channel?: string;
|
|
347
|
+
isSandbox?: boolean;
|
|
348
|
+
merchantPricing?: MerchantPricingSnapshot;
|
|
349
|
+
}
|
|
350
|
+
interface CancelOrderResponse {
|
|
351
|
+
cancelled: boolean;
|
|
352
|
+
status: "PENDING" | "PAID" | "CANCELLED" | "REFUNDED" | "FAILED";
|
|
353
|
+
orderId: string;
|
|
354
|
+
internalId?: string | null;
|
|
355
|
+
}
|
|
356
|
+
interface CompleteFreeOrderResponse {
|
|
357
|
+
completed: boolean;
|
|
358
|
+
status: "paid" | "pending" | "cancelled" | "refunded" | "failed" | "unknown";
|
|
359
|
+
orderId: string;
|
|
360
|
+
internalId?: string | null;
|
|
292
361
|
}
|
|
293
362
|
/**
|
|
294
363
|
* Payment Callback Notification
|
|
@@ -405,12 +474,27 @@ declare class PaymentClient {
|
|
|
405
474
|
locale?: string;
|
|
406
475
|
currency?: string;
|
|
407
476
|
}): Promise<Product[]>;
|
|
477
|
+
/**
|
|
478
|
+
* Fetch the realtime stock snapshot for a single product.
|
|
479
|
+
*/
|
|
480
|
+
getProductStock(productIdOrCode: string, options?: ProductStockQueryOptions): Promise<ProductStock>;
|
|
481
|
+
/**
|
|
482
|
+
* Fetch realtime stock snapshots for multiple products.
|
|
483
|
+
*/
|
|
484
|
+
getProductStocks(params: ProductStocksQueryParams, options?: ProductStockQueryOptions): Promise<ProductStock[]>;
|
|
485
|
+
getProductStocks(params: ProductStocksQueryParams & ProductStockQueryOptions): Promise<ProductStock[]>;
|
|
408
486
|
/**
|
|
409
487
|
* Create a new order
|
|
410
488
|
* @param params - Order creation parameters
|
|
411
489
|
* @returns Order details with payment parameters
|
|
412
490
|
*/
|
|
413
491
|
createOrder(params: CreateOrderParams): Promise<CreateOrderResponse>;
|
|
492
|
+
/**
|
|
493
|
+
* Create a paid manual bank transfer order.
|
|
494
|
+
* @param params - Order creation parameters without channel
|
|
495
|
+
* @returns Paid order details
|
|
496
|
+
*/
|
|
497
|
+
createBankTransferOrder(params: CreateBankTransferOrderParams): Promise<CreateOrderResponse>;
|
|
414
498
|
/**
|
|
415
499
|
* Create a WeChat Mini Program order (channel fixed to WECHAT_MINI)
|
|
416
500
|
* @param params - Mini program order parameters
|
|
@@ -428,6 +512,18 @@ declare class PaymentClient {
|
|
|
428
512
|
openid?: string;
|
|
429
513
|
[key: string]: any;
|
|
430
514
|
}): Promise<CreateOrderResponse>;
|
|
515
|
+
/**
|
|
516
|
+
* Cancel a pending order and release its inventory reservation.
|
|
517
|
+
* Paid/refunded/failed orders are returned unchanged by the gateway.
|
|
518
|
+
*/
|
|
519
|
+
cancelOrder(orderId: string, params?: {
|
|
520
|
+
reason?: string;
|
|
521
|
+
}): Promise<CancelOrderResponse>;
|
|
522
|
+
/**
|
|
523
|
+
* Complete a zero-amount FREE order.
|
|
524
|
+
* This marks the pending order as paid and triggers normal paid-order side effects.
|
|
525
|
+
*/
|
|
526
|
+
completeFreeOrder(orderId: string): Promise<CompleteFreeOrderResponse>;
|
|
431
527
|
/**
|
|
432
528
|
* Query order status
|
|
433
529
|
* @param orderId - The order ID to query
|
|
@@ -519,4 +615,4 @@ declare class PaymentClient {
|
|
|
519
615
|
bindPhoneNumber(params: BindPhoneNumberParams): Promise<BindPhoneNumberResponse>;
|
|
520
616
|
}
|
|
521
617
|
|
|
522
|
-
export { type ActiveSubscriptionInfo, type BindPhoneNumberParams, type BindPhoneNumberResponse, type CreateMiniProgramOrderParams, type CreateOrderParams, type CreateOrderResponse, type CustomAmountRechargeRule, type CustomAmountRechargeValidationResult, type EnsureUserWithTrialResponse, type EntitlementDetail, type EntitlementDetailItem, type GetOrdersParams, type GetOrdersResponse, type OrderDetails, type OrderListItem, type OrderStatus, type PaymentCallbackData, PaymentClient, type PaymentClientOptions, type PaymentNotification, type PricingBreakdown, type Product, type ProductCustomAmount, type ProductCustomAmountCurrency, type ProductEntitlements, type ProductMetadata, type ProductPrice, type ProductResetRule, type ProductSubscriptionPeriod, type SendPhoneVerificationCodeParams, type SendPhoneVerificationCodeResponse, type VerifiedLoginToken, type WechatJsapiPayParams, getCustomAmountRechargeRule, validateCustomAmountRecharge };
|
|
618
|
+
export { type ActiveSubscriptionInfo, type BindPhoneNumberParams, type BindPhoneNumberResponse, type CancelOrderResponse, type CompleteFreeOrderResponse, type CreateBankTransferOrderParams, type CreateMiniProgramOrderParams, type CreateOrderParams, type CreateOrderResponse, type CustomAmountRechargeRule, type CustomAmountRechargeValidationResult, type EnsureUserWithTrialResponse, type EntitlementDetail, type EntitlementDetailItem, type GetOrdersParams, type GetOrdersResponse, type MerchantPricing, type MerchantPricingBreakdownItem, type MerchantPricingSnapshot, type OrderDetails, type OrderListItem, type OrderStatus, type PaymentCallbackData, PaymentClient, type PaymentClientOptions, type PaymentNotification, type PricingBreakdown, type Product, type ProductCustomAmount, type ProductCustomAmountCurrency, type ProductEntitlements, type ProductInventory, type ProductMetadata, type ProductPrice, type ProductResetRule, type ProductStock, type ProductStockLookupMode, type ProductStockQueryOptions, type ProductStocksQueryParams, type ProductSubscriptionPeriod, type SendPhoneVerificationCodeParams, type SendPhoneVerificationCodeResponse, type VerifiedLoginToken, type WechatJsapiPayParams, getCustomAmountRechargeRule, validateCustomAmountRecharge };
|
package/dist/server.js
CHANGED
|
@@ -163,6 +163,48 @@ var PaymentClient = class {
|
|
|
163
163
|
const path = params.toString() ? `/products?${params.toString()}` : "/products";
|
|
164
164
|
return this.request("GET", path);
|
|
165
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* Fetch the realtime stock snapshot for a single product.
|
|
168
|
+
*/
|
|
169
|
+
async getProductStock(productIdOrCode, options) {
|
|
170
|
+
const value = productIdOrCode?.trim();
|
|
171
|
+
if (!value) {
|
|
172
|
+
throw new Error("productIdOrCode is required");
|
|
173
|
+
}
|
|
174
|
+
const params = new URLSearchParams();
|
|
175
|
+
params.set("productIdOrCode", value);
|
|
176
|
+
if (options?.lookupBy) params.set("lookupBy", options.lookupBy);
|
|
177
|
+
if (options?.locale) params.set("locale", options.locale);
|
|
178
|
+
if (options?.currency) params.set("currency", options.currency);
|
|
179
|
+
return this.request(
|
|
180
|
+
"GET",
|
|
181
|
+
`/products/${encodeURIComponent(value)}/stock?${params.toString()}`
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
async getProductStocks(params, options) {
|
|
185
|
+
const productIds = [
|
|
186
|
+
...new Set(
|
|
187
|
+
(params.productIds || []).map((item) => item.trim()).filter(Boolean)
|
|
188
|
+
)
|
|
189
|
+
];
|
|
190
|
+
const productCodes = [
|
|
191
|
+
...new Set(
|
|
192
|
+
(params.productCodes || []).map((item) => item.trim()).filter(Boolean)
|
|
193
|
+
)
|
|
194
|
+
];
|
|
195
|
+
if (productIds.length === 0 && productCodes.length === 0) {
|
|
196
|
+
throw new Error("productIds or productCodes is required");
|
|
197
|
+
}
|
|
198
|
+
const queryOptions = options || params;
|
|
199
|
+
const query = new URLSearchParams();
|
|
200
|
+
if (productIds.length > 0) query.set("productIds", productIds.join(","));
|
|
201
|
+
if (productCodes.length > 0)
|
|
202
|
+
query.set("productCodes", productCodes.join(","));
|
|
203
|
+
if (queryOptions.lookupBy) query.set("lookupBy", queryOptions.lookupBy);
|
|
204
|
+
if (queryOptions.locale) query.set("locale", queryOptions.locale);
|
|
205
|
+
if (queryOptions.currency) query.set("currency", queryOptions.currency);
|
|
206
|
+
return this.request("GET", `/products/stocks?${query.toString()}`);
|
|
207
|
+
}
|
|
166
208
|
/**
|
|
167
209
|
* Create a new order
|
|
168
210
|
* @param params - Order creation parameters
|
|
@@ -171,6 +213,17 @@ var PaymentClient = class {
|
|
|
171
213
|
async createOrder(params) {
|
|
172
214
|
return this.request("POST", "/orders", params);
|
|
173
215
|
}
|
|
216
|
+
/**
|
|
217
|
+
* Create a paid manual bank transfer order.
|
|
218
|
+
* @param params - Order creation parameters without channel
|
|
219
|
+
* @returns Paid order details
|
|
220
|
+
*/
|
|
221
|
+
async createBankTransferOrder(params) {
|
|
222
|
+
return this.request("POST", "/orders", {
|
|
223
|
+
...params,
|
|
224
|
+
channel: "BANK_TRANSFER"
|
|
225
|
+
});
|
|
226
|
+
}
|
|
174
227
|
/**
|
|
175
228
|
* Create a WeChat Mini Program order (channel fixed to WECHAT_MINI)
|
|
176
229
|
* @param params - Mini program order parameters
|
|
@@ -193,6 +246,36 @@ var PaymentClient = class {
|
|
|
193
246
|
async payOrder(orderId, params) {
|
|
194
247
|
return this.request("POST", `/orders/${orderId}/pay`, params);
|
|
195
248
|
}
|
|
249
|
+
/**
|
|
250
|
+
* Cancel a pending order and release its inventory reservation.
|
|
251
|
+
* Paid/refunded/failed orders are returned unchanged by the gateway.
|
|
252
|
+
*/
|
|
253
|
+
async cancelOrder(orderId, params) {
|
|
254
|
+
const value = orderId?.trim();
|
|
255
|
+
if (!value) {
|
|
256
|
+
throw new Error("orderId is required");
|
|
257
|
+
}
|
|
258
|
+
return this.request(
|
|
259
|
+
"POST",
|
|
260
|
+
`/orders/${encodeURIComponent(value)}/cancel`,
|
|
261
|
+
params || {}
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Complete a zero-amount FREE order.
|
|
266
|
+
* This marks the pending order as paid and triggers normal paid-order side effects.
|
|
267
|
+
*/
|
|
268
|
+
async completeFreeOrder(orderId) {
|
|
269
|
+
const value = orderId?.trim();
|
|
270
|
+
if (!value) {
|
|
271
|
+
throw new Error("orderId is required");
|
|
272
|
+
}
|
|
273
|
+
return this.request(
|
|
274
|
+
"POST",
|
|
275
|
+
`/orders/${encodeURIComponent(value)}/free/complete`,
|
|
276
|
+
{}
|
|
277
|
+
);
|
|
278
|
+
}
|
|
196
279
|
/**
|
|
197
280
|
* Query order status
|
|
198
281
|
* @param orderId - The order ID to query
|
package/dist/server.js.map
CHANGED
|
@@ -1 +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\tpricingBreakdown?: PricingBreakdown\n\tupgrade?: {\n\t\tisUpgrade: boolean\n\t\tfromProductId?: string | null\n\t\tfromProductCode?: string | null\n\t\tfromPriceId?: string | null\n\t\tfromOrderId?: string | null\n\t\tfromSourceKind?: string | null\n\t\tfromSortOrder?: number | null\n\t\ttoSortOrder?: number | null\n\t\toriginalAmount?: number | null\n\t\tcreditAmount?: number | null\n\t\tfinalPayableAmount?: number | null\n\t\tremainingRatio?: number | null\n\t\tnewPeriodStartsAt?: string | null\n\t\tnewPeriodValue?: number | null\n\t\tnewPeriodUnit?: \"days\" | \"months\" | \"years\" | null\n\t} | null\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 ProductCustomAmountCurrency {\n\tminAmount: number\n\tmaxAmount: number\n\tstepAmount?: number\n\tunitsPerCurrencyUnit: number\n\tunitsPerCurrencyUnitBasis?: \"MINOR\" | \"MAJOR\"\n}\n\nexport interface ProductCustomAmount {\n\tenabled: boolean\n\tentitlementKey: string\n\tcurrencies: Record<string, ProductCustomAmountCurrency>\n}\n\nexport interface ProductMetadata {\n\tsubscriptionPeriod?: ProductSubscriptionPeriod\n\texpiringEntitlements?: string[]\n\tresetEntitlements?: Record<string, ProductResetRule>\n\tautoAssignOnNewUser?: boolean\n\ttrialDurationDays?: number\n\tcustomAmount?: ProductCustomAmount\n}\n\nexport interface PricingBreakdown {\n\tisUpgrade: boolean\n\toriginalAmount: number\n\tcreditAmount: number\n\tfinalPayableAmount: number\n\tfromProductCode?: string | null\n}\n\nexport interface ActiveSubscriptionInfo {\n\tproductId: string\n\tproductCode: string\n\tsortOrder: number\n\tpaidAt?: string | null\n\texpiresAt: string\n\tpriceId?: string | null\n\torderId?: string | null\n\tsourceKind?: string | null\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\nexport interface CustomAmountRechargeRule extends ProductCustomAmountCurrency {\n\tproductId: string\n\tproductCode: string\n\tentitlementKey: string\n\tcurrency: string\n\tconfiguredMinAmount: number\n\tminimumGrantAmount: number\n}\n\nexport type CustomAmountRechargeValidationResult =\n\t| {\n\t\t\tvalid: true\n\t\t\trule: CustomAmountRechargeRule\n\t }\n\t| {\n\t\t\tvalid: false\n\t\t\tcode:\n\t\t\t\t| \"CUSTOM_AMOUNT_UNAVAILABLE\"\n\t\t\t\t| \"CUSTOM_AMOUNT_INVALID_AMOUNT\"\n\t\t\t\t| \"CUSTOM_AMOUNT_OUT_OF_RANGE\"\n\t\t\t\t| \"CUSTOM_AMOUNT_INVALID_STEP\"\n\t\t\terror: string\n\t\t\trule?: CustomAmountRechargeRule\n\t }\n\n/**\n * Resolve the custom amount recharge rule for a product and currency.\n *\n * Amounts are in the smallest currency unit. `unitsPerCurrencyUnit` defaults\n * to the smallest currency unit. When `unitsPerCurrencyUnitBasis` is `MAJOR`,\n * fractional entitlement amounts are rounded to the nearest whole unit. The\n * returned `minAmount` is the effective lower bound that both satisfies product\n * metadata and grants at least one entitlement unit. `configuredMinAmount`\n * keeps the raw product metadata value for display or diagnostics.\n */\nexport function getCustomAmountRechargeRule(\n\tproduct: Product | null | undefined,\n\tcurrency: string,\n): CustomAmountRechargeRule | null {\n\tif (!product || product.type !== \"CREDIT\") return null\n\tconst normalizedCurrency = currency.trim().toUpperCase()\n\tif (!/^[A-Z]{3}$/.test(normalizedCurrency)) return null\n\n\tconst customAmount = product.metadata?.customAmount\n\tif (customAmount?.enabled !== true) return null\n\n\tconst currencyConfig = customAmount.currencies?.[normalizedCurrency]\n\tif (!currencyConfig) return null\n\n\tconst minimumGrantAmount =\n\t\tcurrencyConfig.unitsPerCurrencyUnitBasis === \"MAJOR\"\n\t\t\t? Math.ceil(50 / currencyConfig.unitsPerCurrencyUnit)\n\t\t\t: Math.ceil(1 / currencyConfig.unitsPerCurrencyUnit)\n\tlet minAmount = Math.max(currencyConfig.minAmount, minimumGrantAmount)\n\tif (currencyConfig.stepAmount && minAmount > currencyConfig.minAmount) {\n\t\tconst stepCount = Math.ceil(\n\t\t\t(minAmount - currencyConfig.minAmount) / currencyConfig.stepAmount,\n\t\t)\n\t\tminAmount = currencyConfig.minAmount + stepCount * currencyConfig.stepAmount\n\t}\n\n\treturn {\n\t\t...currencyConfig,\n\t\tproductId: product.id,\n\t\tproductCode: product.code,\n\t\tentitlementKey: customAmount.entitlementKey,\n\t\tcurrency: normalizedCurrency,\n\t\tconfiguredMinAmount: currencyConfig.minAmount,\n\t\tminimumGrantAmount,\n\t\tminAmount,\n\t}\n}\n\n/**\n * Validate a custom recharge amount before calling `PaymentUI.openPayment`.\n * This is an SDK-side guardrail for integrator-owned amount inputs; the worker\n * still performs authoritative server-side validation when creating the order.\n */\nexport function validateCustomAmountRecharge(\n\tproduct: Product | null | undefined,\n\tcustomAmount: { amount: number; currency: string },\n): CustomAmountRechargeValidationResult {\n\tconst rule = getCustomAmountRechargeRule(product, customAmount.currency)\n\tif (!rule) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\tcode: \"CUSTOM_AMOUNT_UNAVAILABLE\",\n\t\t\terror:\n\t\t\t\t\"Product does not support custom amount recharge for this currency.\",\n\t\t}\n\t}\n\n\tconst amount = Number(customAmount.amount)\n\tif (!Number.isInteger(amount) || amount <= 0) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\tcode: \"CUSTOM_AMOUNT_INVALID_AMOUNT\",\n\t\t\terror:\n\t\t\t\t\"Custom amount must be a positive integer in the smallest currency unit.\",\n\t\t\trule,\n\t\t}\n\t}\n\n\tif (amount < rule.minAmount || amount > rule.maxAmount) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\tcode: \"CUSTOM_AMOUNT_OUT_OF_RANGE\",\n\t\t\terror: `Custom amount must be between ${rule.minAmount} and ${rule.maxAmount}.`,\n\t\t\trule,\n\t\t}\n\t}\n\n\tif (\n\t\trule.stepAmount &&\n\t\t(amount - rule.configuredMinAmount) % rule.stepAmount !== 0\n\t) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\tcode: \"CUSTOM_AMOUNT_INVALID_STEP\",\n\t\t\terror: `Custom amount must follow step ${rule.stepAmount}.`,\n\t\t\trule,\n\t\t}\n\t}\n\n\treturn { valid: true, rule }\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\tusername?: string | null\n\tavatar?: string | null\n\tphoneCountryCode?: string | null\n\tphoneNumber?: string | null\n\tphoneE164?: string | null\n\tphoneVerifiedAt?: string | null\n\twechatOpenId?: string | null\n\twechatUnionId?: string | null\n\texpiresAt: string\n}\n\nexport interface SendPhoneVerificationCodeParams {\n\tuserId: string\n\tphoneCountryCode?: string\n\tcountryCode?: string\n\tphoneNumber: string\n}\n\nexport interface SendPhoneVerificationCodeResponse {\n\tphoneCountryCode?: string | null\n\tphoneNumber?: string | null\n\tphoneE164: string\n\texpiresAt: string\n\tcooldownSeconds?: number\n\tresendAfterSeconds?: number\n}\n\nexport interface BindPhoneNumberParams {\n\tuserId: string\n\tphoneCountryCode?: string\n\tcountryCode?: string\n\tphoneNumber: string\n\tcode: string\n}\n\nexport interface BindPhoneNumberResponse {\n\tuser: {\n\t\tuserId: string\n\t\tphoneCountryCode?: string | null\n\t\tphoneNumber?: string | null\n\t\tphoneE164?: string | null\n\t\tphoneVerifiedAt?: string | null\n\t}\n\tmerged: boolean\n\tmergeSummary?: Record<string, any>\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\tcallbackUrl?: string\n\tmetadata?: Record<string, any>\n\tmerchantOrderId?: string\n\topenid?: string\n\tlocale?: string\n\tcustomAmount?: {\n\t\tamount: number\n\t\tcurrency: string\n\t}\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\tpricingBreakdown?: PricingBreakdown\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\tlet parsedError: any = null\n\t\t\ttry {\n\t\t\t\tparsedError = JSON.parse(errorText)\n\t\t\t} catch {}\n\t\t\tconst message =\n\t\t\t\tparsedError?.message ||\n\t\t\t\tparsedError?.error ||\n\t\t\t\terrorText ||\n\t\t\t\t\"Request failed\"\n\t\t\tconst error = new Error(message)\n\t\t\t;(error as Error & { status?: number; code?: string }).status =\n\t\t\t\tresponse.status\n\t\t\t;(error as Error & { status?: number; code?: string }).code =\n\t\t\t\tparsedError?.code || parsedError?.error || undefined\n\t\t\tthrow error\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 {\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\tasync getActiveSubscription(\n\t\tuserId: string,\n\t): Promise<ActiveSubscriptionInfo | null> {\n\t\treturn this.request(\"GET\", `/users/${userId}/active-subscription`)\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\t/**\n\t * Send a phone verification code for binding a phone number to a hosted login user.\n\t */\n\tasync sendPhoneVerificationCode(\n\t\tparams: SendPhoneVerificationCodeParams,\n\t): Promise<SendPhoneVerificationCodeResponse> {\n\t\tconst userId = params.userId?.trim()\n\t\tconst phoneNumber = params.phoneNumber?.trim()\n\t\tif (!userId) throw new Error(\"userId is required\")\n\t\tif (!phoneNumber) throw new Error(\"phoneNumber is required\")\n\n\t\treturn this.request(\n\t\t\t\"POST\",\n\t\t\t`/login/users/${encodeURIComponent(userId)}/phone/code`,\n\t\t\t{\n\t\t\t\tphoneCountryCode: params.phoneCountryCode || params.countryCode,\n\t\t\t\tphoneNumber,\n\t\t\t},\n\t\t)\n\t}\n\n\t/**\n\t * Bind a verified phone number to a hosted login user, merging existing accounts when needed.\n\t */\n\tasync bindPhoneNumber(\n\t\tparams: BindPhoneNumberParams,\n\t): Promise<BindPhoneNumberResponse> {\n\t\tconst userId = params.userId?.trim()\n\t\tconst phoneNumber = params.phoneNumber?.trim()\n\t\tconst code = params.code?.trim()\n\t\tif (!userId) throw new Error(\"userId is required\")\n\t\tif (!phoneNumber) throw new Error(\"phoneNumber is required\")\n\t\tif (!code) throw new Error(\"code is required\")\n\n\t\treturn this.request(\n\t\t\t\"POST\",\n\t\t\t`/login/users/${encodeURIComponent(userId)}/phone/bind`,\n\t\t\t{\n\t\t\t\tcode,\n\t\t\t\tphoneCountryCode: params.phoneCountryCode || params.countryCode,\n\t\t\t\tphoneNumber,\n\t\t\t},\n\t\t)\n\t}\n}\n"],"mappings":"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","names":[]}
|
|
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\tmerchantPricing?: MerchantPricingSnapshot\n\tpricingBreakdown?: PricingBreakdown\n\tupgrade?: {\n\t\tisUpgrade: boolean\n\t\tfromProductId?: string | null\n\t\tfromProductCode?: string | null\n\t\tfromPriceId?: string | null\n\t\tfromOrderId?: string | null\n\t\tfromSourceKind?: string | null\n\t\tfromSortOrder?: number | null\n\t\ttoSortOrder?: number | null\n\t\toriginalAmount?: number | null\n\t\tcreditAmount?: number | null\n\t\tfinalPayableAmount?: number | null\n\t\tremainingRatio?: number | null\n\t\tnewPeriodStartsAt?: string | null\n\t\tnewPeriodValue?: number | null\n\t\tnewPeriodUnit?: \"days\" | \"months\" | \"years\" | null\n\t} | null\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 ProductCustomAmountCurrency {\n\tminAmount: number\n\tmaxAmount: number\n\tstepAmount?: number\n\tunitsPerCurrencyUnit: number\n\tunitsPerCurrencyUnitBasis?: \"MINOR\" | \"MAJOR\"\n}\n\nexport interface ProductCustomAmount {\n\tenabled: boolean\n\tentitlementKey: string\n\tcurrencies: Record<string, ProductCustomAmountCurrency>\n}\n\nexport interface ProductInventory {\n\tenabled: boolean\n\ttotalQuantity: number\n\treserveTimeoutSeconds?: number\n}\n\nexport interface ProductMetadata {\n\tsubscriptionPeriod?: ProductSubscriptionPeriod\n\texpiringEntitlements?: string[]\n\tresetEntitlements?: Record<string, ProductResetRule>\n\tautoAssignOnNewUser?: boolean\n\ttrialDurationDays?: number\n\tcustomAmount?: ProductCustomAmount\n\tinventory?: ProductInventory\n}\n\nexport type ProductStockLookupMode = \"auto\" | \"id\" | \"code\"\n\nexport interface ProductStock {\n\tproductId: string\n\tproductCode: string\n\tlimited: boolean\n\ttotal: number | null\n\treserved: number\n\tsold: number\n\tavailable: number | null\n\tupdatedAt: string\n\treserveTimeoutSeconds: number | null\n}\n\nexport interface ProductStockQueryOptions {\n\tlookupBy?: ProductStockLookupMode\n\tlocale?: string\n\tcurrency?: string\n}\n\nexport interface ProductStocksQueryParams {\n\tproductIds?: string[]\n\tproductCodes?: string[]\n}\n\nexport interface PricingBreakdown {\n\tisUpgrade: boolean\n\toriginalAmount: number\n\tcreditAmount: number\n\tfinalPayableAmount: number\n\tfromProductCode?: string | null\n}\n\nexport interface ActiveSubscriptionInfo {\n\tproductId: string\n\tproductCode: string\n\tsortOrder: number\n\tpaidAt?: string | null\n\texpiresAt: string\n\tpriceId?: string | null\n\torderId?: string | null\n\tsourceKind?: string | null\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\nexport interface CustomAmountRechargeRule extends ProductCustomAmountCurrency {\n\tproductId: string\n\tproductCode: string\n\tentitlementKey: string\n\tcurrency: string\n\tconfiguredMinAmount: number\n\tminimumGrantAmount: number\n}\n\nexport type CustomAmountRechargeValidationResult =\n\t| {\n\t\t\tvalid: true\n\t\t\trule: CustomAmountRechargeRule\n\t }\n\t| {\n\t\t\tvalid: false\n\t\t\tcode:\n\t\t\t\t| \"CUSTOM_AMOUNT_UNAVAILABLE\"\n\t\t\t\t| \"CUSTOM_AMOUNT_INVALID_AMOUNT\"\n\t\t\t\t| \"CUSTOM_AMOUNT_OUT_OF_RANGE\"\n\t\t\t\t| \"CUSTOM_AMOUNT_INVALID_STEP\"\n\t\t\terror: string\n\t\t\trule?: CustomAmountRechargeRule\n\t }\n\n/**\n * Resolve the custom amount recharge rule for a product and currency.\n *\n * Amounts are in the smallest currency unit. `unitsPerCurrencyUnit` defaults\n * to the smallest currency unit. When `unitsPerCurrencyUnitBasis` is `MAJOR`,\n * fractional entitlement amounts are rounded to the nearest whole unit. The\n * returned `minAmount` is the effective lower bound that both satisfies product\n * metadata and grants at least one entitlement unit. `configuredMinAmount`\n * keeps the raw product metadata value for display or diagnostics.\n */\nexport function getCustomAmountRechargeRule(\n\tproduct: Product | null | undefined,\n\tcurrency: string,\n): CustomAmountRechargeRule | null {\n\tif (!product || product.type !== \"CREDIT\") return null\n\tconst normalizedCurrency = currency.trim().toUpperCase()\n\tif (!/^[A-Z]{3}$/.test(normalizedCurrency)) return null\n\n\tconst customAmount = product.metadata?.customAmount\n\tif (customAmount?.enabled !== true) return null\n\n\tconst currencyConfig = customAmount.currencies?.[normalizedCurrency]\n\tif (!currencyConfig) return null\n\n\tconst minimumGrantAmount =\n\t\tcurrencyConfig.unitsPerCurrencyUnitBasis === \"MAJOR\"\n\t\t\t? Math.ceil(50 / currencyConfig.unitsPerCurrencyUnit)\n\t\t\t: Math.ceil(1 / currencyConfig.unitsPerCurrencyUnit)\n\tlet minAmount = Math.max(currencyConfig.minAmount, minimumGrantAmount)\n\tif (currencyConfig.stepAmount && minAmount > currencyConfig.minAmount) {\n\t\tconst stepCount = Math.ceil(\n\t\t\t(minAmount - currencyConfig.minAmount) / currencyConfig.stepAmount,\n\t\t)\n\t\tminAmount = currencyConfig.minAmount + stepCount * currencyConfig.stepAmount\n\t}\n\n\treturn {\n\t\t...currencyConfig,\n\t\tproductId: product.id,\n\t\tproductCode: product.code,\n\t\tentitlementKey: customAmount.entitlementKey,\n\t\tcurrency: normalizedCurrency,\n\t\tconfiguredMinAmount: currencyConfig.minAmount,\n\t\tminimumGrantAmount,\n\t\tminAmount,\n\t}\n}\n\n/**\n * Validate a custom recharge amount before calling `PaymentUI.openPayment`.\n * This is an SDK-side guardrail for integrator-owned amount inputs; the worker\n * still performs authoritative server-side validation when creating the order.\n */\nexport function validateCustomAmountRecharge(\n\tproduct: Product | null | undefined,\n\tcustomAmount: { amount: number; currency: string },\n): CustomAmountRechargeValidationResult {\n\tconst rule = getCustomAmountRechargeRule(product, customAmount.currency)\n\tif (!rule) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\tcode: \"CUSTOM_AMOUNT_UNAVAILABLE\",\n\t\t\terror:\n\t\t\t\t\"Product does not support custom amount recharge for this currency.\",\n\t\t}\n\t}\n\n\tconst amount = Number(customAmount.amount)\n\tif (!Number.isInteger(amount) || amount <= 0) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\tcode: \"CUSTOM_AMOUNT_INVALID_AMOUNT\",\n\t\t\terror:\n\t\t\t\t\"Custom amount must be a positive integer in the smallest currency unit.\",\n\t\t\trule,\n\t\t}\n\t}\n\n\tif (amount < rule.minAmount || amount > rule.maxAmount) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\tcode: \"CUSTOM_AMOUNT_OUT_OF_RANGE\",\n\t\t\terror: `Custom amount must be between ${rule.minAmount} and ${rule.maxAmount}.`,\n\t\t\trule,\n\t\t}\n\t}\n\n\tif (\n\t\trule.stepAmount &&\n\t\t(amount - rule.configuredMinAmount) % rule.stepAmount !== 0\n\t) {\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\tcode: \"CUSTOM_AMOUNT_INVALID_STEP\",\n\t\t\terror: `Custom amount must follow step ${rule.stepAmount}.`,\n\t\t\trule,\n\t\t}\n\t}\n\n\treturn { valid: true, rule }\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\tusername?: string | null\n\tavatar?: string | null\n\tphoneCountryCode?: string | null\n\tphoneNumber?: string | null\n\tphoneE164?: string | null\n\tphoneVerifiedAt?: string | null\n\twechatOpenId?: string | null\n\twechatUnionId?: string | null\n\texpiresAt: string\n}\n\nexport interface SendPhoneVerificationCodeParams {\n\tuserId: string\n\tphoneCountryCode?: string\n\tcountryCode?: string\n\tphoneNumber: string\n}\n\nexport interface SendPhoneVerificationCodeResponse {\n\tphoneCountryCode?: string | null\n\tphoneNumber?: string | null\n\tphoneE164: string\n\texpiresAt: string\n\tcooldownSeconds?: number\n\tresendAfterSeconds?: number\n}\n\nexport interface BindPhoneNumberParams {\n\tuserId: string\n\tphoneCountryCode?: string\n\tcountryCode?: string\n\tphoneNumber: string\n\tcode: string\n}\n\nexport interface BindPhoneNumberResponse {\n\tuser: {\n\t\tuserId: string\n\t\tphoneCountryCode?: string | null\n\t\tphoneNumber?: string | null\n\t\tphoneE164?: string | null\n\t\tphoneVerifiedAt?: string | null\n\t}\n\tmerged: boolean\n\tmergeSummary?: Record<string, any>\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\nexport interface MerchantPricingBreakdownItem {\n\ttype: \"coupon\" | \"promotion\" | \"membership\" | \"manual\" | \"other\"\n\tamount: number\n\tlabel?: string\n\tcode?: string\n}\n\nexport interface MerchantPricing {\n\tamount: number\n\tcurrency: string\n\toriginalAmount?: number\n\tdiscountAmount?: number\n\tdiscountReason?: string\n\tdiscountCode?: string\n\tbreakdown?: MerchantPricingBreakdownItem[]\n}\n\nexport interface MerchantPricingSnapshot extends MerchantPricing {\n\toriginalAmount: number\n\tdiscountAmount: number\n\tpriceId: string\n\tproductId: string\n\tproductCode: 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\tcallbackUrl?: string\n\tmetadata?: Record<string, any>\n\tmerchantOrderId?: string\n\topenid?: string\n\tlocale?: string\n\tcustomAmount?: {\n\t\tamount: number\n\t\tcurrency: string\n\t}\n\tmerchantPricing?: MerchantPricing\n}\n\nexport type CreateBankTransferOrderParams = Omit<CreateOrderParams, \"channel\">\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\tpricingBreakdown?: PricingBreakdown\n\tstatus?: \"PENDING\" | \"PAID\" | \"CANCELLED\" | \"REFUNDED\" | \"FAILED\"\n\tpaidAt?: string | null\n\tchannel?: string\n\tisSandbox?: boolean\n\tmerchantPricing?: MerchantPricingSnapshot\n}\n\nexport interface CancelOrderResponse {\n\tcancelled: boolean\n\tstatus: \"PENDING\" | \"PAID\" | \"CANCELLED\" | \"REFUNDED\" | \"FAILED\"\n\torderId: string\n\tinternalId?: string | null\n}\n\nexport interface CompleteFreeOrderResponse {\n\tcompleted: boolean\n\tstatus: \"paid\" | \"pending\" | \"cancelled\" | \"refunded\" | \"failed\" | \"unknown\"\n\torderId: string\n\tinternalId?: string | null\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\tlet parsedError: any = null\n\t\t\ttry {\n\t\t\t\tparsedError = JSON.parse(errorText)\n\t\t\t} catch {}\n\t\t\tconst message =\n\t\t\t\tparsedError?.message ||\n\t\t\t\tparsedError?.error ||\n\t\t\t\terrorText ||\n\t\t\t\t\"Request failed\"\n\t\t\tconst error = new Error(message)\n\t\t\t;(error as Error & { status?: number; code?: string }).status =\n\t\t\t\tresponse.status\n\t\t\t;(error as Error & { status?: number; code?: string }).code =\n\t\t\t\tparsedError?.code || parsedError?.error || undefined\n\t\t\tthrow error\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 {\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 * Fetch the realtime stock snapshot for a single product.\n\t */\n\tasync getProductStock(\n\t\tproductIdOrCode: string,\n\t\toptions?: ProductStockQueryOptions,\n\t): Promise<ProductStock> {\n\t\tconst value = productIdOrCode?.trim()\n\t\tif (!value) {\n\t\t\tthrow new Error(\"productIdOrCode is required\")\n\t\t}\n\n\t\tconst params = new URLSearchParams()\n\t\tparams.set(\"productIdOrCode\", value)\n\t\tif (options?.lookupBy) params.set(\"lookupBy\", options.lookupBy)\n\t\tif (options?.locale) params.set(\"locale\", options.locale)\n\t\tif (options?.currency) params.set(\"currency\", options.currency)\n\n\t\treturn this.request(\n\t\t\t\"GET\",\n\t\t\t`/products/${encodeURIComponent(value)}/stock?${params.toString()}`,\n\t\t)\n\t}\n\n\t/**\n\t * Fetch realtime stock snapshots for multiple products.\n\t */\n\tasync getProductStocks(\n\t\tparams: ProductStocksQueryParams,\n\t\toptions?: ProductStockQueryOptions,\n\t): Promise<ProductStock[]>\n\tasync getProductStocks(\n\t\tparams: ProductStocksQueryParams & ProductStockQueryOptions,\n\t): Promise<ProductStock[]>\n\tasync getProductStocks(\n\t\tparams: ProductStocksQueryParams & ProductStockQueryOptions,\n\t\toptions?: ProductStockQueryOptions,\n\t): Promise<ProductStock[]> {\n\t\tconst productIds = [\n\t\t\t...new Set(\n\t\t\t\t(params.productIds || []).map((item) => item.trim()).filter(Boolean),\n\t\t\t),\n\t\t]\n\t\tconst productCodes = [\n\t\t\t...new Set(\n\t\t\t\t(params.productCodes || []).map((item) => item.trim()).filter(Boolean),\n\t\t\t),\n\t\t]\n\t\tif (productIds.length === 0 && productCodes.length === 0) {\n\t\t\tthrow new Error(\"productIds or productCodes is required\")\n\t\t}\n\n\t\tconst queryOptions = options || params\n\t\tconst query = new URLSearchParams()\n\t\tif (productIds.length > 0) query.set(\"productIds\", productIds.join(\",\"))\n\t\tif (productCodes.length > 0)\n\t\t\tquery.set(\"productCodes\", productCodes.join(\",\"))\n\t\tif (queryOptions.lookupBy) query.set(\"lookupBy\", queryOptions.lookupBy)\n\t\tif (queryOptions.locale) query.set(\"locale\", queryOptions.locale)\n\t\tif (queryOptions.currency) query.set(\"currency\", queryOptions.currency)\n\n\t\treturn this.request(\"GET\", `/products/stocks?${query.toString()}`)\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 paid manual bank transfer order.\n\t * @param params - Order creation parameters without channel\n\t * @returns Paid order details\n\t */\n\tasync createBankTransferOrder(\n\t\tparams: CreateBankTransferOrderParams,\n\t): Promise<CreateOrderResponse> {\n\t\treturn this.request(\"POST\", \"/orders\", {\n\t\t\t...params,\n\t\t\tchannel: \"BANK_TRANSFER\",\n\t\t} satisfies CreateOrderParams)\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 * Cancel a pending order and release its inventory reservation.\n\t * Paid/refunded/failed orders are returned unchanged by the gateway.\n\t */\n\tasync cancelOrder(\n\t\torderId: string,\n\t\tparams?: { reason?: string },\n\t): Promise<CancelOrderResponse> {\n\t\tconst value = orderId?.trim()\n\t\tif (!value) {\n\t\t\tthrow new Error(\"orderId is required\")\n\t\t}\n\n\t\treturn this.request(\n\t\t\t\"POST\",\n\t\t\t`/orders/${encodeURIComponent(value)}/cancel`,\n\t\t\tparams || {},\n\t\t)\n\t}\n\n\t/**\n\t * Complete a zero-amount FREE order.\n\t * This marks the pending order as paid and triggers normal paid-order side effects.\n\t */\n\tasync completeFreeOrder(orderId: string): Promise<CompleteFreeOrderResponse> {\n\t\tconst value = orderId?.trim()\n\t\tif (!value) {\n\t\t\tthrow new Error(\"orderId is required\")\n\t\t}\n\n\t\treturn this.request(\n\t\t\t\"POST\",\n\t\t\t`/orders/${encodeURIComponent(value)}/free/complete`,\n\t\t\t{},\n\t\t)\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\tasync getActiveSubscription(\n\t\tuserId: string,\n\t): Promise<ActiveSubscriptionInfo | null> {\n\t\treturn this.request(\"GET\", `/users/${userId}/active-subscription`)\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\t/**\n\t * Send a phone verification code for binding a phone number to a hosted login user.\n\t */\n\tasync sendPhoneVerificationCode(\n\t\tparams: SendPhoneVerificationCodeParams,\n\t): Promise<SendPhoneVerificationCodeResponse> {\n\t\tconst userId = params.userId?.trim()\n\t\tconst phoneNumber = params.phoneNumber?.trim()\n\t\tif (!userId) throw new Error(\"userId is required\")\n\t\tif (!phoneNumber) throw new Error(\"phoneNumber is required\")\n\n\t\treturn this.request(\n\t\t\t\"POST\",\n\t\t\t`/login/users/${encodeURIComponent(userId)}/phone/code`,\n\t\t\t{\n\t\t\t\tphoneCountryCode: params.phoneCountryCode || params.countryCode,\n\t\t\t\tphoneNumber,\n\t\t\t},\n\t\t)\n\t}\n\n\t/**\n\t * Bind a verified phone number to a hosted login user, merging existing accounts when needed.\n\t */\n\tasync bindPhoneNumber(\n\t\tparams: BindPhoneNumberParams,\n\t): Promise<BindPhoneNumberResponse> {\n\t\tconst userId = params.userId?.trim()\n\t\tconst phoneNumber = params.phoneNumber?.trim()\n\t\tconst code = params.code?.trim()\n\t\tif (!userId) throw new Error(\"userId is required\")\n\t\tif (!phoneNumber) throw new Error(\"phoneNumber is required\")\n\t\tif (!code) throw new Error(\"code is required\")\n\n\t\treturn this.request(\n\t\t\t\"POST\",\n\t\t\t`/login/users/${encodeURIComponent(userId)}/phone/bind`,\n\t\t\t{\n\t\t\t\tcode,\n\t\t\t\tphoneCountryCode: params.phoneCountryCode || params.countryCode,\n\t\t\t\tphoneNumber,\n\t\t\t},\n\t\t)\n\t}\n}\n"],"mappings":"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","names":[]}
|