@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
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/commands/push.ts","../../src/utils/auth.ts","../../src/utils/config-loader.ts"],"sourcesContent":["/**\n * @file commands/push.ts\n * @description The core deployment command. Loads the local config, sends it\n * to Revstack Cloud for diffing, presents the changes, and (upon confirmation)\n * pushes the config to production.\n */\n\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport prompts from \"prompts\";\nimport ora from \"ora\";\nimport { getApiKey } from \"@/utils/auth\";\nimport { loadLocalConfig } from \"@/utils/config-loader\";\nimport { validateConfig, RevstackValidationError } from \"@revstackhq/core\";\n\n// ─── Types ───────────────────────────────────────────────────\n\ninterface DiffEntry {\n action: \"added\" | \"removed\" | \"updated\";\n entity: string;\n id: string;\n message: string;\n}\n\ninterface DiffResponse {\n diff: DiffEntry[];\n canPush: boolean;\n blockedReason?: string;\n}\n\n// ─── Helpers ─────────────────────────────────────────────────\n\nconst API_BASE = \"https://app.revstack.dev\";\n\nconst DIFF_ICONS: Record<DiffEntry[\"action\"], string> = {\n added: chalk.green(\" + \"),\n removed: chalk.red(\" − \"),\n updated: chalk.yellow(\" ~ \"),\n};\n\nconst DIFF_COLORS: Record<DiffEntry[\"action\"], (text: string) => string> = {\n added: chalk.green,\n removed: chalk.red,\n updated: chalk.yellow,\n};\n\nfunction printDiff(diff: DiffEntry[]): void {\n if (diff.length === 0) {\n console.log(\n chalk.dim(\"\\n No changes detected. Your config is up to date.\\n\"),\n );\n return;\n }\n\n console.log(chalk.bold(\"\\n Changes:\\n\"));\n\n for (const entry of diff) {\n const icon = DIFF_ICONS[entry.action];\n const color = DIFF_COLORS[entry.action];\n const label = chalk.dim(`[${entry.entity}]`);\n console.log(\n `${icon}${color(entry.id)} ${label} ${chalk.white(entry.message)}`,\n );\n }\n\n console.log();\n}\n\nfunction requireAuth(): string {\n const apiKey = getApiKey();\n\n if (!apiKey) {\n console.error(\n \"\\n\" +\n chalk.red(\" ✖ Not authenticated.\\n\") +\n chalk.dim(\" Run \") +\n chalk.bold(\"revstack login\") +\n chalk.dim(\" first.\\n\"),\n );\n process.exit(1);\n }\n\n return apiKey;\n}\n\n// ─── Command ─────────────────────────────────────────────────\n\nexport const pushCommand = new Command(\"push\")\n .description(\"Push your local billing config to Revstack Cloud\")\n .option(\"-e, --env <environment>\", \"Target environment\", \"test\")\n .action(async (options: { env: string }) => {\n const apiKey = requireAuth();\n const config = await loadLocalConfig(process.cwd());\n\n // ── Step 1: Validate config ────────────────────────────────\n\n const validationSpinner = ora({\n text: \"Validating billing configuration...\",\n prefixText: \" \",\n }).start();\n\n try {\n validateConfig(config as any); // cast to match RevstackConfig expected by validateConfig\n validationSpinner.succeed(\"Configuration validated\");\n } catch (error: any) {\n if (\n error instanceof RevstackValidationError ||\n error?.name === \"RevstackValidationError\"\n ) {\n validationSpinner.fail(\"Configuration invalid\");\n console.error(\n chalk.red(\n \"\\n ✖ The billing configuration contains business logic errors:\\n\",\n ),\n );\n for (const err of error.errors || []) {\n console.error(chalk.red(` • ${err}`));\n }\n console.log();\n process.exit(1);\n }\n\n validationSpinner.fail(\"Validation failed\");\n console.error(\n chalk.red(\n `\\n An unexpected error occurred during validation: ${error?.message || String(error)}\\n`,\n ),\n );\n process.exit(1);\n }\n\n // ── Step 2: Compute diff ──────────────────────────────────\n\n const spinner = ora({\n text: \"Calculating diff...\",\n prefixText: \" \",\n }).start();\n\n let diffResponse: DiffResponse;\n\n try {\n const res = await fetch(`${API_BASE}/api/v1/cli/diff`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({ env: options.env, config }),\n });\n\n if (!res.ok) {\n spinner.fail(\"Failed to calculate diff\");\n console.error(\n chalk.red(`\\n API returned ${res.status}: ${res.statusText}\\n`),\n );\n process.exit(1);\n }\n\n diffResponse = (await res.json()) as DiffResponse;\n spinner.succeed(\"Diff calculated\");\n } catch (error: unknown) {\n spinner.fail(\"Failed to reach Revstack Cloud\");\n console.error(chalk.red(`\\n ${(error as Error).message}\\n`));\n process.exit(1);\n }\n\n // ── Step 2: Present diff ──────────────────────────────────\n\n printDiff(diffResponse.diff);\n\n if (diffResponse.diff.length === 0) {\n return;\n }\n\n // ── Step 3: Check if push is allowed ──────────────────────\n\n if (!diffResponse.canPush) {\n console.log(\n chalk.red(\" ✖ Push is blocked.\\n\") +\n chalk.dim(\n ` ${diffResponse.blockedReason ?? \"The server rejected this configuration.\"}\\n`,\n ),\n );\n process.exit(1);\n }\n\n // ── Step 4: Confirm ───────────────────────────────────────\n\n const envLabel =\n options.env === \"production\"\n ? chalk.red.bold(options.env)\n : chalk.cyan.bold(options.env);\n\n const { confirm } = await prompts({\n type: \"confirm\",\n name: \"confirm\",\n message: `Apply these changes to ${envLabel}?`,\n initial: false,\n });\n\n if (!confirm) {\n console.log(chalk.dim(\"\\n Push cancelled.\\n\"));\n return;\n }\n\n // ── Step 5: Push ──────────────────────────────────────────\n\n const pushSpinner = ora({\n text: `Pushing to ${options.env}...`,\n prefixText: \" \",\n }).start();\n\n try {\n const res = await fetch(`${API_BASE}/api/v1/cli/push`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({ env: options.env, config }),\n });\n\n if (!res.ok) {\n pushSpinner.fail(\"Push failed\");\n console.error(\n chalk.red(`\\n API returned ${res.status}: ${res.statusText}\\n`),\n );\n process.exit(1);\n }\n\n pushSpinner.succeed(\"Pushed successfully\");\n console.log(\n \"\\n\" +\n chalk.green(\" ✔ Config deployed to \") +\n envLabel +\n \"\\n\" +\n chalk.dim(\" Changes are now live.\\n\"),\n );\n } catch (error: unknown) {\n pushSpinner.fail(\"Push failed\");\n console.error(chalk.red(`\\n ${(error as Error).message}\\n`));\n process.exit(1);\n }\n });\n","/**\n * @file utils/auth.ts\n * @description Manages global Revstack credentials stored at ~/.revstack/credentials.json.\n * Provides simple get/set helpers for the API key used by all authenticated commands.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\n\nconst CREDENTIALS_DIR = path.join(os.homedir(), \".revstack\");\nconst CREDENTIALS_FILE = path.join(CREDENTIALS_DIR, \"credentials.json\");\n\ninterface Credentials {\n apiKey: string;\n}\n\n/**\n * Persist an API key to the global credentials file.\n * Creates `~/.revstack/` if it doesn't exist.\n */\nexport function setApiKey(key: string): void {\n if (!fs.existsSync(CREDENTIALS_DIR)) {\n fs.mkdirSync(CREDENTIALS_DIR, { recursive: true });\n }\n\n const credentials: Credentials = { apiKey: key };\n fs.writeFileSync(\n CREDENTIALS_FILE,\n JSON.stringify(credentials, null, 2),\n \"utf-8\",\n );\n}\n\n/**\n * Read the stored API key, or return `null` if none is configured.\n */\nexport function getApiKey(): string | null {\n if (!fs.existsSync(CREDENTIALS_FILE)) {\n return null;\n }\n\n try {\n const raw = fs.readFileSync(CREDENTIALS_FILE, \"utf-8\");\n const credentials: Credentials = JSON.parse(raw);\n return credentials.apiKey ?? null;\n } catch {\n return null;\n }\n}\n\n/**\n * Remove stored credentials. Used by `revstack logout`.\n */\nexport function clearApiKey(): void {\n if (fs.existsSync(CREDENTIALS_FILE)) {\n fs.unlinkSync(CREDENTIALS_FILE);\n }\n}\n","/**\n * @file utils/config-loader.ts\n * @description Loads and evaluates the user's `revstack.config.ts` at runtime\n * using jiti (just-in-time TypeScript compilation). Returns a sanitized,\n * JSON-safe representation of the config for network transmission.\n */\n\nimport { createJiti } from \"jiti\";\nimport path from \"node:path\";\nimport chalk from \"chalk\";\n\n/**\n * Load the `revstack.config.ts` from the given directory.\n *\n * @param cwd - The directory to search for `revstack.config.ts`.\n * @returns The parsed and sanitized configuration object.\n */\nexport async function loadLocalConfig(\n cwd: string,\n): Promise<Record<string, unknown>> {\n const configPath = path.resolve(cwd, \"revstack.config.ts\");\n\n try {\n const jiti = createJiti(cwd);\n const module = (await jiti.import(configPath)) as Record<string, unknown>;\n const config = (module.default ?? module) as Record<string, unknown>;\n\n // Sanitize: strip functions, class instances, and non-serializable data.\n // This ensures we only send plain JSON to the Revstack Cloud API.\n return JSON.parse(JSON.stringify(config));\n } catch (error: unknown) {\n const err = error as NodeJS.ErrnoException;\n\n if (\n err.code === \"ERR_MODULE_NOT_FOUND\" ||\n err.code === \"ENOENT\" ||\n err.code === \"MODULE_NOT_FOUND\"\n ) {\n console.error(\n chalk.red(\n \"\\n ✖ Could not find revstack.config.ts in the current directory.\\n\",\n ) +\n chalk.dim(\" Run \") +\n chalk.bold(\"revstack init\") +\n chalk.dim(\" to create one.\\n\"),\n );\n } else {\n console.error(\n chalk.red(\"\\n ✖ Failed to parse revstack.config.ts\\n\") +\n chalk.dim(\" \" + (err.message ?? String(error))) +\n \"\\n\",\n );\n }\n\n process.exit(1);\n }\n}\n"],"mappings":"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","names":["chalk","path","chalk"]}
1
+ {"version":3,"sources":["../../src/commands/push.ts","../../src/utils/auth.ts","../../src/utils/config-loader.ts"],"sourcesContent":["/**\n * @file commands/push.ts\n * @description The core deployment command. Loads the local config, sends it\n * to Revstack Cloud for diffing, presents the changes, and (upon confirmation)\n * pushes the config to production.\n */\n\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport prompts from \"prompts\";\nimport ora from \"ora\";\nimport { getApiKey } from \"@/utils/auth\";\nimport { loadLocalConfig } from \"@/utils/config-loader\";\nimport {\n validateConfig,\n RevstackValidationError,\n RevstackConfigSchema,\n} from \"@revstackhq/core\";\n\n// ─── Types ───────────────────────────────────────────────────\n\ninterface DiffEntry {\n action: \"added\" | \"removed\" | \"updated\";\n entity: string;\n id: string;\n message: string;\n}\n\ninterface DiffResponse {\n diff: DiffEntry[];\n canPush: boolean;\n blockedReason?: string;\n}\n\n// ─── Helpers ─────────────────────────────────────────────────\n\nconst API_BASE = \"https://app.revstack.dev\";\n\nconst DIFF_ICONS: Record<DiffEntry[\"action\"], string> = {\n added: chalk.green(\" + \"),\n removed: chalk.red(\" − \"),\n updated: chalk.yellow(\" ~ \"),\n};\n\nconst DIFF_COLORS: Record<DiffEntry[\"action\"], (text: string) => string> = {\n added: chalk.green,\n removed: chalk.red,\n updated: chalk.yellow,\n};\n\nfunction printDiff(diff: DiffEntry[], env: string): void {\n if (diff.length === 0) {\n console.log(\n chalk.dim(\"\\n No changes detected. Your config is up to date.\\n\"),\n );\n return;\n }\n\n if (env === \"production\") {\n console.log(\n chalk.bgRed.white.bold(\"\\n ⚠️ YOU ARE PUSHING TO PRODUCTION ⚠️ \\n\"),\n );\n } else {\n console.log(chalk.bold(\"\\n Changes:\\n\"));\n }\n\n const groups: Record<string, DiffEntry[]> = {};\n for (const entry of diff) {\n if (!groups[entry.entity]) groups[entry.entity] = [];\n groups[entry.entity].push(entry);\n }\n\n let added = 0;\n let updated = 0;\n let removed = 0;\n\n for (const [entityName, entries] of Object.entries(groups)) {\n console.log(chalk.dim(` ${entityName}s`));\n for (const entry of entries) {\n if (entry.action === \"added\") added++;\n if (entry.action === \"updated\") updated++;\n if (entry.action === \"removed\") removed++;\n\n const icon = DIFF_ICONS[entry.action];\n const color = DIFF_COLORS[entry.action];\n console.log(`${icon}${color(entry.id)} ${chalk.white(entry.message)}`);\n }\n console.log();\n }\n\n console.log(\n chalk.bold(\n ` Summary: ${added} added, ${updated} updated, ${removed} removed\\n`,\n ),\n );\n}\n\nfunction requireAuth(): string {\n const apiKey = getApiKey();\n\n if (!apiKey) {\n console.error(\n \"\\n\" +\n chalk.red(\" ✖ Not authenticated.\\n\") +\n chalk.dim(\" Run \") +\n chalk.bold(\"revstack login\") +\n chalk.dim(\" first.\\n\"),\n );\n process.exit(1);\n }\n\n return apiKey;\n}\n\n// ─── Command ─────────────────────────────────────────────────\n\nexport const pushCommand = new Command(\"push\")\n .description(\"Push your local billing config to Revstack Cloud\")\n .option(\"-e, --env <environment>\", \"Target environment\", \"test\")\n .action(async (options: { env: string }) => {\n const apiKey = requireAuth();\n const config = await loadLocalConfig(process.cwd());\n\n // ── Step 1: Validate config ────────────────────────────────\n\n const validationSpinner = ora({\n text: \"Validating billing configuration...\",\n prefixText: \" \",\n }).start();\n\n try {\n // Tier 1: Structural Validation\n const parsedConfig = RevstackConfigSchema.parse(config);\n\n // Tier 2: Business Logic Validation\n validateConfig(parsedConfig as any);\n\n validationSpinner.succeed(\"Configuration validated\");\n } catch (error: any) {\n validationSpinner.fail(\"Configuration invalid\");\n\n if (error?.name === \"ZodError\") {\n console.error(\n chalk.red(\n \"\\n ✖ The billing configuration contains schema/formatting errors:\\n\",\n ),\n );\n for (const err of error.errors || []) {\n const path = err.path.join(\".\");\n console.error(chalk.red(` • [${path}] ${err.message}`));\n }\n console.log();\n process.exit(1);\n }\n\n if (\n error instanceof RevstackValidationError ||\n error?.name === \"RevstackValidationError\"\n ) {\n console.error(\n chalk.red(\n \"\\n ✖ The billing configuration contains business logic errors:\\n\",\n ),\n );\n for (const err of error.errors || []) {\n console.error(chalk.red(` • ${err}`));\n }\n console.log();\n process.exit(1);\n }\n\n validationSpinner.fail(\"Validation failed\");\n console.error(\n chalk.red(\n `\\n An unexpected error occurred during validation: ${error?.message || String(error)}\\n`,\n ),\n );\n process.exit(1);\n }\n\n // ── Step 2: Compute diff ──────────────────────────────────\n\n const spinner = ora({\n text: \"Calculating diff...\",\n prefixText: \" \",\n }).start();\n\n let diffResponse: DiffResponse;\n\n try {\n const res = await fetch(`${API_BASE}/api/v1/cli/diff`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({ env: options.env, config }),\n });\n\n if (!res.ok) {\n spinner.fail(\"Failed to calculate diff\");\n console.error(\n chalk.red(`\\n API returned ${res.status}: ${res.statusText}\\n`),\n );\n process.exit(1);\n }\n\n diffResponse = (await res.json()) as DiffResponse;\n spinner.succeed(\"Diff calculated\");\n } catch (error: unknown) {\n spinner.fail(\"Failed to reach Revstack Cloud\");\n console.error(chalk.red(`\\n ${(error as Error).message}\\n`));\n process.exit(1);\n }\n\n // ── Step 2: Present diff ──────────────────────────────────\n\n printDiff(diffResponse.diff, options.env);\n\n if (diffResponse.diff.length === 0) {\n return;\n }\n\n // ── Step 3: Check if push is allowed ──────────────────────\n\n if (!diffResponse.canPush) {\n console.log(\n \"\\n\" +\n chalk.bgRed.white.bold(\" BLOCKED: PUSH IMPOSSIBLE \") +\n \"\\n\\n\" +\n chalk.red(\n ` ✖ ${diffResponse.blockedReason ?? \"The server rejected this configuration due to destructive changes.\"}\\n`,\n ),\n );\n process.exit(1);\n }\n\n // ── Step 4: Confirm ───────────────────────────────────────\n\n const envLabel =\n options.env === \"production\"\n ? chalk.red.bold(options.env)\n : chalk.cyan.bold(options.env);\n\n const { confirm } = await prompts({\n type: \"confirm\",\n name: \"confirm\",\n message: `Apply these changes to ${envLabel}?`,\n initial: false,\n });\n\n if (!confirm) {\n console.log(chalk.dim(\"\\n Push cancelled.\\n\"));\n return;\n }\n\n // ── Step 5: Push ──────────────────────────────────────────\n\n const pushSpinner = ora({\n text: `Pushing to ${options.env}...`,\n prefixText: \" \",\n }).start();\n\n try {\n const res = await fetch(`${API_BASE}/api/v1/cli/push`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({ env: options.env, config }),\n });\n\n if (!res.ok) {\n pushSpinner.fail(\"Push failed\");\n console.error(\n chalk.red(`\\n API returned ${res.status}: ${res.statusText}\\n`),\n );\n process.exit(1);\n }\n\n pushSpinner.succeed(\"Pushed successfully\");\n console.log(\n \"\\n\" +\n chalk.green(\" ✔ Config deployed to \") +\n envLabel +\n \"\\n\" +\n chalk.dim(\" Changes are now live.\\n\"),\n );\n } catch (error: unknown) {\n pushSpinner.fail(\"Push failed\");\n console.error(chalk.red(`\\n ${(error as Error).message}\\n`));\n process.exit(1);\n }\n });\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport os from \"node:os\";\n\nconst CREDENTIALS_DIR = path.join(os.homedir(), \".revstack\");\nconst CREDENTIALS_FILE = path.join(CREDENTIALS_DIR, \"credentials.json\");\n\ninterface Credentials {\n apiKey: string;\n}\n\n/**\n * Persist an API key to the global credentials file.\n * Creates `~/.revstack/` if it doesn't exist.\n */\nexport function setApiKey(key: string): void {\n if (!fs.existsSync(CREDENTIALS_DIR)) {\n fs.mkdirSync(CREDENTIALS_DIR, { recursive: true });\n }\n\n const credentials: Credentials = { apiKey: key };\n fs.writeFileSync(\n CREDENTIALS_FILE,\n JSON.stringify(credentials, null, 2),\n \"utf-8\",\n );\n}\n\n/**\n * Read the stored API key, or return `null` if none is configured.\n */\nexport function getApiKey(): string | null {\n if (!fs.existsSync(CREDENTIALS_FILE)) {\n return null;\n }\n\n try {\n const raw = fs.readFileSync(CREDENTIALS_FILE, \"utf-8\");\n const credentials: Credentials = JSON.parse(raw);\n return credentials.apiKey ?? null;\n } catch {\n return null;\n }\n}\n\n/**\n * Remove stored credentials. Used by `revstack logout`.\n */\nexport function clearApiKey(): void {\n if (fs.existsSync(CREDENTIALS_FILE)) {\n fs.unlinkSync(CREDENTIALS_FILE);\n }\n}\n","import { createJiti } from \"jiti\";\nimport path from \"node:path\";\nimport chalk from \"chalk\";\n\n/**\n * Load the `revstack.config.ts` from the given directory.\n *\n * @param cwd - The directory to search for `revstack.config.ts`.\n * @returns The parsed and sanitized configuration object.\n */\nexport async function loadLocalConfig(\n cwd: string,\n): Promise<Record<string, unknown>> {\n const configPath = path.resolve(cwd, \"revstack.config.ts\");\n\n try {\n const jiti = createJiti(cwd);\n const module = (await jiti.import(configPath)) as Record<string, unknown>;\n const config = (module.default ?? module) as Record<string, unknown>;\n\n // Sanitize: strip functions, class instances, and non-serializable data.\n // This ensures we only send plain JSON to the Revstack Cloud API.\n return JSON.parse(JSON.stringify(config));\n } catch (error: unknown) {\n const err = error as NodeJS.ErrnoException;\n\n if (\n err.code === \"ERR_MODULE_NOT_FOUND\" ||\n err.code === \"ENOENT\" ||\n err.code === \"MODULE_NOT_FOUND\"\n ) {\n console.error(\n chalk.red(\n \"\\n ✖ Could not find revstack.config.ts in the current directory.\\n\",\n ) +\n chalk.dim(\" Run \") +\n chalk.bold(\"revstack init\") +\n chalk.dim(\" to create one.\\n\"),\n );\n } else if (err.name === \"SyntaxError\" || error instanceof SyntaxError) {\n console.error(\n chalk.red(\"\\n ✖ Syntax Error in revstack.config.ts\\n\") +\n chalk.dim(\" \" + (err.message ?? String(error))) +\n \"\\n\",\n );\n } else {\n console.error(\n chalk.red(\"\\n ✖ Failed to parse revstack.config.ts\\n\") +\n chalk.dim(\" \" + (err.message ?? String(error))) +\n \"\\n\",\n );\n }\n\n process.exit(1);\n }\n}\n"],"mappings":"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","names":["chalk","path","chalk","path"]}
@@ -0,0 +1,5 @@
1
+ import { TemplateConfig } from './starter.js';
2
+
3
+ declare const aiAgentPlatform: TemplateConfig;
4
+
5
+ export { aiAgentPlatform };
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/commands/templates/ai-agent-platform.ts
4
+ var aiAgentPlatform = {
5
+ features: `import { defineFeature } from "@revstackhq/core";
6
+
7
+ export const features = {
8
+ llm_tokens: defineFeature({ name: "LLM Tokens (Input+Output)", type: "metered", unit_type: "count" }),
9
+ active_agents: defineFeature({ name: "Concurrent Agents", type: "static", unit_type: "count" }),
10
+ vector_storage_gb: defineFeature({ name: "Vector Database (GB)", type: "metered", unit_type: "custom" }),
11
+ custom_fine_tuning: defineFeature({ name: "Model Fine-Tuning", type: "boolean", unit_type: "custom" })
12
+ };
13
+ `,
14
+ addons: `import { defineAddon } from "@revstackhq/core";
15
+ import { features } from "./features";
16
+
17
+ export const addons = {
18
+ extra_vector_storage: defineAddon<typeof features>({
19
+ name: "10GB Vector Storage Block",
20
+ description: "Retain long-term memory for your AI agents.",
21
+ type: "recurring",
22
+ amount: 1000,
23
+ currency: "USD",
24
+ billing_interval: "monthly",
25
+ features: {
26
+ vector_storage_gb: { value_limit: 10, type: "increment", is_hard_limit: false }
27
+ }
28
+ }),
29
+ fine_tuning_job: defineAddon<typeof features>({
30
+ name: "Fine-Tuning Job Runner",
31
+ description: "Pay once to run a distributed model fine-tuning job on your dataset.",
32
+ type: "one_time",
33
+ amount: 25000,
34
+ currency: "USD",
35
+ features: {
36
+ custom_fine_tuning: { has_access: true }
37
+ }
38
+ })
39
+ };
40
+ `,
41
+ plans: `import { definePlan } from "@revstackhq/core";
42
+ import { features } from "./features";
43
+
44
+ export const plans = {
45
+ default: definePlan<typeof features>({
46
+ name: "Free Preview",
47
+ description: "Trial sandbox using shared models.",
48
+ is_default: true,
49
+ is_public: true,
50
+ type: "free",
51
+ features: {
52
+ llm_tokens: { value_limit: 100000, is_hard_limit: true, reset_period: "monthly" },
53
+ active_agents: { value_limit: 1, is_hard_limit: true },
54
+ vector_storage_gb: { value_limit: 0, is_hard_limit: true, reset_period: "never" },
55
+ custom_fine_tuning: { value_bool: false }
56
+ },
57
+ }),
58
+ builder: definePlan<typeof features>({
59
+ name: "AI Builder",
60
+ description: "High concurrency and dedicated model endpoints.",
61
+ is_default: false,
62
+ is_public: true,
63
+ type: "paid",
64
+ prices: [
65
+ {
66
+ amount: 4900,
67
+ currency: "USD",
68
+ billing_interval: "monthly",
69
+ available_addons: ["extra_vector_storage", "fine_tuning_job"],
70
+ overage_configuration: {
71
+ llm_tokens: { overage_amount: 15, overage_unit: 1000000 } // $0.15 per 1M tokens
72
+ }
73
+ }
74
+ ],
75
+ features: {
76
+ llm_tokens: { value_limit: 10000000, is_hard_limit: false, reset_period: "monthly" }, // 10M free tokens included
77
+ active_agents: { value_limit: 10, is_hard_limit: true },
78
+ vector_storage_gb: { value_limit: 5, is_hard_limit: true, reset_period: "never" }, // Hard limit until they buy the addon
79
+ custom_fine_tuning: { value_bool: false } // Only unlocked via the one-off addon
80
+ },
81
+ }),
82
+ };
83
+ `,
84
+ coupons: `import type { DiscountDef } from "@revstackhq/core";
85
+
86
+ export const coupons: DiscountDef[] = [
87
+ {
88
+ code: "BETA_TESTER",
89
+ name: "Early Beta Access Discount",
90
+ type: "percent",
91
+ value: 50,
92
+ duration: "repeating",
93
+ duration_in_months: 12,
94
+ max_redemptions: 100
95
+ }
96
+ ];
97
+ `,
98
+ index: `import { defineConfig } from "@revstackhq/core";
99
+ import { features } from "./features";
100
+ import { addons } from "./addons";
101
+ import { plans } from "./plans";
102
+ import { coupons } from "./coupons";
103
+
104
+ export default defineConfig({
105
+ features,
106
+ addons,
107
+ plans,
108
+ coupons,
109
+ });
110
+ `,
111
+ root: `import config from "./revstack";
112
+
113
+ export default config;
114
+ `
115
+ };
116
+ export {
117
+ aiAgentPlatform
118
+ };
119
+ //# sourceMappingURL=ai-agent-platform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/commands/templates/ai-agent-platform.ts"],"sourcesContent":["import { TemplateConfig } from \"./starter\";\r\n\r\nexport const aiAgentPlatform: TemplateConfig = {\r\n features: `import { defineFeature } from \"@revstackhq/core\";\r\n\r\nexport const features = {\r\n llm_tokens: defineFeature({ name: \"LLM Tokens (Input+Output)\", type: \"metered\", unit_type: \"count\" }),\r\n active_agents: defineFeature({ name: \"Concurrent Agents\", type: \"static\", unit_type: \"count\" }),\r\n vector_storage_gb: defineFeature({ name: \"Vector Database (GB)\", type: \"metered\", unit_type: \"custom\" }),\r\n custom_fine_tuning: defineFeature({ name: \"Model Fine-Tuning\", type: \"boolean\", unit_type: \"custom\" })\r\n};\r\n`,\r\n addons: `import { defineAddon } from \"@revstackhq/core\";\r\nimport { features } from \"./features\";\r\n\r\nexport const addons = {\r\n extra_vector_storage: defineAddon<typeof features>({\r\n name: \"10GB Vector Storage Block\",\r\n description: \"Retain long-term memory for your AI agents.\",\r\n type: \"recurring\",\r\n amount: 1000,\r\n currency: \"USD\",\r\n billing_interval: \"monthly\",\r\n features: {\r\n vector_storage_gb: { value_limit: 10, type: \"increment\", is_hard_limit: false }\r\n }\r\n }),\r\n fine_tuning_job: defineAddon<typeof features>({\r\n name: \"Fine-Tuning Job Runner\",\r\n description: \"Pay once to run a distributed model fine-tuning job on your dataset.\",\r\n type: \"one_time\",\r\n amount: 25000,\r\n currency: \"USD\",\r\n features: {\r\n custom_fine_tuning: { has_access: true }\r\n }\r\n })\r\n};\r\n`,\r\n plans: `import { definePlan } from \"@revstackhq/core\";\r\nimport { features } from \"./features\";\r\n\r\nexport const plans = {\r\n default: definePlan<typeof features>({\r\n name: \"Free Preview\",\r\n description: \"Trial sandbox using shared models.\",\r\n is_default: true,\r\n is_public: true,\r\n type: \"free\",\r\n features: {\r\n llm_tokens: { value_limit: 100000, is_hard_limit: true, reset_period: \"monthly\" },\r\n active_agents: { value_limit: 1, is_hard_limit: true },\r\n vector_storage_gb: { value_limit: 0, is_hard_limit: true, reset_period: \"never\" },\r\n custom_fine_tuning: { value_bool: false }\r\n },\r\n }),\r\n builder: definePlan<typeof features>({\r\n name: \"AI Builder\",\r\n description: \"High concurrency and dedicated model endpoints.\",\r\n is_default: false,\r\n is_public: true,\r\n type: \"paid\",\r\n prices: [\r\n {\r\n amount: 4900,\r\n currency: \"USD\",\r\n billing_interval: \"monthly\",\r\n available_addons: [\"extra_vector_storage\", \"fine_tuning_job\"],\r\n overage_configuration: {\r\n llm_tokens: { overage_amount: 15, overage_unit: 1000000 } // $0.15 per 1M tokens\r\n }\r\n }\r\n ],\r\n features: {\r\n llm_tokens: { value_limit: 10000000, is_hard_limit: false, reset_period: \"monthly\" }, // 10M free tokens included\r\n active_agents: { value_limit: 10, is_hard_limit: true },\r\n vector_storage_gb: { value_limit: 5, is_hard_limit: true, reset_period: \"never\" }, // Hard limit until they buy the addon\r\n custom_fine_tuning: { value_bool: false } // Only unlocked via the one-off addon\r\n },\r\n }),\r\n};\r\n`,\r\n coupons: `import type { DiscountDef } from \"@revstackhq/core\";\r\n\r\nexport const coupons: DiscountDef[] = [\r\n {\r\n code: \"BETA_TESTER\",\r\n name: \"Early Beta Access Discount\",\r\n type: \"percent\",\r\n value: 50,\r\n duration: \"repeating\",\r\n duration_in_months: 12,\r\n max_redemptions: 100\r\n }\r\n];\r\n`,\r\n index: `import { defineConfig } from \"@revstackhq/core\";\r\nimport { features } from \"./features\";\r\nimport { addons } from \"./addons\";\r\nimport { plans } from \"./plans\";\r\nimport { coupons } from \"./coupons\";\r\n\r\nexport default defineConfig({\r\n features,\r\n addons,\r\n plans,\r\n coupons,\r\n});\r\n`,\r\n root: `import config from \"./revstack\";\r\n\r\nexport default config;\r\n`,\r\n};\r\n"],"mappings":";;;AAEO,IAAM,kBAAkC;AAAA,EAC7C,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASV,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA2BR,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA2CP,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcT,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaP,MAAM;AAAA;AAAA;AAAA;AAIR;","names":[]}
@@ -18,9 +18,9 @@ export const addons = {
18
18
  name: "10 Extra Users",
19
19
  description: "Add 10 more active users to your workspace.",
20
20
  type: "recurring",
21
- prices: [
22
- { amount: 5000, currency: "USD", billing_interval: "monthly" }
23
- ],
21
+ amount: 5000,
22
+ currency: "USD",
23
+ billing_interval: "monthly",
24
24
  features: {
25
25
  active_users: { value_limit: 10, type: "increment", is_hard_limit: true },
26
26
  }
@@ -29,12 +29,25 @@ export const addons = {
29
29
  name: "Dedicated Support",
30
30
  description: "Enterprise SLA with 1-hour response time.",
31
31
  type: "recurring",
32
- prices: [
33
- { amount: 49900, currency: "USD", billing_interval: "monthly" }
34
- ],
32
+ amount: 49900,
33
+ currency: "USD",
34
+ billing_interval: "monthly",
35
35
  features: {}
36
36
  })
