Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

trpc #69

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open

trpc #69

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/worxpace/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"dependencies": {
"@acme/i18n": "workspace:*",
"@acme/prisma": "workspace:*",
"@acme/trpc": "workspace:*",
"@acme/ui": "workspace:*",
"@acme/validators": "workspace:*",
"@blocknote/core": "^0.15.0",
Expand All @@ -30,6 +31,7 @@
"@liveblocks/react": "^1.12.0",
"@liveblocks/yjs": "^1.12.0",
"@t3-oss/env-nextjs": "^0.10.1",
"@trpc/server": "next",
"lucide-react": "^0.408.0",
"next": "^14.2.3",
"react": "18.3.1",
Expand Down
52 changes: 52 additions & 0 deletions apps/worxpace/src/app/api/trpc/[trpc]/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { appRouter, createTRPCContext } from "@acme/trpc";
import * as trpcNext from '@trpc/server/adapters/next'

export const runtime = "edge";

/**
* Configure basic CORS headers
* You should extend this to match your needs
*/
const setCorsHeaders = (res: Response) => {
res.headers.set("Access-Control-Allow-Origin", "*");
res.headers.set("Access-Control-Request-Method", "*");
res.headers.set("Access-Control-Allow-Methods", "OPTIONS, GET, POST");
res.headers.set("Access-Control-Allow-Headers", "*");
};

export const OPTIONS = () => {
const response = new Response(null, {
status: 204,
});
setCorsHeaders(response);
return response;
};

const handler = trpcNext.createNextApiHandler( {
router: appRouter,
createContext: createTRPCContext,
onError({ error, path }) {
console.error(`>>> tRPC Error on '${path}'`, error);
},
})

// const handler = auth(async (req) => {
// const response = await fetchRequestHandler({
// endpoint: "/api/trpc",
// router: appRouter,
// req,
// createContext: () =>
// createTRPCContext({
// session: req.auth,
// headers: req.headers,
// }),
// onError({ error, path }) {
// console.error(`>>> tRPC Error on '${path}'`, error);
// },
// });

// setCorsHeaders(response);
// return response;
// });

export { handler as GET, handler as POST };
2 changes: 1 addition & 1 deletion apps/worxpace/src/hooks/use-documents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
const fetcher = async ({ workspaceId }: DocumentsKey) => {
try {
return await fetchUrl<DetailedDocument[]>(
`/api/documents?workspaceId=${workspaceId}`,
`/api/trpc/documents?workspaceId=${workspaceId}`,
);
} catch (error) {
console.log(error);
Expand Down
41 changes: 41 additions & 0 deletions packages/trpc/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"name": "@acme/trpc",
"version": "1.0.3",
"private": true,
"type": "module",
"exports": {
".": "./src/index.ts"
},
"license": "MIT",
"scripts": {
"clean": "rm -rf .turbo node_modules",
"format": "prettier --check . --ignore-path ../../.gitignore",
"lint": "eslint .",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@acme/prisma": "workspace:*",
"@acme/validators": "workspace:*",
"@clerk/nextjs": "^5.2.12",
"@t3-oss/env-nextjs": "^0.10.1",
"@trpc/client": "next",
"@trpc/server": "next",
"superjson": "2.2.1",
"zod": "^3.23.7"
},
"devDependencies": {
"@acme/eslint-config": "workspace:*",
"@acme/prettier-config": "workspace:*",
"@acme/tsconfig": "workspace:*",
"eslint": "^8.56.0",
"prettier": "^3.2.5",
"typescript": "^5.5.4"
},
"eslintConfig": {
"root": true,
"extends": [
"@acme/eslint-config/base"
]
},
"prettier": "@acme/prettier-config"
}
33 changes: 33 additions & 0 deletions packages/trpc/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import type { inferRouterInputs, inferRouterOutputs } from "@trpc/server";

import type { AppRouter } from "./root";
import { appRouter } from "./root";
import { createCallerFactory, createTRPCContext } from "./trpc";

/**
* Create a server-side caller for the tRPC API
* @example
* const trpc = createCaller(createContext);
* const res = await trpc.post.all();
* ^? Post[]
*/
const createCaller = createCallerFactory(appRouter);

/**
* Inference helpers for input types
* @example
* type PostByIdInput = RouterInputs['post']['byId']
* ^? { id: number }
**/
type RouterInputs = inferRouterInputs<AppRouter>;

/**
* Inference helpers for output types
* @example
* type AllPostsOutput = RouterOutputs['post']['all']
* ^? Post[]
**/
type RouterOutputs = inferRouterOutputs<AppRouter>;

export { createTRPCContext, appRouter, createCaller };
export type { AppRouter, RouterInputs, RouterOutputs };
11 changes: 11 additions & 0 deletions packages/trpc/src/root.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { authRouter } from "./router/auth";
import { documentRouter } from "./router/document";
import { createTRPCRouter } from "./trpc";

export const appRouter = createTRPCRouter({
auth: authRouter,
document: documentRouter,
});

// export type definition of API
export type AppRouter = typeof appRouter;
16 changes: 16 additions & 0 deletions packages/trpc/src/router/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {currentUser} from "@clerk/nextjs/server"

import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc";

export const authRouter = createTRPCRouter({
getAuth: publicProcedure.query(({ ctx }) => {
return ctx.auth;
}),
getUser: publicProcedure.query(() => {
return currentUser()
}),
getSecretMessage: protectedProcedure.query(() => {
// testing type validation of overridden next-auth Session in @acme/auth package
return "you can see this secret message!";
}),
});
24 changes: 24 additions & 0 deletions packages/trpc/src/router/document.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { z } from "zod";


import { createTRPCRouter, protectedProcedure } from "../trpc";

const include = { workspace: true, createdBy: true, updatedBy: true }

export const documentRouter = createTRPCRouter({
all: protectedProcedure
.input(z.object({ workspaceId: z.string(), isArchived: z.boolean().optional() }))
.query(({ ctx, input }) => {
return ctx.db.document.findMany({
where: input,
orderBy: { createdAt: "desc" },
include,
})
}),

byId: protectedProcedure
.input(z.string())
.query(({ ctx, input }) => {
return ctx.db.document.findUnique({ where: { id: input }, include });
}),
});
104 changes: 104 additions & 0 deletions packages/trpc/src/trpc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/**
* YOU PROBABLY DON'T NEED TO EDIT THIS FILE, UNLESS:
* 1. You want to modify request context (see Part 1)
* 2. You want to create a new middleware or type of procedure (see Part 3)
*
* tl;dr - this is where all the tRPC server stuff is created and plugged in.
* The pieces you will need to use are documented accordingly near the end
*/
import { initTRPC, TRPCError } from "@trpc/server";
import superjson from "superjson";
import { ZodError } from "zod";

import { getAuth } from "@clerk/nextjs/server";
import {worxpace} from "@acme/prisma"
// import { NextApiRequest } from "@trpc/server/adapters/next";
import * as trpcNext from '@trpc/server/adapters/next'

/**
* 1. CONTEXT
*
* This section defines the "contexts" that are available in the backend API.
*
* These allow you to access things when processing a request, like the database, the session, etc.
*
* This helper generates the "internals" for a tRPC context. The API handler and RSC clients each
* wrap this and provides the required context.
*
* @see https://trpc.io/docs/server/context
*/
export const createTRPCContext = async (opts: trpcNext.CreateNextContextOptions) => {

Check failure on line 30 in packages/trpc/src/trpc.ts

View workflow job for this annotation

GitHub Actions / lint

Async arrow function 'createTRPCContext' has no 'await' expression
const auth = getAuth(opts.req)
// const source = opts.headers.get("x-trpc-source") ?? "unknown";
// console.log(">>> tRPC Request from", source, "by", auth?.userId);

return {
auth,
db: worxpace,
};
};

/**
* 2. INITIALIZATION
*
* This is where the trpc api is initialized, connecting the context and
* transformer
*/
const t = initTRPC.context<typeof createTRPCContext>().create({
transformer: superjson,
errorFormatter: ({ shape, error }) => ({
...shape,
data: {
...shape.data,
zodError: error.cause instanceof ZodError ? error.cause.flatten() : null,
},
}),
});

/**
* Create a server-side caller
* @see https://trpc.io/docs/server/server-side-calls
*/
export const createCallerFactory = t.createCallerFactory;

/**
* 3. ROUTER & PROCEDURE (THE IMPORTANT BIT)
*
* These are the pieces you use to build your tRPC API. You should import these
* a lot in the /src/server/api/routers folder
*/

/**
* This is how you create new routers and subrouters in your tRPC API
* @see https://trpc.io/docs/router
*/
export const createTRPCRouter = t.router;

/**
* Public (unauthed) procedure
*
* This is the base piece you use to build new queries and mutations on your
* tRPC API. It does not guarantee that a user querying is authorized, but you
* can still access user session data if they are logged in
*/
export const publicProcedure = t.procedure;

/**
* Protected (authenticated) procedure
*
* If you want a query or mutation to ONLY be accessible to logged in users, use this. It verifies
* the `AuthObject` is valid and guarantees `ctx.auth.userId` is not null.
*
* @see https://trpc.io/docs/procedures
*/
export const protectedProcedure = t.procedure.use(({ ctx, next }) => {
if (!ctx.auth.userId) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next({
ctx: {
// infers the `auth` as non-nullable
auth: ctx.auth,
},
});
});
8 changes: 8 additions & 0 deletions packages/trpc/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": "@acme/tsconfig/base.json",
"compilerOptions": {
"tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json"
},
"include": ["src"],
"exclude": ["node_modules"]
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,44 @@ export const CheckIcon = (props: IconProps) => {
</svg>
);
};

export const Help = () => {
return (
<svg
role="graphics-symbol"
viewBox="0 0 20 20"
key="questionMarkCircled"
className="block size-5 flex-shrink-0 flex-grow-0 overflow-visible fill-[rgb(199,198,196)]"
>
<path d="M10 17.13a7.12 7.12 0 0 1-7.06-7.06c0-.97.18-1.88.55-2.73A7.2 7.2 0 0 1 9.99 3c.97 0 1.88.19 2.73.56a7.22 7.22 0 0 1 4.34 6.5c0 .97-.18 1.88-.55 2.73a7.22 7.22 0 0 1-3.79 3.78c-.85.37-1.76.56-2.73.56Zm0-1.4a5.57 5.57 0 0 0 4-1.65 5.68 5.68 0 1 0-4 1.65Zm-.16-4.3c-.43 0-.65-.2-.65-.59v-.07c0-.32.08-.57.24-.77.16-.2.36-.38.6-.54.3-.2.51-.38.65-.52a.71.71 0 0 0 .22-.53.7.7 0 0 0-.26-.57.97.97 0 0 0-.67-.22 1.06 1.06 0 0 0-.7.26c-.1.09-.18.19-.26.31l-.11.14a.71.71 0 0 1-.23.21.62.62 0 0 1-.32.08.55.55 0 0 1-.37-.15.5.5 0 0 1-.17-.39c0-.06 0-.12.02-.18l.05-.17c.1-.32.35-.6.73-.83.38-.23.86-.35 1.45-.35.4 0 .77.07 1.1.21a2 2 0 0 1 .83.61c.2.27.3.59.3.96 0 .4-.1.72-.3.96a4 4 0 0 1-.8.68c-.23.14-.4.28-.52.42a.73.73 0 0 0-.2.46v.08c0 .14-.07.26-.18.35-.11.1-.26.14-.45.14Zm-.01 2.1a.83.83 0 0 1-.57-.22.71.71 0 0 1-.23-.54.7.7 0 0 1 .23-.53.8.8 0 0 1 .57-.22c.22 0 .41.07.57.21a.7.7 0 0 1 .23.54.7.7 0 0 1-.23.54.81.81 0 0 1-.57.21Z"></path>
</svg>
);
};
export const Star = () => {
return (
<svg
role="graphics-symbol"
viewBox="0 0 16 16"
key="sparkles"
className="block h-full w-4 flex-shrink-0 fill-inherit text-[rgb(144,101,176)]"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M7.2757 4.82358C7.57934 4.71847 7.57934 4.53161 7.2757 4.41483L5.62905 3.78419C5.33709 3.67908 4.99842 3.3404 4.88164 3.03676L4.25101 1.39009C4.1459 1.08644 3.95905 1.08644 3.84226 1.39009L3.21163 3.03676C3.10653 3.32872 2.76786 3.6674 2.46422 3.78419L0.817572 4.41483C0.513934 4.51994 0.513934 4.70679 0.817572 4.82358L2.46422 5.45422C2.75618 5.55933 3.09485 5.898 3.21163 6.20165L3.84226 7.84832C3.94737 8.15196 4.13422 8.15196 4.25101 7.84832L4.88164 6.20165C4.98674 5.90968 5.32541 5.571 5.62905 5.45422L7.2757 4.82358ZM15.2991 10.5929C16.2334 10.3593 16.2334 9.9739 15.2991 9.74032L13.2321 9.22647C12.2978 8.9929 11.3402 8.03526 11.1066 7.10097L10.5928 5.03387C10.3592 4.09959 9.97382 4.09959 9.74025 5.03387L9.2264 7.10097C8.99283 8.03526 8.03521 8.9929 7.10094 9.22647L5.03387 9.74032C4.09961 9.9739 4.09961 10.3593 5.03387 10.5929L7.10094 11.1067C8.03521 11.3403 8.99283 12.2979 9.2264 13.2322L9.74025 15.2993C9.97382 16.2336 10.3592 16.2336 10.5928 15.2993L11.1066 13.2322C11.3402 12.2979 12.2978 11.3403 13.2321 11.1067L15.2991 10.5929Z"
></path>
</svg>
);
};
export const ArrowDown = () => {
return (
<svg
role="graphics-symbol"
viewBox="0 0 16 16"
key="arrowDown"
className="block h-full w-[13px] flex-shrink-0 fill-inherit text-[rgb(145,145,142)]"
>
<path d="M8 1.57715C7.5625 1.57715 7.25488 1.88477 7.25488 2.33594V10.8262L7.30957 12.3027L5.50488 10.2861L3.95312 8.75488C3.82324 8.625 3.63184 8.53613 3.42676 8.53613C3.0166 8.53613 2.70898 8.85059 2.70898 9.26758C2.70898 9.46582 2.78418 9.64355 2.94141 9.80762L7.44629 14.3193C7.59668 14.4697 7.79492 14.5586 8 14.5586C8.20508 14.5586 8.40332 14.4697 8.55371 14.3193L13.0586 9.80762C13.2158 9.64355 13.291 9.46582 13.291 9.26758C13.291 8.85059 12.9902 8.53613 12.5801 8.53613C12.3682 8.53613 12.1836 8.625 12.0469 8.75488L10.4951 10.2861L8.69043 12.2959L8.74512 10.8262V2.33594C8.74512 1.88477 8.44434 1.57715 8 1.57715Z"></path>
</svg>
);
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { ConnectionCard, type ConnectionCardProps } from "./connection-card";
export { HintButton, NotImplemented, PlanLink } from "./helper";
export { Section, SectionItem, SectionSeparator } from "./section";
export { PasswordIcon, CheckIcon } from "./icons";
export * from "./icons";
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ export { Identity } from "./identity";
/** @todo Connections */
/** @todo Import */
/** @todo Billing */
/** @todo Plans */
export { Plans } from "./plans";
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export const plans = {
free: {
title: "Free",
description: "For organizing every corner of your work and life",
comment: "$0 per member / month",
},
education: {
title: "Education Plus",
description: "For students & educators",
comment: "$0 per member / month",
},
plus: {
title: "Plus",
description: "A place for small groups to plan & get organized",
comment: "$0 per member / month",
},
} as const;
Loading
Loading