@waffo/waffo-node 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Waffo Node.js SDK
2
2
 
3
- <!-- Synced with waffo-sdk/README.md @ commit 53f0d42 -->
3
+ <!-- Synced with waffo-sdk/README.md @ commit 9405bd4 -->
4
4
 
5
5
  **English** | [中文](README_CN.md)
6
6
 
@@ -58,6 +58,7 @@ Official Node.js/TypeScript SDK for [Waffo Payment Platform](https://www.waffo.c
58
58
  - [Support](#support)
59
59
  - [License](#license)
60
60
  - [Development & Testing](#development-testing)
61
+ - [Open Business Values and Custom Events](#open-business-values-and-custom-events)
61
62
 
62
63
  ## Requirements
63
64
 
@@ -1208,6 +1209,60 @@ const signature = RsaUtils.sign(data, privateKey);
1208
1209
  const isValid = RsaUtils.verify(data, signature, publicKey);
1209
1210
  ```
1210
1211
 
1212
+ <!-- sdk-sync:start:Open%20Business%20Values%20and%20Custom%20Events -->
1213
+ ## Open Business Values and Custom Events
1214
+
1215
+ Business fields accept arbitrary strings and preserve their original value, including new statuses, currencies, products, periods and actions. The known constants are convenience values. A parsed response or a successful API code does not establish payment success; compare the relevant business status explicitly.
1216
+
1217
+ ### Read protocol values without changing existing calls
1218
+
1219
+ These offline examples show the real SDK model/accessor APIs. `FUTURE_STATUS` is synthetic and does not declare server support. Parsing or API code success does not establish business success.
1220
+
1221
+ ```typescript
1222
+ // Existing aliases/getData stay compatible; getData can contain future strings.
1223
+ // getOpenData/OpenBusinessValues opt into open strings: handle a default branch.
1224
+ // create/change preserve required fields; concrete eventType types stay fixed.
1225
+ import { ApiResponse, type InquirySubscriptionData } from '@waffo/waffo-node';
1226
+
1227
+ const source = JSON.parse('{"subscriptionStatus":"ACTIVE","paymentDetails":[{"orderStatus":"INIT"}]}');
1228
+ const response = ApiResponse.success<InquirySubscriptionData>(source);
1229
+ const data = response.getOpenData();
1230
+ console.log(data?.subscriptionStatus, data?.paymentDetails?.[0]?.orderStatus);
1231
+ if (data?.subscriptionStatus === 'FUTURE_STATUS') {
1232
+ console.warn('Unsupported business status:', data.subscriptionStatus);
1233
+ }
1234
+ ```
1235
+
1236
+ `WebhookEventType` and concrete built-in notification types remain the known event catalogue. Unknown events return a signed failure unless your application registers that exact name. Register before serving callbacks; custom registrations are per instance, case-sensitive, and a later registration replaces the same name. Built-in names use their dedicated methods. Blank names and invalid callbacks/configuration fail at registration with `S0006`; PHP rejects non-callable arguments with its native `TypeError`.
1237
+
1238
+ Java, Python and PHP custom callbacks must complete synchronously; PHP Promise/generator callbacks are unsupported. Python rejects async functions at registration and returns failure for an unexpected awaitable result. Node.js explicitly supports Promise callbacks.
1239
+
1240
+ The examples below take the **raw, unmodified UTF-8 body file** as their first argument and `WAFFO_WEBHOOK_SIGNATURE` as the request signature. Set `WAFFO_API_KEY`, `WAFFO_PRIVATE_KEY`, `WAFFO_PUBLIC_KEY` and Java/Python's `WAFFO_MERCHANT_ID` using your authorized configuration. They print the signed response header/body; in your HTTP adapter send those bytes with HTTP 200 and the `X-SIGNATURE` header. `EXAMPLE_CUSTOM_NOTIFICATION` is an offline example name: replace it and implement your business action against the event's real contract. Reject/throw/return an error if processing fails; Node.js awaits the callback, and Go converts callback errors or panics into failure responses.
1241
+
1242
+ ```typescript
1243
+ import { readFileSync } from 'node:fs';
1244
+ import { WebhookHandler, Environment } from '@waffo/waffo-node';
1245
+
1246
+ async function main() {
1247
+ const handler = new WebhookHandler({
1248
+ apiKey: process.env.WAFFO_API_KEY!,
1249
+ privateKey: process.env.WAFFO_PRIVATE_KEY!,
1250
+ waffoPublicKey: process.env.WAFFO_PUBLIC_KEY!,
1251
+ environment: Environment.SANDBOX,
1252
+ }).onEvent('EXAMPLE_CUSTOM_NOTIFICATION', async notification => {
1253
+ // Validate the event's documented fields and perform your business action here.
1254
+ console.error('Handled custom event:', notification.eventType);
1255
+ });
1256
+ const body = readFileSync(process.argv[2], 'utf8');
1257
+ const result = await handler.handleWebhook(body, process.env.WAFFO_WEBHOOK_SIGNATURE ?? '');
1258
+ if (!result.success) console.error(result.error);
1259
+ console.log('X-SIGNATURE: ' + result.responseSignature);
1260
+ console.log(result.responseBody);
1261
+ }
1262
+ main().catch(error => { console.error(error); process.exitCode = 1; });
1263
+ ```
1264
+ <!-- sdk-sync:end:Open%20Business%20Values%20and%20Custom%20Events -->
1265
+
1211
1266
  ## Handling New API Fields (ExtraParams)
1212
1267
 
1213
1268
  When Waffo API adds new fields that are not yet defined in the SDK, you can use the ExtraParams feature to access these fields without waiting for an SDK update.
package/dist/index.d.mts CHANGED
@@ -1607,6 +1607,7 @@ declare class WebhookHandler {
1607
1607
  private subscriptionPaymentHandler?;
1608
1608
  private subscriptionPeriodChangedHandler?;
1609
1609
  private subscriptionChangeHandler?;
1610
+ private readonly customEventHandlers;
1610
1611
  constructor(config: WaffoConfig);
1611
1612
  /**
1612
1613
  * Registers a handler for payment notifications.
@@ -1633,6 +1634,8 @@ declare class WebhookHandler {
1633
1634
  * Registers a handler for subscription change notifications.
1634
1635
  */
1635
1636
  onSubscriptionChange(handler: SubscriptionChangeHandler): this;
1637
+ /** Registers an exact custom event name before receiving webhooks. Later registration replaces the same name. */
1638
+ onEvent(eventType: string, handler: (notification: BaseNotification & Record<string, unknown>) => void | Promise<void>): this;
1636
1639
  /**
1637
1640
  * Processes a webhook notification.
1638
1641
  *
@@ -1667,6 +1670,11 @@ declare class WebhookHandler {
1667
1670
  private createFailedResult;
1668
1671
  }
1669
1672
 
1673
+ /** Optional view for JSON business data that preserves future protocol strings. */
1674
+ type OpenBusinessValues<T> = T extends string ? string : T extends object ? {
1675
+ [K in keyof T]: K extends 'eventType' ? T[K] : OpenBusinessValues<T[K]>;
1676
+ } : T;
1677
+
1670
1678
  /**
1671
1679
  * Generic API response wrapper.
1672
1680
  *
@@ -1717,6 +1725,8 @@ declare class ApiResponse<T> {
1717
1725
  * @returns The response data, or undefined if the response is an error
1718
1726
  */
1719
1727
  getData(): T | undefined;
1728
+ /** Returns the same JSON data with business string literals opened to future values. */
1729
+ getOpenData(): OpenBusinessValues<T> | undefined;
1720
1730
  /**
1721
1731
  * Gets the error message.
1722
1732
  *
@@ -1929,6 +1939,7 @@ declare class SubscriptionResource extends BaseResource {
1929
1939
  * @returns API response with subscription data
1930
1940
  * @throws WaffoUnknownStatusError for network errors
1931
1941
  */
1942
+ create(params: OpenBusinessValues<CreateSubscriptionParams>, options?: RequestOptions): Promise<ApiResponse<CreateSubscriptionData>>;
1932
1943
  create(params: CreateSubscriptionParams, options?: RequestOptions): Promise<ApiResponse<CreateSubscriptionData>>;
1933
1944
  /**
1934
1945
  * Queries an existing subscription.
@@ -2010,6 +2021,7 @@ declare class SubscriptionResource extends BaseResource {
2010
2021
  * }
2011
2022
  * ```
2012
2023
  */
2024
+ change(params: OpenBusinessValues<SubscriptionChangeParams>, options?: RequestOptions): Promise<ApiResponse<SubscriptionChangeData>>;
2013
2025
  change(params: SubscriptionChangeParams, options?: RequestOptions): Promise<ApiResponse<SubscriptionChangeData>>;
2014
2026
  /**
2015
2027
  * Queries the status of a subscription change.
@@ -2658,4 +2670,4 @@ declare const RsaUtils: {
2658
2670
  generateKeyPair: typeof generateKeyPair;
2659
2671
  };
2660
2672
 
2661
- export { type AddressInfo, ApiResponse, type BaseNotification, type CancelOrderData, type CancelOrderParams, type CancelSubscriptionData, type CancelSubscriptionParams, type CaptureOrderData, type CaptureOrderParams, type CardInfo, type CreateOrderData, type CreateOrderParams, type CreateSubscriptionData, type CreateSubscriptionParams, Environment, EnvironmentBaseUrl, type FixedMaintenanceRule, type GoodsInfo, type HttpRequest, type HttpResponse, type HttpTransport, type InquiryMerchantConfigData, type InquiryMerchantConfigParams, type InquiryOrderData, type InquiryOrderParams, type InquiryPayMethodConfigData, type InquiryPayMethodConfigParams, type InquiryRefundData, type InquiryRefundParams, type InquirySubscriptionData, type InquirySubscriptionParams, type ManageSubscriptionData, type ManageSubscriptionParams, MerchantConfigResource, type MerchantInfo, OrderResource, type OrderStatus, PayMethodConfigResource, type PayMethodDetail, type PayMethodInfo, type PaymentInfo, type PaymentNotification, type PaymentNotificationResult, type PeriodType, type ProductInfo, type PromotionInfo, type RefundNotification, type RefundNotificationResult, type RefundOrderData, type RefundOrderParams, RefundResource, type RefundStatus$1 as RefundStatus, type RefundUserInfo, type RequestOptions, type RiskData, RsaUtils, type SubscriptionChangeData, type SubscriptionChangeInquiryData, type SubscriptionChangeInquiryParams, type SubscriptionChangeParams, type SubscriptionChangeProductInfo, type SubscriptionChangeStatus, type SubscriptionInfo, type SubscriptionManageAction, type SubscriptionMerchantInfo, type SubscriptionNotificationResult, type SubscriptionPaymentDetail, type SubscriptionPaymentInfo, type SubscriptionPeriodChangedNotification, type SubscriptionPromotionInfo, SubscriptionResource, type SubscriptionScheduledAmount, type SubscriptionStatus, type SubscriptionStatusNotification, type SubscriptionUpdateProductInfo, type SubscriptionUpdateTopupData, type SubscriptionUpdateTopupInfo, type SubscriptionUserInfo, type UpdateSubscriptionData, type UpdateSubscriptionParams, type UserInfo, Waffo, type WaffoConfig, WaffoConfigDefaults, WaffoError, WaffoErrorCode, WaffoHttpClient, type WaffoLogger, WaffoUnknownStatusError, type WalletInquiryData, type WalletInquiryParams, WalletResource, WebhookEventType, WebhookHandler, type WebhookResult, type X402Info };
2673
+ export { type AddressInfo, ApiResponse, type BaseNotification, type CancelOrderData, type CancelOrderParams, type CancelSubscriptionData, type CancelSubscriptionParams, type CaptureOrderData, type CaptureOrderParams, type CardInfo, type CreateOrderData, type CreateOrderParams, type CreateSubscriptionData, type CreateSubscriptionParams, Environment, EnvironmentBaseUrl, type FixedMaintenanceRule, type GoodsInfo, type HttpRequest, type HttpResponse, type HttpTransport, type InquiryMerchantConfigData, type InquiryMerchantConfigParams, type InquiryOrderData, type InquiryOrderParams, type InquiryPayMethodConfigData, type InquiryPayMethodConfigParams, type InquiryRefundData, type InquiryRefundParams, type InquirySubscriptionData, type InquirySubscriptionParams, type ManageSubscriptionData, type ManageSubscriptionParams, MerchantConfigResource, type MerchantInfo, type OpenBusinessValues, OrderResource, type OrderStatus, PayMethodConfigResource, type PayMethodDetail, type PayMethodInfo, type PaymentInfo, type PaymentNotification, type PaymentNotificationResult, type PeriodType, type ProductInfo, type PromotionInfo, type RefundNotification, type RefundNotificationResult, type RefundOrderData, type RefundOrderParams, RefundResource, type RefundStatus$1 as RefundStatus, type RefundUserInfo, type RequestOptions, type RiskData, RsaUtils, type SubscriptionChangeData, type SubscriptionChangeInquiryData, type SubscriptionChangeInquiryParams, type SubscriptionChangeParams, type SubscriptionChangeProductInfo, type SubscriptionChangeStatus, type SubscriptionInfo, type SubscriptionManageAction, type SubscriptionMerchantInfo, type SubscriptionNotificationResult, type SubscriptionPaymentDetail, type SubscriptionPaymentInfo, type SubscriptionPeriodChangedNotification, type SubscriptionPromotionInfo, SubscriptionResource, type SubscriptionScheduledAmount, type SubscriptionStatus, type SubscriptionStatusNotification, type SubscriptionUpdateProductInfo, type SubscriptionUpdateTopupData, type SubscriptionUpdateTopupInfo, type SubscriptionUserInfo, type UpdateSubscriptionData, type UpdateSubscriptionParams, type UserInfo, Waffo, type WaffoConfig, WaffoConfigDefaults, WaffoError, WaffoErrorCode, WaffoHttpClient, type WaffoLogger, WaffoUnknownStatusError, type WalletInquiryData, type WalletInquiryParams, WalletResource, WebhookEventType, WebhookHandler, type WebhookResult, type X402Info };
package/dist/index.d.ts CHANGED
@@ -1607,6 +1607,7 @@ declare class WebhookHandler {
1607
1607
  private subscriptionPaymentHandler?;
1608
1608
  private subscriptionPeriodChangedHandler?;
1609
1609
  private subscriptionChangeHandler?;
1610
+ private readonly customEventHandlers;
1610
1611
  constructor(config: WaffoConfig);
1611
1612
  /**
1612
1613
  * Registers a handler for payment notifications.
@@ -1633,6 +1634,8 @@ declare class WebhookHandler {
1633
1634
  * Registers a handler for subscription change notifications.
1634
1635
  */
1635
1636
  onSubscriptionChange(handler: SubscriptionChangeHandler): this;
1637
+ /** Registers an exact custom event name before receiving webhooks. Later registration replaces the same name. */
1638
+ onEvent(eventType: string, handler: (notification: BaseNotification & Record<string, unknown>) => void | Promise<void>): this;
1636
1639
  /**
1637
1640
  * Processes a webhook notification.
1638
1641
  *
@@ -1667,6 +1670,11 @@ declare class WebhookHandler {
1667
1670
  private createFailedResult;
1668
1671
  }
1669
1672
 
1673
+ /** Optional view for JSON business data that preserves future protocol strings. */
1674
+ type OpenBusinessValues<T> = T extends string ? string : T extends object ? {
1675
+ [K in keyof T]: K extends 'eventType' ? T[K] : OpenBusinessValues<T[K]>;
1676
+ } : T;
1677
+
1670
1678
  /**
1671
1679
  * Generic API response wrapper.
1672
1680
  *
@@ -1717,6 +1725,8 @@ declare class ApiResponse<T> {
1717
1725
  * @returns The response data, or undefined if the response is an error
1718
1726
  */
1719
1727
  getData(): T | undefined;
1728
+ /** Returns the same JSON data with business string literals opened to future values. */
1729
+ getOpenData(): OpenBusinessValues<T> | undefined;
1720
1730
  /**
1721
1731
  * Gets the error message.
1722
1732
  *
@@ -1929,6 +1939,7 @@ declare class SubscriptionResource extends BaseResource {
1929
1939
  * @returns API response with subscription data
1930
1940
  * @throws WaffoUnknownStatusError for network errors
1931
1941
  */
1942
+ create(params: OpenBusinessValues<CreateSubscriptionParams>, options?: RequestOptions): Promise<ApiResponse<CreateSubscriptionData>>;
1932
1943
  create(params: CreateSubscriptionParams, options?: RequestOptions): Promise<ApiResponse<CreateSubscriptionData>>;
1933
1944
  /**
1934
1945
  * Queries an existing subscription.
@@ -2010,6 +2021,7 @@ declare class SubscriptionResource extends BaseResource {
2010
2021
  * }
2011
2022
  * ```
2012
2023
  */
2024
+ change(params: OpenBusinessValues<SubscriptionChangeParams>, options?: RequestOptions): Promise<ApiResponse<SubscriptionChangeData>>;
2013
2025
  change(params: SubscriptionChangeParams, options?: RequestOptions): Promise<ApiResponse<SubscriptionChangeData>>;
2014
2026
  /**
2015
2027
  * Queries the status of a subscription change.
@@ -2658,4 +2670,4 @@ declare const RsaUtils: {
2658
2670
  generateKeyPair: typeof generateKeyPair;
2659
2671
  };
2660
2672
 
2661
- export { type AddressInfo, ApiResponse, type BaseNotification, type CancelOrderData, type CancelOrderParams, type CancelSubscriptionData, type CancelSubscriptionParams, type CaptureOrderData, type CaptureOrderParams, type CardInfo, type CreateOrderData, type CreateOrderParams, type CreateSubscriptionData, type CreateSubscriptionParams, Environment, EnvironmentBaseUrl, type FixedMaintenanceRule, type GoodsInfo, type HttpRequest, type HttpResponse, type HttpTransport, type InquiryMerchantConfigData, type InquiryMerchantConfigParams, type InquiryOrderData, type InquiryOrderParams, type InquiryPayMethodConfigData, type InquiryPayMethodConfigParams, type InquiryRefundData, type InquiryRefundParams, type InquirySubscriptionData, type InquirySubscriptionParams, type ManageSubscriptionData, type ManageSubscriptionParams, MerchantConfigResource, type MerchantInfo, OrderResource, type OrderStatus, PayMethodConfigResource, type PayMethodDetail, type PayMethodInfo, type PaymentInfo, type PaymentNotification, type PaymentNotificationResult, type PeriodType, type ProductInfo, type PromotionInfo, type RefundNotification, type RefundNotificationResult, type RefundOrderData, type RefundOrderParams, RefundResource, type RefundStatus$1 as RefundStatus, type RefundUserInfo, type RequestOptions, type RiskData, RsaUtils, type SubscriptionChangeData, type SubscriptionChangeInquiryData, type SubscriptionChangeInquiryParams, type SubscriptionChangeParams, type SubscriptionChangeProductInfo, type SubscriptionChangeStatus, type SubscriptionInfo, type SubscriptionManageAction, type SubscriptionMerchantInfo, type SubscriptionNotificationResult, type SubscriptionPaymentDetail, type SubscriptionPaymentInfo, type SubscriptionPeriodChangedNotification, type SubscriptionPromotionInfo, SubscriptionResource, type SubscriptionScheduledAmount, type SubscriptionStatus, type SubscriptionStatusNotification, type SubscriptionUpdateProductInfo, type SubscriptionUpdateTopupData, type SubscriptionUpdateTopupInfo, type SubscriptionUserInfo, type UpdateSubscriptionData, type UpdateSubscriptionParams, type UserInfo, Waffo, type WaffoConfig, WaffoConfigDefaults, WaffoError, WaffoErrorCode, WaffoHttpClient, type WaffoLogger, WaffoUnknownStatusError, type WalletInquiryData, type WalletInquiryParams, WalletResource, WebhookEventType, WebhookHandler, type WebhookResult, type X402Info };
2673
+ export { type AddressInfo, ApiResponse, type BaseNotification, type CancelOrderData, type CancelOrderParams, type CancelSubscriptionData, type CancelSubscriptionParams, type CaptureOrderData, type CaptureOrderParams, type CardInfo, type CreateOrderData, type CreateOrderParams, type CreateSubscriptionData, type CreateSubscriptionParams, Environment, EnvironmentBaseUrl, type FixedMaintenanceRule, type GoodsInfo, type HttpRequest, type HttpResponse, type HttpTransport, type InquiryMerchantConfigData, type InquiryMerchantConfigParams, type InquiryOrderData, type InquiryOrderParams, type InquiryPayMethodConfigData, type InquiryPayMethodConfigParams, type InquiryRefundData, type InquiryRefundParams, type InquirySubscriptionData, type InquirySubscriptionParams, type ManageSubscriptionData, type ManageSubscriptionParams, MerchantConfigResource, type MerchantInfo, type OpenBusinessValues, OrderResource, type OrderStatus, PayMethodConfigResource, type PayMethodDetail, type PayMethodInfo, type PaymentInfo, type PaymentNotification, type PaymentNotificationResult, type PeriodType, type ProductInfo, type PromotionInfo, type RefundNotification, type RefundNotificationResult, type RefundOrderData, type RefundOrderParams, RefundResource, type RefundStatus$1 as RefundStatus, type RefundUserInfo, type RequestOptions, type RiskData, RsaUtils, type SubscriptionChangeData, type SubscriptionChangeInquiryData, type SubscriptionChangeInquiryParams, type SubscriptionChangeParams, type SubscriptionChangeProductInfo, type SubscriptionChangeStatus, type SubscriptionInfo, type SubscriptionManageAction, type SubscriptionMerchantInfo, type SubscriptionNotificationResult, type SubscriptionPaymentDetail, type SubscriptionPaymentInfo, type SubscriptionPeriodChangedNotification, type SubscriptionPromotionInfo, SubscriptionResource, type SubscriptionScheduledAmount, type SubscriptionStatus, type SubscriptionStatusNotification, type SubscriptionUpdateProductInfo, type SubscriptionUpdateTopupData, type SubscriptionUpdateTopupInfo, type SubscriptionUserInfo, type UpdateSubscriptionData, type UpdateSubscriptionParams, type UserInfo, Waffo, type WaffoConfig, WaffoConfigDefaults, WaffoError, WaffoErrorCode, WaffoHttpClient, type WaffoLogger, WaffoUnknownStatusError, type WalletInquiryData, type WalletInquiryParams, WalletResource, WebhookEventType, WebhookHandler, type WebhookResult, type X402Info };
package/dist/index.js CHANGED
@@ -370,6 +370,10 @@ var ApiResponse = class _ApiResponse {
370
370
  getData() {
371
371
  return this.data;
372
372
  }
373
+ /** Returns the same JSON data with business string literals opened to future values. */
374
+ getOpenData() {
375
+ return this.data;
376
+ }
373
377
  /**
374
378
  * Gets the error message.
375
379
  *
@@ -477,7 +481,7 @@ var HEADER_SDK_VERSION = "x-sdk-version";
477
481
  var HEADER_CONTENT_TYPE = "content-type";
478
482
  var CONTENT_TYPE_JSON = "application/json";
479
483
  var API_VERSION = "1.0.0";
480
- var SDK_VERSION = "waffo-node/3.1.0";
484
+ var SDK_VERSION = "waffo-node/3.2.0";
481
485
  var WaffoHttpClient = class {
482
486
  baseUrl;
483
487
  apiKey;
@@ -668,6 +672,7 @@ var WebhookHandler = class {
668
672
  subscriptionPaymentHandler;
669
673
  subscriptionPeriodChangedHandler;
670
674
  subscriptionChangeHandler;
675
+ customEventHandlers = /* @__PURE__ */ new Map();
671
676
  constructor(config) {
672
677
  this.waffoPublicKey = config.waffoPublicKey;
673
678
  this.privateKey = config.privateKey;
@@ -716,6 +721,20 @@ var WebhookHandler = class {
716
721
  this.subscriptionChangeHandler = handler;
717
722
  return this;
718
723
  }
724
+ /** Registers an exact custom event name before receiving webhooks. Later registration replaces the same name. */
725
+ onEvent(eventType, handler) {
726
+ if (typeof eventType !== "string" || !eventType.trim()) {
727
+ throw new WaffoError(WaffoErrorCode.UNEXPECTED, "Custom event name must not be blank");
728
+ }
729
+ if (typeof handler !== "function") {
730
+ throw new WaffoError(WaffoErrorCode.UNEXPECTED, "Custom event handler must be a function");
731
+ }
732
+ if (Object.values(WebhookEventType).some((known) => known === eventType)) {
733
+ throw new WaffoError(WaffoErrorCode.UNEXPECTED, `Use the dedicated handler for built-in event: ${eventType}`);
734
+ }
735
+ this.customEventHandlers.set(eventType, handler);
736
+ return this;
737
+ }
719
738
  /**
720
739
  * Processes a webhook notification.
721
740
  *
@@ -735,6 +754,9 @@ var WebhookHandler = class {
735
754
  return this.createFailedResult("Invalid signature");
736
755
  }
737
756
  const parsed = JSON.parse(body);
757
+ if (!parsed || typeof parsed.eventType !== "string") {
758
+ return this.createFailedResult("Unknown event type");
759
+ }
738
760
  const eventType = parsed.eventType;
739
761
  switch (eventType) {
740
762
  case "PAYMENT_NOTIFICATION" /* PAYMENT_NOTIFICATION */:
@@ -764,9 +786,15 @@ var WebhookHandler = class {
764
786
  await this.subscriptionChangeHandler(parsed);
765
787
  }
766
788
  break;
767
- default:
768
- this.logger?.warn(`Unknown webhook event type: ${eventType}`);
769
- return this.createFailedResult(`Unknown event type: ${eventType}`);
789
+ default: {
790
+ const handler = this.customEventHandlers.get(eventType);
791
+ if (!handler) {
792
+ this.logger?.warn(`Unknown webhook event type: ${eventType}`);
793
+ return this.createFailedResult(`Unknown event type: ${eventType}`);
794
+ }
795
+ await handler(parsed);
796
+ break;
797
+ }
770
798
  }
771
799
  return this.createSuccessResult();
772
800
  } catch (error) {
@@ -959,14 +987,6 @@ var SubscriptionResource = class _SubscriptionResource extends BaseResource {
959
987
  static PATH_UPDATE = "/update";
960
988
  static PATH_CHANGE = "/change";
961
989
  static PATH_CHANGE_INQUIRY = "/change/inquiry";
962
- /**
963
- * Creates a new subscription.
964
- *
965
- * @param params - Subscription creation parameters
966
- * @param options - Optional request options
967
- * @returns API response with subscription data
968
- * @throws WaffoUnknownStatusError for network errors
969
- */
970
990
  async create(params, options) {
971
991
  if (!params.requestedAt) {
972
992
  params.requestedAt = getCurrentTimestamp();
@@ -1048,47 +1068,6 @@ var SubscriptionResource = class _SubscriptionResource extends BaseResource {
1048
1068
  null
1049
1069
  );
1050
1070
  }
1051
- /**
1052
- * Changes (upgrades/downgrades) an existing subscription.
1053
- *
1054
- * This method allows changing an active subscription to a new plan with different
1055
- * pricing, billing period, or other terms. The remaining amount from the original
1056
- * subscription can be applied to the new subscription.
1057
- *
1058
- * @param params - Subscription change parameters
1059
- * @param options - Optional request options
1060
- * @returns API response with change result
1061
- * @throws WaffoUnknownStatusError for network errors
1062
- *
1063
- * @example
1064
- * ```typescript
1065
- * const response = await waffo.subscription().change({
1066
- * subscriptionRequest: 'new-request-id',
1067
- * originSubscriptionRequest: 'original-request-id',
1068
- * remainingAmount: '50.00',
1069
- * currency: 'HKD',
1070
- * requestedAt: new Date().toISOString(),
1071
- * notifyUrl: 'https://example.com/webhook',
1072
- * productInfoList: [{
1073
- * description: 'Premium Monthly',
1074
- * periodType: 'MONTH',
1075
- * periodInterval: '1',
1076
- * amount: '199.00',
1077
- * }],
1078
- * userInfo: { userId: 'user-123', userEmail: 'user@example.com' },
1079
- * goodsInfo: { goodsId: 'premium', goodsName: 'Premium Plan' },
1080
- * paymentInfo: { productName: 'SUBSCRIPTION' },
1081
- * });
1082
- *
1083
- * if (response.isSuccess()) {
1084
- * const data = response.getData();
1085
- * if (data?.subscriptionChangeStatus === 'AUTHORIZATION_REQUIRED') {
1086
- * // Redirect user to authorization URL
1087
- * const webUrl = JSON.parse(data.subscriptionAction || '{}').webUrl;
1088
- * }
1089
- * }
1090
- * ```
1091
- */
1092
1071
  async change(params, options) {
1093
1072
  if (!params.requestedAt) {
1094
1073
  params.requestedAt = getCurrentTimestamp();