@waffo/pancake-ts 0.1.7 → 0.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/dist/index.js CHANGED
@@ -1,6 +1,3 @@
1
- // src/http-client.ts
2
- import { createHash as createHash2 } from "crypto";
3
-
4
1
  // src/errors.ts
5
2
  var WaffoPancakeError = class extends Error {
6
3
  status;
@@ -14,6 +11,45 @@ var WaffoPancakeError = class extends Error {
14
11
  }
15
12
  };
16
13
 
14
+ // src/buyer-http-client.ts
15
+ var DEFAULT_BASE_URL = "https://api.waffo.ai";
16
+ var BuyerHttpClient = class {
17
+ token;
18
+ baseUrl;
19
+ _fetch;
20
+ constructor(token, config) {
21
+ this.token = token;
22
+ this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
23
+ this._fetch = config.fetch ?? fetch;
24
+ }
25
+ /**
26
+ * Send a Bearer-authenticated POST request and return the parsed `data` field.
27
+ *
28
+ * @param path - API path
29
+ * @param body - Request body object
30
+ * @returns Parsed `data` field from the response
31
+ * @throws {WaffoPancakeError} When the API returns errors
32
+ */
33
+ async post(path, body) {
34
+ const response = await this._fetch(`${this.baseUrl}${path}`, {
35
+ method: "POST",
36
+ headers: {
37
+ "Content-Type": "application/json",
38
+ "Authorization": `Bearer ${this.token}`
39
+ },
40
+ body: JSON.stringify(body)
41
+ });
42
+ const result = await response.json();
43
+ if ("errors" in result && result.errors) {
44
+ throw new WaffoPancakeError(response.status, result.errors);
45
+ }
46
+ return result.data;
47
+ }
48
+ };
49
+
50
+ // src/http-client.ts
51
+ import { createHash as createHash2 } from "crypto";
52
+
17
53
  // src/signing.ts
18
54
  import { createHash, createPrivateKey, createPublicKey, createSign } from "crypto";
19
55
  var PKCS8_HEADER = "-----BEGIN PRIVATE KEY-----";
