@stacksjs/buddy 0.70.59 → 0.70.60

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 (79) hide show
  1. package/dist/cli.js +162 -4
  2. package/dist/commands/about.js +35 -0
  3. package/dist/commands/add.d.ts +2 -0
  4. package/dist/commands/add.js +33 -0
  5. package/dist/commands/auth.js +68 -0
  6. package/dist/commands/build.js +153 -0
  7. package/dist/commands/cd.js +39 -0
  8. package/dist/commands/changelog.js +32 -0
  9. package/dist/commands/clean.js +37 -0
  10. package/dist/commands/cloud.js +503 -0
  11. package/dist/commands/commit.js +16 -0
  12. package/dist/commands/completion.js +143 -0
  13. package/dist/commands/config-migrate.js +94 -0
  14. package/dist/commands/configure.js +48 -0
  15. package/dist/commands/create.js +137 -0
  16. package/dist/commands/deploy.js +1404 -0
  17. package/dist/commands/dev.js +911 -0
  18. package/dist/commands/dns.js +62 -0
  19. package/dist/commands/doctor.js +280 -0
  20. package/dist/commands/domains.js +159 -0
  21. package/dist/commands/email.js +526 -0
  22. package/dist/commands/env.js +246 -0
  23. package/dist/commands/features.js +422 -0
  24. package/dist/commands/fresh.js +39 -0
  25. package/dist/commands/generate.js +104 -0
  26. package/dist/commands/http.js +30 -0
  27. package/dist/commands/index.js +53 -0
  28. package/dist/commands/install.js +23 -0
  29. package/dist/commands/key.js +23 -0
  30. package/dist/commands/lint.js +50 -0
  31. package/dist/commands/list.js +108 -0
  32. package/dist/commands/mail.js +693 -0
  33. package/dist/commands/maintenance.d.ts +2 -0
  34. package/dist/commands/maintenance.js +141 -0
  35. package/dist/commands/make.js +375 -0
  36. package/dist/commands/migrate-project.js +49 -0
  37. package/dist/commands/migrate.js +373 -0
  38. package/dist/commands/outdated.js +19 -0
  39. package/dist/commands/package.d.ts +2 -0
  40. package/dist/commands/package.js +17 -0
  41. package/dist/commands/phone.js +188 -0
  42. package/dist/commands/ports.js +118 -0
  43. package/dist/commands/prepublish.js +17 -0
  44. package/dist/commands/projects.js +29 -0
  45. package/dist/commands/publish.js +169 -0
  46. package/dist/commands/queue.js +249 -0
  47. package/dist/commands/release.js +30 -0
  48. package/dist/commands/route.js +21 -0
  49. package/dist/commands/saas.js +25 -0
  50. package/dist/commands/schedule.js +61 -0
  51. package/dist/commands/search.js +84 -0
  52. package/dist/commands/seed.js +71 -0
  53. package/dist/commands/serve.js +176 -0
  54. package/dist/commands/setup.js +203 -0
  55. package/dist/commands/share.d.ts +2 -0
  56. package/dist/commands/share.js +209 -0
  57. package/dist/commands/sms.js +328 -0
  58. package/dist/commands/stacks.d.ts +2 -0
  59. package/dist/commands/stacks.js +69 -0
  60. package/dist/commands/telemetry.js +74 -0
  61. package/dist/commands/test.js +130 -0
  62. package/dist/commands/tinker.js +37 -0
  63. package/dist/commands/types.js +18 -0
  64. package/dist/commands/upgrade.js +97 -0
  65. package/dist/commands/version.js +16 -0
  66. package/dist/config.d.ts +43 -0
  67. package/dist/config.js +223 -0
  68. package/dist/custom-cli.d.ts +1 -0
  69. package/dist/custom-cli.js +23 -0
  70. package/dist/index.js +1 -3424
  71. package/dist/lazy-commands.d.ts +61 -0
  72. package/dist/lazy-commands.js +182 -0
  73. package/dist/migrators/index.js +62 -0
  74. package/dist/migrators/laravel/index.js +148 -0
  75. package/dist/migrators/laravel/migrations.js +231 -0
  76. package/dist/migrators/laravel/models.js +132 -0
  77. package/dist/migrators/rails/index.js +11 -0
  78. package/dist/migrators/types.js +0 -0
  79. package/package.json +1 -1
