@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.
- package/.turbo/turbo-build.log +51 -42
- package/CHANGELOG.md +11 -0
- package/dist/cli.js +622 -49
- package/dist/cli.js.map +1 -1
- package/dist/commands/init.d.ts +0 -7
- package/dist/commands/init.js +443 -24
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/login.d.ts +0 -6
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logout.d.ts +0 -5
- package/dist/commands/logout.js.map +1 -1
- package/dist/commands/pull.d.ts +0 -7
- package/dist/commands/pull.js +120 -11
- package/dist/commands/pull.js.map +1 -1
- package/dist/commands/push.js +59 -14
- package/dist/commands/push.js.map +1 -1
- package/dist/commands/templates/ai-agent-platform.d.ts +5 -0
- package/dist/commands/templates/ai-agent-platform.js +119 -0
- package/dist/commands/templates/ai-agent-platform.js.map +1 -0
- package/dist/commands/templates/b2b-saas.js +23 -10
- package/dist/commands/templates/b2b-saas.js.map +1 -1
- package/dist/commands/templates/developer-tools.d.ts +5 -0
- package/dist/commands/templates/developer-tools.js +131 -0
- package/dist/commands/templates/developer-tools.js.map +1 -0
- package/dist/commands/templates/ecommerce-platform.d.ts +5 -0
- package/dist/commands/templates/ecommerce-platform.js +144 -0
- package/dist/commands/templates/ecommerce-platform.js.map +1 -0
- package/dist/commands/templates/index.js +437 -23
- package/dist/commands/templates/index.js.map +1 -1
- package/dist/commands/templates/starter.d.ts +1 -0
- package/dist/commands/templates/starter.js +13 -8
- package/dist/commands/templates/starter.js.map +1 -1
- package/dist/commands/templates/usage-based.js +18 -4
- package/dist/commands/templates/usage-based.js.map +1 -1
- package/dist/utils/auth.d.ts +0 -5
- package/dist/utils/auth.js.map +1 -1
- package/dist/utils/config-loader.d.ts +0 -6
- package/dist/utils/config-loader.js +4 -0
- package/dist/utils/config-loader.js.map +1 -1
- package/package.json +2 -2
- package/src/commands/init.ts +6 -8
- package/src/commands/login.ts +0 -6
- package/src/commands/logout.ts +0 -5
- package/src/commands/pull.ts +148 -60
- package/src/commands/push.ts +67 -16
- package/src/commands/templates/ai-agent-platform.ts +114 -0
- package/src/commands/templates/b2b-saas.ts +23 -10
- package/src/commands/templates/developer-tools.ts +126 -0
- package/src/commands/templates/ecommerce-platform.ts +139 -0
- package/src/commands/templates/index.ts +6 -0
- package/src/commands/templates/starter.ts +14 -8
- package/src/commands/templates/usage-based.ts +18 -4
- package/src/utils/auth.ts +0 -6
- package/src/utils/config-loader.ts +6 -7
- package/tests/integration/pull.test.ts +6 -0
- package/tests/integration/push.test.ts +3 -0
package/src/commands/push.ts
CHANGED
|
@@ -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 {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
180
|
-
chalk.
|
|
181
|
-
|
|
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
|
-
|
|
21
|
-
|
|
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
|
-
|
|
32
|
-
|
|
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
|
-
|
|
26
|
-
|
|
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
|
-
|
|
37
|
-
|
|
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";
|