@kevinmarrec/create-app 0.8.0 → 0.10.0

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 (66) hide show
  1. package/README.md +4 -0
  2. package/dist/index.js +1 -1
  3. package/package.json +14 -16
  4. package/template/.docker/traefik/bin/install_cert +18 -0
  5. package/template/.docker/traefik/bin/uninstall_cert +9 -0
  6. package/template/.docker/traefik/dynamic/tls.yml +4 -0
  7. package/template/.github/scripts/build-stats.md.ts +71 -0
  8. package/template/.github/workflows/ci.yml +16 -0
  9. package/template/.gitignore +2 -0
  10. package/template/.npmrc +0 -1
  11. package/template/.vscode/settings.json +1 -1
  12. package/template/README.md +330 -0
  13. package/template/api/.env.development +4 -0
  14. package/template/{server → api}/package.json +8 -7
  15. package/template/{server → api}/src/auth/index.ts +4 -1
  16. package/template/{server → api}/src/database/drizzle/config.ts +3 -2
  17. package/template/{server → api}/src/database/index.ts +6 -4
  18. package/template/api/src/env.ts +67 -0
  19. package/template/api/src/main.ts +39 -0
  20. package/template/{server → api}/src/orpc/context.ts +4 -3
  21. package/template/api/src/orpc/index.ts +27 -0
  22. package/template/{server → api}/src/orpc/middlewares/auth.ts +2 -1
  23. package/template/api/src/orpc/plugins/error.ts +17 -0
  24. package/template/{server → api}/src/orpc/router/index.ts +13 -1
  25. package/template/{server → api}/src/utils/cors.ts +8 -5
  26. package/template/{server → api}/src/utils/logger.ts +3 -1
  27. package/template/app/.env +1 -0
  28. package/template/{client → app}/index.html +1 -0
  29. package/template/{client → app}/package.json +9 -10
  30. package/template/{client → app}/src/App.vue +2 -1
  31. package/template/{client → app}/src/composables/content.ts +2 -1
  32. package/template/{client → app}/src/lib/orpc.ts +3 -1
  33. package/template/{client → app}/src/main.ts +1 -1
  34. package/template/{client → app}/vite.config.ts +1 -1
  35. package/template/compose.yaml +120 -12
  36. package/template/knip.config.ts +8 -10
  37. package/template/package.json +12 -11
  38. package/template/tsconfig.json +2 -2
  39. package/template/.scripts/dev.ts +0 -8
  40. package/template/client/.env +0 -1
  41. package/template/server/.env.development +0 -4
  42. package/template/server/src/env.d.ts +0 -11
  43. package/template/server/src/main.ts +0 -51
  44. package/template/server/src/orpc/handler.ts +0 -34
  45. package/template/server/src/orpc/index.ts +0 -18
  46. package/template/server/src/orpc/middlewares/index.ts +0 -1
  47. /package/template/{server → api}/src/database/migrations/0000_init.sql +0 -0
  48. /package/template/{server → api}/src/database/migrations/meta/0000_snapshot.json +0 -0
  49. /package/template/{server → api}/src/database/migrations/meta/_journal.json +0 -0
  50. /package/template/{server → api}/src/database/schema/accounts.ts +0 -0
  51. /package/template/{server → api}/src/database/schema/index.ts +0 -0
  52. /package/template/{server → api}/src/database/schema/sessions.ts +0 -0
  53. /package/template/{server → api}/src/database/schema/users.ts +0 -0
  54. /package/template/{server → api}/src/database/schema/verifications.ts +0 -0
  55. /package/template/{server → api}/tsconfig.json +0 -0
  56. /package/template/{client → app}/public/favicon.svg +0 -0
  57. /package/template/{client → app}/public/robots.txt +0 -0
  58. /package/template/{client → app}/src/components/.gitkeep +0 -0
  59. /package/template/{client → app}/src/composables/auth.ts +0 -0
  60. /package/template/{client → app}/src/composables/index.ts +0 -0
  61. /package/template/{client → app}/src/env.d.ts +0 -0
  62. /package/template/{client → app}/src/locales/en.yml +0 -0
  63. /package/template/{client → app}/src/locales/fr.yml +0 -0
  64. /package/template/{client → app}/tsconfig.json +0 -0
  65. /package/template/{client → app}/uno.config.ts +0 -0
  66. /package/template/{client → app}/wrangler.json +0 -0
