atmn 0.0.23 → 0.0.24

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.
Files changed (3) hide show
  1. package/dist/cli.cjs +133 -37
  2. package/dist/cli.js +133 -37
  3. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -603,68 +603,105 @@ export const ${idToVar({ id: feature.id, prefix: "feature" })} = feature({
603
603
  })`;
604
604
  return snippet;
605
605
  }
606
- var ProductItemIntervalEnum = v4.z.enum([
607
- "minute",
608
- "hour",
609
- "day",
610
- "week",
611
- "month",
612
- "quarter",
613
- "semi_annual",
614
- "year"
615
- ]);
616
- var UsageModelEnum = v4.z.enum(["prepaid", "pay_per_use"]);
606
+ var ProductItemIntervalEnum = v4.z.enum(
607
+ ["minute", "hour", "day", "week", "month", "quarter", "semi_annual", "year"],
608
+ {
609
+ message: "Interval must be 'minute', 'hour', 'day', 'week', 'month', 'quarter', 'semi_annual', or 'year'"
610
+ }
611
+ );
612
+ var UsageModelEnum = v4.z.enum(["prepaid", "pay_per_use"], {
613
+ message: "Usage model must be 'prepaid' or 'pay_per_use'"
614
+ });
617
615
  var ProductItemSchema = v4.z.object({
618
- type: v4.z.enum(["feature", "priced_feature"]).nullish(),
619
- feature_id: v4.z.string().nullish(),
620
- included_usage: v4.z.union([v4.z.number(), v4.z.literal("inf")]).nullish(),
616
+ type: v4.z.enum(["feature", "priced_feature"], {
617
+ message: "Type must be 'feature' or 'priced_feature'"
618
+ }).nullish(),
619
+ feature_id: v4.z.string({
620
+ message: "Feature ID must be a string"
621
+ }).nullish(),
622
+ included_usage: v4.z.union([v4.z.number(), v4.z.literal("inf")], {
623
+ message: 'Included usage must be a number or "inf"'
624
+ }).nullish(),
621
625
  interval: ProductItemIntervalEnum.nullish(),
622
626
  usage_model: UsageModelEnum.nullish(),
623
- price: v4.z.number().nullish(),
627
+ price: v4.z.number({
628
+ message: "Price must be a valid number"
629
+ }).nullish(),
624
630
  tiers: v4.z.array(
625
631
  v4.z.object({
626
- amount: v4.z.number(),
627
- to: v4.z.union([v4.z.number(), v4.z.literal("inf")])
632
+ amount: v4.z.number({
633
+ message: "Tier amount must be a valid number"
634
+ }),
635
+ to: v4.z.union([v4.z.number(), v4.z.literal("inf")], {
636
+ message: 'Tier "to" must be a number or "inf"'
637
+ })
628
638
  })
629
639
  ).nullish(),
630
- billing_units: v4.z.number().nullish(),
631
- // amount per billing unit (eg. $9 / 250 units)
632
- reset_usage_when_enabled: v4.z.boolean().optional(),
633
- entity_feature_id: v4.z.string().optional()
640
+ billing_units: v4.z.number({
641
+ message: "Billing units must be a valid number"
642
+ }).nullish(),
643
+ reset_usage_when_enabled: v4.z.boolean({
644
+ message: "Reset usage when enabled must be true or false"
645
+ }).optional(),
646
+ entity_feature_id: v4.z.string({
647
+ message: "Entity feature ID must be a string"
648
+ }).optional()
634
649
  });
635
650
  v4.z.object({
636
- feature_id: v4.z.string(),
637
- included_usage: v4.z.number().nullish(),
651
+ feature_id: v4.z.string({
652
+ message: "Feature ID is required and must be a string"
653
+ }),
654
+ included_usage: v4.z.number({
655
+ message: "Included usage must be a valid number"
656
+ }).nullish(),
638
657
  interval: ProductItemIntervalEnum.nullish()
639
658
  });
640
659
  v4.z.object({
641
- price: v4.z.number().gt(0),
660
+ price: v4.z.number({
661
+ message: "Price must be a valid number"
662
+ }).gt(0, "Price must be greater than 0"),
642
663
  interval: ProductItemIntervalEnum.nullish()
643
664
  });
644
665
 
645
666
  // source/compose/models/composeModels.ts
646
667
  var FreeTrialSchema = v4.z.object({
647
- duration: v4.z.enum(["day", "month", "year"]),
648
- length: v4.z.number(),
649
- unique_fingerprint: v4.z.boolean(),
650
- card_required: v4.z.boolean()
668
+ duration: v4.z.enum(["day", "month", "year"], {
669
+ message: "Duration must be 'day', 'month', or 'year'"
670
+ }),
671
+ length: v4.z.number({
672
+ message: "Length must be a valid number"
673
+ }),
674
+ unique_fingerprint: v4.z.boolean({
675
+ message: "Unique fingerprint must be true or false"
676
+ }),
677
+ card_required: v4.z.boolean({
678
+ message: "Card required must be true or false"
679
+ })
651
680
  });
652
681
  var ProductSchema = v4.z.object({
653
- id: v4.z.string().min(1),
654
- name: v4.z.string().min(1),
682
+ id: v4.z.string().min(1, "Product ID is required and cannot be empty"),
683
+ name: v4.z.string().min(1, "Product name is required and cannot be empty"),
655
684
  is_add_on: v4.z.boolean().prefault(false).optional(),
656
685
  is_default: v4.z.boolean().prefault(false).optional(),
657
- items: v4.z.array(ProductItemSchema),
686
+ items: v4.z.array(ProductItemSchema, {
687
+ message: "Items must be an array of product items"
688
+ }),
658
689
  free_trial: FreeTrialSchema.optional()
659
690
  });
660
691
  var FeatureSchema = v4.z.object({
661
- id: v4.z.string().min(1),
692
+ id: v4.z.string().min(1, "Feature ID is required and cannot be empty"),
662
693
  name: v4.z.string().optional(),
663
- type: v4.z.enum(["boolean", "single_use", "continuous_use", "credit_system"]),
694
+ type: v4.z.enum(["boolean", "single_use", "continuous_use", "credit_system"], {
695
+ message: "Type must be 'boolean', 'single_use', 'continuous_use', or 'credit_system'"
696
+ }),
664
697
  credit_schema: v4.z.array(
665
698
  v4.z.object({
666
- metered_feature_id: v4.z.string(),
667
- credit_cost: v4.z.number()
699
+ metered_feature_id: v4.z.string({
700
+ message: "Metered feature ID must be a string"
701
+ }),
702
+ credit_cost: v4.z.number({
703
+ message: "Credit cost must be a valid number"
704
+ })
668
705
  })
669
706
  ).optional(),
670
707
  archived: v4.z.boolean().optional()
@@ -721,7 +758,7 @@ function isProduct(value) {
721
758
  try {
722
759
  ProductSchema.parse(value);
723
760
  return true;
724
- } catch {
761
+ } catch (error) {
725
762
  return false;
726
763
  }
727
764
  }
@@ -733,6 +770,41 @@ function isFeature(value) {
733
770
  return false;
734
771
  }
735
772
  }
773
+ function detectObjectType(value) {
774
+ if (value && typeof value === "object") {
775
+ if (value.items && Array.isArray(value.items)) {
776
+ return "product";
777
+ }
778
+ if (value.type) {
779
+ return "feature";
780
+ }
781
+ }
782
+ return "unknown";
783
+ }
784
+ function getValidationError(schema, value) {
785
+ try {
786
+ schema.parse(value);
787
+ return "";
788
+ } catch (error) {
789
+ if (error.name === "ZodError" && error.issues) {
790
+ const formattedErrors = error.issues.map((issue) => {
791
+ const path2 = issue.path.length > 0 ? `${issue.path.join(".")}` : "root";
792
+ return ` \u2022 ${path2}: ${issue.message}`;
793
+ });
794
+ return `
795
+ ${formattedErrors.join("\n")}`;
796
+ }
797
+ if (error.errors && Array.isArray(error.errors)) {
798
+ const formattedErrors = error.errors.map((e) => {
799
+ const path2 = e.path && e.path.length > 0 ? `${e.path.join(".")}` : "root";
800
+ return ` \u2022 ${path2}: ${e.message}`;
801
+ });
802
+ return `
803
+ ${formattedErrors.join("\n")}`;
804
+ }
805
+ return error.message || "Unknown validation error";
806
+ }
807
+ }
736
808
  async function loadAutumnConfigFile() {
737
809
  const configPath = path__default.default.join(process.cwd(), "autumn.config.ts");
738
810
  const absolutePath = path.resolve(configPath);
@@ -764,6 +836,28 @@ async function loadAutumnConfigFile() {
764
836
  products.push(value);
765
837
  } else if (isFeature(value)) {
766
838
  features.push(value);
839
+ } else {
840
+ const detectedType = detectObjectType(value);
841
+ if (detectedType === "product") {
842
+ const validationError = getValidationError(ProductSchema, value);
843
+ console.error("\n" + chalk8__default.default.red("\u274C Invalid product configuration"));
844
+ console.error(chalk8__default.default.yellow(`Product: "${key}"`));
845
+ console.error(chalk8__default.default.red("Validation errors:") + validationError);
846
+ process.exit(1);
847
+ } else if (detectedType === "feature") {
848
+ const validationError = getValidationError(FeatureSchema, value);
849
+ console.error("\n" + chalk8__default.default.red("\u274C Invalid feature configuration"));
850
+ console.error(chalk8__default.default.yellow(`Feature: "${key}"`));
851
+ console.error(chalk8__default.default.red("Validation errors:") + validationError);
852
+ process.exit(1);
853
+ } else {
854
+ console.error("\n" + chalk8__default.default.red("\u274C Invalid object configuration"));
855
+ console.error(chalk8__default.default.yellow(`Object: "${key}"`));
856
+ console.error(
857
+ chalk8__default.default.red("Error:") + " Object must be either a product (with 'items' field) or feature (with 'type' field)"
858
+ );
859
+ process.exit(1);
860
+ }
767
861
  }
768
862
  }
769
863
  }
@@ -987,7 +1081,9 @@ async function checkForDeletables(currentFeatures, currentProducts) {
987
1081
  const featureIds = features.map((feature) => feature.id);
988
1082
  const currentFeatureIds = currentFeatures.map((feature) => feature.id);
989
1083
  const featuresToDelete = featureIds.filter(
990
- (featureId) => !currentFeatureIds.includes(featureId) && !features.archived
1084
+ (featureId) => !currentFeatureIds.includes(featureId) && !features.some(
1085
+ (feature) => feature.id === featureId && feature.archived
1086
+ )
991
1087
  );
992
1088
  const products = await getAllProducts();
993
1089
  const productIds = products.map((product) => product.id);
package/dist/cli.js CHANGED
@@ -586,68 +586,105 @@ export const ${idToVar({ id: feature.id, prefix: "feature" })} = feature({
586
586
  })`;
