@korajs/cli 0.0.0-canary-20261008174129

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 (310) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +44 -0
  3. package/dist/bin.cjs +9465 -0
  4. package/dist/bin.cjs.map +1 -0
  5. package/dist/bin.js +3150 -0
  6. package/dist/bin.js.map +1 -0
  7. package/dist/chunk-5NI2FEQL.js +92 -0
  8. package/dist/chunk-5NI2FEQL.js.map +1 -0
  9. package/dist/chunk-6C4BHSRA.js +82 -0
  10. package/dist/chunk-6C4BHSRA.js.map +1 -0
  11. package/dist/chunk-7Y4J2GXP.js +796 -0
  12. package/dist/chunk-7Y4J2GXP.js.map +1 -0
  13. package/dist/chunk-BURFQVMV.js +719 -0
  14. package/dist/chunk-BURFQVMV.js.map +1 -0
  15. package/dist/chunk-TVIRMDER.js +2569 -0
  16. package/dist/chunk-TVIRMDER.js.map +1 -0
  17. package/dist/create.cjs +1368 -0
  18. package/dist/create.cjs.map +1 -0
  19. package/dist/create.js +11 -0
  20. package/dist/create.js.map +1 -0
  21. package/dist/index.cjs +3489 -0
  22. package/dist/index.cjs.map +1 -0
  23. package/dist/index.d.cts +772 -0
  24. package/dist/index.d.ts +772 -0
  25. package/dist/index.js +129 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/lab-manager-KUDII6BT.js +280 -0
  28. package/dist/lab-manager-KUDII6BT.js.map +1 -0
  29. package/dist/schema-loader-GGHECMTM.js +9 -0
  30. package/dist/schema-loader-GGHECMTM.js.map +1 -0
  31. package/dist/spectator-manager-FTH2NFSE.js +145 -0
  32. package/dist/spectator-manager-FTH2NFSE.js.map +1 -0
  33. package/dist/studio-server-XLGZNGG5.js +1747 -0
  34. package/dist/studio-server-XLGZNGG5.js.map +1 -0
  35. package/dist/vite.cjs +351 -0
  36. package/dist/vite.cjs.map +1 -0
  37. package/dist/vite.d.cts +161 -0
  38. package/dist/vite.d.ts +161 -0
  39. package/dist/vite.js +321 -0
  40. package/dist/vite.js.map +1 -0
  41. package/package.json +79 -0
  42. package/templates/react-basic/.env.example +3 -0
  43. package/templates/react-basic/AGENTS.md +87 -0
  44. package/templates/react-basic/README.md.hbs +62 -0
  45. package/templates/react-basic/index.html.hbs +12 -0
  46. package/templates/react-basic/kora.config.ts +13 -0
  47. package/templates/react-basic/package.json.hbs +35 -0
  48. package/templates/react-basic/src/App.tsx +132 -0
  49. package/templates/react-basic/src/index.css +287 -0
  50. package/templates/react-basic/src/kora-worker.ts +9 -0
  51. package/templates/react-basic/src/main.tsx +24 -0
  52. package/templates/react-basic/src/modules/todos/todo.mutations.ts +25 -0
  53. package/templates/react-basic/src/modules/todos/todo.queries.ts +5 -0
  54. package/templates/react-basic/src/modules/todos/todo.schema.ts +10 -0
  55. package/templates/react-basic/src/modules/todos/useTodos.ts +31 -0
  56. package/templates/react-basic/src/schema.ts +9 -0
  57. package/templates/react-basic/src/vite-env.d.ts +18 -0
  58. package/templates/react-basic/tsconfig.json.hbs +14 -0
  59. package/templates/react-basic/vite.config.ts +88 -0
  60. package/templates/react-sync/.env.example +25 -0
  61. package/templates/react-sync/AGENTS.md +87 -0
  62. package/templates/react-sync/README.md.hbs +106 -0
  63. package/templates/react-sync/index.html.hbs +12 -0
  64. package/templates/react-sync/kora.config.ts +17 -0
  65. package/templates/react-sync/package.json.hbs +44 -0
  66. package/templates/react-sync/server.ts +141 -0
  67. package/templates/react-sync/src/App.tsx +160 -0
  68. package/templates/react-sync/src/auth.ts +25 -0
  69. package/templates/react-sync/src/index.css +350 -0
  70. package/templates/react-sync/src/kora-worker.ts +9 -0
  71. package/templates/react-sync/src/main.tsx +52 -0
  72. package/templates/react-sync/src/modules/todos/todo.mutations.ts +25 -0
  73. package/templates/react-sync/src/modules/todos/todo.queries.ts +5 -0
  74. package/templates/react-sync/src/modules/todos/todo.schema.ts +10 -0
  75. package/templates/react-sync/src/modules/todos/useTodos.ts +31 -0
  76. package/templates/react-sync/src/schema.ts +9 -0
  77. package/templates/react-sync/src/vite-env.d.ts +19 -0
  78. package/templates/react-sync/tsconfig.json.hbs +14 -0
  79. package/templates/react-sync/vite.config.ts +105 -0
  80. package/templates/react-tailwind/.env.example +3 -0
  81. package/templates/react-tailwind/AGENTS.md +87 -0
  82. package/templates/react-tailwind/README.md.hbs +62 -0
  83. package/templates/react-tailwind/index.html.hbs +12 -0
  84. package/templates/react-tailwind/kora.config.ts +13 -0
  85. package/templates/react-tailwind/package.json.hbs +38 -0
  86. package/templates/react-tailwind/src/App.tsx +201 -0
  87. package/templates/react-tailwind/src/index.css +7 -0
  88. package/templates/react-tailwind/src/kora-worker.ts +9 -0
  89. package/templates/react-tailwind/src/main.tsx +31 -0
  90. package/templates/react-tailwind/src/modules/todos/todo.mutations.ts +25 -0
  91. package/templates/react-tailwind/src/modules/todos/todo.queries.ts +5 -0
  92. package/templates/react-tailwind/src/modules/todos/todo.schema.ts +10 -0
  93. package/templates/react-tailwind/src/modules/todos/useTodos.ts +31 -0
  94. package/templates/react-tailwind/src/schema.ts +9 -0
  95. package/templates/react-tailwind/src/vite-env.d.ts +18 -0
  96. package/templates/react-tailwind/tsconfig.json.hbs +14 -0
  97. package/templates/react-tailwind/vite.config.ts +95 -0
  98. package/templates/react-tailwind-sync/.env.example +25 -0
  99. package/templates/react-tailwind-sync/AGENTS.md +89 -0
  100. package/templates/react-tailwind-sync/README.md.hbs +106 -0
  101. package/templates/react-tailwind-sync/index.html.hbs +12 -0
  102. package/templates/react-tailwind-sync/kora.config.ts +17 -0
  103. package/templates/react-tailwind-sync/package.json.hbs +47 -0
  104. package/templates/react-tailwind-sync/server.ts +141 -0
  105. package/templates/react-tailwind-sync/src/App.tsx +293 -0
  106. package/templates/react-tailwind-sync/src/auth.ts +25 -0
  107. package/templates/react-tailwind-sync/src/index.css +7 -0
  108. package/templates/react-tailwind-sync/src/kora-worker.ts +9 -0
  109. package/templates/react-tailwind-sync/src/kora.ts +32 -0
  110. package/templates/react-tailwind-sync/src/main.tsx +44 -0
  111. package/templates/react-tailwind-sync/src/modules/todos/todo.mutations.ts +21 -0
  112. package/templates/react-tailwind-sync/src/modules/todos/todo.queries.ts +5 -0
  113. package/templates/react-tailwind-sync/src/modules/todos/todo.schema.ts +10 -0
  114. package/templates/react-tailwind-sync/src/modules/todos/useTodos.ts +31 -0
  115. package/templates/react-tailwind-sync/src/schema.ts +9 -0
  116. package/templates/react-tailwind-sync/src/vite-env.d.ts +19 -0
  117. package/templates/react-tailwind-sync/tsconfig.json.hbs +14 -0
  118. package/templates/react-tailwind-sync/vite.config.ts +112 -0
  119. package/templates/svelte-basic/.env.example +3 -0
  120. package/templates/svelte-basic/AGENTS.md +76 -0
  121. package/templates/svelte-basic/README.md.hbs +62 -0
  122. package/templates/svelte-basic/index.html.hbs +12 -0
  123. package/templates/svelte-basic/kora.config.ts +12 -0
  124. package/templates/svelte-basic/package.json.hbs +33 -0
  125. package/templates/svelte-basic/src/App.svelte +128 -0
  126. package/templates/svelte-basic/src/Root.svelte +14 -0
  127. package/templates/svelte-basic/src/index.css +287 -0
  128. package/templates/svelte-basic/src/kora-worker.ts +9 -0
  129. package/templates/svelte-basic/src/main.ts +16 -0
  130. package/templates/svelte-basic/src/modules/todos/todo.mutations.ts +25 -0
  131. package/templates/svelte-basic/src/modules/todos/todo.queries.ts +5 -0
  132. package/templates/svelte-basic/src/modules/todos/todo.schema.ts +10 -0
  133. package/templates/svelte-basic/src/modules/todos/useTodos.ts +25 -0
  134. package/templates/svelte-basic/src/schema.ts +9 -0
  135. package/templates/svelte-basic/src/vite-env.d.ts +12 -0
  136. package/templates/svelte-basic/svelte.config.js +5 -0
  137. package/templates/svelte-basic/tsconfig.json.hbs +14 -0
  138. package/templates/svelte-basic/vite.config.ts +57 -0
  139. package/templates/svelte-sync/.env.example +25 -0
  140. package/templates/svelte-sync/AGENTS.md +76 -0
  141. package/templates/svelte-sync/README.md.hbs +106 -0
  142. package/templates/svelte-sync/index.html.hbs +12 -0
  143. package/templates/svelte-sync/kora.config.ts +17 -0
  144. package/templates/svelte-sync/package.json.hbs +43 -0
  145. package/templates/svelte-sync/server.ts +141 -0
  146. package/templates/svelte-sync/src/App.svelte +151 -0
  147. package/templates/svelte-sync/src/Root.svelte +22 -0
  148. package/templates/svelte-sync/src/auth.ts +25 -0
  149. package/templates/svelte-sync/src/index.css +339 -0
  150. package/templates/svelte-sync/src/kora-worker.ts +9 -0
  151. package/templates/svelte-sync/src/main.ts +32 -0
  152. package/templates/svelte-sync/src/modules/todos/todo.mutations.ts +25 -0
  153. package/templates/svelte-sync/src/modules/todos/todo.queries.ts +5 -0
  154. package/templates/svelte-sync/src/modules/todos/todo.schema.ts +10 -0
  155. package/templates/svelte-sync/src/modules/todos/useTodos.ts +25 -0
  156. package/templates/svelte-sync/src/schema.ts +9 -0
  157. package/templates/svelte-sync/src/vite-env.d.ts +22 -0
  158. package/templates/svelte-sync/svelte.config.js +5 -0
  159. package/templates/svelte-sync/tsconfig.json.hbs +14 -0
  160. package/templates/svelte-sync/vite.config.ts +91 -0
  161. package/templates/svelte-tailwind/AGENTS.md +76 -0
  162. package/templates/svelte-tailwind/README.md.hbs +62 -0
  163. package/templates/svelte-tailwind/index.html.hbs +12 -0
  164. package/templates/svelte-tailwind/kora.config.ts +12 -0
  165. package/templates/svelte-tailwind/package.json.hbs +36 -0
  166. package/templates/svelte-tailwind/src/App.svelte +76 -0
  167. package/templates/svelte-tailwind/src/Root.svelte +14 -0
  168. package/templates/svelte-tailwind/src/index.css +7 -0
  169. package/templates/svelte-tailwind/src/kora-worker.ts +9 -0
  170. package/templates/svelte-tailwind/src/main.ts +16 -0
  171. package/templates/svelte-tailwind/src/modules/todos/todo.mutations.ts +25 -0
  172. package/templates/svelte-tailwind/src/modules/todos/todo.queries.ts +5 -0
  173. package/templates/svelte-tailwind/src/modules/todos/todo.schema.ts +10 -0
  174. package/templates/svelte-tailwind/src/modules/todos/useTodos.ts +25 -0
  175. package/templates/svelte-tailwind/src/schema.ts +9 -0
  176. package/templates/svelte-tailwind/src/vite-env.d.ts +12 -0
  177. package/templates/svelte-tailwind/svelte.config.js +5 -0
  178. package/templates/svelte-tailwind/tsconfig.json.hbs +14 -0
  179. package/templates/svelte-tailwind/vite.config.ts +64 -0
  180. package/templates/svelte-tailwind-sync/.env.example +25 -0
  181. package/templates/svelte-tailwind-sync/AGENTS.md +76 -0
  182. package/templates/svelte-tailwind-sync/README.md.hbs +106 -0
  183. package/templates/svelte-tailwind-sync/index.html.hbs +12 -0
  184. package/templates/svelte-tailwind-sync/kora.config.ts +17 -0
  185. package/templates/svelte-tailwind-sync/package.json.hbs +46 -0
  186. package/templates/svelte-tailwind-sync/server.ts +141 -0
  187. package/templates/svelte-tailwind-sync/src/App.svelte +193 -0
  188. package/templates/svelte-tailwind-sync/src/Root.svelte +26 -0
  189. package/templates/svelte-tailwind-sync/src/auth.ts +25 -0
  190. package/templates/svelte-tailwind-sync/src/index.css +7 -0
  191. package/templates/svelte-tailwind-sync/src/kora-worker.ts +9 -0
  192. package/templates/svelte-tailwind-sync/src/main.ts +32 -0
  193. package/templates/svelte-tailwind-sync/src/modules/todos/todo.mutations.ts +25 -0
  194. package/templates/svelte-tailwind-sync/src/modules/todos/todo.queries.ts +5 -0
  195. package/templates/svelte-tailwind-sync/src/modules/todos/todo.schema.ts +10 -0
  196. package/templates/svelte-tailwind-sync/src/modules/todos/useTodos.ts +25 -0
  197. package/templates/svelte-tailwind-sync/src/schema.ts +9 -0
  198. package/templates/svelte-tailwind-sync/src/vite-env.d.ts +22 -0
  199. package/templates/svelte-tailwind-sync/svelte.config.js +5 -0
  200. package/templates/svelte-tailwind-sync/tsconfig.json.hbs +14 -0
  201. package/templates/svelte-tailwind-sync/vite.config.ts +98 -0
  202. package/templates/tauri-react/.env.example +27 -0
  203. package/templates/tauri-react/.github/workflows/release-desktop.yml +107 -0
  204. package/templates/tauri-react/AGENTS.md +91 -0
  205. package/templates/tauri-react/README.md.hbs +183 -0
  206. package/templates/tauri-react/dev.ts +37 -0
  207. package/templates/tauri-react/index.html.hbs +16 -0
  208. package/templates/tauri-react/kora.config.ts +17 -0
  209. package/templates/tauri-react/package.json.hbs +46 -0
  210. package/templates/tauri-react/server.ts +148 -0
  211. package/templates/tauri-react/src/App.tsx +803 -0
  212. package/templates/tauri-react/src/AppShell.tsx +158 -0
  213. package/templates/tauri-react/src/SetupScreen.tsx +288 -0
  214. package/templates/tauri-react/src/auth.ts +45 -0
  215. package/templates/tauri-react/src/main.tsx +9 -0
  216. package/templates/tauri-react/src/modules/todos/todo.mutations.ts +25 -0
  217. package/templates/tauri-react/src/modules/todos/todo.queries.ts +5 -0
  218. package/templates/tauri-react/src/modules/todos/todo.schema.ts +10 -0
  219. package/templates/tauri-react/src/modules/todos/useTodos.ts +31 -0
  220. package/templates/tauri-react/src/schema.ts +9 -0
  221. package/templates/tauri-react/src/sync-config.ts +103 -0
  222. package/templates/tauri-react/src/updater.ts +38 -0
  223. package/templates/tauri-react/src/vite-env.d.ts +19 -0
  224. package/templates/tauri-react/src-tauri/Cargo.toml +19 -0
  225. package/templates/tauri-react/src-tauri/build.rs +3 -0
  226. package/templates/tauri-react/src-tauri/capabilities/default.json +12 -0
  227. package/templates/tauri-react/src-tauri/icons/128x128.png +0 -0
  228. package/templates/tauri-react/src-tauri/icons/128x128@2x.png +0 -0
  229. package/templates/tauri-react/src-tauri/icons/32x32.png +0 -0
  230. package/templates/tauri-react/src-tauri/icons/icon.icns +0 -0
  231. package/templates/tauri-react/src-tauri/icons/icon.ico +0 -0
  232. package/templates/tauri-react/src-tauri/src/lib.rs +8 -0
  233. package/templates/tauri-react/src-tauri/src/main.rs +6 -0
  234. package/templates/tauri-react/src-tauri/tauri.conf.json +44 -0
  235. package/templates/tauri-react/tsconfig.json.hbs +14 -0
  236. package/templates/tauri-react/vite.config.ts +15 -0
  237. package/templates/vue-basic/AGENTS.md +84 -0
  238. package/templates/vue-basic/README.md.hbs +62 -0
  239. package/templates/vue-basic/index.html.hbs +12 -0
  240. package/templates/vue-basic/kora.config.ts +12 -0
  241. package/templates/vue-basic/package.json.hbs +32 -0
  242. package/templates/vue-basic/src/App.vue +117 -0
  243. package/templates/vue-basic/src/index.css +287 -0
  244. package/templates/vue-basic/src/kora-worker.ts +9 -0
  245. package/templates/vue-basic/src/main.ts +20 -0
  246. package/templates/vue-basic/src/modules/todos/todo.mutations.ts +25 -0
  247. package/templates/vue-basic/src/modules/todos/todo.queries.ts +5 -0
  248. package/templates/vue-basic/src/modules/todos/todo.schema.ts +10 -0
  249. package/templates/vue-basic/src/modules/todos/useTodos.ts +32 -0
  250. package/templates/vue-basic/src/schema.ts +9 -0
  251. package/templates/vue-basic/src/vite-env.d.ts +17 -0
  252. package/templates/vue-basic/tsconfig.json.hbs +15 -0
  253. package/templates/vue-basic/vite.config.ts +74 -0
  254. package/templates/vue-sync/.env.example +25 -0
  255. package/templates/vue-sync/AGENTS.md +84 -0
  256. package/templates/vue-sync/README.md.hbs +106 -0
  257. package/templates/vue-sync/index.html.hbs +12 -0
  258. package/templates/vue-sync/kora.config.ts +17 -0
  259. package/templates/vue-sync/package.json.hbs +42 -0
  260. package/templates/vue-sync/server.ts +141 -0
  261. package/templates/vue-sync/src/App.vue +135 -0
  262. package/templates/vue-sync/src/auth.ts +25 -0
  263. package/templates/vue-sync/src/index.css +339 -0
  264. package/templates/vue-sync/src/kora-worker.ts +9 -0
  265. package/templates/vue-sync/src/main.ts +47 -0
  266. package/templates/vue-sync/src/modules/todos/todo.mutations.ts +25 -0
  267. package/templates/vue-sync/src/modules/todos/todo.queries.ts +5 -0
  268. package/templates/vue-sync/src/modules/todos/todo.schema.ts +10 -0
  269. package/templates/vue-sync/src/modules/todos/useTodos.ts +32 -0
  270. package/templates/vue-sync/src/schema.ts +9 -0
  271. package/templates/vue-sync/src/vite-env.d.ts +27 -0
  272. package/templates/vue-sync/tsconfig.json.hbs +15 -0
  273. package/templates/vue-sync/vite.config.ts +91 -0
  274. package/templates/vue-tailwind/AGENTS.md +84 -0
  275. package/templates/vue-tailwind/README.md.hbs +62 -0
  276. package/templates/vue-tailwind/index.html.hbs +12 -0
  277. package/templates/vue-tailwind/kora.config.ts +12 -0
  278. package/templates/vue-tailwind/package.json.hbs +35 -0
  279. package/templates/vue-tailwind/src/App.vue +135 -0
  280. package/templates/vue-tailwind/src/index.css +7 -0
  281. package/templates/vue-tailwind/src/kora-worker.ts +9 -0
  282. package/templates/vue-tailwind/src/main.ts +31 -0
  283. package/templates/vue-tailwind/src/modules/todos/todo.mutations.ts +25 -0
  284. package/templates/vue-tailwind/src/modules/todos/todo.queries.ts +5 -0
  285. package/templates/vue-tailwind/src/modules/todos/todo.schema.ts +10 -0
  286. package/templates/vue-tailwind/src/modules/todos/useTodos.ts +32 -0
  287. package/templates/vue-tailwind/src/schema.ts +9 -0
  288. package/templates/vue-tailwind/src/vite-env.d.ts +17 -0
  289. package/templates/vue-tailwind/tsconfig.json.hbs +15 -0
  290. package/templates/vue-tailwind/vite.config.ts +75 -0
  291. package/templates/vue-tailwind-sync/.env.example +25 -0
  292. package/templates/vue-tailwind-sync/AGENTS.md +84 -0
  293. package/templates/vue-tailwind-sync/README.md.hbs +106 -0
  294. package/templates/vue-tailwind-sync/index.html.hbs +12 -0
  295. package/templates/vue-tailwind-sync/kora.config.ts +17 -0
  296. package/templates/vue-tailwind-sync/package.json.hbs +45 -0
  297. package/templates/vue-tailwind-sync/server.ts +141 -0
  298. package/templates/vue-tailwind-sync/src/App.vue +245 -0
  299. package/templates/vue-tailwind-sync/src/auth.ts +25 -0
  300. package/templates/vue-tailwind-sync/src/index.css +7 -0
  301. package/templates/vue-tailwind-sync/src/kora-worker.ts +9 -0
  302. package/templates/vue-tailwind-sync/src/main.ts +56 -0
  303. package/templates/vue-tailwind-sync/src/modules/todos/todo.mutations.ts +25 -0
  304. package/templates/vue-tailwind-sync/src/modules/todos/todo.queries.ts +5 -0
  305. package/templates/vue-tailwind-sync/src/modules/todos/todo.schema.ts +10 -0
  306. package/templates/vue-tailwind-sync/src/modules/todos/useTodos.ts +32 -0
  307. package/templates/vue-tailwind-sync/src/schema.ts +9 -0
  308. package/templates/vue-tailwind-sync/src/vite-env.d.ts +27 -0
  309. package/templates/vue-tailwind-sync/tsconfig.json.hbs +15 -0
  310. package/templates/vue-tailwind-sync/vite.config.ts +92 -0
