@korajs/cli 0.4.0 → 0.6.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 (253) hide show
  1. package/dist/bin.cjs +1636 -601
  2. package/dist/bin.cjs.map +1 -1
  3. package/dist/bin.js +1086 -139
  4. package/dist/bin.js.map +1 -1
  5. package/dist/{chunk-MVP5PDT4.js → chunk-EEZNRI5W.js} +51 -6
  6. package/dist/chunk-EEZNRI5W.js.map +1 -0
  7. package/dist/{chunk-YGVO4POI.js → chunk-Q2FBCOQD.js} +27 -15
  8. package/dist/chunk-Q2FBCOQD.js.map +1 -0
  9. package/dist/{chunk-CMSX76KM.js → chunk-VLTPEATY.js} +172 -99
  10. package/dist/chunk-VLTPEATY.js.map +1 -0
  11. package/dist/create.cjs +130 -54
  12. package/dist/create.cjs.map +1 -1
  13. package/dist/create.js +2 -2
  14. package/dist/index.cjs +143 -62
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +8 -6
  17. package/dist/index.d.ts +8 -6
  18. package/dist/index.js +2 -2
  19. package/package.json +9 -3
  20. package/templates/react-basic/README.md.hbs +10 -1
  21. package/templates/react-basic/src/App.tsx +112 -126
  22. package/templates/react-basic/src/index.css +165 -159
  23. package/templates/react-basic/src/kora-worker.ts +0 -1
  24. package/templates/react-basic/src/main.tsx +12 -12
  25. package/templates/react-basic/src/modules/todos/todo.mutations.ts +25 -0
  26. package/templates/react-basic/src/modules/todos/todo.queries.ts +5 -0
  27. package/templates/react-basic/src/modules/todos/todo.schema.ts +10 -0
  28. package/templates/react-basic/src/modules/todos/useTodos.ts +31 -0
  29. package/templates/react-basic/src/schema.ts +6 -12
  30. package/templates/react-basic/src/vite-env.d.ts +17 -0
  31. package/templates/react-basic/{tsconfig.json → tsconfig.json.hbs} +1 -2
  32. package/templates/react-basic/vite.config.ts +57 -50
  33. package/templates/react-sync/.env.example +19 -0
  34. package/templates/react-sync/README.md.hbs +43 -1
  35. package/templates/react-sync/package.json.hbs +3 -0
  36. package/templates/react-sync/server.ts +90 -26
  37. package/templates/react-sync/src/App.tsx +132 -130
  38. package/templates/react-sync/src/auth.ts +25 -0
  39. package/templates/react-sync/src/index.css +212 -165
  40. package/templates/react-sync/src/kora-worker.ts +0 -1
  41. package/templates/react-sync/src/main.tsx +34 -18
  42. package/templates/react-sync/src/modules/todos/todo.mutations.ts +25 -0
  43. package/templates/react-sync/src/modules/todos/todo.queries.ts +5 -0
  44. package/templates/react-sync/src/modules/todos/todo.schema.ts +10 -0
  45. package/templates/react-sync/src/modules/todos/useTodos.ts +31 -0
  46. package/templates/react-sync/src/schema.ts +6 -12
  47. package/templates/react-sync/src/vite-env.d.ts +17 -0
  48. package/templates/react-sync/{tsconfig.json → tsconfig.json.hbs} +1 -2
  49. package/templates/react-sync/vite.config.ts +67 -60
  50. package/templates/react-tailwind/README.md.hbs +10 -1
  51. package/templates/react-tailwind/src/App.tsx +186 -197
  52. package/templates/react-tailwind/src/index.css +3 -3
  53. package/templates/react-tailwind/src/kora-worker.ts +0 -1
  54. package/templates/react-tailwind/src/main.tsx +19 -12
  55. package/templates/react-tailwind/src/modules/todos/todo.mutations.ts +25 -0
  56. package/templates/react-tailwind/src/modules/todos/todo.queries.ts +5 -0
  57. package/templates/react-tailwind/src/modules/todos/todo.schema.ts +10 -0
  58. package/templates/react-tailwind/src/modules/todos/useTodos.ts +31 -0
  59. package/templates/react-tailwind/src/schema.ts +6 -12
  60. package/templates/react-tailwind/src/vite-env.d.ts +17 -0
  61. package/templates/react-tailwind/{tsconfig.json → tsconfig.json.hbs} +1 -2
  62. package/templates/react-tailwind/vite.config.ts +57 -50
  63. package/templates/react-tailwind-sync/.env.example +19 -0
  64. package/templates/react-tailwind-sync/README.md.hbs +43 -1
  65. package/templates/react-tailwind-sync/package.json.hbs +3 -0
  66. package/templates/react-tailwind-sync/server.ts +90 -26
  67. package/templates/react-tailwind-sync/src/App.tsx +246 -222
  68. package/templates/react-tailwind-sync/src/auth.ts +25 -0
  69. package/templates/react-tailwind-sync/src/index.css +3 -3
  70. package/templates/react-tailwind-sync/src/kora-worker.ts +0 -1
  71. package/templates/react-tailwind-sync/src/main.tsx +48 -18
  72. package/templates/react-tailwind-sync/src/modules/todos/todo.mutations.ts +25 -0
  73. package/templates/react-tailwind-sync/src/modules/todos/todo.queries.ts +5 -0
  74. package/templates/react-tailwind-sync/src/modules/todos/todo.schema.ts +10 -0
  75. package/templates/react-tailwind-sync/src/modules/todos/useTodos.ts +31 -0
  76. package/templates/react-tailwind-sync/src/schema.ts +6 -12
  77. package/templates/react-tailwind-sync/src/vite-env.d.ts +17 -0
  78. package/templates/react-tailwind-sync/{tsconfig.json → tsconfig.json.hbs} +1 -2
  79. package/templates/react-tailwind-sync/vite.config.ts +67 -60
  80. package/templates/svelte-basic/.env.example +3 -0
  81. package/templates/svelte-basic/README.md.hbs +62 -0
  82. package/templates/svelte-basic/index.html.hbs +12 -0
  83. package/templates/svelte-basic/kora.config.ts +12 -0
  84. package/templates/svelte-basic/package.json.hbs +27 -0
  85. package/templates/svelte-basic/src/App.svelte +131 -0
  86. package/templates/svelte-basic/src/Root.svelte +14 -0
  87. package/templates/svelte-basic/src/index.css +287 -0
  88. package/templates/svelte-basic/src/kora-worker.ts +9 -0
  89. package/templates/svelte-basic/src/main.ts +16 -0
  90. package/templates/svelte-basic/src/modules/todos/todo.mutations.ts +25 -0
  91. package/templates/svelte-basic/src/modules/todos/todo.queries.ts +5 -0
  92. package/templates/svelte-basic/src/modules/todos/todo.schema.ts +10 -0
  93. package/templates/svelte-basic/src/modules/todos/useTodos.ts +25 -0
  94. package/templates/svelte-basic/src/schema.ts +9 -0
  95. package/templates/svelte-basic/src/vite-env.d.ts +12 -0
  96. package/templates/svelte-basic/svelte.config.js +5 -0
  97. package/templates/svelte-basic/tsconfig.json.hbs +14 -0
  98. package/templates/svelte-basic/vite.config.ts +52 -0
  99. package/templates/svelte-sync/.env.example +25 -0
  100. package/templates/svelte-sync/README.md.hbs +105 -0
  101. package/templates/svelte-sync/index.html.hbs +12 -0
  102. package/templates/svelte-sync/kora.config.ts +17 -0
  103. package/templates/svelte-sync/package.json.hbs +43 -0
  104. package/templates/svelte-sync/server.ts +90 -0
  105. package/templates/svelte-sync/src/App.svelte +154 -0
  106. package/templates/svelte-sync/src/Root.svelte +22 -0
  107. package/templates/svelte-sync/src/auth.ts +25 -0
  108. package/templates/svelte-sync/src/index.css +339 -0
  109. package/templates/svelte-sync/src/kora-worker.ts +9 -0
  110. package/templates/svelte-sync/src/main.ts +32 -0
  111. package/templates/svelte-sync/src/modules/todos/todo.mutations.ts +25 -0
  112. package/templates/svelte-sync/src/modules/todos/todo.queries.ts +5 -0
  113. package/templates/svelte-sync/src/modules/todos/todo.schema.ts +10 -0
  114. package/templates/svelte-sync/src/modules/todos/useTodos.ts +25 -0
  115. package/templates/svelte-sync/src/schema.ts +9 -0
  116. package/templates/svelte-sync/src/vite-env.d.ts +21 -0
  117. package/templates/svelte-sync/svelte.config.js +5 -0
  118. package/templates/svelte-sync/tsconfig.json.hbs +14 -0
  119. package/templates/svelte-sync/vite.config.ts +79 -0
  120. package/templates/svelte-tailwind/README.md.hbs +62 -0
  121. package/templates/svelte-tailwind/index.html.hbs +12 -0
  122. package/templates/svelte-tailwind/kora.config.ts +12 -0
  123. package/templates/svelte-tailwind/package.json.hbs +30 -0
  124. package/templates/svelte-tailwind/src/App.svelte +79 -0
  125. package/templates/svelte-tailwind/src/Root.svelte +14 -0
  126. package/templates/svelte-tailwind/src/index.css +7 -0
  127. package/templates/svelte-tailwind/src/kora-worker.ts +9 -0
  128. package/templates/svelte-tailwind/src/main.ts +16 -0
  129. package/templates/svelte-tailwind/src/modules/todos/todo.mutations.ts +25 -0
  130. package/templates/svelte-tailwind/src/modules/todos/todo.queries.ts +5 -0
  131. package/templates/svelte-tailwind/src/modules/todos/todo.schema.ts +10 -0
  132. package/templates/svelte-tailwind/src/modules/todos/useTodos.ts +25 -0
  133. package/templates/svelte-tailwind/src/schema.ts +9 -0
  134. package/templates/svelte-tailwind/src/vite-env.d.ts +12 -0
  135. package/templates/svelte-tailwind/svelte.config.js +5 -0
  136. package/templates/svelte-tailwind/tsconfig.json.hbs +14 -0
  137. package/templates/svelte-tailwind/vite.config.ts +53 -0
  138. package/templates/svelte-tailwind-sync/.env.example +25 -0
  139. package/templates/svelte-tailwind-sync/README.md.hbs +105 -0
  140. package/templates/svelte-tailwind-sync/index.html.hbs +12 -0
  141. package/templates/svelte-tailwind-sync/kora.config.ts +17 -0
  142. package/templates/svelte-tailwind-sync/package.json.hbs +46 -0
  143. package/templates/svelte-tailwind-sync/server.ts +90 -0
  144. package/templates/svelte-tailwind-sync/src/App.svelte +196 -0
  145. package/templates/svelte-tailwind-sync/src/Root.svelte +26 -0
  146. package/templates/svelte-tailwind-sync/src/auth.ts +25 -0
  147. package/templates/svelte-tailwind-sync/src/index.css +7 -0
  148. package/templates/svelte-tailwind-sync/src/kora-worker.ts +9 -0
  149. package/templates/svelte-tailwind-sync/src/main.ts +32 -0
  150. package/templates/svelte-tailwind-sync/src/modules/todos/todo.mutations.ts +25 -0
  151. package/templates/svelte-tailwind-sync/src/modules/todos/todo.queries.ts +5 -0
  152. package/templates/svelte-tailwind-sync/src/modules/todos/todo.schema.ts +10 -0
  153. package/templates/svelte-tailwind-sync/src/modules/todos/useTodos.ts +25 -0
  154. package/templates/svelte-tailwind-sync/src/schema.ts +9 -0
  155. package/templates/svelte-tailwind-sync/src/vite-env.d.ts +21 -0
  156. package/templates/svelte-tailwind-sync/svelte.config.js +5 -0
  157. package/templates/svelte-tailwind-sync/tsconfig.json.hbs +14 -0
  158. package/templates/svelte-tailwind-sync/vite.config.ts +80 -0
  159. package/templates/tauri-react/.env.example +20 -0
  160. package/templates/tauri-react/README.md.hbs +36 -1
  161. package/templates/tauri-react/dev.ts +11 -11
  162. package/templates/tauri-react/package.json.hbs +2 -0
  163. package/templates/tauri-react/server.ts +86 -12
  164. package/templates/tauri-react/src/App.tsx +769 -544
  165. package/templates/tauri-react/src/AppShell.tsx +125 -83
  166. package/templates/tauri-react/src/SetupScreen.tsx +257 -208
  167. package/templates/tauri-react/src/auth.ts +45 -0
  168. package/templates/tauri-react/src/main.tsx +3 -3
  169. package/templates/tauri-react/src/modules/todos/todo.mutations.ts +25 -0
  170. package/templates/tauri-react/src/modules/todos/todo.queries.ts +5 -0
  171. package/templates/tauri-react/src/modules/todos/todo.schema.ts +10 -0
  172. package/templates/tauri-react/src/modules/todos/useTodos.ts +31 -0
  173. package/templates/tauri-react/src/schema.ts +6 -12
  174. package/templates/tauri-react/src/sync-config.ts +47 -47
  175. package/templates/tauri-react/src/updater.ts +15 -15
  176. package/templates/tauri-react/src/vite-env.d.ts +17 -0
  177. package/templates/tauri-react/src-tauri/tauri.conf.json +1 -1
  178. package/templates/tauri-react/tsconfig.json.hbs +14 -0
  179. package/templates/tauri-react/vite.config.ts +9 -9
  180. package/templates/vue-basic/README.md.hbs +62 -0
  181. package/templates/vue-basic/index.html.hbs +12 -0
  182. package/templates/vue-basic/kora.config.ts +12 -0
  183. package/templates/vue-basic/package.json.hbs +26 -0
  184. package/templates/vue-basic/src/App.vue +117 -0
  185. package/templates/vue-basic/src/index.css +287 -0
  186. package/templates/vue-basic/src/kora-worker.ts +9 -0
  187. package/templates/vue-basic/src/main.ts +20 -0
  188. package/templates/vue-basic/src/modules/todos/todo.mutations.ts +25 -0
  189. package/templates/vue-basic/src/modules/todos/todo.queries.ts +5 -0
  190. package/templates/vue-basic/src/modules/todos/todo.schema.ts +10 -0
  191. package/templates/vue-basic/src/modules/todos/useTodos.ts +32 -0
  192. package/templates/vue-basic/src/schema.ts +9 -0
  193. package/templates/vue-basic/src/vite-env.d.ts +17 -0
  194. package/templates/vue-basic/tsconfig.json.hbs +15 -0
  195. package/templates/vue-basic/vite.config.ts +69 -0
  196. package/templates/vue-sync/.env.example +25 -0
  197. package/templates/vue-sync/README.md.hbs +105 -0
  198. package/templates/vue-sync/index.html.hbs +12 -0
  199. package/templates/vue-sync/kora.config.ts +17 -0
  200. package/templates/vue-sync/package.json.hbs +42 -0
  201. package/templates/vue-sync/server.ts +90 -0
  202. package/templates/vue-sync/src/App.vue +135 -0
  203. package/templates/vue-sync/src/auth.ts +25 -0
  204. package/templates/vue-sync/src/index.css +339 -0
  205. package/templates/vue-sync/src/kora-worker.ts +9 -0
  206. package/templates/vue-sync/src/main.ts +43 -0
  207. package/templates/vue-sync/src/modules/todos/todo.mutations.ts +25 -0
  208. package/templates/vue-sync/src/modules/todos/todo.queries.ts +5 -0
  209. package/templates/vue-sync/src/modules/todos/todo.schema.ts +10 -0
  210. package/templates/vue-sync/src/modules/todos/useTodos.ts +32 -0
  211. package/templates/vue-sync/src/schema.ts +9 -0
  212. package/templates/vue-sync/src/vite-env.d.ts +26 -0
  213. package/templates/vue-sync/tsconfig.json.hbs +15 -0
  214. package/templates/vue-sync/vite.config.ts +79 -0
  215. package/templates/vue-tailwind/README.md.hbs +62 -0
  216. package/templates/vue-tailwind/index.html.hbs +12 -0
  217. package/templates/vue-tailwind/kora.config.ts +12 -0
  218. package/templates/vue-tailwind/package.json.hbs +29 -0
  219. package/templates/vue-tailwind/src/App.vue +142 -0
  220. package/templates/vue-tailwind/src/index.css +7 -0
  221. package/templates/vue-tailwind/src/kora-worker.ts +9 -0
  222. package/templates/vue-tailwind/src/main.ts +31 -0
  223. package/templates/vue-tailwind/src/modules/todos/todo.mutations.ts +25 -0
  224. package/templates/vue-tailwind/src/modules/todos/todo.queries.ts +5 -0
  225. package/templates/vue-tailwind/src/modules/todos/todo.schema.ts +10 -0
  226. package/templates/vue-tailwind/src/modules/todos/useTodos.ts +32 -0
  227. package/templates/vue-tailwind/src/schema.ts +9 -0
  228. package/templates/vue-tailwind/src/vite-env.d.ts +17 -0
  229. package/templates/vue-tailwind/tsconfig.json.hbs +15 -0
  230. package/templates/vue-tailwind/vite.config.ts +70 -0
  231. package/templates/vue-tailwind-sync/.env.example +25 -0
  232. package/templates/vue-tailwind-sync/README.md.hbs +105 -0
  233. package/templates/vue-tailwind-sync/index.html.hbs +12 -0
  234. package/templates/vue-tailwind-sync/kora.config.ts +17 -0
  235. package/templates/vue-tailwind-sync/package.json.hbs +45 -0
  236. package/templates/vue-tailwind-sync/server.ts +90 -0
  237. package/templates/vue-tailwind-sync/src/App.vue +245 -0
  238. package/templates/vue-tailwind-sync/src/auth.ts +25 -0
  239. package/templates/vue-tailwind-sync/src/index.css +7 -0
  240. package/templates/vue-tailwind-sync/src/kora-worker.ts +9 -0
  241. package/templates/vue-tailwind-sync/src/main.ts +56 -0
  242. package/templates/vue-tailwind-sync/src/modules/todos/todo.mutations.ts +25 -0
  243. package/templates/vue-tailwind-sync/src/modules/todos/todo.queries.ts +5 -0
  244. package/templates/vue-tailwind-sync/src/modules/todos/todo.schema.ts +10 -0
  245. package/templates/vue-tailwind-sync/src/modules/todos/useTodos.ts +32 -0
  246. package/templates/vue-tailwind-sync/src/schema.ts +9 -0
  247. package/templates/vue-tailwind-sync/src/vite-env.d.ts +26 -0
  248. package/templates/vue-tailwind-sync/tsconfig.json.hbs +15 -0
  249. package/templates/vue-tailwind-sync/vite.config.ts +80 -0
  250. package/dist/chunk-CMSX76KM.js.map +0 -1
  251. package/dist/chunk-MVP5PDT4.js.map +0 -1
  252. package/dist/chunk-YGVO4POI.js.map +0 -1
  253. package/templates/tauri-react/tsconfig.json +0 -15
