create-better-t-stack 2.40.3-canary.50a1b944 → 2.40.4
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.
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/dist/{src-D59j3XG5.js → src-BTNbBm4L.js} +28 -21
- package/package.json +1 -1
- package/templates/api/orpc/server/next/src/app/rpc/[...all]/route.ts.hbs +32 -3
- package/templates/backend/server/elysia/src/index.ts.hbs +31 -2
- package/templates/backend/server/express/src/index.ts.hbs +38 -4
- package/templates/backend/server/fastify/src/index.ts.hbs +33 -2
- package/templates/backend/server/hono/src/index.ts.hbs +40 -5
package/dist/cli.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -110,6 +110,8 @@ const dependencyVersionMap = {
|
|
|
110
110
|
streamdown: "^1.1.6",
|
|
111
111
|
"@orpc/server": "^1.8.6",
|
|
112
112
|
"@orpc/client": "^1.8.6",
|
|
113
|
+
"@orpc/openapi": "^1.8.6",
|
|
114
|
+
"@orpc/zod": "^1.8.6",
|
|
113
115
|
"@orpc/tanstack-query": "^1.8.6",
|
|
114
116
|
"@trpc/tanstack-react-query": "^11.5.0",
|
|
115
117
|
"@trpc/server": "^11.5.0",
|
|
@@ -496,6 +498,8 @@ function ensureSingleWebAndNative(frontends) {
|
|
|
496
498
|
function validateWorkersCompatibility(providedFlags, options, config) {
|
|
497
499
|
if (providedFlags.has("runtime") && options.runtime === "workers" && config.backend && config.backend !== "hono") exitWithError(`Cloudflare Workers runtime (--runtime workers) is only supported with Hono backend (--backend hono). Current backend: ${config.backend}. Please use '--backend hono' or choose a different runtime.`);
|
|
498
500
|
if (providedFlags.has("backend") && config.backend && config.backend !== "hono" && config.runtime === "workers") exitWithError(`Backend '${config.backend}' is not compatible with Cloudflare Workers runtime. Cloudflare Workers runtime is only supported with Hono backend. Please use '--backend hono' or choose a different runtime.`);
|
|
501
|
+
if (providedFlags.has("runtime") && options.runtime === "workers" && config.orm && config.orm !== "drizzle" && config.orm !== "none") exitWithError(`Cloudflare Workers runtime (--runtime workers) is only supported with Drizzle ORM (--orm drizzle) or no ORM (--orm none). Current ORM: ${config.orm}. Please use '--orm drizzle', '--orm none', or choose a different runtime.`);
|
|
502
|
+
if (providedFlags.has("orm") && config.orm && config.orm !== "drizzle" && config.orm !== "none" && config.runtime === "workers") exitWithError(`ORM '${config.orm}' is not compatible with Cloudflare Workers runtime. Cloudflare Workers runtime is only supported with Drizzle ORM or no ORM. Please use '--orm drizzle', '--orm none', or choose a different runtime.`);
|
|
499
503
|
if (providedFlags.has("runtime") && options.runtime === "workers" && config.database === "mongodb") exitWithError("Cloudflare Workers runtime (--runtime workers) is not compatible with MongoDB database. MongoDB requires Prisma or Mongoose ORM, but Workers runtime only supports Drizzle ORM. Please use a different database or runtime.");
|
|
500
504
|
if (providedFlags.has("runtime") && options.runtime === "workers" && config.dbSetup === "docker") exitWithError("Cloudflare Workers runtime (--runtime workers) is not compatible with Docker setup. Workers runtime uses serverless databases (D1) and doesn't support local Docker containers. Please use '--db-setup d1' for SQLite or choose a different runtime.");
|
|
501
505
|
if (providedFlags.has("database") && config.database === "mongodb" && config.runtime === "workers") exitWithError("MongoDB database is not compatible with Cloudflare Workers runtime. MongoDB requires Prisma or Mongoose ORM, but Workers runtime only supports Drizzle ORM. Please use a different database or runtime.");
|
|
@@ -993,11 +997,12 @@ async function getORMChoice(orm, hasDatabase, database, backend, runtime) {
|
|
|
993
997
|
if (backend === "convex") return "none";
|
|
994
998
|
if (!hasDatabase) return "none";
|
|
995
999
|
if (orm !== void 0) return orm;
|
|
1000
|
+
if (runtime === "workers") return "drizzle";
|
|
996
1001
|
const options = [...database === "mongodb" ? [ormOptions.prisma, ormOptions.mongoose] : [ormOptions.drizzle, ormOptions.prisma]];
|
|
997
1002
|
const response = await select({
|
|
998
1003
|
message: "Select ORM",
|
|
999
1004
|
options,
|
|
1000
|
-
initialValue: database === "mongodb" ? "prisma" :
|
|
1005
|
+
initialValue: database === "mongodb" ? "prisma" : DEFAULT_CONFIG.orm
|
|
1001
1006
|
});
|
|
1002
1007
|
if (isCancel(response)) return exitCancelled("Operation cancelled");
|
|
1003
1008
|
return response;
|
|
@@ -1330,7 +1335,7 @@ const getLatestCLIVersion = () => {
|
|
|
1330
1335
|
*/
|
|
1331
1336
|
function isTelemetryEnabled() {
|
|
1332
1337
|
const BTS_TELEMETRY_DISABLED = process.env.BTS_TELEMETRY_DISABLED;
|
|
1333
|
-
const BTS_TELEMETRY = "
|
|
1338
|
+
const BTS_TELEMETRY = "1";
|
|
1334
1339
|
if (BTS_TELEMETRY_DISABLED !== void 0) return BTS_TELEMETRY_DISABLED !== "1";
|
|
1335
1340
|
if (BTS_TELEMETRY !== void 0) return BTS_TELEMETRY === "1";
|
|
1336
1341
|
return true;
|
|
@@ -1338,8 +1343,8 @@ function isTelemetryEnabled() {
|
|
|
1338
1343
|
|
|
1339
1344
|
//#endregion
|
|
1340
1345
|
//#region src/utils/analytics.ts
|
|
1341
|
-
const POSTHOG_API_KEY = "
|
|
1342
|
-
const POSTHOG_HOST = "
|
|
1346
|
+
const POSTHOG_API_KEY = "phc_8ZUxEwwfKMajJLvxz1daGd931dYbQrwKNficBmsdIrs";
|
|
1347
|
+
const POSTHOG_HOST = "https://us.i.posthog.com";
|
|
1343
1348
|
function generateSessionId() {
|
|
1344
1349
|
const rand = Math.random().toString(36).slice(2);
|
|
1345
1350
|
const now = Date.now().toString(36);
|
|
@@ -3093,8 +3098,7 @@ async function setupNextAlchemyDeploy(projectDir, _packageManager, options) {
|
|
|
3093
3098
|
if (!options?.skipAppScripts) pkg.scripts = {
|
|
3094
3099
|
...pkg.scripts,
|
|
3095
3100
|
deploy: "alchemy deploy",
|
|
3096
|
-
destroy: "alchemy destroy"
|
|
3097
|
-
dev: "alchemy dev"
|
|
3101
|
+
destroy: "alchemy destroy"
|
|
3098
3102
|
};
|
|
3099
3103
|
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3100
3104
|
}
|
|
@@ -3119,8 +3123,7 @@ async function setupNuxtAlchemyDeploy(projectDir, _packageManager, options) {
|
|
|
3119
3123
|
if (!options?.skipAppScripts) pkg.scripts = {
|
|
3120
3124
|
...pkg.scripts,
|
|
3121
3125
|
deploy: "alchemy deploy",
|
|
3122
|
-
destroy: "alchemy destroy"
|
|
3123
|
-
dev: "alchemy dev"
|
|
3126
|
+
destroy: "alchemy destroy"
|
|
3124
3127
|
};
|
|
3125
3128
|
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3126
3129
|
}
|
|
@@ -3183,8 +3186,7 @@ async function setupReactRouterAlchemyDeploy(projectDir, _packageManager, option
|
|
|
3183
3186
|
if (!options?.skipAppScripts) pkg.scripts = {
|
|
3184
3187
|
...pkg.scripts,
|
|
3185
3188
|
deploy: "alchemy deploy",
|
|
3186
|
-
destroy: "alchemy destroy"
|
|
3187
|
-
dev: "alchemy dev"
|
|
3189
|
+
destroy: "alchemy destroy"
|
|
3188
3190
|
};
|
|
3189
3191
|
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3190
3192
|
}
|
|
@@ -3205,8 +3207,7 @@ async function setupSolidAlchemyDeploy(projectDir, _packageManager, options) {
|
|
|
3205
3207
|
if (!options?.skipAppScripts) pkg.scripts = {
|
|
3206
3208
|
...pkg.scripts,
|
|
3207
3209
|
deploy: "alchemy deploy",
|
|
3208
|
-
destroy: "alchemy destroy"
|
|
3209
|
-
dev: "alchemy dev"
|
|
3210
|
+
destroy: "alchemy destroy"
|
|
3210
3211
|
};
|
|
3211
3212
|
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3212
3213
|
}
|
|
@@ -3231,8 +3232,7 @@ async function setupSvelteAlchemyDeploy(projectDir, _packageManager, options) {
|
|
|
3231
3232
|
if (!options?.skipAppScripts) pkg.scripts = {
|
|
3232
3233
|
...pkg.scripts,
|
|
3233
3234
|
deploy: "alchemy deploy",
|
|
3234
|
-
destroy: "alchemy destroy"
|
|
3235
|
-
dev: "alchemy dev"
|
|
3235
|
+
destroy: "alchemy destroy"
|
|
3236
3236
|
};
|
|
3237
3237
|
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3238
3238
|
}
|
|
@@ -3298,8 +3298,7 @@ async function setupTanStackRouterAlchemyDeploy(projectDir, _packageManager, opt
|
|
|
3298
3298
|
if (!options?.skipAppScripts) pkg.scripts = {
|
|
3299
3299
|
...pkg.scripts,
|
|
3300
3300
|
deploy: "alchemy deploy",
|
|
3301
|
-
destroy: "alchemy destroy"
|
|
3302
|
-
dev: "alchemy dev"
|
|
3301
|
+
destroy: "alchemy destroy"
|
|
3303
3302
|
};
|
|
3304
3303
|
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3305
3304
|
}
|
|
@@ -3324,8 +3323,7 @@ async function setupTanStackStartAlchemyDeploy(projectDir, _packageManager, opti
|
|
|
3324
3323
|
if (!options?.skipAppScripts) pkg.scripts = {
|
|
3325
3324
|
...pkg.scripts,
|
|
3326
3325
|
deploy: "alchemy deploy",
|
|
3327
|
-
destroy: "alchemy destroy"
|
|
3328
|
-
dev: "alchemy dev"
|
|
3326
|
+
destroy: "alchemy destroy"
|
|
3329
3327
|
};
|
|
3330
3328
|
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
3331
3329
|
}
|
|
@@ -3889,7 +3887,12 @@ function getFrontendType(frontend) {
|
|
|
3889
3887
|
}
|
|
3890
3888
|
function getApiDependencies(api, frontendType) {
|
|
3891
3889
|
const deps = {};
|
|
3892
|
-
if (api === "orpc") deps.server = { dependencies: [
|
|
3890
|
+
if (api === "orpc") deps.server = { dependencies: [
|
|
3891
|
+
"@orpc/server",
|
|
3892
|
+
"@orpc/client",
|
|
3893
|
+
"@orpc/openapi",
|
|
3894
|
+
"@orpc/zod"
|
|
3895
|
+
] };
|
|
3893
3896
|
else if (api === "trpc") deps.server = { dependencies: ["@trpc/server", "@trpc/client"] };
|
|
3894
3897
|
if (frontendType.hasReactWeb) {
|
|
3895
3898
|
if (api === "orpc") deps.web = { dependencies: ["@orpc/tanstack-query", "@orpc/client"] };
|
|
@@ -5737,7 +5740,7 @@ async function getDockerStatus(database) {
|
|
|
5737
5740
|
//#endregion
|
|
5738
5741
|
//#region src/helpers/core/post-installation.ts
|
|
5739
5742
|
async function displayPostInstallInstructions(config) {
|
|
5740
|
-
const { database, relativePath, packageManager, depsInstalled, orm, addons, runtime, frontend, backend, dbSetup, webDeploy, serverDeploy } = config;
|
|
5743
|
+
const { api, database, relativePath, packageManager, depsInstalled, orm, addons, runtime, frontend, backend, dbSetup, webDeploy, serverDeploy } = config;
|
|
5741
5744
|
const isConvex = backend === "convex";
|
|
5742
5745
|
const runCmd = packageManager === "npm" ? "npm run" : packageManager === "pnpm" ? "pnpm run" : "bun run";
|
|
5743
5746
|
const cdCmd = `cd ${relativePath}`;
|
|
@@ -5785,7 +5788,11 @@ async function displayPostInstallInstructions(config) {
|
|
|
5785
5788
|
output += `${pc.bold("Your project will be available at:")}\n`;
|
|
5786
5789
|
if (hasWeb) output += `${pc.cyan("•")} Frontend: http://localhost:${webPort}\n`;
|
|
5787
5790
|
else if (!hasNative && !addons?.includes("starlight")) output += `${pc.yellow("NOTE:")} You are creating a backend-only app\n (no frontend selected)\n`;
|
|
5788
|
-
if (!isConvex)
|
|
5791
|
+
if (!isConvex) {
|
|
5792
|
+
output += `${pc.cyan("•")} Backend API: http://localhost:3000\n`;
|
|
5793
|
+
if (api === "orpc") if (backend === "next") output += `${pc.cyan("•")} OpenAPI (Scalar UI): http://localhost:3000/rpc/api\n`;
|
|
5794
|
+
else output += `${pc.cyan("•")} OpenAPI (Scalar UI): http://localhost:3000/api\n`;
|
|
5795
|
+
}
|
|
5789
5796
|
if (addons?.includes("starlight")) output += `${pc.cyan("•")} Docs: http://localhost:4321\n`;
|
|
5790
5797
|
if (addons?.includes("fumadocs")) output += `${pc.cyan("•")} Fumadocs: http://localhost:4000\n`;
|
|
5791
5798
|
if (nativeInstructions) output += `\n${nativeInstructions.trim()}\n`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-better-t-stack",
|
|
3
|
-
"version": "2.40.
|
|
3
|
+
"version": "2.40.4",
|
|
4
4
|
"description": "A modern CLI tool for scaffolding end-to-end type-safe TypeScript projects with best practices and customizable configurations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -2,18 +2,47 @@
|
|
|
2
2
|
import { createContext } from '@/lib/context'
|
|
3
3
|
{{/if}}
|
|
4
4
|
import { appRouter } from '@/routers'
|
|
5
|
+
import { OpenAPIHandler } from '@orpc/openapi/fetch'
|
|
6
|
+
import { OpenAPIReferencePlugin } from '@orpc/openapi/plugins'
|
|
7
|
+
import { ZodToJsonSchemaConverter } from '@orpc/zod/zod4'
|
|
5
8
|
import { RPCHandler } from '@orpc/server/fetch'
|
|
9
|
+
import { onError } from '@orpc/server'
|
|
6
10
|
import { NextRequest } from 'next/server'
|
|
7
11
|
|
|
8
|
-
const
|
|
12
|
+
const rpcHandler = new RPCHandler(appRouter, {
|
|
13
|
+
interceptors: [
|
|
14
|
+
onError((error) => {
|
|
15
|
+
console.error(error)
|
|
16
|
+
}),
|
|
17
|
+
],
|
|
18
|
+
})
|
|
19
|
+
const apiHandler = new OpenAPIHandler(appRouter, {
|
|
20
|
+
plugins: [
|
|
21
|
+
new OpenAPIReferencePlugin({
|
|
22
|
+
schemaConverters: [new ZodToJsonSchemaConverter()],
|
|
23
|
+
}),
|
|
24
|
+
],
|
|
25
|
+
interceptors: [
|
|
26
|
+
onError((error) => {
|
|
27
|
+
console.error(error)
|
|
28
|
+
}),
|
|
29
|
+
],
|
|
30
|
+
})
|
|
9
31
|
|
|
10
32
|
async function handleRequest(req: NextRequest) {
|
|
11
|
-
const
|
|
33
|
+
const rpcResult = await rpcHandler.handle(req, {
|
|
12
34
|
prefix: '/rpc',
|
|
13
35
|
context: {{#if (eq auth "better-auth")}}await createContext(req){{else}}{}{{/if}},
|
|
14
36
|
})
|
|
37
|
+
if (rpcResult.response) return rpcResult.response
|
|
15
38
|
|
|
16
|
-
|
|
39
|
+
const apiResult = await apiHandler.handle(req, {
|
|
40
|
+
prefix: '/rpc/api',
|
|
41
|
+
context: {{#if (eq auth "better-auth")}}await createContext(req){{else}}{}{{/if}},
|
|
42
|
+
})
|
|
43
|
+
if (apiResult.response) return apiResult.response
|
|
44
|
+
|
|
45
|
+
return new Response('Not found', { status: 404 })
|
|
17
46
|
}
|
|
18
47
|
|
|
19
48
|
export const GET = handleRequest
|
|
@@ -10,7 +10,11 @@ import { appRouter } from "./routers/index";
|
|
|
10
10
|
import { fetchRequestHandler } from "@trpc/server/adapters/fetch";
|
|
11
11
|
{{/if}}
|
|
12
12
|
{{#if (eq api "orpc")}}
|
|
13
|
+
import { OpenAPIHandler } from "@orpc/openapi/fetch";
|
|
14
|
+
import { OpenAPIReferencePlugin } from "@orpc/openapi/plugins";
|
|
15
|
+
import { ZodToJsonSchemaConverter } from "@orpc/zod/zod4";
|
|
13
16
|
import { RPCHandler } from "@orpc/server/fetch";
|
|
17
|
+
import { onError } from "@orpc/server";
|
|
14
18
|
import { appRouter } from "./routers";
|
|
15
19
|
import { createContext } from "./lib/context";
|
|
16
20
|
{{/if}}
|
|
@@ -19,7 +23,25 @@ import { auth } from "./lib/auth";
|
|
|
19
23
|
{{/if}}
|
|
20
24
|
|
|
21
25
|
{{#if (eq api "orpc")}}
|
|
22
|
-
const
|
|
26
|
+
const rpcHandler = new RPCHandler(appRouter, {
|
|
27
|
+
interceptors: [
|
|
28
|
+
onError((error) => {
|
|
29
|
+
console.error(error);
|
|
30
|
+
}),
|
|
31
|
+
],
|
|
32
|
+
});
|
|
33
|
+
const apiHandler = new OpenAPIHandler(appRouter, {
|
|
34
|
+
plugins: [
|
|
35
|
+
new OpenAPIReferencePlugin({
|
|
36
|
+
schemaConverters: [new ZodToJsonSchemaConverter()],
|
|
37
|
+
}),
|
|
38
|
+
],
|
|
39
|
+
interceptors: [
|
|
40
|
+
onError((error) => {
|
|
41
|
+
console.error(error);
|
|
42
|
+
}),
|
|
43
|
+
],
|
|
44
|
+
});
|
|
23
45
|
{{/if}}
|
|
24
46
|
|
|
25
47
|
{{#if (eq runtime "node")}}
|
|
@@ -48,12 +70,19 @@ const app = new Elysia()
|
|
|
48
70
|
{{/if}}
|
|
49
71
|
{{#if (eq api "orpc")}}
|
|
50
72
|
.all('/rpc*', async (context) => {
|
|
51
|
-
const { response } = await
|
|
73
|
+
const { response } = await rpcHandler.handle(context.request, {
|
|
52
74
|
prefix: '/rpc',
|
|
53
75
|
context: await createContext({ context })
|
|
54
76
|
})
|
|
55
77
|
return response ?? new Response('Not Found', { status: 404 })
|
|
56
78
|
})
|
|
79
|
+
.all('/api*', async (context) => {
|
|
80
|
+
const { response } = await apiHandler.handle(context.request, {
|
|
81
|
+
prefix: '/api',
|
|
82
|
+
context: await createContext({ context })
|
|
83
|
+
})
|
|
84
|
+
return response ?? new Response('Not Found', { status: 404 })
|
|
85
|
+
})
|
|
57
86
|
{{/if}}
|
|
58
87
|
{{#if (eq api "trpc")}}
|
|
59
88
|
.all("/trpc/*", async (context) => {
|
|
@@ -5,7 +5,11 @@ import { createContext } from "./lib/context";
|
|
|
5
5
|
import { appRouter } from "./routers/index";
|
|
6
6
|
{{/if}}
|
|
7
7
|
{{#if (eq api "orpc")}}
|
|
8
|
+
import { OpenAPIHandler } from "@orpc/openapi/node";
|
|
9
|
+
import { OpenAPIReferencePlugin } from "@orpc/openapi/plugins";
|
|
10
|
+
import { ZodToJsonSchemaConverter } from "@orpc/zod/zod4";
|
|
8
11
|
import { RPCHandler } from "@orpc/server/node";
|
|
12
|
+
import { onError } from "@orpc/server";
|
|
9
13
|
import { appRouter } from "./routers";
|
|
10
14
|
{{#if (eq auth "better-auth")}}
|
|
11
15
|
import { createContext } from "./lib/context";
|
|
@@ -50,9 +54,28 @@ app.use(
|
|
|
50
54
|
{{/if}}
|
|
51
55
|
|
|
52
56
|
{{#if (eq api "orpc")}}
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
57
|
+
const rpcHandler = new RPCHandler(appRouter, {
|
|
58
|
+
interceptors: [
|
|
59
|
+
onError((error) => {
|
|
60
|
+
console.error(error);
|
|
61
|
+
}),
|
|
62
|
+
],
|
|
63
|
+
});
|
|
64
|
+
const apiHandler = new OpenAPIHandler(appRouter, {
|
|
65
|
+
plugins: [
|
|
66
|
+
new OpenAPIReferencePlugin({
|
|
67
|
+
schemaConverters: [new ZodToJsonSchemaConverter()],
|
|
68
|
+
}),
|
|
69
|
+
],
|
|
70
|
+
interceptors: [
|
|
71
|
+
onError((error) => {
|
|
72
|
+
console.error(error);
|
|
73
|
+
}),
|
|
74
|
+
],
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
app.use(async (req, res, next) => {
|
|
78
|
+
const rpcResult = await rpcHandler.handle(req, res, {
|
|
56
79
|
prefix: "/rpc",
|
|
57
80
|
{{#if (eq auth "better-auth")}}
|
|
58
81
|
context: await createContext({ req }),
|
|
@@ -60,7 +83,18 @@ app.use("/rpc{*path}", async (req, res, next) => {
|
|
|
60
83
|
context: {},
|
|
61
84
|
{{/if}}
|
|
62
85
|
});
|
|
63
|
-
if (matched) return;
|
|
86
|
+
if (rpcResult.matched) return;
|
|
87
|
+
|
|
88
|
+
const apiResult = await apiHandler.handle(req, res, {
|
|
89
|
+
prefix: "/api",
|
|
90
|
+
{{#if (eq auth "better-auth")}}
|
|
91
|
+
context: await createContext({ req }),
|
|
92
|
+
{{else}}
|
|
93
|
+
context: {},
|
|
94
|
+
{{/if}}
|
|
95
|
+
});
|
|
96
|
+
if (apiResult.matched) return;
|
|
97
|
+
|
|
64
98
|
next();
|
|
65
99
|
});
|
|
66
100
|
{{/if}}
|
|
@@ -9,8 +9,12 @@ import { appRouter, type AppRouter } from "./routers/index";
|
|
|
9
9
|
{{/if}}
|
|
10
10
|
|
|
11
11
|
{{#if (eq api "orpc")}}
|
|
12
|
+
import { OpenAPIHandler } from "@orpc/openapi/node";
|
|
13
|
+
import { OpenAPIReferencePlugin } from "@orpc/openapi/plugins";
|
|
14
|
+
import { ZodToJsonSchemaConverter } from "@orpc/zod/zod4";
|
|
12
15
|
import { RPCHandler } from "@orpc/server/node";
|
|
13
16
|
import { CORSPlugin } from "@orpc/server/plugins";
|
|
17
|
+
import { onError } from "@orpc/server";
|
|
14
18
|
import { appRouter } from "./routers/index";
|
|
15
19
|
import { createServer } from "node:http";
|
|
16
20
|
{{#if (eq auth "better-auth")}}
|
|
@@ -40,7 +44,7 @@ const baseCorsConfig = {
|
|
|
40
44
|
};
|
|
41
45
|
|
|
42
46
|
{{#if (eq api "orpc")}}
|
|
43
|
-
const
|
|
47
|
+
const rpcHandler = new RPCHandler(appRouter, {
|
|
44
48
|
plugins: [
|
|
45
49
|
new CORSPlugin({
|
|
46
50
|
origin: process.env.CORS_ORIGIN,
|
|
@@ -48,13 +52,31 @@ const handler = new RPCHandler(appRouter, {
|
|
|
48
52
|
allowHeaders: ["Content-Type", "Authorization"],
|
|
49
53
|
}),
|
|
50
54
|
],
|
|
55
|
+
interceptors: [
|
|
56
|
+
onError((error) => {
|
|
57
|
+
console.error(error);
|
|
58
|
+
}),
|
|
59
|
+
],
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const apiHandler = new OpenAPIHandler(appRouter, {
|
|
63
|
+
plugins: [
|
|
64
|
+
new OpenAPIReferencePlugin({
|
|
65
|
+
schemaConverters: [new ZodToJsonSchemaConverter()],
|
|
66
|
+
}),
|
|
67
|
+
],
|
|
68
|
+
interceptors: [
|
|
69
|
+
onError((error) => {
|
|
70
|
+
console.error(error);
|
|
71
|
+
}),
|
|
72
|
+
],
|
|
51
73
|
});
|
|
52
74
|
|
|
53
75
|
const fastify = Fastify({
|
|
54
76
|
logger: true,
|
|
55
77
|
serverFactory: (fastifyHandler) => {
|
|
56
78
|
const server = createServer(async (req, res) => {
|
|
57
|
-
const { matched } = await
|
|
79
|
+
const { matched } = await rpcHandler.handle(req, res, {
|
|
58
80
|
context: await createContext(req.headers),
|
|
59
81
|
prefix: "/rpc",
|
|
60
82
|
});
|
|
@@ -63,6 +85,15 @@ const fastify = Fastify({
|
|
|
63
85
|
return;
|
|
64
86
|
}
|
|
65
87
|
|
|
88
|
+
const apiResult = await apiHandler.handle(req, res, {
|
|
89
|
+
context: await createContext(req.headers),
|
|
90
|
+
prefix: "/api",
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
if (apiResult.matched) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
66
97
|
fastifyHandler(req, res);
|
|
67
98
|
});
|
|
68
99
|
|
|
@@ -5,7 +5,11 @@ import "dotenv/config";
|
|
|
5
5
|
import { env } from "cloudflare:workers";
|
|
6
6
|
{{/if}}
|
|
7
7
|
{{#if (eq api "orpc")}}
|
|
8
|
+
import { OpenAPIHandler } from "@orpc/openapi/fetch";
|
|
9
|
+
import { OpenAPIReferencePlugin } from "@orpc/openapi/plugins";
|
|
10
|
+
import { ZodToJsonSchemaConverter } from "@orpc/zod/zod4";
|
|
8
11
|
import { RPCHandler } from "@orpc/server/fetch";
|
|
12
|
+
import { onError } from "@orpc/server";
|
|
9
13
|
import { createContext } from "./lib/context";
|
|
10
14
|
import { appRouter } from "./routers/index";
|
|
11
15
|
{{/if}}
|
|
@@ -54,17 +58,48 @@ app.on(["POST", "GET"], "/api/auth/**", (c) => auth.handler(c.req.raw));
|
|
|
54
58
|
{{/if}}
|
|
55
59
|
|
|
56
60
|
{{#if (eq api "orpc")}}
|
|
57
|
-
const
|
|
58
|
-
|
|
61
|
+
export const apiHandler = new OpenAPIHandler(appRouter, {
|
|
62
|
+
plugins: [
|
|
63
|
+
new OpenAPIReferencePlugin({
|
|
64
|
+
schemaConverters: [new ZodToJsonSchemaConverter()],
|
|
65
|
+
}),
|
|
66
|
+
],
|
|
67
|
+
interceptors: [
|
|
68
|
+
onError((error) => {
|
|
69
|
+
console.error(error);
|
|
70
|
+
}),
|
|
71
|
+
],
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
export const rpcHandler = new RPCHandler(appRouter, {
|
|
75
|
+
interceptors: [
|
|
76
|
+
onError((error) => {
|
|
77
|
+
console.error(error);
|
|
78
|
+
}),
|
|
79
|
+
],
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
app.use("/*", async (c, next) => {
|
|
59
83
|
const context = await createContext({ context: c });
|
|
60
|
-
|
|
84
|
+
|
|
85
|
+
const rpcResult = await rpcHandler.handle(c.req.raw, {
|
|
61
86
|
prefix: "/rpc",
|
|
62
87
|
context: context,
|
|
63
88
|
});
|
|
64
89
|
|
|
65
|
-
if (matched) {
|
|
66
|
-
return c.newResponse(response.body, response);
|
|
90
|
+
if (rpcResult.matched) {
|
|
91
|
+
return c.newResponse(rpcResult.response.body, rpcResult.response);
|
|
67
92
|
}
|
|
93
|
+
|
|
94
|
+
const apiResult = await apiHandler.handle(c.req.raw, {
|
|
95
|
+
prefix: "/api",
|
|
96
|
+
context: context,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
if (apiResult.matched) {
|
|
100
|
+
return c.newResponse(apiResult.response.body, apiResult.response);
|
|
101
|
+
}
|
|
102
|
+
|
|
68
103
|
await next();
|
|
69
104
|
});
|
|
70
105
|
{{/if}}
|