587
587
  return snippet;
588
588
  }
589
- var ProductItemIntervalEnum = z.enum([
590
- "minute",
591
- "hour",
592
- "day",
593
- "week",
594
- "month",
595
- "quarter",
596
- "semi_annual",
597
- "year"
598
- ]);
599
- var UsageModelEnum = z.enum(["prepaid", "pay_per_use"]);
589
+ var ProductItemIntervalEnum = z.enum(
590
+ ["minute", "hour", "day", "week", "month", "quarter", "semi_annual", "year"],
591
+ {
592
+ message: "Interval must be 'minute', 'hour', 'day', 'week', 'month', 'quarter', 'semi_annual', or 'year'"
593
+ }
594
+ );
595
+ var UsageModelEnum = z.enum(["prepaid", "pay_per_use"], {
596
+ message: "Usage model must be 'prepaid' or 'pay_per_use'"
597
+ });
600
598
  var ProductItemSchema = z.object({
601
- type: z.enum(["feature", "priced_feature"]).nullish(),
602
- feature_id: z.string().nullish(),
603
- included_usage: z.union([z.number(), z.literal("inf")]).nullish(),
599
+ type: z.enum(["feature", "priced_feature"], {
600
+ message: "Type must be 'feature' or 'priced_feature'"
601
+ }).nullish(),
602
+ feature_id: z.string({
603
+ message: "Feature ID must be a string"
604
+ }).nullish(),
605
+ included_usage: z.union([z.number(), z.literal("inf")], {
606
+ message: 'Included usage must be a number or "inf"'
607
+ }).nullish(),
604
608
  interval: ProductItemIntervalEnum.nullish(),
605
609
  usage_model: UsageModelEnum.nullish(),
606
- price: z.number().nullish(),
610
+ price: z.number({
611
+ message: "Price must be a valid number"
612
+ }).nullish(),
607
613
  tiers: z.array(
608
614
  z.object({
609
- amount: z.number(),
610
- to: z.union([z.number(), z.literal("inf")])
615
+ amount: z.number({
616
+ message: "Tier amount must be a valid number"
617
+ }),
618
+ to: z.union([z.number(), z.literal("inf")], {
619
+ message: 'Tier "to" must be a number or "inf"'
620
+ })
611
621
  })
612
622
  ).nullish(),
613
- billing_units: z.number().nullish(),
614
- // amount per billing unit (eg. $9 / 250 units)
615
- reset_usage_when_enabled: z.boolean().optional(),
616
- entity_feature_id: z.string().optional()
623
+ billing_units: z.number({
624
+ message: "Billing units must be a valid number"
625
+ }).nullish(),
626
+ reset_usage_when_enabled: z.boolean({
627
+ message: "Reset usage when enabled must be true or false"
628
+ }).optional(),
629
+ entity_feature_id: z.string({
630
+ message: "Entity feature ID must be a string"
631
+ }).optional()
617
632
  });