@@ -1,24 +1,31 @@
1
- import { createApp } from 'korajs'
2
1
  import { KoraProvider } from '@korajs/react'
2
+ import { createApp } from 'korajs'
3
3
  import { StrictMode } from 'react'
4
4
  import { createRoot } from 'react-dom/client'
5
- import schema from './schema'
6
5
  import { App } from './App'
6
+ import schema from './schema'
7
7
  import './index.css'
8
8
  import koraWorkerUrl from './kora-worker.ts?worker&url'
9
9
 
10
10
  const app = createApp({
11
- schema,
12
- store: {
13
- workerUrl: koraWorkerUrl,
14
- },
15
- devtools: true,
11
+ schema,
12
+ store: {
13
+ workerUrl: koraWorkerUrl,
14
+ },
15
+ devtools: true,
16
16
  })
17
17
 
18
18
  createRoot(document.getElementById('root')!).render(
19
- <StrictMode>
20
- <KoraProvider app={app} fallback={<div className="flex items-center justify-center h-screen bg-gray-950 text-gray-400">Loading...</div>}>
21
- <App />
22
- </KoraProvider>
23
- </StrictMode>,
19
+ <StrictMode>
20
+ <KoraProvider
21
+ app={app}
22
+ fallback={
23
+ <div className="flex items-center justify-center h-screen bg-gray-950 text-gray-400">
24
+ Loading...
25
+ </div>
26
+ }
27
+ >
28
+ <App />
29
+ </KoraProvider>
30
+ </StrictMode>,
24
31
  )