@@ -0,0 +1,106 @@
1
+ # {{projectName}}
2
+
3
+ An offline-first application built with [Kora.js](https://ehoneahobed.github.io/kora/).
4
+
5
+ ## Getting Started
6
+
7
+ ```bash
8
+ npm run dev
9
+ ```
10
+
11
+ This starts both the Vite dev server and the Kora sync server.
12
+
13
+ - **App**: http://localhost:5173
14
+ - **Sync server**: ws://localhost:3001/kora-sync
15
+
16
+ ## Project Structure
17
+
18
+ ```
19
+ src/
20
+ schema.ts # Schema entry point
21
+ auth.ts # Auth client and OAuth callback handling
22
+ main.tsx # App initialization and Kora setup
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
30
+ kora-worker.ts # SQLite WASM web worker
31
+ index.css # Styles
32
+ server.ts # Kora sync server
33
+ kora.config.ts # Kora configuration
34
+ ```
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
+
39
+ ## Environment Variables
40
+
41
+ | Variable | Default | Description |
42
+ |----------|---------|-------------|
43
+ | `VITE_SYNC_URL` | `ws://localhost:3001/kora-sync` | WebSocket URL for the sync endpoint |
44
+ | `VITE_AUTH_URL` | current origin | HTTP URL for `/auth/*` routes |
45
+ | `PORT` | `3001` | Sync server port |
46
+ | `KORA_SERVER_DB` | `./.kora/kora-server.db` | SQLite file used by the sync server when `DATABASE_URL` is empty |
47
+ | `KORA_AUTH_DB` | `./.kora/kora-auth.db` | SQLite file used by OAuth state and linked identities when `DATABASE_URL` is empty |
48
+ | `KORA_COEP_POLICY` | `credentialless` | Dev/preview Cross-Origin-Embedder-Policy. Use `require-corp` only when every embedded resource opts in. |
49
+ | `DATABASE_URL` | (none) | PostgreSQL connection string for production sync server deployments |
50
+ | `KORA_SYNC_PATH` | `/kora-sync` | WebSocket path exposed by the sync server |
51
+ | `KORA_AUTH_SECRET` | (none) | Enables built-in `/auth/*` routes and authenticated sync when set |
52
+ | `KORA_GOOGLE_CLIENT_ID` | (none) | Enables Google OAuth when set with `KORA_GOOGLE_REDIRECT_URI` |
53
+ | `KORA_GOOGLE_CLIENT_SECRET` | (none) | Google OAuth client secret for confidential web clients |
54
+ | `KORA_GOOGLE_REDIRECT_URI` | (none) | OAuth callback URL, usually your app URL that handles `code` and `state` |
55
+ | `KORA_OAUTH_PKCE` | `true` when no client secret | Enables PKCE for public desktop/mobile OAuth clients |
56
+ | `KORA_ADMIN_TOKEN` | (none) | Protects `/__kora`, `/__kora/status`, and `/__kora/events` |
57
+ | `KORA_METRICS_TOKEN` | (none) | Protects `/__kora/metrics` |
58
+ | `KORA_BACKUP_TOKEN` | (none) | Protects server backup and restore endpoints |
59
+
60
+ ## Authentication
61
+
62
+ Set `KORA_AUTH_SECRET` to enable built-in auth on the sync server. Generate a secret with:
63
+
64
+ ```bash
65
+ node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))"
66
+ ```
67
+
68
+ The template already creates `src/auth.ts`, wraps the app in `AuthProvider`, and wires sync with `createKoraAuthSync({ authClient, schema })`. To enable Google OAuth, set:
69
+
70
+ ```bash
71
+ KORA_AUTH_SECRET=...
72
+ KORA_GOOGLE_CLIENT_ID=...
73
+ KORA_GOOGLE_CLIENT_SECRET=...
74
+ KORA_GOOGLE_REDIRECT_URI=http://localhost:5173
75
+ ```
76
+
77
+ 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).
78
+
79
+ ## Scripts
80
+
81
+ | Script | Description |
82
+ |--------|-------------|
83
+ | `npm run dev` | Start dev server + sync server |
84
+ | `npm run dev:server` | Start sync server only |
85
+ | `npm run build` | Build for production |
86
+ | `npm run preview` | Preview production build |
87
+
88
+ ## Deployment
89
+
90
+ The client and sync server must be deployed separately:
91
+
92
+ - **Client**: Any static host (Vercel, Netlify, Cloudflare Pages)
93
+ - **Sync server**: Any Node.js host with WebSocket support (Railway, Render, Fly.io)
94
+
95
+ Set `VITE_SYNC_URL` to your deployed sync server URL when building:
96
+
97
+ ```bash
98
+ VITE_SYNC_URL=wss://your-server.example.com/kora-sync npm run build
99
+ ```
100
+
101
+ ## Learn More
102
+
103
+ - [Documentation](https://ehoneahobed.github.io/kora/)
104
+ - [Storage Configuration](https://ehoneahobed.github.io/kora/guide/storage-configuration)
105
+ - [Sync Configuration](https://ehoneahobed.github.io/kora/guide/sync-configuration)
106
+ - [Deployment Guide](https://ehoneahobed.github.io/kora/guide/deployment)
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>{{projectName}}</title>
7
+ </head>
8
+ <body>
9
+ <div id="app"></div>
10
+ <script type="module" src="/src/main.ts"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,17 @@
1
+ import { defineConfig } from 'korajs/config'
2
+
3
+ export default defineConfig({
4
+ schema: './src/schema.ts',
5
+ dev: {
6
+ port: 5173,
7
+ sync: {
8
+ enabled: true,
9
+ port: 3001,
10
+ store: 'sqlite',
11
+ },
12
+ watch: {
13
+ enabled: true,
14
+ debounceMs: 300,
15
+ },
16
+ },
17
+ })
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "{{projectName}}",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "kora dev",
8
+ "dev:server": "tsx server.ts",
9
+ "build": "vue-tsc --noEmit && vite build",
10
+ "start": "node --import tsx server.ts",
11
+ "preview": "vite preview"
12
+ },
13
+ "dependencies": {
14
+ "korajs": "{{koraVersion}}",
15
+ "@korajs/auth": "{{koraVersion}}",
16
+ "@korajs/vue": "{{koraVersion}}",
17
+ "@korajs/store": "{{koraVersion}}",
18
+ "@sqlite.org/sqlite-wasm": ">=3.51.0-build1",
19
+ "vue": "^3.5.0",
20
+ "ws": "^8.18.0",
21
+ "yjs": "^13.6.30"
22
+ },
23
+ "pnpm": {
24
+ "onlyBuiltDependencies": [
25
+ "better-sqlite3",
26
+ "esbuild",
27
+ "protobufjs"
28
+ ]
29
+ },
30
+ "devDependencies": {
31
+ "@korajs/cli": "{{koraVersion}}",
32
+ "@korajs/server": "{{koraVersion}}",
33
+ "@types/ws": "^8.5.0",
34
+ "@vitejs/plugin-vue": "^5.2.0",
35
+ "better-sqlite3": "^12.9.0",
36
+ "postgres": "^3.4.0",
37
+ "tsx": "^4.19.0",
38
+ "typescript": "^5.7.0",
39
+ "vite": "^6.0.0",
40
+ "vue-tsc": "^2.2.0"
41
+ }
42
+ }
@@ -0,0 +1,141 @@
1
+ import { existsSync, readFileSync } from 'node:fs'
2
+ import {
3
+ type CreateKoraAuthServerOptions,
4
+ createKoraAuthServer,
5
+ createPostgresOAuthStores,
6
+ createPostgresUserStore,
7
+ createSqliteOAuthStores,
8
+ createSqliteUserStore,
9
+ googleProvider,
10
+ } from '@korajs/auth/server'
11
+ import {
12
+ createPostgresServerStore,
13
+ createProductionServer,
14
+ createSqliteServerStore,
15
+ } from '@korajs/server'
16
+ import schema from './src/schema'
17
+
18
+ loadLocalEnv()
19
+
20
+ function loadLocalEnv(mode = process.env.NODE_ENV || 'development') {
21
+ const existingKeys = new Set(Object.keys(process.env))
22
+ for (const file of ['.env', '.env.local', `.env.${mode}`, `.env.${mode}.local`]) {
23
+ if (!existsSync(file)) continue
24
+ for (const [key, value] of Object.entries(parseEnvFile(readFileSync(file, 'utf8')))) {
25
+ if (!existingKeys.has(key)) {
26
+ process.env[key] = value
27
+ }
28
+ }
29
+ }
30
+ }
31
+
32
+ function parseEnvFile(contents: string): Record<string, string> {
33
+ const env: Record<string, string> = {}
34
+ for (const rawLine of contents.split(/\r?\n/)) {
35
+ const line = rawLine.trim()
36
+ if (!line || line.startsWith('#')) continue
37
+ const normalized = line.startsWith('export ') ? line.slice('export '.length).trim() : line
38
+ const equalsIndex = normalized.indexOf('=')
39
+ if (equalsIndex <= 0) continue
40
+ const key = normalized.slice(0, equalsIndex).trim()
41
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) continue
42
+ env[key] = parseEnvValue(normalized.slice(equalsIndex + 1).trim())
43
+ }
44
+ return env
45
+ }
46
+
47
+ function parseEnvValue(value: string): string {
48
+ const quote = value[0]
49
+ if ((quote === '"' || quote === "'") && value[value.length - 1] === quote) {
50
+ const inner = value.slice(1, -1)
51
+ return quote === '"' ? inner.replace(/\\n/g, '\n').replace(/\\r/g, '\r') : inner
52
+ }
53
+ const commentIndex = value.search(/\s#/)
54
+ return (commentIndex >= 0 ? value.slice(0, commentIndex) : value).trim()
55
+ }
56
+
57
+ async function createStore() {
58
+ if (process.env.DATABASE_URL) {
59
+ return createPostgresServerStore({
60
+ connectionString: process.env.DATABASE_URL,
61
+ })
62
+ }
63
+
64
+ return createSqliteServerStore({
65
+ filename: process.env.KORA_SERVER_DB || './.kora/kora-server.db',
66
+ })
67
+ }
68
+
69
+ async function start() {
70
+ const store = await createStore()
71
+ await store.setSchema(schema)
72
+
73
+ const syncPath = process.env.KORA_SYNC_PATH || '/kora-sync'
74
+ const auth = await createAuth()
75
+ const server = createProductionServer({
76
+ store,
77
+ port: Number(process.env.PORT) || 3001,
78
+ staticDir: './dist',
79
+ syncPath,
80
+ httpRoutes: auth ? [{ path: '/auth', handle: auth.handleRequest }] : undefined,
81
+ syncOptions: {
82
+ schemaVersion: schema.version,
83
+ ...(auth ? { auth: auth.auth } : {}),
84
+ },
85
+ operationalAuth: {
86
+ adminToken: process.env.KORA_ADMIN_TOKEN,
87
+ metricsToken: process.env.KORA_METRICS_TOKEN,
88
+ backupToken: process.env.KORA_BACKUP_TOKEN,
89
+ },
90
+ })
91
+
92
+ const url = await server.start()
93
+ console.log(`Kora app running at ${url}`)
94
+ console.log(` Sync endpoint: ${url.replace('http', 'ws')}${syncPath}`)
95
+ if (auth) console.log(` Auth endpoint: ${url}/auth`)
96
+ }
97
+
98
+ void start()
99
+
100
+ async function createAuth() {
101
+ if (!process.env.KORA_AUTH_SECRET) {
102
+ return null
103
+ }
104
+
105
+ const oauth = await createOAuthConfig()
106
+ // Users and token revocations persist in the same database (the user store's
107
+ // revocation store is used automatically), so sign-outs survive restarts.
108
+ const userStore = process.env.DATABASE_URL
109
+ ? await createPostgresUserStore({ connectionString: process.env.DATABASE_URL })
110
+ : await createSqliteUserStore({ filename: process.env.KORA_AUTH_DB || './.kora/kora-auth.db' })
111
+ return createKoraAuthServer({
112
+ jwtSecret: process.env.KORA_AUTH_SECRET,
113
+ userStore,
114
+ ...(oauth ? { oauth } : {}),
115
+ })
116
+ }
117
+
118
+ async function createOAuthConfig(): Promise<CreateKoraAuthServerOptions['oauth'] | undefined> {
119
+ if (!process.env.KORA_GOOGLE_CLIENT_ID || !process.env.KORA_GOOGLE_REDIRECT_URI) {
120
+ return undefined
121
+ }
122
+
123
+ const oauthStores = process.env.DATABASE_URL
124
+ ? await createPostgresOAuthStores({ connectionString: process.env.DATABASE_URL })
125
+ : await createSqliteOAuthStores({
126
+ filename: process.env.KORA_AUTH_DB || './.kora/kora-auth.db',
127
+ })
128
+
129
+ return {
130
+ providers: [
131
+ googleProvider({
132
+ clientId: process.env.KORA_GOOGLE_CLIENT_ID,
133
+ clientSecret: process.env.KORA_GOOGLE_CLIENT_SECRET,
134
+ redirectUri: process.env.KORA_GOOGLE_REDIRECT_URI,
135
+ pkce: process.env.KORA_OAUTH_PKCE === 'true' || !process.env.KORA_GOOGLE_CLIENT_SECRET,
136
+ }),
137
+ ],
138
+ stateStore: oauthStores.stateStore,
139
+ linkedIdentityStore: oauthStores.linkedIdentityStore,
140
+ }
141
+ }
@@ -0,0 +1,135 @@
1
+ <script setup lang="ts">
2
+ import { useAuth } from '@korajs/auth/vue'
3
+ import { useSyncStatus } from '@korajs/vue'
4
+ import { computed, ref } from 'vue'
5
+ import { useTodos } from './modules/todos/useTodos'
6
+
7
+ type Filter = 'all' | 'active' | 'completed'
8
+
9
+ const { allTodos, activeTodos, completedTodos, addTodo, toggleTodo, deleteTodo } = useTodos()
10
+ const syncStatus = useSyncStatus()
11
+ const { user, isAuthenticated, signInWithOAuth, signOut, error } = useAuth()
12
+
13
+ const filter = ref<Filter>('all')
14
+ const input = ref('')
15
+
16
+ const filteredTodos = computed(() => {
17
+ if (filter.value === 'active') return activeTodos.value
18
+ if (filter.value === 'completed') return completedTodos.value
19
+ return allTodos.value
20
+ })
21
+
22
+ function handleSubmit(): void {
23
+ const title = input.value.trim()
24
+ if (!title) return
25
+ addTodo.mutate({ title })
26
+ input.value = ''
27
+ }
28
+
29
+ function clearCompleted(): void {
30
+ for (const todo of completedTodos.value) {
31
+ deleteTodo.mutate(todo.id)
32
+ }
33
+ }
34
+
35
+ function formatTime(timestamp: number): string {
36
+ const date = new Date(timestamp)
37
+ const now = new Date()
38
+ if (date.toDateString() === now.toDateString()) {
39
+ return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
40
+ }
41
+ return date.toLocaleDateString([], { month: 'short', day: 'numeric' })
42
+ }
43
+ </script>
44
+
45
+ <template>
46
+ <div class="app">
47
+ <div class="header">
48
+ <h1>My Tasks</h1>
49
+ <div class="header-actions">
50
+ <div class="sync-badge">
51
+ <span :class="['sync-dot', syncStatus.status]" />
52
+ <span>{{ syncStatus.status }}</span>
53
+ </div>
54
+ <button v-if="isAuthenticated" type="button" class="auth-button" @click="signOut()">
55
+ {{ user?.email || 'Sign out' }}
56
+ </button>
57
+ <button v-else type="button" class="auth-button" @click="signInWithOAuth('google')">
58
+ Sign in
59
+ </button>
60
+ </div>
61
+ </div>
62
+
63
+ <div v-if="error" class="auth-error">{{ error }}</div>
64
+
65
+ <div class="stats">
66
+ <div class="stat-card">
67
+ <div class="label">Total</div>
68
+ <div class="value muted">{{ allTodos.length }}</div>
69
+ </div>
70
+ <div class="stat-card">
71
+ <div class="label">Remaining</div>
72
+ <div class="value warning">{{ activeTodos.length }}</div>
73
+ </div>
74
+ <div class="stat-card">
75
+ <div class="label">Done</div>
76
+ <div class="value success">{{ completedTodos.length }}</div>
77
+ </div>
78
+ </div>
79
+
80
+ <form class="add-form" @submit.prevent="handleSubmit">
81
+ <input v-model="input" type="text" placeholder="What needs to be done?" />
82
+ <button type="submit" :disabled="!input.trim()">Add</button>
83
+ </form>
84
+
85
+ <div class="filters">
86
+ <button
87
+ v-for="f in (['all', 'active', 'completed'] as const)"
88
+ :key="f"
89
+ type="button"
90
+ :class="['filter-btn', { active: filter === f }]"
91
+ @click="filter = f"
92
+ >
93
+ {{ f.charAt(0).toUpperCase() + f.slice(1) }}
94
+ <span class="badge">
95
+ {{
96
+ f === 'all'
97
+ ? allTodos.length
98
+ : f === 'active'
99
+ ? activeTodos.length
100
+ : completedTodos.length
101
+ }}
102
+ </span>
103
+ </button>
104
+ </div>
105
+
106
+ <div class="todo-list">
107
+ <div v-if="filteredTodos.length === 0" class="empty-state">
108
+ <template v-if="filter === 'all'">No tasks yet. Add one above!</template>
109
+ <template v-else-if="filter === 'active'">All caught up! No active tasks.</template>
110
+ <template v-else>No completed tasks yet.</template>
111
+ </div>
112
+ <div v-for="todo in filteredTodos" v-else :key="todo.id" class="todo-item">
113
+ <button
114
+ type="button"
115
+ :class="['toggle', { checked: todo.completed }]"
116
+ @click="toggleTodo.mutate(todo.id, { completed: !todo.completed })"
117
+ >
118
+ {{ todo.completed ? '✓' : '' }}
119
+ </button>
120
+ <span :class="['title', { done: todo.completed }]">{{ String(todo.title) }}</span>
121
+ <span v-if="todo.createdAt" class="time">{{ formatTime(Number(todo.createdAt)) }}</span>
122
+ <button type="button" class="delete-btn" @click="deleteTodo.mutate(todo.id)">×</button>
123
+ </div>
124
+ </div>
125
+
126
+ <div v-if="allTodos.length > 0" class="footer">
127
+ <span>{{ activeTodos.length }} item{{ activeTodos.length !== 1 ? 's' : '' }} left</span>
128
+ <button v-if="completedTodos.length > 0" type="button" @click="clearCompleted">
129
+ Clear completed
130
+ </button>
131
+ </div>
132
+
133
+ <p class="branding">Powered by Kora — offline-first, real-time sync</p>
134
+ </div>
135
+ </template>
@@ -0,0 +1,25 @@
1
+ import { createKoraAuth } from '@korajs/auth'
2
+
3
+ export const authServerUrl =
4
+ import.meta.env.VITE_AUTH_URL || `${window.location.protocol}//${window.location.host}`
5
+
6
+ export const authClient = createKoraAuth({
7
+ serverUrl: authServerUrl,
8
+ })
9
+
10
+ export async function completeOAuthCallbackFromLocation(): Promise<void> {
11
+ const url = new URL(window.location.href)
12
+ const code = url.searchParams.get('code')
13
+ const state = url.searchParams.get('state')
14
+ const provider = url.searchParams.get('provider') || 'google'
15
+
16
+ if (!code || !state) {
17
+ return
18
+ }
19
+
20
+ await authClient.completeOAuthSignIn(provider, { code, state })
21
+ url.searchParams.delete('code')
22
+ url.searchParams.delete('state')
23
+ url.searchParams.delete('provider')
24
+ window.history.replaceState({}, document.title, `${url.pathname}${url.search}${url.hash}`)
25
+ }