@farm.js/cli 0.1.0-beta.4 → 0.1.0-beta.5

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/README.md CHANGED
@@ -8,4 +8,16 @@ Farm.js is currently in beta.
8
8
  npm install @farm.js/cli@beta
9
9
  ```
10
10
 
11
+ Upgrade every published `@farm.js/*` dependency in an app to one release channel:
12
+
13
+ ```bash
14
+ farm upgrade --latest
15
+ farm upgrade --beta
16
+ farm upgrade --latest --dry-run
17
+ ```
18
+
19
+ `--latest` selects the newest stable release. `--beta` selects the newest beta release. The CLI
20
+ detects npm, pnpm, Yarn, or Bun from the project and leaves `workspace:`, `file:`, and other local
21
+ package references unchanged.
22
+
11
23
  See the [Farm.js repository](https://github.com/farming-labs/farm.js) for documentation, examples, and support.
package/bin/farm.js CHANGED
@@ -80,6 +80,39 @@ program
80
80
  }
81
81
  });
82
82
 
83
+ program
84
+ .command("upgrade")
85
+ .description("Upgrade installed Farm.js packages to a stable or beta release")
86
+ .option("-r, --root <root>", "Project root", process.cwd())
87
+ .option("--latest", "Upgrade to the latest stable release")
88
+ .option("--beta", "Upgrade to the latest beta release")
89
+ .option("--dry-run", "Print the package-manager commands without installing")
90
+ .action(async (options) => {
91
+ try {
92
+ if (options.latest === options.beta) {
93
+ throw new Error("Choose exactly one release channel: --latest (stable) or --beta.");
94
+ }
95
+
96
+ const { formatFarmUpgradePlan, upgradeFarm } = require("../dist/index.js");
97
+ const result = await upgradeFarm({
98
+ root: options.root,
99
+ channel: options.beta ? "beta" : "latest",
100
+ dryRun: options.dryRun,
101
+ });
102
+ console.log(formatFarmUpgradePlan(result.plan));
103
+ console.log(
104
+ result.executed
105
+ ? `Upgraded ${result.plan.packages.length} Farm package${
106
+ result.plan.packages.length === 1 ? "" : "s"
107
+ } to ${result.plan.channel}.`
108
+ : "Dry run only. No packages were changed.",
109
+ );
110
+ } catch (error) {
111
+ console.error("Failed to upgrade Farm packages:", error);
112
+ process.exit(1);
113
+ }
114
+ });
115
+
83
116
  program
84
117
  .command("generate")
85
118
  .description("Generate route/API types and integration schema artifacts")
package/dist/index.js CHANGED
@@ -1428,7 +1428,7 @@ async function runFarmDoctor(options = {}) {
1428
1428
  if (!options.offline) try {
1429
1429
  return createLiveReport(await fetchLiveSnapshot(liveTarget, options), liveTarget, options.now);
1430
1430
  } catch (error) {
1431
- liveError = formatError$1(error);
1431
+ liveError = formatError$2(error);
1432
1432
  }
1433
1433
  const report = await createProjectReport(root, options);
1434
1434
  if (!options.offline && hasExplicitLiveTarget(options) && liveError) {
@@ -1588,7 +1588,7 @@ async function createProjectReport(root, options) {
1588
1588
  status: "fail",
1589
1589
  code: "CONFIG_INVALID",
1590
1590
  title: "Farm config could not be resolved",
1591
- message: formatError$1(error),
1591
+ message: formatError$2(error),
1592
1592
  action: "Fix the config or environment validation error, then run farm doctor again."
1593
1593
  });
1594
1594
  }
@@ -1651,7 +1651,7 @@ function collectPackageCheck(root, checks) {
1651
1651
  status: "fail",
1652
1652
  code: "PACKAGE_INVALID",
1653
1653
  title: "package.json is invalid",
1654
- message: formatError$1(error),
1654
+ message: formatError$2(error),
1655
1655
  action: "Fix the package manifest JSON."
1656
1656
  });
1657
1657
  }
@@ -1804,7 +1804,7 @@ function finalizeReport(report) {
1804
1804
  function asRecord(value) {
1805
1805
  return value && typeof value === "object" ? value : {};
1806
1806
  }
1807
- function formatError$1(error) {
1807
+ function formatError$2(error) {
1808
1808
  return error instanceof Error ? error.message : String(error);
1809
1809
  }
1810
1810
  function formatCount$1(value, noun) {
@@ -1861,7 +1861,7 @@ async function startFarmCronScheduler(options = {}) {
1861
1861
  _farm_js_core.logger.warn(`Cron ${job.name} skipped an overlapping run.`);
1862
1862
  },
1863
1863
  catch: (error) => {
1864
- _farm_js_core.logger.error(`Cron ${job.name} failed: ${formatError(error)}`);
1864
+ _farm_js_core.logger.error(`Cron ${job.name} failed: ${formatError$1(error)}`);
1865
1865
  }
1866
1866
  }, async () => {
1867
1867
  _farm_js_core.logger.info(`Cron ${job.name} -> ${job.path}`);
@@ -1950,7 +1950,7 @@ function formatResponseDetail(body) {
1950
1950
  const detail = typeof body === "string" ? body : JSON.stringify(body);
1951
1951
  return detail ? `: ${detail}` : "";
1952
1952
  }
1953
- function formatError(error) {
1953
+ function formatError$1(error) {
1954
1954
  return error instanceof Error ? error.message : String(error);
1955
1955
  }
1956
1956
  //#endregion
@@ -2420,8 +2420,179 @@ function toPosix(value) {
2420
2420
  return value.split(node_path.default.sep).join("/");
2421
2421
  }
2422
2422
  //#endregion
2423
+ //#region src/upgrade.ts
2424
+ const DEPENDENCY_SECTIONS = [
2425
+ "dependencies",
2426
+ "devDependencies",
2427
+ "optionalDependencies",
2428
+ "peerDependencies"
2429
+ ];
2430
+ const LOCAL_SPECIFIER_PREFIXES = [
2431
+ "workspace:",
2432
+ "file:",
2433
+ "link:",
2434
+ "portal:",
2435
+ "catalog:"
2436
+ ];
2437
+ async function createFarmUpgradePlan(options) {
2438
+ assertUpgradeChannel(options.channel);
2439
+ const root = node_path.default.resolve(options.root || process.cwd());
2440
+ const packageJsonPath = node_path.default.join(root, "package.json");
2441
+ let packageJson;
2442
+ try {
2443
+ packageJson = JSON.parse(await (0, node_fs_promises.readFile)(packageJsonPath, "utf8"));
2444
+ } catch (error) {
2445
+ if (!(0, node_fs.existsSync)(packageJsonPath)) throw new Error(`No package.json found at ${packageJsonPath}.`);
2446
+ throw new Error(`Could not read ${packageJsonPath}: ${formatError(error)}`);
2447
+ }
2448
+ const packageManager = options.packageManager || detectFarmPackageManager(root, packageJson.packageManager);
2449
+ const packages = [];
2450
+ const skipped = [];
2451
+ const seen = /* @__PURE__ */ new Set();
2452
+ for (const section of DEPENDENCY_SECTIONS) {
2453
+ const dependencies = packageJson[section];
2454
+ if (!dependencies || typeof dependencies !== "object") continue;
2455
+ for (const [name, rawSpecifier] of Object.entries(dependencies)) {
2456
+ if (!name.startsWith("@farm.js/") || seen.has(name)) continue;
2457
+ seen.add(name);
2458
+ const current = typeof rawSpecifier === "string" ? rawSpecifier : String(rawSpecifier);
2459
+ if (isLocalSpecifier(current)) {
2460
+ skipped.push({
2461
+ name,
2462
+ current,
2463
+ section,
2464
+ reason: "local workspace and file dependencies are not published-package upgrades"
2465
+ });
2466
+ continue;
2467
+ }
2468
+ packages.push({
2469
+ name,
2470
+ current,
2471
+ section,
2472
+ target: `${name}@${options.channel}`
2473
+ });
2474
+ }
2475
+ }
2476
+ if (packages.length === 0) {
2477
+ const suffix = skipped.length > 0 ? " The Farm packages in this project use local workspace or file references." : "";
2478
+ throw new Error(`No published @farm.js/* dependencies were found in ${packageJsonPath}.${suffix}`);
2479
+ }
2480
+ packages.sort((left, right) => left.name.localeCompare(right.name));
2481
+ skipped.sort((left, right) => left.name.localeCompare(right.name));
2482
+ return {
2483
+ root,
2484
+ packageJsonPath,
2485
+ packageManager,
2486
+ channel: options.channel,
2487
+ packages,
2488
+ skipped,
2489
+ commands: createUpgradeCommands(root, packageManager, packages)
2490
+ };
2491
+ }
2492
+ async function upgradeFarm(options) {
2493
+ const plan = await createFarmUpgradePlan(options);
2494
+ if (options.dryRun) return {
2495
+ plan,
2496
+ executed: false
2497
+ };
2498
+ const runCommand = options.runCommand || runFarmUpgradeCommand;
2499
+ for (const command of plan.commands) await runCommand(command);
2500
+ return {
2501
+ plan,
2502
+ executed: true
2503
+ };
2504
+ }
2505
+ function formatFarmUpgradePlan(plan) {
2506
+ const lines = [
2507
+ `Farm upgrade: ${plan.channel === "latest" ? "latest stable" : "latest beta"}`,
2508
+ `Project: ${plan.root}`,
2509
+ `Package manager: ${plan.packageManager}`,
2510
+ "Packages:"
2511
+ ];
2512
+ for (const entry of plan.packages) lines.push(` ${entry.name} (${entry.section}): ${entry.current} -> ${plan.channel}`);
2513
+ if (plan.skipped.length > 0) {
2514
+ lines.push("Skipped local packages:");
2515
+ for (const entry of plan.skipped) lines.push(` ${entry.name} (${entry.current})`);
2516
+ }
2517
+ lines.push("Commands:");
2518
+ for (const command of plan.commands) lines.push(` ${command.command} ${command.args.join(" ")}`);
2519
+ return lines.join("\n");
2520
+ }
2521
+ function detectFarmPackageManager(root, packageManagerField) {
2522
+ if (typeof packageManagerField === "string") {
2523
+ const name = packageManagerField.split("@", 1)[0];
2524
+ if (isFarmPackageManager(name)) return name;
2525
+ }
2526
+ for (const [packageManager, lockfiles] of [
2527
+ ["pnpm", ["pnpm-lock.yaml"]],
2528
+ ["yarn", ["yarn.lock"]],
2529
+ ["bun", ["bun.lock", "bun.lockb"]],
2530
+ ["npm", ["package-lock.json", "npm-shrinkwrap.json"]]
2531
+ ]) if (lockfiles.some((lockfile) => (0, node_fs.existsSync)(node_path.default.join(root, lockfile)))) return packageManager;
2532
+ return "npm";
2533
+ }
2534
+ function createUpgradeCommands(root, packageManager, packages) {
2535
+ const command = packageManager === "npm" ? "install" : "add";
2536
+ return DEPENDENCY_SECTIONS.flatMap((section) => {
2537
+ const targets = packages.filter((entry) => entry.section === section).map((entry) => entry.target);
2538
+ if (targets.length === 0) return [];
2539
+ return [{
2540
+ command: packageManager,
2541
+ args: [
2542
+ command,
2543
+ ...getDependencySectionFlags(packageManager, section),
2544
+ ...targets
2545
+ ],
2546
+ cwd: root
2547
+ }];
2548
+ });
2549
+ }
2550
+ function getDependencySectionFlags(packageManager, section) {
2551
+ if (section === "dependencies") return [];
2552
+ if (packageManager === "yarn" || packageManager === "bun") {
2553
+ if (section === "devDependencies") return ["--dev"];
2554
+ if (section === "optionalDependencies") return ["--optional"];
2555
+ return ["--peer"];
2556
+ }
2557
+ if (section === "devDependencies") return ["--save-dev"];
2558
+ if (section === "optionalDependencies") return ["--save-optional"];
2559
+ return ["--save-peer"];
2560
+ }
2561
+ function runFarmUpgradeCommand(command) {
2562
+ return new Promise((resolve, reject) => {
2563
+ const executable = process.platform === "win32" ? `${command.command}.cmd` : command.command;
2564
+ const child = (0, node_child_process.spawn)(executable, command.args, {
2565
+ cwd: command.cwd,
2566
+ env: process.env,
2567
+ stdio: "inherit"
2568
+ });
2569
+ child.on("error", reject);
2570
+ child.on("close", (code, signal) => {
2571
+ if (code === 0) {
2572
+ resolve();
2573
+ return;
2574
+ }
2575
+ const termination = signal ? `signal ${signal}` : `exit code ${code ?? "unknown"}`;
2576
+ reject(/* @__PURE__ */ new Error(`${command.command} ${command.args.join(" ")} failed with ${termination}.`));
2577
+ });
2578
+ });
2579
+ }
2580
+ function isLocalSpecifier(specifier) {
2581
+ return LOCAL_SPECIFIER_PREFIXES.some((prefix) => specifier.startsWith(prefix));
2582
+ }
2583
+ function isFarmPackageManager(value) {
2584
+ return value === "npm" || value === "pnpm" || value === "yarn" || value === "bun";
2585
+ }
2586
+ function assertUpgradeChannel(channel) {
2587
+ if (channel !== "latest" && channel !== "beta") throw new Error("Farm upgrade channel must be \"latest\" or \"beta\".");
2588
+ }
2589
+ function formatError(error) {
2590
+ return error instanceof Error ? error.message : String(error);
2591
+ }
2592
+ //#endregion
2423
2593
  exports.addFarmIntegration = require_add_integration.addFarmIntegration;
