diff --git a/.gitignore b/.gitignore index 5e3893a..6d5c17c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,6 @@ dist-npm/ .DS_Store merged.txt .eslintcache -.cursorrules node_modules/ addons/premium/ addons/**/premium/ diff --git a/.reliverse b/.reliverse index c493658..11a8770 100644 --- a/.reliverse +++ b/.reliverse @@ -61,7 +61,7 @@ "ignoreDependencies": [], // Config revalidation (1h | 1d | 2d | 7d) - "configLastRevalidate": "2024-12-25T13:06:12.128Z", + "configLastRevalidate": "2024-12-29T20:57:03.697Z", "configRevalidateFrequency": "2d", // Custom rules for Reliverse AI diff --git a/build.optim.ts b/build.optim.ts index d0b7758..f1ce4e8 100644 --- a/build.optim.ts +++ b/build.optim.ts @@ -27,10 +27,9 @@ const npmFilesToDelete: string[] = [ "types/internal.d.ts", "**/*.temp.js", "**/*.temp.d.ts", - "**/*.txt", ]; -const jsrFilesToDelete: string[] = ["**/*.test.ts", "**/*.temp.ts", "**/*.txt"]; +const jsrFilesToDelete: string[] = ["**/*.test.ts", "**/*.temp.ts"]; /** * Deletes files matching the provided patterns within the base directory. @@ -241,6 +240,31 @@ async function copySrcToOutput(): Promise { } } +/** + * Renames all .tsx files to -tsx.txt in the specified directory and its subdirectories. + * @param dir - The directory to process. + */ +async function renameTsxFiles(dir: string): Promise { + try { + const files = await globby("**/*.tsx", { + cwd: dir, + absolute: true, + }); + + for (const filePath of files) { + const newPath = filePath.replace(/\.tsx$/, "-tsx.txt"); + await fs.rename(filePath, newPath); + relinka("info-verbose", `Renamed: ${filePath} -> ${newPath}`); + } + } catch (error) { + relinka( + "error", + "Error renaming .tsx files:", + error instanceof Error ? error.message : String(error), + ); + } +} + /** * Optimizes the build for production by processing files and deleting unnecessary ones. * @param dir - The directory to optimize. @@ -256,6 +280,8 @@ async function optimizeBuildForProduction(dir: string): Promise { await copySrcToOutput(); relinka("info", "Processing copied files to replace import paths..."); await processFiles(outputDir); // Process files after copying + relinka("info", "Renaming .tsx files to -tsx.txt for JSR compatibility..."); + await renameTsxFiles(outputDir); } else { relinka("info", "Creating an optimized production build..."); await processFiles(dir); diff --git a/bun.lockb b/bun.lockb index 00bc285..01c5775 100644 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/cspell.json b/cspell.json index ddc88a0..7fedc6b 100644 --- a/cspell.json +++ b/cspell.json @@ -1,9 +1,6 @@ { "version": "0.2", "language": "en", - "import": [ - "@cspell/dict-npm/cspell-ext.json" - ], "ignorePaths": [ "**/*.lock", "**/*.txt", @@ -46,6 +43,7 @@ "continuar", "cristal", "cronvel", + "crossplatform", "datepart", "dateparts", "deafult", @@ -99,6 +97,7 @@ "mkdist", "Mkey", "montag", + "moonrepo", "Nazar", "Nazarii", "nenc", @@ -149,6 +148,7 @@ "termkit", "tseslint", "Tully", + "turborepo", "turso", "typebox", "typecheck", @@ -164,6 +164,7 @@ "valign", "venv", "versator", + "VITE", "Vous", "vsprintf", "Whoo", diff --git a/jsr.jsonc b/jsr.jsonc index 01922f9..61d7e30 100644 --- a/jsr.jsonc +++ b/jsr.jsonc @@ -1,6 +1,6 @@ { "name": "@reliverse/cli", - "version": "1.4.3", + "version": "1.4.8", "author": "blefnk", "license": "MIT", "exports": "./dist-jsr/main.ts", @@ -34,4 +34,4 @@ "tests-runtime/**" ] } -} +} \ No newline at end of file diff --git a/package.json b/package.json index ba15850..f007065 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@reliverse/cli", - "version": "1.4.3", + "version": "1.4.8", "author": "blefnk", "type": "module", "description": "This superapp CLI tool can help you easily create new web projects, manage existing projects, and automatically make advanced codebase modifications, with more features coming soon.", @@ -44,9 +44,17 @@ "url": "https://github.com/reliverse/cli/issues", "email": "blefnk@gmail.com" }, - "files": ["package.json", "README.md", "LICENSE.md", "dist-npm"], + "files": [ + "package.json", + "README.md", + "LICENSE.md", + "dist-npm" + ], "homepage": "https://github.com/reliverse/cli", - "keywords": ["cli", "reliverse"], + "keywords": [ + "cli", + "reliverse" + ], "license": "MIT", "dependencies": { "@clack/core": "^0.4.0", @@ -71,8 +79,8 @@ "drizzle-orm": "^0.38.3", "execa": "^9.5.2", "fs-extra": "^11.2.0", + "geist": "^1.3.1", "globby": "^14.0.2", - "gradient-string": "^3.0.0", "magic-regexp": "^0.8.0", "nanoid": "^5.0.9", "node-emoji": "^2.2.0", @@ -104,6 +112,7 @@ "@planetscale/database": "^1.19.0", "@prisma/adapter-planetscale": "^6.1.0", "@prisma/client": "^6.1.0", + "@react-router/dev": "^7.1.1", "@stylistic/eslint-plugin": "^2.12.1", "@swc/core": "^1.10.3", "@t3-oss/env-nextjs": "^0.11.1", @@ -118,7 +127,6 @@ "@types/cross-spawn": "^6.0.6", "@types/eslint__js": "^8.42.3", "@types/fs-extra": "^11.0.4", - "@types/gradient-string": "^1.1.6", "@types/node": "^22.10.2", "@types/react": "^19.0.2", "@types/react-dom": "^19.0.2", @@ -152,4 +160,4 @@ "vitest": "^2.1.8", "zod": "^3.24.1" } -} +} \ No newline at end of file diff --git a/src/app/db/constants.ts b/src/app/db/constants.ts index dd5db0c..8eb5a06 100644 --- a/src/app/db/constants.ts +++ b/src/app/db/constants.ts @@ -1,7 +1,10 @@ import path from "pathe"; +import { fileURLToPath } from "url"; export const isVerboseEnabled = false; +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); export const PKG_ROOT = path.resolve(__dirname, "../../../.."); // File conflict settings, useful for prompting user to resolve conflicts during project setup diff --git a/src/app/menu/askGithubName.ts b/src/app/menu/askGithubName.ts index 57dfa3a..4a693ea 100644 --- a/src/app/menu/askGithubName.ts +++ b/src/app/menu/askGithubName.ts @@ -1,42 +1,56 @@ import { inputPrompt } from "@reliverse/prompts"; -import pc from "picocolors"; import { readReliverseMemory, updateReliverseMemory, } from "~/args/memory/impl.js"; +import { relinka } from "~/utils/console.js"; -export async function askGithubName(): Promise { - const memory = await readReliverseMemory(); +export async function askGithubName(): Promise { + try { + const memory = await readReliverseMemory(); + if (!memory) { + relinka("error", "Failed to read reliverse memory"); + return null; + } - let placeholder = ""; - let content = ""; + if (memory.githubUsername && memory.githubUsername !== "") { + return memory.githubUsername; + } - if (memory.githubUsername) { - placeholder = memory.githubUsername; - content = `Last used GitHub username: ${pc.cyanBright(placeholder)}`; - } + const ghUsername = await inputPrompt({ + title: "What's your GitHub username?", + content: + "šŸ’” If you don't have a GitHub account, you can create one for free at https://github.com/signup", + validate: (value: string | undefined) => { + if (!value?.trim()) { + return "GitHub username is required for deployment"; + } + if (!/^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i.test(value)) { + return "Invalid GitHub username format"; + } + return true; + }, + }); - const githubUsername = await inputPrompt({ - title: "What's your GitHub username?", - placeholder, - content, - validate: (value: string | undefined) => { - if (!value?.trim()) { - return "GitHub username is required for deployment"; - } - if (!/^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i.test(value)) { - return "Invalid GitHub username format"; - } - return true; - }, - }); + if (ghUsername !== "" && ghUsername !== memory.githubUsername) { + await updateReliverseMemory({ + githubUsername: ghUsername, + }); + } else { + relinka( + "error", + "Something went wrong while saving your GitHub username...", + ); + } - if (githubUsername && githubUsername !== placeholder) { - await updateReliverseMemory({ - githubUsername, - }); + return ghUsername; + } catch (error) { + relinka( + "error", + "Failed to get GitHub username:", + error instanceof Error ? error.message : String(error), + ); + return null; } - - return githubUsername; } diff --git a/src/app/menu/askVercelName.ts b/src/app/menu/askVercelName.ts index c8b9b79..ecc4727 100644 --- a/src/app/menu/askVercelName.ts +++ b/src/app/menu/askVercelName.ts @@ -1,5 +1,4 @@ import { inputPrompt } from "@reliverse/prompts"; -import pc from "picocolors"; import { readReliverseMemory, @@ -10,33 +9,31 @@ export async function askVercelName(): Promise { const memory = await readReliverseMemory(); let placeholder = ""; - let content = ""; if (memory.vercelUsername) { placeholder = memory.vercelUsername; - content = `Last used Vercel username: ${pc.cyanBright(placeholder)}`; } - const vercelUsername = await inputPrompt({ - title: "What's your Vercel team name?", - placeholder, - content, - validate: (value: string): string | boolean => { - if (!value?.trim()) { - return "Vercel username is required for deployment"; - } - if (!/^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i.test(value)) { - return "Invalid Vercel username format"; - } - return true; - }, - }); + if (placeholder === "") { + placeholder = await inputPrompt({ + title: "What's your Vercel team name?", + validate: (value: string): string | boolean => { + if (!value?.trim()) { + return "Vercel username is required for deployment"; + } + if (!/^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i.test(value)) { + return "Invalid Vercel username format"; + } + return true; + }, + }); + } - if (vercelUsername && vercelUsername !== placeholder) { + if (placeholder !== "" && placeholder !== memory.vercelUsername) { await updateReliverseMemory({ - vercelUsername, + vercelUsername: placeholder, }); } - return vercelUsername; + return placeholder; } diff --git a/src/app/menu/buildBrandNewThing.ts b/src/app/menu/buildBrandNewThing.ts index fd2435a..df78064 100644 --- a/src/app/menu/buildBrandNewThing.ts +++ b/src/app/menu/buildBrandNewThing.ts @@ -273,14 +273,14 @@ export async function buildBrandNewThing( title: "Should I continue with advanced or simple mode?", options: [ { - label: "Advanced", + label: pc.bold(pc.greenBright("Advanced")), value: "recommended", - hint: pc.greenBright("āœØ recommended"), + hint: pc.greenBright(pc.reset("āœØ STABLE & RECOMMENDED")), }, { - label: "Simple", + label: pc.dim(pc.red("Simple")), value: "offline", - hint: pc.redBright("šŸšØ experimental, offline"), + hint: pc.red("šŸšØ experimental, offline"), }, ], }); diff --git a/src/app/menu/compose-env-file/mod.ts b/src/app/menu/compose-env-file/mod.ts index 8062ef4..5fdd31e 100644 --- a/src/app/menu/compose-env-file/mod.ts +++ b/src/app/menu/compose-env-file/mod.ts @@ -2,7 +2,6 @@ import { selectPrompt, inputPrompt, confirmPrompt } from "@reliverse/prompts"; import { execa } from "execa"; import fs from "fs-extra"; import open from "open"; -import pc from "picocolors"; import { relinka } from "~/utils/console.js"; @@ -81,8 +80,8 @@ export async function composeEnvFile( "Please provide the path to your existing .env file or directory:", placeholder: process.platform === "win32" - ? `Enter the path (e.g. ${pc.cyanBright("C:\\Users\\name\\project\\.env")} or ${pc.cyanBright("C:\\Users\\name\\project")})` - : `Enter the path (e.g. ${pc.cyanBright("/home/user/project/.env")} or ${pc.cyanBright("/home/user/project")})`, + ? `Enter the path (e.g. "C:\\Users\\name\\project\\.env" or "C:\\Users\\name\\project"` + : `Enter the path (e.g. "/home/user/project/.env" or "/home/user/project"`, content: "You can provide either the .env file path or the directory containing it.", contentColor: "yellowBright", diff --git a/src/app/menu/createWebProject.ts b/src/app/menu/createWebProject.ts index d0b5d76..65e1829 100644 --- a/src/app/menu/createWebProject.ts +++ b/src/app/menu/createWebProject.ts @@ -1,4 +1,4 @@ -import { confirmPrompt, task } from "@reliverse/prompts"; +import { confirmPrompt, spinnerTaskPrompt } from "@reliverse/prompts"; import { multiselectPrompt, nextStepsPrompt } from "@reliverse/prompts"; import { execa } from "execa"; import fs from "fs-extra"; @@ -6,7 +6,7 @@ import { installDependencies } from "nypm"; import open from "open"; import path from "pathe"; -import type { Behavior, ReliverseConfig } from "~/types.js"; +import type { Behavior, DeploymentService, ReliverseConfig } from "~/types.js"; import { decideBehavior } from "~/utils/behavior.js"; import { relinka } from "~/utils/console.js"; @@ -67,12 +67,12 @@ export async function createWebProject({ relinka("info", `Now I'm downloading the ${template} template...`); - await task({ + await spinnerTaskPrompt({ spinnerSolution: "ora", initialMessage: "Downloading template...", successMessage: "āœ… Template downloaded successfully!", errorMessage: "āŒ Failed to download template...", - async action(updateMessage) { + async action(updateMessage: (message: string) => void) { const dir = await downloadGitRepo(projectName, template, isDev); if (!dir) { throw new Error("Failed to create target directory"); @@ -82,13 +82,13 @@ export async function createWebProject({ }, }); - await task({ + await spinnerTaskPrompt({ spinnerSolution: "ora", initialMessage: "Editing some texts in the initialized files...", successMessage: "āœ… I edited some texts in the initialized files for you.", errorMessage: "āŒ I've failed to edit some texts in the initialized files...", - async action(updateMessage) { + async action(updateMessage: (message: string) => void) { const { author, projectName: oldProjectName } = extractRepoInfo(template); updateMessage("Some magic is happening... This may take a while..."); await replaceStringsInFiles(targetDir, { @@ -121,12 +121,12 @@ export async function createWebProject({ } if (i18nShouldBeEnabled && !i18nFolderExists) { - await task({ + await spinnerTaskPrompt({ spinnerSolution: "ora", initialMessage: "Moving app to locale...", successMessage: "āœ… I moved app to locale successfully!", errorMessage: "āŒ I've failed to move app to locale...", - async action(updateMessage) { + async action(updateMessage: (message: string) => void) { try { await i18nMove(targetDir, "moveLocaleToApp"); updateMessage( @@ -147,12 +147,12 @@ export async function createWebProject({ if (!i18nShouldBeEnabled && i18nFolderExists) { relinka("info", "Converting from i18n version to non-i18n..."); - await task({ + await spinnerTaskPrompt({ spinnerSolution: "ora", initialMessage: "Moving app to locale...", successMessage: "āœ… I moved app to locale successfully!", errorMessage: "āŒ I've failed to move app to locale...", - async action(updateMessage) { + async action(updateMessage: (message: string) => void) { await i18nMove(targetDir, "moveLocaleToApp"); updateMessage("Some magic is happening... This may take a while..."); await setupI18nFiles(targetDir); @@ -271,15 +271,17 @@ export async function createWebProject({ const vscodeInstalled = isVSCodeInstalled(); + let deployService: DeploymentService = "none"; + // We skip git deploy if no config is provided if (config) { - await promptGitDeploy(projectName, config, targetDir); + deployService = await promptGitDeploy(projectName, config, targetDir); } await generateReliverseFile({ projectName, frontendUsername, - deployService: "Vercel", + deployService, domain, targetDir, i18nShouldBeEnabled: defaultI18nShouldBeEnabled, @@ -302,6 +304,7 @@ export async function createWebProject({ const nextActions = await multiselectPrompt({ title: "What would you like to do next?", + allowAllUnselected: true, titleColor: "cyanBright", defaultValue: ["ide"], options: [ @@ -323,7 +326,10 @@ export async function createWebProject({ for (const action of nextActions) { if (action === "docs") { - relinka("info", "Opening Reliverse Documentation..."); + relinka( + "info", + "Opening Reliverse Documentation ( https://docs.reliverse.org )...", + ); try { await open("https://docs.reliverse.org"); } catch (error) { @@ -334,7 +340,10 @@ export async function createWebProject({ ); } } else if (action === "discord") { - relinka("info", "Joining Reliverse Discord server..."); + relinka( + "info", + "Opening Reliverse Discord server ( https://discord.gg/Pb8uKbwpsJ )...", + ); try { await open("https://discord.gg/Pb8uKbwpsJ"); } catch (error) { diff --git a/src/app/menu/generateProjectConfigs.ts b/src/app/menu/generateProjectConfigs.ts index 550a5a3..d56f217 100644 --- a/src/app/menu/generateProjectConfigs.ts +++ b/src/app/menu/generateProjectConfigs.ts @@ -1,4 +1,4 @@ -import { task } from "@reliverse/prompts"; +import { spinnerTaskPrompt } from "@reliverse/prompts"; import { destr } from "destr"; import fs from "fs-extra"; import path from "pathe"; @@ -146,7 +146,6 @@ async function generateVSCodeSettings( "markdownlint.config": { MD033: false, }, - // Removed ".reliverserules" association since it's no longer used "typescript.enablePromptUseWorkspaceTsdk": true, }; @@ -197,7 +196,7 @@ async function generateConfigFiles( overwrite = false, filesToGenerate: string[] = [], ): Promise { - await task({ + await spinnerTaskPrompt({ spinnerSolution: "ora", initialMessage: filesToGenerate.length === 0 @@ -213,7 +212,6 @@ async function generateConfigFiles( ); }; - // Removed .reliverserules since it's merged into .reliverse const configGenerators = { ".reliverse": () => generateReliverseConfig(targetDir, overwrite), "biome.json": () => generateBiomeConfig(targetDir, overwrite), diff --git a/src/app/menu/git-deploy-prompts/helpers/deploy.ts b/src/app/menu/git-deploy-prompts/helpers/deploy.ts index 9d9fecd..3c6bb42 100644 --- a/src/app/menu/git-deploy-prompts/helpers/deploy.ts +++ b/src/app/menu/git-deploy-prompts/helpers/deploy.ts @@ -23,10 +23,16 @@ export async function selectDeploymentService( return await selectPrompt({ title: "Select deployment service", options: [ - { label: "Vercel (Recommended)", value: "Vercel" }, - { label: "...", value: "none", hint: pc.dim("coming soon") }, + { label: "Vercel", value: "vercel", hint: "recommended" }, + { label: "None", value: "none", hint: "skip deployment" }, + { + label: "...", + value: "deno", + hint: pc.dim("coming soon"), + disabled: true, + }, ], - defaultValue: "Vercel", + defaultValue: "vercel", }); } @@ -35,35 +41,35 @@ export async function deployProject( config: ReliverseConfig, targetDir: string, domain = "", -): Promise { +): Promise { try { - const shouldUseDataFromConfig = - config?.experimental?.skipPromptsUseAutoBehavior ?? false; - const deployService = await selectDeploymentService(config); if (deployService === "none") { relinka("info", "No deployment service selected. Skipping deployment."); - return false; + return "none"; } const memory = await readReliverseMemory(); if (!memory) { relinka("error", "Failed to read reliverse memory"); - return false; + return "none"; } - if (deployService === "Vercel") { + if (deployService === "vercel") { const { askGithubName } = await import("~/app/menu/askGithubName.js"); + const githubUsername = memory.githubUsername + ? memory.githubUsername + : await askGithubName(); + const { askVercelName } = await import("~/app/menu/askVercelName.js"); + const vercelUsername = memory.vercelUsername + ? memory.vercelUsername + : await askVercelName(); - const githubUsername = - shouldUseDataFromConfig && memory.githubUsername - ? memory.githubUsername - : await askGithubName(); - const vercelUsername = - shouldUseDataFromConfig && memory.vercelUsername - ? memory.vercelUsername - : await askVercelName(); + if (!githubUsername || !vercelUsername) { + relinka("error", "Could not determine GitHub or Vercel username"); + return "none"; + } await createVercelDeployment( targetDir, @@ -72,17 +78,17 @@ export async function deployProject( vercelUsername, domain, ); - return true; + return "vercel"; } relinka("info", `Deployment to ${deployService} is not yet implemented.`); - return false; + return "none"; } catch (error) { relinka( "error", "Error deploying project:", error instanceof Error ? error.message : String(error), ); - return false; + return "none"; } } diff --git a/src/app/menu/git-deploy-prompts/helpers/git.ts b/src/app/menu/git-deploy-prompts/helpers/git.ts index 79b3b82..1ce05f0 100644 --- a/src/app/menu/git-deploy-prompts/helpers/git.ts +++ b/src/app/menu/git-deploy-prompts/helpers/git.ts @@ -4,18 +4,44 @@ import fs from "fs-extra"; import path from "pathe"; import { simpleGit } from "simple-git"; -import type { ReliverseConfig } from "~/types.js"; - +import { askGithubName } from "~/app/menu/askGithubName.js"; import { readReliverseMemory } from "~/args/memory/impl.js"; import { relinka } from "~/utils/console.js"; import { createGithubRepo } from "./github.js"; +/** + * Checks if the given directory is a git repository + * @param dir - Directory to check + * @returns Promise - Whether the directory is a git repository + */ async function isGitRepo(dir: string): Promise { try { + if (!(await fs.pathExists(dir))) { + relinka("error", `Directory does not exist: ${dir}`); + return false; + } + + const gitDir = path.join(dir, ".git"); + if (!(await fs.pathExists(gitDir))) { + return false; + } + const git = simpleGit({ baseDir: dir }); return await git.checkIsRepo(); - } catch { + } catch (error) { + // Only log if it's not a "not a git repo" error + if ( + !( + error instanceof Error && error.message.includes("not a git repository") + ) + ) { + relinka( + "error", + "Error checking git repository:", + error instanceof Error ? error.message : String(error), + ); + } return false; } } @@ -28,12 +54,6 @@ export async function initGit(dir: string): Promise { return false; } - // Check if git is already initialized - if (await isGitRepo(dir)) { - relinka("info", "Git repository already initialized."); - return true; - } - // Clean any partial .git directory const gitDir = path.join(dir, ".git"); if (await fs.pathExists(gitDir)) { @@ -70,39 +90,53 @@ export async function initGit(dir: string): Promise { } } -export async function createRepo( +/** + * Creates a GitHub repository and sets it up locally + * @param projectName - Name of the project/repository + * @param targetDir - Local directory path + * @param config - Reliverse configuration + * @returns Promise - Whether the operation was successful + */ +export async function createGithubRepository( projectName: string, targetDir: string, - config: ReliverseConfig, ): Promise { try { - const shouldUseDataFromConfig = - config?.experimental?.skipPromptsUseAutoBehavior ?? false; const memory = await readReliverseMemory(); if (!memory) { relinka("error", "Failed to read reliverse memory"); return false; } - // Import askGithubName dynamically to avoid circular dependencies - const { askGithubName } = await import("~/app/menu/askGithubName.js"); - const githubUsername = - shouldUseDataFromConfig && memory.githubUsername - ? memory.githubUsername - : await askGithubName(); + const githubUsername = await askGithubName(); + if (!githubUsername) { + relinka("error", "Could not determine GitHub username"); + return false; + } - return await createGithubRepo( + const success = await createGithubRepo( memory, projectName, githubUsername, targetDir, ); + + if (!success) { + relinka("error", "Failed to create GitHub repository"); + return false; + } + + return true; } catch (error) { - relinka( - "error", - "Error creating GitHub repository:", - error instanceof Error ? error.message : String(error), - ); + if (error instanceof Error && error.message.includes("already exists")) { + relinka("error", `Repository '${projectName}' already exists on GitHub`); + } else { + relinka( + "error", + "Failed to create GitHub repository:", + error instanceof Error ? error.message : String(error), + ); + } return false; } } @@ -120,7 +154,10 @@ export async function setupGitRemote( } if (!(await isGitRepo(dir))) { - relinka("error", "Not a git repository. Please initialize git first."); + relinka( + "error", + "Not a git repository, git should be initialized before setupGitRemote. Something went wrong. Please notify developers.", + ); return false; } diff --git a/src/app/menu/git-deploy-prompts/helpers/vercel.ts b/src/app/menu/git-deploy-prompts/helpers/vercel.ts index 807a18a..53963dd 100644 --- a/src/app/menu/git-deploy-prompts/helpers/vercel.ts +++ b/src/app/menu/git-deploy-prompts/helpers/vercel.ts @@ -1,9 +1,8 @@ import type { Vercel as VercelClient } from "@vercel/sdk"; -import { inputPrompt, task } from "@reliverse/prompts"; +import { inputPrompt, spinnerTaskPrompt } from "@reliverse/prompts"; import fs from "fs-extra"; import path from "pathe"; -import { simpleGit } from "simple-git"; import { readReliverseMemory, @@ -17,7 +16,6 @@ async function ensureVercelToken(): Promise { return memory.vercelKey; } - relinka("info", "Opening Vercel tokens page in your browser..."); const vercelToken = await inputPrompt({ title: "Please create and paste your Vercel token:", content: "Visit šŸ‘‰ https://vercel.com/account/tokens", @@ -43,23 +41,6 @@ async function ensureVercelToken(): Promise { return vercelToken; } -async function pushToRemoteIfNeeded(targetDir: string) { - relinka("info", "Pushing to remote repository..."); - const git = simpleGit({ baseDir: targetDir }); - - try { - await git.push("origin", "main", ["--set-upstream"]); - relinka("success", "Successfully pushed to remote repository!"); - } catch (pushError) { - relinka( - "error", - "Failed to push to repository:", - pushError instanceof Error ? pushError.message : String(pushError), - ); - throw pushError; - } -} - async function createVercelProject( vercel: VercelClient, repoOwner: string, @@ -181,7 +162,7 @@ async function createAndCheckVercelDeployment( let deploymentStatus: string | undefined; let deploymentURL: string | undefined; - await task({ + await spinnerTaskPrompt({ spinnerSolution: "ora", initialMessage: "Checking deployment status...", successMessage: "āœ… Deployment status check complete", @@ -236,8 +217,6 @@ export async function createVercelDeployment( domain: string, ) { try { - await pushToRemoteIfNeeded(targetDir); - relinka("info", "Checking for Vercel authentication..."); const vercelToken = await ensureVercelToken(); const { Vercel } = await import("@vercel/sdk"); diff --git a/src/app/menu/git-deploy-prompts/mod.ts b/src/app/menu/git-deploy-prompts/mod.ts index ae785e7..69a85ff 100644 --- a/src/app/menu/git-deploy-prompts/mod.ts +++ b/src/app/menu/git-deploy-prompts/mod.ts @@ -1,109 +1,158 @@ import { confirmPrompt } from "@reliverse/prompts"; -import type { Behavior, ReliverseConfig } from "~/types.js"; +import type { DeploymentService, ReliverseConfig } from "~/types.js"; import { relinka } from "~/utils/console.js"; import { deployProject } from "./helpers/deploy.js"; -import { createRepo, initGit } from "./helpers/git.js"; +import { createGithubRepository, initGit } from "./helpers/git.js"; +type DecisionKey = "gitBehavior" | "deployBehavior"; + +/** + * Makes a decision based on config or user prompt + * @param config - Reliverse configuration + * @param behaviorKey - Which behavior to check + * @param title - Prompt title for user + * @param defaultValue - Default value if prompting + */ async function decide( config: ReliverseConfig, - behaviorKey: keyof NonNullable, + behaviorKey: DecisionKey, title: string, defaultValue = true, ): Promise { - const behavior = (config?.experimental?.[behaviorKey] ?? - "prompt") as Behavior; - switch (behavior) { - case "autoYes": - relinka("info-verbose", `Auto-answering YES to: ${title}`); - return true; - case "autoNo": - relinka("info-verbose", `Auto-answering NO to: ${title}`); - return false; - default: - return await confirmPrompt({ title, defaultValue }); + try { + const behavior = config?.experimental?.[behaviorKey] ?? "prompt"; + + switch (behavior) { + case "autoYes": + relinka("info-verbose", `Auto-answering YES to: ${title}`); + return true; + case "autoNo": + relinka("info-verbose", `Auto-answering NO to: ${title}`); + return false; + case "prompt": + return await confirmPrompt({ + title, + defaultValue, + content: "Press Enter to confirm or Esc to cancel", + }); + default: + relinka("warn", `Unknown behavior '${behavior}', defaulting to prompt`); + return await confirmPrompt({ title, defaultValue }); + } + } catch (error) { + relinka( + "error", + "Failed to get decision:", + error instanceof Error ? error.message : String(error), + ); + return defaultValue; } } +/** + * Handles the git initialization step + */ +async function handleGitInit(targetDir: string): Promise { + const gitInitialized = await initGit(targetDir); + if (!gitInitialized) { + relinka( + "error", + "Failed to initialize git. Stopping git and deploy process.", + ); + return false; + } + return true; +} + +/** + * Handles the GitHub repository creation step + */ +async function handleGithubRepo( + projectName: string, + targetDir: string, +): Promise { + const repoCreated = await createGithubRepository(projectName, targetDir); + if (!repoCreated) { + relinka( + "error", + "Failed to create GitHub repository. Stopping deploy process.", + ); + return false; + } + return true; +} + +/** + * Main function to handle git initialization, GitHub repo creation, and deployment + */ export async function promptGitDeploy( projectName: string, config: ReliverseConfig, targetDir: string, -): Promise { +): Promise { try { - // 1. First ask about git initialization + // 1. Git initialization const shouldInitGit = await decide( config, "gitBehavior", - "Do you want to initialize git?", + "Do you want to initialize git in your project? (This will allow you to push your project to e.g. GitHub and deploy it to e.g. Vercel)", ); if (!shouldInitGit) { relinka("info", "Skipping git initialization."); - return; + return "none"; } - // Initialize git locally without remote - const gitInitialized = await initGit(targetDir); - if (!gitInitialized) { - relinka( - "error", - "Failed to initialize git. Stopping git and deploy process.", - ); - return; - } + if (!(await handleGitInit(targetDir))) return "none"; - // 2. Then ask about GitHub repository + // 2. GitHub repository const shouldCreateRepo = await decide( config, "gitBehavior", - "Do you want to create a GitHub repository and push the initial commit?", + "Do you want to create a GitHub repository and push your code?", ); if (!shouldCreateRepo) { relinka("info", "Skipping GitHub repository creation."); - return; + return "none"; } - const repoCreated = await createRepo(projectName, targetDir, config); - if (!repoCreated) { - relinka( - "error", - "Failed to create GitHub repository. Stopping deploy process.", - ); - return; - } + if (!(await handleGithubRepo(projectName, targetDir))) return "none"; - // 3. Finally ask about deployment + // 3. Deployment const shouldDeployProject = await decide( config, "deployBehavior", - "Do you want to deploy this project to Vercel?", + "Do you want to deploy this project?", ); if (!shouldDeployProject) { relinka("info", "Skipping project deployment."); - return; + return "none"; } - const deployed = await deployProject(projectName, config, targetDir); - - if (!deployed) { - relinka("error", "Failed to deploy project."); - return; - } + if ((await deployProject(projectName, config, targetDir)) === "none") + return "none"; relinka( "success", - "Git initialization, GitHub setup, and deployment completed successfully!", + "Git initialization, GitHub setup, and deployment completed successfully! šŸŽ‰", ); + + return "vercel"; } catch (error) { - relinka( - "error", - "An unexpected error occurred:", - error instanceof Error ? error.message : String(error), - ); + if (error instanceof Error) { + relinka("error", `Deployment process failed: ${error.message}`); + if (error.stack) { + relinka("error-verbose", "Stack trace:", error.stack); + } + } else { + relinka("error", "An unexpected error occurred:", String(error)); + } } + + return "vercel"; } diff --git a/src/app/menu/show-composer-mode/helpers/createProject.ts b/src/app/menu/show-composer-mode/helpers/createProject.ts index 9fb5a6d..bac5913 100644 --- a/src/app/menu/show-composer-mode/helpers/createProject.ts +++ b/src/app/menu/show-composer-mode/helpers/createProject.ts @@ -1,7 +1,8 @@ import fs from "fs-extra"; +import { globby } from "globby"; import path from "pathe"; -import { PKG_ROOT } from "~/consts.js"; +import { PKG_ROOT } from "~/app/db/constants.js"; import { selectAppFile, selectIndexFile, @@ -10,13 +11,10 @@ import { } from "~/app/menu/show-composer-mode/helpers/selectBoilerplate.js"; import { getUserPkgManager } from "~/app/menu/show-composer-mode/utils/getUserPkgManager.js"; -import type { - DatabaseProvider, - PkgInstallerMap, -} from "../../installers/index.js"; +import type { DatabaseProvider, PkgInstallerMap } from "../opts.js"; import { installPackages } from "./installPackages.js"; -import { scaffoldProject } from "./handlers/scaffoldProject.js"; +import { scaffoldProject } from "./scaffoldProject.js"; type CreateProjectOptions = { projectName: string; @@ -28,6 +26,26 @@ type CreateProjectOptions = { databaseProvider: DatabaseProvider; }; +/** + * Renames all .tsx files to -tsx.txt in the specified directory and its subdirectories. + * @param dir - The directory to process. + */ +async function renameTsxFiles(dir: string): Promise { + try { + const files = await globby("**/*.tsx", { + cwd: dir, + absolute: true, + }); + + for (const filePath of files) { + const newPath = filePath.replace(/\.tsx$/, "-tsx.txt"); + await fs.rename(filePath, newPath); + } + } catch (error) { + console.error("Error renaming .tsx files:", error); + } +} + export const createProject = async ({ projectName, scopedAppName, @@ -51,7 +69,7 @@ export const createProject = async ({ }); // Install the selected packages - installPackages({ + await installPackages({ projectName, scopedAppName, projectDir, @@ -92,5 +110,8 @@ export const createProject = async ({ fs.copyFileSync(indexModuleCss, indexModuleCssDest); } + // Rename all .tsx files to -tsx.txt + await renameTsxFiles(projectDir); + return projectDir; }; diff --git a/src/app/menu/show-composer-mode/helpers/installPackages.ts b/src/app/menu/show-composer-mode/helpers/installPackages.ts index a58552e..6142af6 100644 --- a/src/app/menu/show-composer-mode/helpers/installPackages.ts +++ b/src/app/menu/show-composer-mode/helpers/installPackages.ts @@ -1,25 +1,24 @@ +import { execa } from "execa"; import ora from "ora"; import pc from "picocolors"; import { relinka } from "~/utils/console.js"; -import { - type InstallerOptions, - type PkgInstallerMap, -} from "../../installers/index.js"; +import type { PkgInstallerMap } from "../opts.js"; +import type { InstallerOptions } from "../opts.js"; type InstallPackagesOptions = InstallerOptions & { packages: PkgInstallerMap; }; // This runs the installer for all the packages that the user has selected -export const installPackages = (options: InstallPackagesOptions) => { +export const installPackages = async (options: InstallPackagesOptions) => { const { packages } = options; relinka("info", "Adding boilerplate..."); for (const [name, pkgOpts] of Object.entries(packages)) { if (pkgOpts.inUse) { const spinner = ora(`Boilerplating ${name}...`).start(); - pkgOpts.installer(options); + await pkgOpts.installer(options); spinner.succeed( pc.green(`Successfully setup boilerplate for ${pc.bold(name)}`), ); @@ -28,3 +27,20 @@ export const installPackages = (options: InstallPackagesOptions) => { relinka("info", ""); }; + +const trpcDependencies = { + "@tanstack/react-query": "^5.17.19", + "@trpc/client": "^11.0.0", + "@trpc/next": "^11.0.0", + "@trpc/react-query": "^11.0.0", + "@trpc/server": "^11.0.0", + superjson: "^2.2.1", +}; + +export async function installTRPCDependencies(projectDir: string) { + const deps = Object.entries(trpcDependencies) + .map(([pkg, version]) => `${pkg}@${version}`) + .join(" "); + + await execa(`npm install ${deps}`, { cwd: projectDir }); +} diff --git a/src/app/menu/show-composer-mode/helpers/logNextSteps.ts b/src/app/menu/show-composer-mode/helpers/logNextSteps.ts index 084eab5..5fa58c6 100644 --- a/src/app/menu/show-composer-mode/helpers/logNextSteps.ts +++ b/src/app/menu/show-composer-mode/helpers/logNextSteps.ts @@ -1,9 +1,8 @@ -import { DEFAULT_APP_NAME } from "~/consts.js"; -import { type InstallerOptions } from "~/installers/index.js"; +import { DEFAULT_APP_NAME } from "~/app/db/constants.js"; import { relinka } from "~/utils/console.js"; -import { getUserPkgManager } from "~/utils/getUserPkgManager.js"; -import { logger } from "~/utils/logger.js"; +import { type InstallerOptions } from "../opts.js"; +import { getUserPkgManager } from "../utils/getUserPkgManager.js"; import { isInsideGitRepo, isRootGitRepo } from "./git.js"; // This logs the next steps that the user should take in order to advance the project @@ -66,7 +65,7 @@ export const logNextSteps = async ({ } if (!(await isInsideGitRepo(projectDir)) && !isRootGitRepo(projectDir)) { - relinka("info", ` git init`); + relinka("info", " git init"); } - relinka("info", ` git commit -m "initial commit"`); + relinka("info", " git commit -m 'initial commit'"); }; diff --git a/src/app/menu/show-composer-mode/helpers/scaffoldProject.ts b/src/app/menu/show-composer-mode/helpers/scaffoldProject.ts index 8d40b25..8661015 100644 --- a/src/app/menu/show-composer-mode/helpers/scaffoldProject.ts +++ b/src/app/menu/show-composer-mode/helpers/scaffoldProject.ts @@ -1,5 +1,6 @@ import * as p from "@clack/prompts"; import fs from "fs-extra"; +import { globby } from "globby"; import ora from "ora"; import path from "pathe"; import pc from "picocolors"; @@ -9,6 +10,30 @@ import { relinka } from "~/utils/console.js"; import type { InstallerOptions } from "../opts.js"; +/** + * Renames all -tsx.txt files back to .tsx in the specified directory and its subdirectories. + * @param dir - The directory to process. + */ +async function renameTsxFiles(dir: string): Promise { + try { + const files = await globby("**/*-tsx.txt", { + cwd: dir, + absolute: true, + }); + + for (const filePath of files) { + const newPath = filePath.replace(/-tsx\.txt$/, ".tsx"); + await fs.rename(filePath, newPath); + } + } catch (error) { + relinka( + "error", + "Error renaming -tsx.txt files:", + error instanceof Error ? error.message : String(error), + ); + } +} + // This bootstraps the base Next.js application export const scaffoldProject = async ({ projectName, @@ -91,6 +116,9 @@ export const scaffoldProject = async ({ path.join(projectDir, ".gitignore"), ); + // Convert any -tsx.txt files back to .tsx + await renameTsxFiles(projectDir); + const scaffoldedName = projectName === "." ? "App" : pc.bold(pc.cyan(projectName)); diff --git a/src/app/menu/show-composer-mode/helpers/selectBoilerplate.ts b/src/app/menu/show-composer-mode/helpers/selectBoilerplate.ts index bd032ac..3812292 100644 --- a/src/app/menu/show-composer-mode/helpers/selectBoilerplate.ts +++ b/src/app/menu/show-composer-mode/helpers/selectBoilerplate.ts @@ -1,8 +1,9 @@ -import path from "pathe"; import fs from "fs-extra"; +import path from "pathe"; + +import { PKG_ROOT } from "~/app/db/constants.js"; -import { PKG_ROOT } from "~/consts.js"; -import { type InstallerOptions } from "~/installers/index.js"; +import { type InstallerOptions } from "../opts.js"; type SelectBoilerplateProps = Required< Pick diff --git a/src/app/menu/show-composer-mode/helpers/setImportAlias.ts b/src/app/menu/show-composer-mode/helpers/setImportAlias.ts index 7404f17..02ae95c 100644 --- a/src/app/menu/show-composer-mode/helpers/setImportAlias.ts +++ b/src/app/menu/show-composer-mode/helpers/setImportAlias.ts @@ -23,8 +23,9 @@ function replaceTextInFiles( export const setImportAlias = (projectDir: string, importAlias: string) => { const normalizedImportAlias = importAlias .replace(/\*/g, "") // remove any wildcards (~/* -> ~/) + // eslint-disable-next-line no-useless-escape .replace(/[^\/]$/, "$&/"); // ensure trailing slash (@ -> ~/) // update import alias in any files if not using the default - replaceTextInFiles(projectDir, `~/`, normalizedImportAlias); + replaceTextInFiles(projectDir, "~/", normalizedImportAlias); }; diff --git a/src/app/menu/show-composer-mode/installers/dbContainer.ts b/src/app/menu/show-composer-mode/installers/dbContainer.ts index 8d1df35..8cd2dfe 100644 --- a/src/app/menu/show-composer-mode/installers/dbContainer.ts +++ b/src/app/menu/show-composer-mode/installers/dbContainer.ts @@ -1,9 +1,10 @@ import fs from "fs-extra"; import path from "pathe"; -import { PKG_ROOT } from "~/consts.js"; -import { type Installer } from "~/installers/index.js"; -import { parseNameAndPath } from "~/utils/parseNameAndPath.js"; +import { PKG_ROOT } from "~/app/db/constants.js"; + +import { type Installer } from "../opts.js"; +import { parseNameAndPath } from "../utils/parseNameAndPath.js"; // Sanitizes a project name to ensure it adheres to Docker container naming conventions. const sanitizeName = (name: string): string => { diff --git a/src/app/menu/show-composer-mode/installers/drizzle.ts b/src/app/menu/show-composer-mode/installers/drizzle.ts index 2c9cfb8..378b335 100644 --- a/src/app/menu/show-composer-mode/installers/drizzle.ts +++ b/src/app/menu/show-composer-mode/installers/drizzle.ts @@ -1,10 +1,12 @@ -import path from "pathe"; +import type { PackageJson } from "type-fest"; + import fs from "fs-extra"; -import { type PackageJson } from "type-fest"; +import path from "pathe"; + +import { PKG_ROOT } from "~/app/db/constants.js"; -import { PKG_ROOT } from "~/consts.js"; -import { type Installer } from "~/installers/index.js"; -import { addPackageDependency } from "~/utils/addPackageDependency.js"; +import { type Installer } from "../opts.js"; +import { addPackageDependency } from "../utils/addPackageDependency.js"; import { type AvailableDependencies } from "./dependencyVersionMap.js"; export const drizzleInstaller: Installer = ({ diff --git a/src/app/menu/show-composer-mode/installers/envVars.ts b/src/app/menu/show-composer-mode/installers/envVars.ts index a90047f..758a542 100644 --- a/src/app/menu/show-composer-mode/installers/envVars.ts +++ b/src/app/menu/show-composer-mode/installers/envVars.ts @@ -2,8 +2,9 @@ import fs from "fs-extra"; import crypto from "node:crypto"; import path from "pathe"; -import { PKG_ROOT } from "~/consts.js"; -import { type DatabaseProvider, type Installer } from "~/installers/index.js"; +import { PKG_ROOT } from "~/app/db/constants.js"; + +import { type DatabaseProvider, type Installer } from "../opts.js"; export const envVariablesInstaller: Installer = ({ projectDir, @@ -15,7 +16,7 @@ export const envVariablesInstaller: Installer = ({ const usingPrisma = packages?.prisma.inUse; const usingDrizzle = packages?.drizzle.inUse; - const usingDb = usingPrisma || usingDrizzle; + const usingDb = usingPrisma ?? usingDrizzle; const usingPlanetScale = databaseProvider === "planetscale"; const envContent = getEnvContent( diff --git a/src/app/menu/show-composer-mode/installers/eslint.ts b/src/app/menu/show-composer-mode/installers/eslint.ts deleted file mode 100644 index b3522c1..0000000 --- a/src/app/menu/show-composer-mode/installers/eslint.ts +++ /dev/null @@ -1,42 +0,0 @@ -import path from "pathe"; -import fs from "fs-extra"; - -import { _initialConfig } from "~/../template/extras/config/_eslint.js"; -import { type Installer } from "~/installers/index.js"; - -export const dynamicEslintInstaller: Installer = ({ projectDir, packages }) => { - const usingDrizzle = !!packages?.drizzle?.inUse; - - const eslintConfig = getEslintConfig({ usingDrizzle }); - - // Convert config from _eslint.config.json to .eslintrc.cjs - const eslintrcFileContents = [ - '/** @type {import("eslint").Linter.Config} */', - `const config = ${JSON.stringify(eslintConfig, null, 2)}`, - "module.exports = config;", - ].join("\n"); - - const eslintConfigDest = path.join(projectDir, ".eslintrc.cjs"); - fs.writeFileSync(eslintConfigDest, eslintrcFileContents, "utf-8"); -}; - -const getEslintConfig = ({ usingDrizzle }: { usingDrizzle: boolean }) => { - const eslintConfig = _initialConfig; - - if (usingDrizzle) { - eslintConfig.plugins = [...(eslintConfig.plugins ?? []), "drizzle"]; - - eslintConfig.rules = { - ...eslintConfig.rules, - "drizzle/enforce-delete-with-where": [ - "error", - { drizzleObjectName: ["db", "ctx.db"] }, - ], - "drizzle/enforce-update-with-where": [ - "error", - { drizzleObjectName: ["db", "ctx.db"] }, - ], - }; - } - return eslintConfig; -}; diff --git a/src/app/menu/show-composer-mode/installers/nextAuth.ts b/src/app/menu/show-composer-mode/installers/nextAuth.ts index 37e4ed3..5cfaa11 100644 --- a/src/app/menu/show-composer-mode/installers/nextAuth.ts +++ b/src/app/menu/show-composer-mode/installers/nextAuth.ts @@ -1,10 +1,11 @@ -import path from "pathe"; import fs from "fs-extra"; +import path from "pathe"; + +import { PKG_ROOT } from "~/app/db/constants.js"; -import { PKG_ROOT } from "~/consts.js"; -import { type AvailableDependencies } from "~/installers/dependencyVersionMap.js"; -import { type Installer } from "~/installers/index.js"; -import { addPackageDependency } from "~/utils/addPackageDependency.js"; +import { type Installer } from "../opts.js"; +import { addPackageDependency } from "../utils/addPackageDependency.js"; +import { type AvailableDependencies } from "./dependencyVersionMap.js"; export const nextAuthInstaller: Installer = ({ projectDir, packages }) => { const usingPrisma = packages?.prisma.inUse; diff --git a/src/app/menu/show-composer-mode/installers/prisma.ts b/src/app/menu/show-composer-mode/installers/prisma.ts index c5d1ba0..7e6970e 100644 --- a/src/app/menu/show-composer-mode/installers/prisma.ts +++ b/src/app/menu/show-composer-mode/installers/prisma.ts @@ -1,10 +1,12 @@ -import path from "pathe"; +import type { PackageJson } from "type-fest"; + import fs from "fs-extra"; -import { type PackageJson } from "type-fest"; +import path from "pathe"; + +import { PKG_ROOT } from "~/app/db/constants.js"; -import { PKG_ROOT } from "~/consts.js"; -import { type Installer } from "~/installers/index.js"; -import { addPackageDependency } from "~/utils/addPackageDependency.js"; +import { type Installer } from "../opts.js"; +import { addPackageDependency } from "../utils/addPackageDependency.js"; export const prismaInstaller: Installer = ({ projectDir, diff --git a/src/app/menu/show-composer-mode/installers/tailwind.ts b/src/app/menu/show-composer-mode/installers/tailwind.ts index b309f5e..29acf5e 100644 --- a/src/app/menu/show-composer-mode/installers/tailwind.ts +++ b/src/app/menu/show-composer-mode/installers/tailwind.ts @@ -1,10 +1,12 @@ +import type { PackageJson } from "type-fest"; + import fs from "fs-extra"; import path from "pathe"; -import { type PackageJson } from "type-fest"; import { PKG_ROOT } from "~/app/db/constants.js"; -import { type Installer } from "~/app/menu/show-composer-mode/helpers/installers/index.js"; -import { addPackageDependency } from "~/app/menu/show-composer-mode/utils/addPackageDependency.js"; + +import { type Installer } from "../opts.js"; +import { addPackageDependency } from "../utils/addPackageDependency.js"; export const tailwindInstaller: Installer = ({ projectDir }) => { addPackageDependency({ diff --git a/src/app/menu/show-composer-mode/installers/trpc.ts b/src/app/menu/show-composer-mode/installers/trpc.ts index d14cea8..e6335b0 100644 --- a/src/app/menu/show-composer-mode/installers/trpc.ts +++ b/src/app/menu/show-composer-mode/installers/trpc.ts @@ -1,9 +1,10 @@ -import path from "pathe"; import fs from "fs-extra"; +import path from "pathe"; + +import { PKG_ROOT } from "~/app/db/constants.js"; -import { PKG_ROOT } from "~/consts.js"; -import { type Installer } from "~/installers/index.js"; -import { addPackageDependency } from "~/utils/addPackageDependency.js"; +import { type Installer } from "../opts.js"; +import { addPackageDependency } from "../utils/addPackageDependency.js"; export const trpcInstaller: Installer = ({ projectDir, @@ -25,7 +26,7 @@ export const trpcInstaller: Installer = ({ const usingAuth = packages?.nextAuth.inUse; const usingPrisma = packages?.prisma.inUse; const usingDrizzle = packages?.drizzle.inUse; - const usingDb = usingPrisma || usingDrizzle; + const usingDb = usingPrisma ?? usingDrizzle; const extrasDir = path.join(PKG_ROOT, "template/extras"); diff --git a/src/app/menu/show-composer-mode/mod.ts b/src/app/menu/show-composer-mode/mod.ts index e2824ca..9f73117 100644 --- a/src/app/menu/show-composer-mode/mod.ts +++ b/src/app/menu/show-composer-mode/mod.ts @@ -20,7 +20,7 @@ import { export async function showComposerMode(cliResults: CliResults) { const npmVersion = await getNpmVersion(); const pkgManager = getUserPkgManager(); - renderTitle(); + await renderTitle(); if (npmVersion) { renderVersionWarning(npmVersion); } diff --git a/src/app/menu/show-composer-mode/opts.ts b/src/app/menu/show-composer-mode/opts.ts index 498e3ec..a5f8fd4 100644 --- a/src/app/menu/show-composer-mode/opts.ts +++ b/src/app/menu/show-composer-mode/opts.ts @@ -1,9 +1,11 @@ +import path from "pathe"; + import { DEFAULT_APP_NAME } from "~/app/db/constants.js"; +import { configureEslint } from "~/utils/eslint.js"; import { dbContainerInstaller } from "./installers/dbContainer.js"; import { drizzleInstaller } from "./installers/drizzle.js"; import { envVariablesInstaller } from "./installers/envVars.js"; -import { dynamicEslintInstaller } from "./installers/eslint.js"; import { nextAuthInstaller } from "./installers/nextAuth.js"; import { prismaInstaller } from "./installers/prisma.js"; import { tailwindInstaller } from "./installers/tailwind.js"; @@ -43,7 +45,7 @@ export type InstallerOptions = { databaseProvider: DatabaseProvider; }; -export type Installer = (opts: InstallerOptions) => void; +export type Installer = (opts: InstallerOptions) => Promise | void; export type PkgInstallerMap = Record< AvailablePackages, @@ -87,7 +89,19 @@ export const buildPkgInstallerMap = ( }, eslint: { inUse: true, - installer: dynamicEslintInstaller, + installer: async (opts) => { + await configureEslint({ + eslintConfig: path.join(opts.projectDir, "eslint.config.js"), + eslintRulesDisabledConfig: path.join( + opts.projectDir, + "eslint.config.disabled.js", + ), + eslintUltimateConfig: path.join( + opts.projectDir, + "eslint.config.ultimate.js", + ), + }); + }, }, }); diff --git a/src/app/menu/show-composer-mode/template/base/package.json b/src/app/menu/show-composer-mode/template/base/pkg.json similarity index 100% rename from src/app/menu/show-composer-mode/template/base/package.json rename to src/app/menu/show-composer-mode/template/base/pkg.json diff --git a/src/app/menu/show-composer-mode/template/base/src/env.js b/src/app/menu/show-composer-mode/template/base/src/env.js index 5c2f937..b9e2ba4 100644 --- a/src/app/menu/show-composer-mode/template/base/src/env.js +++ b/src/app/menu/show-composer-mode/template/base/src/env.js @@ -1,3 +1,4 @@ +/* eslint-disable no-undef */ import { createEnv } from "@t3-oss/env-nextjs"; import { z } from "zod"; diff --git a/src/app/menu/show-composer-mode/template/base/src/styles/globals.css b/src/app/menu/show-composer-mode/template/base/src/styles/globals.css index e5e2dcc..4fe5f5b 100644 --- a/src/app/menu/show-composer-mode/template/base/src/styles/globals.css +++ b/src/app/menu/show-composer-mode/template/base/src/styles/globals.css @@ -2,7 +2,9 @@ html, body { padding: 0; margin: 0; - font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, + font-family: + -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, + /* biome-ignore lint/suspicious/noDuplicateFontNames: */ Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; } diff --git a/src/app/menu/show-composer-mode/template/extras/.env b/src/app/menu/show-composer-mode/template/extras/.env new file mode 100644 index 0000000..c7400d6 --- /dev/null +++ b/src/app/menu/show-composer-mode/template/extras/.env @@ -0,0 +1,2 @@ +VITE_API_URL=http://localhost:3000/api +VITE_AUTH_URL=http://localhost:3000/auth \ No newline at end of file diff --git a/src/app/menu/show-composer-mode/template/extras/config/drizzle-config-mysql.ts b/src/app/menu/show-composer-mode/template/extras/config/drizzle-config-mysql.ts index 1f71d75..5469c04 100644 --- a/src/app/menu/show-composer-mode/template/extras/config/drizzle-config-mysql.ts +++ b/src/app/menu/show-composer-mode/template/extras/config/drizzle-config-mysql.ts @@ -1,5 +1,6 @@ import { type Config } from "drizzle-kit"; +// @ts-expect-error TODO: fix ts import { env } from "~/env"; export default { diff --git a/src/app/menu/show-composer-mode/template/extras/config/drizzle-config-postgres.ts b/src/app/menu/show-composer-mode/template/extras/config/drizzle-config-postgres.ts index d2a21ed..6dae689 100644 --- a/src/app/menu/show-composer-mode/template/extras/config/drizzle-config-postgres.ts +++ b/src/app/menu/show-composer-mode/template/extras/config/drizzle-config-postgres.ts @@ -1,5 +1,6 @@ import { type Config } from "drizzle-kit"; +// @ts-expect-error TODO: fix ts import { env } from "~/env"; export default { diff --git a/src/app/menu/show-composer-mode/template/extras/config/drizzle-config-sqlite.ts b/src/app/menu/show-composer-mode/template/extras/config/drizzle-config-sqlite.ts index 34f8fa2..ff55828 100644 --- a/src/app/menu/show-composer-mode/template/extras/config/drizzle-config-sqlite.ts +++ b/src/app/menu/show-composer-mode/template/extras/config/drizzle-config-sqlite.ts @@ -1,5 +1,6 @@ import { type Config } from "drizzle-kit"; +// @ts-expect-error TODO: fix ts import { env } from "~/env"; export default { diff --git a/src/app/menu/show-composer-mode/template/extras/config/react-router.config.ts b/src/app/menu/show-composer-mode/template/extras/config/react-router.config.ts new file mode 100644 index 0000000..3ff1b9f --- /dev/null +++ b/src/app/menu/show-composer-mode/template/extras/config/react-router.config.ts @@ -0,0 +1,6 @@ +import type { Config } from "@react-router/dev/config"; + +export default { + appDirectory: "src", + ssr: false, +} satisfies Config; diff --git a/src/app/menu/show-composer-mode/template/extras/config/tailwind.config.ts b/src/app/menu/show-composer-mode/template/extras/config/tailwind.config.ts index 5fd44e8..2cee2fd 100644 --- a/src/app/menu/show-composer-mode/template/extras/config/tailwind.config.ts +++ b/src/app/menu/show-composer-mode/template/extras/config/tailwind.config.ts @@ -1,12 +1,11 @@ import { type Config } from "tailwindcss"; -import { fontFamily } from "tailwindcss/defaultTheme"; export default { content: ["./src/**/*.tsx"], theme: { extend: { fontFamily: { - sans: ["var(--font-geist-sans)", ...fontFamily.sans], + sans: ["var(--font-geist-sans)"], }, }, }, diff --git a/src/app/menu/show-composer-mode/template/extras/config/vite.config.ts b/src/app/menu/show-composer-mode/template/extras/config/vite.config.ts index 5bc6c19..65784e4 100644 --- a/src/app/menu/show-composer-mode/template/extras/config/vite.config.ts +++ b/src/app/menu/show-composer-mode/template/extras/config/vite.config.ts @@ -4,5 +4,17 @@ import Pages from "vite-plugin-pages"; // https://vite.dev/config export default defineConfig({ - plugins: [react(), Pages()], + plugins: [ + react(), + Pages({ + dirs: "src/pages", + extensions: ["tsx", "ts"], + exclude: ["**/components/**/*", "**/api/**/*"], + }), + ], + resolve: { + alias: { + "~": "/src", + }, + }, }); diff --git a/src/app/menu/show-composer-mode/template/extras/eslint.ts b/src/app/menu/show-composer-mode/template/extras/eslint.ts new file mode 100644 index 0000000..d299245 --- /dev/null +++ b/src/app/menu/show-composer-mode/template/extras/eslint.ts @@ -0,0 +1,34 @@ +// @ts-check + +import eslint from "@eslint/js"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import tseslint from "typescript-eslint"; + +const config = tseslint.config( + { + ignores: ["**/.git/", "**/node_modules/"], + }, + eslint.configs.recommended, + ...tseslint.configs.recommendedTypeChecked, + ...tseslint.configs.stylisticTypeChecked, + { + files: ["**/*.{js,jsx,md,json}"], + ...tseslint.configs.disableTypeChecked, + }, + { + files: ["**/*.{js,jsx,ts,tsx}"], + languageOptions: { + parserOptions: { + projectService: true, + warnOnUnsupportedTypeScriptVersion: false, + tsconfigRootDir: path.dirname(fileURLToPath(import.meta.url)), + }, + }, + rules: { + "max-lines": ["error", 700], + }, + }, +); + +export default config; diff --git a/src/app/menu/show-composer-mode/template/extras/index.html b/src/app/menu/show-composer-mode/template/extras/index.html new file mode 100644 index 0000000..1e1d279 --- /dev/null +++ b/src/app/menu/show-composer-mode/template/extras/index.html @@ -0,0 +1,16 @@ + + + + + + + + @reliverse/cli + + + +
+ + + + \ No newline at end of file diff --git a/src/app/menu/show-composer-mode/template/extras/pkg.json b/src/app/menu/show-composer-mode/template/extras/pkg.json new file mode 100644 index 0000000..c5dff4e --- /dev/null +++ b/src/app/menu/show-composer-mode/template/extras/pkg.json @@ -0,0 +1,35 @@ +{ + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview", + "lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0" + }, + "dependencies": { + "@tanstack/react-query": "^4.36.1", + "@trpc/client": "^10.43.6", + "@trpc/react-query": "^10.43.6", + "@trpc/server": "^10.43.6", + "@vitejs/plugin-react": "^4.2.0", + "next-auth": "^4.24.5", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.20.0", + "superjson": "^2.2.1", + "vite": "^5.0.0", + "vite-plugin-pages": "^0.31.0", + "@geist-ui/core": "^2.3.8", + "zod": "^3.22.4" + }, + "devDependencies": { + "@types/react": "^18.2.37", + "@types/react-dom": "^18.2.15", + "@typescript-eslint/eslint-plugin": "^6.10.0", + "@typescript-eslint/parser": "^6.10.0", + "eslint": "^8.53.0", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.4", + "typescript": "^5.2.2" + } +} diff --git a/src/app/menu/show-composer-mode/template/extras/src/app/_components/post-tw.tsx b/src/app/menu/show-composer-mode/template/extras/src/app/_components/post-tw.tsx index ebe15ea..522bd0e 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/app/_components/post-tw.tsx +++ b/src/app/menu/show-composer-mode/template/extras/src/app/_components/post-tw.tsx @@ -2,7 +2,7 @@ import { useState } from "react"; -import { api } from "~/trpc/react"; +import { api } from "../../utils/api.js"; export function LatestPost() { const [latestPost] = api.post.getLatest.useSuspenseQuery(); @@ -34,7 +34,9 @@ export function LatestPost() { type="text" placeholder="Title" value={name} - onChange={(e) => setName(e.target.value)} + onChange={(e) => { + setName(e.target.value); + }} className="w-full rounded-full px-4 py-2 text-black" /> + + ); +} diff --git a/src/app/menu/show-composer-mode/template/extras/src/pages/with-auth-trpc.tsx b/src/app/menu/show-composer-mode/template/extras/src/pages/with-auth-trpc.tsx new file mode 100644 index 0000000..8c9bb4a --- /dev/null +++ b/src/app/menu/show-composer-mode/template/extras/src/pages/with-auth-trpc.tsx @@ -0,0 +1,77 @@ +import { signIn, signOut, useSession } from "next-auth/react"; +import React from "react"; +import { Link } from "react-router-dom"; + +// @ts-expect-error TODO: fix ts +import { api } from "~/utils/api"; + +import styles from "./index.module.css"; + +export default function WithAuthTrpcPage() { + const hello = api.post.hello.useQuery({ text: "from tRPC" }); + + return ( +
+
+

+ Basic Reliverse App +

+
+ +

First Steps ā†’

+
+ Just the basics - Everything you need to know to set up your + database and authentication. +
+ + +

Documentation ā†’

+
+ Learn more about @reliverse/cli, the libraries it uses, and how to + deploy it. +
+ +
+
+

+ {hello.data ? hello.data.greeting : "Loading tRPC query..."} +

+ +
+
+
+ ); +} + +function AuthShowcase() { + const { data: sessionData } = useSession(); + + const { data: secretMessage } = api.post.getSecretMessage.useQuery( + undefined, + { enabled: sessionData?.user !== undefined }, + ); + + return ( +
+

+ {sessionData && Logged in as {sessionData.user?.name}} + {secretMessage && - {secretMessage}} +

+ +
+ ); +} diff --git a/src/app/menu/show-composer-mode/template/extras/src/pages/with-tw.tsx b/src/app/menu/show-composer-mode/template/extras/src/pages/with-tw.tsx new file mode 100644 index 0000000..562a9ff --- /dev/null +++ b/src/app/menu/show-composer-mode/template/extras/src/pages/with-tw.tsx @@ -0,0 +1,38 @@ +import React from "react"; +import { Link } from "react-router-dom"; + +export default function WithTailwindPage() { + return ( +
+
+

+ Basic Reliverse App +

+
+ +

First Steps ā†’

+
+ Just the basics - Everything you need to know to set up your + database and authentication. +
+ + +

Documentation ā†’

+
+ Learn more about @reliverse/cli, the libraries it uses, and how to + deploy it. +
+ +
+
+
+ ); +} diff --git a/src/app/menu/show-composer-mode/template/extras/src/providers/auth.tsx b/src/app/menu/show-composer-mode/template/extras/src/providers/auth.tsx new file mode 100644 index 0000000..4b777a8 --- /dev/null +++ b/src/app/menu/show-composer-mode/template/extras/src/providers/auth.tsx @@ -0,0 +1,10 @@ +import { SessionProvider } from "next-auth/react"; +import { type ReactNode } from "react"; + +type AuthProviderProps = { + children: ReactNode; +}; + +export function AuthProvider({ children }: AuthProviderProps) { + return {children}; +} diff --git a/src/app/menu/show-composer-mode/template/extras/src/root.tsx b/src/app/menu/show-composer-mode/template/extras/src/root.tsx new file mode 100644 index 0000000..9129776 --- /dev/null +++ b/src/app/menu/show-composer-mode/template/extras/src/root.tsx @@ -0,0 +1,26 @@ +import { Links, Meta, Outlet, Scripts, ScrollRestoration } from "react-router"; + +import "./styles/globals.css"; + +export function Layout() { + return ( + + + + + @reliverse/cli + + + + + + + + + + ); +} + +export default function Root() { + return ; +} diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/api/root.ts b/src/app/menu/show-composer-mode/template/extras/src/server/api/root.ts index f01ab74..1f17fdc 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/api/root.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/api/root.ts @@ -1,23 +1,8 @@ -import { postRouter } from "~/server/api/routers/post"; -import { createCallerFactory, createTRPCRouter } from "~/server/api/trpc"; +import { postRouter } from "./routers/post.js"; +import { createTRPCRouter } from "./trpc.js"; -/** - * This is the primary router for your server. - * - * All routers added in /api/routers should be manually added here. - */ -export const framework = createTRPCRouter({ +export const appRouter = createTRPCRouter({ post: postRouter, }); -// export type definition of API -export type framework = typeof framework; - -/** - * Create a server-side caller for the tRPC API. - * @example - * const trpc = createCaller(createContext); - * const res = await trpc.post.all(); - * ^? Post[] - */ -export const createCaller = createCallerFactory(framework); +export type AppRouter = typeof appRouter; diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post.ts b/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post.ts new file mode 100644 index 0000000..ea02ef7 --- /dev/null +++ b/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post.ts @@ -0,0 +1,31 @@ +import { z } from "zod"; + +import { + createTRPCRouter, + publicProcedure, + protectedProcedure, +} from "../trpc.js"; + +export const postRouter = createTRPCRouter({ + hello: publicProcedure + .input(z.object({ text: z.string() })) + .query(({ input }) => { + return { + greeting: `Hello ${input.text}`, + }; + }), + + getSecretMessage: protectedProcedure.query(() => { + return "you can now see this secret message!"; + }), + + getLatest: publicProcedure.query(() => { + return { name: "Example Post" }; + }), + + create: publicProcedure + .input(z.object({ name: z.string() })) + .mutation(({ input }) => { + return { name: input.name }; + }), +}); diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post/base.ts b/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post/base.ts index afe46d8..d16a4ad 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post/base.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post/base.ts @@ -1,12 +1,13 @@ import { z } from "zod"; +// @ts-expect-error TODO: fix ts import { createTRPCRouter, publicProcedure } from "~/server/api/trpc"; // Mocked DB -interface Post { +type Post = { id: number; name: string; -} +}; const posts: Post[] = [ { id: 1, @@ -17,6 +18,7 @@ const posts: Post[] = [ export const postRouter = createTRPCRouter({ hello: publicProcedure .input(z.object({ text: z.string() })) + // @ts-expect-error TODO: fix ts .query(({ input }) => { return { greeting: `Hello ${input.text}`, @@ -25,7 +27,8 @@ export const postRouter = createTRPCRouter({ create: publicProcedure .input(z.object({ name: z.string().min(1) })) - .mutation(async ({ input }) => { + // @ts-expect-error TODO: fix ts + .mutation(({ input }) => { const post: Post = { id: posts.length + 1, name: input.name, diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post/with-auth-drizzle.ts b/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post/with-auth-drizzle.ts index b8954c8..aafbed3 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post/with-auth-drizzle.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post/with-auth-drizzle.ts @@ -4,12 +4,15 @@ import { createTRPCRouter, protectedProcedure, publicProcedure, + // @ts-expect-error TODO: fix ts } from "~/server/api/trpc"; +// @ts-expect-error TODO: fix ts import { posts } from "~/server/db/schema"; export const postRouter = createTRPCRouter({ hello: publicProcedure .input(z.object({ text: z.string() })) + // @ts-expect-error TODO: fix ts .query(({ input }) => { return { greeting: `Hello ${input.text}`, @@ -18,6 +21,7 @@ export const postRouter = createTRPCRouter({ create: protectedProcedure .input(z.object({ name: z.string().min(1) })) + // @ts-expect-error TODO: fix ts .mutation(async ({ ctx, input }) => { await ctx.db.insert(posts).values({ name: input.name, @@ -25,8 +29,10 @@ export const postRouter = createTRPCRouter({ }); }), + // @ts-expect-error TODO: fix ts getLatest: protectedProcedure.query(async ({ ctx }) => { const post = await ctx.db.query.posts.findFirst({ + // @ts-expect-error TODO: fix ts orderBy: (posts, { desc }) => [desc(posts.createdAt)], }); diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post/with-auth-prisma.ts b/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post/with-auth-prisma.ts index b602dd5..01a228e 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post/with-auth-prisma.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post/with-auth-prisma.ts @@ -4,11 +4,13 @@ import { createTRPCRouter, protectedProcedure, publicProcedure, + // @ts-expect-error TODO: fix ts } from "~/server/api/trpc"; export const postRouter = createTRPCRouter({ hello: publicProcedure .input(z.object({ text: z.string() })) + // @ts-expect-error TODO: fix ts .query(({ input }) => { return { greeting: `Hello ${input.text}`, @@ -17,7 +19,8 @@ export const postRouter = createTRPCRouter({ create: protectedProcedure .input(z.object({ name: z.string().min(1) })) - .mutation(async ({ ctx, input }) => { + // @ts-expect-error TODO: fix ts + .mutation(({ ctx, input }) => { return ctx.db.post.create({ data: { name: input.name, @@ -26,6 +29,7 @@ export const postRouter = createTRPCRouter({ }); }), + // @ts-expect-error TODO: fix ts getLatest: protectedProcedure.query(async ({ ctx }) => { const post = await ctx.db.post.findFirst({ orderBy: { createdAt: "desc" }, diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post/with-auth.ts b/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post/with-auth.ts index 199b617..78ad861 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post/with-auth.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post/with-auth.ts @@ -4,6 +4,7 @@ import { createTRPCRouter, protectedProcedure, publicProcedure, + // @ts-expect-error TODO: fix ts } from "~/server/api/trpc"; let post = { @@ -14,6 +15,7 @@ let post = { export const postRouter = createTRPCRouter({ hello: publicProcedure .input(z.object({ text: z.string() })) + // @ts-expect-error TODO: fix ts .query(({ input }) => { return { greeting: `Hello ${input.text}`, @@ -22,7 +24,8 @@ export const postRouter = createTRPCRouter({ create: protectedProcedure .input(z.object({ name: z.string().min(1) })) - .mutation(async ({ input }) => { + // @ts-expect-error TODO: fix ts + .mutation(({ input }) => { post = { id: post.id + 1, name: input.name }; return post; }), diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post/with-drizzle.ts b/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post/with-drizzle.ts index 4bbf615..130ed76 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post/with-drizzle.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post/with-drizzle.ts @@ -1,11 +1,14 @@ import { z } from "zod"; +// @ts-expect-error TODO: fix ts import { createTRPCRouter, publicProcedure } from "~/server/api/trpc"; +// @ts-expect-error TODO: fix ts import { posts } from "~/server/db/schema"; export const postRouter = createTRPCRouter({ hello: publicProcedure .input(z.object({ text: z.string() })) + // @ts-expect-error TODO: fix ts .query(({ input }) => { return { greeting: `Hello ${input.text}`, @@ -14,14 +17,17 @@ export const postRouter = createTRPCRouter({ create: publicProcedure .input(z.object({ name: z.string().min(1) })) + // @ts-expect-error TODO: fix ts .mutation(async ({ ctx, input }) => { await ctx.db.insert(posts).values({ name: input.name, }); }), + // @ts-expect-error TODO: fix ts getLatest: publicProcedure.query(async ({ ctx }) => { const post = await ctx.db.query.posts.findFirst({ + // @ts-expect-error TODO: fix ts orderBy: (posts, { desc }) => [desc(posts.createdAt)], }); diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post/with-prisma.ts b/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post/with-prisma.ts index da1c799..a4819af 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post/with-prisma.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/api/routers/post/with-prisma.ts @@ -1,10 +1,12 @@ import { z } from "zod"; +// @ts-expect-error TODO: fix ts import { createTRPCRouter, publicProcedure } from "~/server/api/trpc"; export const postRouter = createTRPCRouter({ hello: publicProcedure .input(z.object({ text: z.string() })) + // @ts-expect-error TODO: fix ts .query(({ input }) => { return { greeting: `Hello ${input.text}`, @@ -13,7 +15,8 @@ export const postRouter = createTRPCRouter({ create: publicProcedure .input(z.object({ name: z.string().min(1) })) - .mutation(async ({ ctx, input }) => { + // @ts-expect-error TODO: fix ts + .mutation(({ ctx, input }) => { return ctx.db.post.create({ data: { name: input.name, @@ -21,6 +24,7 @@ export const postRouter = createTRPCRouter({ }); }), + // @ts-expect-error TODO: fix ts getLatest: publicProcedure.query(async ({ ctx }) => { const post = await ctx.db.post.findFirst({ orderBy: { createdAt: "desc" }, diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-app/base.ts b/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-app/base.ts index b38d2fa..4e87228 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-app/base.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-app/base.ts @@ -22,7 +22,7 @@ import { ZodError } from "zod"; * * @see https://trpc.io/docs/server/context */ -export const createTRPCContext = async (opts: { headers: Headers }) => { +export const createTRPCContext = (opts: { headers: Headers }) => { return { ...opts, }; diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-app/with-auth-db.ts b/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-app/with-auth-db.ts index 00d924f..ff88fe1 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-app/with-auth-db.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-app/with-auth-db.ts @@ -11,7 +11,9 @@ import { initTRPC, TRPCError } from "@trpc/server"; import superjson from "superjson"; import { ZodError } from "zod"; +// @ts-expect-error TODO: fix ts import { auth } from "~/server/auth"; +// @ts-expect-error TODO: fix ts import { db } from "~/server/db"; /** @@ -121,7 +123,7 @@ export const publicProcedure = t.procedure.use(timingMiddleware); export const protectedProcedure = t.procedure .use(timingMiddleware) .use(({ ctx, next }) => { - if (!ctx.session || !ctx.session.user) { + if (!ctx.session?.user) { throw new TRPCError({ code: "UNAUTHORIZED" }); } return next({ diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-app/with-auth.ts b/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-app/with-auth.ts index 755b973..44fb1be 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-app/with-auth.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-app/with-auth.ts @@ -10,6 +10,7 @@ import { initTRPC, TRPCError } from "@trpc/server"; import superjson from "superjson"; import { ZodError } from "zod"; +// @ts-expect-error TODO: fix ts import { auth } from "~/server/auth"; /** @@ -118,7 +119,7 @@ export const publicProcedure = t.procedure.use(timingMiddleware); export const protectedProcedure = t.procedure .use(timingMiddleware) .use(({ ctx, next }) => { - if (!ctx.session || !ctx.session.user) { + if (!ctx.session?.user) { throw new TRPCError({ code: "UNAUTHORIZED" }); } return next({ diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-app/with-db.ts b/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-app/with-db.ts index 4e24ba4..b8316bc 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-app/with-db.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-app/with-db.ts @@ -10,6 +10,7 @@ import { initTRPC } from "@trpc/server"; import superjson from "superjson"; import { ZodError } from "zod"; +// @ts-expect-error TODO: fix ts import { db } from "~/server/db"; /** @@ -24,7 +25,7 @@ import { db } from "~/server/db"; * * @see https://trpc.io/docs/server/context */ -export const createTRPCContext = async (opts: { headers: Headers }) => { +export const createTRPCContext = (opts: { headers: Headers }) => { return { db, ...opts, diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-pages/with-auth-db.ts b/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-pages/with-auth-db.ts index 2bf20ee..307b779 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-pages/with-auth-db.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-pages/with-auth-db.ts @@ -13,7 +13,9 @@ import { type Session } from "next-auth"; import superjson from "superjson"; import { ZodError } from "zod"; +// @ts-expect-error TODO: fix ts import { auth } from "~/server/auth"; +// @ts-expect-error TODO: fix ts import { db } from "~/server/db"; /** diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-pages/with-auth.ts b/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-pages/with-auth.ts index e85e587..97f7132 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-pages/with-auth.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-pages/with-auth.ts @@ -12,6 +12,7 @@ import { type Session } from "next-auth"; import superjson from "superjson"; import { ZodError } from "zod"; +// @ts-expect-error TODO: fix ts import { auth } from "~/server/auth"; /** diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-pages/with-db.ts b/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-pages/with-db.ts index a2e7015..7bca4e6 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-pages/with-db.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc-pages/with-db.ts @@ -11,6 +11,7 @@ import { type CreateNextContextOptions } from "@trpc/server/adapters/next"; import superjson from "superjson"; import { ZodError } from "zod"; +// @ts-expect-error TODO: fix ts import { db } from "~/server/db"; /** diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc.ts b/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc.ts new file mode 100644 index 0000000..225febc --- /dev/null +++ b/src/app/menu/show-composer-mode/template/extras/src/server/api/trpc.ts @@ -0,0 +1,43 @@ +import { initTRPC, TRPCError } from "@trpc/server"; +import { type Session } from "next-auth"; +import superjson from "superjson"; +import { ZodError } from "zod"; + +type CreateContextOptions = { + session: Session | null; +}; + +export const createTRPCContext = (opts: CreateContextOptions) => { + const { session } = opts; + return { session }; +}; + +const t = initTRPC.context().create({ + transformer: superjson, + errorFormatter({ shape, error }) { + return { + ...shape, + data: { + ...shape.data, + zodError: + error.cause instanceof ZodError ? error.cause.flatten() : null, + }, + }; + }, +}); + +export const createTRPCRouter = t.router; +export const publicProcedure = t.procedure; + +const enforceUserIsAuthed = t.middleware(({ ctx, next }) => { + if (!ctx.session?.user) { + throw new TRPCError({ code: "UNAUTHORIZED" }); + } + return next({ + ctx: { + session: { ...ctx.session, user: ctx.session.user }, + }, + }); +}); + +export const protectedProcedure = t.procedure.use(enforceUserIsAuthed); diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/auth/config/base.ts b/src/app/menu/show-composer-mode/template/extras/src/server/auth/config/base.ts index c88101a..9a5c095 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/auth/config/base.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/auth/config/base.ts @@ -1,3 +1,4 @@ +// @ts-expect-error TODO: fix ts import { type DefaultSession, type NextAuthConfig } from "next-auth"; import DiscordProvider from "next-auth/providers/discord"; @@ -8,6 +9,7 @@ import DiscordProvider from "next-auth/providers/discord"; * @see https://next-auth.js.org/getting-started/typescript#module-augmentation */ declare module "next-auth" { + // eslint-disable-next-line @typescript-eslint/consistent-type-definitions interface Session extends DefaultSession { user: { id: string; @@ -41,6 +43,7 @@ export const authConfig = { */ ], callbacks: { + // @ts-expect-error TODO: fix ts session: ({ session, token }) => ({ ...session, user: { diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/auth/config/with-drizzle.ts b/src/app/menu/show-composer-mode/template/extras/src/server/auth/config/with-drizzle.ts index 3ef82a2..e720c7e 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/auth/config/with-drizzle.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/auth/config/with-drizzle.ts @@ -1,13 +1,15 @@ import { DrizzleAdapter } from "@auth/drizzle-adapter"; -import { type DefaultSession, type NextAuthConfig } from "next-auth"; +import { type DefaultSession } from "next-auth"; import DiscordProvider from "next-auth/providers/discord"; +// @ts-expect-error TODO: fix ts import { db } from "~/server/db"; import { accounts, sessions, users, verificationTokens, + // @ts-expect-error TODO: fix ts } from "~/server/db/schema"; /** @@ -17,6 +19,7 @@ import { * @see https://next-auth.js.org/getting-started/typescript#module-augmentation */ declare module "next-auth" { + // eslint-disable-next-line @typescript-eslint/consistent-type-definitions interface Session extends DefaultSession { user: { id: string; @@ -56,6 +59,7 @@ export const authConfig = { verificationTokensTable: verificationTokens, }), callbacks: { + // @ts-expect-error TODO: fix ts session: ({ session, user }) => ({ ...session, user: { @@ -64,4 +68,5 @@ export const authConfig = { }, }), }, + // @ts-expect-error TODO: fix ts } satisfies NextAuthConfig; diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/auth/config/with-prisma.ts b/src/app/menu/show-composer-mode/template/extras/src/server/auth/config/with-prisma.ts index 9b8ec79..40552e2 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/auth/config/with-prisma.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/auth/config/with-prisma.ts @@ -1,7 +1,9 @@ import { PrismaAdapter } from "@auth/prisma-adapter"; +// @ts-expect-error TODO: fix ts import { type DefaultSession, type NextAuthConfig } from "next-auth"; import DiscordProvider from "next-auth/providers/discord"; +// @ts-expect-error TODO: fix ts import { db } from "~/server/db"; /** @@ -11,6 +13,7 @@ import { db } from "~/server/db"; * @see https://next-auth.js.org/getting-started/typescript#module-augmentation */ declare module "next-auth" { + // eslint-disable-next-line @typescript-eslint/consistent-type-definitions interface Session extends DefaultSession { user: { id: string; @@ -44,7 +47,9 @@ export const authConfig = { */ ], adapter: PrismaAdapter(db), + callbacks: { + // @ts-expect-error TODO: fix ts session: ({ session, user }) => ({ ...session, user: { diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/auth/index.ts b/src/app/menu/show-composer-mode/template/extras/src/server/auth/index.ts index fa6d0a9..c9f210c 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/auth/index.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/auth/index.ts @@ -1,8 +1,10 @@ import NextAuth from "next-auth"; import { cache } from "react"; +// @ts-expect-error TODO: fix ts import { authConfig } from "./config.js"; +// @ts-expect-error TODO: fix ts const { auth: uncachedAuth, handlers, signIn, signOut } = NextAuth(authConfig); const auth = cache(uncachedAuth); diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/db/db-prisma-planetscale.ts b/src/app/menu/show-composer-mode/template/extras/src/server/db/db-prisma-planetscale.ts index 5218893..ba1d84b 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/db/db-prisma-planetscale.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/db/db-prisma-planetscale.ts @@ -2,6 +2,7 @@ import { Client } from "@planetscale/database"; import { PrismaPlanetScale } from "@prisma/adapter-planetscale"; import { PrismaClient } from "@prisma/client"; +// @ts-expect-error TODO: fix ts import { env } from "~/env"; const psClient = new Client({ url: env.DATABASE_URL }); @@ -14,6 +15,7 @@ const createPrismaClient = () => }); const globalForPrisma = globalThis as unknown as { + // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents prisma: ReturnType | undefined; }; diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/db/db-prisma.ts b/src/app/menu/show-composer-mode/template/extras/src/server/db/db-prisma.ts index 07dc027..06f4bf2 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/db/db-prisma.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/db/db-prisma.ts @@ -1,5 +1,6 @@ import { PrismaClient } from "@prisma/client"; +// @ts-expect-error TODO: fix ts import { env } from "~/env"; const createPrismaClient = () => @@ -9,6 +10,7 @@ const createPrismaClient = () => }); const globalForPrisma = globalThis as unknown as { + // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents prisma: ReturnType | undefined; }; diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/db/index-drizzle/with-mysql.ts b/src/app/menu/show-composer-mode/template/extras/src/server/db/index-drizzle/with-mysql.ts index ca6b59f..676f68d 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/db/index-drizzle/with-mysql.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/db/index-drizzle/with-mysql.ts @@ -1,7 +1,10 @@ import { drizzle } from "drizzle-orm/mysql2"; import { createPool, type Pool } from "mysql2/promise"; +// @ts-expect-error TODO: fix ts import { env } from "~/env"; + +// @ts-expect-error TODO: fix ts import * as schema from "./schema.js"; /** diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/db/index-drizzle/with-planetscale.ts b/src/app/menu/show-composer-mode/template/extras/src/server/db/index-drizzle/with-planetscale.ts index efa6556..eda0fcb 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/db/index-drizzle/with-planetscale.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/db/index-drizzle/with-planetscale.ts @@ -1,7 +1,10 @@ import { Client } from "@planetscale/database"; import { drizzle } from "drizzle-orm/planetscale-serverless"; +// @ts-expect-error TODO: fix ts import { env } from "~/env"; + +// @ts-expect-error TODO: fix ts import * as schema from "./schema.js"; export const db = drizzle(new Client({ url: env.DATABASE_URL }), { schema }); diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/db/index-drizzle/with-postgres.ts b/src/app/menu/show-composer-mode/template/extras/src/server/db/index-drizzle/with-postgres.ts index c04b4da..f34cce2 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/db/index-drizzle/with-postgres.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/db/index-drizzle/with-postgres.ts @@ -1,7 +1,10 @@ import { drizzle } from "drizzle-orm/postgres-js"; import postgres from "postgres"; +// @ts-expect-error TODO: fix ts import { env } from "~/env"; + +// @ts-expect-error TODO: fix ts import * as schema from "./schema.js"; /** diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/db/index-drizzle/with-sqlite.ts b/src/app/menu/show-composer-mode/template/extras/src/server/db/index-drizzle/with-sqlite.ts index b83aeab..af10f1b 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/db/index-drizzle/with-sqlite.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/db/index-drizzle/with-sqlite.ts @@ -1,7 +1,10 @@ import { createClient, type Client } from "@libsql/client"; import { drizzle } from "drizzle-orm/libsql"; +// @ts-expect-error TODO: fix ts import { env } from "~/env"; + +// @ts-expect-error TODO: fix ts import * as schema from "./schema.js"; /** diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/base-mysql.ts b/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/base-mysql.ts index bfb0807..78686f9 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/base-mysql.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/base-mysql.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-deprecated */ // Example model schema from the Drizzle docs // https://orm.drizzle.team/docs/sql-schema-declaration @@ -30,5 +31,5 @@ export const posts = createTable( }, (example) => ({ nameIndex: index("name_idx").on(example.name), - }) + }), ); diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/base-planetscale.ts b/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/base-planetscale.ts index bfb0807..78686f9 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/base-planetscale.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/base-planetscale.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-deprecated */ // Example model schema from the Drizzle docs // https://orm.drizzle.team/docs/sql-schema-declaration @@ -30,5 +31,5 @@ export const posts = createTable( }, (example) => ({ nameIndex: index("name_idx").on(example.name), - }) + }), ); diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/base-postgres.ts b/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/base-postgres.ts index 3878a98..9990604 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/base-postgres.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/base-postgres.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-deprecated */ // Example model schema from the Drizzle docs // https://orm.drizzle.team/docs/sql-schema-declaration @@ -27,10 +28,10 @@ export const posts = createTable( .default(sql`CURRENT_TIMESTAMP`) .notNull(), updatedAt: timestamp("updated_at", { withTimezone: true }).$onUpdate( - () => new Date() + () => new Date(), ), }, (example) => ({ nameIndex: index("name_idx").on(example.name), - }) + }), ); diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/base-sqlite.ts b/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/base-sqlite.ts index cc74c86..e2309c2 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/base-sqlite.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/base-sqlite.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-deprecated */ // Example model schema from the Drizzle docs // https://orm.drizzle.team/docs/sql-schema-declaration @@ -21,10 +22,10 @@ export const posts = createTable( .default(sql`(unixepoch())`) .notNull(), updatedAt: int("updated_at", { mode: "timestamp" }).$onUpdate( - () => new Date() + () => new Date(), ), }, (example) => ({ nameIndex: index("name_idx").on(example.name), - }) + }), ); diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/with-auth-mysql.ts b/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/with-auth-mysql.ts index 96e9a85..1cf7ae4 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/with-auth-mysql.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/with-auth-mysql.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-deprecated */ import { relations, sql } from "drizzle-orm"; import { bigint, @@ -35,7 +36,7 @@ export const posts = createTable( (example) => ({ createdByIdIdx: index("created_by_idx").on(example.createdById), nameIndex: index("name_idx").on(example.name), - }) + }), ); export const users = createTable("user", { @@ -83,7 +84,7 @@ export const accounts = createTable( columns: [account.provider, account.providerAccountId], }), userIdIdx: index("account_user_id_idx").on(account.userId), - }) + }), ); export const accountsRelations = relations(accounts, ({ one }) => ({ @@ -103,7 +104,7 @@ export const sessions = createTable( }, (session) => ({ userIdIdx: index("session_user_id_idx").on(session.userId), - }) + }), ); export const sessionsRelations = relations(sessions, ({ one }) => ({ @@ -119,5 +120,5 @@ export const verificationTokens = createTable( }, (vt) => ({ compoundKey: primaryKey({ columns: [vt.identifier, vt.token] }), - }) + }), ); diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/with-auth-planetscale.ts b/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/with-auth-planetscale.ts index a0b1d72..7703af8 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/with-auth-planetscale.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/with-auth-planetscale.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-deprecated */ import { relations, sql } from "drizzle-orm"; import { bigint, @@ -33,7 +34,7 @@ export const posts = createTable( (example) => ({ createdByIdIdx: index("created_by_idx").on(example.createdById), nameIndex: index("name_idx").on(example.name), - }) + }), ); export const users = createTable("user", { @@ -79,7 +80,7 @@ export const accounts = createTable( columns: [account.provider, account.providerAccountId], }), userIdIdx: index("accounts_user_id_idx").on(account.userId), - }) + }), ); export const accountsRelations = relations(accounts, ({ one }) => ({ @@ -97,7 +98,7 @@ export const sessions = createTable( }, (session) => ({ userIdIdx: index("session_user_id_idx").on(session.userId), - }) + }), ); export const sessionsRelations = relations(sessions, ({ one }) => ({ @@ -113,5 +114,5 @@ export const verificationTokens = createTable( }, (vt) => ({ compoundKey: primaryKey({ columns: [vt.identifier, vt.token] }), - }) + }), ); diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/with-auth-postgres.ts b/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/with-auth-postgres.ts index 43e6243..6bc69e4 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/with-auth-postgres.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/with-auth-postgres.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-deprecated */ import { relations, sql } from "drizzle-orm"; import { index, @@ -30,13 +31,13 @@ export const posts = createTable( .default(sql`CURRENT_TIMESTAMP`) .notNull(), updatedAt: timestamp("updated_at", { withTimezone: true }).$onUpdate( - () => new Date() + () => new Date(), ), }, (example) => ({ createdByIdIdx: index("created_by_idx").on(example.createdById), nameIndex: index("name_idx").on(example.name), - }) + }), ); export const users = createTable("user", { @@ -83,7 +84,7 @@ export const accounts = createTable( columns: [account.provider, account.providerAccountId], }), userIdIdx: index("account_user_id_idx").on(account.userId), - }) + }), ); export const accountsRelations = relations(accounts, ({ one }) => ({ @@ -106,7 +107,7 @@ export const sessions = createTable( }, (session) => ({ userIdIdx: index("session_user_id_idx").on(session.userId), - }) + }), ); export const sessionsRelations = relations(sessions, ({ one }) => ({ @@ -125,5 +126,5 @@ export const verificationTokens = createTable( }, (vt) => ({ compoundKey: primaryKey({ columns: [vt.identifier, vt.token] }), - }) + }), ); diff --git a/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/with-auth-sqlite.ts b/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/with-auth-sqlite.ts index 12ee290..f373424 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/with-auth-sqlite.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/server/db/schema-drizzle/with-auth-sqlite.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-deprecated */ import { relations, sql } from "drizzle-orm"; import { index, @@ -28,13 +29,13 @@ export const posts = createTable( .default(sql`(unixepoch())`) .notNull(), updatedAt: int("updatedAt", { mode: "timestamp" }).$onUpdate( - () => new Date() + () => new Date(), ), }, (example) => ({ createdByIdIdx: index("created_by_idx").on(example.createdById), nameIndex: index("name_idx").on(example.name), - }) + }), ); export const users = createTable("user", { @@ -78,7 +79,7 @@ export const accounts = createTable( columns: [account.provider, account.providerAccountId], }), userIdIdx: index("account_user_id_idx").on(account.userId), - }) + }), ); export const accountsRelations = relations(accounts, ({ one }) => ({ @@ -96,7 +97,7 @@ export const sessions = createTable( }, (session) => ({ userIdIdx: index("session_userId_idx").on(session.userId), - }) + }), ); export const sessionsRelations = relations(sessions, ({ one }) => ({ @@ -112,5 +113,5 @@ export const verificationTokens = createTable( }, (vt) => ({ compoundKey: primaryKey({ columns: [vt.identifier, vt.token] }), - }) + }), ); diff --git a/src/app/menu/show-composer-mode/template/extras/src/trpc/react.tsx b/src/app/menu/show-composer-mode/template/extras/src/trpc/react.tsx index fcb1c95..6d15b6d 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/trpc/react.tsx +++ b/src/app/menu/show-composer-mode/template/extras/src/trpc/react.tsx @@ -8,7 +8,7 @@ import { useState } from "react"; import React from "react"; import SuperJSON from "superjson"; -import { type framework } from "../server/api/root.js"; +import { type AppRouter } from "../server/api/root.js"; import { createQueryClient } from "./query-client.js"; let clientQueryClientSingleton: QueryClient | undefined = undefined; @@ -21,27 +21,27 @@ const getQueryClient = () => { return (clientQueryClientSingleton ??= createQueryClient()); }; -export const api = createTRPCReact(); +export const api = createTRPCReact(); /** * Inference helper for inputs. * * @example type HelloInput = RouterInputs['example']['hello'] */ -export type RouterInputs = inferRouterInputs; +export type RouterInputs = inferRouterInputs; /** * Inference helper for outputs. * * @example type HelloOutput = RouterOutputs['example']['hello'] */ -export type RouterOutputs = inferRouterOutputs; +export type RouterOutputs = inferRouterOutputs; export function TRPCReactProvider(props: { children: React.ReactNode }) { const queryClient = getQueryClient(); - const [trpcClient] = useState(() => - api.createClient({ + const [trpcClient] = useState(() => { + return api.createClient({ links: [ loggerLink({ enabled: (op) => @@ -58,11 +58,12 @@ export function TRPCReactProvider(props: { children: React.ReactNode }) { }, }), ], - }), - ); + }); + }); return ( + {/* @ts-expect-error cli codebase hasn't have access to node_modules */} {props.children} diff --git a/src/app/menu/show-composer-mode/template/extras/src/trpc/server.ts b/src/app/menu/show-composer-mode/template/extras/src/trpc/server.ts index 692fdf5..718f7d2 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/trpc/server.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/trpc/server.ts @@ -1,11 +1,11 @@ import "server-only"; - import { createHydrationHelpers } from "@trpc/react-query/rsc"; +// @ts-expect-error TODO: fix Next.js 15 import { headers } from "next/headers"; import { cache } from "react"; -import { createCaller, type framework } from "~/server/api/root"; -import { createTRPCContext } from "~/server/api/trpc"; +import { type AppRouter } from "./../server/api/root.js"; +import { createTRPCContext } from "./../server/api/trpc.js"; import { createQueryClient } from "./query-client.js"; /** @@ -17,14 +17,17 @@ const createContext = cache(async () => { heads.set("x-trpc-source", "rsc"); return createTRPCContext({ + // @ts-expect-error TODO: fix ts headers: heads, }); }); const getQueryClient = cache(createQueryClient); +// @ts-expect-error TODO: fix ts const caller = createCaller(createContext); -export const { trpc: api, HydrateClient } = createHydrationHelpers( +export const { trpc: api, HydrateClient } = createHydrationHelpers( caller, + // @ts-expect-error TODO: fix query import path getQueryClient, ); diff --git a/src/app/menu/show-composer-mode/template/extras/src/utils/api.ts b/src/app/menu/show-composer-mode/template/extras/src/utils/api.ts index a965868..7b4a074 100644 --- a/src/app/menu/show-composer-mode/template/extras/src/utils/api.ts +++ b/src/app/menu/show-composer-mode/template/extras/src/utils/api.ts @@ -1,56 +1,28 @@ +import { QueryClient } from "@tanstack/react-query"; /** * This is the client-side entrypoint for your tRPC API. It is used to create the `api` object which * contains the Next.js App-wrapper, as well as your type-safe React Query hooks. * * We also create a few inference helpers for input and output types. */ -import { httpBatchLink, loggerLink } from "@trpc/client"; -import { createTRPCNext } from "@trpc/next"; +import { createTRPCClient, httpBatchLink } from "@trpc/client"; +import { createTRPCReact } from "@trpc/react-query"; import { type inferRouterInputs, type inferRouterOutputs } from "@trpc/server"; -import superjson from "superjson"; +import SuperJSON from "superjson"; -import { type framework } from "~/server/api/root"; +import type { AppRouter } from "../server/api/root.js"; -const getBaseUrl = () => { - if (typeof window !== "undefined") return ""; // browser should use relative url - if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`; // SSR should use vercel url - return `http://localhost:${process.env.PORT ?? 3000}`; // dev SSR should use localhost -}; +export const api = createTRPCReact(); -/** A set of type-safe react-query hooks for your tRPC API. */ -export const api = createTRPCNext({ - config() { - return { - /** - * Links used to determine request flow from client to server. - * - * @see https://trpc.io/docs/links - */ - links: [ - loggerLink({ - enabled: (opts) => - process.env.NODE_ENV === "development" || - (opts.direction === "down" && opts.result instanceof Error), - }), - httpBatchLink({ - /** - * Transformer used for data de-serialization from the server. - * - * @see https://trpc.io/docs/data-transformers - */ - transformer: superjson, - url: `${getBaseUrl()}/api/trpc`, - }), - ], - }; - }, - /** - * Whether tRPC should await queries when server rendering pages. - * - * @see https://trpc.io/docs/nextjs#ssr-boolean-default-false - */ - ssr: false, - transformer: superjson, +export const queryClient = new QueryClient(); + +export const trpcClient = createTRPCClient({ + links: [ + httpBatchLink({ + url: `${import.meta.env["VITE_API_URL"]}/trpc`, + transformer: SuperJSON, + }), + ], }); /** @@ -58,11 +30,11 @@ export const api = createTRPCNext({ * * @example type HelloInput = RouterInputs['example']['hello'] */ -export type RouterInputs = inferRouterInputs; +export type RouterInputs = inferRouterInputs; /** * Inference helper for outputs. * * @example type HelloOutput = RouterOutputs['example']['hello'] */ -export type RouterOutputs = inferRouterOutputs; +export type RouterOutputs = inferRouterOutputs; diff --git a/src/app/menu/show-composer-mode/template/extras/ts-config.json b/src/app/menu/show-composer-mode/template/extras/ts-config.json new file mode 100644 index 0000000..f88622d --- /dev/null +++ b/src/app/menu/show-composer-mode/template/extras/ts-config.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "baseUrl": ".", + "paths": { + "~/*": ["src/*"], + "~react-pages": ["./.vite/pages-generated.d.ts"] + } + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/src/app/menu/show-composer-mode/template/extras/ts-config.node.json b/src/app/menu/show-composer-mode/template/extras/ts-config.node.json new file mode 100644 index 0000000..42872c5 --- /dev/null +++ b/src/app/menu/show-composer-mode/template/extras/ts-config.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/src/app/menu/show-composer-mode/utils/addPackageDependency.ts b/src/app/menu/show-composer-mode/utils/addPackageDependency.ts index 4adaa2a..21d88e6 100644 --- a/src/app/menu/show-composer-mode/utils/addPackageDependency.ts +++ b/src/app/menu/show-composer-mode/utils/addPackageDependency.ts @@ -1,12 +1,12 @@ -import path from "pathe"; +import type { PackageJson } from "type-fest"; + import fs from "fs-extra"; +import path from "pathe"; import sortPackageJson from "sort-package-json"; -import { type PackageJson } from "type-fest"; -import { - dependencyVersionMap, - type AvailableDependencies, -} from "~/installers/dependencyVersionMap.js"; +import type { AvailableDependencies } from "../installers/dependencyVersionMap.js"; + +import { dependencyVersionMap } from "../installers/dependencyVersionMap.js"; export const addPackageDependency = (opts: { dependencies: AvailableDependencies[]; diff --git a/src/app/menu/show-composer-mode/utils/getReliverseCliVersion.ts b/src/app/menu/show-composer-mode/utils/getReliverseCliVersion.ts index 01ce4c2..6b3d6a9 100644 --- a/src/app/menu/show-composer-mode/utils/getReliverseCliVersion.ts +++ b/src/app/menu/show-composer-mode/utils/getReliverseCliVersion.ts @@ -1,8 +1,9 @@ +import type { PackageJson } from "type-fest"; + import fs from "fs-extra"; import path from "pathe"; -import { type PackageJson } from "type-fest"; -import { PKG_ROOT } from "~/consts.js"; +import { PKG_ROOT } from "~/app/db/constants.js"; export const getVersion = () => { const packageJsonPath = path.join(PKG_ROOT, "package.json"); diff --git a/src/app/menu/show-composer-mode/utils/getUserPkgManager.ts b/src/app/menu/show-composer-mode/utils/getUserPkgManager.ts index c57d3c3..61e3842 100644 --- a/src/app/menu/show-composer-mode/utils/getUserPkgManager.ts +++ b/src/app/menu/show-composer-mode/utils/getUserPkgManager.ts @@ -2,7 +2,7 @@ export type PackageManager = "npm" | "pnpm" | "yarn" | "bun"; export const getUserPkgManager: () => PackageManager = () => { // This environment variable is set by npm and yarn but pnpm seems less consistent - const userAgent = process.env.npm_config_user_agent; + const userAgent = process.env["npm_config_user_agent"]; if (userAgent) { if (userAgent.startsWith("yarn")) { diff --git a/src/app/menu/show-composer-mode/utils/isTTYError.ts b/src/app/menu/show-composer-mode/utils/isTTYError.ts index d227b82..45d2fac 100644 --- a/src/app/menu/show-composer-mode/utils/isTTYError.ts +++ b/src/app/menu/show-composer-mode/utils/isTTYError.ts @@ -1,4 +1,6 @@ +/* eslint-disable @typescript-eslint/no-useless-constructor */ export class IsTTYError extends Error { + // biome-ignore lint/complexity/noUselessConstructor: constructor(msg: string) { super(msg); } diff --git a/src/app/menu/show-composer-mode/utils/renderTitle.ts b/src/app/menu/show-composer-mode/utils/renderTitle.ts index 336e9d4..887d025 100644 --- a/src/app/menu/show-composer-mode/utils/renderTitle.ts +++ b/src/app/menu/show-composer-mode/utils/renderTitle.ts @@ -1,24 +1,8 @@ -import gradient from "gradient-string"; +import { createAsciiArt } from "@reliverse/prompts"; -import { TITLE_TEXT } from "~/app/db/constants.js"; -import { getUserPkgManager } from "~/app/menu/show-composer-mode/utils/getUserPkgManager.js"; - -const gradientTheme = { - blue: "#add7ff", - cyan: "#89ddff", - green: "#5de4c7", - magenta: "#fae4fc", - red: "#d0679d", - yellow: "#fffac2", -}; - -export const renderTitle = () => { - const titleGradient = gradient(Object.values(gradientTheme)); - - // resolves weird behavior where the ascii is offset - const pkgManager = getUserPkgManager(); - if (pkgManager === "yarn" || pkgManager === "pnpm") { - console.log(""); - } - console.log(titleGradient.multiline(TITLE_TEXT)); +export const renderTitle = async () => { + await createAsciiArt({ + message: "Reliverse", + font: "block", + }); }; diff --git a/src/app/menu/show-composer-mode/utils/renderVersionWarning.ts b/src/app/menu/show-composer-mode/utils/renderVersionWarning.ts index 1109eb0..eaebd58 100644 --- a/src/app/menu/show-composer-mode/utils/renderVersionWarning.ts +++ b/src/app/menu/show-composer-mode/utils/renderVersionWarning.ts @@ -47,6 +47,7 @@ function checkForLatestVersion(): Promise { (res) => { if (res.statusCode === 200) { let body = ""; + // eslint-disable-next-line @typescript-eslint/restrict-plus-operands res.on("data", (data) => (body += data)); res.on("end", () => { resolve((JSON.parse(body) as DistTagsBody).latest); diff --git a/src/app/menu/showAnykeyPrompt.ts b/src/app/menu/showAnykeyPrompt.ts index 0f92115..6da686b 100644 --- a/src/app/menu/showAnykeyPrompt.ts +++ b/src/app/menu/showAnykeyPrompt.ts @@ -2,7 +2,7 @@ import { anykeyPrompt } from "@reliverse/prompts"; import pc from "picocolors"; export async function showAnykeyPrompt() { - const notification = `šŸ¤– Hello, my name is Reliverse! I'm your assistant for creating new web projects, integrating new features, and making advanced codebase modifications. āœØ I'm constantly evolving, with even more features on the way! In the future, I'll be able to work with not only web apps. Let's get started!\nā”‚ ============================\nā”‚ ${pc.bold("Press any key to continue...")}`; + const notification = `šŸ¤– Hello, my name is Reliverse! I'm your assistant for creating new web projects, integrating new features, and making advanced codebase modifications.\nāœØ I'm constantly evolving, with even more features on the way! In the future, I'll be able to work with not only web apps. Let's get started!\nā”‚ ============================\nā”‚ ${pc.bold("Press any key to continue...")}`; await anykeyPrompt(notification); } diff --git a/src/app/menu/showStartEndPrompt.ts b/src/app/menu/showStartEndPrompt.ts index 7bff706..2977b3e 100644 --- a/src/app/menu/showStartEndPrompt.ts +++ b/src/app/menu/showStartEndPrompt.ts @@ -6,7 +6,7 @@ export async function showStartPrompt() { titleColor: "inverse", clearConsole: true, packageName: "@reliverse/cli", - packageVersion: "1.4.3", + packageVersion: "1.4.8", }); } diff --git a/src/args/config/mod.ts b/src/args/config/mod.ts index d0a8ce2..07cd4bc 100644 --- a/src/args/config/mod.ts +++ b/src/args/config/mod.ts @@ -49,7 +49,7 @@ export default defineCommand({ projectCategory: rules.experimental?.projectCategory ?? "website", projectType: rules.experimental?.projectType ?? "development", projectDeployService: - rules.experimental?.projectDeployService ?? "Vercel", + rules.experimental?.projectDeployService ?? "vercel", projectDisplayName: rules.experimental?.projectDisplayName ?? "", projectDomain: rules.experimental?.projectDomain ?? "", projectState: rules.experimental?.projectState ?? "creating", @@ -64,9 +64,6 @@ export default defineCommand({ rules.experimental?.projectPackageManager ?? "npm", nodeVersion: rules.experimental?.nodeVersion ?? "latest", runtime: rules.experimental?.runtime ?? "nodejs", - - // Deployment - deployPlatform: rules.experimental?.deployPlatform ?? "Vercel", productionBranch: rules.experimental?.productionBranch ?? "main", deployUrl: rules.experimental?.deployUrl ?? "", diff --git a/src/args/login/impl.ts b/src/args/login/impl.ts index 43729b1..f8630d2 100644 --- a/src/args/login/impl.ts +++ b/src/args/login/impl.ts @@ -1,6 +1,6 @@ import type { ParsedUrlQuery } from "querystring"; -import { task } from "@reliverse/prompts"; +import { spinnerTaskPrompt } from "@reliverse/prompts"; import { listen } from "async-listen"; import http from "http"; import { customAlphabet } from "nanoid"; @@ -39,13 +39,13 @@ export async function auth({ }) { relinka("info", "Let's authenticate you..."); - await task({ + await spinnerTaskPrompt({ initialMessage: "Waiting for user confirmation...", successMessage: "Login cancelled. See you next time šŸ‘‹", errorMessage: "Authentication failed!", spinnerSolution: "ora", spinnerType: "arc", - action: async (updateMessage) => { + action: async (updateMessage: (message: string) => void) => { // Create a local HTTP server to handle the authentication callback const server = http.createServer(); let port: number | string | undefined; diff --git a/src/main.ts b/src/main.ts index 52001fe..8bcc4ad 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,12 +2,12 @@ import { defineCommand, errorHandler, runMain } from "@reliverse/prompts"; -import { logger } from "./app/menu/show-composer-mode/utils/logger.js"; +import { relinka } from "~/utils/console.js"; const main = defineCommand({ meta: { name: "reliverse", - version: "1.4.3", + version: "1.4.8", description: "https://docs.reliverse.org", }, subCommands: { diff --git a/src/types.ts b/src/types.ts index 0c47426..9ca5572 100644 --- a/src/types.ts +++ b/src/types.ts @@ -64,7 +64,12 @@ export type IntegrationCategory = export type IntegrationOptions = Record; -export type DeploymentService = "Vercel" | "Netlify" | "Railway" | "none"; +export type DeploymentService = + | "vercel" + | "deno" + | "netlify" + | "railway" + | "none"; export type PreferredLibraries = { stateManagement?: "zustand" | "jotai" | "redux-toolkit" | "none"; @@ -83,7 +88,7 @@ export type PreferredLibraries = { api?: "trpc" | "graphql" | "rest" | "none"; linting?: "eslint" | "none"; formatting?: "biome" | "none"; - deployment?: "vercel" | "none"; + deployment?: DeploymentService; payment?: "stripe" | "none"; analytics?: "vercel" | "none"; monitoring?: "sentry" | "none"; @@ -150,7 +155,7 @@ export type TemplateOption = | "blefnk/next-react-ts-src-minimal"; // design = graphic|video|audio|3d design -export type ProjectTypeOtions = "" | "development" | "design" | "marketing"; +export type ProjectTypeOptions = "" | "development" | "design" | "marketing"; export type ProjectCategory = | "" @@ -189,7 +194,7 @@ export type ReliverseConfig = { projectRepository?: string | undefined; projectState?: ProjectState | undefined; projectDomain?: string | undefined; - projectType?: ProjectTypeOtions | undefined; + projectType?: ProjectTypeOptions | undefined; projectCategory?: ProjectCategory | undefined; projectSubcategory?: ProjectSubcategory | undefined; projectTemplate?: TemplateOption | undefined; @@ -201,12 +206,8 @@ export type ReliverseConfig = { projectDisplayName?: string | undefined; nodeVersion?: string | undefined; runtime?: string | undefined; - - // Deployment - deployPlatform?: DeploymentService | undefined; productionBranch?: string | undefined; deployUrl?: string | undefined; - monorepo?: | { type: string; diff --git a/src/utils/configs/miscellaneousConfigHelpers.ts b/src/utils/configs/miscellaneousConfigHelpers.ts index 12e3be7..6e5abcc 100644 --- a/src/utils/configs/miscellaneousConfigHelpers.ts +++ b/src/utils/configs/miscellaneousConfigHelpers.ts @@ -139,15 +139,13 @@ export async function readConfig(cwd: string): Promise { rules.experimental?.projectRepository ?? config.experimental?.projectRepository ?? "", - - deployPlatform: rules.experimental?.deployPlatform ?? "Vercel", productionBranch: rules.experimental?.productionBranch ?? "main", deployUrl: rules.experimental?.deployUrl ?? "", projectActivation: rules.experimental?.projectActivation ?? "auto", projectCategory: rules.experimental?.projectCategory ?? "website", projectType: rules.experimental?.projectType ?? "development", projectDeployService: - rules.experimental?.projectDeployService ?? "Vercel", + rules.experimental?.projectDeployService ?? "vercel", projectDisplayName: rules.experimental?.projectDisplayName ?? "", projectDomain: rules.experimental?.projectDomain ?? "", projectState: rules.experimental?.projectState ?? "creating", diff --git a/src/utils/downloadGitRepo.ts b/src/utils/downloadGitRepo.ts index 7b88759..b81f7cf 100644 --- a/src/utils/downloadGitRepo.ts +++ b/src/utils/downloadGitRepo.ts @@ -26,11 +26,11 @@ export async function downloadGitRepo( // Check if directory contains only .reliverse const files = await fs.readdir(targetDir); - const hasOnlyReliverserules = + const hasOnlyReliverseConfig = files.length === 1 && files[0] === ".reliverse"; // If directory is not empty and doesn't contain only .reliverse, throw error - if (files.length > 0 && !hasOnlyReliverserules) { + if (files.length > 0 && !hasOnlyReliverseConfig) { throw new Error( `Target directory ${targetDir} is not empty and contains files other than .reliverse`, ); @@ -38,11 +38,11 @@ export async function downloadGitRepo( // Temporarily move .reliverse if it exists const parentDir = path.dirname(targetDir); - const tempReliverserulesPath = path.join(parentDir, ".reliverse"); + const tempReliverseConfigPath = path.join(parentDir, ".reliverse"); - if (hasOnlyReliverserules) { + if (hasOnlyReliverseConfig) { // Check if .reliverse already exists in parent directory - if (await fs.pathExists(tempReliverserulesPath)) { + if (await fs.pathExists(tempReliverseConfigPath)) { const choice = await selectPrompt({ title: ".reliverse already exists in parent directory. What would you like to do?", @@ -53,7 +53,7 @@ export async function downloadGitRepo( }); if (choice === "delete") { - await fs.remove(tempReliverserulesPath); + await fs.remove(tempReliverseConfigPath); } else { // Find appropriate backup name let backupPath = path.join(parentDir, ".reliverse.bak"); @@ -62,11 +62,14 @@ export async function downloadGitRepo( backupPath = path.join(parentDir, `.reliverse_${iteration}.bak`); iteration++; } - await fs.move(tempReliverserulesPath, backupPath); + await fs.move(tempReliverseConfigPath, backupPath); } } - await fs.move(path.join(targetDir, ".reliverse"), tempReliverserulesPath); + await fs.move( + path.join(targetDir, ".reliverse"), + tempReliverseConfigPath, + ); await fs.remove(targetDir); await fs.ensureDir(targetDir); } @@ -78,9 +81,9 @@ export async function downloadGitRepo( await git.clone(repoUrl, targetDir); // Restore .reliverse if it was moved - if (hasOnlyReliverserules) { + if (hasOnlyReliverseConfig) { await fs.move( - tempReliverserulesPath, + tempReliverseConfigPath, path.join(targetDir, ".reliverse"), { overwrite: true }, ); @@ -91,12 +94,12 @@ export async function downloadGitRepo( } catch (error) { // Restore .reliverse if operation failed if ( - hasOnlyReliverserules && - (await fs.pathExists(tempReliverserulesPath)) + hasOnlyReliverseConfig && + (await fs.pathExists(tempReliverseConfigPath)) ) { await fs.ensureDir(targetDir); await fs.move( - tempReliverserulesPath, + tempReliverseConfigPath, path.join(targetDir, ".reliverse"), { overwrite: true }, ); diff --git a/src/utils/handlers/codemods/convertToMonorepo.ts b/src/utils/handlers/codemods/convertToMonorepo.ts index be9900c..b742160 100644 --- a/src/utils/handlers/codemods/convertToMonorepo.ts +++ b/src/utils/handlers/codemods/convertToMonorepo.ts @@ -74,7 +74,7 @@ export async function convertToMonorepo( // Move other common files const commonFiles = [ "tsconfig.json", - ".eslintrc.js", + "eslint.config.js", ".prettierrc", "next.config.js", "postcss.config.js", diff --git a/tsconfig.json b/tsconfig.json index 514401a..a200e9c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -38,6 +38,7 @@ "build.optim.ts", "build.config.ts", "vitest.config.ts", + "src/**/*.js", "src/**/*.ts", "src/**/*.tsx", "addons/**/*.ts",