@revstackhq/cli 0.0.0-dev-20260227103607 → 0.0.0-dev-20260228060138

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 (56) hide show
  1. package/.turbo/turbo-build.log +51 -42
  2. package/CHANGELOG.md +11 -0
  3. package/dist/cli.js +622 -49
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/init.d.ts +0 -7
  6. package/dist/commands/init.js +443 -24
  7. package/dist/commands/init.js.map +1 -1
  8. package/dist/commands/login.d.ts +0 -6
  9. package/dist/commands/login.js.map +1 -1
  10. package/dist/commands/logout.d.ts +0 -5
  11. package/dist/commands/logout.js.map +1 -1
  12. package/dist/commands/pull.d.ts +0 -7
  13. package/dist/commands/pull.js +120 -11
  14. package/dist/commands/pull.js.map +1 -1
  15. package/dist/commands/push.js +59 -14
  16. package/dist/commands/push.js.map +1 -1
  17. package/dist/commands/templates/ai-agent-platform.d.ts +5 -0
  18. package/dist/commands/templates/ai-agent-platform.js +119 -0
  19. package/dist/commands/templates/ai-agent-platform.js.map +1 -0
  20. package/dist/commands/templates/b2b-saas.js +23 -10
  21. package/dist/commands/templates/b2b-saas.js.map +1 -1
  22. package/dist/commands/templates/developer-tools.d.ts +5 -0
  23. package/dist/commands/templates/developer-tools.js +131 -0
  24. package/dist/commands/templates/developer-tools.js.map +1 -0
  25. package/dist/commands/templates/ecommerce-platform.d.ts +5 -0
  26. package/dist/commands/templates/ecommerce-platform.js +144 -0
  27. package/dist/commands/templates/ecommerce-platform.js.map +1 -0
  28. package/dist/commands/templates/index.js +437 -23
  29. package/dist/commands/templates/index.js.map +1 -1
  30. package/dist/commands/templates/starter.d.ts +1 -0
  31. package/dist/commands/templates/starter.js +13 -8
  32. package/dist/commands/templates/starter.js.map +1 -1
  33. package/dist/commands/templates/usage-based.js +18 -4
  34. package/dist/commands/templates/usage-based.js.map +1 -1
  35. package/dist/utils/auth.d.ts +0 -5
  36. package/dist/utils/auth.js.map +1 -1
  37. package/dist/utils/config-loader.d.ts +0 -6
  38. package/dist/utils/config-loader.js +4 -0
  39. package/dist/utils/config-loader.js.map +1 -1
  40. package/package.json +2 -2
  41. package/src/commands/init.ts +6 -8
  42. package/src/commands/login.ts +0 -6
  43. package/src/commands/logout.ts +0 -5
  44. package/src/commands/pull.ts +148 -60
  45. package/src/commands/push.ts +67 -16
  46. package/src/commands/templates/ai-agent-platform.ts +114 -0
  47. package/src/commands/templates/b2b-saas.ts +23 -10
  48. package/src/commands/templates/developer-tools.ts +126 -0
  49. package/src/commands/templates/ecommerce-platform.ts +139 -0
  50. package/src/commands/templates/index.ts +6 -0
  51. package/src/commands/templates/starter.ts +14 -8
  52. package/src/commands/templates/usage-based.ts +18 -4
  53. package/src/utils/auth.ts +0 -6
  54. package/src/utils/config-loader.ts +6 -7
  55. package/tests/integration/pull.test.ts +6 -0
  56. package/tests/integration/push.test.ts +3 -0
@@ -11,7 +11,11 @@ import prompts from "prompts";
11
11
  import ora from "ora";
12
12
  import { getApiKey } from "@/utils/auth";
13
13
  import { loadLocalConfig } from "@/utils/config-loader";