2424
2594
  exports.buildFarm = require_build.buildFarm;
2595
+ exports.createFarmUpgradePlan = createFarmUpgradePlan;
2425
2596
  exports.createFrameworkMigrationPlan = createFrameworkMigrationPlan;
2426
2597
  exports.createGatewaySession = createGatewaySession;
2427
2598
  exports.createPreviewGatewayPlan = createPreviewGatewayPlan;
@@ -2433,8 +2604,10 @@ Object.defineProperty(exports, "createServer", {
2433
2604
  }
2434
2605
  });
2435
2606
  exports.deployFarm = deployFarm;
2607
+ exports.detectFarmPackageManager = detectFarmPackageManager;
2436
2608
  exports.formatFarmCronJobs = formatFarmCronJobs;
2437
2609
  exports.formatFarmDoctorReport = formatFarmDoctorReport;
2610
+ exports.formatFarmUpgradePlan = formatFarmUpgradePlan;
2438
2611
  exports.forwardGatewayRequest = forwardGatewayRequest;
2439
2612
  exports.generateFarmArtifacts = generateFarmArtifacts;
2440
2613
  exports.inspectFrameworkMigrations = inspectFrameworkMigrations;
@@ -2456,5 +2629,6 @@ Object.defineProperty(exports, "startDevServer", {
2456
2629
  }
2457
2630
  });
2458
2631
  exports.startFarmCronScheduler = startFarmCronScheduler;
2632
+ exports.upgradeFarm = upgradeFarm;
2459
2633
 
2460
2634
  //# sourceMappingURL=index.js.map