create-better-t-stack 0.1.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/README.md +59 -49
  2. package/dist/index.js +135 -305
  3. package/package.json +19 -11
  4. package/template/base/_gitignore +2 -0
  5. package/template/base/package.json +18 -0
  6. package/template/base/packages/client/_gitignore +23 -0
  7. package/template/base/packages/client/components.json +21 -0
  8. package/template/base/packages/client/index.html +12 -0
  9. package/template/base/packages/client/package.json +49 -0
  10. package/template/base/packages/client/src/components/header.tsx +31 -0
  11. package/template/base/packages/client/src/components/loader.tsx +9 -0
  12. package/template/base/packages/client/src/components/mode-toggle.tsx +37 -0
  13. package/template/base/packages/client/src/components/theme-provider.tsx +73 -0
  14. package/template/base/packages/client/src/components/ui/button.tsx +57 -0
  15. package/template/base/packages/client/src/components/ui/card.tsx +92 -0
  16. package/template/base/packages/client/src/components/ui/checkbox.tsx +30 -0
  17. package/template/base/packages/client/src/components/ui/dropdown-menu.tsx +199 -0
  18. package/template/base/packages/client/src/components/ui/input.tsx +22 -0
  19. package/template/base/packages/client/src/components/ui/label.tsx +24 -0
  20. package/template/base/packages/client/src/components/ui/skeleton.tsx +15 -0
  21. package/template/base/packages/client/src/components/ui/sonner.tsx +29 -0
  22. package/template/base/packages/client/src/index.css +119 -0
  23. package/template/base/packages/client/src/lib/utils.ts +6 -0
  24. package/template/base/packages/client/src/main.tsx +72 -0
  25. package/template/base/packages/client/src/routes/__root.tsx +58 -0
  26. package/template/base/packages/client/src/routes/index.tsx +89 -0
  27. package/template/base/packages/client/src/utils/trpc.ts +4 -0
  28. package/template/base/packages/client/tsconfig.json +18 -0
  29. package/template/base/packages/client/vite.config.ts +14 -0
  30. package/template/base/packages/server/_gitignore +36 -0
  31. package/template/base/packages/server/package.json +27 -0
  32. package/template/base/packages/server/src/index.ts +41 -0
  33. package/template/base/packages/server/src/lib/context.ts +13 -0
  34. package/template/base/packages/server/src/lib/trpc.ts +8 -0
  35. package/template/base/packages/server/src/routers/index.ts +11 -0
  36. package/template/base/packages/server/tsconfig.json +18 -0
  37. package/template/base/turbo.json +27 -0
  38. package/template/examples/todo/packages/client/src/routes/todos.tsx +128 -0
  39. package/template/examples/todo/packages/server/src/routers/with-drizzle-todo.ts +44 -0
  40. package/template/examples/todo/packages/server/src/routers/with-prisma-todo.ts +55 -0
  41. package/template/with-auth/packages/client/src/components/auth-forms.tsx +13 -0
  42. package/template/with-auth/packages/client/src/components/header.tsx +34 -0
  43. package/template/with-auth/packages/client/src/components/sign-in-form.tsx +139 -0
  44. package/template/with-auth/packages/client/src/components/sign-up-form.tsx +164 -0
  45. package/template/with-auth/packages/client/src/components/user-menu.tsx +62 -0
  46. package/template/with-auth/packages/client/src/lib/auth-client.ts +5 -0
  47. package/template/with-auth/packages/client/src/main.tsx +78 -0
  48. package/template/with-auth/packages/client/src/routes/dashboard.tsx +36 -0
  49. package/template/with-auth/packages/client/src/routes/login.tsx +11 -0
  50. package/template/with-auth/packages/server/src/index.ts +46 -0
  51. package/template/with-auth/packages/server/src/lib/trpc.ts +24 -0
  52. package/template/with-auth/packages/server/src/routers/index.ts +19 -0
  53. package/template/with-biome/biome.json +42 -0
  54. package/template/with-drizzle-postgres/packages/server/drizzle.config.ts +10 -0
  55. package/template/with-drizzle-postgres/packages/server/src/db/index.ts +5 -0
  56. package/template/with-drizzle-postgres/packages/server/src/db/schema/auth.ts +47 -0
  57. package/template/with-drizzle-postgres/packages/server/src/db/schema/todo.ts +7 -0
  58. package/template/with-drizzle-postgres/packages/server/src/routers/todo.ts +44 -0
  59. package/template/with-drizzle-postgres/packages/server/src/with-auth-lib/auth.ts +15 -0
  60. package/template/with-drizzle-postgres/packages/server/src/with-auth-lib/context.ts +18 -0
  61. package/template/with-drizzle-postgres/packages/server/src/with-auth-lib/trpc.ts +24 -0
  62. package/template/with-drizzle-sqlite/packages/server/drizzle.config.ts +11 -0
  63. package/template/with-drizzle-sqlite/packages/server/src/db/index.ts +9 -0
  64. package/template/with-drizzle-sqlite/packages/server/src/db/schema/auth.ts +61 -0
  65. package/template/with-drizzle-sqlite/packages/server/src/db/schema/todo.ts +7 -0
  66. package/template/with-drizzle-sqlite/packages/server/src/with-auth-lib/auth.ts +15 -0
  67. package/template/with-drizzle-sqlite/packages/server/src/with-auth-lib/context.ts +18 -0
  68. package/template/with-drizzle-sqlite/packages/server/src/with-auth-lib/trpc.ts +24 -0
  69. package/template/with-husky/.husky/pre-commit +1 -0
  70. package/template/with-prisma-postgres/packages/server/prisma/index.ts +5 -0
  71. package/template/with-prisma-postgres/packages/server/prisma/schema/auth.prisma +59 -0
  72. package/template/with-prisma-postgres/packages/server/prisma/schema/schema.prisma +9 -0
  73. package/template/with-prisma-postgres/packages/server/prisma/schema/todo.prisma +7 -0
  74. package/template/with-prisma-postgres/packages/server/src/with-auth-lib/auth.ts +17 -0
  75. package/template/with-prisma-postgres/packages/server/src/with-auth-lib/context.ts +18 -0
  76. package/template/with-prisma-postgres/packages/server/src/with-auth-lib/trpc.ts +24 -0
  77. package/template/with-prisma-sqlite/packages/server/prisma/index.ts +5 -0
  78. package/template/with-prisma-sqlite/packages/server/prisma/schema/auth.prisma +59 -0
  79. package/template/with-prisma-sqlite/packages/server/prisma/schema/schema.prisma +8 -0
  80. package/template/with-prisma-sqlite/packages/server/prisma/schema/todo.prisma +7 -0
  81. package/template/with-prisma-sqlite/packages/server/src/with-auth-lib/auth.ts +17 -0
  82. package/template/with-prisma-sqlite/packages/server/src/with-auth-lib/context.ts +18 -0
  83. package/template/with-prisma-sqlite/packages/server/src/with-auth-lib/trpc.ts +24 -0
  84. package/template/with-pwa/packages/client/public/logo.png +0 -0
  85. package/template/with-pwa/packages/client/pwa-assets.config.ts +12 -0
  86. package/template/with-pwa/packages/client/vite.config.ts +35 -0
