create-better-t-stack 3.7.3-canary.8e4d5716 → 3.7.3-canary.98ba1e7a
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/cli.d.ts +1 -0
- package/dist/cli.js +8 -0
- package/dist/index.d.ts +347 -0
- package/dist/index.js +4 -0
- package/dist/src-yXf02Wox.js +7077 -0
- package/package.json +11 -7
- package/src/cli.ts +0 -3
- package/src/constants.ts +0 -188
- package/src/helpers/addons/addons-setup.ts +0 -226
- package/src/helpers/addons/examples-setup.ts +0 -104
- package/src/helpers/addons/fumadocs-setup.ts +0 -103
- package/src/helpers/addons/ruler-setup.ts +0 -139
- package/src/helpers/addons/starlight-setup.ts +0 -51
- package/src/helpers/addons/tauri-setup.ts +0 -96
- package/src/helpers/addons/ultracite-setup.ts +0 -232
- package/src/helpers/addons/vite-pwa-setup.ts +0 -59
- package/src/helpers/core/add-addons.ts +0 -85
- package/src/helpers/core/add-deployment.ts +0 -102
- package/src/helpers/core/api-setup.ts +0 -280
- package/src/helpers/core/auth-setup.ts +0 -203
- package/src/helpers/core/backend-setup.ts +0 -73
- package/src/helpers/core/command-handlers.ts +0 -354
- package/src/helpers/core/convex-codegen.ts +0 -14
- package/src/helpers/core/create-project.ts +0 -133
- package/src/helpers/core/create-readme.ts +0 -687
- package/src/helpers/core/db-setup.ts +0 -184
- package/src/helpers/core/detect-project-config.ts +0 -41
- package/src/helpers/core/env-setup.ts +0 -449
- package/src/helpers/core/git.ts +0 -31
- package/src/helpers/core/install-dependencies.ts +0 -32
- package/src/helpers/core/payments-setup.ts +0 -48
- package/src/helpers/core/post-installation.ts +0 -383
- package/src/helpers/core/project-config.ts +0 -246
- package/src/helpers/core/runtime-setup.ts +0 -76
- package/src/helpers/core/template-manager.ts +0 -917
- package/src/helpers/core/workspace-setup.ts +0 -184
- package/src/helpers/database-providers/d1-setup.ts +0 -28
- package/src/helpers/database-providers/docker-compose-setup.ts +0 -50
- package/src/helpers/database-providers/mongodb-atlas-setup.ts +0 -186
- package/src/helpers/database-providers/neon-setup.ts +0 -243
- package/src/helpers/database-providers/planetscale-setup.ts +0 -78
- package/src/helpers/database-providers/prisma-postgres-setup.ts +0 -196
- package/src/helpers/database-providers/supabase-setup.ts +0 -218
- package/src/helpers/database-providers/turso-setup.ts +0 -309
- package/src/helpers/deployment/alchemy/alchemy-combined-setup.ts +0 -80
- package/src/helpers/deployment/alchemy/alchemy-next-setup.ts +0 -51
- package/src/helpers/deployment/alchemy/alchemy-nuxt-setup.ts +0 -104
- package/src/helpers/deployment/alchemy/alchemy-react-router-setup.ts +0 -32
- package/src/helpers/deployment/alchemy/alchemy-solid-setup.ts +0 -32
- package/src/helpers/deployment/alchemy/alchemy-svelte-setup.ts +0 -98
- package/src/helpers/deployment/alchemy/alchemy-tanstack-router-setup.ts +0 -33
- package/src/helpers/deployment/alchemy/alchemy-tanstack-start-setup.ts +0 -98
- package/src/helpers/deployment/alchemy/env-dts-setup.ts +0 -76
- package/src/helpers/deployment/alchemy/index.ts +0 -7
- package/src/helpers/deployment/server-deploy-setup.ts +0 -55
- package/src/helpers/deployment/web-deploy-setup.ts +0 -58
- package/src/index.ts +0 -253
- package/src/prompts/addons.ts +0 -178
- package/src/prompts/api.ts +0 -49
- package/src/prompts/auth.ts +0 -84
- package/src/prompts/backend.ts +0 -83
- package/src/prompts/config-prompts.ts +0 -138
- package/src/prompts/database-setup.ts +0 -112
- package/src/prompts/database.ts +0 -57
- package/src/prompts/examples.ts +0 -64
- package/src/prompts/frontend.ts +0 -118
- package/src/prompts/git.ts +0 -16
- package/src/prompts/install.ts +0 -16
- package/src/prompts/orm.ts +0 -53
- package/src/prompts/package-manager.ts +0 -32
- package/src/prompts/payments.ts +0 -50
- package/src/prompts/project-name.ts +0 -86
- package/src/prompts/runtime.ts +0 -47
- package/src/prompts/server-deploy.ts +0 -91
- package/src/prompts/web-deploy.ts +0 -107
- package/src/types.ts +0 -2
- package/src/utils/add-package-deps.ts +0 -57
- package/src/utils/analytics.ts +0 -39
- package/src/utils/better-auth-plugin-setup.ts +0 -71
- package/src/utils/biome-formatter.ts +0 -82
- package/src/utils/bts-config.ts +0 -122
- package/src/utils/command-exists.ts +0 -16
- package/src/utils/compatibility-rules.ts +0 -319
- package/src/utils/compatibility.ts +0 -11
- package/src/utils/config-processing.ts +0 -130
- package/src/utils/config-validation.ts +0 -470
- package/src/utils/display-config.ts +0 -96
- package/src/utils/docker-utils.ts +0 -70
- package/src/utils/errors.ts +0 -32
- package/src/utils/generate-reproducible-command.ts +0 -53
- package/src/utils/get-latest-cli-version.ts +0 -11
- package/src/utils/get-package-manager.ts +0 -13
- package/src/utils/open-url.ts +0 -25
- package/src/utils/package-runner.ts +0 -23
- package/src/utils/project-directory.ts +0 -102
- package/src/utils/project-name-validation.ts +0 -43
- package/src/utils/render-title.ts +0 -48
- package/src/utils/setup-catalogs.ts +0 -192
- package/src/utils/sponsors.ts +0 -101
- package/src/utils/telemetry.ts +0 -19
- package/src/utils/template-processor.ts +0 -64
- package/src/utils/templates.ts +0 -94
- package/src/utils/ts-morph.ts +0 -26
- package/src/validation.ts +0 -117
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import fs from "fs-extra";
|
|
3
|
-
import type { AvailableDependencies } from "../../constants";
|
|
4
|
-
import type { ProjectConfig } from "../../types";
|
|
5
|
-
import { addPackageDependency } from "../../utils/add-package-deps";
|
|
6
|
-
|
|
7
|
-
export async function setupWorkspaceDependencies(projectDir: string, options: ProjectConfig) {
|
|
8
|
-
const { projectName, packageManager, database, auth, api, runtime, backend } = options;
|
|
9
|
-
const workspaceVersion = packageManager === "npm" ? "*" : "workspace:*";
|
|
10
|
-
|
|
11
|
-
const commonDeps: AvailableDependencies[] = ["dotenv", "zod"];
|
|
12
|
-
const commonDevDeps: AvailableDependencies[] = ["typescript"];
|
|
13
|
-
|
|
14
|
-
const configDir = path.join(projectDir, "packages/config");
|
|
15
|
-
const dbDir = path.join(projectDir, "packages/db");
|
|
16
|
-
const authDir = path.join(projectDir, "packages/auth");
|
|
17
|
-
const apiDir = path.join(projectDir, "packages/api");
|
|
18
|
-
const backendDir = path.join(projectDir, "packages/backend");
|
|
19
|
-
const serverDir = path.join(projectDir, "apps/server");
|
|
20
|
-
const webDir = path.join(projectDir, "apps/web");
|
|
21
|
-
const nativeDir = path.join(projectDir, "apps/native");
|
|
22
|
-
|
|
23
|
-
const [
|
|
24
|
-
configExists,
|
|
25
|
-
dbExists,
|
|
26
|
-
authExists,
|
|
27
|
-
apiExists,
|
|
28
|
-
backendExists,
|
|
29
|
-
serverExists,
|
|
30
|
-
webExists,
|
|
31
|
-
nativeExists,
|
|
32
|
-
] = await Promise.all([
|
|
33
|
-
fs.pathExists(configDir),
|
|
34
|
-
fs.pathExists(dbDir),
|
|
35
|
-
fs.pathExists(authDir),
|
|
36
|
-
fs.pathExists(apiDir),
|
|
37
|
-
fs.pathExists(backendDir),
|
|
38
|
-
fs.pathExists(serverDir),
|
|
39
|
-
fs.pathExists(webDir),
|
|
40
|
-
fs.pathExists(nativeDir),
|
|
41
|
-
]);
|
|
42
|
-
|
|
43
|
-
const configDep: Record<string, string> = configExists
|
|
44
|
-
? { [`@${projectName}/config`]: workspaceVersion }
|
|
45
|
-
: {};
|
|
46
|
-
|
|
47
|
-
if (dbExists) {
|
|
48
|
-
await addPackageDependency({
|
|
49
|
-
dependencies: commonDeps,
|
|
50
|
-
devDependencies: commonDevDeps,
|
|
51
|
-
customDevDependencies: configDep,
|
|
52
|
-
projectDir: dbDir,
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (authExists) {
|
|
57
|
-
const authDeps: Record<string, string> = {};
|
|
58
|
-
if (database !== "none" && dbExists) {
|
|
59
|
-
authDeps[`@${projectName}/db`] = workspaceVersion;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
await addPackageDependency({
|
|
63
|
-
dependencies: commonDeps,
|
|
64
|
-
devDependencies: commonDevDeps,
|
|
65
|
-
customDependencies: authDeps,
|
|
66
|
-
customDevDependencies: configDep,
|
|
67
|
-
projectDir: authDir,
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (apiExists) {
|
|
72
|
-
const apiDeps: Record<string, string> = {};
|
|
73
|
-
if (auth !== "none" && authExists) {
|
|
74
|
-
apiDeps[`@${projectName}/auth`] = workspaceVersion;
|
|
75
|
-
}
|
|
76
|
-
if (database !== "none" && dbExists) {
|
|
77
|
-
apiDeps[`@${projectName}/db`] = workspaceVersion;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
await addPackageDependency({
|
|
81
|
-
dependencies: commonDeps,
|
|
82
|
-
devDependencies: commonDevDeps,
|
|
83
|
-
customDependencies: apiDeps,
|
|
84
|
-
customDevDependencies: configDep,
|
|
85
|
-
projectDir: apiDir,
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (backendExists) {
|
|
90
|
-
await addPackageDependency({
|
|
91
|
-
dependencies: commonDeps,
|
|
92
|
-
devDependencies: commonDevDeps,
|
|
93
|
-
customDevDependencies: configDep,
|
|
94
|
-
projectDir: backendDir,
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (serverExists) {
|
|
99
|
-
const serverDeps: Record<string, string> = {};
|
|
100
|
-
if (api !== "none" && apiExists) {
|
|
101
|
-
serverDeps[`@${projectName}/api`] = workspaceVersion;
|
|
102
|
-
}
|
|
103
|
-
if (auth !== "none" && authExists) {
|
|
104
|
-
serverDeps[`@${projectName}/auth`] = workspaceVersion;
|
|
105
|
-
}
|
|
106
|
-
if (database !== "none" && dbExists) {
|
|
107
|
-
serverDeps[`@${projectName}/db`] = workspaceVersion;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
await addPackageDependency({
|
|
111
|
-
dependencies: commonDeps,
|
|
112
|
-
devDependencies: [...commonDevDeps, "tsdown"],
|
|
113
|
-
customDependencies: serverDeps,
|
|
114
|
-
customDevDependencies: configDep,
|
|
115
|
-
projectDir: serverDir,
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (webExists) {
|
|
120
|
-
const webDeps: Record<string, string> = {};
|
|
121
|
-
if (api !== "none" && apiExists) {
|
|
122
|
-
webDeps[`@${projectName}/api`] = workspaceVersion;
|
|
123
|
-
}
|
|
124
|
-
if (auth !== "none" && authExists) {
|
|
125
|
-
webDeps[`@${projectName}/auth`] = workspaceVersion;
|
|
126
|
-
}
|
|
127
|
-
if (backend === "convex" && backendExists) {
|
|
128
|
-
webDeps[`@${projectName}/backend`] = workspaceVersion;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
await addPackageDependency({
|
|
132
|
-
dependencies: commonDeps,
|
|
133
|
-
devDependencies: commonDevDeps,
|
|
134
|
-
customDependencies: webDeps,
|
|
135
|
-
customDevDependencies: configDep,
|
|
136
|
-
projectDir: webDir,
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (nativeExists) {
|
|
141
|
-
const nativeDeps: Record<string, string> = {};
|
|
142
|
-
if (api !== "none" && apiExists) {
|
|
143
|
-
nativeDeps[`@${projectName}/api`] = workspaceVersion;
|
|
144
|
-
}
|
|
145
|
-
if (backend === "convex" && backendExists) {
|
|
146
|
-
nativeDeps[`@${projectName}/backend`] = workspaceVersion;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
await addPackageDependency({
|
|
150
|
-
dependencies: commonDeps,
|
|
151
|
-
devDependencies: commonDevDeps,
|
|
152
|
-
customDependencies: nativeDeps,
|
|
153
|
-
customDevDependencies: configDep,
|
|
154
|
-
projectDir: nativeDir,
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const runtimeDevDeps = getRuntimeDevDeps(runtime, backend);
|
|
159
|
-
|
|
160
|
-
await addPackageDependency({
|
|
161
|
-
dependencies: commonDeps,
|
|
162
|
-
devDependencies: [...commonDevDeps, ...runtimeDevDeps],
|
|
163
|
-
projectDir,
|
|
164
|
-
});
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
function getRuntimeDevDeps(
|
|
168
|
-
runtime: ProjectConfig["runtime"],
|
|
169
|
-
backend: ProjectConfig["backend"],
|
|
170
|
-
): AvailableDependencies[] {
|
|
171
|
-
if (runtime === "none" && backend === "self") {
|
|
172
|
-
return ["@types/node"];
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (runtime === "node" || runtime === "workers") {
|
|
176
|
-
return ["@types/node"];
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
if (runtime === "bun") {
|
|
180
|
-
return ["@types/bun"];
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return [];
|
|
184
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import type { ProjectConfig } from "../../types";
|
|
3
|
-
import { addPackageDependency } from "../../utils/add-package-deps";
|
|
4
|
-
import { addEnvVariablesToFile, type EnvVariable } from "../core/env-setup";
|
|
5
|
-
|
|
6
|
-
export async function setupCloudflareD1(config: ProjectConfig) {
|
|
7
|
-
const { projectDir, serverDeploy, orm, backend } = config;
|
|
8
|
-
|
|
9
|
-
if (serverDeploy === "alchemy" && orm === "prisma") {
|
|
10
|
-
const targetApp2 = backend === "self" ? "apps/web" : "apps/server";
|
|
11
|
-
const envPath = path.join(projectDir, targetApp2, ".env");
|
|
12
|
-
const variables: EnvVariable[] = [
|
|
13
|
-
{
|
|
14
|
-
key: "DATABASE_URL",
|
|
15
|
-
value: `file:${path.join(projectDir, "apps/server", "local.db")}`,
|
|
16
|
-
condition: true,
|
|
17
|
-
},
|
|
18
|
-
];
|
|
19
|
-
|
|
20
|
-
await addEnvVariablesToFile(envPath, variables);
|
|
21
|
-
|
|
22
|
-
const serverDir = path.join(projectDir, backend === "self" ? "apps/web" : "apps/server");
|
|
23
|
-
await addPackageDependency({
|
|
24
|
-
dependencies: ["@prisma/adapter-d1"],
|
|
25
|
-
projectDir: serverDir,
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import type { Database, ProjectConfig } from "../../types";
|
|
3
|
-
import { addEnvVariablesToFile, type EnvVariable } from "../core/env-setup";
|
|
4
|
-
|
|
5
|
-
export async function setupDockerCompose(config: ProjectConfig) {
|
|
6
|
-
const { database, projectDir, projectName, backend } = config;
|
|
7
|
-
|
|
8
|
-
if (database === "none" || database === "sqlite") {
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
try {
|
|
13
|
-
await writeEnvFile(projectDir, database, projectName, backend);
|
|
14
|
-
} catch (error) {
|
|
15
|
-
if (error instanceof Error) {
|
|
16
|
-
console.error(`Error: ${error.message}`);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
async function writeEnvFile(
|
|
22
|
-
projectDir: string,
|
|
23
|
-
database: Database,
|
|
24
|
-
projectName: string,
|
|
25
|
-
backend?: string,
|
|
26
|
-
) {
|
|
27
|
-
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
28
|
-
const envPath = path.join(projectDir, targetApp, ".env");
|
|
29
|
-
const variables: EnvVariable[] = [
|
|
30
|
-
{
|
|
31
|
-
key: "DATABASE_URL",
|
|
32
|
-
value: getDatabaseUrl(database, projectName),
|
|
33
|
-
condition: true,
|
|
34
|
-
},
|
|
35
|
-
];
|
|
36
|
-
await addEnvVariablesToFile(envPath, variables);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function getDatabaseUrl(database: Database, projectName: string) {
|
|
40
|
-
switch (database) {
|
|
41
|
-
case "postgres":
|
|
42
|
-
return `postgresql://postgres:password@localhost:5432/${projectName}`;
|
|
43
|
-
case "mysql":
|
|
44
|
-
return `mysql://user:password@localhost:3306/${projectName}`;
|
|
45
|
-
case "mongodb":
|
|
46
|
-
return `mongodb://root:password@localhost:27017/${projectName}?authSource=admin`;
|
|
47
|
-
default:
|
|
48
|
-
return "";
|
|
49
|
-
}
|
|
50
|
-
}
|
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import { cancel, isCancel, log, select, text } from "@clack/prompts";
|
|
3
|
-
import consola from "consola";
|
|
4
|
-
import { execa } from "execa";
|
|
5
|
-
import fs from "fs-extra";
|
|
6
|
-
import pc from "picocolors";
|
|
7
|
-
import type { ProjectConfig } from "../../types";
|
|
8
|
-
import { commandExists } from "../../utils/command-exists";
|
|
9
|
-
import { exitCancelled } from "../../utils/errors";
|
|
10
|
-
import { addEnvVariablesToFile, type EnvVariable } from "../core/env-setup";
|
|
11
|
-
|
|
12
|
-
type MongoDBConfig = {
|
|
13
|
-
connectionString: string;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
async function checkAtlasCLI() {
|
|
17
|
-
try {
|
|
18
|
-
const exists = await commandExists("atlas");
|
|
19
|
-
if (exists) {
|
|
20
|
-
log.info("MongoDB Atlas CLI found");
|
|
21
|
-
} else {
|
|
22
|
-
log.warn(pc.yellow("MongoDB Atlas CLI not found"));
|
|
23
|
-
}
|
|
24
|
-
return exists;
|
|
25
|
-
} catch {
|
|
26
|
-
log.error(pc.red("Error checking MongoDB Atlas CLI"));
|
|
27
|
-
return false;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async function initMongoDBAtlas(serverDir: string) {
|
|
32
|
-
try {
|
|
33
|
-
const hasAtlas = await checkAtlasCLI();
|
|
34
|
-
|
|
35
|
-
if (!hasAtlas) {
|
|
36
|
-
consola.error(pc.red("MongoDB Atlas CLI not found."));
|
|
37
|
-
log.info(
|
|
38
|
-
pc.yellow(
|
|
39
|
-
"Please install it from: https://www.mongodb.com/docs/atlas/cli/current/install-atlas-cli/",
|
|
40
|
-
),
|
|
41
|
-
);
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
log.info("Running MongoDB Atlas setup...");
|
|
46
|
-
|
|
47
|
-
await execa("atlas", ["deployments", "setup"], {
|
|
48
|
-
cwd: serverDir,
|
|
49
|
-
shell: true,
|
|
50
|
-
stdio: "inherit",
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
log.success("MongoDB Atlas deployment ready");
|
|
54
|
-
|
|
55
|
-
const connectionString = await text({
|
|
56
|
-
message: "Enter your MongoDB connection string:",
|
|
57
|
-
placeholder: "mongodb+srv://username:password@cluster.mongodb.net/database",
|
|
58
|
-
validate(value) {
|
|
59
|
-
if (!value) return "Please enter a connection string";
|
|
60
|
-
if (!value.startsWith("mongodb")) {
|
|
61
|
-
return "URL should start with mongodb:// or mongodb+srv://";
|
|
62
|
-
}
|
|
63
|
-
},
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
if (isCancel(connectionString)) {
|
|
67
|
-
cancel("MongoDB setup cancelled");
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return {
|
|
72
|
-
connectionString: connectionString as string,
|
|
73
|
-
};
|
|
74
|
-
} catch (error) {
|
|
75
|
-
if (error instanceof Error) {
|
|
76
|
-
consola.error(pc.red(error.message));
|
|
77
|
-
}
|
|
78
|
-
return null;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
async function writeEnvFile(
|
|
83
|
-
projectDir: string,
|
|
84
|
-
backend: ProjectConfig["backend"],
|
|
85
|
-
config?: MongoDBConfig,
|
|
86
|
-
) {
|
|
87
|
-
try {
|
|
88
|
-
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
89
|
-
const envPath = path.join(projectDir, targetApp, ".env");
|
|
90
|
-
const variables: EnvVariable[] = [
|
|
91
|
-
{
|
|
92
|
-
key: "DATABASE_URL",
|
|
93
|
-
value: config?.connectionString ?? "mongodb://localhost:27017/mydb",
|
|
94
|
-
condition: true,
|
|
95
|
-
},
|
|
96
|
-
];
|
|
97
|
-
await addEnvVariablesToFile(envPath, variables);
|
|
98
|
-
} catch {
|
|
99
|
-
consola.error("Failed to update environment configuration");
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function displayManualSetupInstructions() {
|
|
104
|
-
log.info(`
|
|
105
|
-
${pc.green("MongoDB Atlas Manual Setup Instructions:")}
|
|
106
|
-
|
|
107
|
-
1. Install Atlas CLI:
|
|
108
|
-
${pc.blue("https://www.mongodb.com/docs/atlas/cli/stable/install-atlas-cli/")}
|
|
109
|
-
|
|
110
|
-
2. Run the following command and follow the prompts:
|
|
111
|
-
${pc.blue("atlas deployments setup")}
|
|
112
|
-
|
|
113
|
-
3. Get your connection string from the Atlas dashboard:
|
|
114
|
-
Format: ${pc.dim("mongodb+srv://USERNAME:PASSWORD@CLUSTER.mongodb.net/DATABASE_NAME")}
|
|
115
|
-
|
|
116
|
-
4. Add the connection string to your .env file:
|
|
117
|
-
${pc.dim('DATABASE_URL="your_connection_string"')}
|
|
118
|
-
`);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export async function setupMongoDBAtlas(config: ProjectConfig, cliInput?: { manualDb?: boolean }) {
|
|
122
|
-
const { projectDir, backend } = config;
|
|
123
|
-
const manualDb = cliInput?.manualDb ?? false;
|
|
124
|
-
|
|
125
|
-
const serverDir = path.join(projectDir, "packages/db");
|
|
126
|
-
try {
|
|
127
|
-
await fs.ensureDir(serverDir);
|
|
128
|
-
|
|
129
|
-
if (manualDb) {
|
|
130
|
-
log.info("MongoDB Atlas manual setup selected");
|
|
131
|
-
await writeEnvFile(projectDir, backend);
|
|
132
|
-
displayManualSetupInstructions();
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const mode = await select({
|
|
137
|
-
message: "MongoDB Atlas setup: choose mode",
|
|
138
|
-
options: [
|
|
139
|
-
{
|
|
140
|
-
label: "Automatic",
|
|
141
|
-
value: "auto",
|
|
142
|
-
hint: "Automated setup with provider CLI, sets .env",
|
|
143
|
-
},
|
|
144
|
-
{
|
|
145
|
-
label: "Manual",
|
|
146
|
-
value: "manual",
|
|
147
|
-
hint: "Manual setup, add env vars yourself",
|
|
148
|
-
},
|
|
149
|
-
],
|
|
150
|
-
initialValue: "auto",
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
if (isCancel(mode)) return exitCancelled("Operation cancelled");
|
|
154
|
-
|
|
155
|
-
if (mode === "manual") {
|
|
156
|
-
log.info("MongoDB Atlas manual setup selected");
|
|
157
|
-
await writeEnvFile(projectDir, backend);
|
|
158
|
-
displayManualSetupInstructions();
|
|
159
|
-
return;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const config = await initMongoDBAtlas(serverDir);
|
|
163
|
-
|
|
164
|
-
if (config) {
|
|
165
|
-
await writeEnvFile(projectDir, backend, config);
|
|
166
|
-
log.success(pc.green("MongoDB Atlas setup complete! Connection saved to .env file."));
|
|
167
|
-
} else {
|
|
168
|
-
log.warn(pc.yellow("Falling back to local MongoDB configuration"));
|
|
169
|
-
await writeEnvFile(projectDir, backend);
|
|
170
|
-
displayManualSetupInstructions();
|
|
171
|
-
}
|
|
172
|
-
} catch (error) {
|
|
173
|
-
consola.error(
|
|
174
|
-
pc.red(
|
|
175
|
-
`Error during MongoDB Atlas setup: ${
|
|
176
|
-
error instanceof Error ? error.message : String(error)
|
|
177
|
-
}`,
|
|
178
|
-
),
|
|
179
|
-
);
|
|
180
|
-
|
|
181
|
-
try {
|
|
182
|
-
await writeEnvFile(projectDir, backend);
|
|
183
|
-
displayManualSetupInstructions();
|
|
184
|
-
} catch {}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import { isCancel, log, select, spinner, text } from "@clack/prompts";
|
|
3
|
-
import { consola } from "consola";
|
|
4
|
-
import { execa } from "execa";
|
|
5
|
-
import fs from "fs-extra";
|
|
6
|
-
import pc from "picocolors";
|
|
7
|
-
import type { PackageManager, ProjectConfig } from "../../types";
|
|
8
|
-
import { exitCancelled } from "../../utils/errors";
|
|
9
|
-
import { getPackageExecutionCommand } from "../../utils/package-runner";
|
|
10
|
-
import { addEnvVariablesToFile, type EnvVariable } from "../core/env-setup";
|
|
11
|
-
|
|
12
|
-
type NeonConfig = {
|
|
13
|
-
connectionString: string;
|
|
14
|
-
projectId: string;
|
|
15
|
-
dbName: string;
|
|
16
|
-
roleName: string;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
type NeonRegion = {
|
|
20
|
-
label: string;
|
|
21
|
-
value: string;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const NEON_REGIONS: NeonRegion[] = [
|
|
25
|
-
{ label: "AWS US East (N. Virginia)", value: "aws-us-east-1" },
|
|
26
|
-
{ label: "AWS US East (Ohio)", value: "aws-us-east-2" },
|
|
27
|
-
{ label: "AWS US West (Oregon)", value: "aws-us-west-2" },
|
|
28
|
-
{ label: "AWS Europe (Frankfurt)", value: "aws-eu-central-1" },
|
|
29
|
-
{ label: "AWS Asia Pacific (Singapore)", value: "aws-ap-southeast-1" },
|
|
30
|
-
{ label: "AWS South America East 1 (São Paulo)", value: "aws-sa-east-1" },
|
|
31
|
-
{ label: "AWS Asia Pacific (Sydney)", value: "aws-ap-southeast-2" },
|
|
32
|
-
{ label: "Azure East US 2 region (Virginia)", value: "azure-eastus2" },
|
|
33
|
-
];
|
|
34
|
-
|
|
35
|
-
async function executeNeonCommand(
|
|
36
|
-
packageManager: PackageManager,
|
|
37
|
-
commandArgsString: string,
|
|
38
|
-
spinnerText?: string,
|
|
39
|
-
) {
|
|
40
|
-
const s = spinner();
|
|
41
|
-
try {
|
|
42
|
-
const fullCommand = getPackageExecutionCommand(packageManager, commandArgsString);
|
|
43
|
-
|
|
44
|
-
if (spinnerText) s.start(spinnerText);
|
|
45
|
-
const result = await execa(fullCommand, { shell: true });
|
|
46
|
-
if (spinnerText) s.stop(pc.green(spinnerText.replace("...", "").replace("ing ", "ed ").trim()));
|
|
47
|
-
return result;
|
|
48
|
-
} catch (error) {
|
|
49
|
-
if (s) s.stop(pc.red(`Failed: ${spinnerText || "Command execution"}`));
|
|
50
|
-
throw error;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
async function createNeonProject(
|
|
55
|
-
projectName: string,
|
|
56
|
-
regionId: string,
|
|
57
|
-
packageManager: PackageManager,
|
|
58
|
-
) {
|
|
59
|
-
try {
|
|
60
|
-
const commandArgsString = `neonctl@latest projects create --name ${projectName} --region-id ${regionId} --output json`;
|
|
61
|
-
const { stdout } = await executeNeonCommand(
|
|
62
|
-
packageManager,
|
|
63
|
-
commandArgsString,
|
|
64
|
-
`Creating Neon project "${projectName}"...`,
|
|
65
|
-
);
|
|
66
|
-
|
|
67
|
-
const response = JSON.parse(stdout);
|
|
68
|
-
|
|
69
|
-
if (response.project && response.connection_uris && response.connection_uris.length > 0) {
|
|
70
|
-
const projectId = response.project.id;
|
|
71
|
-
const connectionUri = response.connection_uris[0].connection_uri;
|
|
72
|
-
const params = response.connection_uris[0].connection_parameters;
|
|
73
|
-
|
|
74
|
-
return {
|
|
75
|
-
connectionString: connectionUri,
|
|
76
|
-
projectId: projectId,
|
|
77
|
-
dbName: params.database,
|
|
78
|
-
roleName: params.role,
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
consola.error(pc.red("Failed to extract connection information from response"));
|
|
82
|
-
return null;
|
|
83
|
-
} catch {
|
|
84
|
-
consola.error(pc.red("Failed to create Neon project"));
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
async function writeEnvFile(
|
|
89
|
-
projectDir: string,
|
|
90
|
-
backend: ProjectConfig["backend"],
|
|
91
|
-
config?: NeonConfig,
|
|
92
|
-
) {
|
|
93
|
-
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
94
|
-
const envPath = path.join(projectDir, targetApp, ".env");
|
|
95
|
-
const variables: EnvVariable[] = [
|
|
96
|
-
{
|
|
97
|
-
key: "DATABASE_URL",
|
|
98
|
-
value:
|
|
99
|
-
config?.connectionString ??
|
|
100
|
-
"postgresql://postgres:postgres@localhost:5432/mydb?schema=public",
|
|
101
|
-
condition: true,
|
|
102
|
-
},
|
|
103
|
-
];
|
|
104
|
-
await addEnvVariablesToFile(envPath, variables);
|
|
105
|
-
|
|
106
|
-
return true;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
async function setupWithNeonDb(
|
|
110
|
-
projectDir: string,
|
|
111
|
-
packageManager: PackageManager,
|
|
112
|
-
backend: ProjectConfig["backend"],
|
|
113
|
-
) {
|
|
114
|
-
try {
|
|
115
|
-
const s = spinner();
|
|
116
|
-
s.start("Creating Neon database using get-db...");
|
|
117
|
-
|
|
118
|
-
const targetApp = backend === "self" ? "apps/web" : "apps/server";
|
|
119
|
-
const targetDir = path.join(projectDir, targetApp);
|
|
120
|
-
await fs.ensureDir(targetDir);
|
|
121
|
-
|
|
122
|
-
const packageCmd = getPackageExecutionCommand(packageManager, "get-db@latest --yes");
|
|
123
|
-
|
|
124
|
-
await execa(packageCmd, {
|
|
125
|
-
shell: true,
|
|
126
|
-
cwd: targetDir,
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
s.stop(pc.green("Neon database created successfully!"));
|
|
130
|
-
|
|
131
|
-
return true;
|
|
132
|
-
} catch (error) {
|
|
133
|
-
consola.error(pc.red("Failed to create database with get-db"));
|
|
134
|
-
throw error;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function displayManualSetupInstructions(target: "apps/web" | "apps/server") {
|
|
139
|
-
log.info(`Manual Neon PostgreSQL Setup Instructions:
|
|
140
|
-
|
|
141
|
-
1. Visit https://neon.tech and create an account
|
|
142
|
-
2. Create a new project from the dashboard
|
|
143
|
-
3. Get your connection string
|
|
144
|
-
4. Add the database URL to the .env file in ${target}/.env
|
|
145
|
-
|
|
146
|
-
DATABASE_URL="your_connection_string"`);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
export async function setupNeonPostgres(config: ProjectConfig, cliInput?: { manualDb?: boolean }) {
|
|
150
|
-
const { packageManager, projectDir, backend } = config;
|
|
151
|
-
const manualDb = cliInput?.manualDb ?? false;
|
|
152
|
-
|
|
153
|
-
try {
|
|
154
|
-
if (manualDb) {
|
|
155
|
-
await writeEnvFile(projectDir, backend);
|
|
156
|
-
displayManualSetupInstructions(backend === "self" ? "apps/web" : "apps/server");
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const mode = await select({
|
|
161
|
-
message: "Neon setup: choose mode",
|
|
162
|
-
options: [
|
|
163
|
-
{
|
|
164
|
-
label: "Automatic",
|
|
165
|
-
value: "auto",
|
|
166
|
-
hint: "Automated setup with provider CLI, sets .env",
|
|
167
|
-
},
|
|
168
|
-
{
|
|
169
|
-
label: "Manual",
|
|
170
|
-
value: "manual",
|
|
171
|
-
hint: "Manual setup, add env vars yourself",
|
|
172
|
-
},
|
|
173
|
-
],
|
|
174
|
-
initialValue: "auto",
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
if (isCancel(mode)) return exitCancelled("Operation cancelled");
|
|
178
|
-
|
|
179
|
-
if (mode === "manual") {
|
|
180
|
-
await writeEnvFile(projectDir, backend);
|
|
181
|
-
displayManualSetupInstructions(backend === "self" ? "apps/web" : "apps/server");
|
|
182
|
-
return;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
const setupMethod = await select({
|
|
186
|
-
message: "Choose your Neon setup method:",
|
|
187
|
-
options: [
|
|
188
|
-
{
|
|
189
|
-
label: "Quick setup with get-db",
|
|
190
|
-
value: "neondb",
|
|
191
|
-
hint: "fastest, no auth required",
|
|
192
|
-
},
|
|
193
|
-
{
|
|
194
|
-
label: "Custom setup with neonctl",
|
|
195
|
-
value: "neonctl",
|
|
196
|
-
hint: "More control - choose project name and region",
|
|
197
|
-
},
|
|
198
|
-
],
|
|
199
|
-
initialValue: "neondb",
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
if (isCancel(setupMethod)) return exitCancelled("Operation cancelled");
|
|
203
|
-
|
|
204
|
-
if (setupMethod === "neondb") {
|
|
205
|
-
await setupWithNeonDb(projectDir, packageManager, backend);
|
|
206
|
-
} else {
|
|
207
|
-
const suggestedProjectName = path.basename(projectDir);
|
|
208
|
-
const projectName = await text({
|
|
209
|
-
message: "Enter a name for your Neon project:",
|
|
210
|
-
defaultValue: suggestedProjectName,
|
|
211
|
-
initialValue: suggestedProjectName,
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
const regionId = await select({
|
|
215
|
-
message: "Select a region for your Neon project:",
|
|
216
|
-
options: NEON_REGIONS,
|
|
217
|
-
initialValue: NEON_REGIONS[0].value,
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
if (isCancel(projectName) || isCancel(regionId)) return exitCancelled("Operation cancelled");
|
|
221
|
-
|
|
222
|
-
const neonConfig = await createNeonProject(projectName as string, regionId, packageManager);
|
|
223
|
-
|
|
224
|
-
if (!neonConfig) {
|
|
225
|
-
throw new Error("Failed to create project - couldn't get connection information");
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const finalSpinner = spinner();
|
|
229
|
-
finalSpinner.start("Configuring database connection");
|
|
230
|
-
|
|
231
|
-
await writeEnvFile(projectDir, backend, neonConfig);
|
|
232
|
-
|
|
233
|
-
finalSpinner.stop("Neon database configured!");
|
|
234
|
-
}
|
|
235
|
-
} catch (error) {
|
|
236
|
-
if (error instanceof Error) {
|
|
237
|
-
consola.error(pc.red(error.message));
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
await writeEnvFile(projectDir, backend);
|
|
241
|
-
displayManualSetupInstructions(backend === "self" ? "apps/web" : "apps/server");
|
|
242
|
-
}
|
|
243
|
-
}
|