mirror of
https://github.com/FranP-code/create-better-t-stack.git
synced 2025-10-12 23:52:15 +00:00
add orpc
This commit is contained in:
72
apps/cli/templates/backend/elysia/src/index.ts.hbs
Normal file
72
apps/cli/templates/backend/elysia/src/index.ts.hbs
Normal file
@@ -0,0 +1,72 @@
|
||||
{{#if (eq runtime "node")}}
|
||||
import { node } from "@elysiajs/node";
|
||||
{{/if}}
|
||||
import "dotenv/config";
|
||||
import { Elysia } from "elysia";
|
||||
import { cors } from "@elysiajs/cors";
|
||||
{{#if (eq api "trpc")}}
|
||||
import { createContext } from "./lib/context";
|
||||
import { appRouter } from "./routers/index";
|
||||
import { fetchRequestHandler } from "@trpc/server/adapters/fetch";
|
||||
{{/if}}
|
||||
{{#if (eq api "orpc")}}
|
||||
import { RPCHandler } from "@orpc/server/fetch";
|
||||
import { appRouter } from "./routers";
|
||||
import { createContext } from "./lib/context";
|
||||
{{/if}}
|
||||
{{#if auth}}
|
||||
import { auth } from "./lib/auth";
|
||||
{{/if}}
|
||||
|
||||
{{#if (eq api "orpc")}}
|
||||
const handler = new RPCHandler(appRouter);
|
||||
{{/if}}
|
||||
|
||||
{{#if (eq runtime "node")}}
|
||||
const app = new Elysia({ adapter: node() })
|
||||
{{else}}
|
||||
const app = new Elysia()
|
||||
{{/if}}
|
||||
.use(
|
||||
cors({
|
||||
origin: process.env.CORS_ORIGIN || "",
|
||||
methods: ["GET", "POST", "OPTIONS"],
|
||||
{{#if auth}}
|
||||
allowedHeaders: ["Content-Type", "Authorization"],
|
||||
credentials: true,
|
||||
{{/if}}
|
||||
}),
|
||||
)
|
||||
{{#if auth}}
|
||||
.all("/api/auth/*", async (context) => {
|
||||
const { request } = context;
|
||||
if (["POST", "GET"].includes(request.method)) {
|
||||
return auth.handler(request);
|
||||
}
|
||||
context.error(405);
|
||||
})
|
||||
{{/if}}
|
||||
{{#if (eq api "orpc")}}
|
||||
.all('/rpc*', async (context) => {
|
||||
const { response } = await handler.handle(context.request, {
|
||||
prefix: '/rpc',
|
||||
context: await createContext({ context })
|
||||
})
|
||||
return response ?? new Response('Not Found', { status: 404 })
|
||||
})
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
.all("/trpc/*", async (context) => {
|
||||
const res = await fetchRequestHandler({
|
||||
endpoint: "/trpc",
|
||||
router: appRouter,
|
||||
req: context.request,
|
||||
createContext: () => createContext({ context }),
|
||||
});
|
||||
return res;
|
||||
})
|
||||
{{/if}}
|
||||
.get("/", () => "OK")
|
||||
.listen(3000, () => {
|
||||
console.log(`Server is running on http://localhost:3000`);
|
||||
});
|
||||
78
apps/cli/templates/backend/express/src/index.ts.hbs
Normal file
78
apps/cli/templates/backend/express/src/index.ts.hbs
Normal file
@@ -0,0 +1,78 @@
|
||||
import "dotenv/config";
|
||||
{{#if (eq api "trpc")}}
|
||||
import { createExpressMiddleware } from "@trpc/server/adapters/express";
|
||||
import { createContext } from "./lib/context";
|
||||
import { appRouter } from "./routers/index";
|
||||
{{/if}}
|
||||
{{#if (eq api "orpc")}}
|
||||
import { RPCHandler } from "@orpc/server/node";
|
||||
import { appRouter } from "./routers";
|
||||
{{/if}}
|
||||
import cors from "cors";
|
||||
import express from "express";
|
||||
{{#if (includes examples "ai")}}
|
||||
import { streamText } from "ai";
|
||||
import { google } from "@ai-sdk/google";
|
||||
{{/if}}
|
||||
{{#if auth}}
|
||||
import { auth } from "./lib/auth";
|
||||
{{/if}}
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(
|
||||
cors({
|
||||
origin: process.env.CORS_ORIGIN || "",
|
||||
methods: ["GET", "POST", "OPTIONS"],
|
||||
{{#if auth}}
|
||||
allowedHeaders: ["Content-Type", "Authorization"],
|
||||
credentials: true,
|
||||
{{/if}}
|
||||
})
|
||||
);
|
||||
|
||||
{{#if auth}}
|
||||
app.all("/api/auth{/*path}", toNodeHandler(auth));
|
||||
{{/if}}
|
||||
|
||||
{{#if (eq api "trpc")}}
|
||||
app.use(
|
||||
"/trpc",
|
||||
createExpressMiddleware({
|
||||
router: appRouter,
|
||||
createContext
|
||||
})
|
||||
);
|
||||
{{/if}}
|
||||
|
||||
{{#if (eq api "orpc")}}
|
||||
const handler = new RPCHandler(appRouter);
|
||||
app.use('/rpc{*path}', async (req, res, next) => {
|
||||
const { matched } = await handler.handle(req, res, {
|
||||
prefix: '/rpc',
|
||||
context: {},
|
||||
});
|
||||
if (matched) return;
|
||||
next();
|
||||
});
|
||||
{{/if}}
|
||||
|
||||
{{#if (includes examples "ai")}}
|
||||
// AI chat endpoint
|
||||
app.post("/ai", async (req, res) => {
|
||||
const { messages = [] } = req.body;
|
||||
const result = streamText({
|
||||
model: google("gemini-1.5-flash"),
|
||||
messages,
|
||||
});
|
||||
result.pipeDataStreamToResponse(res);
|
||||
});
|
||||
{{/if}}
|
||||
|
||||
app.get("/", (_req, res) => {
|
||||
res.status(200).send("OK");
|
||||
});
|
||||
|
||||
app.listen(3000, () => {
|
||||
console.log("Server is running on port 3000");
|
||||
});
|
||||
105
apps/cli/templates/backend/hono/src/index.ts.hbs
Normal file
105
apps/cli/templates/backend/hono/src/index.ts.hbs
Normal file
@@ -0,0 +1,105 @@
|
||||
{{#if (eq api "orpc")}}
|
||||
import { RPCHandler } from "@orpc/server/fetch";
|
||||
import { createContext } from "./lib/context";
|
||||
import { appRouter } from "./routers/index";
|
||||
{{#if auth}}
|
||||
import { auth } from "./lib/auth";
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
import { trpcServer } from "@hono/trpc-server";
|
||||
{{/if}}
|
||||
import "dotenv/config";
|
||||
import { Hono } from "hono";
|
||||
import { cors } from "hono/cors";
|
||||
import { logger } from "hono/logger";
|
||||
{{#if (includes examples "ai")}}
|
||||
import { streamText } from "ai";
|
||||
import { google } from "@ai-sdk/google";
|
||||
import { stream } from "hono/streaming";
|
||||
{{/if}}
|
||||
{{#if (eq api "trpc")}}
|
||||
import { createContext } from "./lib/context";
|
||||
import { appRouter } from "./routers/index";
|
||||
{{#if auth}}
|
||||
import { auth } from "./lib/auth";
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
|
||||
const app = new Hono();
|
||||
|
||||
app.use(logger());
|
||||
app.use(
|
||||
"/*",
|
||||
cors({
|
||||
origin: process.env.CORS_ORIGIN || "",
|
||||
allowMethods: ["GET", "POST", "OPTIONS"],
|
||||
{{#if auth}}
|
||||
allowHeaders: ["Content-Type", "Authorization"],
|
||||
credentials: true,
|
||||
{{/if}}
|
||||
})
|
||||
);
|
||||
|
||||
{{#if auth}}
|
||||
app.on(["POST", "GET"], "/api/auth/**", (c) => auth.handler(c.req.raw));
|
||||
{{/if}}
|
||||
|
||||
{{#if (eq api "orpc")}}
|
||||
const handler = new RPCHandler(appRouter);
|
||||
app.use("/rpc/*", async (c, next) => {
|
||||
const context = await createContext({ context: c });
|
||||
const { matched, response } = await handler.handle(c.req.raw, {
|
||||
prefix: "/rpc",
|
||||
context: context,
|
||||
});
|
||||
if (matched) {
|
||||
return c.newResponse(response.body, response);
|
||||
}
|
||||
await next();
|
||||
});
|
||||
{{/if}}
|
||||
|
||||
{{#if (eq api "trpc")}}
|
||||
app.use("/trpc/*", trpcServer({
|
||||
router: appRouter,
|
||||
createContext: (_opts, context) => {
|
||||
return createContext({ context });
|
||||
},
|
||||
}));
|
||||
{{/if}}
|
||||
|
||||
{{#if (includes examples "ai")}}
|
||||
// AI chat endpoint
|
||||
app.post("/ai", async (c) => {
|
||||
const body = await c.req.json();
|
||||
const messages = body.messages || [];
|
||||
|
||||
const result = streamText({
|
||||
model: google("gemini-1.5-flash"),
|
||||
messages,
|
||||
});
|
||||
|
||||
c.header("X-Vercel-AI-Data-Stream", "v1");
|
||||
c.header("Content-Type", "text/plain; charset=utf-8");
|
||||
|
||||
return stream(c, (stream) => stream.pipe(result.toDataStream()));
|
||||
});
|
||||
{{/if}}
|
||||
|
||||
app.get("/", (c) => {
|
||||
return c.text("OK");
|
||||
});
|
||||
|
||||
{{#if (eq runtime "node")}}
|
||||
import { serve } from "@hono/node-server";
|
||||
|
||||
serve({
|
||||
fetch: app.fetch,
|
||||
port: 3000,
|
||||
}, (info) => {
|
||||
console.log(`Server is running on http://localhost:${info.port}`);
|
||||
});
|
||||
{{else}}
|
||||
export default app;
|
||||
{{/if}}
|
||||
5
apps/cli/templates/backend/next/next-env.d.ts
vendored
Normal file
5
apps/cli/templates/backend/next/next-env.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||
7
apps/cli/templates/backend/next/next.config.ts
Normal file
7
apps/cli/templates/backend/next/next.config.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
/* config options here */
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
18
apps/cli/templates/backend/next/package.json
Normal file
18
apps/cli/templates/backend/next/package.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "server",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev --turbopack",
|
||||
"build": "next build",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "15.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^19",
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
||||
5
apps/cli/templates/backend/next/src/app/route.ts
Normal file
5
apps/cli/templates/backend/next/src/app/route.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET() {
|
||||
return NextResponse.json({ message: "OK" });
|
||||
}
|
||||
19
apps/cli/templates/backend/next/src/middleware.ts
Normal file
19
apps/cli/templates/backend/next/src/middleware.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export function middleware() {
|
||||
const res = NextResponse.next()
|
||||
|
||||
res.headers.append('Access-Control-Allow-Credentials', "true")
|
||||
res.headers.append('Access-Control-Allow-Origin', process.env.CORS_ORIGIN || "")
|
||||
res.headers.append('Access-Control-Allow-Methods', 'GET,POST,OPTIONS')
|
||||
res.headers.append(
|
||||
'Access-Control-Allow-Headers',
|
||||
'Content-Type, Authorization'
|
||||
)
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
export const config = {
|
||||
matcher: '/:path*',
|
||||
}
|
||||
27
apps/cli/templates/backend/next/tsconfig.json
Normal file
27
apps/cli/templates/backend/next/tsconfig.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2017",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
51
apps/cli/templates/backend/server-base/_gitignore
Normal file
51
apps/cli/templates/backend/server-base/_gitignore
Normal file
@@ -0,0 +1,51 @@
|
||||
# prod
|
||||
dist/
|
||||
/build
|
||||
/out/
|
||||
|
||||
# dev
|
||||
.yarn/
|
||||
!.yarn/patches
|
||||
!.yarn/plugins
|
||||
!.yarn/releases
|
||||
!.yarn/versions
|
||||
.vscode/*
|
||||
!.vscode/launch.json
|
||||
!.vscode/*.code-snippets
|
||||
.idea/workspace.xml
|
||||
.idea/usage.statistics.xml
|
||||
.idea/shelf
|
||||
.wrangler
|
||||
/.next/
|
||||
.vercel
|
||||
|
||||
# deps
|
||||
node_modules/
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.*
|
||||
|
||||
# env
|
||||
.env*
|
||||
.env.production
|
||||
.dev.vars
|
||||
|
||||
# logs
|
||||
logs/
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# local db
|
||||
*.db*
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
18
apps/cli/templates/backend/server-base/package.json
Normal file
18
apps/cli/templates/backend/server-base/package.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "server",
|
||||
"main": "src/index.ts",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "tsc && tsc-alias",
|
||||
"check-types": "tsc --noEmit",
|
||||
"compile": "bun build --compile --minify --sourcemap --bytecode ./src/index.ts --outfile server"
|
||||
},
|
||||
"dependencies": {
|
||||
"dotenv": "^16.4.7",
|
||||
"zod": "^3.24.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"tsc-alias": "^1.8.11",
|
||||
"typescript": "^5.8.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
{{#if (eq api "orpc")}}
|
||||
import { {{#if auth}}protectedProcedure, {{/if}}publicProcedure } from "../lib/orpc";
|
||||
{{#if (includes examples "todo")}}
|
||||
import { todoRouter } from "./todo";
|
||||
{{/if}}
|
||||
|
||||
export const appRouter = {
|
||||
healthCheck: publicProcedure.handler(() => {
|
||||
return "OK";
|
||||
}),
|
||||
{{#if auth}}
|
||||
privateData: protectedProcedure.handler(({ context }) => {
|
||||
return {
|
||||
message: "This is private",
|
||||
user: context.session!.user,
|
||||
};
|
||||
}),
|
||||
{{/if}}
|
||||
{{#if (includes examples "todo")}}
|
||||
todo: todoRouter,
|
||||
{{/if}}
|
||||
};
|
||||
{{/if}}
|
||||
|
||||
{{#if (eq api "trpc")}}
|
||||
import {
|
||||
{{#if auth}}protectedProcedure, {{/if}}publicProcedure,
|
||||
router,
|
||||
} from "../lib/trpc";
|
||||
{{#if (includes examples "todo")}}
|
||||
import { todoRouter } from "./todo";
|
||||
{{/if}}
|
||||
|
||||
export const appRouter = router({
|
||||
healthCheck: publicProcedure.query(() => {
|
||||
return "OK";
|
||||
}),
|
||||
{{#if auth}}
|
||||
privateData: protectedProcedure.query(({ ctx }) => {
|
||||
return {
|
||||
message: "This is private",
|
||||
user: ctx.session.user,
|
||||
};
|
||||
}),
|
||||
{{/if}}
|
||||
{{#if (includes examples "todo")}}
|
||||
todo: todoRouter,
|
||||
{{/if}}
|
||||
});
|
||||
{{/if}}
|
||||
export type AppRouter = typeof appRouter;
|
||||
18
apps/cli/templates/backend/server-base/tsconfig.json
Normal file
18
apps/cli/templates/backend/server-base/tsconfig.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"verbatimModuleSyntax": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"baseUrl": "./",
|
||||
"outDir": "./dist",
|
||||
"types": ["node", "bun"],
|
||||
"jsx": "react-jsx",
|
||||
"jsxImportSource": "hono/jsx"
|
||||
},
|
||||
"tsc-alias": {
|
||||
"resolveFullPaths": true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user