@@ -0,0 +1,29 @@
1
+ import { useTheme } from "next-themes"
2
+ import { Toaster as Sonner } from "sonner"
3
+
4
+ type ToasterProps = React.ComponentProps<typeof Sonner>
5
+
6
+ const Toaster = ({ ...props }: ToasterProps) => {
7
+ const { theme = "system" } = useTheme()
8
+
9
+ return (
10
+ <Sonner
11
+ theme={theme as ToasterProps["theme"]}
12
+ className="toaster group"
13
+ toastOptions={{
14
+ classNames: {
15
+ toast:
16
+ "group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
17
+ description: "group-[.toast]:text-muted-foreground",
18
+ actionButton:
19
+ "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
20
+ cancelButton:
21
+ "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
22
+ },
23
+ }}
24
+ {...props}
25
+ />
26
+ )
27
+ }
28
+
29
+ export { Toaster }
@@ -0,0 +1,119 @@
1
+ @import 'tailwindcss';
2
+
3
+ @plugin 'tailwindcss-animate';
4
+
5
+ @custom-variant dark (&:is(.dark *));
6
+
7
+ @theme {
8
+ --radius-lg: var(--radius);
9
+ --radius-md: calc(var(--radius) - 2px);
10
+ --radius-sm: calc(var(--radius) - 4px);
11
+
12
+ --color-background: hsl(var(--background));
13
+ --color-foreground: hsl(var(--foreground));
14
+
15
+ --color-card: hsl(var(--card));
16
+ --color-card-foreground: hsl(var(--card-foreground));
17
+
18
+ --color-popover: hsl(var(--popover));
19
+ --color-popover-foreground: hsl(var(--popover-foreground));
20
+
21
+ --color-primary: hsl(var(--primary));
22
+ --color-primary-foreground: hsl(var(--primary-foreground));
23
+
24
+ --color-secondary: hsl(var(--secondary));
25
+ --color-secondary-foreground: hsl(var(--secondary-foreground));
26
+
27
+ --color-muted: hsl(var(--muted));
28
+ --color-muted-foreground: hsl(var(--muted-foreground));
29
+
30
+ --color-accent: hsl(var(--accent));
31
+ --color-accent-foreground: hsl(var(--accent-foreground));
32
+
33
+ --color-destructive: hsl(var(--destructive));
34
+ --color-destructive-foreground: hsl(var(--destructive-foreground));
35
+
36
+ --color-border: hsl(var(--border));
37
+ --color-input: hsl(var(--input));
38
+ --color-ring: hsl(var(--ring));
39
+
40
+ --color-chart-1: hsl(var(--chart-1));
41
+ --color-chart-2: hsl(var(--chart-2));
42
+ --color-chart-3: hsl(var(--chart-3));
43
+ --color-chart-4: hsl(var(--chart-4));
44
+ --color-chart-5: hsl(var(--chart-5));
45
+ }
46
+
47
+ @layer base {
48
+ *,
49
+ ::after,
50
+ ::before,
51
+ ::backdrop,
52
+ ::file-selector-button {
53
+ border-color: var(--color-gray-200, currentColor);
54
+ }
55
+ }
56
+
57
+ @layer base {
58
+ :root {
59
+ --background: 0 0% 100%;
60
+ --foreground: 0 0% 3.9%;
61
+ --card: 0 0% 100%;
62
+ --card-foreground: 0 0% 3.9%;
63
+ --popover: 0 0% 100%;
64
+ --popover-foreground: 0 0% 3.9%;
65
+ --primary: 0 0% 9%;
66
+ --primary-foreground: 0 0% 98%;
67
+ --secondary: 0 0% 96.1%;
68
+ --secondary-foreground: 0 0% 9%;
69
+ --muted: 0 0% 96.1%;
70
+ --muted-foreground: 0 0% 45.1%;
71
+ --accent: 0 0% 96.1%;
72
+ --accent-foreground: 0 0% 9%;
73
+ --destructive: 0 84.2% 60.2%;
74
+ --destructive-foreground: 0 0% 98%;
75
+ --border: 0 0% 89.8%;
76
+ --input: 0 0% 89.8%;
77
+ --ring: 0 0% 3.9%;
78
+ --chart-1: 12 76% 61%;
79
+ --chart-2: 173 58% 39%;
80
+ --chart-3: 197 37% 24%;
81
+ --chart-4: 43 74% 66%;
82
+ --chart-5: 27 87% 67%;
83
+ --radius: 0.5rem;
84
+ }
85
+ .dark {
86
+ --background: 0 0% 3.9%;
87
+ --foreground: 0 0% 98%;
88
+ --card: 0 0% 3.9%;
89
+ --card-foreground: 0 0% 98%;
90
+ --popover: 0 0% 3.9%;
91
+ --popover-foreground: 0 0% 98%;
92
+ --primary: 0 0% 98%;
93
+ --primary-foreground: 0 0% 9%;
94
+ --secondary: 0 0% 14.9%;
95
+ --secondary-foreground: 0 0% 98%;
96
+ --muted: 0 0% 14.9%;
97
+ --muted-foreground: 0 0% 63.9%;
98
+ --accent: 0 0% 14.9%;
99
+ --accent-foreground: 0 0% 98%;
100
+ --destructive: 0 62.8% 30.6%;
101
+ --destructive-foreground: 0 0% 98%;
102
+ --border: 0 0% 14.9%;
103
+ --input: 0 0% 14.9%;
104
+ --ring: 0 0% 83.1%;
105
+ --chart-1: 220 70% 50%;
106
+ --chart-2: 160 60% 45%;
107
+ --chart-3: 30 80% 55%;
108
+ --chart-4: 280 65% 60%;
109
+ --chart-5: 340 75% 55%;
110
+ }
111
+ }
112
+ @layer base {
113
+ * {
114
+ @apply border-border;
115
+ }
116
+ body {
117
+ @apply bg-background text-foreground;
118
+ }
119
+ }
@@ -0,0 +1,6 @@
1
+ import { clsx, type ClassValue } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs))
6
+ }
@@ -0,0 +1,72 @@
1
+ import {
2
+ QueryCache,
3
+ QueryClient,
4
+ QueryClientProvider,
5
+ } from "@tanstack/react-query";
6
+ import { RouterProvider, createRouter } from "@tanstack/react-router";
7
+ import { httpBatchLink } from "@trpc/client";
8
+ import { createTRPCQueryUtils } from "@trpc/react-query";
9
+ import ReactDOM from "react-dom/client";
10
+ import { toast } from "sonner";
11
+ import Loader from "./components/loader";
12
+ import { routeTree } from "./routeTree.gen";
13
+ import { trpc } from "./utils/trpc";
14
+
15
+ const queryClient = new QueryClient({
16
+ queryCache: new QueryCache({
17
+ onError: (error) => {
18
+ toast.error(error.message, {
19
+ action: {
20
+ label: "retry",
21
+ onClick: () => {
22
+ queryClient.invalidateQueries();
23
+ },
24
+ },
25
+ });
26
+ },
27
+ }),
28
+ });
29
+
30
+ const trpcClient = trpc.createClient({
31
+ links: [
32
+ httpBatchLink({
33
+ url: `${import.meta.env.VITE_SERVER_URL}/trpc`,
34
+ }),
35
+ ],
36
+ });
37
+
38
+ export const trpcQueryUtils = createTRPCQueryUtils({
39
+ queryClient,
40
+ client: trpcClient,
41
+ });
42
+
43
+ const router = createRouter({
44
+ routeTree,
45
+ defaultPreload: "intent",
46
+ context: { trpcQueryUtils },
47
+ defaultPendingComponent: () => <Loader />,
48
+ Wrap: function WrapComponent({ children }) {
49
+ return (
50
+ <trpc.Provider client={trpcClient} queryClient={queryClient}>
51
+ <QueryClientProvider client={queryClient}>
52
+ {children}
53
+ </QueryClientProvider>
54
+ </trpc.Provider>
55
+ );
56
+ },
57
+ });
58
+
59
+ // Register things for typesafety
60
+ declare module "@tanstack/react-router" {
61
+ interface Register {
62
+ router: typeof router;
63
+ }
64
+ }
65
+
66
+ const rootElement = document.getElementById("app");
67
+ if (!rootElement) throw new Error("Root element not found");
68
+
69
+ if (!rootElement.innerHTML) {
70
+ const root = ReactDOM.createRoot(rootElement);
71
+ root.render(<RouterProvider router={router} />);
72
+ }
@@ -0,0 +1,58 @@
1
+ import Header from "@/components/header";
2
+ import Loader from "@/components/loader";
3
+ import { ThemeProvider } from "@/components/theme-provider";
4
+ import { Toaster } from "@/components/ui/sonner";
5
+ import { trpcQueryUtils } from "@/main";
6
+ import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
7
+ import {
8
+ Outlet,
9
+ createRootRouteWithContext,
10
+ useRouterState,
11
+ HeadContent,
12
+ } from "@tanstack/react-router";
13
+ import { TanStackRouterDevtools } from "@tanstack/react-router-devtools";
14
+ import "../index.css";
15
+
16
+ export interface RouterAppContext {
17
+ trpcQueryUtils: typeof trpcQueryUtils;
18
+ }
19
+
20
+ export const Route = createRootRouteWithContext<RouterAppContext>()({
21
+ component: RootComponent,
22
+ head: () => ({
23
+ meta: [
24
+ {
25
+ title: "My App",
26
+ },
27
+ {
28
+ name: "description",
29
+ content: "My App is a web application",
30
+ },
31
+ ],
32
+ links: [
33
+ {
34
+ rel: "icon",
35
+ href: "/favicon.ico",
36
+ },
37
+ ],
38
+ }),
39
+ });
40
+
41
+ function RootComponent() {
42
+ const isFetching = useRouterState({
43
+ select: (s) => s.isLoading,
44
+ });
45
+ return (
46
+ <>
47
+ <HeadContent />
48
+ <ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">
49
+ <Header />
50
+ {isFetching && <Loader />}
51
+ <Outlet />
52
+ <Toaster richColors />
53
+ </ThemeProvider>
54
+ <TanStackRouterDevtools position="bottom-left" />
55
+ <ReactQueryDevtools position="bottom" buttonPosition="bottom-right" />
56
+ </>
57
+ );
58
+ }
@@ -0,0 +1,89 @@
1
+ import { trpc } from "@/utils/trpc";
2
+ import { createFileRoute, Link } from "@tanstack/react-router";
3
+ import { ArrowRight } from "lucide-react";
4
+ import { Button } from "@/components/ui/button";
5
+
6
+ export const Route = createFileRoute("/")({
7
+ component: HomeComponent,
8
+ });
9
+
10
+ const TITLE_TEXT = `
11
+ ██████╗ ███████╗████████╗████████╗███████╗██████╗
12
+ ██╔══██╗██╔════╝╚══██╔══╝╚══██╔══╝██╔════╝██╔══██╗
13
+ ██████╔╝█████╗ ██║ ██║ █████╗ ██████╔╝
14
+ ██╔══██╗██╔══╝ ██║ ██║ ██╔══╝ ██╔══██╗
15
+ ██████╔╝███████╗ ██║ ██║ ███████╗██║ ██║
16
+ ╚═════╝ ╚══════╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝
17
+
18
+ ████████╗ ███████╗████████╗ █████╗ ██████╗██╗ ██╗
19
+ ╚══██╔══╝ ██╔════╝╚══██╔══╝██╔══██╗██╔════╝██║ ██╔╝
20
+ ██║ ███████╗ ██║ ███████║██║ █████╔╝
21
+ ██║ ╚════██║ ██║ ██╔══██║██║ ██╔═██╗
22
+ ██║ ███████║ ██║ ██║ ██║╚██████╗██║ ██╗
23
+ ╚═╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝
24
+ `;
25
+
26
+ function HomeComponent() {
27
+ const healthCheck = trpc.healthCheck.useQuery();
28
+
29
+ return (
30
+ <div className="container mx-auto max-w-3xl px-4 py-2">
31
+ <pre className="overflow-x-auto font-mono text-sm">{TITLE_TEXT}</pre>
32
+ <div className="grid gap-6">
33
+ <section className="rounded-lg border p-4">
34
+ <h2 className="mb-2 font-medium">API Status</h2>
35
+ <div className="flex items-center gap-2">
36
+ <div
37
+ className={`h-2 w-2 rounded-full ${healthCheck.data ? "bg-green-500" : "bg-red-500"}`}
38
+ />
39
+ <span className="text-sm text-muted-foreground">
40
+ {healthCheck.isLoading
41
+ ? "Checking..."
42
+ : healthCheck.data
43
+ ? "Connected"
44
+ : "Disconnected"}
45
+ </span>
46
+ </div>
47
+ </section>
48
+
49
+ <section>
50
+ <h2 className="mb-3 font-medium">Core Features</h2>
51
+ <ul className="grid grid-cols-2 gap-3">
52
+ <FeatureItem
53
+ title="Type-Safe API"
54
+ description="End-to-end type safety with tRPC"
55
+ />
56
+ <FeatureItem
57
+ title="Modern React"
58
+ description="TanStack Router + TanStack Query"
59
+ />
60
+ <FeatureItem
61
+ title="Fast Backend"
62
+ description="Lightweight Hono server"
63
+ />
64
+ <FeatureItem
65
+ title="Beautiful UI"
66
+ description="TailwindCSS + shadcn/ui components"
67
+ />
68
+ </ul>
69
+ </section>
70
+ <div id="buttons"></div>
71
+ </div>
72
+ </div>
73
+ );
74
+ }
75
+
76
+ function FeatureItem({
77
+ title,
78
+ description,
79
+ }: {
80
+ title: string;
81
+ description: string;
82
+ }) {
83
+ return (
84
+ <li className="border-l-2 border-primary py-1 pl-3">
85
+ <h3 className="font-medium">{title}</h3>
86
+ <p className="text-sm text-muted-foreground">{description}</p>
87
+ </li>
88
+ );
89
+ }
@@ -0,0 +1,4 @@
1
+ import { createTRPCReact } from "@trpc/react-query";
2
+ import type { AppRouter } from "../../../server/src/routers";
3
+
4
+ export const trpc = createTRPCReact<AppRouter>();
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "strict": true,
4
+ "esModuleInterop": true,
5
+ "jsx": "react-jsx",
6
+ "target": "ESNext",
7
+ "module": "ESNext",
8
+ "moduleResolution": "Bundler",
9
+ "verbatimModuleSyntax": true,
10
+ "skipLibCheck": true,
11
+ "types": ["vite/client"],
12
+ "rootDirs": ["."],
13
+ "baseUrl": ".",
14
+ "paths": {
15
+ "@/*": ["./src/*"]
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,14 @@
1
+ import tailwindcss from "@tailwindcss/vite";
2
+ import { TanStackRouterVite } from "@tanstack/router-plugin/vite";
3
+ import react from "@vitejs/plugin-react";
4
+ import path from "node:path";
5
+ import { defineConfig } from "vite";
6
+
7
+ export default defineConfig({
8
+ plugins: [tailwindcss(), TanStackRouterVite({}), react()],
9
+ resolve: {
10
+ alias: {
11
+ "@": path.resolve(__dirname, "./src"),
12
+ },
13
+ },
14
+ });
@@ -0,0 +1,36 @@
1
+ # prod
2
+ dist/
3
+
4
+ # dev
5
+ .yarn/
6
+ !.yarn/releases
7
+ .vscode/*
8
+ !.vscode/launch.json
9
+ !.vscode/*.code-snippets
10
+ .idea/workspace.xml
11
+ .idea/usage.statistics.xml
12
+ .idea/shelf
13
+
14
+ # deps
15
+ node_modules/
16
+ .wrangler
17
+
18
+ # env
19
+ .env
20
+ .env.production
21
+ .dev.vars
22
+
23
+ # logs
24
+ logs/
25
+ *.log
26
+ npm-debug.log*
27
+ yarn-debug.log*
28
+ yarn-error.log*
29
+ pnpm-debug.log*
30
+ lerna-debug.log*
31
+
32
+ # misc
33
+ .DS_Store
34
+
35
+ # local db
36
+ *.db*
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "server",
3
+ "main": "src/index.ts",
4
+ "type": "module",
5
+ "scripts": {
6
+ "dev": "tsx watch src/index.ts",
7
+ "start": "node dist/src/index.js",
8
+ "build": "tsc && tsc-alias",
9
+ "dev:bun": "bun run --hot src/index.ts",
10
+ "check-types": "tsc --noEmit",
11
+ "compile": "bun build --compile --minify --sourcemap --bytecode ./src/index.ts --outfile server"
12
+ },
13
+ "dependencies": {
14
+ "@hono/node-server": "^1.14.0",
15
+ "@hono/trpc-server": "^0.3.4",
16
+ "@trpc/server": "^11.0.0",
17
+ "dotenv": "^16.4.7",
18
+ "hono": "^4.7.5",
19
+ "zod": "^3.24.2"
20
+ },
21
+ "devDependencies": {
22
+ "tsc-alias": "^1.8.11",
23
+ "tsx": "^4.19.2",
24
+ "@types/node": "^22.13.11",
25
+ "typescript": "^5.8.2"
26
+ }
27
+ }
@@ -0,0 +1,41 @@
1
+ import { serve } from "@hono/node-server";
2
+ import { trpcServer } from "@hono/trpc-server";
3
+ import "dotenv/config";
4
+ import { Hono } from "hono";
5
+ import { cors } from "hono/cors";
6
+ import { logger } from "hono/logger";
7
+ import { createContext } from "./lib/context";
8
+ import { appRouter } from "./routers/index";
9
+
10
+ const app = new Hono();
11
+
12
+ app.use(logger());
13
+
14
+ app.use(
15
+ "/*",
16
+ cors({
17
+ origin: process.env.CORS_ORIGIN || "",
18
+ allowMethods: ["GET", "POST", "OPTIONS"],
19
+ }),
20
+ );
21
+
22
+ app.use(
23
+ "/trpc/*",
24
+ trpcServer({
25
+ router: appRouter,
26
+ createContext: (_opts, hono) => {
27
+ return createContext({ hono });
28
+ },
29
+ }),
30
+ );
31
+
32
+ app.get("/", (c) => {
33
+ return c.text("OK");
34
+ });
35
+
36
+ serve({
37
+ fetch: app.fetch,
38
+ port: 3000,
39
+ }, (info) => {
40
+ console.log(`Server is running on http://localhost:${info.port}`)
41
+ });
@@ -0,0 +1,13 @@
1
+ import type { Context as HonoContext } from "hono";
2
+
3
+ export type CreateContextOptions = {
4
+ hono: HonoContext;
5
+ };
6
+
7
+ export async function createContext({ hono }: CreateContextOptions) {
8
+ return {
9
+ session: null,
10
+ };
11
+ }
12
+
13
+ export type Context = Awaited<ReturnType<typeof createContext>>;
@@ -0,0 +1,8 @@
1
+ import { initTRPC, TRPCError } from "@trpc/server";
2
+ import type { Context } from "./context";
3
+
4
+ export const t = initTRPC.context<Context>().create();
5
+
6
+ export const router = t.router;
7
+
8
+ export const publicProcedure = t.procedure;
@@ -0,0 +1,11 @@
1
+ import { router, publicProcedure } from "../lib/trpc";
2
+ import { todoRouter } from "./todo";
3
+
4
+ export const appRouter = router({
5
+ healthCheck: publicProcedure.query(() => {
6
+ return "OK";
7
+ }),
8
+ todo: todoRouter,
9
+ });
10
+
11
+ export type AppRouter = typeof appRouter;
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "verbatimModuleSyntax": true,
7
+ "strict": true,
8
+ "skipLibCheck": true,
9
+ "baseUrl": "./",
10
+ "outDir": "./dist",
11
+ "types": ["node"],
12
+ "jsx": "react-jsx",
13
+ "jsxImportSource": "hono/jsx"
14
+ },
15
+ "tsc-alias": {
16
+ "resolveFullPaths": true
17
+ }
18
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "$schema": "https://turbo.build/schema.json",
3
+ "ui": "tui",
4
+ "tasks": {
5
+ "build": {
6
+ "dependsOn": ["^build"],
7
+ "inputs": ["$TURBO_DEFAULT$", ".env*"],
8
+ "outputs": ["dist/**"]
9
+ },
10
+ "lint": {
11
+ "dependsOn": ["^lint"]
12
+ },
13
+ "check": {
14
+ "dependsOn": ["^check-types"]
15
+ },
16
+ "dev": {
17
+ "cache": false,
18
+ "persistent": true
19
+ },
20
+ "db:push": {
21
+ "cache": false
22
+ },
23
+ "db:studio": {
24
+ "cache": false
25
+ }
26
+ }
27
+ }