@@ -126,7 +162,7 @@ ${bodyHash}`;
126
162
  }
127
163
 
128
164
  // src/http-client.ts
129
- var DEFAULT_BASE_URL = "https://waffo-pancake-auth-service.vercel.app";
165
+ var DEFAULT_BASE_URL2 = "https://api.waffo.ai";
130
166
  var HttpClient = class {
131
167
  merchantId;
132
168
  privateKey;
@@ -135,7 +171,7 @@ var HttpClient = class {
135
171
  constructor(config) {
136
172
  this.merchantId = config.merchantId;
137
173
  this.privateKey = normalizePrivateKey(config.privateKey);
138
- this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
174
+ this.baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL2).replace(/\/+$/, "");
139
175
  this._fetch = config.fetch ?? fetch;
140
176
  }
141
177
  /**
@@ -187,7 +223,7 @@ var AuthResource = class {
187
223
  *
188
224
  * @example
189
225
  * const { token, expiresAt } = await client.auth.issueSessionToken({
190
- * storeId: "store_xxx",
226
+ * storeId: "STO_xxx",
191
227
  * buyerIdentity: "customer@example.com",
192
228
  * });
193
229
  */
@@ -196,21 +232,222 @@ var AuthResource = class {
196
232
  }
197
233
  };
198
234
 
235
+ // src/resources/buyer.ts
236
+ var BuyerSession = class {
237
+ constructor(http) {
238
+ this.http = http;
239
+ this.graphql = new BuyerGraphQL(http);
240
+ }
241
+ /** GraphQL query access scoped to the buyer's data. */
242
+ graphql;
243
+ /**
244
+ * Cancel a subscription order.
245
+ *
246
+ * @param params - Order to cancel
247
+ * @returns Order ID and resulting status
248
+ *
249
+ * @example
250
+ * const { orderId, status } = await buyer.cancelSubscription({ orderId: "ORD_xxx" });
251
+ * // status: "canceled" (was pending) or "canceling" (was active)
252
+ */
253
+ async cancelSubscription(params) {
254
+ return this.http.post(
255
+ "/v1/actions/subscription-order/cancel-order",
256
+ params
257
+ );
258
+ }
259
+ /**
260
+ * Cancel a one-time order (only while payment is still pending).
261
+ *
262
+ * @param params - Order to cancel
263
+ * @returns Order ID and resulting status
264
+ *
265
+ * @example
266
+ * const { orderId, status } = await buyer.cancelOnetimeOrder({ orderId: "ORD_xxx" });
267
+ */
268
+ async cancelOnetimeOrder(params) {
269
+ return this.http.post(
270
+ "/v1/actions/onetime-order/cancel-order",
271
+ params
272
+ );
273
+ }
274
+ /**
275
+ * Reactivate a subscription that is in `canceling` status.
276
+ *
277
+ * @param params - Order to reactivate
278
+ * @returns Order ID and resulting status
279
+ *
280
+ * @example
281
+ * const { orderId, status } = await buyer.reactivateSubscription({ orderId: "ORD_xxx" });
282
+ * // status: "active"
283
+ */
284
+ async reactivateSubscription(params) {
285
+ return this.http.post(
286
+ "/v1/actions/subscription-order/reactivate-order",
287
+ params
288
+ );
289
+ }
290
+ /**
291
+ * Submit a refund request for a payment.
292
+ *
293
+ * @param params - Refund ticket details
294
+ * @returns Created refund ticket
295
+ *
296
+ * @example
297
+ * const { ticket } = await buyer.createRefundTicket({
298
+ * paymentId: "PAY_xxx",
299
+ * reason: "Product not as described",
300
+ * requestedAmount: { amount: "29.00", currency: "USD" },
301
+ * });
302
+ */
303
+ async createRefundTicket(params) {
304
+ return this.http.post(
305
+ "/v1/actions/refund-ticket/create-ticket",
306
+ params
307
+ );
308
+ }
309
+ /**
310
+ * Resubmit a previously rejected refund ticket with updated details.
311
+ *
312
+ * @param params - Updated ticket details
313
+ * @returns Updated refund ticket
314
+ *
315
+ * @example
316
+ * const { ticket } = await buyer.resubmitRefundTicket({
317
+ * ticketId: "TKT_xxx",
318
+ * paymentId: "PAY_xxx",
319
+ * reason: "Updated reason with more detail",
320
+ * requestedAmount: { amount: "29.00", currency: "USD" },
321
+ * });
322
+ */
323
+ async resubmitRefundTicket(params) {
324
+ return this.http.post(
325
+ "/v1/actions/refund-ticket/resubmit-ticket",
326
+ params
327
+ );
328
+ }
329
+ };
330
+ var BuyerGraphQL = class {
331
+ constructor(http) {
332
+ this.http = http;
333
+ }
334
+ /**
335
+ * Execute a GraphQL query scoped to the buyer's data.
336
+ *
337
+ * @param params - GraphQL query and variables
338
+ * @returns GraphQL response
339
+ *
340
+ * @example
341
+ * const result = await buyer.graphql.query({
342
+ * query: `query { orders { id status } }`,
343
+ * });
344
+ */
345
+ async query(params) {
346
+ return this.http.post("/v1/graphql", params);
347
+ }
348
+ };
349
+
350
+ // src/resources/checkout-anonymous.ts
351
+ var CheckoutAnonymousResource = class {
352
+ constructor(http) {
353
+ this.http = http;
354
+ }
355
+ /**
356
+ * Create an anonymous checkout session.
357
+ *
358
+ * @param params - Checkout parameters (no buyer identity required)
359
+ * @returns Session ID, checkout URL, and expiration
360
+ *
361
+ * @example
362
+ * const result = await client.checkout.anonymous.create({
363
+ * storeId: "STO_xxx",
364
+ * productId: "PROD_xxx",
365
+ * productType: "onetime",
366
+ * currency: "USD",
367
+ * });
368
+ * // Redirect to result.checkoutUrl
369
+ */
370
+ async create(params) {
371
+ return this.http.post(
372
+ "/v1/actions/checkout/create-session",
373
+ params
374
+ );
375
+ }
376
+ };
377
+
378
+ // src/resources/checkout-authenticated.ts
379
+ var CheckoutAuthenticatedResource = class {
380
+ constructor(http) {
381
+ this.http = http;
382
+ }
383
+ /**
384
+ * Create an authenticated checkout session.
385
+ *
386
+ * Behavior:
387
+ * - Issues a session token via `issue-session-token`
388
+ * - Creates a checkout session via `create-session`
389
+ * - Appends the token to the checkout URL as a URL fragment
390
+ * - Defaults `buyerEmail` to `buyerIdentity` when omitted
391
+ *
392
+ * @param params - Checkout parameters including buyer identity
393
+ * @returns Session details with token-appended checkout URL
394
+ *
395
+ * @example
396
+ * const result = await client.checkout.authenticated.create({
397
+ * storeId: "STO_xxx",
398
+ * productId: "PROD_xxx",
399
+ * productType: "onetime",
400
+ * currency: "USD",
401
+ * buyerIdentity: "customer@example.com",
402
+ * });
403
+ * // Redirect to result.checkoutUrl (includes #token=...)
404
+ */
405
+ async create(params) {
406
+ const { buyerIdentity, buyerEmail, ...sessionFields } = params;
407
+ const [tokenResult, sessionResult] = await Promise.all([
408
+ this.http.post("/v1/actions/auth/issue-session-token", {
409
+ storeId: params.storeId,
410
+ buyerIdentity
411
+ }),
412
+ this.http.post("/v1/actions/checkout/create-session", {
413
+ ...sessionFields,
414
+ buyerEmail: buyerEmail ?? buyerIdentity
415
+ })
416
+ ]);
417
+ return {
418
+ sessionId: sessionResult.sessionId,
419
+ checkoutUrl: `${sessionResult.checkoutUrl}#token=${tokenResult.token}`,
420
+ expiresAt: sessionResult.expiresAt,
421
+ token: tokenResult.token,
422
+ tokenExpiresAt: tokenResult.expiresAt
423
+ };
424
+ }
425
+ };
426
+
199
427
  // src/resources/checkout.ts