@@ -0,0 +1,25 @@
1
+ import type { CollectionAccessor } from 'korajs'
2
+
3
+ export interface CreateTodoInput {
4
+ title: string
5
+ }
6
+
7
+ export interface UpdateTodoStatusInput {
8
+ completed: boolean
9
+ }
10
+
11
+ export function createTodo(todos: CollectionAccessor, data: CreateTodoInput) {
12
+ return todos.insert({ title: data.title })
13
+ }
14
+
15
+ export function updateTodoStatus(
16
+ todos: CollectionAccessor,
17
+ id: string,
18
+ data: UpdateTodoStatusInput,
19
+ ) {
20
+ return todos.update(id, { completed: data.completed })
21
+ }
22
+
23
+ export function deleteTodo(todos: CollectionAccessor, id: string) {
24
+ return todos.delete(id)
25
+ }
@@ -0,0 +1,5 @@
1
+ import type { CollectionAccessor } from 'korajs'
2
+
3
+ export function orderedTodos(todos: CollectionAccessor) {
4
+ return todos.where({}).orderBy('createdAt', 'desc')
5
+ }
@@ -0,0 +1,10 @@
1
+ import { t } from 'korajs'
2
+
3
+ export const todos = {
4
+ fields: {
5
+ title: t.string(),
6
+ completed: t.boolean().default(false),
7
+ createdAt: t.timestamp().auto(),
8
+ },
9
+ indexes: ['completed', 'createdAt'],
10
+ }
@@ -0,0 +1,31 @@
1
+ import { useCollection, useMutation, useQuery } from '@korajs/react'
2
+ import {
3
+ type CreateTodoInput,
4
+ type UpdateTodoStatusInput,
5
+ createTodo,
6
+ deleteTodo,
7
+ updateTodoStatus,
8
+ } from './todo.mutations'
9
+ import { orderedTodos } from './todo.queries'
10
+
11
+ export function useTodos() {
12
+ const todos = useCollection('todos')
13
+ const allTodos = useQuery(orderedTodos(todos))
14
+ const addTodo = useMutation((data: CreateTodoInput) => createTodo(todos, data))
15
+ const toggleTodo = useMutation((id: string, data: UpdateTodoStatusInput) =>
16
+ updateTodoStatus(todos, id, data),
17
+ )
18
+ const removeTodo = useMutation((id: string) => deleteTodo(todos, id))
19
+
20
+ const activeTodos = allTodos.filter((todo) => !todo.completed)
21
+ const completedTodos = allTodos.filter((todo) => !!todo.completed)
22
+
23
+ return {
24
+ allTodos,
25
+ activeTodos,
26
+ completedTodos,
27
+ addTodo,
28
+ toggleTodo,
29
+ deleteTodo: removeTodo,
30
+ }
31
+ }
@@ -1,15 +1,9 @@
1
- import { defineSchema, t } from 'korajs'
1
+ import { defineSchema } from 'korajs'
2
+ import { todos } from './modules/todos/todo.schema'
2
3
 
