create-vitnode-app 1.2.0-canary.9 → 2.0.0-canary.2
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/LICENSE.md +1 -1
- package/README.md +58 -18
- package/copy-of-vitnode-app/.vscode/settings.json +10 -0
- package/copy-of-vitnode-app/README.md +62 -0
- package/copy-of-vitnode-app/api/.gitignore_template +32 -0
- package/copy-of-vitnode-app/api/drizzle.config.ts +12 -0
- package/copy-of-vitnode-app/api/src/index.ts +27 -0
- package/copy-of-vitnode-app/api/src/vitnode.api.config.ts +57 -0
- package/copy-of-vitnode-app/api/tsconfig.json +17 -0
- package/copy-of-vitnode-app/api-bun/src/index.ts +16 -0
- package/copy-of-vitnode-app/api-single-app/drizzle.config.ts +12 -0
- package/copy-of-vitnode-app/api-single-app/src/routes/api/$.ts +32 -0
- package/copy-of-vitnode-app/api-single-app/src/server/api-bridge.ts +22 -0
- package/copy-of-vitnode-app/api-single-app/src/server/vitnode-api.server.ts +29 -0
- package/copy-of-vitnode-app/api-single-app/src/vitnode.api.config.ts +36 -0
- package/copy-of-vitnode-app/docker/docker-compose.yml +30 -0
- package/copy-of-vitnode-app/eslint/.prettierrc.mjs +1 -1
- package/copy-of-vitnode-app/eslint/eslint.config.mjs +18 -2
- package/copy-of-vitnode-app/{root → eslint-react}/.prettierrc.mjs +1 -1
- package/copy-of-vitnode-app/eslint-react/eslint.config.mjs +19 -0
- package/copy-of-vitnode-app/monorepo/.gitignore_template +41 -0
- package/copy-of-vitnode-app/monorepo/apps/api/.env.example +12 -0
- package/copy-of-vitnode-app/monorepo/apps/web/.env.example +12 -0
- package/copy-of-vitnode-app/monorepo/turbo.json +53 -0
- package/copy-of-vitnode-app/root/.env.example +16 -5
- package/copy-of-vitnode-app/root/.gitignore_template +41 -0
- package/copy-of-vitnode-app/root/global.d.ts +28 -0
- package/copy-of-vitnode-app/root/src/components/admin-shell.tsx +72 -0
- package/copy-of-vitnode-app/root/src/components/main-header.tsx +33 -0
- package/copy-of-vitnode-app/root/src/lib/admin-auth.ts +11 -0
- package/copy-of-vitnode-app/root/src/lib/admin-nav.ts +43 -0
- package/copy-of-vitnode-app/root/src/lib/admin-search.ts +37 -0
- package/copy-of-vitnode-app/root/src/lib/auth.ts +66 -0
- package/copy-of-vitnode-app/root/src/lib/content-registry.ts +52 -0
- package/copy-of-vitnode-app/root/src/lib/i18n/runtime.ts +75 -0
- package/copy-of-vitnode-app/root/src/lib/i18n/shared.ts +20 -0
- package/copy-of-vitnode-app/root/src/lib/navigation.ts +24 -0
- package/copy-of-vitnode-app/root/src/lib/page-head.ts +19 -0
- package/copy-of-vitnode-app/root/src/locales/app.ts +28 -0
- package/copy-of-vitnode-app/root/src/locales/packages.ts +43 -0
- package/copy-of-vitnode-app/root/src/router.tsx +227 -0
- package/copy-of-vitnode-app/root/src/routes/__root.tsx +212 -0
- package/copy-of-vitnode-app/root/src/routes/_admin/admin.core.index.tsx +69 -0
- package/copy-of-vitnode-app/root/src/routes/_admin.tsx +258 -0
- package/copy-of-vitnode-app/root/src/routes/_main/index.tsx +60 -0
- package/copy-of-vitnode-app/root/src/routes/_main.tsx +64 -0
- package/copy-of-vitnode-app/root/src/server/messages.server.ts +21 -0
- package/copy-of-vitnode-app/root/src/start.ts +24 -0
- package/copy-of-vitnode-app/root/src/styles.css +139 -0
- package/copy-of-vitnode-app/root/src/vitnode.config.ts +73 -0
- package/copy-of-vitnode-app/root/src/vitnode.server.config.ts +23 -0
- package/copy-of-vitnode-app/root/tsconfig.json +24 -16
- package/copy-of-vitnode-app/root/tsr.config.json +3 -0
- package/copy-of-vitnode-app/root/vite.config.ts +106 -0
- package/copy-of-vitnode-plugin/root/.swcrc +26 -0
- package/copy-of-vitnode-plugin/root/global.d.ts +21 -0
- package/copy-of-vitnode-plugin/root/npmignore.template +17 -0
- package/copy-of-vitnode-plugin/root/tsconfig.build.json +5 -0
- package/copy-of-vitnode-plugin/root/tsconfig.json +25 -0
- package/dist/src/create/create-package-json.js +266 -56
- package/dist/src/create/create-vitnode.js +177 -28
- package/dist/src/create/package-versions.js +49 -0
- package/dist/src/helpers/get-available-package-managers.js +6 -6
- package/dist/src/helpers/get-package-json.js +2 -2
- package/dist/src/helpers/get-package-manager-from-root.js +15 -0
- package/dist/src/helpers/get-vitnode-package-version.js +9 -0
- package/dist/src/helpers/init-vitnode.js +34 -0
- package/dist/src/helpers/install-dependencies.js +55 -14
- package/dist/src/helpers/is-folder-empty.js +25 -26
- package/dist/src/helpers/is-online.js +16 -16
- package/dist/src/helpers/is-writeable.js +3 -3
- package/dist/src/helpers/validate-pkg.js +1 -1
- package/dist/src/helpers/with-If.js +1 -0
- package/dist/src/index.js +29 -26
- package/dist/src/plugin/create/add-plugin-to-workspace.js +74 -0
- package/dist/src/plugin/create/create-package-json.js +54 -0
- package/dist/src/plugin/create/create-plugin-vitnode.js +80 -0
- package/dist/src/plugin/create/route-templates.js +144 -0
- package/dist/src/plugin/index.js +17 -6
- package/dist/src/plugin/questions.js +14 -0
- package/dist/src/plugin/validation.js +76 -0
- package/dist/src/prepare/prepare.js +11 -8
- package/dist/src/questions.js +52 -15
- package/dist/src/validation.js +15 -15
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/package.json +22 -12
- package/copy-of-vitnode-app/root/README.md +0 -1
- package/copy-of-vitnode-app/root/drizzle.config.ts +0 -12
- package/copy-of-vitnode-app/root/gitignore_template +0 -43
- package/copy-of-vitnode-app/root/next.config.ts +0 -11
- package/copy-of-vitnode-app/root/postcss.config.mjs +0 -8
- package/copy-of-vitnode-app/root/src/app/[locale]/(main)/[...rest]/page.tsx +0 -5
- package/copy-of-vitnode-app/root/src/app/[locale]/(main)/layout.tsx +0 -10
- package/copy-of-vitnode-app/root/src/app/[locale]/(main)/not-found.tsx +0 -5
- package/copy-of-vitnode-app/root/src/app/[locale]/(main)/page.tsx +0 -113
- package/copy-of-vitnode-app/root/src/app/[locale]/admin/(auth)/layout.tsx +0 -10
- package/copy-of-vitnode-app/root/src/app/[locale]/admin/not-found.tsx +0 -5
- package/copy-of-vitnode-app/root/src/app/[locale]/admin/page.tsx +0 -5
- package/copy-of-vitnode-app/root/src/app/[locale]/layout.tsx +0 -36
- package/copy-of-vitnode-app/root/src/app/api/[...route]/route.ts +0 -18
- package/copy-of-vitnode-app/root/src/app/favicon.ico +0 -0
- package/copy-of-vitnode-app/root/src/app/global-error.tsx +0 -27
- package/copy-of-vitnode-app/root/src/app/global.css +0 -128
- package/copy-of-vitnode-app/root/src/app/layout.tsx +0 -9
- package/copy-of-vitnode-app/root/src/app/not-found.tsx +0 -13
- package/copy-of-vitnode-app/root/src/vitnode.api.config.ts +0 -5
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -1,55 +1,204 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import color from
|
|
7
|
-
import {
|
|
8
|
-
import { installDependencies } from
|
|
9
|
-
import { isFolderEmpty } from
|
|
10
|
-
import { createPackageJSON } from
|
|
11
|
-
export const createVitNode = async ({ root, appName, packageManager, eslint, install, }) => {
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { copyFile, cp, mkdir, readFile, rename, writeFile, } from "node:fs/promises";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import ora from "ora";
|
|
6
|
+
import color from "picocolors";
|
|
7
|
+
import { generateMigrationsVitnode } from "../helpers/init-vitnode.js";
|
|
8
|
+
import { installDependencies } from "../helpers/install-dependencies.js";
|
|
9
|
+
import { isFolderEmpty } from "../helpers/is-folder-empty.js";
|
|
10
|
+
import { createPackageJSON } from "./create-package-json.js";
|
|
11
|
+
export const createVitNode = async ({ root, appName, packageManager, eslint, install, docker, mode, monorepo, }) => {
|
|
12
12
|
const spinner = ora(`Creating a new VitNode app in ${color.green(root)}. Using ${color.green(packageManager)}...`).start();
|
|
13
13
|
const __filename = fileURLToPath(import.meta.url);
|
|
14
14
|
const __dirname = dirname(__filename);
|
|
15
|
-
const templatePath = join(__dirname,
|
|
15
|
+
const templatePath = join(__dirname, "..", "..", "..", "copy-of-vitnode-app");
|
|
16
16
|
if (!existsSync(templatePath)) {
|
|
17
|
-
spinner.fail(`\n${color.red(
|
|
17
|
+
spinner.fail(`\n${color.red("Error!")} Template path ${color.cyan(templatePath)} does not exist.`);
|
|
18
18
|
process.exit(1);
|
|
19
19
|
}
|
|
20
20
|
await mkdir(root, { recursive: true });
|
|
21
21
|
if (!isFolderEmpty(root, appName)) {
|
|
22
22
|
process.exit(1);
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
const monorepoStructure = {
|
|
25
|
+
api: join(root, "apps", "api"),
|
|
26
|
+
web: join(root, "apps", "web"),
|
|
27
|
+
};
|
|
28
|
+
spinner.text = "Preparing the project structure...";
|
|
29
|
+
if (monorepo || mode === "apiMonorepo") {
|
|
30
|
+
monorepo = true;
|
|
31
|
+
const dirsToCreate = [];
|
|
32
|
+
if (mode === "apiMonorepo" || (monorepo && mode === "onlyApi")) {
|
|
33
|
+
dirsToCreate.push(monorepoStructure.api);
|
|
34
|
+
}
|
|
35
|
+
if (mode === "apiMonorepo" || (monorepo && mode === "singleApp")) {
|
|
36
|
+
dirsToCreate.push(monorepoStructure.web);
|
|
37
|
+
}
|
|
38
|
+
await Promise.all(dirsToCreate.map(async (dir) => mkdir(dir, { recursive: true })));
|
|
39
|
+
}
|
|
40
|
+
spinner.text = "Copying files...";
|
|
41
|
+
await cp(join(templatePath, ".vscode"), join(root, ".vscode"), {
|
|
26
42
|
recursive: true,
|
|
27
43
|
});
|
|
28
|
-
if (
|
|
29
|
-
|
|
30
|
-
await cp(join(templatePath,
|
|
44
|
+
if (mode === "singleApp") {
|
|
45
|
+
const destination = monorepo ? monorepoStructure.web : root;
|
|
46
|
+
await cp(join(templatePath, "root"), destination, { recursive: true });
|
|
47
|
+
await cp(join(templatePath, "api-single-app"), destination, {
|
|
48
|
+
recursive: true,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
else if (mode === "apiMonorepo") {
|
|
52
|
+
await Promise.all([
|
|
53
|
+
cp(join(templatePath, "root"), monorepoStructure.web, {
|
|
54
|
+
recursive: true,
|
|
55
|
+
}),
|
|
56
|
+
cp(join(templatePath, "api"), monorepoStructure.api, {
|
|
57
|
+
recursive: true,
|
|
58
|
+
}),
|
|
59
|
+
]);
|
|
60
|
+
if (packageManager === "bun") {
|
|
61
|
+
await cp(join(templatePath, "api-bun"), monorepoStructure.api, {
|
|
62
|
+
recursive: true,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else if (mode === "onlyApi") {
|
|
67
|
+
await cp(join(templatePath, "api"), monorepo ? monorepoStructure.api : root, {
|
|
68
|
+
recursive: true,
|
|
69
|
+
});
|
|
70
|
+
if (packageManager === "bun") {
|
|
71
|
+
await cp(join(templatePath, "api-bun"), monorepo ? monorepoStructure.api : root, {
|
|
72
|
+
recursive: true,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (mode === "apiMonorepo" || (monorepo && mode !== "singleApp")) {
|
|
77
|
+
await cp(join(templatePath, "monorepo"), root, {
|
|
31
78
|
recursive: true,
|
|
32
79
|
});
|
|
33
80
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
81
|
+
else if (monorepo && mode === "singleApp") {
|
|
82
|
+
await copyFile(join(templatePath, "monorepo", "turbo.json"), join(root, "turbo.json"));
|
|
83
|
+
await copyFile(join(templatePath, "monorepo", ".gitignore_template"), join(root, ".gitignore_template"));
|
|
84
|
+
}
|
|
85
|
+
if (eslint) {
|
|
86
|
+
spinner.text = "Copying ESLint & Prettier files...";
|
|
87
|
+
if (monorepo) {
|
|
88
|
+
if (existsSync(monorepoStructure.api)) {
|
|
89
|
+
await cp(join(templatePath, "eslint"), monorepoStructure.api, {
|
|
90
|
+
recursive: true,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
if (existsSync(monorepoStructure.web)) {
|
|
94
|
+
await cp(join(templatePath, "eslint-react"), monorepoStructure.web, {
|
|
95
|
+
recursive: true,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
if (mode === "onlyApi") {
|
|
101
|
+
await cp(join(templatePath, "eslint"), root, {
|
|
102
|
+
recursive: true,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
else if (mode === "singleApp") {
|
|
106
|
+
await cp(join(templatePath, "eslint-react"), root, {
|
|
107
|
+
recursive: true,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
spinner.text = "Renaming special files...";
|
|
113
|
+
await rename(join(root, ".gitignore_template"), join(root, ".gitignore"));
|
|
114
|
+
if (mode === "apiMonorepo" || monorepo) {
|
|
115
|
+
if (existsSync(join(monorepoStructure.api, ".gitignore_template"))) {
|
|
116
|
+
await rename(join(monorepoStructure.api, ".gitignore_template"), join(monorepoStructure.api, ".gitignore"));
|
|
117
|
+
}
|
|
118
|
+
if (existsSync(join(monorepoStructure.web, ".gitignore_template"))) {
|
|
119
|
+
await rename(join(monorepoStructure.web, ".gitignore_template"), join(monorepoStructure.web, ".gitignore"));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
spinner.text = "Creating package.json...";
|
|
37
123
|
await createPackageJSON({
|
|
38
124
|
root,
|
|
39
125
|
appName,
|
|
40
126
|
packageManager,
|
|
41
127
|
eslint,
|
|
128
|
+
docker,
|
|
129
|
+
mode,
|
|
130
|
+
monorepo,
|
|
42
131
|
});
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
132
|
+
if ((mode === "apiMonorepo" || monorepo) && packageManager === "pnpm") {
|
|
133
|
+
spinner.text = "Creating pnpm-workspace.yaml...";
|
|
134
|
+
const pnpmWorkspaceContent = `packages:\n - 'apps/*'\n - 'plugins/*'\n`;
|
|
135
|
+
await writeFile(join(root, "pnpm-workspace.yaml"), pnpmWorkspaceContent);
|
|
136
|
+
}
|
|
137
|
+
if (docker) {
|
|
138
|
+
spinner.text = "Copying docker files...";
|
|
139
|
+
await copyFile(join(templatePath, "docker", "docker-compose.yml"), join(root, "docker-compose.yml"));
|
|
140
|
+
const dockerComposePath = join(root, "docker-compose.yml");
|
|
141
|
+
const dockerComposeContent = await readFile(dockerComposePath, "utf-8");
|
|
142
|
+
const updatedContent = dockerComposeContent.replace(/vitnode_postgres_dev/g, `${appName}_vitnode_postgres_dev`);
|
|
143
|
+
await writeFile(dockerComposePath, updatedContent);
|
|
144
|
+
}
|
|
145
|
+
spinner.text = "Updating VitNode paths...";
|
|
146
|
+
if ((mode === "apiMonorepo" || monorepo) &&
|
|
147
|
+
packageManager === "npm" &&
|
|
148
|
+
mode !== "onlyApi") {
|
|
149
|
+
const stylesPath = join(monorepoStructure.web, "src", "styles.css");
|
|
150
|
+
const stylesContent = await readFile(stylesPath, "utf-8");
|
|
151
|
+
await writeFile(stylesPath, stylesContent.replaceAll('@source "../node_modules/@vitnode/', '@source "../../../node_modules/@vitnode/'));
|
|
152
|
+
}
|
|
153
|
+
if (mode === "apiMonorepo") {
|
|
154
|
+
spinner.text = "Setting up environment variables...";
|
|
155
|
+
const envExamplePath = join(monorepoStructure.web, ".env.example");
|
|
156
|
+
if (existsSync(envExamplePath)) {
|
|
157
|
+
await rename(envExamplePath, join(monorepoStructure.web, ".env"));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
48
160
|
if (install) {
|
|
49
|
-
spinner.text =
|
|
161
|
+
spinner.text = "Installing dependencies...";
|
|
50
162
|
await installDependencies({
|
|
51
163
|
packageManager,
|
|
164
|
+
cwd: root,
|
|
52
165
|
});
|
|
166
|
+
spinner.text = "Preparing README...";
|
|
167
|
+
await copyFile(join(templatePath, "README.md"), join(root, "README.md"));
|
|
168
|
+
let readmeContent = await readFile(join(root, "README.md"), "utf-8");
|
|
169
|
+
readmeContent = readmeContent.replaceAll("pnpm", packageManager);
|
|
170
|
+
let startUrlsText = "[http://localhost:3000](http://localhost:3000)";
|
|
171
|
+
if (mode === "onlyApi") {
|
|
172
|
+
startUrlsText = "[http://localhost:8000](http://localhost:8000)";
|
|
173
|
+
}
|
|
174
|
+
else if (mode === "apiMonorepo") {
|
|
175
|
+
startUrlsText =
|
|
176
|
+
"[http://localhost:3000](http://localhost:3000) for the Web app and [http://localhost:8000](http://localhost:8000) for the API";
|
|
177
|
+
}
|
|
178
|
+
readmeContent = readmeContent.replace("{{START_URLS}}", startUrlsText);
|
|
179
|
+
await writeFile(join(root, "README.md"), readmeContent);
|
|
180
|
+
spinner.text = "Generating migrations...";
|
|
181
|
+
let migrationsCwd;
|
|
182
|
+
if (mode === "apiMonorepo" || (monorepo && mode !== "singleApp")) {
|
|
183
|
+
migrationsCwd = monorepoStructure.api;
|
|
184
|
+
}
|
|
185
|
+
else if (mode === "singleApp" && monorepo) {
|
|
186
|
+
migrationsCwd = monorepoStructure.web;
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
migrationsCwd = root;
|
|
190
|
+
}
|
|
191
|
+
try {
|
|
192
|
+
await generateMigrationsVitnode({
|
|
193
|
+
packageManager,
|
|
194
|
+
cwd: migrationsCwd,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
spinner.fail(`${color.red("Error!")} Created ${color.cyan(appName)}, but could not generate its migrations.`);
|
|
199
|
+
console.error(color.red(error instanceof Error ? error.message : String(error)));
|
|
200
|
+
process.exit(1);
|
|
201
|
+
}
|
|
53
202
|
}
|
|
54
|
-
spinner.succeed(`${color.green(
|
|
203
|
+
spinner.succeed(`${color.green("Success!")} Created ${color.cyan(appName)} at ${color.cyan(root)}`);
|
|
55
204
|
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export const versionsPackageJson = {
|
|
2
|
+
typesNode: "^26",
|
|
3
|
+
typesReact: "^19.2",
|
|
4
|
+
typesReactDom: "^19.2",
|
|
5
|
+
typesBun: "latest",
|
|
6
|
+
turbo: "^2.10",
|
|
7
|
+
typescript: "^6.0",
|
|
8
|
+
tsx: "^4",
|
|
9
|
+
tscAlias: "^1.9",
|
|
10
|
+
eslint: "^10",
|
|
11
|
+
prettier: "^3.9",
|
|
12
|
+
prettierTailwind: "^0.8",
|
|
13
|
+
tailwind: "^4.2",
|
|
14
|
+
twAnimateCss: "^1.4.0",
|
|
15
|
+
react: "^19.2",
|
|
16
|
+
reactDom: "^19.2",
|
|
17
|
+
useIntl: "^4.13.7",
|
|
18
|
+
rhf: "^7",
|
|
19
|
+
rhfResolvers: "^5.1.1",
|
|
20
|
+
lucide: "^1.21",
|
|
21
|
+
sonner: "^2.0.7",
|
|
22
|
+
dotenv: "^17.4",
|
|
23
|
+
drizzleKit: "1.0.0-rc.4",
|
|
24
|
+
drizzleOrm: "1.0.0-rc.4",
|
|
25
|
+
hono: "^4.12",
|
|
26
|
+
honoZodOpenapi: "^1.5",
|
|
27
|
+
honoZodValidator: "^0.9",
|
|
28
|
+
reactEmail: "^6.9",
|
|
29
|
+
reactEmailUi: "^6.9",
|
|
30
|
+
zod: "^4.4",
|
|
31
|
+
ws: "^8",
|
|
32
|
+
cva: "^0.7.1",
|
|
33
|
+
tanstackReactRouter: "^1.170",
|
|
34
|
+
tanstackReactStart: "^1.168",
|
|
35
|
+
tanstackReactQuery: "^5.101",
|
|
36
|
+
tanstackRouterSsrQuery: "^1.167",
|
|
37
|
+
tanstackReactDevtools: "^0.10",
|
|
38
|
+
tanstackDevtoolsVite: "^0.8",
|
|
39
|
+
tanstackQueryDevtools: "^5.102",
|
|
40
|
+
tanstackRouterDevtools: "^1.167",
|
|
41
|
+
vite: "^8.0",
|
|
42
|
+
viteReact: "^6.0",
|
|
43
|
+
tailwindVite: "^4.2",
|
|
44
|
+
nitro: "3.0.260610-beta",
|
|
45
|
+
tslib: "^2.8.1",
|
|
46
|
+
swcCli: "^0.8.1",
|
|
47
|
+
swcCore: "^1.15",
|
|
48
|
+
shadcn: "^4",
|
|
49
|
+
};
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import { exec } from
|
|
1
|
+
import { exec } from "node:child_process";
|
|
2
2
|
export const execShellCommand = async (cmd) => {
|
|
3
|
-
return new Promise(resolve => {
|
|
3
|
+
return await new Promise(resolve => {
|
|
4
4
|
exec(cmd, (error, stdout, stderr) => {
|
|
5
5
|
if (error) {
|
|
6
6
|
resolve(undefined);
|
|
7
7
|
}
|
|
8
8
|
const result = stdout ? stdout : stderr;
|
|
9
|
-
resolve(result.replace(/\s+/g,
|
|
9
|
+
resolve(result.replace(/\s+/g, ""));
|
|
10
10
|
});
|
|
11
11
|
});
|
|
12
12
|
};
|
|
13
13
|
export const getAvailablePackageManagers = async () => {
|
|
14
14
|
const [npm, pnpm, bun] = await Promise.all([
|
|
15
|
-
execShellCommand(
|
|
16
|
-
execShellCommand(
|
|
17
|
-
execShellCommand(
|
|
15
|
+
execShellCommand("npm --version"),
|
|
16
|
+
execShellCommand("pnpm --version"),
|
|
17
|
+
execShellCommand("bun --version"),
|
|
18
18
|
]);
|
|
19
19
|
return {
|
|
20
20
|
pnpm,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { readFileSync } from
|
|
2
|
-
export const packageJson = JSON.parse(readFileSync(new URL(
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
export const packageJson = JSON.parse(readFileSync(new URL("../../../package.json", import.meta.url), "utf-8"));
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
export const getPackageManagerFromRoot = (rootPath) => {
|
|
4
|
+
try {
|
|
5
|
+
const packageJsonPath = join(rootPath, "package.json");
|
|
6
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
7
|
+
if (packageJson.packageManager) {
|
|
8
|
+
return packageJson.packageManager.split("@")[0];
|
|
9
|
+
}
|
|
10
|
+
return "npm";
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return "npm";
|
|
14
|
+
}
|
|
15
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { readFile } from "fs/promises";
|
|
2
|
+
import { dirname, join } from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
5
|
+
const __dirname = dirname(__filename);
|
|
6
|
+
export const getVitnodePackageVersion = async () => {
|
|
7
|
+
const cliPkg = JSON.parse(await readFile(join(__dirname, "..", "..", "..", "package.json"), "utf-8"));
|
|
8
|
+
return `^${cliPkg.version}`;
|
|
9
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import color from "picocolors";
|
|
3
|
+
export const generateMigrationsVitnode = async ({ packageManager: pm, cwd, }) => {
|
|
4
|
+
const packageManager = pm.split("@")[0];
|
|
5
|
+
const args = ["vitnode", "migrate", "--generate"];
|
|
6
|
+
await new Promise((resolve, reject) => {
|
|
7
|
+
let output = "";
|
|
8
|
+
const child = spawn(packageManager, args, {
|
|
9
|
+
cwd,
|
|
10
|
+
env: process.env,
|
|
11
|
+
shell: true,
|
|
12
|
+
stdio: "pipe",
|
|
13
|
+
});
|
|
14
|
+
child.stdout?.on("data", (data) => {
|
|
15
|
+
output += data.toString();
|
|
16
|
+
});
|
|
17
|
+
child.stderr?.on("data", (data) => {
|
|
18
|
+
output += data.toString();
|
|
19
|
+
});
|
|
20
|
+
child.on("error", error => {
|
|
21
|
+
reject(new Error(`Failed to start ${packageManager}: ${error.message}\nRun "${packageManager} vitnode db:prepare" in the new project once your database is running.`));
|
|
22
|
+
});
|
|
23
|
+
child.on("close", code => {
|
|
24
|
+
if (code === 0) {
|
|
25
|
+
resolve();
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (output.trim().length > 0) {
|
|
29
|
+
console.error(color.red(output.trim()));
|
|
30
|
+
}
|
|
31
|
+
reject(new Error(`"${packageManager} vitnode migrate --generate" exited with code ${String(code)}. Your project was created - run "${packageManager} dev" once your database is running and it will migrate itself.`));
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
};
|
|
@@ -1,30 +1,71 @@
|
|
|
1
|
-
import { spawn } from
|
|
2
|
-
import
|
|
3
|
-
import { getOnline } from
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import consoleColor from "picocolors";
|
|
3
|
+
import { getOnline } from "./is-online.js";
|
|
4
|
+
function printInstallErrorSuggestions(stderr, color) {
|
|
5
|
+
if (stderr.includes("ENOTFOUND") || stderr.includes("network")) {
|
|
6
|
+
console.error(color.yellow("💡 Network error detected. Please check your internet connection."));
|
|
7
|
+
}
|
|
8
|
+
else if (stderr.includes("EACCES") ||
|
|
9
|
+
stderr.includes("permission denied")) {
|
|
10
|
+
console.error(color.yellow("💡 Permission error detected. Try running with elevated privileges or check file permissions."));
|
|
11
|
+
}
|
|
12
|
+
else if (stderr.includes("ENOSPC")) {
|
|
13
|
+
console.error(color.yellow("💡 Disk space error detected. Please free up some disk space."));
|
|
14
|
+
}
|
|
15
|
+
else if (stderr.includes("ERR_PNPM_PEER_DEP_ISSUES")) {
|
|
16
|
+
console.error(color.yellow("💡 Peer dependency issues detected. Consider using --force flag or resolve conflicts manually."));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export const installDependencies = async ({ packageManager: pm, cwd, }) => {
|
|
20
|
+
const packageManager = pm.split("@")[0];
|
|
6
21
|
const isOnline = await getOnline();
|
|
7
|
-
const args =
|
|
22
|
+
const args = ["install"];
|
|
8
23
|
if (!isOnline) {
|
|
9
|
-
console.log(
|
|
10
|
-
args.push(
|
|
24
|
+
console.log(consoleColor.yellow("You appear to be offline.\nFalling back to the local cache."));
|
|
25
|
+
args.push("--offline");
|
|
11
26
|
}
|
|
12
27
|
return new Promise((resolve, reject) => {
|
|
28
|
+
let stdout = "";
|
|
29
|
+
let stderr = "";
|
|
13
30
|
const child = spawn(packageManager, args, {
|
|
14
|
-
stdio:
|
|
31
|
+
stdio: "pipe",
|
|
32
|
+
cwd,
|
|
33
|
+
shell: true,
|
|
15
34
|
env: {
|
|
16
35
|
...process.env,
|
|
17
|
-
ADBLOCK:
|
|
18
|
-
NODE_ENV:
|
|
19
|
-
DISABLE_OPENCOLLECTIVE:
|
|
36
|
+
ADBLOCK: "1",
|
|
37
|
+
NODE_ENV: "development",
|
|
38
|
+
DISABLE_OPENCOLLECTIVE: "1",
|
|
20
39
|
},
|
|
21
40
|
});
|
|
22
|
-
child.on(
|
|
41
|
+
child.stdout?.on("data", (data) => {
|
|
42
|
+
const output = data.toString();
|
|
43
|
+
stdout += output;
|
|
44
|
+
});
|
|
45
|
+
child.stderr?.on("data", (data) => {
|
|
46
|
+
const output = data.toString();
|
|
47
|
+
stderr += output;
|
|
48
|
+
});
|
|
49
|
+
child.on("close", code => {
|
|
23
50
|
if (code !== 0) {
|
|
24
|
-
|
|
51
|
+
console.error(consoleColor.red(`\n❌ Installation failed with exit code: ${code}`));
|
|
52
|
+
if (stderr) {
|
|
53
|
+
console.error(consoleColor.red("Error output:"));
|
|
54
|
+
console.error(stderr);
|
|
55
|
+
}
|
|
56
|
+
if (stdout) {
|
|
57
|
+
console.log(consoleColor.yellow("Standard output:"));
|
|
58
|
+
console.log(stdout);
|
|
59
|
+
}
|
|
60
|
+
printInstallErrorSuggestions(stderr, consoleColor);
|
|
61
|
+
reject(new Error(`Failed to install dependencies using ${packageManager}. Exit code: ${code}\n${stderr || stdout}`));
|
|
25
62
|
return;
|
|
26
63
|
}
|
|
27
64
|
resolve();
|
|
28
65
|
});
|
|
66
|
+
child.on("error", error => {
|
|
67
|
+
console.error(consoleColor.red(`❌ Failed to start ${packageManager}:`), error.message);
|
|
68
|
+
reject(new Error(`Failed to start ${packageManager}: ${error.message}`));
|
|
69
|
+
});
|
|
29
70
|
});
|
|
30
71
|
};
|
|
@@ -1,31 +1,30 @@
|
|
|
1
|
-
import { lstatSync, readdirSync } from
|
|
2
|
-
import { join } from
|
|
3
|
-
import colors from
|
|
1
|
+
import { lstatSync, readdirSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import colors from "picocolors";
|
|
4
4
|
export function isFolderEmpty(root, name) {
|
|
5
5
|
const validFiles = [
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
6
|
+
".DS_Store",
|
|
7
|
+
".git",
|
|
8
|
+
".gitattributes",
|
|
9
|
+
".gitignore",
|
|
10
|
+
".gitlab-ci.yml",
|
|
11
|
+
".hg",
|
|
12
|
+
".hgcheck",
|
|
13
|
+
".hgignore",
|
|
14
|
+
".idea",
|
|
15
|
+
".npmignore",
|
|
16
|
+
".travis.yml",
|
|
17
|
+
"LICENSE",
|
|
18
|
+
"Thumbs.db",
|
|
19
|
+
"docs",
|
|
20
|
+
"mkdocs.yml",
|
|
21
|
+
"npm-debug.log",
|
|
22
|
+
"yarn-debug.log",
|
|
23
|
+
"yarn-error.log",
|
|
24
|
+
"yarnrc.yml",
|
|
25
|
+
".yarn",
|
|
26
26
|
];
|
|
27
|
-
const conflicts = readdirSync(root).filter(file => !validFiles.includes(file)
|
|
28
|
-
!file.endsWith('.iml'));
|
|
27
|
+
const conflicts = readdirSync(root).filter(file => !(validFiles.includes(file) || file.endsWith(".iml")));
|
|
29
28
|
if (conflicts.length > 0) {
|
|
30
29
|
console.log(`The directory ${colors.green(name)} contains files that could conflict:\n`);
|
|
31
30
|
for (const file of conflicts) {
|
|
@@ -42,7 +41,7 @@ export function isFolderEmpty(root, name) {
|
|
|
42
41
|
console.log(file);
|
|
43
42
|
}
|
|
44
43
|
}
|
|
45
|
-
console.log(
|
|
44
|
+
console.log("\nEither try using a new directory name, or remove the files listed above.\n");
|
|
46
45
|
return false;
|
|
47
46
|
}
|
|
48
47
|
return true;
|
|
@@ -1,9 +1,21 @@
|
|
|
1
|
-
import { execSync } from
|
|
2
|
-
import { lookup } from
|
|
3
|
-
import { URL } from
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import { lookup } from "node:dns/promises";
|
|
3
|
+
import { URL } from "node:url";
|
|
4
|
+
function getProxy() {
|
|
5
|
+
if (process.env.https_proxy) {
|
|
6
|
+
return process.env.https_proxy;
|
|
7
|
+
}
|
|
8
|
+
try {
|
|
9
|
+
const httpsProxy = execSync("npm config get https-proxy").toString().trim();
|
|
10
|
+
return httpsProxy !== "null" ? httpsProxy : undefined;
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
4
16
|
export async function getOnline() {
|
|
5
17
|
try {
|
|
6
|
-
await lookup(
|
|
18
|
+
await lookup("registry.yarnpkg.com");
|
|
7
19
|
return true;
|
|
8
20
|
}
|
|
9
21
|
catch {
|
|
@@ -24,15 +36,3 @@ export async function getOnline() {
|
|
|
24
36
|
}
|
|
25
37
|
}
|
|
26
38
|
}
|
|
27
|
-
function getProxy() {
|
|
28
|
-
if (process.env.https_proxy) {
|
|
29
|
-
return process.env.https_proxy;
|
|
30
|
-
}
|
|
31
|
-
try {
|
|
32
|
-
const httpsProxy = execSync('npm config get https-proxy').toString().trim();
|
|
33
|
-
return httpsProxy !== 'null' ? httpsProxy : undefined;
|
|
34
|
-
}
|
|
35
|
-
catch (_) {
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { W_OK } from
|
|
2
|
-
import { access } from
|
|
1
|
+
import { W_OK } from "node:constants";
|
|
2
|
+
import { access } from "node:fs/promises";
|
|
3
3
|
export async function isWriteable(directory) {
|
|
4
4
|
try {
|
|
5
5
|
await access(directory, W_OK);
|
|
6
6
|
return true;
|
|
7
7
|
}
|
|
8
|
-
catch
|
|
8
|
+
catch {
|
|
9
9
|
return false;
|
|
10
10
|
}
|
|
11
11
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const withIf = (cond, obj) => (cond ? obj : {});
|