200
428
  var CheckoutResource = class {
201
429
  constructor(http) {
202
430
  this.http = http;
431
+ this.anonymous = new CheckoutAnonymousResource(http);
432
+ this.authenticated = new CheckoutAuthenticatedResource(http);
203
433
  }
434
+ /** Anonymous checkout — no buyer identity, empty form. */
435
+ anonymous;
436
+ /** Authenticated checkout — merchant provides buyer identity. */
437
+ authenticated;
204
438
  /**
205
- * Create a checkout session. Returns a URL to redirect the customer to.
439
+ * Create a checkout session (low-level). Returns a URL to redirect the customer to.
440
+ *
441
+ * For most use cases, prefer `checkout.anonymous.create()` or
442
+ * `checkout.authenticated.create()` which handle the full flow automatically.
206
443
  *
207
444
  * @param params - Checkout session parameters
208
445
  * @returns Session ID, checkout URL, and expiration
209
446
  *
210
447
  * @example
211
448
  * const session = await client.checkout.createSession({
212
- * storeId: "store_xxx",
213
- * productId: "prod_xxx",
449
+ * storeId: "STO_xxx",
450
+ * productId: "PROD_xxx",
214
451
  * productType: "onetime",
215
452
  * currency: "USD",
216
453
  * buyerEmail: "customer@example.com",
@@ -242,7 +479,7 @@ var GraphQLResource = class {
242
479
  * @example
243
480
  * const result = await client.graphql.query({
244
481
  * query: `query ($id: ID!) { onetimeProduct(id: $id) { id name prices } }`,
245
- * variables: { id: "prod_xxx" },
482
+ * variables: { id: "PROD_xxx" },
246
483
  * });
247
484
  */
248
485
  async query(params) {
@@ -263,9 +500,9 @@ var OnetimeProductsResource = class {
263
500
  *
264
501
  * @example
265
502
  * const { product } = await client.onetimeProducts.create({
266
- * storeId: "store_xxx",
503
+ * storeId: "STO_xxx",
267
504
  * name: "E-Book",
268
- * prices: { USD: { amount: 2900, taxCategory: "digital_goods" } },
505
+ * prices: { USD: { amount: "29.00", taxCategory: "digital_goods" } },
269
506
  * });
270
507
  */
271
508
  async create(params) {
@@ -279,9 +516,9 @@ var OnetimeProductsResource = class {
279
516
  *
280
517
  * @example
281
518
  * const { product } = await client.onetimeProducts.update({
282
- * id: "prod_xxx",
519
+ * id: "PROD_xxx",
283
520
  * name: "E-Book v2",
284
- * prices: { USD: { amount: 3900, taxCategory: "digital_goods" } },
521
+ * prices: { USD: { amount: "39.00", taxCategory: "digital_goods" } },
285
522
  * });
286
523
  */
287
524
  async update(params) {
@@ -294,7 +531,7 @@ var OnetimeProductsResource = class {
294
531
  * @returns Published product detail
295
532
  *
296
533
  * @example
297
- * const { product } = await client.onetimeProducts.publish({ id: "prod_xxx" });
534
+ * const { product } = await client.onetimeProducts.publish({ id: "PROD_xxx" });
298
535
  */
299
536
  async publish(params) {
300
537
  return this.http.post("/v1/actions/onetime-product/publish-product", params);
@@ -307,7 +544,7 @@ var OnetimeProductsResource = class {
307
544
  *
308
545
  * @example
309
546
  * const { product } = await client.onetimeProducts.updateStatus({
310
- * id: "prod_xxx",
547
+ * id: "PROD_xxx",
311
548
  * status: ProductVersionStatus.Inactive,
312
549
  * });
313
550
  */
@@ -332,7 +569,7 @@ var OrdersResource = class {
332
569
  *
333
570
  * @example
334
571
  * const { orderId, status } = await client.orders.cancelSubscription({
335
- * orderId: "order_xxx",
572
+ * orderId: "ORD_xxx",
336
573
  * });
337
574
  * // status: "canceled" or "canceling"
338
575
  */
@@ -354,7 +591,7 @@ var StoreMerchantsResource = class {
354
591
  *
355
592
  * @example
356
593
  * const result = await client.storeMerchants.add({
357
- * storeId: "store_xxx",
594
+ * storeId: "STO_xxx",
358
595
  * email: "member@example.com",
359
596
  * role: "admin",
360
597
  * });
@@ -370,8 +607,8 @@ var StoreMerchantsResource = class {
370
607
  *
371
608
  * @example
372
609
  * const result = await client.storeMerchants.remove({
373
- * storeId: "store_xxx",
374
- * merchantId: "merchant_xxx",
610
+ * storeId: "STO_xxx",
611
+ * merchantId: "MER_xxx",
375
612
  * });
376
613
  */
377
614
  async remove(params) {
@@ -385,8 +622,8 @@ var StoreMerchantsResource = class {
385
622
  *
386
623
  * @example
387
624
  * const result = await client.storeMerchants.updateRole({
388
- * storeId: "store_xxx",
389
- * merchantId: "merchant_xxx",
625
+ * storeId: "STO_xxx",
626
+ * merchantId: "MER_xxx",
390
627
  * role: "member",
391
628
  * });
392
629
  */
@@ -420,7 +657,7 @@ var StoresResource = class {
420
657
  *
421
658
  * @example
422
659
  * const { store } = await client.stores.update({
423
- * id: "store_xxx",
660
+ * id: "STO_xxx",
424
661
  * name: "Updated Name",
425
662
  * });
426
663
  */
@@ -434,7 +671,7 @@ var StoresResource = class {
434
671
  * @returns Deleted store entity (with `deletedAt` set)
435
672
  *
436
673
  * @example
437
- * const { store } = await client.stores.delete({ id: "store_xxx" });
674
+ * const { store } = await client.stores.delete({ id: "STO_xxx" });
438
675
  */
439
676
  async delete(params) {
440
677
  return this.http.post("/v1/actions/store/delete-store", params);
@@ -454,10 +691,10 @@ var SubscriptionProductGroupsResource = class {
454
691
  *
455
692
  * @example
456
693
  * const { group } = await client.subscriptionProductGroups.create({
457
- * storeId: "store_xxx",
694
+ * storeId: "STO_xxx",
458
695
  * name: "Pro Plans",
459
696
  * rules: { sharedTrial: true },
460
- * productIds: ["prod_aaa", "prod_bbb"],
697
+ * productIds: ["PROD_aaa", "PROD_bbb"],
461
698
  * });
462
699
  */
463
700
  async create(params) {
@@ -471,8 +708,8 @@ var SubscriptionProductGroupsResource = class {
471
708
  *
472
709
  * @example
473
710
  * const { group } = await client.subscriptionProductGroups.update({
474
- * id: "group_xxx",
475
- * productIds: ["prod_aaa", "prod_bbb", "prod_ccc"],
711
+ * id: "GRP_xxx",
712
+ * productIds: ["PROD_aaa", "PROD_bbb", "PROD_ccc"],
476
713
  * });
477
714
  */
478
715
  async update(params) {
@@ -485,7 +722,7 @@ var SubscriptionProductGroupsResource = class {
485
722
  * @returns Deleted group entity
486
723
  *
487
724
  * @example
488
- * const { group } = await client.subscriptionProductGroups.delete({ id: "group_xxx" });
725
+ * const { group } = await client.subscriptionProductGroups.delete({ id: "GRP_xxx" });
489
726
  */
490
727
  async delete(params) {
491
728
  return this.http.post("/v1/actions/subscription-product-group/delete-group", params);
@@ -497,7 +734,7 @@ var SubscriptionProductGroupsResource = class {
497
734
  * @returns Published group entity
498
735
  *
499
736
  * @example
500
- * const { group } = await client.subscriptionProductGroups.publish({ id: "group_xxx" });
737
+ * const { group } = await client.subscriptionProductGroups.publish({ id: "GRP_xxx" });
501
738
  */
502
739
  async publish(params) {
503
740
  return this.http.post("/v1/actions/subscription-product-group/publish-group", params);
@@ -517,10 +754,10 @@ var SubscriptionProductsResource = class {
517
754
  *
518
755
  * @example
519
756
  * const { product } = await client.subscriptionProducts.create({
520
- * storeId: "store_xxx",
757
+ * storeId: "STO_xxx",
521
758
  * name: "Pro Plan",
522
759
  * billingPeriod: "monthly",
523
- * prices: { USD: { amount: 999, taxCategory: "saas" } },
760
+ * prices: { USD: { amount: "9.99", taxCategory: "saas" } },
524
761
  * });
525
762
  */
526
763
  async create(params) {
@@ -534,10 +771,10 @@ var SubscriptionProductsResource = class {
534
771
  *
535
772
  * @example
536
773
  * const { product } = await client.subscriptionProducts.update({
537
- * id: "prod_xxx",
774
+ * id: "PROD_xxx",
538
775
  * name: "Pro Plan v2",
539
776
  * billingPeriod: "monthly",
540
- * prices: { USD: { amount: 1499, taxCategory: "saas" } },
777
+ * prices: { USD: { amount: "14.99", taxCategory: "saas" } },
541
778
  * });
542
779
  */
543
780
  async update(params) {
@@ -550,7 +787,7 @@ var SubscriptionProductsResource = class {
550
787
  * @returns Published product detail
551
788
  *
552
789
  * @example
553
- * const { product } = await client.subscriptionProducts.publish({ id: "prod_xxx" });
790
+ * const { product } = await client.subscriptionProducts.publish({ id: "PROD_xxx" });
554
791
  */
555
792
  async publish(params) {
556
793
  return this.http.post("/v1/actions/subscription-product/publish-product", params);
@@ -563,7 +800,7 @@ var SubscriptionProductsResource = class {
563
800
  *
564
801
  * @example
565
802
  * const { product } = await client.subscriptionProducts.updateStatus({
566
- * id: "prod_xxx",
803
+ * id: "PROD_xxx",
567
804
  * status: ProductVersionStatus.Active,
568
805
  * });
569
806
  */
@@ -719,6 +956,7 @@ var WebhooksResource = class {
719
956
  // src/client.ts
720
957
  var WaffoPancake = class {
721
958
  http;
959
+ config;
722
960
  auth;
723
961
  stores;
724
962
  storeMerchants;
@@ -730,6 +968,7 @@ var WaffoPancake = class {
730
968
  graphql;
731
969
  webhooks;
732
970
  constructor(config) {
971
+ this.config = config;
733
972
  this.http = new HttpClient(config);
734
973
  this.auth = new AuthResource(this.http);
735
974
  this.stores = new StoresResource(this.http);
@@ -742,6 +981,31 @@ var WaffoPancake = class {
742
981
  this.graphql = new GraphQLResource(this.http);
743
982
  this.webhooks = new WebhooksResource(config.webhookPublicKey);
744
983
  }
984
+ /**
985
+ * Create a buyer session for self-service operations.
986
+ *
987
+ * The returned session uses Bearer token authentication and provides
988
+ * methods for order cancellation, subscription management, refund tickets,
989
+ * and scoped GraphQL queries.
990
+ *
991
+ * @param token - Session token from `client.auth.issueSessionToken()`
992
+ * @returns A buyer session with self-service methods
993
+ *
994
+ * @example
995
+ * const { token } = await client.auth.issueSessionToken({
996
+ * storeId: "STO_xxx",
997
+ * buyerIdentity: "customer@example.com",
998
+ * });
999
+ * const buyer = client.buyer(token);
1000
+ * await buyer.cancelSubscription({ orderId: "ORD_xxx" });
1001
+ */
1002
+ buyer(token) {
1003
+ const buyerHttp = new BuyerHttpClient(token, {
1004
+ baseUrl: this.config.baseUrl,
1005
+ fetch: this.config.fetch
1006
+ });
1007
+ return new BuyerSession(buyerHttp);
1008
+ }
745
1009
  };
746
1010
 
747
1011
  // src/types.ts
@@ -794,8 +1058,9 @@ var SubscriptionOrderStatus = /* @__PURE__ */ ((SubscriptionOrderStatus2) => {
794
1058
  SubscriptionOrderStatus2["Pending"] = "pending";
795
1059
  SubscriptionOrderStatus2["Active"] = "active";
796
1060
  SubscriptionOrderStatus2["Canceling"] = "canceling";
797
- SubscriptionOrderStatus2["Canceled"] = "canceled";
798
1061
  SubscriptionOrderStatus2["PastDue"] = "past_due";
1062
+ SubscriptionOrderStatus2["Closed"] = "closed";
1063
+ SubscriptionOrderStatus2["Canceled"] = "canceled";
799
1064
  SubscriptionOrderStatus2["Expired"] = "expired";
800
1065
  return SubscriptionOrderStatus2;
801
1066
  })(SubscriptionOrderStatus || {});
@@ -836,6 +1101,7 @@ var ErrorLayer = /* @__PURE__ */ ((ErrorLayer2) => {
836
1101
  ErrorLayer2["Store"] = "store";
837
1102
  ErrorLayer2["Product"] = "product";
838
1103
  ErrorLayer2["Order"] = "order";
1104
+ ErrorLayer2["Ticket"] = "ticket";
839
1105
  ErrorLayer2["GraphQL"] = "graphql";
840
1106
  ErrorLayer2["Resource"] = "resource";
841
1107
  ErrorLayer2["Email"] = "email";