@waffo/pancake-ts 0.2.0 → 0.2.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/CHANGELOG.md CHANGED
@@ -4,6 +4,22 @@ All notable changes to `@waffo/pancake-ts` will be documented in this file.
4
4
 
5
5
  Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.2.1] - 2026-04-02
8
+
9
+ ### Added
10
+
11
+ - **Client-side input validation** — All resource methods now validate inputs before sending network requests. Checks include: required field presence, Short ID format (`STO_xxx`, `PROD_xxx`, etc.), ISO 4217 currency codes, ISO 3166-1 country codes, display-format amount strings, enum value ranges, and positive integers. Validation errors throw `WaffoPancakeError` with `status: 400` and `layer: "sdk"`, so developers catch them uniformly with API errors.
12
+ - **`ErrorLayer.Sdk`** — New `"sdk"` value in the `ErrorLayer` enum for client-side validation errors.
13
+
14
+ ### Fixed
15
+
16
+ - **Types** — `RefundTicketStatus` enum now includes all 9 statuses: added `UnderReview`, `Returned`, `Cancelled` (previously missing 3 values)
17
+ - **Types** — `RefundTicket.currentVersionId` corrected to `string | null` (was `string`)
18
+ - **Types** — `RefundTicket.versionNumber` corrected to `number | null` (was `number`)
19
+ - **Types** — `RefundTicket.versionData` corrected to `Record<string, unknown> | null` (was non-nullable)
20
+ - **Types** — `RefundTicket` now includes `createdAt` and `updatedAt` fields (previously missing)
21
+ - **Types** — `PriceInfo`, `Prices`, `WebhookEvent` JSDoc examples corrected from numeric amounts to display-format strings
22
+
7
23
  ## [0.2.0] - 2026-04-02
8
24
 
9
25
  ### Added
package/dist/index.cjs CHANGED
@@ -253,6 +253,105 @@ var HttpClient = class {
253
253
  }
254
254
  };
255
255
 
