@revstackhq/cli 0.0.0-dev-20260227103607 → 0.0.0-dev-20260228062053
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 +18 -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/dist/cli.js
CHANGED
|
@@ -107,9 +107,9 @@ export const addons = {
|
|
|
107
107
|
name: "5 Extra Seats",
|
|
108
108
|
description: "Add 5 more team members to your workspace.",
|
|
109
109
|
type: "recurring",
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
110
|
+
amount: 1500,
|
|
111
|
+
currency: "USD",
|
|
112
|
+
billing_interval: "monthly",
|
|
113
113
|
features: {
|
|
114
114
|
seats: { value_limit: 5, type: "increment", is_hard_limit: false },
|
|
115
115
|
}
|
|
@@ -118,9 +118,9 @@ export const addons = {
|
|
|
118
118
|
name: "Priority Support",
|
|
119
119
|
description: "24/7 Slack channel support.",
|
|
120
120
|
type: "recurring",
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
121
|
+
amount: 9900,
|
|
122
|
+
currency: "USD",
|
|
123
|
+
billing_interval: "monthly",
|
|
124
124
|
features: {
|
|
125
125
|
priority_support: { has_access: true },
|
|
126
126
|
}
|
|
@@ -146,25 +146,30 @@ export const plans = {
|
|
|
146
146
|
is_default: false,
|
|
147
147
|
is_public: true,
|
|
148
148
|
type: "paid",
|
|
149
|
-
available_addons: ["extra_seats", "vip_support"],
|
|
150
149
|
prices: [
|
|
151
|
-
{ amount: 2900, currency: "USD", billing_interval: "monthly", trial_period_days: 14 }
|
|
150
|
+
{ amount: 2900, currency: "USD", billing_interval: "monthly", trial_period_days: 14, available_addons: ["extra_seats", "vip_support"] }
|
|
152
151
|
],
|
|
153
152
|
features: {
|
|
154
153
|
seats: { value_limit: 5, is_hard_limit: true },
|
|
155
154
|
},
|
|
156
155
|
}),
|
|
157
156
|
};
|
|
157
|
+
`,
|
|
158
|
+
coupons: `import type { DiscountDef } from "@revstackhq/core";
|
|
159
|
+
|
|
160
|
+
export const coupons: DiscountDef[] = [];
|
|
158
161
|
`,
|
|
159
162
|
index: `import { defineConfig } from "@revstackhq/core";
|
|
160
163
|
import { features } from "./features";
|
|
161
164
|
import { addons } from "./addons";
|
|
162
165
|
import { plans } from "./plans";
|
|
166
|
+
import { coupons } from "./coupons";
|
|
163
167
|
|
|
164
168
|
export default defineConfig({
|
|
165
169
|
features,
|
|
166
170
|
addons,
|
|
167
171
|
plans,
|
|
172
|
+
coupons,
|
|
168
173
|
});
|
|
169
174
|
`,
|
|
170
175
|
root: `import config from "./revstack";
|
|
@@ -191,9 +196,9 @@ export const addons = {
|
|
|
191
196
|
name: "10 Extra Users",
|
|
192
197
|
description: "Add 10 more active users to your workspace.",
|
|
193
198
|
type: "recurring",
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
199
|
+
amount: 5000,
|
|
200
|
+
currency: "USD",
|
|
201
|
+
billing_interval: "monthly",
|
|
197
202
|
features: {
|
|
198
203
|
active_users: { value_limit: 10, type: "increment", is_hard_limit: true },
|
|
199
204
|
}
|
|
@@ -202,12 +207,25 @@ export const addons = {
|
|
|
202
207
|
name: "Dedicated Support",
|
|
203
208
|
description: "Enterprise SLA with 1-hour response time.",
|
|
204
209
|
type: "recurring",
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
210
|
+
amount: 49900,
|
|
211
|
+
currency: "USD",
|
|
212
|
+
billing_interval: "monthly",
|
|
208
213
|
features: {}
|
|
209
214
|
})
|
|
210
215
|
};
|
|
216
|
+
`,
|
|
217
|
+
coupons: `import type { DiscountDef } from "@revstackhq/core";
|
|
218
|
+
|
|
219
|
+
export const coupons: DiscountDef[] = [
|
|
220
|
+
{
|
|
221
|
+
code: "ENTERPRISE_B2B",
|
|
222
|
+
name: "Annual Contract Rebate",
|
|
223
|
+
type: "amount",
|
|
224
|
+
value: 50000,
|
|
225
|
+
duration: "once",
|
|
226
|
+
applies_to_plans: ["enterprise"]
|
|
227
|
+
}
|
|
228
|
+
];
|
|
211
229
|
`,
|
|
212
230
|
plans: `import { definePlan } from "@revstackhq/core";
|
|
213
231
|
import { features } from "./features";
|
|
@@ -227,9 +245,8 @@ export const plans = {
|
|
|
227
245
|
is_default: false,
|
|
228
246
|
is_public: true,
|
|
229
247
|
type: "paid",
|
|
230
|
-
available_addons: ["extra_users"],
|
|
231
248
|
prices: [
|
|
232
|
-
{ amount: 9900, currency: "USD", billing_interval: "monthly" }
|
|
249
|
+
{ amount: 9900, currency: "USD", billing_interval: "monthly", available_addons: ["extra_users"] }
|
|
233
250
|
],
|
|
234
251
|
features: {
|
|
235
252
|
active_users: { value_limit: 10, is_hard_limit: true },
|
|
@@ -243,9 +260,8 @@ export const plans = {
|
|
|
243
260
|
is_default: false,
|
|
244
261
|
is_public: true,
|
|
245
262
|
type: "paid",
|
|
246
|
-
available_addons: ["extra_users", "dedicated_support"],
|
|
247
263
|
prices: [
|
|
248
|
-
{ amount: 49900, currency: "USD", billing_interval: "monthly" }
|
|
264
|
+
{ amount: 49900, currency: "USD", billing_interval: "monthly", available_addons: ["extra_users", "dedicated_support"] }
|
|
249
265
|
],
|
|
250
266
|
features: {
|
|
251
267
|
active_users: { value_limit: 100, is_hard_limit: false },
|
|
@@ -259,11 +275,13 @@ export const plans = {
|
|
|
259
275
|
import { features } from "./features";
|
|
260
276
|
import { addons } from "./addons";
|
|
261
277
|
import { plans } from "./plans";
|
|
278
|
+
import { coupons } from "./coupons";
|
|
262
279
|
|
|
263
280
|
export default defineConfig({
|
|
264
281
|
features,
|
|
265
282
|
addons,
|
|
266
283
|
plans,
|
|
284
|
+
coupons,
|
|
267
285
|
});
|
|
268
286
|
`,
|
|
269
287
|
root: `import config from "./revstack";
|
|
@@ -289,12 +307,24 @@ export const addons = {
|
|
|
289
307
|
name: "Premium Support",
|
|
290
308
|
description: "24/7 dedicated support.",
|
|
291
309
|
type: "recurring",
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
310
|
+
amount: 20000,
|
|
311
|
+
currency: "USD",
|
|
312
|
+
billing_interval: "monthly",
|
|
295
313
|
features: {}
|
|
296
314
|
})
|
|
297
315
|
};
|
|
316
|
+
`,
|
|
317
|
+
coupons: `import type { DiscountDef } from "@revstackhq/core";
|
|
318
|
+
|
|
319
|
+
export const coupons: DiscountDef[] = [
|
|
320
|
+
{
|
|
321
|
+
code: "STARTUP_ACCELERATOR",
|
|
322
|
+
name: "Startup Program Credits",
|
|
323
|
+
type: "amount",
|
|
324
|
+
value: 500000, // $5,000 credit
|
|
325
|
+
duration: "forever",
|
|
326
|
+
}
|
|
327
|
+
];
|
|
298
328
|
`,
|
|
299
329
|
plans: `import { definePlan } from "@revstackhq/core";
|
|
300
330
|
import { features } from "./features";
|
|
@@ -314,12 +344,12 @@ export const plans = {
|
|
|
314
344
|
is_default: false,
|
|
315
345
|
is_public: true,
|
|
316
346
|
type: "paid",
|
|
317
|
-
available_addons: ["premium_support"],
|
|
318
347
|
prices: [
|
|
319
348
|
{
|
|
320
349
|
amount: 0,
|
|
321
350
|
currency: "USD",
|
|
322
351
|
billing_interval: "monthly",
|
|
352
|
+
available_addons: ["premium_support"],
|
|
323
353
|
overage_configuration: {
|
|
324
354
|
api_requests: { overage_amount: 15, overage_unit: 1000 }, // $0.15 per 1k extra requests
|
|
325
355
|
storage_gb: { overage_amount: 50, overage_unit: 1 }, // $0.50 per extra GB
|
|
@@ -337,11 +367,392 @@ export const plans = {
|
|
|
337
367
|
import { features } from "./features";
|
|
338
368
|
import { addons } from "./addons";
|
|
339
369
|
import { plans } from "./plans";
|
|
370
|
+
import { coupons } from "./coupons";
|
|
371
|
+
|
|
372
|
+
export default defineConfig({
|
|
373
|
+
features,
|
|
374
|
+
addons,
|
|
375
|
+
plans,
|
|
376
|
+
coupons,
|
|
377
|
+
});
|
|
378
|
+
`,
|
|
379
|
+
root: `import config from "./revstack";
|
|
380
|
+
|
|
381
|
+
export default config;
|
|
382
|
+
`
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
// src/commands/templates/ecommerce-platform.ts
|
|
386
|
+
var ecommercePlatform = {
|
|
387
|
+
features: `import { defineFeature } from "@revstackhq/core";
|
|
388
|
+
|
|
389
|
+
export const features = {
|
|
390
|
+
orders: defineFeature({ name: "Monthly Orders", type: "metered", unit_type: "count" }),
|
|
391
|
+
storefronts: defineFeature({ name: "Storefronts", type: "static", unit_type: "count" }),
|
|
392
|
+
advanced_analytics: defineFeature({ name: "Advanced Analytics", type: "boolean", unit_type: "custom" }),
|
|
393
|
+
};
|
|
394
|
+
`,
|
|
395
|
+
addons: `import { defineAddon } from "@revstackhq/core";
|
|
396
|
+
import { features } from "./features";
|
|
397
|
+
|
|
398
|
+
export const addons = {
|
|
399
|
+
extra_storefront: defineAddon<typeof features>({
|
|
400
|
+
name: "Additional Storefront",
|
|
401
|
+
description: "Launch a new brand under the same account.",
|
|
402
|
+
type: "recurring",
|
|
403
|
+
amount: 5000,
|
|
404
|
+
currency: "USD",
|
|
405
|
+
billing_interval: "monthly",
|
|
406
|
+
features: {
|
|
407
|
+
storefronts: { value_limit: 1, type: "increment", is_hard_limit: true },
|
|
408
|
+
}
|
|
409
|
+
}),
|
|
410
|
+
custom_domain_ssl: defineAddon<typeof features>({
|
|
411
|
+
name: "Custom Domain & SSL",
|
|
412
|
+
description: "Secure your storefront with a custom domain.",
|
|
413
|
+
type: "recurring",
|
|
414
|
+
amount: 1500,
|
|
415
|
+
currency: "USD",
|
|
416
|
+
billing_interval: "monthly",
|
|
417
|
+
features: {}
|
|
418
|
+
})
|
|
419
|
+
};
|
|
420
|
+
`,
|
|
421
|
+
plans: `import { definePlan } from "@revstackhq/core";
|
|
422
|
+
import { features } from "./features";
|
|
423
|
+
|
|
424
|
+
export const plans = {
|
|
425
|
+
default: definePlan<typeof features>({
|
|
426
|
+
name: "Default Sandbox",
|
|
427
|
+
description: "Test your store safely before going live.",
|
|
428
|
+
is_default: true,
|
|
429
|
+
is_public: false,
|
|
430
|
+
type: "free",
|
|
431
|
+
features: {},
|
|
432
|
+
}),
|
|
433
|
+
basic: definePlan<typeof features>({
|
|
434
|
+
name: "Basic Commerce",
|
|
435
|
+
description: "Everything you need to sell online.",
|
|
436
|
+
is_default: false,
|
|
437
|
+
is_public: true,
|
|
438
|
+
type: "paid",
|
|
439
|
+
prices: [
|
|
440
|
+
{
|
|
441
|
+
amount: 2900,
|
|
442
|
+
currency: "USD",
|
|
443
|
+
billing_interval: "monthly",
|
|
444
|
+
available_addons: ["custom_domain_ssl"],
|
|
445
|
+
overage_configuration: {
|
|
446
|
+
orders: { overage_amount: 50, overage_unit: 100 } // $0.50 per 100 extra orders
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
],
|
|
450
|
+
features: {
|
|
451
|
+
orders: { value_limit: 500, is_hard_limit: false, reset_period: "monthly" },
|
|
452
|
+
storefronts: { value_limit: 1, is_hard_limit: true },
|
|
453
|
+
advanced_analytics: { value_bool: false },
|
|
454
|
+
},
|
|
455
|
+
}),
|
|
456
|
+
pro: definePlan<typeof features>({
|
|
457
|
+
name: "Pro Seller",
|
|
458
|
+
description: "For scaling businesses.",
|
|
459
|
+
is_default: false,
|
|
460
|
+
is_public: true,
|
|
461
|
+
type: "paid",
|
|
462
|
+
prices: [
|
|
463
|
+
{
|
|
464
|
+
amount: 19900,
|
|
465
|
+
currency: "USD",
|
|
466
|
+
billing_interval: "monthly",
|
|
467
|
+
available_addons: ["extra_storefront", "custom_domain_ssl"],
|
|
468
|
+
overage_configuration: {
|
|
469
|
+
orders: { overage_amount: 30, overage_unit: 100 } // $0.30 per 100 extra orders
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
],
|
|
473
|
+
features: {
|
|
474
|
+
orders: { value_limit: 5000, is_hard_limit: false, reset_period: "monthly" },
|
|
475
|
+
storefronts: { value_limit: 2, is_hard_limit: true },
|
|
476
|
+
advanced_analytics: { value_bool: true },
|
|
477
|
+
},
|
|
478
|
+
}),
|
|
479
|
+
};
|
|
480
|
+
`,
|
|
481
|
+
coupons: `import type { DiscountDef } from "@revstackhq/core";
|
|
482
|
+
|
|
483
|
+
export const coupons: DiscountDef[] = [
|
|
484
|
+
{
|
|
485
|
+
code: "BFCM_PROMO",
|
|
486
|
+
name: "Black Friday Cyber Monday 20%",
|
|
487
|
+
type: "percent",
|
|
488
|
+
value: 20,
|
|
489
|
+
duration: "repeating",
|
|
490
|
+
duration_in_months: 6,
|
|
491
|
+
expires_at: "2024-11-29T00:00:00Z", // Ephemeral timestamp
|
|
492
|
+
max_redemptions: 5000
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
code: "FIRST_MONTH_FREE",
|
|
496
|
+
name: "New Store Launch",
|
|
497
|
+
type: "percent",
|
|
498
|
+
value: 100,
|
|
499
|
+
duration: "repeating",
|
|
500
|
+
duration_in_months: 1,
|
|
501
|
+
applies_to_plans: ["basic"]
|
|
502
|
+
}
|
|
503
|
+
];
|
|
504
|
+
`,
|
|
505
|
+
index: `import { defineConfig } from "@revstackhq/core";
|
|
506
|
+
import { features } from "./features";
|
|
507
|
+
import { addons } from "./addons";
|
|
508
|
+
import { plans } from "./plans";
|
|
509
|
+
import { coupons } from "./coupons";
|
|
510
|
+
|
|
511
|
+
export default defineConfig({
|
|
512
|
+
features,
|
|
513
|
+
addons,
|
|
514
|
+
plans,
|
|
515
|
+
coupons,
|
|
516
|
+
});
|
|
517
|
+
`,
|
|
518
|
+
root: `import config from "./revstack";
|
|
519
|
+
|
|
520
|
+
export default config;
|
|
521
|
+
`
|
|
522
|
+
};
|
|
523
|
+
|
|
524
|
+
// src/commands/templates/developer-tools.ts
|
|
525
|
+
var developerTools = {
|
|
526
|
+
features: `import { defineFeature } from "@revstackhq/core";
|
|
527
|
+
|
|
528
|
+
export const features = {
|
|
529
|
+
bandwidth_gb: defineFeature({ name: "Bandwidth (GB)", type: "metered", unit_type: "custom" }),
|
|
530
|
+
compute_hours: defineFeature({ name: "Compute (GB-Hours)", type: "metered", unit_type: "custom" }),
|
|
531
|
+
serverless_invokes: defineFeature({ name: "Serverless Invocations", type: "metered", unit_type: "count" }),
|
|
532
|
+
sso_auth: defineFeature({ name: "Enterprise SSO", type: "boolean", unit_type: "custom" })
|
|
533
|
+
};
|
|
534
|
+
`,
|
|
535
|
+
addons: `import { defineAddon } from "@revstackhq/core";
|
|
536
|
+
import { features } from "./features";
|
|
537
|
+
|
|
538
|
+
export const addons = {
|
|
539
|
+
dedicated_ipv4: defineAddon<typeof features>({
|
|
540
|
+
name: "Dedicated IPv4 Address",
|
|
541
|
+
description: "Assign a static IP to your deployments.",
|
|
542
|
+
type: "recurring",
|
|
543
|
+
amount: 500,
|
|
544
|
+
currency: "USD",
|
|
545
|
+
billing_interval: "monthly",
|
|
546
|
+
features: {}
|
|
547
|
+
}),
|
|
548
|
+
premium_sla: defineAddon<typeof features>({
|
|
549
|
+
name: "Premium Escalation SLA",
|
|
550
|
+
description: "Direct engineering support with 30-min response time.",
|
|
551
|
+
type: "recurring",
|
|
552
|
+
amount: 150000,
|
|
553
|
+
currency: "USD",
|
|
554
|
+
billing_interval: "monthly",
|
|
555
|
+
features: {}
|
|
556
|
+
})
|
|
557
|
+
};
|
|
558
|
+
`,
|
|
559
|
+
plans: `import { definePlan } from "@revstackhq/core";
|
|
560
|
+
import { features } from "./features";
|
|
561
|
+
|
|
562
|
+
export const plans = {
|
|
563
|
+
default: definePlan<typeof features>({
|
|
564
|
+
name: "Hobby",
|
|
565
|
+
description: "For personal or non-commercial projects.",
|
|
566
|
+
is_default: true,
|
|
567
|
+
is_public: true,
|
|
568
|
+
type: "free",
|
|
569
|
+
features: {
|
|
570
|
+
bandwidth_gb: { value_limit: 100, is_hard_limit: true, reset_period: "monthly" },
|
|
571
|
+
compute_hours: { value_limit: 100, is_hard_limit: true, reset_period: "monthly" },
|
|
572
|
+
serverless_invokes: { value_limit: 100000, is_hard_limit: true, reset_period: "monthly" },
|
|
573
|
+
sso_auth: { value_bool: false }
|
|
574
|
+
},
|
|
575
|
+
}),
|
|
576
|
+
pro: definePlan<typeof features>({
|
|
577
|
+
name: "Pro",
|
|
578
|
+
description: "For production apps and growing teams.",
|
|
579
|
+
is_default: false,
|
|
580
|
+
is_public: true,
|
|
581
|
+
type: "paid",
|
|
582
|
+
prices: [
|
|
583
|
+
{
|
|
584
|
+
amount: 2000,
|
|
585
|
+
currency: "USD",
|
|
586
|
+
billing_interval: "monthly",
|
|
587
|
+
available_addons: ["dedicated_ipv4"],
|
|
588
|
+
overage_configuration: {
|
|
589
|
+
bandwidth_gb: { overage_amount: 40, overage_unit: 100 }, // $0.40 per 100GB extra
|
|
590
|
+
compute_hours: { overage_amount: 2, overage_unit: 1 }, // $0.02 per extra GB hr
|
|
591
|
+
serverless_invokes: { overage_amount: 50, overage_unit: 1000000 } // $0.50 per 1M invokes
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
],
|
|
595
|
+
features: {
|
|
596
|
+
bandwidth_gb: { value_limit: 1000, is_hard_limit: false, reset_period: "monthly" },
|
|
597
|
+
compute_hours: { value_limit: 1000, is_hard_limit: false, reset_period: "monthly" },
|
|
598
|
+
serverless_invokes: { value_limit: 5000000, is_hard_limit: false, reset_period: "monthly" },
|
|
599
|
+
sso_auth: { value_bool: false }
|
|
600
|
+
},
|
|
601
|
+
}),
|
|
602
|
+
enterprise: definePlan<typeof features>({
|
|
603
|
+
name: "Enterprise",
|
|
604
|
+
description: "Custom infrastructure and legal compliance.",
|
|
605
|
+
is_default: false,
|
|
606
|
+
is_public: true,
|
|
607
|
+
type: "custom",
|
|
608
|
+
prices: [],
|
|
609
|
+
features: {
|
|
610
|
+
bandwidth_gb: { value_limit: 50000, is_hard_limit: false, reset_period: "monthly" },
|
|
611
|
+
compute_hours: { value_limit: 10000, is_hard_limit: false, reset_period: "monthly" },
|
|
612
|
+
serverless_invokes: { value_limit: 100000000, is_hard_limit: false, reset_period: "monthly" },
|
|
613
|
+
sso_auth: { value_bool: true }
|
|
614
|
+
},
|
|
615
|
+
}),
|
|
616
|
+
};
|
|
617
|
+
`,
|
|
618
|
+
coupons: `import type { DiscountDef } from "@revstackhq/core";
|
|
619
|
+
|
|
620
|
+
export const coupons: DiscountDef[] = [
|
|
621
|
+
{
|
|
622
|
+
code: "YCOMBINATOR",
|
|
623
|
+
name: "YC Startup Accelerator Credit",
|
|
624
|
+
type: "amount",
|
|
625
|
+
value: 1000000, // $10,000 credit
|
|
626
|
+
duration: "forever",
|
|
627
|
+
applies_to_plans: ["pro", "enterprise"]
|
|
628
|
+
}
|
|
629
|
+
];
|
|
630
|
+
`,
|
|
631
|
+
index: `import { defineConfig } from "@revstackhq/core";
|
|
632
|
+
import { features } from "./features";
|
|
633
|
+
import { addons } from "./addons";
|
|
634
|
+
import { plans } from "./plans";
|
|
635
|
+
import { coupons } from "./coupons";
|
|
340
636
|
|
|
341
637
|
export default defineConfig({
|
|
342
638
|
features,
|
|
343
639
|
addons,
|
|
344
640
|
plans,
|
|
641
|
+
coupons,
|
|
642
|
+
});
|
|
643
|
+
`,
|
|
644
|
+
root: `import config from "./revstack";
|
|
645
|
+
|
|
646
|
+
export default config;
|
|
647
|
+
`
|
|
648
|
+
};
|
|
649
|
+
|
|
650
|
+
// src/commands/templates/ai-agent-platform.ts
|
|
651
|
+
var aiAgentPlatform = {
|
|
652
|
+
features: `import { defineFeature } from "@revstackhq/core";
|
|
653
|
+
|
|
654
|
+
export const features = {
|
|
655
|
+
llm_tokens: defineFeature({ name: "LLM Tokens (Input+Output)", type: "metered", unit_type: "count" }),
|
|
656
|
+
active_agents: defineFeature({ name: "Concurrent Agents", type: "static", unit_type: "count" }),
|
|
657
|
+
vector_storage_gb: defineFeature({ name: "Vector Database (GB)", type: "metered", unit_type: "custom" }),
|
|
658
|
+
custom_fine_tuning: defineFeature({ name: "Model Fine-Tuning", type: "boolean", unit_type: "custom" })
|
|
659
|
+
};
|
|
660
|
+
`,
|
|
661
|
+
addons: `import { defineAddon } from "@revstackhq/core";
|
|
662
|
+
import { features } from "./features";
|
|
663
|
+
|
|
664
|
+
export const addons = {
|
|
665
|
+
extra_vector_storage: defineAddon<typeof features>({
|
|
666
|
+
name: "10GB Vector Storage Block",
|
|
667
|
+
description: "Retain long-term memory for your AI agents.",
|
|
668
|
+
type: "recurring",
|
|
669
|
+
amount: 1000,
|
|
670
|
+
currency: "USD",
|
|
671
|
+
billing_interval: "monthly",
|
|
672
|
+
features: {
|
|
673
|
+
vector_storage_gb: { value_limit: 10, type: "increment", is_hard_limit: false }
|
|
674
|
+
}
|
|
675
|
+
}),
|
|
676
|
+
fine_tuning_job: defineAddon<typeof features>({
|
|
677
|
+
name: "Fine-Tuning Job Runner",
|
|
678
|
+
description: "Pay once to run a distributed model fine-tuning job on your dataset.",
|
|
679
|
+
type: "one_time",
|
|
680
|
+
amount: 25000,
|
|
681
|
+
currency: "USD",
|
|
682
|
+
features: {
|
|
683
|
+
custom_fine_tuning: { has_access: true }
|
|
684
|
+
}
|
|
685
|
+
})
|
|
686
|
+
};
|
|
687
|
+
`,
|
|
688
|
+
plans: `import { definePlan } from "@revstackhq/core";
|
|
689
|
+
import { features } from "./features";
|
|
690
|
+
|
|
691
|
+
export const plans = {
|
|
692
|
+
default: definePlan<typeof features>({
|
|
693
|
+
name: "Free Preview",
|
|
694
|
+
description: "Trial sandbox using shared models.",
|
|
695
|
+
is_default: true,
|
|
696
|
+
is_public: true,
|
|
697
|
+
type: "free",
|
|
698
|
+
features: {
|
|
699
|
+
llm_tokens: { value_limit: 100000, is_hard_limit: true, reset_period: "monthly" },
|
|
700
|
+
active_agents: { value_limit: 1, is_hard_limit: true },
|
|
701
|
+
vector_storage_gb: { value_limit: 0, is_hard_limit: true, reset_period: "never" },
|
|
702
|
+
custom_fine_tuning: { value_bool: false }
|
|
703
|
+
},
|
|
704
|
+
}),
|
|
705
|
+
builder: definePlan<typeof features>({
|
|
706
|
+
name: "AI Builder",
|
|
707
|
+
description: "High concurrency and dedicated model endpoints.",
|
|
708
|
+
is_default: false,
|
|
709
|
+
is_public: true,
|
|
710
|
+
type: "paid",
|
|
711
|
+
prices: [
|
|
712
|
+
{
|
|
713
|
+
amount: 4900,
|
|
714
|
+
currency: "USD",
|
|
715
|
+
billing_interval: "monthly",
|
|
716
|
+
available_addons: ["extra_vector_storage", "fine_tuning_job"],
|
|
717
|
+
overage_configuration: {
|
|
718
|
+
llm_tokens: { overage_amount: 15, overage_unit: 1000000 } // $0.15 per 1M tokens
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
],
|
|
722
|
+
features: {
|
|
723
|
+
llm_tokens: { value_limit: 10000000, is_hard_limit: false, reset_period: "monthly" }, // 10M free tokens included
|
|
724
|
+
active_agents: { value_limit: 10, is_hard_limit: true },
|
|
725
|
+
vector_storage_gb: { value_limit: 5, is_hard_limit: true, reset_period: "never" }, // Hard limit until they buy the addon
|
|
726
|
+
custom_fine_tuning: { value_bool: false } // Only unlocked via the one-off addon
|
|
727
|
+
},
|
|
728
|
+
}),
|
|
729
|
+
};
|
|
730
|
+
`,
|
|
731
|
+
coupons: `import type { DiscountDef } from "@revstackhq/core";
|
|
732
|
+
|
|
733
|
+
export const coupons: DiscountDef[] = [
|
|
734
|
+
{
|
|
735
|
+
code: "BETA_TESTER",
|
|
736
|
+
name: "Early Beta Access Discount",
|
|
737
|
+
type: "percent",
|
|
738
|
+
value: 50,
|
|
739
|
+
duration: "repeating",
|
|
740
|
+
duration_in_months: 12,
|
|
741
|
+
max_redemptions: 100
|
|
742
|
+
}
|
|
743
|
+
];
|
|
744
|
+
`,
|
|
745
|
+
index: `import { defineConfig } from "@revstackhq/core";
|
|
746
|
+
import { features } from "./features";
|
|
747
|
+
import { addons } from "./addons";
|
|
748
|
+
import { plans } from "./plans";
|
|
749
|
+
import { coupons } from "./coupons";
|
|
750
|
+
|
|
751
|
+
export default defineConfig({
|
|
752
|
+
features,
|
|
753
|
+
addons,
|
|
754
|
+
plans,
|
|
755
|
+
coupons,
|
|
345
756
|
});
|
|
346
757
|
`,
|
|
347
758
|
root: `import config from "./revstack";
|
|
@@ -354,13 +765,16 @@ export default config;
|
|
|
354
765
|
var TEMPLATES = {
|
|
355
766
|
starter,
|
|
356
767
|
"b2b-saas": b2bSaas,
|
|
357
|
-
"usage-based": usageBased
|
|
768
|
+
"usage-based": usageBased,
|
|
769
|
+
"ecommerce-platform": ecommercePlatform,
|
|
770
|
+
"developer-tools": developerTools,
|
|
771
|
+
"ai-agent-platform": aiAgentPlatform
|
|
358
772
|
};
|
|
359
773
|
|
|
360
774
|
// src/commands/init.ts
|
|
361
775
|
var initCommand = new Command3("init").description("Scaffold a new revstack.config.ts in the current directory").option(
|
|
362
776
|
"-t, --template <name>",
|
|
363
|
-
|
|
777
|
+
`Choose a starting template (${Object.keys(TEMPLATES).join(", ")})`,
|
|
364
778
|
"starter"
|
|
365
779
|
).action(async (options) => {
|
|
366
780
|
const templateName = options.template || "starter";
|
|
@@ -397,6 +811,11 @@ var initCommand = new Command3("init").description("Scaffold a new revstack.conf
|
|
|
397
811
|
template.addons,
|
|
398
812
|
"utf-8"
|
|
399
813
|
);
|
|
814
|
+
fs2.writeFileSync(
|
|
815
|
+
path2.resolve(revstackDir, "coupons.ts"),
|
|
816
|
+
template.coupons,
|
|
817
|
+
"utf-8"
|
|
818
|
+
);
|
|
400
819
|
fs2.writeFileSync(
|
|
401
820
|
path2.resolve(revstackDir, "plans.ts"),
|
|
402
821
|
template.plans,
|
|
@@ -495,6 +914,10 @@ async function loadLocalConfig(cwd) {
|
|
|
495
914
|
"\n \u2716 Could not find revstack.config.ts in the current directory.\n"
|
|
496
915
|
) + chalk4.dim(" Run ") + chalk4.bold("revstack init") + chalk4.dim(" to create one.\n")
|
|
497
916
|
);
|
|
917
|
+
} else if (err.name === "SyntaxError" || error instanceof SyntaxError) {
|
|
918
|
+
console.error(
|
|
919
|
+
chalk4.red("\n \u2716 Syntax Error in revstack.config.ts\n") + chalk4.dim(" " + (err.message ?? String(error))) + "\n"
|
|
920
|
+
);
|
|
498
921
|
} else {
|
|
499
922
|
console.error(
|
|
500
923
|
chalk4.red("\n \u2716 Failed to parse revstack.config.ts\n") + chalk4.dim(" " + (err.message ?? String(error))) + "\n"
|
|
@@ -505,7 +928,11 @@ async function loadLocalConfig(cwd) {
|
|
|
505
928
|
}
|
|
506
929
|
|
|
507
930
|
// src/commands/push.ts
|
|
508
|
-
import {
|
|
931
|
+
import {
|
|
932
|
+
validateConfig,
|
|
933
|
+
RevstackValidationError,
|
|
934
|
+
RevstackConfigSchema
|
|
935
|
+
} from "@revstackhq/core";
|
|
509
936
|
var API_BASE = "https://app.revstack.dev";
|
|
510
937
|
var DIFF_ICONS = {
|
|
511
938
|
added: chalk5.green(" + "),
|
|
@@ -517,23 +944,46 @@ var DIFF_COLORS = {
|
|
|
517
944
|
removed: chalk5.red,
|
|
518
945
|
updated: chalk5.yellow
|
|
519
946
|
};
|
|
520
|
-
function printDiff(diff) {
|
|
947
|
+
function printDiff(diff, env) {
|
|
521
948
|
if (diff.length === 0) {
|
|
522
949
|
console.log(
|
|
523
950
|
chalk5.dim("\n No changes detected. Your config is up to date.\n")
|
|
524
951
|
);
|
|
525
952
|
return;
|
|
526
953
|
}
|
|
527
|
-
|
|
528
|
-
for (const entry of diff) {
|
|
529
|
-
const icon = DIFF_ICONS[entry.action];
|
|
530
|
-
const color = DIFF_COLORS[entry.action];
|
|
531
|
-
const label = chalk5.dim(`[${entry.entity}]`);
|
|
954
|
+
if (env === "production") {
|
|
532
955
|
console.log(
|
|
533
|
-
|
|
956
|
+
chalk5.bgRed.white.bold("\n \u26A0\uFE0F YOU ARE PUSHING TO PRODUCTION \u26A0\uFE0F \n")
|
|
534
957
|
);
|
|
958
|
+
} else {
|
|
959
|
+
console.log(chalk5.bold("\n Changes:\n"));
|
|
960
|
+
}
|
|
961
|
+
const groups = {};
|
|
962
|
+
for (const entry of diff) {
|
|
963
|
+
if (!groups[entry.entity]) groups[entry.entity] = [];
|
|
964
|
+
groups[entry.entity].push(entry);
|
|
965
|
+
}
|
|
966
|
+
let added = 0;
|
|
967
|
+
let updated = 0;
|
|
968
|
+
let removed = 0;
|
|
969
|
+
for (const [entityName, entries] of Object.entries(groups)) {
|
|
970
|
+
console.log(chalk5.dim(` ${entityName}s`));
|
|
971
|
+
for (const entry of entries) {
|
|
972
|
+
if (entry.action === "added") added++;
|
|
973
|
+
if (entry.action === "updated") updated++;
|
|
974
|
+
if (entry.action === "removed") removed++;
|
|
975
|
+
const icon = DIFF_ICONS[entry.action];
|
|
976
|
+
const color = DIFF_COLORS[entry.action];
|
|
977
|
+
console.log(`${icon}${color(entry.id)} ${chalk5.white(entry.message)}`);
|
|
978
|
+
}
|
|
979
|
+
console.log();
|
|
535
980
|
}
|
|
536
|
-
console.log(
|
|
981
|
+
console.log(
|
|
982
|
+
chalk5.bold(
|
|
983
|
+
` Summary: ${added} added, ${updated} updated, ${removed} removed
|
|
984
|
+
`
|
|
985
|
+
)
|
|
986
|
+
);
|
|
537
987
|
}
|
|
538
988
|
function requireAuth() {
|
|
539
989
|
const apiKey = getApiKey();
|
|
@@ -553,11 +1003,25 @@ var pushCommand = new Command4("push").description("Push your local billing conf
|
|
|
553
1003
|
prefixText: " "
|
|
554
1004
|
}).start();
|
|
555
1005
|
try {
|
|
556
|
-
|
|
1006
|
+
const parsedConfig = RevstackConfigSchema.parse(config);
|
|
1007
|
+
validateConfig(parsedConfig);
|
|
557
1008
|
validationSpinner.succeed("Configuration validated");
|
|
558
1009
|
} catch (error) {
|
|
1010
|
+
validationSpinner.fail("Configuration invalid");
|
|
1011
|
+
if (error?.name === "ZodError") {
|
|
1012
|
+
console.error(
|
|
1013
|
+
chalk5.red(
|
|
1014
|
+
"\n \u2716 The billing configuration contains schema/formatting errors:\n"
|
|
1015
|
+
)
|
|
1016
|
+
);
|
|
1017
|
+
for (const err of error.errors || []) {
|
|
1018
|
+
const path5 = err.path.join(".");
|
|
1019
|
+
console.error(chalk5.red(` \u2022 [${path5}] ${err.message}`));
|
|
1020
|
+
}
|
|
1021
|
+
console.log();
|
|
1022
|
+
process.exit(1);
|
|
1023
|
+
}
|
|
559
1024
|
if (error instanceof RevstackValidationError || error?.name === "RevstackValidationError") {
|
|
560
|
-
validationSpinner.fail("Configuration invalid");
|
|
561
1025
|
console.error(
|
|
562
1026
|
chalk5.red(
|
|
563
1027
|
"\n \u2716 The billing configuration contains business logic errors:\n"
|
|
@@ -611,14 +1075,14 @@ var pushCommand = new Command4("push").description("Push your local billing conf
|
|
|
611
1075
|
`));
|
|
612
1076
|
process.exit(1);
|
|
613
1077
|
}
|
|
614
|
-
printDiff(diffResponse.diff);
|
|
1078
|
+
printDiff(diffResponse.diff, options.env);
|
|
615
1079
|
if (diffResponse.diff.length === 0) {
|
|
616
1080
|
return;
|
|
617
1081
|
}
|
|
618
1082
|
if (!diffResponse.canPush) {
|
|
619
1083
|
console.log(
|
|
620
|
-
chalk5.
|
|
621
|
-
`
|
|
1084
|
+
"\n" + chalk5.bgRed.white.bold(" BLOCKED: PUSH IMPOSSIBLE ") + "\n\n" + chalk5.red(
|
|
1085
|
+
` \u2716 ${diffResponse.blockedReason ?? "The server rejected this configuration due to destructive changes."}
|
|
622
1086
|
`
|
|
623
1087
|
)
|
|
624
1088
|
);
|
|
@@ -677,6 +1141,8 @@ import ora3 from "ora";
|
|
|
677
1141
|
import prompts3 from "prompts";
|
|
678
1142
|
import fs3 from "fs";
|
|
679
1143
|
import path4 from "path";
|
|
1144
|
+
import { execa } from "execa";
|
|
1145
|
+
import { RevstackConfigSchema as RevstackConfigSchema2 } from "@revstackhq/core";
|
|
680
1146
|
function serializeObject(obj, depth = 0) {
|
|
681
1147
|
const entries = Object.entries(obj);
|
|
682
1148
|
if (entries.length === 0) return "{}";
|
|
@@ -747,15 +1213,83 @@ ${planEntries.join("\n")}
|
|
|
747
1213
|
};
|
|
748
1214
|
`;
|
|
749
1215
|
}
|
|
750
|
-
function
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
1216
|
+
function generateAddonsSource(config) {
|
|
1217
|
+
if (!config.addons) return "";
|
|
1218
|
+
const addonEntries = Object.entries(config.addons).map(([slug, addon]) => {
|
|
1219
|
+
const props = {
|
|
1220
|
+
name: addon.name,
|
|
1221
|
+
type: addon.type,
|
|
1222
|
+
amount: addon.amount,
|
|
1223
|
+
currency: addon.currency
|
|
1224
|
+
};
|
|
1225
|
+
if (addon.description) props.description = addon.description;
|
|
1226
|
+
if (addon.billing_interval) props.billing_interval = addon.billing_interval;
|
|
1227
|
+
props.features = addon.features;
|
|
1228
|
+
return ` ${slug}: defineAddon<typeof features>(${serializeObject(props, 2)}),`;
|
|
1229
|
+
});
|
|
1230
|
+
return `import { defineAddon } from "@revstackhq/core";
|
|
1231
|
+
import { features } from "./features";
|
|
754
1232
|
|
|
755
|
-
export
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
1233
|
+
export const addons = {
|
|
1234
|
+
${addonEntries.join("\n")}
|
|
1235
|
+
};
|
|
1236
|
+
`;
|
|
1237
|
+
}
|
|
1238
|
+
function generateCouponsSource(config) {
|
|
1239
|
+
if (!config.coupons || config.coupons.length === 0) return "";
|
|
1240
|
+
const couponsArray = config.coupons.map((coupon) => {
|
|
1241
|
+
const props = {
|
|
1242
|
+
code: coupon.code,
|
|
1243
|
+
type: coupon.type,
|
|
1244
|
+
value: coupon.value,
|
|
1245
|
+
duration: coupon.duration
|
|
1246
|
+
};
|
|
1247
|
+
if (coupon.name) props.name = coupon.name;
|
|
1248
|
+
if (coupon.duration_in_months)
|
|
1249
|
+
props.duration_in_months = coupon.duration_in_months;
|
|
1250
|
+
if (coupon.applies_to_plans)
|
|
1251
|
+
props.applies_to_plans = coupon.applies_to_plans;
|
|
1252
|
+
if (coupon.max_redemptions) props.max_redemptions = coupon.max_redemptions;
|
|
1253
|
+
if (coupon.expires_at) props.expires_at = coupon.expires_at;
|
|
1254
|
+
return props;
|
|
1255
|
+
});
|
|
1256
|
+
return `import type { DiscountDef } from "@revstackhq/core";
|
|
1257
|
+
|
|
1258
|
+
export const coupons: DiscountDef[] = ${serializeArray(couponsArray, 0)};
|
|
1259
|
+
`;
|
|
1260
|
+
}
|
|
1261
|
+
function generateRootConfigSource(config) {
|
|
1262
|
+
const hasAddons = !!config.addons && Object.keys(config.addons).length > 0;
|
|
1263
|
+
const hasCoupons = !!config.coupons && config.coupons.length > 0;
|
|
1264
|
+
const imports = [
|
|
1265
|
+
`import { defineConfig } from "@revstackhq/core";`,
|
|
1266
|
+
`import { features } from "./revstack/features";`,
|
|
1267
|
+
`import { plans } from "./revstack/plans";`
|
|
1268
|
+
];
|
|
1269
|
+
if (hasAddons) {
|
|
1270
|
+
imports.push(`import { addons } from "./revstack/addons";`);
|
|
1271
|
+
}
|
|
1272
|
+
if (hasCoupons) {
|
|
1273
|
+
imports.push(`import { coupons } from "./revstack/coupons";`);
|
|
1274
|
+
}
|
|
1275
|
+
const configProps = {
|
|
1276
|
+
features: "__RAW_features",
|
|
1277
|
+
plans: "__RAW_plans"
|
|
1278
|
+
};
|
|
1279
|
+
if (hasAddons) {
|
|
1280
|
+
configProps.addons = "__RAW_addons";
|
|
1281
|
+
}
|
|
1282
|
+
if (hasCoupons) {
|
|
1283
|
+
configProps.coupons = "__RAW_coupons";
|
|
1284
|
+
}
|
|
1285
|
+
let configStr = serializeObject(configProps, 0);
|
|
1286
|
+
configStr = configStr.replace(/"__RAW_features"/g, "features");
|
|
1287
|
+
configStr = configStr.replace(/"__RAW_plans"/g, "plans");
|
|
1288
|
+
configStr = configStr.replace(/"__RAW_addons"/g, "addons");
|
|
1289
|
+
configStr = configStr.replace(/"__RAW_coupons"/g, "coupons");
|
|
1290
|
+
return `${imports.join("\n")}
|
|
1291
|
+
|
|
1292
|
+
export default defineConfig(${configStr});
|
|
759
1293
|
`;
|
|
760
1294
|
}
|
|
761
1295
|
var API_BASE2 = "https://app.revstack.dev";
|
|
@@ -790,7 +1324,16 @@ var pullCommand = new Command5("pull").description(
|
|
|
790
1324
|
);
|
|
791
1325
|
process.exit(1);
|
|
792
1326
|
}
|
|
793
|
-
|
|
1327
|
+
const rawData = await res.json();
|
|
1328
|
+
try {
|
|
1329
|
+
remoteConfig = RevstackConfigSchema2.parse(rawData);
|
|
1330
|
+
} catch (validationError) {
|
|
1331
|
+
spinner.fail("Remote config failed schema validation");
|
|
1332
|
+
console.error(chalk6.red(`
|
|
1333
|
+
${validationError.message}
|
|
1334
|
+
`));
|
|
1335
|
+
process.exit(1);
|
|
1336
|
+
}
|
|
794
1337
|
spinner.succeed("Remote config fetched");
|
|
795
1338
|
} catch (error) {
|
|
796
1339
|
spinner.fail("Failed to reach Revstack Cloud");
|
|
@@ -801,8 +1344,12 @@ var pullCommand = new Command5("pull").description(
|
|
|
801
1344
|
}
|
|
802
1345
|
const featureCount = Object.keys(remoteConfig.features).length;
|
|
803
1346
|
const planCount = Object.keys(remoteConfig.plans).length;
|
|
1347
|
+
const addonCount = remoteConfig.addons ? Object.keys(remoteConfig.addons).length : 0;
|
|
1348
|
+
const couponCount = remoteConfig.coupons ? remoteConfig.coupons.length : 0;
|
|
804
1349
|
console.log(
|
|
805
|
-
"\n" + chalk6.dim(" Remote state: ") + chalk6.white(
|
|
1350
|
+
"\n" + chalk6.dim(" Remote state: ") + chalk6.white(
|
|
1351
|
+
`${featureCount} features, ${planCount} plans, ${addonCount} addons, ${couponCount} coupons`
|
|
1352
|
+
) + chalk6.dim(` (${options.env})
|
|
806
1353
|
`)
|
|
807
1354
|
);
|
|
808
1355
|
const cwd = process.cwd();
|
|
@@ -829,10 +1376,36 @@ var pullCommand = new Command5("pull").description(
|
|
|
829
1376
|
}
|
|
830
1377
|
const featuresSource = generateFeaturesSource(remoteConfig);
|
|
831
1378
|
const plansSource = generatePlansSource(remoteConfig);
|
|
832
|
-
const rootSource = generateRootConfigSource();
|
|
1379
|
+
const rootSource = generateRootConfigSource(remoteConfig);
|
|
833
1380
|
fs3.writeFileSync(featuresPath, featuresSource, "utf-8");
|
|
834
1381
|
fs3.writeFileSync(plansPath, plansSource, "utf-8");
|
|
835
1382
|
fs3.writeFileSync(configPath, rootSource, "utf-8");
|
|
1383
|
+
if (remoteConfig.addons && Object.keys(remoteConfig.addons).length > 0) {
|
|
1384
|
+
const addonsSource = generateAddonsSource(remoteConfig);
|
|
1385
|
+
const addonsPath = path4.resolve(revstackDir, "addons.ts");
|
|
1386
|
+
fs3.writeFileSync(addonsPath, addonsSource, "utf-8");
|
|
1387
|
+
}
|
|
1388
|
+
if (remoteConfig.coupons && remoteConfig.coupons.length > 0) {
|
|
1389
|
+
const couponsSource = generateCouponsSource(remoteConfig);
|
|
1390
|
+
const couponsPath = path4.resolve(revstackDir, "coupons.ts");
|
|
1391
|
+
fs3.writeFileSync(couponsPath, couponsSource, "utf-8");
|
|
1392
|
+
}
|
|
1393
|
+
const formatSpinner = ora3("Formatting generated files...").start();
|
|
1394
|
+
try {
|
|
1395
|
+
await execa(
|
|
1396
|
+
"npx",
|
|
1397
|
+
["prettier", "--write", "revstack.config.ts", "revstack/**/*.ts"],
|
|
1398
|
+
{
|
|
1399
|
+
cwd,
|
|
1400
|
+
stdio: "ignore"
|
|
1401
|
+
}
|
|
1402
|
+
);
|
|
1403
|
+
formatSpinner.succeed("Files formatted successfully");
|
|
1404
|
+
} catch (err) {
|
|
1405
|
+
formatSpinner.info(
|
|
1406
|
+
"Files written properly, but automatic formatting (prettier) skipped or failed."
|
|
1407
|
+
);
|
|
1408
|
+
}
|
|
836
1409
|
console.log(
|
|
837
1410
|
"\n" + chalk6.green(" \u2714 Local files updated from remote.\n") + chalk6.dim(" Review the files and run ") + chalk6.bold("revstack push") + chalk6.dim(" to re-deploy.\n")
|
|
838
1411
|
);
|