use-convex 0.0.2
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/LICENSE +2 -0
- package/README.md +321 -0
- package/dist/module.d.mts +97 -0
- package/dist/module.json +12 -0
- package/dist/module.mjs +232 -0
- package/dist/runtime/components/AuthLoading.d.vue.ts +13 -0
- package/dist/runtime/components/AuthLoading.vue +8 -0
- package/dist/runtime/components/AuthLoading.vue.d.ts +13 -0
- package/dist/runtime/components/AuthRefreshing.d.vue.ts +13 -0
- package/dist/runtime/components/AuthRefreshing.vue +8 -0
- package/dist/runtime/components/AuthRefreshing.vue.d.ts +13 -0
- package/dist/runtime/components/Authenticated.d.vue.ts +13 -0
- package/dist/runtime/components/Authenticated.vue +8 -0
- package/dist/runtime/components/Authenticated.vue.d.ts +13 -0
- package/dist/runtime/components/Unauthenticated.d.vue.ts +13 -0
- package/dist/runtime/components/Unauthenticated.vue +8 -0
- package/dist/runtime/components/Unauthenticated.vue.d.ts +13 -0
- package/dist/runtime/composables/prewarmQuery.d.ts +9 -0
- package/dist/runtime/composables/prewarmQuery.js +14 -0
- package/dist/runtime/composables/useAuth.d.ts +60 -0
- package/dist/runtime/composables/useAuth.js +426 -0
- package/dist/runtime/composables/useAuthToken.d.ts +24 -0
- package/dist/runtime/composables/useAuthToken.js +71 -0
- package/dist/runtime/composables/useConvex.d.ts +5 -0
- package/dist/runtime/composables/useConvex.js +10 -0
- package/dist/runtime/composables/useConvexAction.d.ts +13 -0
- package/dist/runtime/composables/useConvexAction.js +30 -0
- package/dist/runtime/composables/useConvexAuth.d.ts +51 -0
- package/dist/runtime/composables/useConvexAuth.js +96 -0
- package/dist/runtime/composables/useConvexConnectionState.d.ts +8 -0
- package/dist/runtime/composables/useConvexConnectionState.js +21 -0
- package/dist/runtime/composables/useConvexGate.d.ts +20 -0
- package/dist/runtime/composables/useConvexGate.js +21 -0
- package/dist/runtime/composables/useConvexMutation.d.ts +25 -0
- package/dist/runtime/composables/useConvexMutation.js +35 -0
- package/dist/runtime/composables/useConvexPaginatedQuery.d.ts +43 -0
- package/dist/runtime/composables/useConvexPaginatedQuery.js +188 -0
- package/dist/runtime/composables/useConvexQueries.d.ts +27 -0
- package/dist/runtime/composables/useConvexQueries.js +84 -0
- package/dist/runtime/composables/useConvexQuery.d.ts +56 -0
- package/dist/runtime/composables/useConvexQuery.js +147 -0
- package/dist/runtime/plugin.auth.client.d.ts +8 -0
- package/dist/runtime/plugin.auth.client.js +41 -0
- package/dist/runtime/plugin.client.d.ts +7 -0
- package/dist/runtime/plugin.client.js +40 -0
- package/dist/runtime/plugin.devtools.client.d.ts +6 -0
- package/dist/runtime/plugin.devtools.client.js +16 -0
- package/dist/runtime/plugin.server.d.ts +7 -0
- package/dist/runtime/plugin.server.js +44 -0
- package/dist/runtime/server/api/convex/auth/session.d.ts +36 -0
- package/dist/runtime/server/api/convex/auth/session.js +95 -0
- package/dist/runtime/server/auth.d.ts +19 -0
- package/dist/runtime/server/auth.js +32 -0
- package/dist/runtime/server/authCookies.d.ts +9 -0
- package/dist/runtime/server/authCookies.js +86 -0
- package/dist/runtime/server/fetch.d.ts +43 -0
- package/dist/runtime/server/fetch.js +63 -0
- package/dist/runtime/server/routes/__convex_devtools.get.d.ts +6 -0
- package/dist/runtime/server/routes/__convex_devtools.get.js +32 -0
- package/dist/runtime/server/sameOrigin.d.ts +14 -0
- package/dist/runtime/server/sameOrigin.js +33 -0
- package/dist/runtime/utils/authCookie.d.ts +21 -0
- package/dist/runtime/utils/authCookie.js +47 -0
- package/dist/runtime/utils/authGate.d.ts +11 -0
- package/dist/runtime/utils/authGate.js +9 -0
- package/dist/runtime/utils/authMutex.d.ts +15 -0
- package/dist/runtime/utils/authMutex.js +47 -0
- package/dist/runtime/utils/authState.d.ts +31 -0
- package/dist/runtime/utils/authState.js +35 -0
- package/dist/runtime/utils/authStorage.d.ts +55 -0
- package/dist/runtime/utils/authStorage.js +85 -0
- package/dist/runtime/utils/context.d.ts +53 -0
- package/dist/runtime/utils/context.js +41 -0
- package/dist/runtime/utils/fetchToken.d.ts +9 -0
- package/dist/runtime/utils/fetchToken.js +6 -0
- package/dist/runtime/utils/http.d.ts +10 -0
- package/dist/runtime/utils/http.js +13 -0
- package/dist/runtime/utils/oauthRedirect.d.ts +5 -0
- package/dist/runtime/utils/oauthRedirect.js +12 -0
- package/dist/runtime/utils/overlay.d.ts +18 -0
- package/dist/runtime/utils/overlay.js +48 -0
- package/dist/runtime/utils/paginatedOptimistic.d.ts +37 -0
- package/dist/runtime/utils/paginatedOptimistic.js +178 -0
- package/dist/runtime/utils/queryKey.d.ts +8 -0
- package/dist/runtime/utils/queryKey.js +11 -0
- package/dist/types.d.mts +29 -0
- package/package.json +66 -0
package/LICENSE
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
# use-convex
|
|
2
|
+
|
|
3
|
+
First-class [Convex](https://convex.dev) integration for [Nuxt 4](https://nuxt.com).
|
|
4
|
+
|
|
5
|
+
SSR snapshots hydrate through the Nuxt payload, then the browser overlays a live WebSocket subscription.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add use-convex convex
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
// nuxt.config.ts
|
|
15
|
+
export default defineNuxtConfig({
|
|
16
|
+
modules: ['use-convex'],
|
|
17
|
+
convex: {
|
|
18
|
+
url: process.env.NUXT_PUBLIC_CONVEX_URL,
|
|
19
|
+
},
|
|
20
|
+
})
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```vue
|
|
24
|
+
<script setup lang="ts">
|
|
25
|
+
import { api } from '~~/convex/_generated/api'
|
|
26
|
+
|
|
27
|
+
const { data, pending, error } = await useConvexQuery(api.tasks.list, {})
|
|
28
|
+
</script>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
With Nuxt 4's `app/` directory, `~~` is the project root (where `convex/` lives).
|
|
32
|
+
|
|
33
|
+
## How it works
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
useConvexQuery()
|
|
37
|
+
│
|
|
38
|
+
┌────────┴────────┐
|
|
39
|
+
│ │
|
|
40
|
+
Nuxt SSR Browser
|
|
41
|
+
│ │
|
|
42
|
+
ConvexHttpClient ConvexClient
|
|
43
|
+
│ │
|
|
44
|
+
useAsyncData onUpdate
|
|
45
|
+
│ │
|
|
46
|
+
Nuxt payload ──► live ?? payload
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Server and client share the same `useAsyncData` key so hydration reuses the payload. The browser then overlays `ConvexClient.onUpdate`.
|
|
50
|
+
|
|
51
|
+
Set `convex.server: false` to skip SSR snapshots globally, or pass `{ server: false }` on a single query.
|
|
52
|
+
|
|
53
|
+
## Queries
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
const { data, pending, error, refresh } = await useConvexQuery(
|
|
57
|
+
api.tasks.list,
|
|
58
|
+
{}, // args, a ref / getter, or 'skip'
|
|
59
|
+
)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
| Option | Default | Purpose |
|
|
63
|
+
|---|---|---|
|
|
64
|
+
| `key` | function name + args | Nuxt payload / cache key |
|
|
65
|
+
| `server` | `convex.server` (`true`) | SSR HttpClient snapshot |
|
|
66
|
+
| `lazy` | `false` | Non-blocking on client navigation |
|
|
67
|
+
| `live` | `true` | Subscribe after hydration |
|
|
68
|
+
| `authenticated` | `false` | Wait for Convex auth before live subscribe |
|
|
69
|
+
| `token` | cookie / none | Per-request JWT for SSR |
|
|
70
|
+
|
|
71
|
+
Args accept the query's `FunctionArgs`, `'skip'`, or a `MaybeRefOrGetter` of either.
|
|
72
|
+
|
|
73
|
+
- **`'skip'`** — gate on missing ids, feature flags, etc. Keeps the same payload key as empty args so SSR HTML survives.
|
|
74
|
+
- **`authenticated: true`** — skip live subscribe until Convex confirms auth. SSR still snapshots when the JWT cookie is present. Prefer this over wrapping args yourself.
|
|
75
|
+
- **`token`** — authenticated SSR for this call only. Never put JWTs in `runtimeConfig.public`. When `convex.auth.cookie` / HttpOnly auth is set, queries fall back to that cookie.
|
|
76
|
+
|
|
77
|
+
Warm a subscription before a screen mounts:
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
prewarmQuery(api.tasks.list, {})
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Several queries
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
const results = useConvexQueries(() => ({
|
|
87
|
+
inbox: { query: api.messages.list, args: { channel: 'inbox' } },
|
|
88
|
+
later: selectedId.value
|
|
89
|
+
? { query: api.messages.get, args: { id: selectedId.value } }
|
|
90
|
+
: 'skip',
|
|
91
|
+
}))
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Pagination
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
const { results, status, isLoading, loadMore } = await useConvexPaginatedQuery(
|
|
98
|
+
api.tasks.listPaginated,
|
|
99
|
+
{},
|
|
100
|
+
{ initialNumItems: 20 },
|
|
101
|
+
)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
The first page is SSR'd. On the browser, every loaded page stays live. `loadMore` fetches the next page.
|
|
105
|
+
|
|
106
|
+
## Mutations and actions
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
const { mutate, pending, error } = useConvexMutation(api.tasks.create, {
|
|
110
|
+
optimisticUpdate: (localStore, args) => {
|
|
111
|
+
const existing = localStore.getQuery(api.tasks.list, {}) ?? []
|
|
112
|
+
localStore.setQuery(api.tasks.list, {}, [
|
|
113
|
+
{ _id: 'tmp', text: args.text, completed: false },
|
|
114
|
+
...existing,
|
|
115
|
+
])
|
|
116
|
+
},
|
|
117
|
+
})
|
|
118
|
+
await mutate({ text: 'Ship it' })
|
|
119
|
+
|
|
120
|
+
const { run } = useConvexAction(api.ai.summarize)
|
|
121
|
+
await run({ text: '…' })
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
For paginated lists:
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
insertAtTop({
|
|
128
|
+
paginatedQuery: api.tasks.listPaginated,
|
|
129
|
+
localQueryStore: localStore,
|
|
130
|
+
item: { _id: 'tmp', text: args.text, completed: false },
|
|
131
|
+
})
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Also available: `insertAtBottomIfLoaded`, `insertAtPosition`, `optimisticallyUpdateValueInPaginatedQuery`.
|
|
135
|
+
|
|
136
|
+
`useConvex()` returns the browser `ConvexClient` when you need an escape hatch. `useConvexConnectionState()` is a reactive WebSocket `ConnectionState`.
|
|
137
|
+
|
|
138
|
+
## Auth
|
|
139
|
+
|
|
140
|
+
### Convex Auth
|
|
141
|
+
|
|
142
|
+
Opt in with `provider: 'convex-auth'`. The module hydrates tokens, finishes OAuth `?code=` callbacks, and wires `setAuth`. Forms only call `signIn` / `signOut`.
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
convex: {
|
|
146
|
+
url: process.env.NUXT_PUBLIC_CONVEX_URL,
|
|
147
|
+
auth: {
|
|
148
|
+
provider: 'convex-auth',
|
|
149
|
+
// cookie defaults to 'convex_jwt'
|
|
150
|
+
},
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
```vue
|
|
155
|
+
<script setup lang="ts">
|
|
156
|
+
const { signIn, signOut } = useAuth()
|
|
157
|
+
</script>
|
|
158
|
+
|
|
159
|
+
<template>
|
|
160
|
+
<AuthLoading>Resolving…</AuthLoading>
|
|
161
|
+
<Authenticated>
|
|
162
|
+
<!-- signed-in shell -->
|
|
163
|
+
</Authenticated>
|
|
164
|
+
<Unauthenticated>
|
|
165
|
+
<!-- sign-in form -->
|
|
166
|
+
</Unauthenticated>
|
|
167
|
+
</template>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Prefer `<Authenticated>` (or `showAuthedUi`) so SSR HTML does not flash the sign-in form. Gate private queries with `{ authenticated: true }`.
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
await signIn('password', { email, password, flow: 'signIn' })
|
|
174
|
+
await signIn('github') // OAuth redirect; the plugin finishes on ?code=
|
|
175
|
+
await signOut()
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
You still own the Convex backend:
|
|
179
|
+
|
|
180
|
+
- `convex/auth.ts` — `convexAuth({ providers })` exporting `auth`, `signIn`, `signOut`
|
|
181
|
+
- `convex/schema.ts` — spread `authTables`
|
|
182
|
+
- `convex/http.ts` — `auth.addHttpRoutes(http)` (required for OAuth / magic links)
|
|
183
|
+
- `convex/auth.config.ts` — JWT issuer (`CONVEX_SITE_URL`)
|
|
184
|
+
- Env: `JWT_PRIVATE_KEY` + `JWKS` (`npx @convex-dev/auth`), plus `SITE_URL` for OAuth
|
|
185
|
+
|
|
186
|
+
By default the JWT is a readable cookie (`convex_jwt`) and the refresh token lives in `localStorage`. For production Convex Auth apps, prefer HttpOnly dual cookies:
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
auth: {
|
|
190
|
+
provider: 'convex-auth',
|
|
191
|
+
httpOnly: true, // JWT + refresh via Nitro `/api/convex/auth/session`
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
A readable `convex_auth_present` marker drives `hasSsrSession` / `showAuthedUi` (UI shell only — **not** authorization). Always gate private live queries with `{ authenticated: true }` (or equivalent). Tokens are HttpOnly cookies; the session API returns the JWT only via same-origin `POST { getToken: true }` for `ConvexClient.setAuth`. That mitigates cookie theft, **not** XSS (any XSS that can call your origin can still obtain a token once the client needs it in memory).
|
|
196
|
+
|
|
197
|
+
### SSR query budget
|
|
198
|
+
|
|
199
|
+
Defaults are `convex.server: true` and per-query `live: true` (HttpClient snapshot **and** WebSocket). On list-heavy pages, skip SSR or live selectively:
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
await useConvexQuery(api.tasks.list, {}, { server: false }) // client-only
|
|
203
|
+
await useConvexQuery(api.stats.get, {}, { live: false }) // SSR / one-shot only
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Or set `convex: { server: false }` globally.
|
|
207
|
+
|
|
208
|
+
Protect a route:
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
// middleware/auth.ts
|
|
212
|
+
export default defineNuxtRouteMiddleware(() => {
|
|
213
|
+
return requireConvexAuthMiddleware({ redirectTo: '/login' })
|
|
214
|
+
})
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
`useAuthToken()` returns the current JWT for authenticated HTTP calls. `useConvexGate()` exposes `{ showAuthedUi, showLoading, showSignedOut, showRefreshing }` if you prefer flags over layout components.
|
|
218
|
+
|
|
219
|
+
### Bring your own (Clerk, Auth0, custom)
|
|
220
|
+
|
|
221
|
+
Omit `provider` and wire `useConvexAuth` yourself:
|
|
222
|
+
|
|
223
|
+
```ts
|
|
224
|
+
// plugins/my-auth.client.ts
|
|
225
|
+
useConvexAuth({
|
|
226
|
+
fetchToken: ({ forceRefreshToken }) => auth.getToken({ forceRefreshToken }),
|
|
227
|
+
isLoading: auth.isLoading,
|
|
228
|
+
isAuthenticated: auth.hasSession,
|
|
229
|
+
})
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
```ts
|
|
233
|
+
const { data } = await useConvexQuery(api.tasks.list, {}, { authenticated: true })
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
Optional SSR cookie (you must write the JWT after sign-in):
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
auth: { cookie: 'convex_jwt' }
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Server routes
|
|
243
|
+
|
|
244
|
+
Nitro helpers are auto-imported in `server/`. Pass the H3 `event` so they resolve the deployment URL and, when a cookie is configured, the JWT:
|
|
245
|
+
|
|
246
|
+
```ts
|
|
247
|
+
// server/api/tasks.get.ts
|
|
248
|
+
export default defineEventHandler(async (event) => {
|
|
249
|
+
requireConvexAuth(event)
|
|
250
|
+
return await fetchQuery(api.tasks.list, {}, { event })
|
|
251
|
+
})
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
```ts
|
|
255
|
+
// server/api/tasks.post.ts
|
|
256
|
+
export default defineEventHandler(async (event) => {
|
|
257
|
+
requireConvexAuth(event)
|
|
258
|
+
const { text } = await readBody(event)
|
|
259
|
+
return await fetchMutation(api.tasks.create, { text }, { event })
|
|
260
|
+
})
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
`fetchAction` uses the same options. Each helper builds a fresh `ConvexHttpClient`. Override with `{ token }` when you already have a JWT. `getConvexToken(event)` reads the cookie without throwing.
|
|
264
|
+
|
|
265
|
+
## Config
|
|
266
|
+
|
|
267
|
+
```ts
|
|
268
|
+
convex: {
|
|
269
|
+
url: process.env.NUXT_PUBLIC_CONVEX_URL,
|
|
270
|
+
server: true, // SSR snapshots; override per query with { server }
|
|
271
|
+
client: { unsavedChangesWarning: false }, // forwarded to new ConvexClient()
|
|
272
|
+
auth: {
|
|
273
|
+
provider: 'convex-auth',
|
|
274
|
+
cookie: 'convex_jwt',
|
|
275
|
+
httpOnly: false,
|
|
276
|
+
presentCookie: 'convex_auth_present',
|
|
277
|
+
},
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
`url` also reads `NUXT_PUBLIC_CONVEX_URL` via `runtimeConfig.public.convex.url`, so you can change the deployment without rebuilding.
|
|
282
|
+
|
|
283
|
+
## Playground
|
|
284
|
+
|
|
285
|
+
`playground/` is a normal Nuxt app that consumes this module (workspace-linked).
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
pnpm install
|
|
289
|
+
|
|
290
|
+
# Terminal 1 — Convex backend (writes NUXT_PUBLIC_CONVEX_URL to .env.local)
|
|
291
|
+
pnpm run dev:backend
|
|
292
|
+
# first time: npx @convex-dev/auth # JWT_PRIVATE_KEY + JWKS
|
|
293
|
+
|
|
294
|
+
# Terminal 2 — Nuxt
|
|
295
|
+
pnpm run dev
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
| Route | What it shows |
|
|
299
|
+
|---|---|
|
|
300
|
+
| `/` | SSR snapshot + live overlay (sign up, CRUD todos) |
|
|
301
|
+
| `/server` | Nitro `fetchQuery` / `fetchMutation` / `fetchAction` |
|
|
302
|
+
| `/extras` | `live: false`, pagination, action, connection state |
|
|
303
|
+
|
|
304
|
+
On `/server`: `GET /api/health` is public; `GET`/`POST /api/tasks` use the cookie JWT; `POST /api/shout` is a public `fetchAction` demo.
|
|
305
|
+
|
|
306
|
+
## Releasing
|
|
307
|
+
|
|
308
|
+
Releases run from `.github/workflows/release.yml` when commits land on `main`. Version bumps follow [conventional commits](https://www.conventionalcommits.org/):
|
|
309
|
+
|
|
310
|
+
| Commit | Release |
|
|
311
|
+
|---|---|
|
|
312
|
+
| `fix:` | patch |
|
|
313
|
+
| `feat:` | minor |
|
|
314
|
+
| `feat!:` or `BREAKING CHANGE:` | major |
|
|
315
|
+
| `chore:`, `docs:`, `ci:`, … | none |
|
|
316
|
+
|
|
317
|
+
semantic-release publishes `use-convex` to npm, tags `vX.Y.Z`, and opens a GitHub Release. The repo `package.json` version is not committed back.
|
|
318
|
+
|
|
319
|
+
## License
|
|
320
|
+
|
|
321
|
+
MIT
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
+
import * as convex_browser from 'convex/browser';
|
|
3
|
+
export { AuthTokens, SignInResult, UseAuthReturn } from '../dist/runtime/composables/useAuth.js';
|
|
4
|
+
export { ConvexQueryArgs, UseConvexQueryOptions, UseConvexQueryReturn } from '../dist/runtime/composables/useConvexQuery.js';
|
|
5
|
+
export { AuthTokenFetcher, UseConvexAuthReturn, UseConvexAuthSetupOptions } from '../dist/runtime/composables/useConvexAuth.js';
|
|
6
|
+
export { UseConvexMutationOptions } from '../dist/runtime/composables/useConvexMutation.js';
|
|
7
|
+
export { PaginatedQueryReference, PaginationStatus, UseConvexPaginatedQueryOptions, UseConvexPaginatedQueryReturn } from '../dist/runtime/composables/useConvexPaginatedQuery.js';
|
|
8
|
+
export { ConvexQueriesRequest, ConvexQueriesResult } from '../dist/runtime/composables/useConvexQueries.js';
|
|
9
|
+
export { ConvexFetchOptions } from '../dist/runtime/server/fetch.js';
|
|
10
|
+
export { ConvexAuthContext, ConvexNuxtContext } from '../dist/runtime/utils/context.js';
|
|
11
|
+
export { ConnectionState } from '../dist/runtime/composables/useConvexConnectionState.js';
|
|
12
|
+
export { ConvexGate } from '../dist/runtime/composables/useConvexGate.js';
|
|
13
|
+
|
|
14
|
+
interface ModuleAuthOptions {
|
|
15
|
+
/**
|
|
16
|
+
* Opt-in first-party Convex Auth (`@convex-dev/auth`) client.
|
|
17
|
+
*
|
|
18
|
+
* When set to `'convex-auth'`, the module registers a client plugin that
|
|
19
|
+
* hydrates tokens, handles OAuth `?code=` callbacks, and wires
|
|
20
|
+
* `useConvexAuth({ fetchToken })`. It also auto-imports `useAuth`,
|
|
21
|
+
* `signIn`, and `signOut` so apps only need forms.
|
|
22
|
+
*
|
|
23
|
+
* Omit for bring-your-own providers (Clerk, Auth0, custom) — wire
|
|
24
|
+
* `useConvexAuth({ fetchToken })` yourself.
|
|
25
|
+
*/
|
|
26
|
+
provider?: 'convex-auth';
|
|
27
|
+
/**
|
|
28
|
+
* Cookie name whose value is a JWT used for authenticated SSR queries.
|
|
29
|
+
* When set, the server plugin reads this cookie into `ctx.ssrToken` and
|
|
30
|
+
* `useConvexQuery` falls back to it when `options.token` is omitted.
|
|
31
|
+
* `useAuth` / `useConvexAuth` expose the presence of this cookie as
|
|
32
|
+
* `hasSsrSession`.
|
|
33
|
+
* Nitro `fetch*` helpers also read this cookie when `{ event }` is passed.
|
|
34
|
+
*
|
|
35
|
+
* Defaults to `'convex_jwt'` when `provider === 'convex-auth'` and
|
|
36
|
+
* `httpOnly` is off. With `httpOnly: true`, defaults to `__convexAuthJWT`.
|
|
37
|
+
* Otherwise off — BYO apps must opt in and write the JWT after sign-in.
|
|
38
|
+
*/
|
|
39
|
+
cookie?: string;
|
|
40
|
+
/**
|
|
41
|
+
* Store JWT + refresh tokens in HttpOnly cookies via Nitro
|
|
42
|
+
* (`/api/convex/auth/session`). Cookies are not readable via
|
|
43
|
+
* `document.cookie`. Prefer `true` in production.
|
|
44
|
+
*
|
|
45
|
+
* Note: ConvexClient still needs the JWT in memory for the WebSocket;
|
|
46
|
+
* the session route returns it only via same-origin POST `{ getToken: true }`.
|
|
47
|
+
* HttpOnly mitigates cookie theft, not XSS session theft. The readable
|
|
48
|
+
* presence cookie drives `hasSsrSession` / `showAuthedUi` (UI only — gate
|
|
49
|
+
* private queries with `{ authenticated: true }`).
|
|
50
|
+
*
|
|
51
|
+
* @default false
|
|
52
|
+
*/
|
|
53
|
+
httpOnly?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Readable presence cookie when `httpOnly` is enabled.
|
|
56
|
+
* @default 'convex_auth_present'
|
|
57
|
+
*/
|
|
58
|
+
presentCookie?: string;
|
|
59
|
+
}
|
|
60
|
+
interface ModuleOptions {
|
|
61
|
+
/**
|
|
62
|
+
* Convex deployment URL.
|
|
63
|
+
*
|
|
64
|
+
* Defaults to runtimeConfig.public.convex.url, allowing
|
|
65
|
+
* NUXT_PUBLIC_CONVEX_URL to be changed without rebuilding.
|
|
66
|
+
*/
|
|
67
|
+
url?: string;
|
|
68
|
+
/**
|
|
69
|
+
* Run Convex queries during SSR (`useAsyncData` on the server).
|
|
70
|
+
* Per-call `useConvexQuery(..., { server })` overrides this default.
|
|
71
|
+
* @default true
|
|
72
|
+
*/
|
|
73
|
+
server?: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Options forwarded to `new ConvexClient(url, client)`.
|
|
76
|
+
* Useful for `unsavedChangesWarning`, `verbose`, custom WebSocket, etc.
|
|
77
|
+
*/
|
|
78
|
+
client?: convex_browser.ConvexClientOptions;
|
|
79
|
+
/**
|
|
80
|
+
* Optional auth: SSR cookie and/or first-party Convex Auth provider.
|
|
81
|
+
*/
|
|
82
|
+
auth?: ModuleAuthOptions;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
interface ModulePublicRuntimeConfig {
|
|
86
|
+
convex: {
|
|
87
|
+
url?: string;
|
|
88
|
+
server?: boolean;
|
|
89
|
+
client?: convex_browser.ConvexClientOptions;
|
|
90
|
+
auth?: ModuleAuthOptions;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
|
95
|
+
|
|
96
|
+
export { _default as default };
|
|
97
|
+
export type { ModuleAuthOptions, ModuleOptions, ModulePublicRuntimeConfig };
|
package/dist/module.json
ADDED
package/dist/module.mjs
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { defineNuxtModule, createResolver, addPlugin, addComponent, addServerScanDir, addServerHandler, addImports, addServerImports, addTypeTemplate } from '@nuxt/kit';
|
|
2
|
+
import { defu } from 'defu';
|
|
3
|
+
import { resolveAuthCookieName } from '../dist/runtime/utils/authStorage.js';
|
|
4
|
+
|
|
5
|
+
const module$1 = defineNuxtModule({
|
|
6
|
+
meta: {
|
|
7
|
+
name: "use-convex",
|
|
8
|
+
configKey: "convex",
|
|
9
|
+
compatibility: {
|
|
10
|
+
nuxt: "^4.0.0"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
defaults: {
|
|
14
|
+
url: void 0,
|
|
15
|
+
server: true
|
|
16
|
+
},
|
|
17
|
+
setup(options, nuxt) {
|
|
18
|
+
const existing = nuxt.options.runtimeConfig.public.convex;
|
|
19
|
+
const auth = options.auth ? {
|
|
20
|
+
...options.auth,
|
|
21
|
+
cookie: resolveAuthCookieName(options.auth) ?? options.auth.cookie
|
|
22
|
+
} : options.auth;
|
|
23
|
+
nuxt.options.runtimeConfig.public.convex = defu(existing ?? {}, {
|
|
24
|
+
url: options.url,
|
|
25
|
+
server: options.server,
|
|
26
|
+
client: options.client,
|
|
27
|
+
auth
|
|
28
|
+
});
|
|
29
|
+
const resolver = createResolver(import.meta.url);
|
|
30
|
+
const runtimeDir = resolver.resolve("./runtime");
|
|
31
|
+
const useConvexAuthProvider = auth?.provider === "convex-auth";
|
|
32
|
+
nuxt.options.build.transpile.push(runtimeDir);
|
|
33
|
+
nuxt.hooks.hook("nitro:config", (nitroConfig) => {
|
|
34
|
+
nitroConfig.externals ||= {};
|
|
35
|
+
nitroConfig.externals.inline ||= [];
|
|
36
|
+
if (Array.isArray(nitroConfig.externals.inline)) {
|
|
37
|
+
nitroConfig.externals.inline.push(runtimeDir);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
addPlugin({
|
|
41
|
+
src: resolver.resolve("./runtime/plugin.server"),
|
|
42
|
+
mode: "server"
|
|
43
|
+
});
|
|
44
|
+
addPlugin({
|
|
45
|
+
src: resolver.resolve("./runtime/plugin.client"),
|
|
46
|
+
mode: "client"
|
|
47
|
+
});
|
|
48
|
+
if (useConvexAuthProvider) {
|
|
49
|
+
addPlugin({
|
|
50
|
+
src: resolver.resolve("./runtime/plugin.auth.client"),
|
|
51
|
+
mode: "client"
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
if (nuxt.options.dev) {
|
|
55
|
+
addPlugin({
|
|
56
|
+
src: resolver.resolve("./runtime/plugin.devtools.client"),
|
|
57
|
+
mode: "client"
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
for (const name of ["Authenticated", "Unauthenticated", "AuthLoading"]) {
|
|
61
|
+
addComponent({
|
|
62
|
+
name,
|
|
63
|
+
filePath: resolver.resolve(`./runtime/components/${name}.vue`)
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
addServerScanDir(resolver.resolve("./runtime/server"));
|
|
67
|
+
addServerHandler({
|
|
68
|
+
route: "/api/convex/auth/session",
|
|
69
|
+
handler: resolver.resolve("./runtime/server/api/convex/auth/session")
|
|
70
|
+
});
|
|
71
|
+
if (nuxt.options.dev) {
|
|
72
|
+
addServerHandler({
|
|
73
|
+
route: "/__convex_devtools",
|
|
74
|
+
handler: resolver.resolve("./runtime/server/routes/__convex_devtools.get")
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
addImports([
|
|
78
|
+
{
|
|
79
|
+
name: "useConvex",
|
|
80
|
+
from: resolver.resolve("./runtime/composables/useConvex")
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
name: "useConvexAuth",
|
|
84
|
+
from: resolver.resolve("./runtime/composables/useConvexAuth")
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: "useConvexGate",
|
|
88
|
+
from: resolver.resolve("./runtime/composables/useConvexGate")
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: "useConvexQuery",
|
|
92
|
+
from: resolver.resolve("./runtime/composables/useConvexQuery")
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: "useConvexQueries",
|
|
96
|
+
from: resolver.resolve("./runtime/composables/useConvexQueries")
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: "useConvexPaginatedQuery",
|
|
100
|
+
from: resolver.resolve("./runtime/composables/useConvexPaginatedQuery")
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: "useConvexMutation",
|
|
104
|
+
from: resolver.resolve("./runtime/composables/useConvexMutation")
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: "useConvexAction",
|
|
108
|
+
from: resolver.resolve("./runtime/composables/useConvexAction")
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
name: "useConvexConnectionState",
|
|
112
|
+
from: resolver.resolve("./runtime/composables/useConvexConnectionState")
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: "useAuthToken",
|
|
116
|
+
from: resolver.resolve("./runtime/composables/useAuthToken")
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
name: "requireConvexAuthMiddleware",
|
|
120
|
+
from: resolver.resolve("./runtime/composables/useAuthToken")
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: "prewarmQuery",
|
|
124
|
+
from: resolver.resolve("./runtime/composables/prewarmQuery")
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
name: "optimisticallyUpdateValueInPaginatedQuery",
|
|
128
|
+
from: resolver.resolve("./runtime/utils/paginatedOptimistic")
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: "insertAtTop",
|
|
132
|
+
from: resolver.resolve("./runtime/utils/paginatedOptimistic")
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
name: "insertAtBottomIfLoaded",
|
|
136
|
+
from: resolver.resolve("./runtime/utils/paginatedOptimistic")
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
name: "insertAtPosition",
|
|
140
|
+
from: resolver.resolve("./runtime/utils/paginatedOptimistic")
|
|
141
|
+
},
|
|
142
|
+
...useConvexAuthProvider ? [
|
|
143
|
+
{
|
|
144
|
+
name: "useAuth",
|
|
145
|
+
from: resolver.resolve("./runtime/composables/useAuth")
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
name: "signIn",
|
|
149
|
+
from: resolver.resolve("./runtime/composables/useAuth")
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
name: "signOut",
|
|
153
|
+
from: resolver.resolve("./runtime/composables/useAuth")
|
|
154
|
+
}
|
|
155
|
+
] : []
|
|
156
|
+
]);
|
|
157
|
+
addServerImports([
|
|
158
|
+
{
|
|
159
|
+
name: "fetchQuery",
|
|
160
|
+
from: resolver.resolve("./runtime/server/fetch")
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
name: "fetchMutation",
|
|
164
|
+
from: resolver.resolve("./runtime/server/fetch")
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: "fetchAction",
|
|
168
|
+
from: resolver.resolve("./runtime/server/fetch")
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
name: "getConvexToken",
|
|
172
|
+
from: resolver.resolve("./runtime/server/auth")
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
name: "requireConvexAuth",
|
|
176
|
+
from: resolver.resolve("./runtime/server/auth")
|
|
177
|
+
}
|
|
178
|
+
]);
|
|
179
|
+
if (nuxt.options.dev) {
|
|
180
|
+
nuxt.hooks.hook("devtools:customTabs", (tabs) => {
|
|
181
|
+
tabs.push({
|
|
182
|
+
name: "convex-nuxt",
|
|
183
|
+
title: "Convex",
|
|
184
|
+
icon: "carbon:data-base",
|
|
185
|
+
view: {
|
|
186
|
+
type: "iframe",
|
|
187
|
+
src: "/__convex_devtools"
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
const contextTypes = resolver.resolve("./runtime/utils/context");
|
|
193
|
+
addTypeTemplate({
|
|
194
|
+
filename: "types/convex-nuxt.d.ts",
|
|
195
|
+
getContents: () => `// Generated by use-convex
|
|
196
|
+
import type { ConvexNuxtContext } from '${contextTypes}'
|
|
197
|
+
|
|
198
|
+
declare module '@nuxt/schema' {
|
|
199
|
+
interface PublicRuntimeConfig {
|
|
200
|
+
convex: {
|
|
201
|
+
url?: string
|
|
202
|
+
server?: boolean
|
|
203
|
+
client?: import('convex/browser').ConvexClientOptions
|
|
204
|
+
auth?: {
|
|
205
|
+
provider?: 'convex-auth'
|
|
206
|
+
cookie?: string
|
|
207
|
+
httpOnly?: boolean
|
|
208
|
+
presentCookie?: string
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
declare module 'nuxt/app' {
|
|
215
|
+
interface NuxtApp {
|
|
216
|
+
$convex: ConvexNuxtContext
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
declare module 'vue' {
|
|
221
|
+
interface ComponentCustomProperties {
|
|
222
|
+
$convex: ConvexNuxtContext
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export {}
|
|
227
|
+
`
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
export { module$1 as default };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
declare var __VLS_1: {};
|
|
2
|
+
type __VLS_Slots = {} & {
|
|
3
|
+
default?: (props: typeof __VLS_1) => any;
|
|
4
|
+
};
|
|
5
|
+
declare const __VLS_base: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
6
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
7
|
+
declare const _default: typeof __VLS_export;
|
|
8
|
+
export default _default;
|
|
9
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
10
|
+
new (): {
|
|
11
|
+
$slots: S;
|
|
12
|
+
};
|
|
13
|
+
};
|