3
4
  export default defineSchema({
4
- version: 1,
5
- collections: {
6
- todos: {
7
- fields: {
8
- title: t.string(),
9
- completed: t.boolean().default(false),
10
- createdAt: t.timestamp().auto(),
11
- },
12
- indexes: ['completed'],
13
- },
14
- },
5
+ version: 1,
6
+ collections: {
7
+ todos,
8
+ },
15
9
  })
@@ -0,0 +1,17 @@
1
+ interface ImportMetaEnv {
2
+ readonly VITE_SYNC_URL?: string
3
+ }
4
+
5
+ interface ImportMeta {
6
+ readonly env: ImportMetaEnv
7
+ }
8
+
9
+ declare module '*?worker&url' {
10
+ const url: string
11
+ export default url
12
+ }
13
+
14
+ declare module '*?url' {
15
+ const url: string
16
+ export default url
17
+ }
@@ -8,8 +8,7 @@
8
8
  "noUncheckedIndexedAccess": true,
9
9
  "esModuleInterop": true,
10
10
  "skipLibCheck": true,
11
- "outDir": "dist",
12
- "types": ["vite/client"]
11
+ "outDir": "dist"
13
12
  },
14
13
  "include": ["src"]
15
14
  }
@@ -1,5 +1,5 @@
1
- import { existsSync, readdirSync, copyFileSync } from 'node:fs'
2
- import { resolve, join } from 'node:path'
1
+ import { copyFileSync, existsSync, readdirSync } from 'node:fs'
2
+ import { join, resolve } from 'node:path'
3
3
  import tailwindcss from '@tailwindcss/vite'