@@ -0,0 +1,67 @@
1
+ import * as v from 'valibot'
2
+
3
+ const schema = v.object({
4
+ auth: v.object({
5
+ secret: v.string(),
6
+ }),
7
+ cors: v.object({
8
+ allowedOrigins: v.pipe(
9
+ v.optional(v.string(), ''),
10
+ v.transform(input => input.split(',').filter(Boolean)),
11
+ ),
12
+ }),
13
+ database: v.object({
14
+ url: v.string(),
15
+ }),
16
+ log: v.object({
17
+ level: v.optional(v.union([
18
+ v.literal('fatal'),
19
+ v.literal('error'),
20
+ v.literal('warn'),
21
+ v.literal('info'),
22
+ v.literal('debug'),
23
+ v.literal('trace'),
24
+ v.literal('silent'),
25
+ ]), 'info'),
26
+ }),
27
+ server: v.object({
28
+ host: v.optional(v.string(), '0.0.0.0'),
29
+ port: v.pipe(
30
+ v.optional(v.string(), '4000'),
31
+ v.decimal(),
32
+ v.transform(input => Number(input)),
33
+ ),
34
+ }),
35
+ })
36
+
37
+ const parsed = v.safeParse(schema, {
38
+ auth: {
39
+ secret: import.meta.env.AUTH_SECRET,
40
+ },
41
+ cors: {
42
+ allowedOrigins: import.meta.env.ALLOWED_ORIGINS,
43
+ },
44
+ database: {
45
+ url: import.meta.env.DATABASE_URL,
46
+ },
47
+ log: {
48
+ level: import.meta.env.LOG_LEVEL,
49
+ },
50
+ server: {
51
+ host: import.meta.env.HOST,
52
+ port: import.meta.env.PORT,
53
+ },
54
+ })
55
+
56
+ if (!parsed.success) {
57
+ throw new Error([
58
+ '🚨 Environment Validation Error!',
59
+ ...parsed.issues.map(issue =>
60
+ issue.path
61
+ ? `[${issue.path.map(p => p.key).join('.')}] ${issue.message}`
62
+ : issue.message,
63
+ ),
64
+ ].join('\n'))
65
+ }
66
+
67
+ export const env = parsed.output
@@ -0,0 +1,39 @@
1
+ import process from 'node:process'
2
+
3
+ import { createBetterAuth } from './auth'
4
+ import { db } from './database'
5
+ import { env } from './env'
6
+ import { createRpc } from './orpc'
7
+ import { router } from './orpc/router'
8
+ import { cors } from './utils/cors'
9
+ import { logger } from './utils/logger'
10
+
11
+ const auth = createBetterAuth({ db, logger })
12
+ const rpc = createRpc({ auth, db, logger }, router)
13
+
14
+ const server = Bun.serve({
15
+ hostname: env.server.host,
16
+ port: env.server.port,
17
+ routes: {
18
+ '/health': () => new Response('OK', { status: 200 }),
19
+ '/auth/*': cors(auth.handler),
20
+ '/rpc/*': cors(rpc.handler),
21
+ },
22
+ error(error) {
23
+ logger.error(error)
24
+ return new Response('Internal Server Error', { status: 500 })
25
+ },
26
+ })
27
+
28
+ logger.info(`Listening on ${server.url}`)
29
+
30
+ // Graceful Shutdown
31
+
32
+ async function gracefulShutdown() {
33
+ logger.info('Gracefully shutting down...')
34
+ await server.stop()
35
+ process.exit(0)
36
+ }
37
+
38
+ process.on('SIGINT', gracefulShutdown)
39
+ process.on('SIGTERM', gracefulShutdown)
@@ -1,7 +1,8 @@
1
1
  import type { RequestHeadersPluginContext, ResponseHeadersPluginContext } from '@orpc/server/plugins'
