import ora from "ora" const appRoutesTemplate = ` import { BrowserRouter, Routes, Route } from "react-router-dom"; import Home from "./pages/Home"; import NotFound from "./pages/NotFound"; export default function AppRoutes() { return ( } /> } /> ); } ` const postCssTemplate = ` module.exports = { plugins: { 'postcss-preset-mantine': {}, 'postcss-simple-vars': { variables: { 'mantine-breakpoint-xs': '36em', 'mantine-breakpoint-sm': '48em', 'mantine-breakpoint-md': '62em', 'mantine-breakpoint-lg': '75em', 'mantine-breakpoint-xl': '88em', }, }, }, }; ` const appTemplate = ` import '@mantine/core/styles.css'; import { MantineProvider } from '@mantine/core'; import AppRoutes from './AppRoutes'; export function App() { return ; } ` const homeTemplate = ` export default function Home() { return (

Home

); } ` const serverTemplate = ` import Elysia from "elysia"; import Swagger from "@elysiajs/swagger"; import html from "./index.html" import Darmasaba from "./server/routes/darmasaba"; import apiAuth from "./server/middlewares/apiAuth"; const Docs = new Elysia() .use(Swagger({ path: "/docs", })) const Api = new Elysia({ prefix: "/api", }) .use(apiAuth) .use(Darmasaba) const app = new Elysia() .use(Api) .use(Docs) .get("*", html) .listen(3000, () => { console.log("Server running at http://localhost:3000"); }); export type Server = typeof app; ` const notFoundTemplate = ` export default function NotFound() { return (

404 Not Found

); } ` const prismaTemplate = ` import { PrismaClient } from 'generated/prisma' const globalForPrisma = globalThis as unknown as { prisma: PrismaClient | undefined } export const prisma = globalForPrisma.prisma ?? new PrismaClient() if (process.env.NODE_ENV !== 'production') { globalForPrisma.prisma = prisma } ` const apiAuthTemplate = ` //* eslint-disable @typescript-eslint/no-explicit-any */ import jwt, { type JWTPayloadSpec } from '@elysiajs/jwt' import Elysia from 'elysia' import { prisma } from '../lib/prisma' const secret = process.env.JWT_SECRET export default function apiAuth(app: Elysia) { if (!secret) { throw new Error('JWT_SECRET is not defined') } return app .use( jwt({ name: 'jwt', secret, }) ) .derive(async ({ cookie, headers, jwt }) => { let token: string | undefined if (cookie?.token?.value) { token = cookie.token.value as any } if (headers['x-token']?.startsWith('Bearer ')) { token = (headers['x-token'] as string).slice(7) } if (headers['authorization']?.startsWith('Bearer ')) { token = (headers['authorization'] as string).slice(7) } let user: null | Awaited> = null if (token) { try { const decoded = (await jwt.verify(token)) as JWTPayloadSpec if (decoded.sub) { user = await prisma.user.findUnique({ where: { id: decoded.sub as string }, }) } } catch (err) { console.warn('[SERVER][apiAuth] Invalid token', err) } } return { user } }) .onBeforeHandle(({ user, set }) => { if (!user) { set.status = 401 return { error: 'Unauthorized' } } }) } ` const envFileTemplate = (appName: string) => ` DATABASE_URL="postgresql://bip:Production_123@localhost:5432/${appName}?schema=public" JWT_SECRET=super_sangat_rahasia_sekali ` const prismaSchemaTemplate = ` generator client { provider = "prisma-client-js" output = "../generated/prisma" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } model User { id String @id @default(cuid()) name String? email String? @unique password String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } ` const cmd = (appName: string) => ` bun init --react ${appName} echo "init react" cd ${appName} echo "cd ${appName}" echo "install dependencies" bun add react-router-dom bun add @mantine/core @mantine/hooks bun add --dev postcss postcss-preset-mantine postcss-simple-vars bun add elysia @elysiajs/cors @elysiajs/swagger @elysiajs/eden @elysiajs/jwt prisma @prisma/client echo "init prisma" bun x prisma init echo "generate file ..." echo "generate postcss.config.js" cat < postcss.config.js ${postCssTemplate} EOF echo "generate src/App.tsx" cat < src/App.tsx ${appTemplate} EOF echo "generate src/AppRoutes.tsx" cat < src/AppRoutes.tsx ${appRoutesTemplate} EOF echo "create dir src/pages" mkdir src/pages echo "generate src/pages/Home.tsx" cat < src/pages/Home.tsx ${homeTemplate} EOF echo "generate src/index.tsx" cat < src/index.tsx ${serverTemplate} EOF echo "generate src/pages/NotFound.tsx" cat < src/pages/NotFound.tsx ${notFoundTemplate} EOF echo "create dir src/server/lib" mkdir -p src/server/lib echo "generate src/server/lib/prisma.ts" cat < src/server/lib/prisma.ts ${prismaTemplate} EOF echo "create dir server/middlewares" mkdir -p server/middlewares echo "generate server/middlewares/apiAuth.ts" cat < server/middlewares/apiAuth.ts ${apiAuthTemplate} EOF echo "generate .env" cat < .env ${envFileTemplate(appName)} EOF echo "generate prisma/schema.prisma" cat < prisma/schema.prisma ${prismaSchemaTemplate} EOF echo "remove src/APITester.tsx" rm src/APITester.tsx ls echo "✅ done" ` export default async function appCreate({ appName }: { appName: string }) { const spinner = ora(`Creating app ${appName}...`).start(); const { stdout } = Bun.spawnSync(["bash", "-c", cmd(appName)]); spinner.stop(); console.log(stdout.toString()); }