4
4
  import react from '@vitejs/plugin-react'
5
5
  import type { Plugin } from 'vite'
@@ -11,23 +11,23 @@ import { defineConfig } from 'vite'
11
11
  * cannot be used and SQLite WASM falls back to in-memory storage (no persistence).
12
12
  */
13
13
  function crossOriginIsolation(): Plugin {
14
- return {
15
- name: 'cross-origin-isolation',
16
- configureServer(server) {
17
- server.middlewares.use((_req, res, next) => {
18
- res.setHeader('Cross-Origin-Opener-Policy', 'same-origin')
19
- res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp')
20
- next()
21
- })
22
- },
23
- configurePreviewServer(server) {
24
- server.middlewares.use((_req, res, next) => {
25
- res.setHeader('Cross-Origin-Opener-Policy', 'same-origin')
26
- res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp')
27
- next()
28
- })
29
- },
30
- }
14
+ return {
15
+ name: 'cross-origin-isolation',
16
+ configureServer(server) {
17
+ server.middlewares.use((_req, res, next) => {
18
+ res.setHeader('Cross-Origin-Opener-Policy', 'same-origin')
19
+ res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp')
20
+ next()
21
+ })
22
+ },
23
+ configurePreviewServer(server) {
24
+ server.middlewares.use((_req, res, next) => {
25
+ res.setHeader('Cross-Origin-Opener-Policy', 'same-origin')
26
+ res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp')
27
+ next()
28
+ })
29
+ },
30
+ }
31
31
  }
