fresh-squeezy 0.1.13 → 0.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli/main.ts
4
- import { readFileSync } from "fs";
4
+ import { readFileSync as readFileSync2 } from "fs";
5
5
  import { Command } from "commander";
6
6
  import dotenv from "dotenv";
7
7
 
@@ -9,7 +9,7 @@ import dotenv from "dotenv";
9
9
  import { existsSync } from "fs";
10
10
  import { mkdir, readFile, writeFile } from "fs/promises";
11
11
  import { dirname, resolve } from "path";
12
- async function runAugmentCommand(options = {}) {
12
+ var runAugmentCommand = async (options = {}) => {
13
13
  const cwd = options.cwd ?? process.cwd();
14
14
  const outPath = resolve(cwd, options.out ?? "lemonsqueezy.augment.d.ts");
15
15
  try {
@@ -37,8 +37,8 @@ async function runAugmentCommand(options = {}) {
37
37
  `);
38
38
  return 2;
39
39
  }
40
- }
41
- async function detectFlavour(cwd, force) {
40
+ };
41
+ var detectFlavour = async (cwd, force) => {
42
42
  if (force) return "generic";
43
43
  const pkgPath = resolve(cwd, "package.json");
44
44
  if (!existsSync(pkgPath)) return "generic";
@@ -50,8 +50,8 @@ async function detectFlavour(cwd, force) {
50
50
  ...pkg.peerDependencies ?? {}
51
51
  };
52
52
  return "@lemonsqueezy/lemonsqueezy.js" in deps ? "with-sdk" : "generic";
53
- }
54
- function renderAugmentationFile(flavour) {
53
+ };
54
+ var renderAugmentationFile = (flavour) => {
55
55
  const header = `/**
56
56
  * Generated by \`fresh-squeezy types:augment\` \u2014 re-run after upgrading
57
57
  * fresh-squeezy to refresh the field set.
@@ -215,7 +215,7 @@ export type {
215
215
  * }
216
216
  */
217
217
  `;
218
- }
218
+ };
219
219
 
220
220
  // src/core/errors.ts
221
221
  var FreshSqueezyError = class _FreshSqueezyError extends Error {
@@ -239,7 +239,7 @@ var ENV_KEYS = {
239
239
  storeId: "LEMON_SQUEEZY_STORE_ID",
240
240
  mode: "LEMON_SQUEEZY_MODE"
241
241
  };
242
- function resolveConfig(input2 = {}) {
242
+ var resolveConfig = (input2 = {}) => {
243
243
  const apiKey = input2.apiKey ?? process.env[ENV_KEYS.apiKey];
244
244
  if (!apiKey) {
245
245
  throw new FreshSqueezyError({
@@ -256,14 +256,14 @@ function resolveConfig(input2 = {}) {
256
256
  baseUrl: input2.baseUrl ?? DEFAULT_BASE_URL,
257
257
  fetch: input2.fetch ?? globalThis.fetch
258
258
  };
259
- }
260
- function normalizeMode(value) {
259
+ };
260
+ var normalizeMode = (value) => {
261
261
  if (value === "test" || value === "live") return value;
262
262
  throw new FreshSqueezyError({
263
263
  code: "INVALID_MODE",
264
264
  message: `Mode must be "test" or "live", got "${value}".`
265
265
  });
266
- }
266
+ };
267
267
 
268
268
  // src/core/http.ts
269
269
  var HttpClient = class {
@@ -309,6 +309,37 @@ var HttpClient = class {
309
309
  const doc = await this.request({ path: path4 });
310
310
  return doc.data;
311
311
  }
312
+ /**
313
+ * POST a JSON:API document and return the created `data` resource.
314
+ *
315
+ * @param path - API path starting with `/v1/...`.
316
+ * @param body - JSON:API create document.
317
+ * @returns The created resource.
318
+ */
319
+ async postResource(path4, body) {
320
+ const doc = await this.request({ method: "POST", path: path4, body });
321
+ return doc.data;
322
+ }
323
+ /**
324
+ * PATCH a JSON:API document and return the updated `data` resource.
325
+ *
326
+ * @param path - API path starting with `/v1/...`.
327
+ * @param body - JSON:API update document.
328
+ * @returns The updated resource.
329
+ */
330
+ async patchResource(path4, body) {
331
+ const doc = await this.request({ method: "PATCH", path: path4, body });
332
+ return doc.data;
333
+ }
334
+ /**
335
+ * DELETE a resource. Lemon Squeezy often returns an empty body on success.
336
+ *
337
+ * @param path - API path starting with `/v1/...`.
338
+ * @returns Nothing — single void return, not a multi-field bag.
339
+ */
340
+ async deleteResource(path4) {
341
+ await this.request({ method: "DELETE", path: path4 });
342
+ }
312
343
  /**
313
344
  * Fetch a single page of a JSON:API collection. Most callers want
314
345
  * `paginate()` instead — this method is kept for one-shot lookups where
@@ -356,48 +387,913 @@ var HttpClient = class {
356
387
  return url.toString();
357
388
  }
358
389
  };
359
- function safeJsonParse(text) {
390
+ var safeJsonParse = (text) => {
360
391
  try {
361
392
  return JSON.parse(text);
362
393
  } catch {
363
394
  return text;
364
395
  }
365
- }
366
- function toApiError(status, body) {
396
+ };
397
+ var toApiError = (status, body) => {
367
398
  const errors = extractJsonApiErrors(body);
368
399
  const first = errors[0];
369
400
  const code = status === 401 ? "UNAUTHORIZED" : status === 404 ? "NOT_FOUND" : status === 429 ? "RATE_LIMITED" : first?.code ?? `HTTP_${status}`;
370
401
  const message = first?.detail ?? first?.title ?? `Lemon Squeezy request failed with status ${status}`;
371
402
  return new FreshSqueezyError({ code, status, message, detail: body });
372
- }
373
- function extractJsonApiErrors(body) {
403
+ };
404
+ var extractJsonApiErrors = (body) => {
374
405
  if (!body || typeof body !== "object") return [];
375
406
  const errors = body.errors;
376
407
  if (!Array.isArray(errors)) return [];
377
408
  return errors.filter(
378
409
  (entry) => typeof entry === "object" && entry !== null
379
410
  );
380
- }
411
+ };
381
412
 
382
- // src/core/mode.ts
383
- function resolveActualMode(testMode) {
384
- if (testMode === true) return "test";
385
- if (testMode === false) return "live";
386
- return void 0;
387
- }
413
+ // src/resources/affiliates.ts
414
+ var getAffiliate = async (http, affiliateId) => {
415
+ return http.getResource(`/v1/affiliates/${affiliateId}`);
416
+ };
417
+ var listAffiliatesForStore = async (http, storeId) => {
418
+ return http.paginate("/v1/affiliates", {
419
+ "filter[store_id]": String(storeId)
420
+ });
421
+ };
422
+
423
+ // src/resources/checkouts.ts
424
+ var getCheckout = async (http, checkoutId) => {
425
+ return http.getResource(`/v1/checkouts/${checkoutId}`);
426
+ };
427
+ var listCheckoutsForStore = async (http, storeId) => {
428
+ return http.paginate("/v1/checkouts", {
429
+ "filter[store_id]": String(storeId)
430
+ });
431
+ };
432
+ var createCheckout = async (http, body) => {
433
+ return http.postResource("/v1/checkouts", body);
434
+ };
435
+
436
+ // src/resources/customers.ts
437
+ var getCustomer = async (http, customerId) => {
438
+ return http.getResource(`/v1/customers/${customerId}`);
439
+ };
440
+ var listCustomersForStore = async (http, storeId) => {
441
+ return http.paginate("/v1/customers", {
442
+ "filter[store_id]": String(storeId)
443
+ });
444
+ };
445
+ var createCustomer = async (http, body) => {
446
+ return http.postResource("/v1/customers", body);
447
+ };
448
+ var updateCustomer = async (http, customerId, body) => {
449
+ return http.patchResource(`/v1/customers/${customerId}`, body);
450
+ };
451
+
452
+ // src/resources/discountRedemptions.ts
453
+ var getDiscountRedemption = async (http, discountRedemptionId) => {
454
+ return http.getResource(
455
+ `/v1/discount-redemptions/${discountRedemptionId}`
456
+ );
457
+ };
458
+ var listDiscountRedemptionsForDiscount = async (http, discountId) => {
459
+ return http.paginate("/v1/discount-redemptions", {
460
+ "filter[discount_id]": String(discountId)
461
+ });
462
+ };
463
+
464
+ // src/resources/discounts.ts
465
+ var getDiscount = async (http, discountId) => {
466
+ return http.getResource(`/v1/discounts/${discountId}`);
467
+ };
468
+ var listDiscountsForStore = async (http, storeId) => {
469
+ return http.paginate("/v1/discounts", {
470
+ "filter[store_id]": String(storeId)
471
+ });
472
+ };
473
+ var createDiscount = async (http, body) => {
474
+ return http.postResource("/v1/discounts", body);
475
+ };
476
+ var deleteDiscount = async (http, discountId) => {
477
+ await http.deleteResource(`/v1/discounts/${discountId}`);
478
+ };
479
+
480
+ // src/resources/files.ts
481
+ var getFile = async (http, fileId) => {
482
+ return http.getResource(`/v1/files/${fileId}`);
483
+ };
484
+ var listFilesForVariant = async (http, variantId) => {
485
+ return http.paginate("/v1/files", {
486
+ "filter[variant_id]": String(variantId)
487
+ });
488
+ };
489
+
490
+ // src/resources/licenseKeyInstances.ts
491
+ var getLicenseKeyInstance = async (http, licenseKeyInstanceId) => {
492
+ return http.getResource(
493
+ `/v1/license-key-instances/${licenseKeyInstanceId}`
494
+ );
495
+ };
496
+ var listLicenseKeyInstancesForLicenseKey = async (http, licenseKeyId) => {
497
+ return http.paginate("/v1/license-key-instances", {
498
+ "filter[license_key_id]": String(licenseKeyId)
499
+ });
500
+ };
501
+
502
+ // src/resources/licenseKeys.ts
503
+ var getLicenseKey = async (http, licenseKeyId) => {
504
+ return http.getResource(`/v1/license-keys/${licenseKeyId}`);
505
+ };
506
+ var listLicenseKeysForStore = async (http, storeId) => {
507
+ return http.paginate("/v1/license-keys", {
508
+ "filter[store_id]": String(storeId)
509
+ });
510
+ };
511
+ var updateLicenseKey = async (http, licenseKeyId, body) => {
512
+ return http.patchResource(`/v1/license-keys/${licenseKeyId}`, body);
513
+ };
514
+
515
+ // src/resources/orderItems.ts
516
+ var getOrderItem = async (http, orderItemId) => {
517
+ return http.getResource(`/v1/order-items/${orderItemId}`);
518
+ };
519
+ var listOrderItemsForOrder = async (http, orderId) => {
520
+ return http.paginate("/v1/order-items", {
521
+ "filter[order_id]": String(orderId)
522
+ });
523
+ };
524
+
525
+ // src/resources/orders.ts
526
+ var getOrder = async (http, orderId) => {
527
+ return http.getResource(`/v1/orders/${orderId}`);
528
+ };
529
+ var listOrdersForStore = async (http, storeId) => {
530
+ return http.paginate("/v1/orders", {
531
+ "filter[store_id]": String(storeId)
532
+ });
533
+ };
534
+ var refundOrder = async (http, orderId, body) => {
535
+ return http.postResource(`/v1/orders/${orderId}/refund`, body ?? {});
536
+ };
537
+ var generateOrderInvoice = async (http, orderId, body) => {
538
+ return http.request({
539
+ method: "POST",
540
+ path: `/v1/orders/${orderId}/generate-invoice`,
541
+ body: body ?? {}
542
+ });
543
+ };
544
+
545
+ // src/resources/prices.ts
546
+ var getPrice = async (http, priceId) => {
547
+ return http.getResource(`/v1/prices/${priceId}`);
548
+ };
549
+ var listPricesForVariant = async (http, variantId) => {
550
+ return http.paginate("/v1/prices", {
551
+ "filter[variant_id]": String(variantId)
552
+ });
553
+ };
554
+
555
+ // src/resources/products.ts
556
+ var getProduct = async (http, productId) => {
557
+ return http.getResource(`/v1/products/${productId}`);
558
+ };
559
+ var listProducts = async (http, storeId) => {
560
+ return http.paginate("/v1/products", {
561
+ "filter[store_id]": String(storeId)
562
+ });
563
+ };
564
+
565
+ // src/resources/registry.ts
566
+ var resourceRegistry = [
567
+ // users
568
+ { resource: "user", verb: "get", docsPath: "users/retrieve-user", body: "none", idRole: "none" },
569
+ // stores (read-only)
570
+ { resource: "store", verb: "get", docsPath: "stores/retrieve-store", body: "none", idRole: "id" },
571
+ {
572
+ resource: "store",
573
+ verb: "list",
574
+ docsPath: "stores/list-all-stores",
575
+ body: "none",
576
+ idRole: "none"
577
+ },
578
+ // products (read-only)
579
+ {
580
+ resource: "product",
581
+ verb: "get",
582
+ docsPath: "products/retrieve-product",
583
+ body: "none",
584
+ idRole: "id"
585
+ },
586
+ {
587
+ resource: "product",
588
+ verb: "list",
589
+ docsPath: "products/list-all-products",
590
+ body: "none",
591
+ idRole: "store"
592
+ },
593
+ // variants (read-only)
594
+ {
595
+ resource: "variant",
596
+ verb: "get",
597
+ docsPath: "variants/retrieve-variant",
598
+ body: "none",
599
+ idRole: "id"
600
+ },
601
+ {
602
+ resource: "variant",
603
+ verb: "list",
604
+ docsPath: "variants/list-all-variants",
605
+ body: "none",
606
+ idRole: "parent"
607
+ },
608
+ // prices (read-only)
609
+ { resource: "price", verb: "get", docsPath: "prices/retrieve-price", body: "none", idRole: "id" },
610
+ {
611
+ resource: "price",
612
+ verb: "list",
613
+ docsPath: "prices/list-all-prices",
614
+ body: "none",
615
+ idRole: "parent"
616
+ },
617
+ // files (read-only)
618
+ { resource: "file", verb: "get", docsPath: "files/retrieve-file", body: "none", idRole: "id" },
619
+ {
620
+ resource: "file",
621
+ verb: "list",
622
+ docsPath: "files/list-all-files",
623
+ body: "none",
624
+ idRole: "parent"
625
+ },
626
+ // customers
627
+ {
628
+ resource: "customer",
629
+ verb: "get",
630
+ docsPath: "customers/retrieve-customer",
631
+ body: "none",
632
+ idRole: "id"
633
+ },
634
+ {
635
+ resource: "customer",
636
+ verb: "list",
637
+ docsPath: "customers/list-all-customers",
638
+ body: "none",
639
+ idRole: "store"
640
+ },
641
+ {
642
+ resource: "customer",
643
+ verb: "create",
644
+ docsPath: "customers/create-customer",
645
+ body: "required",
646
+ idRole: "none"
647
+ },
648
+ {
649
+ resource: "customer",
650
+ verb: "update",
651
+ docsPath: "customers/update-customer",
652
+ body: "required",
653
+ idRole: "id"
654
+ },
655
+ // orders
656
+ { resource: "order", verb: "get", docsPath: "orders/retrieve-order", body: "none", idRole: "id" },
657
+ {
658
+ resource: "order",
659
+ verb: "list",
660
+ docsPath: "orders/list-all-orders",
661
+ body: "none",
662
+ idRole: "store"
663
+ },
664
+ {
665
+ resource: "order",
666
+ verb: "refund",
667
+ docsPath: "orders/issue-refund",
668
+ body: "optional",
669
+ destructive: true,
670
+ idRole: "id"
671
+ },
672
+ {
673
+ resource: "order",
674
+ verb: "generate-invoice",
675
+ docsPath: "orders/generate-order-invoice",
676
+ body: "optional",
677
+ idRole: "id"
678
+ },
679
+ // order-items (read-only)
680
+ {
681
+ resource: "order-item",
682
+ verb: "get",
683
+ docsPath: "order-items/retrieve-order-item",
684
+ body: "none",
685
+ idRole: "id"
686
+ },
687
+ {
688
+ resource: "order-item",
689
+ verb: "list",
690
+ docsPath: "order-items/list-all-order-items",
691
+ body: "none",
692
+ idRole: "parent"
693
+ },
694
+ // subscriptions
695
+ {
696
+ resource: "subscription",
697
+ verb: "get",
698
+ docsPath: "subscriptions/retrieve-subscription",
699
+ body: "none",
700
+ idRole: "id"
701
+ },
702
+ {
703
+ resource: "subscription",
704
+ verb: "list",
705
+ docsPath: "subscriptions/list-all-subscriptions",
706
+ body: "none",
707
+ idRole: "store"
708
+ },
709
+ {
710
+ resource: "subscription",
711
+ verb: "update",
712
+ docsPath: "subscriptions/update-subscription",
713
+ body: "required",
714
+ idRole: "id"
715
+ },
716
+ {
717
+ resource: "subscription",
718
+ verb: "cancel",
719
+ docsPath: "subscriptions/cancel-subscription",
720
+ body: "none",
721
+ destructive: true,
722
+ idRole: "id"
723
+ },
724
+ // subscription-items
725
+ {
726
+ resource: "subscription-item",
727
+ verb: "get",
728
+ docsPath: "subscription-items/retrieve-subscription-item",
729
+ body: "none",
730
+ idRole: "id"
731
+ },
732
+ {
733
+ resource: "subscription-item",
734
+ verb: "list",
735
+ docsPath: "subscription-items/list-all-subscription-items",
736
+ body: "none",
737
+ idRole: "parent"
738
+ },
739
+ {
740
+ resource: "subscription-item",
741
+ verb: "update",
742
+ docsPath: "subscription-items/update-subscription-item",
743
+ body: "required",
744
+ idRole: "id"
745
+ },
746
+ {
747
+ resource: "subscription-item",
748
+ verb: "current-usage",
749
+ docsPath: "subscription-items/retrieve-subscription-item-current-usage",
750
+ body: "none",
751
+ idRole: "id"
752
+ },
753
+ // subscription-invoices
754
+ {
755
+ resource: "subscription-invoice",
756
+ verb: "get",
757
+ docsPath: "subscription-invoices/retrieve-subscription-invoice",
758
+ body: "none",
759
+ idRole: "id"
760
+ },
761
+ {
762
+ resource: "subscription-invoice",
763
+ verb: "list",
764
+ docsPath: "subscription-invoices/list-all-subscription-invoices",
765
+ body: "none",
766
+ idRole: "parent"
767
+ },
768
+ {
769
+ resource: "subscription-invoice",
770
+ verb: "refund",
771
+ docsPath: "subscription-invoices/issue-refund",
772
+ body: "optional",
773
+ destructive: true,
774
+ idRole: "id"
775
+ },
776
+ {
777
+ resource: "subscription-invoice",
778
+ verb: "generate-invoice",
779
+ docsPath: "subscription-invoices/generate-subscription-invoice",
780
+ body: "optional",
781
+ idRole: "id"
782
+ },
783
+ // usage-records
784
+ {
785
+ resource: "usage-record",
786
+ verb: "get",
787
+ docsPath: "usage-records/retrieve-usage-record",
788
+ body: "none",
789
+ idRole: "id"
790
+ },
791
+ {
792
+ resource: "usage-record",
793
+ verb: "list",
794
+ docsPath: "usage-records/list-all-usage-records",
795
+ body: "none",
796
+ idRole: "parent"
797
+ },
798
+ {
799
+ resource: "usage-record",
800
+ verb: "create",
801
+ docsPath: "usage-records/create-usage-record",
802
+ body: "required",
803
+ idRole: "none"
804
+ },
805
+ // discounts
806
+ {
807
+ resource: "discount",
808
+ verb: "get",
809
+ docsPath: "discounts/retrieve-discount",
810
+ body: "none",
811
+ idRole: "id"
812
+ },
813
+ {
814
+ resource: "discount",
815
+ verb: "list",
816
+ docsPath: "discounts/list-all-discounts",
817
+ body: "none",
818
+ idRole: "store"
819
+ },
820
+ {
821
+ resource: "discount",
822
+ verb: "create",
823
+ docsPath: "discounts/create-discount",
824
+ body: "required",
825
+ idRole: "none"
826
+ },
827
+ {
828
+ resource: "discount",
829
+ verb: "delete",
830
+ docsPath: "discounts/delete-discount",
831
+ body: "none",
832
+ destructive: true,
833
+ idRole: "id"
834
+ },
835
+ // discount-redemptions (read-only)
836
+ {
837
+ resource: "discount-redemption",
838
+ verb: "get",
839
+ docsPath: "discount-redemptions/retrieve-discount-redemption",
840
+ body: "none",
841
+ idRole: "id"
842
+ },
843
+ {
844
+ resource: "discount-redemption",
845
+ verb: "list",
846
+ docsPath: "discount-redemptions/list-all-discount-redemptions",
847
+ body: "none",
848
+ idRole: "parent"
849
+ },
850
+ // license-keys
851
+ {
852
+ resource: "license-key",
853
+ verb: "get",
854
+ docsPath: "license-keys/retrieve-license-key",
855
+ body: "none",
856
+ idRole: "id"
857
+ },
858
+ {
859
+ resource: "license-key",
860
+ verb: "list",
861
+ docsPath: "license-keys/list-all-license-keys",
862
+ body: "none",
863
+ idRole: "store"
864
+ },
865
+ {
866
+ resource: "license-key",
867
+ verb: "update",
868
+ docsPath: "license-keys/update-license-key",
869
+ body: "required",
870
+ idRole: "id"
871
+ },
872
+ // license-key-instances (read-only)
873
+ {
874
+ resource: "license-key-instance",
875
+ verb: "get",
876
+ docsPath: "license-key-instances/retrieve-license-key-instance",
877
+ body: "none",
878
+ idRole: "id"
879
+ },
880
+ {
881
+ resource: "license-key-instance",
882
+ verb: "list",
883
+ docsPath: "license-key-instances/list-all-license-key-instances",
884
+ body: "none",
885
+ idRole: "parent"
886
+ },
887
+ // checkouts
888
+ {
889
+ resource: "checkout",
890
+ verb: "get",
891
+ docsPath: "checkouts/retrieve-checkout",
892
+ body: "none",
893
+ idRole: "id"
894
+ },
895
+ {
896
+ resource: "checkout",
897
+ verb: "list",
898
+ docsPath: "checkouts/list-all-checkouts",
899
+ body: "none",
900
+ idRole: "store"
901
+ },
902
+ {
903
+ resource: "checkout",
904
+ verb: "create",
905
+ docsPath: "checkouts/create-checkout",
906
+ body: "required",
907
+ idRole: "none"
908
+ },
909
+ // webhooks
910
+ {
911
+ resource: "webhook",
912
+ verb: "get",
913
+ docsPath: "webhooks/retrieve-webhook",
914
+ body: "none",
915
+ idRole: "id"
916
+ },
917
+ {
918
+ resource: "webhook",
919
+ verb: "list",
920
+ docsPath: "webhooks/list-all-webhooks",
921
+ body: "none",
922
+ idRole: "store"
923
+ },
924
+ {
925
+ resource: "webhook",
926
+ verb: "create",
927
+ docsPath: "webhooks/create-webhook",
928
+ body: "required",
929
+ idRole: "none"
930
+ },
931
+ {
932
+ resource: "webhook",
933
+ verb: "update",
934
+ docsPath: "webhooks/update-webhook",
935
+ body: "required",
936
+ idRole: "id"
937
+ },
938
+ {
939
+ resource: "webhook",
940
+ verb: "delete",
941
+ docsPath: "webhooks/delete-webhook",
942
+ body: "none",
943
+ destructive: true,
944
+ idRole: "id"
945
+ },
946
+ // affiliates (read-only)
947
+ {
948
+ resource: "affiliate",
949
+ verb: "get",
950
+ docsPath: "affiliates/retrieve-affiliate",
951
+ body: "none",
952
+ idRole: "id"
953
+ },
954
+ {
955
+ resource: "affiliate",
956
+ verb: "list",
957
+ docsPath: "affiliates/list-all-affiliates",
958
+ body: "none",
959
+ idRole: "store"
960
+ }
961
+ ];
962
+ var findResourceVerb = (resource, verb) => {
963
+ const normalized = resource.replace(/_/g, "-").toLowerCase();
964
+ const singular = normalized.endsWith("s") && normalized !== "status" ? normalized.slice(0, -1) : normalized;
965
+ const aliases = {
966
+ products: "product",
967
+ stores: "store",
968
+ customers: "customer",
969
+ orders: "order",
970
+ "order-items": "order-item",
971
+ subscriptions: "subscription",
972
+ "subscription-items": "subscription-item",
973
+ "subscription-invoices": "subscription-invoice",
974
+ "usage-records": "usage-record",
975
+ discounts: "discount",
976
+ "discount-redemptions": "discount-redemption",
977
+ "license-keys": "license-key",
978
+ "license-key-instances": "license-key-instance",
979
+ checkouts: "checkout",
980
+ webhooks: "webhook",
981
+ affiliates: "affiliate",
982
+ variants: "variant",
983
+ prices: "price",
984
+ files: "file",
985
+ users: "user"
986
+ };
987
+ const key = aliases[normalized] ?? singular;
988
+ return resourceRegistry.find((entry) => entry.resource === key && entry.verb === verb);
989
+ };
990
+ var listRegisteredResources = () => {
991
+ return [...new Set(resourceRegistry.map((entry) => entry.resource))].sort();
992
+ };
388
993
 
389
994
  // src/resources/stores.ts
390
- async function getStore(http, storeId) {
995
+ var getStore = async (http, storeId) => {
391
996
  return http.getResource(`/v1/stores/${storeId}`);
392
- }
393
- async function listStores(http) {
997
+ };
998
+ var listStores = async (http) => {
394
999
  return http.paginate("/v1/stores");
395
- }
1000
+ };
1001
+
1002
+ // src/resources/subscriptionInvoices.ts
1003
+ var getSubscriptionInvoice = async (http, subscriptionInvoiceId) => {
1004
+ return http.getResource(
1005
+ `/v1/subscription-invoices/${subscriptionInvoiceId}`
1006
+ );
1007
+ };
1008
+ var listSubscriptionInvoicesForSubscription = async (http, subscriptionId) => {
1009
+ return http.paginate("/v1/subscription-invoices", {
1010
+ "filter[subscription_id]": String(subscriptionId)
1011
+ });
1012
+ };
1013
+ var refundSubscriptionInvoice = async (http, subscriptionInvoiceId, body) => {
1014
+ return http.postResource(
1015
+ `/v1/subscription-invoices/${subscriptionInvoiceId}/refund`,
1016
+ body ?? {}
1017
+ );
1018
+ };
1019
+ var generateSubscriptionInvoice = async (http, subscriptionInvoiceId, body) => {
1020
+ return http.request({
1021
+ method: "POST",
1022
+ path: `/v1/subscription-invoices/${subscriptionInvoiceId}/generate-invoice`,
1023
+ body: body ?? {}
1024
+ });
1025
+ };
1026
+
1027
+ // src/resources/subscriptionItems.ts
1028
+ var getSubscriptionItem = async (http, subscriptionItemId) => {
1029
+ return http.getResource(
1030
+ `/v1/subscription-items/${subscriptionItemId}`
1031
+ );
1032
+ };
1033
+ var listSubscriptionItemsForSubscription = async (http, subscriptionId) => {
1034
+ return http.paginate("/v1/subscription-items", {
1035
+ "filter[subscription_id]": String(subscriptionId)
1036
+ });
1037
+ };
1038
+ var updateSubscriptionItem = async (http, subscriptionItemId, body) => {
1039
+ return http.patchResource(
1040
+ `/v1/subscription-items/${subscriptionItemId}`,
1041
+ body
1042
+ );
1043
+ };
1044
+ var getSubscriptionItemCurrentUsage = async (http, subscriptionItemId) => {
1045
+ return http.request({
1046
+ path: `/v1/subscription-items/${subscriptionItemId}/current-usage`
1047
+ });
1048
+ };
1049
+
1050
+ // src/resources/subscriptions.ts
1051
+ var getSubscription = async (http, subscriptionId) => {
1052
+ return http.getResource(`/v1/subscriptions/${subscriptionId}`);
1053
+ };
1054
+ var listSubscriptionsForStore = async (http, storeId) => {
1055
+ return http.paginate("/v1/subscriptions", {
1056
+ "filter[store_id]": String(storeId)
1057
+ });
1058
+ };
1059
+ var updateSubscription = async (http, subscriptionId, body) => {
1060
+ return http.patchResource(`/v1/subscriptions/${subscriptionId}`, body);
1061
+ };
1062
+ var cancelSubscription = async (http, subscriptionId) => {
1063
+ const doc = await http.request({
1064
+ method: "DELETE",
1065
+ path: `/v1/subscriptions/${subscriptionId}`
1066
+ });
1067
+ return doc?.data;
1068
+ };
1069
+
1070
+ // src/resources/usageRecords.ts
1071
+ var getUsageRecord = async (http, usageRecordId) => {
1072
+ return http.getResource(`/v1/usage-records/${usageRecordId}`);
1073
+ };
1074
+ var listUsageRecordsForSubscriptionItem = async (http, subscriptionItemId) => {
1075
+ return http.paginate("/v1/usage-records", {
1076
+ "filter[subscription_item_id]": String(subscriptionItemId)
1077
+ });
1078
+ };
1079
+ var createUsageRecord = async (http, body) => {
1080
+ return http.postResource("/v1/usage-records", body);
1081
+ };
396
1082
 
397
1083
  // src/resources/users.ts
398
- async function getAuthenticatedUser(http) {
1084
+ var getAuthenticatedUser = async (http) => {
399
1085
  return http.request({ path: "/v1/users/me" });
400
- }
1086
+ };
1087
+ var userResource = (doc) => {
1088
+ return doc.data;
1089
+ };
1090
+
1091
+ // src/resources/variants.ts
1092
+ var getVariant = async (http, variantId) => {
1093
+ return http.getResource(`/v1/variants/${variantId}`);
1094
+ };
1095
+ var listVariantsForProduct = async (http, productId) => {
1096
+ return http.paginate("/v1/variants", {
1097
+ "filter[product_id]": String(productId)
1098
+ });
1099
+ };
1100
+
1101
+ // src/resources/webhooks.ts
1102
+ var getWebhook = async (http, webhookId) => {
1103
+ return http.getResource(`/v1/webhooks/${webhookId}`);
1104
+ };
1105
+ var listWebhooksForStore = async (http, storeId) => {
1106
+ return http.paginate("/v1/webhooks", {
1107
+ "filter[store_id]": String(storeId)
1108
+ });
1109
+ };
1110
+ var createWebhook = async (http, body) => {
1111
+ return http.postResource("/v1/webhooks", body);
1112
+ };
1113
+ var updateWebhook = async (http, webhookId, body) => {
1114
+ return http.patchResource(`/v1/webhooks/${webhookId}`, body);
1115
+ };
1116
+ var deleteWebhook = async (http, webhookId) => {
1117
+ await http.deleteResource(`/v1/webhooks/${webhookId}`);
1118
+ };
1119
+
1120
+ // src/resources/invokeOp.ts
1121
+ var invokeOp = async (http, resource, verb, args = {}) => {
1122
+ const spec = findResourceVerb(resource, verb);
1123
+ if (!spec) {
1124
+ throw new FreshSqueezyError({
1125
+ code: "UNKNOWN_OP",
1126
+ message: `Unknown or unsupported op: ${verb} ${resource}. Run \`fresh-squeezy ops --list\`.`
1127
+ });
1128
+ }
1129
+ const key = `${spec.resource}:${spec.verb}`;
1130
+ switch (key) {
1131
+ case "user:get":
1132
+ return userResource(await getAuthenticatedUser(http));
1133
+ case "store:get":
1134
+ return getStore(http, requireId(args, "store"));
1135
+ case "store:list":
1136
+ return listStores(http);
1137
+ case "product:get":
1138
+ return getProduct(http, requireId(args, "product"));
1139
+ case "product:list":
1140
+ return listProducts(http, requireStore(args));
1141
+ case "variant:get":
1142
+ return getVariant(http, requireId(args, "variant"));
1143
+ case "variant:list":
1144
+ return listVariantsForProduct(http, requireParent(args, "product"));
1145
+ case "price:get":
1146
+ return getPrice(http, requireId(args, "price"));
1147
+ case "price:list":
1148
+ return listPricesForVariant(http, requireParent(args, "variant"));
1149
+ case "file:get":
1150
+ return getFile(http, requireId(args, "file"));
1151
+ case "file:list":
1152
+ return listFilesForVariant(http, requireParent(args, "variant"));
1153
+ case "customer:get":
1154
+ return getCustomer(http, requireId(args, "customer"));
1155
+ case "customer:list":
1156
+ return listCustomersForStore(http, requireStore(args));
1157
+ case "customer:create":
1158
+ return createCustomer(http, requireBody(args));
1159
+ case "customer:update":
1160
+ return updateCustomer(http, requireId(args, "customer"), requireBody(args));
1161
+ case "order:get":
1162
+ return getOrder(http, requireId(args, "order"));
1163
+ case "order:list":
1164
+ return listOrdersForStore(http, requireStore(args));
1165
+ case "order:refund":
1166
+ return refundOrder(http, requireId(args, "order"), args.body);
1167
+ case "order:generate-invoice":
1168
+ return generateOrderInvoice(http, requireId(args, "order"), args.body);
1169
+ case "order-item:get":
1170
+ return getOrderItem(http, requireId(args, "order-item"));
1171
+ case "order-item:list":
1172
+ return listOrderItemsForOrder(http, requireParent(args, "order"));
1173
+ case "subscription:get":
1174
+ return getSubscription(http, requireId(args, "subscription"));
1175
+ case "subscription:list":
1176
+ return listSubscriptionsForStore(http, requireStore(args));
1177
+ case "subscription:update":
1178
+ return updateSubscription(http, requireId(args, "subscription"), requireBody(args));
1179
+ case "subscription:cancel":
1180
+ return cancelSubscription(http, requireId(args, "subscription"));
1181
+ case "subscription-item:get":
1182
+ return getSubscriptionItem(http, requireId(args, "subscription-item"));
1183
+ case "subscription-item:list":
1184
+ return listSubscriptionItemsForSubscription(http, requireParent(args, "subscription"));
1185
+ case "subscription-item:update":
1186
+ return updateSubscriptionItem(http, requireId(args, "subscription-item"), requireBody(args));
1187
+ case "subscription-item:current-usage":
1188
+ return getSubscriptionItemCurrentUsage(http, requireId(args, "subscription-item"));
1189
+ case "subscription-invoice:get":
1190
+ return getSubscriptionInvoice(http, requireId(args, "subscription-invoice"));
1191
+ case "subscription-invoice:list":
1192
+ return listSubscriptionInvoicesForSubscription(http, requireParent(args, "subscription"));
1193
+ case "subscription-invoice:refund":
1194
+ return refundSubscriptionInvoice(http, requireId(args, "subscription-invoice"), args.body);
1195
+ case "subscription-invoice:generate-invoice":
1196
+ return generateSubscriptionInvoice(http, requireId(args, "subscription-invoice"), args.body);
1197
+ case "usage-record:get":
1198
+ return getUsageRecord(http, requireId(args, "usage-record"));
1199
+ case "usage-record:list":
1200
+ return listUsageRecordsForSubscriptionItem(http, requireParent(args, "subscription-item"));
1201
+ case "usage-record:create":
1202
+ return createUsageRecord(http, requireBody(args));
1203
+ case "discount:get":
1204
+ return getDiscount(http, requireId(args, "discount"));
1205
+ case "discount:list":
1206
+ return listDiscountsForStore(http, requireStore(args));
1207
+ case "discount:create":
1208
+ return createDiscount(http, requireBody(args));
1209
+ case "discount:delete":
1210
+ await deleteDiscount(http, requireId(args, "discount"));
1211
+ return void 0;
1212
+ case "discount-redemption:get":
1213
+ return getDiscountRedemption(http, requireId(args, "discount-redemption"));
1214
+ case "discount-redemption:list":
1215
+ return listDiscountRedemptionsForDiscount(http, requireParent(args, "discount"));
1216
+ case "license-key:get":
1217
+ return getLicenseKey(http, requireId(args, "license-key"));
1218
+ case "license-key:list":
1219
+ return listLicenseKeysForStore(http, requireStore(args));
1220
+ case "license-key:update":
1221
+ return updateLicenseKey(http, requireId(args, "license-key"), requireBody(args));
1222
+ case "license-key-instance:get":
1223
+ return getLicenseKeyInstance(http, requireId(args, "license-key-instance"));
1224
+ case "license-key-instance:list":
1225
+ return listLicenseKeyInstancesForLicenseKey(http, requireParent(args, "license-key"));
1226
+ case "checkout:get":
1227
+ return getCheckout(http, requireId(args, "checkout"));
1228
+ case "checkout:list":
1229
+ return listCheckoutsForStore(http, requireStore(args));
1230
+ case "checkout:create":
1231
+ return createCheckout(http, requireBody(args));
1232
+ case "webhook:get":
1233
+ return getWebhook(http, requireId(args, "webhook"));
1234
+ case "webhook:list":
1235
+ return listWebhooksForStore(http, requireStore(args));
1236
+ case "webhook:create":
1237
+ return createWebhook(http, requireBody(args));
1238
+ case "webhook:update":
1239
+ return updateWebhook(http, requireId(args, "webhook"), requireBody(args));
1240
+ case "webhook:delete":
1241
+ await deleteWebhook(http, requireId(args, "webhook"));
1242
+ return void 0;
1243
+ case "affiliate:get":
1244
+ return getAffiliate(http, requireId(args, "affiliate"));
1245
+ case "affiliate:list":
1246
+ return listAffiliatesForStore(http, requireStore(args));
1247
+ default:
1248
+ throw new FreshSqueezyError({
1249
+ code: "UNKNOWN_OP",
1250
+ message: `Op registered but not wired: ${key}`
1251
+ });
1252
+ }
1253
+ };
1254
+ var requireId = (args, label) => {
1255
+ if (args.id === void 0 || args.id === "") {
1256
+ throw new FreshSqueezyError({
1257
+ code: "MISSING_ARG",
1258
+ message: `--id is required for this ${label} operation.`
1259
+ });
1260
+ }
1261
+ return args.id;
1262
+ };
1263
+ var requireStore = (args) => {
1264
+ if (args.storeId === void 0 || args.storeId === "") {
1265
+ throw new FreshSqueezyError({
1266
+ code: "MISSING_ARG",
1267
+ message: "--store-ids (or store id) is required for this list operation."
1268
+ });
1269
+ }
1270
+ return args.storeId;
1271
+ };
1272
+ var requireParent = (args, label) => {
1273
+ if (args.parentId === void 0 || args.parentId === "") {
1274
+ throw new FreshSqueezyError({
1275
+ code: "MISSING_ARG",
1276
+ message: `--parent-id (${label} id) is required for this list operation.`
1277
+ });
1278
+ }
1279
+ return args.parentId;
1280
+ };
1281
+ var requireBody = (args) => {
1282
+ if (args.body === void 0) {
1283
+ throw new FreshSqueezyError({
1284
+ code: "MISSING_ARG",
1285
+ message: "A JSON body is required (--body, --body-file, or stdin)."
1286
+ });
1287
+ }
1288
+ return args.body;
1289
+ };
1290
+
1291
+ // src/core/mode.ts
1292
+ var resolveActualMode = (testMode) => {
1293
+ if (testMode === true) return "test";
1294
+ if (testMode === false) return "live";
1295
+ return void 0;
1296
+ };
401
1297
 
