@farm.js/cli 0.1.0-beta.1 → 0.1.0-beta.10

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.js CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_add_integration = require("./add-integration-pp16Zr0U.js");
2
+ const require_add_integration = require("./add-integration-Xc0p-k-m.js");
3
3
  const require_build = require("./build.js");
4
4
  let _farm_js_core_server = require("@farm.js/core/server");
5
5
  let node_fs = require("node:fs");
@@ -16,6 +16,8 @@ let node_timers_promises = require("node:timers/promises");
16
16
  let picocolors = require("picocolors");
17
17
  picocolors = require_add_integration.__toESM(picocolors);
18
18
  let croner = require("croner");
19
+ let node_module = require("node:module");
20
+ let node_url = require("node:url");
19
21
  //#region src/deploy.ts
20
22
  /**
21
23
  * Deploy Farm.js application
@@ -59,9 +61,7 @@ async function deployPlatform(platform, root, outputDir, deployConfig, prod) {
59
61
  case "cloudflare":
60
62
  await deployCloudflare(root, outputDir, deployConfig.cloudflare?.projectName || deployConfig.projectName);
61
63
  break;
62
- case "netlify":
63
- await deployNetlify(root, outputDir, deployConfig.netlify?.site);
64
- break;
64
+ case "netlify": await deployNetlify(root, outputDir, deployConfig.netlify?.site);
65
65
  }
66
66
  }
67
67
  /**
@@ -282,7 +282,8 @@ async function deployNetlify(root, outputDir, site) {
282
282
  }
283
283
  try {
284
284
  process.chdir(outputDir);
285
- (0, child_process.execSync)(`netlify deploy --prod --dir=.${site ? ` --site=${site}` : ""}`, { stdio: "inherit" });
285
+ const siteFlag = site ? ` --site=${site}` : "";
286
+ (0, child_process.execSync)(`netlify deploy --prod --dir=.${siteFlag}`, { stdio: "inherit" });
286
287
  _farm_js_core.logger.success("✅ Deployed to Netlify successfully!");
287
288
  } catch (error) {
288
289
  _farm_js_core.logger.error(`❌ Failed to deploy to Netlify: ${error.message}`);
@@ -765,7 +766,7 @@ function commandExists(command) {
765
766
  return !result.error && result.status === 0;
766
767
  }
767
768
  function expandTunnelTemplate(template, target, requestedName, requestedHostname) {
768
- return template.replaceAll("{url}", shellQuote(target.localUrl)).replaceAll("{port}", shellQuote(String(target.port))).replaceAll("{host}", shellQuote(target.host)).replaceAll("{name}", shellQuote(requestedName)).replaceAll("{hostname}", shellQuote(requestedHostname));
769
+ return template.split("{url}").join(shellQuote(target.localUrl)).split("{port}").join(shellQuote(String(target.port))).split("{host}").join(shellQuote(target.host)).split("{name}").join(shellQuote(requestedName)).split("{hostname}").join(shellQuote(requestedHostname));
769
770
  }
770
771
  function shellQuote(value) {
771
772
  return `"${value.replace(/(["\\$`])/g, "\\$1")}"`;
@@ -808,31 +809,19 @@ async function generateFarmArtifacts(options = {}) {
808
809
  if (!userConfig && hasSchemaOptions(options)) throw new Error("No Farm config found. Please create farm.config.ts or config.ts.");
809
810
  const resolvedConfig = await (0, _farm_js_core.resolveConfig)({
810
811
  root,
811
- ...userConfig || {}
812
+ ...userConfig
812
813
  }, "development");
813
814
  const extraRoutes = [...resolvedConfig.openapi?.enabled && resolvedConfig.openapi.route ? [resolvedConfig.openapi.route] : [], ...(0, _farm_js_core.getFarmDocsRouteTypeEntries)(resolvedConfig.docs)];
814
- await (0, _farm_js_core.generateRouteTypes)({
815
+ const typeArtifacts = await (0, _farm_js_core.generateFarmTypeArtifacts)({
815
816
  root: resolvedConfig.root,
816
817
  srcDir: resolvedConfig.srcDir,
818
+ configPath: options.configPath,
819
+ layers: resolvedConfig.layers,
817
820
  extraRoutes,
818
- suppressLintOnLink: resolvedConfig.suppressLintOnLink
819
- });
820
- await (0, _farm_js_core.generateEnvTypes)({
821
- root: resolvedConfig.root,
822
- srcDir: resolvedConfig.srcDir,
823
- configPath: options.configPath
821
+ suppressLintOnLink: resolvedConfig.suppressLintOnLink,
822
+ i18nConfig: resolvedConfig.i18n
824
823
  });
825
- const apiGenerator = new _farm_js_core.APITypeGenerator(node_path.default.join(resolvedConfig.root, resolvedConfig.srcDir, "app"));
826
- const apiRoutes = apiGenerator.scanAPIRoutes();
827
- const apiTypesPath = node_path.default.join(resolvedConfig.root, resolvedConfig.srcDir, "lib", "api.generated.ts");
828
- await (0, node_fs_promises.mkdir)(node_path.default.dirname(apiTypesPath), { recursive: true });
829
- await (0, node_fs_promises.writeFile)(apiTypesPath, apiGenerator.generateAPIRouter(apiRoutes), "utf8");
830
- if (resolvedConfig.i18n.enabled) await (0, _farm_js_core.generateFarmI18nTypes)({
831
- root: resolvedConfig.root,
832
- srcDir: resolvedConfig.srcDir,
833
- config: resolvedConfig.i18n
834
- });
835
- _farm_js_core.logger.success(`Generated route, API, env${resolvedConfig.i18n.enabled ? ", and i18n" : ""} types (${apiRoutes.length} API route${apiRoutes.length === 1 ? "" : "s"}).`);
824
+ _farm_js_core.logger.success(`Generated route, API, env${resolvedConfig.i18n.enabled ? ", and i18n" : ""} types (${typeArtifacts.apiRoutes.length} API route${typeArtifacts.apiRoutes.length === 1 ? "" : "s"}).`);
836
825
  const schemas = (0, _farm_js_core.getIntegrationSchemas)(resolvedConfig.integrations);
837
826
  const schemaEntries = Object.entries(schemas);
838
827
  if (!schemaEntries.length) {
@@ -1071,7 +1060,8 @@ async function writePrismaSchema(schemaPath, models) {
1071
1060
  const source = await (0, node_fs_promises.readFile)(schemaPath, "utf8");
1072
1061
  const generated = createPrismaGeneratedBlock(generatePrismaSchema(models));
1073
1062
  const pattern = new RegExp(`${escapeRegExp(PRISMA_GENERATED_START)}[\\s\\S]*?${escapeRegExp(PRISMA_GENERATED_END)}`, "m");
1074
- await (0, node_fs_promises.writeFile)(schemaPath, pattern.test(source) ? source.replace(pattern, generated) : `${source.trimEnd()}\n\n${generated}\n`, "utf8");
1063
+ const nextSource = pattern.test(source) ? source.replace(pattern, generated) : `${source.trimEnd()}\n\n${generated}\n`;
1064
+ await (0, node_fs_promises.writeFile)(schemaPath, nextSource, "utf8");
1075
1065
  }
1076
1066
  function generatePrismaSchema(models) {
1077
1067
  return models.map((model) => renderPrismaModel(model)).join("\n\n");
@@ -1427,7 +1417,7 @@ async function runFarmDoctor(options = {}) {
1427
1417
  if (!options.offline) try {
1428
1418
  return createLiveReport(await fetchLiveSnapshot(liveTarget, options), liveTarget, options.now);
1429
1419
  } catch (error) {
1430
- liveError = formatError$1(error);
1420
+ liveError = formatError$2(error);
1431
1421
  }
1432
1422
  const report = await createProjectReport(root, options);
1433
1423
  if (!options.offline && hasExplicitLiveTarget(options) && liveError) {
@@ -1587,7 +1577,7 @@ async function createProjectReport(root, options) {
1587
1577
  status: "fail",
1588
1578
  code: "CONFIG_INVALID",
1589
1579
  title: "Farm config could not be resolved",
1590
- message: formatError$1(error),
1580
+ message: formatError$2(error),
1591
1581
  action: "Fix the config or environment validation error, then run farm doctor again."
1592
1582
  });
1593
1583
  }
@@ -1650,7 +1640,7 @@ function collectPackageCheck(root, checks) {
1650
1640
  status: "fail",
1651
1641
  code: "PACKAGE_INVALID",
1652
1642
  title: "package.json is invalid",
1653
- message: formatError$1(error),
1643
+ message: formatError$2(error),
1654
1644
  action: "Fix the package manifest JSON."
1655
1645
  });
1656
1646
  }
@@ -1803,7 +1793,7 @@ function finalizeReport(report) {
1803
1793
  function asRecord(value) {
1804
1794
  return value && typeof value === "object" ? value : {};
1805
1795
  }
1806
- function formatError$1(error) {
1796
+ function formatError$2(error) {
1807
1797
  return error instanceof Error ? error.message : String(error);
1808
1798
  }
1809
1799
  function formatCount$1(value, noun) {
@@ -1860,7 +1850,7 @@ async function startFarmCronScheduler(options = {}) {
1860
1850
  _farm_js_core.logger.warn(`Cron ${job.name} skipped an overlapping run.`);
1861
1851
  },
1862
1852
  catch: (error) => {
1863
- _farm_js_core.logger.error(`Cron ${job.name} failed: ${formatError(error)}`);
1853
+ _farm_js_core.logger.error(`Cron ${job.name} failed: ${formatError$1(error)}`);
1864
1854
  }
1865
1855
  }, async () => {
1866
1856
  _farm_js_core.logger.info(`Cron ${job.name} -> ${job.path}`);
@@ -1949,7 +1939,7 @@ function formatResponseDetail(body) {
1949
1939
  const detail = typeof body === "string" ? body : JSON.stringify(body);
1950
1940
  return detail ? `: ${detail}` : "";
1951
1941
  }
1952
- function formatError(error) {
1942
+ function formatError$1(error) {
1953
1943
  return error instanceof Error ? error.message : String(error);
1954
1944
  }
1955
1945
  //#endregion
@@ -2066,7 +2056,7 @@ async function createFrameworkMigrationPlan(root, source, options = {}) {
2066
2056
  };
2067
2057
  if (source === "next") await planNextMigration(root, packageJson, plan, options);
2068
2058
  else await planTanStackMigration(root, packageJson, plan, options);
2069
- addSharedFarmFiles(root, packageJson, plan, source, options);
2059
+ addSharedFarmFiles(root, packageJson, plan, options);
2070
2060
  return plan;
2071
2061
  }
2072
2062
  async function planNextMigration(root, packageJson, plan, options) {
@@ -2146,32 +2136,22 @@ async function planTanStackMigration(root, packageJson, plan, options) {
2146
2136
  plan.manual.push("Review loaders, beforeLoad hooks, search params, and Route.use* calls; Farm page modules should move that logic into props, API routes, or server helpers.");
2147
2137
  if (packageJson) addPackageOperation(root, plan, createMigratedPackageJson(packageJson, "tanstack"));
2148
2138
  }
2149
- function addSharedFarmFiles(root, packageJson, plan, source, options) {
2139
+ function addSharedFarmFiles(root, packageJson, plan, options) {
2150
2140
  if (![
2151
2141
  "farm.config.ts",
2152
2142
  "farm.config.mts",
2153
2143
  "farm.config.js",
2154
2144
  "farm.config.mjs"
2155
- ].map((file) => node_path.default.join(root, file)).find((file) => (0, node_fs.existsSync)(file))) {
2156
- const output = source === "next" ? `import { defineConfig } from "@farm.js/core";
2157
-
2158
- export default defineConfig({
2159
- srcDir: "src",
2160
- });
2161
- ` : `import { defineConfig } from "@farm.js/core";
2145
+ ].map((file) => node_path.default.join(root, file)).find((file) => (0, node_fs.existsSync)(file))) plan.operations.push({
2146
+ kind: "write-file",
2147
+ path: node_path.default.join(root, "farm.config.ts"),
2148
+ description: "Create farm.config.ts",
2149
+ content: `import { defineConfig } from "@farm.js/core";
2162
2150
 
2163
- export default defineConfig({
2164
- srcDir: "src",
2165
- });
2166
- `;
2167
- plan.operations.push({
2168
- kind: "write-file",
2169
- path: node_path.default.join(root, "farm.config.ts"),
2170
- description: "Create farm.config.ts",
2171
- content: output,
2172
- skipped: false
2173
- });
2174
- }
2151
+ export default defineConfig({});
2152
+ `,
2153
+ skipped: false
2154
+ });
2175
2155
  const layoutPath = node_path.default.join(root, "src", "app", "layout.tsx");
2176
2156
  if (!(0, node_fs.existsSync)(layoutPath)) plan.operations.push({
2177
2157
  kind: "write-file",
@@ -2429,8 +2409,204 @@ function toPosix(value) {
2429
2409
  return value.split(node_path.default.sep).join("/");
2430
2410
  }
2431
2411
  //#endregion
2412
+ //#region src/auth.ts
2413
+ async function migrateFarmAuth(options = {}) {
2414
+ const root = node_path.default.resolve(options.root || process.cwd());
2415
+ const userConfig = await (0, _farm_js_core.loadConfig)(root, options.configPath, "production");
2416
+ if (!userConfig) throw new Error(`No farm.config file was found in ${root}.`);
2417
+ if (!(await (0, _farm_js_core.resolveConfig)({
2418
+ ...userConfig,
2419
+ root
2420
+ }, "production")).auth.enabled) throw new Error("Farm Auth is disabled. Add `auth: true` to farm.config.ts first.");
2421
+ const resolveFromApp = (0, node_module.createRequire)(node_path.default.join(root, "package.json"));
2422
+ let modulePath;
2423
+ try {
2424
+ modulePath = resolveFromApp.resolve("@farm.js/auth/internal");
2425
+ } catch {
2426
+ throw new Error("Install @farm.js/auth before running `farm auth migrate`.");
2427
+ }
2428
+ const runtime = await import(
2429
+ /* @vite-ignore */
2430
+ (0, node_url.pathToFileURL)(modulePath).href
2431
+ );
2432
+ _farm_js_core.logger.info("Applying the Farm Auth database schema...");
2433
+ await runtime.migrateFarmAuth();
2434
+ _farm_js_core.logger.success("Farm Auth database is ready.");
2435
+ }
2436
+ //#endregion
2437
+ //#region src/upgrade.ts
2438
+ const DEPENDENCY_SECTIONS = [
2439
+ "dependencies",
2440
+ "devDependencies",
2441
+ "optionalDependencies",
2442
+ "peerDependencies"
2443
+ ];
2444
+ const LOCAL_SPECIFIER_PREFIXES = [
2445
+ "workspace:",
2446
+ "file:",
2447
+ "link:",
2448
+ "portal:",
2449
+ "catalog:"
2450
+ ];
2451
+ async function createFarmUpgradePlan(options) {
2452
+ assertUpgradeChannel(options.channel);
2453
+ const root = node_path.default.resolve(options.root || process.cwd());
2454
+ const packageJsonPath = node_path.default.join(root, "package.json");
2455
+ let packageJson;
2456
+ try {
2457
+ packageJson = JSON.parse(await (0, node_fs_promises.readFile)(packageJsonPath, "utf8"));
2458
+ } catch (error) {
2459
+ if (!(0, node_fs.existsSync)(packageJsonPath)) throw new Error(`No package.json found at ${packageJsonPath}.`);
2460
+ throw new Error(`Could not read ${packageJsonPath}: ${formatError(error)}`);
2461
+ }
2462
+ const packageManager = options.packageManager || detectFarmPackageManager(root, packageJson.packageManager);
2463
+ const packages = [];
2464
+ const skipped = [];
2465
+ const seen = /* @__PURE__ */ new Set();
2466
+ for (const section of DEPENDENCY_SECTIONS) {
2467
+ const dependencies = packageJson[section];
2468
+ if (!dependencies || typeof dependencies !== "object") continue;
2469
+ for (const [name, rawSpecifier] of Object.entries(dependencies)) {
2470
+ if (!name.startsWith("@farm.js/") || seen.has(name)) continue;
2471
+ seen.add(name);
2472
+ const current = typeof rawSpecifier === "string" ? rawSpecifier : String(rawSpecifier);
2473
+ if (isLocalSpecifier(current)) {
2474
+ skipped.push({
2475
+ name,
2476
+ current,
2477
+ section,
2478
+ reason: "local workspace and file dependencies are not published-package upgrades"
2479
+ });
2480
+ continue;
2481
+ }
2482
+ packages.push({
2483
+ name,
2484
+ current,
2485
+ section,
2486
+ target: `${name}@${options.channel}`
2487
+ });
2488
+ }
2489
+ }
2490
+ if (packages.length === 0) {
2491
+ const suffix = skipped.length > 0 ? " The Farm packages in this project use local workspace or file references." : "";
2492
+ throw new Error(`No published @farm.js/* dependencies were found in ${packageJsonPath}.${suffix}`);
2493
+ }
2494
+ packages.sort((left, right) => left.name.localeCompare(right.name));
2495
+ skipped.sort((left, right) => left.name.localeCompare(right.name));
2496
+ return {
2497
+ root,
2498
+ packageJsonPath,
2499
+ packageManager,
2500
+ channel: options.channel,
2501
+ packages,
2502
+ skipped,
2503
+ commands: createUpgradeCommands(root, packageManager, packages)
2504
+ };
2505
+ }
2506
+ async function upgradeFarm(options) {
2507
+ const plan = await createFarmUpgradePlan(options);
2508
+ if (options.dryRun) return {
2509
+ plan,
2510
+ executed: false
2511
+ };
2512
+ const runCommand = options.runCommand || runFarmUpgradeCommand;
2513
+ for (const command of plan.commands) await runCommand(command);
2514
+ return {
2515
+ plan,
2516
+ executed: true
2517
+ };
2518
+ }
2519
+ function formatFarmUpgradePlan(plan) {
2520
+ const lines = [
2521
+ `Farm upgrade: ${plan.channel === "latest" ? "latest stable" : "latest beta"}`,
2522
+ `Project: ${plan.root}`,
2523
+ `Package manager: ${plan.packageManager}`,
2524
+ "Packages:"
2525
+ ];
2526
+ for (const entry of plan.packages) lines.push(` ${entry.name} (${entry.section}): ${entry.current} -> ${plan.channel}`);
2527
+ if (plan.skipped.length > 0) {
2528
+ lines.push("Skipped local packages:");
2529
+ for (const entry of plan.skipped) lines.push(` ${entry.name} (${entry.current})`);
2530
+ }
2531
+ lines.push("Commands:");
2532
+ for (const command of plan.commands) lines.push(` ${command.command} ${command.args.join(" ")}`);
2533
+ return lines.join("\n");
2534
+ }
2535
+ function detectFarmPackageManager(root, packageManagerField) {
2536
+ if (typeof packageManagerField === "string") {
2537
+ const name = packageManagerField.split("@", 1)[0];
2538
+ if (isFarmPackageManager(name)) return name;
2539
+ }
2540
+ for (const [packageManager, lockfiles] of [
2541
+ ["pnpm", ["pnpm-lock.yaml"]],
2542
+ ["yarn", ["yarn.lock"]],
2543
+ ["bun", ["bun.lock", "bun.lockb"]],
2544
+ ["npm", ["package-lock.json", "npm-shrinkwrap.json"]]
2545
+ ]) if (lockfiles.some((lockfile) => (0, node_fs.existsSync)(node_path.default.join(root, lockfile)))) return packageManager;
2546
+ return "npm";
2547
+ }
2548
+ function createUpgradeCommands(root, packageManager, packages) {
2549
+ const command = packageManager === "npm" ? "install" : "add";
2550
+ return DEPENDENCY_SECTIONS.flatMap((section) => {
2551
+ const targets = packages.filter((entry) => entry.section === section).map((entry) => entry.target);
2552
+ if (targets.length === 0) return [];
2553
+ return [{
2554
+ command: packageManager,
2555
+ args: [
2556
+ command,
2557
+ ...getDependencySectionFlags(packageManager, section),
2558
+ ...targets
2559
+ ],
2560
+ cwd: root
2561
+ }];
2562
+ });
2563
+ }
2564
+ function getDependencySectionFlags(packageManager, section) {
2565
+ if (section === "dependencies") return [];
2566
+ if (packageManager === "yarn" || packageManager === "bun") {
2567
+ if (section === "devDependencies") return ["--dev"];
2568
+ if (section === "optionalDependencies") return ["--optional"];
2569
+ return ["--peer"];
2570
+ }
2571
+ if (section === "devDependencies") return ["--save-dev"];
2572
+ if (section === "optionalDependencies") return ["--save-optional"];
2573
+ return ["--save-peer"];
2574
+ }
2575
+ function runFarmUpgradeCommand(command) {
2576
+ return new Promise((resolve, reject) => {
2577
+ const executable = process.platform === "win32" ? `${command.command}.cmd` : command.command;
2578
+ const child = (0, node_child_process.spawn)(executable, command.args, {
2579
+ cwd: command.cwd,
2580
+ env: process.env,
2581
+ stdio: "inherit"
2582
+ });
2583
+ child.on("error", reject);
2584
+ child.on("close", (code, signal) => {
2585
+ if (code === 0) {
2586
+ resolve();
2587
+ return;
2588
+ }
2589
+ const termination = signal ? `signal ${signal}` : `exit code ${code ?? "unknown"}`;
2590
+ reject(/* @__PURE__ */ new Error(`${command.command} ${command.args.join(" ")} failed with ${termination}.`));
2591
+ });
2592
+ });
2593
+ }
2594
+ function isLocalSpecifier(specifier) {
2595
+ return LOCAL_SPECIFIER_PREFIXES.some((prefix) => specifier.startsWith(prefix));
2596
+ }
2597
+ function isFarmPackageManager(value) {
2598
+ return value === "npm" || value === "pnpm" || value === "yarn" || value === "bun";
2599
+ }
2600
+ function assertUpgradeChannel(channel) {
2601
+ if (channel !== "latest" && channel !== "beta") throw new Error("Farm upgrade channel must be \"latest\" or \"beta\".");
2602
+ }
2603
+ function formatError(error) {
2604
+ return error instanceof Error ? error.message : String(error);
2605
+ }
2606
+ //#endregion
2432
2607
  exports.addFarmIntegration = require_add_integration.addFarmIntegration;
