use-convex 1.2.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +120 -41
- package/dist/module.d.mts +73 -31
- package/dist/module.mjs +73 -17
- package/dist/runtime/auth/oauth.d.ts +96 -0
- package/dist/runtime/auth/oauth.js +170 -0
- package/dist/runtime/auth/sessionRoutes.d.ts +37 -0
- package/dist/runtime/auth/sessionRoutes.js +41 -0
- package/dist/runtime/composables/useAuth.d.ts +81 -48
- package/dist/runtime/composables/useAuth.js +69 -398
- package/dist/runtime/composables/useAuthToken.d.ts +2 -2
- package/dist/runtime/composables/useAuthToken.js +4 -0
- package/dist/runtime/composables/useConvexAuth.js +1 -1
- package/dist/runtime/composables/useConvexPaginatedQuery.js +6 -1
- package/dist/runtime/composables/useConvexQueries.d.ts +36 -7
- package/dist/runtime/composables/useConvexQueries.js +37 -13
- package/dist/runtime/composables/useConvexQuery.js +6 -1
- package/dist/runtime/plugin.auth.client.d.ts +8 -3
- package/dist/runtime/plugin.auth.client.js +208 -23
- package/dist/runtime/plugin.server.js +8 -2
- package/dist/runtime/server/auth.d.ts +7 -2
- package/dist/runtime/server/auth.js +14 -3
- package/dist/runtime/server/convexAuth/refresh.d.ts +3 -0
- package/dist/runtime/server/convexAuth/refresh.js +5 -0
- package/dist/runtime/server/convexAuth/session.middleware.d.ts +10 -0
- package/dist/runtime/server/convexAuth/session.middleware.js +37 -0
- package/dist/runtime/server/convexAuth/setup.d.ts +21 -0
- package/dist/runtime/server/convexAuth/setup.js +90 -0
- package/dist/runtime/server/convexAuth/signin.d.ts +3 -0
- package/dist/runtime/server/convexAuth/signin.js +5 -0
- package/dist/runtime/server/convexAuth/signout.d.ts +3 -0
- package/dist/runtime/server/convexAuth/signout.js +5 -0
- package/dist/runtime/server/convexConfig.d.ts +2 -6
- package/dist/runtime/server/fetch.d.ts +9 -1
- package/dist/runtime/server/fetch.js +7 -10
- package/dist/runtime/utils/authClientOptions.d.ts +54 -0
- package/dist/runtime/utils/authClientOptions.js +10 -0
- package/dist/runtime/utils/authCookie.d.ts +8 -14
- package/dist/runtime/utils/authCookie.js +23 -27
- package/dist/runtime/utils/authStorage.d.ts +80 -42
- package/dist/runtime/utils/authStorage.js +56 -66
- package/dist/runtime/utils/context.d.ts +42 -6
- package/dist/runtime/utils/http.d.ts +7 -0
- package/dist/runtime/utils/http.js +5 -2
- package/dist/types.d.mts +6 -2
- package/package.json +10 -5
- package/dist/runtime/server/api/convex/auth/session.d.ts +0 -36
- package/dist/runtime/server/api/convex/auth/session.js +0 -90
- package/dist/runtime/server/authCookies.d.ts +0 -9
- package/dist/runtime/server/authCookies.js +0 -64
- package/dist/runtime/server/sameOrigin.d.ts +0 -14
- package/dist/runtime/server/sameOrigin.js +0 -29
- package/dist/runtime/utils/authMutex.d.ts +0 -15
- package/dist/runtime/utils/authMutex.js +0 -47
- package/dist/runtime/utils/oauthRedirect.d.ts +0 -5
- package/dist/runtime/utils/oauthRedirect.js +0 -13
package/README.md
CHANGED
|
@@ -75,7 +75,7 @@ Args accept the query's `FunctionArgs`, `'skip'`, or a `MaybeRefOrGetter` of eit
|
|
|
75
75
|
|
|
76
76
|
- **`'skip'`** — gate on missing ids, feature flags, etc. Keeps the same payload key as empty args so SSR HTML survives.
|
|
77
77
|
- **`authenticated: true`** — skip live subscribe until Convex confirms auth. SSR still snapshots when the JWT cookie is present. Prefer this over wrapping args yourself.
|
|
78
|
-
- **`token`** — authenticated SSR for this call only. Never put JWTs in `runtimeConfig.public`.
|
|
78
|
+
- **`token`** — authenticated SSR for this call only. Never put JWTs in `runtimeConfig.public`. Otherwise queries use the session token (Convex Auth SSR mode, or a BYO `convex.auth.cookie`).
|
|
79
79
|
|
|
80
80
|
Warm a subscription before a screen mounts:
|
|
81
81
|
|
|
@@ -88,13 +88,20 @@ prewarmQuery(api.tasks.list, {})
|
|
|
88
88
|
Browser-only live map (no SSR). Each value is `data | undefined` (loading) | `Error`. Combine with `useConvexQuery` when you need an SSR snapshot for known queries.
|
|
89
89
|
|
|
90
90
|
```ts
|
|
91
|
-
const results = useConvexQueries(
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
91
|
+
const results = useConvexQueries(
|
|
92
|
+
() => ({
|
|
93
|
+
tasks: { query: api.tasks.list, args: {} },
|
|
94
|
+
files: showFiles.value ? { query: api.files.list, args: {} } : 'skip',
|
|
95
|
+
// Per-entry gate (overrides the options bag when set):
|
|
96
|
+
// admin: { query: api.admin.stats, args: {}, authenticated: true },
|
|
97
|
+
}),
|
|
98
|
+
{ authenticated: true }, // wait for Convex auth before any subscribe
|
|
99
|
+
)
|
|
95
100
|
// results.value.tasks
|
|
96
101
|
```
|
|
97
102
|
|
|
103
|
+
`'skip'` still wins for missing ids / feature flags. Prefer `{ authenticated: true }` over wrapping every private entry yourself.
|
|
104
|
+
|
|
98
105
|
### Pagination
|
|
99
106
|
|
|
100
107
|
```ts
|
|
@@ -126,6 +133,12 @@ const { run, pending, error } = useConvexAction(api.tasks.shout)
|
|
|
126
133
|
const shouted = await run({ text: 'hello' }) // browser-only
|
|
127
134
|
```
|
|
128
135
|
|
|
136
|
+
`useConvexAction` calls `ConvexClient.action`. Actions from one client run in parallel with each other and with mutations. If a later call depends on an earlier one, await the earlier call before starting the next.
|
|
137
|
+
|
|
138
|
+
A failed action stays failed: Convex leaves retry to the caller, because the action may already have performed a side effect. `run` throws and sets `error`. Retry from your code when repeating the action is safe.
|
|
139
|
+
|
|
140
|
+
Use `useConvexAction` (and `fetchAction`) for work the user is waiting on. For durable work, write the user's intent in a mutation and schedule an `internalAction` from that mutation.
|
|
141
|
+
|
|
129
142
|
For paginated lists:
|
|
130
143
|
|
|
131
144
|
```ts
|
|
@@ -183,30 +196,64 @@ That runs `generateUploadUrl` → `PUT` to the signed URL → `syncMetadata({ ke
|
|
|
183
196
|
|
|
184
197
|
## Auth
|
|
185
198
|
|
|
186
|
-
### Convex Auth
|
|
199
|
+
### Convex Auth (v2)
|
|
200
|
+
|
|
201
|
+
First-party support for [Convex Auth v2](https://docs.convex.dev/auth/convex-auth/) (`@convex-dev/auth@^2`), built on its framework-agnostic `AuthClient` (`@convex-dev/auth/browser`) and SSR handlers (`@convex-dev/auth/ssr`). Requires `convex@^1.48`.
|
|
187
202
|
|
|
188
|
-
|
|
203
|
+
```bash
|
|
204
|
+
npm i @convex-dev/auth
|
|
205
|
+
```
|
|
189
206
|
|
|
190
207
|
```ts
|
|
191
208
|
convex: {
|
|
192
209
|
url: process.env.NUXT_PUBLIC_CONVEX_URL,
|
|
193
210
|
auth: {
|
|
194
211
|
provider: 'convex-auth',
|
|
195
|
-
//
|
|
212
|
+
// Every Convex function that can issue a session. The SSR auth proxy refuses the rest.
|
|
213
|
+
signIn: ['auth:signInWithUsernamePassword', 'auth:signUpWithUsernamePassword'],
|
|
214
|
+
// mode: 'ssr', // default; or 'spa'
|
|
215
|
+
// api: { refreshSession, signOut, isAuthenticated }, // default 'auth:<name>'
|
|
216
|
+
// routePrefix: '/api/convex/auth',
|
|
217
|
+
// cookieOptions: { secure, domain, path },
|
|
218
|
+
// allowedOrigins: ['https://app.example.com'],
|
|
219
|
+
// storage: 'localStorage', // or 'inMemory'
|
|
220
|
+
// storageNamespace: 'myapp', // default = deployment URL
|
|
221
|
+
// verbose: false,
|
|
196
222
|
},
|
|
197
223
|
}
|
|
198
224
|
```
|
|
199
225
|
|
|
226
|
+
**Session models**
|
|
227
|
+
|
|
228
|
+
| `mode` | Refresh token | Sign-in calls | SSR |
|
|
229
|
+
| --------------- | ---------------------------------- | ----------------------------------- | --------------------------------------------------- |
|
|
230
|
+
| `ssr` (default) | httpOnly cookie, set by Nitro | `POST <prefix>/signin` (auth proxy) | Authenticated; access token refreshed by middleware |
|
|
231
|
+
| `spa` | `localStorage` (or custom storage) | Straight to Convex | Signed out until the client restores |
|
|
232
|
+
|
|
233
|
+
In SSR mode the module mounts `<prefix>/signin`, `<prefix>/refresh` and `<prefix>/signout` (Convex Auth's `setupConvexAuthServer` handlers, with their CSRF origin check) and a Nitro middleware. Access tokens live 60 seconds, so the middleware refreshes an expiring token from the refresh cookie before SSR queries run, rotates both cookies, and hands the fresh token to the client payload. `signIn`, `allowedOrigins` and `cookieOptions` are server-only (`runtimeConfig.convexAuth`).
|
|
234
|
+
|
|
235
|
+
**Sign in.** Each v2 method exports its own typed functions. `useConvexSignIn` runs any of them through the right transport and adopts the session it returns:
|
|
236
|
+
|
|
200
237
|
```vue
|
|
201
238
|
<script setup lang="ts">
|
|
202
|
-
|
|
239
|
+
import { api } from '~~/convex/_generated/api'
|
|
240
|
+
|
|
241
|
+
const { run: signIn, pending } = useConvexSignIn(api.auth.signInWithUsernamePassword)
|
|
242
|
+
const { signOut, showAuthedUi } = useAuth()
|
|
243
|
+
|
|
244
|
+
async function submit() {
|
|
245
|
+
const result = await signIn({ username, password })
|
|
246
|
+
if (result.status === 'error') {
|
|
247
|
+
// result.userError.error: 'INVALID_CREDENTIALS' | 'RATE_LIMITED' | … | 'OTHER_ERROR'
|
|
248
|
+
}
|
|
249
|
+
}
|
|
203
250
|
</script>
|
|
204
251
|
|
|
205
252
|
<template>
|
|
206
253
|
<AuthLoading>Resolving…</AuthLoading>
|
|
207
254
|
<AuthRefreshing>Refreshing session…</AuthRefreshing>
|
|
208
255
|
<Authenticated>
|
|
209
|
-
|
|
256
|
+
<button @click="signOut()">Sign out</button>
|
|
210
257
|
</Authenticated>
|
|
211
258
|
<Unauthenticated>
|
|
212
259
|
<!-- sign-in form -->
|
|
@@ -214,32 +261,56 @@ const { signIn, signOut } = useAuth()
|
|
|
214
261
|
</template>
|
|
215
262
|
```
|
|
216
263
|
|
|
217
|
-
|
|
264
|
+
Pass `{ kind: 'action' }` when a sign-in function is an action (function kinds are type-only).
|
|
265
|
+
|
|
266
|
+
**OAuth** (GitHub, Google, Apple). Starting a flow navigates to the provider. The callback (`?convexAuthCode=`) is finished on whichever page it lands, and the params are stripped from the URL and from `vue-router`:
|
|
218
267
|
|
|
219
268
|
```ts
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
269
|
+
const { signIn } = useOAuthSignIn({
|
|
270
|
+
providerName: 'github',
|
|
271
|
+
startSignIn: api.auth.startSignInWithGithub,
|
|
272
|
+
completeSignIn: api.auth.completeSignInWithGithub, // list it in `signIn` for SSR mode
|
|
273
|
+
})
|
|
274
|
+
await signIn() // or signIn({ redirectTo: '/after-login' })
|
|
275
|
+
|
|
276
|
+
const { flowError } = useOAuth() // ACCESS_DENIED | EXPIRED | INVALID_FLOW | OTHER_ERROR
|
|
223
277
|
```
|
|
224
278
|
|
|
225
|
-
|
|
279
|
+
`useAuth()` returns `isLoading`, `isAuthenticated`, `isRefreshing`, `hasSsrSession`, `showAuthedUi`, `token`, `setSession(bundle)` and `signOut()`. While signed in, the client subscribes to your `isAuthenticated` query, so a session revoked on the server signs the browser out right away.
|
|
226
280
|
|
|
227
|
-
|
|
228
|
-
- `convex/schema.ts` — spread `authTables`
|
|
229
|
-
- `convex/http.ts` — `auth.addHttpRoutes(http)` (required for OAuth / magic links)
|
|
230
|
-
- `convex/auth.config.ts` — JWT issuer (`CONVEX_SITE_URL`)
|
|
231
|
-
- Env: `JWT_PRIVATE_KEY` + `JWKS` (`npx @convex-dev/auth`), plus `SITE_URL` for OAuth
|
|
281
|
+
Prefer `<Authenticated>` (or `showAuthedUi`) so SSR HTML does not flash the sign-in form. Gate private queries with `{ authenticated: true }`.
|
|
232
282
|
|
|
233
|
-
|
|
283
|
+
For a custom `TokenStorage`, extra ambient sign-ins, or a custom `replaceUrl`, call `configureConvexAuth` from a client plugin that runs first:
|
|
234
284
|
|
|
235
285
|
```ts
|
|
236
|
-
auth
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
286
|
+
// plugins/convex-auth-options.client.ts
|
|
287
|
+
export default defineNuxtPlugin({
|
|
288
|
+
name: 'convex-auth-options',
|
|
289
|
+
enforce: 'pre',
|
|
290
|
+
setup() {
|
|
291
|
+
configureConvexAuth({
|
|
292
|
+
storage: { getItem, setItem, removeItem }, // may be async
|
|
293
|
+
// ambientSignIns: [convexOAuth()], // [] disables OAuth callback handling
|
|
294
|
+
})
|
|
295
|
+
},
|
|
296
|
+
})
|
|
240
297
|
```
|
|
241
298
|
|
|
242
|
-
|
|
299
|
+
You own the Convex backend (see the [v2 docs](https://docs.convex.dev/auth/convex-auth/) and `playground/convex`):
|
|
300
|
+
|
|
301
|
+
- `convex/convex.config.ts`: `app.use(auth)` plus each method's components (e.g. `authPassword`, `authUsername`)
|
|
302
|
+
- `convex/auth.config.ts`: `providers: [convexAuthProvider()]`
|
|
303
|
+
- `convex/auth.ts`: `setupConvexAuth({ component: components.auth })` exporting `signOut`, `refreshSession`, `isAuthenticated`, plus each method's sign-in functions
|
|
304
|
+
- Your own `users` table and a `createUser` callback. No `authTables`, `JWT_PRIVATE_KEY` or `JWKS`.
|
|
305
|
+
|
|
306
|
+
#### Migrating from v1 (`use-convex` 0.x)
|
|
307
|
+
|
|
308
|
+
- Backend: follow Convex's [v1 → v2 guide](https://docs.convex.dev/auth/convex-auth/migrating/from-convex-auth-v1).
|
|
309
|
+
- `signIn(provider, params)` is gone. Use `useConvexSignIn(api.auth.<fn>)` or `useOAuthSignIn(refs)`.
|
|
310
|
+
- `useAuth()` no longer returns `signIn`, `pending` or `error`. Sign-in results come back as `{ status, userError }`.
|
|
311
|
+
- Options removed: `httpOnly`, `presentCookie`, `shouldHandleCode` (and `configureConvexAuth({ replaceURL, shouldHandleCode, storageNamespace })`). SSR mode is the default and keeps the refresh token in an httpOnly cookie. `replaceURL` is now `replaceUrl`.
|
|
312
|
+
- `cookie` applies only to bring-your-own providers. Convex Auth uses `__convexAuthJWT` / `__convexAuthRefreshToken`.
|
|
313
|
+
- `/api/convex/auth/session` is replaced by `<prefix>/signin|refresh|signout`. List every session-issuing function in `convex.auth.signIn`.
|
|
243
314
|
|
|
244
315
|
### SSR query budget
|
|
245
316
|
|
|
@@ -290,7 +361,7 @@ auth: {
|
|
|
290
361
|
|
|
291
362
|
## Server routes
|
|
292
363
|
|
|
293
|
-
Nitro helpers are auto-imported in `server/`. Pass the H3 `event` so they resolve the deployment URL and
|
|
364
|
+
Nitro helpers are auto-imported in `server/`. Pass the H3 `event` so they resolve the deployment URL and the session JWT (Convex Auth SSR mode or a BYO cookie):
|
|
294
365
|
|
|
295
366
|
```ts
|
|
296
367
|
// server/api/tasks.get.ts
|
|
@@ -318,7 +389,9 @@ export default defineEventHandler(async (event) => {
|
|
|
318
389
|
})
|
|
319
390
|
```
|
|
320
391
|
|
|
321
|
-
`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.
|
|
392
|
+
`fetchAction` uses the same options. Each helper builds a fresh `ConvexHttpClient`. Override with `{ token }` when you already have a JWT. Pass `{ adminToken }` (deploy key / admin key) for privileged server tooling — same as Next.js `fetchQuery` (user `token` is ignored when `adminToken` is set). `getConvexToken(event)` reads the cookie without throwing.
|
|
393
|
+
|
|
394
|
+
`fetchAction` throws on failure. Convex leaves retry to the caller, because the action may already have performed a side effect. Retry in the route when repeating the action is safe. Use `fetchAction` for work the request is waiting on. For durable work, write the intent in a mutation and schedule an `internalAction` from that mutation. Browser actions run in parallel with each other and with mutations; see [Mutations and actions](#mutations-and-actions).
|
|
322
395
|
|
|
323
396
|
## Config
|
|
324
397
|
|
|
@@ -328,10 +401,17 @@ convex: {
|
|
|
328
401
|
server: true, // SSR snapshots; override per query with { server }
|
|
329
402
|
client: { unsavedChangesWarning: false }, // forwarded to new ConvexClient()
|
|
330
403
|
auth: {
|
|
331
|
-
provider: 'convex-auth',
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
404
|
+
provider: 'convex-auth', // omit for BYO providers
|
|
405
|
+
mode: 'ssr', // or 'spa'
|
|
406
|
+
signIn: ['auth:signInWithUsernamePassword'], // SSR auth proxy allowlist (server-only)
|
|
407
|
+
// api: { refreshSession: 'auth:refreshSession', signOut: 'auth:signOut', isAuthenticated: 'auth:isAuthenticated' },
|
|
408
|
+
// routePrefix: '/api/convex/auth',
|
|
409
|
+
// cookieOptions: { secure: true, domain: undefined, path: '/' },
|
|
410
|
+
// allowedOrigins: [],
|
|
411
|
+
// storage: 'localStorage', // or 'inMemory'
|
|
412
|
+
// storageNamespace: 'myapp',
|
|
413
|
+
// verbose: false,
|
|
414
|
+
// cookie: 'convex_jwt', // BYO providers only
|
|
335
415
|
},
|
|
336
416
|
}
|
|
337
417
|
```
|
|
@@ -360,21 +440,20 @@ pnpm install
|
|
|
360
440
|
|
|
361
441
|
# Terminal 1 — Convex backend (writes CONVEX_URL to playground/.env.local)
|
|
362
442
|
pnpm run dev:backend
|
|
363
|
-
# first time: npx @convex-dev/auth # JWT_PRIVATE_KEY + JWKS
|
|
364
443
|
|
|
365
444
|
# Terminal 2 — Nuxt
|
|
366
445
|
pnpm run dev
|
|
367
446
|
```
|
|
368
447
|
|
|
369
|
-
| Route | What it shows
|
|
370
|
-
| --------- |
|
|
371
|
-
| `/` | Shell session: features + composable call-shape demos
|
|
372
|
-
| `/live` | SSR snapshot + live overlay (sign up, CRUD todos)
|
|
373
|
-
| `/server` | Nitro `fetchQuery` / `fetchMutation` / `fetchAction`
|
|
374
|
-
| `/files` | `useConvexFileUpload` (upload, list, preview, delete)
|
|
375
|
-
| `/extras` | `live: false`, pagination, action, connection state
|
|
448
|
+
| Route | What it shows |
|
|
449
|
+
| --------- | --------------------------------------------------------------------- |
|
|
450
|
+
| `/` | Shell session: features + composable call-shape demos |
|
|
451
|
+
| `/live` | SSR snapshot + live overlay (username + password sign up, CRUD todos) |
|
|
452
|
+
| `/server` | Nitro `fetchQuery` / `fetchMutation` / `fetchAction` |
|
|
453
|
+
| `/files` | `useConvexFileUpload` (upload, list, preview, delete) |
|
|
454
|
+
| `/extras` | `live: false`, pagination, action, connection state |
|
|
376
455
|
|
|
377
|
-
On `/server`: `GET /api/health` is public; `GET`/`POST /api/tasks` use the
|
|
456
|
+
On `/server`: `GET /api/health` is public; `GET`/`POST /api/tasks` and `POST /api/shout` use the session JWT (refreshed by the Convex Auth middleware). `POST /api/shout` is an authenticated `fetchAction` demo.
|
|
378
457
|
|
|
379
458
|
## Releasing
|
|
380
459
|
|
package/dist/module.d.mts
CHANGED
|
@@ -1,64 +1,106 @@
|
|
|
1
1
|
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
2
|
import * as convex_browser from 'convex/browser';
|
|
3
|
-
export {
|
|
3
|
+
export { ConvexAuthSession, ConvexSignInResult, OAuthCompleteResult, OAuthFlowError, OAuthProviderRefs, OAuthSignInOptions, OAuthStartResult, UseAuthReturn } from '../dist/runtime/composables/useAuth.js';
|
|
4
4
|
export { ConvexQueryArgs, UseConvexQueryOptions, UseConvexQueryReturn } from '../dist/runtime/composables/useConvexQuery.js';
|
|
5
5
|
export { AuthTokenFetcher, UseConvexAuthReturn, UseConvexAuthSetupOptions } from '../dist/runtime/composables/useConvexAuth.js';
|
|
6
6
|
export { OptimisticUpdate, UseConvexMutationOptions } from '../dist/runtime/composables/useConvexMutation.js';
|
|
7
7
|
export { ConvexFileUploadExtraArgs, ConvexFileUploadMeta, UseConvexFileUploadOptions } from '../dist/runtime/composables/useConvexFileUpload.js';
|
|
8
8
|
export { ConvexR2UploadApi, ConvexR2UploadProgress } from '../dist/runtime/composables/useConvexR2Upload.js';
|
|
9
9
|
export { PaginatedQueryArgs, PaginatedQueryItem, PaginatedQueryReference, PaginationStatus, UseConvexPaginatedQueryOptions, UseConvexPaginatedQueryReturn } from '../dist/runtime/composables/useConvexPaginatedQuery.js';
|
|
10
|
-
export { ConvexQueriesRequest, ConvexQueriesResult, ConvexQueryRequestEntry } from '../dist/runtime/composables/useConvexQueries.js';
|
|
10
|
+
export { ConvexQueriesRequest, ConvexQueriesResult, ConvexQueryRequestEntry, UseConvexQueriesOptions } from '../dist/runtime/composables/useConvexQueries.js';
|
|
11
11
|
export { ConvexFetchOptions } from '../dist/runtime/server/fetch.js';
|
|
12
12
|
export { ConvexRef } from '../dist/runtime/utils/functionReference.js';
|
|
13
13
|
export { ConvexAuthContext, ConvexNuxtContext } from '../dist/runtime/utils/context.js';
|
|
14
14
|
export { ConnectionState } from '../dist/runtime/composables/useConvexConnectionState.js';
|
|
15
15
|
export { ConvexGate } from '../dist/runtime/composables/useConvexGate.js';
|
|
16
|
+
export { ConvexAmbientSignIn, ConvexAuthClientOptions, ConvexAuthStorageMode, ConvexAuthTokenStorage, configureConvexAuth } from '../dist/runtime/utils/authClientOptions.js';
|
|
17
|
+
export { ConvexAuthServerRuntimeConfig } from '../dist/runtime/utils/authStorage.js';
|
|
16
18
|
|
|
17
19
|
interface ModuleAuthOptions {
|
|
18
20
|
/**
|
|
19
|
-
* Opt-in first-party Convex Auth (`@convex-dev/auth`)
|
|
21
|
+
* Opt-in first-party Convex Auth v2 (`@convex-dev/auth@^2`).
|
|
20
22
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* `
|
|
23
|
+
* Registers a client plugin built on `AuthClient` from
|
|
24
|
+
* `@convex-dev/auth/browser` (session restore, refresh, cross-tab sync,
|
|
25
|
+
* OAuth callbacks, server-side revocation), auto-imports `useAuth`,
|
|
26
|
+
* `useConvexSignIn`, `useOAuth`, `useOAuthSignIn` and `signOut`, and in
|
|
27
|
+
* SSR mode mounts the auth routes from `@convex-dev/auth/ssr` in Nitro.
|
|
25
28
|
*
|
|
26
29
|
* Omit for bring-your-own providers (Clerk, Auth0, custom) — wire
|
|
27
30
|
* `useConvexAuth({ fetchToken })` yourself.
|
|
28
31
|
*/
|
|
29
32
|
provider?: 'convex-auth';
|
|
30
33
|
/**
|
|
31
|
-
*
|
|
32
|
-
* When set, the server plugin reads this cookie into `ctx.ssrToken` and
|
|
33
|
-
* `useConvexQuery` falls back to it when `options.token` is omitted.
|
|
34
|
-
* `useAuth` / `useConvexAuth` expose the presence of this cookie as
|
|
35
|
-
* `hasSsrSession`.
|
|
36
|
-
* Nitro `fetch*` helpers also read this cookie when `{ event }` is passed.
|
|
34
|
+
* Convex Auth session model.
|
|
37
35
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
36
|
+
* - `'ssr'` (default): the refresh token lives in an httpOnly cookie set by
|
|
37
|
+
* Nitro; sign-ins go through the auth proxy route; SSR renders
|
|
38
|
+
* authenticated. Requires {@link signIn}.
|
|
39
|
+
* - `'spa'`: tokens live in browser storage and sign-ins go straight to
|
|
40
|
+
* Convex. SSR renders signed out.
|
|
41
|
+
*
|
|
42
|
+
* @default 'ssr'
|
|
41
43
|
*/
|
|
42
|
-
|
|
44
|
+
mode?: 'ssr' | 'spa';
|
|
43
45
|
/**
|
|
44
|
-
*
|
|
45
|
-
* (
|
|
46
|
-
* `document.cookie`. Prefer `true` in production.
|
|
47
|
-
*
|
|
48
|
-
* Note: ConvexClient still needs the JWT in memory for the WebSocket;
|
|
49
|
-
* the session route returns it only via same-origin POST `{ getToken: true }`.
|
|
50
|
-
* HttpOnly mitigates cookie theft, not XSS session theft. The readable
|
|
51
|
-
* presence cookie drives `hasSsrSession` / `showAuthedUi` (UI only — gate
|
|
52
|
-
* private queries with `{ authenticated: true }`).
|
|
46
|
+
* Names of the session functions exported from your Convex auth file
|
|
47
|
+
* (the result of `setupConvexAuth`).
|
|
53
48
|
*
|
|
54
|
-
* @default
|
|
49
|
+
* @default { refreshSession: 'auth:refreshSession', signOut: 'auth:signOut', isAuthenticated: 'auth:isAuthenticated' }
|
|
50
|
+
*/
|
|
51
|
+
api?: {
|
|
52
|
+
refreshSession?: string;
|
|
53
|
+
signOut?: string;
|
|
54
|
+
isAuthenticated?: string;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* SSR mode: every Convex function that can issue a session (sign-in,
|
|
58
|
+
* sign-up, OAuth `completeSignIn*`, …), e.g.
|
|
59
|
+
* `['auth:signInWithUsernamePassword', 'auth:signUpWithUsernamePassword']`.
|
|
60
|
+
* The auth proxy refuses anything not listed. Stored in private runtime
|
|
61
|
+
* config (`runtimeConfig.convexAuth.signIn`).
|
|
62
|
+
*/
|
|
63
|
+
signIn?: string[];
|
|
64
|
+
/**
|
|
65
|
+
* SSR mode: path prefix for the Nitro auth routes
|
|
66
|
+
* (`<prefix>/signin`, `<prefix>/refresh`, `<prefix>/signout`).
|
|
67
|
+
* @default '/api/convex/auth'
|
|
68
|
+
*/
|
|
69
|
+
routePrefix?: string;
|
|
70
|
+
/**
|
|
71
|
+
* SSR mode: origins trusted by the auth routes' CSRF check besides the
|
|
72
|
+
* request's own Host (e.g. behind a proxy that rewrites Host).
|
|
55
73
|
*/
|
|
56
|
-
|
|
74
|
+
allowedOrigins?: string[];
|
|
57
75
|
/**
|
|
58
|
-
*
|
|
59
|
-
*
|
|
76
|
+
* SSR mode: auth cookie attributes. `httpOnly`, `sameSite` and lifetimes
|
|
77
|
+
* are fixed by Convex Auth. `secure` defaults to true except on localhost.
|
|
60
78
|
*/
|
|
61
|
-
|
|
79
|
+
cookieOptions?: {
|
|
80
|
+
secure?: boolean;
|
|
81
|
+
domain?: string;
|
|
82
|
+
path?: string;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Namespace for token storage keys. Non-alphanumeric characters are
|
|
86
|
+
* ignored. Defaults to the deployment URL.
|
|
87
|
+
*/
|
|
88
|
+
storageNamespace?: string;
|
|
89
|
+
/**
|
|
90
|
+
* Client token storage. `'localStorage'` (default) or `'inMemory'`.
|
|
91
|
+
* For a custom TokenStorage, call `configureConvexAuth({ storage })` from a
|
|
92
|
+
* client plugin with `enforce: 'pre'`.
|
|
93
|
+
* @default 'localStorage'
|
|
94
|
+
*/
|
|
95
|
+
storage?: 'localStorage' | 'inMemory';
|
|
96
|
+
/** Log Convex Auth refresh / lifecycle steps to the console. */
|
|
97
|
+
verbose?: boolean;
|
|
98
|
+
/**
|
|
99
|
+
* BYO providers only: cookie whose value is a JWT used for authenticated
|
|
100
|
+
* SSR queries and Nitro `fetch*` helpers. The app writes it after sign-in.
|
|
101
|
+
* Ignored with `provider: 'convex-auth'`.
|
|
102
|
+
*/
|
|
103
|
+
cookie?: string;
|
|
62
104
|
}
|
|
63
105
|
interface ModuleOptions {
|
|
64
106
|
/**
|
package/dist/module.mjs
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { defineNuxtModule, createResolver, addPlugin, addComponent, addServerScanDir, addServerHandler, addImports, addServerImports, addTypeTemplate } from '@nuxt/kit';
|
|
2
2
|
import { defu } from 'defu';
|
|
3
|
-
import {
|
|
3
|
+
import { isConvexAuth, resolveAuthMode, resolveAuthRoutes } from '../dist/runtime/utils/authStorage.js';
|
|
4
4
|
import { suggestedCloudUrlFromMismatch } from '../dist/runtime/utils/convexDashboard.js';
|
|
5
5
|
import { warnStaleLocalConvexUrl } from '../dist/runtime/utils/errors.js';
|
|
6
|
+
export { configureConvexAuth } from '../dist/runtime/utils/authClientOptions.js';
|
|
6
7
|
|
|
7
8
|
const module$1 = defineNuxtModule({
|
|
8
9
|
meta: {
|
|
@@ -18,10 +19,35 @@ const module$1 = defineNuxtModule({
|
|
|
18
19
|
},
|
|
19
20
|
setup(options, nuxt) {
|
|
20
21
|
const existing = nuxt.options.runtimeConfig.public.convex;
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
const {
|
|
23
|
+
signIn: authSignIn,
|
|
24
|
+
allowedOrigins: authAllowedOrigins,
|
|
25
|
+
cookieOptions: authCookieOptions,
|
|
26
|
+
...publicAuth
|
|
27
|
+
} = options.auth ?? {};
|
|
28
|
+
const auth = options.auth ? publicAuth : void 0;
|
|
29
|
+
if (auth && isConvexAuth(auth)) {
|
|
30
|
+
for (const legacy of ["httpOnly", "presentCookie", "shouldHandleCode"]) {
|
|
31
|
+
if (legacy in auth) {
|
|
32
|
+
console.warn(
|
|
33
|
+
`[use-convex] convex.auth.${legacy} was removed with Convex Auth v2 support. See the README migration notes.`
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (resolveAuthMode(auth) === "ssr" && !authSignIn?.length) {
|
|
38
|
+
console.warn(
|
|
39
|
+
"[use-convex] convex.auth.signIn is empty: the SSR auth proxy will refuse every sign-in. List your session-issuing functions, e.g. ['auth:signInWithUsernamePassword']."
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
nuxt.options.runtimeConfig.convexAuth = defu(
|
|
44
|
+
nuxt.options.runtimeConfig.convexAuth ?? {},
|
|
45
|
+
{
|
|
46
|
+
signIn: authSignIn ?? [],
|
|
47
|
+
allowedOrigins: authAllowedOrigins ?? [],
|
|
48
|
+
cookie: authCookieOptions ?? {}
|
|
49
|
+
}
|
|
50
|
+
);
|
|
25
51
|
nuxt.options.runtimeConfig.public.convex = defu(existing ?? {}, {
|
|
26
52
|
url: options.url,
|
|
27
53
|
server: options.server,
|
|
@@ -49,7 +75,8 @@ const module$1 = defineNuxtModule({
|
|
|
49
75
|
}
|
|
50
76
|
const resolver = createResolver(import.meta.url);
|
|
51
77
|
const runtimeDir = resolver.resolve("./runtime");
|
|
52
|
-
const useConvexAuthProvider = auth
|
|
78
|
+
const useConvexAuthProvider = isConvexAuth(auth);
|
|
79
|
+
const useSsrConvexAuth = useConvexAuthProvider && resolveAuthMode(auth) === "ssr";
|
|
53
80
|
nuxt.options.build.transpile.push(runtimeDir);
|
|
54
81
|
nuxt.hooks.hook("nitro:config", (nitroConfig) => {
|
|
55
82
|
nitroConfig.externals ||= {};
|
|
@@ -90,10 +117,24 @@ const module$1 = defineNuxtModule({
|
|
|
90
117
|
});
|
|
91
118
|
}
|
|
92
119
|
addServerScanDir(resolver.resolve("./runtime/server"));
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
120
|
+
if (useSsrConvexAuth) {
|
|
121
|
+
const routes = resolveAuthRoutes(auth);
|
|
122
|
+
for (const [route, file] of [
|
|
123
|
+
[routes.signIn, "signin"],
|
|
124
|
+
[routes.refresh, "refresh"],
|
|
125
|
+
[routes.signOut, "signout"]
|
|
126
|
+
]) {
|
|
127
|
+
addServerHandler({
|
|
128
|
+
route,
|
|
129
|
+
method: "post",
|
|
130
|
+
handler: resolver.resolve(`./runtime/server/convexAuth/${file}`)
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
addServerHandler({
|
|
134
|
+
middleware: true,
|
|
135
|
+
handler: resolver.resolve("./runtime/server/convexAuth/session.middleware")
|
|
136
|
+
});
|
|
137
|
+
}
|
|
97
138
|
if (nuxt.options.dev) {
|
|
98
139
|
addServerHandler({
|
|
99
140
|
route: "/__convex_devtools",
|
|
@@ -179,12 +220,28 @@ const module$1 = defineNuxtModule({
|
|
|
179
220
|
from: resolver.resolve("./runtime/composables/useAuth")
|
|
180
221
|
},
|
|
181
222
|
{
|
|
182
|
-
name: "
|
|
223
|
+
name: "useConvexSignIn",
|
|
183
224
|
from: resolver.resolve("./runtime/composables/useAuth")
|
|
184
225
|
},
|
|
226
|
+
{
|
|
227
|
+
name: "useOAuth",
|
|
228
|
+
from: resolver.resolve("./runtime/composables/useAuth")
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
name: "useOAuthSignIn",
|
|
232
|
+
from: resolver.resolve("./runtime/composables/useAuth")
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
name: "convexOAuth",
|
|
236
|
+
from: resolver.resolve("./runtime/auth/oauth")
|
|
237
|
+
},
|
|
185
238
|
{
|
|
186
239
|
name: "signOut",
|
|
187
240
|
from: resolver.resolve("./runtime/composables/useAuth")
|
|
241
|
+
},
|
|
242
|
+
{
|
|
243
|
+
name: "configureConvexAuth",
|
|
244
|
+
from: resolver.resolve("./runtime/utils/authClientOptions")
|
|
188
245
|
}
|
|
189
246
|
] : []
|
|
190
247
|
]);
|
|
@@ -224,6 +281,7 @@ const module$1 = defineNuxtModule({
|
|
|
224
281
|
});
|
|
225
282
|
}
|
|
226
283
|
const contextTypes = resolver.resolve("./runtime/utils/context");
|
|
284
|
+
const authTypes = resolver.resolve("./runtime/utils/authStorage");
|
|
227
285
|
addTypeTemplate({
|
|
228
286
|
filename: "types/convex-nuxt.d.ts",
|
|
229
287
|
getContents: () => `// Generated by use-convex
|
|
@@ -235,14 +293,12 @@ declare module '@nuxt/schema' {
|
|
|
235
293
|
url?: string
|
|
236
294
|
server?: boolean
|
|
237
295
|
client?: import('convex/browser').ConvexClientOptions
|
|
238
|
-
auth?: {
|
|
239
|
-
provider?: 'convex-auth'
|
|
240
|
-
cookie?: string
|
|
241
|
-
httpOnly?: boolean
|
|
242
|
-
presentCookie?: string
|
|
243
|
-
}
|
|
296
|
+
auth?: import('${authTypes}').ConvexAuthConfig
|
|
244
297
|
}
|
|
245
298
|
}
|
|
299
|
+
interface RuntimeConfig {
|
|
300
|
+
convexAuth: import('${authTypes}').ConvexAuthServerRuntimeConfig
|
|
301
|
+
}
|
|
246
302
|
}
|
|
247
303
|
|
|
248
304
|
declare module 'nuxt/app' {
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth ambient sign-in for Convex Auth v2.
|
|
3
|
+
*
|
|
4
|
+
* Port of `@convex-dev/auth`'s framework-agnostic OAuth client, which the
|
|
5
|
+
* package only ships behind its React entry point. Same wire contract:
|
|
6
|
+
* `startSignIn({ redirectTo })` → `{ redirect, state }`; the state is kept in
|
|
7
|
+
* the sign-in's storage, and the callback's `convexAuthCode` is redeemed with
|
|
8
|
+
* `completeSignIn({ code, state })` through the sign-in API (the auth proxy
|
|
9
|
+
* under SSR).
|
|
10
|
+
*/
|
|
11
|
+
import type { AuthClientConfig } from '@convex-dev/auth/browser';
|
|
12
|
+
import { type FunctionReference } from 'convex/server';
|
|
13
|
+
type AmbientSignIns = NonNullable<AuthClientConfig['ambientSignIns']>;
|
|
14
|
+
export type AmbientSignInClient = AmbientSignIns['signIns'][number];
|
|
15
|
+
export type AmbientSignInContext = Parameters<AmbientSignInClient['setup']>[0];
|
|
16
|
+
/** Callback params written by the Convex Auth OAuth component. */
|
|
17
|
+
export declare const OAUTH_CODE_PARAM = "convexAuthCode";
|
|
18
|
+
export declare const OAUTH_ERROR_PARAM = "convexAuthError";
|
|
19
|
+
export declare const OAUTH_SETUP_ID = "oauth";
|
|
20
|
+
export declare const OAUTH_ACTIONS_KEY = "actions";
|
|
21
|
+
export declare const OAUTH_FLOW_ERROR_KEY = "flowError";
|
|
22
|
+
/** A provider's `startSignIn*` / `completeSignIn*` mutations plus its name. */
|
|
23
|
+
export type OAuthProviderRefs = {
|
|
24
|
+
/** Label only, e.g. `'github'`. */
|
|
25
|
+
providerName: string;
|
|
26
|
+
startSignIn: FunctionReference<'mutation', 'public', {
|
|
27
|
+
redirectTo: string;
|
|
28
|
+
}, {
|
|
29
|
+
redirect: string;
|
|
30
|
+
state: string;
|
|
31
|
+
}>;
|
|
32
|
+
completeSignIn: FunctionReference<'mutation', 'public', {
|
|
33
|
+
code: string;
|
|
34
|
+
state: string;
|
|
35
|
+
}, any>;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Why a flow failed after the identity provider sent the user back.
|
|
39
|
+
* Switch on `error` and supply your own copy.
|
|
40
|
+
*/
|
|
41
|
+
export type OAuthFlowError = {
|
|
42
|
+
error: 'ACCESS_DENIED';
|
|
43
|
+
} | {
|
|
44
|
+
error: 'EXPIRED';
|
|
45
|
+
} | {
|
|
46
|
+
error: 'INVALID_FLOW';
|
|
47
|
+
} | {
|
|
48
|
+
error: 'OTHER_ERROR';
|
|
49
|
+
cause: unknown;
|
|
50
|
+
};
|
|
51
|
+
export type OAuthStartResult = {
|
|
52
|
+
status: 'redirect';
|
|
53
|
+
redirect: URL;
|
|
54
|
+
} | {
|
|
55
|
+
status: 'error';
|
|
56
|
+
userError: {
|
|
57
|
+
error: 'OTHER_ERROR';
|
|
58
|
+
cause: unknown;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
export type OAuthCompleteResult = {
|
|
62
|
+
status: 'complete';
|
|
63
|
+
} | {
|
|
64
|
+
status: 'error';
|
|
65
|
+
userError: OAuthFlowError;
|
|
66
|
+
};
|
|
67
|
+
export type OAuthSignInOptions = {
|
|
68
|
+
/** Where the provider sends the user back. Defaults to the current URL. */
|
|
69
|
+
redirectTo?: string;
|
|
70
|
+
/** Finish a flow started elsewhere instead of starting one. */
|
|
71
|
+
code?: string;
|
|
72
|
+
};
|
|
73
|
+
export type OAuthActions = {
|
|
74
|
+
signIn: (refs: OAuthProviderRefs, options?: OAuthSignInOptions) => Promise<OAuthStartResult | OAuthCompleteResult>;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* The OAuth ambient sign-in. Registered by default; pass it explicitly via
|
|
78
|
+
* `configureConvexAuth({ ambientSignIns: [convexOAuth(), …] })` when adding
|
|
79
|
+
* others.
|
|
80
|
+
*/
|
|
81
|
+
export type ConvexOAuthOptions = {
|
|
82
|
+
/**
|
|
83
|
+
* Where to keep the pending flow across the provider redirect, when the
|
|
84
|
+
* session token storage does not survive navigation (e.g. in-memory
|
|
85
|
+
* tokens). Defaults to the client's token storage.
|
|
86
|
+
*/
|
|
87
|
+
flowStorage?: {
|
|
88
|
+
getItem: (key: string) => string | null | undefined | Promise<string | null | undefined>;
|
|
89
|
+
setItem: (key: string, value: string) => void | Promise<void>;
|
|
90
|
+
removeItem: (key: string) => void | Promise<void>;
|
|
91
|
+
};
|
|
92
|
+
/** Key namespace for `flowStorage`, typically the deployment URL. */
|
|
93
|
+
namespace?: string;
|
|
94
|
+
};
|
|
95
|
+
export declare function convexOAuth(options?: ConvexOAuthOptions): AmbientSignInClient;
|
|
96
|
+
export {};
|