32
32
 
33
33
  /**
@@ -37,40 +37,47 @@ function crossOriginIsolation(): Plugin {
37
37
  * sqlite3 loads it dynamically) so the full OPFS VFS can initialize without errors
38
38
  */
39
39
  function sqliteWasmHotfix(): Plugin {
40
- return {
41
- name: 'sqlite-wasm-hotfix',
42
- apply: 'build',
43
- closeBundle() {
44
- const assetsDir = resolve('dist', 'assets')
45
- if (!existsSync(assetsDir)) return
40
+ return {
41
+ name: 'sqlite-wasm-hotfix',
42
+ apply: 'build',
43
+ closeBundle() {
44
+ const assetsDir = resolve('dist', 'assets')
45
+ if (!existsSync(assetsDir)) return
46
46
 
47
- // Copy hashed sqlite3.wasm to unhashed name
48
- for (const file of readdirSync(assetsDir)) {
49
- if (/^sqlite3-.+\.wasm$/.test(file)) {
50
- copyFileSync(join(assetsDir, file), join(assetsDir, 'sqlite3.wasm'))
51
- break
52
- }
53
- }
47
+ // Copy hashed sqlite3.wasm to unhashed name
48
+ for (const file of readdirSync(assetsDir)) {
49
+ if (/^sqlite3-.+\.wasm$/.test(file)) {
50
+ copyFileSync(join(assetsDir, file), join(assetsDir, 'sqlite3.wasm'))
51
+ break
52
+ }
53
+ }
54
54
 
55
- // Copy OPFS async proxy worker (dynamically loaded by sqlite3, not detected by Vite)
56
- const proxyFile = resolve('node_modules', '@sqlite.org', 'sqlite-wasm', 'sqlite-wasm', 'jswasm', 'sqlite3-opfs-async-proxy.js')
57
- if (existsSync(proxyFile)) {
58
- copyFileSync(proxyFile, join(assetsDir, 'sqlite3-opfs-async-proxy.js'))
59
- }
60
- },
61
- }
55
+ // Copy OPFS async proxy worker (dynamically loaded by sqlite3, not detected by Vite)
56
+ const proxyFile = resolve(
57
+ 'node_modules',
58
+ '@sqlite.org',
59
+ 'sqlite-wasm',
60
+ 'sqlite-wasm',
61
+ 'jswasm',
62
+ 'sqlite3-opfs-async-proxy.js',
63
+ )
64
+ if (existsSync(proxyFile)) {
65
+ copyFileSync(proxyFile, join(assetsDir, 'sqlite3-opfs-async-proxy.js'))
66
+ }
67
+ },
68
+ }
62
69
  }
63
70
 
64
71
  export default defineConfig({
65
- plugins: [react(), tailwindcss(), crossOriginIsolation(), sqliteWasmHotfix()],
66
- worker: {
67
- format: 'es',
68
- },
69
- optimizeDeps: {
70
- exclude: ['@sqlite.org/sqlite-wasm', '@korajs/store'],
71
- include: ['yjs'],
72
- },
73
- resolve: {
74
- dedupe: ['yjs'],
75
- },
72
+ plugins: [react(), tailwindcss(), crossOriginIsolation(), sqliteWasmHotfix()],
73
+ worker: {
74
+ format: 'es',
75
+ },
76
+ optimizeDeps: {
77
+ exclude: ['@sqlite.org/sqlite-wasm', '@korajs/store'],
78
+ include: ['yjs'],
79
+ },
80
+ resolve: {
81
+ dedupe: ['yjs'],
82
+ },
76
83
  })
@@ -4,3 +4,22 @@ VITE_SYNC_URL=ws://localhost:3001
4
4
 
5
5
  # Sync server port
6
6
  PORT=3001
