project setup
This commit is contained in:
26
src/env.js
Normal file
26
src/env.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import { createEnv } from "@t3-oss/env-nextjs";
|
||||
import { z } from "zod";
|
||||
|
||||
export const env = createEnv({
|
||||
server: {
|
||||
DATABASE_URL: z
|
||||
.string()
|
||||
.url()
|
||||
.refine(
|
||||
str => !str.includes("YOUR_MYSQL_URL_HERE"),
|
||||
"You forgot to change the default URL",
|
||||
),
|
||||
NODE_ENV: z
|
||||
.enum(["development", "test", "production"])
|
||||
.default("development"),
|
||||
},
|
||||
|
||||
client: {},
|
||||
|
||||
runtimeEnv: {
|
||||
DATABASE_URL: process.env.DATABASE_URL,
|
||||
NODE_ENV: process.env.NODE_ENV,
|
||||
},
|
||||
skipValidation: !!process.env.SKIP_ENV_VALIDATION,
|
||||
emptyStringAsUndefined: true,
|
||||
});
|
||||
11
src/pages/_app.tsx
Normal file
11
src/pages/_app.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import { type AppType } from "next/app";
|
||||
|
||||
import { api } from "~/utils/api";
|
||||
|
||||
import "~/styles/globals.css";
|
||||
|
||||
const MyApp: AppType = ({ Component, pageProps }) => {
|
||||
return <Component {...pageProps} />;
|
||||
};
|
||||
|
||||
export default api.withTRPC(MyApp);
|
||||
18
src/pages/api/trpc/[trpc].ts
Normal file
18
src/pages/api/trpc/[trpc].ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { createNextApiHandler } from "@trpc/server/adapters/next";
|
||||
|
||||
import { env } from "~/env";
|
||||
import { appRouter } from "~/server/api/root";
|
||||
import { createTRPCContext } from "~/server/api/trpc";
|
||||
|
||||
export default createNextApiHandler({
|
||||
router: appRouter,
|
||||
createContext: createTRPCContext,
|
||||
onError:
|
||||
env.NODE_ENV === "development"
|
||||
? ({ path, error }) => {
|
||||
console.error(
|
||||
`❌ tRPC failed on ${path ?? "<no-path>"}: ${error.message}`,
|
||||
);
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
12
src/pages/index.tsx
Normal file
12
src/pages/index.tsx
Normal file
@@ -0,0 +1,12 @@
|
||||
import Head from "next/head";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>pihkaal</title>
|
||||
</Head>
|
||||
<main></main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
5
src/server/api/root.ts
Normal file
5
src/server/api/root.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { createTRPCRouter } from "~/server/api/trpc";
|
||||
|
||||
export const appRouter = createTRPCRouter({});
|
||||
|
||||
export type AppRouter = typeof appRouter;
|
||||
48
src/server/api/trpc.ts
Normal file
48
src/server/api/trpc.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { initTRPC } from "@trpc/server";
|
||||
import { type CreateNextContextOptions } from "@trpc/server/adapters/next";
|
||||
import superjson from "superjson";
|
||||
import { ZodError } from "zod";
|
||||
|
||||
import { db } from "~/server/db";
|
||||
|
||||
/**
|
||||
* 1. CONTEXT
|
||||
*/
|
||||
|
||||
type CreateContextOptions = Record<string, never>;
|
||||
|
||||
const createInnerTRPCContext = (_opts: CreateContextOptions) => {
|
||||
return {
|
||||
db,
|
||||
};
|
||||
};
|
||||
|
||||
export const createTRPCContext = (_opts: CreateNextContextOptions) => {
|
||||
return createInnerTRPCContext({});
|
||||
};
|
||||
|
||||
/**
|
||||
* 2. INITIALIZATION
|
||||
*/
|
||||
|
||||
const t = initTRPC.context<typeof createTRPCContext>().create({
|
||||
transformer: superjson,
|
||||
errorFormatter({ shape, error }) {
|
||||
return {
|
||||
...shape,
|
||||
data: {
|
||||
...shape.data,
|
||||
zodError:
|
||||
error.cause instanceof ZodError ? error.cause.flatten() : null,
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* 3. ROUTER & PROCEDURE (THE IMPORTANT BIT)
|
||||
*/
|
||||
|
||||
export const createTRPCRouter = t.router;
|
||||
|
||||
export const publicProcedure = t.procedure;
|
||||
12
src/server/db/index.ts
Normal file
12
src/server/db/index.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Client } from "@planetscale/database";
|
||||
import { drizzle } from "drizzle-orm/planetscale-serverless";
|
||||
|
||||
import { env } from "~/env";
|
||||
import * as schema from "./schema";
|
||||
|
||||
export const db = drizzle(
|
||||
new Client({
|
||||
url: env.DATABASE_URL,
|
||||
}).connection(),
|
||||
{ schema },
|
||||
);
|
||||
3
src/server/db/schema.ts
Normal file
3
src/server/db/schema.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { mysqlTableCreator } from "drizzle-orm/mysql-core";
|
||||
|
||||
export const mysqlTable = mysqlTableCreator(name => `me_${name}`);
|
||||
3
src/styles/globals.css
Normal file
3
src/styles/globals.css
Normal file
@@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
36
src/utils/api.ts
Normal file
36
src/utils/api.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { httpBatchLink, loggerLink } from "@trpc/client";
|
||||
import { createTRPCNext } from "@trpc/next";
|
||||
import { type inferRouterInputs, type inferRouterOutputs } from "@trpc/server";
|
||||
import superjson from "superjson";
|
||||
|
||||
import { type AppRouter } from "~/server/api/root";
|
||||
|
||||
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 = createTRPCNext<AppRouter>({
|
||||
config() {
|
||||
return {
|
||||
transformer: superjson,
|
||||
|
||||
links: [
|
||||
loggerLink({
|
||||
enabled: opts =>
|
||||
process.env.NODE_ENV === "development" ||
|
||||
(opts.direction === "down" && opts.result instanceof Error),
|
||||
}),
|
||||
httpBatchLink({
|
||||
url: `${getBaseUrl()}/api/trpc`,
|
||||
}),
|
||||
],
|
||||
};
|
||||
},
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
export type RouterInputs = inferRouterInputs<AppRouter>;
|
||||
|
||||
export type RouterOutputs = inferRouterOutputs<AppRouter>;
|
||||
Reference in New Issue
Block a user