@farm.js/cli 0.1.0-beta.13 → 0.1.0-beta.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -2,13 +2,13 @@ import { n as listFarmIntegrationProviders, t as addFarmIntegration } from "./ad
2
2
  import { buildFarm } from "./build.mjs";
3
3
  import { createRequire } from "node:module";
4
4
  import { createServer, startDevServer } from "@farm.js/core/server";
5
- import { existsSync, readFileSync, readdirSync } from "node:fs";
5
+ import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, writeFileSync } from "node:fs";
6
6
  import { mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
7
7
  import path from "node:path";
8
8
  import { execFileSync, execSync } from "child_process";
9
9
  import { existsSync as existsSync$1, readFileSync as readFileSync$1 } from "fs";
10
10
  import path$1 from "path";
11
- import { generateFarmTypeArtifacts, getFarmDocsRouteTypeEntries, getFarmSourceRoots, getIntegrationSchemas, getPresetForDeployTarget, loadConfig, logger, normalizeDeployTarget, resolveConfig, resolveDeployConfig, resolveDeployOutputPath } from "@farm.js/core";
11
+ import { farmRouteRuleMatches, generateFarmTypeArtifacts, getFarmDocsRouteTypeEntries, getFarmPresetRuntime, getFarmSourceRoots, getIntegrationSchemas, getPresetForDeployTarget, isProgrammaticRoutesFileName, loadConfig, logger, mergeFarmRouteRuntimeConfigs, normalizeDeployTarget, resolveConfig, resolveDeployConfig, resolveDeployOutputPath, resolveFarmRouteRuleRuntimeConfig, resolveFarmRouteRuntimeConfig, resolveRouteRenderingConfig, scanProgrammaticPagePaths } from "@farm.js/core";
12
12
  import { spawn, spawnSync } from "node:child_process";
13
13
  import { setTimeout as setTimeout$1 } from "node:timers/promises";
14
14
  import pc from "picocolors";
@@ -22,32 +22,97 @@ var __require = /* #__PURE__ */ (() => createRequire(import.meta.url))();
22
22
  * Deploy Farm.js application
23
23
  */
24
24
  async function deployFarm(options = {}) {
25
- const root = options.root || process.cwd();
25
+ const { plan, deployConfig } = await resolveFarmDeployContext(options);
26
+ if (options.plan) {
27
+ logger.info(formatFarmDeployPlan(plan));
28
+ return plan;
29
+ }
30
+ logger.info(`🚀 Building with ${plan.preset} preset...`);
31
+ await buildFarm({
32
+ root: plan.root,
33
+ preset: plan.preset
34
+ });
35
+ if (!existsSync$1(plan.outputDir)) throw new Error(`Build output not found at ${plan.outputDir}. Please run 'farm build' first.`);
36
+ await deployPlatform(plan.target, plan.root, plan.outputDir, deployConfig, options.prod);
37
+ return plan;
38
+ }
39
+ async function createFarmDeployPlan(options = {}) {
40
+ return (await resolveFarmDeployContext(options)).plan;
41
+ }
42
+ function formatFarmDeployPlan(plan) {
43
+ return [
44
+ "FARM / DEPLOY PLAN",
45
+ "",
46
+ `Target: ${plan.target}`,
47
+ `Preset: ${plan.preset}`,
48
+ `Runtime: ${plan.runtime}`,
49
+ `Output: ${plan.outputDir}`,
50
+ `Production: ${plan.production ? "yes" : "no"}`,
51
+ "",
52
+ `1. ${plan.build.command}`,
53
+ ` cwd: ${plan.build.cwd}`,
54
+ `2. ${plan.deploy.command}`,
55
+ ` cwd: ${plan.deploy.cwd}`,
56
+ ...plan.cloudflareAgent ? ["", `Cloudflare Agent config: ${plan.cloudflareAgent.configPath}${plan.cloudflareAgent.generated ? " (generated during build)" : ""}`] : []
57
+ ].join("\n");
58
+ }
59
+ async function resolveFarmDeployContext(options) {
60
+ const root = path$1.resolve(options.root || process.cwd());
26
61
  const mode = "production";
27
62
  const userConfig = await loadConfig(root, void 0, mode);
28
- const config = userConfig ? await resolveConfig(userConfig, mode) : void 0;
63
+ const config = await resolveConfig({
64
+ root,
65
+ ...userConfig
66
+ }, mode);
29
67
  const cliTarget = options.vercel ? "vercel" : options.cloudflare ? "cloudflare" : options.netlify ? "netlify" : void 0;
30
- const platform = normalizeDeployTarget(cliTarget || config?.deploy.target);
31
- if (platform !== "vercel" && platform !== "cloudflare" && platform !== "netlify") {
32
- logger.error("Please specify a deployment target with --vercel, --cloudflare, --netlify, or farm.config deploy.target.");
33
- process.exit(1);
34
- }
68
+ const platform = normalizeDeployTarget(cliTarget || config.deploy.target);
69
+ if (platform !== "vercel" && platform !== "cloudflare" && platform !== "netlify") throw new Error("Please specify a deployment target with --vercel, --cloudflare, --netlify, or farm.config deploy.target.");
35
70
  const deployConfig = resolveDeployConfig(userConfig || {}, {
36
71
  target: platform,
37
72
  preset: cliTarget ? userConfig?.deploy?.preset || userConfig?.preset || getPresetForDeployTarget(platform) : void 0
38
73
  });
39
74
  const preset = deployConfig.preset || getPresetForDeployTarget(platform) || "node-server";
40
- logger.info(`🚀 Building with ${preset} preset...`);
41
- await buildFarm({
42
- root,
43
- preset
44
- });
45
75
  const nitroOutput = resolveDeployOutputPath(root, deployConfig.outputDir);
46
- if (!existsSync$1(nitroOutput)) {
47
- logger.error(`Build output not found at ${nitroOutput}. Please run 'farm build' first.`);
48
- process.exit(1);
76
+ const cloudflareAgent = platform === "cloudflare" ? resolveCloudflareAgentDeployPlan(root) || resolveConfiguredCloudflareAgentDeployPlan(root, config.integrations) : void 0;
77
+ const deploy = createDeployCommand(platform, root, nitroOutput, deployConfig, options.prod, cloudflareAgent);
78
+ return {
79
+ plan: {
80
+ root: path$1.resolve(root),
81
+ target: platform,
82
+ preset,
83
+ runtime: getFarmPresetRuntime(preset),
84
+ outputDir: nitroOutput,
85
+ production: platform === "netlify" || Boolean(options.prod),
86
+ build: {
87
+ command: `farm build --preset ${preset}`,
88
+ cwd: path$1.resolve(root)
89
+ },
90
+ deploy,
91
+ ...cloudflareAgent ? { cloudflareAgent } : {}
92
+ },
93
+ deployConfig
94
+ };
95
+ }
96
+ function createDeployCommand(platform, root, outputDir, deployConfig, prod, cloudflareAgent) {
97
+ if (platform === "vercel") return {
98
+ command: `vercel deploy --prebuilt --yes${prod ? " --prod" : ""}`,
99
+ cwd: path$1.resolve(root)
100
+ };
101
+ if (platform === "netlify") {
102
+ const site = deployConfig.netlify?.site;
103
+ return {
104
+ command: `netlify deploy --prod --dir=.${site ? ` --site=${site}` : ""}`,
105
+ cwd: outputDir
106
+ };
49
107
  }
50
- await deployPlatform(platform, root, nitroOutput, deployConfig, options.prod);
108
+ if (cloudflareAgent) return {
109
+ command: `wrangler deploy --config ${cloudflareAgent.configPath}${cloudflareAgent.environment ? ` --env ${cloudflareAgent.environment}` : ""}`,
110
+ cwd: path$1.resolve(root)
111
+ };
112
+ return {
113
+ command: `wrangler pages deploy . --project-name=${deployConfig.cloudflare?.projectName || deployConfig.projectName || "farm-app"}`,
114
+ cwd: outputDir
115
+ };
51
116
  }
52
117
  /**
53
118
  * Deploy using platform's native CLI (user credentials)
@@ -252,6 +317,26 @@ function resolveCloudflareAgentDeployPlan(root) {
252
317
  ...typeof environment === "string" ? { environment: environment.trim() } : {}
253
318
  };
254
319
  }
320
+ function resolveConfiguredCloudflareAgentDeployPlan(root, integrations) {
321
+ const integration = Object.values(integrations || {}).find((value) => isRecord(value) && value.category === "agent" && value.type === "cloudflare" && value.serverRuntime === false);
322
+ if (!isRecord(integration) || !isRecord(integration.instance)) return void 0;
323
+ const configuredPath = integration.instance.config;
324
+ if (typeof configuredPath !== "string" || !configuredPath.trim()) return void 0;
325
+ const projectRoot = path$1.resolve(root);
326
+ const sourceConfigPath = path$1.resolve(projectRoot, configuredPath);
327
+ assertPathInsideProject(projectRoot, sourceConfigPath, "Cloudflare Agents source config");
328
+ const configPath = path$1.join(path$1.dirname(sourceConfigPath), ".farm-cf-agent.wrangler.jsonc");
329
+ const environment = integration.instance.environment;
330
+ return {
331
+ configPath,
332
+ ...typeof environment === "string" && environment.trim() ? { environment: environment.trim() } : {},
333
+ generated: true
334
+ };
335
+ }
336
+ function assertPathInsideProject(projectRoot, candidate, label) {
337
+ const relativePath = path$1.relative(projectRoot, candidate);
338
+ if (relativePath === ".." || relativePath.startsWith(`..${path$1.sep}`) || path$1.isAbsolute(relativePath)) throw new Error(`${label} must stay inside the Farm project root.`);
339
+ }
255
340
  function assertWranglerInstalled(root) {
256
341
  try {
257
342
  execFileSync("wrangler", ["--version"], {
@@ -800,10 +885,20 @@ function normalizePreviewDomain(value) {
800
885
  }
801
886
  //#endregion
802
887
  //#region src/generate.ts
888
+ var FarmGeneratedArtifactsStaleError = class extends Error {
889
+ constructor(root, stalePaths) {
890
+ const normalizedPaths = [...new Set(stalePaths)].sort();
891
+ const relativePaths = normalizedPaths.map((filePath) => path.relative(root, filePath));
892
+ super(`Generated types are stale:\n${relativePaths.map((filePath) => ` - ${filePath}`).join("\n")}\nRun farm generate and commit the updated files.`);
893
+ this.name = "FarmGeneratedArtifactsStaleError";
894
+ this.stalePaths = normalizedPaths;
895
+ }
896
+ };
803
897
  const PRISMA_GENERATED_START = "// Farm.js integrations generated schema: start";
804
898
  const PRISMA_GENERATED_END = "// Farm.js integrations generated schema: end";
805
899
  async function generateFarmArtifacts(options = {}) {
806
900
  const root = path.resolve(options.root || process.cwd());
901
+ if (options.check && hasSchemaOptions(options)) throw new Error("--check verifies generated framework types and cannot be combined with schema output options.");
807
902
  const userConfig = await loadConfig(root, options.configPath, "development");
808
903
  if (!userConfig && hasSchemaOptions(options)) throw new Error("No Farm config found. Please create farm.config.ts or config.ts.");
809
904
  const resolvedConfig = await resolveConfig({
@@ -818,14 +913,20 @@ async function generateFarmArtifacts(options = {}) {
818
913
  layers: resolvedConfig.layers,
819
914
  extraRoutes,
820
915
  suppressLintOnLink: resolvedConfig.suppressLintOnLink,
821
- i18nConfig: resolvedConfig.i18n
916
+ i18nConfig: resolvedConfig.i18n,
917
+ check: options.check
822
918
  });
919
+ if (options.check) {
920
+ if (typeArtifacts.stalePaths.length) throw new FarmGeneratedArtifactsStaleError(root, typeArtifacts.stalePaths);
921
+ logger.success(`Generated route, API, env${resolvedConfig.i18n.enabled ? ", and i18n" : ""} types are up to date.`);
922
+ return typeArtifacts;
923
+ }
823
924
  logger.success(`Generated route, API, env${resolvedConfig.i18n.enabled ? ", and i18n" : ""} types (${typeArtifacts.apiRoutes.length} API route${typeArtifacts.apiRoutes.length === 1 ? "" : "s"}).`);
824
925
  const schemas = getIntegrationSchemas(resolvedConfig.integrations);
825
926
  const schemaEntries = Object.entries(schemas);
826
927
  if (!schemaEntries.length) {
827
928
  if (hasSchemaOptions(options)) logger.warn("No integration schemas were found in the current Farm config.");
828
- return;
929
+ return typeArtifacts;
829
930
  }
830
931
  const packageManifest = await readPackageManifest(root);
831
932
  const schemaOptionsExplicit = hasSchemaOptions(options);
@@ -835,12 +936,12 @@ async function generateFarmArtifacts(options = {}) {
835
936
  } catch (error) {
836
937
  if (schemaOptionsExplicit) throw error;
837
938
  logger.warn(`Integration schemas were found, but Farm could not choose a schema target automatically: ${error.message}`);
838
- return;
939
+ return typeArtifacts;
839
940
  }
840
941
  if (!orm) {
841
942
  if (!schemaOptionsExplicit) {
842
943
  logger.warn("Integration schemas were found, but no data layer was detected. Pass --orm prisma|drizzle|postgres|mysql|sqlite|mongodb to generate schema artifacts.");
843
- return;
944
+ return typeArtifacts;
844
945
  }
845
946
  throw new Error("Could not auto-detect a schema target. Pass one explicitly with --orm prisma|drizzle|postgres|mysql|sqlite|mongodb.");
846
947
  }
@@ -851,7 +952,7 @@ async function generateFarmArtifacts(options = {}) {
851
952
  if (!existsSync(schemaPath)) throw new Error(`Prisma target was selected but no schema file was found at ${schemaPath}. Create prisma/schema.prisma or pass --output.`);
852
953
  await writePrismaSchema(schemaPath, collectedModels);
853
954
  logger.success(`Generated Prisma integration schema in ${path.relative(root, schemaPath)}.`);
854
- return;
955
+ return typeArtifacts;
855
956
  }
856
957
  case "drizzle": {
857
958
  const dialect = options.dialect ?? await detectDrizzleDialect(root, packageManifest) ?? void 0;
@@ -859,7 +960,7 @@ async function generateFarmArtifacts(options = {}) {
859
960
  const outputPath = options.output ? path.resolve(root, options.output) : path.join(root, "farm-integrations.generated.ts");
860
961
  await writeGeneratedFile(outputPath, generateDrizzleSchema(collectedModels, dialect));
861
962
  logger.success(`Generated Drizzle integration schema in ${path.relative(root, outputPath)}.`);
862
- return;
963
+ return typeArtifacts;
863
964
  }
864
965
  case "postgres":
865
966
  case "mysql":
@@ -867,13 +968,13 @@ async function generateFarmArtifacts(options = {}) {
867
968
  const outputPath = options.output ? path.resolve(root, options.output) : path.join(root, `farm-integrations.generated.${orm}.sql`);
868
969
  await writeGeneratedFile(outputPath, generateSqlSchema(collectedModels, orm));
869
970
  logger.success(`Generated ${orm} integration schema in ${path.relative(root, outputPath)}.`);
870
- return;
971
+ return typeArtifacts;
871
972
  }
872
973
  case "mongodb": {
873
974
  const outputPath = options.output ? path.resolve(root, options.output) : path.join(root, "farm-integrations.generated.mongodb.ts");
874
975
  await writeGeneratedFile(outputPath, generateMongoBootstrap(collectedModels));
875
976
  logger.success(`Generated MongoDB integration bootstrap in ${path.relative(root, outputPath)}.`);
876
- return;
977
+ return typeArtifacts;
877
978
  }
878
979
  }
879
980
  }
@@ -1058,7 +1159,7 @@ function cloneSchemaModel(model) {
1058
1159
  async function writePrismaSchema(schemaPath, models) {
1059
1160
  const source = await readFile(schemaPath, "utf8");
1060
1161
  const generated = createPrismaGeneratedBlock(generatePrismaSchema(models));
1061
- const pattern = new RegExp(`${escapeRegExp(PRISMA_GENERATED_START)}[\\s\\S]*?${escapeRegExp(PRISMA_GENERATED_END)}`, "m");
1162
+ const pattern = new RegExp(`${escapeRegExp$1(PRISMA_GENERATED_START)}[\\s\\S]*?${escapeRegExp$1(PRISMA_GENERATED_END)}`, "m");
1062
1163
  const nextSource = pattern.test(source) ? source.replace(pattern, generated) : `${source.trimEnd()}\n\n${generated}\n`;
1063
1164
  await writeFile(schemaPath, nextSource, "utf8");
1064
1165
  }
@@ -1386,12 +1487,12 @@ function toCamelCase(value) {
1386
1487
  function escapeString(value) {
1387
1488
  return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/'/g, "''");
1388
1489
  }
1389
- function escapeRegExp(value) {
1490
+ function escapeRegExp$1(value) {
1390
1491
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1391
1492
  }
1392
1493
  //#endregion
1393
1494
  //#region src/doctor.ts
1394
- const ROUTE_EXTENSIONS = [
1495
+ const ROUTE_EXTENSIONS$1 = [
1395
1496
  "ts",
1396
1497
  "tsx",
1397
1498
  "js",
@@ -1413,7 +1514,7 @@ async function runFarmDoctor(options = {}) {
1413
1514
  const root = path.resolve(options.root || process.cwd());
1414
1515
  const liveTarget = resolveLiveTarget(options);
1415
1516
  let liveError;
1416
- if (!options.offline) try {
1517
+ if (!options.offline && !options.fix) try {
1417
1518
  return createLiveReport(await fetchLiveSnapshot(liveTarget, options), liveTarget, options.now);
1418
1519
  } catch (error) {
1419
1520
  liveError = formatError$2(error);
@@ -1460,6 +1561,13 @@ function formatFarmDoctorReport(report, options = {}) {
1460
1561
  `${report.summary.fail} failed`,
1461
1562
  `${report.summary.info} info`
1462
1563
  ].join(" / ");
1564
+ if (report.fixes?.length) {
1565
+ lines.push("", color.bold("FIXED"));
1566
+ for (const fix of report.fixes) {
1567
+ lines.push(` ${color.green("✓")} ${fix.title}`);
1568
+ lines.push(` ${color.dim(fix.filePath)}`);
1569
+ }
1570
+ }
1463
1571
  lines.push("", `${color.bold("SUMMARY")} ${summary}`);
1464
1572
  if (report.target?.devtoolsUrl) lines.push(`${color.bold("DEVTOOLS")} ${report.target.devtoolsUrl}`);
1465
1573
  return lines.join("\n");
@@ -1559,9 +1667,10 @@ async function createProjectReport(root, options) {
1559
1667
  action: "Add farm.config.ts and export defineConfig({...})."
1560
1668
  });
1561
1669
  else {
1670
+ const configRoot = path.resolve(root, userConfig.root || ".");
1562
1671
  config = await resolveConfig({
1563
- root,
1564
- ...userConfig
1672
+ ...userConfig,
1673
+ root: configRoot
1565
1674
  }, "development");
1566
1675
  const configFile = findConfigFile(root, options.configPath);
1567
1676
  checks.push({
@@ -1585,9 +1694,40 @@ async function createProjectReport(root, options) {
1585
1694
  report.target = collectDeploymentChecks(config, userConfig, checks);
1586
1695
  collectCronChecks(config, options.env || process.env, checks);
1587
1696
  }
1697
+ if (config && options.fix) {
1698
+ const fixes = applySafeProjectFixes(root, config, checks);
1699
+ if (fixes.length) {
1700
+ const refreshed = await createProjectReport(root, {
1701
+ ...options,
1702
+ fix: false
1703
+ });
1704
+ refreshed.fixes = fixes;
1705
+ return refreshed;
1706
+ }
1707
+ report.fixes = [];
1708
+ }
1588
1709
  finalizeReport(report);
1589
1710
  return report;
1590
1711
  }
1712
+ function applySafeProjectFixes(root, config, checks) {
1713
+ const fixes = [];
1714
+ if (checks.some((check) => check.code === "ROOT_LAYOUT_MISSING")) {
1715
+ const layoutPath = path.join(config.root, config.srcDir, "app", "layout.tsx");
1716
+ if (!existsSync(layoutPath)) {
1717
+ mkdirSync(path.dirname(layoutPath), { recursive: true });
1718
+ writeFileSync(layoutPath, `import type { ReactNode } from "react";\n\nexport default function RootLayout({ children }: { children: ReactNode }) {\n return (\n <html lang="en">\n <body>{children}</body>\n </html>\n );\n}\n`, {
1719
+ encoding: "utf8",
1720
+ flag: "wx"
1721
+ });
1722
+ fixes.push({
1723
+ code: "ROOT_LAYOUT_CREATED",
1724
+ title: "Created the missing root layout",
1725
+ filePath: path.relative(root, layoutPath)
1726
+ });
1727
+ }
1728
+ }
1729
+ return fixes;
1730
+ }
1591
1731
  function collectNodeCheck(checks) {
1592
1732
  const major = Number(process.versions.node.split(".")[0]);
1593
1733
  checks.push(major >= 18 ? {
@@ -1648,7 +1788,7 @@ function collectRouterChecks(config, checks) {
1648
1788
  const sources = getFarmSourceRoots(config);
1649
1789
  const appDirectories = sources.map((source) => path.join(source.root, source.srcDir, "app"));
1650
1790
  const hasPages = appDirectories.some((directory) => containsFile(directory, /^page\.(?:ts|tsx|js|jsx|md|mdx)$/));
1651
- const hasProgrammaticRoutes = sources.some((source) => ROUTE_EXTENSIONS.some((extension) => existsSync(path.join(source.root, source.srcDir, `farm.routes.${extension}`))));
1791
+ const hasProgrammaticRoutes = sources.some((source) => ROUTE_EXTENSIONS$1.some((extension) => existsSync(path.join(source.root, source.srcDir, `farm.routes.${extension}`))));
1652
1792
  checks.push(hasPages || hasProgrammaticRoutes ? {
1653
1793
  status: "pass",
1654
1794
  code: "APP_ROUTER_READY",
@@ -1661,7 +1801,7 @@ function collectRouterChecks(config, checks) {
1661
1801
  message: `Farm found no page modules under ${config.srcDir}/app.`,
1662
1802
  action: `Add ${config.srcDir}/app/page.tsx or ${config.srcDir}/farm.routes.tsx.`
1663
1803
  });
1664
- const hasRootLayout = appDirectories.some((directory) => ROUTE_EXTENSIONS.some((extension) => existsSync(path.join(directory, `layout.${extension}`))));
1804
+ const hasRootLayout = appDirectories.some((directory) => ROUTE_EXTENSIONS$1.some((extension) => existsSync(path.join(directory, `layout.${extension}`))));
1665
1805
  checks.push(hasRootLayout ? {
1666
1806
  status: "pass",
1667
1807
  code: "ROOT_LAYOUT_READY",
@@ -1731,7 +1871,7 @@ function hasCronRoute(config, job) {
1731
1871
  const relative = job.path.replace(/^\/+/, "").replace(/^api\//, "");
1732
1872
  return getFarmSourceRoots(config).some((source) => {
1733
1873
  const directory = path.join(source.root, source.srcDir, "app", "api", relative);
1734
- return ROUTE_EXTENSIONS.some((extension) => existsSync(path.join(directory, `route.${extension}`)));
1874
+ return ROUTE_EXTENSIONS$1.some((extension) => existsSync(path.join(directory, `route.${extension}`)));
1735
1875
  });
1736
1876
  }
1737
1877
  function containsFile(directory, pattern) {
@@ -1799,6 +1939,415 @@ function formatCount$1(value, noun) {
1799
1939
  return `${value} ${noun}${value === 1 ? "" : "s"}`;
1800
1940
  }
1801
1941
  //#endregion
1942
+ //#region src/explain.ts
1943
+ const ROUTE_EXTENSIONS = [
1944
+ "tsx",
1945
+ "ts",
1946
+ "jsx",
1947
+ "js",
1948
+ "mdx",
1949
+ "md"
1950
+ ];
1951
+ const MIDDLEWARE_EXTENSIONS = [
1952
+ "ts",
1953
+ "tsx",
1954
+ "js",
1955
+ "jsx",
1956
+ "mjs",
1957
+ "cjs"
1958
+ ];
1959
+ const SOCIAL_IMAGE_EXTENSIONS = [
1960
+ "tsx",
1961
+ "ts",
1962
+ "jsx",
1963
+ "js",
1964
+ "png",
1965
+ "jpg",
1966
+ "jpeg",
1967
+ "gif",
1968
+ "webp"
1969
+ ];
1970
+ async function explainFarmRoute(pathname, options = {}) {
1971
+ const root = path.resolve(options.root || process.cwd());
1972
+ const userConfig = await loadConfig(root, options.configPath, "production");
1973
+ const config = await resolveConfig({
1974
+ root,
1975
+ ...userConfig
1976
+ }, "production");
1977
+ const normalizedPathname = normalizePathname(pathname, config.basePath || "/");
1978
+ const page = discoverMatchingPages(config, normalizedPathname).sort((left, right) => right.score - left.score || right.priority - left.priority)[0];
1979
+ if (!page) throw new Error(`No Farm page route matches ${normalizedPathname}.`);
1980
+ const layouts = collectInheritedRouteFiles(config, normalizedPathname, "layout", ROUTE_EXTENSIONS);
1981
+ const middleware = collectMiddleware(root, Boolean(userConfig?.middleware && Object.keys(userConfig.middleware).length), config, normalizedPathname);
1982
+ const pageSource = readFileSync(page.filePath, "utf8");
1983
+ const layoutSources = layouts.map((filePath) => ({
1984
+ filePath,
1985
+ source: readFileSync(filePath, "utf8")
1986
+ }));
1987
+ const runtime = resolveFarmRouteRuntimeConfig(mergeFarmRouteRuntimeConfigs(resolveFarmRouteRuleRuntimeConfig(normalizedPathname, config.routeRules), ...layoutSources.map(({ source }) => readRuntimeExports(source)), readRuntimeExports(pageSource)), `Route ${page.pattern}`);
1988
+ const matchingRules = Object.entries(config.routeRules).filter(([pattern]) => farmRouteRuleMatches(pattern, normalizedPathname)).sort(([left], [right]) => routeSpecificity(left) - routeSpecificity(right));
1989
+ const rendering = resolveRendering(pageSource, matchingRules);
1990
+ const cache = resolveCaching(pageSource, matchingRules);
1991
+ const metadataSources = [...layoutSources, {
1992
+ filePath: page.filePath,
1993
+ source: pageSource
1994
+ }];
1995
+ const openGraphImage = findNearestSocialImage(config, normalizedPathname, "opengraph-image");
1996
+ const twitterImage = findNearestSocialImage(config, normalizedPathname, "twitter-image");
1997
+ const preset = String(config.deploy.preset || config.preset || "node-server");
1998
+ const presetRuntime = getFarmPresetRuntime(preset);
1999
+ const compatible = rendering.mode === "static" || rendering.mode === "client" || runtime.runtime === "auto" || presetRuntime !== "unknown" && runtime.runtime === presetRuntime;
2000
+ const warnings = [];
2001
+ if (presetRuntime === "unknown" && runtime.runtime !== "auto") warnings.push(`Farm cannot verify the ${runtime.runtime} route requirement because the ${preset} preset runtime is unknown.`);
2002
+ else if (!compatible) warnings.push(`The route requires ${runtime.runtime}, but the ${preset} preset emits ${presetRuntime} functions.`);
2003
+ if (runtime.regions?.length && preset !== "vercel" && preset !== "vercel-edge") warnings.push(`${preset} does not map Farm per-route region hints.`);
2004
+ if (runtime.maxDuration && preset !== "vercel") warnings.push(`${preset} does not map Farm per-route maxDuration.`);
2005
+ return {
2006
+ pathname: normalizedPathname,
2007
+ pattern: page.pattern,
2008
+ params: page.params,
2009
+ filePath: toProjectPath(root, page.filePath),
2010
+ source: page.source,
2011
+ layouts: layouts.map((filePath) => toProjectPath(root, filePath)),
2012
+ middleware,
2013
+ runtime,
2014
+ rendering,
2015
+ cache,
2016
+ metadata: {
2017
+ static: metadataSources.filter(({ source }) => /export\s+const\s+metadata\b/.test(source)).map(({ filePath }) => toProjectPath(root, filePath)),
2018
+ dynamic: metadataSources.filter(({ source }) => /export\s+(?:async\s+)?function\s+generateMetadata\b|export\s+const\s+generateMetadata\b/.test(source)).map(({ filePath }) => toProjectPath(root, filePath)),
2019
+ ...openGraphImage ? { openGraphImage: toProjectPath(root, openGraphImage) } : {},
2020
+ ...twitterImage ? { twitterImage: toProjectPath(root, twitterImage) } : {}
2021
+ },
2022
+ deployment: {
2023
+ target: String(config.deploy.target || "node"),
2024
+ preset,
2025
+ runtime: presetRuntime,
2026
+ compatible,
2027
+ warnings
2028
+ }
2029
+ };
2030
+ }
2031
+ function formatFarmRouteExplanation(explanation, options = {}) {
2032
+ const color = options.color === void 0 ? pc : pc.createColors(options.color);
2033
+ const lines = [
2034
+ color.bold("FARM / EXPLAIN"),
2035
+ "",
2036
+ `${color.bold("Path")} ${explanation.pathname}`,
2037
+ `${color.bold("Pattern")} ${explanation.pattern}`,
2038
+ `${color.bold("File")} ${explanation.filePath}`,
2039
+ `${color.bold("Source")} ${explanation.source}`,
2040
+ `${color.bold("Params")} ${formatParams(explanation.params)}`,
2041
+ `${color.bold("Layouts")} ${explanation.layouts.length ? explanation.layouts.join(" -> ") : "none"}`,
2042
+ `${color.bold("Middleware")} ${explanation.middleware.length ? explanation.middleware.map((entry) => entry.filePath).join(", ") : "none"}`,
2043
+ `${color.bold("Runtime")} ${formatRuntime(explanation.runtime)}`,
2044
+ `${color.bold("Rendering")} ${explanation.rendering.mode} (${explanation.rendering.reason})${explanation.rendering.ppr ? ", PPR" : ""}`,
2045
+ `${color.bold("Caching")} ${formatCaching(explanation.cache)}`,
2046
+ `${color.bold("Metadata")} ${formatMetadata(explanation.metadata)}`,
2047
+ `${color.bold("Deployment")} ${explanation.deployment.target} / ${explanation.deployment.preset} — ${explanation.deployment.compatible ? color.green("compatible") : color.red("incompatible")}`
2048
+ ];
2049
+ for (const warning of explanation.deployment.warnings) lines.push(` ${color.yellow("!")} ${warning}`);
2050
+ return lines.join("\n");
2051
+ }
2052
+ function discoverMatchingPages(config, pathname) {
2053
+ const candidates = [];
2054
+ for (const [priority, source] of getFarmSourceRoots(config).entries()) {
2055
+ const appDirectory = path.join(source.root, source.srcDir, "app");
2056
+ if (existsSync(appDirectory)) for (const filePath of walkFiles(appDirectory)) {
2057
+ if (!/^page\.(?:tsx?|jsx?|mdx?)$/.test(path.basename(filePath))) continue;
2058
+ const relativeDirectory = path.relative(appDirectory, path.dirname(filePath));
2059
+ if (relativeDirectory.split(path.sep).includes("api") || isRouteSlotDirectory(relativeDirectory)) continue;
2060
+ const pattern = directoryToRoutePattern(relativeDirectory);
2061
+ const match = matchRoutePattern(pattern, pathname);
2062
+ if (!match) continue;
2063
+ candidates.push({
2064
+ filePath,
2065
+ pattern,
2066
+ params: match.params,
2067
+ score: match.score,
2068
+ source: source.name,
2069
+ priority
2070
+ });
2071
+ }
2072
+ const sourceDirectory = path.join(source.root, source.srcDir);
2073
+ if (!existsSync(sourceDirectory)) continue;
2074
+ for (const entry of readdirSync(sourceDirectory, { withFileTypes: true })) {
2075
+ if (!entry.isFile() || !isProgrammaticRoutesFileName(entry.name)) continue;
2076
+ const filePath = path.join(sourceDirectory, entry.name);
2077
+ const moduleSource = readFileSync(filePath, "utf8");
2078
+ for (const pattern of scanProgrammaticPagePaths(moduleSource)) {
2079
+ const match = matchRoutePattern(pattern, pathname);
2080
+ if (!match) continue;
2081
+ candidates.push({
2082
+ filePath,
2083
+ pattern,
2084
+ params: match.params,
2085
+ score: match.score,
2086
+ source: source.name,
2087
+ priority
2088
+ });
2089
+ }
2090
+ }
2091
+ }
2092
+ return candidates;
2093
+ }
2094
+ function isRouteSlotDirectory(relativeDirectory) {
2095
+ return relativeDirectory.split(path.sep).some((segment) => /^@[A-Za-z][\w-]*$/.test(segment));
2096
+ }
2097
+ function walkFiles(directory) {
2098
+ const files = [];
2099
+ const pending = [directory];
2100
+ while (pending.length) {
2101
+ const current = pending.pop();
2102
+ for (const entry of readdirSync(current, { withFileTypes: true })) {
2103
+ const entryPath = path.join(current, entry.name);
2104
+ if (entry.isDirectory()) {
2105
+ if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
2106
+ pending.push(entryPath);
2107
+ continue;
2108
+ }
2109
+ files.push(entryPath);
2110
+ }
2111
+ }
2112
+ return files;
2113
+ }
2114
+ function directoryToRoutePattern(relativeDirectory) {
2115
+ const segments = relativeDirectory.split(path.sep).filter(Boolean).filter((segment) => !/^\(.+\)$/.test(segment) && !segment.startsWith("@")).map((segment) => segment.replace(/^\(\.{1,3}\)/, ""));
2116
+ return segments.length ? `/${segments.join("/")}` : "/";
2117
+ }
2118
+ function matchRoutePattern(pattern, pathname) {
2119
+ const patternSegments = splitPath(pattern);
2120
+ const pathSegments = splitPath(pathname);
2121
+ const params = {};
2122
+ let score = 0;
2123
+ let pathIndex = 0;
2124
+ for (const segment of patternSegments) {
2125
+ const optionalCatchAll = segment.match(/^\[\[\.\.\.(.+)\]\]$/);
2126
+ if (optionalCatchAll) {
2127
+ params[optionalCatchAll[1]] = pathSegments.slice(pathIndex);
2128
+ pathIndex = pathSegments.length;
2129
+ score += 1;
2130
+ continue;
2131
+ }
2132
+ const catchAll = segment.match(/^\[\.\.\.(.+)\]$/);
2133
+ if (catchAll) {
2134
+ if (pathIndex >= pathSegments.length) return null;
2135
+ params[catchAll[1]] = pathSegments.slice(pathIndex);
2136
+ pathIndex = pathSegments.length;
2137
+ score += 10;
2138
+ continue;
2139
+ }
2140
+ const dynamic = segment.match(/^\[(.+)\]$/);
2141
+ if (dynamic) {
2142
+ if (pathIndex >= pathSegments.length) return null;
2143
+ params[dynamic[1]] = pathSegments[pathIndex++];
2144
+ score += 50;
2145
+ continue;
2146
+ }
2147
+ if (segment !== pathSegments[pathIndex++]) return null;
2148
+ score += 100;
2149
+ }
2150
+ return pathIndex === pathSegments.length ? {
2151
+ params,
2152
+ score
2153
+ } : null;
2154
+ }
2155
+ function collectInheritedRouteFiles(config, pathname, baseName, extensions) {
2156
+ return collectLayeredRouteFiles(config, baseName, extensions).filter((entry) => matchesRoutePrefix(entry.pattern, pathname)).sort(compareInheritedRouteFiles).map((entry) => entry.filePath);
2157
+ }
2158
+ function collectMiddleware(root, hasConfigMiddleware, config, pathname) {
2159
+ const rootMiddleware = /* @__PURE__ */ new Map();
2160
+ for (const source of getFarmSourceRoots(config)) {
2161
+ const filePath = findFile(path.join(source.root, source.srcDir), "middleware", MIDDLEWARE_EXTENSIONS);
2162
+ if (filePath) rootMiddleware.set("root", {
2163
+ filePath,
2164
+ pattern: "/"
2165
+ });
2166
+ }
2167
+ const files = [...rootMiddleware.values(), ...collectLayeredRouteFiles(config, "middleware", MIDDLEWARE_EXTENSIONS).filter((entry) => matchesRoutePrefix(entry.pattern, pathname))].sort(compareInheritedRouteFiles).map((entry) => entry.filePath);
2168
+ return [...hasConfigMiddleware ? [{
2169
+ source: "config",
2170
+ filePath: "farm.config (middleware)"
2171
+ }] : [], ...files.map((filePath) => ({
2172
+ source: "file",
2173
+ filePath: toProjectPath(root, filePath)
2174
+ }))];
2175
+ }
2176
+ function collectLayeredRouteFiles(config, baseName, extensions) {
2177
+ const files = /* @__PURE__ */ new Map();
2178
+ const filePattern = new RegExp(`^${escapeRegExp(baseName)}\\.(?:${extensions.map(escapeRegExp).join("|")})$`);
2179
+ for (const source of getFarmSourceRoots(config)) {
2180
+ const appDirectory = path.join(source.root, source.srcDir, "app");
2181
+ if (!existsSync(appDirectory)) continue;
2182
+ for (const filePath of walkFiles(appDirectory)) {
2183
+ if (!filePattern.test(path.basename(filePath))) continue;
2184
+ const pattern = directoryToRoutePattern(path.relative(appDirectory, path.dirname(filePath)));
2185
+ files.set(pattern, {
2186
+ filePath,
2187
+ pattern
2188
+ });
2189
+ }
2190
+ }
2191
+ return [...files.values()];
2192
+ }
2193
+ function findNearestSocialImage(config, pathname, baseName) {
2194
+ return collectLayeredRouteFiles(config, baseName, SOCIAL_IMAGE_EXTENSIONS).filter((entry) => matchesRoutePrefix(entry.pattern, pathname)).sort((left, right) => compareInheritedRouteFiles(right, left))[0]?.filePath;
2195
+ }
2196
+ function compareInheritedRouteFiles(left, right) {
2197
+ return splitPath(left.pattern).length - splitPath(right.pattern).length;
2198
+ }
2199
+ function matchesRoutePrefix(pattern, pathname) {
2200
+ const patternSegments = splitPath(pattern);
2201
+ const pathSegments = splitPath(pathname);
2202
+ if (patternSegments.length > pathSegments.length) return false;
2203
+ return patternSegments.every((segment, index) => {
2204
+ if (/^\[{1,2}(?:\.\.\.)?.+\]{1,2}$/.test(segment)) return true;
2205
+ return segment === pathSegments[index];
2206
+ });
2207
+ }
2208
+ function findFile(directory, baseName, extensions) {
2209
+ return extensions.map((extension) => path.join(directory, `${baseName}.${extension}`)).find(existsSync);
2210
+ }
2211
+ function escapeRegExp(value) {
2212
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2213
+ }
2214
+ function readRuntimeExports(source) {
2215
+ const runtime = readStringExport(source, "runtime");
2216
+ const maxDuration = readNumberOrAutoExport(source, "maxDuration");
2217
+ const regions = readStringArrayOrAutoExport(source, "regions");
2218
+ return {
2219
+ ...runtime === "auto" || runtime === "node" || runtime === "edge" ? { runtime } : {},
2220
+ ...regions ? { regions } : {},
2221
+ ...maxDuration !== void 0 ? { maxDuration } : {}
2222
+ };
2223
+ }
2224
+ function resolveRendering(pageSource, matchingRules) {
2225
+ const pageRendering = resolveRouteRenderingConfig({
2226
+ ...readBooleanExport(pageSource, "ssg") !== void 0 ? { ssg: readBooleanExport(pageSource, "ssg") } : {},
2227
+ ...readBooleanExport(pageSource, "ppr") !== void 0 ? { ppr: readBooleanExport(pageSource, "ppr") } : {},
2228
+ ...readBooleanExport(pageSource, "experimental_ppr") !== void 0 ? { experimental_ppr: readBooleanExport(pageSource, "experimental_ppr") } : {},
2229
+ ...readNumberOrFalseExport(pageSource, "revalidate") !== void 0 ? { revalidate: readNumberOrFalseExport(pageSource, "revalidate") } : {},
2230
+ ...readDynamicExport(pageSource) ? { dynamic: readDynamicExport(pageSource) } : {}
2231
+ }, pageSource);
2232
+ let mode = pageRendering.ssg ? "static" : pageRendering.ppr ? "partial" : "dynamic";
2233
+ let reason = pageRendering.directive ? `page directive ${JSON.stringify(pageRendering.directive)}` : pageRendering.ssg ? "page static rendering declaration" : pageRendering.ppr ? "page PPR declaration" : "default server rendering";
2234
+ let ppr = pageRendering.ppr;
2235
+ for (const [pattern, rule] of matchingRules) if (rule.prerender === true || rule.render === "static") {
2236
+ mode = "static";
2237
+ reason = `routeRules ${pattern}`;
2238
+ ppr = false;
2239
+ } else if (rule.prerender === false || rule.render === "dynamic" || rule.ssr === true) {
2240
+ mode = "dynamic";
2241
+ reason = `routeRules ${pattern}`;
2242
+ ppr = false;
2243
+ } else if (rule.ssr === false) {
2244
+ mode = "client";
2245
+ reason = `routeRules ${pattern}`;
2246
+ ppr = false;
2247
+ }
2248
+ return {
2249
+ mode,
2250
+ reason,
2251
+ ppr
2252
+ };
2253
+ }
2254
+ function resolveCaching(pageSource, matchingRules) {
2255
+ let swr;
2256
+ let isr;
2257
+ for (const [, rule] of matchingRules) {
2258
+ if (typeof rule.swr === "number" || typeof rule.swr === "boolean") swr = rule.swr;
2259
+ if (typeof rule.isr === "number" || typeof rule.isr === "boolean") isr = rule.isr;
2260
+ }
2261
+ return {
2262
+ ...readNumberOrFalseExport(pageSource, "revalidate") !== void 0 ? { revalidate: readNumberOrFalseExport(pageSource, "revalidate") } : {},
2263
+ ...swr !== void 0 ? { swr } : {},
2264
+ ...isr !== void 0 ? { isr } : {},
2265
+ rules: matchingRules.map(([pattern]) => pattern)
2266
+ };
2267
+ }
2268
+ function readStringExport(source, name) {
2269
+ return source.match(new RegExp(`export\\s+const\\s+${name}\\s*=\\s*["']([^"']+)["']`))?.[1];
2270
+ }
2271
+ function readDynamicExport(source) {
2272
+ const dynamic = readStringExport(source, "dynamic");
2273
+ return dynamic === "auto" || dynamic === "force-dynamic" || dynamic === "error" || dynamic === "force-static" ? dynamic : void 0;
2274
+ }
2275
+ function readBooleanExport(source, name) {
2276
+ const value = source.match(new RegExp(`export\\s+const\\s+${name}\\s*=\\s*(true|false)`))?.[1];
2277
+ return value === void 0 ? void 0 : value === "true";
2278
+ }
2279
+ function readNumberOrAutoExport(source, name) {
2280
+ const value = source.match(new RegExp(`export\\s+const\\s+${name}\\s*=\\s*(?:["'](auto)["']|(\\d+))`));
2281
+ return value?.[1] === "auto" ? "auto" : value?.[2] ? Number(value[2]) : void 0;
2282
+ }
2283
+ function readNumberOrFalseExport(source, name) {
2284
+ const value = source.match(new RegExp(`export\\s+const\\s+${name}\\s*=\\s*(false|\\d+)`))?.[1];
2285
+ return value === "false" ? false : value ? Number(value) : void 0;
2286
+ }
2287
+ function readStringArrayOrAutoExport(source, name) {
2288
+ if (source.match(new RegExp(`export\\s+const\\s+${name}\\s*=\\s*["']auto["']`))) return "auto";
2289
+ const array = source.match(new RegExp(`export\\s+const\\s+${name}\\s*=\\s*\\[([^\\]]*)\\]`))?.[1];
2290
+ if (array === void 0) return void 0;
2291
+ return [...array.matchAll(/["']([^"']+)["']/g)].map((match) => match[1]);
2292
+ }
2293
+ function routeSpecificity(pattern) {
2294
+ return splitPath(pattern).reduce((score, segment) => {
2295
+ if (segment === "**" || segment.startsWith("[[...")) return score + 1;
2296
+ if (segment === "*" || segment.startsWith("[...")) return score + 10;
2297
+ if (segment.startsWith("[") || segment.startsWith(":")) return score + 50;
2298
+ return score + 100;
2299
+ }, 0);
2300
+ }
2301
+ function normalizePathname(value, basePath) {
2302
+ let pathname;
2303
+ try {
2304
+ pathname = new URL(value, "http://farm.local").pathname;
2305
+ } catch {
2306
+ pathname = value;
2307
+ }
2308
+ pathname = pathname.startsWith("/") ? pathname : `/${pathname}`;
2309
+ const normalizedBase = basePath && basePath !== "/" ? `/${basePath.replace(/^\/+|\/+$/g, "")}` : "";
2310
+ if (normalizedBase && (pathname === normalizedBase || pathname.startsWith(`${normalizedBase}/`))) pathname = pathname.slice(normalizedBase.length) || "/";
2311
+ return pathname.length > 1 ? pathname.replace(/\/+$/, "") : pathname;
2312
+ }
2313
+ function splitPath(value) {
2314
+ return value.split("/").filter(Boolean).map(decodeURIComponent);
2315
+ }
2316
+ function toProjectPath(root, filePath) {
2317
+ let relativePath = path.relative(root, filePath);
2318
+ if ((relativePath === ".." || relativePath.startsWith(`..${path.sep}`)) && existsSync(root) && existsSync(filePath)) relativePath = path.relative(realpathSync(root), realpathSync(filePath));
2319
+ return relativePath.split(path.sep).join("/");
2320
+ }
2321
+ function formatParams(params) {
2322
+ const entries = Object.entries(params);
2323
+ return entries.length ? entries.map(([key, value]) => `${key}=${Array.isArray(value) ? value.join("/") : value}`).join(", ") : "none";
2324
+ }
2325
+ function formatRuntime(runtime) {
2326
+ return [
2327
+ runtime.runtime,
2328
+ runtime.regions?.length ? `regions=${runtime.regions.join(",")}` : "",
2329
+ runtime.maxDuration ? `maxDuration=${runtime.maxDuration}s` : ""
2330
+ ].filter(Boolean).join(", ");
2331
+ }
2332
+ function formatCaching(cache) {
2333
+ const values = [
2334
+ cache.revalidate !== void 0 ? `revalidate=${cache.revalidate}` : "",
2335
+ cache.swr !== void 0 ? `swr=${cache.swr}` : "",
2336
+ cache.isr !== void 0 ? `isr=${cache.isr}` : "",
2337
+ cache.rules.length ? `rules=${cache.rules.join(",")}` : ""
2338
+ ].filter(Boolean);
2339
+ return values.length ? values.join("; ") : "request-time / no declared cache";
2340
+ }
2341
+ function formatMetadata(metadata) {
2342
+ const values = [
2343
+ metadata.static.length ? `static=${metadata.static.join(",")}` : "",
2344
+ metadata.dynamic.length ? `dynamic=${metadata.dynamic.join(",")}` : "",
2345
+ metadata.openGraphImage ? `og=${metadata.openGraphImage}` : "",
2346
+ metadata.twitterImage ? `twitter=${metadata.twitterImage}` : ""
2347
+ ].filter(Boolean);
2348
+ return values.length ? values.join("; ") : "none";
2349
+ }
2350
+ //#endregion
1802
2351
  //#region src/cron.ts
1803
2352
  async function loadFarmCronConfig(options = {}) {
1804
2353
  const root = path.resolve(options.root || process.cwd());
@@ -2603,6 +3152,6 @@ function formatError(error) {
2603
3152
  return error instanceof Error ? error.message : String(error);
2604
3153
  }
2605
3154
  //#endregion
2606
- export { addFarmIntegration, buildFarm, createFarmUpgradePlan, createFrameworkMigrationPlan, createGatewaySession, createPreviewGatewayPlan, createPreviewTunnelPlan, createServer, deployFarm, detectFarmPackageManager, formatFarmCronJobs, formatFarmDoctorReport, formatFarmUpgradePlan, forwardGatewayRequest, generateFarmArtifacts, inspectFrameworkMigrations, listFarmCronJobs, listFarmIntegrationProviders, loadFarmCronConfig, migrateFarm, migrateFarmAuth, parsePreviewPublicUrl, previewFarm, resolveCloudflareAgentDeployPlan, resolvePreviewTarget, runFarmCronJob, runFarmDoctor, runPreviewGateway, startDevServer, startFarmCronScheduler, upgradeFarm };
3155
+ export { FarmGeneratedArtifactsStaleError, addFarmIntegration, buildFarm, createFarmDeployPlan, createFarmUpgradePlan, createFrameworkMigrationPlan, createGatewaySession, createPreviewGatewayPlan, createPreviewTunnelPlan, createServer, deployFarm, detectFarmPackageManager, explainFarmRoute, formatFarmCronJobs, formatFarmDeployPlan, formatFarmDoctorReport, formatFarmRouteExplanation, formatFarmUpgradePlan, forwardGatewayRequest, generateFarmArtifacts, inspectFrameworkMigrations, listFarmCronJobs, listFarmIntegrationProviders, loadFarmCronConfig, migrateFarm, migrateFarmAuth, parsePreviewPublicUrl, previewFarm, resolveCloudflareAgentDeployPlan, resolvePreviewTarget, runFarmCronJob, runFarmDoctor, runPreviewGateway, startDevServer, startFarmCronScheduler, upgradeFarm };
2607
3156
 
2608
3157
  //# sourceMappingURL=index.mjs.map