create-kubojs 0.5.1 → 0.6.0
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.mjs +1 -1
- package/dist/index.d.mts +20 -0
- package/dist/index.mjs +1 -1
- package/dist/{src-DdCJmpnU.mjs → src-CYAa_B_y.mjs} +182 -72
- package/package.json +3 -3
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { _ as types_exports, g as setTelemetrySource, i as SchemaNameSchema, l as create, m as getSchemaResult, s as add, u as createBtsCli, v as getLatestCLIVersion } from "./src-
|
|
2
|
+
import { _ as types_exports, g as setTelemetrySource, i as SchemaNameSchema, l as create, m as getSchemaResult, s as add, u as createBtsCli, v as getLatestCLIVersion } from "./src-CYAa_B_y.mjs";
|
|
3
3
|
import z from "zod";
|
|
4
4
|
import { format } from "node:util";
|
|
5
5
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
package/dist/index.d.mts
CHANGED
|
@@ -216,6 +216,8 @@ declare const router: _$_trpc_server0.TRPCBuiltRouter<{
|
|
|
216
216
|
installCli?: boolean | undefined;
|
|
217
217
|
} | undefined;
|
|
218
218
|
} | undefined;
|
|
219
|
+
layout?: string | undefined;
|
|
220
|
+
layoutCode?: string | undefined;
|
|
219
221
|
}];
|
|
220
222
|
output: CreateProjectResult | undefined;
|
|
221
223
|
meta: TrpcCliMeta;
|
|
@@ -286,6 +288,24 @@ declare const router: _$_trpc_server0.TRPCBuiltRouter<{
|
|
|
286
288
|
renderTitle?: boolean | undefined;
|
|
287
289
|
disableAnalytics?: boolean | undefined;
|
|
288
290
|
manualDb?: boolean | undefined;
|
|
291
|
+
layout?: {
|
|
292
|
+
version?: 1 | undefined;
|
|
293
|
+
preset?: "server-separated" | "standard" | "libs" | undefined;
|
|
294
|
+
dirs?: {
|
|
295
|
+
apps?: string | undefined;
|
|
296
|
+
packages?: string | undefined;
|
|
297
|
+
} | undefined;
|
|
298
|
+
apps?: {
|
|
299
|
+
web?: string | undefined;
|
|
300
|
+
server?: string | undefined;
|
|
301
|
+
native?: string | undefined;
|
|
302
|
+
desktop?: string | undefined;
|
|
303
|
+
docs?: string | undefined;
|
|
304
|
+
api?: string | undefined;
|
|
305
|
+
} | undefined;
|
|
306
|
+
packages?: Record<string, string> | undefined;
|
|
307
|
+
} | undefined;
|
|
308
|
+
layoutCode?: string | undefined;
|
|
289
309
|
};
|
|
290
310
|
output: CreateProjectResult;
|
|
291
311
|
meta: TrpcCliMeta;
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { C as ProjectCreationError, S as DirectoryConflictError, T as ValidationError, a as TEMPLATE_COUNT, b as CompatibilityError, c as builder, d as createVirtual, f as docs, h as router, i as SchemaNameSchema, l as create, m as getSchemaResult, n as GeneratorError, o as VirtualFileSystem, p as generate, r as Result, s as add, t as EMBEDDED_TEMPLATES, u as createBtsCli, w as UserCancelledError, x as DatabaseSetupError, y as CLIError } from "./src-
|
|
2
|
+
import { C as ProjectCreationError, S as DirectoryConflictError, T as ValidationError, a as TEMPLATE_COUNT, b as CompatibilityError, c as builder, d as createVirtual, f as docs, h as router, i as SchemaNameSchema, l as create, m as getSchemaResult, n as GeneratorError, o as VirtualFileSystem, p as generate, r as Result, s as add, t as EMBEDDED_TEMPLATES, u as createBtsCli, w as UserCancelledError, x as DatabaseSetupError, y as CLIError } from "./src-CYAa_B_y.mjs";
|
|
3
3
|
export { CLIError, CompatibilityError, DatabaseSetupError, DirectoryConflictError, EMBEDDED_TEMPLATES, GeneratorError, ProjectCreationError, Result, SchemaNameSchema, TEMPLATE_COUNT, UserCancelledError, ValidationError, VirtualFileSystem, add, builder, create, createBtsCli, createVirtual, docs, generate, getSchemaResult, router };
|
|
@@ -12,7 +12,7 @@ import envPaths from "env-paths";
|
|
|
12
12
|
import fs from "fs-extra";
|
|
13
13
|
import { fileURLToPath } from "node:url";
|
|
14
14
|
import { ADDON_COMPATIBILITY, COMMUNICATION_PRODUCT_NAMES, CONVEX_BETTER_AUTH_INCOMPATIBLE_FRONTENDS, CONVEX_BETTER_AUTH_SUPPORTED_FRONTENDS, FRONTEND_VALUES, KUBO_CLI_TITLE, KUBO_TITLE_COLORS, KuboConfigFileSchema, KubojsConfigFileSchema, WEB_FRONTENDS_REQUIRING_ORPC, backendAllowsAiExample, backendAllowsApi, backendAllowsOnlyNoneApi, evaluate, getCommunicationCompatibilityIssue, getPaymentCompatibilityIssue, isCommunicationProvider, isWebFrontend, normalizeCommunication, normalizeCommunication as normalizeCommunication$2, normalizeLegacyKuboConfig, normalizeObservability, normalizePayments } from "@kubojs/types";
|
|
15
|
-
import { EMBEDDED_TEMPLATES, EMBEDDED_TEMPLATES as EMBEDDED_TEMPLATES$1, GeneratorError, GeneratorError as GeneratorError$1, KUBO_CONFIG_FILE, TEMPLATE_COUNT, VirtualFileSystem, VirtualFileSystem as VirtualFileSystem$1, applyAddonCatalog, dependencyVersionMap, generate, generate as generate$1, generateReproducibleCommand, getWebAppPath, isBinaryFile, processEnvVariables, processPackageConfigs, processTemplateString, resolveLayout, serializeKuboConfigFile } from "@kubojs/template-generator";
|
|
15
|
+
import { EMBEDDED_TEMPLATES, EMBEDDED_TEMPLATES as EMBEDDED_TEMPLATES$1, GeneratorError, GeneratorError as GeneratorError$1, KUBO_CONFIG_FILE, TEMPLATE_COUNT, VirtualFileSystem, VirtualFileSystem as VirtualFileSystem$1, appDir, applyAddonCatalog, createLayoutResolver, dependencyVersionMap, generate, generate as generate$1, generateReproducibleCommand, getWebAppPath, isBinaryFile, pkgDir, processEnvVariables, processPackageConfigs, processTemplateString, relocateLayoutPaths, resolveLayout, serializeKuboConfigFile } from "@kubojs/template-generator";
|
|
16
16
|
import { consola, createConsola } from "consola";
|
|
17
17
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
18
18
|
import gradient from "gradient-string";
|
|
@@ -2477,6 +2477,15 @@ async function setupSkills(config) {
|
|
|
2477
2477
|
return Result.ok(void 0);
|
|
2478
2478
|
}
|
|
2479
2479
|
//#endregion
|
|
2480
|
+
//#region src/utils/layout-paths.ts
|
|
2481
|
+
/**
|
|
2482
|
+
* App folder that holds the database `.env` (the web app for fullstack `self` backends,
|
|
2483
|
+
* otherwise the server app), resolved against the project layout.
|
|
2484
|
+
*/
|
|
2485
|
+
function getDbEnvTargetApp(config) {
|
|
2486
|
+
return appDir(config, config.backend === "self" ? "web" : "server");
|
|
2487
|
+
}
|
|
2488
|
+
//#endregion
|
|
2480
2489
|
//#region src/helpers/addons/tauri-setup.ts
|
|
2481
2490
|
function getWebFrontend(frontend) {
|
|
2482
2491
|
return frontend.find((value) => types_exports.desktopWebFrontends.includes(value));
|
|
@@ -2527,7 +2536,7 @@ async function setupTauri(config) {
|
|
|
2527
2536
|
if (shouldSkipExternalCommands()) return Result.ok(void 0);
|
|
2528
2537
|
const { packageManager, frontend, projectDir } = config;
|
|
2529
2538
|
const s = createSpinner();
|
|
2530
|
-
const clientPackageDir = path.join(projectDir, "
|
|
2539
|
+
const clientPackageDir = path.join(projectDir, appDir(config, "web"));
|
|
2531
2540
|
if (!await fs.pathExists(clientPackageDir)) return Result.ok(void 0);
|
|
2532
2541
|
s.start("Setting up Tauri desktop app support...");
|
|
2533
2542
|
const [command, ...args] = buildTauriInitArgs({
|
|
@@ -4393,6 +4402,90 @@ function displayConfig(config) {
|
|
|
4393
4402
|
return configDisplay.join("\n");
|
|
4394
4403
|
}
|
|
4395
4404
|
//#endregion
|
|
4405
|
+
//#region src/utils/layout-input.ts
|
|
4406
|
+
function formatZodIssues(error) {
|
|
4407
|
+
return error.issues.map((issue) => `${issue.path.length > 0 ? issue.path.join(".") : "layout"}: ${issue.message}`).join("; ");
|
|
4408
|
+
}
|
|
4409
|
+
function isLayoutPreset(value) {
|
|
4410
|
+
return types_exports.LAYOUT_PRESET_IDS.some((preset) => preset === value);
|
|
4411
|
+
}
|
|
4412
|
+
/**
|
|
4413
|
+
* Parses the `--layout` flag: a preset name (`standard`, `libs`) or a JSON layout object,
|
|
4414
|
+
* e.g. `--layout '{"preset":"libs","apps":{"web":"web"}}'`.
|
|
4415
|
+
*/
|
|
4416
|
+
function parseLayoutFlag(value) {
|
|
4417
|
+
const trimmed = value.trim();
|
|
4418
|
+
if (isLayoutPreset(trimmed)) return Result.ok({
|
|
4419
|
+
version: 1,
|
|
4420
|
+
preset: trimmed
|
|
4421
|
+
});
|
|
4422
|
+
if (!trimmed.startsWith("{")) return Result.err(new CLIError({ message: `Invalid --layout "${value}". Use a preset (${types_exports.LAYOUT_PRESET_IDS.join(", ")}) or a JSON layout object.` }));
|
|
4423
|
+
const json = Result.try({
|
|
4424
|
+
try: () => JSON.parse(trimmed),
|
|
4425
|
+
catch: (cause) => new CLIError({
|
|
4426
|
+
message: "Invalid --layout JSON",
|
|
4427
|
+
cause
|
|
4428
|
+
})
|
|
4429
|
+
});
|
|
4430
|
+
if (json.isErr()) return Result.err(json.error);
|
|
4431
|
+
const parsed = types_exports.LayoutConfigSchema.safeParse(json.value);
|
|
4432
|
+
if (!parsed.success) return Result.err(new CLIError({ message: `Invalid --layout: ${formatZodIssues(parsed.error)}` }));
|
|
4433
|
+
return Result.ok(parsed.data);
|
|
4434
|
+
}
|
|
4435
|
+
/**
|
|
4436
|
+
* Validates a layout before anything is written: schema shape plus folder conflicts
|
|
4437
|
+
* (collisions, case-only collisions, nested folders).
|
|
4438
|
+
*/
|
|
4439
|
+
function validateCreateLayout(layout) {
|
|
4440
|
+
if (layout === void 0) return Result.ok(void 0);
|
|
4441
|
+
const parsed = types_exports.LayoutConfigSchema.safeParse(layout);
|
|
4442
|
+
if (!parsed.success) return Result.err(new CLIError({ message: `Invalid layout: ${formatZodIssues(parsed.error)}` }));
|
|
4443
|
+
const resolver = createLayoutResolver(parsed.data);
|
|
4444
|
+
if (resolver.isErr()) return Result.err(new CLIError({
|
|
4445
|
+
message: `Invalid layout: ${resolver.error.message}`,
|
|
4446
|
+
cause: resolver.error
|
|
4447
|
+
}));
|
|
4448
|
+
return Result.ok(parsed.data);
|
|
4449
|
+
}
|
|
4450
|
+
const DEFAULT_KUBO_API_URL = "https://kubojs.dev";
|
|
4451
|
+
const REDEEM_TIMEOUT_MS = 1e4;
|
|
4452
|
+
function getRedeemUrl() {
|
|
4453
|
+
return `${process.env.KUBO_API_URL?.replace(/\/$/, "") || DEFAULT_KUBO_API_URL}/api/layout/redeem`;
|
|
4454
|
+
}
|
|
4455
|
+
/**
|
|
4456
|
+
* Exchanges a single-use code from kubojs.dev for the layout saved in the account. The code
|
|
4457
|
+
* is consumed on success; it is never logged or sent to telemetry.
|
|
4458
|
+
*/
|
|
4459
|
+
async function redeemLayoutCode(code) {
|
|
4460
|
+
const response = await Result.tryPromise({
|
|
4461
|
+
try: () => fetch(getRedeemUrl(), {
|
|
4462
|
+
method: "POST",
|
|
4463
|
+
headers: { "Content-Type": "application/json" },
|
|
4464
|
+
body: JSON.stringify({ code }),
|
|
4465
|
+
signal: AbortSignal.timeout(REDEEM_TIMEOUT_MS)
|
|
4466
|
+
}),
|
|
4467
|
+
catch: (cause) => new CLIError({
|
|
4468
|
+
message: "Could not reach kubojs.dev to redeem the layout code. Check your connection.",
|
|
4469
|
+
cause
|
|
4470
|
+
})
|
|
4471
|
+
});
|
|
4472
|
+
if (response.isErr()) return Result.err(response.error);
|
|
4473
|
+
if (response.value.status === 400 || response.value.status === 404) return Result.err(new CLIError({ message: "This layout code is invalid, expired or was already used. Generate a new one in the Layout tab at kubojs.dev/new." }));
|
|
4474
|
+
if (!response.value.ok) return Result.err(new CLIError({ message: `Layout code redemption failed (HTTP ${response.value.status}).` }));
|
|
4475
|
+
const body = await Result.tryPromise({
|
|
4476
|
+
try: async () => response.value.json(),
|
|
4477
|
+
catch: (cause) => new CLIError({
|
|
4478
|
+
message: "Invalid response while redeeming the layout code",
|
|
4479
|
+
cause
|
|
4480
|
+
})
|
|
4481
|
+
});
|
|
4482
|
+
if (body.isErr()) return Result.err(body.error);
|
|
4483
|
+
const layout = typeof body.value === "object" && body.value !== null && "layout" in body.value ? body.value.layout : void 0;
|
|
4484
|
+
const parsed = types_exports.LayoutConfigSchema.safeParse(layout);
|
|
4485
|
+
if (!parsed.success) return Result.err(new CLIError({ message: "The redeemed layout is not valid." }));
|
|
4486
|
+
return Result.ok(parsed.data);
|
|
4487
|
+
}
|
|
4488
|
+
//#endregion
|
|
4396
4489
|
//#region src/utils/project-directory.ts
|
|
4397
4490
|
async function handleDirectoryConflict(currentPathInput) {
|
|
4398
4491
|
while (true) {
|
|
@@ -4806,7 +4899,7 @@ async function generateRouteTreeIfNeeded(projectDir, config) {
|
|
|
4806
4899
|
if (!needsRouteTree(config.frontend)) return Result.ok(void 0);
|
|
4807
4900
|
const target = resolveRouteTreeTarget(config.frontend);
|
|
4808
4901
|
if (!target) return Result.ok(void 0);
|
|
4809
|
-
const webAppDir = path.join(projectDir, "
|
|
4902
|
+
const webAppDir = path.join(projectDir, appDir(config, "web"));
|
|
4810
4903
|
const routesDir = path.join(webAppDir, "src/routes");
|
|
4811
4904
|
if (!await fs.pathExists(routesDir)) return Result.ok(void 0);
|
|
4812
4905
|
return Result.tryPromise({
|
|
@@ -4869,7 +4962,7 @@ async function setupCloudflareD1(config) {
|
|
|
4869
4962
|
if (!(orm === "prisma" && (serverDeploy === "cloudflare" || backend === "self" && webDeploy === "cloudflare"))) return Result.ok(void 0);
|
|
4870
4963
|
return Result.tryPromise({
|
|
4871
4964
|
try: async () => {
|
|
4872
|
-
const targetApp =
|
|
4965
|
+
const targetApp = getDbEnvTargetApp(config);
|
|
4873
4966
|
await addEnvVariablesToFile(path.join(projectDir, targetApp, ".env"), [{
|
|
4874
4967
|
key: "DATABASE_URL",
|
|
4875
4968
|
value: `file:${path.join(projectDir, targetApp, "local.db")}`,
|
|
@@ -4877,7 +4970,7 @@ async function setupCloudflareD1(config) {
|
|
|
4877
4970
|
}]);
|
|
4878
4971
|
await addPackageDependency({
|
|
4879
4972
|
dependencies: ["@prisma/adapter-d1"],
|
|
4880
|
-
projectDir: path.join(projectDir,
|
|
4973
|
+
projectDir: path.join(projectDir, getDbEnvTargetApp(config))
|
|
4881
4974
|
});
|
|
4882
4975
|
},
|
|
4883
4976
|
catch: (e) => new DatabaseSetupError({
|
|
@@ -4890,11 +4983,11 @@ async function setupCloudflareD1(config) {
|
|
|
4890
4983
|
//#endregion
|
|
4891
4984
|
//#region src/helpers/database-providers/docker-compose-setup.ts
|
|
4892
4985
|
async function setupDockerCompose(config) {
|
|
4893
|
-
const { database, projectDir, projectName
|
|
4986
|
+
const { database, projectDir, projectName } = config;
|
|
4894
4987
|
if (database === "none" || database === "sqlite") return Result.ok(void 0);
|
|
4895
4988
|
const result = await Result.tryPromise({
|
|
4896
4989
|
try: async () => {
|
|
4897
|
-
await writeEnvFile$4(projectDir, database, projectName,
|
|
4990
|
+
await writeEnvFile$4(projectDir, database, projectName, config);
|
|
4898
4991
|
},
|
|
4899
4992
|
catch: (e) => new DatabaseSetupError({
|
|
4900
4993
|
provider: "docker-compose",
|
|
@@ -4904,8 +4997,8 @@ async function setupDockerCompose(config) {
|
|
|
4904
4997
|
});
|
|
4905
4998
|
return result.isErr() ? result : Result.ok(void 0);
|
|
4906
4999
|
}
|
|
4907
|
-
async function writeEnvFile$4(projectDir, database, projectName,
|
|
4908
|
-
const targetApp =
|
|
5000
|
+
async function writeEnvFile$4(projectDir, database, projectName, project) {
|
|
5001
|
+
const targetApp = getDbEnvTargetApp(project);
|
|
4909
5002
|
await addEnvVariablesToFile(path.join(projectDir, targetApp, ".env"), [{
|
|
4910
5003
|
key: "DATABASE_URL",
|
|
4911
5004
|
value: getDatabaseUrl(database, projectName),
|
|
@@ -5006,10 +5099,10 @@ async function initMongoDBAtlas(serverDir) {
|
|
|
5006
5099
|
}
|
|
5007
5100
|
return Result.ok({ connectionString });
|
|
5008
5101
|
}
|
|
5009
|
-
async function writeEnvFile$3(projectDir,
|
|
5102
|
+
async function writeEnvFile$3(projectDir, project, config) {
|
|
5010
5103
|
return Result.tryPromise({
|
|
5011
5104
|
try: async () => {
|
|
5012
|
-
const targetApp =
|
|
5105
|
+
const targetApp = getDbEnvTargetApp(project);
|
|
5013
5106
|
await addEnvVariablesToFile(path.join(projectDir, targetApp, ".env"), [{
|
|
5014
5107
|
key: "DATABASE_URL",
|
|
5015
5108
|
value: config?.connectionString ?? "mongodb://localhost:27017/mydb",
|
|
@@ -5041,12 +5134,12 @@ ${pc.green("MongoDB Atlas Manual Setup Instructions:")}
|
|
|
5041
5134
|
`);
|
|
5042
5135
|
}
|
|
5043
5136
|
async function setupMongoDBAtlas(config, cliInput) {
|
|
5044
|
-
const { projectDir
|
|
5137
|
+
const { projectDir } = config;
|
|
5045
5138
|
const setupMode = resolveDbSetupMode("mongodb-atlas", {
|
|
5046
5139
|
manualDb: cliInput?.manualDb,
|
|
5047
5140
|
dbSetupOptions: cliInput?.dbSetupOptions ?? config.dbSetupOptions
|
|
5048
5141
|
});
|
|
5049
|
-
const serverDir = path.join(projectDir, "
|
|
5142
|
+
const serverDir = path.join(projectDir, pkgDir(config, "db"));
|
|
5050
5143
|
const ensureDirResult = await Result.tryPromise({
|
|
5051
5144
|
try: () => fs.ensureDir(serverDir),
|
|
5052
5145
|
catch: (e) => new DatabaseSetupError({
|
|
@@ -5058,7 +5151,7 @@ async function setupMongoDBAtlas(config, cliInput) {
|
|
|
5058
5151
|
if (ensureDirResult.isErr()) return ensureDirResult;
|
|
5059
5152
|
if (setupMode === "manual") {
|
|
5060
5153
|
cliLog.info("MongoDB Atlas manual setup selected");
|
|
5061
|
-
const envResult = await writeEnvFile$3(projectDir,
|
|
5154
|
+
const envResult = await writeEnvFile$3(projectDir, config);
|
|
5062
5155
|
if (envResult.isErr()) return envResult;
|
|
5063
5156
|
displayManualSetupInstructions$3();
|
|
5064
5157
|
return Result.ok(void 0);
|
|
@@ -5067,7 +5160,7 @@ async function setupMongoDBAtlas(config, cliInput) {
|
|
|
5067
5160
|
if (!mode) {
|
|
5068
5161
|
if (isSilent()) {
|
|
5069
5162
|
cliLog.warn(pc.yellow("MongoDB Atlas automatic setup requires interactive input. Falling back to manual setup."));
|
|
5070
|
-
const envResult = await writeEnvFile$3(projectDir,
|
|
5163
|
+
const envResult = await writeEnvFile$3(projectDir, config);
|
|
5071
5164
|
if (envResult.isErr()) return envResult;
|
|
5072
5165
|
displayManualSetupInstructions$3();
|
|
5073
5166
|
return Result.ok(void 0);
|
|
@@ -5090,21 +5183,21 @@ async function setupMongoDBAtlas(config, cliInput) {
|
|
|
5090
5183
|
}
|
|
5091
5184
|
if (mode === "manual") {
|
|
5092
5185
|
cliLog.info("MongoDB Atlas manual setup selected");
|
|
5093
|
-
const envResult = await writeEnvFile$3(projectDir,
|
|
5186
|
+
const envResult = await writeEnvFile$3(projectDir, config);
|
|
5094
5187
|
if (envResult.isErr()) return envResult;
|
|
5095
5188
|
displayManualSetupInstructions$3();
|
|
5096
5189
|
return Result.ok(void 0);
|
|
5097
5190
|
}
|
|
5098
5191
|
const mongoConfigResult = await initMongoDBAtlas(serverDir);
|
|
5099
5192
|
if (mongoConfigResult.isOk()) {
|
|
5100
|
-
const envResult = await writeEnvFile$3(projectDir,
|
|
5193
|
+
const envResult = await writeEnvFile$3(projectDir, config, mongoConfigResult.value);
|
|
5101
5194
|
if (envResult.isErr()) return envResult;
|
|
5102
5195
|
cliLog.success(pc.green("MongoDB Atlas setup complete! Connection saved to .env file."));
|
|
5103
5196
|
return Result.ok(void 0);
|
|
5104
5197
|
}
|
|
5105
5198
|
if (UserCancelledError.is(mongoConfigResult.error)) return Result.err(mongoConfigResult.error);
|
|
5106
5199
|
cliLog.warn(pc.yellow("Falling back to local MongoDB configuration"));
|
|
5107
|
-
const envResult = await writeEnvFile$3(projectDir,
|
|
5200
|
+
const envResult = await writeEnvFile$3(projectDir, config);
|
|
5108
5201
|
if (envResult.isErr()) return envResult;
|
|
5109
5202
|
displayManualSetupInstructions$3();
|
|
5110
5203
|
return Result.ok(void 0);
|
|
@@ -5191,10 +5284,10 @@ async function createNeonProject(projectName, regionId, packageManager) {
|
|
|
5191
5284
|
}
|
|
5192
5285
|
return databaseSetupError("neon", "Failed to extract connection information from Neon response");
|
|
5193
5286
|
}
|
|
5194
|
-
async function writeEnvFile$2(projectDir,
|
|
5287
|
+
async function writeEnvFile$2(projectDir, project, config) {
|
|
5195
5288
|
return Result.tryPromise({
|
|
5196
5289
|
try: async () => {
|
|
5197
|
-
const targetApp =
|
|
5290
|
+
const targetApp = getDbEnvTargetApp(project);
|
|
5198
5291
|
await addEnvVariablesToFile(path.join(projectDir, targetApp, ".env"), [{
|
|
5199
5292
|
key: "DATABASE_URL",
|
|
5200
5293
|
value: config?.connectionString ?? "postgresql://postgres:postgres@localhost:5432/mydb?schema=public",
|
|
@@ -5208,10 +5301,10 @@ async function writeEnvFile$2(projectDir, backend, config) {
|
|
|
5208
5301
|
})
|
|
5209
5302
|
});
|
|
5210
5303
|
}
|
|
5211
|
-
async function setupWithNeonDb(projectDir, packageManager,
|
|
5304
|
+
async function setupWithNeonDb(projectDir, packageManager, project) {
|
|
5212
5305
|
const s = createSpinner();
|
|
5213
5306
|
s.start("Creating Neon database using neon-new...");
|
|
5214
|
-
const targetApp =
|
|
5307
|
+
const targetApp = getDbEnvTargetApp(project);
|
|
5215
5308
|
const targetDir = path.join(projectDir, targetApp);
|
|
5216
5309
|
const ensureDirResult = await Result.tryPromise({
|
|
5217
5310
|
try: () => fs.ensureDir(targetDir),
|
|
@@ -5252,20 +5345,20 @@ function displayManualSetupInstructions$2(target) {
|
|
|
5252
5345
|
DATABASE_URL="your_connection_string"`);
|
|
5253
5346
|
}
|
|
5254
5347
|
async function setupNeonPostgres(config, cliInput) {
|
|
5255
|
-
const { packageManager, projectDir
|
|
5348
|
+
const { packageManager, projectDir } = config;
|
|
5256
5349
|
const setupMode = resolveDbSetupMode("neon", {
|
|
5257
5350
|
manualDb: cliInput?.manualDb,
|
|
5258
5351
|
dbSetupOptions: cliInput?.dbSetupOptions ?? config.dbSetupOptions
|
|
5259
5352
|
});
|
|
5260
|
-
const target =
|
|
5353
|
+
const target = getDbEnvTargetApp(config);
|
|
5261
5354
|
if (shouldSkipExternalCommands()) {
|
|
5262
|
-
const envResult = await writeEnvFile$2(projectDir,
|
|
5355
|
+
const envResult = await writeEnvFile$2(projectDir, config);
|
|
5263
5356
|
if (envResult.isErr()) return envResult;
|
|
5264
5357
|
displayManualSetupInstructions$2(target);
|
|
5265
5358
|
return Result.ok(void 0);
|
|
5266
5359
|
}
|
|
5267
5360
|
if (setupMode === "manual") {
|
|
5268
|
-
const envResult = await writeEnvFile$2(projectDir,
|
|
5361
|
+
const envResult = await writeEnvFile$2(projectDir, config);
|
|
5269
5362
|
if (envResult.isErr()) return envResult;
|
|
5270
5363
|
displayManualSetupInstructions$2(target);
|
|
5271
5364
|
return Result.ok(void 0);
|
|
@@ -5290,7 +5383,7 @@ async function setupNeonPostgres(config, cliInput) {
|
|
|
5290
5383
|
selectedMode = promptedMode;
|
|
5291
5384
|
}
|
|
5292
5385
|
if (selectedMode === "manual") {
|
|
5293
|
-
const envResult = await writeEnvFile$2(projectDir,
|
|
5386
|
+
const envResult = await writeEnvFile$2(projectDir, config);
|
|
5294
5387
|
if (envResult.isErr()) return envResult;
|
|
5295
5388
|
displayManualSetupInstructions$2(target);
|
|
5296
5389
|
return Result.ok(void 0);
|
|
@@ -5315,10 +5408,10 @@ async function setupNeonPostgres(config, cliInput) {
|
|
|
5315
5408
|
setupMethod = promptedSetupMethod;
|
|
5316
5409
|
}
|
|
5317
5410
|
if (setupMethod === "neondb") {
|
|
5318
|
-
const neonDbResult = await setupWithNeonDb(projectDir, packageManager,
|
|
5411
|
+
const neonDbResult = await setupWithNeonDb(projectDir, packageManager, config);
|
|
5319
5412
|
if (neonDbResult.isErr()) {
|
|
5320
5413
|
cliLog.error(pc.red(neonDbResult.error.message));
|
|
5321
|
-
const envResult = await writeEnvFile$2(projectDir,
|
|
5414
|
+
const envResult = await writeEnvFile$2(projectDir, config);
|
|
5322
5415
|
if (envResult.isErr()) return envResult;
|
|
5323
5416
|
displayManualSetupInstructions$2(target);
|
|
5324
5417
|
return Result.ok(void 0);
|
|
@@ -5352,14 +5445,14 @@ async function setupNeonPostgres(config, cliInput) {
|
|
|
5352
5445
|
const neonConfigResult = await createNeonProject(projectName, regionId, packageManager);
|
|
5353
5446
|
if (neonConfigResult.isErr()) {
|
|
5354
5447
|
cliLog.error(pc.red(neonConfigResult.error.message));
|
|
5355
|
-
const envResult = await writeEnvFile$2(projectDir,
|
|
5448
|
+
const envResult = await writeEnvFile$2(projectDir, config);
|
|
5356
5449
|
if (envResult.isErr()) return envResult;
|
|
5357
5450
|
displayManualSetupInstructions$2(target);
|
|
5358
5451
|
return Result.ok(void 0);
|
|
5359
5452
|
}
|
|
5360
5453
|
const finalSpinner = createSpinner();
|
|
5361
5454
|
finalSpinner.start("Configuring database connection");
|
|
5362
|
-
const envResult = await writeEnvFile$2(projectDir,
|
|
5455
|
+
const envResult = await writeEnvFile$2(projectDir, config, neonConfigResult.value);
|
|
5363
5456
|
if (envResult.isErr()) {
|
|
5364
5457
|
finalSpinner.stop(pc.red("Failed to configure database connection"));
|
|
5365
5458
|
return envResult;
|
|
@@ -5371,11 +5464,11 @@ async function setupNeonPostgres(config, cliInput) {
|
|
|
5371
5464
|
//#endregion
|
|
5372
5465
|
//#region src/helpers/database-providers/planetscale-setup.ts
|
|
5373
5466
|
async function setupPlanetScale(config) {
|
|
5374
|
-
const { projectDir, database, orm
|
|
5467
|
+
const { projectDir, database, orm } = config;
|
|
5375
5468
|
if (!["mysql", "postgres"].includes(database)) return Result.ok(void 0);
|
|
5376
5469
|
return Result.tryPromise({
|
|
5377
5470
|
try: async () => {
|
|
5378
|
-
const targetApp =
|
|
5471
|
+
const targetApp = getDbEnvTargetApp(config);
|
|
5379
5472
|
const envPath = path.join(projectDir, targetApp, ".env");
|
|
5380
5473
|
if (database === "mysql" && orm === "drizzle") {
|
|
5381
5474
|
const variables = [
|
|
@@ -5523,10 +5616,10 @@ async function setupWithCreateDb(serverDir, packageManager, regionId) {
|
|
|
5523
5616
|
claimUrl: createDbResponse.claimUrl
|
|
5524
5617
|
});
|
|
5525
5618
|
}
|
|
5526
|
-
async function writeEnvFile$1(projectDir,
|
|
5619
|
+
async function writeEnvFile$1(projectDir, project, config) {
|
|
5527
5620
|
return Result.tryPromise({
|
|
5528
5621
|
try: async () => {
|
|
5529
|
-
const targetApp =
|
|
5622
|
+
const targetApp = getDbEnvTargetApp(project);
|
|
5530
5623
|
const envPath = path.join(projectDir, targetApp, ".env");
|
|
5531
5624
|
const variables = [{
|
|
5532
5625
|
key: "DATABASE_URL",
|
|
@@ -5558,13 +5651,13 @@ function displayManualSetupInstructions$1(target) {
|
|
|
5558
5651
|
DATABASE_URL="your_database_url"`);
|
|
5559
5652
|
}
|
|
5560
5653
|
async function setupPrismaPostgres(config, cliInput) {
|
|
5561
|
-
const { packageManager, projectDir
|
|
5654
|
+
const { packageManager, projectDir } = config;
|
|
5562
5655
|
const setupMode = resolveDbSetupMode("prisma-postgres", {
|
|
5563
5656
|
manualDb: cliInput?.manualDb,
|
|
5564
5657
|
dbSetupOptions: cliInput?.dbSetupOptions ?? config.dbSetupOptions
|
|
5565
5658
|
});
|
|
5566
|
-
const dbDir = path.join(projectDir, "
|
|
5567
|
-
const target =
|
|
5659
|
+
const dbDir = path.join(projectDir, pkgDir(config, "db"));
|
|
5660
|
+
const target = getDbEnvTargetApp(config);
|
|
5568
5661
|
const ensureDirResult = await Result.tryPromise({
|
|
5569
5662
|
try: () => fs.ensureDir(dbDir),
|
|
5570
5663
|
catch: (e) => new DatabaseSetupError({
|
|
@@ -5575,7 +5668,7 @@ async function setupPrismaPostgres(config, cliInput) {
|
|
|
5575
5668
|
});
|
|
5576
5669
|
if (ensureDirResult.isErr()) return ensureDirResult;
|
|
5577
5670
|
if (setupMode === "manual") {
|
|
5578
|
-
const envResult = await writeEnvFile$1(projectDir,
|
|
5671
|
+
const envResult = await writeEnvFile$1(projectDir, config);
|
|
5579
5672
|
if (envResult.isErr()) return envResult;
|
|
5580
5673
|
displayManualSetupInstructions$1(target);
|
|
5581
5674
|
return Result.ok(void 0);
|
|
@@ -5600,7 +5693,7 @@ async function setupPrismaPostgres(config, cliInput) {
|
|
|
5600
5693
|
selectedSetupMode = promptedSetupMode;
|
|
5601
5694
|
}
|
|
5602
5695
|
if (selectedSetupMode === "manual") {
|
|
5603
|
-
const envResult = await writeEnvFile$1(projectDir,
|
|
5696
|
+
const envResult = await writeEnvFile$1(projectDir, config);
|
|
5604
5697
|
if (envResult.isErr()) return envResult;
|
|
5605
5698
|
displayManualSetupInstructions$1(target);
|
|
5606
5699
|
return Result.ok(void 0);
|
|
@@ -5609,13 +5702,13 @@ async function setupPrismaPostgres(config, cliInput) {
|
|
|
5609
5702
|
if (prismaConfigResult.isErr()) {
|
|
5610
5703
|
if (UserCancelledError.is(prismaConfigResult.error)) return Result.err(prismaConfigResult.error);
|
|
5611
5704
|
cliLog.error(pc.red(prismaConfigResult.error.message));
|
|
5612
|
-
const envResult = await writeEnvFile$1(projectDir,
|
|
5705
|
+
const envResult = await writeEnvFile$1(projectDir, config);
|
|
5613
5706
|
if (envResult.isErr()) return envResult;
|
|
5614
5707
|
displayManualSetupInstructions$1(target);
|
|
5615
5708
|
cliLog.info("Setup completed with manual configuration required.");
|
|
5616
5709
|
return Result.ok(void 0);
|
|
5617
5710
|
}
|
|
5618
|
-
const envResult = await writeEnvFile$1(projectDir,
|
|
5711
|
+
const envResult = await writeEnvFile$1(projectDir, config, prismaConfigResult.value);
|
|
5619
5712
|
if (envResult.isErr()) return envResult;
|
|
5620
5713
|
cliLog.success(pc.green("Prisma Postgres database configured successfully!"));
|
|
5621
5714
|
if (prismaConfigResult.value.claimUrl) cliLog.info(pc.blue(`Claim URL saved to .env: ${prismaConfigResult.value.claimUrl}`));
|
|
@@ -5623,10 +5716,10 @@ async function setupPrismaPostgres(config, cliInput) {
|
|
|
5623
5716
|
}
|
|
5624
5717
|
//#endregion
|
|
5625
5718
|
//#region src/helpers/database-providers/supabase-setup.ts
|
|
5626
|
-
async function writeSupabaseEnvFile(projectDir,
|
|
5719
|
+
async function writeSupabaseEnvFile(projectDir, project, databaseUrl) {
|
|
5627
5720
|
return Result.tryPromise({
|
|
5628
5721
|
try: async () => {
|
|
5629
|
-
const targetApp =
|
|
5722
|
+
const targetApp = getDbEnvTargetApp(project);
|
|
5630
5723
|
const envPath = path.join(projectDir, targetApp, ".env");
|
|
5631
5724
|
const dbUrlToUse = databaseUrl || "postgresql://postgres:postgres@127.0.0.1:54322/postgres";
|
|
5632
5725
|
await addEnvVariablesToFile(envPath, [{
|
|
@@ -5710,13 +5803,13 @@ ${pc.dim(output)}` : ""}
|
|
|
5710
5803
|
${pc.gray("DATABASE_URL=\"your_supabase_db_url\"")}`);
|
|
5711
5804
|
}
|
|
5712
5805
|
async function setupSupabase(config, cliInput) {
|
|
5713
|
-
const { projectDir, packageManager
|
|
5714
|
-
const targetApp =
|
|
5806
|
+
const { projectDir, packageManager } = config;
|
|
5807
|
+
const targetApp = getDbEnvTargetApp(config);
|
|
5715
5808
|
const setupMode = resolveDbSetupMode("supabase", {
|
|
5716
5809
|
manualDb: cliInput?.manualDb,
|
|
5717
5810
|
dbSetupOptions: cliInput?.dbSetupOptions ?? config.dbSetupOptions
|
|
5718
5811
|
});
|
|
5719
|
-
const serverDir = path.join(projectDir,
|
|
5812
|
+
const serverDir = path.join(projectDir, pkgDir(config, "db"));
|
|
5720
5813
|
const ensureDirResult = await Result.tryPromise({
|
|
5721
5814
|
try: () => fs.ensureDir(serverDir),
|
|
5722
5815
|
catch: (e) => new DatabaseSetupError({
|
|
@@ -5728,7 +5821,7 @@ async function setupSupabase(config, cliInput) {
|
|
|
5728
5821
|
if (ensureDirResult.isErr()) return ensureDirResult;
|
|
5729
5822
|
if (setupMode === "manual") {
|
|
5730
5823
|
displayManualSupabaseInstructions(targetApp);
|
|
5731
|
-
return writeSupabaseEnvFile(projectDir,
|
|
5824
|
+
return writeSupabaseEnvFile(projectDir, config, "");
|
|
5732
5825
|
}
|
|
5733
5826
|
let mode = setupMode;
|
|
5734
5827
|
if (!mode) if (isSilent()) mode = "manual";
|
|
@@ -5751,24 +5844,24 @@ async function setupSupabase(config, cliInput) {
|
|
|
5751
5844
|
}
|
|
5752
5845
|
if (mode === "manual") {
|
|
5753
5846
|
displayManualSupabaseInstructions(targetApp);
|
|
5754
|
-
return writeSupabaseEnvFile(projectDir,
|
|
5847
|
+
return writeSupabaseEnvFile(projectDir, config, "");
|
|
5755
5848
|
}
|
|
5756
5849
|
const initResult = await initializeSupabase(serverDir, packageManager);
|
|
5757
5850
|
if (initResult.isErr()) {
|
|
5758
5851
|
cliLog.error(pc.red(initResult.error.message));
|
|
5759
5852
|
displayManualSupabaseInstructions(targetApp);
|
|
5760
|
-
return writeSupabaseEnvFile(projectDir,
|
|
5853
|
+
return writeSupabaseEnvFile(projectDir, config, "");
|
|
5761
5854
|
}
|
|
5762
5855
|
const startResult = await startSupabase(serverDir, packageManager);
|
|
5763
5856
|
if (startResult.isErr()) {
|
|
5764
5857
|
cliLog.error(pc.red(startResult.error.message));
|
|
5765
5858
|
displayManualSupabaseInstructions(targetApp);
|
|
5766
|
-
return writeSupabaseEnvFile(projectDir,
|
|
5859
|
+
return writeSupabaseEnvFile(projectDir, config, "");
|
|
5767
5860
|
}
|
|
5768
5861
|
const supabaseOutput = startResult.value;
|
|
5769
5862
|
const dbUrl = extractDbUrl(supabaseOutput);
|
|
5770
5863
|
if (dbUrl) {
|
|
5771
|
-
const envResult = await writeSupabaseEnvFile(projectDir,
|
|
5864
|
+
const envResult = await writeSupabaseEnvFile(projectDir, config, dbUrl);
|
|
5772
5865
|
if (envResult.isOk()) cliLog.success(pc.green("Supabase local development setup ready!"));
|
|
5773
5866
|
else {
|
|
5774
5867
|
cliLog.error(pc.red("Supabase setup completed, but failed to update .env automatically."));
|
|
@@ -5929,10 +6022,10 @@ async function createTursoDatabase(dbName, groupName) {
|
|
|
5929
6022
|
}
|
|
5930
6023
|
});
|
|
5931
6024
|
}
|
|
5932
|
-
async function writeEnvFile(projectDir,
|
|
6025
|
+
async function writeEnvFile(projectDir, project, config) {
|
|
5933
6026
|
return Result.tryPromise({
|
|
5934
6027
|
try: async () => {
|
|
5935
|
-
const targetApp =
|
|
6028
|
+
const targetApp = getDbEnvTargetApp(project);
|
|
5936
6029
|
await addEnvVariablesToFile(path.join(projectDir, targetApp, ".env"), [{
|
|
5937
6030
|
key: "DATABASE_URL",
|
|
5938
6031
|
value: config?.dbUrl ?? "",
|
|
@@ -5962,15 +6055,15 @@ DATABASE_URL=your_database_url
|
|
|
5962
6055
|
DATABASE_AUTH_TOKEN=your_auth_token`);
|
|
5963
6056
|
}
|
|
5964
6057
|
async function setupTurso(config, cliInput) {
|
|
5965
|
-
const { projectDir
|
|
5966
|
-
const targetApp =
|
|
6058
|
+
const { projectDir } = config;
|
|
6059
|
+
const targetApp = getDbEnvTargetApp(config);
|
|
5967
6060
|
const setupMode = resolveDbSetupMode("turso", {
|
|
5968
6061
|
manualDb: cliInput?.manualDb,
|
|
5969
6062
|
dbSetupOptions: cliInput?.dbSetupOptions ?? config.dbSetupOptions
|
|
5970
6063
|
});
|
|
5971
6064
|
const setupSpinner = createSpinner();
|
|
5972
6065
|
if (setupMode === "manual") {
|
|
5973
|
-
const envResult = await writeEnvFile(projectDir,
|
|
6066
|
+
const envResult = await writeEnvFile(projectDir, config);
|
|
5974
6067
|
if (envResult.isErr()) return envResult;
|
|
5975
6068
|
displayManualSetupInstructions(targetApp);
|
|
5976
6069
|
return Result.ok(void 0);
|
|
@@ -5995,7 +6088,7 @@ async function setupTurso(config, cliInput) {
|
|
|
5995
6088
|
mode = promptedMode;
|
|
5996
6089
|
}
|
|
5997
6090
|
if (mode === "manual") {
|
|
5998
|
-
const envResult = await writeEnvFile(projectDir,
|
|
6091
|
+
const envResult = await writeEnvFile(projectDir, config);
|
|
5999
6092
|
if (envResult.isErr()) return envResult;
|
|
6000
6093
|
displayManualSetupInstructions(targetApp);
|
|
6001
6094
|
return Result.ok(void 0);
|
|
@@ -6006,7 +6099,7 @@ async function setupTurso(config, cliInput) {
|
|
|
6006
6099
|
if (platform === "win32") {
|
|
6007
6100
|
setupSpinner.stop(pc.yellow("Turso setup not supported on Windows"));
|
|
6008
6101
|
cliLog.warn(pc.yellow("Automatic Turso setup is not supported on Windows."));
|
|
6009
|
-
const envResult = await writeEnvFile(projectDir,
|
|
6102
|
+
const envResult = await writeEnvFile(projectDir, config);
|
|
6010
6103
|
if (envResult.isErr()) return envResult;
|
|
6011
6104
|
displayManualSetupInstructions(targetApp);
|
|
6012
6105
|
return Result.ok(void 0);
|
|
@@ -6024,7 +6117,7 @@ async function setupTurso(config, cliInput) {
|
|
|
6024
6117
|
shouldInstall = promptedInstall;
|
|
6025
6118
|
}
|
|
6026
6119
|
if (!shouldInstall) {
|
|
6027
|
-
const envResult = await writeEnvFile(projectDir,
|
|
6120
|
+
const envResult = await writeEnvFile(projectDir, config);
|
|
6028
6121
|
if (envResult.isErr()) return envResult;
|
|
6029
6122
|
displayManualSetupInstructions(targetApp);
|
|
6030
6123
|
return Result.ok(void 0);
|
|
@@ -6032,7 +6125,7 @@ async function setupTurso(config, cliInput) {
|
|
|
6032
6125
|
const installResult = await installTursoCLI(isMac);
|
|
6033
6126
|
if (installResult.isErr()) {
|
|
6034
6127
|
cliLog.error(pc.red(installResult.error.message));
|
|
6035
|
-
const envResult = await writeEnvFile(projectDir,
|
|
6128
|
+
const envResult = await writeEnvFile(projectDir, config);
|
|
6036
6129
|
if (envResult.isErr()) return envResult;
|
|
6037
6130
|
displayManualSetupInstructions(targetApp);
|
|
6038
6131
|
return Result.ok(void 0);
|
|
@@ -6041,7 +6134,7 @@ async function setupTurso(config, cliInput) {
|
|
|
6041
6134
|
if (!await isTursoLoggedIn()) {
|
|
6042
6135
|
if (isSilent()) {
|
|
6043
6136
|
cliLog.warn(pc.yellow("Turso CLI is not logged in. Falling back to manual setup."));
|
|
6044
|
-
const envResult = await writeEnvFile(projectDir,
|
|
6137
|
+
const envResult = await writeEnvFile(projectDir, config);
|
|
6045
6138
|
if (envResult.isErr()) return envResult;
|
|
6046
6139
|
displayManualSetupInstructions(targetApp);
|
|
6047
6140
|
return Result.ok(void 0);
|
|
@@ -6049,7 +6142,7 @@ async function setupTurso(config, cliInput) {
|
|
|
6049
6142
|
const loginResult = await loginToTurso();
|
|
6050
6143
|
if (loginResult.isErr()) {
|
|
6051
6144
|
cliLog.error(pc.red(loginResult.error.message));
|
|
6052
|
-
const envResult = await writeEnvFile(projectDir,
|
|
6145
|
+
const envResult = await writeEnvFile(projectDir, config);
|
|
6053
6146
|
if (envResult.isErr()) return envResult;
|
|
6054
6147
|
displayManualSetupInstructions(targetApp);
|
|
6055
6148
|
return Result.ok(void 0);
|
|
@@ -6067,13 +6160,13 @@ async function setupTurso(config, cliInput) {
|
|
|
6067
6160
|
const createResult = await createTursoDatabase(suggestedName, selectedGroup);
|
|
6068
6161
|
if (createResult.isErr()) {
|
|
6069
6162
|
cliLog.error(pc.red(createResult.error.message));
|
|
6070
|
-
const envResult = await writeEnvFile(projectDir,
|
|
6163
|
+
const envResult = await writeEnvFile(projectDir, config);
|
|
6071
6164
|
if (envResult.isErr()) return envResult;
|
|
6072
6165
|
displayManualSetupInstructions(targetApp);
|
|
6073
6166
|
cliLog.success("Setup completed with manual configuration required.");
|
|
6074
6167
|
return Result.ok(void 0);
|
|
6075
6168
|
}
|
|
6076
|
-
const envResult = await writeEnvFile(projectDir,
|
|
6169
|
+
const envResult = await writeEnvFile(projectDir, config, createResult.value);
|
|
6077
6170
|
if (envResult.isErr()) return envResult;
|
|
6078
6171
|
cliLog.success("Turso database setup completed successfully!");
|
|
6079
6172
|
return Result.ok(void 0);
|
|
@@ -6095,13 +6188,13 @@ async function setupTurso(config, cliInput) {
|
|
|
6095
6188
|
continue;
|
|
6096
6189
|
}
|
|
6097
6190
|
cliLog.error(pc.red(createResult.error.message));
|
|
6098
|
-
const envResult = await writeEnvFile(projectDir,
|
|
6191
|
+
const envResult = await writeEnvFile(projectDir, config);
|
|
6099
6192
|
if (envResult.isErr()) return envResult;
|
|
6100
6193
|
displayManualSetupInstructions(targetApp);
|
|
6101
6194
|
cliLog.success("Setup completed with manual configuration required.");
|
|
6102
6195
|
return Result.ok(void 0);
|
|
6103
6196
|
}
|
|
6104
|
-
const envResult = await writeEnvFile(projectDir,
|
|
6197
|
+
const envResult = await writeEnvFile(projectDir, config, createResult.value);
|
|
6105
6198
|
if (envResult.isErr()) return envResult;
|
|
6106
6199
|
cliLog.success("Turso database setup completed successfully!");
|
|
6107
6200
|
return Result.ok(void 0);
|
|
@@ -6118,12 +6211,12 @@ async function setupDatabase(config, cliInput) {
|
|
|
6118
6211
|
const { database, dbSetup, backend, projectDir } = config;
|
|
6119
6212
|
if (backend === "convex" || database === "none") {
|
|
6120
6213
|
if (backend !== "convex") {
|
|
6121
|
-
const serverDbDir = path.join(projectDir, "
|
|
6214
|
+
const serverDbDir = path.join(projectDir, appDir(config, "server"), "src/db");
|
|
6122
6215
|
if (await fs.pathExists(serverDbDir)) await fs.remove(serverDbDir);
|
|
6123
6216
|
}
|
|
6124
6217
|
return;
|
|
6125
6218
|
}
|
|
6126
|
-
const dbPackageDir = path.join(projectDir, "
|
|
6219
|
+
const dbPackageDir = path.join(projectDir, pkgDir(config, "db"));
|
|
6127
6220
|
if (!await fs.pathExists(dbPackageDir)) return;
|
|
6128
6221
|
async function runSetup(setupFn) {
|
|
6129
6222
|
const result = await setupFn();
|
|
@@ -6338,7 +6431,7 @@ async function displayPostInstallInstructions(config) {
|
|
|
6338
6431
|
if (bunWebNativeWarning) output += `\n${bunWebNativeWarning.trim()}\n`;
|
|
6339
6432
|
output += `\n${pc$1.bold("Like kubojs?")} Please consider giving us a star\n on GitHub:\n`;
|
|
6340
6433
|
output += pc$1.cyan("https://github.com/albuquerquesz/kubo");
|
|
6341
|
-
cliConsola.box(output);
|
|
6434
|
+
cliConsola.box(relocateLayoutPaths(output, config));
|
|
6342
6435
|
}
|
|
6343
6436
|
function getNativeInstructions(isConvex, isBackendSelf, frontend, runCmd) {
|
|
6344
6437
|
const envVar = isConvex ? "EXPO_PUBLIC_CONVEX_URL" : "EXPO_PUBLIC_SERVER_URL";
|
|
@@ -6731,6 +6824,13 @@ async function createProjectHandler(input, options = {}) {
|
|
|
6731
6824
|
process.exit(1);
|
|
6732
6825
|
});
|
|
6733
6826
|
}
|
|
6827
|
+
/** `--layout` and `--layout-code` are exclusive; a code is redeemed (and consumed) here. */
|
|
6828
|
+
async function resolveInputLayout(input) {
|
|
6829
|
+
if (input.layoutCode === void 0) return Result.ok(input.layout);
|
|
6830
|
+
if (input.layout !== void 0) return Result.err(new CLIError({ message: "Use either --layout or --layout-code, not both." }));
|
|
6831
|
+
if (input.dryRun) return Result.err(new CLIError({ message: "--layout-code is single-use and cannot be combined with --dry-run." }));
|
|
6832
|
+
return redeemLayoutCode(input.layoutCode);
|
|
6833
|
+
}
|
|
6734
6834
|
/** Stack-selecting flags; their presence means the user chose the stack via flags, not prompts. */
|
|
6735
6835
|
const STACK_FLAG_KEYS = [
|
|
6736
6836
|
"database",
|
|
@@ -6768,6 +6868,7 @@ async function createProjectHandlerInternal(input, startTime, timeScaffolded) {
|
|
|
6768
6868
|
if (!isSilent() && input.renderTitle !== false) renderTitle();
|
|
6769
6869
|
if (!isSilent()) intro(cliColors.bright("Creating a new kubojs project"));
|
|
6770
6870
|
if (!isSilent() && input.yolo) cliConsola.fatal("YOLO mode enabled - skipping checks. Things may break!");
|
|
6871
|
+
const layout = yield* validateCreateLayout(yield* Result.await(resolveInputLayout(input)));
|
|
6771
6872
|
let currentPathInput;
|
|
6772
6873
|
if (isSilent()) currentPathInput = yield* Result.await(resolveProjectNameForSilent(input));
|
|
6773
6874
|
else if (input.yes && input.projectName) currentPathInput = input.projectName;
|
|
@@ -6897,6 +6998,10 @@ async function createProjectHandlerInternal(input, startTime, timeScaffolded) {
|
|
|
6897
6998
|
...config,
|
|
6898
6999
|
dbSetupOptions: effectiveDbSetupOptions
|
|
6899
7000
|
};
|
|
7001
|
+
if (layout) config = {
|
|
7002
|
+
...config,
|
|
7003
|
+
layout
|
|
7004
|
+
};
|
|
6900
7005
|
if (!input.yolo) {
|
|
6901
7006
|
const addonsValidationResult = validateAddonsAgainstFrontends(config.addons, config.frontend, config.auth, config.backend, config.runtime);
|
|
6902
7007
|
if (addonsValidationResult.isErr()) return Result.err(new CLIError({ message: addonsValidationResult.error.message }));
|
|
@@ -7106,12 +7211,17 @@ const router = t.router({
|
|
|
7106
7211
|
renderTitle: z.boolean().optional(),
|
|
7107
7212
|
disableAnalytics: z.boolean().optional().default(false).describe("Disable analytics"),
|
|
7108
7213
|
manualDb: z.boolean().optional().default(false).describe("Skip automatic/manual database setup prompt and use manual setup"),
|
|
7109
|
-
dbSetupOptions: types_exports.DbSetupOptionsSchema.optional().describe("Structured database setup options")
|
|
7214
|
+
dbSetupOptions: types_exports.DbSetupOptionsSchema.optional().describe("Structured database setup options"),
|
|
7215
|
+
layout: z.string().optional().describe("Folder layout: a preset (standard, libs) or JSON, e.g. '{\"preset\":\"libs\",\"apps\":{\"web\":\"web\"}}'"),
|
|
7216
|
+
layoutCode: z.string().optional().describe("Single-use code from the Layout tab at kubojs.dev/new (applies your saved layout)")
|
|
7110
7217
|
})])).mutation(async ({ input }) => {
|
|
7111
7218
|
const [projectName, options] = input;
|
|
7219
|
+
const layoutResult = options.layout === void 0 ? Result.ok(void 0) : parseLayoutFlag(options.layout);
|
|
7220
|
+
if (layoutResult.isErr()) throw layoutResult.error;
|
|
7112
7221
|
const result = await createProjectHandler({
|
|
7113
7222
|
projectName,
|
|
7114
|
-
...options
|
|
7223
|
+
...options,
|
|
7224
|
+
layout: layoutResult.value
|
|
7115
7225
|
});
|
|
7116
7226
|
if (options.verbose || options.dryRun) return result;
|
|
7117
7227
|
}),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-kubojs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "A modern CLI tool for scaffolding end-to-end type-safe TypeScript projects with best practices and customizable configurations",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"better-auth",
|
|
@@ -73,8 +73,8 @@
|
|
|
73
73
|
"dependencies": {
|
|
74
74
|
"@clack/core": "^1.4.1",
|
|
75
75
|
"@clack/prompts": "^1.5.1",
|
|
76
|
-
"@kubojs/template-generator": "^0.
|
|
77
|
-
"@kubojs/types": "^0.
|
|
76
|
+
"@kubojs/template-generator": "^0.6.0",
|
|
77
|
+
"@kubojs/types": "^0.6.0",
|
|
78
78
|
"@modelcontextprotocol/sdk": "1.29.0",
|
|
79
79
|
"@tanstack/router-generator": "1.167.28",
|
|
80
80
|
"@trpc/server": "^11.17.0",
|