256
+ // src/validation.ts
257
+ var SHORT_ID_REGEX = /^[A-Z]{2,4}_[A-Za-z0-9]+$/;
258
+ var CURRENCY_CODE_REGEX = /^[A-Z]{3}$/;
259
+ var COUNTRY_CODE_REGEX = /^[A-Z]{2}$/;
260
+ var AMOUNT_STRING_REGEX = /^\d+(\.\d+)?$/;
261
+ var SHORT_ID_LABELS = {
262
+ STO: "Store",
263
+ PROD: "Product",
264
+ ORD: "Order",
265
+ PAY: "Payment",
266
+ REF: "Refund",
267
+ TKT: "Ticket",
268
+ MER: "Merchant"
269
+ };
270
+ function fail(message) {
271
+ throw new WaffoPancakeError(400, [{ message, layer: "sdk" }]);
272
+ }
273
+ function validateRequired(field, value) {
274
+ if (value === void 0 || value === null) {
275
+ fail(`Missing required field: ${field}`);
276
+ }
277
+ if (typeof value === "string" && value.trim() === "") {
278
+ fail(`${field} cannot be empty`);
279
+ }
280
+ }
281
+ function validateShortId(field, value, prefix) {
282
+ validateRequired(field, value);
283
+ const label = SHORT_ID_LABELS[prefix] ?? prefix;
284
+ if (!SHORT_ID_REGEX.test(value)) {
285
+ fail(`Invalid ${field}: expected ${label} Short ID format (${prefix}_xxx), got "${value}"`);
286
+ }
287
+ if (!value.startsWith(`${prefix}_`)) {
288
+ fail(`Invalid ${field}: expected ${prefix}_ prefix (${label}), got "${value.split("_")[0]}_"`);
289
+ }
290
+ }
291
+ function validateCurrencyCode(field, value) {
292
+ validateRequired(field, value);
293
+ if (!CURRENCY_CODE_REGEX.test(value)) {
294
+ fail(`Invalid ${field}: expected 3-letter ISO 4217 currency code (e.g., "USD"), got "${value}"`);
295
+ }
296
+ }
297
+ function validateAmountString(field, value) {
298
+ validateRequired(field, value);
299
+ if (!AMOUNT_STRING_REGEX.test(value)) {
300
+ fail(`Invalid ${field}: expected numeric string in display format (e.g., "9.99", "1000"), got "${value}"`);
301
+ }
302
+ }
303
+ function validateEnum(field, value, allowed) {
304
+ validateRequired(field, value);
305
+ if (!allowed.includes(value)) {
306
+ fail(`Invalid ${field}: expected one of [${allowed.join(", ")}], got "${value}"`);
307
+ }
308
+ }
309
+ function validatePositiveInteger(field, value) {
310
+ if (!Number.isInteger(value) || value <= 0) {
311
+ fail(`Invalid ${field}: expected positive integer, got ${value}`);
312
+ }
313
+ }
314
+ function validateCountryCode(field, value) {
315
+ validateRequired(field, value);
316
+ if (!COUNTRY_CODE_REGEX.test(value)) {
317
+ fail(`Invalid ${field}: expected 2-letter ISO 3166-1 country code (e.g., "US"), got "${value}"`);
318
+ }
319
+ }
320
+ function validatePrices(field, prices) {
321
+ validateRequired(field, prices);
322
+ const entries = Object.entries(prices);
323
+ if (entries.length === 0) {
324
+ fail(`${field} must contain at least one currency`);
325
+ }
326
+ for (const [currency, info] of entries) {
327
+ validateCurrencyCode(`${field}.${currency} (key)`, currency);
328
+ validateAmountString(`${field}.${currency}.amount`, info.amount);
329
+ validateRequired(`${field}.${currency}.taxCategory`, info.taxCategory);
330
+ }
331
+ }
332
+ function validateBillingDetail(detail) {
333
+ validateCountryCode("billingDetail.country", detail.country);
334
+ if (typeof detail.isBusiness !== "boolean") {
335
+ fail(`Invalid billingDetail.isBusiness: expected boolean, got ${typeof detail.isBusiness}`);
336
+ }
337
+ }
338
+ function validateCheckoutCommon(params) {
339
+ validateShortId("storeId", params.storeId, "STO");
340
+ validateShortId("productId", params.productId, "PROD");
341
+ validateEnum("productType", params.productType, ["onetime", "subscription"]);
342
+ validateCurrencyCode("currency", params.currency);
343
+ if (params.priceSnapshot) {
344
+ validateAmountString("priceSnapshot.amount", params.priceSnapshot.amount);
345
+ validateRequired("priceSnapshot.taxCategory", params.priceSnapshot.taxCategory);
346
+ }
347
+ if (params.billingDetail) {
348
+ validateBillingDetail(params.billingDetail);
349
+ }
350
+ if (params.expiresInSeconds !== void 0) {
351
+ validatePositiveInteger("expiresInSeconds", params.expiresInSeconds);
352
+ }
353
+ }
354
+
256
355
  // src/resources/auth.ts
257
356
  var AuthResource = class {
258
357
  constructor(http) {
@@ -271,6 +370,8 @@ var AuthResource = class {
271
370
  * });
272
371
  */
273
372
  async issueSessionToken(params) {
373
+ validateShortId("storeId", params.storeId, "STO");
374
+ validateRequired("buyerIdentity", params.buyerIdentity);
274
375
  return this.http.post("/v1/actions/auth/issue-session-token", params);
275
376
  }
276
377
  };