@@ -0,0 +1,94 @@
1
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import process from "node:process";
3
+ import { italic, log } from "@stacksjs/cli";
4
+ import { projectPath } from "@stacksjs/path";
5
+ const CODEMODS = [
6
+ {
7
+ id: "0.65-cache-driver-rename",
8
+ description: "Rename `cache.driver` to `cache.default` (introduced in 0.65).",
9
+ files: ["cache.ts"],
10
+ shouldApply: (c) => /\bdriver\s*:/.test(c) && !c.includes("default:"),
11
+ apply: (c) => c.replace(/(\bcache\b[\s\S]*?)\bdriver(\s*:)/m, "$1default$2")
12
+ },
13
+ {
14
+ id: "0.68-search-engine-name",
15
+ description: "Rename `searchEngine.driver` to `searchEngine.default` (matches other configs).",
16
+ files: ["search-engine.ts"],
17
+ shouldApply: (c) => /\bdriver\s*:/.test(c),
18
+ apply: (c) => c.replace(/\bdriver(\s*:)/g, "default$1")
19
+ },
20
+ {
21
+ id: "0.70-ports-string-to-number",
22
+ description: 'Convert string port values like `"3000"` to numbers (TypeScript types now require number).',
23
+ files: ["ports.ts"],
24
+ shouldApply: (c) => /:\s*['"]\d+['"]/.test(c),
25
+ apply: (c) => c.replace(/:\s*['"](\d+)['"]/g, ": $1")
26
+ }
27
+ ];
28
+ export async function runConfigMigrations(opts) {
29
+ const changed = [], skipped = [], codemods = opts.only ? CODEMODS.filter((m) => m.id === opts.only) : CODEMODS;
30
+ if (codemods.length === 0) {
31
+ log.warn(`No matching codemods. Available: ${CODEMODS.map((m) => m.id).join(", ")}`);
32
+ return { changed, skipped };
33
+ }
34
+ for (const cm of codemods) {
35
+ log.info(`Codemod ${italic(cm.id)} \u2014 ${cm.description}`);
36
+ for (const rel of cm.files) {
37
+ const full = projectPath(`config/${rel}`);
38
+ if (!existsSync(full)) {
39
+ skipped.push(`${full} (missing)`);
40
+ continue;
41
+ }
42
+ const before = readFileSync(full, "utf-8");
43
+ if (!cm.shouldApply(before)) {
44
+ skipped.push(`${full} (no changes)`);
45
+ continue;
46
+ }
47
+ const after = cm.apply(before);
48
+ if (after === before) {
49
+ skipped.push(`${full} (no changes)`);
50
+ continue;
51
+ }
52
+ if (opts.dryRun) {
53
+ log.info(`[dry-run] would update ${full}`);
54
+ printDiff(before, after);
55
+ } else {
56
+ writeFileSync(full, after);
57
+ log.success(`updated ${full}`);
58
+ }
59
+ changed.push(full);
60
+ }
61
+ }
62
+ return { changed, skipped };
63
+ }
64
+ function printDiff(before, after) {
65
+ const beforeLines = before.split(`
66
+ `), afterLines = after.split(`
67
+ `), max = Math.max(beforeLines.length, afterLines.length);
68
+ for (let i = 0;i < max; i++) {
69
+ const b = beforeLines[i], a = afterLines[i];
70
+ if (b === a)
71
+ continue;
72
+ if (b !== void 0)
73
+ process.stdout.write(` - ${b}
74
+ `);
75
+ if (a !== void 0)
76
+ process.stdout.write(` + ${a}
77
+ `);
78
+ }
79
+ process.stdout.write(`
80
+ `);
81
+ }
82
+ export function configMigrate(buddy) {
83
+ buddy.command("config:migrate", "Apply config-shape codemods for the latest Stacks version").option("--dry-run", "Preview changes without writing", { default: !1 }).option("--only [id]", "Run a single codemod by id", { default: "" }).action(async (options) => {
84
+ log.info("Running `buddy config:migrate` ...");
85
+ const { changed, skipped } = await runConfigMigrations({
86
+ dryRun: Boolean(options.dryRun),
87
+ only: options.only?.length ? options.only : void 0
88
+ });
89
+ log.info(`Changed: ${changed.length}, Skipped: ${skipped.length}`);
90
+ if (skipped.length > 0)
91
+ for (const s of skipped)
92
+ log.debug(` skipped: ${s}`);
93
+ });
94
+ }
@@ -0,0 +1,48 @@
1
+ import process from "node:process";
2
+ import { log, onUnknownSubcommand, outro, runCommand } from "@stacksjs/cli";
3
+ import { path as p } from "@stacksjs/path";
4
+ import { ExitCode } from "@stacksjs/types";
5
+ export function configure(buddy) {
6
+ const descriptions = {
7
+ configure: "Configure options",
8
+ aws: "Configure the AWS connection",
9
+ project: "Target a specific project",
10
+ profile: "The AWS profile to use",
11
+ verbose: "Enable verbose output"
12
+ };
13
+ buddy.command("configure", descriptions.configure).option("--aws", descriptions.aws, { default: !1 }).option("-p, --project [project]", descriptions.project, { default: !1 }).option("--verbose", descriptions.verbose, { default: !1 }).action(async (options) => {
14
+ log.debug("Running `buddy configure` ...", options);
15
+ if (options?.aws) {
16
+ await configureAws(options);
17
+ process.exit(ExitCode.Success);
18
+ }
19
+ log.info("Not implemented yet. Please use the --aws flag to configure AWS.");
20
+ process.exit(ExitCode.Success);
21
+ });
22
+ buddy.command("configure:aws", descriptions.aws).option("-p, --project [project]", descriptions.project, { default: !1 }).option("--profile", descriptions.profile, {
23
+ default: process.env.AWS_PROFILE
24
+ }).option("--verbose", descriptions.verbose, { default: !1 }).option("--access-key-id", "The AWS access key").option("--secret-access-key", "The AWS secret access key").option("--region", "The AWS region").option("--output", "The AWS output format").option("--quiet", "Suppress output").action(async (options) => {
25
+ log.debug("Running `buddy configure:aws` ...", options);
26
+ await configureAws(options);
27
+ process.exit(ExitCode.Success);
28
+ });
29
+ onUnknownSubcommand(buddy, "configure");
30
+ }
31
+ async function configureAws(options) {
32
+ const startTime = performance.now(), awsAccessKeyId = options?.accessKeyId ?? process.env.AWS_ACCESS_KEY_ID, awsSecretAccessKey = options?.secretAccessKey ?? process.env.AWS_SECRET_ACCESS_KEY, defaultRegion = "us-east-1", defaultOutputFormat = options?.output ?? "json", profile = process.env.AWS_PROFILE ?? options?.profile, command = profile ? `aws configure --profile ${profile}` : "aws configure", input = `${awsAccessKeyId}
33
+ ${awsSecretAccessKey}
34
+ ${defaultRegion}
35
+ ${defaultOutputFormat}
36
+ `, result = await runCommand(command, {
37
+ cwd: p.projectPath(),
38
+ stdin: "pipe",
39
+ input
40
+ });
41
+ if (result.isErr) {
42
+ await outro("While running the cloud command, there was an issue", { startTime, useSeconds: !0 }, result.error);
43
+ process.exit(ExitCode.FatalError);
44
+ }
45
+ if (options?.quiet)
46
+ return;
47
+ await outro("Exited", { startTime, useSeconds: !0 });
48
+ }
@@ -0,0 +1,137 @@
1
+ import { chmodSync } from "node:fs";
2
+ import process from "node:process";
3
+ import { runAction } from "@stacksjs/actions";
4
+ import { bold, cyan, dim, intro, log, onUnknownSubcommand, runCommand } from "@stacksjs/cli";
5
+ import { Action } from "@stacksjs/enums";
6
+ import { resolve } from "@stacksjs/path";
7
+ import { isFolder } from "@stacksjs/storage";
8
+ import { ExitCode } from "@stacksjs/types";
9
+ import { useOnline } from "@stacksjs/utils";
10
+ import { uninstallAllFeatures } from "./features";
11
+ import { ensurePantryDependencies, ensurePantryInstalled } from "./setup";
12
+ export function create(buddy) {
13
+ const descriptions = {
14
+ name: "The name of the project",
15
+ command: "Create a new Stacks project",
16
+ ui: "Are you building a UI?",
17
+ components: "Are you building UI components?",
18
+ webComponents: "Automagically built optimized custom elements/web components?",
19
+ vue: "Automagically built a Vue component library?",
20
+ views: "How about views?",
21
+ functions: "Are you developing functions/composables?",
22
+ api: "Are you building an API?",
23
+ database: "Do you need a database?",
24
+ notifications: "Do you need notifications? e.g. email, SMS, push or chat notifications",
25
+ cache: "Do you need caching?",
26
+ email: "Do you need email?",
27
+ project: "Target a specific project",
28
+ minimal: "Skip optional feature bundles (cms, commerce, dashboard, marketing, monitoring, realtime, queue) \u2014 bare-bones API/SPA starter that can re-add them later via `./buddy <feature>:install`.",
29
+ verbose: "Enable verbose output"
30
+ };
31
+ buddy.command("new [name]", descriptions.command).alias("create [name]").option("-n, --name [name]", descriptions.name, { default: !1 }).option("-u, --ui", descriptions.ui, { default: !0 }).option("-c, --components", descriptions.components, { default: !0 }).option("-w, --web-components", descriptions.webComponents, { default: !0 }).option("-v, --vue", descriptions.vue, { default: !0 }).option("-p, --views", descriptions.views, { default: !0 }).option("-f, --functions", descriptions.functions, { default: !0 }).option("-a, --api", descriptions.api, { default: !0 }).option("-d, --database", descriptions.database, { default: !0 }).option("-ca, --cache", descriptions.cache, { default: !1 }).option("-e, --email", descriptions.email, { default: !1 }).option("-p, --project [project]", descriptions.project, { default: !1 }).option("-m, --minimal", descriptions.minimal, { default: !1 }).option("--verbose", descriptions.verbose, { default: !1 }).action(async (name, options) => {
32
+ log.debug("Running `buddy new <name>` ...", options);
33
+ const startTime = await intro("buddy new");
34
+ name = name ?? options.name;
35
+ const path = resolve(process.cwd(), name);
36
+ isFolderCheck(path);
37
+ onlineCheck();
38
+ const result = await download(name, path, options);
39
+ if (result.isErr) {
40
+ log.error(result.error);
41
+ process.exit(ExitCode.FatalError);
42
+ }
43
+ await ensureEnv(path, options);
44
+ ensureExecutableScripts(path);
45
+ await install(path, options);
46
+ if (options.minimal)
47
+ await stripFeatures(path);
48
+ if (startTime) {
49
+ const time = performance.now() - startTime;
50
+ log.success(dim(`[${time.toFixed(2)}ms] Completed`));
51
+ }
52
+ log.info(bold("Welcome to the Stacks Framework! \u269B\uFE0F"));
53
+ log.info("To learn more, visit https://stacksjs.com");
54
+ process.exit(ExitCode.Success);
55
+ });
56
+ onUnknownSubcommand(buddy, "new");
57
+ }
58
+ function isFolderCheck(path) {
59
+ if (isFolder(path)) {
60
+ log.error(`Path ${path} already exists`);
61
+ process.exit(ExitCode.FatalError);
62
+ }
63
+ }
64
+ function onlineCheck() {
65
+ if (!useOnline()) {
66
+ log.info("It appears you are disconnected from the internet.");
67
+ log.info("The Stacks setup requires a brief internet connection for setup.");
68
+ log.info("For instance, it installs your dependencies from.");
69
+ process.exit(ExitCode.FatalError);
70
+ }
71
+ }
72
+ async function download(name, path, _options) {
73
+ log.info("Setting up your stack.");
74
+ try {
75
+ const { downloadTemplate } = await import("@stacksjs/gitit");
76
+ await downloadTemplate("stacks", { dir: name });
77
+ log.success(`Successfully scaffolded your project at ${cyan(path)}`);
78
+ return { isErr: !1 };
79
+ } catch (error) {
80
+ return { isErr: !0, error: error instanceof Error ? error.message : String(error) };
81
+ }
82
+ }
83
+ function ensureExecutableScripts(path) {
84
+ for (const script of ["buddy", "bootstrap"])
85
+ try {
86
+ chmodSync(resolve(path, script), 493);
87
+ } catch {}
88
+ }
89
+ async function ensureEnv(path, _options) {
90
+ log.info("Ensuring your environment is ready...");
91
+ await ensurePantryInstalled();
92
+ await ensurePantryDependencies(path);
93
+ log.success("Environment is ready");
94
+ }
95
+ async function install(path, options) {
96
+ log.info("Installing & setting up Stacks");
97
+ log.info("Running bun install...");
98
+ let result = await runCommand("bun install", { ...options, cwd: path });
99
+ if (result?.isErr) {
100
+ log.error(result.error);
101
+ process.exit(ExitCode.FatalError);
102
+ }
103
+ log.info("Copying .env.example \u2192 .env");
104
+ result = await runCommand("cp .env.example .env", { ...options, cwd: path });
105
+ if (result?.isErr) {
106
+ log.error(result.error);
107
+ process.exit(ExitCode.FatalError);
108
+ }
109
+ log.info("Generating application key...");
110
+ const keyResult = await runAction(Action.KeyGenerate, { ...options, cwd: path });
111
+ if (keyResult.isErr) {
112
+ log.error(keyResult.error);
113
+ process.exit(ExitCode.FatalError);
114
+ }
115
+ log.info("Initializing git repository...");
116
+ result = await runCommand("git init", { ...options, cwd: path });
117
+ if (result.isErr) {
118
+ log.error(result.error);
119
+ process.exit(ExitCode.FatalError);
120
+ }
121
+ log.success("Installed & set-up \uD83D\uDE80");
122
+ }
123
+ async function stripFeatures(path) {
124
+ log.info("Stripping optional feature bundles (--minimal)...");
125
+ const results = await uninstallAllFeatures({ root: path });
126
+ let strippedAny = !1;
127
+ for (const { feature, configOutcome, filesRemoved } of results)
128
+ if (configOutcome === "flipped" || filesRemoved.length > 0) {
129
+ strippedAny = !0;
130
+ const fileSummary = filesRemoved.length > 0 ? ` (${filesRemoved.length} path${filesRemoved.length === 1 ? "" : "s"})` : "";
131
+ log.info(` - ${feature}${fileSummary}`);
132
+ }
133
+ if (!strippedAny)
134
+ log.info(" \u2192 no feature scaffolding present; nothing to strip.");
135
+ else
136
+ log.success("Minimal skeleton ready \u2014 run `./buddy <feature>:install` to add features back.");
137
+ }