618
633
  z.object({
619
- feature_id: z.string(),
620
- included_usage: z.number().nullish(),
634
+ feature_id: z.string({
635
+ message: "Feature ID is required and must be a string"
636
+ }),
637
+ included_usage: z.number({
638
+ message: "Included usage must be a valid number"
639
+ }).nullish(),
621
640
  interval: ProductItemIntervalEnum.nullish()
622
641
  });
623
642
  z.object({
624
- price: z.number().gt(0),
643
+ price: z.number({
644
+ message: "Price must be a valid number"
645
+ }).gt(0, "Price must be greater than 0"),
625
646
  interval: ProductItemIntervalEnum.nullish()
626
647
  });
627
648
 
628
649
  // source/compose/models/composeModels.ts
629
650
  var FreeTrialSchema = z.object({
630
- duration: z.enum(["day", "month", "year"]),
631
- length: z.number(),
632
- unique_fingerprint: z.boolean(),
633
- card_required: z.boolean()
651
+ duration: z.enum(["day", "month", "year"], {
652
+ message: "Duration must be 'day', 'month', or 'year'"
653
+ }),
654
+ length: z.number({
655
+ message: "Length must be a valid number"
656
+ }),
657
+ unique_fingerprint: z.boolean({
658
+ message: "Unique fingerprint must be true or false"
659
+ }),
660
+ card_required: z.boolean({
661
+ message: "Card required must be true or false"
662
+ })
634
663
  });
