| 1 | import path from "node:path"; |
| 2 | import { consola } from "consola"; |
| 3 | import { execa } from "execa"; |
| 4 | import fs from "fs-extra"; |
| 5 | import pc from "picocolors"; |
| 6 | import yoctoSpinner from "yocto-spinner"; |
| 7 | import { |
| 8 | defaultTemplate, |
| 9 | honoClientTemplate, |
| 10 | honoRpcTemplate, |
| 11 | shadcnTemplate, |
| 12 | tailwindTemplate, |
| 13 | } from "@/utils/templates"; |
| 14 | |
| 15 | export async function patchFilesForRPC( |
| 16 | projectPath: string, |
| 17 | templateChoice: string, |
| 18 | ): Promise<boolean> { |
| 19 | const spinner = yoctoSpinner({ text: "Setting up RPC client..." }).start(); |
| 20 | |
| 21 | try { |
| 22 | // 1. Update client package.json to ensure hono client is installed |
| 23 | const clientPkgPath = path.join(projectPath, "client", "package.json"); |
| 24 | const clientPkg = await fs.readJson(clientPkgPath); |
| 25 | |
| 26 | if (!clientPkg.dependencies.hono) { |
| 27 | await execa("bun", ["install", "hono"], { cwd: projectPath }); |
| 28 | } |
| 29 | |
| 30 | await fs.writeJson(clientPkgPath, clientPkg, { spaces: 2 }); |
| 31 | |
| 32 | // 2. Update server package.json dev script for RPC |
| 33 | const serverPkgPath = path.join(projectPath, "server", "package.json"); |
| 34 | const serverPkg = await fs.readJson(serverPkgPath); |
| 35 | |
| 36 | // Update the dev script to include TypeScript compilation |
| 37 | serverPkg.scripts.dev = "bun --watch run src/index.ts && tsc --watch"; |
| 38 | |
| 39 | await fs.writeJson(serverPkgPath, serverPkg, { spaces: 2 }); |
| 40 | |
| 41 | // 3. Server modification for RPC export type (no client imports) |
| 42 | const serverIndexPath = path.join(projectPath, "server", "src", "index.ts"); |
| 43 | await fs.writeFile(serverIndexPath, honoRpcTemplate, "utf8"); |
| 44 | |
| 45 | // 4. Create separate client helper file |
| 46 | const clientHelperPath = path.join( |
| 47 | projectPath, |
| 48 | "server", |
| 49 | "src", |
| 50 | "client.ts", |
| 51 | ); |
| 52 | await fs.writeFile(clientHelperPath, honoClientTemplate, "utf8"); |
| 53 | |
| 54 | // 5. Update App.tsx based on template selection using switch statement |
| 55 | const appTsxPath = path.join(projectPath, "client", "src", "App.tsx"); |
| 56 | |
| 57 | // Determine template content based on the template type |
| 58 | let updatedAppContent: string; |
| 59 | |
| 60 | // Select template based on choice |
| 61 | switch (templateChoice) { |
| 62 | case "shadcn": |
| 63 | updatedAppContent = shadcnTemplate; |
| 64 | break; |
| 65 | case "tailwind": |
| 66 | updatedAppContent = tailwindTemplate; |
| 67 | break; |
| 68 | default: |
| 69 | updatedAppContent = defaultTemplate; |
| 70 | break; |
| 71 | } |
| 72 | |
| 73 | await fs.writeFile(appTsxPath, updatedAppContent, "utf8"); |
| 74 | spinner.success("RPC client setup completed"); |
| 75 | return true; |
| 76 | } catch (err: unknown) { |
| 77 | spinner.error("Failed to set up RPC client"); |
| 78 | if (err instanceof Error) { |
| 79 | consola.error(pc.red("Error:"), err.message); |
| 80 | } else { |
| 81 | consola.error(pc.red("Error: Unknown error")); |
| 82 | } |
| 83 | return false; |
| 84 | } |
| 85 | } |