create-softeneers-app 0.1.0 → 0.2.1

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.
Files changed (84) hide show
  1. package/README.html +56 -0
  2. package/README.md +16 -8
  3. package/dist/args.js +33 -4
  4. package/dist/args.js.map +1 -1
  5. package/dist/fragments.js +127 -0
  6. package/dist/fragments.js.map +1 -0
  7. package/dist/index.js +18 -7
  8. package/dist/index.js.map +1 -1
  9. package/dist/prompts.js +27 -1
  10. package/dist/prompts.js.map +1 -1
  11. package/dist/templates.js +33 -8
  12. package/dist/templates.js.map +1 -1
  13. package/package.json +2 -2
  14. package/templates/express-api/.env.example +13 -0
  15. package/templates/express-api/README.md +77 -0
  16. package/templates/express-api/docker-compose.yml +15 -0
  17. package/templates/express-api/package.json +36 -0
  18. package/templates/express-api/softeneers.template.json +17 -0
  19. package/templates/express-api/src/auth/auth.ts +11 -0
  20. package/templates/express-api/src/cars/demo.ts +10 -0
  21. package/templates/express-api/src/cars/routes.ts +58 -0
  22. package/templates/express-api/src/cars/store.ts +150 -0
  23. package/templates/express-api/src/cars/types.ts +8 -0
  24. package/templates/express-api/src/cars/validate.ts +16 -0
  25. package/templates/express-api/src/db.ts +13 -0
  26. package/templates/express-api/src/env.ts +23 -0
  27. package/templates/express-api/src/index.ts +37 -0
  28. package/templates/express-api/src/scripts/migrate.ts +13 -0
  29. package/templates/express-api/src/scripts/seed.ts +20 -0
  30. package/templates/express-api/test/validate.test.ts +25 -0
  31. package/templates/express-api/tsconfig.json +14 -0
  32. package/templates/hono-api/.env.example +13 -0
  33. package/templates/hono-api/README.md +77 -0
  34. package/templates/hono-api/docker-compose.yml +15 -0
  35. package/templates/hono-api/package.json +34 -0
  36. package/templates/hono-api/softeneers.template.json +17 -0
  37. package/templates/hono-api/src/auth/auth.ts +11 -0
  38. package/templates/hono-api/src/cars/demo.ts +10 -0
  39. package/templates/hono-api/src/cars/routes.ts +43 -0
  40. package/templates/hono-api/src/cars/store.ts +150 -0
  41. package/templates/hono-api/src/cars/types.ts +8 -0
  42. package/templates/hono-api/src/cars/validate.ts +16 -0
  43. package/templates/hono-api/src/db.ts +13 -0
  44. package/templates/hono-api/src/env.ts +23 -0
  45. package/templates/hono-api/src/index.ts +26 -0
  46. package/templates/hono-api/src/scripts/migrate.ts +13 -0
  47. package/templates/hono-api/src/scripts/seed.ts +20 -0
  48. package/templates/hono-api/test/validate.test.ts +25 -0
  49. package/templates/hono-api/tsconfig.json +14 -0
  50. package/templates/minimal/.env.example +2 -0
  51. package/templates/minimal/README.md +33 -0
  52. package/templates/minimal/package.json +22 -0
  53. package/templates/minimal/src/index.ts +20 -0
  54. package/templates/minimal/test/greet.test.ts +12 -0
  55. package/templates/minimal/tsconfig.json +15 -0
  56. package/templates/tanstack-start/.env.example +11 -0
  57. package/templates/tanstack-start/README.md +74 -0
  58. package/templates/tanstack-start/docker-compose.yml +15 -0
  59. package/templates/tanstack-start/package.json +56 -0
  60. package/templates/tanstack-start/public/favicon.ico +0 -0
  61. package/templates/tanstack-start/public/logo192.png +0 -0
  62. package/templates/tanstack-start/public/logo512.png +0 -0
  63. package/templates/tanstack-start/public/manifest.json +25 -0
  64. package/templates/tanstack-start/public/robots.txt +3 -0
  65. package/templates/tanstack-start/softeneers.template.json +17 -0
  66. package/templates/tanstack-start/src/cars/types.ts +8 -0
  67. package/templates/tanstack-start/src/cars/validate.ts +16 -0
  68. package/templates/tanstack-start/src/router.tsx +19 -0
  69. package/templates/tanstack-start/src/routes/__root.tsx +54 -0
  70. package/templates/tanstack-start/src/routes/api/auth/$.ts +14 -0
  71. package/templates/tanstack-start/src/routes/cars.tsx +87 -0
  72. package/templates/tanstack-start/src/routes/index.tsx +20 -0
  73. package/templates/tanstack-start/src/server/auth.ts +11 -0
  74. package/templates/tanstack-start/src/server/cars.ts +27 -0
  75. package/templates/tanstack-start/src/server/db.ts +12 -0
  76. package/templates/tanstack-start/src/server/demo.ts +9 -0
  77. package/templates/tanstack-start/src/server/env.ts +22 -0
  78. package/templates/tanstack-start/src/server/scripts/migrate.ts +13 -0
  79. package/templates/tanstack-start/src/server/scripts/seed.ts +20 -0
  80. package/templates/tanstack-start/src/server/store.ts +132 -0
  81. package/templates/tanstack-start/src/styles.css +17 -0
  82. package/templates/tanstack-start/tsconfig.json +28 -0
  83. package/templates/tanstack-start/tsr.config.json +3 -0
  84. package/templates/tanstack-start/vite.config.ts +14 -0