635
664
  var ProductSchema = z.object({
636
- id: z.string().min(1),
637
- name: z.string().min(1),
665
+ id: z.string().min(1, "Product ID is required and cannot be empty"),
666
+ name: z.string().min(1, "Product name is required and cannot be empty"),
638
667
  is_add_on: z.boolean().prefault(false).optional(),
639
668
  is_default: z.boolean().prefault(false).optional(),
640
- items: z.array(ProductItemSchema),
669
+ items: z.array(ProductItemSchema, {
670
+ message: "Items must be an array of product items"
671
+ }),
641
672
  free_trial: FreeTrialSchema.optional()
642
673
  });
643
674
  var FeatureSchema = z.object({
644
- id: z.string().min(1),
675
+ id: z.string().min(1, "Feature ID is required and cannot be empty"),
645
676
  name: z.string().optional(),
646
- type: z.enum(["boolean", "single_use", "continuous_use", "credit_system"]),
677
+ type: z.enum(["boolean", "single_use", "continuous_use", "credit_system"], {
678
+ message: "Type must be 'boolean', 'single_use', 'continuous_use', or 'credit_system'"
679
+ }),
647
680
  credit_schema: z.array(
648
681
  z.object({
649
- metered_feature_id: z.string(),
650
- credit_cost: z.number()
682
+ metered_feature_id: z.string({
683
+ message: "Metered feature ID must be a string"
684
+ }),
685
+ credit_cost: z.number({
686
+ message: "Credit cost must be a valid number"
687
+ })
651
688
  })
652
689
  ).optional(),
653
690
  archived: z.boolean().optional()
@@ -704,7 +741,7 @@ function isProduct(value) {
704
741
  try {
705
742
  ProductSchema.parse(value);
706
743
  return true;
707
- } catch {
744
+ } catch (error) {
708
745
  return false;
709
746
  }
710
747
  }
@@ -716,6 +753,41 @@ function isFeature(value) {
716
753
  return false;
717
754
  }
718
755
  }
756
+ function detectObjectType(value) {
757
+ if (value && typeof value === "object") {
758
+ if (value.items && Array.isArray(value.items)) {
759
+ return "product";
760
+ }
761
+ if (value.type) {
762
+ return "feature";
763
+ }
764
+ }
765
+ return "unknown";
766
+ }
767
+ function getValidationError(schema, value) {
768
+ try {
769
+ schema.parse(value);
770
+ return "";
771
+ } catch (error) {
772
+ if (error.name === "ZodError" && error.issues) {
773
+ const formattedErrors = error.issues.map((issue) => {
774
+ const path2 = issue.path.length > 0 ? `${issue.path.join(".")}` : "root";
775
+ return ` \u2022 ${path2}: ${issue.message}`;
776
+ });
777
+ return `
778
+ ${formattedErrors.join("\n")}`;
779
+ }
780
+ if (error.errors && Array.isArray(error.errors)) {
781
+ const formattedErrors = error.errors.map((e) => {
782
+ const path2 = e.path && e.path.length > 0 ? `${e.path.join(".")}` : "root";
783
+ return ` \u2022 ${path2}: ${e.message}`;
784
+ });
785
+ return `
786
+ ${formattedErrors.join("\n")}`;
787
+ }
788
+ return error.message || "Unknown validation error";
789
+ }
790
+ }
719
791
  async function loadAutumnConfigFile() {
720
792
  const configPath = path.join(process.cwd(), "autumn.config.ts");
721
793
  const absolutePath = resolve(configPath);
@@ -747,6 +819,28 @@ async function loadAutumnConfigFile() {
747
819
  products.push(value);
748
820
  } else if (isFeature(value)) {
749
821
  features.push(value);
822
+ } else {
823
+ const detectedType = detectObjectType(value);
824
+ if (detectedType === "product") {
825
+ const validationError = getValidationError(ProductSchema, value);
826
+ console.error("\n" + chalk8.red("\u274C Invalid product configuration"));
827
+ console.error(chalk8.yellow(`Product: "${key}"`));
828
+ console.error(chalk8.red("Validation errors:") + validationError);
829
+ process.exit(1);
830
+ } else if (detectedType === "feature") {
831
+ const validationError = getValidationError(FeatureSchema, value);
832
+ console.error("\n" + chalk8.red("\u274C Invalid feature configuration"));
833
+ console.error(chalk8.yellow(`Feature: "${key}"`));
834
+ console.error(chalk8.red("Validation errors:") + validationError);
835
+ process.exit(1);
836
+ } else {
837
+ console.error("\n" + chalk8.red("\u274C Invalid object configuration"));
838
+ console.error(chalk8.yellow(`Object: "${key}"`));
839
+ console.error(
840
+ chalk8.red("Error:") + " Object must be either a product (with 'items' field) or feature (with 'type' field)"
841
+ );
842
+ process.exit(1);
843
+ }
750
844
  }
751
845
  }
752
846
  }
@@ -970,7 +1064,9 @@ async function checkForDeletables(currentFeatures, currentProducts) {
970
1064
  const featureIds = features.map((feature) => feature.id);
971
1065
  const currentFeatureIds = currentFeatures.map((feature) => feature.id);
972
1066
  const featuresToDelete = featureIds.filter(
973
- (featureId) => !currentFeatureIds.includes(featureId) && !features.archived
1067
+ (featureId) => !currentFeatureIds.includes(featureId) && !features.some(
1068
+ (feature) => feature.id === featureId && feature.archived
1069
+ )
974
1070
  );
975
1071
  const products = await getAllProducts();
976
1072
  const productIds = products.map((product) => product.id);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "atmn",
3
- "version": "0.0.23",
3
+ "version": "0.0.24",
4
4
  "license": "MIT",
5
5
  "bin": "dist/cli.js",
6
6
  "main": "dist/index.js",