402
1298
  // src/validate/rules.ts
403
1299
  var ISSUE_CODES = {
@@ -436,16 +1332,16 @@ var ISSUE_CODES = {
436
1332
  NETWORK_ERROR: "NETWORK_ERROR",
437
1333
  UNKNOWN: "UNKNOWN"
438
1334
  };
439
- function issue(code, severity, message, extras = {}) {
1335
+ var issue = (code, severity, message, extras = {}) => {
440
1336
  const base = { code, severity, message };
441
1337
  if (extras.suggestedFix !== void 0) base.suggestedFix = extras.suggestedFix;
442
1338
  if (extras.context !== void 0) base.context = extras.context;
443
1339
  return base;
444
- }
445
- function isOk(issues) {
1340
+ };
1341
+ var isOk = (issues) => {
446
1342
  return !issues.some((entry) => entry.severity === "error");
447
- }
448
- function buildResult(name, mode, issues, resource, target) {
1343
+ };
1344
+ var buildResult = (name, mode, issues, resource, target) => {
449
1345
  const result = {
450
1346
  name,
451
1347
  ok: isOk(issues),
@@ -455,10 +1351,10 @@ function buildResult(name, mode, issues, resource, target) {
455
1351
  if (resource !== void 0) result.resource = resource;
456
1352
  if (target !== void 0) result.target = target;
457
1353
  return result;
458
- }
1354
+ };
459
1355
 
460
1356
  // src/validate/probe.ts
461
- function mapErrorToIssue(err, mapping = {}) {
1357
+ var mapErrorToIssue = (err, mapping = {}) => {
462
1358
  if (err instanceof FreshSqueezyError) {
463
1359
  if (mapping.unauthorized && (err.status === 401 || err.code === "UNAUTHORIZED")) {
464
1360
  return issue(mapping.unauthorized.code, "error", mapping.unauthorized.message, {
@@ -485,8 +1381,8 @@ function mapErrorToIssue(err, mapping = {}) {
485
1381
  }
486
1382
  const message = err instanceof Error ? err.message : "Unknown error";
487
1383
  return issue(ISSUE_CODES.UNKNOWN, "error", message);
488
- }
489
- async function probeFetch(fetcher, options) {
1384
+ };
1385
+ var probeFetch = async (fetcher, options) => {
490
1386
  return probeCollection(fetcher, {
491
1387
  notFound: {
492
1388
  code: options.notFoundCode,
@@ -495,15 +1391,15 @@ async function probeFetch(fetcher, options) {
495
1391
  ...options.notFoundContext !== void 0 ? { context: options.notFoundContext } : {}
496
1392
  }
497
1393
  });
498
- }
499
- async function probeCollection(fetcher, mapping = {}) {
1394
+ };
1395
+ var probeCollection = async (fetcher, mapping = {}) => {
500
1396
  try {
501
1397
  return { ok: true, resource: await fetcher() };
502
1398
  } catch (err) {
503
1399
  return { ok: false, issue: mapErrorToIssue(err, mapping) };
504
1400
  }
505
- }
506
- function checkStoreOwnership(check) {
1401
+ };
1402
+ var checkStoreOwnership = (check) => {
507
1403
  const expected = String(check.expectedStoreId);
508
1404
  const actual = String(check.actualStoreId);
509
1405
  if (expected === actual) return null;
@@ -521,10 +1417,10 @@ function checkStoreOwnership(check) {
521
1417
  context
522
1418
  }
523
1419
  );
524
- }
1420
+ };
525
1421
 
526
1422
  // src/validate/connection.ts
527
- async function validateConnection(http, mode) {
1423
+ var validateConnection = async (http, mode) => {
528
1424
  const issues = [];
529
1425
  const fetched = await probeCollection(
530
1426
  async () => {
@@ -577,15 +1473,10 @@ async function validateConnection(http, mode) {
577
1473
  );
578
1474
  }
579
1475
  return buildResult("connection", mode, issues, summary);
580
- }
581
-
582
- // src/resources/discounts.ts
583
- async function getDiscount(http, discountId) {
584
- return http.getResource(`/v1/discounts/${discountId}`);
585
- }
1476
+ };
586
1477
 
587
1478
  // src/validate/discount.ts
588
- async function validateDiscount(http, mode, options) {
1479
+ var validateDiscount = async (http, mode, options) => {
589
1480
  const issues = [];
590
1481
  const fetched = await probeFetch(() => getDiscount(http, options.discountId), {
591
1482
  notFoundCode: ISSUE_CODES.DISCOUNT_NOT_FOUND,
@@ -606,8 +1497,8 @@ async function validateDiscount(http, mode, options) {
606
1497
  label: `${attrs.name} (${attrs.code})`,
607
1498
  id: String(options.discountId)
608
1499
  });
609
- }
610
- function checkDiscount(attrs, options) {
1500
+ };
1501
+ var checkDiscount = (attrs, options) => {
611
1502
  const issues = [];
612
1503
  const mismatch = checkStoreOwnership({
613
1504
  expectedStoreId: options.storeId,
@@ -696,15 +1587,10 @@ function checkDiscount(attrs, options) {
696
1587
  );
697
1588
  }
698
1589
  return issues;
699
- }
700
-
701
- // src/resources/licenseKeys.ts
702
- async function getLicenseKey(http, licenseKeyId) {
703
- return http.getResource(`/v1/license-keys/${licenseKeyId}`);
704
- }
1590
+ };
705
1591
 
706
1592
  // src/validate/licenseKey.ts
707
- async function validateLicenseKey(http, mode, options) {
1593
+ var validateLicenseKey = async (http, mode, options) => {
708
1594
  const issues = [];
709
1595
  const fetched = await probeFetch(() => getLicenseKey(http, options.licenseKeyId), {
710
1596
  notFoundCode: ISSUE_CODES.LICENSE_KEY_NOT_FOUND,
@@ -725,8 +1611,8 @@ async function validateLicenseKey(http, mode, options) {
725
1611
  label: attrs.key_short,
726
1612
  id: String(options.licenseKeyId)
727
1613
  });
728
- }
729
- function checkLicenseKey(attrs, options) {
1614
+ };
1615
+ var checkLicenseKey = (attrs, options) => {
730
1616
  const issues = [];
731
1617
  const mismatch = checkStoreOwnership({
732
1618
  expectedStoreId: options.storeId,
@@ -780,25 +1666,10 @@ function checkLicenseKey(attrs, options) {
780
1666
  );
781
1667
  }
782
1668
  return issues;
783
- }
784
-
785
- // src/resources/products.ts
786
- async function getProduct(http, productId) {
787
- return http.getResource(`/v1/products/${productId}`);
788
- }
789
-
790
- // src/resources/variants.ts
791
- async function getVariant(http, variantId) {
792
- return http.getResource(`/v1/variants/${variantId}`);
793
- }
794
- async function listVariantsForProduct(http, productId) {
795
- return http.paginate("/v1/variants", {
796
- "filter[product_id]": String(productId)
797
- });
798
- }
1669
+ };
799
1670
 
800
1671
  // src/validate/product.ts
801
- async function validateProduct(http, mode, options) {
1672
+ var validateProduct = async (http, mode, options) => {
802
1673
  const issues = [];
803
1674
  const fetched = await probeFetch(() => getProduct(http, options.productId), {
804
1675
  notFoundCode: ISSUE_CODES.PRODUCT_NOT_FOUND,
@@ -844,8 +1715,8 @@ async function validateProduct(http, mode, options) {
844
1715
  label: attrs.name,
845
1716
  id: String(options.productId)
846
1717
  });
847
- }
848
- function checkProduct(attrs, options = {}) {
1718
+ };
1719
+ var checkProduct = (attrs, options = {}) => {
849
1720
  const issues = [];
850
1721
  if (options.expectedStoreId !== void 0) {
851
1722
  const mismatch = checkStoreOwnership({
@@ -881,10 +1752,10 @@ function checkProduct(attrs, options = {}) {
881
1752
  );
882
1753
  }
883
1754
  return issues;
884
- }
1755
+ };
885
1756
 
886
1757
  // src/validate/store.ts
887
- async function validateStore(http, mode, storeId) {
1758
+ var validateStore = async (http, mode, storeId) => {
888
1759
  const issues = [];
889
1760
  const fetched = await probeFetch(() => getStore(http, storeId), {
890
1761
  notFoundCode: ISSUE_CODES.STORE_NOT_FOUND,
@@ -903,11 +1774,11 @@ async function validateStore(http, mode, storeId) {
903
1774
  label: fetched.resource.attributes.name,
904
1775
  id: String(storeId)
905
1776
  });
906
- }
1777
+ };
907
1778
 
908
1779
  // src/validate/subscriptionPlan.ts
909
1780
  var VALID_INTERVALS = /* @__PURE__ */ new Set(["day", "week", "month", "year"]);
910
- async function validateSubscriptionPlan(http, mode, options) {
1781
+ var validateSubscriptionPlan = async (http, mode, options) => {
911
1782
  const issues = [];
912
1783
  const fetched = await probeFetch(
913
1784
  () => getVariant(http, options.variantId),
@@ -953,8 +1824,8 @@ async function validateSubscriptionPlan(http, mode, options) {
953
1824
  label: attrs.name,
954
1825
  id: String(options.variantId)
955
1826
  });
956
- }
957
- function checkSubscriptionPlan(attrs, options) {
1827
+ };
1828
+ var checkSubscriptionPlan = (attrs, options) => {
958
1829
  const issues = [];
959
1830
  if (!attrs.is_subscription) {
960
1831
  issues.push(
@@ -1038,22 +1909,15 @@ function checkSubscriptionPlan(attrs, options) {
1038
1909
  );
1039
1910
  }
1040
1911
  return issues;
1041
- }
1912
+ };
1042
1913
 
1043
1914
  // src/core/equality.ts
1044
- function sameWebhookUrl(a, b) {
1915
+ var sameWebhookUrl = (a, b) => {
1045
1916
  return normalizeWebhookUrl(a) === normalizeWebhookUrl(b);
1046
- }
1047
- function normalizeWebhookUrl(raw) {
1917
+ };
1918
+ var normalizeWebhookUrl = (raw) => {
1048
1919
  return raw.replace(/\/+$/, "").toLowerCase();
1049
- }
1050
-
1051
- // src/resources/webhooks.ts
1052
- async function listWebhooksForStore(http, storeId) {
1053
- return http.paginate("/v1/webhooks", {
1054
- "filter[store_id]": String(storeId)
1055
- });
1056
- }
1920
+ };
1057
1921
 
1058
1922
  // src/support/manifest.ts
1059
1923
  var RECOMMENDED_WEBHOOK_EVENTS = [
@@ -1075,7 +1939,7 @@ var OPTIONAL_WEBHOOK_EVENTS = [
1075
1939
  ];
1076
1940
 
1077
1941
  // src/validate/webhook.ts
1078
- async function validateWebhook(http, mode, options) {
1942
+ var validateWebhook = async (http, mode, options) => {
1079
1943
  const issues = [];
1080
1944
  const fetched = await probeCollection(() => listWebhooksForStore(http, options.storeId));
1081
1945
  if (!fetched.ok) {
@@ -1135,7 +1999,7 @@ async function validateWebhook(http, mode, options) {
1135
1999
  id: match.id,
1136
2000
  url: match.attributes.url
1137
2001
  });
1138
- }
2002
+ };
1139
2003
 
1140
2004
  // src/validate/doctor.ts
1141
2005
  var DEFAULT_VALIDATORS = {
@@ -1147,7 +2011,7 @@ var DEFAULT_VALIDATORS = {
1147
2011
  licenseKey: validateLicenseKey,
1148
2012
  subscriptionPlan: validateSubscriptionPlan
1149
2013
  };
1150
- async function doctor(http, mode, options = {}, validators = DEFAULT_VALIDATORS) {
2014
+ var doctor = async (http, mode, options = {}, validators = DEFAULT_VALIDATORS) => {
1151
2015
  assertOptionsCoherent(options);
1152
2016
  const results = [];
1153
2017
  const productIds = collectValues(options.productId, options.productIds);
@@ -1213,8 +2077,8 @@ async function doctor(http, mode, options = {}, validators = DEFAULT_VALIDATORS)
1213
2077
  }
1214
2078
  const ok = results.every((result) => result.ok);
1215
2079
  return { ok, mode, results };
1216
- }
1217
- function assertOptionsCoherent(options) {
2080
+ };
2081
+ var assertOptionsCoherent = (options) => {
1218
2082
  if (options.storeId !== void 0) return;
1219
2083
  const dependent = [];
1220
2084
  if (hasAny(options.webhookUrl, options.webhookUrls)) dependent.push("webhookUrl");
@@ -1226,23 +2090,24 @@ function assertOptionsCoherent(options) {
1226
2090
  code: "DOCTOR_OPTIONS_INVALID",
1227
2091
  message: `doctor() received ${dependent.join(", ")} without storeId. These validators cannot run without a store; pass \`storeId\` or remove the dependent options.`
1228
2092
  });
1229
- }
1230
- function collectValues(single, many) {
2093
+ };
2094
+ var collectValues = (single, many) => {
1231
2095
  const values2 = /* @__PURE__ */ new Set();
1232
2096
  if (single !== void 0) values2.add(single);
1233
2097
  for (const value of many ?? []) {
1234
2098
  if (value !== void 0) values2.add(value);
1235
2099
  }
1236
2100
  return Array.from(values2);
1237
- }
1238
- function hasAny(single, many) {
2101
+ };
2102
+ var hasAny = (single, many) => {
1239
2103
  return single !== void 0 || (many?.length ?? 0) > 0;
1240
- }
2104
+ };
1241
2105
 
1242
2106
  // src/createFreshSqueezy.ts
1243
- function createFreshSqueezy(config = {}) {
2107
+ var createFreshSqueezy = (config = {}) => {
1244
2108
  const resolved = resolveConfig(config);
1245
2109
  const http = new HttpClient(resolved);
2110
+ const op = (resource, verb, args = {}) => invokeOp(http, resource, verb, args);
1246
2111
  return {
1247
2112
  mode: resolved.mode,
1248
2113
  request: (options) => http.request(options),
@@ -1265,12 +2130,109 @@ function createFreshSqueezy(config = {}) {
1265
2130
  licenseKeyIds: options?.licenseKeyIds,
1266
2131
  variantId: options?.variantId,
1267
2132
  variantIds: options?.variantIds
1268
- })
2133
+ }),
2134
+ users: {
2135
+ me: () => op("user", "get")
2136
+ },
2137
+ stores: {
2138
+ get: (id) => op("store", "get", { id }),
2139
+ list: () => op("store", "list")
2140
+ },
2141
+ products: {
2142
+ get: (id) => op("product", "get", { id }),
2143
+ list: (storeId) => op("product", "list", { storeId })
2144
+ },
2145
+ variants: {
2146
+ get: (id) => op("variant", "get", { id }),
2147
+ list: (productId) => op("variant", "list", { parentId: productId })
2148
+ },
2149
+ prices: {
2150
+ get: (id) => op("price", "get", { id }),
2151
+ list: (variantId) => op("price", "list", { parentId: variantId })
2152
+ },
2153
+ files: {
2154
+ get: (id) => op("file", "get", { id }),
2155
+ list: (variantId) => op("file", "list", { parentId: variantId })
2156
+ },
2157
+ customers: {
2158
+ get: (id) => op("customer", "get", { id }),
2159
+ list: (storeId) => op("customer", "list", { storeId }),
2160
+ create: (body) => op("customer", "create", { body }),
2161
+ update: (id, body) => op("customer", "update", { id, body })
2162
+ },
2163
+ orders: {
2164
+ get: (id) => op("order", "get", { id }),
2165
+ list: (storeId) => op("order", "list", { storeId }),
2166
+ refund: (id, body) => op("order", "refund", { id, body }),
2167
+ generateInvoice: (id, body) => op("order", "generate-invoice", { id, body })
2168
+ },
2169
+ orderItems: {
2170
+ get: (id) => op("order-item", "get", { id }),
2171
+ list: (orderId) => op("order-item", "list", { parentId: orderId })
2172
+ },
2173
+ subscriptions: {
2174
+ get: (id) => op("subscription", "get", { id }),
2175
+ list: (storeId) => op("subscription", "list", { storeId }),
2176
+ update: (id, body) => op("subscription", "update", { id, body }),
2177
+ cancel: (id) => op("subscription", "cancel", { id })
2178
+ },
2179
+ subscriptionItems: {
2180
+ get: (id) => op("subscription-item", "get", { id }),
2181
+ list: (subscriptionId) => op("subscription-item", "list", { parentId: subscriptionId }),
2182
+ update: (id, body) => op("subscription-item", "update", { id, body }),
2183
+ currentUsage: (id) => op("subscription-item", "current-usage", { id })
2184
+ },
2185
+ subscriptionInvoices: {
2186
+ get: (id) => op("subscription-invoice", "get", { id }),
2187
+ list: (subscriptionId) => op("subscription-invoice", "list", { parentId: subscriptionId }),
2188
+ refund: (id, body) => op("subscription-invoice", "refund", { id, body }),
2189
+ generateInvoice: (id, body) => op("subscription-invoice", "generate-invoice", { id, body })
2190
+ },
2191
+ usageRecords: {
2192
+ get: (id) => op("usage-record", "get", { id }),
2193
+ list: (subscriptionItemId) => op("usage-record", "list", { parentId: subscriptionItemId }),
2194
+ create: (body) => op("usage-record", "create", { body })
2195
+ },
2196
+ discounts: {
2197
+ get: (id) => op("discount", "get", { id }),
2198
+ list: (storeId) => op("discount", "list", { storeId }),
2199
+ create: (body) => op("discount", "create", { body }),
2200
+ delete: (id) => op("discount", "delete", { id })
2201
+ },
2202
+ discountRedemptions: {
2203
+ get: (id) => op("discount-redemption", "get", { id }),
2204
+ list: (discountId) => op("discount-redemption", "list", { parentId: discountId })
2205
+ },
2206
+ licenseKeys: {
2207
+ get: (id) => op("license-key", "get", { id }),
2208
+ list: (storeId) => op("license-key", "list", { storeId }),
2209
+ update: (id, body) => op("license-key", "update", { id, body })
2210
+ },
2211
+ licenseKeyInstances: {
2212
+ get: (id) => op("license-key-instance", "get", { id }),
2213
+ list: (licenseKeyId) => op("license-key-instance", "list", { parentId: licenseKeyId })
2214
+ },
2215
+ checkouts: {
2216
+ get: (id) => op("checkout", "get", { id }),
2217
+ list: (storeId) => op("checkout", "list", { storeId }),
2218
+ create: (body) => op("checkout", "create", { body })
2219
+ },
2220
+ webhooks: {
2221
+ get: (id) => op("webhook", "get", { id }),
2222
+ list: (storeId) => op("webhook", "list", { storeId }),
2223
+ create: (body) => op("webhook", "create", { body }),
2224
+ update: (id, body) => op("webhook", "update", { id, body }),
2225
+ delete: (id) => op("webhook", "delete", { id })
2226
+ },
2227
+ affiliates: {
2228
+ get: (id) => op("affiliate", "get", { id }),
2229
+ list: (storeId) => op("affiliate", "list", { storeId })
2230
+ }
1269
2231
  };
1270
- }
2232
+ };
1271
2233
 
1272
2234
  // src/cli/errors.ts
1273
- function renderCliError(message, hints = []) {
2235
+ var renderCliError = (message, hints = []) => {
1274
2236
  const lines = [`fresh-squeezy: ${message}`];
1275
2237
  if (hints.length > 0) {
1276
2238
  lines.push("", "Try:");
@@ -1280,8 +2242,8 @@ function renderCliError(message, hints = []) {
1280
2242
  }
1281
2243
  return `${lines.join("\n")}
1282
2244
  `;
1283
- }
1284
- function getDoctorHints(err) {
2245
+ };
2246
+ var getDoctorHints = (err) => {
1285
2247
  if (!isFreshSqueezyError(err)) return [];
1286
2248
  if (err.code === "MISSING_API_KEY") {
1287
2249
  return ["fresh-squeezy init", `export ${ENV_KEYS.apiKey}=ls_live_or_test_key`];
@@ -1293,8 +2255,8 @@ function getDoctorHints(err) {
1293
2255
  return ["Check that the API key belongs to an account with a Lemon Squeezy store."];
1294
2256
  }
1295
2257
  return [];
1296
- }
1297
- function getValidateHints(err, target) {
2258
+ };
2259
+ var getValidateHints = (err, target) => {
1298
2260
  if (!isFreshSqueezyError(err)) return [];
1299
2261
  if (err.code === "MISSING_API_KEY") {
1300
2262
  return ["fresh-squeezy init", `export ${ENV_KEYS.apiKey}=ls_live_or_test_key`];
@@ -1309,8 +2271,8 @@ function getValidateHints(err, target) {
1309
2271
  return getMissingArgHints(target);
1310
2272
  }
1311
2273
  return [];
1312
- }
1313
- function getMissingArgHints(target) {
2274
+ };
2275
+ var getMissingArgHints = (target) => {
1314
2276
  if (target === "connection") {
1315
2277
  return ["fresh-squeezy validate connection"];
1316
2278
  }
@@ -1336,14 +2298,14 @@ function getMissingArgHints(target) {
1336
2298
  return ["fresh-squeezy validate license-key --store-ids 12 --license-key-id 123"];
1337
2299
  }
1338
2300
  return ["fresh-squeezy validate subscription-plan --store-ids 12 --variant-id 123"];
1339
- }
1340
- function isFreshSqueezyError(err) {
2301
+ };
2302
+ var isFreshSqueezyError = (err) => {
1341
2303
  return err instanceof FreshSqueezyError;
1342
- }
2304
+ };
1343
2305
 
1344
2306
  // src/cli/render.ts
1345
2307
  import chalk from "chalk";
1346
- function renderResult(result) {
2308
+ var renderResult = (result) => {
1347
2309
  const lines = [];
1348
2310
  const badge = result.ok ? chalk.green("PASS") : chalk.red("FAIL");
1349
2311
  const mode = chalk.dim(`[${result.mode}]`);
@@ -1357,15 +2319,15 @@ function renderResult(result) {
1357
2319
  }
1358
2320
  }
1359
2321
  return lines.join("\n");
1360
- }
1361
- function renderTarget(target) {
2322
+ };
2323
+ var renderTarget = (target) => {
1362
2324
  if (!target) return "";
1363
2325
  const parts = [target.label];
1364
2326
  if (target.id) parts.push(`id ${target.id}`);
1365
2327
  if (target.url && target.url !== target.label) parts.push(target.url);
1366
2328
  return parts.join(" - ");
1367
- }
1368
- function renderReport(report) {
2329
+ };
2330
+ var renderReport = (report) => {
1369
2331
  const header = report.ok ? chalk.green.bold("fresh-squeezy doctor: OK") : chalk.red.bold("fresh-squeezy doctor: FAILED");
1370
2332
  const failed = report.results.filter((result) => !result.ok).length;
1371
2333
  const summary = failed === 0 ? chalk.dim(`${report.results.length} checks passed`) : chalk.dim(`${failed}/${report.results.length} checks failed`);
@@ -1374,11 +2336,11 @@ function renderReport(report) {
1374
2336
  ${summary}
1375
2337
 
1376
2338
  ${body}`;
1377
- }
1378
- function renderIssueLine(issue2) {
2339
+ };
2340
+ var renderIssueLine = (issue2) => {
1379
2341
  const label = issue2.severity === "error" ? chalk.red("\u2717 error") : issue2.severity === "warning" ? chalk.yellow("! warn ") : chalk.blue("i info ");
1380
2342
  return `${label} ${chalk.gray(`[${issue2.code}]`)} ${issue2.message}`;
1381
- }
2343
+ };
1382
2344
 
1383
2345
  // src/cli/prompts.ts
1384
2346
  import path from "path";
@@ -1392,7 +2354,7 @@ var EMPTY_INIT_RESOURCE_CHOICES = {
1392
2354
  licenseKeys: { choices: [] },
1393
2355
  subscriptionPlans: { choices: [] }
1394
2356
  };
1395
- async function discoverInitResourceChoices(client, storeId, targets) {
2357
+ var discoverInitResourceChoices = async (client, storeId, targets) => {
1396
2358
  const choices = {
1397
2359
  products: { choices: [] },
1398
2360
  webhooks: { choices: [] },
@@ -1439,8 +2401,8 @@ async function discoverInitResourceChoices(client, storeId, targets) {
1439
2401
  }
1440
2402
  }
1441
2403
  return choices;
1442
- }
1443
- async function discoverSubscriptionPlans(client, products) {
2404
+ };
2405
+ var discoverSubscriptionPlans = async (client, products) => {
1444
2406
  const discovered = [];
1445
2407
  for (const product of products) {
1446
2408
  const result = await discover(
@@ -1458,8 +2420,8 @@ async function discoverSubscriptionPlans(client, products) {
1458
2420
  }
1459
2421
  }
1460
2422
  return { choices: discovered };
1461
- }
1462
- async function paginate(client, path4, query) {
2423
+ };
2424
+ var paginate = async (client, path4, query) => {
1463
2425
  const all = [];
1464
2426
  let pageNumber = Number(query?.["page[number]"] ?? 1);
1465
2427
  while (true) {
@@ -1472,45 +2434,45 @@ async function paginate(client, path4, query) {
1472
2434
  if (lastPage === void 0 || pageNumber >= lastPage) return all;
1473
2435
  pageNumber += 1;
1474
2436
  }
1475
- }
1476
- async function discover(load) {
2437
+ };
2438
+ var discover = async (load) => {
1477
2439
  try {
1478
2440
  return { ok: true, value: await load() };
1479
2441
  } catch (err) {
1480
2442
  return { ok: false, error: err instanceof Error ? err.message : String(err) };
1481
2443
  }
1482
- }
1483
- function toProductChoice(product) {
2444
+ };
2445
+ var toProductChoice = (product) => {
1484
2446
  return {
1485
2447
  value: product.id,
1486
2448
  label: `${product.attributes.name} (${product.attributes.status}) - id ${product.id}`
1487
2449
  };
1488
- }
1489
- function toWebhookChoice(webhook) {
2450
+ };
2451
+ var toWebhookChoice = (webhook) => {
1490
2452
  return {
1491
2453
  value: webhook.attributes.url,
1492
2454
  label: `${webhook.attributes.url} - id ${webhook.id}`
1493
2455
  };
1494
- }
1495
- function toDiscountChoice(discount) {
2456
+ };
2457
+ var toDiscountChoice = (discount) => {
1496
2458
  return {
1497
2459
  value: discount.id,
1498
2460
  label: `${discount.attributes.name} (${discount.attributes.code}) - id ${discount.id}`
1499
2461
  };
1500
- }
1501
- function toLicenseKeyChoice(licenseKey) {
2462
+ };
2463
+ var toLicenseKeyChoice = (licenseKey) => {
1502
2464
  return {
1503
2465
  value: licenseKey.id,
1504
2466
  label: `${licenseKey.attributes.key_short} (${licenseKey.attributes.status}) - id ${licenseKey.id}`
1505
2467
  };
1506
- }
1507
- function toSubscriptionPlanChoice(variant, productName) {
2468
+ };
2469
+ var toSubscriptionPlanChoice = (variant, productName) => {
1508
2470
  const interval = variant.attributes.interval ? `${variant.attributes.interval_count ?? 1}/${variant.attributes.interval}` : "no interval";
1509
2471
  return {
1510
2472
  value: variant.id,
1511
2473
  label: `${productName} / ${variant.attributes.name} (${interval}) - id ${variant.id}`
1512
2474
  };
1513
- }
2475
+ };
1514
2476
 
1515
2477
  // src/cli/prompts.ts
1516
2478
  var PROMPT_THEME = {
@@ -1519,7 +2481,7 @@ var PROMPT_THEME = {
1519
2481
  done: "\u2713"
1520
2482
  }
1521
2483
  };
1522
- async function pickLauncherAction() {
2484
+ var pickLauncherAction = async () => {
1523
2485
  return select({
1524
2486
  message: "What do you want to do?",
1525
2487
  theme: PROMPT_THEME,
@@ -1542,8 +2504,8 @@ async function pickLauncherAction() {
1542
2504
  }
1543
2505
  ]
1544
2506
  });
1545
- }
1546
- async function askForApiKey() {
2507
+ };
2508
+ var askForApiKey = async () => {
1547
2509
  const apiKey = await password({
1548
2510
  message: "Paste your Lemon Squeezy API key:",
1549
2511
  mask: false,
@@ -1551,8 +2513,8 @@ async function askForApiKey() {
1551
2513
  validate: (value) => value.trim().length > 0 ? true : "API key is required."
1552
2514
  });
1553
2515
  return { apiKey: apiKey.trim() };
1554
- }
1555
- async function pickStore(choices) {
2516
+ };
2517
+ var pickStore = async (choices) => {
1556
2518
  return select({
1557
2519
  message: "Pick a store to validate against:",
1558
2520
  theme: PROMPT_THEME,
@@ -1561,8 +2523,8 @@ async function pickStore(choices) {
1561
2523
  value: entry.id
1562
2524
  }))
1563
2525
  });
1564
- }
1565
- async function pickStores(choices) {
2526
+ };
2527
+ var pickStores = async (choices) => {
1566
2528
  return checkbox({
1567
2529
  message: "Pick one or more stores (space to toggle, enter to confirm):",
1568
2530
  theme: PROMPT_THEME,
@@ -1573,8 +2535,8 @@ async function pickStores(choices) {
1573
2535
  })),
1574
2536
  validate: (selected) => selected.length > 0 ? true : "Pick at least one store."
1575
2537
  });
1576
- }
1577
- async function selectDoctorTargets() {
2538
+ };
2539
+ var selectDoctorTargets = async () => {
1578
2540
  return checkbox({
1579
2541
  message: "Add resource checks to this doctor run?",
1580
2542
  theme: PROMPT_THEME,
@@ -1586,8 +2548,8 @@ async function selectDoctorTargets() {
1586
2548
  { name: "Subscription plan", value: "subscription-plan" }
1587
2549
  ]
1588
2550
  });
1589
- }
1590
- async function askForDoctorTargetValues(targets, choices = EMPTY_INIT_RESOURCE_CHOICES) {
2551
+ };
2552
+ var askForDoctorTargetValues = async (targets, choices = EMPTY_INIT_RESOURCE_CHOICES) => {
1591
2553
  if (targets.length === 0) return {};
1592
2554
  const answers = {};
1593
2555
  const manualQuestions = [];
@@ -1665,22 +2627,29 @@ async function askForDoctorTargetValues(targets, choices = EMPTY_INIT_RESOURCE_C
1665
2627
  licenseKeyIds: cleanList(answers.licenseKeyIds),
1666
2628
  variantIds: cleanList(answers.variantIds)
1667
2629
  };
1668
- }
1669
- async function confirmLiveModeRun() {
2630
+ };
2631
+ var confirmLiveModeRun = async () => {
1670
2632
  return confirm({
1671
2633
  message: "This is a live-mode key. Continue with live checks?",
1672
2634
  default: false,
1673
2635
  theme: PROMPT_THEME
1674
2636
  });
1675
- }
1676
- async function confirmWriteEnvFile(filePath) {
2637
+ };
2638
+ var confirmWriteEnvFile = async (filePath) => {
1677
2639
  return confirm({
1678
2640
  message: `Write these values to ${formatPromptPath(filePath)}?`,
1679
2641
  default: true,
1680
2642
  theme: PROMPT_THEME
1681
2643
  });
1682
- }
1683
- async function resolveTargetValue(input2) {
2644
+ };
2645
+ var confirmResourceOp = async (message) => {
2646
+ return confirm({
2647
+ message,
2648
+ default: false,
2649
+ theme: PROMPT_THEME
2650
+ });
2651
+ };
2652
+ var resolveTargetValue = async (input2) => {
1684
2653
  if (input2.group.choices.length === 0) {
1685
2654
  input2.manualQuestions.push({
1686
2655
  field: input2.field,
@@ -1709,8 +2678,8 @@ async function resolveTargetValue(input2) {
1709
2678
  validate: input2.validate
1710
2679
  });
1711
2680
  }
1712
- }
1713
- async function askEmptyTargetAction(message) {
2681
+ };
2682
+ var askEmptyTargetAction = async (message) => {
1714
2683
  return select({
1715
2684
  message,
1716
2685
  theme: PROMPT_THEME,
@@ -1719,18 +2688,18 @@ async function askEmptyTargetAction(message) {
1719
2688
  { name: "Skip this check", value: "skip" }
1720
2689
  ]
1721
2690
  });
1722
- }
1723
- function required(label) {
2691
+ };
2692
+ var required = (label) => {
1724
2693
  return (value) => value.trim().length > 0 ? true : `${label} is required.`;
1725
- }
1726
- function optional(label) {
2694
+ };
2695
+ var optional = (label) => {
1727
2696
  return (value) => {
1728
2697
  const trimmed = value.trim();
1729
2698
  if (trimmed.length === 0) return true;
1730
2699
  return required(label)(trimmed);
1731
2700
  };
1732
- }
1733
- function validateWebhookUrl(value) {
2701
+ };
2702
+ var validateWebhookUrl = (value) => {
1734
2703
  const trimmed = value.trim();
1735
2704
  if (trimmed.length === 0) return "Webhook URL is required.";
1736
2705
  try {
@@ -1739,32 +2708,32 @@ function validateWebhookUrl(value) {
1739
2708
  } catch {
1740
2709
  return "Enter a valid webhook URL.";
1741
2710
  }
1742
- }
1743
- function optionalWebhookUrls(value) {
2711
+ };
2712
+ var optionalWebhookUrls = (value) => {
1744
2713
  const values2 = splitManualValues(value);
1745
2714
  if (values2.length === 0) return true;
1746
2715
  return values2.every((entry) => validateWebhookUrl(entry) === true) ? true : "Enter valid webhook URLs.";
1747
- }
1748
- function cleanList(value) {
2716
+ };
2717
+ var cleanList = (value) => {
1749
2718
  const values2 = Array.isArray(value) ? value : splitManualValues(value);
1750
2719
  const cleanValues = Array.from(new Set(values2.map((entry) => entry.trim()).filter(Boolean)));
1751
2720
  return cleanValues.length > 0 ? cleanValues : void 0;
1752
- }
1753
- function splitManualValues(value) {
2721
+ };
2722
+ var splitManualValues = (value) => {
1754
2723
  return (value ?? "").split(",").map((entry) => entry.trim()).filter(Boolean);
1755
- }
1756
- function formatPromptPath(filePath) {
2724
+ };
2725
+ var formatPromptPath = (filePath) => {
1757
2726
  const relative = path.relative(process.cwd(), filePath);
1758
2727
  if (relative && !relative.startsWith("..") && !path.isAbsolute(relative)) return relative;
1759
2728
  return path.basename(filePath);
1760
- }
1761
- function isPromptCancel(error) {
2729
+ };
2730
+ var isPromptCancel = (error) => {
1762
2731
  if (!(error instanceof Error)) return false;
1763
2732
  return error.name === "ExitPromptError" || error.message.includes("User force closed");
1764
- }
2733
+ };
1765
2734
 
1766
2735
  // src/cli/resolveStores.ts
1767
- async function resolveStores(client, input2) {
2736
+ var resolveStores = async (client, input2) => {
1768
2737
  if (input2.storeIds && input2.storeIds.length > 0) {
1769
2738
  return { storeIds: dedupe(input2.storeIds), skipped: false };
1770
2739
  }
@@ -1809,8 +2778,8 @@ async function resolveStores(client, input2) {
1809
2778
  });
1810
2779
  }
1811
2780
  return { storeIds: picked, skipped: false };
1812
- }
1813
- async function fetchReachableStoreIds(client) {
2781
+ };
2782
+ var fetchReachableStoreIds = async (client) => {
1814
2783
  const connection = await client.validateConnection();
1815
2784
  if (!connection.ok) {
1816
2785
  const authIssue = connection.issues.find((entry) => entry.code === "AUTH_FAILED");
@@ -1822,10 +2791,10 @@ async function fetchReachableStoreIds(client) {
1822
2791
  }
1823
2792
  }
1824
2793
  return connection.resource?.storeIds ?? [];
1825
- }
1826
- function dedupe(values2) {
2794
+ };
2795
+ var dedupe = (values2) => {
1827
2796
  return Array.from(new Set(values2.map((value) => value.trim()).filter(Boolean)));
1828
- }
2797
+ };
1829
2798
 
1830
2799
  // src/cli/commands/doctor.ts
1831
2800
  var ALL_RESOURCE_TARGETS = [
@@ -1835,7 +2804,7 @@ var ALL_RESOURCE_TARGETS = [
1835
2804
  "license-key",
1836
2805
  "subscription-plan"
1837
2806
  ];
1838
- async function runDoctorCommand(options) {
2807
+ var runDoctorCommand = async (options) => {
1839
2808
  try {
1840
2809
  const client = createFreshSqueezy({ mode: options.mode });
1841
2810
  const resolved = await resolveStores(client, {
@@ -1874,8 +2843,8 @@ async function runDoctorCommand(options) {
1874
2843
  writeFatal(err, options.json ?? false);
1875
2844
  return 2;
1876
2845
  }
1877
- }
1878
- async function resolveDoctorTargets(client, storeId, options) {
2846
+ };
2847
+ var resolveDoctorTargets = async (client, storeId, options) => {
1879
2848
  const explicit = {
1880
2849
  productIds: one(options.productId),
1881
2850
  webhookUrls: one(options.webhookUrl),
@@ -1899,8 +2868,8 @@ async function resolveDoctorTargets(client, storeId, options) {
1899
2868
  licenseKeyIds: mergeValues(explicit.licenseKeyIds, values(discovered.licenseKeys)),
1900
2869
  variantIds: mergeValues(explicit.variantIds, values(discovered.subscriptionPlans))
1901
2870
  };
1902
- }
1903
- function formatDiscoveryCounts(choices) {
2871
+ };
2872
+ var formatDiscoveryCounts = (choices) => {
1904
2873
  return [
1905
2874
  countLabel("products", choices.products.choices.length),
1906
2875
  countLabel("webhooks", choices.webhooks.choices.length),
@@ -1908,11 +2877,11 @@ function formatDiscoveryCounts(choices) {
1908
2877
  countLabel("license keys", choices.licenseKeys.choices.length),
1909
2878
  countLabel("subscription plans", choices.subscriptionPlans.choices.length)
1910
2879
  ].join(", ");
1911
- }
1912
- function countLabel(label, count) {
2880
+ };
2881
+ var countLabel = (label, count) => {
1913
2882
  return `${label} ${count}`;
1914
- }
1915
- function reportDiscoveryErrors(choices) {
2883
+ };
2884
+ var reportDiscoveryErrors = (choices) => {
1916
2885
  const errors = [
1917
2886
  choices.products.error && `products: ${choices.products.error}`,
1918
2887
  choices.webhooks.error && `webhooks: ${choices.webhooks.error}`,
@@ -1924,23 +2893,23 @@ function reportDiscoveryErrors(choices) {
1924
2893
  process.stderr.write(`fresh-squeezy: discovery skipped ${error}
1925
2894
  `);
1926
2895
  }
1927
- }
1928
- function values(group) {
2896
+ };
2897
+ var values = (group) => {
1929
2898
  return group.choices.length > 0 ? group.choices.map((choice) => choice.value) : void 0;
1930
- }
1931
- function one(value) {
2899
+ };
2900
+ var one = (value) => {
1932
2901
  return value ? [value] : void 0;
1933
- }
1934
- function mergeValues(explicit, discovered) {
2902
+ };
2903
+ var mergeValues = (explicit, discovered) => {
1935
2904
  const merged = Array.from(/* @__PURE__ */ new Set([...explicit ?? [], ...discovered ?? []]));
1936
2905
  return merged.length > 0 ? merged : void 0;
1937
- }
1938
- function hasExplicitResourceSelection(options) {
2906
+ };
2907
+ var hasExplicitResourceSelection = (options) => {
1939
2908
  return Boolean(
1940
2909
  options.productId || options.webhookUrl || options.discountId || options.licenseKeyId || options.variantId
1941
2910
  );
1942
- }
1943
- async function runConnectionOnly(client, options) {
2911
+ };
2912
+ var runConnectionOnly = async (client, options) => {
1944
2913
  const connection = await client.validateConnection();
1945
2914
  const report = {
1946
2915
  ok: connection.ok,
@@ -1959,8 +2928,8 @@ async function runConnectionOnly(client, options) {
1959
2928
  `);
1960
2929
  }
1961
2930
  return connection.ok ? 0 : 1;
1962
- }
1963
- function writeFatal(err, asJson) {
2931
+ };
2932
+ var writeFatal = (err, asJson) => {
1964
2933
  if (asJson) {
1965
2934
  const payload = err instanceof FreshSqueezyError ? { ok: false, error: { code: err.code, message: err.message, status: err.status ?? null } } : {
1966
2935
  ok: false,
@@ -1972,7 +2941,7 @@ function writeFatal(err, asJson) {
1972
2941
  }
1973
2942
  const message = err instanceof Error ? err.message : String(err);
1974
2943
  process.stderr.write(renderCliError(message, getDoctorHints(err)));
1975
- }
2944
+ };
1976
2945
 
1977
2946
  // src/cli/commands/init.ts
1978
2947
  import fs from "fs/promises";
@@ -1983,24 +2952,24 @@ import chalk3 from "chalk";
1983
2952
  import chalk2 from "chalk";
1984
2953
  var brand = chalk2.green.bold("fresh-squeezy");
1985
2954
  var divider = chalk2.dim("\u2022");
1986
- function renderBrandHeader(title, subtitle) {
2955
+ var renderBrandHeader = (title, subtitle) => {
1987
2956
  const lines = [`${brand} ${divider} ${chalk2.bold(title)}`];
1988
2957
  if (subtitle) lines.push(chalk2.dim(subtitle));
1989
2958
  lines.push("");
1990
2959
  return lines.join("\n");
1991
- }
1992
- function renderStep(index, total, title, detail) {
2960
+ };
2961
+ var renderStep = (index, total, title, detail) => {
1993
2962
  const suffix = detail ? ` ${chalk2.dim(detail)}` : "";
1994
2963
  const prefix = index > 1 ? "\n" : "";
1995
2964
  return `${prefix}${chalk2.yellow("\u25CF")} ${chalk2.dim(`${index}/${total}`)} ${chalk2.bold(title)}${suffix}
1996
2965
  `;
1997
- }
1998
- function renderDetected(label, value, source) {
2966
+ };
2967
+ var renderDetected = (label, value, source) => {
1999
2968
  const suffix = source ? ` ${chalk2.dim(`from ${source}`)}` : "";
2000
2969
  return ` ${chalk2.green("\u2713")} ${chalk2.bold(label)} ${value}${suffix}
2001
2970
  `;
2002
- }
2003
- function renderCommandExamples() {
2971
+ };
2972
+ var renderCommandExamples = () => {
2004
2973
  return [
2005
2974
  renderBrandHeader("Command examples", "Direct commands stay stable for scripts and CI."),
2006
2975
  `${chalk2.bold("Guided setup")}`,
@@ -2018,14 +2987,14 @@ function renderCommandExamples() {
2018
2987
  " fresh-squeezy doctor --all-stores --json",
2019
2988
  ""
2020
2989
  ].join("\n");
2021
- }
2022
- function renderCancelMessage() {
2990
+ };
2991
+ var renderCancelMessage = () => {
2023
2992
  return `${chalk2.dim("fresh-squeezy cancelled.")}
2024
2993
  `;
2025
- }
2994
+ };
2026
2995
 
2027
2996
  // src/cli/commands/init.ts
2028
- async function runInitCommand(options = {}) {
2997
+ var runInitCommand = async (options = {}) => {
2029
2998
  try {
2030
2999
  return await runInitFlow(options);
2031
3000
  } catch (err) {
@@ -2035,8 +3004,8 @@ async function runInitCommand(options = {}) {
2035
3004
  }
2036
3005
  throw err;
2037
3006
  }
2038
- }
2039
- async function runInitFlow(options) {
3007
+ };
3008
+ var runInitFlow = async (options) => {
2040
3009
  if (options.isInteractive === false) {
2041
3010
  process.stderr.write(
2042
3011
  renderCliError("`fresh-squeezy init` requires an interactive terminal.", [
@@ -2113,8 +3082,8 @@ Running doctor (${checkNames.join(", ")})...
2113
3082
  process.stdout.write(`${renderReport(report)}
2114
3083
  `);
2115
3084
  return report.ok ? 0 : 1;
2116
- }
2117
- async function resolveStoreSelection(pickable) {
3085
+ };
3086
+ var resolveStoreSelection = async (pickable) => {
2118
3087
  if (pickable.length === 1) {
2119
3088
  const store = pickable[0];
2120
3089
  if (!store) throw new Error("Expected one reachable store.");
@@ -2124,8 +3093,8 @@ async function resolveStoreSelection(pickable) {
2124
3093
  return store.id;
2125
3094
  }
2126
3095
  return pickStore(pickable);
2127
- }
2128
- async function discoverChoices(client, storeId, selectedTargets) {
3096
+ };
3097
+ var discoverChoices = async (client, storeId, selectedTargets) => {
2129
3098
  if (selectedTargets.length === 0)
2130
3099
  return {
2131
3100
  products: { choices: [] },
@@ -2135,8 +3104,8 @@ async function discoverChoices(client, storeId, selectedTargets) {
2135
3104
  subscriptionPlans: { choices: [] }
2136
3105
  };
2137
3106
  return discoverInitResourceChoices(client, storeId, selectedTargets);
2138
- }
2139
- async function resolveApiKey() {
3107
+ };
3108
+ var resolveApiKey = async () => {
2140
3109
  const envApiKey = process.env[ENV_KEYS.apiKey]?.trim();
2141
3110
  if (envApiKey) {
2142
3111
  process.stdout.write(chalk3.dim(`Using ${ENV_KEYS.apiKey} from environment.
@@ -2145,8 +3114,8 @@ async function resolveApiKey() {
2145
3114
  }
2146
3115
  const answers = await askForApiKey();
2147
3116
  return answers.apiKey;
2148
- }
2149
- async function createDetectedClient(apiKey) {
3117
+ };
3118
+ var createDetectedClient = async (apiKey) => {
2150
3119
  const envMode = parseEnvMode();
2151
3120
  const initialMode = envMode ?? "test";
2152
3121
  let client = createFreshSqueezy({ apiKey, mode: initialMode });
@@ -2174,8 +3143,8 @@ async function createDetectedClient(apiKey) {
2174
3143
  }
2175
3144
  process.stdout.write(chalk3.dim("Could not auto-detect key mode; using test mode.\n"));
2176
3145
  return { client, mode: initialMode, connection };
2177
- }
2178
- function parseEnvMode() {
3146
+ };
3147
+ var parseEnvMode = () => {
2179
3148
  const value = process.env[ENV_KEYS.mode]?.trim();
2180
3149
  if (value === "test" || value === "live") return value;
2181
3150
  if (value) {
@@ -2185,8 +3154,8 @@ function parseEnvMode() {
2185
3154
  );
2186
3155
  }
2187
3156
  return void 0;
2188
- }
2189
- function getDoctorCheckNames(targets) {
3157
+ };
3158
+ var getDoctorCheckNames = (targets) => {
2190
3159
  const names = ["connection", "store"];
2191
3160
  pushCheckName(names, "product", targets.productIds);
2192
3161
  pushCheckName(names, "webhook", targets.webhookUrls);
@@ -2194,12 +3163,12 @@ function getDoctorCheckNames(targets) {
2194
3163
  pushCheckName(names, "licenseKey", targets.licenseKeyIds);
2195
3164
  pushCheckName(names, "subscriptionPlan", targets.variantIds);
2196
3165
  return names;
2197
- }
2198
- function pushCheckName(names, name, values2) {
3166
+ };
3167
+ var pushCheckName = (names, name, values2) => {
2199
3168
  if (!values2 || values2.length === 0) return;
2200
3169
  names.push(values2.length === 1 ? name : `${name} x${values2.length}`);
2201
- }
2202
- function renderSetupSummary(input2) {
3170
+ };
3171
+ var renderSetupSummary = (input2) => {
2203
3172
  return [
2204
3173
  renderStep(5, 5, "Ready to verify", "review before writing env"),
2205
3174
  ` ${chalk3.dim("mode")} ${input2.mode}`,
@@ -2208,8 +3177,8 @@ function renderSetupSummary(input2) {
2208
3177
  ` ${chalk3.dim("env")} ${input2.envPath}`,
2209
3178
  ""
2210
3179
  ].join("\n");
2211
- }
2212
- async function writeEnvFile(envPath, values2) {
3180
+ };
3181
+ var writeEnvFile = async (envPath, values2) => {
2213
3182
  const updates = /* @__PURE__ */ new Map([
2214
3183
  [ENV_KEYS.apiKey, values2.apiKey],
2215
3184
  [ENV_KEYS.storeId, values2.storeId],
@@ -2236,8 +3205,8 @@ async function writeEnvFile(envPath, values2) {
2236
3205
  await fs.mkdir(path2.dirname(envPath), { recursive: true });
2237
3206
  await fs.writeFile(envPath, `${next.join("\n").replace(/\n*$/, "")}
2238
3207
  `, { encoding: "utf8" });
2239
- }
2240
- async function readEnvFile(envPath) {
3208
+ };
3209
+ var readEnvFile = async (envPath) => {
2241
3210
  try {
2242
3211
  return await fs.readFile(envPath, "utf8");
2243
3212
  } catch (err) {
@@ -2246,8 +3215,8 @@ async function readEnvFile(envPath) {
2246
3215
  }
2247
3216
  throw err;
2248
3217
  }
2249
- }
2250
- function renderDiscoverySummary(choices, selectedTargets) {
3218
+ };
3219
+ var renderDiscoverySummary = (choices, selectedTargets) => {
2251
3220
  if (selectedTargets.length === 0) return chalk3.dim(" No optional resource checks selected.\n");
2252
3221
  const groups = [
2253
3222
  ["product", "Products", choices.products],
@@ -2269,7 +3238,7 @@ function renderDiscoverySummary(choices, selectedTargets) {
2269
3238
  }
2270
3239
  return `${lines.join("\n")}
2271
3240
  `;
2272
- }
3241
+ };
2273
3242
 
2274
3243
  // src/cli/commands/launcher.ts
2275
3244
  import chalk4 from "chalk";
@@ -2279,7 +3248,7 @@ import { spawn } from "child_process";
2279
3248
  import fs2 from "fs/promises";
2280
3249
  import path3 from "path";
2281
3250
  var PACKAGE_NAME = "fresh-squeezy";
2282
- async function ensureFreshSqueezyDevDependency(options = {}) {
3251
+ var ensureFreshSqueezyDevDependency = async (options = {}) => {
2283
3252
  if (options.skipInstall) {
2284
3253
  return { status: "skipped" };
2285
3254
  }
@@ -2307,8 +3276,8 @@ async function ensureFreshSqueezyDevDependency(options = {}) {
2307
3276
  throw new Error(`${command.join(" ")} failed with exit code ${code}`);
2308
3277
  }
2309
3278
  return { status: "installed", projectDir, packageJsonPath, packageManager, command };
2310
- }
2311
- async function findPackageJson(cwd) {
3279
+ };
3280
+ var findPackageJson = async (cwd) => {
2312
3281
  let current = path3.resolve(cwd);
2313
3282
  while (true) {
2314
3283
  const candidate = path3.join(current, "package.json");
@@ -2317,34 +3286,34 @@ async function findPackageJson(cwd) {
2317
3286
  if (parent === current) return void 0;
2318
3287
  current = parent;
2319
3288
  }
2320
- }
2321
- async function readPackageJson(packageJsonPath) {
3289
+ };
3290
+ var readPackageJson = async (packageJsonPath) => {
2322
3291
  const raw = await fs2.readFile(packageJsonPath, "utf8");
2323
3292
  return JSON.parse(raw);
2324
- }
2325
- async function detectPackageManager(projectDir) {
3293
+ };
3294
+ var detectPackageManager = async (projectDir) => {
2326
3295
  if (await pathExists(path3.join(projectDir, "pnpm-lock.yaml"))) return "pnpm";
2327
3296
  if (await pathExists(path3.join(projectDir, "yarn.lock"))) return "yarn";
2328
3297
  if (await pathExists(path3.join(projectDir, "bun.lock")) || await pathExists(path3.join(projectDir, "bun.lockb"))) {
2329
3298
  return "bun";
2330
3299
  }
2331
3300
  return "npm";
2332
- }
2333
- function hasFreshSqueezy(manifest) {
3301
+ };
3302
+ var hasFreshSqueezy = (manifest) => {
2334
3303
  return [
2335
3304
  manifest.dependencies,
2336
3305
  manifest.devDependencies,
2337
3306
  manifest.optionalDependencies,
2338
3307
  manifest.peerDependencies
2339
3308
  ].some((section) => section?.[PACKAGE_NAME] !== void 0);
2340
- }
2341
- function buildInstallCommand(packageManager, packageSpec) {
3309
+ };
3310
+ var buildInstallCommand = (packageManager, packageSpec) => {
2342
3311
  if (packageManager === "pnpm") return ["pnpm", "add", "-D", packageSpec];
2343
3312
  if (packageManager === "yarn") return ["yarn", "add", "-D", packageSpec];
2344
3313
  if (packageManager === "bun") return ["bun", "add", "-d", packageSpec];
2345
3314
  return ["npm", "install", "--save-dev", packageSpec];
2346
- }
2347
- function runPackageCommand(command, args, options) {
3315
+ };
3316
+ var runPackageCommand = (command, args, options) => {
2348
3317
  return new Promise((resolve2, reject) => {
2349
3318
  const child = spawn(command, args, {
2350
3319
  cwd: options.cwd,
@@ -2354,18 +3323,18 @@ function runPackageCommand(command, args, options) {
2354
3323
  child.on("error", reject);
2355
3324
  child.on("close", (code) => resolve2(code ?? 1));
2356
3325
  });
2357
- }
2358
- async function pathExists(filePath) {
3326
+ };
3327
+ var pathExists = async (filePath) => {
2359
3328
  try {
2360
3329
  await fs2.access(filePath);
2361
3330
  return true;
2362
3331
  } catch {
2363
3332
  return false;
2364
3333
  }
2365
- }
3334
+ };
2366
3335
 
2367
3336
  // src/cli/commands/launcher.ts
2368
- async function runLauncherCommand(options) {
3337
+ var runLauncherCommand = async (options) => {
2369
3338
  if (!options.isInteractive) return 2;
2370
3339
  try {
2371
3340
  process.stdout.write(
@@ -2396,8 +3365,8 @@ async function runLauncherCommand(options) {
2396
3365
  process.stderr.write(renderCommandExamples());
2397
3366
  return 1;
2398
3367
  }
2399
- }
2400
- async function routeLauncherAction(action) {
3368
+ };
3369
+ var routeLauncherAction = async (action) => {
2401
3370
  switch (action) {
2402
3371
  case "init":
2403
3372
  return startGuidedSetup();
@@ -2409,14 +3378,14 @@ async function routeLauncherAction(action) {
2409
3378
  case "exit":
2410
3379
  return 0;
2411
3380
  }
2412
- }
2413
- function startGuidedSetup() {
3381
+ };
3382
+ var startGuidedSetup = () => {
2414
3383
  process.stdout.write(
2415
3384
  renderStep(2, 2, "Guided setup", "detect credentials, stores, and resources")
2416
3385
  );
2417
3386
  return runInitCommand({ isInteractive: true });
2418
- }
2419
- function renderProjectInstallResult(result) {
3387
+ };
3388
+ var renderProjectInstallResult = (result) => {
2420
3389
  if (result.status === "installed") {
2421
3390
  return renderDetected(
2422
3391
  "Dev dependency",
@@ -2434,10 +3403,150 @@ function renderProjectInstallResult(result) {
2434
3403
  return chalk4.dim(" Skipped dev dependency install (--no-install).\n");
2435
3404
  }
2436
3405
  return chalk4.yellow(" No package.json found; running without installing a dev dependency.\n");
2437
- }
3406
+ };
3407
+
3408
+ // src/cli/commands/resourceOps.ts
3409
+ import { readFileSync } from "fs";
3410
+ var runResourceOpCommand = async (options) => {
3411
+ if (options.listCatalog) {
3412
+ writeCatalog(options.json ?? false);
3413
+ return 0;
3414
+ }
3415
+ const spec = findResourceVerb(options.resource, options.verb);
3416
+ if (!spec) {
3417
+ process.stderr.write(
3418
+ renderCliError(`Unknown or unsupported op: ${options.verb} ${options.resource}`, [
3419
+ "fresh-squeezy ops --list",
3420
+ "fresh-squeezy get product --id 1",
3421
+ "fresh-squeezy list webhook --store-ids 1"
3422
+ ])
3423
+ );
3424
+ return 2;
3425
+ }
3426
+ try {
3427
+ const body = readBody(options);
3428
+ if (spec.body === "required" && body === void 0) {
3429
+ throw new FreshSqueezyError({
3430
+ code: "MISSING_ARG",
3431
+ message: "This op requires a JSON body (--body, --body-file, or stdin)."
3432
+ });
3433
+ }
3434
+ const client = createFreshSqueezy({ mode: options.mode });
3435
+ const allowed = await assertWriteSafety(spec, client.mode, options);
3436
+ if (!allowed) return 2;
3437
+ const config = resolveConfig({ mode: options.mode });
3438
+ const http = new HttpClient(config);
3439
+ const data = await invokeOp(http, options.resource, options.verb, {
3440
+ id: options.id,
3441
+ storeId: options.storeIds?.[0],
3442
+ parentId: options.parentId,
3443
+ body
3444
+ });
3445
+ const payload = {
3446
+ ok: true,
3447
+ mode: client.mode,
3448
+ resource: spec.resource,
3449
+ verb: spec.verb,
3450
+ docs: `https://docs.lemonsqueezy.com/api/${spec.docsPath}`,
3451
+ data: data ?? null
3452
+ };
3453
+ if (options.json) {
3454
+ process.stdout.write(`${JSON.stringify(payload, null, 2)}
3455
+ `);
3456
+ } else {
3457
+ process.stdout.write(
3458
+ `${spec.verb} ${spec.resource} \u2014 ok (mode=${client.mode})
3459
+ ${JSON.stringify(data ?? null, null, 2)}
3460
+ `
3461
+ );
3462
+ }
3463
+ return 0;
3464
+ } catch (err) {
3465
+ writeFatal2(err, options.json ?? false);
3466
+ return 2;
3467
+ }
3468
+ };
3469
+ var writeCatalog = (asJson) => {
3470
+ if (asJson) {
3471
+ process.stdout.write(
3472
+ `${JSON.stringify(
3473
+ {
3474
+ resources: listRegisteredResources(),
3475
+ ops: resourceRegistry
3476
+ },
3477
+ null,
3478
+ 2
3479
+ )}
3480
+ `
3481
+ );
3482
+ return;
3483
+ }
3484
+ process.stdout.write("Docs-backed ops (Lemon Squeezy official API only):\n\n");
3485
+ for (const entry of resourceRegistry) {
3486
+ const flags = [
3487
+ entry.destructive ? "destructive" : void 0,
3488
+ entry.body && entry.body !== "none" ? `body=${entry.body}` : void 0
3489
+ ].filter(Boolean).join(", ");
3490
+ process.stdout.write(
3491
+ ` ${entry.verb.padEnd(18)} ${entry.resource.padEnd(22)} ${entry.docsPath}${flags ? ` (${flags})` : ""}
3492
+ `
3493
+ );
3494
+ }
3495
+ process.stdout.write(
3496
+ "\nCatalog resources (product, variant, price, file, store, \u2026) are read-only in the API.\n"
3497
+ );
3498
+ };
3499
+ var assertWriteSafety = async (spec, mode, options) => {
3500
+ const isWrite = spec.verb !== "get" && spec.verb !== "list" && spec.verb !== "current-usage";
3501
+ if (!isWrite) return true;
3502
+ const needsGate = Boolean(spec.destructive) || mode === "live";
3503
+ if (!needsGate) return true;
3504
+ if (options.yes) return true;
3505
+ if (options.isInteractive) {
3506
+ return confirmResourceOp(
3507
+ mode === "live" ? `LIVE mode: allow ${spec.verb} ${spec.resource}?` : `Confirm ${spec.verb} ${spec.resource}?`
3508
+ );
3509
+ }
3510
+ process.stderr.write(
3511
+ renderCliError(
3512
+ `${spec.verb} ${spec.resource} requires --yes in non-interactive ${mode} mode${spec.destructive ? " (destructive op)" : ""}`,
3513
+ [
3514
+ `fresh-squeezy ${spec.verb} ${spec.resource} --yes \u2026`,
3515
+ "Use test mode for safer experimentation: --mode test"
3516
+ ]
3517
+ )
3518
+ );
3519
+ return false;
3520
+ };
3521
+ var readBody = (options) => {
3522
+ if (options.bodyFile) {
3523
+ const text = readFileSync(options.bodyFile, "utf8");
3524
+ return JSON.parse(text);
3525
+ }
3526
+ if (options.body !== void 0) {
3527
+ return JSON.parse(options.body);
3528
+ }
3529
+ if (!process.stdin.isTTY && !options.isInteractive) {
3530
+ }
3531
+ return void 0;
3532
+ };
3533
+ var writeFatal2 = (err, json) => {
3534
+ if (json) {
3535
+ const code = err instanceof FreshSqueezyError ? err.code : "FATAL";
3536
+ const message2 = err instanceof Error ? err.message : String(err);
3537
+ const status = err instanceof FreshSqueezyError ? err.status : void 0;
3538
+ process.stderr.write(
3539
+ `${JSON.stringify({ ok: false, error: { code, message: message2, status } }, null, 2)}
3540
+ `
3541
+ );
3542
+ return;
3543
+ }
3544
+ const message = err instanceof Error ? err.message : String(err);
3545
+ process.stderr.write(renderCliError(message, ["fresh-squeezy ops --list"]));
3546
+ };
2438
3547
 
2439
3548
  // src/cli/commands/validate.ts
2440
- async function runValidateCommand(target, options) {
3549
+ var runValidateCommand = async (target, options) => {
2441
3550
  try {
2442
3551
  const client = createFreshSqueezy({ mode: options.mode });
2443
3552
  if (target === "connection") {
@@ -2473,8 +3582,8 @@ async function runValidateCommand(target, options) {
2473
3582
  process.stderr.write(renderCliError(message, getValidateHints(err, target)));
2474
3583
  return 2;
2475
3584
  }
2476
- }
2477
- async function resolveStoresForTarget(client, target, options) {
3585
+ };
3586
+ var resolveStoresForTarget = async (client, target, options) => {
2478
3587
  const resolved = await resolveStores(client, {
2479
3588
  storeIds: options.storeIds,
2480
3589
  allStores: options.allStores,
@@ -2487,8 +3596,8 @@ async function resolveStoresForTarget(client, target, options) {
2487
3596
  });
2488
3597
  }
2489
3598
  return resolved.storeIds;
2490
- }
2491
- async function runPerStore(client, target, storeIds, options) {
3599
+ };
3600
+ var runPerStore = async (client, target, storeIds, options) => {
2492
3601
  if (target === "store") {
2493
3602
  return Promise.all(storeIds.map((id) => client.validateStore(id)));
2494
3603
  }
@@ -2497,16 +3606,16 @@ async function runPerStore(client, target, storeIds, options) {
2497
3606
  return Promise.all(storeIds.map((storeId) => client.validateWebhook({ storeId, url })));
2498
3607
  }
2499
3608
  return [];
2500
- }
2501
- async function runProduct(client, options) {
3609
+ };
3610
+ var runProduct = async (client, options) => {
2502
3611
  const productId = required2(options.productId, "--product-id is required for `validate product`.");
2503
3612
  const expected = options.storeIds?.[0];
2504
3613
  return client.validateProduct({
2505
3614
  productId,
2506
3615
  expectedStoreId: expected
2507
3616
  });
2508
- }
2509
- async function runDiscount(client, options) {
3617
+ };
3618
+ var runDiscount = async (client, options) => {
2510
3619
  const discountId = required2(
2511
3620
  options.discountId,
2512
3621
  "--discount-id is required for `validate discount`."
@@ -2516,8 +3625,8 @@ async function runDiscount(client, options) {
2516
3625
  "--store-ids is required for `validate discount`."
2517
3626
  );
2518
3627
  return client.validateDiscount({ storeId, discountId });
2519
- }
2520
- async function runLicenseKey(client, options) {
3628
+ };
3629
+ var runLicenseKey = async (client, options) => {
2521
3630
  const licenseKeyId = required2(
2522
3631
  options.licenseKeyId,
2523
3632
  "--license-key-id is required for `validate license-key`."
@@ -2527,8 +3636,8 @@ async function runLicenseKey(client, options) {
2527
3636
  "--store-ids is required for `validate license-key`."
2528
3637
  );
2529
3638
  return client.validateLicenseKey({ storeId, licenseKeyId });
2530
- }
2531
- async function runSubscriptionPlan(client, options) {
3639
+ };
3640
+ var runSubscriptionPlan = async (client, options) => {
2532
3641
  const variantId = required2(
2533
3642
  options.variantId,
2534
3643
  "--variant-id is required for `validate subscription-plan`."
@@ -2538,8 +3647,8 @@ async function runSubscriptionPlan(client, options) {
2538
3647
  "--store-ids is required for `validate subscription-plan`."
2539
3648
  );
2540
3649
  return client.validateSubscriptionPlan({ storeId, variantId });
2541
- }
2542
- function emit(result, options) {
3650
+ };
3651
+ var emit = (result, options) => {
2543
3652
  if (options.json) {
2544
3653
  process.stdout.write(`${JSON.stringify(result, null, 2)}
2545
3654
  `);
@@ -2548,29 +3657,79 @@ function emit(result, options) {
2548
3657
  `);
2549
3658
  }
2550
3659
  return result.ok ? 0 : 1;
2551
- }
2552
- function required2(value, message) {
3660
+ };
3661
+ var required2 = (value, message) => {
2553
3662
  if (value === void 0 || value === null || value === "") {
2554
3663
  throw new FreshSqueezyError({ code: "MISSING_ARG", message });
2555
3664
  }
2556
3665
  return value;
2557
- }
3666
+ };
2558
3667
 
2559
3668
  // src/cli/main.ts
2560
3669
  dotenv.config();
3670
+ var parseMode = (value) => {
3671
+ if (value === "test" || value === "live") return value;
3672
+ throw new Error(`Mode must be "test" or "live", got "${value}"`);
3673
+ };
3674
+ var parseCsv = (value) => {
3675
+ return value.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
3676
+ };
3677
+ var readPackageVersion = () => {
3678
+ const candidates = [
3679
+ new URL("../package.json", import.meta.url),
3680
+ new URL("../../package.json", import.meta.url)
3681
+ ];
3682
+ for (const candidate of candidates) {
3683
+ try {
3684
+ const payload = JSON.parse(readFileSync2(candidate, "utf8"));
3685
+ if (typeof payload.version === "string") return payload.version;
3686
+ } catch {
3687
+ }
3688
+ }
3689
+ return "0.0.0";
3690
+ };
2561
3691
  var isInteractive = Boolean(process.stdin.isTTY);
2562
3692
  var packageVersion = readPackageVersion();
3693
+ var runValidate = async (target, opts) => {
3694
+ const code = await runValidateCommand(target, {
3695
+ mode: opts.mode,
3696
+ storeIds: opts.storeIds,
3697
+ allStores: Boolean(opts.allStores),
3698
+ productId: opts.productId,
3699
+ webhookUrl: opts.webhookUrl,
3700
+ discountId: opts.discountId,
3701
+ licenseKeyId: opts.licenseKeyId,
3702
+ variantId: opts.variantId,
3703
+ json: Boolean(opts.json),
3704
+ isInteractive
3705
+ });
3706
+ process.exit(code);
3707
+ };
2563
3708
  var program = new Command();
2564
- program.name("fresh-squeezy").description("Lemon Squeezy integration doctor for billing teams").version(packageVersion).option("--no-install", "Skip adding fresh-squeezy to devDependencies before guided setup").showSuggestionAfterError().showHelpAfterError("\nRun `fresh-squeezy --help` for examples.");
3709
+ program.name("fresh-squeezy").description(
3710
+ "Dual-mode Lemon Squeezy CLI: doctor/validate pre-flight + docs-backed resource ops (get/list/create/\u2026)"
3711
+ ).version(packageVersion).option("--no-install", "Skip adding fresh-squeezy to devDependencies before guided setup").showSuggestionAfterError().showHelpAfterError("\nRun `fresh-squeezy --help` for examples.");
2565
3712
  program.addHelpText(
2566
3713
  "after",
2567
3714
  `
2568
- Start:
3715
+ Start (doctor setup):
2569
3716
  fresh-squeezy add as a dev dependency, then run guided setup
2570
3717
  fresh-squeezy --no-install run guided setup without editing package.json
2571
3718
  fresh-squeezy doctor --all-stores --all-resources
2572
3719
  fresh-squeezy validate webhook --store-ids 12 --webhook-url https://app.example.com/api/webhooks/lemon-squeezy
2573
3720
 
3721
+ Ops (docs-backed Lemon Squeezy API only \u2014 products/variants are read-only):
3722
+ fresh-squeezy ops --list
3723
+ fresh-squeezy get product --id 42 --json
3724
+ fresh-squeezy list webhook --store-ids 12
3725
+ fresh-squeezy create webhook --body-file webhook.json --yes
3726
+ fresh-squeezy cancel subscription --id 9 --yes
3727
+ fresh-squeezy refund order --id 100 --yes
3728
+ fresh-squeezy generate-invoice order --id 100 --yes
3729
+
3730
+ Safety: delete/cancel/refund always need --yes (or TTY confirm); live-mode writes need --yes too.
3731
+ Bodies are JSON:API documents via --body or --body-file (not flat flags).
3732
+
2574
3733
  Store selection:
2575
3734
  Use --store-ids 12,34 for explicit stores, --all-stores for automation, or run in a TTY to pick stores interactively.
2576
3735
  `
@@ -2659,46 +3818,55 @@ types.command("augment").description(
2659
3818
  const code = await runAugmentCommand({ out: opts.out, force: Boolean(opts.force) });
2660
3819
  process.exit(code);
2661
3820
  });
3821
+ program.command("ops").description("List docs-backed resource ops (Lemon Squeezy official API matrix)").option("--list", "Print the full verb matrix", true).option("--json", "Emit machine-readable JSON").action(async (opts) => {
3822
+ const code = await runResourceOpCommand({
3823
+ resource: "",
3824
+ verb: "get",
3825
+ listCatalog: true,
3826
+ json: Boolean(opts.json)
3827
+ });
3828
+ process.exit(code);
3829
+ });
3830
+ var OP_VERBS = [
3831
+ "get",
3832
+ "list",
3833
+ "create",
3834
+ "update",
3835
+ "delete",
3836
+ "cancel",
3837
+ "refund",
3838
+ "generate-invoice",
3839
+ "current-usage"
3840
+ ];
3841
+ for (const verb of OP_VERBS) {
3842
+ program.command(`${verb} <resource>`).description(`Docs-backed ${verb} for a Lemon Squeezy resource`).option("-m, --mode <mode>", "test or live", parseMode).option("--id <id>", "Resource id").option(
3843
+ "--store-ids <ids>",
3844
+ "Comma-separated store IDs (first used for list filters)",
3845
+ parseCsv
3846
+ ).option(
3847
+ "--parent-id <id>",
3848
+ "Parent resource id for nested lists (product, order, subscription, \u2026)"
3849
+ ).option("--body <json>", "JSON:API body string").option("--body-file <path>", "Path to JSON:API body file").option("--yes", "Skip confirm; required for live writes and destructive ops when non-TTY").option("--json", "Emit machine-readable JSON").action(async (resource, opts) => {
3850
+ const code = await runResourceOpCommand({
3851
+ verb,
3852
+ resource,
3853
+ mode: opts.mode,
3854
+ id: opts.id,
3855
+ storeIds: opts.storeIds,
3856
+ parentId: opts.parentId,
3857
+ body: opts.body,
3858
+ bodyFile: opts.bodyFile,
3859
+ yes: Boolean(opts.yes),
3860
+ json: Boolean(opts.json),
3861
+ isInteractive
3862
+ });
3863
+ process.exit(code);
3864
+ });
3865
+ }
2662
3866
  program.parseAsync(process.argv).catch((err) => {
2663
3867
  const message = err instanceof Error ? err.message : String(err);
2664
3868
  const hints = message.includes("Mode must be") ? ["fresh-squeezy doctor --mode test", "fresh-squeezy doctor --mode live"] : ["fresh-squeezy --help"];
2665
3869
  process.stderr.write(renderCliError(message, hints));
2666
3870
  process.exit(2);
2667
3871
  });
2668
- function parseMode(value) {
2669
- if (value === "test" || value === "live") return value;
2670
- throw new Error(`Mode must be "test" or "live", got "${value}"`);
2671
- }
2672
- function parseCsv(value) {
2673
- return value.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
2674
- }
2675
- function readPackageVersion() {
2676
- const candidates = [
2677
- new URL("../package.json", import.meta.url),
2678
- new URL("../../package.json", import.meta.url)
2679
- ];
2680
- for (const candidate of candidates) {
2681
- try {
2682
- const payload = JSON.parse(readFileSync(candidate, "utf8"));
2683
- if (typeof payload.version === "string") return payload.version;
2684
- } catch {
2685
- }
2686
- }
2687
- return "0.0.0";
2688
- }
2689
- async function runValidate(target, opts) {
2690
- const code = await runValidateCommand(target, {
2691
- mode: opts.mode,
2692
- storeIds: opts.storeIds,
2693
- allStores: Boolean(opts.allStores),
2694
- productId: opts.productId,
2695
- webhookUrl: opts.webhookUrl,
2696
- discountId: opts.discountId,
2697
- licenseKeyId: opts.licenseKeyId,
2698
- variantId: opts.variantId,
2699
- json: Boolean(opts.json),
2700
- isInteractive
2701
- });
2702
- process.exit(code);
2703
- }
2704
3872
  //# sourceMappingURL=cli.js.map