14
- import { validateConfig, RevstackValidationError } from "@revstackhq/core";
14
+ import {
15
+ validateConfig,
16
+ RevstackValidationError,
17
+ RevstackConfigSchema,
18
+ } from "@revstackhq/core";
15
19
 
16
20
  // ─── Types ───────────────────────────────────────────────────
17
21
 
@@ -44,7 +48,7 @@ const DIFF_COLORS: Record<DiffEntry["action"], (text: string) => string> = {
44
48
  updated: chalk.yellow,
45
49
  };
46
50
 
47
- function printDiff(diff: DiffEntry[]): void {
51
+ function printDiff(diff: DiffEntry[], env: string): void {
48
52
  if (diff.length === 0) {
49
53
  console.log(
50
54
  chalk.dim("\n No changes detected. Your config is up to date.\n"),
@@ -52,18 +56,43 @@ function printDiff(diff: DiffEntry[]): void {
52
56
  return;
53
57
  }
54
58
 
55
- console.log(chalk.bold("\n Changes:\n"));
56
-
57
- for (const entry of diff) {
58
- const icon = DIFF_ICONS[entry.action];
59
- const color = DIFF_COLORS[entry.action];
60
- const label = chalk.dim(`[${entry.entity}]`);
59
+ if (env === "production") {
61
60
  console.log(
62
- `${icon}${color(entry.id)} ${label} ${chalk.white(entry.message)}`,
61
+ chalk.bgRed.white.bold("\n ⚠️ YOU ARE PUSHING TO PRODUCTION ⚠️ \n"),
63
62
  );
63
+ } else {
64
+ console.log(chalk.bold("\n Changes:\n"));
64
65
  }
65
66
 
66
- console.log();
67
+ const groups: Record<string, DiffEntry[]> = {};
68
+ for (const entry of diff) {
69
+ if (!groups[entry.entity]) groups[entry.entity] = [];
70
+ groups[entry.entity].push(entry);
71
+ }
72
+
73
+ let added = 0;
74
+ let updated = 0;
75
+ let removed = 0;
76
+
77
+ for (const [entityName, entries] of Object.entries(groups)) {
78
+ console.log(chalk.dim(` ${entityName}s`));
79
+ for (const entry of entries) {
80
+ if (entry.action === "added") added++;
81
+ if (entry.action === "updated") updated++;
82
+ if (entry.action === "removed") removed++;
83
+
84
+ const icon = DIFF_ICONS[entry.action];
85
+ const color = DIFF_COLORS[entry.action];
86
+ console.log(`${icon}${color(entry.id)} ${chalk.white(entry.message)}`);
87
+ }
88
+ console.log();
89
+ }
90
+
91
+ console.log(
92
+ chalk.bold(
93
+ ` Summary: ${added} added, ${updated} updated, ${removed} removed\n`,
94
+ ),
95
+ );
67
96
  }
68
97
 
69
98
  function requireAuth(): string {
@@ -100,14 +129,34 @@ export const pushCommand = new Command("push")
100
129
  }).start();
101
130
 
102
131
  try {
103
- validateConfig(config as any); // cast to match RevstackConfig expected by validateConfig
132
+ // Tier 1: Structural Validation
133
+ const parsedConfig = RevstackConfigSchema.parse(config);
134
+
135
+ // Tier 2: Business Logic Validation
136
+ validateConfig(parsedConfig as any);
137
+
104
138
  validationSpinner.succeed("Configuration validated");
105
139
  } catch (error: any) {
140
+ validationSpinner.fail("Configuration invalid");
141
+
142
+ if (error?.name === "ZodError") {
143
+ console.error(
144
+ chalk.red(
145
+ "\n ✖ The billing configuration contains schema/formatting errors:\n",
146
+ ),
147
+ );
148
+ for (const err of error.errors || []) {
149
+ const path = err.path.join(".");
150
+ console.error(chalk.red(` • [${path}] ${err.message}`));
151
+ }
152
+ console.log();
153
+ process.exit(1);
154
+ }
155
+
106
156
  if (
107
157
  error instanceof RevstackValidationError ||
108
158
  error?.name === "RevstackValidationError"
109
159
  ) {
110
- validationSpinner.fail("Configuration invalid");
111
160
  console.error(
112
161
  chalk.red(
113
162
  "\n ✖ The billing configuration contains business logic errors:\n",
@@ -166,7 +215,7 @@ export const pushCommand = new Command("push")
166
215
 
167
216
  // ── Step 2: Present diff ──────────────────────────────────
168
217
 
169
- printDiff(diffResponse.diff);
218
+ printDiff(diffResponse.diff, options.env);
170
219
 
171
220
  if (diffResponse.diff.length === 0) {
172
221
  return;
@@ -176,9 +225,11 @@ export const pushCommand = new Command("push")
176
225
 
177
226
  if (!diffResponse.canPush) {
178
227
  console.log(
179
- chalk.red(" ✖ Push is blocked.\n") +
180
- chalk.dim(
181
- ` ${diffResponse.blockedReason ?? "The server rejected this configuration."}\n`,
228
+ "\n" +
229
+ chalk.bgRed.white.bold(" BLOCKED: PUSH IMPOSSIBLE ") +
230
+ "\n\n" +
231
+ chalk.red(
232
+ ` ✖ ${diffResponse.blockedReason ?? "The server rejected this configuration due to destructive changes."}\n`,
182
233
  ),
183
234
  );
184
235
  process.exit(1);
@@ -0,0 +1,114 @@
1
+ import { TemplateConfig } from "./starter";
2
+
3
+ export const aiAgentPlatform: TemplateConfig = {
4
+ features: `import { defineFeature } from "@revstackhq/core";
5
+
6
+ export const features = {
7
+ llm_tokens: defineFeature({ name: "LLM Tokens (Input+Output)", type: "metered", unit_type: "count" }),
8
+ active_agents: defineFeature({ name: "Concurrent Agents", type: "static", unit_type: "count" }),
9
+ vector_storage_gb: defineFeature({ name: "Vector Database (GB)", type: "metered", unit_type: "custom" }),
10
+ custom_fine_tuning: defineFeature({ name: "Model Fine-Tuning", type: "boolean", unit_type: "custom" })
11
+ };
12
+ `,
13
+ addons: `import { defineAddon } from "@revstackhq/core";
14
+ import { features } from "./features";
15
+
16
+ export const addons = {
17
+ extra_vector_storage: defineAddon<typeof features>({
18
+ name: "10GB Vector Storage Block",
19
+ description: "Retain long-term memory for your AI agents.",
20
+ type: "recurring",
21
+ amount: 1000,
22
+ currency: "USD",
23
+ billing_interval: "monthly",
24
+ features: {
25
+ vector_storage_gb: { value_limit: 10, type: "increment", is_hard_limit: false }
26
+ }
27
+ }),
28
+ fine_tuning_job: defineAddon<typeof features>({
29
+ name: "Fine-Tuning Job Runner",
30
+ description: "Pay once to run a distributed model fine-tuning job on your dataset.",
31
+ type: "one_time",
32
+ amount: 25000,
33
+ currency: "USD",
34
+ features: {
35
+ custom_fine_tuning: { has_access: true }
36
+ }
37
+ })
38
+ };
39
+ `,
40
+ plans: `import { definePlan } from "@revstackhq/core";
41
+ import { features } from "./features";
42
+
43
+ export const plans = {
44
+ default: definePlan<typeof features>({
45
+ name: "Free Preview",
46
+ description: "Trial sandbox using shared models.",
47
+ is_default: true,
48
+ is_public: true,
49
+ type: "free",
50
+ features: {
51
+ llm_tokens: { value_limit: 100000, is_hard_limit: true, reset_period: "monthly" },
52
+ active_agents: { value_limit: 1, is_hard_limit: true },
53
+ vector_storage_gb: { value_limit: 0, is_hard_limit: true, reset_period: "never" },
54
+ custom_fine_tuning: { value_bool: false }
55
+ },
56
+ }),
57
+ builder: definePlan<typeof features>({
58
+ name: "AI Builder",
59
+ description: "High concurrency and dedicated model endpoints.",
60
+ is_default: false,
61
+ is_public: true,
62
+ type: "paid",
63
+ prices: [
64
+ {
65
+ amount: 4900,
66
+ currency: "USD",
67
+ billing_interval: "monthly",
68
+ available_addons: ["extra_vector_storage", "fine_tuning_job"],
69
+ overage_configuration: {
70
+ llm_tokens: { overage_amount: 15, overage_unit: 1000000 } // $0.15 per 1M tokens
71
+ }
72
+ }
73
+ ],
74
+ features: {
75
+ llm_tokens: { value_limit: 10000000, is_hard_limit: false, reset_period: "monthly" }, // 10M free tokens included
76
+ active_agents: { value_limit: 10, is_hard_limit: true },
77
+ vector_storage_gb: { value_limit: 5, is_hard_limit: true, reset_period: "never" }, // Hard limit until they buy the addon
78
+ custom_fine_tuning: { value_bool: false } // Only unlocked via the one-off addon
79
+ },
80
+ }),
81
+ };
82
+ `,
83
+ coupons: `import type { DiscountDef } from "@revstackhq/core";
84
+
85
+ export const coupons: DiscountDef[] = [
86
+ {
87
+ code: "BETA_TESTER",
88
+ name: "Early Beta Access Discount",
89
+ type: "percent",
90
+ value: 50,
91
+ duration: "repeating",
92
+ duration_in_months: 12,
93
+ max_redemptions: 100
94
+ }
95
+ ];
96
+ `,
97
+ index: `import { defineConfig } from "@revstackhq/core";
98
+ import { features } from "./features";
99
+ import { addons } from "./addons";
100
+ import { plans } from "./plans";
101
+ import { coupons } from "./coupons";
102
+
103
+ export default defineConfig({
104
+ features,
105
+ addons,
106
+ plans,
107
+ coupons,
108
+ });
109
+ `,
110
+ root: `import config from "./revstack";
111
+
112
+ export default config;
113
+ `,
114
+ };
@@ -17,9 +17,9 @@ export const addons = {
17
17
  name: "10 Extra Users",
18
18
  description: "Add 10 more active users to your workspace.",
19
19
  type: "recurring",
20
- prices: [
21
- { amount: 5000, currency: "USD", billing_interval: "monthly" }
22
- ],
20
+ amount: 5000,
21
+ currency: "USD",
22
+ billing_interval: "monthly",
23
23
  features: {
24
24
  active_users: { value_limit: 10, type: "increment", is_hard_limit: true },
25
25
  }
@@ -28,12 +28,25 @@ export const addons = {
28
28
  name: "Dedicated Support",
29
29
  description: "Enterprise SLA with 1-hour response time.",
30
30
  type: "recurring",
31
- prices: [
32
- { amount: 49900, currency: "USD", billing_interval: "monthly" }
33
- ],
31
+ amount: 49900,
32
+ currency: "USD",
33
+ billing_interval: "monthly",
34
34
  features: {}
35
35
  })
36
36
  };
37
+ `,
38
+ coupons: `import type { DiscountDef } from "@revstackhq/core";
39
+
40
+ export const coupons: DiscountDef[] = [
41
+ {
42
+ code: "ENTERPRISE_B2B",
43
+ name: "Annual Contract Rebate",
44
+ type: "amount",
45
+ value: 50000,
46
+ duration: "once",
47
+ applies_to_plans: ["enterprise"]
48
+ }
49
+ ];
37
50
  `,
38
51
  plans: `import { definePlan } from "@revstackhq/core";
39
52
  import { features } from "./features";
@@ -53,9 +66,8 @@ export const plans = {
53
66
  is_default: false,
54
67
  is_public: true,
55
68
  type: "paid",
56
- available_addons: ["extra_users"],
57
69
  prices: [
58
- { amount: 9900, currency: "USD", billing_interval: "monthly" }
70
+ { amount: 9900, currency: "USD", billing_interval: "monthly", available_addons: ["extra_users"] }
59
71
  ],
60
72
  features: {
61
73
  active_users: { value_limit: 10, is_hard_limit: true },
@@ -69,9 +81,8 @@ export const plans = {
69
81
  is_default: false,
70
82
  is_public: true,
71
83
  type: "paid",
72
- available_addons: ["extra_users", "dedicated_support"],
73
84
  prices: [
74
- { amount: 49900, currency: "USD", billing_interval: "monthly" }
85
+ { amount: 49900, currency: "USD", billing_interval: "monthly", available_addons: ["extra_users", "dedicated_support"] }
75
86
  ],
76
87
  features: {
77
88
  active_users: { value_limit: 100, is_hard_limit: false },
@@ -85,11 +96,13 @@ export const plans = {
85
96
  import { features } from "./features";
86
97
  import { addons } from "./addons";
87
98
  import { plans } from "./plans";
99
+ import { coupons } from "./coupons";
88
100
 
89
101
  export default defineConfig({
90
102
  features,
91
103
  addons,
92
104
  plans,
105
+ coupons,
93
106
  });
94
107
  `,
95
108
  root: `import config from "./revstack";
@@ -0,0 +1,126 @@
1
+ import { TemplateConfig } from "./starter";
2
+
3
+ export const developerTools: TemplateConfig = {
4
+ features: `import { defineFeature } from "@revstackhq/core";
5
+
6
+ export const features = {
7
+ bandwidth_gb: defineFeature({ name: "Bandwidth (GB)", type: "metered", unit_type: "custom" }),
8
+ compute_hours: defineFeature({ name: "Compute (GB-Hours)", type: "metered", unit_type: "custom" }),
9
+ serverless_invokes: defineFeature({ name: "Serverless Invocations", type: "metered", unit_type: "count" }),
10
+ sso_auth: defineFeature({ name: "Enterprise SSO", type: "boolean", unit_type: "custom" })
11
+ };
12
+ `,
13
+ addons: `import { defineAddon } from "@revstackhq/core";
14
+ import { features } from "./features";
15
+
16
+ export const addons = {
17
+ dedicated_ipv4: defineAddon<typeof features>({
18
+ name: "Dedicated IPv4 Address",
19
+ description: "Assign a static IP to your deployments.",
20
+ type: "recurring",
21
+ amount: 500,
22
+ currency: "USD",
23
+ billing_interval: "monthly",
24
+ features: {}
25
+ }),
26
+ premium_sla: defineAddon<typeof features>({
27
+ name: "Premium Escalation SLA",
28
+ description: "Direct engineering support with 30-min response time.",
29
+ type: "recurring",
30
+ amount: 150000,
31
+ currency: "USD",
32
+ billing_interval: "monthly",
33
+ features: {}
34
+ })
35
+ };
36
+ `,
37
+ plans: `import { definePlan } from "@revstackhq/core";
38
+ import { features } from "./features";
39
+
40
+ export const plans = {
41
+ default: definePlan<typeof features>({
42
+ name: "Hobby",
43
+ description: "For personal or non-commercial projects.",
44
+ is_default: true,
45
+ is_public: true,
46
+ type: "free",
47
+ features: {
48
+ bandwidth_gb: { value_limit: 100, is_hard_limit: true, reset_period: "monthly" },
49
+ compute_hours: { value_limit: 100, is_hard_limit: true, reset_period: "monthly" },
50
+ serverless_invokes: { value_limit: 100000, is_hard_limit: true, reset_period: "monthly" },
51
+ sso_auth: { value_bool: false }
52
+ },
53
+ }),
54
+ pro: definePlan<typeof features>({
55
+ name: "Pro",
56
+ description: "For production apps and growing teams.",
57
+ is_default: false,
58
+ is_public: true,
59
+ type: "paid",
60
+ prices: [
61
+ {
62
+ amount: 2000,
63
+ currency: "USD",
64
+ billing_interval: "monthly",
65
+ available_addons: ["dedicated_ipv4"],
66
+ overage_configuration: {
67
+ bandwidth_gb: { overage_amount: 40, overage_unit: 100 }, // $0.40 per 100GB extra
68
+ compute_hours: { overage_amount: 2, overage_unit: 1 }, // $0.02 per extra GB hr
69
+ serverless_invokes: { overage_amount: 50, overage_unit: 1000000 } // $0.50 per 1M invokes
70
+ }
71
+ }
72
+ ],
73
+ features: {
74
+ bandwidth_gb: { value_limit: 1000, is_hard_limit: false, reset_period: "monthly" },
75
+ compute_hours: { value_limit: 1000, is_hard_limit: false, reset_period: "monthly" },
76
+ serverless_invokes: { value_limit: 5000000, is_hard_limit: false, reset_period: "monthly" },
77
+ sso_auth: { value_bool: false }
78
+ },
79
+ }),
80
+ enterprise: definePlan<typeof features>({
81
+ name: "Enterprise",
82
+ description: "Custom infrastructure and legal compliance.",
83
+ is_default: false,
84
+ is_public: true,
85
+ type: "custom",
86
+ prices: [],
87
+ features: {
88
+ bandwidth_gb: { value_limit: 50000, is_hard_limit: false, reset_period: "monthly" },
89
+ compute_hours: { value_limit: 10000, is_hard_limit: false, reset_period: "monthly" },
90
+ serverless_invokes: { value_limit: 100000000, is_hard_limit: false, reset_period: "monthly" },
91
+ sso_auth: { value_bool: true }
92
+ },
93
+ }),
94
+ };
95
+ `,
96
+ coupons: `import type { DiscountDef } from "@revstackhq/core";
97
+
98
+ export const coupons: DiscountDef[] = [
99
+ {
100
+ code: "YCOMBINATOR",
101
+ name: "YC Startup Accelerator Credit",
102
+ type: "amount",
103
+ value: 1000000, // $10,000 credit
104
+ duration: "forever",
105
+ applies_to_plans: ["pro", "enterprise"]
106
+ }
107
+ ];
108
+ `,
109
+ index: `import { defineConfig } from "@revstackhq/core";
110
+ import { features } from "./features";
111
+ import { addons } from "./addons";
112
+ import { plans } from "./plans";
113
+ import { coupons } from "./coupons";
114
+
115
+ export default defineConfig({
116
+ features,
117
+ addons,
118
+ plans,
119
+ coupons,
120
+ });
121
+ `,
122
+ root: `import config from "./revstack";
123
+
124
+ export default config;
125
+ `,
126
+ };
@@ -0,0 +1,139 @@
1
+ import { TemplateConfig } from "./starter";
2
+
3
+ export const ecommercePlatform: TemplateConfig = {
4
+ features: `import { defineFeature } from "@revstackhq/core";
5
+
6
+ export const features = {
7
+ orders: defineFeature({ name: "Monthly Orders", type: "metered", unit_type: "count" }),
8
+ storefronts: defineFeature({ name: "Storefronts", type: "static", unit_type: "count" }),
9
+ advanced_analytics: defineFeature({ name: "Advanced Analytics", type: "boolean", unit_type: "custom" }),
10
+ };
11
+ `,
12
+ addons: `import { defineAddon } from "@revstackhq/core";
13
+ import { features } from "./features";
14
+
15
+ export const addons = {
16
+ extra_storefront: defineAddon<typeof features>({
17
+ name: "Additional Storefront",
18
+ description: "Launch a new brand under the same account.",
19
+ type: "recurring",
20
+ amount: 5000,
21
+ currency: "USD",
22
+ billing_interval: "monthly",
23
+ features: {
24
+ storefronts: { value_limit: 1, type: "increment", is_hard_limit: true },
25
+ }
26
+ }),
27
+ custom_domain_ssl: defineAddon<typeof features>({
28
+ name: "Custom Domain & SSL",
29
+ description: "Secure your storefront with a custom domain.",
30
+ type: "recurring",
31
+ amount: 1500,
32
+ currency: "USD",
33
+ billing_interval: "monthly",
34
+ features: {}
35
+ })
36
+ };
37
+ `,
38
+ plans: `import { definePlan } from "@revstackhq/core";
39
+ import { features } from "./features";
40
+
41
+ export const plans = {
42
+ default: definePlan<typeof features>({
43
+ name: "Default Sandbox",
44
+ description: "Test your store safely before going live.",
45
+ is_default: true,
46
+ is_public: false,
47
+ type: "free",
48
+ features: {},
49
+ }),
50
+ basic: definePlan<typeof features>({
51
+ name: "Basic Commerce",
52
+ description: "Everything you need to sell online.",
53
+ is_default: false,
54
+ is_public: true,
55
+ type: "paid",
56
+ prices: [
57
+ {
58
+ amount: 2900,
59
+ currency: "USD",
60
+ billing_interval: "monthly",
61
+ available_addons: ["custom_domain_ssl"],
62
+ overage_configuration: {
63
+ orders: { overage_amount: 50, overage_unit: 100 } // $0.50 per 100 extra orders
64
+ }
65
+ }
66
+ ],
67
+ features: {
68
+ orders: { value_limit: 500, is_hard_limit: false, reset_period: "monthly" },
69
+ storefronts: { value_limit: 1, is_hard_limit: true },
70
+ advanced_analytics: { value_bool: false },
71
+ },
72
+ }),
73
+ pro: definePlan<typeof features>({
74
+ name: "Pro Seller",
75
+ description: "For scaling businesses.",
76
+ is_default: false,
77
+ is_public: true,
78
+ type: "paid",
79
+ prices: [
80
+ {
81
+ amount: 19900,
82
+ currency: "USD",
83
+ billing_interval: "monthly",
84
+ available_addons: ["extra_storefront", "custom_domain_ssl"],
85
+ overage_configuration: {
86
+ orders: { overage_amount: 30, overage_unit: 100 } // $0.30 per 100 extra orders
87
+ }
88
+ }
89
+ ],
90
+ features: {
91
+ orders: { value_limit: 5000, is_hard_limit: false, reset_period: "monthly" },
92
+ storefronts: { value_limit: 2, is_hard_limit: true },
93
+ advanced_analytics: { value_bool: true },
94
+ },
95
+ }),
96
+ };
97
+ `,
98
+ coupons: `import type { DiscountDef } from "@revstackhq/core";
99
+
100
+ export const coupons: DiscountDef[] = [
101
+ {
102
+ code: "BFCM_PROMO",
103
+ name: "Black Friday Cyber Monday 20%",
104
+ type: "percent",
105
+ value: 20,
106
+ duration: "repeating",
107
+ duration_in_months: 6,
108
+ expires_at: "2024-11-29T00:00:00Z", // Ephemeral timestamp
109
+ max_redemptions: 5000
110
+ },
111
+ {
112
+ code: "FIRST_MONTH_FREE",
113
+ name: "New Store Launch",
114
+ type: "percent",
115
+ value: 100,
116
+ duration: "repeating",
117
+ duration_in_months: 1,
118
+ applies_to_plans: ["basic"]
119
+ }
120
+ ];
121
+ `,
122
+ index: `import { defineConfig } from "@revstackhq/core";
123
+ import { features } from "./features";
124
+ import { addons } from "./addons";
125
+ import { plans } from "./plans";
126
+ import { coupons } from "./coupons";
127
+
128
+ export default defineConfig({
129
+ features,
130
+ addons,
131
+ plans,
132
+ coupons,
133
+ });
134
+ `,
135
+ root: `import config from "./revstack";
136
+
137
+ export default config;
138
+ `,
139
+ };
@@ -1,12 +1,18 @@
1
1
  import { starter } from "./starter";
2
2
  import { b2bSaas } from "./b2b-saas";
3
3
  import { usageBased } from "./usage-based";
4
+ import { ecommercePlatform } from "./ecommerce-platform";
5
+ import { developerTools } from "./developer-tools";
6
+ import { aiAgentPlatform } from "./ai-agent-platform";
4
7
  import type { TemplateConfig } from "./starter";
5
8
 
6
9
  export const TEMPLATES: Record<string, TemplateConfig> = {
7
10
  starter: starter,
8
11
  "b2b-saas": b2bSaas,
9
12
  "usage-based": usageBased,
13
+ "ecommerce-platform": ecommercePlatform,
14
+ "developer-tools": developerTools,
15
+ "ai-agent-platform": aiAgentPlatform,
10
16
  };
11
17
 
12
18
  export type { TemplateConfig };
@@ -2,6 +2,7 @@ export interface TemplateConfig {
2
2
  features: string;
3
3
  addons: string;
4
4
  plans: string;
5
+ coupons: string;
5
6
  index: string;
6
7
  root: string;
7
8
  }
@@ -22,9 +23,9 @@ export const addons = {
22
23
  name: "5 Extra Seats",
23
24
  description: "Add 5 more team members to your workspace.",
24
25
  type: "recurring",
25
- prices: [
26
- { amount: 1500, currency: "USD", billing_interval: "monthly" }
27
- ],
26
+ amount: 1500,
27
+ currency: "USD",
28
+ billing_interval: "monthly",
28
29
  features: {
29
30
  seats: { value_limit: 5, type: "increment", is_hard_limit: false },
30
31
  }
@@ -33,9 +34,9 @@ export const addons = {
33
34
  name: "Priority Support",
34
35
  description: "24/7 Slack channel support.",
35
36
  type: "recurring",
36
- prices: [
37
- { amount: 9900, currency: "USD", billing_interval: "monthly" }
38
- ],
37
+ amount: 9900,
38
+ currency: "USD",
39
+ billing_interval: "monthly",
39
40
  features: {
40
41
  priority_support: { has_access: true },
41
42
  }
@@ -61,25 +62,30 @@ export const plans = {
61
62
  is_default: false,
62
63
  is_public: true,
63
64
  type: "paid",
64
- available_addons: ["extra_seats", "vip_support"],
65
65
  prices: [
66
- { amount: 2900, currency: "USD", billing_interval: "monthly", trial_period_days: 14 }
66
+ { amount: 2900, currency: "USD", billing_interval: "monthly", trial_period_days: 14, available_addons: ["extra_seats", "vip_support"] }
67
67
  ],
68
68
  features: {
69
69
  seats: { value_limit: 5, is_hard_limit: true },
70
70
  },
71
71
  }),
72
72
  };
73
+ `,
74
+ coupons: `import type { DiscountDef } from "@revstackhq/core";
75
+
76
+ export const coupons: DiscountDef[] = [];
73
77
  `,
74
78
  index: `import { defineConfig } from "@revstackhq/core";
75
79
  import { features } from "./features";
76
80
  import { addons } from "./addons";
77
81
  import { plans } from "./plans";
82
+ import { coupons } from "./coupons";
78
83
 
79
84
  export default defineConfig({
80
85
  features,
81
86
  addons,
82
87
  plans,
88
+ coupons,
83
89
  });
84
90
  `,
85
91
  root: `import config from "./revstack";