create-better-t-stack 2.40.3 → 2.40.5

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 CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { createBtsCli } from "./src-BOnnM-3r.js";
2
+ import { createBtsCli } from "./src-jRwaAdo-.js";
3
3
 
4
4
  //#region src/cli.ts
5
5
  createBtsCli().run();
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import { builder, createBtsCli, docs, init, router, sponsors } from "./src-BOnnM-3r.js";
2
+ import { builder, createBtsCli, docs, init, router, sponsors } from "./src-jRwaAdo-.js";
3
3
 
4
4
  export { builder, createBtsCli, docs, init, router, sponsors };
@@ -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",
@@ -3096,8 +3098,7 @@ async function setupNextAlchemyDeploy(projectDir, _packageManager, options) {
3096
3098
  if (!options?.skipAppScripts) pkg.scripts = {
3097
3099
  ...pkg.scripts,
3098
3100
  deploy: "alchemy deploy",
3099
- destroy: "alchemy destroy",
3100
- dev: "alchemy dev"
3101
+ destroy: "alchemy destroy"
3101
3102
  };
3102
3103
  await fs.writeJson(pkgPath, pkg, { spaces: 2 });
3103
3104
  }
@@ -3122,8 +3123,7 @@ async function setupNuxtAlchemyDeploy(projectDir, _packageManager, options) {
3122
3123
  if (!options?.skipAppScripts) pkg.scripts = {
3123
3124
  ...pkg.scripts,
3124
3125
  deploy: "alchemy deploy",
3125
- destroy: "alchemy destroy",
3126
- dev: "alchemy dev"
3126
+ destroy: "alchemy destroy"
3127
3127
  };
3128
3128
  await fs.writeJson(pkgPath, pkg, { spaces: 2 });
3129
3129
  }
@@ -3186,8 +3186,7 @@ async function setupReactRouterAlchemyDeploy(projectDir, _packageManager, option
3186
3186
  if (!options?.skipAppScripts) pkg.scripts = {
3187
3187
  ...pkg.scripts,
3188
3188
  deploy: "alchemy deploy",
3189
- destroy: "alchemy destroy",
3190
- dev: "alchemy dev"
3189
+ destroy: "alchemy destroy"
3191
3190
  };
3192
3191
  await fs.writeJson(pkgPath, pkg, { spaces: 2 });
3193
3192
  }
@@ -3208,8 +3207,7 @@ async function setupSolidAlchemyDeploy(projectDir, _packageManager, options) {
3208
3207
  if (!options?.skipAppScripts) pkg.scripts = {
3209
3208
  ...pkg.scripts,
3210
3209
  deploy: "alchemy deploy",
3211
- destroy: "alchemy destroy",
3212
- dev: "alchemy dev"
3210
+ destroy: "alchemy destroy"
3213
3211
  };
3214
3212
  await fs.writeJson(pkgPath, pkg, { spaces: 2 });
3215
3213
  }
@@ -3234,8 +3232,7 @@ async function setupSvelteAlchemyDeploy(projectDir, _packageManager, options) {
3234
3232
  if (!options?.skipAppScripts) pkg.scripts = {
3235
3233
  ...pkg.scripts,
3236
3234
  deploy: "alchemy deploy",
3237
- destroy: "alchemy destroy",
3238
- dev: "alchemy dev"
3235
+ destroy: "alchemy destroy"
3239
3236
  };
3240
3237
  await fs.writeJson(pkgPath, pkg, { spaces: 2 });
3241
3238
  }
@@ -3301,8 +3298,7 @@ async function setupTanStackRouterAlchemyDeploy(projectDir, _packageManager, opt
3301
3298
  if (!options?.skipAppScripts) pkg.scripts = {
3302
3299
  ...pkg.scripts,
3303
3300
  deploy: "alchemy deploy",
3304
- destroy: "alchemy destroy",
3305
- dev: "alchemy dev"
3301
+ destroy: "alchemy destroy"
3306
3302
  };
3307
3303
  await fs.writeJson(pkgPath, pkg, { spaces: 2 });
3308
3304
  }
@@ -3327,8 +3323,7 @@ async function setupTanStackStartAlchemyDeploy(projectDir, _packageManager, opti
3327
3323
  if (!options?.skipAppScripts) pkg.scripts = {
3328
3324
  ...pkg.scripts,
3329
3325
  deploy: "alchemy deploy",
3330
- destroy: "alchemy destroy",
3331
- dev: "alchemy dev"
3326
+ destroy: "alchemy destroy"
3332
3327
  };
3333
3328
  await fs.writeJson(pkgPath, pkg, { spaces: 2 });
3334
3329
  }
@@ -3892,7 +3887,12 @@ function getFrontendType(frontend) {
3892
3887
  }