2433
2608
  exports.buildFarm = require_build.buildFarm;
2609
+ exports.createFarmUpgradePlan = createFarmUpgradePlan;
2434
2610
  exports.createFrameworkMigrationPlan = createFrameworkMigrationPlan;
2435
2611
  exports.createGatewaySession = createGatewaySession;
2436
2612
  exports.createPreviewGatewayPlan = createPreviewGatewayPlan;
@@ -2442,8 +2618,10 @@ Object.defineProperty(exports, "createServer", {
2442
2618
  }
2443
2619
  });
2444
2620
  exports.deployFarm = deployFarm;
2621
+ exports.detectFarmPackageManager = detectFarmPackageManager;
2445
2622
  exports.formatFarmCronJobs = formatFarmCronJobs;
2446
2623
  exports.formatFarmDoctorReport = formatFarmDoctorReport;
2624
+ exports.formatFarmUpgradePlan = formatFarmUpgradePlan;
2447
2625
  exports.forwardGatewayRequest = forwardGatewayRequest;
2448
2626
  exports.generateFarmArtifacts = generateFarmArtifacts;
2449
2627
  exports.inspectFrameworkMigrations = inspectFrameworkMigrations;
@@ -2451,6 +2629,7 @@ exports.listFarmCronJobs = listFarmCronJobs;
2451
2629
  exports.listFarmIntegrationProviders = require_add_integration.listFarmIntegrationProviders;
2452
2630
  exports.loadFarmCronConfig = loadFarmCronConfig;
2453
2631
  exports.migrateFarm = migrateFarm;
2632
+ exports.migrateFarmAuth = migrateFarmAuth;
2454
2633
  exports.parsePreviewPublicUrl = parsePreviewPublicUrl;
2455
2634
  exports.previewFarm = previewFarm;
2456
2635
  exports.resolveCloudflareAgentDeployPlan = resolveCloudflareAgentDeployPlan;
@@ -2465,5 +2644,6 @@ Object.defineProperty(exports, "startDevServer", {
2465
2644
  }
2466
2645
  });
2467
2646
  exports.startFarmCronScheduler = startFarmCronScheduler;
2647
+ exports.upgradeFarm = upgradeFarm;
2468
2648
 
2469
2649
  //# sourceMappingURL=index.js.map