spfn 0.2.0-beta.1 → 0.2.0-beta.2

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 (2) hide show
  1. package/dist/index.js +247 -37
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -1183,7 +1183,7 @@ import { existsSync as existsSync11, readFileSync as readFileSync3, writeFileSyn
1183
1183
  import { join as join11 } from "path";
1184
1184
  import { execa as execa4 } from "execa";
1185
1185
  import chokidar from "chokidar";
1186
- var devCommand = new Command4("dev").description("Start SPFN development server (detects and runs Next.js + Hono)").option("-p, --port <port>", "Server port", "8790").option("-h, --host <host>", "Server host", "localhost").option("--routes <path>", "Routes directory path").option("--server-only", "Run only Hono server (skip Next.js)").option("--watch", "Enable hot reload (watch mode)").action(async (options) => {
1186
+ var devCommand = new Command4("dev").description("Start SPFN development server (detects and runs Next.js + Hono)").option("-p, --port <port>", "Server port").option("-H, --host <host>", "Server host").option("--routes <path>", "Routes directory path").option("--server-only", "Run only Hono server (skip Next.js)").option("--watch", "Enable hot reload (watch mode)").action(async (options) => {
1187
1187
  process.setMaxListeners(20);
1188
1188
  if (!process.env.NODE_ENV) {
1189
1189
  process.env.NODE_ENV = "development";
@@ -1205,6 +1205,11 @@ var devCommand = new Command4("dev").description("Start SPFN development server
1205
1205
  const serverEntry = join11(tempDir, "server.mjs");
1206
1206
  const watcherEntry = join11(tempDir, "watcher.mjs");
1207
1207
  mkdirSync(tempDir, { recursive: true });
1208
+ const configParts = [];
1209
+ if (options.port) configParts.push(`port: ${options.port}`);
1210
+ if (options.host) configParts.push(`host: '${options.host}'`);
1211
+ if (options.routes) configParts.push(`routesPath: '${options.routes}'`);
1212
+ configParts.push("debug: true");
1208
1213
  writeFileSync6(serverEntry, `
1209
1214
  // Load environment variables FIRST (before any imports that depend on them)
1210
1215
  // Use centralized environment loader for standard dotenv priority
@@ -1214,9 +1219,7 @@ await import('@spfn/core/config');
1214
1219
  const { startServer } = await import('@spfn/core/server');
1215
1220
 
1216
1221
  await startServer({
1217
- port: ${options.port},
1218
- host: '${options.host}',
1219
- ${options.routes ? `routesPath: '${options.routes}',` : ""}debug: true
1222
+ ${configParts.join(",\n ")}
1220
1223
  });
1221
1224
  `);
1222
1225
  writeFileSync6(watcherEntry, `
@@ -1312,7 +1315,7 @@ catch (error)
1312
1315
  serverProcess2.kill("SIGTERM");
1313
1316
  await serverProcess2.catch(() => {
1314
1317
  });
1315
- await new Promise((resolve) => setTimeout(resolve, 500));
1318
+ await new Promise((resolve2) => setTimeout(resolve2, 500));
1316
1319
  } catch (error) {
1317
1320
  }
1318
1321
  }
@@ -1356,12 +1359,12 @@ catch (error)
1356
1359
  process.on("SIGTERM", cleanup2);
1357
1360
  startWatcher2();
1358
1361
  startServer2();
1359
- await new Promise((resolve) => {
1362
+ await new Promise((resolve2) => {
1360
1363
  const keepAlive = setInterval(() => {
1361
1364
  }, 1e6);
1362
1365
  process.once("beforeExit", () => {
1363
1366
  clearInterval(keepAlive);
1364
- resolve();
1367
+ resolve2();
1365
1368
  });
1366
1369
  });
1367
1370
  return;
@@ -1421,7 +1424,7 @@ catch (error)
1421
1424
  serverProcess.kill("SIGTERM");
1422
1425
  await serverProcess.catch(() => {
1423
1426
  });
1424
- await new Promise((resolve) => setTimeout(resolve, 500));
1427
+ await new Promise((resolve2) => setTimeout(resolve2, 500));
1425
1428
  } catch (error) {
1426
1429
  }
1427
1430
  }
@@ -1468,14 +1471,14 @@ catch (error)
1468
1471
  process.on("SIGTERM", cleanup);
1469
1472
  startWatcher();
1470
1473
  startServer();
1471
- await new Promise((resolve) => setTimeout(resolve, 2e3));
1474
+ await new Promise((resolve2) => setTimeout(resolve2, 2e3));
1472
1475
  startNext();
1473
- await new Promise((resolve) => {
1476
+ await new Promise((resolve2) => {
1474
1477
  const keepAlive = setInterval(() => {
1475
1478
  }, 1e6);
1476
1479
  process.once("beforeExit", () => {
1477
1480
  clearInterval(keepAlive);
1478
- resolve();
1481
+ resolve2();
1479
1482
  });
1480
1483
  });
1481
1484
  });
@@ -2024,7 +2027,7 @@ async function runDrizzleCommand(command) {
2024
2027
  }
2025
2028
  const args = command.split(" ");
2026
2029
  args.push(`--config=${configPath}`);
2027
- return new Promise((resolve, reject) => {
2030
+ return new Promise((resolve2, reject) => {
2028
2031
  const drizzleProcess = spawn("drizzle-kit", args, {
2029
2032
  stdio: "inherit",
2030
2033
  // Allow interactive input
@@ -2038,7 +2041,7 @@ async function runDrizzleCommand(command) {
2038
2041
  drizzleProcess.on("close", (code) => {
2039
2042
  cleanup();
2040
2043
  if (code === 0) {
2041
- resolve();
2044
+ resolve2();
2042
2045
  } else {
2043
2046
  reject(new Error(`drizzle-kit ${command} exited with code ${code}`));
2044
2047
  }
@@ -2130,15 +2133,15 @@ function parseDatabaseUrl(dbUrl) {
2130
2133
  }
2131
2134
  }
2132
2135
  async function isPortAvailable(port) {
2133
- return new Promise((resolve) => {
2136
+ return new Promise((resolve2) => {
2134
2137
  const server = net.createServer();
2135
2138
  server.once("error", () => {
2136
2139
  server.close();
2137
- resolve(false);
2140
+ resolve2(false);
2138
2141
  });
2139
2142
  server.once("listening", () => {
2140
2143
  server.close();
2141
- resolve(true);
2144
+ resolve2(true);
2142
2145
  });
2143
2146
  server.listen(port, "127.0.0.1");
2144
2147
  });
@@ -2392,7 +2395,7 @@ async function dbBackup(options) {
2392
2395
  pgDump.stderr?.on("data", (data) => {
2393
2396
  errorOutput += data.toString();
2394
2397
  });
2395
- await new Promise((resolve, reject) => {
2398
+ await new Promise((resolve2, reject) => {
2396
2399
  pgDump.on("close", async (code) => {
2397
2400
  if (code === 0) {
2398
2401
  try {
@@ -2429,7 +2432,7 @@ async function dbBackup(options) {
2429
2432
  tags: tags.length > 0 ? tags : void 0
2430
2433
  };
2431
2434
  await saveBackupMetadata(metadata, filename);
2432
- resolve();
2435
+ resolve2();
2433
2436
  } catch (error) {
2434
2437
  reject(error);
2435
2438
  }
@@ -2761,12 +2764,12 @@ async function dbRestore(backupFile, options = {}) {
2761
2764
  restoreProcess.stderr?.on("data", (data) => {
2762
2765
  errorOutput += data.toString();
2763
2766
  });
2764
- await new Promise((resolve, reject) => {
2767
+ await new Promise((resolve2, reject) => {
2765
2768
  restoreProcess.on("close", (code) => {
2766
2769
  if (code === 0) {
2767
2770
  spinner.succeed("Restore completed");
2768
2771
  console.log(chalk20.green("\n\u2705 Database restored successfully"));
2769
- resolve();
2772
+ resolve2();
2770
2773
  } else {
2771
2774
  spinner.fail("Restore failed");
2772
2775
  reject(new Error(errorOutput || "Restore failed"));
@@ -4285,6 +4288,20 @@ generateCommand.command("fn").description("Generate a new SPFN function module")
4285
4288
  // src/commands/env.ts
4286
4289
  import { Command as Command12 } from "commander";
4287
4290
  import chalk26 from "chalk";
4291
+ import { existsSync as existsSync23, readFileSync as readFileSync8, writeFileSync as writeFileSync18 } from "fs";
4292
+ import { resolve } from "path";
4293
+ import { parse } from "dotenv";
4294
+ var ENV_FILES = {
4295
+ nextjs: [".env", ".env.local"],
4296
+ server: [".env.server", ".env.server.local"]
4297
+ };
4298
+ function getTargetFile(schema) {
4299
+ const isNextjs = schema.nextjs ?? schema.key?.startsWith("NEXT_PUBLIC_");
4300
+ if (isNextjs) {
4301
+ return schema.sensitive ? ".env.local" : ".env";
4302
+ }
4303
+ return schema.sensitive ? ".env.server.local" : ".env.server";
4304
+ }
4288
4305
  async function loadEnvSchema(packageName) {
4289
4306
  try {
4290
4307
  const schemaPath = `${packageName}/config`;
@@ -4329,26 +4346,34 @@ async function listEnvVars(options) {
4329
4346
  const packageName = options.package || "@spfn/core";
4330
4347
  try {
4331
4348
  const envSchema = await loadEnvSchema(packageName);
4332
- console.log(chalk26.blue.bold(`
4333
- \u{1F4CB} Environment Variables (${packageName})
4334
- `));
4335
4349
  const allVars = Object.entries(envSchema);
4336
- for (const [key, schema] of allVars) {
4337
- const typeStr = formatType(schema.type);
4338
- const requiredStr = schema.required || schema.default !== void 0 ? chalk26.red("[required]") : chalk26.dim("[optional]");
4339
- const sensitiveStr = schema.sensitive ? chalk26.yellow(" [sensitive]") : "";
4340
- console.log(`${chalk26.bold.cyan(key)} ${chalk26.dim("(")}${typeStr}${chalk26.dim(")")} ${requiredStr}${sensitiveStr}`);
4341
- console.log(` ${chalk26.dim(schema.description)}`);
4342
- if (schema.default !== void 0) {
4343
- console.log(` ${chalk26.dim("Default:")} ${formatDefault(schema.default, schema.type)}`);
4350
+ if (options.group) {
4351
+ const grouped = allVars.reduce((acc, [key, schema]) => {
4352
+ const target = getTargetFile(schema);
4353
+ if (!acc[target]) acc[target] = [];
4354
+ acc[target].push([key, schema]);
4355
+ return acc;
4356
+ }, {});
4357
+ console.log(chalk26.blue.bold(`
4358
+ \u{1F4CB} Environment Variables by File (${packageName})
4359
+ `));
4360
+ for (const [file, vars] of Object.entries(grouped)) {
4361
+ console.log(chalk26.bold.magenta(`
4362
+ ${file}`));
4363
+ console.log(chalk26.dim("\u2500".repeat(50)));
4364
+ for (const [key, schema] of vars) {
4365
+ printEnvVar(key, schema);
4366
+ }
4344
4367
  }
4345
- if (schema.examples && schema.examples.length > 0) {
4346
- const exampleStr = schema.examples.map((ex) => formatDefault(ex, schema.type)).join(", ");
4347
- console.log(` ${chalk26.dim("Examples:")} ${exampleStr}`);
4368
+ } else {
4369
+ console.log(chalk26.blue.bold(`
4370
+ \u{1F4CB} Environment Variables (${packageName})
4371
+ `));
4372
+ for (const [key, schema] of allVars) {
4373
+ printEnvVar(key, schema, true);
4348
4374
  }
4349
- console.log();
4350
4375
  }
4351
- console.log(chalk26.dim("\n\u{1F4A1} Tip: Use these variable names in your .env files\n"));
4376
+ console.log(chalk26.dim("\n\u{1F4A1} Tip: Use `spfn env init` to generate .env template files\n"));
4352
4377
  } catch (error) {
4353
4378
  console.error(chalk26.red(`
4354
4379
  \u274C ${error instanceof Error ? error.message : "Unknown error"}
@@ -4356,6 +4381,22 @@ async function listEnvVars(options) {
4356
4381
  process.exit(1);
4357
4382
  }
4358
4383
  }
4384
+ function printEnvVar(key, schema, showFile = false) {
4385
+ const typeStr = formatType(schema.type);
4386
+ const requiredStr = schema.required || schema.default !== void 0 ? chalk26.red("[required]") : chalk26.dim("[optional]");
4387
+ const sensitiveStr = schema.sensitive ? chalk26.yellow(" [sensitive]") : "";
4388
+ const fileStr = showFile ? chalk26.dim(` \u2192 ${getTargetFile(schema)}`) : "";
4389
+ console.log(`${chalk26.bold.cyan(key)} ${chalk26.dim("(")}${typeStr}${chalk26.dim(")")} ${requiredStr}${sensitiveStr}${fileStr}`);
4390
+ console.log(` ${chalk26.dim(schema.description)}`);
4391
+ if (schema.default !== void 0) {
4392
+ console.log(` ${chalk26.dim("Default:")} ${formatDefault(schema.default, schema.type)}`);
4393
+ }
4394
+ if (schema.examples && schema.examples.length > 0) {
4395
+ const exampleStr = schema.examples.map((ex) => formatDefault(ex, schema.type)).join(", ");
4396
+ console.log(` ${chalk26.dim("Examples:")} ${exampleStr}`);
4397
+ }
4398
+ console.log();
4399
+ }
4359
4400
  async function showEnvStats(options) {
4360
4401
  const packageName = options.package || "@spfn/core";
4361
4402
  try {
@@ -4367,14 +4408,32 @@ async function showEnvStats(options) {
4367
4408
  const required = allVars.filter(([_, schema]) => schema.required || schema.default !== void 0);
4368
4409
  const optional = allVars.filter(([_, schema]) => !schema.required && schema.default === void 0);
4369
4410
  const sensitive = allVars.filter(([_, schema]) => schema.sensitive);
4411
+ const nextjsVars = allVars.filter(
4412
+ ([_, schema]) => schema.nextjs ?? schema.key?.startsWith("NEXT_PUBLIC_")
4413
+ );
4414
+ const serverOnlyVars = allVars.filter(
4415
+ ([_, schema]) => !(schema.nextjs ?? schema.key?.startsWith("NEXT_PUBLIC_"))
4416
+ );
4370
4417
  const typeCount = allVars.reduce((acc, [_, schema]) => {
4371
4418
  acc[schema.type] = (acc[schema.type] || 0) + 1;
4372
4419
  return acc;
4373
4420
  }, {});
4421
+ const fileCount = allVars.reduce((acc, [_, schema]) => {
4422
+ const file = getTargetFile(schema);
4423
+ acc[file] = (acc[file] || 0) + 1;
4424
+ return acc;
4425
+ }, {});
4374
4426
  console.log(`${chalk26.bold("Total variables:")} ${chalk26.cyan(allVars.length)}`);
4375
4427
  console.log(`${chalk26.bold("Required:")} ${chalk26.red(required.length)}`);
4376
4428
  console.log(`${chalk26.bold("Optional:")} ${chalk26.dim(optional.length)}`);
4377
4429
  console.log(`${chalk26.bold("Sensitive:")} ${chalk26.yellow(sensitive.length)}`);
4430
+ console.log(chalk26.bold("\nBy Target:"));
4431
+ console.log(` ${chalk26.blue("Next.js accessible:")} ${chalk26.cyan(nextjsVars.length)}`);
4432
+ console.log(` ${chalk26.magenta("SPFN server only:")} ${chalk26.cyan(serverOnlyVars.length)}`);
4433
+ console.log(chalk26.bold("\nBy File:"));
4434
+ for (const [file, count] of Object.entries(fileCount)) {
4435
+ console.log(` ${chalk26.dim(file)}: ${chalk26.cyan(count)}`);
4436
+ }
4378
4437
  console.log(chalk26.bold("\nBy Type:"));
4379
4438
  for (const [type, count] of Object.entries(typeCount)) {
4380
4439
  console.log(` ${formatType(type)}: ${chalk26.cyan(count)}`);
@@ -4427,9 +4486,160 @@ async function searchEnvVars(query, options) {
4427
4486
  }
4428
4487
  }
4429
4488
  var envCommand = new Command12("env").description("Manage environment variables");
4430
- envCommand.command("list").description("List all environment variables from schema").option("-p, --package <package>", "Package name to read env schema from", "@spfn/core").action(listEnvVars);
4489
+ envCommand.command("list").description("List all environment variables from schema").option("-p, --package <package>", "Package name to read env schema from", "@spfn/core").option("-g, --group", "Group variables by target file").action(listEnvVars);
4431
4490
  envCommand.command("stats").description("Show environment variable statistics").option("-p, --package <package>", "Package name to read env schema from", "@spfn/core").action(showEnvStats);
4432
4491
  envCommand.command("search").description("Search environment variables").argument("<query>", "Search query (matches key or description)").option("-p, --package <package>", "Package name to read env schema from", "@spfn/core").action(searchEnvVars);
4492
+ async function initEnvFiles(options) {
4493
+ const packageName = options.package || "@spfn/core";
4494
+ const cwd = process.cwd();
4495
+ try {
4496
+ const envSchema = await loadEnvSchema(packageName);
4497
+ const allVars = Object.entries(envSchema);
4498
+ const grouped = allVars.reduce((acc, [key, schema]) => {
4499
+ const target = getTargetFile(schema);
4500
+ const exampleFile = target + ".example";
4501
+ if (!acc[exampleFile]) acc[exampleFile] = [];
4502
+ acc[exampleFile].push([key, schema]);
4503
+ return acc;
4504
+ }, {});
4505
+ console.log(chalk26.blue.bold(`
4506
+ \u{1F680} Generating .env template files
4507
+ `));
4508
+ for (const [file, vars] of Object.entries(grouped)) {
4509
+ const filePath = resolve(cwd, file);
4510
+ if (existsSync23(filePath) && !options.force) {
4511
+ console.log(chalk26.yellow(` \u23ED\uFE0F ${file} already exists (use --force to overwrite)`));
4512
+ continue;
4513
+ }
4514
+ const content = generateEnvFileContent(vars);
4515
+ writeFileSync18(filePath, content, "utf-8");
4516
+ console.log(chalk26.green(` \u2705 ${file} (${vars.length} variables)`));
4517
+ }
4518
+ console.log(chalk26.dim("\n\u{1F4A1} Copy .example files to create your actual .env files:"));
4519
+ console.log(chalk26.dim(" cp .env.example .env"));
4520
+ console.log(chalk26.dim(" cp .env.local.example .env.local"));
4521
+ console.log(chalk26.dim(" cp .env.server.example .env.server"));
4522
+ console.log(chalk26.dim(" cp .env.server.local.example .env.server.local\n"));
4523
+ } catch (error) {
4524
+ console.error(chalk26.red(`
4525
+ \u274C ${error instanceof Error ? error.message : "Unknown error"}
4526
+ `));
4527
+ process.exit(1);
4528
+ }
4529
+ }
4530
+ function generateEnvFileContent(vars) {
4531
+ const lines = [
4532
+ "# Auto-generated by spfn env init",
4533
+ "# Copy this file and fill in the values",
4534
+ ""
4535
+ ];
4536
+ for (const [key, schema] of vars) {
4537
+ lines.push(`# ${schema.description}`);
4538
+ if (schema.required) {
4539
+ lines.push(`# [required]`);
4540
+ }
4541
+ if (schema.sensitive) {
4542
+ lines.push(`# [sensitive] - Do not commit this value!`);
4543
+ }
4544
+ let value = "";
4545
+ if (schema.default !== void 0) {
4546
+ value = String(schema.default);
4547
+ } else if (schema.examples && schema.examples.length > 0) {
4548
+ value = String(schema.examples[0]);
4549
+ }
4550
+ lines.push(`${key}=${value}`);
4551
+ lines.push("");
4552
+ }
4553
+ return lines.join("\n");
4554
+ }
4555
+ async function checkEnvFiles(options) {
4556
+ const packageName = options.package || "@spfn/core";
4557
+ const cwd = process.cwd();
4558
+ try {
4559
+ const envSchema = await loadEnvSchema(packageName);
4560
+ const allVars = Object.entries(envSchema);
4561
+ console.log(chalk26.blue.bold(`
4562
+ \u{1F50D} Checking .env files against schema
4563
+ `));
4564
+ const allFiles = [...ENV_FILES.nextjs, ...ENV_FILES.server];
4565
+ const loadedEnv = {};
4566
+ const issues = [];
4567
+ const warnings = [];
4568
+ for (const file of allFiles) {
4569
+ const filePath = resolve(cwd, file);
4570
+ if (!existsSync23(filePath)) {
4571
+ continue;
4572
+ }
4573
+ const content = readFileSync8(filePath, "utf-8");
4574
+ const parsed = parse(content);
4575
+ for (const [key, value] of Object.entries(parsed)) {
4576
+ loadedEnv[key] = { value: value || "", file };
4577
+ }
4578
+ console.log(chalk26.dim(` \u{1F4C4} ${file} loaded`));
4579
+ }
4580
+ console.log("");
4581
+ for (const [key, schema] of allVars) {
4582
+ const expectedFile = getTargetFile(schema);
4583
+ const found = loadedEnv[key];
4584
+ if (!found) {
4585
+ if (schema.required && schema.default === void 0) {
4586
+ issues.push(`${chalk26.red("\u2717")} ${chalk26.cyan(key)} is required but not found in any .env file`);
4587
+ }
4588
+ continue;
4589
+ }
4590
+ const isNextjsFile = ENV_FILES.nextjs.includes(found.file);
4591
+ const isServerFile = ENV_FILES.server.includes(found.file);
4592
+ const shouldBeNextjs = schema.nextjs ?? key.startsWith("NEXT_PUBLIC_");
4593
+ if (!shouldBeNextjs && isNextjsFile && !isServerFile) {
4594
+ if (schema.sensitive) {
4595
+ issues.push(
4596
+ `${chalk26.red("\u2717")} ${chalk26.cyan(key)} is sensitive and should be in ${chalk26.magenta(expectedFile)}, but found in ${chalk26.yellow(found.file)} (security risk!)`
4597
+ );
4598
+ } else {
4599
+ warnings.push(
4600
+ `${chalk26.yellow("\u26A0")} ${chalk26.cyan(key)} should be in ${chalk26.magenta(expectedFile)}, but found in ${chalk26.dim(found.file)}`
4601
+ );
4602
+ }
4603
+ }
4604
+ }
4605
+ for (const [key, { file }] of Object.entries(loadedEnv)) {
4606
+ const inSchema = allVars.some(([k]) => k === key);
4607
+ if (!inSchema) {
4608
+ warnings.push(`${chalk26.yellow("\u26A0")} ${chalk26.cyan(key)} in ${chalk26.dim(file)} is not in schema`);
4609
+ }
4610
+ }
4611
+ if (issues.length > 0) {
4612
+ console.log(chalk26.red.bold("Issues:"));
4613
+ for (const issue of issues) {
4614
+ console.log(` ${issue}`);
4615
+ }
4616
+ console.log("");
4617
+ }
4618
+ if (warnings.length > 0) {
4619
+ console.log(chalk26.yellow.bold("Warnings:"));
4620
+ for (const warning of warnings) {
4621
+ console.log(` ${warning}`);
4622
+ }
4623
+ console.log("");
4624
+ }
4625
+ if (issues.length === 0 && warnings.length === 0) {
4626
+ console.log(chalk26.green("\u2705 All environment variables are correctly configured!\n"));
4627
+ } else {
4628
+ console.log(chalk26.dim(`Found ${issues.length} issue(s) and ${warnings.length} warning(s)
4629
+ `));
4630
+ if (issues.length > 0) {
4631
+ process.exit(1);
4632
+ }
4633
+ }
4634
+ } catch (error) {
4635
+ console.error(chalk26.red(`
4636
+ \u274C ${error instanceof Error ? error.message : "Unknown error"}
4637
+ `));
4638
+ process.exit(1);
4639
+ }
4640
+ }
4641
+ envCommand.command("init").description("Generate .env template files from schema").option("-p, --package <package>", "Package name to read env schema from", "@spfn/core").option("-f, --force", "Overwrite existing files").action(initEnvFiles);
4642
+ envCommand.command("check").description("Check .env files against schema").option("-p, --package <package>", "Package name to read env schema from", "@spfn/core").action(checkEnvFiles);
4433
4643
 
4434
4644
  // src/index.ts
4435
4645
  var program = new Command13();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spfn",
3
- "version": "0.2.0-beta.1",
3
+ "version": "0.2.0-beta.2",
4
4
  "description": "Superfunction CLI - Add SPFN to your Next.js project",
5
5
  "type": "module",
6
6
  "bin": {
@@ -58,6 +58,7 @@
58
58
  "chalk": "^5.6.2",
59
59
  "chokidar": "^4.0.3",
60
60
  "commander": "^11.1.0",
61
+ "dotenv": "^17.2.3",
61
62
  "drizzle-orm": "^0.44.7",
62
63
  "execa": "^8.0.1",
63
64
  "fs-extra": "^11.2.0",
@@ -66,7 +67,7 @@
66
67
  "postgres": "^3.4.0",
67
68
  "prompts": "^2.4.2",
68
69
  "tsup": "^8.5.0",
69
- "@spfn/core": "0.2.0-beta.1"
70
+ "@spfn/core": "0.2.0-beta.4"
70
71
  },
71
72
  "devDependencies": {
72
73
  "@types/fs-extra": "^11.0.4",
@@ -74,7 +75,6 @@
74
75
  "@types/pg": "^8.10.9",
75
76
  "@types/prompts": "^2.4.9",
76
77
  "concurrently": "^9.2.1",
77
- "dotenv": "^17.2.3",
78
78
  "drizzle-kit": "^0.31.6",
79
79
  "tsx": "^4.20.6",
80
80
  "typescript": "^5.3.3"