7
+
8
+ # Server database
9
+ # Leave DATABASE_URL empty to use SQLite at KORA_SERVER_DB.
10
+ KORA_SERVER_DB=./kora-server.db
11
+ DATABASE_URL=
12
+
13
+ # Operational endpoints (/__kora, /__kora/status, /__kora/events, /__kora/metrics, backups)
14
+ # Set these in production. Use Authorization: Bearer <token> when calling protected endpoints.
15
+ KORA_ADMIN_TOKEN=
16
+ KORA_METRICS_TOKEN=
17
+ KORA_BACKUP_TOKEN=
18
+
19
+ # Optional sync path
20
+ KORA_SYNC_PATH=/kora-sync
21
+
22
+ # Auth
23
+ # Set this to enable built-in /auth/* routes and authenticated sync.
24
+ # Generate with: node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))"
25
+ KORA_AUTH_SECRET=
@@ -17,21 +17,63 @@ This starts both the Vite dev server and the Kora sync server.
17
17
 
18
18
  ```
19
19
  src/
20
- schema.ts # Data schema definition
20
+ schema.ts # Schema entry point
21
+ auth.ts # Auth client and OAuth callback handling
21
22
  main.tsx # App initialization and Kora setup
22
23
  App.tsx # Main application component
24
+ modules/
25
+ todos/
26
+ todo.schema.ts # Todo collection definition
27
+ todo.queries.ts # Reusable todo query builders
28
+ todo.mutations.ts # Todo mutation helpers
29
+ useTodos.ts # React hook connecting todos to the UI
23
30
  kora-worker.ts # SQLite WASM web worker
24
31
  index.css # Styles
25
32
  server.ts # Kora sync server
26
33
  kora.config.ts # Kora configuration
27
34
  ```
28
35
 
36
+ In a feature module, `schema` defines data shape, `queries` contain reads only, `mutations` contain
37
+ writes, and `useTodos.ts` is the React binding that exposes todo data and actions to components.
38
+
29
39
  ## Environment Variables
30
40
 
31
41
  | Variable | Default | Description |
32
42
  |----------|---------|-------------|
33
43
  | `VITE_SYNC_URL` | `ws://localhost:3001` | WebSocket URL for the sync server |
44
+ | `VITE_AUTH_URL` | current origin | HTTP URL for `/auth/*` routes |
34
45
  | `PORT` | `3001` | Sync server port |
