@youidian/sdk 3.3.10 → 3.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.d.cts CHANGED
@@ -95,6 +95,8 @@ interface ProductInventory {
95
95
  }
96
96
  interface ProductMetadata {
97
97
  subscriptionPeriod?: ProductSubscriptionPeriod;
98
+ subscriptionGroup?: string;
99
+ restrictSubscriptionPurchase?: boolean;
98
100
  expiringEntitlements?: string[];
99
101
  resetEntitlements?: Record<string, ProductResetRule>;
100
102
  autoAssignOnNewUser?: boolean;
@@ -130,6 +132,32 @@ interface PricingBreakdown {
130
132
  finalPayableAmount: number;
131
133
  fromProductCode?: string | null;
132
134
  }
135
+ interface ConsumeEntitlementPoolResult {
136
+ balance: number;
137
+ balances: Record<string, number>;
138
+ consumed: Record<string, number>;
139
+ consumedBuckets?: EntitlementCreditBucketConsumption[];
140
+ }
141
+ interface EntitlementCreditBucket {
142
+ key: string;
143
+ grantId: string | null;
144
+ sourceKind: string;
145
+ sourceProductId: string | null;
146
+ sourceOrderId: string | null;
147
+ amount: number;
148
+ remaining: number;
149
+ expiresAt: string | null;
150
+ grantedAt: string | null;
151
+ metadata?: Record<string, any> | null;
152
+ }
153
+ interface EntitlementCreditBucketConsumption {
154
+ key: string;
155
+ grantId: string | null;
156
+ amount: number;
157
+ expiresAt: string | null;
158
+ sourceProductId: string | null;
159
+ sourceOrderId: string | null;
160
+ }
133
161
  interface ActiveSubscriptionInfo {
134
162
  productId: string;
135
163
  productCode: string;
@@ -575,6 +603,18 @@ declare class PaymentClient {
575
603
  }): Promise<{
576
604
  balance: number;
577
605
  }>;
606
+ /**
607
+ * Consume numeric entitlements from an ordered key pool.
608
+ * Useful when subscription credits and perpetual credits use separate keys.
609
+ */
610
+ consumeEntitlementPool(userId: string, keys: string[], amount: number, options?: {
611
+ idempotencyKey?: string;
612
+ metadata?: Record<string, any>;
613
+ }): Promise<ConsumeEntitlementPoolResult>;
614
+ /**
615
+ * Get active numeric entitlement buckets ordered by expiration.
616
+ */
617
+ getEntitlementCreditBuckets(userId: string, keys?: string[]): Promise<EntitlementCreditBucket[]>;
578
618
  /**
579
619
  * Add numeric entitlement (e.g. refund)
580
620
  * @param userId - User ID
@@ -615,4 +655,4 @@ declare class PaymentClient {
615
655
  bindPhoneNumber(params: BindPhoneNumberParams): Promise<BindPhoneNumberResponse>;
616
656
  }
617
657
 
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 };
658
+ export { type ActiveSubscriptionInfo, type BindPhoneNumberParams, type BindPhoneNumberResponse, type CancelOrderResponse, type CompleteFreeOrderResponse, type ConsumeEntitlementPoolResult, type CreateBankTransferOrderParams, type CreateMiniProgramOrderParams, type CreateOrderParams, type CreateOrderResponse, type CustomAmountRechargeRule, type CustomAmountRechargeValidationResult, type EnsureUserWithTrialResponse, type EntitlementCreditBucket, type EntitlementCreditBucketConsumption, 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
@@ -95,6 +95,8 @@ interface ProductInventory {
95
95
  }
96
96
  interface ProductMetadata {
97
97
  subscriptionPeriod?: ProductSubscriptionPeriod;
98
+ subscriptionGroup?: string;
99
+ restrictSubscriptionPurchase?: boolean;
98
100
  expiringEntitlements?: string[];
99
101
  resetEntitlements?: Record<string, ProductResetRule>;
100
102
  autoAssignOnNewUser?: boolean;
@@ -130,6 +132,32 @@ interface PricingBreakdown {
130
132
  finalPayableAmount: number;
131
133
  fromProductCode?: string | null;
132
134
  }
135
+ interface ConsumeEntitlementPoolResult {
136
+ balance: number;
137
+ balances: Record<string, number>;
138
+ consumed: Record<string, number>;
139
+ consumedBuckets?: EntitlementCreditBucketConsumption[];
140
+ }
141
+ interface EntitlementCreditBucket {
142
+ key: string;
143
+ grantId: string | null;
144
+ sourceKind: string;
145
+ sourceProductId: string | null;
146
+ sourceOrderId: string | null;
147
+ amount: number;
148
+ remaining: number;
149
+ expiresAt: string | null;
150
+ grantedAt: string | null;
151
+ metadata?: Record<string, any> | null;
152
+ }
153
+ interface EntitlementCreditBucketConsumption {
154
+ key: string;
155
+ grantId: string | null;
156
+ amount: number;
157
+ expiresAt: string | null;
158
+ sourceProductId: string | null;
159
+ sourceOrderId: string | null;
160
+ }
133
161
  interface ActiveSubscriptionInfo {
134
162
  productId: string;
135
163
  productCode: string;
@@ -575,6 +603,18 @@ declare class PaymentClient {
575
603
  }): Promise<{
576
604
  balance: number;
577
605
  }>;
606
+ /**
607
+ * Consume numeric entitlements from an ordered key pool.
608
+ * Useful when subscription credits and perpetual credits use separate keys.
609
+ */
610
+ consumeEntitlementPool(userId: string, keys: string[], amount: number, options?: {
611
+ idempotencyKey?: string;
612
+ metadata?: Record<string, any>;
613
+ }): Promise<ConsumeEntitlementPoolResult>;
614
+ /**
615
+ * Get active numeric entitlement buckets ordered by expiration.
616
+ */
617
+ getEntitlementCreditBuckets(userId: string, keys?: string[]): Promise<EntitlementCreditBucket[]>;
578
618
  /**
579
619
  * Add numeric entitlement (e.g. refund)
580
620
  * @param userId - User ID
@@ -615,4 +655,4 @@ declare class PaymentClient {
615
655
  bindPhoneNumber(params: BindPhoneNumberParams): Promise<BindPhoneNumberResponse>;
616
656
  }
617
657
 
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 };
658
+ export { type ActiveSubscriptionInfo, type BindPhoneNumberParams, type BindPhoneNumberResponse, type CancelOrderResponse, type CompleteFreeOrderResponse, type ConsumeEntitlementPoolResult, type CreateBankTransferOrderParams, type CreateMiniProgramOrderParams, type CreateOrderParams, type CreateOrderResponse, type CustomAmountRechargeRule, type CustomAmountRechargeValidationResult, type EnsureUserWithTrialResponse, type EntitlementCreditBucket, type EntitlementCreditBucketConsumption, 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
@@ -354,6 +354,31 @@ var PaymentClient = class {
354
354
  ...options
355
355
  });
356
356
  }
357
+ /**
358
+ * Consume numeric entitlements from an ordered key pool.
359
+ * Useful when subscription credits and perpetual credits use separate keys.
360
+ */
361
+ async consumeEntitlementPool(userId, keys, amount, options) {
362
+ return this.request(
363
+ "POST",
364
+ `/users/${userId}/entitlements/consume-pool`,
365
+ {
366
+ keys,
367
+ amount,
368
+ ...options
369
+ }
370
+ );
371
+ }
372
+ /**
373
+ * Get active numeric entitlement buckets ordered by expiration.
374
+ */
375
+ async getEntitlementCreditBuckets(userId, keys) {
376
+ const query = keys && keys.length > 0 ? `?keys=${encodeURIComponent(keys.join(","))}` : "";
377
+ return this.request(
378
+ "GET",
379
+ `/users/${userId}/entitlements/credit-buckets${query}`
380
+ );
381
+ }
357
382
  /**
358
383
  * Add numeric entitlement (e.g. refund)
359
384
  * @param userId - User ID
@@ -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\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":[]}
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\tsubscriptionGroup?: string\n\trestrictSubscriptionPurchase?: boolean\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 ConsumeEntitlementPoolResult {\n\tbalance: number\n\tbalances: Record<string, number>\n\tconsumed: Record<string, number>\n\tconsumedBuckets?: EntitlementCreditBucketConsumption[]\n}\n\nexport interface EntitlementCreditBucket {\n\tkey: string\n\tgrantId: string | null\n\tsourceKind: string\n\tsourceProductId: string | null\n\tsourceOrderId: string | null\n\tamount: number\n\tremaining: number\n\texpiresAt: string | null\n\tgrantedAt: string | null\n\tmetadata?: Record<string, any> | null\n}\n\nexport interface EntitlementCreditBucketConsumption {\n\tkey: string\n\tgrantId: string | null\n\tamount: number\n\texpiresAt: string | null\n\tsourceProductId: string | null\n\tsourceOrderId: 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 * Consume numeric entitlements from an ordered key pool.\n\t * Useful when subscription credits and perpetual credits use separate keys.\n\t */\n\tasync consumeEntitlementPool(\n\t\tuserId: string,\n\t\tkeys: 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<ConsumeEntitlementPoolResult> {\n\t\treturn this.request(\n\t\t\t\"POST\",\n\t\t\t`/users/${userId}/entitlements/consume-pool`,\n\t\t\t{\n\t\t\t\tkeys,\n\t\t\t\tamount,\n\t\t\t\t...options,\n\t\t\t},\n\t\t)\n\t}\n\n\t/**\n\t * Get active numeric entitlement buckets ordered by expiration.\n\t */\n\tasync getEntitlementCreditBuckets(\n\t\tuserId: string,\n\t\tkeys?: string[],\n\t): Promise<EntitlementCreditBucket[]> {\n\t\tconst query =\n\t\t\tkeys && keys.length > 0\n\t\t\t\t? `?keys=${encodeURIComponent(keys.join(\",\"))}`\n\t\t\t\t: \"\"\n\t\treturn this.request(\n\t\t\t\"GET\",\n\t\t\t`/users/${userId}/entitlements/credit-buckets${query}`,\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":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@youidian/sdk",
3
- "version": "3.3.10",
3
+ "version": "3.4.1",
4
4
  "description": "Youidian Unified SDK - payment and hosted login SDK",
5
5
  "author": "Youidian",
6
6
  "license": "MIT",
@@ -19,6 +19,11 @@
19
19
  "import": "./dist/client.js",
20
20
  "require": "./dist/client.cjs"
21
21
  },
22
+ "./feedback": {
23
+ "types": "./dist/feedback.d.ts",
24
+ "import": "./dist/feedback.js",
25
+ "require": "./dist/feedback.cjs"
26
+ },
22
27
  "./server": {
23
28
  "types": "./dist/server.d.ts",
24
29
  "import": "./dist/server.js",