@revstackhq/cli 0.0.0-dev-20260226064743 → 0.0.0-dev-20260227092523

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.
@@ -1,36 +1,48 @@
1
- [?9001h[?1004h[?25l> @revstackhq/cli@0.0.0-dev-20260226064743 build C:\Users\flava\OneDrive\Desktop\Work\revstack-os\packages\cli
2
- > tsup]0;C:\WINDOWS\system32\cmd.exe[?25hCLI Building entry: src/cli.ts, src/commands/init.ts, src/commands/login.ts, src/commands/logout.ts, src/commands/pull.ts, src/commands/push.ts, src/utils/auth.ts, src/utils/config-loader.ts
1
+ [?9001h[?1004h[?25l> @revstackhq/cli@0.0.0-dev-20260227092523 build C:\Users\flava\OneDrive\Desktop\Work\revstack-os\packages\cli
2
+ > tsup]0;C:\WINDOWS\system32\cmd.exe[?25hCLI Building entry: src/cli.ts, src/commands/init.ts, src/commands/login.ts, src/commands/logout.ts, src/commands/pull.ts, src/commands/push.ts, src/utils/auth.ts, src/utils/config-loader.ts, src/commands/templates/b2b-saas.ts, src/commands/templates/index.ts, src/commands/templates/starter.ts, src/commands/templates/usage-based.ts
3
3
  CLI Using tsconfig: tsconfig.json
4
4
  CLI tsup v8.5.1
5
- CLI Using tsup config: C:\Users\flava\OneDrive\Desktop\Work\revstack-os\packages\cli\tsup.config.ts
6
- CLI Target: node18
5
+ CLI Using tsup config: C:\Users\flava\OneDrive\Desktop\Work\revstack-os\packages\cli\tsup.config.ts
6
+ CLI Target: node18
7
7
  CLI Cleaning output folder
8
8
  ESM Build start
9
- ESM dist\cli.js 18.65 KB
10
- ESM dist\commands\logout.js 1.17 KB
11
- ESM dist\commands\login.js 1.42 KB
12
- ESM dist\commands\init.js 5.41 KB
13
- ESM dist\commands\pull.js 6.22 KB
14
- ESM dist\commands\push.js 5.31 KB
15
- ESM dist\utils\auth.js 971.00 B
16
- ESM dist\utils\config-loader.js 1.05 KB
17
- ESM dist\cli.js.map 39.75 KB
18
- ESM dist\commands\logout.js.map 3.03 KB
19
- ESM dist\commands\login.js.map 3.70 KB
20
- ESM dist\commands\init.js.map 9.97 KB
21
- ESM dist\commands\pull.js.map 14.06 KB
22
- ESM dist\utils\auth.js.map 2.24 KB
23
- ESM dist\commands\push.js.map 13.02 KB
24
- ESM dist\utils\config-loader.js.map 2.55 KB
25
- ESM ⚡️ Build success in 131ms
9
+ ESM dist\cli.js 25.74 KB
10
+ ESM dist\commands\templates\b2b-saas.js 2.85 KB
11
+ ESM dist\commands\login.js 1.42 KB
12
+ ESM dist\commands\init.js 11.53 KB
13
+ ESM dist\utils\config-loader.js 1.05 KB
14
+ ESM dist\utils\auth.js 971.00 B
15
+ ESM dist\commands\logout.js 1.17 KB
16
+ ESM dist\commands\pull.js 6.22 KB
17
+ ESM dist\commands\push.js 6.27 KB
18
+ ESM dist\commands\templates\starter.js 2.27 KB
19
+ ESM dist\commands\templates\usage-based.js 2.02 KB
20
+ ESM dist\commands\templates\index.js 7.09 KB
21
+ ESM dist\cli.js.map 50.88 KB
22
+ ESM dist\commands\login.js.map 3.70 KB
23
+ ESM dist\commands\templates\b2b-saas.js.map 3.84 KB
24
+ ESM dist\commands\init.js.map 19.25 KB
25
+ ESM dist\utils\config-loader.js.map 2.55 KB
26
+ ESM dist\commands\logout.js.map 3.03 KB
27
+ ESM dist\utils\auth.js.map 2.24 KB
28
+ ESM dist\commands\pull.js.map 14.06 KB
29
+ ESM dist\commands\templates\usage-based.js.map 2.75 KB
30
+ ESM dist\commands\templates\starter.js.map 3.21 KB
31
+ ESM dist\commands\push.js.map 14.83 KB
32
+ ESM dist\commands\templates\index.js.map 10.15 KB
33
+ ESM ⚡️ Build success in 81ms
26
34
  DTS Build start
27
- DTS ⚡️ Build success in 3515ms
28
- DTS dist\cli.d.ts 13.00 B
29
- DTS dist\commands\init.d.ts 353.00 B
30
- DTS dist\commands\login.d.ts 288.00 B
31
- DTS dist\commands\logout.d.ts 192.00 B
32
- DTS dist\commands\pull.d.ts 334.00 B
33
- DTS dist\commands\push.d.ts 328.00 B
34
- DTS dist\utils\auth.d.ts 637.00 B
35
- DTS dist\utils\config-loader.d.ts 566.00 B
35
+ DTS ⚡️ Build success in 7779ms
36
+ DTS dist\cli.d.ts 13.00 B
37
+ DTS dist\commands\init.d.ts 353.00 B
38
+ DTS dist\commands\login.d.ts 288.00 B
39
+ DTS dist\commands\logout.d.ts 192.00 B
40
+ DTS dist\commands\pull.d.ts 334.00 B
41
+ DTS dist\commands\push.d.ts 328.00 B
42
+ DTS dist\utils\auth.d.ts 637.00 B
43
+ DTS dist\utils\config-loader.d.ts 566.00 B
44
+ DTS dist\commands\templates\b2b-saas.d.ts 108.00 B
45
+ DTS dist\commands\templates\index.d.ts 144.00 B
46
+ DTS dist\commands\templates\usage-based.d.ts 114.00 B
47
+ DTS dist\commands\templates\starter.d.ts 208.00 B
36
48
  [?9001l[?1004l
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @revstackhq/cli
2
2
 
3
+ ## 0.0.0-dev-20260227092523
4
+
5
+ ### Minor Changes
6
+
7
+ - implement modular enterprise configuration structure and interactive addons in init command
8
+
3
9
  ## 0.0.0-dev-20260226064743
4
10
 
5
11
  ### Patch Changes
package/README.md CHANGED
@@ -32,12 +32,14 @@ Scaffold a new `revstack.config.ts` in your project root:
32
32
  revstack init
33
33
  ```
34
34
 
35
- This creates a starter config with example plans and features using the type-safe helpers from `@revstackhq/core`:
35
+ This creates a `revstack/` directory and a `revstack.config.ts` file in your project root, scaffolding a starter config with example plans and features using type-safe helpers from `@revstackhq/core`:
36
+
37
+ **`revstack/features.ts`**
36
38
 
37
39
  ```typescript
38
- import { defineConfig, definePlan, defineFeature } from "@revstackhq/core";
40
+ import { defineFeature } from "@revstackhq/core";
39
41
 
40
- const features = {
42
+ export const features = {
41
43
  seats: defineFeature({
42
44
  name: "Seats",
43
45
  type: "static",
@@ -49,44 +51,62 @@ const features = {
49
51
  unit_type: "count",
50
52
  }),
51
53
  };
54
+ ```
55
+
56
+ **`revstack/plans.ts`**
57
+
58
+ ```typescript
59
+ import { definePlan } from "@revstackhq/core";
60
+ import { features } from "./features";
61
+
62
+ export const plans = {
63
+ // DO NOT DELETE: Automatically created default plan for guests.
64
+ default: definePlan<typeof features>({
65
+ name: "Default",
66
+ description: "Automatically created default plan for guests.",
67
+ is_default: true,
68
+ is_public: false,
69
+ type: "free",
70
+ features: {},
71
+ }),
72
+ pro: definePlan<typeof features>({
73
+ name: "Pro",
74
+ description: "For professional teams.",
75
+ is_default: false,
76
+ is_public: true,
77
+ type: "paid",
78
+ prices: [
79
+ {
80
+ amount: 2900,
81
+ currency: "USD",
82
+ billing_interval: "monthly",
83
+ trial_period_days: 14,
84
+ },
85
+ {
86
+ amount: 29000,
87
+ currency: "USD",
88
+ billing_interval: "yearly",
89
+ trial_period_days: 14,
90
+ },
91
+ ],
92
+ features: {
93
+ seats: { value_limit: 5, is_hard_limit: true },
94
+ ai_tokens: { value_limit: 1000, reset_period: "monthly" },
95
+ },
96
+ }),
97
+ };
98
+ ```
99
+
100
+ **`revstack.config.ts`**
101
+
102
+ ```typescript
103
+ import { defineConfig } from "@revstackhq/core";
104
+ import { features } from "./revstack/features";
105
+ import { plans } from "./revstack/plans";
52
106
 
53
107
  export default defineConfig({
54
108
  features,
55
- plans: {
56
- default: definePlan<typeof features>({
57
- name: "Default",
58
- description: "Automatically created default plan for guests.",
59
- is_default: true,
60
- is_public: false,
61
- type: "free",
62
- features: {},
63
- }),
64
- pro: definePlan<typeof features>({
65
- name: "Pro",
66
- description: "For professional teams.",
67
- is_default: false,
68
- is_public: true,
69
- type: "paid",
70
- prices: [
71
- {
72
- amount: 2900,
73
- currency: "USD",
74
- billing_interval: "monthly",
75
- trial_period_days: 14,
76
- },
77
- {
78
- amount: 29000,
79
- currency: "USD",
80
- billing_interval: "yearly",
81
- trial_period_days: 14,
82
- },
83
- ],
84
- features: {
85
- seats: { value_limit: 5, is_hard_limit: true },
86
- ai_tokens: { value_limit: 1000, reset_period: "monthly" },
87
- },
88
- }),
89
- },
109
+ plans,
90
110
  });
91
111
  ```
92
112
 
package/dist/cli.js CHANGED
@@ -89,22 +89,45 @@ import path2 from "path";
89
89
  import { spawnSync } from "child_process";
90
90
  import { fileURLToPath } from "url";
91
91
  import ora from "ora";
92
- var STARTER_FEATURES = `import { defineFeature } from "@revstackhq/core";
92
+
93
+ // src/commands/templates/starter.ts
94
+ var starter = {
95
+ features: `import { defineFeature } from "@revstackhq/core";
93
96
 
94
97
  export const features = {
95
- seats: defineFeature({
96
- name: "Seats",
97
- type: "static",
98
- unit_type: "count",
99
- }),
100
- ai_tokens: defineFeature({
101
- name: "AI Tokens",
102
- type: "metered",
103
- unit_type: "count",
98
+ seats: defineFeature({ name: "Seats", type: "static", unit_type: "count" }),
99
+ priority_support: defineFeature({ name: "Priority Support", type: "boolean", unit_type: "custom" }),
100
+ };
101
+ `,
102
+ addons: `import { defineAddon } from "@revstackhq/core";
103
+ import { features } from "./features";
104
+
105
+ export const addons = {
106
+ extra_seats: defineAddon<typeof features>({
107
+ name: "5 Extra Seats",
108
+ description: "Add 5 more team members to your workspace.",
109
+ type: "recurring",
110
+ prices: [
111
+ { amount: 1500, currency: "USD", billing_interval: "monthly" }
112
+ ],
113
+ features: {
114
+ seats: { value_limit: 5, type: "increment", is_hard_limit: false },
115
+ }
104
116
  }),
117
+ vip_support: defineAddon<typeof features>({
118
+ name: "Priority Support",
119
+ description: "24/7 Slack channel support.",
120
+ type: "recurring",
121
+ prices: [
122
+ { amount: 9900, currency: "USD", billing_interval: "monthly" }
123
+ ],
124
+ features: {
125
+ priority_support: { has_access: true },
126
+ }
127
+ })
105
128
  };
106
- `;
107
- var STARTER_PLANS = `import { definePlan } from "@revstackhq/core";
129
+ `,
130
+ plans: `import { definePlan } from "@revstackhq/core";
108
131
  import { features } from "./features";
109
132
 
110
133
  export const plans = {
@@ -123,54 +146,260 @@ export const plans = {
123
146
  is_default: false,
124
147
  is_public: true,
125
148
  type: "paid",
149
+ available_addons: ["extra_seats", "vip_support"],
126
150
  prices: [
127
- {
128
- amount: 2900,
129
- currency: "USD",
130
- billing_interval: "monthly",
131
- trial_period_days: 14,
132
- },
133
- {
134
- amount: 29000,
135
- currency: "USD",
136
- billing_interval: "yearly",
137
- trial_period_days: 14,
138
- }
151
+ { amount: 2900, currency: "USD", billing_interval: "monthly", trial_period_days: 14 }
139
152
  ],
140
153
  features: {
141
154
  seats: { value_limit: 5, is_hard_limit: true },
142
- ai_tokens: { value_limit: 1000, reset_period: "monthly" },
143
155
  },
144
156
  }),
145
157
  };
146
- `;
147
- var STARTER_CONFIG = `import { defineConfig } from "@revstackhq/core";
148
- import { features } from "./revstack/features";
149
- import { plans } from "./revstack/plans";
158
+ `,
159
+ index: `import { defineConfig } from "@revstackhq/core";
160
+ import { features } from "./features";
161
+ import { addons } from "./addons";
162
+ import { plans } from "./plans";
150
163
 
151
164
  export default defineConfig({
152
165
  features,
166
+ addons,
153
167
  plans,
154
168
  });
155
- `;
156
- var initCommand = new Command3("init").description("Scaffold a new revstack.config.ts in the current directory").action(async () => {
169
+ `,
170
+ root: `import config from "./revstack";
171
+
172
+ export default config;
173
+ `
174
+ };
175
+
176
+ // src/commands/templates/b2b-saas.ts
177
+ var b2bSaas = {
178
+ features: `import { defineFeature } from "@revstackhq/core";
179
+
180
+ export const features = {
181
+ active_users: defineFeature({ name: "Active Users", type: "static", unit_type: "count" }),
182
+ api_access: defineFeature({ name: "API Access", type: "boolean", unit_type: "custom" }),
183
+ custom_domain: defineFeature({ name: "Custom Domain", type: "boolean", unit_type: "custom" }),
184
+ };
185
+ `,
186
+ addons: `import { defineAddon } from "@revstackhq/core";
187
+ import { features } from "./features";
188
+
189
+ export const addons = {
190
+ extra_users: defineAddon<typeof features>({
191
+ name: "10 Extra Users",
192
+ description: "Add 10 more active users to your workspace.",
193
+ type: "recurring",
194
+ prices: [
195
+ { amount: 5000, currency: "USD", billing_interval: "monthly" }
196
+ ],
197
+ features: {
198
+ active_users: { value_limit: 10, type: "increment", is_hard_limit: true },
199
+ }
200
+ }),
201
+ dedicated_support: defineAddon<typeof features>({
202
+ name: "Dedicated Support",
203
+ description: "Enterprise SLA with 1-hour response time.",
204
+ type: "recurring",
205
+ prices: [
206
+ { amount: 49900, currency: "USD", billing_interval: "monthly" }
207
+ ],
208
+ features: {}
209
+ })
210
+ };
211
+ `,
212
+ plans: `import { definePlan } from "@revstackhq/core";
213
+ import { features } from "./features";
214
+
215
+ export const plans = {
216
+ default: definePlan<typeof features>({
217
+ name: "Default",
218
+ description: "Automatically created default plan for guests.",
219
+ is_default: true,
220
+ is_public: false,
221
+ type: "free",
222
+ features: {},
223
+ }),
224
+ startup: definePlan<typeof features>({
225
+ name: "Startup",
226
+ description: "For small teams getting started.",
227
+ is_default: false,
228
+ is_public: true,
229
+ type: "paid",
230
+ available_addons: ["extra_users"],
231
+ prices: [
232
+ { amount: 9900, currency: "USD", billing_interval: "monthly" }
233
+ ],
234
+ features: {
235
+ active_users: { value_limit: 10, is_hard_limit: true },
236
+ api_access: { value_bool: false },
237
+ custom_domain: { value_bool: false },
238
+ },
239
+ }),
240
+ enterprise: definePlan<typeof features>({
241
+ name: "Enterprise",
242
+ description: "Advanced features for scale.",
243
+ is_default: false,
244
+ is_public: true,
245
+ type: "paid",
246
+ available_addons: ["extra_users", "dedicated_support"],
247
+ prices: [
248
+ { amount: 49900, currency: "USD", billing_interval: "monthly" }
249
+ ],
250
+ features: {
251
+ active_users: { value_limit: 100, is_hard_limit: false },
252
+ api_access: { value_bool: true },
253
+ custom_domain: { value_bool: true },
254
+ },
255
+ }),
256
+ };
257
+ `,
258
+ index: `import { defineConfig } from "@revstackhq/core";
259
+ import { features } from "./features";
260
+ import { addons } from "./addons";
261
+ import { plans } from "./plans";
262
+
263
+ export default defineConfig({
264
+ features,
265
+ addons,
266
+ plans,
267
+ });
268
+ `,
269
+ root: `import config from "./revstack";
270
+
271
+ export default config;
272
+ `
273
+ };
274
+
275
+ // src/commands/templates/usage-based.ts
276
+ var usageBased = {
277
+ features: `import { defineFeature } from "@revstackhq/core";
278
+
279
+ export const features = {
280
+ api_requests: defineFeature({ name: "API Requests", type: "metered", unit_type: "requests" }),
281
+ storage_gb: defineFeature({ name: "Storage (GB)", type: "metered", unit_type: "custom" }),
282
+ };
283
+ `,
284
+ addons: `import { defineAddon } from "@revstackhq/core";
285
+ import { features } from "./features";
286
+
287
+ export const addons = {
288
+ premium_support: defineAddon<typeof features>({
289
+ name: "Premium Support",
290
+ description: "24/7 dedicated support.",
291
+ type: "recurring",
292
+ prices: [
293
+ { amount: 20000, currency: "USD", billing_interval: "monthly" }
294
+ ],
295
+ features: {}
296
+ })
297
+ };
298
+ `,
299
+ plans: `import { definePlan } from "@revstackhq/core";
300
+ import { features } from "./features";
301
+
302
+ export const plans = {
303
+ default: definePlan<typeof features>({
304
+ name: "Default",
305
+ description: "Automatically created default plan for guests.",
306
+ is_default: true,
307
+ is_public: false,
308
+ type: "free",
309
+ features: {},
310
+ }),
311
+ pay_as_you_go: definePlan<typeof features>({
312
+ name: "Pay As You Go",
313
+ description: "Flexible usage-based pricing.",
314
+ is_default: false,
315
+ is_public: true,
316
+ type: "paid",
317
+ available_addons: ["premium_support"],
318
+ prices: [
319
+ { amount: 0, currency: "USD", billing_interval: "monthly" } // Base platform fee
320
+ ],
321
+ features: {
322
+ api_requests: { value_limit: 10000, is_hard_limit: false, reset_period: "monthly" }, // 10k free requests per month
323
+ storage_gb: { value_limit: 5, is_hard_limit: false, reset_period: "never" }, // 5GB free storage lifetime
324
+ },
325
+ }),
326
+ };
327
+ `,
328
+ index: `import { defineConfig } from "@revstackhq/core";
329
+ import { features } from "./features";
330
+ import { addons } from "./addons";
331
+ import { plans } from "./plans";
332
+
333
+ export default defineConfig({
334
+ features,
335
+ addons,
336
+ plans,
337
+ });
338
+ `,
339
+ root: `import config from "./revstack";
340
+
341
+ export default config;
342
+ `
343
+ };
344
+
345
+ // src/commands/templates/index.ts
346
+ var TEMPLATES = {
347
+ starter,
348
+ "b2b-saas": b2bSaas,
349
+ "usage-based": usageBased
350
+ };
351
+
352
+ // src/commands/init.ts
353
+ var initCommand = new Command3("init").description("Scaffold a new revstack.config.ts in the current directory").option(
354
+ "-t, --template <name>",
355
+ "Choose a starting template (starter, b2b-saas, usage-based)",
356
+ "starter"
357
+ ).action(async (options) => {
358
+ const templateName = options.template || "starter";
359
+ const template = TEMPLATES[templateName];
360
+ if (!template) {
361
+ console.log(
362
+ chalk3.red(
363
+ `
364
+ \u2716 Unknown template "${templateName}". Available templates: ${Object.keys(TEMPLATES).join(", ")}
365
+ `
366
+ )
367
+ );
368
+ process.exit(1);
369
+ }
157
370
  const cwd = process.cwd();
158
371
  const configPath = path2.resolve(cwd, "revstack.config.ts");
159
- const revstackDir = path2.resolve(cwd, "revstack");
160
- const featuresPath = path2.resolve(revstackDir, "features.ts");
161
- const plansPath = path2.resolve(revstackDir, "plans.ts");
162
372
  if (fs2.existsSync(configPath)) {
163
373
  console.log(
164
374
  "\n" + chalk3.yellow(" \u26A0 revstack.config.ts already exists.\n") + chalk3.dim(" Delete it first if you want to start fresh.\n")
165
375
  );
166
376
  process.exit(1);
167
377
  }
378
+ const revstackDir = path2.resolve(cwd, "revstack");
168
379
  if (!fs2.existsSync(revstackDir)) {
169
380
  fs2.mkdirSync(revstackDir, { recursive: true });
170
381
  }
171
- fs2.writeFileSync(featuresPath, STARTER_FEATURES, "utf-8");
172
- fs2.writeFileSync(plansPath, STARTER_PLANS, "utf-8");
173
- fs2.writeFileSync(configPath, STARTER_CONFIG, "utf-8");
382
+ fs2.writeFileSync(
383
+ path2.resolve(revstackDir, "features.ts"),
384
+ template.features,
385
+ "utf-8"
386
+ );
387
+ fs2.writeFileSync(
388
+ path2.resolve(revstackDir, "addons.ts"),
389
+ template.addons,
390
+ "utf-8"
391
+ );
392
+ fs2.writeFileSync(
393
+ path2.resolve(revstackDir, "plans.ts"),
394
+ template.plans,
395
+ "utf-8"
396
+ );
397
+ fs2.writeFileSync(
398
+ path2.resolve(revstackDir, "index.ts"),
399
+ template.index,
400
+ "utf-8"
401
+ );
402
+ fs2.writeFileSync(configPath, template.root, "utf-8");
174
403
  let packageManager = "npm";
175
404
  if (fs2.existsSync(path2.resolve(cwd, "pnpm-lock.yaml"))) {
176
405
  packageManager = "pnpm";
@@ -268,6 +497,7 @@ async function loadLocalConfig(cwd) {
268
497
  }
269
498
 
270
499
  // src/commands/push.ts
500
+ import { validateConfig, RevstackValidationError } from "@revstackhq/core";
271
501
  var API_BASE = "https://app.revstack.dev";
272
502
  var DIFF_ICONS = {
273
503
  added: chalk5.green(" + "),
@@ -310,6 +540,37 @@ function requireAuth() {
310
540
  var pushCommand = new Command4("push").description("Push your local billing config to Revstack Cloud").option("-e, --env <environment>", "Target environment", "test").action(async (options) => {
311
541
  const apiKey = requireAuth();
312
542
  const config = await loadLocalConfig(process.cwd());
543
+ const validationSpinner = ora2({
544
+ text: "Validating billing configuration...",
545
+ prefixText: " "
546
+ }).start();
547
+ try {
548
+ validateConfig(config);
549
+ validationSpinner.succeed("Configuration validated");
550
+ } catch (error) {
551
+ if (error instanceof RevstackValidationError || error?.name === "RevstackValidationError") {
552
+ validationSpinner.fail("Configuration invalid");
553
+ console.error(
554
+ chalk5.red(
555
+ "\n \u2716 The billing configuration contains business logic errors:\n"
556
+ )
557
+ );
558
+ for (const err of error.errors || []) {
559
+ console.error(chalk5.red(` \u2022 ${err}`));
560
+ }
561
+ console.log();
562
+ process.exit(1);
563
+ }
564
+ validationSpinner.fail("Validation failed");
565
+ console.error(
566
+ chalk5.red(
567
+ `
568
+ An unexpected error occurred during validation: ${error?.message || String(error)}
569
+ `
570
+ )
571
+ );
572
+ process.exit(1);
573
+ }
313
574
  const spinner = ora2({
314
575
  text: "Calculating diff...",
315
576
  prefixText: " "