@korajs/cli 1.0.0-beta.12 → 1.0.0-beta.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -107
- package/dist/bin.cjs +808 -340
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +588 -174
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-G2PBYMMA.js → chunk-7Y4J2GXP.js} +168 -153
- package/dist/chunk-7Y4J2GXP.js.map +1 -0
- package/dist/{chunk-Z7GCXMGW.js → chunk-BURFQVMV.js} +44 -9
- package/dist/chunk-BURFQVMV.js.map +1 -0
- package/dist/{chunk-4IKCHRJ6.js → chunk-TVIRMDER.js} +122 -112
- package/dist/chunk-TVIRMDER.js.map +1 -0
- package/dist/create.cjs +63 -28
- package/dist/create.cjs.map +1 -1
- package/dist/create.js +2 -2
- package/dist/index.cjs +41 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -1
- package/dist/index.d.ts +21 -1
- package/dist/index.js +8 -2
- package/dist/{studio-server-NIFKZI4F.js → studio-server-XLGZNGG5.js} +11 -2
- package/dist/studio-server-XLGZNGG5.js.map +1 -0
- package/dist/vite.cjs +351 -0
- package/dist/vite.cjs.map +1 -0
- package/dist/vite.d.cts +161 -0
- package/dist/vite.d.ts +161 -0
- package/dist/vite.js +321 -0
- package/dist/vite.js.map +1 -0
- package/package.json +18 -8
- package/templates/react-basic/AGENTS.md +5 -5
- package/templates/react-basic/vite.config.ts +4 -1
- package/templates/react-sync/.env.example +1 -1
- package/templates/react-sync/AGENTS.md +5 -5
- package/templates/react-sync/server.ts +8 -0
- package/templates/react-sync/src/vite-env.d.ts +1 -0
- package/templates/react-sync/vite.config.ts +4 -1
- package/templates/react-tailwind/AGENTS.md +5 -5
- package/templates/react-tailwind/vite.config.ts +10 -1
- package/templates/react-tailwind-sync/.env.example +1 -1
- package/templates/react-tailwind-sync/AGENTS.md +9 -7
- package/templates/react-tailwind-sync/server.ts +8 -0
- package/templates/react-tailwind-sync/src/App.tsx +1 -1
- package/templates/react-tailwind-sync/src/kora.ts +32 -0
- package/templates/react-tailwind-sync/src/main.tsx +1 -23
- package/templates/react-tailwind-sync/src/modules/todos/todo.mutations.ts +4 -8
- package/templates/react-tailwind-sync/src/modules/todos/todo.queries.ts +2 -2
- package/templates/react-tailwind-sync/src/modules/todos/useTodos.ts +1 -1
- package/templates/react-tailwind-sync/src/vite-env.d.ts +1 -0
- package/templates/react-tailwind-sync/vite.config.ts +10 -1
- package/templates/svelte-basic/AGENTS.md +4 -4
- package/templates/svelte-basic/package.json.hbs +6 -0
- package/templates/svelte-basic/src/App.svelte +2 -1
- package/templates/svelte-basic/vite.config.ts +4 -1
- package/templates/svelte-sync/.env.example +1 -1
- package/templates/svelte-sync/AGENTS.md +4 -4
- package/templates/svelte-sync/server.ts +8 -0
- package/templates/svelte-sync/src/App.svelte +2 -1
- package/templates/svelte-sync/vite.config.ts +4 -1
- package/templates/svelte-tailwind/AGENTS.md +4 -4
- package/templates/svelte-tailwind/package.json.hbs +7 -1
- package/templates/svelte-tailwind/src/App.svelte +2 -1
- package/templates/svelte-tailwind/vite.config.ts +10 -1
- package/templates/svelte-tailwind-sync/.env.example +1 -1
- package/templates/svelte-tailwind-sync/AGENTS.md +4 -4
- package/templates/svelte-tailwind-sync/package.json.hbs +1 -1
- package/templates/svelte-tailwind-sync/server.ts +8 -0
- package/templates/svelte-tailwind-sync/src/App.svelte +2 -1
- package/templates/svelte-tailwind-sync/vite.config.ts +10 -1
- package/templates/tauri-react/.env.example +1 -1
- package/templates/tauri-react/AGENTS.md +5 -5
- package/templates/tauri-react/README.md.hbs +2 -2
- package/templates/tauri-react/package.json.hbs +1 -1
- package/templates/tauri-react/server.ts +10 -2
- package/templates/tauri-react/src/vite-env.d.ts +1 -0
- package/templates/vue-basic/AGENTS.md +4 -4
- package/templates/vue-basic/package.json.hbs +6 -0
- package/templates/vue-basic/vite.config.ts +4 -1
- package/templates/vue-sync/.env.example +1 -1
- package/templates/vue-sync/AGENTS.md +4 -4
- package/templates/vue-sync/server.ts +8 -0
- package/templates/vue-sync/vite.config.ts +4 -1
- package/templates/vue-tailwind/AGENTS.md +4 -4
- package/templates/vue-tailwind/package.json.hbs +6 -0
- package/templates/vue-tailwind/vite.config.ts +4 -1
- package/templates/vue-tailwind-sync/.env.example +1 -1
- package/templates/vue-tailwind-sync/AGENTS.md +4 -4
- package/templates/vue-tailwind-sync/server.ts +8 -0
- package/templates/vue-tailwind-sync/vite.config.ts +4 -1
- package/dist/chunk-4IKCHRJ6.js.map +0 -1
- package/dist/chunk-G2PBYMMA.js.map +0 -1
- package/dist/chunk-Z7GCXMGW.js.map +0 -1
- package/dist/studio-server-NIFKZI4F.js.map +0 -1
|
@@ -13,17 +13,23 @@
|
|
|
13
13
|
"korajs": "{{koraVersion}}",
|
|
14
14
|
"@korajs/svelte": "{{koraVersion}}",
|
|
15
15
|
"@korajs/store": "{{koraVersion}}",
|
|
16
|
-
"@lucide/svelte": "^0.
|
|
16
|
+
"@lucide/svelte": "^0.479.0",
|
|
17
17
|
"@sqlite.org/sqlite-wasm": ">=3.51.0-build1",
|
|
18
18
|
"svelte": "^5.0.0",
|
|
19
19
|
"yjs": "^13.6.30"
|
|
20
20
|
},
|
|
21
|
+
"pnpm": {
|
|
22
|
+
"onlyBuiltDependencies": [
|
|
23
|
+
"esbuild"
|
|
24
|
+
]
|
|
25
|
+
},
|
|
21
26
|
"devDependencies": {
|
|
22
27
|
"@korajs/cli": "{{koraVersion}}",
|
|
23
28
|
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
|
24
29
|
"@tailwindcss/vite": "^4.0.0",
|
|
25
30
|
"svelte-check": "^4.1.0",
|
|
26
31
|
"tailwindcss": "^4.0.0",
|
|
32
|
+
"tsx": "^4.19.0",
|
|
27
33
|
"typescript": "^5.7.0",
|
|
28
34
|
"vite": "^6.0.0"
|
|
29
35
|
}
|
|
@@ -7,7 +7,8 @@ type Filter = 'all' | 'active' | 'completed'
|
|
|
7
7
|
const { allTodos, activeTodos, completedTodos, addTodo, toggleTodo, deleteTodo } =
|
|
8
8
|
createTodosStores()
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
// biome-ignore lint/style/useConst: reassigned in the markup, which Biome does not see
|
|
11
|
+
let filter = $state<Filter>('all')
|
|
11
12
|
let input = $state('')
|
|
12
13
|
|
|
13
14
|
const filteredTodos = $derived(
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { copyFileSync, existsSync, readdirSync } from 'node:fs'
|
|
2
2
|
import { join, resolve } from 'node:path'
|
|
3
|
+
import { koraServiceWorker } from '@korajs/cli/vite'
|
|
3
4
|
import { svelte } from '@sveltejs/vite-plugin-svelte'
|
|
4
5
|
import tailwindcss from '@tailwindcss/vite'
|
|
5
6
|
import type { Plugin } from 'vite'
|
|
@@ -44,8 +45,16 @@ function sqliteWasmHotfix(): Plugin {
|
|
|
44
45
|
}
|
|
45
46
|
}
|
|
46
47
|
|
|
48
|
+
// koraServiceWorker() (build only, keep it last): precaches the built app shell so the
|
|
49
|
+
// app opens offline, with a "new version available" reload prompt. See @korajs/cli/vite.
|
|
47
50
|
export default defineConfig({
|
|
48
|
-
plugins: [
|
|
51
|
+
plugins: [
|
|
52
|
+
svelte(),
|
|
53
|
+
tailwindcss(),
|
|
54
|
+
crossOriginIsolation(),
|
|
55
|
+
sqliteWasmHotfix(),
|
|
56
|
+
koraServiceWorker(),
|
|
57
|
+
],
|
|
49
58
|
worker: { format: 'es' },
|
|
50
59
|
optimizeDeps: {
|
|
51
60
|
exclude: ['@sqlite.org/sqlite-wasm', '@korajs/store'],
|
|
@@ -7,7 +7,7 @@ PORT=3001
|
|
|
7
7
|
|
|
8
8
|
# Server database
|
|
9
9
|
# Leave DATABASE_URL empty to use SQLite at KORA_SERVER_DB.
|
|
10
|
-
KORA_SERVER_DB
|
|
10
|
+
KORA_SERVER_DB=./.kora/kora-server.db
|
|
11
11
|
DATABASE_URL=
|
|
12
12
|
|
|
13
13
|
# Operational endpoints (/__kora, /__kora/status, /__kora/events, /__kora/metrics, backups)
|
|
@@ -12,7 +12,7 @@ This is a **Kora.js** application: an offline-first app where all data lives in
|
|
|
12
12
|
2. **Never fetch application data over HTTP.** Do not add REST or GraphQL calls for app data, and do not talk to the sync server directly. Read and write through Kora collections only; sync happens automatically in the background.
|
|
13
13
|
3. **Await readiness before direct collection access.** Outside the UI bindings, `await app.ready` before calling `app.<collection>` methods. The bindings handle this for you inside components.
|
|
14
14
|
4. **Offline must keep working.** Any feature you add must function with the network off. Never gate a write or a read on connectivity. If you find yourself checking `navigator.onLine` before a data operation, you are doing it wrong.
|
|
15
|
-
5. **Surface mutation errors.** Fire-and-forget mutate calls
|
|
15
|
+
5. **Surface mutation errors.** Fire-and-forget mutate calls put errors into the mutation state. Always render the mutation's `error` in the UI or handle the promise from the async variant. Silent failure is the worst failure.
|
|
16
16
|
6. **Do not touch `src/kora-worker.ts`.** It wires the SQLite WASM binary URL for both dev and production builds. Changing it breaks production builds in ways that only show up after deploy.
|
|
17
17
|
7. **Do not add a state management library for server or app data.** Kora's reactive queries are the store. Local UI state (form inputs, toggles) can use the framework's normal state tools.
|
|
18
18
|
|
|
@@ -52,12 +52,12 @@ export default defineSchema({
|
|
|
52
52
|
})
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
If you
|
|
55
|
+
If you change a collection's shape, increment `version` and add a `migrations` entry for it (`migrate().addField(...)`): each device migrates its local database on its next open. `npx kora migrate` generates the matching migration for server databases and a transform stub for clients still on the older version.
|
|
56
56
|
|
|
57
57
|
## Project conventions
|
|
58
58
|
|
|
59
59
|
- Feature code lives in `src/modules/<feature>/` with the pattern: `<feature>.schema.ts` (collection definition, imported into `src/schema.ts`), `<feature>.queries.ts` (query builders), `<feature>.mutations.ts` (mutation functions taking a collection accessor).
|
|
60
|
-
- Conflict handling is declarative. Concurrent edits merge automatically (last-write-wins per field,
|
|
60
|
+
- Conflict handling is declarative. Concurrent edits merge automatically (last-write-wins per field, arrays as multisets that keep every device's additions and removals, objects per top-level key). If a field needs domain-specific merging (counters, quantities), add a `resolve` function in the schema rather than writing sync logic.
|
|
61
61
|
- `kora.config.ts` controls the dev environment (ports, sync server, schema watcher).
|
|
62
62
|
|
|
63
63
|
## Commands
|
|
@@ -73,4 +73,4 @@ Sync is configured in `src/main.*` via `createApp({ sync: { url, authClient } })
|
|
|
73
73
|
|
|
74
74
|
## Svelte bindings
|
|
75
75
|
|
|
76
|
-
Kora's Svelte package exposes store-based bindings from `@korajs/svelte`, wired through the provider set up in the app entry. Queries are reactive stores
|
|
76
|
+
Kora's Svelte package exposes store-based bindings from `@korajs/svelte`, wired through the provider set up in the app entry. Queries are reactive stores over the local database (no network, no spinner; `[]` until the first local result); mutations expose error state that must be surfaced in the UI.
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"@korajs/auth": "{{koraVersion}}",
|
|
17
17
|
"@korajs/svelte": "{{koraVersion}}",
|
|
18
18
|
"@korajs/store": "{{koraVersion}}",
|
|
19
|
-
"@lucide/svelte": "^0.
|
|
19
|
+
"@lucide/svelte": "^0.479.0",
|
|
20
20
|
"@sqlite.org/sqlite-wasm": ">=3.51.0-build1",
|
|
21
21
|
"svelte": "^5.0.0",
|
|
22
22
|
"ws": "^8.18.0",
|
|
@@ -3,7 +3,9 @@ import {
|
|
|
3
3
|
type CreateKoraAuthServerOptions,
|
|
4
4
|
createKoraAuthServer,
|
|
5
5
|
createPostgresOAuthStores,
|
|
6
|
+
createPostgresUserStore,
|
|
6
7
|
createSqliteOAuthStores,
|
|
8
|
+
createSqliteUserStore,
|
|
7
9
|
googleProvider,
|
|
8
10
|
} from '@korajs/auth/server'
|
|
9
11
|
import {
|
|
@@ -101,8 +103,14 @@ async function createAuth() {
|
|
|
101
103
|
}
|
|
102
104
|
|
|
103
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' })
|
|
104
111
|
return createKoraAuthServer({
|
|
105
112
|
jwtSecret: process.env.KORA_AUTH_SECRET,
|
|
113
|
+
userStore,
|
|
106
114
|
...(oauth ? { oauth } : {}),
|
|
107
115
|
})
|
|
108
116
|
}
|
|
@@ -21,7 +21,8 @@ const auth = createAuthStore()
|
|
|
21
21
|
const todos = createTodosStores()
|
|
22
22
|
const { allTodos, activeTodos, completedTodos, addTodo, toggleTodo, deleteTodo } = todos
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
// biome-ignore lint/style/useConst: reassigned in the markup, which Biome does not see
|
|
25
|
+
let filter = $state<Filter>('all')
|
|
25
26
|
let input = $state('')
|
|
26
27
|
|
|
27
28
|
const filteredTodos = $derived(
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { copyFileSync, existsSync, readdirSync } from 'node:fs'
|
|
2
2
|
import { join, resolve } from 'node:path'
|
|
3
|
+
import { koraServiceWorker } from '@korajs/cli/vite'
|
|
3
4
|
import { svelte } from '@sveltejs/vite-plugin-svelte'
|
|
4
5
|
import tailwindcss from '@tailwindcss/vite'
|
|
5
6
|
import type { Plugin } from 'vite'
|
|
@@ -57,8 +58,16 @@ function sqliteWasmHotfix(): Plugin {
|
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
|
|
61
|
+
// koraServiceWorker() (build only, keep it last): precaches the built app shell so the
|
|
62
|
+
// app opens offline, with a "new version available" reload prompt. See @korajs/cli/vite.
|
|
60
63
|
export default defineConfig({
|
|
61
|
-
plugins: [
|
|
64
|
+
plugins: [
|
|
65
|
+
svelte(),
|
|
66
|
+
tailwindcss(),
|
|
67
|
+
crossOriginIsolation(),
|
|
68
|
+
sqliteWasmHotfix(),
|
|
69
|
+
koraServiceWorker(),
|
|
70
|
+
],
|
|
62
71
|
worker: {
|
|
63
72
|
format: 'es',
|
|
64
73
|
},
|
|
@@ -9,7 +9,7 @@ PORT=3001
|
|
|
9
9
|
# Server database
|
|
10
10
|
# Leave DATABASE_URL empty to use SQLite at KORA_SERVER_DB.
|
|
11
11
|
# Set DATABASE_URL for cloud Postgres deployments.
|
|
12
|
-
KORA_SERVER_DB
|
|
12
|
+
KORA_SERVER_DB=./.kora/kora-server.db
|
|
13
13
|
DATABASE_URL=
|
|
14
14
|
|
|
15
15
|
# Operational endpoints (/__kora, /__kora/status, /__kora/events, /__kora/metrics, backups)
|
|
@@ -12,7 +12,7 @@ This is a **Kora.js** application: an offline-first app where all data lives in
|
|
|
12
12
|
2. **Never fetch application data over HTTP.** Do not add REST or GraphQL calls for app data, and do not talk to the sync server directly. Read and write through Kora collections only; sync happens automatically in the background.
|
|
13
13
|
3. **Await readiness before direct collection access.** Outside the UI bindings, `await app.ready` before calling `app.<collection>` methods. The bindings handle this for you inside components.
|
|
14
14
|
4. **Offline must keep working.** Any feature you add must function with the network off. Never gate a write or a read on connectivity. If you find yourself checking `navigator.onLine` before a data operation, you are doing it wrong.
|
|
15
|
-
5. **Surface mutation errors.** Fire-and-forget mutate calls
|
|
15
|
+
5. **Surface mutation errors.** Fire-and-forget mutate calls put errors into the mutation state. Always render the mutation's `error` in the UI or handle the promise from the async variant. Silent failure is the worst failure.
|
|
16
16
|
6. **Do not touch `src/kora-worker.ts`.** It wires the SQLite WASM binary URL for both dev and production builds. Changing it breaks production builds in ways that only show up after deploy.
|
|
17
17
|
7. **Do not add a state management library for server or app data.** Kora's reactive queries are the store. Local UI state (form inputs, toggles) can use the framework's normal state tools.
|
|
18
18
|
|
|
@@ -52,12 +52,12 @@ export default defineSchema({
|
|
|
52
52
|
})
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
If you
|
|
55
|
+
If you change a collection's shape, increment `version` and add a `migrations` entry for it (`migrate().addField(...)`): each device migrates its local database on its next open. `npx kora migrate` generates the matching migration for server databases and a transform stub for clients still on the older version.
|
|
56
56
|
|
|
57
57
|
## Project conventions
|
|
58
58
|
|
|
59
59
|
- Feature code lives in `src/modules/<feature>/` with the pattern: `<feature>.schema.ts` (collection definition, imported into `src/schema.ts`), `<feature>.queries.ts` (query builders), `<feature>.mutations.ts` (mutation functions taking a collection accessor).
|
|
60
|
-
- Conflict handling is declarative. Concurrent edits merge automatically (last-write-wins per field,
|
|
60
|
+
- Conflict handling is declarative. Concurrent edits merge automatically (last-write-wins per field, arrays as multisets that keep every device's additions and removals, objects per top-level key). If a field needs domain-specific merging (counters, quantities), add a `resolve` function in the schema rather than writing sync logic.
|
|
61
61
|
- `kora.config.ts` controls the dev environment (ports, sync server, schema watcher).
|
|
62
62
|
|
|
63
63
|
## Commands
|
|
@@ -77,14 +77,14 @@ Sync is configured in `src/main.*` via `createApp({ sync: { url, authClient } })
|
|
|
77
77
|
import { useCollection, useMutation, useQuery, useSyncStatus } from '@korajs/react'
|
|
78
78
|
|
|
79
79
|
const todos = useCollection('todos')
|
|
80
|
-
const rows = useQuery(orderedTodos(todos)) // reactive
|
|
80
|
+
const rows = useQuery(orderedTodos(todos)) // reactive; [] on the very first render
|
|
81
81
|
const addTodo = useMutation((data) => todos.insert(data))
|
|
82
82
|
addTodo.mutate({ title: 'x' }) // fire-and-forget; errors land in addTodo.error
|
|
83
83
|
await addTodo.mutateAsync({ title: 'x' }) // throws on failure; use when you need the error
|
|
84
84
|
const status = useSyncStatus() // status.status, status.pendingOperations
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
-
Rules: always render `mutation.error` somewhere. The app must work under React StrictMode (the framework's hooks are StrictMode-safe; keep `<StrictMode>` in `src/main.tsx`). `useQuery` returns
|
|
87
|
+
Rules: always render `mutation.error` somewhere. The app must work under React StrictMode (the framework's hooks are StrictMode-safe; keep `<StrictMode>` in `src/main.tsx`). `useQuery` reads the local store: no network, no spinner. Its very first render returns `[]` before the local query has run; use `useQueryState` when you must tell "loading" from "no rows".
|
|
88
88
|
|
|
89
89
|
## Tauri specifics
|
|
90
90
|
|
|
@@ -136,8 +136,8 @@ Users can also skip setup and use the app offline — they can connect later fro
|
|
|
136
136
|
| `VITE_SYNC_URL` | (none) | Pre-configure sync URL at build time |
|
|
137
137
|
| `VITE_AUTH_URL` | derived from sync URL | HTTP URL for `/auth/*` routes |
|
|
138
138
|
| `PORT` | `3001` | Sync server port |
|
|
139
|
-
| `KORA_SERVER_DB` |
|
|
140
|
-
| `KORA_AUTH_DB` |
|
|
139
|
+
| `KORA_SERVER_DB` | `./.kora/kora-server.db` | SQLite file used by the sync server when `DATABASE_URL` is empty |
|
|
140
|
+
| `KORA_AUTH_DB` | `./.kora/kora-auth.db` | SQLite file used by OAuth state and linked identities when `DATABASE_URL` is empty |
|
|
141
141
|
| `DATABASE_URL` | (none) | PostgreSQL connection string for production sync server deployments |
|
|
142
142
|
| `KORA_SYNC_PATH` | `/kora-sync` | WebSocket path exposed by the sync server |
|
|
143
143
|
| `KORA_AUTH_SECRET` | (none) | Enables built-in `/auth/*` routes and authenticated sync when set |
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"@korajs/auth": "{{koraVersion}}",
|
|
17
17
|
"@korajs/core": "{{koraVersion}}",
|
|
18
18
|
"@korajs/react": "{{koraVersion}}",
|
|
19
|
-
"@korajs/tauri": "{{
|
|
19
|
+
"@korajs/tauri": "{{tauriVersion}}",
|
|
20
20
|
"@tauri-apps/api": "^2.0.0",
|
|
21
21
|
"@tauri-apps/plugin-updater": "^2.0.0",
|
|
22
22
|
"lucide-react": "^0.468.0",
|
|
@@ -3,7 +3,9 @@ import {
|
|
|
3
3
|
type CreateKoraAuthServerOptions,
|
|
4
4
|
createKoraAuthServer,
|
|
5
5
|
createPostgresOAuthStores,
|
|
6
|
+
createPostgresUserStore,
|
|
6
7
|
createSqliteOAuthStores,
|
|
8
|
+
createSqliteUserStore,
|
|
7
9
|
googleProvider,
|
|
8
10
|
} from '@korajs/auth/server'
|
|
9
11
|
import {
|
|
@@ -68,7 +70,7 @@ async function createStore() {
|
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
return createSqliteServerStore({
|
|
71
|
-
filename: process.env.KORA_SERVER_DB || '
|
|
73
|
+
filename: process.env.KORA_SERVER_DB || './.kora/kora-server.db',
|
|
72
74
|
})
|
|
73
75
|
}
|
|
74
76
|
|
|
@@ -108,8 +110,14 @@ async function createAuth() {
|
|
|
108
110
|
}
|
|
109
111
|
|
|
110
112
|
const oauth = await createOAuthConfig()
|
|
113
|
+
// Users and token revocations persist in the same database (the user store's
|
|
114
|
+
// revocation store is used automatically), so sign-outs survive restarts.
|
|
115
|
+
const userStore = process.env.DATABASE_URL
|
|
116
|
+
? await createPostgresUserStore({ connectionString: process.env.DATABASE_URL })
|
|
117
|
+
: await createSqliteUserStore({ filename: process.env.KORA_AUTH_DB || './.kora/kora-auth.db' })
|
|
111
118
|
return createKoraAuthServer({
|
|
112
119
|
jwtSecret: process.env.KORA_AUTH_SECRET,
|
|
120
|
+
userStore,
|
|
113
121
|
...(oauth ? { oauth } : {}),
|
|
114
122
|
})
|
|
115
123
|
}
|
|
@@ -122,7 +130,7 @@ async function createOAuthConfig(): Promise<CreateKoraAuthServerOptions['oauth']
|
|
|
122
130
|
const oauthStores = process.env.DATABASE_URL
|
|
123
131
|
? await createPostgresOAuthStores({ connectionString: process.env.DATABASE_URL })
|
|
124
132
|
: await createSqliteOAuthStores({
|
|
125
|
-
filename: process.env.KORA_AUTH_DB || '
|
|
133
|
+
filename: process.env.KORA_AUTH_DB || './.kora/kora-auth.db',
|
|
126
134
|
})
|
|
127
135
|
|
|
128
136
|
return {
|
|
@@ -12,7 +12,7 @@ This is a **Kora.js** application: an offline-first app where all data lives in
|
|
|
12
12
|
2. **Never fetch application data over HTTP.** Do not add REST or GraphQL calls for app data, and do not talk to the sync server directly. Read and write through Kora collections only; sync happens automatically in the background.
|
|
13
13
|
3. **Await readiness before direct collection access.** Outside the UI bindings, `await app.ready` before calling `app.<collection>` methods. The bindings handle this for you inside components.
|
|
14
14
|
4. **Offline must keep working.** Any feature you add must function with the network off. Never gate a write or a read on connectivity. If you find yourself checking `navigator.onLine` before a data operation, you are doing it wrong.
|
|
15
|
-
5. **Surface mutation errors.** Fire-and-forget mutate calls
|
|
15
|
+
5. **Surface mutation errors.** Fire-and-forget mutate calls put errors into the mutation state. Always render the mutation's `error` in the UI or handle the promise from the async variant. Silent failure is the worst failure.
|
|
16
16
|
6. **Do not touch `src/kora-worker.ts`.** It wires the SQLite WASM binary URL for both dev and production builds. Changing it breaks production builds in ways that only show up after deploy.
|
|
17
17
|
7. **Do not add a state management library for server or app data.** Kora's reactive queries are the store. Local UI state (form inputs, toggles) can use the framework's normal state tools.
|
|
18
18
|
|
|
@@ -52,12 +52,12 @@ export default defineSchema({
|
|
|
52
52
|
})
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
If you
|
|
55
|
+
If you change a collection's shape, increment `version` and add a `migrations` entry for it (`migrate().addField(...)`): each device migrates its local database on its next open. `npx kora migrate` generates the matching migration for server databases and a transform stub for clients still on the older version.
|
|
56
56
|
|
|
57
57
|
## Project conventions
|
|
58
58
|
|
|
59
59
|
- Feature code lives in `src/modules/<feature>/` with the pattern: `<feature>.schema.ts` (collection definition, imported into `src/schema.ts`), `<feature>.queries.ts` (query builders), `<feature>.mutations.ts` (mutation functions taking a collection accessor).
|
|
60
|
-
- Conflict handling is declarative. Concurrent edits merge automatically (last-write-wins per field,
|
|
60
|
+
- Conflict handling is declarative. Concurrent edits merge automatically (last-write-wins per field, arrays as multisets that keep every device's additions and removals, objects per top-level key). If a field needs domain-specific merging (counters, quantities), add a `resolve` function in the schema rather than writing sync logic.
|
|
61
61
|
- `kora.config.ts` controls the dev environment (ports, sync server, schema watcher).
|
|
62
62
|
|
|
63
63
|
## Commands
|
|
@@ -81,4 +81,4 @@ const rows = useQuery(orderedTodos(todos)) // readonly reactive ref
|
|
|
81
81
|
const addTodo = useMutation((data) => todos.insert(data))
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
Rules: always surface the mutation's error state in the UI. `useQuery` reads
|
|
84
|
+
Rules: always surface the mutation's error state in the UI. `useQuery` reads the local store (no network, no spinner); the ref holds `[]` until the first local result. The Kora context is provided by the `KoraProvider` component wired in `src/main.ts`.
|
|
@@ -16,9 +16,15 @@
|
|
|
16
16
|
"vue": "^3.5.0",
|
|
17
17
|
"yjs": "^13.6.30"
|
|
18
18
|
},
|
|
19
|
+
"pnpm": {
|
|
20
|
+
"onlyBuiltDependencies": [
|
|
21
|
+
"esbuild"
|
|
22
|
+
]
|
|
23
|
+
},
|
|
19
24
|
"devDependencies": {
|
|
20
25
|
"@korajs/cli": "{{koraVersion}}",
|
|
21
26
|
"@vitejs/plugin-vue": "^5.2.0",
|
|
27
|
+
"tsx": "^4.19.0",
|
|
22
28
|
"typescript": "^5.7.0",
|
|
23
29
|
"vite": "^6.0.0",
|
|
24
30
|
"vue-tsc": "^2.2.0"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { copyFileSync, existsSync, readdirSync } from 'node:fs'
|
|
2
2
|
import { join, resolve } from 'node:path'
|
|
3
|
+
import { koraServiceWorker } from '@korajs/cli/vite'
|
|
3
4
|
import vue from '@vitejs/plugin-vue'
|
|
4
5
|
import type { Plugin } from 'vite'
|
|
5
6
|
import { defineConfig } from 'vite'
|
|
@@ -56,8 +57,10 @@ function sqliteWasmHotfix(): Plugin {
|
|
|
56
57
|
}
|
|
57
58
|
}
|
|
58
59
|
|
|
60
|
+
// koraServiceWorker() (build only, keep it last): precaches the built app shell so the
|
|
61
|
+
// app opens offline, with a "new version available" reload prompt. See @korajs/cli/vite.
|
|
59
62
|
export default defineConfig({
|
|
60
|
-
plugins: [vue(), crossOriginIsolation(), sqliteWasmHotfix()],
|
|
63
|
+
plugins: [vue(), crossOriginIsolation(), sqliteWasmHotfix(), koraServiceWorker()],
|
|
61
64
|
worker: {
|
|
62
65
|
format: 'es',
|
|
63
66
|
},
|
|
@@ -7,7 +7,7 @@ PORT=3001
|
|
|
7
7
|
|
|
8
8
|
# Server database
|
|
9
9
|
# Leave DATABASE_URL empty to use SQLite at KORA_SERVER_DB.
|
|
10
|
-
KORA_SERVER_DB
|
|
10
|
+
KORA_SERVER_DB=./.kora/kora-server.db
|
|
11
11
|
DATABASE_URL=
|
|
12
12
|
|
|
13
13
|
# Operational endpoints (/__kora, /__kora/status, /__kora/events, /__kora/metrics, backups)
|
|
@@ -12,7 +12,7 @@ This is a **Kora.js** application: an offline-first app where all data lives in
|
|
|
12
12
|
2. **Never fetch application data over HTTP.** Do not add REST or GraphQL calls for app data, and do not talk to the sync server directly. Read and write through Kora collections only; sync happens automatically in the background.
|
|
13
13
|
3. **Await readiness before direct collection access.** Outside the UI bindings, `await app.ready` before calling `app.<collection>` methods. The bindings handle this for you inside components.
|
|
14
14
|
4. **Offline must keep working.** Any feature you add must function with the network off. Never gate a write or a read on connectivity. If you find yourself checking `navigator.onLine` before a data operation, you are doing it wrong.
|
|
15
|
-
5. **Surface mutation errors.** Fire-and-forget mutate calls
|
|
15
|
+
5. **Surface mutation errors.** Fire-and-forget mutate calls put errors into the mutation state. Always render the mutation's `error` in the UI or handle the promise from the async variant. Silent failure is the worst failure.
|
|
16
16
|
6. **Do not touch `src/kora-worker.ts`.** It wires the SQLite WASM binary URL for both dev and production builds. Changing it breaks production builds in ways that only show up after deploy.
|
|
17
17
|
7. **Do not add a state management library for server or app data.** Kora's reactive queries are the store. Local UI state (form inputs, toggles) can use the framework's normal state tools.
|
|
18
18
|
|
|
@@ -52,12 +52,12 @@ export default defineSchema({
|
|
|
52
52
|
})
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
If you
|
|
55
|
+
If you change a collection's shape, increment `version` and add a `migrations` entry for it (`migrate().addField(...)`): each device migrates its local database on its next open. `npx kora migrate` generates the matching migration for server databases and a transform stub for clients still on the older version.
|
|
56
56
|
|
|
57
57
|
## Project conventions
|
|
58
58
|
|
|
59
59
|
- Feature code lives in `src/modules/<feature>/` with the pattern: `<feature>.schema.ts` (collection definition, imported into `src/schema.ts`), `<feature>.queries.ts` (query builders), `<feature>.mutations.ts` (mutation functions taking a collection accessor).
|
|
60
|
-
- Conflict handling is declarative. Concurrent edits merge automatically (last-write-wins per field,
|
|
60
|
+
- Conflict handling is declarative. Concurrent edits merge automatically (last-write-wins per field, arrays as multisets that keep every device's additions and removals, objects per top-level key). If a field needs domain-specific merging (counters, quantities), add a `resolve` function in the schema rather than writing sync logic.
|
|
61
61
|
- `kora.config.ts` controls the dev environment (ports, sync server, schema watcher).
|
|
62
62
|
|
|
63
63
|
## Commands
|
|
@@ -81,4 +81,4 @@ const rows = useQuery(orderedTodos(todos)) // readonly reactive ref
|
|
|
81
81
|
const addTodo = useMutation((data) => todos.insert(data))
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
Rules: always surface the mutation's error state in the UI. `useQuery` reads
|
|
84
|
+
Rules: always surface the mutation's error state in the UI. `useQuery` reads the local store (no network, no spinner); the ref holds `[]` until the first local result. The Kora context is provided by the `KoraProvider` component wired in `src/main.ts`.
|
|
@@ -3,7 +3,9 @@ import {
|
|
|
3
3
|
type CreateKoraAuthServerOptions,
|
|
4
4
|
createKoraAuthServer,
|
|
5
5
|
createPostgresOAuthStores,
|
|
6
|
+
createPostgresUserStore,
|
|
6
7
|
createSqliteOAuthStores,
|
|
8
|
+
createSqliteUserStore,
|
|
7
9
|
googleProvider,
|
|
8
10
|
} from '@korajs/auth/server'
|
|
9
11
|
import {
|
|
@@ -101,8 +103,14 @@ async function createAuth() {
|
|
|
101
103
|
}
|
|
102
104
|
|
|
103
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' })
|
|
104
111
|
return createKoraAuthServer({
|
|
105
112
|
jwtSecret: process.env.KORA_AUTH_SECRET,
|
|
113
|
+
userStore,
|
|
106
114
|
...(oauth ? { oauth } : {}),
|
|
107
115
|
})
|
|
108
116
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { copyFileSync, existsSync, readdirSync } from 'node:fs'
|
|
2
2
|
import { join, resolve } from 'node:path'
|
|
3
|
+
import { koraServiceWorker } from '@korajs/cli/vite'
|
|
3
4
|
import vue from '@vitejs/plugin-vue'
|
|
4
5
|
import type { Plugin } from 'vite'
|
|
5
6
|
import { defineConfig } from 'vite'
|
|
@@ -56,8 +57,10 @@ function sqliteWasmHotfix(): Plugin {
|
|
|
56
57
|
}
|
|
57
58
|
}
|
|
58
59
|
|
|
60
|
+
// koraServiceWorker() (build only, keep it last): precaches the built app shell so the
|
|
61
|
+
// app opens offline, with a "new version available" reload prompt. See @korajs/cli/vite.
|
|
59
62
|
export default defineConfig({
|
|
60
|
-
plugins: [vue(), crossOriginIsolation(), sqliteWasmHotfix()],
|
|
63
|
+
plugins: [vue(), crossOriginIsolation(), sqliteWasmHotfix(), koraServiceWorker()],
|
|
61
64
|
worker: {
|
|
62
65
|
format: 'es',
|
|
63
66
|
},
|
|
@@ -12,7 +12,7 @@ This is a **Kora.js** application: an offline-first app where all data lives in
|
|
|
12
12
|
2. **Never fetch application data over HTTP.** Do not add REST or GraphQL calls for app data, and do not talk to the sync server directly. Read and write through Kora collections only; sync happens automatically in the background.
|
|
13
13
|
3. **Await readiness before direct collection access.** Outside the UI bindings, `await app.ready` before calling `app.<collection>` methods. The bindings handle this for you inside components.
|
|
14
14
|
4. **Offline must keep working.** Any feature you add must function with the network off. Never gate a write or a read on connectivity. If you find yourself checking `navigator.onLine` before a data operation, you are doing it wrong.
|
|
15
|
-
5. **Surface mutation errors.** Fire-and-forget mutate calls
|
|
15
|
+
5. **Surface mutation errors.** Fire-and-forget mutate calls put errors into the mutation state. Always render the mutation's `error` in the UI or handle the promise from the async variant. Silent failure is the worst failure.
|
|
16
16
|
6. **Do not touch `src/kora-worker.ts`.** It wires the SQLite WASM binary URL for both dev and production builds. Changing it breaks production builds in ways that only show up after deploy.
|
|
17
17
|
7. **Do not add a state management library for server or app data.** Kora's reactive queries are the store. Local UI state (form inputs, toggles) can use the framework's normal state tools.
|
|
18
18
|
|
|
@@ -52,12 +52,12 @@ export default defineSchema({
|
|
|
52
52
|
})
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
If you
|
|
55
|
+
If you change a collection's shape, increment `version` and add a `migrations` entry for it (`migrate().addField(...)`): each device migrates its local database on its next open. `npx kora migrate` generates the matching migration for server databases and a transform stub for clients still on the older version.
|
|
56
56
|
|
|
57
57
|
## Project conventions
|
|
58
58
|
|
|
59
59
|
- Feature code lives in `src/modules/<feature>/` with the pattern: `<feature>.schema.ts` (collection definition, imported into `src/schema.ts`), `<feature>.queries.ts` (query builders), `<feature>.mutations.ts` (mutation functions taking a collection accessor).
|
|
60
|
-
- Conflict handling is declarative. Concurrent edits merge automatically (last-write-wins per field,
|
|
60
|
+
- Conflict handling is declarative. Concurrent edits merge automatically (last-write-wins per field, arrays as multisets that keep every device's additions and removals, objects per top-level key). If a field needs domain-specific merging (counters, quantities), add a `resolve` function in the schema rather than writing sync logic.
|
|
61
61
|
- `kora.config.ts` controls the dev environment (ports, sync server, schema watcher).
|
|
62
62
|
|
|
63
63
|
## Commands
|
|
@@ -81,4 +81,4 @@ const rows = useQuery(orderedTodos(todos)) // readonly reactive ref
|
|
|
81
81
|
const addTodo = useMutation((data) => todos.insert(data))
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
Rules: always surface the mutation's error state in the UI. `useQuery` reads
|
|
84
|
+
Rules: always surface the mutation's error state in the UI. `useQuery` reads the local store (no network, no spinner); the ref holds `[]` until the first local result. The Kora context is provided by the `KoraProvider` component wired in `src/main.ts`.
|
|
@@ -17,11 +17,17 @@
|
|
|
17
17
|
"vue": "^3.5.0",
|
|
18
18
|
"yjs": "^13.6.30"
|
|
19
19
|
},
|
|
20
|
+
"pnpm": {
|
|
21
|
+
"onlyBuiltDependencies": [
|
|
22
|
+
"esbuild"
|
|
23
|
+
]
|
|
24
|
+
},
|
|
20
25
|
"devDependencies": {
|
|
21
26
|
"@korajs/cli": "{{koraVersion}}",
|
|
22
27
|
"@tailwindcss/vite": "^4.0.0",
|
|
23
28
|
"@vitejs/plugin-vue": "^5.2.0",
|
|
24
29
|
"tailwindcss": "^4.0.0",
|
|
30
|
+
"tsx": "^4.19.0",
|
|
25
31
|
"typescript": "^5.7.0",
|
|
26
32
|
"vite": "^6.0.0",
|
|
27
33
|
"vue-tsc": "^2.2.0"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { copyFileSync, existsSync, readdirSync } from 'node:fs'
|
|
2
2
|
import { join, resolve } from 'node:path'
|
|
3
|
+
import { koraServiceWorker } from '@korajs/cli/vite'
|
|
3
4
|
import tailwindcss from '@tailwindcss/vite'
|
|
4
5
|
import vue from '@vitejs/plugin-vue'
|
|
5
6
|
import type { Plugin } from 'vite'
|
|
@@ -57,8 +58,10 @@ function sqliteWasmHotfix(): Plugin {
|
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
|
|
61
|
+
// koraServiceWorker() (build only, keep it last): precaches the built app shell so the
|
|
62
|
+
// app opens offline, with a "new version available" reload prompt. See @korajs/cli/vite.
|
|
60
63
|
export default defineConfig({
|
|
61
|
-
plugins: [vue(), tailwindcss(), crossOriginIsolation(), sqliteWasmHotfix()],
|
|
64
|
+
plugins: [vue(), tailwindcss(), crossOriginIsolation(), sqliteWasmHotfix(), koraServiceWorker()],
|
|
62
65
|
worker: {
|
|
63
66
|
format: 'es',
|
|
64
67
|
},
|
|
@@ -7,7 +7,7 @@ PORT=3001
|
|
|
7
7
|
|
|
8
8
|
# Server database
|
|
9
9
|
# Leave DATABASE_URL empty to use SQLite at KORA_SERVER_DB.
|
|
10
|
-
KORA_SERVER_DB
|
|
10
|
+
KORA_SERVER_DB=./.kora/kora-server.db
|
|
11
11
|
DATABASE_URL=
|
|
12
12
|
|
|
13
13
|
# Operational endpoints (/__kora, /__kora/status, /__kora/events, /__kora/metrics, backups)
|
|
@@ -12,7 +12,7 @@ This is a **Kora.js** application: an offline-first app where all data lives in
|
|
|
12
12
|
2. **Never fetch application data over HTTP.** Do not add REST or GraphQL calls for app data, and do not talk to the sync server directly. Read and write through Kora collections only; sync happens automatically in the background.
|
|
13
13
|
3. **Await readiness before direct collection access.** Outside the UI bindings, `await app.ready` before calling `app.<collection>` methods. The bindings handle this for you inside components.
|
|
14
14
|
4. **Offline must keep working.** Any feature you add must function with the network off. Never gate a write or a read on connectivity. If you find yourself checking `navigator.onLine` before a data operation, you are doing it wrong.
|
|
15
|
-
5. **Surface mutation errors.** Fire-and-forget mutate calls
|
|
15
|
+
5. **Surface mutation errors.** Fire-and-forget mutate calls put errors into the mutation state. Always render the mutation's `error` in the UI or handle the promise from the async variant. Silent failure is the worst failure.
|
|
16
16
|
6. **Do not touch `src/kora-worker.ts`.** It wires the SQLite WASM binary URL for both dev and production builds. Changing it breaks production builds in ways that only show up after deploy.
|
|
17
17
|
7. **Do not add a state management library for server or app data.** Kora's reactive queries are the store. Local UI state (form inputs, toggles) can use the framework's normal state tools.
|
|
18
18
|
|
|
@@ -52,12 +52,12 @@ export default defineSchema({
|
|
|
52
52
|
})
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
If you
|
|
55
|
+
If you change a collection's shape, increment `version` and add a `migrations` entry for it (`migrate().addField(...)`): each device migrates its local database on its next open. `npx kora migrate` generates the matching migration for server databases and a transform stub for clients still on the older version.
|
|
56
56
|
|
|
57
57
|
## Project conventions
|
|
58
58
|
|
|
59
59
|
- Feature code lives in `src/modules/<feature>/` with the pattern: `<feature>.schema.ts` (collection definition, imported into `src/schema.ts`), `<feature>.queries.ts` (query builders), `<feature>.mutations.ts` (mutation functions taking a collection accessor).
|
|
60
|
-
- Conflict handling is declarative. Concurrent edits merge automatically (last-write-wins per field,
|
|
60
|
+
- Conflict handling is declarative. Concurrent edits merge automatically (last-write-wins per field, arrays as multisets that keep every device's additions and removals, objects per top-level key). If a field needs domain-specific merging (counters, quantities), add a `resolve` function in the schema rather than writing sync logic.
|
|
61
61
|
- `kora.config.ts` controls the dev environment (ports, sync server, schema watcher).
|
|
62
62
|
|
|
63
63
|
## Commands
|
|
@@ -81,4 +81,4 @@ const rows = useQuery(orderedTodos(todos)) // readonly reactive ref
|
|
|
81
81
|
const addTodo = useMutation((data) => todos.insert(data))
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
Rules: always surface the mutation's error state in the UI. `useQuery` reads
|
|
84
|
+
Rules: always surface the mutation's error state in the UI. `useQuery` reads the local store (no network, no spinner); the ref holds `[]` until the first local result. The Kora context is provided by the `KoraProvider` component wired in `src/main.ts`.
|
|
@@ -3,7 +3,9 @@ import {
|
|
|
3
3
|
type CreateKoraAuthServerOptions,
|
|
4
4
|
createKoraAuthServer,
|
|
5
5
|
createPostgresOAuthStores,
|
|
6
|
+
createPostgresUserStore,
|
|
6
7
|
createSqliteOAuthStores,
|
|
8
|
+
createSqliteUserStore,
|
|
7
9
|
googleProvider,
|
|
8
10
|
} from '@korajs/auth/server'
|
|
9
11
|
import {
|
|
@@ -101,8 +103,14 @@ async function createAuth() {
|
|
|
101
103
|
}
|
|
102
104
|
|
|
103
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' })
|
|
104
111
|
return createKoraAuthServer({
|
|
105
112
|
jwtSecret: process.env.KORA_AUTH_SECRET,
|
|
113
|
+
userStore,
|
|
106
114
|
...(oauth ? { oauth } : {}),
|
|
107
115
|
})
|
|
108
116
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { copyFileSync, existsSync, readdirSync } from 'node:fs'
|
|
2
2
|
import { join, resolve } from 'node:path'
|
|
3
|
+
import { koraServiceWorker } from '@korajs/cli/vite'
|
|
3
4
|
import tailwindcss from '@tailwindcss/vite'
|
|
4
5
|
import vue from '@vitejs/plugin-vue'
|
|
5
6
|
import type { Plugin } from 'vite'
|
|
@@ -57,8 +58,10 @@ function sqliteWasmHotfix(): Plugin {
|
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
|
|
61
|
+
// koraServiceWorker() (build only, keep it last): precaches the built app shell so the
|
|
62
|
+
// app opens offline, with a "new version available" reload prompt. See @korajs/cli/vite.
|
|
60
63
|
export default defineConfig({
|
|
61
|
-
plugins: [vue(), tailwindcss(), crossOriginIsolation(), sqliteWasmHotfix()],
|
|
64
|
+
plugins: [vue(), tailwindcss(), crossOriginIsolation(), sqliteWasmHotfix(), koraServiceWorker()],
|
|
62
65
|
worker: {
|
|
63
66
|
format: 'es',
|
|
64
67
|
},
|