@@ -0,0 +1,17 @@
1
+ {
2
+ "toggles": { "db": false, "auth": false, "docker": false },
3
+ "fragments": {
4
+ "db": {
5
+ "removePaths": ["src/server/db.ts", "src/server/scripts", "docker-compose.yml"],
6
+ "removeDeps": ["@softeneers/db", "mysql2"],
7
+ "removeScripts": ["db:migrate", "db:seed", "db:reset"]
8
+ },
9
+ "auth": {
10
+ "removePaths": ["src/server/auth.ts", "src/routes/api"],
11
+ "removeDeps": ["@softeneers/auth"]
12
+ },
13
+ "docker": {
14
+ "removePaths": ["docker-compose.yml"]
15
+ }
16
+ }
17
+ }
@@ -0,0 +1,8 @@
1
+ export interface Car {
2
+ id: number
3
+ brand: string
4
+ model: string
5
+ year: number
6
+ }
7
+
8
+ export type NewCar = Omit<Car, 'id'>
@@ -0,0 +1,16 @@
1
+ import type { NewCar } from './types'
2
+
3
+ /** Thrown when a submitted car is invalid. */
4
+ export class ValidationError extends Error {}
5
+
6
+ /** Validate and normalize untrusted input into a NewCar. Runs on the server. */
7
+ export function parseNewCar(input: unknown): NewCar {
8
+ const b = (input ?? {}) as Record<string, unknown>
9
+ const brand = typeof b.brand === 'string' ? b.brand.trim() : ''
10
+ const model = typeof b.model === 'string' ? b.model.trim() : ''
11
+ const year = Number(b.year)
12
+ if (!brand || !model || !Number.isInteger(year)) {
13
+ throw new ValidationError('brand (string), model (string) and year (integer) are required.')
14
+ }
15
+ return { brand, model, year }
16
+ }
@@ -0,0 +1,19 @@
1
+ import { createRouter as createTanStackRouter } from '@tanstack/react-router'
2
+ import { routeTree } from './routeTree.gen'
3
+
4
+ export function getRouter() {
5
+ const router = createTanStackRouter({
6
+ routeTree,
7
+ scrollRestoration: true,
8
+ defaultPreload: 'intent',
9
+ defaultPreloadStaleTime: 0,
10
+ })
11
+
12
+ return router
13
+ }
14
+
15
+ declare module '@tanstack/react-router' {
16
+ interface Register {
17
+ router: ReturnType<typeof getRouter>
18
+ }
19
+ }
@@ -0,0 +1,54 @@
1
+ import { HeadContent, Scripts, createRootRoute } from '@tanstack/react-router'
2
+ import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools'
3
+ import { TanStackDevtools } from '@tanstack/react-devtools'
4
+
5
+ import appCss from '../styles.css?url'
6
+
7
+ export const Route = createRootRoute({
8
+ head: () => ({
9
+ meta: [
10
+ {
11
+ charSet: 'utf-8',
12
+ },
13
+ {
14
+ name: 'viewport',
15
+ content: 'width=device-width, initial-scale=1',
16
+ },
17
+ {
18
+ title: 'TanStack Start Starter',
19
+ },
20
+ ],
21
+ links: [
22
+ {
23
+ rel: 'stylesheet',
24
+ href: appCss,
25
+ },
26
+ ],
27
+ }),
28
+ shellComponent: RootDocument,
29
+ })
30
+
31
+ function RootDocument({ children }: { children: React.ReactNode }) {
32
+ return (
33
+ <html lang="en">
34
+ <head>
35
+ <HeadContent />
36
+ </head>
37
+ <body>
38
+ {children}
39
+ <TanStackDevtools
40
+ config={{
41
+ position: 'bottom-right',
42
+ }}
43
+ plugins={[
44
+ {
45
+ name: 'Tanstack Router',
46
+ render: <TanStackRouterDevtoolsPanel />,
47
+ },
48
+ ]}
49
+ />
50
+ <Scripts />
51
+ </body>
52
+ </html>
53
+ )
54
+ }
@@ -0,0 +1,14 @@
1
+ import { createFileRoute } from '@tanstack/react-router'
2
+
3
+ import { auth } from '../../../server/auth'
4
+
5
+ // Catch-all server route: better-auth speaks the Fetch API, so hand it the raw
6
+ // Request and return its Response. Handles every /api/auth/* endpoint.
7
+ export const Route = createFileRoute('/api/auth/$')({
8
+ server: {
9
+ handlers: {
10
+ GET: ({ request }) => auth.handler(request),
11
+ POST: ({ request }) => auth.handler(request),
12
+ },
13
+ },
14
+ })
@@ -0,0 +1,87 @@
1
+ import { createFileRoute, useRouter } from '@tanstack/react-router'
2
+ import { useState } from 'react'
3
+
4
+ import { createCar, listCars, removeCar } from '../server/cars'
5
+
6
+ export const Route = createFileRoute('/cars')({
7
+ component: CarsPage,
8
+ loader: async () => listCars(),
9
+ })
10
+
11
+ function CarsPage() {
12
+ const cars = Route.useLoaderData()
13
+ const router = useRouter()
14
+ const [brand, setBrand] = useState('')
15
+ const [model, setModel] = useState('')
16
+ const [year, setYear] = useState('')
17
+ const [error, setError] = useState('')
18
+
19
+ async function add(event: React.FormEvent) {
20
+ event.preventDefault()
21
+ setError('')
22
+ try {
23
+ await createCar({ data: { brand, model, year: Number(year) } })
24
+ setBrand('')
25
+ setModel('')
26
+ setYear('')
27
+ await router.invalidate()
28
+ } catch {
29
+ setError('Please provide a brand, model and a valid year.')
30
+ }
31
+ }
32
+
33
+ async function del(id: number) {
34
+ await removeCar({ data: id })
35
+ await router.invalidate()
36
+ }
37
+
38
+ return (
39
+ <div className="mx-auto max-w-2xl p-8">
40
+ <h1 className="text-3xl font-bold">Cars</h1>
41
+ <p className="mt-1 text-gray-500">A full CRUD example backed by a server function.</p>
42
+
43
+ <form onSubmit={add} className="mt-6 flex flex-wrap gap-2">
44
+ <input
45
+ className="flex-1 rounded border border-gray-300 px-3 py-2"
46
+ placeholder="Brand"
47
+ value={brand}
48
+ onChange={(e) => setBrand(e.target.value)}
49
+ />
50
+ <input
51
+ className="flex-1 rounded border border-gray-300 px-3 py-2"
52
+ placeholder="Model"
53
+ value={model}
54
+ onChange={(e) => setModel(e.target.value)}
55
+ />
56
+ <input
57
+ className="w-24 rounded border border-gray-300 px-3 py-2"
58
+ placeholder="Year"
59
+ value={year}
60
+ onChange={(e) => setYear(e.target.value)}
61
+ />
62
+ <button className="rounded bg-black px-4 py-2 font-medium text-white" type="submit">
63
+ Add
64
+ </button>
65
+ </form>
66
+ {error && <p className="mt-2 text-sm text-red-600">{error}</p>}
67
+
68
+ <ul className="mt-6 divide-y divide-gray-200">
69
+ {cars.length === 0 && <li className="py-3 text-gray-500">No cars yet — add one above.</li>}
70
+ {cars.map((car) => (
71
+ <li key={car.id} className="flex items-center justify-between py-3">
72
+ <span>
73
+ {car.brand} {car.model} <span className="text-gray-400">({car.year})</span>
74
+ </span>
75
+ <button
76
+ className="text-sm text-red-600 hover:underline"
77
+ type="button"
78
+ onClick={() => del(car.id)}
79
+ >
80
+ Delete
81
+ </button>
82
+ </li>
83
+ ))}
84
+ </ul>
85
+ </div>
86
+ )
87
+ }
@@ -0,0 +1,20 @@
1
+ import { Link, createFileRoute } from '@tanstack/react-router'
2
+
3
+ export const Route = createFileRoute('/')({ component: Home })
4
+
5
+ function Home() {
6
+ return (
7
+ <div className="mx-auto max-w-2xl p-8">
8
+ <h1 className="text-4xl font-bold">Welcome to TanStack Start</h1>
9
+ <p className="mt-4 text-lg text-gray-600">
10
+ Generated by create-softeneers-app. A fullstack React app with type-safe server functions.
11
+ </p>
12
+ <Link
13
+ to="/cars"
14
+ className="mt-6 inline-block rounded bg-black px-5 py-2.5 font-medium text-white"
15
+ >
16
+ Open the cars CRUD demo →
17
+ </Link>
18
+ </div>
19
+ )
20
+ }
@@ -0,0 +1,11 @@
1
+ import { createAuth } from '@softeneers/auth'
2
+
3
+ import { env } from './env'
4
+
5
+ // Email + password auth via better-auth (@softeneers/auth). With no `database`
6
+ // configured better-auth uses an in-memory store — fine for local dev; point it
7
+ // at your DB for persistence. Mounted at /api/auth/* in routes/api/auth/$.ts.
8
+ export const auth = createAuth({
9
+ secret: env.AUTH_SECRET,
10
+ baseURL: env.AUTH_BASE_URL,
11
+ })
@@ -0,0 +1,27 @@
1
+ import { createServerFn } from '@tanstack/react-start'
2
+
3
+ import { parseNewCar } from '../cars/validate'
4
+ import { carStore } from './store'
5
+
6
+ // Server functions: type-safe RPC the client calls directly. Their bodies (and
7
+ // the store/db imports above) run only on the server and are stripped from the
8
+ // client bundle.
9
+ export const listCars = createServerFn({ method: 'GET' }).handler(async () => {
10
+ return carStore.list()
11
+ })
12
+
13
+ export const createCar = createServerFn({ method: 'POST' })
14
+ .validator((data: unknown) => parseNewCar(data))
15
+ .handler(async ({ data }) => {
16
+ return carStore.create(data)
17
+ })
18
+
19
+ export const removeCar = createServerFn({ method: 'POST' })
20
+ .validator((data: unknown) => {
21
+ const id = Number(data)
22
+ if (!Number.isInteger(id)) throw new Error('A numeric car id is required.')
23
+ return id
24
+ })
25
+ .handler(async ({ data }) => {
26
+ return carStore.remove(data)
27
+ })
@@ -0,0 +1,12 @@
1
+ import { createDb } from '@softeneers/db'
2
+
3
+ import { env } from './env'
4
+
5
+ // Configured (not-yet-connected) Sequelize instance. Server-only.
6
+ export const sequelize = createDb({
7
+ host: env.DB_HOST,
8
+ port: env.DB_PORT,
9
+ database: env.DB_NAME,
10
+ username: env.DB_USER,
11
+ password: env.DB_PASSWORD,
12
+ })
@@ -0,0 +1,9 @@
1
+ import type { NewCar } from '../cars/types'
2
+
3
+ // Demo garage inventory seeded on first run so `npm run dev` shows a working
4
+ // CRUD demo immediately — into MySQL when reachable, else the in-memory store.
5
+ export const DEMO_CARS: NewCar[] = [
6
+ { brand: 'Toyota', model: 'Corolla', year: 2021 },
7
+ { brand: 'Tesla', model: 'Model 3', year: 2023 },
8
+ { brand: 'Ford', model: 'Mustang', year: 1969 },
9
+ ]
@@ -0,0 +1,22 @@
1
+ import 'dotenv/config'
2
+
3
+ import { createEnv, z } from '@softeneers/env'
4
+
5
+ // Server-only validated environment. Variables for a feature exist only when
6
+ // that toggle is enabled at generation time.
7
+ export const env = createEnv({
8
+ schema: {
9
+ NODE_ENV: z.enum(['development', 'test', 'production']).default('development'),
10
+ // #if db
11
+ DB_HOST: z.string().default('127.0.0.1'),
12
+ DB_PORT: z.coerce.number().default(3306),
13
+ DB_NAME: z.string().default('app_dev'),
14
+ DB_USER: z.string().default('root'),
15
+ DB_PASSWORD: z.string().default(''),
16
+ // #endif
17
+ // #if auth
18
+ AUTH_SECRET: z.string().min(16).default('dev-secret-change-me-to-a-long-random-string'),
19
+ AUTH_BASE_URL: z.string().default('http://localhost:3000'),
20
+ // #endif
21
+ },
22
+ })
@@ -0,0 +1,13 @@
1
+ import 'dotenv/config'
2
+
3
+ import { assertConnection } from '@softeneers/db'
4
+
5
+ import { sequelize } from '../db'
6
+ import '../store' // importing the store registers the Car model
7
+
8
+ const reset = process.argv.includes('--reset')
9
+
10
+ await assertConnection(sequelize)
11
+ await sequelize.sync({ force: reset })
12
+ console.log(reset ? 'Database reset — tables recreated.' : 'Database synced — tables ensured.')
13
+ await sequelize.close()
@@ -0,0 +1,20 @@
1
+ import 'dotenv/config'
2
+
3
+ import { assertConnection } from '@softeneers/db'
4
+
5
+ import { DEMO_CARS } from '../demo'
6
+ import { sequelize } from '../db'
7
+ import { CarModel } from '../store'
8
+
9
+ await assertConnection(sequelize)
10
+ await sequelize.sync()
11
+
12
+ const count = await CarModel.count()
13
+ if (count > 0) {
14
+ console.log(`Skipped seeding — ${count} cars already present.`)
15
+ } else {
16
+ await CarModel.bulkCreate([...DEMO_CARS])
17
+ console.log(`Seeded ${DEMO_CARS.length} cars.`)
18
+ }
19
+
20
+ await sequelize.close()
@@ -0,0 +1,132 @@
1
+ import type { Car, NewCar } from '../cars/types'
2
+ import { DEMO_CARS } from './demo'
3
+
4
+ // Server-only data layer behind the cars server functions. With `db` on it
5
+ // persists to MySQL (Sequelize via @softeneers/db) and **falls back to an
6
+ // in-memory store if the database is unreachable**, so `npm run dev` always
7
+ // yields a working, pre-seeded demo. With `db` off it is always in-memory.
8
+ // Never bundled into the client — only reached from server functions.
9
+ export interface CarStore {
10
+ list(): Promise<Array<Car>>
11
+ get(id: number): Promise<Car | null>
12
+ create(input: NewCar): Promise<Car>
13
+ remove(id: number): Promise<boolean>
14
+ }
15
+
16
+ // In-memory backend (the default, and the fallback when no database is reachable).
17
+ function createMemoryStore(): CarStore {
18
+ let nextId = 1
19
+ const cars = new Map<number, Car>()
20
+ for (const car of DEMO_CARS) {
21
+ const id = nextId++
22
+ cars.set(id, { id, ...car })
23
+ }
24
+ return {
25
+ async list() {
26
+ return [...cars.values()].sort((a, b) => a.id - b.id)
27
+ },
28
+ async get(id) {
29
+ return cars.get(id) ?? null
30
+ },
31
+ async create(input) {
32
+ const car: Car = { id: nextId++, ...input }
33
+ cars.set(car.id, car)
34
+ return car
35
+ },
36
+ async remove(id) {
37
+ return cars.delete(id)
38
+ },
39
+ }
40
+ }
41
+
42
+ // #if db
43
+ import { DataTypes, Model, assertConnection } from '@softeneers/db'
44
+
45
+ import { sequelize } from './db'
46
+
47
+ class CarModel extends Model {
48
+ declare id: number
49
+ declare brand: string
50
+ declare model: string
51
+ declare year: number
52
+ }
53
+
54
+ CarModel.init(
55
+ {
56
+ id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true },
57
+ brand: { type: DataTypes.STRING, allowNull: false },
58
+ model: { type: DataTypes.STRING, allowNull: false },
59
+ year: { type: DataTypes.INTEGER, allowNull: false },
60
+ },
61
+ { sequelize, modelName: 'Car', tableName: 'cars' },
62
+ )
63
+
64
+ export { CarModel }
65
+
66
+ const toCar = (m: CarModel): Car => ({ id: m.id, brand: m.brand, model: m.model, year: m.year })
67
+
68
+ function createDbStore(): CarStore {
69
+ return {
70
+ async list() {
71
+ return (await CarModel.findAll({ order: [['id', 'ASC']] })).map(toCar)
72
+ },
73
+ async get(id) {
74
+ const m = await CarModel.findByPk(id)
75
+ return m ? toCar(m) : null
76
+ },
77
+ async create(input) {
78
+ return toCar(await CarModel.create(input))
79
+ },
80
+ async remove(id) {
81
+ const m = await CarModel.findByPk(id)
82
+ if (!m) return false
83
+ await m.destroy()
84
+ return true
85
+ },
86
+ }
87
+ }
88
+
89
+ // Resolve the backend once, lazily, on first use: try MySQL (create tables +
90
+ // seed if empty); on any connection error, fall back to the in-memory store.
91
+ let backend: Promise<CarStore> | null = null
92
+ function resolveBackend(): Promise<CarStore> {
93
+ if (!backend) {
94
+ backend = (async () => {
95
+ try {
96
+ await assertConnection(sequelize)
97
+ await sequelize.sync()
98
+ const db = createDbStore()
99
+ if ((await db.list()).length === 0) {
100
+ for (const car of DEMO_CARS) await db.create(car)
101
+ }
102
+ console.log('Data store: MySQL')
103
+ return db
104
+ } catch {
105
+ console.warn(
106
+ 'Data store: in-memory — database unreachable. Run `docker compose up -d` (and `npm run db:migrate && npm run db:seed`) for MySQL.',
107
+ )
108
+ return createMemoryStore()
109
+ }
110
+ })()
111
+ }
112
+ return backend
113
+ }
114
+
115
+ export const carStore: CarStore = {
116
+ async list() {
117
+ return (await resolveBackend()).list()
118
+ },
119
+ async get(id) {
120
+ return (await resolveBackend()).get(id)
121
+ },
122
+ async create(input) {
123
+ return (await resolveBackend()).create(input)
124
+ },
125
+ async remove(id) {
126
+ return (await resolveBackend()).remove(id)
127
+ },
128
+ }
129
+ // #endif
130
+ // #if !db
131
+ export const carStore: CarStore = createMemoryStore()
132
+ // #endif
@@ -0,0 +1,17 @@
1
+
2
+ @import "tailwindcss";
3
+
4
+ * {
5
+ box-sizing: border-box;
6
+ }
7
+
8
+ html,
9
+ body,
10
+ #app {
11
+ min-height: 100%;
12
+ }
13
+
14
+ body {
15
+ margin: 0;
16
+ }
17
+
@@ -0,0 +1,28 @@
1
+ {
2
+ "include": ["**/*.ts", "**/*.tsx"],
3
+ "compilerOptions": {
4
+ "target": "ES2022",
5
+ "jsx": "react-jsx",
6
+ "module": "ESNext",
7
+ "paths": {
8
+ "#/*": ["./src/*"],
9
+ "@/*": ["./src/*"]
10
+ },
11
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
12
+ "types": ["vite/client"],
13
+
14
+ /* Bundler mode */
15
+ "moduleResolution": "bundler",
16
+ "allowImportingTsExtensions": true,
17
+ "verbatimModuleSyntax": true,
18
+ "noEmit": true,
19
+
20
+ /* Linting */
21
+ "skipLibCheck": true,
22
+ "strict": true,
23
+ "noUnusedLocals": true,
24
+ "noUnusedParameters": true,
25
+ "noFallthroughCasesInSwitch": true,
26
+ "noUncheckedSideEffectImports": true
27
+ }
28
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "target": "react"
3
+ }
@@ -0,0 +1,14 @@
1
+ import { defineConfig } from 'vite'
2
+ import { devtools } from '@tanstack/devtools-vite'
3
+
4
+ import { tanstackStart } from '@tanstack/react-start/plugin/vite'
5
+
6
+ import viteReact from '@vitejs/plugin-react'
7
+ import tailwindcss from '@tailwindcss/vite'
8
+
9
+ const config = defineConfig({
10
+ resolve: { tsconfigPaths: true },
11
+ plugins: [devtools(), tailwindcss(), tanstackStart(), viteReact()],
12
+ })
13
+
14
+ export default config