@superbuilds/create-supersaas-app 0.0.0-stage → 2.0.0

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/README.md CHANGED
@@ -1,3 +1,139 @@
1
- # Temporary Holding Version
1
+ # create-supersaas-app
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ > Scaffold production-ready SaaS apps in seconds
4
+
5
+ The fastest way to get your indie SaaS off the ground. Built for serious builders who ship.
6
+
7
+ ## Quick Start
8
+
9
+ ```bash
10
+ npx create-supersaas-app my-saas --key YOUR_LICENSE_KEY
11
+ cd my-saas
12
+ npm run dev
13
+ ```
14
+
15
+ ## What You Get
16
+
17
+ - **Next.js 15** + React 19 + TypeScript
18
+ - **Authentication** (Better Auth) - email, OAuth, magic links
19
+ - **Payments** (Stripe) - subscriptions, one-time, webhooks
20
+ - **Database** (Drizzle ORM) - type-safe, migrations included
21
+ - **Email** (Resend) - transactional + newsletter
22
+ - **Teams** - multi-tenant with invites
23
+ - **Admin Dashboard** - user management, analytics
24
+ - **Beautiful UI** - Tailwind CSS v4, dark mode, responsive
25
+ - **API Routes** - rate limiting, validation, error handling
26
+
27
+ ## Usage
28
+
29
+ ### Interactive Mode (Recommended)
30
+
31
+ ```bash
32
+ npx create-supersaas-app
33
+ ```
34
+
35
+ You'll be prompted for:
36
+ - App name
37
+ - Database provider (Neon, Supabase, PlanetScale, SQLite)
38
+ - Optional features (blog, AI routes, admin, waitlist)
39
+
40
+ ### Non-Interactive Mode
41
+
42
+ Perfect for CI/CD or automation:
43
+
44
+ ```bash
45
+ npx create-supersaas-app my-saas \
46
+ --key YOUR_LICENSE_KEY \
47
+ --db neon \
48
+ --features blog,ai,admin \
49
+ --yes
50
+ ```
51
+
52
+ ## Options
53
+
54
+ | Flag | Description | Example |
55
+ |------|-------------|---------|
56
+ | `--key` | License key (required) | `--key lic_abc123` |
57
+ | `--db` | Database provider | `--db neon` |
58
+ | `--features` | Comma-separated features | `--features blog,ai` |
59
+ | `--yes` | Skip prompts, use defaults | `--yes` |
60
+
61
+ ## Features
62
+
63
+ ### Core (All Tiers)
64
+
65
+ - Authentication (email + OAuth)
66
+ - Database with migrations
67
+ - Payment processing
68
+ - Email delivery
69
+ - Team management
70
+ - API routes
71
+
72
+ ### Pro Tier
73
+
74
+ - AI routes (OpenAI/Anthropic)
75
+ - Admin dashboard
76
+ - Advanced themes
77
+ - Priority support
78
+
79
+ ### Bundle Tier
80
+
81
+ - Everything in Pro
82
+ - Lifetime updates
83
+ - Team licenses
84
+ - Early access to new features
85
+
86
+ ## Database Options
87
+
88
+ - **Neon** (Postgres) - Recommended, generous free tier
89
+ - **Supabase** (Postgres) - Auth + DB + Storage
90
+ - **PlanetScale** (MySQL) - Serverless MySQL
91
+ - **SQLite** - Local development
92
+
93
+ ## After Installation
94
+
95
+ ```bash
96
+ cd your-app
97
+
98
+ # 1. Set up environment variables
99
+ cp .env.example .env.local
100
+ # Edit .env.local with your keys
101
+
102
+ # 2. Run migrations
103
+ npm run db:push
104
+
105
+ # 3. Start dev server
106
+ npm run dev
107
+ ```
108
+
109
+ Visit `http://localhost:3000`
110
+
111
+ ## CLI Commands (built-in)
112
+
113
+ Once your app is created, use the built-in CLI from your project directory:
114
+
115
+ ```bash
116
+ npx supersaas setup stripe
117
+ npx supersaas add blog
118
+ npx supersaas deploy
119
+ ```
120
+
121
+ ## License
122
+
123
+ You need a valid supersaas-kit license to use this. Get yours at [supersaas-kit.superbuilds.fun](https://supersaas-kit.superbuilds.fun)
124
+
125
+ ## Support
126
+
127
+ - **Docs:** https://supersaas-kit.superbuilds.fun/docs
128
+ - **Issues:** https://github.com/bixblues/supersaas-kit/issues
129
+ - **Email:** hi@superbuilds.fun
130
+
131
+ ## What's Next?
132
+
133
+ 1. Read the docs: https://supersaas-kit.superbuilds.fun/docs
134
+ 2. Join Discord: https://supersaas-kit.superbuilds.fun/discord
135
+ 3. Follow updates: https://x.com/superbuilds
136
+
137
+ ---
138
+
139
+ Built with ❤️ by indie hackers, for indie hackers.
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/index.js ADDED
@@ -0,0 +1,446 @@
1
+ #!/usr/bin/env node
2
+ import { program } from 'commander';
3
+ import * as p3 from '@clack/prompts';
4
+ import chalk from 'chalk';
5
+ import path from 'path';
6
+ import fs from 'fs-extra';
7
+ import ora from 'ora';
8
+ import { execSync } from 'child_process';
9
+ import os2 from 'os';
10
+ import { createRequire } from 'module';
11
+
12
+ var API_BASE = process.env.SUPERSAAS_API_URL || "https://supersaas-kit.superbuilds.fun";
13
+ var SUBSTITUTIONS = {
14
+ __APP_NAME__: (c) => c.name
15
+ };
16
+ var FEATURE_PATHS = {
17
+ blog: [
18
+ "src/app/(marketing)/blog",
19
+ "src/app/blog",
20
+ "src/lib/blog.ts",
21
+ "content/blog",
22
+ "src/components/blog"
23
+ ],
24
+ admin: [
25
+ "src/app/(app)/admin",
26
+ "src/lib/admin"
27
+ ]
28
+ };
29
+ var DATABASE_CONFIGS = {
30
+ neon: { hint: "# Get your connection string from https://console.neon.tech" },
31
+ supabase: { hint: "# Get your connection string from Supabase Dashboard > Settings > Database" },
32
+ local: { hint: "# Local Docker Postgres: docker compose up -d" }
33
+ };
34
+ async function downloadTemplate(licenseKey, targetDir) {
35
+ const spinner = ora("Downloading template...").start();
36
+ try {
37
+ const res = await fetch(`${API_BASE}/api/download`, {
38
+ method: "POST",
39
+ headers: { "Content-Type": "application/json" },
40
+ body: JSON.stringify({
41
+ license_key: licenseKey
42
+ })
43
+ });
44
+ if (!res.ok) {
45
+ spinner.fail(chalk.red("Download failed"));
46
+ const errorBody = await res.json().catch(() => ({}));
47
+ const msg = errorBody.error || `HTTP ${res.status}`;
48
+ p3.log.error(chalk.red(msg));
49
+ if (res.status === 403) {
50
+ p3.log.info(chalk.dim("Your license may not include this tier. Check https://supersaas-kit.superbuilds.fun"));
51
+ }
52
+ if (res.status === 429) {
53
+ p3.log.info(chalk.dim("Too many downloads. Wait an hour and try again."));
54
+ }
55
+ return false;
56
+ }
57
+ const tmpDir = path.join(os2.tmpdir(), `supersaas-kit-${Date.now()}`);
58
+ await fs.ensureDir(tmpDir);
59
+ const archivePath = path.join(tmpDir, "template.tar.gz");
60
+ const arrayBuffer = await res.arrayBuffer();
61
+ await fs.writeFile(archivePath, Buffer.from(arrayBuffer));
62
+ spinner.text = "Extracting template...";
63
+ await fs.ensureDir(targetDir);
64
+ execSync(`tar -xzf "${archivePath}" -C "${targetDir}"`, {
65
+ stdio: "pipe"
66
+ });
67
+ await fs.remove(tmpDir);
68
+ spinner.succeed(chalk.green("Template downloaded and extracted"));
69
+ return true;
70
+ } catch (err) {
71
+ spinner.fail(chalk.red("Download failed"));
72
+ p3.log.error(
73
+ chalk.red(
74
+ `Could not download template: ${err.message}`
75
+ )
76
+ );
77
+ p3.log.info(chalk.dim("Check your internet connection and try again."));
78
+ return false;
79
+ }
80
+ }
81
+ async function createApp(config) {
82
+ const targetDir = path.resolve(process.cwd(), config.name);
83
+ if (await fs.pathExists(targetDir)) {
84
+ p3.log.error(chalk.red(`Directory "${config.name}" already exists.`));
85
+ process.exit(1);
86
+ }
87
+ const downloaded = await downloadTemplate(config.licenseKey, targetDir);
88
+ if (!downloaded) {
89
+ process.exit(1);
90
+ }
91
+ const excludePaths = /* @__PURE__ */ new Set();
92
+ for (const [feature, paths] of Object.entries(FEATURE_PATHS)) {
93
+ if (!config.features.includes(feature)) {
94
+ for (const p4 of paths) {
95
+ excludePaths.add(p4);
96
+ }
97
+ }
98
+ }
99
+ for (const excludePath of excludePaths) {
100
+ const fullPath = path.join(targetDir, excludePath);
101
+ if (await fs.pathExists(fullPath)) {
102
+ await fs.remove(fullPath);
103
+ }
104
+ }
105
+ const pkgTemplatePath = path.join(targetDir, "package.json.template");
106
+ if (await fs.pathExists(pkgTemplatePath)) {
107
+ await fs.move(pkgTemplatePath, path.join(targetDir, "package.json"));
108
+ }
109
+ await substituteVars(targetDir, config);
110
+ await configureDatabase(targetDir, config);
111
+ await updateManifest(targetDir, config);
112
+ const envExample = path.join(targetDir, ".env.example");
113
+ if (await fs.pathExists(envExample)) {
114
+ await fs.copy(envExample, path.join(targetDir, ".env"));
115
+ }
116
+ await cleanupFeatureImports(targetDir, config);
117
+ const activeFeatures = ["auth", "payments", "email", "seo", ...config.features];
118
+ p3.log.info(chalk.dim(`Database: ${config.database}`));
119
+ p3.log.info(chalk.dim(`Features: ${activeFeatures.join(", ")}`));
120
+ }
121
+ async function configureDatabase(targetDir, config) {
122
+ const dbConfig = DATABASE_CONFIGS[config.database];
123
+ if (!dbConfig) return;
124
+ const envPath = path.join(targetDir, ".env.example");
125
+ if (await fs.pathExists(envPath)) {
126
+ let content = await fs.readFile(envPath, "utf-8");
127
+ const hint = dbConfig.hint;
128
+ if (hint && !content.includes(hint)) {
129
+ content = content.replace(/DATABASE_URL=/, `${hint}
130
+ DATABASE_URL=`);
131
+ await fs.writeFile(envPath, content);
132
+ }
133
+ }
134
+ if (config.database === "local") {
135
+ const envPath2 = path.join(targetDir, ".env.example");
136
+ if (await fs.pathExists(envPath2)) {
137
+ let content = await fs.readFile(envPath2, "utf-8");
138
+ if (content.includes("DATABASE_URL=postgres://postgres:postgres@localhost:5432/app")) ;
139
+ await fs.writeFile(envPath2, content);
140
+ }
141
+ }
142
+ }
143
+ async function updateManifest(targetDir, config) {
144
+ const manifestPath = path.join(targetDir, ".supersaas", "manifest.json");
145
+ if (await fs.pathExists(manifestPath)) {
146
+ const manifest = await fs.readJson(manifestPath);
147
+ manifest.database = config.database;
148
+ manifest.features = config.features;
149
+ manifest.tier = config.tier;
150
+ manifest.createdAt = (/* @__PURE__ */ new Date()).toISOString();
151
+ if (manifest.providers) {
152
+ if (manifest.providers.db) manifest.providers.db = "postgres";
153
+ }
154
+ await fs.writeJson(manifestPath, manifest, { spaces: 2 });
155
+ }
156
+ }
157
+ async function cleanupFeatureImports(targetDir, config) {
158
+ if (!config.features.includes("blog")) {
159
+ const sitemapPath = path.join(targetDir, "src/app/sitemap.ts");
160
+ if (await fs.pathExists(sitemapPath)) {
161
+ await fs.writeFile(sitemapPath, `import { MetadataRoute } from "next";
162
+ import { appConfig } from "@/config/app";
163
+
164
+ const baseUrl = appConfig.url;
165
+
166
+ export default function sitemap(): MetadataRoute.Sitemap {
167
+ const now = new Date();
168
+
169
+ return [
170
+ { url: baseUrl, lastModified: now, changeFrequency: "weekly", priority: 1.0 },
171
+ { url: \`\${baseUrl}/sign-up\`, lastModified: now, changeFrequency: "yearly", priority: 0.5 },
172
+ ];
173
+ }
174
+ `);
175
+ }
176
+ const configPath = path.join(targetDir, "src/config/app.ts");
177
+ if (await fs.pathExists(configPath)) {
178
+ let content = await fs.readFile(configPath, "utf-8");
179
+ content = content.replace(/\s*\{\s*label:\s*["']Blog["'],\s*href:\s*["']\/blog["']\s*\},?\n?/g, "");
180
+ await fs.writeFile(configPath, content);
181
+ }
182
+ }
183
+ if (!config.features.includes("admin")) {
184
+ const sidebarPath = path.join(targetDir, "src/components/layout/sidebar.tsx");
185
+ if (await fs.pathExists(sidebarPath)) {
186
+ let content = await fs.readFile(sidebarPath, "utf-8");
187
+ content = content.replace(/\s*\{\s*label:\s*["']Admin["'].*?\},?\n?/gs, "");
188
+ await fs.writeFile(sidebarPath, content);
189
+ }
190
+ }
191
+ }
192
+ async function substituteVars(dir, config) {
193
+ const textExtensions = [
194
+ ".ts",
195
+ ".tsx",
196
+ ".js",
197
+ ".jsx",
198
+ ".json",
199
+ ".md",
200
+ ".mdx",
201
+ ".css",
202
+ ".env",
203
+ ".example"
204
+ ];
205
+ const files = await getAllFiles(dir);
206
+ for (const file of files) {
207
+ const ext = path.extname(file);
208
+ const basename = path.basename(file);
209
+ if (!textExtensions.includes(ext) && !basename.startsWith(".env")) continue;
210
+ let content = await fs.readFile(file, "utf-8");
211
+ let changed = false;
212
+ for (const [placeholder, resolver] of Object.entries(SUBSTITUTIONS)) {
213
+ if (content.includes(placeholder)) {
214
+ content = content.replaceAll(placeholder, resolver(config));
215
+ changed = true;
216
+ }
217
+ }
218
+ if (changed) {
219
+ await fs.writeFile(file, content);
220
+ }
221
+ }
222
+ }
223
+ async function getAllFiles(dir) {
224
+ const entries = await fs.readdir(dir, { withFileTypes: true });
225
+ const files = [];
226
+ for (const entry of entries) {
227
+ const full = path.join(dir, entry.name);
228
+ if (entry.isDirectory()) {
229
+ if (entry.name === "node_modules" || entry.name === ".next") continue;
230
+ files.push(...await getAllFiles(full));
231
+ } else {
232
+ files.push(full);
233
+ }
234
+ }
235
+ return files;
236
+ }
237
+ var SUPERSAAS_DIR = path.join(os2.homedir(), ".supersaas");
238
+ var LICENSE_PATH = path.join(SUPERSAAS_DIR, "license.json");
239
+ var DODO_BASE_URL = process.env.SUPERSAAS_DODO_URL || "https://test.dodopayments.com";
240
+ function inferTierFromActivation(_data) {
241
+ return "bundle";
242
+ }
243
+ async function loadLocalLicense() {
244
+ try {
245
+ if (await fs.pathExists(LICENSE_PATH)) {
246
+ const data = await fs.readJson(LICENSE_PATH);
247
+ if (data.key && data.tier && data.instance_id) {
248
+ return data;
249
+ }
250
+ }
251
+ } catch {
252
+ }
253
+ return null;
254
+ }
255
+ async function validateKey(key) {
256
+ try {
257
+ const res = await fetch(`${DODO_BASE_URL}/licenses/validate`, {
258
+ method: "POST",
259
+ headers: { "Content-Type": "application/json" },
260
+ body: JSON.stringify({ license_key: key })
261
+ });
262
+ if (!res.ok) {
263
+ return { valid: false };
264
+ }
265
+ const data = await res.json();
266
+ return { valid: data.valid !== false, data };
267
+ } catch {
268
+ return { valid: false };
269
+ }
270
+ }
271
+ async function activateOnline(key) {
272
+ const machineName = `${os2.hostname()} (${os2.platform()})`;
273
+ try {
274
+ const validation = await validateKey(key);
275
+ if (!validation.valid) {
276
+ p3.log.error(chalk.red("Invalid or expired license key."));
277
+ return null;
278
+ }
279
+ const res = await fetch(`${DODO_BASE_URL}/licenses/activate`, {
280
+ method: "POST",
281
+ headers: { "Content-Type": "application/json" },
282
+ body: JSON.stringify({
283
+ license_key: key,
284
+ name: machineName
285
+ })
286
+ });
287
+ if (!res.ok) {
288
+ const body = await res.json().catch(() => ({}));
289
+ const msg = body.message || body.error || `HTTP ${res.status}`;
290
+ p3.log.error(chalk.red(`Activation failed: ${msg}`));
291
+ return null;
292
+ }
293
+ const result = await res.json();
294
+ const tier = inferTierFromActivation(result);
295
+ const license = {
296
+ key,
297
+ tier,
298
+ instance_id: result.id || result.license_key_instance_id || "",
299
+ activated_at: (/* @__PURE__ */ new Date()).toISOString(),
300
+ valid: true
301
+ };
302
+ await fs.ensureDir(SUPERSAAS_DIR);
303
+ await fs.writeJson(LICENSE_PATH, license, { spaces: 2 });
304
+ return license;
305
+ } catch {
306
+ p3.log.error(
307
+ chalk.red("Could not reach license server. Check your connection.")
308
+ );
309
+ return null;
310
+ }
311
+ }
312
+ async function activate(keyArg, nonInteractive) {
313
+ const existing = await loadLocalLicense();
314
+ if (existing) {
315
+ const check = await validateKey(existing.key).catch(() => ({ valid: true }));
316
+ if (check.valid) {
317
+ p3.log.success(
318
+ chalk.dim(
319
+ `Licensed (${existing.tier}) - ${existing.key.slice(0, 12)}...`
320
+ )
321
+ );
322
+ return existing;
323
+ }
324
+ await fs.remove(LICENSE_PATH);
325
+ p3.log.warning(chalk.yellow("License expired or revoked. Please re-activate."));
326
+ }
327
+ if (!keyArg && nonInteractive) {
328
+ return null;
329
+ }
330
+ const key = keyArg || await p3.text({
331
+ message: "Enter your license key:",
332
+ placeholder: "Paste your license key from the purchase email",
333
+ validate: (v) => {
334
+ if (!v) return "License key is required";
335
+ if (v.length < 8) return "Invalid key format";
336
+ }
337
+ });
338
+ if (p3.isCancel(key)) return null;
339
+ p3.log.step("Activating license...");
340
+ const license = await activateOnline(key);
341
+ if (license) {
342
+ p3.log.success(chalk.green(`Activated! Tier: ${license.tier}`));
343
+ return license;
344
+ }
345
+ return null;
346
+ }
347
+ var require2 = createRequire(import.meta.url);
348
+ var { version } = require2("../package.json");
349
+ var VALID_DBS = ["neon", "supabase", "local"];
350
+ var VALID_FEATURES = ["blog", "admin"];
351
+ program.name("create-supersaas-app").description("Scaffold production-ready SaaS apps in seconds").version(version).argument("[name]", "Name of your app").option("--key <license-key>", "License key for activation").option("--defaults", "Skip prompts, use default settings (for agents)").option("--yes", "Alias for --defaults (non-interactive mode)").option("--db <provider>", "Database provider (neon|supabase|local)").option("--features <list>", "Comma-separated features (blog,admin)").action(async (name, options) => {
352
+ const nonInteractive = options.defaults || options.yes || !process.stdin.isTTY;
353
+ if (!nonInteractive) p3.intro(chalk.bold("supersaas-kit"));
354
+ let licenseResult = await activate(options.key, nonInteractive);
355
+ if (!licenseResult) {
356
+ if (!nonInteractive) p3.cancel("License activation failed.");
357
+ else console.error("License activation failed.");
358
+ process.exit(1);
359
+ }
360
+ let appName = name;
361
+ if (!appName && nonInteractive) {
362
+ console.error("Error: app name is required in non-interactive mode. Pass it as the first argument: create-supersaas-app <name>");
363
+ process.exit(1);
364
+ }
365
+ if (!appName) {
366
+ appName = await p3.text({
367
+ message: "What's your app called?",
368
+ placeholder: "my-saas",
369
+ validate: (v) => {
370
+ if (!v) return "App name is required";
371
+ if (!/^[a-z0-9-]+$/.test(v))
372
+ return "Use lowercase letters, numbers, and hyphens only";
373
+ }
374
+ });
375
+ if (p3.isCancel(appName)) {
376
+ p3.cancel("Cancelled.");
377
+ process.exit(0);
378
+ }
379
+ }
380
+ let dbChoice = options.db || (nonInteractive ? "neon" : null);
381
+ if (dbChoice && !VALID_DBS.includes(dbChoice)) {
382
+ const msg = `Invalid --db value "${dbChoice}". Valid options: ${VALID_DBS.join(", ")}`;
383
+ if (nonInteractive) {
384
+ console.error(`Error: ${msg}`);
385
+ process.exit(1);
386
+ }
387
+ p3.log.warn(chalk.yellow(msg));
388
+ dbChoice = null;
389
+ }
390
+ if (!dbChoice) {
391
+ dbChoice = await p3.select({
392
+ message: "Database provider?",
393
+ options: [
394
+ { value: "neon", label: "Neon (Postgres)", hint: "serverless, recommended" },
395
+ { value: "supabase", label: "Supabase (Postgres)" },
396
+ { value: "local", label: "Local Docker Postgres", hint: "docker compose up -d" }
397
+ ]
398
+ });
399
+ if (p3.isCancel(dbChoice)) {
400
+ p3.cancel("Cancelled.");
401
+ process.exit(0);
402
+ }
403
+ }
404
+ let features = options.features ? options.features.split(",").map((f) => f.trim()).filter(Boolean) : [];
405
+ if (features.length > 0) {
406
+ const invalid = features.filter((f) => !VALID_FEATURES.includes(f));
407
+ if (invalid.length > 0) {
408
+ const msg = `Unknown features: ${invalid.join(", ")}. Valid options: ${VALID_FEATURES.join(", ")}`;
409
+ if (nonInteractive) {
410
+ console.error(`Error: ${msg}`);
411
+ process.exit(1);
412
+ }
413
+ p3.log.warn(chalk.yellow(msg));
414
+ features = features.filter((f) => VALID_FEATURES.includes(f));
415
+ }
416
+ }
417
+ if (!nonInteractive && !options.features) {
418
+ features = await p3.multiselect({
419
+ message: "Include optional modules?",
420
+ options: [
421
+ { value: "blog", label: "Blog (MDX)", hint: "SEO boost" },
422
+ { value: "admin", label: "Admin Dashboard", hint: "Pro" }
423
+ ],
424
+ required: false
425
+ });
426
+ if (p3.isCancel(features)) {
427
+ p3.cancel("Cancelled.");
428
+ process.exit(0);
429
+ }
430
+ }
431
+ await createApp({
432
+ name: appName,
433
+ database: dbChoice,
434
+ features: features || [],
435
+ tier: licenseResult.tier,
436
+ licenseKey: licenseResult.key
437
+ });
438
+ if (!nonInteractive) {
439
+ p3.outro(
440
+ chalk.green("Done!") + ` Run ${chalk.cyan(`cd ${appName} && npm install && npm run dev`)} to start.`
441
+ );
442
+ } else {
443
+ console.log(`\u2714 Created ${appName}. Run: cd ${appName} && npm install && npm run dev`);
444
+ }
445
+ });
446
+ program.parse();
package/package.json CHANGED
@@ -1,6 +1,60 @@
1
1
  {
2
2
  "name": "@superbuilds/create-supersaas-app",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "2.0.0",
4
+ "description": "Scaffold production-ready SaaS apps in seconds — SuperSaaS Kit CLI",
5
+ "author": "superbuilds",
6
+ "license": "MIT",
7
+ "homepage": "https://supersaas-kit.superbuilds.fun",
8
+ "bugs": {
9
+ "url": "https://github.com/bixblues/supersaas-kit/issues"
10
+ },
11
+ "bin": {
12
+ "create-supersaas-app": "./dist/index.js"
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsup src/index.ts --format esm --dts --treeshake --define.__DEV_MODE__=false",
20
+ "build:dev": "tsup src/index.ts --format esm --dts --define.__DEV_MODE__=true",
21
+ "dev": "tsup src/index.ts --format esm --watch --define.__DEV_MODE__=true"
22
+ },
23
+ "dependencies": {
24
+ "@clack/prompts": "^0.9.1",
25
+ "chalk": "^5.4.1",
26
+ "commander": "^13.1.0",
27
+ "fs-extra": "^11.3.0",
28
+ "ora": "^8.2.0"
29
+ },
30
+ "devDependencies": {
31
+ "@types/fs-extra": "^11.0.4",
32
+ "@types/node": "^22.15.0",
33
+ "tsup": "^8.4.0",
34
+ "typescript": "^5.8.0"
35
+ },
36
+ "type": "module",
37
+ "engines": {
38
+ "node": ">=18.17.0"
39
+ },
40
+ "keywords": [
41
+ "supersaas-kit",
42
+ "superbuilds",
43
+ "saas",
44
+ "saas-boilerplate",
45
+ "nextjs",
46
+ "nextjs-starter",
47
+ "indie-hacker",
48
+ "create-app",
49
+ "starter",
50
+ "boilerplate"
51
+ ],
52
+ "publishConfig": {
53
+ "access": "public"
54
+ },
55
+ "repository": {
56
+ "type": "git",
57
+ "url": "https://github.com/bixblues/supersaas-kit",
58
+ "directory": "packages/create-supersaas-app"
59
+ }
60
+ }