46
+ | `KORA_SERVER_DB` | `./kora-server.db` | SQLite file used by the sync server when `DATABASE_URL` is empty |
47
+ | `KORA_AUTH_DB` | `./kora-auth.db` | SQLite file used by OAuth state and linked identities when `DATABASE_URL` is empty |
48
+ | `DATABASE_URL` | (none) | PostgreSQL connection string for production sync server deployments |
49
+ | `KORA_SYNC_PATH` | `/kora-sync` | WebSocket path exposed by the sync server |
50
+ | `KORA_AUTH_SECRET` | (none) | Enables built-in `/auth/*` routes and authenticated sync when set |
51
+ | `KORA_GOOGLE_CLIENT_ID` | (none) | Enables Google OAuth when set with `KORA_GOOGLE_REDIRECT_URI` |
52
+ | `KORA_GOOGLE_CLIENT_SECRET` | (none) | Google OAuth client secret for confidential web clients |
53
+ | `KORA_GOOGLE_REDIRECT_URI` | (none) | OAuth callback URL, usually your app URL that handles `code` and `state` |
54
+ | `KORA_OAUTH_PKCE` | `true` when no client secret | Enables PKCE for public desktop/mobile OAuth clients |
55
+ | `KORA_ADMIN_TOKEN` | (none) | Protects `/__kora`, `/__kora/status`, and `/__kora/events` |
56
+ | `KORA_METRICS_TOKEN` | (none) | Protects `/__kora/metrics` |
57
+ | `KORA_BACKUP_TOKEN` | (none) | Protects server backup and restore endpoints |
58
+
59
+ ## Authentication
60
+
61
+ Set `KORA_AUTH_SECRET` to enable built-in auth on the sync server. Generate a secret with:
62
+
63
+ ```bash
64
+ node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))"
65
+ ```
66
+
67
+ The template already creates `src/auth.ts`, wraps the app in `AuthProvider`, and wires sync with `createKoraAuthSync({ authClient, schema })`. To enable Google OAuth, set:
68
+
69
+ ```bash
70
+ KORA_AUTH_SECRET=...
71
+ KORA_GOOGLE_CLIENT_ID=...
72
+ KORA_GOOGLE_CLIENT_SECRET=...
73
+ KORA_GOOGLE_REDIRECT_URI=http://localhost:5173
74
+ ```
75
+
76
+ Use `authClient.signInWithOAuth('google')` for web redirect sign-in, or `authClient.getOAuthAuthorizationUrl('google')` plus `authClient.completeOAuthSignIn('google', { code, state })` for custom handoff flows. See the [Authentication Guide](https://ehoneahobed.github.io/kora/guide/authentication).
35
77
 
36
78
  ## Scripts
37
79
 
@@ -12,6 +12,7 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "korajs": "{{koraVersion}}",
15
+ "@korajs/auth": "{{koraVersion}}",
15
16
  "@korajs/react": "{{koraVersion}}",
16
17
  "@korajs/store": "{{koraVersion}}",
17
18
  "@sqlite.org/sqlite-wasm": ">=3.51.0-build1",
@@ -36,6 +37,8 @@
36
37
  "@types/react-dom": "^19.0.0",
37
38
  "@types/ws": "^8.5.0",
38
39
  "@vitejs/plugin-react": "^4.3.0",
40
+ "better-sqlite3": "^12.9.0",
41
+ "postgres": "^3.4.0",
39
42
  "tailwindcss": "^4.0.0",
40
43
  "tsx": "^4.19.0",
41
44
  "typescript": "^5.7.0",
@@ -1,26 +1,90 @@
1
- import { createProductionServer, createSqliteServerStore } from '@korajs/server'
2
-
3
- // SQLite persists data to disk — survives server restarts
4
- const store = createSqliteServerStore({ filename: './kora-server.db' })
5
-
6
- // To use PostgreSQL instead:
7
- // 1. Install: pnpm add postgres
8
- // 2. Replace the store above with:
9
- //
10
- // import { createPostgresServerStore } from '@korajs/server'
11
- // const store = await createPostgresServerStore({
12
- // connectionString: 'postgresql://user:password@localhost:5432/mydb',
13
- // })
14
-
15
- // Production server: serves static files + WebSocket sync on a single port.
16
- // One port means one tunnel (ngrok, cloudflared) handles everything.
17
- const server = createProductionServer({
18
- store,
19
- port: Number(process.env.PORT) || 3001,
20
- staticDir: './dist',
21
- syncPath: '/kora-sync',
22
- })
23
-
24
- server.start().then((url) => {
25
- console.log(`Kora app running at ${url}`)
26
- })
1
+ import {
2
+ type CreateKoraAuthServerOptions,
3
+ createKoraAuthServer,
4
+ createPostgresOAuthStores,
5
+ createSqliteOAuthStores,
6
+ googleProvider,
7
+ } from '@korajs/auth/server'
8
+ import {
9
+ createPostgresServerStore,
10
+ createProductionServer,
11
+ createSqliteServerStore,
12
+ } from '@korajs/server'
13
+ import schema from './src/schema'
14
+
15
+ async function createStore() {
16
+ if (process.env.DATABASE_URL) {
17
+ return createPostgresServerStore({
18
+ connectionString: process.env.DATABASE_URL,
19
+ })
20
+ }
21
+
22
+ return createSqliteServerStore({
23
+ filename: process.env.KORA_SERVER_DB || './kora-server.db',
24
+ })
25
+ }
26
+
27
+ async function start() {
28
+ const store = await createStore()
29
+ await store.setSchema(schema)
30
+
31
+ const syncPath = process.env.KORA_SYNC_PATH || '/kora-sync'
32
+ const auth = await createAuth()
33
+ const server = createProductionServer({
34
+ store,
35
+ port: Number(process.env.PORT) || 3001,
36
+ staticDir: './dist',
37
+ syncPath,
38
+ httpRoutes: auth ? [{ path: '/auth', handle: auth.handleRequest }] : undefined,
39
+ syncOptions: auth ? { auth: auth.auth } : undefined,
40
+ operationalAuth: {
41
+ adminToken: process.env.KORA_ADMIN_TOKEN,
42
+ metricsToken: process.env.KORA_METRICS_TOKEN,
43
+ backupToken: process.env.KORA_BACKUP_TOKEN,
44
+ },
45
+ })
46
+
47
+ const url = await server.start()
48
+ console.log(`Kora app running at ${url}`)
49
+ console.log(` Sync endpoint: ${url.replace('http', 'ws')}${syncPath}`)
50
+ if (auth) console.log(` Auth endpoint: ${url}/auth`)
51
+ }
52
+
53
+ void start()
54
+
55
+ async function createAuth() {
56
+ if (!process.env.KORA_AUTH_SECRET) {
57
+ return null
58
+ }
59
+
60
+ const oauth = await createOAuthConfig()
61
+ return createKoraAuthServer({
62
+ jwtSecret: process.env.KORA_AUTH_SECRET,
63
+ ...(oauth ? { oauth } : {}),
64
+ })
65
+ }
66
+
67
+ async function createOAuthConfig(): Promise<CreateKoraAuthServerOptions['oauth'] | undefined> {
68
+ if (!process.env.KORA_GOOGLE_CLIENT_ID || !process.env.KORA_GOOGLE_REDIRECT_URI) {
69
+ return undefined
70
+ }
71
+
72
+ const oauthStores = process.env.DATABASE_URL
73
+ ? await createPostgresOAuthStores({ connectionString: process.env.DATABASE_URL })
74
+ : await createSqliteOAuthStores({
75
+ filename: process.env.KORA_AUTH_DB || './kora-auth.db',
76
+ })
77
+
78
+ return {
79
+ providers: [
80
+ googleProvider({
81
+ clientId: process.env.KORA_GOOGLE_CLIENT_ID,
82
+ clientSecret: process.env.KORA_GOOGLE_CLIENT_SECRET,
83
+ redirectUri: process.env.KORA_GOOGLE_REDIRECT_URI,
84
+ pkce: process.env.KORA_OAUTH_PKCE === 'true' || !process.env.KORA_GOOGLE_CLIENT_SECRET,
85
+ }),
86
+ ],
87
+ stateStore: oauthStores.stateStore,
88
+ linkedIdentityStore: oauthStores.linkedIdentityStore,
89
+ }
90
+ }