spfn 0.2.0-beta.21 → 0.2.0-beta.23

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 +659 -344
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -755,7 +755,7 @@ var init_deployment_config = __esm({
755
755
 
756
756
  // src/utils/version.ts
757
757
  function getCliVersion() {
758
- return "0.2.0-beta.21";
758
+ return "0.2.0-beta.23";
759
759
  }
760
760
  function getTagFromVersion(version) {
761
761
  const match = version.match(/-([a-z]+)\./i);
@@ -1042,7 +1042,7 @@ __export(function_migrations_exports, {
1042
1042
  discoverFunctionMigrations: () => discoverFunctionMigrations,
1043
1043
  executeFunctionMigrations: () => executeFunctionMigrations
1044
1044
  });
1045
- import chalk11 from "chalk";
1045
+ import chalk12 from "chalk";
1046
1046
  import { join as join15 } from "path";
1047
1047
  import { env as env2 } from "@spfn/core/config";
1048
1048
  import { loadEnv as loadEnv2 } from "@spfn/core/server";
@@ -1073,7 +1073,7 @@ function discoverFunctionMigrations(cwd = process.cwd()) {
1073
1073
  const migrationsDir = join15(packagePath, spfnConfig.migrations.dir);
1074
1074
  if (!existsSync16(migrationsDir)) {
1075
1075
  console.warn(
1076
- chalk11.yellow(`\u26A0\uFE0F Package @spfn/${pkg} specifies migrations but directory not found: ${migrationsDir}`)
1076
+ chalk12.yellow(`\u26A0\uFE0F Package @spfn/${pkg} specifies migrations but directory not found: ${migrationsDir}`)
1077
1077
  );
1078
1078
  continue;
1079
1079
  }
@@ -1083,7 +1083,7 @@ function discoverFunctionMigrations(cwd = process.cwd()) {
1083
1083
  packagePath
1084
1084
  });
1085
1085
  } catch (error) {
1086
- console.warn(chalk11.yellow(`\u26A0\uFE0F Failed to parse package.json for @spfn/${pkg}`));
1086
+ console.warn(chalk12.yellow(`\u26A0\uFE0F Failed to parse package.json for @spfn/${pkg}`));
1087
1087
  }
1088
1088
  }
1089
1089
  return functions;
@@ -1101,13 +1101,13 @@ async function executeFunctionMigrations(functionMigrations) {
1101
1101
  const db = drizzle(connection);
1102
1102
  try {
1103
1103
  for (const func of functionMigrations) {
1104
- console.log(chalk11.blue(`
1104
+ console.log(chalk12.blue(`
1105
1105
  \u{1F4E6} Running ${func.packageName} migrations...`));
1106
1106
  await migrate(db, {
1107
1107
  migrationsFolder: func.migrationsDir,
1108
1108
  migrationsTable: "__spfn_fn_migrations"
1109
1109
  });
1110
- console.log(chalk11.green(` \u2713 ${func.packageName} migrations applied`));
1110
+ console.log(chalk12.green(` \u2713 ${func.packageName} migrations applied`));
1111
1111
  executedCount++;
1112
1112
  }
1113
1113
  } finally {
@@ -2113,6 +2113,7 @@ import chalk10 from "chalk";
2113
2113
  // src/commands/db/utils/drizzle.ts
2114
2114
  import { existsSync as existsSync15, writeFileSync as writeFileSync9, unlinkSync as unlinkSync2 } from "fs";
2115
2115
  import { spawn } from "child_process";
2116
+ import { pathToFileURL } from "url";
2116
2117
  import chalk9 from "chalk";
2117
2118
  import ora6 from "ora";
2118
2119
  import { env } from "@spfn/core/config";
@@ -2188,6 +2189,50 @@ async function runWithSpinner(spinnerText, command, successMessage, failMessage)
2188
2189
  process.exit(1);
2189
2190
  }
2190
2191
  }
2192
+ var tsxRegistered = false;
2193
+ async function ensureTsxLoader() {
2194
+ if (tsxRegistered) return;
2195
+ try {
2196
+ const tsx = await import("tsx/esm/api");
2197
+ tsx.register();
2198
+ tsxRegistered = true;
2199
+ } catch {
2200
+ }
2201
+ }
2202
+ async function loadSchemaImports(schemaFiles) {
2203
+ const hasTsFiles = schemaFiles.some((f) => f.endsWith(".ts"));
2204
+ if (hasTsFiles) {
2205
+ await ensureTsxLoader();
2206
+ }
2207
+ const imports = {};
2208
+ for (const file of schemaFiles) {
2209
+ const moduleUrl = pathToFileURL(file).href;
2210
+ const mod = await import(moduleUrl);
2211
+ for (const [key, value] of Object.entries(mod)) {
2212
+ if (key !== "default") {
2213
+ imports[key] = value;
2214
+ }
2215
+ }
2216
+ }
2217
+ return imports;
2218
+ }
2219
+ async function createPushConnection() {
2220
+ loadEnv();
2221
+ if (!env.DATABASE_URL) {
2222
+ throw new Error("DATABASE_URL is required");
2223
+ }
2224
+ const pg = await import("pg");
2225
+ const { drizzle } = await import("drizzle-orm/node-postgres");
2226
+ const pool = new pg.default.Pool({
2227
+ connectionString: env.DATABASE_URL,
2228
+ max: 1
2229
+ });
2230
+ const db = drizzle(pool);
2231
+ return {
2232
+ db,
2233
+ close: () => pool.end()
2234
+ };
2235
+ }
2191
2236
 
2192
2237
  // src/commands/db/generate.ts
2193
2238
  async function dbGenerate() {
@@ -2202,35 +2247,203 @@ async function dbGenerate() {
2202
2247
  }
2203
2248
 
2204
2249
  // src/commands/db/push.ts
2205
- import chalk12 from "chalk";
2250
+ import chalk13 from "chalk";
2251
+ import prompts3 from "prompts";
2206
2252
  import "@spfn/core/config";
2207
- async function dbPush() {
2208
- await runWithSpinner(
2209
- "Pushing schema changes to database...",
2210
- "push",
2211
- "Schema pushed successfully",
2212
- "Failed to push schema"
2213
- );
2253
+ import { loadEnv as loadEnv3 } from "@spfn/core/server";
2254
+ import { sql } from "drizzle-orm";
2255
+
2256
+ // src/commands/db/utils/sql-classifier.ts
2257
+ var DESTRUCTIVE_PATTERNS = [
2258
+ { pattern: /^\s*DROP\s+TABLE/i, reason: "Drops entire table" },
2259
+ { pattern: /^\s*DROP\s+INDEX/i, reason: "Drops index" },
2260
+ { pattern: /^\s*DROP\s+SCHEMA/i, reason: "Drops schema" },
2261
+ { pattern: /^\s*DROP\s+TYPE/i, reason: "Drops custom type" },
2262
+ { pattern: /ALTER\s+TABLE\s+.*\bDROP\s+COLUMN\b/i, reason: "Drops column" },
2263
+ { pattern: /ALTER\s+TABLE\s+.*\bDROP\s+CONSTRAINT\b/i, reason: "Drops constraint" },
2264
+ { pattern: /ALTER\s+TABLE\s+.*ALTER\s+COLUMN\s+.*\bTYPE\b/i, reason: "Changes column type (potential data loss)" },
2265
+ { pattern: /ALTER\s+TYPE\s+.*\bRENAME\s+VALUE\b/i, reason: "Renames enum value" },
2266
+ { pattern: /^\s*TRUNCATE\b/i, reason: "Truncates table data" },
2267
+ { pattern: /^\s*DELETE\s+FROM\b/i, reason: "Deletes table data" }
2268
+ ];
2269
+ var WARNING_PATTERNS = [
2270
+ { pattern: /ALTER\s+TABLE\s+.*ALTER\s+COLUMN\s+.*\bSET\s+NOT\s+NULL\b/i, reason: "Adds NOT NULL (fails if NULLs exist)" },
2271
+ { pattern: /ALTER\s+TABLE\s+.*\bRENAME\s+COLUMN\b/i, reason: "Renames column" }
2272
+ ];
2273
+ function classifyStatement(sql2) {
2274
+ for (const { pattern, reason } of DESTRUCTIVE_PATTERNS) {
2275
+ if (pattern.test(sql2)) {
2276
+ return { sql: sql2, category: "destructive", reason };
2277
+ }
2278
+ }
2279
+ for (const { pattern, reason } of WARNING_PATTERNS) {
2280
+ if (pattern.test(sql2)) {
2281
+ return { sql: sql2, category: "warning", reason };
2282
+ }
2283
+ }
2284
+ return { sql: sql2, category: "safe", reason: "" };
2285
+ }
2286
+ function classifyStatements(statements) {
2287
+ const result = { safe: [], destructive: [], warning: [] };
2288
+ for (const sql2 of statements) {
2289
+ const classified = classifyStatement(sql2);
2290
+ result[classified.category].push(classified);
2291
+ }
2292
+ return result;
2293
+ }
2294
+
2295
+ // src/commands/db/utils/push-display.ts
2296
+ import chalk11 from "chalk";
2297
+ function formatSql(sql2) {
2298
+ return sql2.replace(/\s+/g, " ").trim();
2299
+ }
2300
+ function printStatements(statements, color) {
2301
+ for (const stmt of statements) {
2302
+ console.log(color(` ${formatSql(stmt.sql)}`));
2303
+ if (stmt.reason) {
2304
+ console.log(chalk11.dim(` \u2192 ${stmt.reason}`));
2305
+ }
2306
+ }
2307
+ }
2308
+ function displayClassifiedStatements(result) {
2309
+ if (result.safe.length > 0) {
2310
+ console.log(chalk11.green(`
2311
+ \u2705 Safe changes (${result.safe.length}):`));
2312
+ printStatements(result.safe, chalk11.green);
2313
+ }
2314
+ if (result.warning.length > 0) {
2315
+ console.log(chalk11.yellow(`
2316
+ \u26A0\uFE0F Warnings (${result.warning.length}):`));
2317
+ printStatements(result.warning, chalk11.yellow);
2318
+ }
2319
+ if (result.destructive.length > 0) {
2320
+ console.log(chalk11.red(`
2321
+ \u274C Destructive changes (${result.destructive.length}):`));
2322
+ printStatements(result.destructive, chalk11.red);
2323
+ }
2324
+ }
2325
+ function displayDryRunSummary(result) {
2326
+ const total = result.safe.length + result.warning.length + result.destructive.length;
2327
+ console.log(chalk11.cyan(`
2328
+ \u{1F50D} Dry-run: ${total} statement(s) detected
2329
+ `));
2330
+ displayClassifiedStatements(result);
2331
+ console.log("");
2332
+ }
2333
+ function displayApplySummary(applied, skipped) {
2334
+ if (applied > 0) {
2335
+ console.log(chalk11.green(`
2336
+ \u2705 Applied ${applied} statement(s)`));
2337
+ }
2338
+ if (skipped > 0) {
2339
+ console.log(chalk11.yellow(`\u23ED\uFE0F Skipped ${skipped} destructive statement(s)`));
2340
+ }
2341
+ console.log("");
2342
+ }
2343
+
2344
+ // src/commands/db/push.ts
2345
+ async function dbPush(options = {}) {
2346
+ validateDatabasePrerequisites();
2347
+ loadEnv3();
2348
+ const { getDrizzleConfig } = await import("@spfn/core/db");
2349
+ const config = getDrizzleConfig({
2350
+ cwd: process.cwd(),
2351
+ expandGlobs: true,
2352
+ autoDetectSchemas: true,
2353
+ disablePackageDiscovery: true
2354
+ });
2355
+ const schemaFiles = Array.isArray(config.schema) ? config.schema : [config.schema];
2356
+ if (schemaFiles.length === 0) {
2357
+ console.log(chalk13.yellow("No schema files found."));
2358
+ return;
2359
+ }
2360
+ console.log(chalk13.dim(`Found ${schemaFiles.length} schema file(s)
2361
+ `));
2362
+ const imports = await loadSchemaImports(schemaFiles);
2363
+ const { db, close } = await createPushConnection();
2364
+ try {
2365
+ const { pushSchema } = await import("drizzle-kit/api");
2366
+ const { statementsToExecute, apply } = await pushSchema(
2367
+ imports,
2368
+ db,
2369
+ config.schemaFilter ?? ["public"]
2370
+ );
2371
+ if (statementsToExecute.length === 0) {
2372
+ console.log(chalk13.green("\u2705 No changes detected \u2014 database is up to date\n"));
2373
+ await applyFunctionMigrations();
2374
+ return;
2375
+ }
2376
+ const result = classifyStatements(statementsToExecute);
2377
+ if (options.dryRun) {
2378
+ displayDryRunSummary(result);
2379
+ return;
2380
+ }
2381
+ displayClassifiedStatements(result);
2382
+ if (options.force) {
2383
+ console.log(chalk13.dim("\n--force: applying all changes..."));
2384
+ await apply();
2385
+ displayApplySummary(statementsToExecute.length, 0);
2386
+ } else if (result.destructive.length === 0) {
2387
+ await apply();
2388
+ displayApplySummary(statementsToExecute.length, 0);
2389
+ } else {
2390
+ const safeCount = result.safe.length + result.warning.length;
2391
+ if (safeCount > 0) {
2392
+ for (const stmt of [...result.safe, ...result.warning]) {
2393
+ await db.execute(sql.raw(stmt.sql));
2394
+ }
2395
+ console.log(chalk13.green(`
2396
+ \u2705 Applied ${safeCount} safe statement(s)`));
2397
+ }
2398
+ console.log(chalk13.red(`
2399
+ \u274C ${result.destructive.length} destructive change(s) require confirmation:`));
2400
+ for (const stmt of result.destructive) {
2401
+ console.log(chalk13.red(` ${stmt.sql.replace(/\s+/g, " ").trim()}`));
2402
+ console.log(chalk13.dim(` \u2192 ${stmt.reason}`));
2403
+ }
2404
+ const { confirm } = await prompts3({
2405
+ type: "confirm",
2406
+ name: "confirm",
2407
+ message: "Apply destructive changes?",
2408
+ initial: false
2409
+ });
2410
+ if (confirm) {
2411
+ for (const stmt of result.destructive) {
2412
+ await db.execute(sql.raw(stmt.sql));
2413
+ }
2414
+ displayApplySummary(statementsToExecute.length, 0);
2415
+ } else {
2416
+ displayApplySummary(safeCount, result.destructive.length);
2417
+ console.log(chalk13.dim("Tip: Use --force to apply all changes without prompting.\n"));
2418
+ }
2419
+ }
2420
+ await applyFunctionMigrations();
2421
+ } finally {
2422
+ await close();
2423
+ }
2424
+ }
2425
+ async function applyFunctionMigrations() {
2214
2426
  const { discoverFunctionMigrations: discoverFunctionMigrations2, executeFunctionMigrations: executeFunctionMigrations2 } = await Promise.resolve().then(() => (init_function_migrations(), function_migrations_exports));
2215
2427
  const functions = discoverFunctionMigrations2(process.cwd());
2216
- if (functions.length > 0) {
2217
- console.log(chalk12.blue("\n\u{1F4E6} Applying function package migrations:"));
2218
- functions.forEach((func) => {
2219
- console.log(chalk12.dim(` - ${func.packageName}`));
2220
- });
2221
- try {
2222
- await executeFunctionMigrations2(functions);
2223
- console.log(chalk12.green("\n\u2705 All function migrations applied\n"));
2224
- } catch (error) {
2225
- console.error(chalk12.red("\n\u274C Failed to apply function migrations"));
2226
- console.error(chalk12.red(error instanceof Error ? error.message : "Unknown error"));
2227
- process.exit(1);
2228
- }
2428
+ if (functions.length === 0) {
2429
+ return;
2430
+ }
2431
+ console.log(chalk13.blue("\n\u{1F4E6} Applying function package migrations:"));
2432
+ functions.forEach((func) => {
2433
+ console.log(chalk13.dim(` - ${func.packageName}`));
2434
+ });
2435
+ try {
2436
+ await executeFunctionMigrations2(functions);
2437
+ console.log(chalk13.green("\n\u2705 All function migrations applied\n"));
2438
+ } catch (error) {
2439
+ console.error(chalk13.red("\n\u274C Failed to apply function migrations"));
2440
+ console.error(chalk13.red(error instanceof Error ? error.message : "Unknown error"));
2441
+ process.exit(1);
2229
2442
  }
2230
2443
  }
2231
2444
 
2232
2445
  // src/commands/db/migrate.ts
2233
- import chalk16 from "chalk";
2446
+ import chalk17 from "chalk";
2234
2447
  import { join as join16 } from "path";
2235
2448
  import { existsSync as existsSync18 } from "fs";
2236
2449
 
@@ -2238,7 +2451,7 @@ import { existsSync as existsSync18 } from "fs";
2238
2451
  import { promises as fs3 } from "fs";
2239
2452
  import path3 from "path";
2240
2453
  import { spawn as spawn2 } from "child_process";
2241
- import chalk15 from "chalk";
2454
+ import chalk16 from "chalk";
2242
2455
  import ora7 from "ora";
2243
2456
 
2244
2457
  // src/commands/db/utils/database.ts
@@ -2307,14 +2520,14 @@ function formatTimestamp() {
2307
2520
  import { promises as fs2 } from "fs";
2308
2521
  import { existsSync as existsSync17 } from "fs";
2309
2522
  import path2 from "path";
2310
- import chalk14 from "chalk";
2523
+ import chalk15 from "chalk";
2311
2524
 
2312
2525
  // src/commands/db/utils/metadata.ts
2313
2526
  import { promises as fs } from "fs";
2314
2527
  import path from "path";
2315
2528
  import { promisify } from "util";
2316
2529
  import { exec } from "child_process";
2317
- import chalk13 from "chalk";
2530
+ import chalk14 from "chalk";
2318
2531
  var execAsync = promisify(exec);
2319
2532
  async function collectGitInfo() {
2320
2533
  try {
@@ -2377,7 +2590,7 @@ async function collectMigrationInfo(dbUrl) {
2377
2590
  await pool.end();
2378
2591
  }
2379
2592
  } catch (error) {
2380
- console.log(chalk13.dim("\u26A0\uFE0F Could not fetch migration info"));
2593
+ console.log(chalk14.dim("\u26A0\uFE0F Could not fetch migration info"));
2381
2594
  return void 0;
2382
2595
  }
2383
2596
  }
@@ -2385,9 +2598,9 @@ async function saveBackupMetadata(metadata, backupFilename) {
2385
2598
  const metadataPath = backupFilename.replace(/\.(sql|dump)$/, ".meta.json");
2386
2599
  try {
2387
2600
  await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2));
2388
- console.log(chalk13.dim(`\u2713 Metadata saved: ${path.basename(metadataPath)}`));
2601
+ console.log(chalk14.dim(`\u2713 Metadata saved: ${path.basename(metadataPath)}`));
2389
2602
  } catch (error) {
2390
- console.log(chalk13.dim("\u26A0\uFE0F Could not save metadata"));
2603
+ console.log(chalk14.dim("\u26A0\uFE0F Could not save metadata"));
2391
2604
  }
2392
2605
  }
2393
2606
  async function loadBackupMetadata(backupFilename) {
@@ -2416,10 +2629,10 @@ async function ensureBackupInGitignore() {
2416
2629
  if (!hasBackupsIgnore) {
2417
2630
  const entry = exists && content && !content.endsWith("\n") ? "\n\n# Database backups\nbackups/\n" : "# Database backups\nbackups/\n";
2418
2631
  await fs2.appendFile(gitignorePath, entry);
2419
- console.log(chalk14.dim("\u2713 Added backups/ to .gitignore"));
2632
+ console.log(chalk15.dim("\u2713 Added backups/ to .gitignore"));
2420
2633
  }
2421
2634
  } catch (error) {
2422
- console.log(chalk14.dim("\u26A0\uFE0F Could not update .gitignore"));
2635
+ console.log(chalk15.dim("\u26A0\uFE0F Could not update .gitignore"));
2423
2636
  }
2424
2637
  }
2425
2638
  async function ensureBackupDir() {
@@ -2467,14 +2680,14 @@ async function listBackupFiles() {
2467
2680
 
2468
2681
  // src/commands/db/backup.ts
2469
2682
  import { env as env3 } from "@spfn/core/config";
2470
- import { loadEnv as loadEnv3 } from "@spfn/core/server";
2683
+ import { loadEnv as loadEnv4 } from "@spfn/core/server";
2471
2684
  async function dbBackup(options) {
2472
- console.log(chalk15.blue("\u{1F4BE} Creating database backup...\n"));
2473
- loadEnv3();
2685
+ console.log(chalk16.blue("\u{1F4BE} Creating database backup...\n"));
2686
+ loadEnv4();
2474
2687
  const dbUrl = env3.DATABASE_URL;
2475
2688
  if (!dbUrl) {
2476
- console.error(chalk15.red("\u274C DATABASE_URL not found in environment"));
2477
- console.log(chalk15.yellow("\n\u{1F4A1} Tip: Add DATABASE_URL to your .env file"));
2689
+ console.error(chalk16.red("\u274C DATABASE_URL not found in environment"));
2690
+ console.log(chalk16.yellow("\n\u{1F4A1} Tip: Add DATABASE_URL to your .env file"));
2478
2691
  process.exit(1);
2479
2692
  }
2480
2693
  const dbInfo = parseDatabaseUrl(dbUrl);
@@ -2484,7 +2697,7 @@ async function dbBackup(options) {
2484
2697
  const ext = format === "sql" ? "sql" : "dump";
2485
2698
  const filename = options.output || path3.join(backupDir, `${dbInfo.database}_${timestamp}.${ext}`);
2486
2699
  if (options.dataOnly && options.schemaOnly) {
2487
- console.error(chalk15.red("\u274C Cannot use --data-only and --schema-only together"));
2700
+ console.error(chalk16.red("\u274C Cannot use --data-only and --schema-only together"));
2488
2701
  process.exit(1);
2489
2702
  }
2490
2703
  const args = [
@@ -2530,11 +2743,11 @@ async function dbBackup(options) {
2530
2743
  const stats = await fs3.stat(filename);
2531
2744
  const size = formatBytes(stats.size);
2532
2745
  spinner.succeed("Backup created");
2533
- console.log(chalk15.green(`
2746
+ console.log(chalk16.green(`
2534
2747
  \u2705 Backup created successfully`));
2535
- console.log(chalk15.gray(` File: ${filename}`));
2536
- console.log(chalk15.gray(` Size: ${size}`));
2537
- console.log(chalk15.dim("\n\u{1F4CB} Collecting metadata..."));
2748
+ console.log(chalk16.gray(` File: ${filename}`));
2749
+ console.log(chalk16.gray(` Size: ${size}`));
2750
+ console.log(chalk16.dim("\n\u{1F4CB} Collecting metadata..."));
2538
2751
  const [gitInfo, migrationInfo] = await Promise.all([
2539
2752
  collectGitInfo(),
2540
2753
  collectMigrationInfo(dbUrl)
@@ -2574,11 +2787,11 @@ async function dbBackup(options) {
2574
2787
  reject(error);
2575
2788
  });
2576
2789
  }).catch((error) => {
2577
- console.error(chalk15.red("\n\u274C Failed to create backup"));
2790
+ console.error(chalk16.red("\n\u274C Failed to create backup"));
2578
2791
  if (errorOutput.includes("pg_dump: command not found") || errorOutput.includes("not found")) {
2579
- console.error(chalk15.yellow("\n\u{1F4A1} pg_dump is not installed. Please install PostgreSQL client tools."));
2792
+ console.error(chalk16.yellow("\n\u{1F4A1} pg_dump is not installed. Please install PostgreSQL client tools."));
2580
2793
  } else {
2581
- console.error(chalk15.red(error instanceof Error ? error.message : "Unknown error"));
2794
+ console.error(chalk16.red(error instanceof Error ? error.message : "Unknown error"));
2582
2795
  }
2583
2796
  process.exit(1);
2584
2797
  });
@@ -2586,7 +2799,7 @@ async function dbBackup(options) {
2586
2799
 
2587
2800
  // src/commands/db/migrate.ts
2588
2801
  import { env as env4 } from "@spfn/core/config";
2589
- import { loadEnv as loadEnv4 } from "@spfn/core/server";
2802
+ import { loadEnv as loadEnv5 } from "@spfn/core/server";
2590
2803
  var FUNCTION_MIGRATIONS_TABLE = "__spfn_fn_migrations";
2591
2804
  var PROJECT_MIGRATIONS_TABLE = "__drizzle_migrations";
2592
2805
  async function dbMigrate(options = {}) {
@@ -2596,7 +2809,7 @@ async function dbMigrate(options = {}) {
2596
2809
  process.exit(1);
2597
2810
  }
2598
2811
  if (options.withBackup) {
2599
- console.log(chalk16.blue("\u{1F4E6} Creating pre-migration backup...\n"));
2812
+ console.log(chalk17.blue("\u{1F4E6} Creating pre-migration backup...\n"));
2600
2813
  await dbBackup({
2601
2814
  format: "custom",
2602
2815
  tag: "pre-migration",
@@ -2607,9 +2820,9 @@ async function dbMigrate(options = {}) {
2607
2820
  const { drizzle } = await import("drizzle-orm/postgres-js");
2608
2821
  const { migrate } = await import("drizzle-orm/postgres-js/migrator");
2609
2822
  const postgres = await import("postgres");
2610
- loadEnv4();
2823
+ loadEnv5();
2611
2824
  if (!env4.DATABASE_URL) {
2612
- console.error(chalk16.red("\u274C DATABASE_URL not found in environment"));
2825
+ console.error(chalk17.red("\u274C DATABASE_URL not found in environment"));
2613
2826
  process.exit(1);
2614
2827
  }
2615
2828
  const { discoverFunctionMigrations: discoverFunctionMigrations2 } = await Promise.resolve().then(() => (init_function_migrations(), function_migrations_exports));
@@ -2618,20 +2831,20 @@ async function dbMigrate(options = {}) {
2618
2831
  const fnConn = postgres.default(env4.DATABASE_URL, { max: 1 });
2619
2832
  const fnDb = drizzle(fnConn);
2620
2833
  try {
2621
- console.log(chalk16.blue("\u{1F4E6} Applying function package migrations:"));
2834
+ console.log(chalk17.blue("\u{1F4E6} Applying function package migrations:"));
2622
2835
  functions.forEach((func) => {
2623
- console.log(chalk16.dim(` - ${func.packageName}`));
2836
+ console.log(chalk17.dim(` - ${func.packageName}`));
2624
2837
  });
2625
2838
  for (const func of functions) {
2626
- console.log(chalk16.blue(`
2839
+ console.log(chalk17.blue(`
2627
2840
  \u{1F4E6} Running ${func.packageName} migrations...`));
2628
2841
  await migrate(fnDb, {
2629
2842
  migrationsFolder: func.migrationsDir,
2630
2843
  migrationsTable: FUNCTION_MIGRATIONS_TABLE
2631
2844
  });
2632
- console.log(chalk16.green(` \u2713 ${func.packageName} migrations applied`));
2845
+ console.log(chalk17.green(` \u2713 ${func.packageName} migrations applied`));
2633
2846
  }
2634
- console.log(chalk16.green("\u2705 Function migrations applied\n"));
2847
+ console.log(chalk17.green("\u2705 Function migrations applied\n"));
2635
2848
  } finally {
2636
2849
  await fnConn.end();
2637
2850
  }
@@ -2641,39 +2854,39 @@ async function dbMigrate(options = {}) {
2641
2854
  const projConn = postgres.default(env4.DATABASE_URL, { max: 1 });
2642
2855
  const projDb = drizzle(projConn);
2643
2856
  try {
2644
- console.log(chalk16.blue("\u{1F4E6} Running project migrations..."));
2857
+ console.log(chalk17.blue("\u{1F4E6} Running project migrations..."));
2645
2858
  await migrate(projDb, {
2646
2859
  migrationsFolder: projectMigrationsDir,
2647
2860
  migrationsTable: PROJECT_MIGRATIONS_TABLE
2648
2861
  });
2649
- console.log(chalk16.green("\u2705 Project migrations applied successfully"));
2862
+ console.log(chalk17.green("\u2705 Project migrations applied successfully"));
2650
2863
  } finally {
2651
2864
  await projConn.end();
2652
2865
  }
2653
2866
  } else {
2654
- console.log(chalk16.dim("No project migrations found (src/server/drizzle)"));
2867
+ console.log(chalk17.dim("No project migrations found (src/server/drizzle)"));
2655
2868
  }
2656
2869
  }
2657
2870
 
2658
2871
  // src/commands/db/studio.ts
2659
- import chalk17 from "chalk";
2872
+ import chalk18 from "chalk";
2660
2873
  import { existsSync as existsSync19, writeFileSync as writeFileSync10, unlinkSync as unlinkSync3 } from "fs";
2661
2874
  import { spawn as spawn3 } from "child_process";
2662
2875
  import { env as env5 } from "@spfn/core/config";
2663
2876
  import "@spfn/core/config";
2664
2877
  async function dbStudio(requestedPort) {
2665
- console.log(chalk17.blue("\u{1F3A8} Opening Drizzle Studio...\n"));
2878
+ console.log(chalk18.blue("\u{1F3A8} Opening Drizzle Studio...\n"));
2666
2879
  const defaultPort = 4983;
2667
2880
  const startPort = requestedPort || defaultPort;
2668
2881
  let port;
2669
2882
  try {
2670
2883
  port = await findAvailablePort(startPort);
2671
2884
  if (port !== startPort) {
2672
- console.log(chalk17.yellow(`\u26A0\uFE0F Port ${startPort} is in use, using port ${port} instead
2885
+ console.log(chalk18.yellow(`\u26A0\uFE0F Port ${startPort} is in use, using port ${port} instead
2673
2886
  `));
2674
2887
  }
2675
2888
  } catch (error) {
2676
- console.error(chalk17.red(error instanceof Error ? error.message : "Failed to find available port"));
2889
+ console.error(chalk18.red(error instanceof Error ? error.message : "Failed to find available port"));
2677
2890
  process.exit(1);
2678
2891
  }
2679
2892
  const hasUserConfig = existsSync19("./drizzle.config.ts");
@@ -2682,8 +2895,8 @@ async function dbStudio(requestedPort) {
2682
2895
  const configPath = hasUserConfig ? "./drizzle.config.ts" : tempConfigPath;
2683
2896
  if (!hasUserConfig) {
2684
2897
  if (!env5.DATABASE_URL) {
2685
- console.error(chalk17.red("\u274C DATABASE_URL not found in environment"));
2686
- console.log(chalk17.yellow("\n\u{1F4A1} Tip: Add DATABASE_URL to your .env file"));
2898
+ console.error(chalk18.red("\u274C DATABASE_URL not found in environment"));
2899
+ console.log(chalk18.yellow("\n\u{1F4A1} Tip: Add DATABASE_URL to your .env file"));
2687
2900
  process.exit(1);
2688
2901
  }
2689
2902
  const { generateDrizzleConfigFile } = await import("@spfn/core/db");
@@ -2694,7 +2907,7 @@ async function dbStudio(requestedPort) {
2694
2907
  // Expand glob patterns for Studio compatibility
2695
2908
  });
2696
2909
  writeFileSync10(tempConfigPath, configContent);
2697
- console.log(chalk17.dim("Using auto-generated Drizzle config\n"));
2910
+ console.log(chalk18.dim("Using auto-generated Drizzle config\n"));
2698
2911
  }
2699
2912
  const studioProcess = spawn3("drizzle-kit", ["studio", `--port=${port}`, `--config=${configPath}`], {
2700
2913
  stdio: "inherit",
@@ -2709,19 +2922,19 @@ async function dbStudio(requestedPort) {
2709
2922
  studioProcess.on("exit", (code) => {
2710
2923
  cleanup();
2711
2924
  if (code !== 0 && code !== null) {
2712
- console.error(chalk17.red(`
2925
+ console.error(chalk18.red(`
2713
2926
  \u274C Drizzle Studio exited with code ${code}`));
2714
2927
  process.exit(code);
2715
2928
  }
2716
2929
  });
2717
2930
  studioProcess.on("error", (error) => {
2718
2931
  cleanup();
2719
- console.error(chalk17.red("\u274C Failed to start Drizzle Studio"));
2720
- console.error(chalk17.red(error.message));
2932
+ console.error(chalk18.red("\u274C Failed to start Drizzle Studio"));
2933
+ console.error(chalk18.red(error.message));
2721
2934
  process.exit(1);
2722
2935
  });
2723
2936
  process.on("SIGINT", () => {
2724
- console.log(chalk17.yellow("\n\n\u{1F44B} Shutting down Drizzle Studio..."));
2937
+ console.log(chalk18.yellow("\n\n\u{1F44B} Shutting down Drizzle Studio..."));
2725
2938
  studioProcess.kill("SIGTERM");
2726
2939
  cleanup();
2727
2940
  process.exit(0);
@@ -2735,25 +2948,25 @@ async function dbStudio(requestedPort) {
2735
2948
  if (!hasUserConfig && existsSync19(tempConfigPath)) {
2736
2949
  unlinkSync3(tempConfigPath);
2737
2950
  }
2738
- console.error(chalk17.red("\u274C Failed to start Drizzle Studio"));
2739
- console.error(chalk17.red(error instanceof Error ? error.message : "Unknown error"));
2951
+ console.error(chalk18.red("\u274C Failed to start Drizzle Studio"));
2952
+ console.error(chalk18.red(error instanceof Error ? error.message : "Unknown error"));
2740
2953
  process.exit(1);
2741
2954
  }
2742
2955
  }
2743
2956
 
2744
2957
  // src/commands/db/drop.ts
2745
- import chalk18 from "chalk";
2746
- import prompts3 from "prompts";
2958
+ import chalk19 from "chalk";
2959
+ import prompts4 from "prompts";
2747
2960
  async function dbDrop() {
2748
- console.log(chalk18.yellow("\u26A0\uFE0F WARNING: This will drop all tables in your database!"));
2749
- const { confirm } = await prompts3({
2961
+ console.log(chalk19.yellow("\u26A0\uFE0F WARNING: This will drop all tables in your database!"));
2962
+ const { confirm } = await prompts4({
2750
2963
  type: "confirm",
2751
2964
  name: "confirm",
2752
2965
  message: "Are you sure you want to drop all tables?",
2753
2966
  initial: false
2754
2967
  });
2755
2968
  if (!confirm) {
2756
- console.log(chalk18.gray("Cancelled."));
2969
+ console.log(chalk19.gray("Cancelled."));
2757
2970
  process.exit(0);
2758
2971
  }
2759
2972
  await runWithSpinner(
@@ -2765,7 +2978,7 @@ async function dbDrop() {
2765
2978
  }
2766
2979
 
2767
2980
  // src/commands/db/check.ts
2768
- import chalk19 from "chalk";
2981
+ import chalk20 from "chalk";
2769
2982
  import ora8 from "ora";
2770
2983
  async function dbCheck() {
2771
2984
  const spinner = ora8("Checking database connection...").start();
@@ -2774,7 +2987,7 @@ async function dbCheck() {
2774
2987
  spinner.succeed("Database connection OK");
2775
2988
  } catch (error) {
2776
2989
  spinner.fail("Database connection failed");
2777
- console.error(chalk19.red(error instanceof Error ? error.message : "Unknown error"));
2990
+ console.error(chalk20.red(error instanceof Error ? error.message : "Unknown error"));
2778
2991
  process.exit(1);
2779
2992
  }
2780
2993
  }
@@ -2782,28 +2995,28 @@ async function dbCheck() {
2782
2995
  // src/commands/db/restore.ts
2783
2996
  import path4 from "path";
2784
2997
  import { spawn as spawn4 } from "child_process";
2785
- import chalk20 from "chalk";
2998
+ import chalk21 from "chalk";
2786
2999
  import ora9 from "ora";
2787
- import prompts4 from "prompts";
3000
+ import prompts5 from "prompts";
2788
3001
  import { env as env6 } from "@spfn/core/config";
2789
- import { loadEnv as loadEnv5 } from "@spfn/core/server";
3002
+ import { loadEnv as loadEnv6 } from "@spfn/core/server";
2790
3003
  async function dbRestore(backupFile, options = {}) {
2791
- console.log(chalk20.blue("\u267B\uFE0F Restoring database from backup...\n"));
2792
- loadEnv5();
3004
+ console.log(chalk21.blue("\u267B\uFE0F Restoring database from backup...\n"));
3005
+ loadEnv6();
2793
3006
  const dbUrl = env6.DATABASE_URL;
2794
3007
  if (!dbUrl) {
2795
- console.error(chalk20.red("\u274C DATABASE_URL not found in environment"));
2796
- console.log(chalk20.yellow("\n\u{1F4A1} Tip: Add DATABASE_URL to your .env file"));
3008
+ console.error(chalk21.red("\u274C DATABASE_URL not found in environment"));
3009
+ console.log(chalk21.yellow("\n\u{1F4A1} Tip: Add DATABASE_URL to your .env file"));
2797
3010
  process.exit(1);
2798
3011
  }
2799
3012
  let file = backupFile;
2800
3013
  if (!file) {
2801
3014
  const backups = await listBackupFiles();
2802
3015
  if (backups.length === 0) {
2803
- console.log(chalk20.yellow("No backups found in ./backups directory"));
3016
+ console.log(chalk21.yellow("No backups found in ./backups directory"));
2804
3017
  process.exit(0);
2805
3018
  }
2806
- const { selected } = await prompts4({
3019
+ const { selected } = await prompts5({
2807
3020
  type: "select",
2808
3021
  name: "selected",
2809
3022
  message: "Select backup to restore:",
@@ -2813,31 +3026,31 @@ async function dbRestore(backupFile, options = {}) {
2813
3026
  }))
2814
3027
  });
2815
3028
  if (!selected) {
2816
- console.log(chalk20.gray("Cancelled"));
3029
+ console.log(chalk21.gray("Cancelled"));
2817
3030
  process.exit(0);
2818
3031
  }
2819
3032
  file = selected;
2820
3033
  }
2821
3034
  if (!file) {
2822
- console.error(chalk20.red("\u274C No backup file selected"));
3035
+ console.error(chalk21.red("\u274C No backup file selected"));
2823
3036
  process.exit(1);
2824
3037
  }
2825
3038
  const metadata = await loadBackupMetadata(file);
2826
3039
  if (metadata) {
2827
- console.log(chalk20.blue("\n\u{1F4CB} Backup Information:\n"));
2828
- console.log(chalk20.dim(` Database: ${metadata.database}`));
2829
- console.log(chalk20.dim(` Created: ${new Date(metadata.timestamp).toLocaleString()}`));
3040
+ console.log(chalk21.blue("\n\u{1F4CB} Backup Information:\n"));
3041
+ console.log(chalk21.dim(` Database: ${metadata.database}`));
3042
+ console.log(chalk21.dim(` Created: ${new Date(metadata.timestamp).toLocaleString()}`));
2830
3043
  if (metadata.environment) {
2831
- console.log(chalk20.dim(` Environment: ${metadata.environment}`));
3044
+ console.log(chalk21.dim(` Environment: ${metadata.environment}`));
2832
3045
  }
2833
3046
  if (metadata.tags && metadata.tags.length > 0) {
2834
- console.log(chalk20.dim(` Tags: ${metadata.tags.join(", ")}`));
3047
+ console.log(chalk21.dim(` Tags: ${metadata.tags.join(", ")}`));
2835
3048
  }
2836
3049
  if (metadata.backup.dataOnly) {
2837
- console.log(chalk20.yellow(" \u26A0\uFE0F Data-only backup (no schema)"));
3050
+ console.log(chalk21.yellow(" \u26A0\uFE0F Data-only backup (no schema)"));
2838
3051
  }
2839
3052
  if (metadata.backup.schemaOnly) {
2840
- console.log(chalk20.yellow(" \u26A0\uFE0F Schema-only backup (no data)"));
3053
+ console.log(chalk21.yellow(" \u26A0\uFE0F Schema-only backup (no data)"));
2841
3054
  }
2842
3055
  const warnings2 = [];
2843
3056
  const [currentGitInfo, currentMigrationInfo] = await Promise.all([
@@ -2860,23 +3073,23 @@ async function dbRestore(backupFile, options = {}) {
2860
3073
  }
2861
3074
  }
2862
3075
  if (warnings2.length > 0) {
2863
- console.log(chalk20.yellow("\n\u26A0\uFE0F Version Warnings:\n"));
2864
- warnings2.forEach((warning) => console.log(chalk20.yellow(` - ${warning}`)));
3076
+ console.log(chalk21.yellow("\n\u26A0\uFE0F Version Warnings:\n"));
3077
+ warnings2.forEach((warning) => console.log(chalk21.yellow(` - ${warning}`)));
2865
3078
  console.log("");
2866
3079
  }
2867
3080
  }
2868
- const { confirm } = await prompts4({
3081
+ const { confirm } = await prompts5({
2869
3082
  type: "confirm",
2870
3083
  name: "confirm",
2871
- message: chalk20.yellow("\u26A0\uFE0F This will replace all data in the database. Continue?"),
3084
+ message: chalk21.yellow("\u26A0\uFE0F This will replace all data in the database. Continue?"),
2872
3085
  initial: false
2873
3086
  });
2874
3087
  if (!confirm) {
2875
- console.log(chalk20.gray("Cancelled"));
3088
+ console.log(chalk21.gray("Cancelled"));
2876
3089
  process.exit(0);
2877
3090
  }
2878
3091
  if (options.dataOnly && options.schemaOnly) {
2879
- console.error(chalk20.red("\u274C Cannot use --data-only and --schema-only together"));
3092
+ console.error(chalk21.red("\u274C Cannot use --data-only and --schema-only together"));
2880
3093
  process.exit(1);
2881
3094
  }
2882
3095
  const dbInfo = parseDatabaseUrl(dbUrl);
@@ -2905,8 +3118,8 @@ async function dbRestore(backupFile, options = {}) {
2905
3118
  args.push(file);
2906
3119
  } else {
2907
3120
  if (options.dataOnly || options.schemaOnly) {
2908
- console.log(chalk20.yellow("\u26A0\uFE0F Note: --data-only and --schema-only options only work with custom format backups (.dump)"));
2909
- console.log(chalk20.yellow(" For SQL files, the backup must have been created with the desired option.\n"));
3121
+ console.log(chalk21.yellow("\u26A0\uFE0F Note: --data-only and --schema-only options only work with custom format backups (.dump)"));
3122
+ console.log(chalk21.yellow(" For SQL files, the backup must have been created with the desired option.\n"));
2910
3123
  }
2911
3124
  args.push("-h", dbInfo.host);
2912
3125
  args.push("-p", dbInfo.port);
@@ -2952,7 +3165,7 @@ async function dbRestore(backupFile, options = {}) {
2952
3165
  }
2953
3166
  if (verbose) {
2954
3167
  spinner.stop();
2955
- console.log(chalk20.dim(` ${line.trim()}`));
3168
+ console.log(chalk21.dim(` ${line.trim()}`));
2956
3169
  spinner.start();
2957
3170
  }
2958
3171
  }
@@ -2960,7 +3173,7 @@ async function dbRestore(backupFile, options = {}) {
2960
3173
  restoreProcess.stdout?.on("data", (data) => {
2961
3174
  if (verbose) {
2962
3175
  spinner.stop();
2963
- console.log(chalk20.dim(` ${data.toString().trim()}`));
3176
+ console.log(chalk21.dim(` ${data.toString().trim()}`));
2964
3177
  spinner.start();
2965
3178
  }
2966
3179
  });
@@ -2970,31 +3183,31 @@ async function dbRestore(backupFile, options = {}) {
2970
3183
  const summary = objectCount > 0 ? ` (${objectCount} objects)` : "";
2971
3184
  spinner.succeed(`Restore completed${summary}`);
2972
3185
  if (warnings.length > 0) {
2973
- console.log(chalk20.yellow(`
3186
+ console.log(chalk21.yellow(`
2974
3187
  \u26A0\uFE0F Warnings during restore (${warnings.length}):
2975
3188
  `));
2976
3189
  for (const w of warnings) {
2977
- console.log(chalk20.yellow(` - ${w}`));
3190
+ console.log(chalk21.yellow(` - ${w}`));
2978
3191
  }
2979
3192
  }
2980
- console.log(chalk20.green("\n\u2705 Database restored successfully"));
3193
+ console.log(chalk21.green("\n\u2705 Database restored successfully"));
2981
3194
  resolve2();
2982
3195
  } else {
2983
3196
  spinner.fail("Restore failed");
2984
3197
  if (errors.length > 0) {
2985
- console.error(chalk20.red(`
3198
+ console.error(chalk21.red(`
2986
3199
  \u274C Errors (${errors.length}):
2987
3200
  `));
2988
3201
  for (const e of errors) {
2989
- console.error(chalk20.red(` - ${e}`));
3202
+ console.error(chalk21.red(` - ${e}`));
2990
3203
  }
2991
3204
  }
2992
3205
  if (warnings.length > 0) {
2993
- console.log(chalk20.yellow(`
3206
+ console.log(chalk21.yellow(`
2994
3207
  \u26A0\uFE0F Warnings (${warnings.length}):
2995
3208
  `));
2996
3209
  for (const w of warnings) {
2997
- console.log(chalk20.yellow(` - ${w}`));
3210
+ console.log(chalk21.yellow(` - ${w}`));
2998
3211
  }
2999
3212
  }
3000
3213
  const fallback = errors.length === 0 && warnings.length === 0 ? "Restore failed with no output" : "";
@@ -3008,7 +3221,7 @@ async function dbRestore(backupFile, options = {}) {
3008
3221
  }).catch((error) => {
3009
3222
  const msg = error instanceof Error ? error.message : "Unknown error";
3010
3223
  if (msg) {
3011
- console.error(chalk20.red(`
3224
+ console.error(chalk21.red(`
3012
3225
  \u274C ${msg}`));
3013
3226
  }
3014
3227
  process.exit(1);
@@ -3016,17 +3229,17 @@ async function dbRestore(backupFile, options = {}) {
3016
3229
  }
3017
3230
 
3018
3231
  // src/commands/db/list.ts
3019
- import chalk21 from "chalk";
3232
+ import chalk22 from "chalk";
3020
3233
  async function dbBackupList() {
3021
- console.log(chalk21.blue("\u{1F4CB} Database backups:\n"));
3234
+ console.log(chalk22.blue("\u{1F4CB} Database backups:\n"));
3022
3235
  const backups = await listBackupFiles();
3023
3236
  if (backups.length === 0) {
3024
- console.log(chalk21.yellow("No backups found in ./backups directory"));
3025
- console.log(chalk21.gray("\n\u{1F4A1} Create a backup with: pnpm spfn db backup\n"));
3237
+ console.log(chalk22.yellow("No backups found in ./backups directory"));
3238
+ console.log(chalk22.gray("\n\u{1F4A1} Create a backup with: pnpm spfn db backup\n"));
3026
3239
  return;
3027
3240
  }
3028
- console.log(chalk21.bold(" Date Size File"));
3029
- console.log(chalk21.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
3241
+ console.log(chalk22.bold(" Date Size File"));
3242
+ console.log(chalk22.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
3030
3243
  backups.forEach((backup) => {
3031
3244
  const date = backup.date.toLocaleString("en-US", {
3032
3245
  year: "numeric",
@@ -3037,23 +3250,23 @@ async function dbBackupList() {
3037
3250
  second: "2-digit"
3038
3251
  });
3039
3252
  const sizeStr = backup.size.padEnd(10);
3040
- console.log(chalk21.white(` ${date} ${sizeStr} ${backup.name}`));
3253
+ console.log(chalk22.white(` ${date} ${sizeStr} ${backup.name}`));
3041
3254
  });
3042
- console.log(chalk21.gray(`
3255
+ console.log(chalk22.gray(`
3043
3256
  Total: ${backups.length} backup(s)
3044
3257
  `));
3045
3258
  }
3046
3259
 
3047
3260
  // src/commands/db/clean.ts
3048
3261
  import { promises as fs4 } from "fs";
3049
- import chalk22 from "chalk";
3262
+ import chalk23 from "chalk";
3050
3263
  import ora10 from "ora";
3051
- import prompts5 from "prompts";
3264
+ import prompts6 from "prompts";
3052
3265
  async function dbBackupClean(options) {
3053
- console.log(chalk22.blue("\u{1F9F9} Cleaning old backups...\n"));
3266
+ console.log(chalk23.blue("\u{1F9F9} Cleaning old backups...\n"));
3054
3267
  const backups = await listBackupFiles();
3055
3268
  if (backups.length === 0) {
3056
- console.log(chalk22.yellow("No backups found"));
3269
+ console.log(chalk23.yellow("No backups found"));
3057
3270
  return;
3058
3271
  }
3059
3272
  let toDelete = [];
@@ -3070,41 +3283,142 @@ async function dbBackupClean(options) {
3070
3283
  toDelete = backups.slice(defaultKeep);
3071
3284
  }
3072
3285
  if (toDelete.length === 0) {
3073
- console.log(chalk22.green("\u2705 No backups to clean"));
3286
+ console.log(chalk23.green("\u2705 No backups to clean"));
3074
3287
  return;
3075
3288
  }
3076
- console.log(chalk22.yellow(`The following ${toDelete.length} backup(s) will be deleted:
3289
+ console.log(chalk23.yellow(`The following ${toDelete.length} backup(s) will be deleted:
3077
3290
  `));
3078
3291
  toDelete.forEach((backup) => {
3079
- console.log(chalk22.gray(` - ${backup.name} (${backup.size})`));
3292
+ console.log(chalk23.gray(` - ${backup.name} (${backup.size})`));
3080
3293
  });
3081
- const { confirm } = await prompts5({
3294
+ const { confirm } = await prompts6({
3082
3295
  type: "confirm",
3083
3296
  name: "confirm",
3084
3297
  message: "\nProceed with deletion?",
3085
3298
  initial: false
3086
3299
  });
3087
3300
  if (!confirm) {
3088
- console.log(chalk22.gray("Cancelled"));
3301
+ console.log(chalk23.gray("Cancelled"));
3089
3302
  return;
3090
3303
  }
3091
3304
  const spinner = ora10("Deleting backups...").start();
3092
3305
  try {
3093
3306
  await Promise.all(toDelete.map((backup) => fs4.unlink(backup.path)));
3094
3307
  spinner.succeed("Backups deleted");
3095
- console.log(chalk22.green(`
3308
+ console.log(chalk23.green(`
3096
3309
  \u2705 Deleted ${toDelete.length} backup(s)`));
3097
3310
  } catch (error) {
3098
3311
  spinner.fail("Failed to delete backups");
3099
- console.error(chalk22.red(error instanceof Error ? error.message : "Unknown error"));
3312
+ console.error(chalk23.red(error instanceof Error ? error.message : "Unknown error"));
3100
3313
  process.exit(1);
3101
3314
  }
3102
3315
  }
3103
3316
 
3317
+ // src/commands/db/reindex.ts
3318
+ import { existsSync as existsSync20, readFileSync as readFileSync6, writeFileSync as writeFileSync11, renameSync, copyFileSync } from "fs";
3319
+ import { join as join17 } from "path";
3320
+ import chalk24 from "chalk";
3321
+ import { loadEnv as loadEnv7 } from "@spfn/core/server";
3322
+ function isTimestampPrefix(tag) {
3323
+ const prefix = tag.split("_")[0];
3324
+ return /^\d{5,}$/.test(prefix);
3325
+ }
3326
+ function parseTag(tag) {
3327
+ const underscoreIdx = tag.indexOf("_");
3328
+ if (underscoreIdx === -1) {
3329
+ return { prefix: tag, suffix: "" };
3330
+ }
3331
+ return {
3332
+ prefix: tag.substring(0, underscoreIdx),
3333
+ suffix: tag.substring(underscoreIdx + 1)
3334
+ };
3335
+ }
3336
+ async function dbReindex(options = {}) {
3337
+ loadEnv7();
3338
+ const { getDrizzleConfig } = await import("@spfn/core/db");
3339
+ const config = getDrizzleConfig({ disablePackageDiscovery: true });
3340
+ const outDir = config.out;
3341
+ const journalPath = join17(outDir, "meta", "_journal.json");
3342
+ if (!existsSync20(journalPath)) {
3343
+ console.error(chalk24.red("\u274C No _journal.json found at:"), journalPath);
3344
+ console.log(chalk24.yellow("\u{1F4A1} Run `spfn db generate` first to create migrations"));
3345
+ process.exit(1);
3346
+ }
3347
+ const journal = JSON.parse(readFileSync6(journalPath, "utf-8"));
3348
+ if (journal.entries.length === 0) {
3349
+ console.log(chalk24.yellow("No migration entries found \u2014 nothing to reindex."));
3350
+ return;
3351
+ }
3352
+ const renames = [];
3353
+ const tagUpdates = [];
3354
+ let skipped = 0;
3355
+ for (const entry of journal.entries) {
3356
+ if (isTimestampPrefix(entry.tag)) {
3357
+ skipped++;
3358
+ continue;
3359
+ }
3360
+ const { prefix: oldPrefix, suffix } = parseTag(entry.tag);
3361
+ const newPrefix = String(entry.when);
3362
+ const newTag = suffix ? `${newPrefix}_${suffix}` : newPrefix;
3363
+ const oldSql = join17(outDir, `${entry.tag}.sql`);
3364
+ const newSql = join17(outDir, `${newTag}.sql`);
3365
+ if (existsSync20(oldSql)) {
3366
+ renames.push({ type: "sql", from: oldSql, to: newSql });
3367
+ }
3368
+ const oldSnapshot = join17(outDir, "meta", `${oldPrefix}_snapshot.json`);
3369
+ const newSnapshot = join17(outDir, "meta", `${newPrefix}_snapshot.json`);
3370
+ if (existsSync20(oldSnapshot)) {
3371
+ renames.push({ type: "snapshot", from: oldSnapshot, to: newSnapshot });
3372
+ }
3373
+ tagUpdates.push({ idx: entry.idx, oldTag: entry.tag, newTag });
3374
+ }
3375
+ if (tagUpdates.length === 0) {
3376
+ console.log(chalk24.green("\u2705 All migrations already use timestamp prefix \u2014 nothing to do."));
3377
+ if (skipped > 0) {
3378
+ console.log(chalk24.dim(` (${skipped} entries already timestamp-prefixed)`));
3379
+ }
3380
+ return;
3381
+ }
3382
+ console.log(chalk24.bold("\n\u{1F4CB} Reindex plan:\n"));
3383
+ for (const update of tagUpdates) {
3384
+ console.log(
3385
+ chalk24.dim(` [${update.idx}]`),
3386
+ chalk24.red(update.oldTag),
3387
+ chalk24.dim("\u2192"),
3388
+ chalk24.green(update.newTag)
3389
+ );
3390
+ }
3391
+ console.log(chalk24.dim(`
3392
+ ${renames.length} file(s) to rename, ${tagUpdates.length} journal tag(s) to update`));
3393
+ if (skipped > 0) {
3394
+ console.log(chalk24.dim(` ${skipped} entry/entries already timestamp-prefixed (skipped)`));
3395
+ }
3396
+ if (options.dryRun) {
3397
+ console.log(chalk24.yellow("\n\u{1F50D} Dry run \u2014 no changes applied."));
3398
+ return;
3399
+ }
3400
+ const backupPath = journalPath + ".bak";
3401
+ copyFileSync(journalPath, backupPath);
3402
+ console.log(chalk24.dim(`
3403
+ Backed up journal \u2192 ${backupPath}`));
3404
+ for (const rename of renames) {
3405
+ renameSync(rename.from, rename.to);
3406
+ }
3407
+ for (const update of tagUpdates) {
3408
+ const entry = journal.entries.find((e) => e.idx === update.idx);
3409
+ if (entry) {
3410
+ entry.tag = update.newTag;
3411
+ }
3412
+ }
3413
+ writeFileSync11(journalPath, JSON.stringify(journal, null, 2) + "\n");
3414
+ console.log(chalk24.green(`
3415
+ \u2705 Reindex complete \u2014 ${tagUpdates.length} migration(s) converted to timestamp prefix.`));
3416
+ }
3417
+
3104
3418
  // src/commands/db/index.ts
3105
3419
  var dbCommand = new Command9("db").description("Database management commands (wraps Drizzle Kit)");
3106
3420
  dbCommand.command("generate").alias("g").description("Generate database migrations from schema changes").action(dbGenerate);
3107
- dbCommand.command("push").description("Push schema changes directly to database (no migrations)").action(dbPush);
3421
+ dbCommand.command("push").description("Push schema changes to database (safe mode by default)").option("--force", "Apply all changes including destructive ones").option("--dry-run", "Show changes without applying").action((options) => dbPush(options));
3108
3422
  dbCommand.command("migrate").alias("m").description("Run pending migrations").option("--with-backup", "Create backup before running migrations").action((options) => dbMigrate(options));
3109
3423
  dbCommand.command("studio").description("Open Drizzle Studio (database GUI)").option("-p, --port <port>", "Studio port (auto-finds if in use)").action((options) => dbStudio(options.port ? Number(options.port) : void 0));
3110
3424
  dbCommand.command("drop").description("Drop all database tables (\u26A0\uFE0F dangerous!)").action(dbDrop);
@@ -3113,31 +3427,32 @@ dbCommand.command("backup").description("Create a database backup").option("-f,
3113
3427
  dbCommand.command("restore [file]").description("Restore database from backup").option("--drop", "Drop existing tables before restore").option("-s, --schema <name>", "Restore specific schema only").option("--data-only", "Restore data only (requires custom format .dump file)").option("--schema-only", "Restore schema only (requires custom format .dump file)").option("-v, --verbose", "Show detailed restore progress").action((file, options) => dbRestore(file, options));
3114
3428
  dbCommand.command("backup:list").description("List all database backups").action(dbBackupList);
3115
3429
  dbCommand.command("backup:clean").description("Clean old database backups").option("-k, --keep <number>", "Keep N most recent backups", parseInt).option("-o, --older-than <days>", "Delete backups older than N days", parseInt).action((options) => dbBackupClean(options));
3430
+ dbCommand.command("reindex").description("Convert migration files from sequential to timestamp prefix").option("--dry-run", "Show changes without applying").action((options) => dbReindex(options));
3116
3431
 
3117
3432
  // src/commands/add.ts
3118
3433
  import { Command as Command10 } from "commander";
3119
- import { existsSync as existsSync20, readFileSync as readFileSync6 } from "fs";
3120
- import { join as join17 } from "path";
3434
+ import { existsSync as existsSync21, readFileSync as readFileSync7 } from "fs";
3435
+ import { join as join18 } from "path";
3121
3436
  import { exec as exec2 } from "child_process";
3122
3437
  import { promisify as promisify2 } from "util";
3123
- import chalk23 from "chalk";
3438
+ import chalk25 from "chalk";
3124
3439
  import ora11 from "ora";
3125
3440
  var execAsync2 = promisify2(exec2);
3126
3441
  async function addPackage(packageName) {
3127
3442
  if (!packageName.includes("/")) {
3128
- console.error(chalk23.red("\u274C Please specify full package name"));
3129
- console.log(chalk23.yellow("\n\u{1F4A1} Examples:"));
3130
- console.log(chalk23.gray(" pnpm spfn add @spfn/cms"));
3131
- console.log(chalk23.gray(" pnpm spfn add @mycompany/spfn-analytics"));
3443
+ console.error(chalk25.red("\u274C Please specify full package name"));
3444
+ console.log(chalk25.yellow("\n\u{1F4A1} Examples:"));
3445
+ console.log(chalk25.gray(" pnpm spfn add @spfn/cms"));
3446
+ console.log(chalk25.gray(" pnpm spfn add @mycompany/spfn-analytics"));
3132
3447
  process.exit(1);
3133
3448
  }
3134
- console.log(chalk23.blue(`
3449
+ console.log(chalk25.blue(`
3135
3450
  \u{1F4E6} Setting up ${packageName}...
3136
3451
  `));
3137
3452
  try {
3138
- const pkgPath = join17(process.cwd(), "node_modules", ...packageName.split("/"));
3139
- const pkgJsonPath = join17(pkgPath, "package.json");
3140
- if (!existsSync20(pkgJsonPath)) {
3453
+ const pkgPath = join18(process.cwd(), "node_modules", ...packageName.split("/"));
3454
+ const pkgJsonPath = join18(pkgPath, "package.json");
3455
+ if (!existsSync21(pkgJsonPath)) {
3141
3456
  const installSpinner = ora11("Installing package...").start();
3142
3457
  try {
3143
3458
  await execAsync2(`pnpm add ${packageName}`);
@@ -3147,21 +3462,21 @@ async function addPackage(packageName) {
3147
3462
  throw error;
3148
3463
  }
3149
3464
  } else {
3150
- console.log(chalk23.gray("\u2713 Package already installed (using local version)\n"));
3465
+ console.log(chalk25.gray("\u2713 Package already installed (using local version)\n"));
3151
3466
  }
3152
- if (!existsSync20(pkgJsonPath)) {
3467
+ if (!existsSync21(pkgJsonPath)) {
3153
3468
  throw new Error(`Package ${packageName} not found after installation`);
3154
3469
  }
3155
- const pkgJson = JSON.parse(readFileSync6(pkgJsonPath, "utf-8"));
3470
+ const pkgJson = JSON.parse(readFileSync7(pkgJsonPath, "utf-8"));
3156
3471
  if (pkgJson.spfn?.migrations) {
3157
- console.log(chalk23.blue(`
3472
+ console.log(chalk25.blue(`
3158
3473
  \u{1F5C4}\uFE0F Setting up database for ${packageName}...
3159
3474
  `));
3160
3475
  const { env: env7 } = await import("@spfn/core/config");
3161
3476
  if (!env7.DATABASE_URL) {
3162
- console.log(chalk23.yellow("\u26A0\uFE0F DATABASE_URL not found"));
3163
- console.log(chalk23.gray("Skipping database setup. Run migrations manually when ready:\n"));
3164
- console.log(chalk23.gray(` pnpm spfn db push
3477
+ console.log(chalk25.yellow("\u26A0\uFE0F DATABASE_URL not found"));
3478
+ console.log(chalk25.gray("Skipping database setup. Run migrations manually when ready:\n"));
3479
+ console.log(chalk25.gray(` pnpm spfn db push
3165
3480
  `));
3166
3481
  } else {
3167
3482
  const { discoverFunctionMigrations: discoverFunctionMigrations2, executeFunctionMigrations: executeFunctionMigrations2 } = await Promise.resolve().then(() => (init_function_migrations(), function_migrations_exports));
@@ -3177,25 +3492,25 @@ async function addPackage(packageName) {
3177
3492
  throw error;
3178
3493
  }
3179
3494
  } else {
3180
- console.log(chalk23.gray("\u2139\uFE0F No migrations found for this package"));
3495
+ console.log(chalk25.gray("\u2139\uFE0F No migrations found for this package"));
3181
3496
  }
3182
3497
  }
3183
3498
  } else {
3184
- console.log(chalk23.gray("\n\u2139\uFE0F No database migrations to apply"));
3499
+ console.log(chalk25.gray("\n\u2139\uFE0F No database migrations to apply"));
3185
3500
  }
3186
- console.log(chalk23.green(`
3501
+ console.log(chalk25.green(`
3187
3502
  \u2705 ${packageName} installed successfully!
3188
3503
  `));
3189
3504
  if (pkgJson.spfn?.setupMessage) {
3190
- console.log(chalk23.cyan("\u{1F4DA} Setup Guide:"));
3505
+ console.log(chalk25.cyan("\u{1F4DA} Setup Guide:"));
3191
3506
  console.log(pkgJson.spfn.setupMessage);
3192
3507
  console.log();
3193
3508
  }
3194
3509
  } catch (error) {
3195
- console.error(chalk23.red(`
3510
+ console.error(chalk25.red(`
3196
3511
  \u274C Failed to install ${packageName}
3197
3512
  `));
3198
- console.error(chalk23.red(error instanceof Error ? error.message : "Unknown error"));
3513
+ console.error(chalk25.red(error instanceof Error ? error.message : "Unknown error"));
3199
3514
  process.exit(1);
3200
3515
  }
3201
3516
  }
@@ -3205,16 +3520,16 @@ var addCommand = new Command10("add").description("Install and set up SPFN ecosy
3205
3520
  init_logger();
3206
3521
  import { Command as Command11 } from "commander";
3207
3522
  import ora12 from "ora";
3208
- import { join as join26 } from "path";
3209
- import { existsSync as existsSync23 } from "fs";
3210
- import chalk25 from "chalk";
3523
+ import { join as join27 } from "path";
3524
+ import { existsSync as existsSync24 } from "fs";
3525
+ import chalk27 from "chalk";
3211
3526
 
3212
3527
  // src/commands/generate/prompts.ts
3213
3528
  init_logger();
3214
- import prompts6 from "prompts";
3215
- import chalk24 from "chalk";
3529
+ import prompts7 from "prompts";
3530
+ import chalk26 from "chalk";
3216
3531
  async function promptScope() {
3217
- const response = await prompts6({
3532
+ const response = await prompts7({
3218
3533
  type: "text",
3219
3534
  name: "scope",
3220
3535
  message: "NPM scope (e.g., @mycompany, @username):",
@@ -3236,7 +3551,7 @@ async function promptScope() {
3236
3551
  return response.scope;
3237
3552
  }
3238
3553
  async function promptFunctionName() {
3239
- const response = await prompts6({
3554
+ const response = await prompts7({
3240
3555
  type: "text",
3241
3556
  name: "fnName",
3242
3557
  message: "Function name:",
@@ -3257,7 +3572,7 @@ async function promptFunctionName() {
3257
3572
  return response.fnName;
3258
3573
  }
3259
3574
  async function promptDescription(fnName) {
3260
- const response = await prompts6({
3575
+ const response = await prompts7({
3261
3576
  type: "text",
3262
3577
  name: "description",
3263
3578
  message: "Function description:",
@@ -3266,7 +3581,7 @@ async function promptDescription(fnName) {
3266
3581
  return response.description || "A description of what this module does";
3267
3582
  }
3268
3583
  async function promptEntities() {
3269
- const response = await prompts6({
3584
+ const response = await prompts7({
3270
3585
  type: "list",
3271
3586
  name: "entities",
3272
3587
  message: "Entity names (comma-separated, press enter to skip):",
@@ -3278,14 +3593,14 @@ async function promptEntities() {
3278
3593
  async function confirmConfiguration(config) {
3279
3594
  const { scope, fnName, description, entities, enableCache, enableRoutes } = config;
3280
3595
  console.log("");
3281
- logger.info(chalk24.bold("\u26A1 Function Configuration:"));
3282
- console.log(` ${chalk24.gray("Package:")} ${chalk24.cyan(`${scope}/${fnName}`)}`);
3283
- console.log(` ${chalk24.gray("Description:")} ${description}`);
3284
- console.log(` ${chalk24.gray("Entities:")} ${entities.length > 0 ? entities.join(", ") : chalk24.gray("none")}`);
3285
- console.log(` ${chalk24.gray("Cache:")} ${enableCache ? chalk24.green("yes") : chalk24.gray("no")}`);
3286
- console.log(` ${chalk24.gray("Routes:")} ${enableRoutes ? chalk24.green("yes") : chalk24.gray("no")}`);
3596
+ logger.info(chalk26.bold("\u26A1 Function Configuration:"));
3597
+ console.log(` ${chalk26.gray("Package:")} ${chalk26.cyan(`${scope}/${fnName}`)}`);
3598
+ console.log(` ${chalk26.gray("Description:")} ${description}`);
3599
+ console.log(` ${chalk26.gray("Entities:")} ${entities.length > 0 ? entities.join(", ") : chalk26.gray("none")}`);
3600
+ console.log(` ${chalk26.gray("Cache:")} ${enableCache ? chalk26.green("yes") : chalk26.gray("no")}`);
3601
+ console.log(` ${chalk26.gray("Routes:")} ${enableRoutes ? chalk26.green("yes") : chalk26.gray("no")}`);
3287
3602
  console.log("");
3288
- const { confirmed } = await prompts6({
3603
+ const { confirmed } = await prompts7({
3289
3604
  type: "confirm",
3290
3605
  name: "confirmed",
3291
3606
  message: "Create function?",
@@ -3299,12 +3614,12 @@ async function confirmConfiguration(config) {
3299
3614
  }
3300
3615
 
3301
3616
  // src/commands/generate/generators/structure.ts
3302
- import { join as join25 } from "path";
3303
- import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync17 } from "fs";
3617
+ import { join as join26 } from "path";
3618
+ import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync18 } from "fs";
3304
3619
 
3305
3620
  // src/commands/generate/generators/config.ts
3306
- import { join as join19 } from "path";
3307
- import { writeFileSync as writeFileSync11, mkdirSync as mkdirSync3 } from "fs";
3621
+ import { join as join20 } from "path";
3622
+ import { writeFileSync as writeFileSync12, mkdirSync as mkdirSync3 } from "fs";
3308
3623
 
3309
3624
  // src/commands/generate/string-utils.ts
3310
3625
  function toPascalCase(str) {
@@ -3333,30 +3648,30 @@ function toSafeSchemaName(str) {
3333
3648
  }
3334
3649
 
3335
3650
  // src/commands/generate/template-loader.ts
3336
- import { readFileSync as readFileSync7, existsSync as existsSync21 } from "fs";
3337
- import { join as join18, dirname as dirname2 } from "path";
3651
+ import { readFileSync as readFileSync8, existsSync as existsSync22 } from "fs";
3652
+ import { join as join19, dirname as dirname2 } from "path";
3338
3653
  import { fileURLToPath as fileURLToPath2 } from "url";
3339
3654
  function findTemplatesPath2() {
3340
3655
  const __filename = fileURLToPath2(import.meta.url);
3341
3656
  const __dirname2 = dirname2(__filename);
3342
- const distPath = join18(__dirname2, "commands", "generate", "templates");
3343
- if (existsSync21(distPath)) {
3657
+ const distPath = join19(__dirname2, "commands", "generate", "templates");
3658
+ if (existsSync22(distPath)) {
3344
3659
  return distPath;
3345
3660
  }
3346
- const sameDirPath = join18(__dirname2, "templates");
3347
- if (existsSync21(sameDirPath)) {
3661
+ const sameDirPath = join19(__dirname2, "templates");
3662
+ if (existsSync22(sameDirPath)) {
3348
3663
  return sameDirPath;
3349
3664
  }
3350
- const srcPath = join18(__dirname2, "..", "..", "src", "commands", "generate", "templates");
3351
- if (existsSync21(srcPath)) {
3665
+ const srcPath = join19(__dirname2, "..", "..", "src", "commands", "generate", "templates");
3666
+ if (existsSync22(srcPath)) {
3352
3667
  return srcPath;
3353
3668
  }
3354
3669
  throw new Error(`Templates directory not found. Tried: ${distPath}, ${sameDirPath}, ${srcPath}`);
3355
3670
  }
3356
3671
  function loadTemplate(templateName, variables) {
3357
3672
  const templatesDir = findTemplatesPath2();
3358
- const templatePath = join18(templatesDir, `${templateName}.template`);
3359
- let content = readFileSync7(templatePath, "utf-8");
3673
+ const templatePath = join19(templatesDir, `${templateName}.template`);
3674
+ let content = readFileSync8(templatePath, "utf-8");
3360
3675
  for (const [key, value] of Object.entries(variables)) {
3361
3676
  const regex = new RegExp(`\\{\\{${key}\\}\\}`, "g");
3362
3677
  content = content.replace(regex, value);
@@ -3458,8 +3773,8 @@ function generatePackageJson(fnDir, scope, fnName, description) {
3458
3773
  vitest: "^4.0.6"
3459
3774
  }
3460
3775
  };
3461
- writeFileSync11(
3462
- join19(fnDir, "package.json"),
3776
+ writeFileSync12(
3777
+ join20(fnDir, "package.json"),
3463
3778
  JSON.stringify(content, null, 4) + "\n"
3464
3779
  );
3465
3780
  }
@@ -3492,8 +3807,8 @@ function generateTsConfig(fnDir) {
3492
3807
  include: ["src/**/*"],
3493
3808
  exclude: ["node_modules", "dist", "**/*.test.ts", "**/__tests__/**"]
3494
3809
  };
3495
- writeFileSync11(
3496
- join19(fnDir, "tsconfig.json"),
3810
+ writeFileSync12(
3811
+ join20(fnDir, "tsconfig.json"),
3497
3812
  JSON.stringify(content, null, 4) + "\n"
3498
3813
  );
3499
3814
  }
@@ -3569,7 +3884,7 @@ export default defineConfig({
3569
3884
  ],
3570
3885
  });
3571
3886
  `;
3572
- writeFileSync11(join19(fnDir, "tsup.config.ts"), content);
3887
+ writeFileSync12(join20(fnDir, "tsup.config.ts"), content);
3573
3888
  }
3574
3889
  function generateDrizzleConfig(fnDir, scope, fnName) {
3575
3890
  const schemaName = `spfn_${toSnakeCase(fnName)}`;
@@ -3589,7 +3904,7 @@ export default defineConfig({
3589
3904
  schemaFilter: ['${schemaName}'], // Only generate for ${fnName} schema
3590
3905
  });
3591
3906
  `;
3592
- writeFileSync11(join19(fnDir, "drizzle.config.ts"), content);
3907
+ writeFileSync12(join20(fnDir, "drizzle.config.ts"), content);
3593
3908
  }
3594
3909
  function generateExampleGenerator(fnDir, scope, fnName) {
3595
3910
  const pascalName = toPascalCase(fnName);
@@ -3658,10 +3973,10 @@ export const moduleName = '${fnName}';
3658
3973
  };
3659
3974
  }
3660
3975
  `;
3661
- const generatorsDir = join19(fnDir, "src/server/generators");
3976
+ const generatorsDir = join20(fnDir, "src/server/generators");
3662
3977
  mkdirSync3(generatorsDir, { recursive: true });
3663
- writeFileSync11(
3664
- join19(generatorsDir, "example-generator.ts"),
3978
+ writeFileSync12(
3979
+ join20(generatorsDir, "example-generator.ts"),
3665
3980
  content
3666
3981
  );
3667
3982
  const indexContent = `/**
@@ -3675,8 +3990,8 @@ export const moduleName = '${fnName}';
3675
3990
 
3676
3991
  export { create${pascalName}ExampleGenerator } from './example-generator.js';
3677
3992
  `;
3678
- writeFileSync11(
3679
- join19(generatorsDir, "index.ts"),
3993
+ writeFileSync12(
3994
+ join20(generatorsDir, "index.ts"),
3680
3995
  indexContent
3681
3996
  );
3682
3997
  }
@@ -4165,15 +4480,15 @@ Contributions are welcome! Please follow the development workflow above.
4165
4480
 
4166
4481
  MIT
4167
4482
  `;
4168
- writeFileSync11(join19(fnDir, "README.md"), content);
4483
+ writeFileSync12(join20(fnDir, "README.md"), content);
4169
4484
  }
4170
4485
 
4171
4486
  // src/commands/generate/generators/entity.ts
4172
- import { join as join20 } from "path";
4173
- import { writeFileSync as writeFileSync12, existsSync as existsSync22 } from "fs";
4487
+ import { join as join21 } from "path";
4488
+ import { writeFileSync as writeFileSync13, existsSync as existsSync23 } from "fs";
4174
4489
  function generateSchema(fnDir, scope, fnName) {
4175
- const schemaFilePath = join20(fnDir, "src/server/entities/schema.ts");
4176
- if (existsSync22(schemaFilePath)) {
4490
+ const schemaFilePath = join21(fnDir, "src/server/entities/schema.ts");
4491
+ if (existsSync23(schemaFilePath)) {
4177
4492
  return;
4178
4493
  }
4179
4494
  const packageName = `${scope}/${fnName}`;
@@ -4184,7 +4499,7 @@ function generateSchema(fnDir, scope, fnName) {
4184
4499
  PACKAGE_NAME: packageName,
4185
4500
  SCHEMA_VAR_NAME: schemaVarName
4186
4501
  });
4187
- writeFileSync12(schemaFilePath, content);
4502
+ writeFileSync13(schemaFilePath, content);
4188
4503
  }
4189
4504
  function generateEntity(fnDir, scope, fnName, entityName) {
4190
4505
  const safeScope = toSafeSchemaName(scope);
@@ -4203,8 +4518,8 @@ function generateEntity(fnDir, scope, fnName, entityName) {
4203
4518
  SCHEMA_VAR_NAME: schemaVarName,
4204
4519
  SCHEMA_FILE_NAME: schemaFileName
4205
4520
  });
4206
- writeFileSync12(
4207
- join20(fnDir, `src/server/entities/${toKebabCase(entityName)}.ts`),
4521
+ writeFileSync13(
4522
+ join21(fnDir, `src/server/entities/${toKebabCase(entityName)}.ts`),
4208
4523
  content
4209
4524
  );
4210
4525
  }
@@ -4212,12 +4527,12 @@ function generateEntitiesIndex(fnDir, entities) {
4212
4527
  const schemaExport = `export * from './schema';`;
4213
4528
  const entityExports = entities.map((entity) => `export * from './${toKebabCase(entity)}';`).join("\n");
4214
4529
  const content = [schemaExport, entityExports].filter(Boolean).join("\n");
4215
- writeFileSync12(join20(fnDir, "src/server/entities/index.ts"), content + "\n");
4530
+ writeFileSync13(join21(fnDir, "src/server/entities/index.ts"), content + "\n");
4216
4531
  }
4217
4532
 
4218
4533
  // src/commands/generate/generators/repository.ts
4219
- import { join as join21 } from "path";
4220
- import { writeFileSync as writeFileSync13 } from "fs";
4534
+ import { join as join22 } from "path";
4535
+ import { writeFileSync as writeFileSync14 } from "fs";
4221
4536
  function generateRepository(fnDir, entityName) {
4222
4537
  const pascalName = toPascalCase(entityName);
4223
4538
  const repoName = `${entityName}Repository`;
@@ -4226,19 +4541,19 @@ function generateRepository(fnDir, entityName) {
4226
4541
  ENTITY_NAME: entityName,
4227
4542
  REPO_NAME: repoName
4228
4543
  });
4229
- writeFileSync13(
4230
- join21(fnDir, `src/server/repositories/${toKebabCase(entityName)}.repository.ts`),
4544
+ writeFileSync14(
4545
+ join22(fnDir, `src/server/repositories/${toKebabCase(entityName)}.repository.ts`),
4231
4546
  content
4232
4547
  );
4233
4548
  }
4234
4549
  function generateRepositoriesIndex(fnDir, entities) {
4235
4550
  const exports = entities.map((entity) => `export * from './${toKebabCase(entity)}.repository';`).join("\n");
4236
- writeFileSync13(join21(fnDir, "src/server/repositories/index.ts"), exports + "\n");
4551
+ writeFileSync14(join22(fnDir, "src/server/repositories/index.ts"), exports + "\n");
4237
4552
  }
4238
4553
 
4239
4554
  // src/commands/generate/generators/route.ts
4240
- import { join as join22 } from "path";
4241
- import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync14 } from "fs";
4555
+ import { join as join23 } from "path";
4556
+ import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync15 } from "fs";
4242
4557
  function generateRoute(fnDir, entityName) {
4243
4558
  const pascalName = toPascalCase(entityName);
4244
4559
  const repoName = `${entityName}Repository`;
@@ -4249,29 +4564,29 @@ function generateRoute(fnDir, entityName) {
4249
4564
  REPO_NAME: repoName,
4250
4565
  KEBAB_NAME: kebabName
4251
4566
  });
4252
- const routeDir = join22(fnDir, `src/server/routes/${kebabName}`);
4567
+ const routeDir = join23(fnDir, `src/server/routes/${kebabName}`);
4253
4568
  mkdirSync4(routeDir, { recursive: true });
4254
- writeFileSync14(join22(routeDir, "index.ts"), content);
4569
+ writeFileSync15(join23(routeDir, "index.ts"), content);
4255
4570
  }
4256
4571
 
4257
4572
  // src/commands/generate/generators/contract.ts
4258
- import { join as join23 } from "path";
4259
- import { writeFileSync as writeFileSync15 } from "fs";
4573
+ import { join as join24 } from "path";
4574
+ import { writeFileSync as writeFileSync16 } from "fs";
4260
4575
  function generateContract(fnDir, entityName) {
4261
4576
  const pascalName = toPascalCase(entityName);
4262
4577
  const content = loadTemplate("contract", {
4263
4578
  PASCAL_NAME: pascalName,
4264
4579
  ENTITY_NAME: entityName
4265
4580
  });
4266
- writeFileSync15(
4267
- join23(fnDir, `src/lib/contracts/${toKebabCase(entityName)}.ts`),
4581
+ writeFileSync16(
4582
+ join24(fnDir, `src/lib/contracts/${toKebabCase(entityName)}.ts`),
4268
4583
  content
4269
4584
  );
4270
4585
  }
4271
4586
 
4272
4587
  // src/commands/generate/generators/index-files.ts
4273
- import { join as join24 } from "path";
4274
- import { writeFileSync as writeFileSync16 } from "fs";
4588
+ import { join as join25 } from "path";
4589
+ import { writeFileSync as writeFileSync17 } from "fs";
4275
4590
  function generateMainIndex(fnDir, fnName) {
4276
4591
  const content = `/**
4277
4592
  * @spfn/${fnName}
@@ -4297,7 +4612,7 @@ export * from '@/lib/types/index';
4297
4612
 
4298
4613
  export * from '@/server/entities/index';
4299
4614
  `;
4300
- writeFileSync16(join24(fnDir, "src/index.ts"), content);
4615
+ writeFileSync17(join25(fnDir, "src/index.ts"), content);
4301
4616
  }
4302
4617
  function generateServerIndex(fnDir) {
4303
4618
  const content = `/**
@@ -4332,7 +4647,7 @@ export * from '@/server/repositories/index';
4332
4647
 
4333
4648
  // TODO: Export helpers here
4334
4649
  `;
4335
- writeFileSync16(join24(fnDir, "src/server.ts"), content);
4650
+ writeFileSync17(join25(fnDir, "src/server.ts"), content);
4336
4651
  }
4337
4652
  function generateClientIndex(fnDir) {
4338
4653
  const content = `/**
@@ -4365,7 +4680,7 @@ export * from './client/store';
4365
4680
 
4366
4681
  export * from './client/components';
4367
4682
  `;
4368
- writeFileSync16(join24(fnDir, "src/client.ts"), content);
4683
+ writeFileSync17(join25(fnDir, "src/client.ts"), content);
4369
4684
  }
4370
4685
  function generateTypesFile(fnDir, fnName) {
4371
4686
  const content = `/**
@@ -4377,7 +4692,7 @@ function generateTypesFile(fnDir, fnName) {
4377
4692
 
4378
4693
  export * from '@/lib/types/index';
4379
4694
  `;
4380
- writeFileSync16(join24(fnDir, "src/types.ts"), content);
4695
+ writeFileSync17(join25(fnDir, "src/types.ts"), content);
4381
4696
  }
4382
4697
 
4383
4698
  // src/commands/generate/generators/structure.ts
@@ -4399,7 +4714,7 @@ async function generateFunctionStructure(options) {
4399
4714
  "src/client/store",
4400
4715
  "src/client/components"
4401
4716
  ];
4402
- dirs.forEach((dir) => mkdirSync5(join25(fnDir, dir), { recursive: true }));
4717
+ dirs.forEach((dir) => mkdirSync5(join26(fnDir, dir), { recursive: true }));
4403
4718
  generatePackageJson(fnDir, scope, fnName, description);
4404
4719
  generateTsConfig(fnDir);
4405
4720
  generateTsupConfig(fnDir);
@@ -4419,15 +4734,15 @@ async function generateFunctionStructure(options) {
4419
4734
  generateEntitiesIndex(fnDir, entities);
4420
4735
  generateRepositoriesIndex(fnDir, entities);
4421
4736
  } else {
4422
- writeFileSync17(join25(fnDir, "src/server/entities/index.ts"), "// Export your entities here\nexport {}\n");
4423
- writeFileSync17(join25(fnDir, "src/server/repositories/index.ts"), "// Export your repositories here\nexport {}\n");
4424
- }
4425
- writeFileSync17(join25(fnDir, "src/client/hooks/index.ts"), "/**\n * Client Hooks\n */\n\n// TODO: Add hooks (e.g., useAuth, useData, etc.)\nexport {}\n");
4426
- writeFileSync17(join25(fnDir, "src/client/store/index.ts"), "/**\n * Client Store\n */\n\n// TODO: Add Zustand store if needed\nexport {}\n");
4427
- writeFileSync17(join25(fnDir, "src/client/components/index.ts"), "/**\n * Client Components\n */\n\n// TODO: Add React components\nexport {}\n");
4428
- writeFileSync17(join25(fnDir, "src/client/index.ts"), "/**\n * Client Module Entry\n */\n\nexport * from './hooks';\nexport * from './store';\nexport * from './components';\n");
4429
- writeFileSync17(join25(fnDir, "src/lib/types/index.ts"), "/**\n * Shared Type Definitions\n */\n\n// Add your shared types here\nexport {}\n");
4430
- writeFileSync17(join25(fnDir, "src/lib/contracts/index.ts"), "/**\n * API Contracts\n */\n\n// Export your contracts here\nexport {}\n");
4737
+ writeFileSync18(join26(fnDir, "src/server/entities/index.ts"), "// Export your entities here\nexport {}\n");
4738
+ writeFileSync18(join26(fnDir, "src/server/repositories/index.ts"), "// Export your repositories here\nexport {}\n");
4739
+ }
4740
+ writeFileSync18(join26(fnDir, "src/client/hooks/index.ts"), "/**\n * Client Hooks\n */\n\n// TODO: Add hooks (e.g., useAuth, useData, etc.)\nexport {}\n");
4741
+ writeFileSync18(join26(fnDir, "src/client/store/index.ts"), "/**\n * Client Store\n */\n\n// TODO: Add Zustand store if needed\nexport {}\n");
4742
+ writeFileSync18(join26(fnDir, "src/client/components/index.ts"), "/**\n * Client Components\n */\n\n// TODO: Add React components\nexport {}\n");
4743
+ writeFileSync18(join26(fnDir, "src/client/index.ts"), "/**\n * Client Module Entry\n */\n\nexport * from './hooks';\nexport * from './store';\nexport * from './components';\n");
4744
+ writeFileSync18(join26(fnDir, "src/lib/types/index.ts"), "/**\n * Shared Type Definitions\n */\n\n// Add your shared types here\nexport {}\n");
4745
+ writeFileSync18(join26(fnDir, "src/lib/contracts/index.ts"), "/**\n * API Contracts\n */\n\n// Export your contracts here\nexport {}\n");
4431
4746
  generateMainIndex(fnDir, fnName);
4432
4747
  generateServerIndex(fnDir);
4433
4748
  generateClientIndex(fnDir);
@@ -4451,8 +4766,8 @@ async function generateFunction(name, options) {
4451
4766
  logger.error("Function name is required");
4452
4767
  process.exit(1);
4453
4768
  }
4454
- const fnDir = join26(cwd, fnName);
4455
- if (existsSync23(fnDir)) {
4769
+ const fnDir = join27(cwd, fnName);
4770
+ if (existsSync24(fnDir)) {
4456
4771
  logger.error(`Directory ${fnName} already exists at ${fnDir}`);
4457
4772
  process.exit(1);
4458
4773
  }
@@ -4497,13 +4812,13 @@ async function generateFunction(name, options) {
4497
4812
  });
4498
4813
  spinner.succeed("Function structure generated");
4499
4814
  console.log("");
4500
- logger.success(`\u2728 Package ${chalk25.cyan(`${scope}/${fnName}`)} created successfully!
4815
+ logger.success(`\u2728 Package ${chalk27.cyan(`${scope}/${fnName}`)} created successfully!
4501
4816
  `);
4502
- logger.info(chalk25.bold("\u{1F4DA} Next steps:"));
4503
- console.log(` ${chalk25.gray("1.")} cd ${fnName}`);
4504
- console.log(` ${chalk25.gray("2.")} pnpm install ${chalk25.dim("(in monorepo root)")}`);
4505
- console.log(` ${chalk25.gray("3.")} pnpm build`);
4506
- console.log(` ${chalk25.gray("4.")} ${chalk25.dim("Use the package in your app")}`);
4817
+ logger.info(chalk27.bold("\u{1F4DA} Next steps:"));
4818
+ console.log(` ${chalk27.gray("1.")} cd ${fnName}`);
4819
+ console.log(` ${chalk27.gray("2.")} pnpm install ${chalk27.dim("(in monorepo root)")}`);
4820
+ console.log(` ${chalk27.gray("3.")} pnpm build`);
4821
+ console.log(` ${chalk27.gray("4.")} ${chalk27.dim("Use the package in your app")}`);
4507
4822
  console.log("");
4508
4823
  } catch (error) {
4509
4824
  spinner.fail("Failed to generate function");
@@ -4516,8 +4831,8 @@ generateCommand.command("fn").description("Generate a new SPFN function module")
4516
4831
 
4517
4832
  // src/commands/env.ts
4518
4833
  import { Command as Command12 } from "commander";
4519
- import chalk26 from "chalk";
4520
- import { existsSync as existsSync24, readFileSync as readFileSync8, writeFileSync as writeFileSync18 } from "fs";
4834
+ import chalk28 from "chalk";
4835
+ import { existsSync as existsSync25, readFileSync as readFileSync9, writeFileSync as writeFileSync19 } from "fs";
4521
4836
  import { resolve } from "path";
4522
4837
  import { parse } from "dotenv";
4523
4838
  var VALID_ENVS = ["local", "development", "staging", "production", "test"];
@@ -4565,26 +4880,26 @@ async function loadEnvSchema(packageName) {
4565
4880
  }
4566
4881
  function formatType(type) {
4567
4882
  const typeColors = {
4568
- string: chalk26.green,
4569
- number: chalk26.blue,
4570
- boolean: chalk26.yellow,
4571
- url: chalk26.cyan,
4572
- enum: chalk26.magenta,
4573
- json: chalk26.red
4883
+ string: chalk28.green,
4884
+ number: chalk28.blue,
4885
+ boolean: chalk28.yellow,
4886
+ url: chalk28.cyan,
4887
+ enum: chalk28.magenta,
4888
+ json: chalk28.red
4574
4889
  };
4575
- return (typeColors[type] || chalk26.white)(type);
4890
+ return (typeColors[type] || chalk28.white)(type);
4576
4891
  }
4577
4892
  function formatDefault(value, type) {
4578
4893
  if (value === void 0) {
4579
- return chalk26.dim("(none)");
4894
+ return chalk28.dim("(none)");
4580
4895
  }
4581
4896
  if (type === "string" || type === "url") {
4582
- return chalk26.green(`"${value}"`);
4897
+ return chalk28.green(`"${value}"`);
4583
4898
  }
4584
4899
  if (type === "boolean") {
4585
- return value ? chalk26.green("true") : chalk26.red("false");
4900
+ return value ? chalk28.green("true") : chalk28.red("false");
4586
4901
  }
4587
- return chalk26.cyan(String(value));
4902
+ return chalk28.cyan(String(value));
4588
4903
  }
4589
4904
  async function listEnvVars(options) {
4590
4905
  const packageName = options.package || "@spfn/core";
@@ -4598,28 +4913,28 @@ async function listEnvVars(options) {
4598
4913
  acc[target].push([key, schema]);
4599
4914
  return acc;
4600
4915
  }, {});
4601
- console.log(chalk26.blue.bold(`
4916
+ console.log(chalk28.blue.bold(`
4602
4917
  \u{1F4CB} Environment Variables by File (${packageName})
4603
4918
  `));
4604
4919
  for (const [file, vars] of Object.entries(grouped)) {
4605
- console.log(chalk26.bold.magenta(`
4920
+ console.log(chalk28.bold.magenta(`
4606
4921
  ${file}`));
4607
- console.log(chalk26.dim("\u2500".repeat(50)));
4922
+ console.log(chalk28.dim("\u2500".repeat(50)));
4608
4923
  for (const [key, schema] of vars) {
4609
4924
  printEnvVar(key, schema);
4610
4925
  }
4611
4926
  }
4612
4927
  } else {
4613
- console.log(chalk26.blue.bold(`
4928
+ console.log(chalk28.blue.bold(`
4614
4929
  \u{1F4CB} Environment Variables (${packageName})
4615
4930
  `));
4616
4931
  for (const [key, schema] of allVars) {
4617
4932
  printEnvVar(key, schema, true);
4618
4933
  }
4619
4934
  }
4620
- console.log(chalk26.dim("\n\u{1F4A1} Tip: Use `spfn env init` to generate .env template files\n"));
4935
+ console.log(chalk28.dim("\n\u{1F4A1} Tip: Use `spfn env init` to generate .env template files\n"));
4621
4936
  } catch (error) {
4622
- console.error(chalk26.red(`
4937
+ console.error(chalk28.red(`
4623
4938
  \u274C ${error instanceof Error ? error.message : "Unknown error"}
4624
4939
  `));
4625
4940
  process.exit(1);
@@ -4627,17 +4942,17 @@ ${file}`));
4627
4942
  }
4628
4943
  function printEnvVar(key, schema, showFile = false) {
4629
4944
  const typeStr = formatType(schema.type);
4630
- const requiredStr = schema.required || schema.default !== void 0 ? chalk26.red("[required]") : chalk26.dim("[optional]");
4631
- const sensitiveStr = schema.sensitive ? chalk26.yellow(" [sensitive]") : "";
4632
- const fileStr = showFile ? chalk26.dim(` \u2192 ${getTargetFile(schema)}`) : "";
4633
- console.log(`${chalk26.bold.cyan(key)} ${chalk26.dim("(")}${typeStr}${chalk26.dim(")")} ${requiredStr}${sensitiveStr}${fileStr}`);
4634
- console.log(` ${chalk26.dim(schema.description)}`);
4945
+ const requiredStr = schema.required || schema.default !== void 0 ? chalk28.red("[required]") : chalk28.dim("[optional]");
4946
+ const sensitiveStr = schema.sensitive ? chalk28.yellow(" [sensitive]") : "";
4947
+ const fileStr = showFile ? chalk28.dim(` \u2192 ${getTargetFile(schema)}`) : "";
4948
+ console.log(`${chalk28.bold.cyan(key)} ${chalk28.dim("(")}${typeStr}${chalk28.dim(")")} ${requiredStr}${sensitiveStr}${fileStr}`);
4949
+ console.log(` ${chalk28.dim(schema.description)}`);
4635
4950
  if (schema.default !== void 0) {
4636
- console.log(` ${chalk26.dim("Default:")} ${formatDefault(schema.default, schema.type)}`);
4951
+ console.log(` ${chalk28.dim("Default:")} ${formatDefault(schema.default, schema.type)}`);
4637
4952
  }
4638
4953
  if (schema.examples && schema.examples.length > 0) {
4639
4954
  const exampleStr = schema.examples.map((ex) => formatDefault(ex, schema.type)).join(", ");
4640
- console.log(` ${chalk26.dim("Examples:")} ${exampleStr}`);
4955
+ console.log(` ${chalk28.dim("Examples:")} ${exampleStr}`);
4641
4956
  }
4642
4957
  console.log();
4643
4958
  }
@@ -4645,7 +4960,7 @@ async function showEnvStats(options) {
4645
4960
  const packageName = options.package || "@spfn/core";
4646
4961
  try {
4647
4962
  const envSchema = await loadEnvSchema(packageName);
4648
- console.log(chalk26.blue.bold(`
4963
+ console.log(chalk28.blue.bold(`
4649
4964
  \u{1F4CA} Environment Variable Statistics (${packageName})
4650
4965
  `));
4651
4966
  const allVars = Object.entries(envSchema);
@@ -4667,24 +4982,24 @@ async function showEnvStats(options) {
4667
4982
  acc[file] = (acc[file] || 0) + 1;
4668
4983
  return acc;
4669
4984
  }, {});
4670
- console.log(`${chalk26.bold("Total variables:")} ${chalk26.cyan(allVars.length)}`);
4671
- console.log(`${chalk26.bold("Required:")} ${chalk26.red(required.length)}`);
4672
- console.log(`${chalk26.bold("Optional:")} ${chalk26.dim(optional.length)}`);
4673
- console.log(`${chalk26.bold("Sensitive:")} ${chalk26.yellow(sensitive.length)}`);
4674
- console.log(chalk26.bold("\nBy Target:"));
4675
- console.log(` ${chalk26.blue("Next.js accessible:")} ${chalk26.cyan(nextjsVars.length)}`);
4676
- console.log(` ${chalk26.magenta("SPFN server only:")} ${chalk26.cyan(serverOnlyVars.length)}`);
4677
- console.log(chalk26.bold("\nBy File:"));
4985
+ console.log(`${chalk28.bold("Total variables:")} ${chalk28.cyan(allVars.length)}`);
4986
+ console.log(`${chalk28.bold("Required:")} ${chalk28.red(required.length)}`);
4987
+ console.log(`${chalk28.bold("Optional:")} ${chalk28.dim(optional.length)}`);
4988
+ console.log(`${chalk28.bold("Sensitive:")} ${chalk28.yellow(sensitive.length)}`);
4989
+ console.log(chalk28.bold("\nBy Target:"));
4990
+ console.log(` ${chalk28.blue("Next.js accessible:")} ${chalk28.cyan(nextjsVars.length)}`);
4991
+ console.log(` ${chalk28.magenta("SPFN server only:")} ${chalk28.cyan(serverOnlyVars.length)}`);
4992
+ console.log(chalk28.bold("\nBy File:"));
4678
4993
  for (const [file, count] of Object.entries(fileCount)) {
4679
- console.log(` ${chalk26.dim(file)}: ${chalk26.cyan(count)}`);
4994
+ console.log(` ${chalk28.dim(file)}: ${chalk28.cyan(count)}`);
4680
4995
  }
4681
- console.log(chalk26.bold("\nBy Type:"));
4996
+ console.log(chalk28.bold("\nBy Type:"));
4682
4997
  for (const [type, count] of Object.entries(typeCount)) {
4683
- console.log(` ${formatType(type)}: ${chalk26.cyan(count)}`);
4998
+ console.log(` ${formatType(type)}: ${chalk28.cyan(count)}`);
4684
4999
  }
4685
5000
  console.log();
4686
5001
  } catch (error) {
4687
- console.error(chalk26.red(`
5002
+ console.error(chalk28.red(`
4688
5003
  \u274C ${error instanceof Error ? error.message : "Unknown error"}
4689
5004
  `));
4690
5005
  process.exit(1);
@@ -4704,26 +5019,26 @@ async function searchEnvVars(query, options) {
4704
5019
  }
4705
5020
  }
4706
5021
  if (results.length === 0) {
4707
- console.log(chalk26.yellow(`
5022
+ console.log(chalk28.yellow(`
4708
5023
  \u26A0\uFE0F No environment variables found matching "${query}"
4709
5024
  `));
4710
5025
  return;
4711
5026
  }
4712
- console.log(chalk26.blue.bold(`
5027
+ console.log(chalk28.blue.bold(`
4713
5028
  \u{1F50D} Found ${results.length} environment variable(s) matching "${query}"
4714
5029
  `));
4715
5030
  for (const [key, schema] of results) {
4716
5031
  const typeStr = formatType(schema.type);
4717
- const requiredStr = schema.required || schema.default !== void 0 ? chalk26.red("[required]") : chalk26.dim("[optional]");
4718
- console.log(`${chalk26.bold.cyan(key)} ${chalk26.dim("(")}${typeStr}${chalk26.dim(")")} ${requiredStr}`);
4719
- console.log(` ${chalk26.dim(schema.description)}`);
5032
+ const requiredStr = schema.required || schema.default !== void 0 ? chalk28.red("[required]") : chalk28.dim("[optional]");
5033
+ console.log(`${chalk28.bold.cyan(key)} ${chalk28.dim("(")}${typeStr}${chalk28.dim(")")} ${requiredStr}`);
5034
+ console.log(` ${chalk28.dim(schema.description)}`);
4720
5035
  if (schema.default !== void 0) {
4721
- console.log(` ${chalk26.dim("Default:")} ${formatDefault(schema.default, schema.type)}`);
5036
+ console.log(` ${chalk28.dim("Default:")} ${formatDefault(schema.default, schema.type)}`);
4722
5037
  }
4723
5038
  console.log();
4724
5039
  }
4725
5040
  } catch (error) {
4726
- console.error(chalk26.red(`
5041
+ console.error(chalk28.red(`
4727
5042
  \u274C ${error instanceof Error ? error.message : "Unknown error"}
4728
5043
  `));
4729
5044
  process.exit(1);
@@ -4735,9 +5050,9 @@ envCommand.command("stats").description("Show environment variable statistics").
4735
5050
  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);
4736
5051
  function validateEnvOption(envValue) {
4737
5052
  if (!VALID_ENVS.includes(envValue)) {
4738
- console.error(chalk26.red(`
5053
+ console.error(chalk28.red(`
4739
5054
  \u274C Invalid environment: "${envValue}"`));
4740
- console.log(chalk26.dim(` Valid values: ${VALID_ENVS.join(", ")}
5055
+ console.log(chalk28.dim(` Valid values: ${VALID_ENVS.join(", ")}
4741
5056
  `));
4742
5057
  process.exit(1);
4743
5058
  }
@@ -4758,8 +5073,8 @@ async function initEnvFiles(options) {
4758
5073
  return acc;
4759
5074
  }, {});
4760
5075
  if (targetEnv) {
4761
- console.log(chalk26.blue.bold(`
4762
- \u{1F680} Generating .env template files for ${chalk26.cyan(targetEnv)} environment
5076
+ console.log(chalk28.blue.bold(`
5077
+ \u{1F680} Generating .env template files for ${chalk28.cyan(targetEnv)} environment
4763
5078
  `));
4764
5079
  const envSpecificFiles = {};
4765
5080
  const committedVars = allVars.filter(([_, schema]) => !schema.sensitive);
@@ -4775,25 +5090,25 @@ async function initEnvFiles(options) {
4775
5090
  writeEnvTemplate(cwd, file, vars, options.force ?? false);
4776
5091
  }
4777
5092
  } else {
4778
- console.log(chalk26.blue.bold(`
5093
+ console.log(chalk28.blue.bold(`
4779
5094
  \u{1F680} Generating .env template files
4780
5095
  `));
4781
5096
  for (const [file, vars] of Object.entries(grouped)) {
4782
5097
  writeEnvTemplate(cwd, file, vars, options.force ?? false);
4783
5098
  }
4784
5099
  }
4785
- console.log(chalk26.dim("\n\u{1F4A1} Copy .example files to create your actual .env files:"));
4786
- console.log(chalk26.dim(" cp .env.example .env"));
4787
- console.log(chalk26.dim(" cp .env.local.example .env.local"));
4788
- console.log(chalk26.dim(" cp .env.server.example .env.server"));
4789
- console.log(chalk26.dim(" cp .env.server.local.example .env.server.local"));
5100
+ console.log(chalk28.dim("\n\u{1F4A1} Copy .example files to create your actual .env files:"));
5101
+ console.log(chalk28.dim(" cp .env.example .env"));
5102
+ console.log(chalk28.dim(" cp .env.local.example .env.local"));
5103
+ console.log(chalk28.dim(" cp .env.server.example .env.server"));
5104
+ console.log(chalk28.dim(" cp .env.server.local.example .env.server.local"));
4790
5105
  if (targetEnv) {
4791
- console.log(chalk26.dim(` cp .env.${targetEnv}.example .env.${targetEnv}`));
4792
- console.log(chalk26.dim(` cp .env.${targetEnv}.local.example .env.${targetEnv}.local`));
5106
+ console.log(chalk28.dim(` cp .env.${targetEnv}.example .env.${targetEnv}`));
5107
+ console.log(chalk28.dim(` cp .env.${targetEnv}.local.example .env.${targetEnv}.local`));
4793
5108
  }
4794
5109
  console.log("");
4795
5110
  } catch (error) {
4796
- console.error(chalk26.red(`
5111
+ console.error(chalk28.red(`
4797
5112
  \u274C ${error instanceof Error ? error.message : "Unknown error"}
4798
5113
  `));
4799
5114
  process.exit(1);
@@ -4801,12 +5116,12 @@ async function initEnvFiles(options) {
4801
5116
  }
4802
5117
  function writeEnvTemplate(cwd, file, vars, force) {
4803
5118
  const filePath = resolve(cwd, file);
4804
- if (existsSync24(filePath) && !force) {
4805
- console.log(chalk26.yellow(` \u23ED\uFE0F ${file} already exists (use --force to overwrite)`));
5119
+ if (existsSync25(filePath) && !force) {
5120
+ console.log(chalk28.yellow(` \u23ED\uFE0F ${file} already exists (use --force to overwrite)`));
4806
5121
  return;
4807
5122
  }
4808
- writeFileSync18(filePath, generateEnvFileContent(vars), "utf-8");
4809
- console.log(chalk26.green(` \u2705 ${file} (${vars.length} variables)`));
5123
+ writeFileSync19(filePath, generateEnvFileContent(vars), "utf-8");
5124
+ console.log(chalk28.green(` \u2705 ${file} (${vars.length} variables)`));
4810
5125
  }
4811
5126
  function generateEnvFileContent(vars) {
4812
5127
  const lines = [
@@ -4841,7 +5156,7 @@ async function checkEnvFiles(options) {
4841
5156
  const envSchema = await loadEnvSchema(packageName);
4842
5157
  const allVars = Object.entries(envSchema);
4843
5158
  const envLabel = targetEnv ? ` (${targetEnv})` : "";
4844
- console.log(chalk26.blue.bold(`
5159
+ console.log(chalk28.blue.bold(`
4845
5160
  \u{1F50D} Checking .env files against schema${envLabel}
4846
5161
  `));
4847
5162
  const filesToCheck = targetEnv ? getEnvFilesForEnvironment(targetEnv) : [...BASE_ENV_FILES.nextjs, ...BASE_ENV_FILES.server];
@@ -4850,15 +5165,15 @@ async function checkEnvFiles(options) {
4850
5165
  const warnings = [];
4851
5166
  for (const file of filesToCheck) {
4852
5167
  const filePath = resolve(cwd, file);
4853
- if (!existsSync24(filePath)) {
5168
+ if (!existsSync25(filePath)) {
4854
5169
  continue;
4855
5170
  }
4856
- const content = readFileSync8(filePath, "utf-8");
5171
+ const content = readFileSync9(filePath, "utf-8");
4857
5172
  const parsed = parse(content);
4858
5173
  for (const [key, value] of Object.entries(parsed)) {
4859
5174
  loadedEnv[key] = { value: value || "", file };
4860
5175
  }
4861
- console.log(chalk26.dim(` \u{1F4C4} ${file} loaded`));
5176
+ console.log(chalk28.dim(` \u{1F4C4} ${file} loaded`));
4862
5177
  }
4863
5178
  console.log("");
4864
5179
  for (const [key, schema] of allVars) {
@@ -4866,7 +5181,7 @@ async function checkEnvFiles(options) {
4866
5181
  const found = loadedEnv[key];
4867
5182
  if (!found) {
4868
5183
  if (schema.required && schema.default === void 0) {
4869
- issues.push(`${chalk26.red("\u2717")} ${chalk26.cyan(key)} is required but not found in any .env file`);
5184
+ issues.push(`${chalk28.red("\u2717")} ${chalk28.cyan(key)} is required but not found in any .env file`);
4870
5185
  }
4871
5186
  continue;
4872
5187
  }
@@ -4876,11 +5191,11 @@ async function checkEnvFiles(options) {
4876
5191
  if (!shouldBeNextjs && isNextjsFile && !isServerFile) {
4877
5192
  if (schema.sensitive) {
4878
5193
  issues.push(
4879
- `${chalk26.red("\u2717")} ${chalk26.cyan(key)} is sensitive and should be in ${chalk26.magenta(expectedFile)}, but found in ${chalk26.yellow(found.file)} (security risk!)`
5194
+ `${chalk28.red("\u2717")} ${chalk28.cyan(key)} is sensitive and should be in ${chalk28.magenta(expectedFile)}, but found in ${chalk28.yellow(found.file)} (security risk!)`
4880
5195
  );
4881
5196
  } else {
4882
5197
  warnings.push(
4883
- `${chalk26.yellow("\u26A0")} ${chalk26.cyan(key)} should be in ${chalk26.magenta(expectedFile)}, but found in ${chalk26.dim(found.file)}`
5198
+ `${chalk28.yellow("\u26A0")} ${chalk28.cyan(key)} should be in ${chalk28.magenta(expectedFile)}, but found in ${chalk28.dim(found.file)}`
4884
5199
  );
4885
5200
  }
4886
5201
  }
@@ -4888,34 +5203,34 @@ async function checkEnvFiles(options) {
4888
5203
  for (const [key, { file }] of Object.entries(loadedEnv)) {
4889
5204
  const inSchema = allVars.some(([k]) => k === key);
4890
5205
  if (!inSchema) {
4891
- warnings.push(`${chalk26.yellow("\u26A0")} ${chalk26.cyan(key)} in ${chalk26.dim(file)} is not in schema`);
5206
+ warnings.push(`${chalk28.yellow("\u26A0")} ${chalk28.cyan(key)} in ${chalk28.dim(file)} is not in schema`);
4892
5207
  }
4893
5208
  }
4894
5209
  if (issues.length > 0) {
4895
- console.log(chalk26.red.bold("Issues:"));
5210
+ console.log(chalk28.red.bold("Issues:"));
4896
5211
  for (const issue of issues) {
4897
5212
  console.log(` ${issue}`);
4898
5213
  }
4899
5214
  console.log("");
4900
5215
  }
4901
5216
  if (warnings.length > 0) {
4902
- console.log(chalk26.yellow.bold("Warnings:"));
5217
+ console.log(chalk28.yellow.bold("Warnings:"));
4903
5218
  for (const warning of warnings) {
4904
5219
  console.log(` ${warning}`);
4905
5220
  }
4906
5221
  console.log("");
4907
5222
  }
4908
5223
  if (issues.length === 0 && warnings.length === 0) {
4909
- console.log(chalk26.green("\u2705 All environment variables are correctly configured!\n"));
5224
+ console.log(chalk28.green("\u2705 All environment variables are correctly configured!\n"));
4910
5225
  } else {
4911
- console.log(chalk26.dim(`Found ${issues.length} issue(s) and ${warnings.length} warning(s)
5226
+ console.log(chalk28.dim(`Found ${issues.length} issue(s) and ${warnings.length} warning(s)
4912
5227
  `));
4913
5228
  if (issues.length > 0) {
4914
5229
  process.exit(1);
4915
5230
  }
4916
5231
  }
4917
5232
  } catch (error) {
4918
- console.error(chalk26.red(`
5233
+ console.error(chalk28.red(`
4919
5234
  \u274C ${error instanceof Error ? error.message : "Unknown error"}
4920
5235
  `));
4921
5236
  process.exit(1);
@@ -4927,17 +5242,17 @@ async function validateEnvVars(options) {
4927
5242
  const packages = options.packages || ["@spfn/core"];
4928
5243
  const targetEnv = options.env ? validateEnvOption(options.env) : void 0;
4929
5244
  if (targetEnv) {
4930
- const { loadEnv: loadEnv6 } = await import("@spfn/core/env/loader");
4931
- const result = loadEnv6({ nodeEnv: targetEnv });
4932
- console.log(chalk26.blue.bold(`
4933
- \u{1F50D} Validating environment variables for ${chalk26.cyan(targetEnv)}
5245
+ const { loadEnv: loadEnv8 } = await import("@spfn/core/env/loader");
5246
+ const result = loadEnv8({ nodeEnv: targetEnv });
5247
+ console.log(chalk28.blue.bold(`
5248
+ \u{1F50D} Validating environment variables for ${chalk28.cyan(targetEnv)}
4934
5249
  `));
4935
5250
  if (result.loadedFiles.length > 0) {
4936
- console.log(chalk26.dim(` Loaded: ${result.loadedFiles.join(", ")}`));
5251
+ console.log(chalk28.dim(` Loaded: ${result.loadedFiles.join(", ")}`));
4937
5252
  }
4938
5253
  console.log("");
4939
5254
  } else {
4940
- console.log(chalk26.blue.bold(`
5255
+ console.log(chalk28.blue.bold(`
4941
5256
  \u{1F50D} Validating environment variables
4942
5257
  `));
4943
5258
  }
@@ -4945,7 +5260,7 @@ async function validateEnvVars(options) {
4945
5260
  const allWarnings = [];
4946
5261
  for (const packageName of packages) {
4947
5262
  try {
4948
- console.log(chalk26.dim(` \u{1F4E6} ${packageName}`));
5263
+ console.log(chalk28.dim(` \u{1F4E6} ${packageName}`));
4949
5264
  const envSchema = await loadEnvSchema(packageName);
4950
5265
  const { createEnvRegistry } = await import("@spfn/core/env");
4951
5266
  const registry = createEnvRegistry(envSchema);
@@ -4958,10 +5273,10 @@ async function validateEnvVars(options) {
4958
5273
  }
4959
5274
  } catch (error) {
4960
5275
  if (error instanceof Error && error.message.includes("does not export envSchema")) {
4961
- console.log(chalk26.dim(` \u23ED\uFE0F No envSchema exported, skipping`));
5276
+ console.log(chalk28.dim(` \u23ED\uFE0F No envSchema exported, skipping`));
4962
5277
  continue;
4963
5278
  }
4964
- console.error(chalk26.red(` \u274C Failed to load: ${error instanceof Error ? error.message : String(error)}`));
5279
+ console.error(chalk28.red(` \u274C Failed to load: ${error instanceof Error ? error.message : String(error)}`));
4965
5280
  if (options.strict) {
4966
5281
  process.exit(1);
4967
5282
  }
@@ -4969,32 +5284,32 @@ async function validateEnvVars(options) {
4969
5284
  }
4970
5285
  console.log("");
4971
5286
  if (allErrors.length > 0) {
4972
- console.log(chalk26.red.bold(`\u274C Validation Errors (${allErrors.length}):
5287
+ console.log(chalk28.red.bold(`\u274C Validation Errors (${allErrors.length}):
4973
5288
  `));
4974
5289
  for (const error of allErrors) {
4975
- console.log(` ${chalk26.red("\u2717")} ${chalk26.cyan(error.key)}`);
4976
- console.log(` ${chalk26.dim(error.message)}`);
4977
- console.log(` ${chalk26.dim(`from ${error.package}`)}`);
5290
+ console.log(` ${chalk28.red("\u2717")} ${chalk28.cyan(error.key)}`);
5291
+ console.log(` ${chalk28.dim(error.message)}`);
5292
+ console.log(` ${chalk28.dim(`from ${error.package}`)}`);
4978
5293
  console.log("");
4979
5294
  }
4980
5295
  }
4981
5296
  if (allWarnings.length > 0) {
4982
- console.log(chalk26.yellow.bold(`\u26A0\uFE0F Warnings (${allWarnings.length}):
5297
+ console.log(chalk28.yellow.bold(`\u26A0\uFE0F Warnings (${allWarnings.length}):
4983
5298
  `));
4984
5299
  for (const warning of allWarnings) {
4985
- console.log(` ${chalk26.yellow("\u26A0")} ${chalk26.cyan(warning.key)}`);
4986
- console.log(` ${chalk26.dim(warning.message)}`);
5300
+ console.log(` ${chalk28.yellow("\u26A0")} ${chalk28.cyan(warning.key)}`);
5301
+ console.log(` ${chalk28.dim(warning.message)}`);
4987
5302
  console.log("");
4988
5303
  }
4989
5304
  }
4990
5305
  if (allErrors.length === 0 && allWarnings.length === 0) {
4991
- console.log(chalk26.green.bold("\u2705 All environment variables are valid!\n"));
5306
+ console.log(chalk28.green.bold("\u2705 All environment variables are valid!\n"));
4992
5307
  } else if (allErrors.length === 0) {
4993
- console.log(chalk26.green("\u2705 No errors found."));
4994
- console.log(chalk26.yellow(`\u26A0\uFE0F ${allWarnings.length} warning(s) found.
5308
+ console.log(chalk28.green("\u2705 No errors found."));
5309
+ console.log(chalk28.yellow(`\u26A0\uFE0F ${allWarnings.length} warning(s) found.
4995
5310
  `));
4996
5311
  } else {
4997
- console.log(chalk26.red(`
5312
+ console.log(chalk28.red(`
4998
5313
  \u274C Validation failed with ${allErrors.length} error(s)
4999
5314
  `));
5000
5315
  process.exit(1);