Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/content/1.getting-started/2.installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ yarn add nuxt-convex convex

::

::note
`nuxt-convex` ships with the recommended Vue integration (`convex-vue`), so you do not need to install it separately.
::

Add the module to your Nuxt configuration:

```ts [nuxt.config.ts]
Expand Down
101 changes: 101 additions & 0 deletions docs/content/3.composables/5.use-convex-paginated-query.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
---
title: useConvexPaginatedQuery
description: Paginate Convex queries with real-time updates.
---

Paginate a Convex query that returns a `PaginationResult`. This composable is **client-only** and subscribes to real-time updates. For SSR, use `useConvexQuery` and fetch a single page on the server.

## Usage

```vue [app/components/Tasks.vue]
<script setup lang="ts">
import { api } from '#convex/api'

const {
data,
pages,
isDone,
isLoading,
isLoadingMore,
loadMore,
reset,
} = useConvexPaginatedQuery(api.tasks.listPaginated, {}, { numItems: 20 })
</script>

<template>
<div v-if="isLoading">
Loading…
</div>
<ul v-else>
<li v-for="task in data" :key="task._id">
{{ task.title }}
</li>
</ul>
<button :disabled="isDone || isLoadingMore" @click="loadMore">
Load more
</button>
<button @click="reset">
Reset
</button>
</template>
```

## Parameters

| Parameter | Type | Description |
| --------- | ---------------------------- | ----------------------------------------------------- |
| `query` | `FunctionReference<'query'>` | The paginated Convex query to call. |
| `args` | `object` | Arguments for the query (excluding `paginationOpts`). |
| `options` | `{ numItems: number }` | Number of items per page. |

## Return Values

| Property | Type | Description |
| --------------- | ----------------------------------------------- | ------------------------------------------ |
| `data` | `ComputedRef<T[]>` | Flattened list of all loaded pages. |
| `pages` | `ComputedRef<T[][]>` | Array of pages. |
| `lastPage` | `ComputedRef<PaginationResult<T> \| undefined>` | Last page result. |
| `isDone` | `Ref<boolean>` | True when all pages are loaded. |
| `isLoading` | `ComputedRef<boolean>` | True while the first page is loading. |
| `isLoadingMore` | `Ref<boolean>` | True while loading additional pages. |
| `loadMore` | `() => void` | Load the next page. |
| `reset` | `() => void` | Clear pages and reload from the start. |
| `suspense` | `() => Promise<T[][]>` | Resolves when the first page is available. |

## Components

`nuxt-convex` also includes renderless components for template usage:

### `<ConvexQuery>`

```vue
<ConvexQuery :query="api.tasks.list" :args="{}">
<template #loading>Loading…</template>
<template #error="{ error }">Error: {{ error.message }}</template>
<template #empty>No tasks yet.</template>
<template #default="{ data }">
<ul>
<li v-for="task in data" :key="task._id">{{ task.title }}</li>
</ul>
</template>
</ConvexQuery>
```

### `<ConvexPaginatedQuery>`

```vue
<ConvexPaginatedQuery :query="api.tasks.listPaginated" :args="{}" :options="{ numItems: 20 }">
<template #loading>Loading…</template>
<template #error="{ error, reset }">
<div>Error: {{ error.message }}</div>
<button @click="reset">Retry</button>
</template>
<template #empty>No tasks yet.</template>
<template #default="{ data, loadMore, isDone }">
<ul>
<li v-for="task in data" :key="task._id">{{ task.title }}</li>
</ul>
<button :disabled="isDone" @click="loadMore">Load more</button>
</template>
</ConvexPaginatedQuery>
```
9 changes: 6 additions & 3 deletions docs/content/5.integrations/1.better-auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ Export CRUD functions that the Better Auth adapter will call:
import { createApi } from '@convex-dev/better-auth'
import schema from './schema'

export const { create, findOne, findMany, updateOne, updateMany, deleteOne, deleteMany } =
createApi(schema, () => ({}))
export const { create, findOne, findMany, updateOne, updateMany, deleteOne, deleteMany }
= createApi(schema, () => ({}))
```

### 7. Add Auth Tables to Schema
Expand Down Expand Up @@ -156,7 +156,9 @@ const { user, signIn, signOut } = useUserSession()
<template>
<div v-if="user">
<p>Welcome, {{ user.name }}</p>
<button @click="signOut()">Sign Out</button>
<button @click="signOut()">
Sign Out
</button>
</div>
<div v-else>
<button @click="signIn.social({ provider: 'github' })">
Expand All @@ -178,6 +180,7 @@ export default defineEventHandler(async (event) => {
## Performance

HTTP latency to Convex (~50-200ms per DB call) is acceptable for auth operations:

- Login/signup are infrequent
- Use JWE session cookies to minimize DB reads
- Enable `cookieCache` for session caching
Expand Down
6 changes: 3 additions & 3 deletions docs/content/5.integrations/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ navigation: false
Integrate nuxt-convex with popular authentication and other services.

::card-group
::card{icon="i-simple-icons-auth0" title="Better Auth" to="/integrations/better-auth"}
Use Convex as the database for Better Auth authentication.
::
::card{icon="i-simple-icons-auth0" title="Better Auth" to="/integrations/better-auth"}
Use Convex as the database for Better Auth authentication.
::
::
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@
"convex": ">=1.0.0"
},
"dependencies": {
"@convex-vue/core": "^0.0.4",
"@nuxt/kit": "catalog:prod",
"consola": "catalog:prod",
"convex-vue": "^0.1.5",
"defu": "catalog:prod",
"pathe": "catalog:prod"
},
Expand Down
2 changes: 1 addition & 1 deletion playground/app/auth.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { defineClientAuth } from '@onmax/nuxt-better-auth/config'
import { convexClient, crossDomainClient } from '@convex-dev/better-auth/client/plugins'
import { defineClientAuth } from '@onmax/nuxt-better-auth/config'

export default defineClientAuth(() => ({
baseURL: `${import.meta.env.VITE_CONVEX_SITE_URL}/api/auth`,
Expand Down
5 changes: 3 additions & 2 deletions playground/convex/auth.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import type { GenericCtx } from '@convex-dev/better-auth'
import type { DataModel } from './_generated/dataModel'
import process from 'node:process'
import { createClient } from '@convex-dev/better-auth'
import { convex, crossDomain } from '@convex-dev/better-auth/plugins'
import { betterAuth } from 'better-auth/minimal'
import { components } from './_generated/api'
import { query } from './_generated/server'
import { betterAuth } from 'better-auth/minimal'
import authConfig from './auth.config'

const siteUrl = process.env.SITE_URL!

export const authComponent = createClient<DataModel>(components.betterAuth)

export const createAuth = (ctx: GenericCtx<DataModel>) => {
export function createAuth(ctx: GenericCtx<DataModel>): ReturnType<typeof betterAuth> {
return betterAuth({
trustedOrigins: [siteUrl],
database: authComponent.adapter(ctx),
Expand Down
2 changes: 1 addition & 1 deletion playground/convex/convex.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { defineApp } from 'convex/server'
import betterAuth from '@convex-dev/better-auth/convex.config'
import { defineApp } from 'convex/server'

const app = defineApp()
app.use(betterAuth)
Expand Down
Loading
Loading