3893
3888
  function getApiDependencies(api, frontendType) {
3894
3889
  const deps = {};
3895
- if (api === "orpc") deps.server = { dependencies: ["@orpc/server", "@orpc/client"] };
3890
+ if (api === "orpc") deps.server = { dependencies: [
3891
+ "@orpc/server",
3892
+ "@orpc/client",
3893
+ "@orpc/openapi",
3894
+ "@orpc/zod"
3895
+ ] };
3896
3896
  else if (api === "trpc") deps.server = { dependencies: ["@trpc/server", "@trpc/client"] };
3897
3897
  if (frontendType.hasReactWeb) {
3898
3898
  if (api === "orpc") deps.web = { dependencies: ["@orpc/tanstack-query", "@orpc/client"] };
@@ -5740,7 +5740,7 @@ async function getDockerStatus(database) {
5740
5740
  //#endregion
5741
5741
  //#region src/helpers/core/post-installation.ts
5742
5742
  async function displayPostInstallInstructions(config) {
5743
- 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;
5744
5744
  const isConvex = backend === "convex";
5745
5745
  const runCmd = packageManager === "npm" ? "npm run" : packageManager === "pnpm" ? "pnpm run" : "bun run";
5746
5746
  const cdCmd = `cd ${relativePath}`;
@@ -5788,7 +5788,11 @@ async function displayPostInstallInstructions(config) {
5788
5788
  output += `${pc.bold("Your project will be available at:")}\n`;
5789
5789
  if (hasWeb) output += `${pc.cyan("•")} Frontend: http://localhost:${webPort}\n`;
5790
5790
  else if (!hasNative && !addons?.includes("starlight")) output += `${pc.yellow("NOTE:")} You are creating a backend-only app\n (no frontend selected)\n`;
5791
- if (!isConvex) output += `${pc.cyan("•")} Backend API: http://localhost:3000\n`;
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
+ }
5792
5796
  if (addons?.includes("starlight")) output += `${pc.cyan("•")} Docs: http://localhost:4321\n`;
5793
5797
  if (addons?.includes("fumadocs")) output += `${pc.cyan("•")} Fumadocs: http://localhost:4000\n`;
5794
5798
  if (nativeInstructions) output += `\n${nativeInstructions.trim()}\n`;
@@ -6365,7 +6369,7 @@ async function openUrl(url) {
6365
6369
 
6366
6370
  //#endregion
6367
6371
  //#region src/utils/sponsors.ts
6368
- const SPONSORS_JSON_URL = "https://sponsors.amanv.dev/sponsors.json";
6372
+ const SPONSORS_JSON_URL = "https://sponsors.better-t-stack.dev/sponsors.json";
6369
6373
  async function fetchSponsors(url = SPONSORS_JSON_URL) {
6370
6374
  const s = spinner();
6371
6375
  s.start("Fetching sponsors…");
@@ -6379,23 +6383,30 @@ async function fetchSponsors(url = SPONSORS_JSON_URL) {
6379
6383
  return sponsors$1;
6380
6384
  }
6381
6385
  function displaySponsors(sponsors$1) {
6382
- if (sponsors$1.length === 0) {
6386
+ const { total_sponsors } = sponsors$1.summary;
6387
+ if (total_sponsors === 0) {
6383
6388
  log.info("No sponsors found. You can be the first one! ✨");
6384
6389
  outro(pc.cyan("Visit https://github.com/sponsors/AmanVarshney01 to become a sponsor."));
6385
6390
  return;
6386
6391
  }
6387
- sponsors$1.forEach((entry, idx) => {
6388
- const sponsor = entry.sponsor;
6389
- const displayName = sponsor.name ?? sponsor.login;
6390
- const tier = entry.tierName ? ` (${entry.tierName})` : "";
6391
- log.step(`${idx + 1}. ${pc.green(displayName)}${pc.yellow(tier)}`);
6392
- log.message(` ${pc.dim("GitHub:")} https://github.com/${sponsor.login}`);
6393
- const website = sponsor.websiteUrl ?? sponsor.linkUrl;
6394
- if (website) log.message(` ${pc.dim("Website:")} ${website}`);
6395
- });
6396
- log.message("");
6392
+ displaySponsorsBox(sponsors$1);
6393
+ if (total_sponsors - sponsors$1.specialSponsors.length > 0) log.message(pc.blue(`+${total_sponsors - sponsors$1.specialSponsors.length} more amazing sponsors.\n`));
6397
6394
  outro(pc.magenta("Visit https://github.com/sponsors/AmanVarshney01 to become a sponsor."));
6398
6395
  }
6396
+ function displaySponsorsBox(sponsors$1) {
6397
+ if (sponsors$1.specialSponsors.length === 0) return;
6398
+ let output = `${pc.bold(pc.cyan("-> Special Sponsors"))}\n\n`;
6399
+ sponsors$1.specialSponsors.forEach((sponsor, idx) => {
6400
+ const displayName = sponsor.name ?? sponsor.githubId;
6401
+ const tier = sponsor.tierName ? ` ${pc.yellow(`(${sponsor.tierName})`)}` : "";
6402
+ output += `${pc.green(`• ${displayName}`)}${tier}\n`;
6403
+ output += ` ${pc.dim("GitHub:")} https://github.com/${sponsor.githubId}\n`;
6404
+ const website = sponsor.websiteUrl ?? sponsor.githubUrl;
6405
+ if (website) output += ` ${pc.dim("Website:")} ${website}\n`;
6406
+ if (idx < sponsors$1.specialSponsors.length - 1) output += "\n";
6407
+ });
6408
+ consola$1.box(output);
6409
+ }
6399
6410
 
6400
6411
  //#endregion
6401
6412
  //#region src/index.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-better-t-stack",
3
- "version": "2.40.3",
3
+ "version": "2.40.5",
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 handler = new RPCHandler(appRouter)
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 { response } = await handler.handle(req, {
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
- return response ?? new Response('Not found', { status: 404 })
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 handler = new RPCHandler(appRouter);
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 handler.handle(context.request, {
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 handler = new RPCHandler(appRouter);
54
- app.use("/rpc{*path}", async (req, res, next) => {
55
- const { matched } = await handler.handle(req, res, {
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 handler = new RPCHandler(appRouter, {
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 handler.handle(req, res, {
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 handler = new RPCHandler(appRouter);
58
- app.use("/rpc/*", async (c, next) => {
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
- const { matched, response } = await handler.handle(c.req.raw, {
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}}