37
37
  };
38
+ `,
39
+ coupons: `import type { DiscountDef } from "@revstackhq/core";
40
+
41
+ export const coupons: DiscountDef[] = [
42
+ {
43
+ code: "ENTERPRISE_B2B",
44
+ name: "Annual Contract Rebate",
45
+ type: "amount",
46
+ value: 50000,
47
+ duration: "once",
48
+ applies_to_plans: ["enterprise"]
49
+ }
50
+ ];
38
51
  `,
39
52
  plans: `import { definePlan } from "@revstackhq/core";
40
53
  import { features } from "./features";
@@ -54,9 +67,8 @@ export const plans = {
54
67
  is_default: false,
55
68
  is_public: true,
56
69
  type: "paid",
57
- available_addons: ["extra_users"],
58
70
  prices: [
59
- { amount: 9900, currency: "USD", billing_interval: "monthly" }
71
+ { amount: 9900, currency: "USD", billing_interval: "monthly", available_addons: ["extra_users"] }
60
72
  ],
61
73
  features: {
62
74
  active_users: { value_limit: 10, is_hard_limit: true },
@@ -70,9 +82,8 @@ export const plans = {
70
82
  is_default: false,
71
83
  is_public: true,
72
84
  type: "paid",
73
- available_addons: ["extra_users", "dedicated_support"],
74
85
  prices: [
75
- { amount: 49900, currency: "USD", billing_interval: "monthly" }
86
+ { amount: 49900, currency: "USD", billing_interval: "monthly", available_addons: ["extra_users", "dedicated_support"] }
76
87
  ],
77
88
  features: {
78
89
  active_users: { value_limit: 100, is_hard_limit: false },
@@ -86,11 +97,13 @@ export const plans = {
86
97
  import { features } from "./features";
87
98
  import { addons } from "./addons";
88
99
  import { plans } from "./plans";
100
+ import { coupons } from "./coupons";
89
101
 
90
102
  export default defineConfig({
91
103
  features,
92
104
  addons,
93
105
  plans,
106
+ coupons,
94
107
  });
95
108
  `,
96
109
  root: `import config from "./revstack";
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/commands/templates/b2b-saas.ts"],"sourcesContent":["import { TemplateConfig } from \"./starter\";\r\n\r\nexport const b2bSaas: TemplateConfig = {\r\n features: `import { defineFeature } from \"@revstackhq/core\";\r\n\r\nexport const features = {\r\n active_users: defineFeature({ name: \"Active Users\", type: \"static\", unit_type: \"count\" }),\r\n api_access: defineFeature({ name: \"API Access\", type: \"boolean\", unit_type: \"custom\" }),\r\n custom_domain: defineFeature({ name: \"Custom Domain\", type: \"boolean\", unit_type: \"custom\" }),\r\n};\r\n`,\r\n addons: `import { defineAddon } from \"@revstackhq/core\";\r\nimport { features } from \"./features\";\r\n\r\nexport const addons = {\r\n extra_users: defineAddon<typeof features>({\r\n name: \"10 Extra Users\",\r\n description: \"Add 10 more active users to your workspace.\",\r\n type: \"recurring\",\r\n prices: [\r\n { amount: 5000, currency: \"USD\", billing_interval: \"monthly\" }\r\n ],\r\n features: {\r\n active_users: { value_limit: 10, type: \"increment\", is_hard_limit: true },\r\n }\r\n }),\r\n dedicated_support: defineAddon<typeof features>({\r\n name: \"Dedicated Support\",\r\n description: \"Enterprise SLA with 1-hour response time.\",\r\n type: \"recurring\",\r\n prices: [\r\n { amount: 49900, currency: \"USD\", billing_interval: \"monthly\" }\r\n ],\r\n features: {}\r\n })\r\n};\r\n`,\r\n plans: `import { definePlan } from \"@revstackhq/core\";\r\nimport { features } from \"./features\";\r\n\r\nexport const plans = {\r\n default: definePlan<typeof features>({\r\n name: \"Default\",\r\n description: \"Automatically created default plan for guests.\",\r\n is_default: true,\r\n is_public: false,\r\n type: \"free\",\r\n features: {},\r\n }),\r\n startup: definePlan<typeof features>({\r\n name: \"Startup\",\r\n description: \"For small teams getting started.\",\r\n is_default: false,\r\n is_public: true,\r\n type: \"paid\",\r\n available_addons: [\"extra_users\"],\r\n prices: [\r\n { amount: 9900, currency: \"USD\", billing_interval: \"monthly\" }\r\n ],\r\n features: {\r\n active_users: { value_limit: 10, is_hard_limit: true },\r\n api_access: { value_bool: false },\r\n custom_domain: { value_bool: false },\r\n },\r\n }),\r\n enterprise: definePlan<typeof features>({\r\n name: \"Enterprise\",\r\n description: \"Advanced features for scale.\",\r\n is_default: false,\r\n is_public: true,\r\n type: \"paid\",\r\n available_addons: [\"extra_users\", \"dedicated_support\"],\r\n prices: [\r\n { amount: 49900, currency: \"USD\", billing_interval: \"monthly\" }\r\n ],\r\n features: {\r\n active_users: { value_limit: 100, is_hard_limit: false },\r\n api_access: { value_bool: true },\r\n custom_domain: { value_bool: true },\r\n },\r\n }),\r\n};\r\n`,\r\n index: `import { defineConfig } from \"@revstackhq/core\";\r\nimport { features } from \"./features\";\r\nimport { addons } from \"./addons\";\r\nimport { plans } from \"./plans\";\r\n\r\nexport default defineConfig({\r\n features,\r\n addons,\r\n plans,\r\n});\r\n`,\r\n root: `import config from \"./revstack\";\r\n\r\nexport default config;\r\n`,\r\n};\r\n"],"mappings":";;;AAEO,IAAM,UAA0B;AAAA,EACrC,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQV,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA0BR,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA8CP,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWP,MAAM;AAAA;AAAA;AAAA;AAIR;","names":[]}
1
+ {"version":3,"sources":["../../../src/commands/templates/b2b-saas.ts"],"sourcesContent":["import { TemplateConfig } from \"./starter\";\r\n\r\nexport const b2bSaas: TemplateConfig = {\r\n features: `import { defineFeature } from \"@revstackhq/core\";\r\n\r\nexport const features = {\r\n active_users: defineFeature({ name: \"Active Users\", type: \"static\", unit_type: \"count\" }),\r\n api_access: defineFeature({ name: \"API Access\", type: \"boolean\", unit_type: \"custom\" }),\r\n custom_domain: defineFeature({ name: \"Custom Domain\", type: \"boolean\", unit_type: \"custom\" }),\r\n};\r\n`,\r\n addons: `import { defineAddon } from \"@revstackhq/core\";\r\nimport { features } from \"./features\";\r\n\r\nexport const addons = {\r\n extra_users: defineAddon<typeof features>({\r\n name: \"10 Extra Users\",\r\n description: \"Add 10 more active users to your workspace.\",\r\n type: \"recurring\",\r\n amount: 5000,\r\n currency: \"USD\",\r\n billing_interval: \"monthly\",\r\n features: {\r\n active_users: { value_limit: 10, type: \"increment\", is_hard_limit: true },\r\n }\r\n }),\r\n dedicated_support: defineAddon<typeof features>({\r\n name: \"Dedicated Support\",\r\n description: \"Enterprise SLA with 1-hour response time.\",\r\n type: \"recurring\",\r\n amount: 49900,\r\n currency: \"USD\",\r\n billing_interval: \"monthly\",\r\n features: {}\r\n })\r\n};\r\n`,\r\n coupons: `import type { DiscountDef } from \"@revstackhq/core\";\r\n\r\nexport const coupons: DiscountDef[] = [\r\n {\r\n code: \"ENTERPRISE_B2B\",\r\n name: \"Annual Contract Rebate\",\r\n type: \"amount\",\r\n value: 50000,\r\n duration: \"once\",\r\n applies_to_plans: [\"enterprise\"]\r\n }\r\n];\r\n`,\r\n plans: `import { definePlan } from \"@revstackhq/core\";\r\nimport { features } from \"./features\";\r\n\r\nexport const plans = {\r\n default: definePlan<typeof features>({\r\n name: \"Default\",\r\n description: \"Automatically created default plan for guests.\",\r\n is_default: true,\r\n is_public: false,\r\n type: \"free\",\r\n features: {},\r\n }),\r\n startup: definePlan<typeof features>({\r\n name: \"Startup\",\r\n description: \"For small teams getting started.\",\r\n is_default: false,\r\n is_public: true,\r\n type: \"paid\",\r\n prices: [\r\n { amount: 9900, currency: \"USD\", billing_interval: \"monthly\", available_addons: [\"extra_users\"] }\r\n ],\r\n features: {\r\n active_users: { value_limit: 10, is_hard_limit: true },\r\n api_access: { value_bool: false },\r\n custom_domain: { value_bool: false },\r\n },\r\n }),\r\n enterprise: definePlan<typeof features>({\r\n name: \"Enterprise\",\r\n description: \"Advanced features for scale.\",\r\n is_default: false,\r\n is_public: true,\r\n type: \"paid\",\r\n prices: [\r\n { amount: 49900, currency: \"USD\", billing_interval: \"monthly\", available_addons: [\"extra_users\", \"dedicated_support\"] }\r\n ],\r\n features: {\r\n active_users: { value_limit: 100, is_hard_limit: false },\r\n api_access: { value_bool: true },\r\n custom_domain: { value_bool: true },\r\n },\r\n }),\r\n};\r\n`,\r\n index: `import { defineConfig } from \"@revstackhq/core\";\r\nimport { features } from \"./features\";\r\nimport { addons } from \"./addons\";\r\nimport { plans } from \"./plans\";\r\nimport { coupons } from \"./coupons\";\r\n\r\nexport default defineConfig({\r\n features,\r\n addons,\r\n plans,\r\n coupons,\r\n});\r\n`,\r\n root: `import config from \"./revstack\";\r\n\r\nexport default config;\r\n`,\r\n};\r\n"],"mappings":";;;AAEO,IAAM,UAA0B;AAAA,EACrC,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQV,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA0BR,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaT,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA4CP,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaP,MAAM;AAAA;AAAA;AAAA;AAIR;","names":[]}
@@ -0,0 +1,5 @@
1
+ import { TemplateConfig } from './starter.js';
2
+
3
+ declare const developerTools: TemplateConfig;
4
+
5
+ export { developerTools };
@@ -0,0 +1,131 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/commands/templates/developer-tools.ts
4
+ var developerTools = {
5
+ features: `import { defineFeature } from "@revstackhq/core";
6
+
7
+ export const features = {
8
+ bandwidth_gb: defineFeature({ name: "Bandwidth (GB)", type: "metered", unit_type: "custom" }),
9
+ compute_hours: defineFeature({ name: "Compute (GB-Hours)", type: "metered", unit_type: "custom" }),
10
+ serverless_invokes: defineFeature({ name: "Serverless Invocations", type: "metered", unit_type: "count" }),
11
+ sso_auth: defineFeature({ name: "Enterprise SSO", type: "boolean", unit_type: "custom" })
12
+ };
13
+ `,
14
+ addons: `import { defineAddon } from "@revstackhq/core";
15
+ import { features } from "./features";
16
+
17
+ export const addons = {
18
+ dedicated_ipv4: defineAddon<typeof features>({
19
+ name: "Dedicated IPv4 Address",
20
+ description: "Assign a static IP to your deployments.",
21
+ type: "recurring",
22
+ amount: 500,
23
+ currency: "USD",
24
+ billing_interval: "monthly",
25
+ features: {}
26
+ }),
27
+ premium_sla: defineAddon<typeof features>({
28
+ name: "Premium Escalation SLA",
29
+ description: "Direct engineering support with 30-min response time.",
30
+ type: "recurring",
31
+ amount: 150000,
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: "Hobby",
44
+ description: "For personal or non-commercial projects.",
45
+ is_default: true,
46
+ is_public: true,
47
+ type: "free",
48
+ features: {
49
+ bandwidth_gb: { value_limit: 100, is_hard_limit: true, reset_period: "monthly" },
50
+ compute_hours: { value_limit: 100, is_hard_limit: true, reset_period: "monthly" },
51
+ serverless_invokes: { value_limit: 100000, is_hard_limit: true, reset_period: "monthly" },
52
+ sso_auth: { value_bool: false }
53
+ },
54
+ }),
55
+ pro: definePlan<typeof features>({
56
+ name: "Pro",
57
+ description: "For production apps and growing teams.",
58
+ is_default: false,
59
+ is_public: true,
60
+ type: "paid",
61
+ prices: [
62
+ {
63
+ amount: 2000,
64
+ currency: "USD",
65
+ billing_interval: "monthly",
66
+ available_addons: ["dedicated_ipv4"],
67
+ overage_configuration: {
68
+ bandwidth_gb: { overage_amount: 40, overage_unit: 100 }, // $0.40 per 100GB extra
69
+ compute_hours: { overage_amount: 2, overage_unit: 1 }, // $0.02 per extra GB hr
70
+ serverless_invokes: { overage_amount: 50, overage_unit: 1000000 } // $0.50 per 1M invokes
71
+ }
72
+ }
73
+ ],
74
+ features: {
75
+ bandwidth_gb: { value_limit: 1000, is_hard_limit: false, reset_period: "monthly" },
76
+ compute_hours: { value_limit: 1000, is_hard_limit: false, reset_period: "monthly" },
77
+ serverless_invokes: { value_limit: 5000000, is_hard_limit: false, reset_period: "monthly" },
78
+ sso_auth: { value_bool: false }
79
+ },
80
+ }),
81
+ enterprise: definePlan<typeof features>({
82
+ name: "Enterprise",
83
+ description: "Custom infrastructure and legal compliance.",
84
+ is_default: false,
85
+ is_public: true,
86
+ type: "custom",
87
+ prices: [],
88
+ features: {
89
+ bandwidth_gb: { value_limit: 50000, is_hard_limit: false, reset_period: "monthly" },
90
+ compute_hours: { value_limit: 10000, is_hard_limit: false, reset_period: "monthly" },
91
+ serverless_invokes: { value_limit: 100000000, is_hard_limit: false, reset_period: "monthly" },
92
+ sso_auth: { value_bool: true }
93
+ },
94
+ }),
95
+ };
96
+ `,
97
+ coupons: `import type { DiscountDef } from "@revstackhq/core";
98
+
99
+ export const coupons: DiscountDef[] = [
100
+ {
101
+ code: "YCOMBINATOR",
102
+ name: "YC Startup Accelerator Credit",
103
+ type: "amount",
104
+ value: 1000000, // $10,000 credit
105
+ duration: "forever",
106
+ applies_to_plans: ["pro", "enterprise"]
107
+ }
108
+ ];
109
+ `,
110
+ index: `import { defineConfig } from "@revstackhq/core";
111
+ import { features } from "./features";
112
+ import { addons } from "./addons";
113
+ import { plans } from "./plans";
114
+ import { coupons } from "./coupons";
115
+
116
+ export default defineConfig({
117
+ features,
118
+ addons,
119
+ plans,
120
+ coupons,
121
+ });
122
+ `,
123
+ root: `import config from "./revstack";
124
+
125
+ export default config;
126
+ `
127
+ };
128
+ export {
129
+ developerTools
130
+ };
131
+ //# sourceMappingURL=developer-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/commands/templates/developer-tools.ts"],"sourcesContent":["import { TemplateConfig } from \"./starter\";\r\n\r\nexport const developerTools: TemplateConfig = {\r\n features: `import { defineFeature } from \"@revstackhq/core\";\r\n\r\nexport const features = {\r\n bandwidth_gb: defineFeature({ name: \"Bandwidth (GB)\", type: \"metered\", unit_type: \"custom\" }),\r\n compute_hours: defineFeature({ name: \"Compute (GB-Hours)\", type: \"metered\", unit_type: \"custom\" }),\r\n serverless_invokes: defineFeature({ name: \"Serverless Invocations\", type: \"metered\", unit_type: \"count\" }),\r\n sso_auth: defineFeature({ name: \"Enterprise SSO\", type: \"boolean\", unit_type: \"custom\" })\r\n};\r\n`,\r\n addons: `import { defineAddon } from \"@revstackhq/core\";\r\nimport { features } from \"./features\";\r\n\r\nexport const addons = {\r\n dedicated_ipv4: defineAddon<typeof features>({\r\n name: \"Dedicated IPv4 Address\",\r\n description: \"Assign a static IP to your deployments.\",\r\n type: \"recurring\",\r\n amount: 500,\r\n currency: \"USD\",\r\n billing_interval: \"monthly\",\r\n features: {}\r\n }),\r\n premium_sla: defineAddon<typeof features>({\r\n name: \"Premium Escalation SLA\",\r\n description: \"Direct engineering support with 30-min response time.\",\r\n type: \"recurring\",\r\n amount: 150000,\r\n currency: \"USD\",\r\n billing_interval: \"monthly\",\r\n features: {}\r\n })\r\n};\r\n`,\r\n plans: `import { definePlan } from \"@revstackhq/core\";\r\nimport { features } from \"./features\";\r\n\r\nexport const plans = {\r\n default: definePlan<typeof features>({\r\n name: \"Hobby\",\r\n description: \"For personal or non-commercial projects.\",\r\n is_default: true,\r\n is_public: true,\r\n type: \"free\",\r\n features: {\r\n bandwidth_gb: { value_limit: 100, is_hard_limit: true, reset_period: \"monthly\" },\r\n compute_hours: { value_limit: 100, is_hard_limit: true, reset_period: \"monthly\" },\r\n serverless_invokes: { value_limit: 100000, is_hard_limit: true, reset_period: \"monthly\" },\r\n sso_auth: { value_bool: false }\r\n },\r\n }),\r\n pro: definePlan<typeof features>({\r\n name: \"Pro\",\r\n description: \"For production apps and growing teams.\",\r\n is_default: false,\r\n is_public: true,\r\n type: \"paid\",\r\n prices: [\r\n {\r\n amount: 2000,\r\n currency: \"USD\",\r\n billing_interval: \"monthly\",\r\n available_addons: [\"dedicated_ipv4\"],\r\n overage_configuration: {\r\n bandwidth_gb: { overage_amount: 40, overage_unit: 100 }, // $0.40 per 100GB extra\r\n compute_hours: { overage_amount: 2, overage_unit: 1 }, // $0.02 per extra GB hr\r\n serverless_invokes: { overage_amount: 50, overage_unit: 1000000 } // $0.50 per 1M invokes\r\n }\r\n }\r\n ],\r\n features: {\r\n bandwidth_gb: { value_limit: 1000, is_hard_limit: false, reset_period: \"monthly\" },\r\n compute_hours: { value_limit: 1000, is_hard_limit: false, reset_period: \"monthly\" },\r\n serverless_invokes: { value_limit: 5000000, is_hard_limit: false, reset_period: \"monthly\" },\r\n sso_auth: { value_bool: false }\r\n },\r\n }),\r\n enterprise: definePlan<typeof features>({\r\n name: \"Enterprise\",\r\n description: \"Custom infrastructure and legal compliance.\",\r\n is_default: false,\r\n is_public: true,\r\n type: \"custom\",\r\n prices: [],\r\n features: {\r\n bandwidth_gb: { value_limit: 50000, is_hard_limit: false, reset_period: \"monthly\" },\r\n compute_hours: { value_limit: 10000, is_hard_limit: false, reset_period: \"monthly\" },\r\n serverless_invokes: { value_limit: 100000000, is_hard_limit: false, reset_period: \"monthly\" },\r\n sso_auth: { value_bool: true }\r\n },\r\n }),\r\n};\r\n`,\r\n coupons: `import type { DiscountDef } from \"@revstackhq/core\";\r\n\r\nexport const coupons: DiscountDef[] = [\r\n {\r\n code: \"YCOMBINATOR\",\r\n name: \"YC Startup Accelerator Credit\",\r\n type: \"amount\",\r\n value: 1000000, // $10,000 credit\r\n duration: \"forever\",\r\n applies_to_plans: [\"pro\", \"enterprise\"]\r\n }\r\n];\r\n`,\r\n index: `import { defineConfig } from \"@revstackhq/core\";\r\nimport { features } from \"./features\";\r\nimport { addons } from \"./addons\";\r\nimport { plans } from \"./plans\";\r\nimport { coupons } from \"./coupons\";\r\n\r\nexport default defineConfig({\r\n features,\r\n addons,\r\n plans,\r\n coupons,\r\n});\r\n`,\r\n root: `import config from \"./revstack\";\r\n\r\nexport default config;\r\n`,\r\n};\r\n"],"mappings":";;;AAEO,IAAM,iBAAiC;AAAA,EAC5C,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASV,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAwBR,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA2DP,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaT,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaP,MAAM;AAAA;AAAA;AAAA;AAIR;","names":[]}
@@ -0,0 +1,5 @@
1
+ import { TemplateConfig } from './starter.js';
2
+
3
+ declare const ecommercePlatform: TemplateConfig;
4
+
5
+ export { ecommercePlatform };
@@ -0,0 +1,144 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/commands/templates/ecommerce-platform.ts
4
+ var ecommercePlatform = {
5
+ features: `import { defineFeature } from "@revstackhq/core";
6
+
7
+ export const features = {
8
+ orders: defineFeature({ name: "Monthly Orders", type: "metered", unit_type: "count" }),
9
+ storefronts: defineFeature({ name: "Storefronts", type: "static", unit_type: "count" }),
10
+ advanced_analytics: defineFeature({ name: "Advanced Analytics", 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_storefront: defineAddon<typeof features>({
18
+ name: "Additional Storefront",
19
+ description: "Launch a new brand under the same account.",
20
+ type: "recurring",
21
+ amount: 5000,
22
+ currency: "USD",
23
+ billing_interval: "monthly",
24
+ features: {
25
+ storefronts: { value_limit: 1, type: "increment", is_hard_limit: true },
26
+ }
27
+ }),
28
+ custom_domain_ssl: defineAddon<typeof features>({
29
+ name: "Custom Domain & SSL",
30
+ description: "Secure your storefront with a custom domain.",
31
+ type: "recurring",
32
+ amount: 1500,
33
+ currency: "USD",
34
+ billing_interval: "monthly",
35
+ features: {}
36
+ })
37
+ };
38
+ `,
39
+ plans: `import { definePlan } from "@revstackhq/core";
40
+ import { features } from "./features";
41
+
42
+ export const plans = {
43
+ default: definePlan<typeof features>({
44
+ name: "Default Sandbox",
45
+ description: "Test your store safely before going live.",
46
+ is_default: true,
47
+ is_public: false,
48
+ type: "free",
49
+ features: {},
50
+ }),
51
+ basic: definePlan<typeof features>({
52
+ name: "Basic Commerce",
53
+ description: "Everything you need to sell online.",
54
+ is_default: false,
55
+ is_public: true,
56
+ type: "paid",
57
+ prices: [
58
+ {
59
+ amount: 2900,
60
+ currency: "USD",
61
+ billing_interval: "monthly",
62
+ available_addons: ["custom_domain_ssl"],
63
+ overage_configuration: {
64
+ orders: { overage_amount: 50, overage_unit: 100 } // $0.50 per 100 extra orders
65
+ }
66
+ }
67
+ ],
68
+ features: {
69
+ orders: { value_limit: 500, is_hard_limit: false, reset_period: "monthly" },
70
+ storefronts: { value_limit: 1, is_hard_limit: true },
71
+ advanced_analytics: { value_bool: false },
72
+ },
73
+ }),
74
+ pro: definePlan<typeof features>({
75
+ name: "Pro Seller",
76
+ description: "For scaling businesses.",
77
+ is_default: false,
78
+ is_public: true,
79
+ type: "paid",
80
+ prices: [
81
+ {
82
+ amount: 19900,
83
+ currency: "USD",
84
+ billing_interval: "monthly",
85
+ available_addons: ["extra_storefront", "custom_domain_ssl"],
86
+ overage_configuration: {
87
+ orders: { overage_amount: 30, overage_unit: 100 } // $0.30 per 100 extra orders
88
+ }
89
+ }
90
+ ],
91
+ features: {
92
+ orders: { value_limit: 5000, is_hard_limit: false, reset_period: "monthly" },
93
+ storefronts: { value_limit: 2, is_hard_limit: true },
94
+ advanced_analytics: { value_bool: true },
95
+ },
96
+ }),
97
+ };
98
+ `,
99
+ coupons: `import type { DiscountDef } from "@revstackhq/core";
100
+
101
+ export const coupons: DiscountDef[] = [
102
+ {
103
+ code: "BFCM_PROMO",
104
+ name: "Black Friday Cyber Monday 20%",
105
+ type: "percent",
106
+ value: 20,
107
+ duration: "repeating",
108
+ duration_in_months: 6,
109
+ expires_at: "2024-11-29T00:00:00Z", // Ephemeral timestamp
110
+ max_redemptions: 5000
111
+ },
112
+ {
113
+ code: "FIRST_MONTH_FREE",
114
+ name: "New Store Launch",
115
+ type: "percent",
116
+ value: 100,
117
+ duration: "repeating",
118
+ duration_in_months: 1,
119
+ applies_to_plans: ["basic"]
120
+ }
121
+ ];
122
+ `,
123
+ index: `import { defineConfig } from "@revstackhq/core";
124
+ import { features } from "./features";
125
+ import { addons } from "./addons";
126
+ import { plans } from "./plans";
127
+ import { coupons } from "./coupons";
128
+
129
+ export default defineConfig({
130
+ features,
131
+ addons,
132
+ plans,
133
+ coupons,
134
+ });
135
+ `,
136
+ root: `import config from "./revstack";
137
+
138
+ export default config;
139
+ `
140
+ };
141
+ export {
142
+ ecommercePlatform
143
+ };
144
+ //# sourceMappingURL=ecommerce-platform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/commands/templates/ecommerce-platform.ts"],"sourcesContent":["import { TemplateConfig } from \"./starter\";\r\n\r\nexport const ecommercePlatform: TemplateConfig = {\r\n features: `import { defineFeature } from \"@revstackhq/core\";\r\n\r\nexport const features = {\r\n orders: defineFeature({ name: \"Monthly Orders\", type: \"metered\", unit_type: \"count\" }),\r\n storefronts: defineFeature({ name: \"Storefronts\", type: \"static\", unit_type: \"count\" }),\r\n advanced_analytics: defineFeature({ name: \"Advanced Analytics\", type: \"boolean\", unit_type: \"custom\" }),\r\n};\r\n`,\r\n addons: `import { defineAddon } from \"@revstackhq/core\";\r\nimport { features } from \"./features\";\r\n\r\nexport const addons = {\r\n extra_storefront: defineAddon<typeof features>({\r\n name: \"Additional Storefront\",\r\n description: \"Launch a new brand under the same account.\",\r\n type: \"recurring\",\r\n amount: 5000,\r\n currency: \"USD\",\r\n billing_interval: \"monthly\",\r\n features: {\r\n storefronts: { value_limit: 1, type: \"increment\", is_hard_limit: true },\r\n }\r\n }),\r\n custom_domain_ssl: defineAddon<typeof features>({\r\n name: \"Custom Domain & SSL\",\r\n description: \"Secure your storefront with a custom domain.\",\r\n type: \"recurring\",\r\n amount: 1500,\r\n currency: \"USD\",\r\n billing_interval: \"monthly\",\r\n features: {}\r\n })\r\n};\r\n`,\r\n plans: `import { definePlan } from \"@revstackhq/core\";\r\nimport { features } from \"./features\";\r\n\r\nexport const plans = {\r\n default: definePlan<typeof features>({\r\n name: \"Default Sandbox\",\r\n description: \"Test your store safely before going live.\",\r\n is_default: true,\r\n is_public: false,\r\n type: \"free\",\r\n features: {},\r\n }),\r\n basic: definePlan<typeof features>({\r\n name: \"Basic Commerce\",\r\n description: \"Everything you need to sell online.\",\r\n is_default: false,\r\n is_public: true,\r\n type: \"paid\",\r\n prices: [\r\n {\r\n amount: 2900,\r\n currency: \"USD\",\r\n billing_interval: \"monthly\",\r\n available_addons: [\"custom_domain_ssl\"],\r\n overage_configuration: {\r\n orders: { overage_amount: 50, overage_unit: 100 } // $0.50 per 100 extra orders\r\n }\r\n }\r\n ],\r\n features: {\r\n orders: { value_limit: 500, is_hard_limit: false, reset_period: \"monthly\" },\r\n storefronts: { value_limit: 1, is_hard_limit: true },\r\n advanced_analytics: { value_bool: false },\r\n },\r\n }),\r\n pro: definePlan<typeof features>({\r\n name: \"Pro Seller\",\r\n description: \"For scaling businesses.\",\r\n is_default: false,\r\n is_public: true,\r\n type: \"paid\",\r\n prices: [\r\n {\r\n amount: 19900,\r\n currency: \"USD\",\r\n billing_interval: \"monthly\",\r\n available_addons: [\"extra_storefront\", \"custom_domain_ssl\"],\r\n overage_configuration: {\r\n orders: { overage_amount: 30, overage_unit: 100 } // $0.30 per 100 extra orders\r\n }\r\n }\r\n ],\r\n features: {\r\n orders: { value_limit: 5000, is_hard_limit: false, reset_period: \"monthly\" },\r\n storefronts: { value_limit: 2, is_hard_limit: true },\r\n advanced_analytics: { value_bool: true },\r\n },\r\n }),\r\n};\r\n`,\r\n coupons: `import type { DiscountDef } from \"@revstackhq/core\";\r\n\r\nexport const coupons: DiscountDef[] = [\r\n {\r\n code: \"BFCM_PROMO\",\r\n name: \"Black Friday Cyber Monday 20%\",\r\n type: \"percent\",\r\n value: 20,\r\n duration: \"repeating\",\r\n duration_in_months: 6,\r\n expires_at: \"2024-11-29T00:00:00Z\", // Ephemeral timestamp\r\n max_redemptions: 5000\r\n },\r\n {\r\n code: \"FIRST_MONTH_FREE\",\r\n name: \"New Store Launch\",\r\n type: \"percent\",\r\n value: 100,\r\n duration: \"repeating\",\r\n duration_in_months: 1,\r\n applies_to_plans: [\"basic\"]\r\n }\r\n];\r\n`,\r\n index: `import { defineConfig } from \"@revstackhq/core\";\r\nimport { features } from \"./features\";\r\nimport { addons } from \"./addons\";\r\nimport { plans } from \"./plans\";\r\nimport { coupons } from \"./coupons\";\r\n\r\nexport default defineConfig({\r\n features,\r\n addons,\r\n plans,\r\n coupons,\r\n});\r\n`,\r\n root: `import config from \"./revstack\";\r\n\r\nexport default config;\r\n`,\r\n};\r\n"],"mappings":";;;AAEO,IAAM,oBAAoC;AAAA,EAC/C,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQV,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA0BR,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA4DP,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAwBT,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaP,MAAM;AAAA;AAAA;AAAA;AAIR;","names":[]}