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,98 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import fs from "fs-extra";
|
|
3
|
-
import { IndentationText, Node, Project, QuoteKind } from "ts-morph";
|
|
4
|
-
import type { PackageManager } from "../../../types";
|
|
5
|
-
import { addPackageDependency } from "../../../utils/add-package-deps";
|
|
6
|
-
|
|
7
|
-
export async function setupSvelteAlchemyDeploy(
|
|
8
|
-
projectDir: string,
|
|
9
|
-
_packageManager: PackageManager,
|
|
10
|
-
options?: { skipAppScripts?: boolean },
|
|
11
|
-
) {
|
|
12
|
-
const webAppDir = path.join(projectDir, "apps/web");
|
|
13
|
-
if (!(await fs.pathExists(webAppDir))) return;
|
|
14
|
-
|
|
15
|
-
await addPackageDependency({
|
|
16
|
-
devDependencies: ["alchemy", "@sveltejs/adapter-cloudflare"],
|
|
17
|
-
projectDir: webAppDir,
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
const pkgPath = path.join(webAppDir, "package.json");
|
|
21
|
-
if (await fs.pathExists(pkgPath)) {
|
|
22
|
-
const pkg = await fs.readJson(pkgPath);
|
|
23
|
-
|
|
24
|
-
if (!options?.skipAppScripts) {
|
|
25
|
-
pkg.scripts = {
|
|
26
|
-
...pkg.scripts,
|
|
27
|
-
deploy: "alchemy deploy",
|
|
28
|
-
destroy: "alchemy destroy",
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const svelteConfigPath = path.join(webAppDir, "svelte.config.js");
|
|
36
|
-
if (!(await fs.pathExists(svelteConfigPath))) return;
|
|
37
|
-
|
|
38
|
-
try {
|
|
39
|
-
const project = new Project({
|
|
40
|
-
manipulationSettings: {
|
|
41
|
-
indentationText: IndentationText.TwoSpaces,
|
|
42
|
-
quoteKind: QuoteKind.Single,
|
|
43
|
-
},
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
project.addSourceFileAtPath(svelteConfigPath);
|
|
47
|
-
const sourceFile = project.getSourceFileOrThrow(svelteConfigPath);
|
|
48
|
-
|
|
49
|
-
const importDeclarations = sourceFile.getImportDeclarations();
|
|
50
|
-
const adapterImport = importDeclarations.find((imp) =>
|
|
51
|
-
imp.getModuleSpecifierValue().includes("@sveltejs/adapter"),
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
if (adapterImport) {
|
|
55
|
-
adapterImport.setModuleSpecifier("alchemy/cloudflare/sveltekit");
|
|
56
|
-
adapterImport.removeDefaultImport();
|
|
57
|
-
adapterImport.setDefaultImport("alchemy");
|
|
58
|
-
} else {
|
|
59
|
-
sourceFile.insertImportDeclaration(0, {
|
|
60
|
-
moduleSpecifier: "alchemy/cloudflare/sveltekit",
|
|
61
|
-
defaultImport: "alchemy",
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const configVariable = sourceFile.getVariableDeclaration("config");
|
|
66
|
-
if (configVariable) {
|
|
67
|
-
const initializer = configVariable.getInitializer();
|
|
68
|
-
if (Node.isObjectLiteralExpression(initializer)) {
|
|
69
|
-
updateAdapterInConfig(initializer);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
await project.save();
|
|
74
|
-
} catch (error) {
|
|
75
|
-
console.warn("Failed to update svelte.config.js:", error);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function updateAdapterInConfig(configObject: Node) {
|
|
80
|
-
if (!Node.isObjectLiteralExpression(configObject)) return;
|
|
81
|
-
|
|
82
|
-
const kitProperty = configObject.getProperty("kit");
|
|
83
|
-
if (kitProperty && Node.isPropertyAssignment(kitProperty)) {
|
|
84
|
-
const kitInitializer = kitProperty.getInitializer();
|
|
85
|
-
if (Node.isObjectLiteralExpression(kitInitializer)) {
|
|
86
|
-
const adapterProperty = kitInitializer.getProperty("adapter");
|
|
87
|
-
if (adapterProperty && Node.isPropertyAssignment(adapterProperty)) {
|
|
88
|
-
const initializer = adapterProperty.getInitializer();
|
|
89
|
-
if (Node.isCallExpression(initializer)) {
|
|
90
|
-
const expression = initializer.getExpression();
|
|
91
|
-
if (Node.isIdentifier(expression) && expression.getText() === "adapter") {
|
|
92
|
-
expression.replaceWithText("alchemy");
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import fs from "fs-extra";
|
|
3
|
-
import type { PackageManager } from "../../../types";
|
|
4
|
-
import { addPackageDependency } from "../../../utils/add-package-deps";
|
|
5
|
-
|
|
6
|
-
export async function setupTanStackRouterAlchemyDeploy(
|
|
7
|
-
projectDir: string,
|
|
8
|
-
_packageManager: PackageManager,
|
|
9
|
-
options?: { skipAppScripts?: boolean },
|
|
10
|
-
) {
|
|
11
|
-
const webAppDir = path.join(projectDir, "apps/web");
|
|
12
|
-
if (!(await fs.pathExists(webAppDir))) return;
|
|
13
|
-
|
|
14
|
-
await addPackageDependency({
|
|
15
|
-
devDependencies: ["alchemy"],
|
|
16
|
-
projectDir: webAppDir,
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
const pkgPath = path.join(webAppDir, "package.json");
|
|
20
|
-
if (await fs.pathExists(pkgPath)) {
|
|
21
|
-
const pkg = await fs.readJson(pkgPath);
|
|
22
|
-
|
|
23
|
-
if (!options?.skipAppScripts) {
|
|
24
|
-
pkg.scripts = {
|
|
25
|
-
...pkg.scripts,
|
|
26
|
-
deploy: "alchemy deploy",
|
|
27
|
-
destroy: "alchemy destroy",
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
32
|
-
}
|
|
33
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import fs from "fs-extra";
|
|
3
|
-
import { IndentationText, Node, Project, QuoteKind } from "ts-morph";
|
|
4
|
-
import type { PackageManager } from "../../../types";
|
|
5
|
-
import { addPackageDependency } from "../../../utils/add-package-deps";
|
|
6
|
-
|
|
7
|
-
export async function setupTanStackStartAlchemyDeploy(
|
|
8
|
-
projectDir: string,
|
|
9
|
-
_packageManager: PackageManager,
|
|
10
|
-
options?: { skipAppScripts?: boolean },
|
|
11
|
-
) {
|
|
12
|
-
const webAppDir = path.join(projectDir, "apps/web");
|
|
13
|
-
if (!(await fs.pathExists(webAppDir))) return;
|
|
14
|
-
|
|
15
|
-
await addPackageDependency({
|
|
16
|
-
devDependencies: ["alchemy", "@cloudflare/vite-plugin"],
|
|
17
|
-
projectDir: webAppDir,
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
const pkgPath = path.join(webAppDir, "package.json");
|
|
21
|
-
if (await fs.pathExists(pkgPath)) {
|
|
22
|
-
const pkg = await fs.readJson(pkgPath);
|
|
23
|
-
|
|
24
|
-
if (!options?.skipAppScripts) {
|
|
25
|
-
pkg.scripts = {
|
|
26
|
-
...pkg.scripts,
|
|
27
|
-
deploy: "alchemy deploy",
|
|
28
|
-
destroy: "alchemy destroy",
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const viteConfigPath = path.join(webAppDir, "vite.config.ts");
|
|
36
|
-
if (await fs.pathExists(viteConfigPath)) {
|
|
37
|
-
try {
|
|
38
|
-
const project = new Project({
|
|
39
|
-
manipulationSettings: {
|
|
40
|
-
indentationText: IndentationText.TwoSpaces,
|
|
41
|
-
quoteKind: QuoteKind.Double,
|
|
42
|
-
},
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
project.addSourceFileAtPath(viteConfigPath);
|
|
46
|
-
const sourceFile = project.getSourceFileOrThrow(viteConfigPath);
|
|
47
|
-
|
|
48
|
-
const alchemyImport = sourceFile.getImportDeclaration("alchemy/cloudflare/tanstack-start");
|
|
49
|
-
if (!alchemyImport) {
|
|
50
|
-
sourceFile.addImportDeclaration({
|
|
51
|
-
moduleSpecifier: "alchemy/cloudflare/tanstack-start",
|
|
52
|
-
defaultImport: "alchemy",
|
|
53
|
-
});
|
|
54
|
-
} else {
|
|
55
|
-
alchemyImport.setModuleSpecifier("alchemy/cloudflare/tanstack-start");
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const exportAssignment = sourceFile.getExportAssignment((d) => !d.isExportEquals());
|
|
59
|
-
if (!exportAssignment) return;
|
|
60
|
-
|
|
61
|
-
const defineConfigCall = exportAssignment.getExpression();
|
|
62
|
-
if (
|
|
63
|
-
!Node.isCallExpression(defineConfigCall) ||
|
|
64
|
-
defineConfigCall.getExpression().getText() !== "defineConfig"
|
|
65
|
-
)
|
|
66
|
-
return;
|
|
67
|
-
|
|
68
|
-
let configObject = defineConfigCall.getArguments()[0];
|
|
69
|
-
if (!configObject) {
|
|
70
|
-
configObject = defineConfigCall.addArgument("{}");
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (Node.isObjectLiteralExpression(configObject)) {
|
|
74
|
-
const pluginsProperty = configObject.getProperty("plugins");
|
|
75
|
-
if (pluginsProperty && Node.isPropertyAssignment(pluginsProperty)) {
|
|
76
|
-
const initializer = pluginsProperty.getInitializer();
|
|
77
|
-
if (Node.isArrayLiteralExpression(initializer)) {
|
|
78
|
-
const hasAlchemy = initializer
|
|
79
|
-
.getElements()
|
|
80
|
-
.some((el) => el.getText().includes("alchemy("));
|
|
81
|
-
if (!hasAlchemy) {
|
|
82
|
-
initializer.addElement("alchemy()");
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
} else {
|
|
86
|
-
configObject.addPropertyAssignment({
|
|
87
|
-
name: "plugins",
|
|
88
|
-
initializer: "[alchemy()]",
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
await project.save();
|
|
94
|
-
} catch (error) {
|
|
95
|
-
console.warn("Failed to update vite.config.ts:", error);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import fs from "fs-extra";
|
|
3
|
-
import { Project } from "ts-morph";
|
|
4
|
-
import type { ProjectConfig } from "../../../types";
|
|
5
|
-
|
|
6
|
-
const tsProject = new Project({
|
|
7
|
-
useInMemoryFileSystem: false,
|
|
8
|
-
skipAddingFilesFromTsConfig: true,
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
function determineImportPath(
|
|
12
|
-
envDtsPath: string,
|
|
13
|
-
projectDir: string,
|
|
14
|
-
config: ProjectConfig,
|
|
15
|
-
): string {
|
|
16
|
-
const { webDeploy, serverDeploy, backend } = config;
|
|
17
|
-
const isBackendSelf = backend === "self";
|
|
18
|
-
|
|
19
|
-
let alchemyRunPath: string;
|
|
20
|
-
|
|
21
|
-
if (webDeploy === "alchemy" && (serverDeploy === "alchemy" || isBackendSelf)) {
|
|
22
|
-
// Both web and server are alchemy, or web + backend=self
|
|
23
|
-
if (isBackendSelf) {
|
|
24
|
-
alchemyRunPath = path.join(projectDir, "apps/web/alchemy.run.ts");
|
|
25
|
-
} else {
|
|
26
|
-
alchemyRunPath = path.join(projectDir, "alchemy.run.ts");
|
|
27
|
-
}
|
|
28
|
-
} else if (webDeploy === "alchemy") {
|
|
29
|
-
// Only web is alchemy
|
|
30
|
-
alchemyRunPath = path.join(projectDir, "apps/web/alchemy.run.ts");
|
|
31
|
-
} else if (serverDeploy === "alchemy") {
|
|
32
|
-
// Only server is alchemy
|
|
33
|
-
alchemyRunPath = path.join(projectDir, "apps/server/alchemy.run.ts");
|
|
34
|
-
} else {
|
|
35
|
-
// Should not happen, but fallback
|
|
36
|
-
alchemyRunPath = path.join(projectDir, "alchemy.run.ts");
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Calculate relative path from env.d.ts to alchemy.run.ts
|
|
40
|
-
const relativePath = path.relative(path.dirname(envDtsPath), alchemyRunPath.replace(/\.ts$/, ""));
|
|
41
|
-
|
|
42
|
-
// Normalize the path for imports (use forward slashes, handle relative paths)
|
|
43
|
-
const importPath = relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
|
|
44
|
-
|
|
45
|
-
return importPath.replace(/\\/g, "/");
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export async function setupEnvDtsImport(
|
|
49
|
-
envDtsPath: string,
|
|
50
|
-
projectDir: string,
|
|
51
|
-
config: ProjectConfig,
|
|
52
|
-
) {
|
|
53
|
-
if (!(await fs.pathExists(envDtsPath))) {
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const importPath = determineImportPath(envDtsPath, projectDir, config);
|
|
58
|
-
|
|
59
|
-
const sourceFile = tsProject.addSourceFileAtPath(envDtsPath);
|
|
60
|
-
|
|
61
|
-
const existingImports = sourceFile.getImportDeclarations();
|
|
62
|
-
const alreadyHasImport = existingImports.some(
|
|
63
|
-
(imp) =>
|
|
64
|
-
imp.getModuleSpecifierValue() === importPath &&
|
|
65
|
-
imp.getNamedImports().some((named) => named.getName() === "server"),
|
|
66
|
-
);
|
|
67
|
-
|
|
68
|
-
if (!alreadyHasImport) {
|
|
69
|
-
sourceFile.insertImportDeclaration(0, {
|
|
70
|
-
moduleSpecifier: importPath,
|
|
71
|
-
namedImports: [{ name: "server", isTypeOnly: true }],
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
await sourceFile.save();
|
|
76
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export { setupNextAlchemyDeploy } from "./alchemy-next-setup";
|
|
2
|
-
export { setupNuxtAlchemyDeploy } from "./alchemy-nuxt-setup";
|
|
3
|
-
export { setupReactRouterAlchemyDeploy } from "./alchemy-react-router-setup";
|
|
4
|
-
export { setupSolidAlchemyDeploy } from "./alchemy-solid-setup";
|
|
5
|
-
export { setupSvelteAlchemyDeploy } from "./alchemy-svelte-setup";
|
|
6
|
-
export { setupTanStackRouterAlchemyDeploy } from "./alchemy-tanstack-router-setup";
|
|
7
|
-
export { setupTanStackStartAlchemyDeploy } from "./alchemy-tanstack-start-setup";
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import fs from "fs-extra";
|
|
3
|
-
import type { ProjectConfig } from "../../types";
|
|
4
|
-
import { addPackageDependency } from "../../utils/add-package-deps";
|
|
5
|
-
|
|
6
|
-
export async function setupServerDeploy(config: ProjectConfig) {
|
|
7
|
-
const { serverDeploy, webDeploy, projectDir } = config;
|
|
8
|
-
|
|
9
|
-
if (serverDeploy === "none") return;
|
|
10
|
-
|
|
11
|
-
if (serverDeploy === "alchemy" && webDeploy === "alchemy") {
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const serverDir = path.join(projectDir, "apps/server");
|
|
16
|
-
if (!(await fs.pathExists(serverDir))) return;
|
|
17
|
-
|
|
18
|
-
if (serverDeploy === "alchemy") {
|
|
19
|
-
await setupAlchemyServerDeploy(serverDir, projectDir);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export async function setupAlchemyServerDeploy(serverDir: string, projectDir?: string) {
|
|
24
|
-
if (!(await fs.pathExists(serverDir))) return;
|
|
25
|
-
|
|
26
|
-
await addPackageDependency({
|
|
27
|
-
devDependencies: ["alchemy", "wrangler", "@types/node", "@cloudflare/workers-types"],
|
|
28
|
-
projectDir: serverDir,
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
if (projectDir) {
|
|
32
|
-
await addAlchemyPackagesDependencies(projectDir);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const packageJsonPath = path.join(serverDir, "package.json");
|
|
36
|
-
if (await fs.pathExists(packageJsonPath)) {
|
|
37
|
-
const packageJson = await fs.readJson(packageJsonPath);
|
|
38
|
-
|
|
39
|
-
packageJson.scripts = {
|
|
40
|
-
...packageJson.scripts,
|
|
41
|
-
dev: "alchemy dev",
|
|
42
|
-
deploy: "alchemy deploy",
|
|
43
|
-
destroy: "alchemy destroy",
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async function addAlchemyPackagesDependencies(projectDir: string) {
|
|
51
|
-
await addPackageDependency({
|
|
52
|
-
devDependencies: ["@cloudflare/workers-types"],
|
|
53
|
-
projectDir,
|
|
54
|
-
});
|
|
55
|
-
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import type { ProjectConfig } from "../../types";
|
|
2
|
-
import { addPackageDependency } from "../../utils/add-package-deps";
|
|
3
|
-
import { setupCombinedAlchemyDeploy } from "./alchemy/alchemy-combined-setup";
|
|
4
|
-
import { setupNextAlchemyDeploy } from "./alchemy/alchemy-next-setup";
|
|
5
|
-
import { setupNuxtAlchemyDeploy } from "./alchemy/alchemy-nuxt-setup";
|
|
6
|
-
import { setupReactRouterAlchemyDeploy } from "./alchemy/alchemy-react-router-setup";
|
|
7
|
-
import { setupSolidAlchemyDeploy } from "./alchemy/alchemy-solid-setup";
|
|
8
|
-
import { setupSvelteAlchemyDeploy } from "./alchemy/alchemy-svelte-setup";
|
|
9
|
-
import { setupTanStackRouterAlchemyDeploy } from "./alchemy/alchemy-tanstack-router-setup";
|
|
10
|
-
import { setupTanStackStartAlchemyDeploy } from "./alchemy/alchemy-tanstack-start-setup";
|
|
11
|
-
|
|
12
|
-
export async function setupWebDeploy(config: ProjectConfig) {
|
|
13
|
-
const { webDeploy, serverDeploy, frontend, projectDir } = config;
|
|
14
|
-
const { packageManager } = config;
|
|
15
|
-
|
|
16
|
-
if (webDeploy === "none") return;
|
|
17
|
-
|
|
18
|
-
if (webDeploy !== "alchemy") return;
|
|
19
|
-
|
|
20
|
-
if (webDeploy === "alchemy" && serverDeploy === "alchemy") {
|
|
21
|
-
await setupCombinedAlchemyDeploy(projectDir, packageManager, config);
|
|
22
|
-
await addAlchemyPackagesDependencies(projectDir);
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const isNext = frontend.includes("next");
|
|
27
|
-
const isNuxt = frontend.includes("nuxt");
|
|
28
|
-
const isSvelte = frontend.includes("svelte");
|
|
29
|
-
const isTanstackRouter = frontend.includes("tanstack-router");
|
|
30
|
-
const isTanstackStart = frontend.includes("tanstack-start");
|
|
31
|
-
const isReactRouter = frontend.includes("react-router");
|
|
32
|
-
const isSolid = frontend.includes("solid");
|
|
33
|
-
|
|
34
|
-
if (isNext) {
|
|
35
|
-
await setupNextAlchemyDeploy(projectDir, packageManager);
|
|
36
|
-
} else if (isNuxt) {
|
|
37
|
-
await setupNuxtAlchemyDeploy(projectDir, packageManager);
|
|
38
|
-
} else if (isSvelte) {
|
|
39
|
-
await setupSvelteAlchemyDeploy(projectDir, packageManager);
|
|
40
|
-
} else if (isTanstackStart) {
|
|
41
|
-
await setupTanStackStartAlchemyDeploy(projectDir, packageManager);
|
|
42
|
-
} else if (isTanstackRouter) {
|
|
43
|
-
await setupTanStackRouterAlchemyDeploy(projectDir, packageManager);
|
|
44
|
-
} else if (isReactRouter) {
|
|
45
|
-
await setupReactRouterAlchemyDeploy(projectDir, packageManager);
|
|
46
|
-
} else if (isSolid) {
|
|
47
|
-
await setupSolidAlchemyDeploy(projectDir, packageManager);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
await addAlchemyPackagesDependencies(projectDir);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async function addAlchemyPackagesDependencies(projectDir: string) {
|
|
54
|
-
await addPackageDependency({
|
|
55
|
-
devDependencies: ["@cloudflare/workers-types"],
|
|
56
|
-
projectDir,
|
|
57
|
-
});
|
|
58
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
import { intro, log } from "@clack/prompts";
|
|
2
|
-
import { createRouterClient, os } from "@orpc/server";
|
|
3
|
-
import pc from "picocolors";
|
|
4
|
-
import { createCli } from "trpc-cli";
|
|
5
|
-
import z from "zod";
|
|
6
|
-
import { addAddonsHandler, createProjectHandler } from "./helpers/core/command-handlers";
|
|
7
|
-
import {
|
|
8
|
-
type AddInput,
|
|
9
|
-
type Addons,
|
|
10
|
-
AddonsSchema,
|
|
11
|
-
type API,
|
|
12
|
-
APISchema,
|
|
13
|
-
AuthSchema,
|
|
14
|
-
type Backend,
|
|
15
|
-
BackendSchema,
|
|
16
|
-
type BetterTStackConfig,
|
|
17
|
-
type CreateInput,
|
|
18
|
-
type Database,
|
|
19
|
-
DatabaseSchema,
|
|
20
|
-
type DatabaseSetup,
|
|
21
|
-
DatabaseSetupSchema,
|
|
22
|
-
type DirectoryConflict,
|
|
23
|
-
DirectoryConflictSchema,
|
|
24
|
-
type Examples,
|
|
25
|
-
ExamplesSchema,
|
|
26
|
-
type Frontend,
|
|
27
|
-
FrontendSchema,
|
|
28
|
-
type InitResult,
|
|
29
|
-
type ORM,
|
|
30
|
-
ORMSchema,
|
|
31
|
-
type PackageManager,
|
|
32
|
-
PackageManagerSchema,
|
|
33
|
-
PaymentsSchema,
|
|
34
|
-
type ProjectConfig,
|
|
35
|
-
ProjectNameSchema,
|
|
36
|
-
type Runtime,
|
|
37
|
-
RuntimeSchema,
|
|
38
|
-
type ServerDeploy,
|
|
39
|
-
ServerDeploySchema,
|
|
40
|
-
type Template,
|
|
41
|
-
TemplateSchema,
|
|
42
|
-
type WebDeploy,
|
|
43
|
-
WebDeploySchema,
|
|
44
|
-
} from "./types";
|
|
45
|
-
import { handleError } from "./utils/errors";
|
|
46
|
-
import { getLatestCLIVersion } from "./utils/get-latest-cli-version";
|
|
47
|
-
import { openUrl } from "./utils/open-url";
|
|
48
|
-
import { renderTitle } from "./utils/render-title";
|
|
49
|
-
import { displaySponsors, fetchSponsors } from "./utils/sponsors";
|
|
50
|
-
|
|
51
|
-
export const router = os.router({
|
|
52
|
-
init: os
|
|
53
|
-
.meta({
|
|
54
|
-
description: "Create a new Better-T-Stack project",
|
|
55
|
-
default: true,
|
|
56
|
-
negateBooleans: true,
|
|
57
|
-
})
|
|
58
|
-
.input(
|
|
59
|
-
z.tuple([
|
|
60
|
-
ProjectNameSchema.optional(),
|
|
61
|
-
z.object({
|
|
62
|
-
template: TemplateSchema.optional().describe("Use a predefined template"),
|
|
63
|
-
yes: z.boolean().optional().default(false).describe("Use default configuration"),
|
|
64
|
-
yolo: z
|
|
65
|
-
.boolean()
|
|
66
|
-
.optional()
|
|
67
|
-
.default(false)
|
|
68
|
-
.describe("(WARNING - NOT RECOMMENDED) Bypass validations and compatibility checks"),
|
|
69
|
-
verbose: z
|
|
70
|
-
.boolean()
|
|
71
|
-
.optional()
|
|
72
|
-
.default(false)
|
|
73
|
-
.describe("Show detailed result information"),
|
|
74
|
-
database: DatabaseSchema.optional(),
|
|
75
|
-
orm: ORMSchema.optional(),
|
|
76
|
-
auth: AuthSchema.optional(),
|
|
77
|
-
payments: PaymentsSchema.optional(),
|
|
78
|
-
frontend: z.array(FrontendSchema).optional(),
|
|
79
|
-
addons: z.array(AddonsSchema).optional(),
|
|
80
|
-
examples: z.array(ExamplesSchema).optional(),
|
|
81
|
-
git: z.boolean().optional(),
|
|
82
|
-
packageManager: PackageManagerSchema.optional(),
|
|
83
|
-
install: z.boolean().optional(),
|
|
84
|
-
dbSetup: DatabaseSetupSchema.optional(),
|
|
85
|
-
backend: BackendSchema.optional(),
|
|
86
|
-
runtime: RuntimeSchema.optional(),
|
|
87
|
-
api: APISchema.optional(),
|
|
88
|
-
webDeploy: WebDeploySchema.optional(),
|
|
89
|
-
serverDeploy: ServerDeploySchema.optional(),
|
|
90
|
-
directoryConflict: DirectoryConflictSchema.optional(),
|
|
91
|
-
renderTitle: z.boolean().optional(),
|
|
92
|
-
disableAnalytics: z.boolean().optional().default(false).describe("Disable analytics"),
|
|
93
|
-
manualDb: z
|
|
94
|
-
.boolean()
|
|
95
|
-
.optional()
|
|
96
|
-
.default(false)
|
|
97
|
-
.describe("Skip automatic/manual database setup prompt and use manual setup"),
|
|
98
|
-
}),
|
|
99
|
-
]),
|
|
100
|
-
)
|
|
101
|
-
.handler(async ({ input }) => {
|
|
102
|
-
const [projectName, options] = input;
|
|
103
|
-
const combinedInput = {
|
|
104
|
-
projectName,
|
|
105
|
-
...options,
|
|
106
|
-
};
|
|
107
|
-
const result = await createProjectHandler(combinedInput);
|
|
108
|
-
|
|
109
|
-
if (options.verbose) {
|
|
110
|
-
return result;
|
|
111
|
-
}
|
|
112
|
-
}),
|
|
113
|
-
add: os
|
|
114
|
-
.meta({
|
|
115
|
-
description: "Add addons or deployment configurations to an existing Better-T-Stack project",
|
|
116
|
-
})
|
|
117
|
-
.input(
|
|
118
|
-
z.tuple([
|
|
119
|
-
z.object({
|
|
120
|
-
addons: z.array(AddonsSchema).optional().default([]),
|
|
121
|
-
webDeploy: WebDeploySchema.optional(),
|
|
122
|
-
serverDeploy: ServerDeploySchema.optional(),
|
|
123
|
-
projectDir: z.string().optional(),
|
|
124
|
-
install: z
|
|
125
|
-
.boolean()
|
|
126
|
-
.optional()
|
|
127
|
-
.default(false)
|
|
128
|
-
.describe("Install dependencies after adding addons or deployment"),
|
|
129
|
-
packageManager: PackageManagerSchema.optional(),
|
|
130
|
-
}),
|
|
131
|
-
]),
|
|
132
|
-
)
|
|
133
|
-
.handler(async ({ input }) => {
|
|
134
|
-
const [options] = input;
|
|
135
|
-
await addAddonsHandler(options);
|
|
136
|
-
}),
|
|
137
|
-
sponsors: os.meta({ description: "Show Better-T-Stack sponsors" }).handler(async () => {
|
|
138
|
-
try {
|
|
139
|
-
renderTitle();
|
|
140
|
-
intro(pc.magenta("Better-T-Stack Sponsors"));
|
|
141
|
-
const sponsors = await fetchSponsors();
|
|
142
|
-
displaySponsors(sponsors);
|
|
143
|
-
} catch (error) {
|
|
144
|
-
handleError(error, "Failed to display sponsors");
|
|
145
|
-
}
|
|
146
|
-
}),
|
|
147
|
-
docs: os.meta({ description: "Open Better-T-Stack documentation" }).handler(async () => {
|
|
148
|
-
const DOCS_URL = "https://better-t-stack.dev/docs";
|
|
149
|
-
try {
|
|
150
|
-
await openUrl(DOCS_URL);
|
|
151
|
-
log.success(pc.blue("Opened docs in your default browser."));
|
|
152
|
-
} catch {
|
|
153
|
-
log.message(`Please visit ${DOCS_URL}`);
|
|
154
|
-
}
|
|
155
|
-
}),
|
|
156
|
-
builder: os.meta({ description: "Open the web-based stack builder" }).handler(async () => {
|
|
157
|
-
const BUILDER_URL = "https://better-t-stack.dev/new";
|
|
158
|
-
try {
|
|
159
|
-
await openUrl(BUILDER_URL);
|
|
160
|
-
log.success(pc.blue("Opened builder in your default browser."));
|
|
161
|
-
} catch {
|
|
162
|
-
log.message(`Please visit ${BUILDER_URL}`);
|
|
163
|
-
}
|
|
164
|
-
}),
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
const caller = createRouterClient(router, { context: {} });
|
|
168
|
-
|
|
169
|
-
export function createBtsCli() {
|
|
170
|
-
return createCli({
|
|
171
|
-
router,
|
|
172
|
-
name: "create-better-t-stack",
|
|
173
|
-
version: getLatestCLIVersion(),
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Initialize a new Better-T-Stack project
|
|
179
|
-
*
|
|
180
|
-
* @example CLI usage:
|
|
181
|
-
* ```bash
|
|
182
|
-
* npx create-better-t-stack my-app --yes
|
|
183
|
-
* ```
|
|
184
|
-
*
|
|
185
|
-
* @example Programmatic usage (always returns structured data):
|
|
186
|
-
* ```typescript
|
|
187
|
-
* import { init } from "create-better-t-stack";
|
|
188
|
-
*
|
|
189
|
-
* const result = await init("my-app", {
|
|
190
|
-
* yes: true,
|
|
191
|
-
* frontend: ["tanstack-router"],
|
|
192
|
-
* backend: "hono",
|
|
193
|
-
* database: "sqlite",
|
|
194
|
-
* orm: "drizzle",
|
|
195
|
-
* auth: "better-auth",
|
|
196
|
-
* addons: ["biome", "turborepo"],
|
|
197
|
-
* packageManager: "bun",
|
|
198
|
-
* install: false,
|
|
199
|
-
* directoryConflict: "increment", // auto-handle conflicts
|
|
200
|
-
* disableAnalytics: true, // disable analytics
|
|
201
|
-
* });
|
|
202
|
-
*
|
|
203
|
-
* if (result.success) {
|
|
204
|
-
* console.log(`Project created at: ${result.projectDirectory}`);
|
|
205
|
-
* console.log(`Reproducible command: ${result.reproducibleCommand}`);
|
|
206
|
-
* console.log(`Time taken: ${result.elapsedTimeMs}ms`);
|
|
207
|
-
* }
|
|
208
|
-
* ```
|
|
209
|
-
*/
|
|
210
|
-
export async function init(projectName?: string, options?: CreateInput) {
|
|
211
|
-
const opts = (options ?? {}) as CreateInput;
|
|
212
|
-
const programmaticOpts = { ...opts, verbose: true };
|
|
213
|
-
const prev = process.env.BTS_PROGRAMMATIC;
|
|
214
|
-
process.env.BTS_PROGRAMMATIC = "1";
|
|
215
|
-
const result = await caller.init([projectName, programmaticOpts]);
|
|
216
|
-
if (prev === undefined) delete process.env.BTS_PROGRAMMATIC;
|
|
217
|
-
else process.env.BTS_PROGRAMMATIC = prev;
|
|
218
|
-
return result as InitResult;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
export async function sponsors() {
|
|
222
|
-
return caller.sponsors();
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
export async function docs() {
|
|
226
|
-
return caller.docs();
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
export async function builder() {
|
|
230
|
-
return caller.builder();
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
export type {
|
|
234
|
-
Database,
|
|
235
|
-
ORM,
|
|
236
|
-
Backend,
|
|
237
|
-
Runtime,
|
|
238
|
-
Frontend,
|
|
239
|
-
Addons,
|
|
240
|
-
Examples,
|
|
241
|
-
PackageManager,
|
|
242
|
-
DatabaseSetup,
|
|
243
|
-
API,
|
|
244
|
-
WebDeploy,
|
|
245
|
-
ServerDeploy,
|
|
246
|
-
DirectoryConflict,
|
|
247
|
-
Template,
|
|
248
|
-
CreateInput,
|
|
249
|
-
AddInput,
|
|
250
|
-
ProjectConfig,
|
|
251
|
-
BetterTStackConfig,
|
|
252
|
-
InitResult,
|
|
253
|
-
};
|