2
- import type { Auth } from '@server/auth'
3
- import type { Database } from '@server/database'
4
- import type { Logger } from '@server/utils/logger'
2
+
3
+ import type { Auth } from '../auth'
4
+ import type { Database } from '../database'
5
+ import type { Logger } from '../utils/logger'
5
6
 
6
7
  export interface Context extends RequestHeadersPluginContext, ResponseHeadersPluginContext {
7
8
  auth: Auth
@@ -0,0 +1,27 @@
1
+ import type { Router } from '@orpc/server'
2
+ import { RPCHandler } from '@orpc/server/fetch'
3
+ import { RequestHeadersPlugin, ResponseHeadersPlugin } from '@orpc/server/plugins'
4
+
5
+ import type { Context } from './context'
6
+ import { ErrorPlugin } from './plugins/error'
7
+
8
+ export function createRpc<T extends Context>(context: T, router: Router<any, T>) {
9
+ const handler = new RPCHandler<T>(router, {
10
+ plugins: [
11
+ new ErrorPlugin(),
12
+ new RequestHeadersPlugin(),
13
+ new ResponseHeadersPlugin(),
14
+ ],
15
+ })
16
+
17
+ return {
18
+ handler: async (req: Request) => {
19
+ const { matched, response } = await handler.handle(req, {
20
+ prefix: '/rpc',
21
+ context,
22
+ })
23
+
24
+ return matched ? response : new Response('Not found', { status: 404 })
25
+ },
26
+ }
27
+ }
@@ -1,5 +1,6 @@
1
1
  import { ORPCError, os } from '@orpc/server'
2
- import type { Context } from '@server/orpc'
2
+
3
+ import type { Context } from '../context'
3
4
 
4
5
  export const authMiddleware = os
5
6
  .$context<Context>()
@@ -0,0 +1,17 @@
1
+ import { onError, ORPCError } from '@orpc/server'
2
+ import type { StandardHandlerOptions, StandardHandlerPlugin } from '@orpc/server/standard'
3
+
4
+ import type { Context } from '../context'
5
+
6
+ export class ErrorPlugin<T extends Context> implements StandardHandlerPlugin<T> {
7
+ init(options: StandardHandlerOptions<T>): void {
8
+ options.clientInterceptors ??= []
9
+ options.clientInterceptors.unshift(onError((error, { context }) => {
10
+ if (error instanceof ORPCError) {
11
+ throw error
12
+ }
13
+
14
+ context.logger.error(error)
15
+ }))
16
+ }
17
+ }
@@ -1,8 +1,20 @@
1
- import { authed, pub } from '@server/orpc'
1
+ import { os } from '@orpc/server'
2
2
  import * as v from 'valibot'
3
3
 
4
+ import type { Context } from '../context'
5
+ import { authMiddleware } from '../middlewares/auth'
6
+
4
7
  export type { RouterClient } from '@orpc/server'
5
8
 
9
+ const pub = os
10
+ .$context<Context>()
11
+ .errors({
12
+ UNAUTHORIZED: { status: 401 },
13
+ })
14
+
15
+ const authed = pub
16
+ .use(authMiddleware)
17
+
6
18
  export const router = {
7
19
  public: pub
8
20
  .input(v.any())
@@ -1,10 +1,10 @@
1
- export function cors(handler: (req: Request) => Promise<Response>) {
2
- const allowedOrigins = import.meta.env.ALLOWED_ORIGINS.split(',')
1
+ import { env } from '../env'
3
2
 
3
+ export function cors(handler: (req: Request) => Promise<Response>) {
4
4
  return async (req: Request) => {
5
- const origin = req.headers.get('origin') ?? ''
5
+ const origin = req.headers.get('origin')
6
6
 
7
- if (!origin || !allowedOrigins.includes(origin)) {
7
+ if (origin && !env.cors.allowedOrigins.includes(origin)) {
8
8
  return new Response('Origin not allowed', { status: 403 })
9
9
  }
10
10
 
@@ -19,7 +19,10 @@ export function cors(handler: (req: Request) => Promise<Response>) {
19
19
  }
20
20
 
21
21
  response.headers.append('Access-Control-Allow-Credentials', 'true')
22
- response.headers.append('Access-Control-Allow-Origin', origin)
22
+
23
+ if (origin) {
24
+ response.headers.append('Access-Control-Allow-Origin', origin)
25
+ }
23
26
 
24
27
  return response
25
28
  }
@@ -1,7 +1,9 @@
1
1
  import pino from 'pino'
2
2
 
3
+ import { env } from '../env'
4
+
3
5
  export const logger = pino({
4
- level: import.meta.env.LOG_LEVEL ?? 'info',
6
+ level: env.log.level,
5
7
  base: {},
6
8
  })
7
9
 
@@ -0,0 +1 @@
1
+ VITE_API_URL=https://api.dev.localhost
@@ -4,6 +4,7 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="description" content="Description" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <meta name="color-scheme" content="dark light" />
7
8
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
8
9
  <title>Title</title>
9
10
  </head>
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "client",
2
+ "name": "app",
3
3
  "type": "module",
4
4
  "private": true,
5
5
  "scripts": {
@@ -10,26 +10,25 @@
10
10
  },
11
11
  "dependencies": {
12
12
  "@kevinmarrec/vue-i18n": "^1.1.3",
13
- "@orpc/client": "^1.10.4",
14
- "@orpc/tanstack-query": "1.10.3",
15
- "@tanstack/query-core": "^5.90.7",
16
- "@tanstack/vue-query": "^5.90.7",
13
+ "@orpc/client": "^1.11.2",
14
+ "@orpc/tanstack-query": "1.11.2",
15
+ "@tanstack/query-core": "^5.90.10",
16
+ "@tanstack/vue-query": "^5.91.2",
17
17
  "@unhead/vue": "^2.0.19",
18
18
  "@vueuse/core": "^14.0.0",
19
19
  "better-auth": "^1.3.34",
20
- "unocss": "^66.5.4",
21
- "vue": "^3.5.22"
20
+ "unocss": "^66.5.6",
21
+ "vue": "^3.5.24"
22
22
  },
23
23
  "devDependencies": {
24
- "@kevinmarrec/unocss-config": "^1.5.4",
24
+ "@kevinmarrec/unocss-config": "^1.5.6",
25
25
  "@kevinmarrec/vite-plugin-dark-mode": "^1.1.2",
26
26
  "@modyfi/vite-plugin-yaml": "^1.1.1",
27
27
  "@unhead/addons": "^2.0.19",
28
- "@unocss/vite": "^66.5.4",
29
28
  "@vitejs/plugin-vue": "^6.0.1",
30
29
  "beasties": "^0.3.5",
31
30
  "rollup-plugin-visualizer": "^6.0.5",
32
- "vite": "^7.2.0",
31
+ "vite": "^7.2.2",
33
32
  "vite-plugin-vue-devtools": "^8.0.3",
34
33
  "vite-ssg": "^28.2.2",
35
34
  "vite-tsconfig-paths": "^5.1.4"
@@ -1,7 +1,8 @@
1
1
  <script setup lang="ts">
2
- import { useAuth, useContent, useHead, useI18n } from '@client/composables'
3
2
  import { ref } from 'vue'
4
3
 
4
+ import { useAuth, useContent, useHead, useI18n } from '~/app/composables'
5
+
5
6
  const { t } = useI18n()
6
7
  useHead({
7
8
  title: () => t('title'),
@@ -1,6 +1,7 @@
1
- import { orpc } from '@client/lib/orpc'
2
1
  import { useQuery } from '@tanstack/vue-query'
3
2
 
3
+ import { orpc } from '~/app/lib/orpc'
4
+
4
5
  export function useContent() {
5
6
  const publicContent = useQuery(orpc.public.queryOptions({})).data
6
7
  const privateContent = useQuery(orpc.private.queryOptions({})).data
@@ -1,7 +1,8 @@
1
1
  import { createORPCClient } from '@orpc/client'
2
2
  import { RPCLink } from '@orpc/client/fetch'
3
3
  import { createTanstackQueryUtils } from '@orpc/tanstack-query'
4
- import type { Router, RouterClient } from '@server/orpc/router'
4
+
5
+ import type { Router, RouterClient } from '~/api/orpc/router'
5
6
 
6
7
  const link = new RPCLink({
7
8
  url: `${import.meta.env.VITE_API_URL}/rpc`,
@@ -9,6 +10,7 @@ const link = new RPCLink({
9
10
  globalThis.fetch(request, {
10
11
  ...init,
11
12
  credentials: 'include',
13
+ signal: AbortSignal.timeout(30_000),
12
14
  }),
13
15
  })
14
16
 
@@ -4,7 +4,7 @@ import { ViteSSG } from 'vite-ssg/single-page'
4
4
 
5
5
  import App from './App.vue'
6
6
 
7
- import 'uno.css'
7
+ import 'virtual:uno.css'
8
8
 
9
9
  export const createApp = ViteSSG(App, async ({ app }) => {
10
10
  const i18n = await createI18n({
@@ -3,9 +3,9 @@ import process from 'node:process'
3
3
  import darkMode from '@kevinmarrec/vite-plugin-dark-mode'
4
4
  import yaml from '@modyfi/vite-plugin-yaml'
5
5
  import unhead from '@unhead/addons/vite'
6
- import unocss from '@unocss/vite'
7
6
  import vue from '@vitejs/plugin-vue'
8
7
  import { visualizer } from 'rollup-plugin-visualizer'
8
+ import unocss from 'unocss/vite'
9
9
  import { defineConfig } from 'vite'
10
10
  import devtools from 'vite-plugin-vue-devtools'
11
11
  import tsconfigPaths from 'vite-tsconfig-paths'
@@ -1,22 +1,130 @@
1
1
  x-common: &common
2
- working_dir: /app
3
2
  volumes:
4
- - ./:/app
3
+ - ./:/code
4
+ working_dir: /code
5
5
  user: 1000:1000
6
6
 
7
7
  services:
8
- server:
8
+ traefik:
9
+ image: traefik:v3.6
10
+ container_name: traefik
11
+ restart: unless-stopped
12
+ security_opt:
13
+ - no-new-privileges:true
14
+ command:
15
+ # General configuration
16
+ - --api.dashboard=true
17
+ - --ping=true
18
+ - --log.level=INFO
19
+ # Entrypoints for HTTP and HTTPS
20
+ - --entrypoints.websecure.address=:443
21
+ - --entrypoints.web.address=:80
22
+ # Redirect HTTP to HTTPS
23
+ - --entrypoints.web.http.redirections.entrypoint.to=websecure
24
+ - --entrypoints.web.http.redirections.entrypoint.scheme=https
25
+ # Providers (Docker & File for dynamic config)
26
+ - --providers.docker=true
27
+ - --providers.docker.exposedbydefault=false
28
+ - --providers.file.directory=/etc/traefik/dynamic
29
+ - --providers.file.watch=true
30
+ ports:
31
+ - 80:80
32
+ - 443:443
33
+ volumes:
34
+ - /var/run/docker.sock:/var/run/docker.sock:ro
35
+ - ./.docker/traefik/dynamic:/etc/traefik/dynamic:ro # Mount the dynamic config directory
36
+ - ./.docker/traefik/certs:/certs:ro # Mount the certs directory
37
+ healthcheck:
38
+ test: [CMD-SHELL, traefik healthcheck --ping]
39
+ interval: 1s
40
+ timeout: 1s
41
+ retries: 10
42
+ labels:
43
+ traefik.enable: 'true'
44
+ traefik.http.routers.traefik.rule: Host(`traefik.dev.localhost`)
45
+ traefik.http.routers.traefik.entrypoints: websecure
46
+ traefik.http.routers.traefik.tls: 'true'
47
+ traefik.http.routers.traefik.service: api@internal
48
+
49
+ postgres:
50
+ image: postgres:18-alpine
51
+ container_name: postgres
52
+ environment:
53
+ - POSTGRES_USER=user
54
+ - POSTGRES_PASSWORD=password
55
+ - POSTGRES_DB=app
56
+ ports:
57
+ - 5432:5432
58
+ volumes:
59
+ - postgres_data:/var/lib/postgresql/data
60
+ healthcheck:
61
+ test: [CMD-SHELL, "psql postgresql://user:password@postgres:5432/app -c 'SELECT 1' 2> /dev/null"]
62
+ interval: 1s
63
+ timeout: 1s
64
+ retries: 10
65
+
66
+ metabase:
67
+ image: metabase/metabase:v0.57.x
68
+ container_name: metabase
69
+ environment:
70
+ - MB_DB_TYPE=h2
71
+ - MB_DB_FILE=/var/lib/metabase/metabase.db
72
+ - MB_SITE_URL=https://metabase.dev.localhost
73
+ volumes:
74
+ - metabase_data:/var/lib/metabase
75
+ healthcheck:
76
+ test: [CMD-SHELL, curl -f http://localhost:3000/api/health]
77
+ interval: 1s
78
+ timeout: 1s
79
+ retries: 20
80
+ labels:
81
+ traefik.enable: 'true'
82
+ traefik.http.routers.metabase.rule: Host(`metabase.dev.localhost`)
83
+ traefik.http.routers.metabase.entrypoints: websecure
84
+ traefik.http.routers.metabase.tls: 'true'
85
+ traefik.http.services.metabase.loadbalancer.server.port: '3000'
86
+
87
+ api:
9
88
  <<: *common
89
+ depends_on:
90
+ traefik:
91
+ condition: service_healthy
92
+ postgres:
93
+ condition: service_healthy
94
+ container_name: api
10
95
  image: oven/bun:1-alpine
11
- command: [bun, --cwd, server, dev]
12
- ports:
13
- - 4000:4000
96
+ init: true
97
+ command: [bun, --cwd, api, dev]
98
+ environment:
99
+ - FORCE_COLOR=1
100
+ labels:
101
+ traefik.enable: 'true'
102
+ traefik.http.routers.api.rule: Host(`api.dev.localhost`)
103
+ traefik.http.routers.api.entrypoints: websecure
104
+ traefik.http.routers.api.tls: 'true'
105
+ traefik.http.services.api.loadbalancer.server.port: '4000'
14
106
 
15
- client:
107
+ app:
16
108
  <<: *common
17
109
  depends_on:
18
- - server
19
- image: imbios/bun-node:22-alpine
20
- command: [bun, --cwd, client, dev, --host, 0.0.0.0]
21
- ports:
22
- - 5173:5173
110
+ - api
111
+ container_name: app
112
+ image: imbios/bun-node:24-alpine
113
+ init: true
114
+ command: [bun, --cwd, app, dev, --host, 0.0.0.0]
115
+ environment:
116
+ - FORCE_COLOR=1
117
+ labels:
118
+ traefik.enable: 'true'
119
+ traefik.http.routers.app.rule: Host(`app.dev.localhost`)
120
+ traefik.http.routers.app.entrypoints: websecure
121
+ traefik.http.routers.app.tls: 'true'
122
+ traefik.http.services.app.loadbalancer.server.port: '5173'
123
+
124
+ networks:
125
+ default:
126
+ name: dev
127
+
128
+ volumes:
129
+ postgres_data:
130
+ metabase_data:
@@ -1,7 +1,9 @@
1
1
  import type { KnipConfig } from 'knip'
2
2
 
3
+ // Required for Knip to pass
3
4
  Object.assign(import.meta.env, {
4
- DATABASE_URL: 'foo.db',
5
+ AUTH_SECRET: '',
6
+ DATABASE_URL: '',
5
7
  })
6
8
 
7
9
  export default {
@@ -10,19 +12,15 @@ export default {
10
12
  '.': {
11
13
  entry: ['*.config.ts'],
12
14
  },
13
- 'client': {
14
- entry: ['src/main.ts'],
15
- ignoreDependencies: [
16
- '@vueuse/core',
17
- 'uno.css',
18
- ],
19
- },
20
- 'server': {
15
+ 'api': {
21
16
  drizzle: {
22
17
  config: 'src/database/drizzle/config.ts',
23
18
  },
19
+ },
20
+ 'app': {
21
+ entry: ['src/main.ts'],
24
22
  ignoreDependencies: [
25
- 'pino-pretty',
23
+ '@vueuse/core',
26
24
  ],
27
25
  },
28
26
  },
@@ -1,14 +1,14 @@
1
1
  {
2
- "name": "app",
2
+ "name": "project",
3
3
  "type": "module",
4
4
  "private": true,
5
- "packageManager": "bun@1.3.1",
5
+ "packageManager": "bun@1.3.2",
6
6
  "engines": {
7
7
  "node": "lts/*"
8
8
  },
9
9
  "workspaces": [
10
- "client",
11
- "server"
10
+ "api",
11
+ "app"
12
12
  ],
13
13
  "scripts": {
14
14
  "check": "bun run check:eslint && bun run check:stylelint && bun run check:unused && bun run check:types",
@@ -16,20 +16,21 @@
16
16
  "check:stylelint": "stylelint '**/*.{css,scss,vue}' --ignorePath .gitignore --cache",
17
17
  "check:types": "vue-tsc --noEmit",
18
18
  "check:unused": "knip -n",
19
- "dev": "bun .scripts/dev.ts",
20
19
  "lint": "bun run check:eslint && bun run check:stylelint",
21
20
  "lint:inspect": "bunx @eslint/config-inspector",
22
21
  "update": "bunx taze -I -rwi"
23
22
  },
24
23
  "devDependencies": {
25
- "@kevinmarrec/eslint-config": "^1.5.4",
26
- "@kevinmarrec/stylelint-config": "^1.5.4",
27
- "@kevinmarrec/tsconfig": "^1.5.4",
28
- "concurrently": "^9.2.1",
24
+ "@kevinmarrec/eslint-config": "^1.5.6",
25
+ "@kevinmarrec/stylelint-config": "^1.5.6",
26
+ "@kevinmarrec/tsconfig": "^1.5.6",
29
27
  "eslint": "^9.39.1",
30
- "knip": "^5.67.1",
28
+ "filesize": "^11.0.13",
29
+ "knip": "^5.69.1",
31
30
  "stylelint": "^16.25.0",
31
+ "tinyexec": "^1.0.2",
32
+ "tinyglobby": "^0.2.15",
32
33
  "typescript": "~5.9.3",
33
- "vue-tsc": "^3.1.3"
34
+ "vue-tsc": "^3.1.4"
34
35
  }
35
36
  }
@@ -2,8 +2,8 @@
2
2
  "extends": "@kevinmarrec/tsconfig",
3
3
  "compilerOptions": {
4
4
  "paths": {
5
- "@client/*": ["./client/src/*"],
6
- "@server/*": ["./server/src/*"]
5
+ "~/api/*": ["./api/src/*"],
6
+ "~/app/*": ["./app/src/*"]
7
7
  }
8
8
  },
9
9
  "exclude": ["**/dist/**"]
@@ -1,8 +0,0 @@
1
- import concurrently, { type ConcurrentlyCommandInput } from 'concurrently'
2
-
3
- const commandInputs: ConcurrentlyCommandInput[] = [
4
- { name: 'server', command: `bun --cwd server dev | pino-pretty`, prefixColor: 'blue' },
5
- { name: 'client', command: `bun --cwd client dev`, prefixColor: 'green' },
6
- ]
7
-
8
- concurrently(commandInputs)
@@ -1 +0,0 @@
1
- VITE_API_URL=http://localhost:4000
@@ -1,4 +0,0 @@
1
- ALLOWED_ORIGINS=http://localhost:5173,http://localhost:5174
2
- AUTH_SECRET=foo
3
- DATABASE_URL=.db
4
- NODE_ENV=development
@@ -1,11 +0,0 @@
1
- interface ImportMetaEnv {
2
- readonly ALLOWED_ORIGINS: string
3
- readonly AUTH_SECRET: string
4
- readonly DATABASE_URL: string
5
- readonly LOG_LEVEL: string
6
- readonly NODE_ENV: string
7
- }
8
-
9
- interface ImportMeta {
10
- readonly env: ImportMetaEnv
11
- }