fresh-squeezy 0.2.0 → 0.3.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.es.md +1 -1
- package/README.ja.md +1 -1
- package/README.md +15 -1
- package/README.pt-BR.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/cli.js +671 -1645
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +194 -1048
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +558 -1302
- package/dist/index.d.ts +558 -1302
- package/dist/index.js +194 -991
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -5,6 +5,21 @@ import { readFileSync as readFileSync2 } from "fs";
|
|
|
5
5
|
import { Command } from "commander";
|
|
6
6
|
import dotenv from "dotenv";
|
|
7
7
|
|
|
8
|
+
// src/core/errors.ts
|
|
9
|
+
var FreshSqueezyError = class _FreshSqueezyError extends Error {
|
|
10
|
+
code;
|
|
11
|
+
status;
|
|
12
|
+
detail;
|
|
13
|
+
constructor(opts) {
|
|
14
|
+
super(opts.message);
|
|
15
|
+
this.name = "FreshSqueezyError";
|
|
16
|
+
this.code = opts.code;
|
|
17
|
+
this.status = opts.status;
|
|
18
|
+
this.detail = opts.detail;
|
|
19
|
+
Object.setPrototypeOf(this, _FreshSqueezyError.prototype);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
|
|
8
23
|
// src/cli/commands/augment.ts
|
|
9
24
|
import { existsSync } from "fs";
|
|
10
25
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
@@ -217,21 +232,6 @@ export type {
|
|
|
217
232
|
`;
|
|
218
233
|
};
|
|
219
234
|
|
|
220
|
-
// src/core/errors.ts
|
|
221
|
-
var FreshSqueezyError = class _FreshSqueezyError extends Error {
|
|
222
|
-
code;
|
|
223
|
-
status;
|
|
224
|
-
detail;
|
|
225
|
-
constructor(opts) {
|
|
226
|
-
super(opts.message);
|
|
227
|
-
this.name = "FreshSqueezyError";
|
|
228
|
-
this.code = opts.code;
|
|
229
|
-
this.status = opts.status;
|
|
230
|
-
this.detail = opts.detail;
|
|
231
|
-
Object.setPrototypeOf(this, _FreshSqueezyError.prototype);
|
|
232
|
-
}
|
|
233
|
-
};
|
|
234
|
-
|
|
235
235
|
// src/core/config.ts
|
|
236
236
|
var DEFAULT_BASE_URL = "https://api.lemonsqueezy.com";
|
|
237
237
|
var ENV_KEYS = {
|
|
@@ -314,46 +314,6 @@ var HttpClient = class {
|
|
|
314
314
|
const doc = await this.request({ path: path4 });
|
|
315
315
|
return doc.data;
|
|
316
316
|
}
|
|
317
|
-
/**
|
|
318
|
-
* POST a JSON:API document and return the created `data` resource.
|
|
319
|
-
*
|
|
320
|
-
* @param path - API path starting with `/v1/...`.
|
|
321
|
-
* @param body - JSON:API create document.
|
|
322
|
-
* @returns The created resource.
|
|
323
|
-
*/
|
|
324
|
-
async postResource(path4, body) {
|
|
325
|
-
const doc = await this.request({ method: "POST", path: path4, body });
|
|
326
|
-
return doc.data;
|
|
327
|
-
}
|
|
328
|
-
/**
|
|
329
|
-
* PATCH a JSON:API document and return the updated `data` resource.
|
|
330
|
-
*
|
|
331
|
-
* @param path - API path starting with `/v1/...`.
|
|
332
|
-
* @param body - JSON:API update document.
|
|
333
|
-
* @returns The updated resource.
|
|
334
|
-
*/
|
|
335
|
-
async patchResource(path4, body) {
|
|
336
|
-
const doc = await this.request({ method: "PATCH", path: path4, body });
|
|
337
|
-
return doc.data;
|
|
338
|
-
}
|
|
339
|
-
/**
|
|
340
|
-
* DELETE a resource. Lemon Squeezy often returns an empty body on success.
|
|
341
|
-
*
|
|
342
|
-
* @param path - API path starting with `/v1/...`.
|
|
343
|
-
* @returns Nothing — single void return, not a multi-field bag.
|
|
344
|
-
*/
|
|
345
|
-
async deleteResource(path4) {
|
|
346
|
-
await this.request({ method: "DELETE", path: path4 });
|
|
347
|
-
}
|
|
348
|
-
/**
|
|
349
|
-
* Fetch a single page of a JSON:API collection. Most callers want
|
|
350
|
-
* `paginate()` instead — this method is kept for one-shot lookups where
|
|
351
|
-
* the caller knows the result fits in a single page.
|
|
352
|
-
*/
|
|
353
|
-
async getCollection(path4, query) {
|
|
354
|
-
const doc = await this.request({ path: path4, query });
|
|
355
|
-
return doc.data;
|
|
356
|
-
}
|
|
357
317
|
/**
|
|
358
318
|
* Walk a JSON:API collection across every page and concatenate the
|
|
359
319
|
* results. Lemon Squeezy returns 25 items per page by default; without
|
|
@@ -416,582 +376,84 @@ var extractJsonApiErrors = (responseBody) => {
|
|
|
416
376
|
);
|
|
417
377
|
};
|
|
418
378
|
|
|
419
|
-
// src/resources/affiliates.ts
|
|
420
|
-
var getAffiliate = async (http, affiliateId) => {
|
|
421
|
-
return http.getResource(`/v1/affiliates/${affiliateId}`);
|
|
422
|
-
};
|
|
423
|
-
var listAffiliatesForStore = async (http, storeId) => {
|
|
424
|
-
return http.paginate("/v1/affiliates", {
|
|
425
|
-
"filter[store_id]": String(storeId)
|
|
426
|
-
});
|
|
427
|
-
};
|
|
428
|
-
|
|
429
|
-
// src/resources/checkouts.ts
|
|
430
|
-
var getCheckout = async (http, checkoutId) => {
|
|
431
|
-
return http.getResource(`/v1/checkouts/${checkoutId}`);
|
|
432
|
-
};
|
|
433
|
-
var listCheckoutsForStore = async (http, storeId) => {
|
|
434
|
-
return http.paginate("/v1/checkouts", {
|
|
435
|
-
"filter[store_id]": String(storeId)
|
|
436
|
-
});
|
|
437
|
-
};
|
|
438
|
-
var createCheckout = async (http, body) => {
|
|
439
|
-
return http.postResource("/v1/checkouts", body);
|
|
440
|
-
};
|
|
441
|
-
|
|
442
|
-
// src/resources/customers.ts
|
|
443
|
-
var getCustomer = async (http, customerId) => {
|
|
444
|
-
return http.getResource(`/v1/customers/${customerId}`);
|
|
445
|
-
};
|
|
446
|
-
var listCustomersForStore = async (http, storeId) => {
|
|
447
|
-
return http.paginate("/v1/customers", {
|
|
448
|
-
"filter[store_id]": String(storeId)
|
|
449
|
-
});
|
|
450
|
-
};
|
|
451
|
-
var createCustomer = async (http, body) => {
|
|
452
|
-
return http.postResource("/v1/customers", body);
|
|
453
|
-
};
|
|
454
|
-
var updateCustomer = async (http, customerId, body) => {
|
|
455
|
-
return http.patchResource(`/v1/customers/${customerId}`, body);
|
|
456
|
-
};
|
|
457
|
-
|
|
458
|
-
// src/resources/discountRedemptions.ts
|
|
459
|
-
var getDiscountRedemption = async (http, discountRedemptionId) => {
|
|
460
|
-
return http.getResource(
|
|
461
|
-
`/v1/discount-redemptions/${discountRedemptionId}`
|
|
462
|
-
);
|
|
463
|
-
};
|
|
464
|
-
var listDiscountRedemptionsForDiscount = async (http, discountId) => {
|
|
465
|
-
return http.paginate("/v1/discount-redemptions", {
|
|
466
|
-
"filter[discount_id]": String(discountId)
|
|
467
|
-
});
|
|
468
|
-
};
|
|
469
|
-
|
|
470
|
-
// src/resources/discounts.ts
|
|
471
|
-
var getDiscount = async (http, discountId) => {
|
|
472
|
-
return http.getResource(`/v1/discounts/${discountId}`);
|
|
473
|
-
};
|
|
474
|
-
var listDiscountsForStore = async (http, storeId) => {
|
|
475
|
-
return http.paginate("/v1/discounts", {
|
|
476
|
-
"filter[store_id]": String(storeId)
|
|
477
|
-
});
|
|
478
|
-
};
|
|
479
|
-
var createDiscount = async (http, body) => {
|
|
480
|
-
return http.postResource("/v1/discounts", body);
|
|
481
|
-
};
|
|
482
|
-
var deleteDiscount = async (http, discountId) => {
|
|
483
|
-
await http.deleteResource(`/v1/discounts/${discountId}`);
|
|
484
|
-
};
|
|
485
|
-
|
|
486
|
-
// src/resources/files.ts
|
|
487
|
-
var getFile = async (http, fileId) => {
|
|
488
|
-
return http.getResource(`/v1/files/${fileId}`);
|
|
489
|
-
};
|
|
490
|
-
var listFilesForVariant = async (http, variantId) => {
|
|
491
|
-
return http.paginate("/v1/files", {
|
|
492
|
-
"filter[variant_id]": String(variantId)
|
|
493
|
-
});
|
|
494
|
-
};
|
|
495
|
-
|
|
496
|
-
// src/resources/licenseKeyInstances.ts
|
|
497
|
-
var getLicenseKeyInstance = async (http, licenseKeyInstanceId) => {
|
|
498
|
-
return http.getResource(
|
|
499
|
-
`/v1/license-key-instances/${licenseKeyInstanceId}`
|
|
500
|
-
);
|
|
501
|
-
};
|
|
502
|
-
var listLicenseKeyInstancesForLicenseKey = async (http, licenseKeyId) => {
|
|
503
|
-
return http.paginate("/v1/license-key-instances", {
|
|
504
|
-
"filter[license_key_id]": String(licenseKeyId)
|
|
505
|
-
});
|
|
506
|
-
};
|
|
507
|
-
|
|
508
|
-
// src/resources/licenseKeys.ts
|
|
509
|
-
var getLicenseKey = async (http, licenseKeyId) => {
|
|
510
|
-
return http.getResource(`/v1/license-keys/${licenseKeyId}`);
|
|
511
|
-
};
|
|
512
|
-
var listLicenseKeysForStore = async (http, storeId) => {
|
|
513
|
-
return http.paginate("/v1/license-keys", {
|
|
514
|
-
"filter[store_id]": String(storeId)
|
|
515
|
-
});
|
|
516
|
-
};
|
|
517
|
-
var updateLicenseKey = async (http, licenseKeyId, body) => {
|
|
518
|
-
return http.patchResource(`/v1/license-keys/${licenseKeyId}`, body);
|
|
519
|
-
};
|
|
520
|
-
|
|
521
|
-
// src/resources/orderItems.ts
|
|
522
|
-
var getOrderItem = async (http, orderItemId) => {
|
|
523
|
-
return http.getResource(`/v1/order-items/${orderItemId}`);
|
|
524
|
-
};
|
|
525
|
-
var listOrderItemsForOrder = async (http, orderId) => {
|
|
526
|
-
return http.paginate("/v1/order-items", {
|
|
527
|
-
"filter[order_id]": String(orderId)
|
|
528
|
-
});
|
|
529
|
-
};
|
|
530
|
-
|
|
531
|
-
// src/resources/orders.ts
|
|
532
|
-
var getOrder = async (http, orderId) => {
|
|
533
|
-
return http.getResource(`/v1/orders/${orderId}`);
|
|
534
|
-
};
|
|
535
|
-
var listOrdersForStore = async (http, storeId) => {
|
|
536
|
-
return http.paginate("/v1/orders", {
|
|
537
|
-
"filter[store_id]": String(storeId)
|
|
538
|
-
});
|
|
539
|
-
};
|
|
540
|
-
var refundOrder = async (http, orderId, body) => {
|
|
541
|
-
return http.postResource(`/v1/orders/${orderId}/refund`, body ?? {});
|
|
542
|
-
};
|
|
543
|
-
var generateOrderInvoice = async (http, orderId, body) => {
|
|
544
|
-
return http.request({
|
|
545
|
-
method: "POST",
|
|
546
|
-
path: `/v1/orders/${orderId}/generate-invoice`,
|
|
547
|
-
body: body ?? {}
|
|
548
|
-
});
|
|
549
|
-
};
|
|
550
|
-
|
|
551
|
-
// src/resources/prices.ts
|
|
552
|
-
var getPrice = async (http, priceId) => {
|
|
553
|
-
return http.getResource(`/v1/prices/${priceId}`);
|
|
554
|
-
};
|
|
555
|
-
var listPricesForVariant = async (http, variantId) => {
|
|
556
|
-
return http.paginate("/v1/prices", {
|
|
557
|
-
"filter[variant_id]": String(variantId)
|
|
558
|
-
});
|
|
559
|
-
};
|
|
560
|
-
|
|
561
|
-
// src/resources/products.ts
|
|
562
|
-
var getProduct = async (http, productId) => {
|
|
563
|
-
return http.getResource(`/v1/products/${productId}`);
|
|
564
|
-
};
|
|
565
|
-
var listProducts = async (http, storeId) => {
|
|
566
|
-
return http.paginate("/v1/products", {
|
|
567
|
-
"filter[store_id]": String(storeId)
|
|
568
|
-
});
|
|
569
|
-
};
|
|
570
|
-
|
|
571
379
|
// src/resources/registry.ts
|
|
572
|
-
var
|
|
573
|
-
|
|
574
|
-
{
|
|
575
|
-
|
|
576
|
-
{
|
|
577
|
-
{
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
},
|
|
584
|
-
// products (read-only)
|
|
585
|
-
{
|
|
586
|
-
resource: "product",
|
|
587
|
-
verb: "get",
|
|
588
|
-
docsPath: "products/retrieve-product",
|
|
589
|
-
body: "none",
|
|
590
|
-
idRole: "id"
|
|
591
|
-
},
|
|
592
|
-
{
|
|
593
|
-
resource: "product",
|
|
594
|
-
verb: "list",
|
|
595
|
-
docsPath: "products/list-all-products",
|
|
596
|
-
body: "none",
|
|
597
|
-
idRole: "store"
|
|
598
|
-
},
|
|
599
|
-
// variants (read-only)
|
|
600
|
-
{
|
|
601
|
-
resource: "variant",
|
|
602
|
-
verb: "get",
|
|
603
|
-
docsPath: "variants/retrieve-variant",
|
|
604
|
-
body: "none",
|
|
605
|
-
idRole: "id"
|
|
606
|
-
},
|
|
607
|
-
{
|
|
608
|
-
resource: "variant",
|
|
609
|
-
verb: "list",
|
|
610
|
-
docsPath: "variants/list-all-variants",
|
|
611
|
-
body: "none",
|
|
612
|
-
idRole: "parent"
|
|
613
|
-
},
|
|
614
|
-
// prices (read-only)
|
|
615
|
-
{ resource: "price", verb: "get", docsPath: "prices/retrieve-price", body: "none", idRole: "id" },
|
|
616
|
-
{
|
|
617
|
-
resource: "price",
|
|
618
|
-
verb: "list",
|
|
619
|
-
docsPath: "prices/list-all-prices",
|
|
620
|
-
body: "none",
|
|
621
|
-
idRole: "parent"
|
|
622
|
-
},
|
|
623
|
-
// files (read-only)
|
|
624
|
-
{ resource: "file", verb: "get", docsPath: "files/retrieve-file", body: "none", idRole: "id" },
|
|
625
|
-
{
|
|
626
|
-
resource: "file",
|
|
627
|
-
verb: "list",
|
|
628
|
-
docsPath: "files/list-all-files",
|
|
629
|
-
body: "none",
|
|
630
|
-
idRole: "parent"
|
|
631
|
-
},
|
|
632
|
-
// customers
|
|
633
|
-
{
|
|
634
|
-
resource: "customer",
|
|
635
|
-
verb: "get",
|
|
636
|
-
docsPath: "customers/retrieve-customer",
|
|
637
|
-
body: "none",
|
|
638
|
-
idRole: "id"
|
|
639
|
-
},
|
|
640
|
-
{
|
|
641
|
-
resource: "customer",
|
|
642
|
-
verb: "list",
|
|
643
|
-
docsPath: "customers/list-all-customers",
|
|
644
|
-
body: "none",
|
|
645
|
-
idRole: "store"
|
|
646
|
-
},
|
|
647
|
-
{
|
|
648
|
-
resource: "customer",
|
|
649
|
-
verb: "create",
|
|
650
|
-
docsPath: "customers/create-customer",
|
|
651
|
-
body: "required",
|
|
652
|
-
idRole: "none"
|
|
653
|
-
},
|
|
654
|
-
{
|
|
655
|
-
resource: "customer",
|
|
656
|
-
verb: "update",
|
|
657
|
-
docsPath: "customers/update-customer",
|
|
658
|
-
body: "required",
|
|
659
|
-
idRole: "id"
|
|
660
|
-
},
|
|
661
|
-
// orders
|
|
662
|
-
{ resource: "order", verb: "get", docsPath: "orders/retrieve-order", body: "none", idRole: "id" },
|
|
663
|
-
{
|
|
664
|
-
resource: "order",
|
|
665
|
-
verb: "list",
|
|
666
|
-
docsPath: "orders/list-all-orders",
|
|
667
|
-
body: "none",
|
|
668
|
-
idRole: "store"
|
|
669
|
-
},
|
|
670
|
-
{
|
|
671
|
-
resource: "order",
|
|
672
|
-
verb: "refund",
|
|
673
|
-
docsPath: "orders/issue-refund",
|
|
674
|
-
body: "optional",
|
|
675
|
-
destructive: true,
|
|
676
|
-
idRole: "id"
|
|
677
|
-
},
|
|
678
|
-
{
|
|
679
|
-
resource: "order",
|
|
680
|
-
verb: "generate-invoice",
|
|
681
|
-
docsPath: "orders/generate-order-invoice",
|
|
682
|
-
body: "optional",
|
|
683
|
-
idRole: "id"
|
|
684
|
-
},
|
|
685
|
-
// order-items (read-only)
|
|
686
|
-
{
|
|
687
|
-
resource: "order-item",
|
|
688
|
-
verb: "get",
|
|
689
|
-
docsPath: "order-items/retrieve-order-item",
|
|
690
|
-
body: "none",
|
|
691
|
-
idRole: "id"
|
|
692
|
-
},
|
|
693
|
-
{
|
|
694
|
-
resource: "order-item",
|
|
695
|
-
verb: "list",
|
|
696
|
-
docsPath: "order-items/list-all-order-items",
|
|
697
|
-
body: "none",
|
|
698
|
-
idRole: "parent"
|
|
699
|
-
},
|
|
700
|
-
// subscriptions
|
|
701
|
-
{
|
|
702
|
-
resource: "subscription",
|
|
703
|
-
verb: "get",
|
|
704
|
-
docsPath: "subscriptions/retrieve-subscription",
|
|
705
|
-
body: "none",
|
|
706
|
-
idRole: "id"
|
|
707
|
-
},
|
|
708
|
-
{
|
|
709
|
-
resource: "subscription",
|
|
710
|
-
verb: "list",
|
|
711
|
-
docsPath: "subscriptions/list-all-subscriptions",
|
|
712
|
-
body: "none",
|
|
713
|
-
idRole: "store"
|
|
714
|
-
},
|
|
715
|
-
{
|
|
716
|
-
resource: "subscription",
|
|
717
|
-
verb: "update",
|
|
718
|
-
docsPath: "subscriptions/update-subscription",
|
|
719
|
-
body: "required",
|
|
720
|
-
idRole: "id"
|
|
721
|
-
},
|
|
722
|
-
{
|
|
723
|
-
resource: "subscription",
|
|
724
|
-
verb: "cancel",
|
|
725
|
-
docsPath: "subscriptions/cancel-subscription",
|
|
726
|
-
body: "none",
|
|
727
|
-
destructive: true,
|
|
728
|
-
idRole: "id"
|
|
729
|
-
},
|
|
730
|
-
// subscription-items
|
|
731
|
-
{
|
|
732
|
-
resource: "subscription-item",
|
|
733
|
-
verb: "get",
|
|
734
|
-
docsPath: "subscription-items/retrieve-subscription-item",
|
|
735
|
-
body: "none",
|
|
736
|
-
idRole: "id"
|
|
737
|
-
},
|
|
738
|
-
{
|
|
739
|
-
resource: "subscription-item",
|
|
740
|
-
verb: "list",
|
|
741
|
-
docsPath: "subscription-items/list-all-subscription-items",
|
|
742
|
-
body: "none",
|
|
743
|
-
idRole: "parent"
|
|
744
|
-
},
|
|
745
|
-
{
|
|
746
|
-
resource: "subscription-item",
|
|
747
|
-
verb: "update",
|
|
748
|
-
docsPath: "subscription-items/update-subscription-item",
|
|
749
|
-
body: "required",
|
|
750
|
-
idRole: "id"
|
|
751
|
-
},
|
|
752
|
-
{
|
|
753
|
-
resource: "subscription-item",
|
|
754
|
-
verb: "current-usage",
|
|
755
|
-
docsPath: "subscription-items/retrieve-subscription-item-current-usage",
|
|
756
|
-
body: "none",
|
|
757
|
-
idRole: "id"
|
|
758
|
-
},
|
|
759
|
-
// subscription-invoices
|
|
760
|
-
{
|
|
761
|
-
resource: "subscription-invoice",
|
|
762
|
-
verb: "get",
|
|
763
|
-
docsPath: "subscription-invoices/retrieve-subscription-invoice",
|
|
764
|
-
body: "none",
|
|
765
|
-
idRole: "id"
|
|
766
|
-
},
|
|
767
|
-
{
|
|
768
|
-
resource: "subscription-invoice",
|
|
769
|
-
verb: "list",
|
|
770
|
-
docsPath: "subscription-invoices/list-all-subscription-invoices",
|
|
771
|
-
body: "none",
|
|
772
|
-
idRole: "parent"
|
|
773
|
-
},
|
|
774
|
-
{
|
|
775
|
-
resource: "subscription-invoice",
|
|
776
|
-
verb: "refund",
|
|
777
|
-
docsPath: "subscription-invoices/issue-refund",
|
|
778
|
-
body: "optional",
|
|
779
|
-
destructive: true,
|
|
780
|
-
idRole: "id"
|
|
781
|
-
},
|
|
782
|
-
{
|
|
783
|
-
resource: "subscription-invoice",
|
|
784
|
-
verb: "generate-invoice",
|
|
785
|
-
docsPath: "subscription-invoices/generate-subscription-invoice",
|
|
380
|
+
var VERB_RULES = {
|
|
381
|
+
get: { method: "GET", path: "/{id}", docs: "retrieve-{r}", body: "none" },
|
|
382
|
+
list: { method: "GET", path: "", docs: "list-all-{r}s", body: "none" },
|
|
383
|
+
create: { method: "POST", path: "", docs: "create-{r}", body: "required" },
|
|
384
|
+
update: { method: "PATCH", path: "/{id}", docs: "update-{r}", body: "required" },
|
|
385
|
+
delete: { method: "DELETE", path: "/{id}", docs: "delete-{r}", body: "none", destructive: true },
|
|
386
|
+
cancel: { method: "DELETE", path: "/{id}", docs: "cancel-{r}", body: "none", destructive: true },
|
|
387
|
+
refund: {
|
|
388
|
+
method: "POST",
|
|
389
|
+
path: "/{id}/refund",
|
|
390
|
+
docs: "issue-refund",
|
|
786
391
|
body: "optional",
|
|
787
|
-
|
|
788
|
-
},
|
|
789
|
-
// usage-records
|
|
790
|
-
{
|
|
791
|
-
resource: "usage-record",
|
|
792
|
-
verb: "get",
|
|
793
|
-
docsPath: "usage-records/retrieve-usage-record",
|
|
794
|
-
body: "none",
|
|
795
|
-
idRole: "id"
|
|
796
|
-
},
|
|
797
|
-
{
|
|
798
|
-
resource: "usage-record",
|
|
799
|
-
verb: "list",
|
|
800
|
-
docsPath: "usage-records/list-all-usage-records",
|
|
801
|
-
body: "none",
|
|
802
|
-
idRole: "parent"
|
|
803
|
-
},
|
|
804
|
-
{
|
|
805
|
-
resource: "usage-record",
|
|
806
|
-
verb: "create",
|
|
807
|
-
docsPath: "usage-records/create-usage-record",
|
|
808
|
-
body: "required",
|
|
809
|
-
idRole: "none"
|
|
810
|
-
},
|
|
811
|
-
// discounts
|
|
812
|
-
{
|
|
813
|
-
resource: "discount",
|
|
814
|
-
verb: "get",
|
|
815
|
-
docsPath: "discounts/retrieve-discount",
|
|
816
|
-
body: "none",
|
|
817
|
-
idRole: "id"
|
|
818
|
-
},
|
|
819
|
-
{
|
|
820
|
-
resource: "discount",
|
|
821
|
-
verb: "list",
|
|
822
|
-
docsPath: "discounts/list-all-discounts",
|
|
823
|
-
body: "none",
|
|
824
|
-
idRole: "store"
|
|
825
|
-
},
|
|
826
|
-
{
|
|
827
|
-
resource: "discount",
|
|
828
|
-
verb: "create",
|
|
829
|
-
docsPath: "discounts/create-discount",
|
|
830
|
-
body: "required",
|
|
831
|
-
idRole: "none"
|
|
832
|
-
},
|
|
833
|
-
{
|
|
834
|
-
resource: "discount",
|
|
835
|
-
verb: "delete",
|
|
836
|
-
docsPath: "discounts/delete-discount",
|
|
837
|
-
body: "none",
|
|
838
|
-
destructive: true,
|
|
839
|
-
idRole: "id"
|
|
840
|
-
},
|
|
841
|
-
// discount-redemptions (read-only)
|
|
842
|
-
{
|
|
843
|
-
resource: "discount-redemption",
|
|
844
|
-
verb: "get",
|
|
845
|
-
docsPath: "discount-redemptions/retrieve-discount-redemption",
|
|
846
|
-
body: "none",
|
|
847
|
-
idRole: "id"
|
|
848
|
-
},
|
|
849
|
-
{
|
|
850
|
-
resource: "discount-redemption",
|
|
851
|
-
verb: "list",
|
|
852
|
-
docsPath: "discount-redemptions/list-all-discount-redemptions",
|
|
853
|
-
body: "none",
|
|
854
|
-
idRole: "parent"
|
|
855
|
-
},
|
|
856
|
-
// license-keys
|
|
857
|
-
{
|
|
858
|
-
resource: "license-key",
|
|
859
|
-
verb: "get",
|
|
860
|
-
docsPath: "license-keys/retrieve-license-key",
|
|
861
|
-
body: "none",
|
|
862
|
-
idRole: "id"
|
|
392
|
+
destructive: true
|
|
863
393
|
},
|
|
864
|
-
{
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
body: "
|
|
869
|
-
idRole: "store"
|
|
870
|
-
},
|
|
871
|
-
{
|
|
872
|
-
resource: "license-key",
|
|
873
|
-
verb: "update",
|
|
874
|
-
docsPath: "license-keys/update-license-key",
|
|
875
|
-
body: "required",
|
|
876
|
-
idRole: "id"
|
|
877
|
-
},
|
|
878
|
-
// license-key-instances (read-only)
|
|
879
|
-
{
|
|
880
|
-
resource: "license-key-instance",
|
|
881
|
-
verb: "get",
|
|
882
|
-
docsPath: "license-key-instances/retrieve-license-key-instance",
|
|
883
|
-
body: "none",
|
|
884
|
-
idRole: "id"
|
|
885
|
-
},
|
|
886
|
-
{
|
|
887
|
-
resource: "license-key-instance",
|
|
888
|
-
verb: "list",
|
|
889
|
-
docsPath: "license-key-instances/list-all-license-key-instances",
|
|
890
|
-
body: "none",
|
|
891
|
-
idRole: "parent"
|
|
892
|
-
},
|
|
893
|
-
// checkouts
|
|
894
|
-
{
|
|
895
|
-
resource: "checkout",
|
|
896
|
-
verb: "get",
|
|
897
|
-
docsPath: "checkouts/retrieve-checkout",
|
|
898
|
-
body: "none",
|
|
899
|
-
idRole: "id"
|
|
900
|
-
},
|
|
901
|
-
{
|
|
902
|
-
resource: "checkout",
|
|
903
|
-
verb: "list",
|
|
904
|
-
docsPath: "checkouts/list-all-checkouts",
|
|
905
|
-
body: "none",
|
|
906
|
-
idRole: "store"
|
|
907
|
-
},
|
|
908
|
-
{
|
|
909
|
-
resource: "checkout",
|
|
910
|
-
verb: "create",
|
|
911
|
-
docsPath: "checkouts/create-checkout",
|
|
912
|
-
body: "required",
|
|
913
|
-
idRole: "none"
|
|
914
|
-
},
|
|
915
|
-
// webhooks
|
|
916
|
-
{
|
|
917
|
-
resource: "webhook",
|
|
918
|
-
verb: "get",
|
|
919
|
-
docsPath: "webhooks/retrieve-webhook",
|
|
920
|
-
body: "none",
|
|
921
|
-
idRole: "id"
|
|
922
|
-
},
|
|
923
|
-
{
|
|
924
|
-
resource: "webhook",
|
|
925
|
-
verb: "list",
|
|
926
|
-
docsPath: "webhooks/list-all-webhooks",
|
|
927
|
-
body: "none",
|
|
928
|
-
idRole: "store"
|
|
929
|
-
},
|
|
930
|
-
{
|
|
931
|
-
resource: "webhook",
|
|
932
|
-
verb: "create",
|
|
933
|
-
docsPath: "webhooks/create-webhook",
|
|
934
|
-
body: "required",
|
|
935
|
-
idRole: "none"
|
|
936
|
-
},
|
|
937
|
-
{
|
|
938
|
-
resource: "webhook",
|
|
939
|
-
verb: "update",
|
|
940
|
-
docsPath: "webhooks/update-webhook",
|
|
941
|
-
body: "required",
|
|
942
|
-
idRole: "id"
|
|
943
|
-
},
|
|
944
|
-
{
|
|
945
|
-
resource: "webhook",
|
|
946
|
-
verb: "delete",
|
|
947
|
-
docsPath: "webhooks/delete-webhook",
|
|
948
|
-
body: "none",
|
|
949
|
-
destructive: true,
|
|
950
|
-
idRole: "id"
|
|
951
|
-
},
|
|
952
|
-
// affiliates (read-only)
|
|
953
|
-
{
|
|
954
|
-
resource: "affiliate",
|
|
955
|
-
verb: "get",
|
|
956
|
-
docsPath: "affiliates/retrieve-affiliate",
|
|
957
|
-
body: "none",
|
|
958
|
-
idRole: "id"
|
|
394
|
+
"generate-invoice": {
|
|
395
|
+
method: "POST",
|
|
396
|
+
path: "/{id}/generate-invoice",
|
|
397
|
+
docs: "generate-{r}-invoice",
|
|
398
|
+
body: "optional"
|
|
959
399
|
},
|
|
960
|
-
{
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
body: "none"
|
|
965
|
-
|
|
966
|
-
|
|
400
|
+
"current-usage": {
|
|
401
|
+
method: "GET",
|
|
402
|
+
path: "/{id}/current-usage",
|
|
403
|
+
docs: "retrieve-{r}-current-usage",
|
|
404
|
+
body: "none"
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
var RESOURCES = [
|
|
408
|
+
["user", ["get"]],
|
|
409
|
+
["store", ["get", "list"]],
|
|
410
|
+
["product", ["get", "list"], "store"],
|
|
411
|
+
["variant", ["get", "list"], "product"],
|
|
412
|
+
["price", ["get", "list"], "variant"],
|
|
413
|
+
["file", ["get", "list"], "variant"],
|
|
414
|
+
["customer", ["get", "list", "create", "update"], "store"],
|
|
415
|
+
["order", ["get", "list", "refund", "generate-invoice"], "store"],
|
|
416
|
+
["order-item", ["get", "list"], "order"],
|
|
417
|
+
["subscription", ["get", "list", "update", "cancel"], "store"],
|
|
418
|
+
["subscription-item", ["get", "list", "update", "current-usage"], "subscription"],
|
|
419
|
+
["subscription-invoice", ["get", "list", "refund", "generate-invoice"], "subscription"],
|
|
420
|
+
["usage-record", ["get", "list", "create"], "subscription-item"],
|
|
421
|
+
["discount", ["get", "list", "create", "delete"], "store"],
|
|
422
|
+
["discount-redemption", ["get", "list"], "discount"],
|
|
423
|
+
["license-key", ["get", "list", "update"], "store"],
|
|
424
|
+
["license-key-instance", ["get", "list"], "license-key"],
|
|
425
|
+
["checkout", ["get", "list", "create"], "store"],
|
|
426
|
+
["webhook", ["get", "list", "create", "update", "delete"], "store"],
|
|
427
|
+
["affiliate", ["get", "list"], "store"]
|
|
967
428
|
];
|
|
968
|
-
var
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
"
|
|
980
|
-
"
|
|
981
|
-
"
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
429
|
+
var DOCS_PATH_EXCEPTIONS = {
|
|
430
|
+
"subscription-invoice:generate-invoice": "subscription-invoices/generate-subscription-invoice"
|
|
431
|
+
};
|
|
432
|
+
var USER_ME_PATH = "/v1/users/me";
|
|
433
|
+
var listIdRole = (listScope) => {
|
|
434
|
+
if (!listScope) return "none";
|
|
435
|
+
return listScope === "store" ? "store" : "parent";
|
|
436
|
+
};
|
|
437
|
+
var toSpec = (resource, verb, listScope) => {
|
|
438
|
+
const rule = VERB_RULES[verb];
|
|
439
|
+
const docsPath = DOCS_PATH_EXCEPTIONS[`${resource}:${verb}`] ?? `${resource}s/${rule.docs.replaceAll("{r}", resource)}`;
|
|
440
|
+
let idRole = rule.path.includes("{id}") ? "id" : "none";
|
|
441
|
+
if (verb === "list") idRole = listIdRole(listScope);
|
|
442
|
+
if (resource === "user") idRole = "none";
|
|
443
|
+
return {
|
|
444
|
+
resource,
|
|
445
|
+
verb,
|
|
446
|
+
docsPath,
|
|
447
|
+
body: rule.body,
|
|
448
|
+
...rule.destructive ? { destructive: true } : {},
|
|
449
|
+
idRole
|
|
450
|
+
};
|
|
989
451
|
};
|
|
452
|
+
var resourceRegistry = RESOURCES.flatMap(
|
|
453
|
+
([resource, verbs, listScope]) => verbs.map((verb) => toSpec(resource, verb, listScope))
|
|
454
|
+
);
|
|
990
455
|
var normalizeResourceName = (resource) => {
|
|
991
456
|
const normalized = resource.replace(/_/g, "-").toLowerCase();
|
|
992
|
-
if (RESOURCE_ALIASES[normalized]) {
|
|
993
|
-
return RESOURCE_ALIASES[normalized];
|
|
994
|
-
}
|
|
995
457
|
if (normalized.endsWith("s") && normalized !== "status") {
|
|
996
458
|
return normalized.slice(0, -1);
|
|
997
459
|
}
|
|
@@ -1004,271 +466,11 @@ var findResourceVerb = (resource, verb) => {
|
|
|
1004
466
|
var listRegisteredResources = () => {
|
|
1005
467
|
return [...new Set(resourceRegistry.map((entry) => entry.resource))].sort();
|
|
1006
468
|
};
|
|
1007
|
-
|
|
1008
|
-
// src/resources/stores.ts
|
|
1009
|
-
var getStore = async (http, storeId) => {
|
|
1010
|
-
return http.getResource(`/v1/stores/${storeId}`);
|
|
1011
|
-
};
|
|
1012
|
-
var listStores = async (http) => {
|
|
1013
|
-
return http.paginate("/v1/stores");
|
|
1014
|
-
};
|
|
1015
|
-
|
|
1016
|
-
// src/resources/subscriptionInvoices.ts
|
|
1017
|
-
var getSubscriptionInvoice = async (http, subscriptionInvoiceId) => {
|
|
1018
|
-
return http.getResource(
|
|
1019
|
-
`/v1/subscription-invoices/${subscriptionInvoiceId}`
|
|
1020
|
-
);
|
|
1021
|
-
};
|
|
1022
|
-
var listSubscriptionInvoicesForSubscription = async (http, subscriptionId) => {
|
|
1023
|
-
return http.paginate("/v1/subscription-invoices", {
|
|
1024
|
-
"filter[subscription_id]": String(subscriptionId)
|
|
1025
|
-
});
|
|
1026
|
-
};
|
|
1027
|
-
var refundSubscriptionInvoice = async (http, subscriptionInvoiceId, body) => {
|
|
1028
|
-
return http.postResource(
|
|
1029
|
-
`/v1/subscription-invoices/${subscriptionInvoiceId}/refund`,
|
|
1030
|
-
body ?? {}
|
|
1031
|
-
);
|
|
1032
|
-
};
|
|
1033
|
-
var generateSubscriptionInvoice = async (http, subscriptionInvoiceId, body) => {
|
|
1034
|
-
return http.request({
|
|
1035
|
-
method: "POST",
|
|
1036
|
-
path: `/v1/subscription-invoices/${subscriptionInvoiceId}/generate-invoice`,
|
|
1037
|
-
body: body ?? {}
|
|
1038
|
-
});
|
|
1039
|
-
};
|
|
1040
|
-
|
|
1041
|
-
// src/resources/subscriptionItems.ts
|
|
1042
|
-
var getSubscriptionItem = async (http, subscriptionItemId) => {
|
|
1043
|
-
return http.getResource(
|
|
1044
|
-
`/v1/subscription-items/${subscriptionItemId}`
|
|
1045
|
-
);
|
|
1046
|
-
};
|
|
1047
|
-
var listSubscriptionItemsForSubscription = async (http, subscriptionId) => {
|
|
1048
|
-
return http.paginate("/v1/subscription-items", {
|
|
1049
|
-
"filter[subscription_id]": String(subscriptionId)
|
|
1050
|
-
});
|
|
1051
|
-
};
|
|
1052
|
-
var updateSubscriptionItem = async (http, subscriptionItemId, body) => {
|
|
1053
|
-
return http.patchResource(
|
|
1054
|
-
`/v1/subscription-items/${subscriptionItemId}`,
|
|
1055
|
-
body
|
|
1056
|
-
);
|
|
1057
|
-
};
|
|
1058
|
-
var getSubscriptionItemCurrentUsage = async (http, subscriptionItemId) => {
|
|
1059
|
-
return http.request({
|
|
1060
|
-
path: `/v1/subscription-items/${subscriptionItemId}/current-usage`
|
|
1061
|
-
});
|
|
1062
|
-
};
|
|
1063
|
-
|
|
1064
|
-
// src/resources/subscriptions.ts
|
|
1065
|
-
var getSubscription = async (http, subscriptionId) => {
|
|
1066
|
-
return http.getResource(`/v1/subscriptions/${subscriptionId}`);
|
|
1067
|
-
};
|
|
1068
|
-
var listSubscriptionsForStore = async (http, storeId) => {
|
|
1069
|
-
return http.paginate("/v1/subscriptions", {
|
|
1070
|
-
"filter[store_id]": String(storeId)
|
|
1071
|
-
});
|
|
1072
|
-
};
|
|
1073
|
-
var updateSubscription = async (http, subscriptionId, body) => {
|
|
1074
|
-
return http.patchResource(`/v1/subscriptions/${subscriptionId}`, body);
|
|
1075
|
-
};
|
|
1076
|
-
var cancelSubscription = async (http, subscriptionId) => {
|
|
1077
|
-
const doc = await http.request({
|
|
1078
|
-
method: "DELETE",
|
|
1079
|
-
path: `/v1/subscriptions/${subscriptionId}`
|
|
1080
|
-
});
|
|
1081
|
-
return doc?.data;
|
|
1082
|
-
};
|
|
1083
|
-
|
|
1084
|
-
// src/resources/usageRecords.ts
|
|
1085
|
-
var getUsageRecord = async (http, usageRecordId) => {
|
|
1086
|
-
return http.getResource(`/v1/usage-records/${usageRecordId}`);
|
|
1087
|
-
};
|
|
1088
|
-
var listUsageRecordsForSubscriptionItem = async (http, subscriptionItemId) => {
|
|
1089
|
-
return http.paginate("/v1/usage-records", {
|
|
1090
|
-
"filter[subscription_item_id]": String(subscriptionItemId)
|
|
1091
|
-
});
|
|
1092
|
-
};
|
|
1093
|
-
var createUsageRecord = async (http, body) => {
|
|
1094
|
-
return http.postResource("/v1/usage-records", body);
|
|
1095
|
-
};
|
|
1096
|
-
|
|
1097
|
-
// src/resources/users.ts
|
|
1098
|
-
var getAuthenticatedUser = async (http) => {
|
|
1099
|
-
return http.request({ path: "/v1/users/me" });
|
|
1100
|
-
};
|
|
1101
|
-
|
|
1102
|
-
// src/resources/variants.ts
|
|
1103
|
-
var getVariant = async (http, variantId) => {
|
|
1104
|
-
return http.getResource(`/v1/variants/${variantId}`);
|
|
1105
|
-
};
|
|
1106
|
-
var listVariantsForProduct = async (http, productId) => {
|
|
1107
|
-
return http.paginate("/v1/variants", {
|
|
1108
|
-
"filter[product_id]": String(productId)
|
|
1109
|
-
});
|
|
1110
|
-
};
|
|
1111
|
-
|
|
1112
|
-
// src/resources/webhooks.ts
|
|
1113
|
-
var getWebhook = async (http, webhookId) => {
|
|
1114
|
-
return http.getResource(`/v1/webhooks/${webhookId}`);
|
|
1115
|
-
};
|
|
1116
|
-
var listWebhooksForStore = async (http, storeId) => {
|
|
1117
|
-
return http.paginate("/v1/webhooks", {
|
|
1118
|
-
"filter[store_id]": String(storeId)
|
|
1119
|
-
});
|
|
1120
|
-
};
|
|
1121
|
-
var createWebhook = async (http, body) => {
|
|
1122
|
-
return http.postResource("/v1/webhooks", body);
|
|
1123
|
-
};
|
|
1124
|
-
var updateWebhook = async (http, webhookId, body) => {
|
|
1125
|
-
return http.patchResource(`/v1/webhooks/${webhookId}`, body);
|
|
1126
|
-
};
|
|
1127
|
-
var deleteWebhook = async (http, webhookId) => {
|
|
1128
|
-
await http.deleteResource(`/v1/webhooks/${webhookId}`);
|
|
1129
|
-
};
|
|
1130
|
-
|
|
1131
|
-
// src/resources/invokeOp.ts
|
|
1132
|
-
var invokeOp = async (http, resource, verb, args = {}) => {
|
|
1133
|
-
const spec = findResourceVerb(resource, verb);
|
|
1134
|
-
if (!spec) {
|
|
1135
|
-
throw new FreshSqueezyError({
|
|
1136
|
-
code: "UNKNOWN_OP",
|
|
1137
|
-
message: `Unknown or unsupported op: ${verb} ${resource}. Run \`fresh-squeezy ops --list\`.`
|
|
1138
|
-
});
|
|
1139
|
-
}
|
|
1140
|
-
const key = `${spec.resource}:${spec.verb}`;
|
|
1141
|
-
switch (key) {
|
|
1142
|
-
case "user:get": {
|
|
1143
|
-
const doc = await getAuthenticatedUser(http);
|
|
1144
|
-
return doc.data;
|
|
1145
|
-
}
|
|
1146
|
-
case "store:get":
|
|
1147
|
-
return getStore(http, requireId(args, "store"));
|
|
1148
|
-
case "store:list":
|
|
1149
|
-
return listStores(http);
|
|
1150
|
-
case "product:get":
|
|
1151
|
-
return getProduct(http, requireId(args, "product"));
|
|
1152
|
-
case "product:list":
|
|
1153
|
-
return listProducts(http, requireStore(args));
|
|
1154
|
-
case "variant:get":
|
|
1155
|
-
return getVariant(http, requireId(args, "variant"));
|
|
1156
|
-
case "variant:list":
|
|
1157
|
-
return listVariantsForProduct(http, requireParent(args, "product"));
|
|
1158
|
-
case "price:get":
|
|
1159
|
-
return getPrice(http, requireId(args, "price"));
|
|
1160
|
-
case "price:list":
|
|
1161
|
-
return listPricesForVariant(http, requireParent(args, "variant"));
|
|
1162
|
-
case "file:get":
|
|
1163
|
-
return getFile(http, requireId(args, "file"));
|
|
1164
|
-
case "file:list":
|
|
1165
|
-
return listFilesForVariant(http, requireParent(args, "variant"));
|
|
1166
|
-
case "customer:get":
|
|
1167
|
-
return getCustomer(http, requireId(args, "customer"));
|
|
1168
|
-
case "customer:list":
|
|
1169
|
-
return listCustomersForStore(http, requireStore(args));
|
|
1170
|
-
case "customer:create":
|
|
1171
|
-
return createCustomer(http, requireBody(args));
|
|
1172
|
-
case "customer:update":
|
|
1173
|
-
return updateCustomer(http, requireId(args, "customer"), requireBody(args));
|
|
1174
|
-
case "order:get":
|
|
1175
|
-
return getOrder(http, requireId(args, "order"));
|
|
1176
|
-
case "order:list":
|
|
1177
|
-
return listOrdersForStore(http, requireStore(args));
|
|
1178
|
-
case "order:refund":
|
|
1179
|
-
return refundOrder(http, requireId(args, "order"), args.body);
|
|
1180
|
-
case "order:generate-invoice":
|
|
1181
|
-
return generateOrderInvoice(http, requireId(args, "order"), args.body);
|
|
1182
|
-
case "order-item:get":
|
|
1183
|
-
return getOrderItem(http, requireId(args, "order-item"));
|
|
1184
|
-
case "order-item:list":
|
|
1185
|
-
return listOrderItemsForOrder(http, requireParent(args, "order"));
|
|
1186
|
-
case "subscription:get":
|
|
1187
|
-
return getSubscription(http, requireId(args, "subscription"));
|
|
1188
|
-
case "subscription:list":
|
|
1189
|
-
return listSubscriptionsForStore(http, requireStore(args));
|
|
1190
|
-
case "subscription:update":
|
|
1191
|
-
return updateSubscription(http, requireId(args, "subscription"), requireBody(args));
|
|
1192
|
-
case "subscription:cancel":
|
|
1193
|
-
return cancelSubscription(http, requireId(args, "subscription"));
|
|
1194
|
-
case "subscription-item:get":
|
|
1195
|
-
return getSubscriptionItem(http, requireId(args, "subscription-item"));
|
|
1196
|
-
case "subscription-item:list":
|
|
1197
|
-
return listSubscriptionItemsForSubscription(http, requireParent(args, "subscription"));
|
|
1198
|
-
case "subscription-item:update":
|
|
1199
|
-
return updateSubscriptionItem(http, requireId(args, "subscription-item"), requireBody(args));
|
|
1200
|
-
case "subscription-item:current-usage":
|
|
1201
|
-
return getSubscriptionItemCurrentUsage(http, requireId(args, "subscription-item"));
|
|
1202
|
-
case "subscription-invoice:get":
|
|
1203
|
-
return getSubscriptionInvoice(http, requireId(args, "subscription-invoice"));
|
|
1204
|
-
case "subscription-invoice:list":
|
|
1205
|
-
return listSubscriptionInvoicesForSubscription(http, requireParent(args, "subscription"));
|
|
1206
|
-
case "subscription-invoice:refund":
|
|
1207
|
-
return refundSubscriptionInvoice(http, requireId(args, "subscription-invoice"), args.body);
|
|
1208
|
-
case "subscription-invoice:generate-invoice":
|
|
1209
|
-
return generateSubscriptionInvoice(http, requireId(args, "subscription-invoice"), args.body);
|
|
1210
|
-
case "usage-record:get":
|
|
1211
|
-
return getUsageRecord(http, requireId(args, "usage-record"));
|
|
1212
|
-
case "usage-record:list":
|
|
1213
|
-
return listUsageRecordsForSubscriptionItem(http, requireParent(args, "subscription-item"));
|
|
1214
|
-
case "usage-record:create":
|
|
1215
|
-
return createUsageRecord(http, requireBody(args));
|
|
1216
|
-
case "discount:get":
|
|
1217
|
-
return getDiscount(http, requireId(args, "discount"));
|
|
1218
|
-
case "discount:list":
|
|
1219
|
-
return listDiscountsForStore(http, requireStore(args));
|
|
1220
|
-
case "discount:create":
|
|
1221
|
-
return createDiscount(http, requireBody(args));
|
|
1222
|
-
case "discount:delete":
|
|
1223
|
-
await deleteDiscount(http, requireId(args, "discount"));
|
|
1224
|
-
return void 0;
|
|
1225
|
-
case "discount-redemption:get":
|
|
1226
|
-
return getDiscountRedemption(http, requireId(args, "discount-redemption"));
|
|
1227
|
-
case "discount-redemption:list":
|
|
1228
|
-
return listDiscountRedemptionsForDiscount(http, requireParent(args, "discount"));
|
|
1229
|
-
case "license-key:get":
|
|
1230
|
-
return getLicenseKey(http, requireId(args, "license-key"));
|
|
1231
|
-
case "license-key:list":
|
|
1232
|
-
return listLicenseKeysForStore(http, requireStore(args));
|
|
1233
|
-
case "license-key:update":
|
|
1234
|
-
return updateLicenseKey(http, requireId(args, "license-key"), requireBody(args));
|
|
1235
|
-
case "license-key-instance:get":
|
|
1236
|
-
return getLicenseKeyInstance(http, requireId(args, "license-key-instance"));
|
|
1237
|
-
case "license-key-instance:list":
|
|
1238
|
-
return listLicenseKeyInstancesForLicenseKey(http, requireParent(args, "license-key"));
|
|
1239
|
-
case "checkout:get":
|
|
1240
|
-
return getCheckout(http, requireId(args, "checkout"));
|
|
1241
|
-
case "checkout:list":
|
|
1242
|
-
return listCheckoutsForStore(http, requireStore(args));
|
|
1243
|
-
case "checkout:create":
|
|
1244
|
-
return createCheckout(http, requireBody(args));
|
|
1245
|
-
case "webhook:get":
|
|
1246
|
-
return getWebhook(http, requireId(args, "webhook"));
|
|
1247
|
-
case "webhook:list":
|
|
1248
|
-
return listWebhooksForStore(http, requireStore(args));
|
|
1249
|
-
case "webhook:create":
|
|
1250
|
-
return createWebhook(http, requireBody(args));
|
|
1251
|
-
case "webhook:update":
|
|
1252
|
-
return updateWebhook(http, requireId(args, "webhook"), requireBody(args));
|
|
1253
|
-
case "webhook:delete":
|
|
1254
|
-
await deleteWebhook(http, requireId(args, "webhook"));
|
|
1255
|
-
return void 0;
|
|
1256
|
-
case "affiliate:get":
|
|
1257
|
-
return getAffiliate(http, requireId(args, "affiliate"));
|
|
1258
|
-
case "affiliate:list":
|
|
1259
|
-
return listAffiliatesForStore(http, requireStore(args));
|
|
1260
|
-
default:
|
|
1261
|
-
throw new FreshSqueezyError({
|
|
1262
|
-
code: "UNKNOWN_OP",
|
|
1263
|
-
message: `Op registered but not wired: ${key}`
|
|
1264
|
-
});
|
|
1265
|
-
}
|
|
1266
|
-
};
|
|
1267
|
-
var requireId = (args, label) => {
|
|
469
|
+
var requireId = (args, spec) => {
|
|
1268
470
|
if (args.id === void 0 || args.id === "") {
|
|
1269
471
|
throw new FreshSqueezyError({
|
|
1270
472
|
code: "MISSING_ARG",
|
|
1271
|
-
message: `--id is required for this ${
|
|
473
|
+
message: `--id is required for this ${spec.resource} operation.`
|
|
1272
474
|
});
|
|
1273
475
|
}
|
|
1274
476
|
return args.id;
|
|
@@ -1282,11 +484,11 @@ var requireStore = (args) => {
|
|
|
1282
484
|
}
|
|
1283
485
|
return args.storeId;
|
|
1284
486
|
};
|
|
1285
|
-
var requireParent = (args,
|
|
487
|
+
var requireParent = (args, parent) => {
|
|
1286
488
|
if (args.parentId === void 0 || args.parentId === "") {
|
|
1287
489
|
throw new FreshSqueezyError({
|
|
1288
490
|
code: "MISSING_ARG",
|
|
1289
|
-
message: `--parent-id (${
|
|
491
|
+
message: `--parent-id (${parent} id) is required for this list operation.`
|
|
1290
492
|
});
|
|
1291
493
|
}
|
|
1292
494
|
return args.parentId;
|
|
@@ -1300,15 +502,44 @@ var requireBody = (args) => {
|
|
|
1300
502
|
}
|
|
1301
503
|
return args.body;
|
|
1302
504
|
};
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
505
|
+
var listFilter = (spec, args) => {
|
|
506
|
+
const listScope = RESOURCES.find(([resource]) => resource === spec.resource)?.[2];
|
|
507
|
+
if (!listScope) return void 0;
|
|
508
|
+
const scopeId = listScope === "store" ? requireStore(args) : requireParent(args, listScope);
|
|
509
|
+
return { [`filter[${listScope.replace(/-/g, "_")}_id]`]: String(scopeId) };
|
|
510
|
+
};
|
|
511
|
+
var requestBody = (rule, args) => {
|
|
512
|
+
if (rule.body === "required") return requireBody(args);
|
|
513
|
+
if (rule.body === "optional") return args.body ?? {};
|
|
1308
514
|
return void 0;
|
|
1309
515
|
};
|
|
516
|
+
var invokeOp = async (http, resource, verb, args = {}) => {
|
|
517
|
+
const spec = findResourceVerb(resource, verb);
|
|
518
|
+
if (!spec) {
|
|
519
|
+
throw new FreshSqueezyError({
|
|
520
|
+
code: "UNKNOWN_OP",
|
|
521
|
+
message: `Unknown or unsupported op: ${verb} ${resource}. Run \`fresh-squeezy ops --list\`.`
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
if (spec.resource === "user") {
|
|
525
|
+
const doc2 = await http.request({ path: USER_ME_PATH });
|
|
526
|
+
return doc2.data;
|
|
527
|
+
}
|
|
528
|
+
const collectionPath = `/v1/${spec.resource}s`;
|
|
529
|
+
if (spec.verb === "list") {
|
|
530
|
+
return http.paginate(collectionPath, listFilter(spec, args));
|
|
531
|
+
}
|
|
532
|
+
const rule = VERB_RULES[spec.verb];
|
|
533
|
+
const path4 = collectionPath + rule.path.replace("{id}", () => String(requireId(args, spec)));
|
|
534
|
+
const doc = await http.request({
|
|
535
|
+
method: rule.method,
|
|
536
|
+
path: path4,
|
|
537
|
+
body: requestBody(rule, args)
|
|
538
|
+
});
|
|
539
|
+
return doc?.data ?? doc;
|
|
540
|
+
};
|
|
1310
541
|
|
|
1311
|
-
// src/validate/
|
|
542
|
+
// src/validate/issues.ts
|
|
1312
543
|
var ISSUE_CODES = {
|
|
1313
544
|
AUTH_FAILED: "AUTH_FAILED",
|
|
1314
545
|
MODE_MISMATCH: "MODE_MISMATCH",
|
|
@@ -1432,11 +663,19 @@ var checkStoreOwnership = (check) => {
|
|
|
1432
663
|
};
|
|
1433
664
|
|
|
1434
665
|
// src/validate/connection.ts
|
|
666
|
+
var resolveActualMode = (testMode) => {
|
|
667
|
+
if (testMode === true) return "test";
|
|
668
|
+
if (testMode === false) return "live";
|
|
669
|
+
return void 0;
|
|
670
|
+
};
|
|
671
|
+
var fetchUserDocument = (http) => {
|
|
672
|
+
return http.request({ path: "/v1/users/me" });
|
|
673
|
+
};
|
|
1435
674
|
var validateConnection = async (http, mode) => {
|
|
1436
675
|
const fetched = await probeCollection(
|
|
1437
676
|
async () => {
|
|
1438
|
-
const userDoc2 = await
|
|
1439
|
-
const stores2 = await
|
|
677
|
+
const userDoc2 = await fetchUserDocument(http);
|
|
678
|
+
const stores2 = await http.paginate("/v1/stores");
|
|
1440
679
|
return { userDoc: userDoc2, stores: stores2 };
|
|
1441
680
|
},
|
|
1442
681
|
{
|
|
@@ -1492,12 +731,15 @@ var validateDiscount = async (http, mode, options) => {
|
|
|
1492
731
|
label: `discount ${options.discountId}`,
|
|
1493
732
|
id: String(options.discountId)
|
|
1494
733
|
};
|
|
1495
|
-
const fetched = await probeFetch(
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
734
|
+
const fetched = await probeFetch(
|
|
735
|
+
() => http.getResource(`/v1/discounts/${options.discountId}`),
|
|
736
|
+
{
|
|
737
|
+
notFoundCode: ISSUE_CODES.DISCOUNT_NOT_FOUND,
|
|
738
|
+
notFoundMessage: `Discount ${options.discountId} not found.`,
|
|
739
|
+
notFoundFix: "Verify the discount ID in the Lemon Squeezy dashboard.",
|
|
740
|
+
notFoundContext: { discountId: String(options.discountId) }
|
|
741
|
+
}
|
|
742
|
+
);
|
|
1501
743
|
if (!fetched.ok) {
|
|
1502
744
|
return buildResult("discount", mode, [fetched.issue], void 0, target);
|
|
1503
745
|
}
|
|
@@ -1604,12 +846,15 @@ var validateLicenseKey = async (http, mode, options) => {
|
|
|
1604
846
|
label: `license key ${options.licenseKeyId}`,
|
|
1605
847
|
id: String(options.licenseKeyId)
|
|
1606
848
|
};
|
|
1607
|
-
const fetched = await probeFetch(
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
849
|
+
const fetched = await probeFetch(
|
|
850
|
+
() => http.getResource(`/v1/license-keys/${options.licenseKeyId}`),
|
|
851
|
+
{
|
|
852
|
+
notFoundCode: ISSUE_CODES.LICENSE_KEY_NOT_FOUND,
|
|
853
|
+
notFoundMessage: `License key ${options.licenseKeyId} not found.`,
|
|
854
|
+
notFoundFix: "Verify the license key ID in the Lemon Squeezy dashboard.",
|
|
855
|
+
notFoundContext: { licenseKeyId: String(options.licenseKeyId) }
|
|
856
|
+
}
|
|
857
|
+
);
|
|
1613
858
|
if (!fetched.ok) {
|
|
1614
859
|
return buildResult(
|
|
1615
860
|
"licenseKey",
|
|
@@ -1691,19 +936,24 @@ var validateProduct = async (http, mode, options) => {
|
|
|
1691
936
|
label: `product ${options.productId}`,
|
|
1692
937
|
id: String(options.productId)
|
|
1693
938
|
};
|
|
1694
|
-
const fetched = await probeFetch(
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
939
|
+
const fetched = await probeFetch(
|
|
940
|
+
() => http.getResource(`/v1/products/${options.productId}`),
|
|
941
|
+
{
|
|
942
|
+
notFoundCode: ISSUE_CODES.PRODUCT_NOT_FOUND,
|
|
943
|
+
notFoundMessage: `Product ${options.productId} not found.`,
|
|
944
|
+
notFoundFix: "Verify the product ID in the Lemon Squeezy dashboard.",
|
|
945
|
+
notFoundContext: { productId: String(options.productId) }
|
|
946
|
+
}
|
|
947
|
+
);
|
|
1700
948
|
if (!fetched.ok) {
|
|
1701
949
|
return buildResult("product", mode, [fetched.issue], void 0, target);
|
|
1702
950
|
}
|
|
1703
951
|
const attrs = fetched.resource.attributes;
|
|
1704
952
|
issues.push(...checkProduct(attrs, { expectedStoreId: options.expectedStoreId }));
|
|
1705
953
|
const variantsProbed = await probeCollection(
|
|
1706
|
-
() =>
|
|
954
|
+
() => http.paginate("/v1/variants", {
|
|
955
|
+
"filter[product_id]": String(options.productId)
|
|
956
|
+
})
|
|
1707
957
|
);
|
|
1708
958
|
if (!variantsProbed.ok) {
|
|
1709
959
|
issues.push({ ...variantsProbed.issue, severity: "warning" });
|
|
@@ -1772,12 +1022,15 @@ var checkProduct = (attrs, options = {}) => {
|
|
|
1772
1022
|
// src/validate/store.ts
|
|
1773
1023
|
var validateStore = async (http, mode, storeId) => {
|
|
1774
1024
|
const target = { label: `store ${storeId}`, id: String(storeId) };
|
|
1775
|
-
const fetched = await probeFetch(
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1025
|
+
const fetched = await probeFetch(
|
|
1026
|
+
() => http.getResource(`/v1/stores/${storeId}`),
|
|
1027
|
+
{
|
|
1028
|
+
notFoundCode: ISSUE_CODES.STORE_NOT_FOUND,
|
|
1029
|
+
notFoundMessage: `Store ${storeId} not found with the current API key.`,
|
|
1030
|
+
notFoundFix: "Check the store ID and confirm the API key belongs to the account that owns it.",
|
|
1031
|
+
notFoundContext: { storeId: String(storeId) }
|
|
1032
|
+
}
|
|
1033
|
+
);
|
|
1781
1034
|
if (!fetched.ok) {
|
|
1782
1035
|
return buildResult("store", mode, [fetched.issue], void 0, target);
|
|
1783
1036
|
}
|
|
@@ -1795,7 +1048,7 @@ var validateSubscriptionPlan = async (http, mode, options) => {
|
|
|
1795
1048
|
id: String(options.variantId)
|
|
1796
1049
|
};
|
|
1797
1050
|
const fetched = await probeFetch(
|
|
1798
|
-
() =>
|
|
1051
|
+
() => http.getResource(`/v1/variants/${options.variantId}`),
|
|
1799
1052
|
{
|
|
1800
1053
|
notFoundCode: ISSUE_CODES.PLAN_VARIANT_NOT_FOUND,
|
|
1801
1054
|
notFoundMessage: `Variant ${options.variantId} not found.`,
|
|
@@ -1815,10 +1068,13 @@ var validateSubscriptionPlan = async (http, mode, options) => {
|
|
|
1815
1068
|
const variant = fetched.resource;
|
|
1816
1069
|
const attrs = variant.attributes;
|
|
1817
1070
|
const issues = checkSubscriptionPlan(attrs, { variantId: options.variantId });
|
|
1818
|
-
const productProbed = await probeFetch(
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1071
|
+
const productProbed = await probeFetch(
|
|
1072
|
+
() => http.getResource(`/v1/products/${attrs.product_id}`),
|
|
1073
|
+
{
|
|
1074
|
+
notFoundCode: ISSUE_CODES.PRODUCT_NOT_FOUND,
|
|
1075
|
+
notFoundMessage: `Product ${attrs.product_id} not found.`
|
|
1076
|
+
}
|
|
1077
|
+
);
|
|
1822
1078
|
if (productProbed.ok) {
|
|
1823
1079
|
const mismatch = checkStoreOwnership({
|
|
1824
1080
|
expectedStoreId: options.storeId,
|
|
@@ -1929,14 +1185,6 @@ var checkSubscriptionPlan = (attrs, options) => {
|
|
|
1929
1185
|
return issues;
|
|
1930
1186
|
};
|
|
1931
1187
|
|
|
1932
|
-
// src/core/equality.ts
|
|
1933
|
-
var sameWebhookUrl = (a, b) => {
|
|
1934
|
-
return normalizeWebhookUrl(a) === normalizeWebhookUrl(b);
|
|
1935
|
-
};
|
|
1936
|
-
var normalizeWebhookUrl = (raw) => {
|
|
1937
|
-
return raw.replace(/\/+$/, "").toLowerCase();
|
|
1938
|
-
};
|
|
1939
|
-
|
|
1940
1188
|
// src/support/manifest.ts
|
|
1941
1189
|
var RECOMMENDED_WEBHOOK_EVENTS = [
|
|
1942
1190
|
"order_created",
|
|
@@ -1957,9 +1205,19 @@ var OPTIONAL_WEBHOOK_EVENTS = [
|
|
|
1957
1205
|
];
|
|
1958
1206
|
|
|
1959
1207
|
// src/validate/webhook.ts
|
|
1208
|
+
var sameWebhookUrl = (a, b) => {
|
|
1209
|
+
return normalizeWebhookUrl(a) === normalizeWebhookUrl(b);
|
|
1210
|
+
};
|
|
1211
|
+
var normalizeWebhookUrl = (raw) => {
|
|
1212
|
+
return raw.replace(/\/+$/, "").toLowerCase();
|
|
1213
|
+
};
|
|
1960
1214
|
var validateWebhook = async (http, mode, options) => {
|
|
1961
1215
|
const target = { label: options.url, url: options.url };
|
|
1962
|
-
const fetched = await probeCollection(
|
|
1216
|
+
const fetched = await probeCollection(
|
|
1217
|
+
() => http.paginate("/v1/webhooks", {
|
|
1218
|
+
"filter[store_id]": String(options.storeId)
|
|
1219
|
+
})
|
|
1220
|
+
);
|
|
1963
1221
|
if (!fetched.ok) {
|
|
1964
1222
|
return buildResult("webhook", mode, [fetched.issue], void 0, target);
|
|
1965
1223
|
}
|
|
@@ -2214,80 +1472,196 @@ var createFreshSqueezy = (config = {}) => {
|
|
|
2214
1472
|
};
|
|
2215
1473
|
};
|
|
2216
1474
|
|
|
2217
|
-
// src/cli/
|
|
2218
|
-
var
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
}
|
|
1475
|
+
// src/cli/optionalValidators.ts
|
|
1476
|
+
var errorMessage = (err) => err instanceof Error ? err.message : String(err);
|
|
1477
|
+
var listChoices = async (load, toChoice) => {
|
|
1478
|
+
try {
|
|
1479
|
+
const items = await load();
|
|
1480
|
+
return { choices: items.map(toChoice) };
|
|
1481
|
+
} catch (err) {
|
|
1482
|
+
return { choices: [], error: errorMessage(err) };
|
|
2225
1483
|
}
|
|
2226
|
-
return `${lines.join("\n")}
|
|
2227
|
-
`;
|
|
2228
1484
|
};
|
|
2229
|
-
var
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
1485
|
+
var discoverSubscriptionPlans = async ({
|
|
1486
|
+
client,
|
|
1487
|
+
listProducts
|
|
1488
|
+
}) => {
|
|
1489
|
+
const choices = [];
|
|
1490
|
+
try {
|
|
1491
|
+
for (const product of await listProducts()) {
|
|
1492
|
+
const variants = await client.variants.list(
|
|
1493
|
+
product.id
|
|
1494
|
+
);
|
|
1495
|
+
for (const variant of variants) {
|
|
1496
|
+
if (!variant.attributes.is_subscription) continue;
|
|
1497
|
+
const { name, interval, interval_count } = variant.attributes;
|
|
1498
|
+
const cadence = interval ? `${interval_count ?? 1}/${interval}` : "no interval";
|
|
1499
|
+
choices.push({
|
|
1500
|
+
value: variant.id,
|
|
1501
|
+
label: `${product.attributes.name} / ${name} (${cadence}) - id ${variant.id}`
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
return { choices };
|
|
1506
|
+
} catch (err) {
|
|
1507
|
+
return { choices, error: errorMessage(err) };
|
|
2239
1508
|
}
|
|
2240
|
-
return [];
|
|
2241
1509
|
};
|
|
2242
|
-
var
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
if (err.code === "INVALID_MODE") {
|
|
2248
|
-
return [
|
|
2249
|
-
`fresh-squeezy validate ${target} --mode test`,
|
|
2250
|
-
`fresh-squeezy validate ${target} --mode live`
|
|
2251
|
-
];
|
|
2252
|
-
}
|
|
2253
|
-
if (err.code === "MISSING_ARG") {
|
|
2254
|
-
return getMissingArgHints(target);
|
|
1510
|
+
var isHttpUrl = (value) => {
|
|
1511
|
+
try {
|
|
1512
|
+
return ["http:", "https:"].includes(new URL(value).protocol);
|
|
1513
|
+
} catch {
|
|
1514
|
+
return false;
|
|
2255
1515
|
}
|
|
2256
|
-
return [];
|
|
2257
1516
|
};
|
|
2258
|
-
var
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
1517
|
+
var validateWebhookUrls = (value) => {
|
|
1518
|
+
const urls = value.split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
1519
|
+
return urls.every(isHttpUrl) ? true : "Enter valid webhook URLs.";
|
|
1520
|
+
};
|
|
1521
|
+
var OPTIONAL_VALIDATORS = [
|
|
1522
|
+
{
|
|
1523
|
+
name: "product",
|
|
1524
|
+
field: "productIds",
|
|
1525
|
+
resultName: "product",
|
|
1526
|
+
label: "Products",
|
|
1527
|
+
menuLabel: "Product checkout",
|
|
1528
|
+
noun: "products",
|
|
1529
|
+
manualNoun: "Product IDs",
|
|
1530
|
+
discover: ({ listProducts }) => listChoices(listProducts, (product) => ({
|
|
1531
|
+
value: product.id,
|
|
1532
|
+
label: `${product.attributes.name} (${product.attributes.status}) - id ${product.id}`
|
|
1533
|
+
}))
|
|
1534
|
+
},
|
|
1535
|
+
{
|
|
1536
|
+
name: "webhook",
|
|
1537
|
+
field: "webhookUrls",
|
|
1538
|
+
resultName: "webhook",
|
|
1539
|
+
label: "Webhooks",
|
|
1540
|
+
menuLabel: "Webhook registration",
|
|
1541
|
+
noun: "webhook URLs",
|
|
1542
|
+
manualNoun: "Webhook URLs",
|
|
1543
|
+
validate: validateWebhookUrls,
|
|
1544
|
+
discover: ({ client, storeId }) => listChoices(
|
|
1545
|
+
() => client.webhooks.list(storeId),
|
|
1546
|
+
(webhook) => ({
|
|
1547
|
+
value: webhook.attributes.url,
|
|
1548
|
+
label: `${webhook.attributes.url} - id ${webhook.id}`
|
|
1549
|
+
})
|
|
1550
|
+
)
|
|
1551
|
+
},
|
|
1552
|
+
{
|
|
1553
|
+
name: "discount",
|
|
1554
|
+
field: "discountIds",
|
|
1555
|
+
resultName: "discount",
|
|
1556
|
+
label: "Discounts",
|
|
1557
|
+
menuLabel: "Discount code",
|
|
1558
|
+
noun: "discounts",
|
|
1559
|
+
manualNoun: "Discount IDs",
|
|
1560
|
+
discover: ({ client, storeId }) => listChoices(
|
|
1561
|
+
() => client.discounts.list(storeId),
|
|
1562
|
+
(discount) => ({
|
|
1563
|
+
value: discount.id,
|
|
1564
|
+
label: `${discount.attributes.name} (${discount.attributes.code}) - id ${discount.id}`
|
|
1565
|
+
})
|
|
1566
|
+
)
|
|
1567
|
+
},
|
|
1568
|
+
{
|
|
1569
|
+
name: "license-key",
|
|
1570
|
+
field: "licenseKeyIds",
|
|
1571
|
+
resultName: "licenseKey",
|
|
1572
|
+
label: "License keys",
|
|
1573
|
+
menuLabel: "License key",
|
|
1574
|
+
noun: "license keys",
|
|
1575
|
+
manualNoun: "License key IDs",
|
|
1576
|
+
discover: ({ client, storeId }) => listChoices(
|
|
1577
|
+
() => client.licenseKeys.list(storeId),
|
|
1578
|
+
(key) => ({
|
|
1579
|
+
value: key.id,
|
|
1580
|
+
label: `${key.attributes.key_short} (${key.attributes.status}) - id ${key.id}`
|
|
1581
|
+
})
|
|
1582
|
+
)
|
|
1583
|
+
},
|
|
1584
|
+
{
|
|
1585
|
+
name: "subscription-plan",
|
|
1586
|
+
field: "variantIds",
|
|
1587
|
+
resultName: "subscriptionPlan",
|
|
1588
|
+
label: "Subscription plans",
|
|
1589
|
+
menuLabel: "Subscription plan",
|
|
1590
|
+
noun: "subscription plans",
|
|
1591
|
+
manualNoun: "Subscription plan variant IDs",
|
|
1592
|
+
discover: discoverSubscriptionPlans
|
|
2279
1593
|
}
|
|
2280
|
-
|
|
2281
|
-
|
|
1594
|
+
];
|
|
1595
|
+
var discoverChoices = async (client, storeId, names) => {
|
|
1596
|
+
let products;
|
|
1597
|
+
const context = {
|
|
1598
|
+
client,
|
|
1599
|
+
storeId,
|
|
1600
|
+
listProducts: () => {
|
|
1601
|
+
products ??= client.products.list(storeId);
|
|
1602
|
+
return products;
|
|
1603
|
+
}
|
|
1604
|
+
};
|
|
1605
|
+
const choices = {};
|
|
1606
|
+
for (const row of OPTIONAL_VALIDATORS) {
|
|
1607
|
+
if (names.includes(row.name)) choices[row.name] = await row.discover(context);
|
|
2282
1608
|
}
|
|
2283
|
-
return
|
|
2284
|
-
};
|
|
2285
|
-
var isFreshSqueezyError = (err) => {
|
|
2286
|
-
return err instanceof FreshSqueezyError;
|
|
1609
|
+
return choices;
|
|
2287
1610
|
};
|
|
2288
1611
|
|
|
2289
1612
|
// src/cli/render.ts
|
|
2290
1613
|
import chalk from "chalk";
|
|
1614
|
+
var MISSING_API_KEY_HINTS = [
|
|
1615
|
+
"fresh-squeezy init",
|
|
1616
|
+
`export ${ENV_KEYS.apiKey}=ls_live_or_test_key`
|
|
1617
|
+
];
|
|
1618
|
+
var brand = chalk.green.bold("fresh-squeezy");
|
|
1619
|
+
var divider = chalk.dim("\u2022");
|
|
1620
|
+
var renderBrandHeader = (title, subtitle) => {
|
|
1621
|
+
const lines = [`${brand} ${divider} ${chalk.bold(title)}`];
|
|
1622
|
+
if (subtitle) lines.push(chalk.dim(subtitle));
|
|
1623
|
+
lines.push("");
|
|
1624
|
+
return lines.join("\n");
|
|
1625
|
+
};
|
|
1626
|
+
var renderStep = (index, total, title, detail) => {
|
|
1627
|
+
const suffix = detail ? ` ${chalk.dim(detail)}` : "";
|
|
1628
|
+
const prefix = index > 1 ? "\n" : "";
|
|
1629
|
+
return `${prefix}${chalk.yellow("\u25CF")} ${chalk.dim(`${index}/${total}`)} ${chalk.bold(title)}${suffix}
|
|
1630
|
+
`;
|
|
1631
|
+
};
|
|
1632
|
+
var renderDetected = (label, value, source) => {
|
|
1633
|
+
const suffix = source ? ` ${chalk.dim(`from ${source}`)}` : "";
|
|
1634
|
+
return ` ${chalk.green("\u2713")} ${chalk.bold(label)} ${value}${suffix}
|
|
1635
|
+
`;
|
|
1636
|
+
};
|
|
1637
|
+
var renderCommandExamples = () => {
|
|
1638
|
+
return [
|
|
1639
|
+
renderBrandHeader("Command examples", "Direct commands stay stable for scripts and CI."),
|
|
1640
|
+
`${chalk.bold("Guided setup")}`,
|
|
1641
|
+
" fresh-squeezy init",
|
|
1642
|
+
"",
|
|
1643
|
+
`${chalk.bold("Full doctor")}`,
|
|
1644
|
+
" fresh-squeezy doctor --all-stores",
|
|
1645
|
+
" fresh-squeezy doctor --store-ids 12 --product-id 987 --webhook-url https://app.example.com/api/webhooks/lemon-squeezy",
|
|
1646
|
+
"",
|
|
1647
|
+
`${chalk.bold("Single checks")}`,
|
|
1648
|
+
" fresh-squeezy validate connection",
|
|
1649
|
+
" fresh-squeezy validate webhook --store-ids 12 --webhook-url https://app.example.com/api/webhooks/lemon-squeezy",
|
|
1650
|
+
"",
|
|
1651
|
+
`${chalk.bold("Bulk ops (delete / cancel / refund)")}`,
|
|
1652
|
+
" fresh-squeezy delete discount --all --store-ids 12 --dry-run",
|
|
1653
|
+
" fresh-squeezy delete discount --all --store-ids 12 --match TEST --yes",
|
|
1654
|
+
" fresh-squeezy delete webhook --ids 1,2,3 --yes",
|
|
1655
|
+
"",
|
|
1656
|
+
`${chalk.bold("Automation")}`,
|
|
1657
|
+
" fresh-squeezy doctor --all-stores --json",
|
|
1658
|
+
""
|
|
1659
|
+
].join("\n");
|
|
1660
|
+
};
|
|
1661
|
+
var renderCancelMessage = () => {
|
|
1662
|
+
return `${chalk.dim("fresh-squeezy cancelled.")}
|
|
1663
|
+
`;
|
|
1664
|
+
};
|
|
2291
1665
|
var renderResult = (result) => {
|
|
2292
1666
|
const lines = [];
|
|
2293
1667
|
const badge = result.ok ? chalk.green("PASS") : chalk.red("FAIL");
|
|
@@ -2324,140 +1698,37 @@ var renderIssueLine = (issue2) => {
|
|
|
2324
1698
|
const label = issue2.severity === "error" ? chalk.red("\u2717 error") : issue2.severity === "warning" ? chalk.yellow("! warn ") : chalk.blue("i info ");
|
|
2325
1699
|
return `${label} ${chalk.gray(`[${issue2.code}]`)} ${issue2.message}`;
|
|
2326
1700
|
};
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
var EMPTY_INIT_RESOURCE_CHOICES = {
|
|
2334
|
-
products: { choices: [] },
|
|
2335
|
-
webhooks: { choices: [] },
|
|
2336
|
-
discounts: { choices: [] },
|
|
2337
|
-
licenseKeys: { choices: [] },
|
|
2338
|
-
subscriptionPlans: { choices: [] }
|
|
2339
|
-
};
|
|
2340
|
-
var discoverInitResourceChoices = async (client, storeId, targets) => {
|
|
2341
|
-
const choices = {
|
|
2342
|
-
products: { choices: [] },
|
|
2343
|
-
webhooks: { choices: [] },
|
|
2344
|
-
discounts: { choices: [] },
|
|
2345
|
-
licenseKeys: { choices: [] },
|
|
2346
|
-
subscriptionPlans: { choices: [] }
|
|
2347
|
-
};
|
|
2348
|
-
let products;
|
|
2349
|
-
if (targets.includes("product") || targets.includes("subscription-plan")) {
|
|
2350
|
-
const result = await discover(
|
|
2351
|
-
() => paginate(client, "/v1/products", { "filter[store_id]": storeId })
|
|
2352
|
-
);
|
|
2353
|
-
if (result.ok) {
|
|
2354
|
-
products = result.value;
|
|
2355
|
-
choices.products = { choices: result.value.map(toProductChoice) };
|
|
2356
|
-
} else {
|
|
2357
|
-
choices.products = { choices: [], error: result.error };
|
|
2358
|
-
}
|
|
2359
|
-
}
|
|
2360
|
-
if (targets.includes("webhook")) {
|
|
2361
|
-
const result = await discover(
|
|
2362
|
-
() => paginate(client, "/v1/webhooks", { "filter[store_id]": storeId })
|
|
2363
|
-
);
|
|
2364
|
-
choices.webhooks = result.ok ? { choices: result.value.map(toWebhookChoice) } : { choices: [], error: result.error };
|
|
2365
|
-
}
|
|
2366
|
-
if (targets.includes("discount")) {
|
|
2367
|
-
const result = await discover(
|
|
2368
|
-
() => paginate(client, "/v1/discounts", { "filter[store_id]": storeId })
|
|
2369
|
-
);
|
|
2370
|
-
choices.discounts = result.ok ? { choices: result.value.map(toDiscountChoice) } : { choices: [], error: result.error };
|
|
2371
|
-
}
|
|
2372
|
-
if (targets.includes("license-key")) {
|
|
2373
|
-
const result = await discover(
|
|
2374
|
-
() => paginate(client, "/v1/license-keys", { "filter[store_id]": storeId })
|
|
2375
|
-
);
|
|
2376
|
-
choices.licenseKeys = result.ok ? { choices: result.value.map(toLicenseKeyChoice) } : { choices: [], error: result.error };
|
|
2377
|
-
}
|
|
2378
|
-
if (targets.includes("subscription-plan")) {
|
|
2379
|
-
const listedProducts = products ?? [];
|
|
2380
|
-
if (choices.products.error) {
|
|
2381
|
-
choices.subscriptionPlans = { choices: [], error: choices.products.error };
|
|
2382
|
-
} else {
|
|
2383
|
-
choices.subscriptionPlans = await discoverSubscriptionPlans(client, listedProducts);
|
|
1701
|
+
var renderCliError = (message, hints = []) => {
|
|
1702
|
+
const lines = [`fresh-squeezy: ${message}`];
|
|
1703
|
+
if (hints.length > 0) {
|
|
1704
|
+
lines.push("", "Try:");
|
|
1705
|
+
for (const hint of hints) {
|
|
1706
|
+
lines.push(` ${hint}`);
|
|
2384
1707
|
}
|
|
2385
1708
|
}
|
|
2386
|
-
return
|
|
1709
|
+
return `${lines.join("\n")}
|
|
1710
|
+
`;
|
|
2387
1711
|
};
|
|
2388
|
-
var
|
|
2389
|
-
|
|
2390
|
-
for (const product of products) {
|
|
2391
|
-
const result = await discover(
|
|
2392
|
-
() => paginate(client, "/v1/variants", {
|
|
2393
|
-
"filter[product_id]": product.id
|
|
2394
|
-
})
|
|
2395
|
-
);
|
|
2396
|
-
if (!result.ok) {
|
|
2397
|
-
return { choices: discovered, error: result.error };
|
|
2398
|
-
}
|
|
2399
|
-
for (const variant of result.value) {
|
|
2400
|
-
if (variant.attributes.is_subscription) {
|
|
2401
|
-
discovered.push(toSubscriptionPlanChoice(variant, product.attributes.name));
|
|
2402
|
-
}
|
|
2403
|
-
}
|
|
2404
|
-
}
|
|
2405
|
-
return { choices: discovered };
|
|
1712
|
+
var isFreshSqueezyError = (err) => {
|
|
1713
|
+
return err instanceof FreshSqueezyError;
|
|
2406
1714
|
};
|
|
2407
|
-
var
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
const doc = await client.request({
|
|
2412
|
-
path: path4,
|
|
2413
|
-
query: { ...query ?? {}, "page[number]": pageNumber }
|
|
2414
|
-
});
|
|
2415
|
-
all.push(...doc.data);
|
|
2416
|
-
const lastPage = doc.meta?.page?.lastPage;
|
|
2417
|
-
if (lastPage === void 0 || pageNumber >= lastPage) return all;
|
|
2418
|
-
pageNumber += 1;
|
|
1715
|
+
var getDoctorHints = (err) => {
|
|
1716
|
+
if (!isFreshSqueezyError(err)) return [];
|
|
1717
|
+
if (err.code === "MISSING_API_KEY") {
|
|
1718
|
+
return MISSING_API_KEY_HINTS;
|
|
2419
1719
|
}
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
try {
|
|
2423
|
-
return { ok: true, value: await load() };
|
|
2424
|
-
} catch (err) {
|
|
2425
|
-
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
1720
|
+
if (err.code === "INVALID_MODE") {
|
|
1721
|
+
return ["fresh-squeezy doctor --mode test", "fresh-squeezy doctor --mode live"];
|
|
2426
1722
|
}
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
label: `${product.attributes.name} (${product.attributes.status}) - id ${product.id}`
|
|
2432
|
-
};
|
|
2433
|
-
};
|
|
2434
|
-
var toWebhookChoice = (webhook) => {
|
|
2435
|
-
return {
|
|
2436
|
-
value: webhook.attributes.url,
|
|
2437
|
-
label: `${webhook.attributes.url} - id ${webhook.id}`
|
|
2438
|
-
};
|
|
2439
|
-
};
|
|
2440
|
-
var toDiscountChoice = (discount) => {
|
|
2441
|
-
return {
|
|
2442
|
-
value: discount.id,
|
|
2443
|
-
label: `${discount.attributes.name} (${discount.attributes.code}) - id ${discount.id}`
|
|
2444
|
-
};
|
|
2445
|
-
};
|
|
2446
|
-
var toLicenseKeyChoice = (licenseKey) => {
|
|
2447
|
-
return {
|
|
2448
|
-
value: licenseKey.id,
|
|
2449
|
-
label: `${licenseKey.attributes.key_short} (${licenseKey.attributes.status}) - id ${licenseKey.id}`
|
|
2450
|
-
};
|
|
2451
|
-
};
|
|
2452
|
-
var toSubscriptionPlanChoice = (variant, productName) => {
|
|
2453
|
-
const interval = variant.attributes.interval ? `${variant.attributes.interval_count ?? 1}/${variant.attributes.interval}` : "no interval";
|
|
2454
|
-
return {
|
|
2455
|
-
value: variant.id,
|
|
2456
|
-
label: `${productName} / ${variant.attributes.name} (${interval}) - id ${variant.id}`
|
|
2457
|
-
};
|
|
1723
|
+
if (err.code === "NO_STORES") {
|
|
1724
|
+
return ["Check that the API key belongs to an account with a Lemon Squeezy store."];
|
|
1725
|
+
}
|
|
1726
|
+
return [];
|
|
2458
1727
|
};
|
|
2459
1728
|
|
|
2460
1729
|
// src/cli/prompts.ts
|
|
1730
|
+
import path from "path";
|
|
1731
|
+
import { checkbox, confirm, input, password, select } from "@inquirer/prompts";
|
|
2461
1732
|
var PROMPT_THEME = {
|
|
2462
1733
|
prefix: {
|
|
2463
1734
|
idle: "\u203A",
|
|
@@ -2523,128 +1794,60 @@ var pickStores = async (choices) => {
|
|
|
2523
1794
|
validate: (selected) => selected.length > 0 ? true : "Pick at least one store."
|
|
2524
1795
|
});
|
|
2525
1796
|
};
|
|
2526
|
-
var
|
|
1797
|
+
var selectOptionalValidators = async () => {
|
|
2527
1798
|
return checkbox({
|
|
2528
1799
|
message: "Add resource checks to this doctor run?",
|
|
2529
1800
|
theme: PROMPT_THEME,
|
|
2530
|
-
choices:
|
|
2531
|
-
{ name: "Product checkout", value: "product" },
|
|
2532
|
-
{ name: "Webhook registration", value: "webhook" },
|
|
2533
|
-
{ name: "Discount code", value: "discount" },
|
|
2534
|
-
{ name: "License key", value: "license-key" },
|
|
2535
|
-
{ name: "Subscription plan", value: "subscription-plan" }
|
|
2536
|
-
]
|
|
1801
|
+
choices: OPTIONAL_VALIDATORS.map((row) => ({ name: row.menuLabel, value: row.name }))
|
|
2537
1802
|
});
|
|
2538
1803
|
};
|
|
2539
1804
|
var splitManualValues = (value) => (value ?? "").split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
2540
|
-
var required = (label) => {
|
|
2541
|
-
return (value) => value.trim().length > 0 ? true : `${label} is required.`;
|
|
2542
|
-
};
|
|
2543
|
-
var optional = (label) => {
|
|
2544
|
-
return (value) => {
|
|
2545
|
-
const trimmed = value.trim();
|
|
2546
|
-
if (trimmed.length === 0) return true;
|
|
2547
|
-
return required(label)(trimmed);
|
|
2548
|
-
};
|
|
2549
|
-
};
|
|
2550
|
-
var validateWebhookUrl = (value) => {
|
|
2551
|
-
const trimmed = value.trim();
|
|
2552
|
-
if (trimmed.length === 0) return "Webhook URL is required.";
|
|
2553
|
-
try {
|
|
2554
|
-
const url = new URL(trimmed);
|
|
2555
|
-
return url.protocol === "http:" || url.protocol === "https:" ? true : "Webhook URL must start with http:// or https://.";
|
|
2556
|
-
} catch {
|
|
2557
|
-
return "Enter a valid webhook URL.";
|
|
2558
|
-
}
|
|
2559
|
-
};
|
|
2560
|
-
var optionalWebhookUrls = (value) => {
|
|
2561
|
-
const values2 = splitManualValues(value);
|
|
2562
|
-
if (values2.length === 0) return true;
|
|
2563
|
-
return values2.every((entry) => validateWebhookUrl(entry) === true) ? true : "Enter valid webhook URLs.";
|
|
2564
|
-
};
|
|
2565
1805
|
var cleanList = (value) => {
|
|
2566
1806
|
const values2 = Array.isArray(value) ? value : splitManualValues(value);
|
|
2567
1807
|
const cleaned = Array.from(new Set(values2.map((entry) => entry.trim()).filter(Boolean)));
|
|
2568
1808
|
return cleaned.length > 0 ? cleaned : void 0;
|
|
2569
1809
|
};
|
|
2570
|
-
var
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
}
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
pickMessage: "Pick discounts to validate:",
|
|
2594
|
-
emptyMessage: "No discounts selected. What now?",
|
|
2595
|
-
manualMessage: "Discount IDs to validate (comma-separated, leave empty to skip):",
|
|
2596
|
-
validate: optional("Discount ID")
|
|
2597
|
-
},
|
|
2598
|
-
{
|
|
2599
|
-
target: "license-key",
|
|
2600
|
-
field: "licenseKeyIds",
|
|
2601
|
-
group: "licenseKeys",
|
|
2602
|
-
pickMessage: "Pick license keys to validate:",
|
|
2603
|
-
emptyMessage: "No license keys selected. What now?",
|
|
2604
|
-
manualMessage: "License key IDs to validate (comma-separated, leave empty to skip):",
|
|
2605
|
-
validate: optional("License key ID")
|
|
2606
|
-
},
|
|
2607
|
-
{
|
|
2608
|
-
target: "subscription-plan",
|
|
2609
|
-
field: "variantIds",
|
|
2610
|
-
group: "subscriptionPlans",
|
|
2611
|
-
pickMessage: "Pick subscription plans to validate:",
|
|
2612
|
-
emptyMessage: "No subscription plans selected. What now?",
|
|
2613
|
-
manualMessage: "Subscription plan variant IDs to validate (comma-separated, leave empty to skip):",
|
|
2614
|
-
validate: optional("Variant ID")
|
|
2615
|
-
}
|
|
2616
|
-
];
|
|
2617
|
-
var askForDoctorTargetValues = async (targets, choices = EMPTY_INIT_RESOURCE_CHOICES) => {
|
|
2618
|
-
if (targets.length === 0) return {};
|
|
1810
|
+
var pickDiscoveredIds = async (row, group) => {
|
|
1811
|
+
const discovered = group?.choices ?? [];
|
|
1812
|
+
if (discovered.length === 0) return "manual";
|
|
1813
|
+
const values2 = await checkbox({
|
|
1814
|
+
message: `Pick ${row.noun} to validate:`,
|
|
1815
|
+
theme: PROMPT_THEME,
|
|
1816
|
+
choices: discovered.map((choice) => ({ name: choice.label, value: choice.value }))
|
|
1817
|
+
});
|
|
1818
|
+
if (values2.length > 0) return values2;
|
|
1819
|
+
return askEmptyTargetAction(`No ${row.noun} selected. What now?`);
|
|
1820
|
+
};
|
|
1821
|
+
var askEmptyTargetAction = async (message) => {
|
|
1822
|
+
return select({
|
|
1823
|
+
message,
|
|
1824
|
+
theme: PROMPT_THEME,
|
|
1825
|
+
choices: [
|
|
1826
|
+
{ name: "Enter manually", value: "manual" },
|
|
1827
|
+
{ name: "Skip this check", value: "skip" }
|
|
1828
|
+
]
|
|
1829
|
+
});
|
|
1830
|
+
};
|
|
1831
|
+
var askForValidatorIds = async (names, choices = {}) => {
|
|
1832
|
+
if (names.length === 0) return {};
|
|
2619
1833
|
const answers = {};
|
|
2620
|
-
const
|
|
2621
|
-
for (const
|
|
2622
|
-
if (!
|
|
2623
|
-
await
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
manualMessage: spec.manualMessage,
|
|
2631
|
-
validate: spec.validate
|
|
2632
|
-
});
|
|
2633
|
-
}
|
|
2634
|
-
for (const question of manualQuestions) {
|
|
2635
|
-
answers[question.field] = await input({
|
|
2636
|
-
message: question.message,
|
|
1834
|
+
const manualRows = [];
|
|
1835
|
+
for (const row of OPTIONAL_VALIDATORS) {
|
|
1836
|
+
if (!names.includes(row.name)) continue;
|
|
1837
|
+
const picked = await pickDiscoveredIds(row, choices[row.name]);
|
|
1838
|
+
if (picked === "manual") manualRows.push(row);
|
|
1839
|
+
else if (picked !== "skip") answers[row.field] = picked;
|
|
1840
|
+
}
|
|
1841
|
+
for (const row of manualRows) {
|
|
1842
|
+
answers[row.field] = await input({
|
|
1843
|
+
message: `${row.manualNoun} to validate (comma-separated, leave empty to skip):`,
|
|
2637
1844
|
theme: PROMPT_THEME,
|
|
2638
|
-
validate:
|
|
1845
|
+
validate: row.validate
|
|
2639
1846
|
});
|
|
2640
1847
|
}
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
discountIds: cleanList(answers.discountIds),
|
|
2645
|
-
licenseKeyIds: cleanList(answers.licenseKeyIds),
|
|
2646
|
-
variantIds: cleanList(answers.variantIds)
|
|
2647
|
-
};
|
|
1848
|
+
const targetValues = {};
|
|
1849
|
+
for (const row of OPTIONAL_VALIDATORS) targetValues[row.field] = cleanList(answers[row.field]);
|
|
1850
|
+
return targetValues;
|
|
2648
1851
|
};
|
|
2649
1852
|
var confirmLiveModeRun = async () => {
|
|
2650
1853
|
return confirm({
|
|
@@ -2667,46 +1870,6 @@ var confirmResourceOp = async (message) => {
|
|
|
2667
1870
|
theme: PROMPT_THEME
|
|
2668
1871
|
});
|
|
2669
1872
|
};
|
|
2670
|
-
var resolveTargetValue = async (input2) => {
|
|
2671
|
-
if (input2.group.choices.length === 0) {
|
|
2672
|
-
input2.manualQuestions.push({
|
|
2673
|
-
field: input2.field,
|
|
2674
|
-
message: input2.manualMessage,
|
|
2675
|
-
validate: input2.validate
|
|
2676
|
-
});
|
|
2677
|
-
return;
|
|
2678
|
-
}
|
|
2679
|
-
const values2 = await checkbox({
|
|
2680
|
-
message: input2.pickMessage,
|
|
2681
|
-
theme: PROMPT_THEME,
|
|
2682
|
-
choices: input2.group.choices.map((choice) => ({
|
|
2683
|
-
name: choice.label,
|
|
2684
|
-
value: choice.value
|
|
2685
|
-
}))
|
|
2686
|
-
});
|
|
2687
|
-
if (values2.length > 0) {
|
|
2688
|
-
input2.answers[input2.field] = values2;
|
|
2689
|
-
return;
|
|
2690
|
-
}
|
|
2691
|
-
const action = await askEmptyTargetAction(input2.emptyMessage);
|
|
2692
|
-
if (action === "manual") {
|
|
2693
|
-
input2.manualQuestions.push({
|
|
2694
|
-
field: input2.field,
|
|
2695
|
-
message: input2.manualMessage,
|
|
2696
|
-
validate: input2.validate
|
|
2697
|
-
});
|
|
2698
|
-
}
|
|
2699
|
-
};
|
|
2700
|
-
var askEmptyTargetAction = async (message) => {
|
|
2701
|
-
return select({
|
|
2702
|
-
message,
|
|
2703
|
-
theme: PROMPT_THEME,
|
|
2704
|
-
choices: [
|
|
2705
|
-
{ name: "Enter manually", value: "manual" },
|
|
2706
|
-
{ name: "Skip this check", value: "skip" }
|
|
2707
|
-
]
|
|
2708
|
-
});
|
|
2709
|
-
};
|
|
2710
1873
|
var formatPromptPath = (filePath) => {
|
|
2711
1874
|
const relative = path.relative(process.cwd(), filePath);
|
|
2712
1875
|
if (relative && !relative.startsWith("..") && !path.isAbsolute(relative)) return relative;
|
|
@@ -2714,7 +1877,7 @@ var formatPromptPath = (filePath) => {
|
|
|
2714
1877
|
};
|
|
2715
1878
|
var isPromptCancel = (error) => {
|
|
2716
1879
|
if (!(error instanceof Error)) return false;
|
|
2717
|
-
return error.name === "ExitPromptError"
|
|
1880
|
+
return error.name === "ExitPromptError";
|
|
2718
1881
|
};
|
|
2719
1882
|
var pickManageOperation = async (ops) => {
|
|
2720
1883
|
return select({
|
|
@@ -2741,6 +1904,14 @@ var pickBulkTargets = async (verb, items) => {
|
|
|
2741
1904
|
};
|
|
2742
1905
|
|
|
2743
1906
|
// src/cli/resolveStores.ts
|
|
1907
|
+
var listStoreChoices = async (client) => {
|
|
1908
|
+
const stores = await client.stores.list();
|
|
1909
|
+
return stores.map((store) => ({
|
|
1910
|
+
id: store.id,
|
|
1911
|
+
name: store.attributes.name,
|
|
1912
|
+
slug: store.attributes.slug
|
|
1913
|
+
}));
|
|
1914
|
+
};
|
|
2744
1915
|
var resolveStores = async (client, input2) => {
|
|
2745
1916
|
if (input2.storeIds && input2.storeIds.length > 0) {
|
|
2746
1917
|
return { storeIds: dedupe(input2.storeIds), skipped: false };
|
|
@@ -2768,17 +1939,7 @@ var resolveStores = async (client, input2) => {
|
|
|
2768
1939
|
if (ids.length === 1) {
|
|
2769
1940
|
return { storeIds: ids, skipped: false };
|
|
2770
1941
|
}
|
|
2771
|
-
const
|
|
2772
|
-
ids.map(async (id) => {
|
|
2773
|
-
const result = await client.validateStore(id);
|
|
2774
|
-
return {
|
|
2775
|
-
id,
|
|
2776
|
-
name: result.resource?.name ?? "(unnamed)",
|
|
2777
|
-
slug: result.resource?.slug ?? ""
|
|
2778
|
-
};
|
|
2779
|
-
})
|
|
2780
|
-
);
|
|
2781
|
-
const picked = await pickStores(detailed);
|
|
1942
|
+
const picked = await pickStores(await listStoreChoices(client));
|
|
2782
1943
|
if (picked.length === 0) {
|
|
2783
1944
|
throw new FreshSqueezyError({
|
|
2784
1945
|
code: "NO_SELECTION",
|
|
@@ -2805,13 +1966,6 @@ var dedupe = (values2) => {
|
|
|
2805
1966
|
};
|
|
2806
1967
|
|
|
2807
1968
|
// src/cli/commands/doctor.ts
|
|
2808
|
-
var ALL_RESOURCE_TARGETS = [
|
|
2809
|
-
"product",
|
|
2810
|
-
"webhook",
|
|
2811
|
-
"discount",
|
|
2812
|
-
"license-key",
|
|
2813
|
-
"subscription-plan"
|
|
2814
|
-
];
|
|
2815
1969
|
var runDoctorCommand = async (options) => {
|
|
2816
1970
|
try {
|
|
2817
1971
|
const client = createFreshSqueezy({ mode: options.mode });
|
|
@@ -2825,8 +1979,8 @@ var runDoctorCommand = async (options) => {
|
|
|
2825
1979
|
}
|
|
2826
1980
|
const reports = await Promise.all(
|
|
2827
1981
|
resolved.storeIds.map(async (storeId) => {
|
|
2828
|
-
const
|
|
2829
|
-
return client.doctor({ storeId, ...
|
|
1982
|
+
const validatorIds = await resolveValidatorIds(client, storeId, options);
|
|
1983
|
+
return client.doctor({ storeId, ...validatorIds });
|
|
2830
1984
|
})
|
|
2831
1985
|
);
|
|
2832
1986
|
const ok = reports.every((report) => report.ok);
|
|
@@ -2852,55 +2006,47 @@ var runDoctorCommand = async (options) => {
|
|
|
2852
2006
|
return 2;
|
|
2853
2007
|
}
|
|
2854
2008
|
};
|
|
2855
|
-
var
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2009
|
+
var one = (value) => value ? [value] : void 0;
|
|
2010
|
+
var explicitValidatorIds = (options) => ({
|
|
2011
|
+
productIds: one(options.productId),
|
|
2012
|
+
webhookUrls: one(options.webhookUrl),
|
|
2013
|
+
discountIds: one(options.discountId),
|
|
2014
|
+
licenseKeyIds: one(options.licenseKeyId),
|
|
2015
|
+
variantIds: one(options.variantId)
|
|
2016
|
+
});
|
|
2017
|
+
var values = (group) => group?.choices.length ? group.choices.map((choice) => choice.value) : void 0;
|
|
2018
|
+
var mergeValues = (explicit, discovered) => {
|
|
2019
|
+
const merged = Array.from(/* @__PURE__ */ new Set([...explicit ?? [], ...discovered ?? []]));
|
|
2020
|
+
return merged.length > 0 ? merged : void 0;
|
|
2021
|
+
};
|
|
2022
|
+
var resolveValidatorIds = async (client, storeId, options) => {
|
|
2023
|
+
const explicit = explicitValidatorIds(options);
|
|
2863
2024
|
if (!options.allResources) return explicit;
|
|
2864
|
-
const
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2025
|
+
const allNames = OPTIONAL_VALIDATORS.map((row) => row.name);
|
|
2026
|
+
const discovered = await discoverChoices(client, storeId, allNames);
|
|
2027
|
+
for (const row of OPTIONAL_VALIDATORS) {
|
|
2028
|
+
const error = discovered[row.name]?.error;
|
|
2029
|
+
if (error) {
|
|
2030
|
+
process.stderr.write(
|
|
2031
|
+
`fresh-squeezy: discovery skipped ${row.label.toLowerCase()}: ${error}
|
|
2869
2032
|
`
|
|
2870
|
-
|
|
2033
|
+
);
|
|
2034
|
+
}
|
|
2871
2035
|
}
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
variantIds: mergeValues(explicit.variantIds, values(discovered.subscriptionPlans))
|
|
2878
|
-
};
|
|
2879
|
-
};
|
|
2880
|
-
var DISCOVERY_LABELS = [
|
|
2881
|
-
["products", "products"],
|
|
2882
|
-
["webhooks", "webhooks"],
|
|
2883
|
-
["discounts", "discounts"],
|
|
2884
|
-
["licenseKeys", "license keys"],
|
|
2885
|
-
["subscriptionPlans", "subscription plans"]
|
|
2886
|
-
];
|
|
2887
|
-
var formatDiscoveryCounts = (choices) => DISCOVERY_LABELS.map(([key, label]) => `${label} ${choices[key].choices.length}`).join(", ");
|
|
2888
|
-
var reportDiscoveryErrors = (choices) => {
|
|
2889
|
-
for (const [key, label] of DISCOVERY_LABELS) {
|
|
2890
|
-
const error = choices[key].error;
|
|
2891
|
-
if (error) process.stderr.write(`fresh-squeezy: discovery skipped ${label}: ${error}
|
|
2036
|
+
if (!options.json) {
|
|
2037
|
+
const counts = OPTIONAL_VALIDATORS.map(
|
|
2038
|
+
(row) => `${row.label.toLowerCase()} ${discovered[row.name]?.choices.length ?? 0}`
|
|
2039
|
+
).join(", ");
|
|
2040
|
+
process.stderr.write(`fresh-squeezy: discovered store ${storeId} resources: ${counts}.
|
|
2892
2041
|
`);
|
|
2893
2042
|
}
|
|
2043
|
+
const merged = {};
|
|
2044
|
+
for (const row of OPTIONAL_VALIDATORS) {
|
|
2045
|
+
merged[row.field] = mergeValues(explicit[row.field], values(discovered[row.name]));
|
|
2046
|
+
}
|
|
2047
|
+
return merged;
|
|
2894
2048
|
};
|
|
2895
|
-
var
|
|
2896
|
-
var one = (value) => value ? [value] : void 0;
|
|
2897
|
-
var mergeValues = (explicit, discovered) => {
|
|
2898
|
-
const merged = Array.from(/* @__PURE__ */ new Set([...explicit ?? [], ...discovered ?? []]));
|
|
2899
|
-
return merged.length > 0 ? merged : void 0;
|
|
2900
|
-
};
|
|
2901
|
-
var hasExplicitResourceSelection = (options) => Boolean(
|
|
2902
|
-
options.productId || options.webhookUrl || options.discountId || options.licenseKeyId || options.variantId
|
|
2903
|
-
);
|
|
2049
|
+
var hasExplicitResourceSelection = (options) => Object.values(explicitValidatorIds(options)).some((ids) => ids !== void 0);
|
|
2904
2050
|
var runConnectionOnly = async (client, options) => {
|
|
2905
2051
|
const connection = await client.validateConnection();
|
|
2906
2052
|
const report = {
|
|
@@ -2937,59 +2083,7 @@ var writeFatal = (err, asJson) => {
|
|
|
2937
2083
|
// src/cli/commands/init.ts
|
|
2938
2084
|
import fs from "fs/promises";
|
|
2939
2085
|
import path2 from "path";
|
|
2940
|
-
import chalk3 from "chalk";
|
|
2941
|
-
|
|
2942
|
-
// src/cli/brand.ts
|
|
2943
2086
|
import chalk2 from "chalk";
|
|
2944
|
-
var brand = chalk2.green.bold("fresh-squeezy");
|
|
2945
|
-
var divider = chalk2.dim("\u2022");
|
|
2946
|
-
var renderBrandHeader = (title, subtitle) => {
|
|
2947
|
-
const lines = [`${brand} ${divider} ${chalk2.bold(title)}`];
|
|
2948
|
-
if (subtitle) lines.push(chalk2.dim(subtitle));
|
|
2949
|
-
lines.push("");
|
|
2950
|
-
return lines.join("\n");
|
|
2951
|
-
};
|
|
2952
|
-
var renderStep = (index, total, title, detail) => {
|
|
2953
|
-
const suffix = detail ? ` ${chalk2.dim(detail)}` : "";
|
|
2954
|
-
const prefix = index > 1 ? "\n" : "";
|
|
2955
|
-
return `${prefix}${chalk2.yellow("\u25CF")} ${chalk2.dim(`${index}/${total}`)} ${chalk2.bold(title)}${suffix}
|
|
2956
|
-
`;
|
|
2957
|
-
};
|
|
2958
|
-
var renderDetected = (label, value, source) => {
|
|
2959
|
-
const suffix = source ? ` ${chalk2.dim(`from ${source}`)}` : "";
|
|
2960
|
-
return ` ${chalk2.green("\u2713")} ${chalk2.bold(label)} ${value}${suffix}
|
|
2961
|
-
`;
|
|
2962
|
-
};
|
|
2963
|
-
var renderCommandExamples = () => {
|
|
2964
|
-
return [
|
|
2965
|
-
renderBrandHeader("Command examples", "Direct commands stay stable for scripts and CI."),
|
|
2966
|
-
`${chalk2.bold("Guided setup")}`,
|
|
2967
|
-
" fresh-squeezy init",
|
|
2968
|
-
"",
|
|
2969
|
-
`${chalk2.bold("Full doctor")}`,
|
|
2970
|
-
" fresh-squeezy doctor --all-stores",
|
|
2971
|
-
" fresh-squeezy doctor --store-ids 12 --product-id 987 --webhook-url https://app.example.com/api/webhooks/lemon-squeezy",
|
|
2972
|
-
"",
|
|
2973
|
-
`${chalk2.bold("Single checks")}`,
|
|
2974
|
-
" fresh-squeezy validate connection",
|
|
2975
|
-
" fresh-squeezy validate webhook --store-ids 12 --webhook-url https://app.example.com/api/webhooks/lemon-squeezy",
|
|
2976
|
-
"",
|
|
2977
|
-
`${chalk2.bold("Bulk ops (delete / cancel / refund)")}`,
|
|
2978
|
-
" fresh-squeezy delete discount --all --store-ids 12 --dry-run",
|
|
2979
|
-
" fresh-squeezy delete discount --all --store-ids 12 --match TEST --yes",
|
|
2980
|
-
" fresh-squeezy delete webhook --ids 1,2,3 --yes",
|
|
2981
|
-
"",
|
|
2982
|
-
`${chalk2.bold("Automation")}`,
|
|
2983
|
-
" fresh-squeezy doctor --all-stores --json",
|
|
2984
|
-
""
|
|
2985
|
-
].join("\n");
|
|
2986
|
-
};
|
|
2987
|
-
var renderCancelMessage = () => {
|
|
2988
|
-
return `${chalk2.dim("fresh-squeezy cancelled.")}
|
|
2989
|
-
`;
|
|
2990
|
-
};
|
|
2991
|
-
|
|
2992
|
-
// src/cli/commands/init.ts
|
|
2993
2087
|
var runInitCommand = async (options = {}) => {
|
|
2994
2088
|
try {
|
|
2995
2089
|
return await runInitFlow(options);
|
|
@@ -3020,7 +2114,8 @@ var runInitFlow = async (options) => {
|
|
|
3020
2114
|
process.stdout.write(renderStep(1, 5, "Credentials", "reuse env when available"));
|
|
3021
2115
|
const apiKey = await resolveApiKey();
|
|
3022
2116
|
process.stdout.write(renderStep(2, 5, "Account probe", "detect mode and reachable stores"));
|
|
3023
|
-
const { client,
|
|
2117
|
+
const { client, connection } = await connectWithDetectedMode(apiKey);
|
|
2118
|
+
const mode = client.mode;
|
|
3024
2119
|
if (!connection.ok) {
|
|
3025
2120
|
process.stdout.write(`${renderReport({ ok: false, mode, results: [connection] })}
|
|
3026
2121
|
`);
|
|
@@ -3030,81 +2125,60 @@ var runInitFlow = async (options) => {
|
|
|
3030
2125
|
process.stderr.write(renderCancelMessage());
|
|
3031
2126
|
return 130;
|
|
3032
2127
|
}
|
|
3033
|
-
const
|
|
3034
|
-
if (
|
|
2128
|
+
const stores = await listStoreChoices(client);
|
|
2129
|
+
if (stores.length === 0) {
|
|
3035
2130
|
process.stdout.write(
|
|
3036
|
-
|
|
2131
|
+
chalk2.yellow(
|
|
3037
2132
|
"No stores reachable with this key. Create a store in Lemon Squeezy and retry.\n"
|
|
3038
2133
|
)
|
|
3039
2134
|
);
|
|
3040
2135
|
return 1;
|
|
3041
2136
|
}
|
|
3042
|
-
process.stdout.write(renderDetected("Stores", String(
|
|
3043
|
-
const stores = await Promise.all(storeIds.map((id) => client.validateStore(id)));
|
|
3044
|
-
const pickable = stores.filter((entry) => entry.ok && entry.resource).map((entry, index) => ({
|
|
3045
|
-
id: storeIds[index] ?? "",
|
|
3046
|
-
name: entry.resource?.name ?? "(unnamed)",
|
|
3047
|
-
slug: entry.resource?.slug ?? ""
|
|
3048
|
-
})).filter((entry) => entry.id !== "");
|
|
3049
|
-
if (pickable.length === 0) {
|
|
3050
|
-
process.stdout.write(
|
|
3051
|
-
chalk3.yellow(
|
|
3052
|
-
"Stores were discovered, but none could be validated. Check account access and retry.\n"
|
|
3053
|
-
)
|
|
3054
|
-
);
|
|
3055
|
-
return 1;
|
|
3056
|
-
}
|
|
2137
|
+
process.stdout.write(renderDetected("Stores", String(stores.length), "Lemon Squeezy API"));
|
|
3057
2138
|
process.stdout.write(renderStep(3, 5, "Store selection", "auto-select when unambiguous"));
|
|
3058
|
-
const storeId = await resolveStoreSelection(
|
|
2139
|
+
const storeId = await resolveStoreSelection(stores);
|
|
3059
2140
|
process.stdout.write(renderStep(4, 5, "Optional checks", "pick resources before manual IDs"));
|
|
3060
|
-
const
|
|
3061
|
-
const resourceChoices = await discoverChoices(client, storeId,
|
|
3062
|
-
process.stdout.write(renderDiscoverySummary(resourceChoices,
|
|
3063
|
-
const
|
|
2141
|
+
const selectedValidators = await selectOptionalValidators();
|
|
2142
|
+
const resourceChoices = await discoverChoices(client, storeId, selectedValidators);
|
|
2143
|
+
process.stdout.write(renderDiscoverySummary(resourceChoices, selectedValidators));
|
|
2144
|
+
const validatorIds = await askForValidatorIds(selectedValidators, resourceChoices);
|
|
3064
2145
|
const envPath = path2.resolve(process.cwd(), options.envFile ?? ".env");
|
|
3065
|
-
const checkNames =
|
|
2146
|
+
const checkNames = listValidatorNames(validatorIds);
|
|
3066
2147
|
process.stdout.write(renderSetupSummary({ envPath, mode, storeId, checkNames }));
|
|
3067
2148
|
const shouldWrite = await confirmWriteEnvFile(envPath);
|
|
3068
2149
|
if (shouldWrite) {
|
|
3069
2150
|
await writeEnvFile(envPath, { apiKey, mode, storeId });
|
|
3070
|
-
process.stdout.write(
|
|
2151
|
+
process.stdout.write(chalk2.green(`Wrote ${envPath}
|
|
3071
2152
|
`));
|
|
3072
2153
|
}
|
|
3073
|
-
process.stdout.write(
|
|
2154
|
+
process.stdout.write(chalk2.dim(`
|
|
3074
2155
|
Running doctor (${checkNames.join(", ")})...
|
|
3075
2156
|
|
|
3076
2157
|
`));
|
|
3077
|
-
const report = await client.doctor({ storeId, ...
|
|
2158
|
+
const report = await client.doctor({ storeId, ...validatorIds });
|
|
3078
2159
|
process.stdout.write(`${renderReport(report)}
|
|
3079
2160
|
`);
|
|
3080
2161
|
return report.ok ? 0 : 1;
|
|
3081
2162
|
};
|
|
3082
|
-
var resolveStoreSelection = async (
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
renderDetected("Store", `${store.name} (${store.slug})`, `id ${store.id}`)
|
|
3088
|
-
);
|
|
3089
|
-
return store.id;
|
|
2163
|
+
var resolveStoreSelection = async (stores) => {
|
|
2164
|
+
const [only, ...others] = stores;
|
|
2165
|
+
if (only && others.length === 0) {
|
|
2166
|
+
process.stdout.write(renderDetected("Store", `${only.name} (${only.slug})`, `id ${only.id}`));
|
|
2167
|
+
return only.id;
|
|
3090
2168
|
}
|
|
3091
|
-
return pickStore(
|
|
3092
|
-
};
|
|
3093
|
-
var discoverChoices = async (client, storeId, selectedTargets) => {
|
|
3094
|
-
if (selectedTargets.length === 0) return EMPTY_INIT_RESOURCE_CHOICES;
|
|
3095
|
-
return discoverInitResourceChoices(client, storeId, selectedTargets);
|
|
2169
|
+
return pickStore(stores);
|
|
3096
2170
|
};
|
|
3097
2171
|
var resolveApiKey = async () => {
|
|
3098
2172
|
const envApiKey = process.env[ENV_KEYS.apiKey]?.trim();
|
|
3099
2173
|
if (envApiKey) {
|
|
3100
|
-
process.stdout.write(
|
|
2174
|
+
process.stdout.write(chalk2.dim(`Using ${ENV_KEYS.apiKey} from environment.
|
|
3101
2175
|
`));
|
|
3102
2176
|
return envApiKey;
|
|
3103
2177
|
}
|
|
3104
2178
|
const answers = await askForApiKey();
|
|
3105
2179
|
return answers.apiKey;
|
|
3106
2180
|
};
|
|
3107
|
-
var
|
|
2181
|
+
var connectWithDetectedMode = async (apiKey) => {
|
|
3108
2182
|
const envMode = parseEnvMode();
|
|
3109
2183
|
const initialMode = envMode ?? "test";
|
|
3110
2184
|
let client = createFreshSqueezy({ apiKey, mode: initialMode });
|
|
@@ -3112,58 +2186,53 @@ var createDetectedClient = async (apiKey) => {
|
|
|
3112
2186
|
const actualMode = connection.resource?.actualMode;
|
|
3113
2187
|
if (actualMode && actualMode !== initialMode) {
|
|
3114
2188
|
const message = envMode ? `Detected ${actualMode}-mode API key; ignoring ${ENV_KEYS.mode}=${initialMode} for this run.` : `Detected ${actualMode}-mode API key.`;
|
|
3115
|
-
process.stdout.write(
|
|
2189
|
+
process.stdout.write(chalk2.yellow(`${message}
|
|
3116
2190
|
`));
|
|
3117
2191
|
client = createFreshSqueezy({ apiKey, mode: actualMode });
|
|
3118
2192
|
connection = await client.validateConnection();
|
|
3119
|
-
return { client,
|
|
2193
|
+
return { client, connection };
|
|
3120
2194
|
}
|
|
3121
2195
|
if (actualMode) {
|
|
3122
|
-
process.stdout.write(
|
|
2196
|
+
process.stdout.write(chalk2.dim(`Detected ${actualMode}-mode API key.
|
|
3123
2197
|
`));
|
|
3124
|
-
return { client,
|
|
2198
|
+
return { client, connection };
|
|
3125
2199
|
}
|
|
3126
2200
|
if (envMode) {
|
|
3127
2201
|
process.stdout.write(
|
|
3128
|
-
|
|
2202
|
+
chalk2.dim(`Using ${ENV_KEYS.mode}=${envMode}; API mode was not exposed.
|
|
3129
2203
|
`)
|
|
3130
2204
|
);
|
|
3131
|
-
return { client,
|
|
2205
|
+
return { client, connection };
|
|
3132
2206
|
}
|
|
3133
|
-
process.stdout.write(
|
|
3134
|
-
return { client,
|
|
2207
|
+
process.stdout.write(chalk2.dim("Could not auto-detect key mode; using test mode.\n"));
|
|
2208
|
+
return { client, connection };
|
|
3135
2209
|
};
|
|
3136
2210
|
var parseEnvMode = () => {
|
|
3137
2211
|
const value = process.env[ENV_KEYS.mode]?.trim();
|
|
3138
2212
|
if (value === "test" || value === "live") return value;
|
|
3139
2213
|
if (value) {
|
|
3140
2214
|
process.stdout.write(
|
|
3141
|
-
|
|
2215
|
+
chalk2.yellow(`Ignoring invalid ${ENV_KEYS.mode}=${value}; expected test or live.
|
|
3142
2216
|
`)
|
|
3143
2217
|
);
|
|
3144
2218
|
}
|
|
3145
2219
|
return void 0;
|
|
3146
2220
|
};
|
|
3147
|
-
var
|
|
2221
|
+
var listValidatorNames = (validatorIds) => {
|
|
3148
2222
|
const names = ["connection", "store"];
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
pushCheckName(names, "subscriptionPlan", targets.variantIds);
|
|
2223
|
+
for (const row of OPTIONAL_VALIDATORS) {
|
|
2224
|
+
const count = validatorIds[row.field]?.length ?? 0;
|
|
2225
|
+
if (count > 0) names.push(count === 1 ? row.resultName : `${row.resultName} x${count}`);
|
|
2226
|
+
}
|
|
3154
2227
|
return names;
|
|
3155
2228
|
};
|
|
3156
|
-
var pushCheckName = (names, name, values2) => {
|
|
3157
|
-
if (!values2 || values2.length === 0) return;
|
|
3158
|
-
names.push(values2.length === 1 ? name : `${name} x${values2.length}`);
|
|
3159
|
-
};
|
|
3160
2229
|
var renderSetupSummary = (input2) => {
|
|
3161
2230
|
return [
|
|
3162
2231
|
renderStep(5, 5, "Ready to verify", "review before writing env"),
|
|
3163
|
-
` ${
|
|
3164
|
-
` ${
|
|
3165
|
-
` ${
|
|
3166
|
-
` ${
|
|
2232
|
+
` ${chalk2.dim("mode")} ${input2.mode}`,
|
|
2233
|
+
` ${chalk2.dim("store")} ${input2.storeId}`,
|
|
2234
|
+
` ${chalk2.dim("checks")} ${input2.checkNames.join(", ")}`,
|
|
2235
|
+
` ${chalk2.dim("env")} ${input2.envPath}`,
|
|
3167
2236
|
""
|
|
3168
2237
|
].join("\n");
|
|
3169
2238
|
};
|
|
@@ -3205,32 +2274,25 @@ var readEnvFile = async (envPath) => {
|
|
|
3205
2274
|
throw err;
|
|
3206
2275
|
}
|
|
3207
2276
|
};
|
|
3208
|
-
var renderDiscoverySummary = (choices,
|
|
3209
|
-
if (
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
if (!selectedTargets.includes(target)) continue;
|
|
3220
|
-
if (group.error) {
|
|
3221
|
-
lines.push(chalk3.yellow(` ! ${label} discovery failed; manual entry is available.`));
|
|
3222
|
-
} else {
|
|
3223
|
-
lines.push(
|
|
3224
|
-
renderDetected(label, String(group.choices.length), "Lemon Squeezy API").trimEnd()
|
|
3225
|
-
);
|
|
2277
|
+
var renderDiscoverySummary = (choices, selectedValidators) => {
|
|
2278
|
+
if (selectedValidators.length === 0)
|
|
2279
|
+
return chalk2.dim(" No optional resource checks selected.\n");
|
|
2280
|
+
const lines = OPTIONAL_VALIDATORS.filter((row) => selectedValidators.includes(row.name)).map(
|
|
2281
|
+
(row) => {
|
|
2282
|
+
const group = choices[row.name];
|
|
2283
|
+
if (group?.error) {
|
|
2284
|
+
return chalk2.yellow(` ! ${row.label} discovery failed; manual entry is available.`);
|
|
2285
|
+
}
|
|
2286
|
+
const count = String(group?.choices.length ?? 0);
|
|
2287
|
+
return renderDetected(row.label, count, "Lemon Squeezy API").trimEnd();
|
|
3226
2288
|
}
|
|
3227
|
-
|
|
2289
|
+
);
|
|
3228
2290
|
return `${lines.join("\n")}
|
|
3229
2291
|
`;
|
|
3230
2292
|
};
|
|
3231
2293
|
|
|
3232
2294
|
// src/cli/commands/launcher.ts
|
|
3233
|
-
import
|
|
2295
|
+
import chalk3 from "chalk";
|
|
3234
2296
|
|
|
3235
2297
|
// src/cli/projectInstall.ts
|
|
3236
2298
|
import { spawn } from "child_process";
|
|
@@ -3518,7 +2580,7 @@ var runLauncherCommand = async (options) => {
|
|
|
3518
2580
|
return 130;
|
|
3519
2581
|
}
|
|
3520
2582
|
const message = err instanceof Error ? err.message : String(err);
|
|
3521
|
-
process.stderr.write(`${
|
|
2583
|
+
process.stderr.write(`${chalk3.red("fresh-squeezy bootstrap failed:")} ${message}
|
|
3522
2584
|
|
|
3523
2585
|
`);
|
|
3524
2586
|
process.stderr.write(renderCommandExamples());
|
|
@@ -3561,9 +2623,9 @@ var renderProjectInstallResult = (result) => {
|
|
|
3561
2623
|
return renderDetected("Project", "fresh-squeezy source repo", "package.json");
|
|
3562
2624
|
}
|
|
3563
2625
|
if (result.status === "skipped") {
|
|
3564
|
-
return
|
|
2626
|
+
return chalk3.dim(" Skipped dev dependency install (--no-install).\n");
|
|
3565
2627
|
}
|
|
3566
|
-
return
|
|
2628
|
+
return chalk3.yellow(" No package.json found; running without installing a dev dependency.\n");
|
|
3567
2629
|
};
|
|
3568
2630
|
|
|
3569
2631
|
// src/cli/commands/resourceOps.ts
|
|
@@ -3600,14 +2662,13 @@ var runResourceOpCommand = async (options) => {
|
|
|
3600
2662
|
message: "This op requires a JSON body (--body, --body-file, or stdin)."
|
|
3601
2663
|
});
|
|
3602
2664
|
}
|
|
3603
|
-
const client = createFreshSqueezy({ mode: options.mode });
|
|
3604
2665
|
const config = resolveConfig({ mode: options.mode });
|
|
3605
2666
|
const http = new HttpClient(config);
|
|
3606
2667
|
const storeId = options.storeIds?.[0] ?? config.storeId;
|
|
3607
2668
|
if (options.all || options.ids) {
|
|
3608
|
-
return await runBulk(http, spec,
|
|
2669
|
+
return await runBulk(http, spec, config.mode, options, { storeId, body });
|
|
3609
2670
|
}
|
|
3610
|
-
const allowed = await assertWriteSafety(spec,
|
|
2671
|
+
const allowed = await assertWriteSafety(spec, config.mode, options);
|
|
3611
2672
|
if (!allowed) return 2;
|
|
3612
2673
|
const opBody = await invokeOp(http, options.resource, options.verb, {
|
|
3613
2674
|
id: options.id,
|
|
@@ -3617,7 +2678,7 @@ var runResourceOpCommand = async (options) => {
|
|
|
3617
2678
|
});
|
|
3618
2679
|
const envelope = {
|
|
3619
2680
|
ok: true,
|
|
3620
|
-
mode:
|
|
2681
|
+
mode: config.mode,
|
|
3621
2682
|
resource: spec.resource,
|
|
3622
2683
|
verb: spec.verb,
|
|
3623
2684
|
docs: `https://docs.lemonsqueezy.com/api/${spec.docsPath}`,
|
|
@@ -3628,7 +2689,7 @@ var runResourceOpCommand = async (options) => {
|
|
|
3628
2689
|
`);
|
|
3629
2690
|
} else {
|
|
3630
2691
|
process.stdout.write(
|
|
3631
|
-
`${spec.verb} ${spec.resource} \u2014 ok (mode=${
|
|
2692
|
+
`${spec.verb} ${spec.resource} \u2014 ok (mode=${config.mode})
|
|
3632
2693
|
${JSON.stringify(opBody ?? null, null, 2)}
|
|
3633
2694
|
`
|
|
3634
2695
|
);
|
|
@@ -3768,44 +2829,15 @@ var writeFatal2 = (err, json) => {
|
|
|
3768
2829
|
};
|
|
3769
2830
|
|
|
3770
2831
|
// src/cli/commands/validate.ts
|
|
3771
|
-
var
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
return emit(await client.validateConnection(), options);
|
|
3776
|
-
}
|
|
3777
|
-
if (target === "product") {
|
|
3778
|
-
return emit(await runProduct(client, options), options);
|
|
3779
|
-
}
|
|
3780
|
-
if (target === "discount") {
|
|
3781
|
-
return emit(await runDiscount(client, options), options);
|
|
3782
|
-
}
|
|
3783
|
-
if (target === "license-key") {
|
|
3784
|
-
return emit(await runLicenseKey(client, options), options);
|
|
3785
|
-
}
|
|
3786
|
-
if (target === "subscription-plan") {
|
|
3787
|
-
return emit(await runSubscriptionPlan(client, options), options);
|
|
3788
|
-
}
|
|
3789
|
-
const storeIds = await resolveStoresForTarget(client, target, options);
|
|
3790
|
-
const results = await runPerStore(client, target, storeIds, options);
|
|
3791
|
-
if (options.json) {
|
|
3792
|
-
process.stdout.write(`${JSON.stringify(results, null, 2)}
|
|
3793
|
-
`);
|
|
3794
|
-
} else {
|
|
3795
|
-
for (const result of results) {
|
|
3796
|
-
process.stdout.write(`${renderResult(result)}
|
|
3797
|
-
|
|
3798
|
-
`);
|
|
3799
|
-
}
|
|
3800
|
-
}
|
|
3801
|
-
return results.every((result) => result.ok) ? 0 : 1;
|
|
3802
|
-
} catch (err) {
|
|
3803
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
3804
|
-
process.stderr.write(renderCliError(message, getValidateHints(err, target)));
|
|
3805
|
-
return 2;
|
|
2832
|
+
var EXAMPLE_WEBHOOK_URL = "https://app.example.com/api/webhooks/lemon-squeezy";
|
|
2833
|
+
var required = (value, message) => {
|
|
2834
|
+
if (value === void 0 || value === null || value === "") {
|
|
2835
|
+
throw new FreshSqueezyError({ code: "MISSING_ARG", message });
|
|
3806
2836
|
}
|
|
2837
|
+
return value;
|
|
3807
2838
|
};
|
|
3808
|
-
var
|
|
2839
|
+
var requiredStoreId = (options, target) => required(options.storeIds?.[0], `--store-ids is required for \`validate ${target}\`.`);
|
|
2840
|
+
var resolveStoresForSubcommand = async (client, target, options) => {
|
|
3809
2841
|
const resolved = await resolveStores(client, {
|
|
3810
2842
|
storeIds: options.storeIds,
|
|
3811
2843
|
allStores: options.allStores,
|
|
@@ -3819,72 +2851,127 @@ var resolveStoresForTarget = async (client, target, options) => {
|
|
|
3819
2851
|
}
|
|
3820
2852
|
return resolved.storeIds;
|
|
3821
2853
|
};
|
|
3822
|
-
var
|
|
3823
|
-
|
|
3824
|
-
|
|
2854
|
+
var VALIDATE_SUBCOMMANDS = {
|
|
2855
|
+
connection: {
|
|
2856
|
+
description: "Check that the API key authenticates",
|
|
2857
|
+
stores: "none",
|
|
2858
|
+
examples: ["fresh-squeezy validate connection"],
|
|
2859
|
+
run: (client) => client.validateConnection()
|
|
2860
|
+
},
|
|
2861
|
+
store: {
|
|
2862
|
+
description: "Check one or more stores are reachable",
|
|
2863
|
+
stores: "multi",
|
|
2864
|
+
storeIdsHelp: "Comma-separated store IDs",
|
|
2865
|
+
examples: [
|
|
2866
|
+
"fresh-squeezy validate store --store-ids 12",
|
|
2867
|
+
"fresh-squeezy validate store --all-stores"
|
|
2868
|
+
],
|
|
2869
|
+
run: async (client, options) => {
|
|
2870
|
+
const storeIds = await resolveStoresForSubcommand(client, "store", options);
|
|
2871
|
+
return Promise.all(storeIds.map((storeId) => client.validateStore(storeId)));
|
|
2872
|
+
}
|
|
2873
|
+
},
|
|
2874
|
+
product: {
|
|
2875
|
+
description: "Check a product is published with at least one variant",
|
|
2876
|
+
stores: "ownership",
|
|
2877
|
+
required: ["--product-id <id>", "Product ID to validate"],
|
|
2878
|
+
storeIdsHelp: "Expected owning store IDs (first is used for cross-check)",
|
|
2879
|
+
examples: ["fresh-squeezy validate product --product-id 987"],
|
|
2880
|
+
run: (client, options) => client.validateProduct({
|
|
2881
|
+
productId: required(options.productId, "--product-id is required for `validate product`."),
|
|
2882
|
+
expectedStoreId: options.storeIds?.[0]
|
|
2883
|
+
})
|
|
2884
|
+
},
|
|
2885
|
+
webhook: {
|
|
2886
|
+
description: "Check a webhook is registered with the recommended events",
|
|
2887
|
+
stores: "multi",
|
|
2888
|
+
required: ["--webhook-url <url>", "Public webhook URL"],
|
|
2889
|
+
storeIdsHelp: "Comma-separated store IDs",
|
|
2890
|
+
examples: [
|
|
2891
|
+
`fresh-squeezy validate webhook --store-ids 12 --webhook-url ${EXAMPLE_WEBHOOK_URL}`,
|
|
2892
|
+
`fresh-squeezy validate webhook --all-stores --webhook-url ${EXAMPLE_WEBHOOK_URL}`
|
|
2893
|
+
],
|
|
2894
|
+
run: async (client, options) => {
|
|
2895
|
+
const storeIds = await resolveStoresForSubcommand(client, "webhook", options);
|
|
2896
|
+
const url = required(options.webhookUrl, "--webhook-url is required for `validate webhook`.");
|
|
2897
|
+
return Promise.all(storeIds.map((storeId) => client.validateWebhook({ storeId, url })));
|
|
2898
|
+
}
|
|
2899
|
+
},
|
|
2900
|
+
discount: {
|
|
2901
|
+
description: "Check a discount code is valid and redeemable",
|
|
2902
|
+
stores: "ownership",
|
|
2903
|
+
required: ["--discount-id <id>", "Discount ID to validate"],
|
|
2904
|
+
storeIdsHelp: "Store ID for ownership check (first ID used)",
|
|
2905
|
+
examples: ["fresh-squeezy validate discount --store-ids 12 --discount-id 123"],
|
|
2906
|
+
run: (client, options) => client.validateDiscount({
|
|
2907
|
+
discountId: required(
|
|
2908
|
+
options.discountId,
|
|
2909
|
+
"--discount-id is required for `validate discount`."
|
|
2910
|
+
),
|
|
2911
|
+
storeId: requiredStoreId(options, "discount")
|
|
2912
|
+
})
|
|
2913
|
+
},
|
|
2914
|
+
"license-key": {
|
|
2915
|
+
description: "Check a license key is active and not at its activation limit",
|
|
2916
|
+
stores: "ownership",
|
|
2917
|
+
required: ["--license-key-id <id>", "License key ID to validate"],
|
|
2918
|
+
storeIdsHelp: "Store ID for ownership check (first ID used)",
|
|
2919
|
+
examples: ["fresh-squeezy validate license-key --store-ids 12 --license-key-id 123"],
|
|
2920
|
+
run: (client, options) => client.validateLicenseKey({
|
|
2921
|
+
licenseKeyId: required(
|
|
2922
|
+
options.licenseKeyId,
|
|
2923
|
+
"--license-key-id is required for `validate license-key`."
|
|
2924
|
+
),
|
|
2925
|
+
storeId: requiredStoreId(options, "license-key")
|
|
2926
|
+
})
|
|
2927
|
+
},
|
|
2928
|
+
"subscription-plan": {
|
|
2929
|
+
description: "Check a subscription plan variant has valid billing interval and trial config",
|
|
2930
|
+
stores: "ownership",
|
|
2931
|
+
required: ["--variant-id <id>", "Variant ID of the subscription plan"],
|
|
2932
|
+
storeIdsHelp: "Store ID for ownership check (first ID used)",
|
|
2933
|
+
examples: ["fresh-squeezy validate subscription-plan --store-ids 12 --variant-id 123"],
|
|
2934
|
+
run: (client, options) => client.validateSubscriptionPlan({
|
|
2935
|
+
variantId: required(
|
|
2936
|
+
options.variantId,
|
|
2937
|
+
"--variant-id is required for `validate subscription-plan`."
|
|
2938
|
+
),
|
|
2939
|
+
storeId: requiredStoreId(options, "subscription-plan")
|
|
2940
|
+
})
|
|
3825
2941
|
}
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
2942
|
+
};
|
|
2943
|
+
var errorHints = (err, target) => {
|
|
2944
|
+
if (!(err instanceof FreshSqueezyError)) return [];
|
|
2945
|
+
if (err.code === "MISSING_API_KEY") return MISSING_API_KEY_HINTS;
|
|
2946
|
+
if (err.code === "INVALID_MODE") {
|
|
2947
|
+
return [
|
|
2948
|
+
`fresh-squeezy validate ${target} --mode test`,
|
|
2949
|
+
`fresh-squeezy validate ${target} --mode live`
|
|
2950
|
+
];
|
|
3829
2951
|
}
|
|
2952
|
+
if (err.code === "MISSING_ARG") return VALIDATE_SUBCOMMANDS[target].examples;
|
|
3830
2953
|
return [];
|
|
3831
2954
|
};
|
|
3832
|
-
var
|
|
3833
|
-
const
|
|
3834
|
-
const expected = options.storeIds?.[0];
|
|
3835
|
-
return client.validateProduct({
|
|
3836
|
-
productId,
|
|
3837
|
-
expectedStoreId: expected
|
|
3838
|
-
});
|
|
3839
|
-
};
|
|
3840
|
-
var runDiscount = async (client, options) => {
|
|
3841
|
-
const discountId = required2(
|
|
3842
|
-
options.discountId,
|
|
3843
|
-
"--discount-id is required for `validate discount`."
|
|
3844
|
-
);
|
|
3845
|
-
const storeId = required2(
|
|
3846
|
-
options.storeIds?.[0],
|
|
3847
|
-
"--store-ids is required for `validate discount`."
|
|
3848
|
-
);
|
|
3849
|
-
return client.validateDiscount({ storeId, discountId });
|
|
3850
|
-
};
|
|
3851
|
-
var runLicenseKey = async (client, options) => {
|
|
3852
|
-
const licenseKeyId = required2(
|
|
3853
|
-
options.licenseKeyId,
|
|
3854
|
-
"--license-key-id is required for `validate license-key`."
|
|
3855
|
-
);
|
|
3856
|
-
const storeId = required2(
|
|
3857
|
-
options.storeIds?.[0],
|
|
3858
|
-
"--store-ids is required for `validate license-key`."
|
|
3859
|
-
);
|
|
3860
|
-
return client.validateLicenseKey({ storeId, licenseKeyId });
|
|
3861
|
-
};
|
|
3862
|
-
var runSubscriptionPlan = async (client, options) => {
|
|
3863
|
-
const variantId = required2(
|
|
3864
|
-
options.variantId,
|
|
3865
|
-
"--variant-id is required for `validate subscription-plan`."
|
|
3866
|
-
);
|
|
3867
|
-
const storeId = required2(
|
|
3868
|
-
options.storeIds?.[0],
|
|
3869
|
-
"--store-ids is required for `validate subscription-plan`."
|
|
3870
|
-
);
|
|
3871
|
-
return client.validateSubscriptionPlan({ storeId, variantId });
|
|
3872
|
-
};
|
|
3873
|
-
var emit = (result, options) => {
|
|
2955
|
+
var writeResults = (results, options) => {
|
|
2956
|
+
const list = Array.isArray(results) ? results : [results];
|
|
3874
2957
|
if (options.json) {
|
|
3875
|
-
process.stdout.write(`${JSON.stringify(
|
|
2958
|
+
process.stdout.write(`${JSON.stringify(results, null, 2)}
|
|
3876
2959
|
`);
|
|
3877
2960
|
} else {
|
|
3878
|
-
|
|
3879
|
-
`);
|
|
2961
|
+
const separator = Array.isArray(results) ? "\n\n" : "\n";
|
|
2962
|
+
for (const result of list) process.stdout.write(`${renderResult(result)}${separator}`);
|
|
3880
2963
|
}
|
|
3881
|
-
return result.ok ? 0 : 1;
|
|
2964
|
+
return list.every((result) => result.ok) ? 0 : 1;
|
|
3882
2965
|
};
|
|
3883
|
-
var
|
|
3884
|
-
|
|
3885
|
-
|
|
2966
|
+
var runValidateCommand = async (target, options) => {
|
|
2967
|
+
try {
|
|
2968
|
+
const client = createFreshSqueezy({ mode: options.mode });
|
|
2969
|
+
return writeResults(await VALIDATE_SUBCOMMANDS[target].run(client, options), options);
|
|
2970
|
+
} catch (err) {
|
|
2971
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2972
|
+
process.stderr.write(renderCliError(message, errorHints(err, target)));
|
|
2973
|
+
return 2;
|
|
3886
2974
|
}
|
|
3887
|
-
return value;
|
|
3888
2975
|
};
|
|
3889
2976
|
|
|
3890
2977
|
// src/cli/main.ts
|
|
@@ -3902,7 +2989,10 @@ var OP_VERBS = [
|
|
|
3902
2989
|
];
|
|
3903
2990
|
var parseMode = (value) => {
|
|
3904
2991
|
if (value === "test" || value === "live") return value;
|
|
3905
|
-
throw new
|
|
2992
|
+
throw new FreshSqueezyError({
|
|
2993
|
+
code: "INVALID_MODE",
|
|
2994
|
+
message: `Mode must be "test" or "live", got "${value}"`
|
|
2995
|
+
});
|
|
3906
2996
|
};
|
|
3907
2997
|
var parseCsv = (value) => value.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
|
|
3908
2998
|
var readPackageVersion = () => {
|
|
@@ -3921,69 +3011,9 @@ var readPackageVersion = () => {
|
|
|
3921
3011
|
};
|
|
3922
3012
|
var isInteractive = Boolean(process.stdin.isTTY);
|
|
3923
3013
|
var packageVersion = readPackageVersion();
|
|
3924
|
-
var VALIDATE_COMMANDS = [
|
|
3925
|
-
{
|
|
3926
|
-
name: "connection",
|
|
3927
|
-
description: "Check that the API key authenticates",
|
|
3928
|
-
stores: "none"
|
|
3929
|
-
},
|
|
3930
|
-
{
|
|
3931
|
-
name: "store",
|
|
3932
|
-
description: "Check one or more stores are reachable",
|
|
3933
|
-
stores: "multi",
|
|
3934
|
-
storeIdsHelp: "Comma-separated store IDs"
|
|
3935
|
-
},
|
|
3936
|
-
{
|
|
3937
|
-
name: "product",
|
|
3938
|
-
description: "Check a product is published with at least one variant",
|
|
3939
|
-
stores: "ownership",
|
|
3940
|
-
required: ["--product-id <id>", "Product ID to validate"],
|
|
3941
|
-
storeIdsHelp: "Expected owning store IDs (first is used for cross-check)"
|
|
3942
|
-
},
|
|
3943
|
-
{
|
|
3944
|
-
name: "webhook",
|
|
3945
|
-
description: "Check a webhook is registered with the recommended events",
|
|
3946
|
-
stores: "multi",
|
|
3947
|
-
required: ["--webhook-url <url>", "Public webhook URL"],
|
|
3948
|
-
storeIdsHelp: "Comma-separated store IDs"
|
|
3949
|
-
},
|
|
3950
|
-
{
|
|
3951
|
-
name: "discount",
|
|
3952
|
-
description: "Check a discount code is valid and redeemable",
|
|
3953
|
-
stores: "ownership",
|
|
3954
|
-
required: ["--discount-id <id>", "Discount ID to validate"],
|
|
3955
|
-
storeIdsHelp: "Store ID for ownership check (first ID used)"
|
|
3956
|
-
},
|
|
3957
|
-
{
|
|
3958
|
-
name: "license-key",
|
|
3959
|
-
description: "Check a license key is active and not at its activation limit",
|
|
3960
|
-
stores: "ownership",
|
|
3961
|
-
required: ["--license-key-id <id>", "License key ID to validate"],
|
|
3962
|
-
storeIdsHelp: "Store ID for ownership check (first ID used)"
|
|
3963
|
-
},
|
|
3964
|
-
{
|
|
3965
|
-
name: "subscription-plan",
|
|
3966
|
-
description: "Check a subscription plan variant has valid billing interval and trial config",
|
|
3967
|
-
stores: "ownership",
|
|
3968
|
-
required: ["--variant-id <id>", "Variant ID of the subscription plan"],
|
|
3969
|
-
storeIdsHelp: "Store ID for ownership check (first ID used)"
|
|
3970
|
-
}
|
|
3971
|
-
];
|
|
3972
3014
|
var exitWith = async (code) => {
|
|
3973
|
-
process.
|
|
3974
|
-
};
|
|
3975
|
-
var toValidateOptions = (opts) => ({
|
|
3976
|
-
mode: opts.mode,
|
|
3977
|
-
storeIds: opts.storeIds,
|
|
3978
|
-
allStores: Boolean(opts.allStores),
|
|
3979
|
-
productId: opts.productId,
|
|
3980
|
-
webhookUrl: opts.webhookUrl,
|
|
3981
|
-
discountId: opts.discountId,
|
|
3982
|
-
licenseKeyId: opts.licenseKeyId,
|
|
3983
|
-
variantId: opts.variantId,
|
|
3984
|
-
json: Boolean(opts.json),
|
|
3985
|
-
isInteractive
|
|
3986
|
-
});
|
|
3015
|
+
process.exitCode = await code;
|
|
3016
|
+
};
|
|
3987
3017
|
var attachModeJson = (cmd) => cmd.option("-m, --mode <mode>", "test or live", parseMode).option("--json", "Emit machine-readable JSON");
|
|
3988
3018
|
var attachValidateFlags = (cmd, spec) => {
|
|
3989
3019
|
if (spec.required) cmd.requiredOption(spec.required[0], spec.required[1]);
|
|
@@ -4035,7 +3065,8 @@ program.action(async (opts) => {
|
|
|
4035
3065
|
"fresh-squeezy validate connection"
|
|
4036
3066
|
])
|
|
4037
3067
|
);
|
|
4038
|
-
process.
|
|
3068
|
+
process.exitCode = 2;
|
|
3069
|
+
return;
|
|
4039
3070
|
}
|
|
4040
3071
|
await exitWith(
|
|
4041
3072
|
runLauncherCommand({
|
|
@@ -4049,12 +3080,7 @@ var doctor2 = program.command("doctor").description("Run the full integration do
|
|
|
4049
3080
|
"--all-resources",
|
|
4050
3081
|
"Discover and validate every supported resource in each selected store"
|
|
4051
3082
|
).option("--product-id <id>", "Product to validate").option("--webhook-url <url>", "Webhook URL to validate").option("--discount-id <id>", "Discount to validate").option("--license-key-id <id>", "License key to validate").option("--variant-id <id>", "Subscription plan variant to validate").option("--json", "Emit machine-readable JSON").action(async (opts) => {
|
|
4052
|
-
await exitWith(
|
|
4053
|
-
runDoctorCommand({
|
|
4054
|
-
...toValidateOptions(opts),
|
|
4055
|
-
allResources: Boolean(opts.allResources)
|
|
4056
|
-
})
|
|
4057
|
-
);
|
|
3083
|
+
await exitWith(runDoctorCommand({ ...opts, isInteractive }));
|
|
4058
3084
|
});
|
|
4059
3085
|
doctor2.addHelpText(
|
|
4060
3086
|
"after",
|
|
@@ -4077,13 +3103,13 @@ Examples:
|
|
|
4077
3103
|
fresh-squeezy validate webhook --store-ids 12 --webhook-url https://app.example.com/api/webhooks/lemon-squeezy
|
|
4078
3104
|
|
|
4079
3105
|
Targets:
|
|
4080
|
-
|
|
3106
|
+
${Object.keys(VALIDATE_SUBCOMMANDS).join(", ")}
|
|
4081
3107
|
`
|
|
4082
3108
|
);
|
|
4083
|
-
for (const spec of
|
|
4084
|
-
attachValidateFlags(validate.command(
|
|
3109
|
+
for (const [name, spec] of Object.entries(VALIDATE_SUBCOMMANDS)) {
|
|
3110
|
+
attachValidateFlags(validate.command(name).description(spec.description), spec).action(
|
|
4085
3111
|
async (opts) => {
|
|
4086
|
-
await exitWith(runValidateCommand(
|
|
3112
|
+
await exitWith(runValidateCommand(name, { ...opts, isInteractive }));
|
|
4087
3113
|
}
|
|
4088
3114
|
);
|
|
4089
3115
|
}
|
|
@@ -4164,6 +3190,6 @@ program.parseAsync(process.argv).catch((err) => {
|
|
|
4164
3190
|
const message = err instanceof Error ? err.message : String(err);
|
|
4165
3191
|
const hints = message.includes("Mode must be") ? ["fresh-squeezy doctor --mode test", "fresh-squeezy doctor --mode live"] : ["fresh-squeezy --help"];
|
|
4166
3192
|
process.stderr.write(renderCliError(message, hints));
|
|
4167
|
-
process.
|
|
3193
|
+
process.exitCode = 2;
|
|
4168
3194
|
});
|
|
4169
3195
|
//# sourceMappingURL=cli.js.map
|