@@ -294,6 +395,7 @@ var BuyerSession = class {
294
395
  * // status: "canceled" (was pending) or "canceling" (was active)
295
396
  */
296
397
  async cancelSubscription(params) {
398
+ validateShortId("orderId", params.orderId, "ORD");
297
399
  return this.http.post(
298
400
  "/v1/actions/subscription-order/cancel-order",
299
401
  params
@@ -309,6 +411,7 @@ var BuyerSession = class {
309
411
  * const { orderId, status } = await buyer.cancelOnetimeOrder({ orderId: "ORD_xxx" });
310
412
  */
311
413
  async cancelOnetimeOrder(params) {
414
+ validateShortId("orderId", params.orderId, "ORD");
312
415
  return this.http.post(
313
416
  "/v1/actions/onetime-order/cancel-order",
314
417
  params
@@ -325,6 +428,7 @@ var BuyerSession = class {
325
428
  * // status: "active"
326
429
  */
327
430
  async reactivateSubscription(params) {
431
+ validateShortId("orderId", params.orderId, "ORD");
328
432
  return this.http.post(
329
433
  "/v1/actions/subscription-order/reactivate-order",
330
434
  params
@@ -344,6 +448,10 @@ var BuyerSession = class {
344
448
  * });
345
449
  */
346
450
  async createRefundTicket(params) {
451
+ validateShortId("paymentId", params.paymentId, "PAY");
452
+ validateRequired("reason", params.reason);
453
+ validateAmountString("requestedAmount.amount", params.requestedAmount.amount);
454
+ validateCurrencyCode("requestedAmount.currency", params.requestedAmount.currency);
347
455
  return this.http.post(
348
456
  "/v1/actions/refund-ticket/create-ticket",
349
457
  params
@@ -364,6 +472,11 @@ var BuyerSession = class {
364
472
  * });
365
473
  */
366
474
  async resubmitRefundTicket(params) {
475
+ validateShortId("ticketId", params.ticketId, "TKT");
476
+ validateShortId("paymentId", params.paymentId, "PAY");
477
+ validateRequired("reason", params.reason);
478
+ validateAmountString("requestedAmount.amount", params.requestedAmount.amount);
479
+ validateCurrencyCode("requestedAmount.currency", params.requestedAmount.currency);
367
480
  return this.http.post(
368
481
  "/v1/actions/refund-ticket/resubmit-ticket",
369
482
  params
@@ -386,6 +499,7 @@ var BuyerGraphQL = class {
386
499
  * });
387
500
  */
388
501
  async query(params) {
502
+ validateRequired("query", params.query);
389
503
  return this.http.post("/v1/graphql", params);
390
504
  }
391
505
  };
@@ -411,6 +525,7 @@ var CheckoutAnonymousResource = class {
411
525
  * // Redirect to result.checkoutUrl
412
526
  */
413
527
  async create(params) {
528
+ validateCheckoutCommon(params);
414
529
  return this.http.post(
415
530
  "/v1/actions/checkout/create-session",
416
531
  params
@@ -446,6 +561,8 @@ var CheckoutAuthenticatedResource = class {
446
561
  * // Redirect to result.checkoutUrl (includes #token=...)
447
562
  */
448
563
  async create(params) {
564
+ validateCheckoutCommon(params);
565
+ validateRequired("buyerIdentity", params.buyerIdentity);
449
566
  const { buyerIdentity, buyerEmail, ...sessionFields } = params;
450
567
  const [tokenResult, sessionResult] = await Promise.all([
451
568
  this.http.post("/v1/actions/auth/issue-session-token", {
@@ -526,6 +643,7 @@ var GraphQLResource = class {
526
643
  * });
527
644
  */
528
645
  async query(params) {
646
+ validateRequired("query", params.query);
529
647
  return this.http.post("/v1/graphql", params);
530
648
  }
531
649
  };
@@ -549,6 +667,9 @@ var OnetimeProductsResource = class {
549
667
  * });
550
668
  */
551
669
  async create(params) {
670
+ validateShortId("storeId", params.storeId, "STO");
671
+ validateRequired("name", params.name);
672
+ validatePrices("prices", params.prices);
552
673
  return this.http.post("/v1/actions/onetime-product/create-product", params);
553
674
  }
554
675
  /**
@@ -565,6 +686,9 @@ var OnetimeProductsResource = class {
565
686
  * });
566
687
  */
567
688
  async update(params) {
689
+ validateShortId("id", params.id, "PROD");
690
+ validateRequired("name", params.name);
691
+ validatePrices("prices", params.prices);
568
692
  return this.http.post("/v1/actions/onetime-product/update-product", params);
569
693
  }
570
694
  /**
@@ -577,6 +701,7 @@ var OnetimeProductsResource = class {
577
701
  * const { product } = await client.onetimeProducts.publish({ id: "PROD_xxx" });
578
702
  */
579
703
  async publish(params) {
704
+ validateShortId("id", params.id, "PROD");
580
705
  return this.http.post("/v1/actions/onetime-product/publish-product", params);
581
706
  }
582
707
  /**
@@ -592,6 +717,8 @@ var OnetimeProductsResource = class {
592
717
  * });
593
718
  */
594
719
  async updateStatus(params) {
720
+ validateShortId("id", params.id, "PROD");
721
+ validateEnum("status", params.status, ["active", "inactive"]);
595
722
  return this.http.post("/v1/actions/onetime-product/update-status", params);
596
723
  }
597
724
  };
@@ -617,6 +744,7 @@ var OrdersResource = class {
617
744
  * // status: "canceled" or "canceling"
618
745
  */
619
746
  async cancelSubscription(params) {
747
+ validateShortId("orderId", params.orderId, "ORD");
620
748
  return this.http.post("/v1/actions/subscription-order/cancel-order", params);
621
749
  }
622
750
  };
@@ -640,6 +768,9 @@ var StoreMerchantsResource = class {
640
768
  * });
641
769
  */
642
770
  async add(params) {
771
+ validateShortId("storeId", params.storeId, "STO");
772
+ validateRequired("email", params.email);
773
+ validateEnum("role", params.role, ["admin", "member"]);
643
774
  return this.http.post("/v1/actions/store-merchant/add-merchant", params);
644
775
  }
645
776
  /**
@@ -655,6 +786,8 @@ var StoreMerchantsResource = class {
655
786
  * });
656
787
  */
657
788
  async remove(params) {
789
+ validateShortId("storeId", params.storeId, "STO");
790
+ validateShortId("merchantId", params.merchantId, "MER");
658
791
  return this.http.post("/v1/actions/store-merchant/remove-merchant", params);
659
792
  }
660
793
  /**
@@ -671,6 +804,9 @@ var StoreMerchantsResource = class {
671
804
  * });
672
805
  */
673
806
  async updateRole(params) {
807
+ validateShortId("storeId", params.storeId, "STO");
808
+ validateShortId("merchantId", params.merchantId, "MER");
809
+ validateEnum("role", params.role, ["admin", "member"]);
674
810
  return this.http.post("/v1/actions/store-merchant/update-role", params);
675
811
  }
676
812
  };
@@ -690,6 +826,7 @@ var StoresResource = class {
690
826
  * const { store } = await client.stores.create({ name: "My Store" });
691
827
  */
692
828
  async create(params) {
829
+ validateRequired("name", params.name);
693
830
  return this.http.post("/v1/actions/store/create-store", params);
694
831
  }
695
832
  /**
@@ -705,6 +842,7 @@ var StoresResource = class {
705
842
  * });
706
843
  */
707
844
  async update(params) {
845
+ validateShortId("id", params.id, "STO");
708
846
  return this.http.post("/v1/actions/store/update-store", params);
709
847
  }
710
848
  /**
@@ -717,6 +855,7 @@ var StoresResource = class {
717
855
  * const { store } = await client.stores.delete({ id: "STO_xxx" });
718
856
  */
719
857
  async delete(params) {
858
+ validateShortId("id", params.id, "STO");
720
859
  return this.http.post("/v1/actions/store/delete-store", params);
721
860
  }
722
861
  };
@@ -741,6 +880,8 @@ var SubscriptionProductGroupsResource = class {
741
880
  * });
742
881
  */
743
882
  async create(params) {
883
+ validateShortId("storeId", params.storeId, "STO");
884
+ validateRequired("name", params.name);
744
885
  return this.http.post("/v1/actions/subscription-product-group/create-group", params);
745
886
  }
746
887
  /**
@@ -756,6 +897,7 @@ var SubscriptionProductGroupsResource = class {
756
897
  * });
757
898
  */
758
899
  async update(params) {
900
+ validateRequired("id", params.id);
759
901
  return this.http.post("/v1/actions/subscription-product-group/update-group", params);
760
902
  }
761
903
  /**
@@ -768,6 +910,7 @@ var SubscriptionProductGroupsResource = class {
768
910
  * const { group } = await client.subscriptionProductGroups.delete({ id: "GRP_xxx" });
769
911
  */
770
912
  async delete(params) {
913
+ validateRequired("id", params.id);
771
914
  return this.http.post("/v1/actions/subscription-product-group/delete-group", params);
772
915
  }
773
916
  /**
@@ -780,6 +923,7 @@ var SubscriptionProductGroupsResource = class {
780
923
  * const { group } = await client.subscriptionProductGroups.publish({ id: "GRP_xxx" });
781
924
  */
782
925
  async publish(params) {
926
+ validateRequired("id", params.id);
783
927
  return this.http.post("/v1/actions/subscription-product-group/publish-group", params);
784
928
  }
785
929
  };
@@ -804,6 +948,10 @@ var SubscriptionProductsResource = class {
804
948
  * });
805
949
  */
806
950
  async create(params) {
951
+ validateShortId("storeId", params.storeId, "STO");
952
+ validateRequired("name", params.name);
953
+ validateEnum("billingPeriod", params.billingPeriod, ["weekly", "monthly", "quarterly", "yearly"]);
954
+ validatePrices("prices", params.prices);
807
955
  return this.http.post("/v1/actions/subscription-product/create-product", params);
808
956
  }
809
957
  /**
@@ -821,6 +969,10 @@ var SubscriptionProductsResource = class {
821
969
  * });
822
970
  */
823
971
  async update(params) {
972
+ validateShortId("id", params.id, "PROD");
973
+ validateRequired("name", params.name);
974
+ validateEnum("billingPeriod", params.billingPeriod, ["weekly", "monthly", "quarterly", "yearly"]);
975
+ validatePrices("prices", params.prices);
824
976
  return this.http.post("/v1/actions/subscription-product/update-product", params);
825
977
  }
826
978
  /**
@@ -833,6 +985,7 @@ var SubscriptionProductsResource = class {
833
985
  * const { product } = await client.subscriptionProducts.publish({ id: "PROD_xxx" });
834
986
  */
835
987
  async publish(params) {
988
+ validateShortId("id", params.id, "PROD");
836
989
  return this.http.post("/v1/actions/subscription-product/publish-product", params);
837
990
  }
838
991
  /**
@@ -848,6 +1001,8 @@ var SubscriptionProductsResource = class {
848
1001
  * });
849
1002
  */
850
1003
  async updateStatus(params) {
1004
+ validateShortId("id", params.id, "PROD");
1005
+ validateEnum("status", params.status, ["active", "inactive"]);
851
1006
  return this.http.post("/v1/actions/subscription-product/update-status", params);
852
1007
  }
853
1008
  };
@@ -1116,11 +1271,14 @@ var PaymentStatus = /* @__PURE__ */ ((PaymentStatus2) => {
1116
1271
  })(PaymentStatus || {});
1117
1272
  var RefundTicketStatus = /* @__PURE__ */ ((RefundTicketStatus2) => {
1118
1273
  RefundTicketStatus2["Pending"] = "pending";
1274
+ RefundTicketStatus2["UnderReview"] = "under_review";
1119
1275
  RefundTicketStatus2["Approved"] = "approved";
1120
1276
  RefundTicketStatus2["Rejected"] = "rejected";
1277
+ RefundTicketStatus2["Returned"] = "returned";
1121
1278
  RefundTicketStatus2["Processing"] = "processing";
1122
1279
  RefundTicketStatus2["Succeeded"] = "succeeded";
1123
1280
  RefundTicketStatus2["Failed"] = "failed";
1281
+ RefundTicketStatus2["Cancelled"] = "cancelled";
1124
1282
  return RefundTicketStatus2;
1125
1283
  })(RefundTicketStatus || {});
1126
1284
  var RefundStatus = /* @__PURE__ */ ((RefundStatus2) => {
@@ -1148,6 +1306,7 @@ var ErrorLayer = /* @__PURE__ */ ((ErrorLayer2) => {
1148
1306
  ErrorLayer2["GraphQL"] = "graphql";
1149
1307
  ErrorLayer2["Resource"] = "resource";
1150
1308
  ErrorLayer2["Email"] = "email";
1309
+ ErrorLayer2["Sdk"] = "sdk";
1151
1310
  return ErrorLayer2;
1152
1311
  })(ErrorLayer || {});
1153
1312
  var WebhookEventType = /* @__PURE__ */ ((WebhookEventType2) => {