spfn 0.2.0-beta.60 → 0.2.0-beta.61

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 +705 -555
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -869,7 +869,7 @@ var init_deployment_config = __esm({
869
869
 
870
870
  // src/utils/version.ts
871
871
  function getCliVersion() {
872
- return "0.2.0-beta.60";
872
+ return "0.2.0-beta.61";
873
873
  }
874
874
  function getTagFromVersion(version) {
875
875
  const match = version.match(/-([a-z]+)\./i);
@@ -1342,39 +1342,39 @@ __export(function_migrations_exports, {
1342
1342
  loadFunctionMigrationPlans: () => loadFunctionMigrationPlans,
1343
1343
  readMigrationEntries: () => readMigrationEntries
1344
1344
  });
1345
- import chalk13 from "chalk";
1345
+ import chalk6 from "chalk";
1346
1346
  import { createHash } from "crypto";
1347
- import { join as join19 } from "path";
1348
- import { env as env2 } from "@spfn/core/config";
1349
- import { loadEnv as loadEnv2 } from "@spfn/core/server";
1350
- import { existsSync as existsSync19, readdirSync as readdirSync2, readFileSync as readFileSync9 } from "fs";
1347
+ import { join as join15 } from "path";
1348
+ import { env } from "@spfn/core/config";
1349
+ import { loadEnv } from "@spfn/core/server";
1350
+ import { existsSync as existsSync14, readdirSync, readFileSync as readFileSync7 } from "fs";
1351
1351
  function discoverFunctionMigrations(cwd = process.cwd()) {
1352
- const nodeModulesPath = join19(cwd, "node_modules");
1353
- if (!existsSync19(nodeModulesPath)) {
1352
+ const nodeModulesPath = join15(cwd, "node_modules");
1353
+ if (!existsSync14(nodeModulesPath)) {
1354
1354
  return [];
1355
1355
  }
1356
1356
  const functions = [];
1357
- const spfnDir = join19(nodeModulesPath, "@spfn");
1358
- if (!existsSync19(spfnDir)) {
1357
+ const spfnDir = join15(nodeModulesPath, "@spfn");
1358
+ if (!existsSync14(spfnDir)) {
1359
1359
  return [];
1360
1360
  }
1361
- const packages = readdirSync2(spfnDir);
1361
+ const packages = readdirSync(spfnDir);
1362
1362
  for (const pkg of packages) {
1363
- const packagePath = join19(spfnDir, pkg);
1364
- const packageJsonPath = join19(packagePath, "package.json");
1365
- if (!existsSync19(packageJsonPath)) {
1363
+ const packagePath = join15(spfnDir, pkg);
1364
+ const packageJsonPath = join15(packagePath, "package.json");
1365
+ if (!existsSync14(packageJsonPath)) {
1366
1366
  continue;
1367
1367
  }
1368
1368
  try {
1369
- const packageJson = JSON.parse(readFileSync9(packageJsonPath, "utf-8"));
1369
+ const packageJson = JSON.parse(readFileSync7(packageJsonPath, "utf-8"));
1370
1370
  const spfnConfig = packageJson.spfn;
1371
1371
  if (!spfnConfig?.migrations) {
1372
1372
  continue;
1373
1373
  }
1374
- const migrationsDir = join19(packagePath, spfnConfig.migrations.dir);
1375
- if (!existsSync19(migrationsDir)) {
1374
+ const migrationsDir = join15(packagePath, spfnConfig.migrations.dir);
1375
+ if (!existsSync14(migrationsDir)) {
1376
1376
  console.warn(
1377
- chalk13.yellow(`\u26A0\uFE0F Package @spfn/${pkg} specifies migrations but directory not found: ${migrationsDir}`)
1377
+ chalk6.yellow(`\u26A0\uFE0F Package @spfn/${pkg} specifies migrations but directory not found: ${migrationsDir}`)
1378
1378
  );
1379
1379
  continue;
1380
1380
  }
@@ -1384,14 +1384,14 @@ function discoverFunctionMigrations(cwd = process.cwd()) {
1384
1384
  packagePath
1385
1385
  });
1386
1386
  } catch (error) {
1387
- console.warn(chalk13.yellow(`\u26A0\uFE0F Failed to parse package.json for @spfn/${pkg}`));
1387
+ console.warn(chalk6.yellow(`\u26A0\uFE0F Failed to parse package.json for @spfn/${pkg}`));
1388
1388
  }
1389
1389
  }
1390
1390
  return functions;
1391
1391
  }
1392
1392
  function readMigrationEntries(migrationsDir, packageName) {
1393
- const journalPath = join19(migrationsDir, "meta", "_journal.json");
1394
- return existsSync19(journalPath) ? readJournalEntries(migrationsDir, journalPath, packageName) : readFolderEntries(migrationsDir, packageName);
1393
+ const journalPath = join15(migrationsDir, "meta", "_journal.json");
1394
+ return existsSync14(journalPath) ? readJournalEntries(migrationsDir, journalPath, packageName) : readFolderEntries(migrationsDir, packageName);
1395
1395
  }
1396
1396
  function loadFunctionMigrationPlans(functionMigrations) {
1397
1397
  return functionMigrations.map((func) => ({
@@ -1402,7 +1402,7 @@ function loadFunctionMigrationPlans(functionMigrations) {
1402
1402
  function readJournalEntries(migrationsDir, journalPath, packageName) {
1403
1403
  let journal;
1404
1404
  try {
1405
- journal = JSON.parse(readFileSync9(journalPath, "utf-8"));
1405
+ journal = JSON.parse(readFileSync7(journalPath, "utf-8"));
1406
1406
  } catch {
1407
1407
  journal = {};
1408
1408
  }
@@ -1415,18 +1415,18 @@ function readJournalEntries(migrationsDir, journalPath, packageName) {
1415
1415
  if (typeof entry?.tag !== "string" || typeof entry?.when !== "number") {
1416
1416
  throw new Error(`${packageName}: invalid journal entry in ${journalPath}`);
1417
1417
  }
1418
- const sqlPath = join19(migrationsDir, `${entry.tag}.sql`);
1419
- if (!existsSync19(sqlPath)) {
1418
+ const sqlPath = join15(migrationsDir, `${entry.tag}.sql`);
1419
+ if (!existsSync14(sqlPath)) {
1420
1420
  throw new Error(`${packageName}: migration file not found: ${entry.tag}.sql`);
1421
1421
  }
1422
- return toEntry(entry.tag, readFileSync9(sqlPath, "utf-8"), entry.when);
1422
+ return toEntry(entry.tag, readFileSync7(sqlPath, "utf-8"), entry.when);
1423
1423
  });
1424
1424
  }
1425
1425
  function readFolderEntries(migrationsDir, packageName) {
1426
- const folders = readdirSync2(migrationsDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name).filter((name) => existsSync19(join19(migrationsDir, name, "migration.sql"))).sort((a, b) => a.localeCompare(b));
1426
+ const folders = readdirSync(migrationsDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name).filter((name) => existsSync14(join15(migrationsDir, name, "migration.sql"))).sort((a, b) => a.localeCompare(b));
1427
1427
  return folders.map((name) => toEntry(
1428
1428
  name,
1429
- readFileSync9(join19(migrationsDir, name, "migration.sql"), "utf-8"),
1429
+ readFileSync7(join15(migrationsDir, name, "migration.sql"), "utf-8"),
1430
1430
  folderTimestampMillis(name, packageName)
1431
1431
  ));
1432
1432
  }
@@ -1466,7 +1466,7 @@ async function migrateLegacyTable(db, plans) {
1466
1466
  if (!legacyCheck[0]?.exists) {
1467
1467
  return;
1468
1468
  }
1469
- console.log(chalk13.dim("\n Migrating legacy shared migration table to per-package tables..."));
1469
+ console.log(chalk6.dim("\n Migrating legacy shared migration table to per-package tables..."));
1470
1470
  const legacyRows = await db.query(
1471
1471
  `SELECT hash, created_at FROM drizzle."__spfn_fn_migrations" ORDER BY id`
1472
1472
  );
@@ -1496,11 +1496,11 @@ async function migrateLegacyTable(db, plans) {
1496
1496
  copied++;
1497
1497
  }
1498
1498
  if (copied > 0) {
1499
- console.log(chalk13.dim(` \u2713 ${plan.packageName}: copied ${copied} migration record(s)`));
1499
+ console.log(chalk6.dim(` \u2713 ${plan.packageName}: copied ${copied} migration record(s)`));
1500
1500
  }
1501
1501
  }
1502
1502
  await db.query(`DROP TABLE drizzle."__spfn_fn_migrations"`);
1503
- console.log(chalk13.dim(" \u2713 Legacy migration table removed\n"));
1503
+ console.log(chalk6.dim(" \u2713 Legacy migration table removed\n"));
1504
1504
  }
1505
1505
  async function ensureMigrationsTable(db, tableName) {
1506
1506
  await db.query(`CREATE SCHEMA IF NOT EXISTS drizzle`);
@@ -1544,20 +1544,20 @@ function createPostgresJsMigrationDb(client) {
1544
1544
  }
1545
1545
  async function executeFunctionMigrations(plans) {
1546
1546
  const postgres = await import("postgres");
1547
- loadEnv2();
1548
- if (!env2.DATABASE_URL) {
1547
+ loadEnv();
1548
+ if (!env.DATABASE_URL) {
1549
1549
  throw new Error("DATABASE_URL not found in environment");
1550
1550
  }
1551
- const connection = postgres.default(env2.DATABASE_URL, { max: 1 });
1551
+ const connection = postgres.default(env.DATABASE_URL, { max: 1 });
1552
1552
  const db = createPostgresJsMigrationDb(connection);
1553
1553
  let appliedCount = 0;
1554
1554
  try {
1555
1555
  await migrateLegacyTable(db, plans);
1556
1556
  for (const plan of plans) {
1557
- console.log(chalk13.blue(`
1557
+ console.log(chalk6.blue(`
1558
1558
  \u{1F4E6} Running ${plan.packageName} migrations...`));
1559
1559
  const applied = await applyFunctionMigrationPlan(db, plan);
1560
- console.log(applied > 0 ? chalk13.green(` \u2713 ${plan.packageName}: ${applied} migration(s) applied`) : chalk13.dim(` \u2013 ${plan.packageName}: up to date`));
1560
+ console.log(applied > 0 ? chalk6.green(` \u2713 ${plan.packageName}: ${applied} migration(s) applied`) : chalk6.dim(` \u2013 ${plan.packageName}: up to date`));
1561
1561
  appliedCount += applied;
1562
1562
  }
1563
1563
  } finally {
@@ -1571,6 +1571,112 @@ var init_function_migrations = __esm({
1571
1571
  }
1572
1572
  });
1573
1573
 
1574
+ // src/utils/migration-status.ts
1575
+ var migration_status_exports = {};
1576
+ __export(migration_status_exports, {
1577
+ filterPendingEntries: () => filterPendingEntries,
1578
+ functionMigrationsTable: () => functionMigrationsTable2,
1579
+ getMigrationStatus: () => getMigrationStatus,
1580
+ warnPendingMigrations: () => warnPendingMigrations
1581
+ });
1582
+ import { join as join16 } from "path";
1583
+ import { existsSync as existsSync15 } from "fs";
1584
+ import chalk7 from "chalk";
1585
+ import { env as env2 } from "@spfn/core/config";
1586
+ import { loadEnv as loadEnv2 } from "@spfn/core/server";
1587
+ function functionMigrationsTable2(packageName) {
1588
+ return `__spfn_fn_${packageName.replace("@spfn/", "")}_migrations`;
1589
+ }
1590
+ function filterPendingEntries(entries, lastAppliedMillis, appliedNames) {
1591
+ return entries.filter((entry) => entry.millis > lastAppliedMillis && !appliedNames.has(entry.name));
1592
+ }
1593
+ async function readAppliedNames(sql2, tableName) {
1594
+ const columnCheck = await sql2`
1595
+ SELECT EXISTS (
1596
+ SELECT 1 FROM information_schema.columns
1597
+ WHERE table_schema = 'drizzle' AND table_name = ${tableName} AND column_name = 'name'
1598
+ ) AS "exists"`;
1599
+ if (!columnCheck[0]?.exists) {
1600
+ return /* @__PURE__ */ new Set();
1601
+ }
1602
+ const rows = await sql2`
1603
+ SELECT name FROM drizzle.${sql2(tableName)} WHERE name IS NOT NULL`;
1604
+ return new Set(rows.map((row) => row.name));
1605
+ }
1606
+ async function collectTargetStatus(sql2, name, migrationsDir, tableName) {
1607
+ const entries = readMigrationEntries(migrationsDir, name);
1608
+ const tableCheck = await sql2`
1609
+ SELECT EXISTS (
1610
+ SELECT 1 FROM information_schema.tables
1611
+ WHERE table_schema = 'drizzle' AND table_name = ${tableName}
1612
+ ) AS "exists"`;
1613
+ let lastApplied = 0;
1614
+ let appliedNames = /* @__PURE__ */ new Set();
1615
+ if (tableCheck[0]?.exists) {
1616
+ const rows = await sql2`
1617
+ SELECT created_at FROM drizzle.${sql2(tableName)}
1618
+ ORDER BY created_at DESC LIMIT 1`;
1619
+ lastApplied = rows[0]?.created_at ? Number(rows[0].created_at) : 0;
1620
+ appliedNames = await readAppliedNames(sql2, tableName);
1621
+ }
1622
+ const pendingEntries = filterPendingEntries(entries, lastApplied, appliedNames);
1623
+ return {
1624
+ name,
1625
+ total: entries.length,
1626
+ applied: entries.length - pendingEntries.length,
1627
+ pending: pendingEntries.length,
1628
+ pendingTags: pendingEntries.map((e) => e.name)
1629
+ };
1630
+ }
1631
+ async function getMigrationStatus(cwd = process.cwd(), databaseUrl) {
1632
+ loadEnv2();
1633
+ const url = databaseUrl ?? env2.DATABASE_URL;
1634
+ if (!url) {
1635
+ throw new Error("DATABASE_URL not found in environment");
1636
+ }
1637
+ const postgres = await import("postgres");
1638
+ const sql2 = postgres.default(url, { max: 1, connect_timeout: 5 });
1639
+ try {
1640
+ const packages = [];
1641
+ for (const func of discoverFunctionMigrations(cwd)) {
1642
+ packages.push(await collectTargetStatus(
1643
+ sql2,
1644
+ func.packageName,
1645
+ func.migrationsDir,
1646
+ functionMigrationsTable2(func.packageName)
1647
+ ));
1648
+ }
1649
+ const projectDir = join16(cwd, "src", "server", "drizzle");
1650
+ const project = existsSync15(projectDir) ? await collectTargetStatus(sql2, "project (src/server/drizzle)", projectDir, "__drizzle_migrations") : null;
1651
+ return { packages, project: project && project.total > 0 ? project : null };
1652
+ } finally {
1653
+ await sql2.end();
1654
+ }
1655
+ }
1656
+ async function warnPendingMigrations(cwd, databaseUrl) {
1657
+ let status;
1658
+ try {
1659
+ status = await getMigrationStatus(cwd, databaseUrl);
1660
+ } catch {
1661
+ return;
1662
+ }
1663
+ const targets = [...status.packages, ...status.project ? [status.project] : []].filter((t) => t.pending > 0);
1664
+ if (targets.length === 0) {
1665
+ return;
1666
+ }
1667
+ console.warn("");
1668
+ for (const target of targets) {
1669
+ console.warn(chalk7.yellow(`\u26A0\uFE0F ${target.name}: ${target.pending} pending migration(s)`));
1670
+ }
1671
+ console.warn(chalk7.yellow(" Missing tables will fail at request time \u2014 run: pnpm spfn db migrate\n"));
1672
+ }
1673
+ var init_migration_status = __esm({
1674
+ "src/utils/migration-status.ts"() {
1675
+ "use strict";
1676
+ init_function_migrations();
1677
+ }
1678
+ });
1679
+
1574
1680
  // src/index.ts
1575
1681
  import { Command as Command13 } from "commander";
1576
1682
 
@@ -1762,8 +1868,8 @@ init_init();
1762
1868
  init_logger();
1763
1869
  init_package_manager();
1764
1870
  import { Command as Command4 } from "commander";
1765
- import { existsSync as existsSync14, readFileSync as readFileSync7, writeFileSync as writeFileSync10, mkdirSync, unlinkSync, rmSync, watch } from "fs";
1766
- import { join as join15, relative, sep } from "path";
1871
+ import { existsSync as existsSync16, readFileSync as readFileSync8, writeFileSync as writeFileSync10, mkdirSync, unlinkSync, rmSync, watch } from "fs";
1872
+ import { join as join17, relative, sep } from "path";
1767
1873
  import { execa as execa6 } from "execa";
1768
1874
  import chokidar from "chokidar";
1769
1875
 
@@ -1939,10 +2045,10 @@ async function resolveKeychainEnv(cwd) {
1939
2045
  return { env: {}, missing: [] };
1940
2046
  }
1941
2047
  const store = detectStore();
1942
- const env8 = {};
2048
+ const env9 = {};
1943
2049
  const missing = [];
1944
2050
  if (!await store.isAvailable()) {
1945
- return { env: env8, missing: refs.map(([key]) => key) };
2051
+ return { env: env9, missing: refs.map(([key]) => key) };
1946
2052
  }
1947
2053
  for (const [key, value] of refs) {
1948
2054
  const name = value.slice(KEYCHAIN_REF_PREFIX.length);
@@ -1950,10 +2056,10 @@ async function resolveKeychainEnv(cwd) {
1950
2056
  if (resolved === null) {
1951
2057
  missing.push(key);
1952
2058
  } else {
1953
- env8[key] = resolved;
2059
+ env9[key] = resolved;
1954
2060
  }
1955
2061
  }
1956
- return { env: env8, missing };
2062
+ return { env: env9, missing };
1957
2063
  }
1958
2064
 
1959
2065
  // src/commands/dev.ts
@@ -1962,20 +2068,20 @@ function ignoreDotfilesUnder(root) {
1962
2068
  }
1963
2069
  function waitForReadyFile(filePath, timeoutMs = 3e4) {
1964
2070
  return new Promise((resolve3, reject) => {
1965
- if (existsSync14(filePath)) {
2071
+ if (existsSync16(filePath)) {
1966
2072
  unlinkSync(filePath);
1967
2073
  }
1968
2074
  const timer = setTimeout(() => {
1969
2075
  watcher.close();
1970
2076
  reject(new Error(`Server did not become ready within ${timeoutMs / 1e3}s`));
1971
2077
  }, timeoutMs);
1972
- const dir = join15(filePath, "..");
2078
+ const dir = join17(filePath, "..");
1973
2079
  const fileName = filePath.split("/").pop();
1974
2080
  const watcher = watch(dir, (_event, name) => {
1975
- if (name === fileName && existsSync14(filePath)) {
2081
+ if (name === fileName && existsSync16(filePath)) {
1976
2082
  watcher.close();
1977
2083
  clearTimeout(timer);
1978
- resolve3(readFileSync7(filePath, "utf-8").trim());
2084
+ resolve3(readFileSync8(filePath, "utf-8").trim());
1979
2085
  }
1980
2086
  });
1981
2087
  });
@@ -1986,8 +2092,8 @@ var devCommand = new Command4("dev").description("Start SPFN development server
1986
2092
  process.env.NODE_ENV = "development";
1987
2093
  }
1988
2094
  const cwd = process.cwd();
1989
- const serverDir = join15(cwd, "src", "server");
1990
- if (!existsSync14(serverDir)) {
2095
+ const serverDir = join17(cwd, "src", "server");
2096
+ if (!existsSync16(serverDir)) {
1991
2097
  logger.error("src/server directory not found.");
1992
2098
  logger.info('Run "spfn init" first to initialize SPFN in your project.');
1993
2099
  process.exit(1);
@@ -2001,23 +2107,25 @@ var devCommand = new Command4("dev").description("Start SPFN development server
2001
2107
  logger.warn(`[SPFN] Could not resolve keychain secret(s): ${keychainMissing.join(", ")} \u2014 run \`spfn secret set <KEY>\``);
2002
2108
  }
2003
2109
  const serverEnv = { ...process.env, ...keychainEnv };
2004
- const packageJsonPath = join15(cwd, "package.json");
2110
+ const { warnPendingMigrations: warnPendingMigrations2 } = await Promise.resolve().then(() => (init_migration_status(), migration_status_exports));
2111
+ await warnPendingMigrations2(cwd, serverEnv.DATABASE_URL);
2112
+ const packageJsonPath = join17(cwd, "package.json");
2005
2113
  let hasNext = false;
2006
- if (existsSync14(packageJsonPath)) {
2007
- const packageJson = JSON.parse(readFileSync7(packageJsonPath, "utf-8"));
2114
+ if (existsSync16(packageJsonPath)) {
2115
+ const packageJson = JSON.parse(readFileSync8(packageJsonPath, "utf-8"));
2008
2116
  hasNext = !!(packageJson.dependencies?.next || packageJson.devDependencies?.next);
2009
2117
  }
2010
- const tempDir = join15(cwd, ".spfn");
2011
- const serverEntry = join15(tempDir, "server.mjs");
2012
- const watcherEntry = join15(tempDir, "watcher.mjs");
2118
+ const tempDir = join17(cwd, ".spfn");
2119
+ const serverEntry = join17(tempDir, "server.mjs");
2120
+ const watcherEntry = join17(tempDir, "watcher.mjs");
2013
2121
  mkdirSync(tempDir, { recursive: true });
2014
- const serverBuildDir = join15(tempDir, "server");
2015
- if (existsSync14(serverBuildDir)) {
2122
+ const serverBuildDir = join17(tempDir, "server");
2123
+ if (existsSync16(serverBuildDir)) {
2016
2124
  rmSync(serverBuildDir, { recursive: true, force: true });
2017
2125
  logger.info("[SPFN] Cleaned stale build cache (.spfn/server)");
2018
2126
  }
2019
- const readySignal = join15(tempDir, "server-ready");
2020
- if (existsSync14(readySignal)) {
2127
+ const readySignal = join17(tempDir, "server-ready");
2128
+ if (existsSync16(readySignal)) {
2021
2129
  unlinkSync(readySignal);
2022
2130
  }
2023
2131
  const configParts = [];
@@ -2025,7 +2133,7 @@ var devCommand = new Command4("dev").description("Start SPFN development server
2025
2133
  if (options.host) configParts.push(`host: '${options.host}'`);
2026
2134
  if (options.routes) configParts.push(`routesPath: '${options.routes}'`);
2027
2135
  configParts.push("debug: true");
2028
- const readyFile = join15(tempDir, "server-ready");
2136
+ const readyFile = join17(tempDir, "server-ready");
2029
2137
  writeFileSync10(serverEntry, `
2030
2138
  import { writeFileSync } from 'fs';
2031
2139
 
@@ -2315,11 +2423,11 @@ catch (error)
2315
2423
  init_logger();
2316
2424
  init_package_manager();
2317
2425
  import { Command as Command5 } from "commander";
2318
- import { existsSync as existsSync15, writeFileSync as writeFileSync11, mkdirSync as mkdirSync2, readdirSync } from "fs";
2319
- import { join as join16 } from "path";
2426
+ import { existsSync as existsSync17, writeFileSync as writeFileSync11, mkdirSync as mkdirSync2, readdirSync as readdirSync2 } from "fs";
2427
+ import { join as join18 } from "path";
2320
2428
  import { execa as execa7 } from "execa";
2321
2429
  import ora5 from "ora";
2322
- import chalk6 from "chalk";
2430
+ import chalk8 from "chalk";
2323
2431
  import { build } from "tsup";
2324
2432
  async function buildProject(options) {
2325
2433
  if (!process.env.NODE_ENV) {
@@ -2330,17 +2438,17 @@ async function buildProject(options) {
2330
2438
  }
2331
2439
  const cwd = process.cwd();
2332
2440
  const pm = detectPackageManager(cwd);
2333
- const packageJsonPath = join16(cwd, "package.json");
2441
+ const packageJsonPath = join18(cwd, "package.json");
2334
2442
  let hasNext = false;
2335
- if (existsSync15(packageJsonPath)) {
2443
+ if (existsSync17(packageJsonPath)) {
2336
2444
  const packageJson = JSON.parse(await import("fs").then(
2337
2445
  (fs5) => fs5.promises.readFile(packageJsonPath, "utf-8")
2338
2446
  ));
2339
2447
  hasNext = !!(packageJson.dependencies?.next || packageJson.devDependencies?.next);
2340
2448
  }
2341
- const serverDir = join16(cwd, "src", "server");
2342
- const hasServer = existsSync15(serverDir);
2343
- console.log(chalk6.blue.bold("\n\u{1F3D7}\uFE0F Building SPFN project for production...\n"));
2449
+ const serverDir = join18(cwd, "src", "server");
2450
+ const hasServer = existsSync17(serverDir);
2451
+ console.log(chalk8.blue.bold("\n\u{1F3D7}\uFE0F Building SPFN project for production...\n"));
2344
2452
  if (hasServer) {
2345
2453
  const spinner = ora5("Generating API client...").start();
2346
2454
  try {
@@ -2376,10 +2484,10 @@ async function buildProject(options) {
2376
2484
  if (hasServer && !options.nextOnly) {
2377
2485
  const spinner = ora5("Building SPFN server...").start();
2378
2486
  try {
2379
- const outputDir = join16(cwd, ".spfn", "server");
2487
+ const outputDir = join18(cwd, ".spfn", "server");
2380
2488
  mkdirSync2(outputDir, { recursive: true });
2381
- const serverDir2 = join16(cwd, "src", "server");
2382
- if (!existsSync15(serverDir2)) {
2489
+ const serverDir2 = join18(cwd, "src", "server");
2490
+ if (!existsSync17(serverDir2)) {
2383
2491
  spinner.fail("SPFN server build failed");
2384
2492
  logger.error("src/server/ directory not found");
2385
2493
  logger.error('Please run "spfn init" to initialize the project.');
@@ -2407,7 +2515,7 @@ async function buildProject(options) {
2407
2515
  onSuccess: async () => {
2408
2516
  }
2409
2517
  });
2410
- const prodServerPath = join16(cwd, ".spfn", "prod-server.mjs");
2518
+ const prodServerPath = join18(cwd, ".spfn", "prod-server.mjs");
2411
2519
  const prodServerContent = `// Load environment variables FIRST (before any imports that depend on them)
2412
2520
  // Use centralized environment loader for standard dotenv priority
2413
2521
  const { env } = await import('@spfn/core/config');
@@ -2433,25 +2541,25 @@ await startServer({
2433
2541
  `;
2434
2542
  writeFileSync11(prodServerPath, prodServerContent);
2435
2543
  spinner.succeed(`SPFN server build completed \u2192 .spfn/server`);
2436
- const routesDir = join16(cwd, ".spfn", "server", "routes");
2437
- if (existsSync15(routesDir)) {
2544
+ const routesDir = join18(cwd, ".spfn", "server", "routes");
2545
+ if (existsSync17(routesDir)) {
2438
2546
  console.log();
2439
- console.log(chalk6.bold("Route (api)"));
2547
+ console.log(chalk8.bold("Route (api)"));
2440
2548
  try {
2441
- const routes = readdirSync(routesDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name).sort();
2549
+ const routes = readdirSync2(routesDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name).sort();
2442
2550
  if (routes.length > 0) {
2443
2551
  routes.forEach((route, index) => {
2444
2552
  const isLast = index === routes.length - 1;
2445
2553
  const prefix = isLast ? "\u2514" : "\u251C";
2446
2554
  const routePath = `/api/${route}`;
2447
2555
  if (route === "health") {
2448
- console.log(`${prefix} ${chalk6.green("GET")} ${routePath}`);
2556
+ console.log(`${prefix} ${chalk8.green("GET")} ${routePath}`);
2449
2557
  } else {
2450
- console.log(`${prefix} ${chalk6.cyan("*")} ${routePath}`);
2558
+ console.log(`${prefix} ${chalk8.cyan("*")} ${routePath}`);
2451
2559
  }
2452
2560
  });
2453
2561
  console.log();
2454
- console.log(chalk6.cyan("*") + " (Hono) multiple methods supported");
2562
+ console.log(chalk8.cyan("*") + " (Hono) multiple methods supported");
2455
2563
  }
2456
2564
  } catch (error) {
2457
2565
  }
@@ -2459,9 +2567,9 @@ await startServer({
2459
2567
  } catch (error) {
2460
2568
  spinner.fail("SPFN server build failed");
2461
2569
  if (error instanceof Error) {
2462
- console.error("\n" + chalk6.red(error.message));
2570
+ console.error("\n" + chalk8.red(error.message));
2463
2571
  if (error.stack) {
2464
- console.error(chalk6.dim("\n" + error.stack));
2572
+ console.error(chalk8.dim("\n" + error.stack));
2465
2573
  }
2466
2574
  } else {
2467
2575
  logger.error(String(error));
@@ -2473,13 +2581,13 @@ await startServer({
2473
2581
  logger.error("No Next.js or SPFN server found in this project.");
2474
2582
  process.exit(1);
2475
2583
  }
2476
- console.log("\n" + chalk6.green.bold("\u2713 Build completed successfully!\n"));
2477
- console.log(chalk6.bold("Next steps:\n"));
2478
- console.log(" " + chalk6.cyan("Start production server:"));
2479
- console.log(` ${chalk6.cyan(getRunCommand(pm))} spfn:start ${chalk6.gray("# Start SPFN + Next.js")}
2584
+ console.log("\n" + chalk8.green.bold("\u2713 Build completed successfully!\n"));
2585
+ console.log(chalk8.bold("Next steps:\n"));
2586
+ console.log(" " + chalk8.cyan("Start production server:"));
2587
+ console.log(` ${chalk8.cyan(getRunCommand(pm))} spfn:start ${chalk8.gray("# Start SPFN + Next.js")}
2480
2588
  `);
2481
- console.log(" " + chalk6.cyan("Or deploy with Docker:"));
2482
- console.log(` ${chalk6.cyan("docker compose -f docker-compose.production.yml up --build -d")}
2589
+ console.log(" " + chalk8.cyan("Or deploy with Docker:"));
2590
+ console.log(` ${chalk8.cyan("docker compose -f docker-compose.production.yml up --build -d")}
2483
2591
  `);
2484
2592
  }
2485
2593
  var buildCommand = new Command5("build").description("Build SPFN project for production (Next.js + Server)").option("--server-only", "Build only SPFN server (skip Next.js)").option("--next-only", "Build only Next.js (skip SPFN server)").option("--turbo", "Use Turbopack for Next.js build").action(async (options) => {
@@ -2490,25 +2598,25 @@ var buildCommand = new Command5("build").description("Build SPFN project for pro
2490
2598
  init_logger();
2491
2599
  init_package_manager();
2492
2600
  import { Command as Command6 } from "commander";
2493
- import { existsSync as existsSync16, readFileSync as readFileSync8 } from "fs";
2494
- import { join as join17 } from "path";
2601
+ import { existsSync as existsSync18, readFileSync as readFileSync9 } from "fs";
2602
+ import { join as join19 } from "path";
2495
2603
  import { execa as execa8 } from "execa";
2496
- import chalk7 from "chalk";
2604
+ import chalk9 from "chalk";
2497
2605
  var startCommand = new Command6("start").description("Start SPFN production server (Next.js + Hono)").option("--server-only", "Run only SPFN server (skip Next.js)").option("--next-only", "Run only Next.js (skip SPFN server)").option("-p, --port <port>", "Server port", "8790").option("-h, --host <host>", "Server host", "0.0.0.0").action(async (options) => {
2498
2606
  if (!process.env.NODE_ENV) {
2499
2607
  process.env.NODE_ENV = "production";
2500
2608
  }
2501
2609
  const cwd = process.cwd();
2502
- const packageJsonPath = join17(cwd, "package.json");
2610
+ const packageJsonPath = join19(cwd, "package.json");
2503
2611
  let hasNext = false;
2504
- if (existsSync16(packageJsonPath)) {
2505
- const packageJson = JSON.parse(readFileSync8(packageJsonPath, "utf-8"));
2612
+ if (existsSync18(packageJsonPath)) {
2613
+ const packageJson = JSON.parse(readFileSync9(packageJsonPath, "utf-8"));
2506
2614
  hasNext = !!(packageJson.dependencies?.next || packageJson.devDependencies?.next);
2507
2615
  }
2508
- const builtServerDir = join17(cwd, ".spfn", "server");
2509
- const hasBuiltServer = existsSync16(builtServerDir);
2510
- const nextBuildDir = join17(cwd, ".next");
2511
- const hasNextBuild = existsSync16(nextBuildDir);
2616
+ const builtServerDir = join19(cwd, ".spfn", "server");
2617
+ const hasBuiltServer = existsSync18(builtServerDir);
2618
+ const nextBuildDir = join19(cwd, ".next");
2619
+ const hasNextBuild = existsSync18(nextBuildDir);
2512
2620
  if (!options.nextOnly && !hasBuiltServer) {
2513
2621
  logger.error('.spfn/server directory not found. Please run "spfn build" first.');
2514
2622
  process.exit(1);
@@ -2518,8 +2626,8 @@ var startCommand = new Command6("start").description("Start SPFN production serv
2518
2626
  process.exit(1);
2519
2627
  }
2520
2628
  const pm = detectPackageManager(cwd);
2521
- const serverEntry = join17(cwd, ".spfn", "prod-server.mjs");
2522
- if (!existsSync16(serverEntry)) {
2629
+ const serverEntry = join19(cwd, ".spfn", "prod-server.mjs");
2630
+ if (!existsSync18(serverEntry)) {
2523
2631
  logger.error('.spfn/prod-server.mjs not found. Please run "spfn build" first.');
2524
2632
  process.exit(1);
2525
2633
  }
@@ -2555,7 +2663,7 @@ var startCommand = new Command6("start").description("Start SPFN production serv
2555
2663
  }
2556
2664
  const nextCmd = "next start -H 0.0.0.0 -p 3790";
2557
2665
  const serverCmd = `node "${serverEntry}"`;
2558
- console.log(chalk7.blue.bold("\n\u{1F680} Starting SPFN production server...\n"));
2666
+ console.log(chalk9.blue.bold("\n\u{1F680} Starting SPFN production server...\n"));
2559
2667
  logger.info("Next.js: http://0.0.0.0:3790");
2560
2668
  logger.info(`SPFN API: http://${options.host}:${options.port}
2561
2669
  `);
@@ -2582,13 +2690,13 @@ var startCommand = new Command6("start").description("Start SPFN production serv
2582
2690
  // src/commands/codegen.ts
2583
2691
  init_logger();
2584
2692
  import { Command as Command7 } from "commander";
2585
- import { existsSync as existsSync17, writeFileSync as writeFileSync12 } from "fs";
2586
- import { join as join18 } from "path";
2587
- import chalk8 from "chalk";
2693
+ import { existsSync as existsSync19, writeFileSync as writeFileSync12 } from "fs";
2694
+ import { join as join20 } from "path";
2695
+ import chalk10 from "chalk";
2588
2696
  async function initCodegen(options) {
2589
2697
  const cwd = process.cwd();
2590
- const rcPath = join18(cwd, ".spfnrc.ts");
2591
- if (existsSync17(rcPath)) {
2698
+ const rcPath = join20(cwd, ".spfnrc.ts");
2699
+ if (existsSync19(rcPath)) {
2592
2700
  logger.warn(".spfnrc.ts already exists");
2593
2701
  logger.info("Edit manually to add custom generators");
2594
2702
  process.exit(0);
@@ -2614,13 +2722,13 @@ export default defineConfig({
2614
2722
  });
2615
2723
  `;
2616
2724
  writeFileSync12(rcPath, content);
2617
- console.log("\n" + chalk8.green.bold("\u2713 Created .spfnrc.ts\n"));
2618
- console.log(chalk8.gray("Configured the @spfn/core:route-map generator."));
2725
+ console.log("\n" + chalk10.green.bold("\u2713 Created .spfnrc.ts\n"));
2726
+ console.log(chalk10.gray("Configured the @spfn/core:route-map generator."));
2619
2727
  if (options.withExample) {
2620
- console.log("\n" + chalk8.yellow("\u{1F4DD} To add custom generators:"));
2728
+ console.log("\n" + chalk10.yellow("\u{1F4DD} To add custom generators:"));
2621
2729
  console.log(" 1. Create your generator file (e.g., src/generators/my-generator.ts)");
2622
2730
  console.log(" 2. Add to .spfnrc.ts:");
2623
- console.log(chalk8.gray(`
2731
+ console.log(chalk10.gray(`
2624
2732
  {
2625
2733
  "codegen": {
2626
2734
  "generators": [
@@ -2630,11 +2738,11 @@ export default defineConfig({
2630
2738
  }
2631
2739
  }
2632
2740
  `));
2633
- console.log(" 3. Run: " + chalk8.cyan("spfn dev") + " (generators run automatically)");
2741
+ console.log(" 3. Run: " + chalk10.cyan("spfn dev") + " (generators run automatically)");
2634
2742
  } else {
2635
- console.log("\n" + chalk8.yellow("\u{1F4DD} Next steps:"));
2743
+ console.log("\n" + chalk10.yellow("\u{1F4DD} Next steps:"));
2636
2744
  console.log(" \u2022 Add custom generators to .spfnrc.ts");
2637
- console.log(" \u2022 Run: " + chalk8.cyan("spfn dev") + " to start development with code generation");
2745
+ console.log(" \u2022 Run: " + chalk10.cyan("spfn dev") + " to start development with code generation");
2638
2746
  }
2639
2747
  }
2640
2748
  async function listGenerators() {
@@ -2647,10 +2755,10 @@ async function listGenerators() {
2647
2755
  logger.info('Run "spfn codegen init" to initialize configuration');
2648
2756
  return;
2649
2757
  }
2650
- console.log("\n" + chalk8.bold("Registered Generators:"));
2758
+ console.log("\n" + chalk10.bold("Registered Generators:"));
2651
2759
  generators.forEach((gen, index) => {
2652
- console.log(` ${index + 1}. ${chalk8.cyan(gen.name)}`);
2653
- console.log(` Patterns: ${chalk8.gray(gen.watchPatterns.join(", "))}`);
2760
+ console.log(` ${index + 1}. ${chalk10.cyan(gen.name)}`);
2761
+ console.log(` Patterns: ${chalk10.gray(gen.watchPatterns.join(", "))}`);
2654
2762
  });
2655
2763
  console.log("");
2656
2764
  }
@@ -2671,7 +2779,7 @@ async function runGenerators() {
2671
2779
  debug: true
2672
2780
  });
2673
2781
  await orchestrator.generateAll();
2674
- console.log("\n" + chalk8.green.bold("\u2713 Code generation completed"));
2782
+ console.log("\n" + chalk10.green.bold("\u2713 Code generation completed"));
2675
2783
  }
2676
2784
  var codegenCommand = new Command7("codegen").description("Code generation management");
2677
2785
  codegenCommand.command("init").description("Initialize .spfnrc.ts with codegen configuration").option("--with-example", "Show example custom generator usage").action(initCodegen);
@@ -2682,7 +2790,7 @@ codegenCommand.command("run").description("Run code generators once (no watch mo
2682
2790
  init_logger();
2683
2791
  import { Command as Command8 } from "commander";
2684
2792
  import { execSync } from "child_process";
2685
- import chalk9 from "chalk";
2793
+ import chalk11 from "chalk";
2686
2794
 
2687
2795
  // src/utils/secret-gen.ts
2688
2796
  import { randomBytes, randomUUID } from "crypto";
@@ -2757,41 +2865,41 @@ function copyToClipboard(text) {
2757
2865
  function generateSecret(bytes, preset, envVarName, copy) {
2758
2866
  const key = randomBase64Url(bytes);
2759
2867
  const config = preset ? PRESETS[preset] : null;
2760
- console.log("\n" + chalk9.green.bold("\u2713 Generated secret key:"));
2868
+ console.log("\n" + chalk11.green.bold("\u2713 Generated secret key:"));
2761
2869
  if (config) {
2762
- console.log(chalk9.dim(` ${config.description} (${bytes * 8} bits)`));
2870
+ console.log(chalk11.dim(` ${config.description} (${bytes * 8} bits)`));
2763
2871
  } else {
2764
- console.log(chalk9.dim(` ${bytes * 8}-bit secret`));
2872
+ console.log(chalk11.dim(` ${bytes * 8}-bit secret`));
2765
2873
  }
2766
- console.log("\n" + chalk9.cyan(key) + "\n");
2874
+ console.log("\n" + chalk11.cyan(key) + "\n");
2767
2875
  const varName = envVarName || config?.envVar || "SECRET_KEY";
2768
- console.log(chalk9.dim("Add to your .env file:"));
2769
- console.log(chalk9.yellow(`${varName}=${key}
2876
+ console.log(chalk11.dim("Add to your .env file:"));
2877
+ console.log(chalk11.yellow(`${varName}=${key}
2770
2878
  `));
2771
2879
  if (config?.usage) {
2772
- console.log(chalk9.dim("Usage:"));
2773
- console.log(chalk9.gray(` ${config.usage}
2880
+ console.log(chalk11.dim("Usage:"));
2881
+ console.log(chalk11.gray(` ${config.usage}
2774
2882
  `));
2775
2883
  }
2776
2884
  if (copy) {
2777
2885
  if (copyToClipboard(key)) {
2778
- console.log(chalk9.green("\u2713 Copied to clipboard!\n"));
2886
+ console.log(chalk11.green("\u2713 Copied to clipboard!\n"));
2779
2887
  } else {
2780
2888
  logger.warn("Could not copy to clipboard");
2781
2889
  }
2782
2890
  }
2783
2891
  }
2784
2892
  function listPresets() {
2785
- console.log("\n" + chalk9.bold("Available presets:"));
2893
+ console.log("\n" + chalk11.bold("Available presets:"));
2786
2894
  console.log();
2787
2895
  Object.entries(PRESETS).forEach(([name, config]) => {
2788
- console.log(` ${chalk9.cyan(name.padEnd(20))} ${chalk9.dim(config.description)}`);
2789
- console.log(` ${" ".repeat(20)} ${chalk9.gray(`\u2192 ${config.envVar} (${config.bytes * 8} bits)`)}`);
2896
+ console.log(` ${chalk11.cyan(name.padEnd(20))} ${chalk11.dim(config.description)}`);
2897
+ console.log(` ${" ".repeat(20)} ${chalk11.gray(`\u2192 ${config.envVar} (${config.bytes * 8} bits)`)}`);
2790
2898
  console.log();
2791
2899
  });
2792
- console.log(chalk9.dim("Usage:"));
2793
- console.log(chalk9.gray(" spfn key <preset>"));
2794
- console.log(chalk9.gray(" spfn key auth-encryption --copy"));
2900
+ console.log(chalk11.dim("Usage:"));
2901
+ console.log(chalk11.gray(" spfn key <preset>"));
2902
+ console.log(chalk11.gray(" spfn key auth-encryption --copy"));
2795
2903
  console.log();
2796
2904
  }
2797
2905
  var generateValueCommand = new Command8("generate").alias("gen").description("Generate random value (simple output, no metadata)").option("-b, --bytes <number>", "Number of random bytes", "32").option("-c, --copy", "Copy to clipboard").action((options) => {
@@ -2804,9 +2912,9 @@ var generateValueCommand = new Command8("generate").alias("gen").description("Ge
2804
2912
  console.log(value);
2805
2913
  if (options.copy) {
2806
2914
  if (copyToClipboard(value)) {
2807
- console.error(chalk9.green("\u2713 Copied to clipboard"));
2915
+ console.error(chalk11.green("\u2713 Copied to clipboard"));
2808
2916
  } else {
2809
- console.error(chalk9.yellow("\u26A0 Could not copy to clipboard"));
2917
+ console.error(chalk11.yellow("\u26A0 Could not copy to clipboard"));
2810
2918
  }
2811
2919
  }
2812
2920
  });
@@ -2824,9 +2932,9 @@ var keyCommand = new Command8("key").alias("k").description("Generate secure ran
2824
2932
  logger.error(`Unknown preset: ${preset}`);
2825
2933
  console.log("\nAvailable presets:");
2826
2934
  Object.entries(PRESETS).forEach(([name, config]) => {
2827
- console.log(` ${chalk9.cyan(name)}: ${config.description}`);
2935
+ console.log(` ${chalk11.cyan(name)}: ${config.description}`);
2828
2936
  });
2829
- console.log("\nUse " + chalk9.cyan("--list") + " to see detailed information");
2937
+ console.log("\nUse " + chalk11.cyan("--list") + " to see detailed information");
2830
2938
  process.exit(1);
2831
2939
  }
2832
2940
  generateSecret(
@@ -2845,16 +2953,16 @@ init_setup();
2845
2953
  import { Command as Command9 } from "commander";
2846
2954
 
2847
2955
  // src/commands/db/generate.ts
2848
- import chalk11 from "chalk";
2956
+ import chalk13 from "chalk";
2849
2957
 
2850
2958
  // src/commands/db/utils/drizzle.ts
2851
- import { existsSync as existsSync18, writeFileSync as writeFileSync13, unlinkSync as unlinkSync2 } from "fs";
2959
+ import { existsSync as existsSync20, writeFileSync as writeFileSync13, unlinkSync as unlinkSync2 } from "fs";
2852
2960
  import { spawn } from "child_process";
2853
2961
  import { pathToFileURL } from "url";
2854
- import chalk10 from "chalk";
2962
+ import chalk12 from "chalk";
2855
2963
  import ora6 from "ora";
2856
- import { env } from "@spfn/core/config";
2857
- import { loadEnv } from "@spfn/core/server";
2964
+ import { env as env3 } from "@spfn/core/config";
2965
+ import { loadEnv as loadEnv3 } from "@spfn/core/server";
2858
2966
  var TLS_SSL_MODES = /* @__PURE__ */ new Set(["no-verify", "prefer", "require", "verify-ca", "verify-full"]);
2859
2967
  function parseDatabaseUrl(databaseUrl) {
2860
2968
  if (!databaseUrl) {
@@ -2907,22 +3015,22 @@ function resolvePushConnectionConfig(databaseUrl) {
2907
3015
  return { connectionString: parsedUrl.toString() };
2908
3016
  }
2909
3017
  function validateDatabasePrerequisites() {
2910
- loadEnv();
2911
- if (!env.DATABASE_URL) {
2912
- console.error(chalk10.red("\u274C DATABASE_URL not found in environment"));
2913
- console.log(chalk10.yellow("\n\u{1F4A1} Tip: Add DATABASE_URL to your .env file"));
3018
+ loadEnv3();
3019
+ if (!env3.DATABASE_URL) {
3020
+ console.error(chalk12.red("\u274C DATABASE_URL not found in environment"));
3021
+ console.log(chalk12.yellow("\n\u{1F4A1} Tip: Add DATABASE_URL to your .env file"));
2914
3022
  throw new Error("DATABASE_URL is required for database operations");
2915
3023
  }
2916
3024
  }
2917
3025
  async function runDrizzleCommand(command) {
2918
- const hasUserConfig = existsSync18("./drizzle.config.ts");
3026
+ const hasUserConfig = existsSync20("./drizzle.config.ts");
2919
3027
  const tempConfigPath = `./drizzle.config.${process.pid}.${Date.now()}.temp.ts`;
2920
3028
  const configPath = hasUserConfig ? "./drizzle.config.ts" : tempConfigPath;
2921
3029
  if (!hasUserConfig) {
2922
- loadEnv();
2923
- if (!env.DATABASE_URL) {
2924
- console.error(chalk10.red("\u274C DATABASE_URL not found in environment"));
2925
- console.log(chalk10.yellow("\n\u{1F4A1} Tip: Add DATABASE_URL to your .env file"));
3030
+ loadEnv3();
3031
+ if (!env3.DATABASE_URL) {
3032
+ console.error(chalk12.red("\u274C DATABASE_URL not found in environment"));
3033
+ console.log(chalk12.yellow("\n\u{1F4A1} Tip: Add DATABASE_URL to your .env file"));
2926
3034
  process.exit(1);
2927
3035
  }
2928
3036
  const { generateDrizzleConfigFile } = await import("@spfn/core/db");
@@ -2935,7 +3043,7 @@ async function runDrizzleCommand(command) {
2935
3043
  autoDetectSchemas: true
2936
3044
  });
2937
3045
  writeFileSync13(tempConfigPath, configContent);
2938
- console.log(chalk10.dim("Using auto-generated Drizzle config\n"));
3046
+ console.log(chalk12.dim("Using auto-generated Drizzle config\n"));
2939
3047
  }
2940
3048
  const args = command.split(" ");
2941
3049
  args.push(`--config=${configPath}`);
@@ -2944,10 +3052,10 @@ async function runDrizzleCommand(command) {
2944
3052
  stdio: "inherit",
2945
3053
  // Allow interactive input
2946
3054
  shell: true,
2947
- env: shouldRelaxDbTls(env.DATABASE_URL) ? { ...process.env, NODE_TLS_REJECT_UNAUTHORIZED: "0" } : { ...process.env }
3055
+ env: shouldRelaxDbTls(env3.DATABASE_URL) ? { ...process.env, NODE_TLS_REJECT_UNAUTHORIZED: "0" } : { ...process.env }
2948
3056
  });
2949
3057
  const cleanup = () => {
2950
- if (!hasUserConfig && existsSync18(tempConfigPath)) {
3058
+ if (!hasUserConfig && existsSync20(tempConfigPath)) {
2951
3059
  unlinkSync2(tempConfigPath);
2952
3060
  }
2953
3061
  };
@@ -2970,10 +3078,10 @@ async function runWithSpinner(spinnerText, command, successMessage, failMessage)
2970
3078
  try {
2971
3079
  spinner.stop();
2972
3080
  await runDrizzleCommand(command);
2973
- console.log(chalk10.green(`\u2705 ${successMessage}`));
3081
+ console.log(chalk12.green(`\u2705 ${successMessage}`));
2974
3082
  } catch (error) {
2975
3083
  spinner.fail(failMessage);
2976
- console.error(chalk10.red(error instanceof Error ? error.message : "Unknown error"));
3084
+ console.error(chalk12.red(error instanceof Error ? error.message : "Unknown error"));
2977
3085
  process.exit(1);
2978
3086
  }
2979
3087
  }
@@ -2997,13 +3105,13 @@ async function loadSchemaImports(schemaFiles) {
2997
3105
  return imports;
2998
3106
  }
2999
3107
  async function createPushConnection() {
3000
- loadEnv();
3001
- if (!env.DATABASE_URL) {
3108
+ loadEnv3();
3109
+ if (!env3.DATABASE_URL) {
3002
3110
  throw new Error("DATABASE_URL is required");
3003
3111
  }
3004
3112
  const pg = await import("pg");
3005
3113
  const { drizzle } = await import("drizzle-orm/node-postgres");
3006
- const connectionConfig = resolvePushConnectionConfig(env.DATABASE_URL);
3114
+ const connectionConfig = resolvePushConnectionConfig(env3.DATABASE_URL);
3007
3115
  const pool = new pg.default.Pool({
3008
3116
  ...connectionConfig,
3009
3117
  max: 1
@@ -3019,19 +3127,19 @@ async function createPushConnection() {
3019
3127
  async function dbGenerate() {
3020
3128
  try {
3021
3129
  await runDrizzleCommand("generate");
3022
- console.log(chalk11.green("\n\u2705 Migrations generated successfully"));
3130
+ console.log(chalk13.green("\n\u2705 Migrations generated successfully"));
3023
3131
  } catch (error) {
3024
- console.error(chalk11.red("\n\u274C Failed to generate migrations"));
3025
- console.error(chalk11.red(error instanceof Error ? error.message : "Unknown error"));
3132
+ console.error(chalk13.red("\n\u274C Failed to generate migrations"));
3133
+ console.error(chalk13.red(error instanceof Error ? error.message : "Unknown error"));
3026
3134
  process.exit(1);
3027
3135
  }
3028
3136
  }
3029
3137
 
3030
3138
  // src/commands/db/push.ts
3031
- import chalk14 from "chalk";
3139
+ import chalk15 from "chalk";
3032
3140
  import prompts3 from "prompts";
3033
3141
  import "@spfn/core/config";
3034
- import { loadEnv as loadEnv3 } from "@spfn/core/server";
3142
+ import { loadEnv as loadEnv4 } from "@spfn/core/server";
3035
3143
  import { sql } from "drizzle-orm";
3036
3144
  import { getTableConfig } from "drizzle-orm/pg-core";
3037
3145
 
@@ -3075,7 +3183,7 @@ function classifyStatements(statements) {
3075
3183
  }
3076
3184
 
3077
3185
  // src/commands/db/utils/push-display.ts
3078
- import chalk12 from "chalk";
3186
+ import chalk14 from "chalk";
3079
3187
  function formatSql(sql2) {
3080
3188
  return sql2.replace(/\s+/g, " ").trim();
3081
3189
  }
@@ -3083,30 +3191,30 @@ function printStatements(statements, color) {
3083
3191
  for (const stmt of statements) {
3084
3192
  console.log(color(` ${formatSql(stmt.sql)}`));
3085
3193
  if (stmt.reason) {
3086
- console.log(chalk12.dim(` \u2192 ${stmt.reason}`));
3194
+ console.log(chalk14.dim(` \u2192 ${stmt.reason}`));
3087
3195
  }
3088
3196
  }
3089
3197
  }
3090
3198
  function displayClassifiedStatements(result) {
3091
3199
  if (result.safe.length > 0) {
3092
- console.log(chalk12.green(`
3200
+ console.log(chalk14.green(`
3093
3201
  \u2705 Safe changes (${result.safe.length}):`));
3094
- printStatements(result.safe, chalk12.green);
3202
+ printStatements(result.safe, chalk14.green);
3095
3203
  }
3096
3204
  if (result.warning.length > 0) {
3097
- console.log(chalk12.yellow(`
3205
+ console.log(chalk14.yellow(`
3098
3206
  \u26A0\uFE0F Warnings (${result.warning.length}):`));
3099
- printStatements(result.warning, chalk12.yellow);
3207
+ printStatements(result.warning, chalk14.yellow);
3100
3208
  }
3101
3209
  if (result.destructive.length > 0) {
3102
- console.log(chalk12.red(`
3210
+ console.log(chalk14.red(`
3103
3211
  \u274C Destructive changes (${result.destructive.length}):`));
3104
- printStatements(result.destructive, chalk12.red);
3212
+ printStatements(result.destructive, chalk14.red);
3105
3213
  }
3106
3214
  }
3107
3215
  function displayDryRunSummary(result) {
3108
3216
  const total = result.safe.length + result.warning.length + result.destructive.length;
3109
- console.log(chalk12.cyan(`
3217
+ console.log(chalk14.cyan(`
3110
3218
  \u{1F50D} Dry-run: ${total} statement(s) detected
3111
3219
  `));
3112
3220
  displayClassifiedStatements(result);
@@ -3114,11 +3222,11 @@ function displayDryRunSummary(result) {
3114
3222
  }
3115
3223
  function displayApplySummary(applied, skipped) {
3116
3224
  if (applied > 0) {
3117
- console.log(chalk12.green(`
3225
+ console.log(chalk14.green(`
3118
3226
  \u2705 Applied ${applied} statement(s)`));
3119
3227
  }
3120
3228
  if (skipped > 0) {
3121
- console.log(chalk12.yellow(`\u23ED\uFE0F Skipped ${skipped} destructive statement(s)`));
3229
+ console.log(chalk14.yellow(`\u23ED\uFE0F Skipped ${skipped} destructive statement(s)`));
3122
3230
  }
3123
3231
  console.log("");
3124
3232
  }
@@ -3153,7 +3261,7 @@ async function applyStatements(db, statements) {
3153
3261
  }
3154
3262
  async function dbPush(options = {}) {
3155
3263
  validateDatabasePrerequisites();
3156
- loadEnv3();
3264
+ loadEnv4();
3157
3265
  const { getDrizzleConfig } = await import("@spfn/core/db");
3158
3266
  const config = getDrizzleConfig({
3159
3267
  cwd: process.cwd(),
@@ -3163,10 +3271,10 @@ async function dbPush(options = {}) {
3163
3271
  });
3164
3272
  const schemaFiles = Array.isArray(config.schema) ? config.schema : [config.schema];
3165
3273
  if (schemaFiles.length === 0) {
3166
- console.log(chalk14.yellow("No schema files found."));
3274
+ console.log(chalk15.yellow("No schema files found."));
3167
3275
  return;
3168
3276
  }
3169
- console.log(chalk14.dim(`Found ${schemaFiles.length} schema file(s)
3277
+ console.log(chalk15.dim(`Found ${schemaFiles.length} schema file(s)
3170
3278
  `));
3171
3279
  const imports = await loadSchemaImports(schemaFiles);
3172
3280
  const detectedSchemas = new Set(config.schemaFilter ?? ["public"]);
@@ -3185,10 +3293,10 @@ async function dbPush(options = {}) {
3185
3293
  try {
3186
3294
  const { statements, hints } = await resolvePushPlan(imports, db, schemaFilter);
3187
3295
  for (const hint of hints) {
3188
- console.log(chalk14.yellow(`\u26A0\uFE0F ${hint.hint}`));
3296
+ console.log(chalk15.yellow(`\u26A0\uFE0F ${hint.hint}`));
3189
3297
  }
3190
3298
  if (statements.length === 0) {
3191
- console.log(chalk14.green("\u2705 No changes detected \u2014 database is up to date\n"));
3299
+ console.log(chalk15.green("\u2705 No changes detected \u2014 database is up to date\n"));
3192
3300
  await applyFunctionMigrations(functionPlans);
3193
3301
  return;
3194
3302
  }
@@ -3199,7 +3307,7 @@ async function dbPush(options = {}) {
3199
3307
  }
3200
3308
  displayClassifiedStatements(result);
3201
3309
  if (options.force) {
3202
- console.log(chalk14.dim("\n--force: applying all changes..."));
3310
+ console.log(chalk15.dim("\n--force: applying all changes..."));
3203
3311
  await applyStatements(db, statements);
3204
3312
  displayApplySummary(statements.length, 0);
3205
3313
  } else if (result.destructive.length === 0) {
@@ -3208,11 +3316,11 @@ async function dbPush(options = {}) {
3208
3316
  } else {
3209
3317
  const destructiveSet = new Set(result.destructive.map((s) => s.sql));
3210
3318
  const nonDestructive = statements.filter((s) => !destructiveSet.has(s));
3211
- console.log(chalk14.red(`
3319
+ console.log(chalk15.red(`
3212
3320
  \u274C ${result.destructive.length} destructive change(s) require confirmation:`));
3213
3321
  for (const stmt of result.destructive) {
3214
- console.log(chalk14.red(` ${stmt.sql.replace(/\s+/g, " ").trim()}`));
3215
- console.log(chalk14.dim(` \u2192 ${stmt.reason}`));
3322
+ console.log(chalk15.red(` ${stmt.sql.replace(/\s+/g, " ").trim()}`));
3323
+ console.log(chalk15.dim(` \u2192 ${stmt.reason}`));
3216
3324
  }
3217
3325
  const { confirm } = await prompts3({
3218
3326
  type: "confirm",
@@ -3228,7 +3336,7 @@ async function dbPush(options = {}) {
3228
3336
  await applyStatements(db, nonDestructive);
3229
3337
  }
3230
3338
  displayApplySummary(nonDestructive.length, result.destructive.length);
3231
- console.log(chalk14.dim("Tip: Use --force to apply all changes without prompting.\n"));
3339
+ console.log(chalk15.dim("Tip: Use --force to apply all changes without prompting.\n"));
3232
3340
  }
3233
3341
  }
3234
3342
  await applyFunctionMigrations(functionPlans);
@@ -3241,8 +3349,8 @@ function loadFunctionPlansOrExit() {
3241
3349
  try {
3242
3350
  return loadFunctionMigrationPlans(functions);
3243
3351
  } catch (error) {
3244
- console.error(chalk14.red("\n\u274C Invalid function package migrations \u2014 nothing was applied"));
3245
- console.error(chalk14.red(error instanceof Error ? error.message : "Unknown error"));
3352
+ console.error(chalk15.red("\n\u274C Invalid function package migrations \u2014 nothing was applied"));
3353
+ console.error(chalk15.red(error instanceof Error ? error.message : "Unknown error"));
3246
3354
  process.exit(1);
3247
3355
  }
3248
3356
  }
@@ -3250,36 +3358,36 @@ async function applyFunctionMigrations(plans) {
3250
3358
  if (plans.length === 0) {
3251
3359
  return;
3252
3360
  }
3253
- console.log(chalk14.blue("\n\u{1F4E6} Applying function package migrations:"));
3361
+ console.log(chalk15.blue("\n\u{1F4E6} Applying function package migrations:"));
3254
3362
  plans.forEach((plan) => {
3255
- console.log(chalk14.dim(` - ${plan.packageName}`));
3363
+ console.log(chalk15.dim(` - ${plan.packageName}`));
3256
3364
  });
3257
3365
  try {
3258
3366
  await executeFunctionMigrations(plans);
3259
- console.log(chalk14.green("\n\u2705 All function migrations applied\n"));
3367
+ console.log(chalk15.green("\n\u2705 All function migrations applied\n"));
3260
3368
  } catch (error) {
3261
- console.error(chalk14.red("\n\u274C Failed to apply function package migrations"));
3262
- console.error(chalk14.red(error instanceof Error ? error.message : "Unknown error"));
3263
- console.error(chalk14.yellow("Project schema changes (if any) were already applied \u2014 only function package migrations failed."));
3369
+ console.error(chalk15.red("\n\u274C Failed to apply function package migrations"));
3370
+ console.error(chalk15.red(error instanceof Error ? error.message : "Unknown error"));
3371
+ console.error(chalk15.yellow("Project schema changes (if any) were already applied \u2014 only function package migrations failed."));
3264
3372
  process.exit(1);
3265
3373
  }
3266
3374
  }
3267
3375
 
3268
3376
  // src/commands/db/migrate.ts
3269
- import chalk19 from "chalk";
3270
- import { join as join20 } from "path";
3271
- import { existsSync as existsSync21 } from "fs";
3377
+ import chalk20 from "chalk";
3378
+ import { join as join21 } from "path";
3379
+ import { existsSync as existsSync22 } from "fs";
3272
3380
 
3273
3381
  // src/commands/db/backup.ts
3274
3382
  import { promises as fs3 } from "fs";
3275
3383
  import path3 from "path";
3276
3384
  import { spawn as spawn2 } from "child_process";
3277
- import chalk18 from "chalk";
3385
+ import chalk19 from "chalk";
3278
3386
  import ora7 from "ora";
3279
3387
 
3280
3388
  // src/commands/db/utils/database.ts
3281
3389
  import net from "net";
3282
- import chalk15 from "chalk";
3390
+ import chalk16 from "chalk";
3283
3391
  import prompts4 from "prompts";
3284
3392
  function parseDatabaseUrl2(dbUrl) {
3285
3393
  try {
@@ -3310,7 +3418,7 @@ async function confirmDangerousTarget(dbInfo) {
3310
3418
  message: `Remote/production database detected. Type the database name "${dbInfo.database}" to continue:`
3311
3419
  });
3312
3420
  if (typed !== dbInfo.database) {
3313
- console.log(chalk15.gray("Cancelled (database name mismatch)."));
3421
+ console.log(chalk16.gray("Cancelled (database name mismatch)."));
3314
3422
  process.exit(0);
3315
3423
  }
3316
3424
  }
@@ -3361,16 +3469,16 @@ function formatTimestamp() {
3361
3469
 
3362
3470
  // src/commands/db/utils/backup-files.ts
3363
3471
  import { promises as fs2 } from "fs";
3364
- import { existsSync as existsSync20 } from "fs";
3472
+ import { existsSync as existsSync21 } from "fs";
3365
3473
  import path2 from "path";
3366
- import chalk17 from "chalk";
3474
+ import chalk18 from "chalk";
3367
3475
 
3368
3476
  // src/commands/db/utils/metadata.ts
3369
3477
  import { promises as fs } from "fs";
3370
3478
  import path from "path";
3371
3479
  import { promisify } from "util";
3372
3480
  import { exec } from "child_process";
3373
- import chalk16 from "chalk";
3481
+ import chalk17 from "chalk";
3374
3482
  var execAsync = promisify(exec);
3375
3483
  async function collectGitInfo() {
3376
3484
  try {
@@ -3433,7 +3541,7 @@ async function collectMigrationInfo(dbUrl) {
3433
3541
  await pool.end();
3434
3542
  }
3435
3543
  } catch (error) {
3436
- console.log(chalk16.dim("\u26A0\uFE0F Could not fetch migration info"));
3544
+ console.log(chalk17.dim("\u26A0\uFE0F Could not fetch migration info"));
3437
3545
  return void 0;
3438
3546
  }
3439
3547
  }
@@ -3441,9 +3549,9 @@ async function saveBackupMetadata(metadata, backupFilename) {
3441
3549
  const metadataPath = backupFilename.replace(/\.(sql|dump)$/, ".meta.json");
3442
3550
  try {
3443
3551
  await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2));
3444
- console.log(chalk16.dim(`\u2713 Metadata saved: ${path.basename(metadataPath)}`));
3552
+ console.log(chalk17.dim(`\u2713 Metadata saved: ${path.basename(metadataPath)}`));
3445
3553
  } catch (error) {
3446
- console.log(chalk16.dim("\u26A0\uFE0F Could not save metadata"));
3554
+ console.log(chalk17.dim("\u26A0\uFE0F Could not save metadata"));
3447
3555
  }
3448
3556
  }
3449
3557
  async function loadBackupMetadata(backupFilename) {
@@ -3461,7 +3569,7 @@ async function ensureBackupInGitignore() {
3461
3569
  const gitignorePath = path2.join(process.cwd(), ".gitignore");
3462
3570
  try {
3463
3571
  let content = "";
3464
- let exists = existsSync20(gitignorePath);
3572
+ let exists = existsSync21(gitignorePath);
3465
3573
  if (exists) {
3466
3574
  content = await fs2.readFile(gitignorePath, "utf-8");
3467
3575
  }
@@ -3472,10 +3580,10 @@ async function ensureBackupInGitignore() {
3472
3580
  if (!hasBackupsIgnore) {
3473
3581
  const entry = exists && content && !content.endsWith("\n") ? "\n\n# Database backups\nbackups/\n" : "# Database backups\nbackups/\n";
3474
3582
  await fs2.appendFile(gitignorePath, entry);
3475
- console.log(chalk17.dim("\u2713 Added backups/ to .gitignore"));
3583
+ console.log(chalk18.dim("\u2713 Added backups/ to .gitignore"));
3476
3584
  }
3477
3585
  } catch (error) {
3478
- console.log(chalk17.dim("\u26A0\uFE0F Could not update .gitignore"));
3586
+ console.log(chalk18.dim("\u26A0\uFE0F Could not update .gitignore"));
3479
3587
  }
3480
3588
  }
3481
3589
  async function ensureBackupDir() {
@@ -3483,7 +3591,7 @@ async function ensureBackupDir() {
3483
3591
  try {
3484
3592
  await fs2.mkdir(backupDir, { recursive: true });
3485
3593
  const gitignorePath = path2.join(backupDir, ".gitignore");
3486
- const gitignoreExists = existsSync20(gitignorePath);
3594
+ const gitignoreExists = existsSync21(gitignorePath);
3487
3595
  if (!gitignoreExists) {
3488
3596
  await fs2.writeFile(gitignorePath, "# Ignore all backup files\n*.sql\n*.dump\n*.meta.json\n");
3489
3597
  }
@@ -3522,15 +3630,15 @@ async function listBackupFiles() {
3522
3630
  }
3523
3631
 
3524
3632
  // src/commands/db/backup.ts
3525
- import { env as env3 } from "@spfn/core/config";
3526
- import { loadEnv as loadEnv4 } from "@spfn/core/server";
3633
+ import { env as env4 } from "@spfn/core/config";
3634
+ import { loadEnv as loadEnv5 } from "@spfn/core/server";
3527
3635
  async function dbBackup(options) {
3528
- console.log(chalk18.blue("\u{1F4BE} Creating database backup...\n"));
3529
- loadEnv4();
3530
- const dbUrl = env3.DATABASE_URL;
3636
+ console.log(chalk19.blue("\u{1F4BE} Creating database backup...\n"));
3637
+ loadEnv5();
3638
+ const dbUrl = env4.DATABASE_URL;
3531
3639
  if (!dbUrl) {
3532
- console.error(chalk18.red("\u274C DATABASE_URL not found in environment"));
3533
- console.log(chalk18.yellow("\n\u{1F4A1} Tip: Add DATABASE_URL to your .env file"));
3640
+ console.error(chalk19.red("\u274C DATABASE_URL not found in environment"));
3641
+ console.log(chalk19.yellow("\n\u{1F4A1} Tip: Add DATABASE_URL to your .env file"));
3534
3642
  process.exit(1);
3535
3643
  }
3536
3644
  const dbInfo = parseDatabaseUrl2(dbUrl);
@@ -3540,7 +3648,7 @@ async function dbBackup(options) {
3540
3648
  const ext = format === "sql" ? "sql" : "dump";
3541
3649
  const filename = options.output || path3.join(backupDir, `${dbInfo.database}_${timestamp}.${ext}`);
3542
3650
  if (options.dataOnly && options.schemaOnly) {
3543
- console.error(chalk18.red("\u274C Cannot use --data-only and --schema-only together"));
3651
+ console.error(chalk19.red("\u274C Cannot use --data-only and --schema-only together"));
3544
3652
  process.exit(1);
3545
3653
  }
3546
3654
  const args = [
@@ -3586,11 +3694,11 @@ async function dbBackup(options) {
3586
3694
  const stats = await fs3.stat(filename);
3587
3695
  const size = formatBytes(stats.size);
3588
3696
  spinner.succeed("Backup created");
3589
- console.log(chalk18.green(`
3697
+ console.log(chalk19.green(`
3590
3698
  \u2705 Backup created successfully`));
3591
- console.log(chalk18.gray(` File: ${filename}`));
3592
- console.log(chalk18.gray(` Size: ${size}`));
3593
- console.log(chalk18.dim("\n\u{1F4CB} Collecting metadata..."));
3699
+ console.log(chalk19.gray(` File: ${filename}`));
3700
+ console.log(chalk19.gray(` Size: ${size}`));
3701
+ console.log(chalk19.dim("\n\u{1F4CB} Collecting metadata..."));
3594
3702
  const [gitInfo, migrationInfo] = await Promise.all([
3595
3703
  collectGitInfo(),
3596
3704
  collectMigrationInfo(dbUrl)
@@ -3630,19 +3738,19 @@ async function dbBackup(options) {
3630
3738
  reject(error);
3631
3739
  });
3632
3740
  }).catch((error) => {
3633
- console.error(chalk18.red("\n\u274C Failed to create backup"));
3741
+ console.error(chalk19.red("\n\u274C Failed to create backup"));
3634
3742
  if (errorOutput.includes("pg_dump: command not found") || errorOutput.includes("not found")) {
3635
- console.error(chalk18.yellow("\n\u{1F4A1} pg_dump is not installed. Please install PostgreSQL client tools."));
3743
+ console.error(chalk19.yellow("\n\u{1F4A1} pg_dump is not installed. Please install PostgreSQL client tools."));
3636
3744
  } else {
3637
- console.error(chalk18.red(error instanceof Error ? error.message : "Unknown error"));
3745
+ console.error(chalk19.red(error instanceof Error ? error.message : "Unknown error"));
3638
3746
  }
3639
3747
  process.exit(1);
3640
3748
  });
3641
3749
  }
3642
3750
 
3643
3751
  // src/commands/db/migrate.ts
3644
- import { env as env4 } from "@spfn/core/config";
3645
- import { loadEnv as loadEnv5 } from "@spfn/core/server";
3752
+ import { env as env5 } from "@spfn/core/config";
3753
+ import { loadEnv as loadEnv6 } from "@spfn/core/server";
3646
3754
  var PROJECT_MIGRATIONS_TABLE = "__drizzle_migrations";
3647
3755
  async function dbMigrate(options = {}) {
3648
3756
  try {
@@ -3651,7 +3759,7 @@ async function dbMigrate(options = {}) {
3651
3759
  process.exit(1);
3652
3760
  }
3653
3761
  if (options.withBackup) {
3654
- console.log(chalk19.blue("\u{1F4E6} Creating pre-migration backup...\n"));
3762
+ console.log(chalk20.blue("\u{1F4E6} Creating pre-migration backup...\n"));
3655
3763
  await dbBackup({
3656
3764
  format: "custom",
3657
3765
  tag: "pre-migration",
@@ -3662,68 +3770,108 @@ async function dbMigrate(options = {}) {
3662
3770
  const { drizzle } = await import("drizzle-orm/postgres-js");
3663
3771
  const { migrate } = await import("drizzle-orm/postgres-js/migrator");
3664
3772
  const postgres = await import("postgres");
3665
- loadEnv5();
3666
- if (!env4.DATABASE_URL) {
3667
- console.error(chalk19.red("\u274C DATABASE_URL not found in environment"));
3773
+ loadEnv6();
3774
+ if (!env5.DATABASE_URL) {
3775
+ console.error(chalk20.red("\u274C DATABASE_URL not found in environment"));
3668
3776
  process.exit(1);
3669
3777
  }
3670
3778
  const { discoverFunctionMigrations: discoverFunctionMigrations2, loadFunctionMigrationPlans: loadFunctionMigrationPlans2, executeFunctionMigrations: executeFunctionMigrations2 } = await Promise.resolve().then(() => (init_function_migrations(), function_migrations_exports));
3671
3779
  const functions = discoverFunctionMigrations2(process.cwd());
3672
3780
  if (functions.length > 0) {
3673
- console.log(chalk19.blue("\u{1F4E6} Applying function package migrations:"));
3781
+ console.log(chalk20.blue("\u{1F4E6} Applying function package migrations:"));
3674
3782
  functions.forEach((func) => {
3675
- console.log(chalk19.dim(` - ${func.packageName}`));
3783
+ console.log(chalk20.dim(` - ${func.packageName}`));
3676
3784
  });
3677
3785
  await executeFunctionMigrations2(loadFunctionMigrationPlans2(functions));
3678
- console.log(chalk19.green("\u2705 Function migrations applied\n"));
3786
+ console.log(chalk20.green("\u2705 Function migrations applied\n"));
3679
3787
  }
3680
- const projectMigrationsDir = join20(process.cwd(), "src/server/drizzle");
3681
- if (existsSync21(projectMigrationsDir)) {
3682
- const projConn = postgres.default(env4.DATABASE_URL, { max: 1 });
3788
+ const projectMigrationsDir = join21(process.cwd(), "src/server/drizzle");
3789
+ if (existsSync22(projectMigrationsDir)) {
3790
+ const projConn = postgres.default(env5.DATABASE_URL, { max: 1 });
3683
3791
  const projDb = drizzle({ client: projConn });
3684
3792
  try {
3685
- console.log(chalk19.blue("\u{1F4E6} Running project migrations..."));
3793
+ console.log(chalk20.blue("\u{1F4E6} Running project migrations..."));
3686
3794
  await migrate(projDb, {
3687
3795
  migrationsFolder: projectMigrationsDir,
3688
3796
  migrationsTable: PROJECT_MIGRATIONS_TABLE
3689
3797
  });
3690
- console.log(chalk19.green("\u2705 Project migrations applied successfully"));
3798
+ console.log(chalk20.green("\u2705 Project migrations applied successfully"));
3691
3799
  } finally {
3692
3800
  await projConn.end();
3693
3801
  }
3694
3802
  } else {
3695
- console.log(chalk19.dim("No project migrations found (src/server/drizzle)"));
3803
+ console.log(chalk20.dim("No project migrations found (src/server/drizzle)"));
3804
+ }
3805
+ }
3806
+
3807
+ // src/commands/db/status.ts
3808
+ import chalk21 from "chalk";
3809
+ init_migration_status();
3810
+ async function dbStatus() {
3811
+ try {
3812
+ validateDatabasePrerequisites();
3813
+ } catch (error) {
3814
+ process.exit(1);
3815
+ }
3816
+ let status;
3817
+ try {
3818
+ status = await getMigrationStatus(process.cwd());
3819
+ } catch (error) {
3820
+ console.error(chalk21.red("\u274C Failed to read migration status"));
3821
+ console.error(chalk21.red(error instanceof Error ? error.message : "Unknown error"));
3822
+ process.exit(1);
3823
+ }
3824
+ const targets = [...status.packages, ...status.project ? [status.project] : []];
3825
+ if (targets.length === 0) {
3826
+ console.log(chalk21.dim("No migrations found (no @spfn packages with migrations, no src/server/drizzle)."));
3827
+ return;
3828
+ }
3829
+ console.log(chalk21.blue("\u{1F4E6} Migration status:\n"));
3830
+ for (const target of targets) {
3831
+ const state = target.pending === 0 ? chalk21.green(`${target.applied}/${target.total} applied`) : chalk21.yellow(`${target.applied}/${target.total} applied, ${target.pending} pending`);
3832
+ console.log(` ${target.name.padEnd(32)} ${state}`);
3833
+ for (const tag of target.pendingTags) {
3834
+ console.log(chalk21.dim(` - ${tag}`));
3835
+ }
3836
+ }
3837
+ const pendingTotal = targets.reduce((sum, t) => sum + t.pending, 0);
3838
+ if (pendingTotal === 0) {
3839
+ console.log(chalk21.green("\n\u2705 Database is up to date\n"));
3840
+ } else {
3841
+ console.log(chalk21.yellow(`
3842
+ \u26A0\uFE0F ${pendingTotal} pending migration(s) \u2014 run: pnpm spfn db migrate
3843
+ `));
3696
3844
  }
3697
3845
  }
3698
3846
 
3699
3847
  // src/commands/db/studio.ts
3700
- import chalk20 from "chalk";
3701
- import { existsSync as existsSync22, writeFileSync as writeFileSync14, unlinkSync as unlinkSync3 } from "fs";
3848
+ import chalk22 from "chalk";
3849
+ import { existsSync as existsSync23, writeFileSync as writeFileSync14, unlinkSync as unlinkSync3 } from "fs";
3702
3850
  import { spawn as spawn3 } from "child_process";
3703
- import { env as env5 } from "@spfn/core/config";
3851
+ import { env as env6 } from "@spfn/core/config";
3704
3852
  async function dbStudio(requestedPort) {
3705
- console.log(chalk20.blue("\u{1F3A8} Opening Drizzle Studio...\n"));
3853
+ console.log(chalk22.blue("\u{1F3A8} Opening Drizzle Studio...\n"));
3706
3854
  const defaultPort = 4983;
3707
3855
  const startPort = requestedPort || defaultPort;
3708
3856
  let port;
3709
3857
  try {
3710
3858
  port = await findAvailablePort(startPort);
3711
3859
  if (port !== startPort) {
3712
- console.log(chalk20.yellow(`\u26A0\uFE0F Port ${startPort} is in use, using port ${port} instead
3860
+ console.log(chalk22.yellow(`\u26A0\uFE0F Port ${startPort} is in use, using port ${port} instead
3713
3861
  `));
3714
3862
  }
3715
3863
  } catch (error) {
3716
- console.error(chalk20.red(error instanceof Error ? error.message : "Failed to find available port"));
3864
+ console.error(chalk22.red(error instanceof Error ? error.message : "Failed to find available port"));
3717
3865
  process.exit(1);
3718
3866
  }
3719
- const hasUserConfig = existsSync22("./drizzle.config.ts");
3867
+ const hasUserConfig = existsSync23("./drizzle.config.ts");
3720
3868
  const tempConfigPath = `./drizzle.config.${process.pid}.${Date.now()}.temp.ts`;
3721
3869
  try {
3722
3870
  const configPath = hasUserConfig ? "./drizzle.config.ts" : tempConfigPath;
3723
3871
  if (!hasUserConfig) {
3724
- if (!env5.DATABASE_URL) {
3725
- console.error(chalk20.red("\u274C DATABASE_URL not found in environment"));
3726
- console.log(chalk20.yellow("\n\u{1F4A1} Tip: Add DATABASE_URL to your .env file"));
3872
+ if (!env6.DATABASE_URL) {
3873
+ console.error(chalk22.red("\u274C DATABASE_URL not found in environment"));
3874
+ console.log(chalk22.yellow("\n\u{1F4A1} Tip: Add DATABASE_URL to your .env file"));
3727
3875
  process.exit(1);
3728
3876
  }
3729
3877
  const { generateDrizzleConfigFile } = await import("@spfn/core/db");
@@ -3734,34 +3882,34 @@ async function dbStudio(requestedPort) {
3734
3882
  // Expand glob patterns for Studio compatibility
3735
3883
  });
3736
3884
  writeFileSync14(tempConfigPath, configContent);
3737
- console.log(chalk20.dim("Using auto-generated Drizzle config\n"));
3885
+ console.log(chalk22.dim("Using auto-generated Drizzle config\n"));
3738
3886
  }
3739
3887
  const studioProcess = spawn3("drizzle-kit", ["studio", `--port=${port}`, `--config=${configPath}`], {
3740
3888
  stdio: "inherit",
3741
3889
  shell: true,
3742
- env: shouldRelaxDbTls(env5.DATABASE_URL) ? { ...process.env, NODE_TLS_REJECT_UNAUTHORIZED: "0" } : { ...process.env }
3890
+ env: shouldRelaxDbTls(env6.DATABASE_URL) ? { ...process.env, NODE_TLS_REJECT_UNAUTHORIZED: "0" } : { ...process.env }
3743
3891
  });
3744
3892
  const cleanup = () => {
3745
- if (!hasUserConfig && existsSync22(tempConfigPath)) {
3893
+ if (!hasUserConfig && existsSync23(tempConfigPath)) {
3746
3894
  unlinkSync3(tempConfigPath);
3747
3895
  }
3748
3896
  };
3749
3897
  studioProcess.on("exit", (code) => {
3750
3898
  cleanup();
3751
3899
  if (code !== 0 && code !== null) {
3752
- console.error(chalk20.red(`
3900
+ console.error(chalk22.red(`
3753
3901
  \u274C Drizzle Studio exited with code ${code}`));
3754
3902
  process.exit(code);
3755
3903
  }
3756
3904
  });
3757
3905
  studioProcess.on("error", (error) => {
3758
3906
  cleanup();
3759
- console.error(chalk20.red("\u274C Failed to start Drizzle Studio"));
3760
- console.error(chalk20.red(error.message));
3907
+ console.error(chalk22.red("\u274C Failed to start Drizzle Studio"));
3908
+ console.error(chalk22.red(error.message));
3761
3909
  process.exit(1);
3762
3910
  });
3763
3911
  process.on("SIGINT", () => {
3764
- console.log(chalk20.yellow("\n\n\u{1F44B} Shutting down Drizzle Studio..."));
3912
+ console.log(chalk22.yellow("\n\n\u{1F44B} Shutting down Drizzle Studio..."));
3765
3913
  studioProcess.kill("SIGTERM");
3766
3914
  cleanup();
3767
3915
  process.exit(0);
@@ -3772,30 +3920,30 @@ async function dbStudio(requestedPort) {
3772
3920
  process.exit(0);
3773
3921
  });
3774
3922
  } catch (error) {
3775
- if (!hasUserConfig && existsSync22(tempConfigPath)) {
3923
+ if (!hasUserConfig && existsSync23(tempConfigPath)) {
3776
3924
  unlinkSync3(tempConfigPath);
3777
3925
  }
3778
- console.error(chalk20.red("\u274C Failed to start Drizzle Studio"));
3779
- console.error(chalk20.red(error instanceof Error ? error.message : "Unknown error"));
3926
+ console.error(chalk22.red("\u274C Failed to start Drizzle Studio"));
3927
+ console.error(chalk22.red(error instanceof Error ? error.message : "Unknown error"));
3780
3928
  process.exit(1);
3781
3929
  }
3782
3930
  }
3783
3931
 
3784
3932
  // src/commands/db/drop.ts
3785
- import chalk21 from "chalk";
3933
+ import chalk23 from "chalk";
3786
3934
  import prompts5 from "prompts";
3787
- import { env as env6 } from "@spfn/core/config";
3788
- import { loadEnv as loadEnv6 } from "@spfn/core/server";
3935
+ import { env as env7 } from "@spfn/core/config";
3936
+ import { loadEnv as loadEnv7 } from "@spfn/core/server";
3789
3937
  async function dbDrop() {
3790
- loadEnv6();
3791
- if (!env6.DATABASE_URL) {
3792
- console.error(chalk21.red("\u274C DATABASE_URL not found in environment"));
3793
- console.log(chalk21.yellow("\n\u{1F4A1} Tip: Add DATABASE_URL to your .env file"));
3938
+ loadEnv7();
3939
+ if (!env7.DATABASE_URL) {
3940
+ console.error(chalk23.red("\u274C DATABASE_URL not found in environment"));
3941
+ console.log(chalk23.yellow("\n\u{1F4A1} Tip: Add DATABASE_URL to your .env file"));
3794
3942
  process.exit(1);
3795
3943
  }
3796
- const dbInfo = parseDatabaseUrl2(env6.DATABASE_URL);
3797
- console.log(chalk21.yellow("\u26A0\uFE0F WARNING: This will drop all tables in your database!"));
3798
- console.log(chalk21.dim(` Target: ${dbInfo.database} @ ${dbInfo.host}:${dbInfo.port}
3944
+ const dbInfo = parseDatabaseUrl2(env7.DATABASE_URL);
3945
+ console.log(chalk23.yellow("\u26A0\uFE0F WARNING: This will drop all tables in your database!"));
3946
+ console.log(chalk23.dim(` Target: ${dbInfo.database} @ ${dbInfo.host}:${dbInfo.port}
3799
3947
  `));
3800
3948
  const { confirm } = await prompts5({
3801
3949
  type: "confirm",
@@ -3804,7 +3952,7 @@ async function dbDrop() {
3804
3952
  initial: false
3805
3953
  });
3806
3954
  if (!confirm) {
3807
- console.log(chalk21.gray("Cancelled."));
3955
+ console.log(chalk23.gray("Cancelled."));
3808
3956
  process.exit(0);
3809
3957
  }
3810
3958
  await confirmDangerousTarget(dbInfo);
@@ -3817,16 +3965,16 @@ async function dbDrop() {
3817
3965
  }
3818
3966
 
3819
3967
  // src/commands/db/check.ts
3820
- import chalk22 from "chalk";
3968
+ import chalk24 from "chalk";
3821
3969
  import ora8 from "ora";
3822
3970
  async function dbCheck() {
3823
- const spinner = ora8("Checking database connection...").start();
3971
+ const spinner = ora8("Checking migration files...").start();
3824
3972
  try {
3825
3973
  await runDrizzleCommand("check");
3826
- spinner.succeed("Database connection OK");
3974
+ spinner.succeed("Migration files consistent");
3827
3975
  } catch (error) {
3828
- spinner.fail("Database connection failed");
3829
- console.error(chalk22.red(error instanceof Error ? error.message : "Unknown error"));
3976
+ spinner.fail("Migration file check failed");
3977
+ console.error(chalk24.red(error instanceof Error ? error.message : "Unknown error"));
3830
3978
  process.exit(1);
3831
3979
  }
3832
3980
  }
@@ -3834,25 +3982,25 @@ async function dbCheck() {
3834
3982
  // src/commands/db/restore.ts
3835
3983
  import path4 from "path";
3836
3984
  import { spawn as spawn4 } from "child_process";
3837
- import chalk23 from "chalk";
3985
+ import chalk25 from "chalk";
3838
3986
  import ora9 from "ora";
3839
3987
  import prompts6 from "prompts";
3840
- import { env as env7 } from "@spfn/core/config";
3841
- import { loadEnv as loadEnv7 } from "@spfn/core/server";
3988
+ import { env as env8 } from "@spfn/core/config";
3989
+ import { loadEnv as loadEnv8 } from "@spfn/core/server";
3842
3990
  async function dbRestore(backupFile, options = {}) {
3843
- console.log(chalk23.blue("\u267B\uFE0F Restoring database from backup...\n"));
3844
- loadEnv7();
3845
- const dbUrl = env7.DATABASE_URL;
3991
+ console.log(chalk25.blue("\u267B\uFE0F Restoring database from backup...\n"));
3992
+ loadEnv8();
3993
+ const dbUrl = env8.DATABASE_URL;
3846
3994
  if (!dbUrl) {
3847
- console.error(chalk23.red("\u274C DATABASE_URL not found in environment"));
3848
- console.log(chalk23.yellow("\n\u{1F4A1} Tip: Add DATABASE_URL to your .env file"));
3995
+ console.error(chalk25.red("\u274C DATABASE_URL not found in environment"));
3996
+ console.log(chalk25.yellow("\n\u{1F4A1} Tip: Add DATABASE_URL to your .env file"));
3849
3997
  process.exit(1);
3850
3998
  }
3851
3999
  let file = backupFile;
3852
4000
  if (!file) {
3853
4001
  const backups = await listBackupFiles();
3854
4002
  if (backups.length === 0) {
3855
- console.log(chalk23.yellow("No backups found in ./backups directory"));
4003
+ console.log(chalk25.yellow("No backups found in ./backups directory"));
3856
4004
  process.exit(0);
3857
4005
  }
3858
4006
  const { selected } = await prompts6({
@@ -3865,31 +4013,31 @@ async function dbRestore(backupFile, options = {}) {
3865
4013
  }))
3866
4014
  });
3867
4015
  if (!selected) {
3868
- console.log(chalk23.gray("Cancelled"));
4016
+ console.log(chalk25.gray("Cancelled"));
3869
4017
  process.exit(0);
3870
4018
  }
3871
4019
  file = selected;
3872
4020
  }
3873
4021
  if (!file) {
3874
- console.error(chalk23.red("\u274C No backup file selected"));
4022
+ console.error(chalk25.red("\u274C No backup file selected"));
3875
4023
  process.exit(1);
3876
4024
  }
3877
4025
  const metadata = await loadBackupMetadata(file);
3878
4026
  if (metadata) {
3879
- console.log(chalk23.blue("\n\u{1F4CB} Backup Information:\n"));
3880
- console.log(chalk23.dim(` Database: ${metadata.database}`));
3881
- console.log(chalk23.dim(` Created: ${new Date(metadata.timestamp).toLocaleString()}`));
4027
+ console.log(chalk25.blue("\n\u{1F4CB} Backup Information:\n"));
4028
+ console.log(chalk25.dim(` Database: ${metadata.database}`));
4029
+ console.log(chalk25.dim(` Created: ${new Date(metadata.timestamp).toLocaleString()}`));
3882
4030
  if (metadata.environment) {
3883
- console.log(chalk23.dim(` Environment: ${metadata.environment}`));
4031
+ console.log(chalk25.dim(` Environment: ${metadata.environment}`));
3884
4032
  }
3885
4033
  if (metadata.tags && metadata.tags.length > 0) {
3886
- console.log(chalk23.dim(` Tags: ${metadata.tags.join(", ")}`));
4034
+ console.log(chalk25.dim(` Tags: ${metadata.tags.join(", ")}`));
3887
4035
  }
3888
4036
  if (metadata.backup.dataOnly) {
3889
- console.log(chalk23.yellow(" \u26A0\uFE0F Data-only backup (no schema)"));
4037
+ console.log(chalk25.yellow(" \u26A0\uFE0F Data-only backup (no schema)"));
3890
4038
  }
3891
4039
  if (metadata.backup.schemaOnly) {
3892
- console.log(chalk23.yellow(" \u26A0\uFE0F Schema-only backup (no data)"));
4040
+ console.log(chalk25.yellow(" \u26A0\uFE0F Schema-only backup (no data)"));
3893
4041
  }
3894
4042
  const warnings2 = [];
3895
4043
  const [currentGitInfo, currentMigrationInfo] = await Promise.all([
@@ -3912,8 +4060,8 @@ async function dbRestore(backupFile, options = {}) {
3912
4060
  }
3913
4061
  }
3914
4062
  if (warnings2.length > 0) {
3915
- console.log(chalk23.yellow("\n\u26A0\uFE0F Version Warnings:\n"));
3916
- warnings2.forEach((warning) => console.log(chalk23.yellow(` - ${warning}`)));
4063
+ console.log(chalk25.yellow("\n\u26A0\uFE0F Version Warnings:\n"));
4064
+ warnings2.forEach((warning) => console.log(chalk25.yellow(` - ${warning}`)));
3917
4065
  console.log("");
3918
4066
  }
3919
4067
  }
@@ -3921,16 +4069,16 @@ async function dbRestore(backupFile, options = {}) {
3921
4069
  const { confirm } = await prompts6({
3922
4070
  type: "confirm",
3923
4071
  name: "confirm",
3924
- message: chalk23.yellow(`\u26A0\uFE0F This will replace all data in "${dbInfo.database}" @ ${dbInfo.host}:${dbInfo.port}. Continue?`),
4072
+ message: chalk25.yellow(`\u26A0\uFE0F This will replace all data in "${dbInfo.database}" @ ${dbInfo.host}:${dbInfo.port}. Continue?`),
3925
4073
  initial: false
3926
4074
  });
3927
4075
  if (!confirm) {
3928
- console.log(chalk23.gray("Cancelled"));
4076
+ console.log(chalk25.gray("Cancelled"));
3929
4077
  process.exit(0);
3930
4078
  }
3931
4079
  await confirmDangerousTarget(dbInfo);
3932
4080
  if (options.dataOnly && options.schemaOnly) {
3933
- console.error(chalk23.red("\u274C Cannot use --data-only and --schema-only together"));
4081
+ console.error(chalk25.red("\u274C Cannot use --data-only and --schema-only together"));
3934
4082
  process.exit(1);
3935
4083
  }
3936
4084
  const ext = path4.extname(file);
@@ -3958,11 +4106,11 @@ async function dbRestore(backupFile, options = {}) {
3958
4106
  args.push(file);
3959
4107
  } else {
3960
4108
  if (options.drop) {
3961
- console.log(chalk23.yellow("\u26A0\uFE0F Note: --drop only works with custom format backups (.dump) and was ignored."));
4109
+ console.log(chalk25.yellow("\u26A0\uFE0F Note: --drop only works with custom format backups (.dump) and was ignored."));
3962
4110
  }
3963
4111
  if (options.dataOnly || options.schemaOnly) {
3964
- console.log(chalk23.yellow("\u26A0\uFE0F Note: --data-only and --schema-only options only work with custom format backups (.dump)"));
3965
- console.log(chalk23.yellow(" For SQL files, the backup must have been created with the desired option.\n"));
4112
+ console.log(chalk25.yellow("\u26A0\uFE0F Note: --data-only and --schema-only options only work with custom format backups (.dump)"));
4113
+ console.log(chalk25.yellow(" For SQL files, the backup must have been created with the desired option.\n"));
3966
4114
  }
3967
4115
  args.push("-h", dbInfo.host);
3968
4116
  args.push("-p", dbInfo.port);
@@ -4005,7 +4153,7 @@ async function dbRestore(backupFile, options = {}) {
4005
4153
  }
4006
4154
  if (verbose) {
4007
4155
  spinner.stop();
4008
- console.log(chalk23.dim(` ${line.trim()}`));
4156
+ console.log(chalk25.dim(` ${line.trim()}`));
4009
4157
  spinner.start();
4010
4158
  }
4011
4159
  }
@@ -4013,7 +4161,7 @@ async function dbRestore(backupFile, options = {}) {
4013
4161
  restoreProcess.stdout?.on("data", (data) => {
4014
4162
  if (verbose) {
4015
4163
  spinner.stop();
4016
- console.log(chalk23.dim(` ${data.toString().trim()}`));
4164
+ console.log(chalk25.dim(` ${data.toString().trim()}`));
4017
4165
  spinner.start();
4018
4166
  }
4019
4167
  });
@@ -4023,31 +4171,31 @@ async function dbRestore(backupFile, options = {}) {
4023
4171
  const summary = objectCount > 0 ? ` (${objectCount} objects)` : "";
4024
4172
  spinner.succeed(`Restore completed${summary}`);
4025
4173
  if (warnings.length > 0) {
4026
- console.log(chalk23.yellow(`
4174
+ console.log(chalk25.yellow(`
4027
4175
  \u26A0\uFE0F Warnings during restore (${warnings.length}):
4028
4176
  `));
4029
4177
  for (const w of warnings) {
4030
- console.log(chalk23.yellow(` - ${w}`));
4178
+ console.log(chalk25.yellow(` - ${w}`));
4031
4179
  }
4032
4180
  }
4033
- console.log(chalk23.green("\n\u2705 Database restored successfully"));
4181
+ console.log(chalk25.green("\n\u2705 Database restored successfully"));
4034
4182
  resolve3();
4035
4183
  } else {
4036
4184
  spinner.fail("Restore failed");
4037
4185
  if (errors.length > 0) {
4038
- console.error(chalk23.red(`
4186
+ console.error(chalk25.red(`
4039
4187
  \u274C Errors (${errors.length}):
4040
4188
  `));
4041
4189
  for (const e of errors) {
4042
- console.error(chalk23.red(` - ${e}`));
4190
+ console.error(chalk25.red(` - ${e}`));
4043
4191
  }
4044
4192
  }
4045
4193
  if (warnings.length > 0) {
4046
- console.log(chalk23.yellow(`
4194
+ console.log(chalk25.yellow(`
4047
4195
  \u26A0\uFE0F Warnings (${warnings.length}):
4048
4196
  `));
4049
4197
  for (const w of warnings) {
4050
- console.log(chalk23.yellow(` - ${w}`));
4198
+ console.log(chalk25.yellow(` - ${w}`));
4051
4199
  }
4052
4200
  }
4053
4201
  const fallback = errors.length === 0 && warnings.length === 0 ? "Restore failed with no output" : "";
@@ -4061,7 +4209,7 @@ async function dbRestore(backupFile, options = {}) {
4061
4209
  }).catch((error) => {
4062
4210
  const msg = error instanceof Error ? error.message : "Unknown error";
4063
4211
  if (msg) {
4064
- console.error(chalk23.red(`
4212
+ console.error(chalk25.red(`
4065
4213
  \u274C ${msg}`));
4066
4214
  }
4067
4215
  process.exit(1);
@@ -4069,17 +4217,17 @@ async function dbRestore(backupFile, options = {}) {
4069
4217
  }
4070
4218
 
4071
4219
  // src/commands/db/list.ts
4072
- import chalk24 from "chalk";
4220
+ import chalk26 from "chalk";
4073
4221
  async function dbBackupList() {
4074
- console.log(chalk24.blue("\u{1F4CB} Database backups:\n"));
4222
+ console.log(chalk26.blue("\u{1F4CB} Database backups:\n"));
4075
4223
  const backups = await listBackupFiles();
4076
4224
  if (backups.length === 0) {
4077
- console.log(chalk24.yellow("No backups found in ./backups directory"));
4078
- console.log(chalk24.gray("\n\u{1F4A1} Create a backup with: pnpm spfn db backup\n"));
4225
+ console.log(chalk26.yellow("No backups found in ./backups directory"));
4226
+ console.log(chalk26.gray("\n\u{1F4A1} Create a backup with: pnpm spfn db backup\n"));
4079
4227
  return;
4080
4228
  }
4081
- console.log(chalk24.bold(" Date Size File"));
4082
- console.log(chalk24.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"));
4229
+ console.log(chalk26.bold(" Date Size File"));
4230
+ console.log(chalk26.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"));
4083
4231
  backups.forEach((backup) => {
4084
4232
  const date = backup.date.toLocaleString("en-US", {
4085
4233
  year: "numeric",
@@ -4090,23 +4238,23 @@ async function dbBackupList() {
4090
4238
  second: "2-digit"
4091
4239
  });
4092
4240
  const sizeStr = backup.size.padEnd(10);
4093
- console.log(chalk24.white(` ${date} ${sizeStr} ${backup.name}`));
4241
+ console.log(chalk26.white(` ${date} ${sizeStr} ${backup.name}`));
4094
4242
  });
4095
- console.log(chalk24.gray(`
4243
+ console.log(chalk26.gray(`
4096
4244
  Total: ${backups.length} backup(s)
4097
4245
  `));
4098
4246
  }
4099
4247
 
4100
4248
  // src/commands/db/clean.ts
4101
4249
  import { promises as fs4 } from "fs";
4102
- import chalk25 from "chalk";
4250
+ import chalk27 from "chalk";
4103
4251
  import ora10 from "ora";
4104
4252
  import prompts7 from "prompts";
4105
4253
  async function dbBackupClean(options) {
4106
- console.log(chalk25.blue("\u{1F9F9} Cleaning old backups...\n"));
4254
+ console.log(chalk27.blue("\u{1F9F9} Cleaning old backups...\n"));
4107
4255
  const backups = await listBackupFiles();
4108
4256
  if (backups.length === 0) {
4109
- console.log(chalk25.yellow("No backups found"));
4257
+ console.log(chalk27.yellow("No backups found"));
4110
4258
  return;
4111
4259
  }
4112
4260
  let toDelete = [];
@@ -4123,13 +4271,13 @@ async function dbBackupClean(options) {
4123
4271
  toDelete = backups.slice(defaultKeep);
4124
4272
  }
4125
4273
  if (toDelete.length === 0) {
4126
- console.log(chalk25.green("\u2705 No backups to clean"));
4274
+ console.log(chalk27.green("\u2705 No backups to clean"));
4127
4275
  return;
4128
4276
  }
4129
- console.log(chalk25.yellow(`The following ${toDelete.length} backup(s) will be deleted:
4277
+ console.log(chalk27.yellow(`The following ${toDelete.length} backup(s) will be deleted:
4130
4278
  `));
4131
4279
  toDelete.forEach((backup) => {
4132
- console.log(chalk25.gray(` - ${backup.name} (${backup.size})`));
4280
+ console.log(chalk27.gray(` - ${backup.name} (${backup.size})`));
4133
4281
  });
4134
4282
  const { confirm } = await prompts7({
4135
4283
  type: "confirm",
@@ -4138,7 +4286,7 @@ async function dbBackupClean(options) {
4138
4286
  initial: false
4139
4287
  });
4140
4288
  if (!confirm) {
4141
- console.log(chalk25.gray("Cancelled"));
4289
+ console.log(chalk27.gray("Cancelled"));
4142
4290
  return;
4143
4291
  }
4144
4292
  const spinner = ora10("Deleting backups...").start();
@@ -4149,20 +4297,20 @@ async function dbBackupClean(options) {
4149
4297
  fs4.rm(backup.path.replace(/\.(sql|dump)$/, ".meta.json"), { force: true })
4150
4298
  ]));
4151
4299
  spinner.succeed("Backups deleted");
4152
- console.log(chalk25.green(`
4300
+ console.log(chalk27.green(`
4153
4301
  \u2705 Deleted ${toDelete.length} backup(s)`));
4154
4302
  } catch (error) {
4155
4303
  spinner.fail("Failed to delete backups");
4156
- console.error(chalk25.red(error instanceof Error ? error.message : "Unknown error"));
4304
+ console.error(chalk27.red(error instanceof Error ? error.message : "Unknown error"));
4157
4305
  process.exit(1);
4158
4306
  }
4159
4307
  }
4160
4308
 
4161
4309
  // src/commands/db/reindex.ts
4162
- import { existsSync as existsSync23, readFileSync as readFileSync10, writeFileSync as writeFileSync15, renameSync, copyFileSync } from "fs";
4163
- import { join as join21 } from "path";
4164
- import chalk26 from "chalk";
4165
- import { loadEnv as loadEnv8 } from "@spfn/core/server";
4310
+ import { existsSync as existsSync24, readFileSync as readFileSync10, writeFileSync as writeFileSync15, renameSync, copyFileSync } from "fs";
4311
+ import { join as join22 } from "path";
4312
+ import chalk28 from "chalk";
4313
+ import { loadEnv as loadEnv9 } from "@spfn/core/server";
4166
4314
  function isTimestampPrefix(tag) {
4167
4315
  const prefix = tag.split("_")[0];
4168
4316
  return /^\d{5,}$/.test(prefix);
@@ -4178,19 +4326,19 @@ function parseTag(tag) {
4178
4326
  };
4179
4327
  }
4180
4328
  async function dbReindex(options = {}) {
4181
- loadEnv8();
4329
+ loadEnv9();
4182
4330
  const { getDrizzleConfig } = await import("@spfn/core/db");
4183
4331
  const config = getDrizzleConfig({ disablePackageDiscovery: true });
4184
4332
  const outDir = config.out;
4185
- const journalPath = join21(outDir, "meta", "_journal.json");
4186
- if (!existsSync23(journalPath)) {
4187
- console.error(chalk26.red("\u274C No _journal.json found at:"), journalPath);
4188
- console.log(chalk26.yellow("\u{1F4A1} Run `spfn db generate` first to create migrations"));
4333
+ const journalPath = join22(outDir, "meta", "_journal.json");
4334
+ if (!existsSync24(journalPath)) {
4335
+ console.error(chalk28.red("\u274C No _journal.json found at:"), journalPath);
4336
+ console.log(chalk28.yellow("\u{1F4A1} Run `spfn db generate` first to create migrations"));
4189
4337
  process.exit(1);
4190
4338
  }
4191
4339
  const journal = JSON.parse(readFileSync10(journalPath, "utf-8"));
4192
4340
  if (journal.entries.length === 0) {
4193
- console.log(chalk26.yellow("No migration entries found \u2014 nothing to reindex."));
4341
+ console.log(chalk28.yellow("No migration entries found \u2014 nothing to reindex."));
4194
4342
  return;
4195
4343
  }
4196
4344
  const renames = [];
@@ -4204,46 +4352,46 @@ async function dbReindex(options = {}) {
4204
4352
  const { prefix: oldPrefix, suffix } = parseTag(entry.tag);
4205
4353
  const newPrefix = String(entry.when);
4206
4354
  const newTag = suffix ? `${newPrefix}_${suffix}` : newPrefix;
4207
- const oldSql = join21(outDir, `${entry.tag}.sql`);
4208
- const newSql = join21(outDir, `${newTag}.sql`);
4209
- if (existsSync23(oldSql)) {
4355
+ const oldSql = join22(outDir, `${entry.tag}.sql`);
4356
+ const newSql = join22(outDir, `${newTag}.sql`);
4357
+ if (existsSync24(oldSql)) {
4210
4358
  renames.push({ type: "sql", from: oldSql, to: newSql });
4211
4359
  }
4212
- const oldSnapshot = join21(outDir, "meta", `${oldPrefix}_snapshot.json`);
4213
- const newSnapshot = join21(outDir, "meta", `${newPrefix}_snapshot.json`);
4214
- if (existsSync23(oldSnapshot)) {
4360
+ const oldSnapshot = join22(outDir, "meta", `${oldPrefix}_snapshot.json`);
4361
+ const newSnapshot = join22(outDir, "meta", `${newPrefix}_snapshot.json`);
4362
+ if (existsSync24(oldSnapshot)) {
4215
4363
  renames.push({ type: "snapshot", from: oldSnapshot, to: newSnapshot });
4216
4364
  }
4217
4365
  tagUpdates.push({ idx: entry.idx, oldTag: entry.tag, newTag });
4218
4366
  }
4219
4367
  if (tagUpdates.length === 0) {
4220
- console.log(chalk26.green("\u2705 All migrations already use timestamp prefix \u2014 nothing to do."));
4368
+ console.log(chalk28.green("\u2705 All migrations already use timestamp prefix \u2014 nothing to do."));
4221
4369
  if (skipped > 0) {
4222
- console.log(chalk26.dim(` (${skipped} entries already timestamp-prefixed)`));
4370
+ console.log(chalk28.dim(` (${skipped} entries already timestamp-prefixed)`));
4223
4371
  }
4224
4372
  return;
4225
4373
  }
4226
- console.log(chalk26.bold("\n\u{1F4CB} Reindex plan:\n"));
4374
+ console.log(chalk28.bold("\n\u{1F4CB} Reindex plan:\n"));
4227
4375
  for (const update of tagUpdates) {
4228
4376
  console.log(
4229
- chalk26.dim(` [${update.idx}]`),
4230
- chalk26.red(update.oldTag),
4231
- chalk26.dim("\u2192"),
4232
- chalk26.green(update.newTag)
4377
+ chalk28.dim(` [${update.idx}]`),
4378
+ chalk28.red(update.oldTag),
4379
+ chalk28.dim("\u2192"),
4380
+ chalk28.green(update.newTag)
4233
4381
  );
4234
4382
  }
4235
- console.log(chalk26.dim(`
4383
+ console.log(chalk28.dim(`
4236
4384
  ${renames.length} file(s) to rename, ${tagUpdates.length} journal tag(s) to update`));
4237
4385
  if (skipped > 0) {
4238
- console.log(chalk26.dim(` ${skipped} entry/entries already timestamp-prefixed (skipped)`));
4386
+ console.log(chalk28.dim(` ${skipped} entry/entries already timestamp-prefixed (skipped)`));
4239
4387
  }
4240
4388
  if (options.dryRun) {
4241
- console.log(chalk26.yellow("\n\u{1F50D} Dry run \u2014 no changes applied."));
4389
+ console.log(chalk28.yellow("\n\u{1F50D} Dry run \u2014 no changes applied."));
4242
4390
  return;
4243
4391
  }
4244
4392
  const backupPath = journalPath + ".bak";
4245
4393
  copyFileSync(journalPath, backupPath);
4246
- console.log(chalk26.dim(`
4394
+ console.log(chalk28.dim(`
4247
4395
  Backed up journal \u2192 ${backupPath}`));
4248
4396
  for (const rename of renames) {
4249
4397
  renameSync(rename.from, rename.to);
@@ -4255,7 +4403,7 @@ async function dbReindex(options = {}) {
4255
4403
  }
4256
4404
  }
4257
4405
  writeFileSync15(journalPath, JSON.stringify(journal, null, 2) + "\n");
4258
- console.log(chalk26.green(`
4406
+ console.log(chalk28.green(`
4259
4407
  \u2705 Reindex complete \u2014 ${tagUpdates.length} migration(s) converted to timestamp prefix.`));
4260
4408
  }
4261
4409
 
@@ -4264,9 +4412,10 @@ var dbCommand = new Command9("db").description("Database management commands (wr
4264
4412
  dbCommand.command("generate").alias("g").description("Generate database migrations from schema changes").action(dbGenerate);
4265
4413
  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));
4266
4414
  dbCommand.command("migrate").alias("m").description("Run pending migrations").option("--with-backup", "Create backup before running migrations").action((options) => dbMigrate(options));
4415
+ dbCommand.command("status").description("Show applied/pending migration status (function packages + project)").action(dbStatus);
4267
4416
  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));
4268
4417
  dbCommand.command("drop").description("Drop all database tables (\u26A0\uFE0F dangerous!)").action(dbDrop);
4269
- dbCommand.command("check").description("Check database connection").action(dbCheck);
4418
+ dbCommand.command("check").description("Check migration file consistency (drizzle-kit check)").action(dbCheck);
4270
4419
  dbCommand.command("backup").description("Create a database backup").option("-f, --format <format>", "Backup format (sql or custom)", "sql").option("-o, --output <path>", "Custom output path").option("-s, --schema <name>", "Backup specific schema only").option("--data-only", "Backup data only (no schema)").option("--schema-only", "Backup schema only (no data)").option("--tag <tags>", "Comma-separated tags for this backup").option("--env <environment>", "Environment label (e.g., production, staging)").action((options) => dbBackup(options));
4271
4420
  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));
4272
4421
  dbCommand.command("backup:list").description("List all database backups").action(dbBackupList);
@@ -4276,25 +4425,25 @@ dbCommand.command("reindex").description("Convert migration files from sequentia
4276
4425
  // src/commands/add.ts
4277
4426
  init_package_manager();
4278
4427
  import { Command as Command10 } from "commander";
4279
- import { existsSync as existsSync24, readFileSync as readFileSync11 } from "fs";
4280
- import { join as join22 } from "path";
4428
+ import { existsSync as existsSync25, readFileSync as readFileSync11 } from "fs";
4429
+ import { join as join23 } from "path";
4281
4430
  import { execa as execa9 } from "execa";
4282
- import chalk27 from "chalk";
4431
+ import chalk29 from "chalk";
4283
4432
  import ora11 from "ora";
4284
4433
  async function addPackage(packageName) {
4285
4434
  if (!packageName.includes("/")) {
4286
- console.error(chalk27.red("\u274C Please specify full package name"));
4287
- console.log(chalk27.yellow("\n\u{1F4A1} Examples:"));
4288
- console.log(chalk27.gray(" pnpm spfn add @spfn/cms"));
4289
- console.log(chalk27.gray(" pnpm spfn add @mycompany/spfn-analytics"));
4435
+ console.error(chalk29.red("\u274C Please specify full package name"));
4436
+ console.log(chalk29.yellow("\n\u{1F4A1} Examples:"));
4437
+ console.log(chalk29.gray(" pnpm spfn add @spfn/cms"));
4438
+ console.log(chalk29.gray(" pnpm spfn add @mycompany/spfn-analytics"));
4290
4439
  process.exit(1);
4291
4440
  }
4292
- console.log(chalk27.blue(`
4441
+ console.log(chalk29.blue(`
4293
4442
  \u{1F4E6} Setting up ${packageName}...
4294
4443
  `));
4295
- const pkgPath = join22(process.cwd(), "node_modules", ...packageName.split("/"));
4296
- const pkgJsonPath = join22(pkgPath, "package.json");
4297
- if (!existsSync24(pkgJsonPath)) {
4444
+ const pkgPath = join23(process.cwd(), "node_modules", ...packageName.split("/"));
4445
+ const pkgJsonPath = join23(pkgPath, "package.json");
4446
+ if (!existsSync25(pkgJsonPath)) {
4298
4447
  const pm = detectPackageManager(process.cwd());
4299
4448
  const installSpinner = ora11("Installing package...").start();
4300
4449
  try {
@@ -4302,26 +4451,27 @@ async function addPackage(packageName) {
4302
4451
  installSpinner.succeed("Package installed");
4303
4452
  } catch (error) {
4304
4453
  installSpinner.fail("Failed to install package");
4305
- console.error(chalk27.red(error instanceof Error ? error.message : "Unknown error"));
4454
+ console.error(chalk29.red(error instanceof Error ? error.message : "Unknown error"));
4306
4455
  process.exit(1);
4307
4456
  }
4308
4457
  } else {
4309
- console.log(chalk27.gray("\u2713 Package already installed (using local version)\n"));
4458
+ console.log(chalk29.gray("\u2713 Package already installed (using local version)\n"));
4310
4459
  }
4311
- if (!existsSync24(pkgJsonPath)) {
4312
- console.error(chalk27.red(`\u274C Package ${packageName} not found after installation`));
4460
+ if (!existsSync25(pkgJsonPath)) {
4461
+ console.error(chalk29.red(`\u274C Package ${packageName} not found after installation`));
4313
4462
  process.exit(1);
4314
4463
  }
4315
4464
  const pkgJson = JSON.parse(readFileSync11(pkgJsonPath, "utf-8"));
4316
4465
  if (pkgJson.spfn?.migrations) {
4317
- console.log(chalk27.blue(`
4466
+ console.log(chalk29.blue(`
4318
4467
  \u{1F5C4}\uFE0F Setting up database for ${packageName}...
4319
4468
  `));
4320
- const { env: env8 } = await import("@spfn/core/config");
4321
- if (!env8.DATABASE_URL) {
4322
- console.log(chalk27.yellow("\u26A0\uFE0F DATABASE_URL not found"));
4323
- console.log(chalk27.gray("Skipping database setup. Run migrations manually when ready:\n"));
4324
- console.log(chalk27.gray(" pnpm spfn db push\n"));
4469
+ const { env: env9 } = await import("@spfn/core/config");
4470
+ if (!env9.DATABASE_URL) {
4471
+ console.log(chalk29.yellow("\u26A0\uFE0F DATABASE_URL not found \u2014 skipping database setup."));
4472
+ console.log(chalk29.yellow(` ${packageName} tables are created by its bundled migrations, not by schema push.`));
4473
+ console.log(chalk29.cyan(" Once DATABASE_URL is set, run: pnpm spfn db migrate"));
4474
+ console.log(chalk29.gray(" (check state anytime with: pnpm spfn db status)\n"));
4325
4475
  } else {
4326
4476
  const { discoverFunctionMigrations: discoverFunctionMigrations2, loadFunctionMigrationPlans: loadFunctionMigrationPlans2, executeFunctionMigrations: executeFunctionMigrations2 } = await Promise.resolve().then(() => (init_function_migrations(), function_migrations_exports));
4327
4477
  const functions = discoverFunctionMigrations2(process.cwd());
@@ -4333,21 +4483,21 @@ async function addPackage(packageName) {
4333
4483
  spinner.succeed("Migrations applied");
4334
4484
  } catch (error) {
4335
4485
  spinner.fail("Failed to apply migrations");
4336
- console.error(chalk27.red(error instanceof Error ? error.message : "Unknown error"));
4486
+ console.error(chalk29.red(error instanceof Error ? error.message : "Unknown error"));
4337
4487
  process.exit(1);
4338
4488
  }
4339
4489
  } else {
4340
- console.log(chalk27.gray("\u2139\uFE0F No migrations found for this package"));
4490
+ console.log(chalk29.gray("\u2139\uFE0F No migrations found for this package"));
4341
4491
  }
4342
4492
  }
4343
4493
  } else {
4344
- console.log(chalk27.gray("\n\u2139\uFE0F No database migrations to apply"));
4494
+ console.log(chalk29.gray("\n\u2139\uFE0F No database migrations to apply"));
4345
4495
  }
4346
- console.log(chalk27.green(`
4496
+ console.log(chalk29.green(`
4347
4497
  \u2705 ${packageName} installed successfully!
4348
4498
  `));
4349
4499
  if (pkgJson.spfn?.setupMessage) {
4350
- console.log(chalk27.cyan("\u{1F4DA} Setup Guide:"));
4500
+ console.log(chalk29.cyan("\u{1F4DA} Setup Guide:"));
4351
4501
  console.log(pkgJson.spfn.setupMessage);
4352
4502
  console.log();
4353
4503
  }
@@ -4356,8 +4506,8 @@ var addCommand = new Command10("add").description("Install and set up SPFN ecosy
4356
4506
 
4357
4507
  // src/commands/env.ts
4358
4508
  import { Command as Command11 } from "commander";
4359
- import chalk28 from "chalk";
4360
- import { existsSync as existsSync25, readFileSync as readFileSync12, writeFileSync as writeFileSync16 } from "fs";
4509
+ import chalk30 from "chalk";
4510
+ import { existsSync as existsSync26, readFileSync as readFileSync12, writeFileSync as writeFileSync16 } from "fs";
4361
4511
  import { resolve as resolve2 } from "path";
4362
4512
  import { parse as parse2 } from "dotenv";
4363
4513
 
@@ -4413,26 +4563,26 @@ function getEnvFilesForEnvironment(nodeEnv) {
4413
4563
  }
4414
4564
  function formatType(type) {
4415
4565
  const typeColors = {
4416
- string: chalk28.green,
4417
- number: chalk28.blue,
4418
- boolean: chalk28.yellow,
4419
- url: chalk28.cyan,
4420
- enum: chalk28.magenta,
4421
- json: chalk28.red
4566
+ string: chalk30.green,
4567
+ number: chalk30.blue,
4568
+ boolean: chalk30.yellow,
4569
+ url: chalk30.cyan,
4570
+ enum: chalk30.magenta,
4571
+ json: chalk30.red
4422
4572
  };
4423
- return (typeColors[type] || chalk28.white)(type);
4573
+ return (typeColors[type] || chalk30.white)(type);
4424
4574
  }
4425
4575
  function formatDefault(value, type) {
4426
4576
  if (value === void 0) {
4427
- return chalk28.dim("(none)");
4577
+ return chalk30.dim("(none)");
4428
4578
  }
4429
4579
  if (type === "string" || type === "url") {
4430
- return chalk28.green(`"${value}"`);
4580
+ return chalk30.green(`"${value}"`);
4431
4581
  }
4432
4582
  if (type === "boolean") {
4433
- return value ? chalk28.green("true") : chalk28.red("false");
4583
+ return value ? chalk30.green("true") : chalk30.red("false");
4434
4584
  }
4435
- return chalk28.cyan(String(value));
4585
+ return chalk30.cyan(String(value));
4436
4586
  }
4437
4587
  async function listEnvVars(options) {
4438
4588
  const packageName = options.package || "@spfn/core";
@@ -4446,28 +4596,28 @@ async function listEnvVars(options) {
4446
4596
  acc[target].push([key, schema]);
4447
4597
  return acc;
4448
4598
  }, {});
4449
- console.log(chalk28.blue.bold(`
4599
+ console.log(chalk30.blue.bold(`
4450
4600
  \u{1F4CB} Environment Variables by File (${packageName})
4451
4601
  `));
4452
4602
  for (const [file, vars] of Object.entries(grouped)) {
4453
- console.log(chalk28.bold.magenta(`
4603
+ console.log(chalk30.bold.magenta(`
4454
4604
  ${file}`));
4455
- console.log(chalk28.dim("\u2500".repeat(50)));
4605
+ console.log(chalk30.dim("\u2500".repeat(50)));
4456
4606
  for (const [key, schema] of vars) {
4457
4607
  printEnvVar(key, schema);
4458
4608
  }
4459
4609
  }
4460
4610
  } else {
4461
- console.log(chalk28.blue.bold(`
4611
+ console.log(chalk30.blue.bold(`
4462
4612
  \u{1F4CB} Environment Variables (${packageName})
4463
4613
  `));
4464
4614
  for (const [key, schema] of allVars) {
4465
4615
  printEnvVar(key, schema, true);
4466
4616
  }
4467
4617
  }
4468
- console.log(chalk28.dim("\n\u{1F4A1} Tip: Use `spfn env init` to generate .env template files\n"));
4618
+ console.log(chalk30.dim("\n\u{1F4A1} Tip: Use `spfn env init` to generate .env template files\n"));
4469
4619
  } catch (error) {
4470
- console.error(chalk28.red(`
4620
+ console.error(chalk30.red(`
4471
4621
  \u274C ${error instanceof Error ? error.message : "Unknown error"}
4472
4622
  `));
4473
4623
  process.exit(1);
@@ -4475,17 +4625,17 @@ ${file}`));
4475
4625
  }
4476
4626
  function printEnvVar(key, schema, showFile = false) {
4477
4627
  const typeStr = formatType(schema.type);
4478
- const requiredStr = schema.required || schema.default !== void 0 ? chalk28.red("[required]") : chalk28.dim("[optional]");
4479
- const sensitiveStr = schema.sensitive ? chalk28.yellow(" [sensitive]") : "";
4480
- const fileStr = showFile ? chalk28.dim(` \u2192 ${getTargetFile(schema)}`) : "";
4481
- console.log(`${chalk28.bold.cyan(key)} ${chalk28.dim("(")}${typeStr}${chalk28.dim(")")} ${requiredStr}${sensitiveStr}${fileStr}`);
4482
- console.log(` ${chalk28.dim(schema.description)}`);
4628
+ const requiredStr = schema.required || schema.default !== void 0 ? chalk30.red("[required]") : chalk30.dim("[optional]");
4629
+ const sensitiveStr = schema.sensitive ? chalk30.yellow(" [sensitive]") : "";
4630
+ const fileStr = showFile ? chalk30.dim(` \u2192 ${getTargetFile(schema)}`) : "";
4631
+ console.log(`${chalk30.bold.cyan(key)} ${chalk30.dim("(")}${typeStr}${chalk30.dim(")")} ${requiredStr}${sensitiveStr}${fileStr}`);
4632
+ console.log(` ${chalk30.dim(schema.description)}`);
4483
4633
  if (schema.default !== void 0) {
4484
- console.log(` ${chalk28.dim("Default:")} ${formatDefault(schema.default, schema.type)}`);
4634
+ console.log(` ${chalk30.dim("Default:")} ${formatDefault(schema.default, schema.type)}`);
4485
4635
  }
4486
4636
  if (schema.examples && schema.examples.length > 0) {
4487
4637
  const exampleStr = schema.examples.map((ex) => formatDefault(ex, schema.type)).join(", ");
4488
- console.log(` ${chalk28.dim("Examples:")} ${exampleStr}`);
4638
+ console.log(` ${chalk30.dim("Examples:")} ${exampleStr}`);
4489
4639
  }
4490
4640
  console.log();
4491
4641
  }
@@ -4493,7 +4643,7 @@ async function showEnvStats(options) {
4493
4643
  const packageName = options.package || "@spfn/core";
4494
4644
  try {
4495
4645
  const envSchema = await loadEnvSchema(packageName);
4496
- console.log(chalk28.blue.bold(`
4646
+ console.log(chalk30.blue.bold(`
4497
4647
  \u{1F4CA} Environment Variable Statistics (${packageName})
4498
4648
  `));
4499
4649
  const allVars = Object.entries(envSchema);
@@ -4515,24 +4665,24 @@ async function showEnvStats(options) {
4515
4665
  acc[file] = (acc[file] || 0) + 1;
4516
4666
  return acc;
4517
4667
  }, {});
4518
- console.log(`${chalk28.bold("Total variables:")} ${chalk28.cyan(allVars.length)}`);
4519
- console.log(`${chalk28.bold("Required:")} ${chalk28.red(required.length)}`);
4520
- console.log(`${chalk28.bold("Optional:")} ${chalk28.dim(optional.length)}`);
4521
- console.log(`${chalk28.bold("Sensitive:")} ${chalk28.yellow(sensitive.length)}`);
4522
- console.log(chalk28.bold("\nBy Target:"));
4523
- console.log(` ${chalk28.blue("Next.js accessible:")} ${chalk28.cyan(nextjsVars.length)}`);
4524
- console.log(` ${chalk28.magenta("SPFN server only:")} ${chalk28.cyan(serverOnlyVars.length)}`);
4525
- console.log(chalk28.bold("\nBy File:"));
4668
+ console.log(`${chalk30.bold("Total variables:")} ${chalk30.cyan(allVars.length)}`);
4669
+ console.log(`${chalk30.bold("Required:")} ${chalk30.red(required.length)}`);
4670
+ console.log(`${chalk30.bold("Optional:")} ${chalk30.dim(optional.length)}`);
4671
+ console.log(`${chalk30.bold("Sensitive:")} ${chalk30.yellow(sensitive.length)}`);
4672
+ console.log(chalk30.bold("\nBy Target:"));
4673
+ console.log(` ${chalk30.blue("Next.js accessible:")} ${chalk30.cyan(nextjsVars.length)}`);
4674
+ console.log(` ${chalk30.magenta("SPFN server only:")} ${chalk30.cyan(serverOnlyVars.length)}`);
4675
+ console.log(chalk30.bold("\nBy File:"));
4526
4676
  for (const [file, count] of Object.entries(fileCount)) {
4527
- console.log(` ${chalk28.dim(file)}: ${chalk28.cyan(count)}`);
4677
+ console.log(` ${chalk30.dim(file)}: ${chalk30.cyan(count)}`);
4528
4678
  }
4529
- console.log(chalk28.bold("\nBy Type:"));
4679
+ console.log(chalk30.bold("\nBy Type:"));
4530
4680
  for (const [type, count] of Object.entries(typeCount)) {
4531
- console.log(` ${formatType(type)}: ${chalk28.cyan(count)}`);
4681
+ console.log(` ${formatType(type)}: ${chalk30.cyan(count)}`);
4532
4682
  }
4533
4683
  console.log();
4534
4684
  } catch (error) {
4535
- console.error(chalk28.red(`
4685
+ console.error(chalk30.red(`
4536
4686
  \u274C ${error instanceof Error ? error.message : "Unknown error"}
4537
4687
  `));
4538
4688
  process.exit(1);
@@ -4552,26 +4702,26 @@ async function searchEnvVars(query, options) {
4552
4702
  }
4553
4703
  }
4554
4704
  if (results.length === 0) {
4555
- console.log(chalk28.yellow(`
4705
+ console.log(chalk30.yellow(`
4556
4706
  \u26A0\uFE0F No environment variables found matching "${query}"
4557
4707
  `));
4558
4708
  return;
4559
4709
  }
4560
- console.log(chalk28.blue.bold(`
4710
+ console.log(chalk30.blue.bold(`
4561
4711
  \u{1F50D} Found ${results.length} environment variable(s) matching "${query}"
4562
4712
  `));
4563
4713
  for (const [key, schema] of results) {
4564
4714
  const typeStr = formatType(schema.type);
4565
- const requiredStr = schema.required || schema.default !== void 0 ? chalk28.red("[required]") : chalk28.dim("[optional]");
4566
- console.log(`${chalk28.bold.cyan(key)} ${chalk28.dim("(")}${typeStr}${chalk28.dim(")")} ${requiredStr}`);
4567
- console.log(` ${chalk28.dim(schema.description)}`);
4715
+ const requiredStr = schema.required || schema.default !== void 0 ? chalk30.red("[required]") : chalk30.dim("[optional]");
4716
+ console.log(`${chalk30.bold.cyan(key)} ${chalk30.dim("(")}${typeStr}${chalk30.dim(")")} ${requiredStr}`);
4717
+ console.log(` ${chalk30.dim(schema.description)}`);
4568
4718
  if (schema.default !== void 0) {
4569
- console.log(` ${chalk28.dim("Default:")} ${formatDefault(schema.default, schema.type)}`);
4719
+ console.log(` ${chalk30.dim("Default:")} ${formatDefault(schema.default, schema.type)}`);
4570
4720
  }
4571
4721
  console.log();
4572
4722
  }
4573
4723
  } catch (error) {
4574
- console.error(chalk28.red(`
4724
+ console.error(chalk30.red(`
4575
4725
  \u274C ${error instanceof Error ? error.message : "Unknown error"}
4576
4726
  `));
4577
4727
  process.exit(1);
@@ -4583,9 +4733,9 @@ envCommand.command("stats").description("Show environment variable statistics").
4583
4733
  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);
4584
4734
  function validateEnvOption(envValue) {
4585
4735
  if (!VALID_ENVS.includes(envValue)) {
4586
- console.error(chalk28.red(`
4736
+ console.error(chalk30.red(`
4587
4737
  \u274C Invalid environment: "${envValue}"`));
4588
- console.log(chalk28.dim(` Valid values: ${VALID_ENVS.join(", ")}
4738
+ console.log(chalk30.dim(` Valid values: ${VALID_ENVS.join(", ")}
4589
4739
  `));
4590
4740
  process.exit(1);
4591
4741
  }
@@ -4606,8 +4756,8 @@ async function initEnvFiles(options) {
4606
4756
  return acc;
4607
4757
  }, {});
4608
4758
  if (targetEnv) {
4609
- console.log(chalk28.blue.bold(`
4610
- \u{1F680} Generating .env template files for ${chalk28.cyan(targetEnv)} environment
4759
+ console.log(chalk30.blue.bold(`
4760
+ \u{1F680} Generating .env template files for ${chalk30.cyan(targetEnv)} environment
4611
4761
  `));
4612
4762
  const envSpecificFiles = {};
4613
4763
  const committedVars = allVars.filter(([_, schema]) => !schema.sensitive);
@@ -4623,24 +4773,24 @@ async function initEnvFiles(options) {
4623
4773
  writeEnvTemplate(cwd, file, vars, options.force ?? false);
4624
4774
  }
4625
4775
  } else {
4626
- console.log(chalk28.blue.bold(`
4776
+ console.log(chalk30.blue.bold(`
4627
4777
  \u{1F680} Generating .env template files
4628
4778
  `));
4629
4779
  for (const [file, vars] of Object.entries(grouped)) {
4630
4780
  writeEnvTemplate(cwd, file, vars, options.force ?? false);
4631
4781
  }
4632
4782
  }
4633
- console.log(chalk28.dim("\n\u{1F4A1} Copy .example files to create your actual .env files:"));
4634
- console.log(chalk28.dim(" cp .env.example .env"));
4635
- console.log(chalk28.dim(" cp .env.local.example .env.local"));
4636
- console.log(chalk28.dim(" cp .env.server.example .env.server"));
4783
+ console.log(chalk30.dim("\n\u{1F4A1} Copy .example files to create your actual .env files:"));
4784
+ console.log(chalk30.dim(" cp .env.example .env"));
4785
+ console.log(chalk30.dim(" cp .env.local.example .env.local"));
4786
+ console.log(chalk30.dim(" cp .env.server.example .env.server"));
4637
4787
  if (targetEnv) {
4638
- console.log(chalk28.dim(` cp .env.${targetEnv}.example .env.${targetEnv}`));
4639
- console.log(chalk28.dim(` cp .env.${targetEnv}.local.example .env.${targetEnv}.local`));
4788
+ console.log(chalk30.dim(` cp .env.${targetEnv}.example .env.${targetEnv}`));
4789
+ console.log(chalk30.dim(` cp .env.${targetEnv}.local.example .env.${targetEnv}.local`));
4640
4790
  }
4641
4791
  console.log("");
4642
4792
  } catch (error) {
4643
- console.error(chalk28.red(`
4793
+ console.error(chalk30.red(`
4644
4794
  \u274C ${error instanceof Error ? error.message : "Unknown error"}
4645
4795
  `));
4646
4796
  process.exit(1);
@@ -4648,12 +4798,12 @@ async function initEnvFiles(options) {
4648
4798
  }
4649
4799
  function writeEnvTemplate(cwd, file, vars, force) {
4650
4800
  const filePath = resolve2(cwd, file);
4651
- if (existsSync25(filePath) && !force) {
4652
- console.log(chalk28.yellow(` \u23ED\uFE0F ${file} already exists (use --force to overwrite)`));
4801
+ if (existsSync26(filePath) && !force) {
4802
+ console.log(chalk30.yellow(` \u23ED\uFE0F ${file} already exists (use --force to overwrite)`));
4653
4803
  return;
4654
4804
  }
4655
4805
  writeFileSync16(filePath, generateEnvFileContent(vars), "utf-8");
4656
- console.log(chalk28.green(` \u2705 ${file} (${vars.length} variables)`));
4806
+ console.log(chalk30.green(` \u2705 ${file} (${vars.length} variables)`));
4657
4807
  }
4658
4808
  function generateEnvFileContent(vars) {
4659
4809
  const lines = [
@@ -4688,7 +4838,7 @@ async function checkEnvFiles(options) {
4688
4838
  const envSchema = await loadEnvSchema(packageName);
4689
4839
  const allVars = Object.entries(envSchema);
4690
4840
  const envLabel = targetEnv ? ` (${targetEnv})` : "";
4691
- console.log(chalk28.blue.bold(`
4841
+ console.log(chalk30.blue.bold(`
4692
4842
  \u{1F50D} Checking .env files against schema${envLabel}
4693
4843
  `));
4694
4844
  const filesToCheck = targetEnv ? getEnvFilesForEnvironment(targetEnv) : [...BASE_ENV_FILES.nextjs, ...BASE_ENV_FILES.server];
@@ -4697,7 +4847,7 @@ async function checkEnvFiles(options) {
4697
4847
  const warnings = [];
4698
4848
  for (const file of filesToCheck) {
4699
4849
  const filePath = resolve2(cwd, file);
4700
- if (!existsSync25(filePath)) {
4850
+ if (!existsSync26(filePath)) {
4701
4851
  continue;
4702
4852
  }
4703
4853
  const content = readFileSync12(filePath, "utf-8");
@@ -4705,7 +4855,7 @@ async function checkEnvFiles(options) {
4705
4855
  for (const [key, value] of Object.entries(parsed)) {
4706
4856
  loadedEnv[key] = { value: value || "", file };
4707
4857
  }
4708
- console.log(chalk28.dim(` \u{1F4C4} ${file} loaded`));
4858
+ console.log(chalk30.dim(` \u{1F4C4} ${file} loaded`));
4709
4859
  }
4710
4860
  console.log("");
4711
4861
  for (const [key, schema] of allVars) {
@@ -4713,7 +4863,7 @@ async function checkEnvFiles(options) {
4713
4863
  const found = loadedEnv[key];
4714
4864
  if (!found) {
4715
4865
  if (schema.required && schema.default === void 0) {
4716
- issues.push(`${chalk28.red("\u2717")} ${chalk28.cyan(key)} is required but not found in any .env file`);
4866
+ issues.push(`${chalk30.red("\u2717")} ${chalk30.cyan(key)} is required but not found in any .env file`);
4717
4867
  }
4718
4868
  continue;
4719
4869
  }
@@ -4723,11 +4873,11 @@ async function checkEnvFiles(options) {
4723
4873
  if (!shouldBeNextjs && isNextjsFile && !isServerFile) {
4724
4874
  if (schema.sensitive) {
4725
4875
  issues.push(
4726
- `${chalk28.red("\u2717")} ${chalk28.cyan(key)} is sensitive and should be in ${chalk28.magenta(expectedFile)}, but found in ${chalk28.yellow(found.file)} (security risk!)`
4876
+ `${chalk30.red("\u2717")} ${chalk30.cyan(key)} is sensitive and should be in ${chalk30.magenta(expectedFile)}, but found in ${chalk30.yellow(found.file)} (security risk!)`
4727
4877
  );
4728
4878
  } else {
4729
4879
  warnings.push(
4730
- `${chalk28.yellow("\u26A0")} ${chalk28.cyan(key)} should be in ${chalk28.magenta(expectedFile)}, but found in ${chalk28.dim(found.file)}`
4880
+ `${chalk30.yellow("\u26A0")} ${chalk30.cyan(key)} should be in ${chalk30.magenta(expectedFile)}, but found in ${chalk30.dim(found.file)}`
4731
4881
  );
4732
4882
  }
4733
4883
  }
@@ -4735,34 +4885,34 @@ async function checkEnvFiles(options) {
4735
4885
  for (const [key, { file }] of Object.entries(loadedEnv)) {
4736
4886
  const inSchema = allVars.some(([k]) => k === key);
4737
4887
  if (!inSchema) {
4738
- warnings.push(`${chalk28.yellow("\u26A0")} ${chalk28.cyan(key)} in ${chalk28.dim(file)} is not in schema`);
4888
+ warnings.push(`${chalk30.yellow("\u26A0")} ${chalk30.cyan(key)} in ${chalk30.dim(file)} is not in schema`);
4739
4889
  }
4740
4890
  }
4741
4891
  if (issues.length > 0) {
4742
- console.log(chalk28.red.bold("Issues:"));
4892
+ console.log(chalk30.red.bold("Issues:"));
4743
4893
  for (const issue of issues) {
4744
4894
  console.log(` ${issue}`);
4745
4895
  }
4746
4896
  console.log("");
4747
4897
  }
4748
4898
  if (warnings.length > 0) {
4749
- console.log(chalk28.yellow.bold("Warnings:"));
4899
+ console.log(chalk30.yellow.bold("Warnings:"));
4750
4900
  for (const warning of warnings) {
4751
4901
  console.log(` ${warning}`);
4752
4902
  }
4753
4903
  console.log("");
4754
4904
  }
4755
4905
  if (issues.length === 0 && warnings.length === 0) {
4756
- console.log(chalk28.green("\u2705 All environment variables are correctly configured!\n"));
4906
+ console.log(chalk30.green("\u2705 All environment variables are correctly configured!\n"));
4757
4907
  } else {
4758
- console.log(chalk28.dim(`Found ${issues.length} issue(s) and ${warnings.length} warning(s)
4908
+ console.log(chalk30.dim(`Found ${issues.length} issue(s) and ${warnings.length} warning(s)
4759
4909
  `));
4760
4910
  if (issues.length > 0) {
4761
4911
  process.exit(1);
4762
4912
  }
4763
4913
  }
4764
4914
  } catch (error) {
4765
- console.error(chalk28.red(`
4915
+ console.error(chalk30.red(`
4766
4916
  \u274C ${error instanceof Error ? error.message : "Unknown error"}
4767
4917
  `));
4768
4918
  process.exit(1);
@@ -4774,17 +4924,17 @@ async function validateEnvVars(options) {
4774
4924
  const packages = options.packages || ["@spfn/core"];
4775
4925
  const targetEnv = options.env ? validateEnvOption(options.env) : void 0;
4776
4926
  if (targetEnv) {
4777
- const { loadEnv: loadEnv9 } = await import("@spfn/core/env/loader");
4778
- const result = loadEnv9({ nodeEnv: targetEnv });
4779
- console.log(chalk28.blue.bold(`
4780
- \u{1F50D} Validating environment variables for ${chalk28.cyan(targetEnv)}
4927
+ const { loadEnv: loadEnv10 } = await import("@spfn/core/env/loader");
4928
+ const result = loadEnv10({ nodeEnv: targetEnv });
4929
+ console.log(chalk30.blue.bold(`
4930
+ \u{1F50D} Validating environment variables for ${chalk30.cyan(targetEnv)}
4781
4931
  `));
4782
4932
  if (result.loadedFiles.length > 0) {
4783
- console.log(chalk28.dim(` Loaded: ${result.loadedFiles.join(", ")}`));
4933
+ console.log(chalk30.dim(` Loaded: ${result.loadedFiles.join(", ")}`));
4784
4934
  }
4785
4935
  console.log("");
4786
4936
  } else {
4787
- console.log(chalk28.blue.bold(`
4937
+ console.log(chalk30.blue.bold(`
4788
4938
  \u{1F50D} Validating environment variables
4789
4939
  `));
4790
4940
  }
@@ -4792,7 +4942,7 @@ async function validateEnvVars(options) {
4792
4942
  const allWarnings = [];
4793
4943
  for (const packageName of packages) {
4794
4944
  try {
4795
- console.log(chalk28.dim(` \u{1F4E6} ${packageName}`));
4945
+ console.log(chalk30.dim(` \u{1F4E6} ${packageName}`));
4796
4946
  const envSchema = await loadEnvSchema(packageName);
4797
4947
  const { createEnvRegistry } = await import("@spfn/core/env");
4798
4948
  const registry = createEnvRegistry(envSchema);
@@ -4805,10 +4955,10 @@ async function validateEnvVars(options) {
4805
4955
  }
4806
4956
  } catch (error) {
4807
4957
  if (error instanceof Error && error.message.includes("does not export envSchema")) {
4808
- console.log(chalk28.dim(` \u23ED\uFE0F No envSchema exported, skipping`));
4958
+ console.log(chalk30.dim(` \u23ED\uFE0F No envSchema exported, skipping`));
4809
4959
  continue;
4810
4960
  }
4811
- console.error(chalk28.red(` \u274C Failed to load: ${error instanceof Error ? error.message : String(error)}`));
4961
+ console.error(chalk30.red(` \u274C Failed to load: ${error instanceof Error ? error.message : String(error)}`));
4812
4962
  if (options.strict) {
4813
4963
  process.exit(1);
4814
4964
  }
@@ -4816,32 +4966,32 @@ async function validateEnvVars(options) {
4816
4966
  }
4817
4967
  console.log("");
4818
4968
  if (allErrors.length > 0) {
4819
- console.log(chalk28.red.bold(`\u274C Validation Errors (${allErrors.length}):
4969
+ console.log(chalk30.red.bold(`\u274C Validation Errors (${allErrors.length}):
4820
4970
  `));
4821
4971
  for (const error of allErrors) {
4822
- console.log(` ${chalk28.red("\u2717")} ${chalk28.cyan(error.key)}`);
4823
- console.log(` ${chalk28.dim(error.message)}`);
4824
- console.log(` ${chalk28.dim(`from ${error.package}`)}`);
4972
+ console.log(` ${chalk30.red("\u2717")} ${chalk30.cyan(error.key)}`);
4973
+ console.log(` ${chalk30.dim(error.message)}`);
4974
+ console.log(` ${chalk30.dim(`from ${error.package}`)}`);
4825
4975
  console.log("");
4826
4976
  }
4827
4977
  }
4828
4978
  if (allWarnings.length > 0) {
4829
- console.log(chalk28.yellow.bold(`\u26A0\uFE0F Warnings (${allWarnings.length}):
4979
+ console.log(chalk30.yellow.bold(`\u26A0\uFE0F Warnings (${allWarnings.length}):
4830
4980
  `));
4831
4981
  for (const warning of allWarnings) {
4832
- console.log(` ${chalk28.yellow("\u26A0")} ${chalk28.cyan(warning.key)}`);
4833
- console.log(` ${chalk28.dim(warning.message)}`);
4982
+ console.log(` ${chalk30.yellow("\u26A0")} ${chalk30.cyan(warning.key)}`);
4983
+ console.log(` ${chalk30.dim(warning.message)}`);
4834
4984
  console.log("");
4835
4985
  }
4836
4986
  }
4837
4987
  if (allErrors.length === 0 && allWarnings.length === 0) {
4838
- console.log(chalk28.green.bold("\u2705 All environment variables are valid!\n"));
4988
+ console.log(chalk30.green.bold("\u2705 All environment variables are valid!\n"));
4839
4989
  } else if (allErrors.length === 0) {
4840
- console.log(chalk28.green("\u2705 No errors found."));
4841
- console.log(chalk28.yellow(`\u26A0\uFE0F ${allWarnings.length} warning(s) found.
4990
+ console.log(chalk30.green("\u2705 No errors found."));
4991
+ console.log(chalk30.yellow(`\u26A0\uFE0F ${allWarnings.length} warning(s) found.
4842
4992
  `));
4843
4993
  } else {
4844
- console.log(chalk28.red(`
4994
+ console.log(chalk30.red(`
4845
4995
  \u274C Validation failed with ${allErrors.length} error(s)
4846
4996
  `));
4847
4997
  process.exit(1);
@@ -4855,12 +5005,12 @@ import { Command as Command12 } from "commander";
4855
5005
  // src/commands/secret/set.ts
4856
5006
  init_logger();
4857
5007
  import prompts8 from "prompts";
4858
- import chalk29 from "chalk";
5008
+ import chalk31 from "chalk";
4859
5009
 
4860
5010
  // src/commands/secret/options.ts
4861
5011
  init_logger();
4862
- function resolveEnv(env8) {
4863
- const value = env8 ?? "local";
5012
+ function resolveEnv(env9) {
5013
+ const value = env9 ?? "local";
4864
5014
  if (!VALID_ENVS.includes(value)) {
4865
5015
  logger.error(`Invalid environment: "${value}". Valid values: ${VALID_ENVS.join(", ")}`);
4866
5016
  process.exit(1);
@@ -4870,12 +5020,12 @@ function resolveEnv(env8) {
4870
5020
 
4871
5021
  // src/commands/secret/store-value.ts
4872
5022
  init_logger();
4873
- import { join as join24 } from "path";
5023
+ import { join as join25 } from "path";
4874
5024
  init_env_file();
4875
5025
 
4876
5026
  // src/utils/sops.ts
4877
5027
  import { execa as execa10 } from "execa";
4878
- import { existsSync as existsSync26, mkdirSync as mkdirSync3, writeFileSync as writeFileSync17 } from "fs";
5028
+ import { existsSync as existsSync27, mkdirSync as mkdirSync3, writeFileSync as writeFileSync17 } from "fs";
4879
5029
  import { dirname as dirname3 } from "path";
4880
5030
  async function ensureSopsInstalled() {
4881
5031
  try {
@@ -4885,14 +5035,14 @@ async function ensureSopsInstalled() {
4885
5035
  }
4886
5036
  }
4887
5037
  async function sopsDecrypt(absFile) {
4888
- if (!existsSync26(absFile)) {
5038
+ if (!existsSync27(absFile)) {
4889
5039
  return {};
4890
5040
  }
4891
5041
  const { stdout } = await execa10("sops", ["--decrypt", "--output-type", "json", absFile]);
4892
5042
  return JSON.parse(stdout);
4893
5043
  }
4894
5044
  async function sopsSetValue(absFile, relFile, key, value) {
4895
- if (existsSync26(absFile)) {
5045
+ if (existsSync27(absFile)) {
4896
5046
  await execa10("sops", ["set", absFile, `["${key}"]`, JSON.stringify(value)]);
4897
5047
  return;
4898
5048
  }
@@ -4918,20 +5068,20 @@ async function sopsUpdateKeys(absFile) {
4918
5068
  }
4919
5069
 
4920
5070
  // src/utils/secret-config.ts
4921
- import { existsSync as existsSync27, readdirSync as readdirSync3 } from "fs";
4922
- import { join as join23 } from "path";
5071
+ import { existsSync as existsSync28, readdirSync as readdirSync3 } from "fs";
5072
+ import { join as join24 } from "path";
4923
5073
  var SECRETS_DIR = "secrets";
4924
- function getSopsFile(cwd, env8) {
4925
- const relFile = `${SECRETS_DIR}/${env8}.enc.json`;
4926
- return { absFile: join23(cwd, relFile), relFile };
5074
+ function getSopsFile(cwd, env9) {
5075
+ const relFile = `${SECRETS_DIR}/${env9}.enc.json`;
5076
+ return { absFile: join24(cwd, relFile), relFile };
4927
5077
  }
4928
5078
  function findUp(cwd, filename, maxDepth = 6) {
4929
5079
  let dir = cwd;
4930
5080
  for (let depth = 0; depth < maxDepth; depth++) {
4931
- if (existsSync27(join23(dir, filename))) {
5081
+ if (existsSync28(join24(dir, filename))) {
4932
5082
  return dir;
4933
5083
  }
4934
- const parent = join23(dir, "..");
5084
+ const parent = join24(dir, "..");
4935
5085
  if (parent === dir) {
4936
5086
  break;
4937
5087
  }
@@ -4941,22 +5091,22 @@ function findUp(cwd, filename, maxDepth = 6) {
4941
5091
  }
4942
5092
  function findSopsConfig(cwd) {
4943
5093
  const dir = findUp(cwd, ".sops.yaml");
4944
- return dir ? join23(dir, ".sops.yaml") : null;
5094
+ return dir ? join24(dir, ".sops.yaml") : null;
4945
5095
  }
4946
5096
  function hasSopsConfig(cwd) {
4947
5097
  return findSopsConfig(cwd) !== null;
4948
5098
  }
4949
5099
  function listSopsFiles(cwd) {
4950
- const dir = join23(cwd, SECRETS_DIR);
4951
- if (!existsSync27(dir)) {
5100
+ const dir = join24(cwd, SECRETS_DIR);
5101
+ if (!existsSync28(dir)) {
4952
5102
  return [];
4953
5103
  }
4954
- return readdirSync3(dir).filter((name) => name.endsWith(".enc.json")).map((name) => join23(dir, name));
5104
+ return readdirSync3(dir).filter((name) => name.endsWith(".enc.json")).map((name) => join24(dir, name));
4955
5105
  }
4956
5106
 
4957
5107
  // src/commands/secret/store-value.ts
4958
- function isLocalEnv(env8) {
4959
- return env8 === "local";
5108
+ function isLocalEnv(env9) {
5109
+ return env9 === "local";
4960
5110
  }
4961
5111
  var KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
4962
5112
  function assertValidKey(key) {
@@ -4964,15 +5114,15 @@ function assertValidKey(key) {
4964
5114
  throw new Error(`Invalid secret key "${key}". Use an env-var name: letters, digits, and underscores, not starting with a digit.`);
4965
5115
  }
4966
5116
  }
4967
- async function describeTarget(env8) {
4968
- if (isLocalEnv(env8)) {
5117
+ async function describeTarget(env9) {
5118
+ if (isLocalEnv(env9)) {
4969
5119
  return detectStore().label;
4970
5120
  }
4971
- return `SOPS (${getSopsFile(process.cwd(), env8).relFile})`;
5121
+ return `SOPS (${getSopsFile(process.cwd(), env9).relFile})`;
4972
5122
  }
4973
- async function storeSecret(cwd, env8, key, value) {
5123
+ async function storeSecret(cwd, env9, key, value) {
4974
5124
  assertValidKey(key);
4975
- if (isLocalEnv(env8)) {
5125
+ if (isLocalEnv(env9)) {
4976
5126
  const store = detectStore();
4977
5127
  if (!await store.isAvailable()) {
4978
5128
  throw new Error(
@@ -4980,7 +5130,7 @@ async function storeSecret(cwd, env8, key, value) {
4980
5130
  );
4981
5131
  }
4982
5132
  await store.set(keychainName(key), value);
4983
- const serverEnvPath = join24(cwd, ".env.server");
5133
+ const serverEnvPath = join25(cwd, ".env.server");
4984
5134
  const result = upsertEnvVar(serverEnvPath, key, keychainRef(key));
4985
5135
  restrictEnvFilePerms(serverEnvPath);
4986
5136
  ensureGitignored(cwd, [{ pattern: ".env.server", comment: "spfn server env (secrets)" }]);
@@ -4993,14 +5143,14 @@ async function storeSecret(cwd, env8, key, value) {
4993
5143
  ".sops.yaml not found \u2014 add a backend (run `spfn secret keygen` for age, or a KMS rule) so the file can be decrypted on deploy."
4994
5144
  );
4995
5145
  }
4996
- const { absFile, relFile } = getSopsFile(cwd, env8);
5146
+ const { absFile, relFile } = getSopsFile(cwd, env9);
4997
5147
  await sopsSetValue(absFile, relFile, key, value);
4998
5148
  logger.success(`Set ${key} in ${relFile} (encrypted). Commit and deploy to apply.`);
4999
5149
  }
5000
5150
 
5001
5151
  // src/commands/secret/set.ts
5002
5152
  async function secretSet(key, options) {
5003
- const env8 = resolveEnv(options.env);
5153
+ const env9 = resolveEnv(options.env);
5004
5154
  const pkg = options.package ?? "@spfn/core";
5005
5155
  const resolvedKey = key ?? await pickSecretKey(pkg);
5006
5156
  if (!resolvedKey) {
@@ -5011,15 +5161,15 @@ async function secretSet(key, options) {
5011
5161
  const { value } = await prompts8({
5012
5162
  type: "password",
5013
5163
  name: "value",
5014
- message: `Value for ${chalk29.cyan(resolvedKey)} (${env8})`
5164
+ message: `Value for ${chalk31.cyan(resolvedKey)} (${env9})`
5015
5165
  });
5016
5166
  if (!value) {
5017
5167
  logger.warn("Cancelled \u2014 no value entered.");
5018
5168
  process.exit(0);
5019
5169
  }
5020
- logger.step(`Storing ${resolvedKey} \u2192 ${await describeTarget(env8)}`);
5170
+ logger.step(`Storing ${resolvedKey} \u2192 ${await describeTarget(env9)}`);
5021
5171
  try {
5022
- await storeSecret(process.cwd(), env8, resolvedKey, value);
5172
+ await storeSecret(process.cwd(), env9, resolvedKey, value);
5023
5173
  } catch (error) {
5024
5174
  logger.error(error instanceof Error ? error.message : String(error));
5025
5175
  process.exit(1);
@@ -5060,9 +5210,9 @@ async function warnIfNotSecret(pkg, key) {
5060
5210
 
5061
5211
  // src/commands/secret/list.ts
5062
5212
  init_logger();
5063
- import chalk30 from "chalk";
5213
+ import chalk32 from "chalk";
5064
5214
  async function secretList(options) {
5065
- const env8 = resolveEnv(options.env);
5215
+ const env9 = resolveEnv(options.env);
5066
5216
  const pkg = options.package ?? "@spfn/core";
5067
5217
  let entries;
5068
5218
  try {
@@ -5075,18 +5225,18 @@ async function secretList(options) {
5075
5225
  logger.info(`No secrets declared in ${pkg}.`);
5076
5226
  return;
5077
5227
  }
5078
- const present = await loadPresence(env8, entries);
5079
- console.log(chalk30.blue.bold(`
5080
- \u{1F511} Secrets (${pkg}) \u2014 ${env8}
5228
+ const present = await loadPresence(env9, entries);
5229
+ console.log(chalk32.blue.bold(`
5230
+ \u{1F511} Secrets (${pkg}) \u2014 ${env9}
5081
5231
  `));
5082
5232
  for (const entry of entries) {
5083
5233
  const status = statusOf(entry, present.has(entry.key));
5084
- console.log(` ${badge(status)} ${chalk30.cyan(entry.key)}${entry.generate ? chalk30.dim(" (generatable)") : ""}`);
5234
+ console.log(` ${badge(status)} ${chalk32.cyan(entry.key)}${entry.generate ? chalk32.dim(" (generatable)") : ""}`);
5085
5235
  }
5086
5236
  console.log();
5087
5237
  }
5088
- async function loadPresence(env8, entries) {
5089
- if (isLocalEnv(env8)) {
5238
+ async function loadPresence(env9, entries) {
5239
+ if (isLocalEnv(env9)) {
5090
5240
  const store = detectStore();
5091
5241
  if (!await store.isAvailable()) {
5092
5242
  logger.warn(`${store.label} unavailable \u2014 status shown as missing.`);
@@ -5101,7 +5251,7 @@ async function loadPresence(env8, entries) {
5101
5251
  return present;
5102
5252
  }
5103
5253
  await ensureSopsInstalled();
5104
- const { absFile } = getSopsFile(process.cwd(), env8);
5254
+ const { absFile } = getSopsFile(process.cwd(), env9);
5105
5255
  const decrypted = await sopsDecrypt(absFile);
5106
5256
  return new Set(Object.keys(decrypted));
5107
5257
  }
@@ -5114,19 +5264,19 @@ function statusOf(entry, present) {
5114
5264
  function badge(status) {
5115
5265
  switch (status) {
5116
5266
  case "set":
5117
- return chalk30.green("\u25CF");
5267
+ return chalk32.green("\u25CF");
5118
5268
  case "missing":
5119
- return chalk30.yellow("\u25CB");
5269
+ return chalk32.yellow("\u25CB");
5120
5270
  case "awaiting-input":
5121
- return chalk30.red("\u25CB");
5271
+ return chalk32.red("\u25CB");
5122
5272
  }
5123
5273
  }
5124
5274
 
5125
5275
  // src/commands/secret/generate.ts
5126
5276
  init_logger();
5127
- import chalk31 from "chalk";
5277
+ import chalk33 from "chalk";
5128
5278
  async function secretGenerate(key, options) {
5129
- const env8 = resolveEnv(options.env);
5279
+ const env9 = resolveEnv(options.env);
5130
5280
  const pkg = options.package ?? "@spfn/core";
5131
5281
  let schema;
5132
5282
  try {
@@ -5140,11 +5290,11 @@ async function secretGenerate(key, options) {
5140
5290
  logger.warn("No generatable secrets found (none declare a `generate` strategy).");
5141
5291
  return;
5142
5292
  }
5143
- logger.step(`Generating ${targets.length} secret(s) \u2192 ${await describeTarget(env8)}`);
5293
+ logger.step(`Generating ${targets.length} secret(s) \u2192 ${await describeTarget(env9)}`);
5144
5294
  for (const entry of targets) {
5145
5295
  const value = generateSecretValue(entry.generate);
5146
5296
  try {
5147
- await storeSecret(process.cwd(), env8, entry.key, value);
5297
+ await storeSecret(process.cwd(), env9, entry.key, value);
5148
5298
  } catch (error) {
5149
5299
  logger.error(`${entry.key}: ${error instanceof Error ? error.message : String(error)}`);
5150
5300
  process.exit(1);
@@ -5162,7 +5312,7 @@ function requireGeneratable(schema, key) {
5162
5312
  process.exit(1);
5163
5313
  }
5164
5314
  if (!entry.generate) {
5165
- logger.error(`${chalk31.cyan(key)} has no generate strategy \u2014 it's an external value. Use \`spfn secret set ${key}\`.`);
5315
+ logger.error(`${chalk33.cyan(key)} has no generate strategy \u2014 it's an external value. Use \`spfn secret set ${key}\`.`);
5166
5316
  process.exit(1);
5167
5317
  }
5168
5318
  return entry;
@@ -5170,9 +5320,9 @@ function requireGeneratable(schema, key) {
5170
5320
 
5171
5321
  // src/commands/secret/rotate.ts
5172
5322
  init_logger();
5173
- import chalk32 from "chalk";
5323
+ import chalk34 from "chalk";
5174
5324
  async function secretRotate(key, options) {
5175
- const env8 = resolveEnv(options.env);
5325
+ const env9 = resolveEnv(options.env);
5176
5326
  const pkg = options.package ?? "@spfn/core";
5177
5327
  let schema;
5178
5328
  try {
@@ -5185,10 +5335,10 @@ async function secretRotate(key, options) {
5185
5335
  const generatable = targets.filter((entry) => entry.generate);
5186
5336
  const external = targets.filter((entry) => !entry.generate);
5187
5337
  if (generatable.length > 0) {
5188
- logger.step(`Rotating ${generatable.length} secret(s) \u2192 ${await describeTarget(env8)}`);
5338
+ logger.step(`Rotating ${generatable.length} secret(s) \u2192 ${await describeTarget(env9)}`);
5189
5339
  for (const entry of generatable) {
5190
5340
  try {
5191
- await storeSecret(process.cwd(), env8, entry.key, generateSecretValue(entry.generate));
5341
+ await storeSecret(process.cwd(), env9, entry.key, generateSecretValue(entry.generate));
5192
5342
  } catch (error) {
5193
5343
  logger.error(`${entry.key}: ${error instanceof Error ? error.message : String(error)}`);
5194
5344
  process.exit(1);
@@ -5196,7 +5346,7 @@ async function secretRotate(key, options) {
5196
5346
  }
5197
5347
  }
5198
5348
  for (const entry of external) {
5199
- logger.warn(`${chalk32.cyan(entry.key)} is external \u2014 reissue it at the provider, then \`spfn secret set ${entry.key} --env ${env8}\`.`);
5349
+ logger.warn(`${chalk34.cyan(entry.key)} is external \u2014 reissue it at the provider, then \`spfn secret set ${entry.key} --env ${env9}\`.`);
5200
5350
  }
5201
5351
  if (generatable.length > 0) {
5202
5352
  logger.info("Rotation updates the source only \u2014 commit and deploy to apply.");
@@ -5218,12 +5368,12 @@ function requireEntry(schema, key) {
5218
5368
  // src/commands/secret/keygen.ts
5219
5369
  init_logger();
5220
5370
  import { execa as execa11 } from "execa";
5221
- import { existsSync as existsSync28, mkdirSync as mkdirSync4 } from "fs";
5371
+ import { existsSync as existsSync29, mkdirSync as mkdirSync4 } from "fs";
5222
5372
  import { homedir } from "os";
5223
- import { dirname as dirname4, join as join25 } from "path";
5224
- import chalk33 from "chalk";
5373
+ import { dirname as dirname4, join as join26 } from "path";
5374
+ import chalk35 from "chalk";
5225
5375
  function ageKeyFile() {
5226
- return process.env.SOPS_AGE_KEY_FILE ?? join25(homedir(), ".config", "sops", "age", "keys.txt");
5376
+ return process.env.SOPS_AGE_KEY_FILE ?? join26(homedir(), ".config", "sops", "age", "keys.txt");
5227
5377
  }
5228
5378
  async function ensureAgeInstalled() {
5229
5379
  try {
@@ -5243,7 +5393,7 @@ async function secretKeygen() {
5243
5393
  process.exit(1);
5244
5394
  }
5245
5395
  const keyFile = ageKeyFile();
5246
- if (existsSync28(keyFile)) {
5396
+ if (existsSync29(keyFile)) {
5247
5397
  const { stdout } = await execa11("age-keygen", ["-y", keyFile]);
5248
5398
  logger.warn(`age key file already exists: ${keyFile}`);
5249
5399
  printPublicKeys(publicKeys(stdout));
@@ -5259,27 +5409,27 @@ function printPublicKeys(keys) {
5259
5409
  logger.warn("Could not read the public key \u2014 run `age-keygen -y <file>` manually.");
5260
5410
  return;
5261
5411
  }
5262
- console.log(chalk33.bold("\nPublic key(s):"));
5412
+ console.log(chalk35.bold("\nPublic key(s):"));
5263
5413
  for (const key of keys) {
5264
- console.log(` ${chalk33.cyan(key)}`);
5414
+ console.log(` ${chalk35.cyan(key)}`);
5265
5415
  }
5266
- console.log(chalk33.dim("\nRegister it as a recipient:"));
5267
- console.log(chalk33.dim(` spfn secret recipients add ${keys[0]}
5416
+ console.log(chalk35.dim("\nRegister it as a recipient:"));
5417
+ console.log(chalk35.dim(` spfn secret recipients add ${keys[0]}
5268
5418
  `));
5269
5419
  }
5270
5420
 
5271
5421
  // src/commands/secret/recipients.ts
5272
5422
  init_logger();
5273
- import { existsSync as existsSync29, readFileSync as readFileSync13, writeFileSync as writeFileSync18 } from "fs";
5274
- import { join as join26 } from "path";
5423
+ import { existsSync as existsSync30, readFileSync as readFileSync13, writeFileSync as writeFileSync18 } from "fs";
5424
+ import { join as join27 } from "path";
5275
5425
  import { parse as parse3, stringify } from "yaml";
5276
- import chalk34 from "chalk";
5426
+ import chalk36 from "chalk";
5277
5427
  var SOPS_CONFIG = ".sops.yaml";
5278
5428
  var DEFAULT_PATH_REGEX = "secrets/.*\\.enc\\.json$";
5279
5429
  var AGE_RECIPIENT = /^age1[0-9a-z]+$/;
5280
5430
  async function secretRecipients(action, key, _options) {
5281
5431
  const cwd = process.cwd();
5282
- const configPath = join26(cwd, SOPS_CONFIG);
5432
+ const configPath = join27(cwd, SOPS_CONFIG);
5283
5433
  if (action === "list") {
5284
5434
  listRecipients(configPath);
5285
5435
  return;
@@ -5311,25 +5461,25 @@ async function secretRecipients(action, key, _options) {
5311
5461
  await reencrypt(cwd);
5312
5462
  }
5313
5463
  function listRecipients(configPath) {
5314
- if (!existsSync29(configPath)) {
5464
+ if (!existsSync30(configPath)) {
5315
5465
  logger.info(`No ${SOPS_CONFIG} found.`);
5316
5466
  return;
5317
5467
  }
5318
5468
  const config = loadConfig(configPath);
5319
5469
  const rules = config.creation_rules ?? [];
5320
- console.log(chalk34.blue.bold(`
5470
+ console.log(chalk36.blue.bold(`
5321
5471
  \u{1F465} Recipients (${SOPS_CONFIG})
5322
5472
  `));
5323
5473
  for (const rule of rules) {
5324
- console.log(chalk34.dim(` ${rule.path_regex ?? "(any path)"}`));
5474
+ console.log(chalk36.dim(` ${rule.path_regex ?? "(any path)"}`));
5325
5475
  for (const recipient of parseRecipients(rule.age)) {
5326
- console.log(` ${chalk34.cyan(recipient)}`);
5476
+ console.log(` ${chalk36.cyan(recipient)}`);
5327
5477
  }
5328
5478
  }
5329
5479
  console.log();
5330
5480
  }
5331
5481
  function loadConfig(configPath) {
5332
- if (!existsSync29(configPath)) {
5482
+ if (!existsSync30(configPath)) {
5333
5483
  return { creation_rules: [] };
5334
5484
  }
5335
5485
  return parse3(readFileSync13(configPath, "utf-8")) ?? { creation_rules: [] };
@@ -5364,8 +5514,8 @@ async function reencrypt(cwd) {
5364
5514
 
5365
5515
  // src/commands/secret/check.ts
5366
5516
  init_logger();
5367
- import { join as join27 } from "path";
5368
- import chalk35 from "chalk";
5517
+ import { join as join28 } from "path";
5518
+ import chalk37 from "chalk";
5369
5519
  init_env_file();
5370
5520
  var COMMITTED_FILES = [".env", ".env.example"];
5371
5521
  var PLACEHOLDER = /(your-|changeme|placeholder|example|<.*>)/i;
@@ -5383,35 +5533,35 @@ async function secretCheck(options) {
5383
5533
  const issues = [];
5384
5534
  const warnings = [];
5385
5535
  for (const file of COMMITTED_FILES) {
5386
- const parsed = parseEnvFile(join27(cwd, file));
5536
+ const parsed = parseEnvFile(join28(cwd, file));
5387
5537
  for (const [key, value] of Object.entries(parsed)) {
5388
5538
  if (secretKeys.has(key) && value.length > 0 && !PLACEHOLDER.test(value)) {
5389
- issues.push(`${chalk35.cyan(key)} has a real value in committed ${chalk35.yellow(file)} \u2014 move it to the keychain/SOPS.`);
5539
+ issues.push(`${chalk37.cyan(key)} has a real value in committed ${chalk37.yellow(file)} \u2014 move it to the keychain/SOPS.`);
5390
5540
  }
5391
5541
  }
5392
5542
  }
5393
- const serverEnv = parseEnvFile(join27(cwd, ".env.server"));
5543
+ const serverEnv = parseEnvFile(join28(cwd, ".env.server"));
5394
5544
  for (const key of secretKeys) {
5395
5545
  const value = serverEnv[key];
5396
5546
  if (value && !value.startsWith(KEYCHAIN_REF_PREFIX)) {
5397
- warnings.push(`${chalk35.cyan(key)} is plaintext in .env.server \u2014 run \`spfn secret set ${key}\` to move it to the keychain.`);
5547
+ warnings.push(`${chalk37.cyan(key)} is plaintext in .env.server \u2014 run \`spfn secret set ${key}\` to move it to the keychain.`);
5398
5548
  }
5399
5549
  }
5400
5550
  report(issues, warnings, cwd);
5401
5551
  }
5402
5552
  function report(issues, warnings, cwd) {
5403
- console.log(chalk35.blue.bold("\n\u{1F50D} Secret hygiene check\n"));
5553
+ console.log(chalk37.blue.bold("\n\u{1F50D} Secret hygiene check\n"));
5404
5554
  for (const issue of issues) {
5405
- console.log(` ${chalk35.red("\u2717")} ${issue}`);
5555
+ console.log(` ${chalk37.red("\u2717")} ${issue}`);
5406
5556
  }
5407
5557
  for (const warning of warnings) {
5408
- console.log(` ${chalk35.yellow("\u26A0")} ${warning}`);
5558
+ console.log(` ${chalk37.yellow("\u26A0")} ${warning}`);
5409
5559
  }
5410
5560
  if (!hasSopsConfig(cwd)) {
5411
- console.log(` ${chalk35.dim("\u2139 no .sops.yaml \u2014 prod secrets need a backend (spfn secret keygen, or add a KMS rule)")}`);
5561
+ console.log(` ${chalk37.dim("\u2139 no .sops.yaml \u2014 prod secrets need a backend (spfn secret keygen, or add a KMS rule)")}`);
5412
5562
  }
5413
5563
  if (issues.length === 0 && warnings.length === 0) {
5414
- console.log(chalk35.green(" \u2713 No plaintext secret leaks found."));
5564
+ console.log(chalk37.green(" \u2713 No plaintext secret leaks found."));
5415
5565
  }
5416
5566
  console.log();
5417
5567
  if (issues.length > 0) {