use-convex 1.1.0 → 1.3.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 +39 -5
- package/dist/module.d.mts +21 -1
- package/dist/module.mjs +5 -0
- package/dist/runtime/composables/prewarmQuery.d.ts +3 -2
- package/dist/runtime/composables/useAuth.js +99 -36
- package/dist/runtime/composables/useConvexAction.d.ts +3 -2
- package/dist/runtime/composables/useConvexFileUpload.d.ts +5 -4
- package/dist/runtime/composables/useConvexMutation.d.ts +4 -3
- package/dist/runtime/composables/useConvexPaginatedQuery.d.ts +3 -1
- package/dist/runtime/composables/useConvexQueries.d.ts +40 -10
- package/dist/runtime/composables/useConvexQueries.js +37 -13
- package/dist/runtime/composables/useConvexQuery.d.ts +4 -3
- package/dist/runtime/composables/useConvexR2Upload.d.ts +4 -3
- package/dist/runtime/plugin.auth.client.js +10 -1
- package/dist/runtime/server/fetch.d.ts +12 -4
- package/dist/runtime/server/fetch.js +4 -2
- package/dist/runtime/utils/authClientOptions.d.ts +61 -0
- package/dist/runtime/utils/authClientOptions.js +73 -0
- package/dist/runtime/utils/authStorage.d.ts +44 -3
- package/dist/runtime/utils/authStorage.js +88 -17
- package/dist/runtime/utils/context.d.ts +2 -3
- package/dist/runtime/utils/functionReference.d.ts +10 -0
- package/dist/runtime/utils/functionReference.js +0 -0
- package/dist/runtime/utils/http.d.ts +7 -0
- package/dist/runtime/utils/http.js +5 -2
- package/dist/runtime/utils/queryKey.d.ts +2 -2
- package/dist/types.d.mts +5 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -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
|
|
@@ -193,10 +200,34 @@ convex: {
|
|
|
193
200
|
auth: {
|
|
194
201
|
provider: 'convex-auth',
|
|
195
202
|
// cookie defaults to 'convex_jwt'
|
|
203
|
+
// storageNamespace: 'myapp', // optional; default = deployment URL
|
|
204
|
+
// storage: 'localStorage', // or 'inMemory' (verifier uses a short-lived cookie)
|
|
205
|
+
// shouldHandleCode: true, // set false to ignore ?code=
|
|
196
206
|
},
|
|
197
207
|
}
|
|
198
208
|
```
|
|
199
209
|
|
|
210
|
+
For non-default OAuth / callback flows (JS router `replaceURL`, function `shouldHandleCode`, custom `TokenStorage`), call `configureConvexAuth` from a client plugin that runs before the auth plugin:
|
|
211
|
+
|
|
212
|
+
```ts
|
|
213
|
+
// plugins/convex-auth-options.client.ts
|
|
214
|
+
export default defineNuxtPlugin({
|
|
215
|
+
name: 'convex-auth-options',
|
|
216
|
+
enforce: 'pre',
|
|
217
|
+
setup() {
|
|
218
|
+
const route = useRoute()
|
|
219
|
+
configureConvexAuth({
|
|
220
|
+
replaceURL: (url) => navigateTo(url, { replace: true }),
|
|
221
|
+
shouldHandleCode: () => route.path === '/auth/callback',
|
|
222
|
+
// storage: window.sessionStorage, // may be async; signIn waits before redirect
|
|
223
|
+
// storageNamespace: 'myapp',
|
|
224
|
+
})
|
|
225
|
+
},
|
|
226
|
+
})
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
`storage: 'inMemory'` keeps JWTs in memory. The OAuth verifier is a short-lived cookie so the `?code=` callback still works after the IdP redirect. Custom storage may return Promises; `signIn` waits for writes before navigating.
|
|
230
|
+
|
|
200
231
|
```vue
|
|
201
232
|
<script setup lang="ts">
|
|
202
233
|
const { signIn, signOut } = useAuth()
|
|
@@ -318,7 +349,7 @@ export default defineEventHandler(async (event) => {
|
|
|
318
349
|
})
|
|
319
350
|
```
|
|
320
351
|
|
|
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.
|
|
352
|
+
`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.
|
|
322
353
|
|
|
323
354
|
## Config
|
|
324
355
|
|
|
@@ -332,6 +363,9 @@ convex: {
|
|
|
332
363
|
cookie: 'convex_jwt',
|
|
333
364
|
httpOnly: false,
|
|
334
365
|
presentCookie: 'convex_auth_present',
|
|
366
|
+
storage: 'localStorage', // or 'inMemory'
|
|
367
|
+
// storageNamespace: 'myapp',
|
|
368
|
+
// shouldHandleCode: true,
|
|
335
369
|
},
|
|
336
370
|
}
|
|
337
371
|
```
|
package/dist/module.d.mts
CHANGED
|
@@ -7,11 +7,13 @@ export { OptimisticUpdate, UseConvexMutationOptions } from '../dist/runtime/comp
|
|
|
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
|
+
export { ConvexRef } from '../dist/runtime/utils/functionReference.js';
|
|
12
13
|
export { ConvexAuthContext, ConvexNuxtContext } from '../dist/runtime/utils/context.js';
|
|
13
14
|
export { ConnectionState } from '../dist/runtime/composables/useConvexConnectionState.js';
|
|
14
15
|
export { ConvexGate } from '../dist/runtime/composables/useConvexGate.js';
|
|
16
|
+
export { ConvexAuthClientOptions, ConvexAuthStorageMode, ConvexAuthTokenStorage, configureConvexAuth } from '../dist/runtime/utils/authClientOptions.js';
|
|
15
17
|
|
|
16
18
|
interface ModuleAuthOptions {
|
|
17
19
|
/**
|
|
@@ -58,6 +60,24 @@ interface ModuleAuthOptions {
|
|
|
58
60
|
* @default 'convex_auth_present'
|
|
59
61
|
*/
|
|
60
62
|
presentCookie?: string;
|
|
63
|
+
/**
|
|
64
|
+
* Namespace for local token keys (React `storageNamespace` parity).
|
|
65
|
+
* Non-alphanumeric characters are stripped. Defaults to the deployment URL.
|
|
66
|
+
*/
|
|
67
|
+
storageNamespace?: string;
|
|
68
|
+
/**
|
|
69
|
+
* Client token storage. `'localStorage'` (default) or `'inMemory'`.
|
|
70
|
+
* For a custom TokenStorage or `replaceURL` / function `shouldHandleCode`,
|
|
71
|
+
* call `configureConvexAuth` from a client plugin with `enforce: 'pre'`.
|
|
72
|
+
* Ignored when `httpOnly` is enabled.
|
|
73
|
+
* @default 'localStorage'
|
|
74
|
+
*/
|
|
75
|
+
storage?: 'localStorage' | 'inMemory';
|
|
76
|
+
/**
|
|
77
|
+
* When `false`, do not consume `?code=` OAuth callbacks.
|
|
78
|
+
* For a function gate, use `configureConvexAuth({ shouldHandleCode })`.
|
|
79
|
+
*/
|
|
80
|
+
shouldHandleCode?: boolean;
|
|
61
81
|
}
|
|
62
82
|
interface ModuleOptions {
|
|
63
83
|
/**
|
package/dist/module.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import { defu } from 'defu';
|
|
|
3
3
|
import { resolveAuthCookieName } 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: {
|
|
@@ -185,6 +186,10 @@ const module$1 = defineNuxtModule({
|
|
|
185
186
|
{
|
|
186
187
|
name: "signOut",
|
|
187
188
|
from: resolver.resolve("./runtime/composables/useAuth")
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
name: "configureConvexAuth",
|
|
192
|
+
from: resolver.resolve("./runtime/utils/authClientOptions")
|
|
188
193
|
}
|
|
189
194
|
] : []
|
|
190
195
|
]);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { FunctionArgs
|
|
1
|
+
import type { FunctionArgs } from 'convex/server';
|
|
2
|
+
import type { ConvexRef } from '../utils/functionReference.js';
|
|
2
3
|
/**
|
|
3
4
|
* Start a live subscription early so the first `useConvexQuery` / screen
|
|
4
5
|
* paint can reuse warm client state (React `prewarmQuery` parity).
|
|
@@ -6,4 +7,4 @@ import type { FunctionArgs, FunctionReference } from 'convex/server';
|
|
|
6
7
|
* Returns an unsubscribe function. When called during Vue `setup`, the
|
|
7
8
|
* subscription is also cleaned up with the current effect scope.
|
|
8
9
|
*/
|
|
9
|
-
export declare function prewarmQuery<Query extends
|
|
10
|
+
export declare function prewarmQuery<Query extends ConvexRef<'query'>>(query: Query, args?: FunctionArgs<Query>): () => void;
|
|
@@ -6,16 +6,21 @@ import { useConvexAuth } from "./useConvexAuth.js";
|
|
|
6
6
|
import { missingConvexUrlError, unreachableConvexUrlError } from "../utils/errors.js";
|
|
7
7
|
import { withRefreshMutex } from "../utils/authMutex.js";
|
|
8
8
|
import { useAuthJwtCookie, useAuthPresentCookie } from "../utils/authCookie.js";
|
|
9
|
+
import { getConvexAuthClientOptions, setConvexAuthModuleDefaults } from "../utils/authClientOptions.js";
|
|
9
10
|
import {
|
|
10
11
|
flattenSignInParams,
|
|
11
12
|
isHttpOnlyAuth,
|
|
12
13
|
JWT_STORAGE_KEY,
|
|
13
|
-
|
|
14
|
+
readLocalAsync,
|
|
15
|
+
readStored,
|
|
16
|
+
readVerifier,
|
|
17
|
+
readVerifierAsync,
|
|
14
18
|
REFRESH_TOKEN_STORAGE_KEY,
|
|
15
19
|
shouldConsumeOAuthCode,
|
|
16
20
|
storageKey,
|
|
17
21
|
VERIFIER_STORAGE_KEY,
|
|
18
|
-
|
|
22
|
+
writeLocalAsync,
|
|
23
|
+
writeVerifier
|
|
19
24
|
} from "../utils/authStorage.js";
|
|
20
25
|
import { tryUseConvexContext } from "../utils/context.js";
|
|
21
26
|
import { parseOAuthRedirect } from "../utils/oauthRedirect.js";
|
|
@@ -61,8 +66,8 @@ export async function signIn(provider, params) {
|
|
|
61
66
|
session.error.value = null;
|
|
62
67
|
try {
|
|
63
68
|
const flatParams = flattenSignInParams(params);
|
|
64
|
-
const existingVerifier =
|
|
65
|
-
|
|
69
|
+
const existingVerifier = await readVerifierAsync(session.verifierKey.value) ?? void 0;
|
|
70
|
+
await writeVerifier(session.verifierKey.value, null);
|
|
66
71
|
const result = await callSignIn(convexUrl, {
|
|
67
72
|
provider,
|
|
68
73
|
params: flatParams,
|
|
@@ -71,9 +76,9 @@ export async function signIn(provider, params) {
|
|
|
71
76
|
if (result.redirect !== void 0) {
|
|
72
77
|
const url = parseOAuthRedirect(result.redirect);
|
|
73
78
|
if (result.verifier) {
|
|
74
|
-
|
|
79
|
+
await writeVerifier(session.verifierKey.value, result.verifier);
|
|
75
80
|
}
|
|
76
|
-
if (
|
|
81
|
+
if (inBrowser()) {
|
|
77
82
|
window.location.href = url.toString();
|
|
78
83
|
}
|
|
79
84
|
return { signingIn: false, redirect: url };
|
|
@@ -98,7 +103,7 @@ export async function signOut() {
|
|
|
98
103
|
session.error.value = null;
|
|
99
104
|
try {
|
|
100
105
|
if (convexUrl) {
|
|
101
|
-
const token =
|
|
106
|
+
const token = await readLocalAsync(session.jwtKey.value);
|
|
102
107
|
const http = new ConvexHttpClient(convexUrl);
|
|
103
108
|
if (token) {
|
|
104
109
|
http.setAuth(token);
|
|
@@ -140,12 +145,23 @@ export function hydrateAuthFromStorage() {
|
|
|
140
145
|
});
|
|
141
146
|
return;
|
|
142
147
|
}
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
+
const stored = readStored(session.jwtKey.value);
|
|
149
|
+
const applyToken = (token) => {
|
|
150
|
+
session.hasSession.value = token !== null;
|
|
151
|
+
session.isLoading.value = false;
|
|
152
|
+
if (token) {
|
|
153
|
+
setJwtCookie(token);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
if (stored instanceof Promise) {
|
|
157
|
+
session.isLoading.value = true;
|
|
158
|
+
void stored.then(applyToken).catch(() => {
|
|
159
|
+
session.hasSession.value = false;
|
|
160
|
+
session.isLoading.value = false;
|
|
161
|
+
});
|
|
162
|
+
return;
|
|
148
163
|
}
|
|
164
|
+
applyToken(stored);
|
|
149
165
|
}
|
|
150
166
|
export async function getAuthToken({
|
|
151
167
|
forceRefreshToken
|
|
@@ -175,31 +191,37 @@ export async function getAuthToken({
|
|
|
175
191
|
});
|
|
176
192
|
}
|
|
177
193
|
if (!forceRefreshToken) {
|
|
178
|
-
return
|
|
194
|
+
return await readLocalAsync(session.jwtKey.value);
|
|
179
195
|
}
|
|
180
196
|
return withRefreshMutex(session.refreshKey.value, async () => {
|
|
181
|
-
const refreshToken =
|
|
197
|
+
const refreshToken = await readLocalAsync(session.refreshKey.value);
|
|
182
198
|
if (!refreshToken) {
|
|
183
|
-
persistTokens(session, null);
|
|
199
|
+
await persistTokens(session, null);
|
|
184
200
|
return null;
|
|
185
201
|
}
|
|
186
202
|
try {
|
|
187
203
|
const result = await callSignInWithRetry(convexUrl, { refreshToken });
|
|
188
204
|
const tokens = result.tokens ?? null;
|
|
189
205
|
if (!tokens) {
|
|
190
|
-
persistTokens(session, null);
|
|
206
|
+
await persistTokens(session, null);
|
|
191
207
|
return null;
|
|
192
208
|
}
|
|
193
|
-
persistTokens(session, tokens);
|
|
209
|
+
await persistTokens(session, tokens);
|
|
194
210
|
return tokens.token;
|
|
195
211
|
} catch {
|
|
196
|
-
persistTokens(session, null);
|
|
212
|
+
await persistTokens(session, null);
|
|
197
213
|
return null;
|
|
198
214
|
}
|
|
199
215
|
});
|
|
200
216
|
}
|
|
217
|
+
function inBrowser() {
|
|
218
|
+
if (import.meta.client) {
|
|
219
|
+
return true;
|
|
220
|
+
}
|
|
221
|
+
return import.meta.client !== false && typeof window !== "undefined";
|
|
222
|
+
}
|
|
201
223
|
export function hasPendingOAuthCallback() {
|
|
202
|
-
if (!
|
|
224
|
+
if (!inBrowser()) {
|
|
203
225
|
return false;
|
|
204
226
|
}
|
|
205
227
|
const session = useAuthSession();
|
|
@@ -207,11 +229,25 @@ export function hasPendingOAuthCallback() {
|
|
|
207
229
|
return false;
|
|
208
230
|
}
|
|
209
231
|
const code = new URLSearchParams(window.location.search).get("code");
|
|
210
|
-
|
|
211
|
-
|
|
232
|
+
if (!code) {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
const gate = getConvexAuthClientOptions().shouldHandleCode;
|
|
236
|
+
if (gate === false || typeof gate === "function" && !gate()) {
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
const verifier = readVerifier(session.verifierKey.value);
|
|
240
|
+
if (verifier instanceof Promise) {
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
return shouldConsumeOAuthCode({
|
|
244
|
+
code,
|
|
245
|
+
verifier,
|
|
246
|
+
shouldHandleCode: gate
|
|
247
|
+
});
|
|
212
248
|
}
|
|
213
249
|
export async function consumeOAuthCodeFromUrl() {
|
|
214
|
-
if (!
|
|
250
|
+
if (!inBrowser()) {
|
|
215
251
|
return false;
|
|
216
252
|
}
|
|
217
253
|
const session = useAuthSession();
|
|
@@ -219,18 +255,36 @@ export async function consumeOAuthCodeFromUrl() {
|
|
|
219
255
|
return false;
|
|
220
256
|
}
|
|
221
257
|
const code = new URLSearchParams(window.location.search).get("code");
|
|
222
|
-
const verifier =
|
|
223
|
-
|
|
258
|
+
const verifier = await readVerifierAsync(session.verifierKey.value);
|
|
259
|
+
const gate = getConvexAuthClientOptions().shouldHandleCode;
|
|
260
|
+
if (!shouldConsumeOAuthCode({
|
|
261
|
+
code,
|
|
262
|
+
verifier,
|
|
263
|
+
shouldHandleCode: gate
|
|
264
|
+
})) {
|
|
224
265
|
return false;
|
|
225
266
|
}
|
|
226
267
|
const url = new URL(window.location.href);
|
|
227
268
|
url.searchParams.delete("code");
|
|
228
|
-
|
|
269
|
+
const relativeUrl = url.pathname + url.search + url.hash;
|
|
270
|
+
const replaceURL = getConvexAuthClientOptions().replaceURL;
|
|
271
|
+
try {
|
|
272
|
+
if (replaceURL) {
|
|
273
|
+
await replaceURL(relativeUrl);
|
|
274
|
+
} else {
|
|
275
|
+
window.history.replaceState({}, "", relativeUrl);
|
|
276
|
+
}
|
|
277
|
+
} catch (cause) {
|
|
278
|
+
session.error.value = cause instanceof Error ? cause.message : "OAuth callback failed";
|
|
279
|
+
session.isLoading.value = false;
|
|
280
|
+
session.pending.value = false;
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
229
283
|
session.pending.value = true;
|
|
230
284
|
session.error.value = null;
|
|
231
285
|
session.isLoading.value = true;
|
|
232
286
|
try {
|
|
233
|
-
|
|
287
|
+
await writeVerifier(session.verifierKey.value, null);
|
|
234
288
|
const result = await callSignInWithRetry(session.convexUrl, {
|
|
235
289
|
params: { code },
|
|
236
290
|
verifier
|
|
@@ -257,19 +311,28 @@ function useAuthSession() {
|
|
|
257
311
|
const config = useRuntimeConfig();
|
|
258
312
|
const convexConfig = config.public.convex;
|
|
259
313
|
const convexUrl = convexConfig?.url;
|
|
260
|
-
const
|
|
314
|
+
const authConfig = convexConfig?.auth;
|
|
315
|
+
const httpOnly = isHttpOnlyAuth(authConfig);
|
|
316
|
+
if (authConfig?.provider === "convex-auth") {
|
|
317
|
+
setConvexAuthModuleDefaults({
|
|
318
|
+
storageNamespace: authConfig.storageNamespace,
|
|
319
|
+
storage: authConfig.storage,
|
|
320
|
+
shouldHandleCode: authConfig.shouldHandleCode
|
|
321
|
+
});
|
|
322
|
+
}
|
|
261
323
|
const isLoading = useState("convex-auth-loading", () => true);
|
|
262
324
|
const hasSession = useState("convex-auth-has-session", () => false);
|
|
263
325
|
const error = useState("convex-auth-error", () => null);
|
|
264
326
|
const pending = useState("convex-auth-pending", () => false);
|
|
327
|
+
const namespace = getConvexAuthClientOptions().storageNamespace ?? authConfig?.storageNamespace ?? convexUrl;
|
|
265
328
|
const jwtKey = computed(
|
|
266
|
-
() =>
|
|
329
|
+
() => namespace ? storageKey(JWT_STORAGE_KEY, namespace) : JWT_STORAGE_KEY
|
|
267
330
|
);
|
|
268
331
|
const refreshKey = computed(
|
|
269
|
-
() =>
|
|
332
|
+
() => namespace ? storageKey(REFRESH_TOKEN_STORAGE_KEY, namespace) : REFRESH_TOKEN_STORAGE_KEY
|
|
270
333
|
);
|
|
271
334
|
const verifierKey = computed(
|
|
272
|
-
() =>
|
|
335
|
+
() => namespace ? storageKey(VERIFIER_STORAGE_KEY, namespace) : VERIFIER_STORAGE_KEY
|
|
273
336
|
);
|
|
274
337
|
return {
|
|
275
338
|
convexUrl,
|
|
@@ -353,8 +416,8 @@ async function persistTokens(session, tokens) {
|
|
|
353
416
|
if (session.httpOnly) {
|
|
354
417
|
if (tokens === null) {
|
|
355
418
|
await writeHttpOnlySession(null);
|
|
356
|
-
|
|
357
|
-
|
|
419
|
+
await writeLocalAsync(session.jwtKey.value, null);
|
|
420
|
+
await writeLocalAsync(session.refreshKey.value, null);
|
|
358
421
|
session.hasSession.value = false;
|
|
359
422
|
session.isLoading.value = false;
|
|
360
423
|
return;
|
|
@@ -365,15 +428,15 @@ async function persistTokens(session, tokens) {
|
|
|
365
428
|
return;
|
|
366
429
|
}
|
|
367
430
|
if (tokens === null) {
|
|
368
|
-
|
|
369
|
-
|
|
431
|
+
await writeLocalAsync(session.jwtKey.value, null);
|
|
432
|
+
await writeLocalAsync(session.refreshKey.value, null);
|
|
370
433
|
setJwtCookie(null);
|
|
371
434
|
session.hasSession.value = false;
|
|
372
435
|
session.isLoading.value = false;
|
|
373
436
|
return;
|
|
374
437
|
}
|
|
375
|
-
|
|
376
|
-
|
|
438
|
+
await writeLocalAsync(session.jwtKey.value, tokens.token);
|
|
439
|
+
await writeLocalAsync(session.refreshKey.value, tokens.refreshToken);
|
|
377
440
|
session.hasSession.value = true;
|
|
378
441
|
session.isLoading.value = false;
|
|
379
442
|
nextTick(() => {
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import type { FunctionArgs,
|
|
1
|
+
import type { FunctionArgs, FunctionReturnType } from 'convex/server';
|
|
2
2
|
import { type MaybeRefOrGetter } from 'vue';
|
|
3
|
+
import type { ConvexRef } from '../utils/functionReference.js';
|
|
3
4
|
/**
|
|
4
5
|
* Browser action helper. Returns `{ run, error, pending }`.
|
|
5
6
|
*
|
|
6
7
|
* Safe to call during SSR setup — the ConvexClient is only touched when
|
|
7
8
|
* `run()` runs in the browser.
|
|
8
9
|
*/
|
|
9
|
-
export declare function useConvexAction<Action extends
|
|
10
|
+
export declare function useConvexAction<Action extends ConvexRef<'action'>>(action: Action): {
|
|
10
11
|
run: (args?: MaybeRefOrGetter<FunctionArgs<Action>>) => Promise<FunctionReturnType<Action>>;
|
|
11
12
|
error: import("vue").Ref<Error | null, Error | null>;
|
|
12
13
|
pending: import("vue").ComputedRef<boolean>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { FunctionArgs,
|
|
1
|
+
import type { FunctionArgs, FunctionReturnType } from 'convex/server';
|
|
2
|
+
import type { ConvexRef } from '../utils/functionReference.js';
|
|
2
3
|
/** Built-in fields the composable always passes into `saveFile`. */
|
|
3
4
|
export type ConvexFileUploadMeta = {
|
|
4
5
|
storageId: string;
|
|
@@ -6,8 +7,8 @@ export type ConvexFileUploadMeta = {
|
|
|
6
7
|
contentType: string;
|
|
7
8
|
size: number;
|
|
8
9
|
};
|
|
9
|
-
export type ConvexFileUploadExtraArgs<SaveFile extends
|
|
10
|
-
export interface UseConvexFileUploadOptions<GenerateUploadUrl extends
|
|
10
|
+
export type ConvexFileUploadExtraArgs<SaveFile extends ConvexRef<'mutation'>> = Omit<FunctionArgs<SaveFile>, 'storageId' | 'name' | 'contentType' | 'size'>;
|
|
11
|
+
export interface UseConvexFileUploadOptions<GenerateUploadUrl extends ConvexRef<'mutation'>, SaveFile extends ConvexRef<'mutation'>> {
|
|
11
12
|
/**
|
|
12
13
|
* Mutation that returns a short-lived Convex upload URL
|
|
13
14
|
* (`ctx.storage.generateUploadUrl()`). Must enforce auth itself.
|
|
@@ -35,7 +36,7 @@ export declare function postFileToUploadUrl(uploadUrl: string, file: File, onPro
|
|
|
35
36
|
* in the browser. Your Convex mutations must enforce auth; never expose an
|
|
36
37
|
* unauthenticated `generateUploadUrl`.
|
|
37
38
|
*/
|
|
38
|
-
export declare function useConvexFileUpload<GenerateUploadUrl extends
|
|
39
|
+
export declare function useConvexFileUpload<GenerateUploadUrl extends ConvexRef<'mutation'>, SaveFile extends ConvexRef<'mutation'>>(options: UseConvexFileUploadOptions<GenerateUploadUrl, SaveFile>): {
|
|
39
40
|
upload: (file: File, extra?: ConvexFileUploadExtraArgs<SaveFile> extends Record<string, never> ? undefined : ConvexFileUploadExtraArgs<SaveFile>) => Promise<FunctionReturnType<SaveFile>>;
|
|
40
41
|
error: import("vue").Ref<Error | null, Error | null>;
|
|
41
42
|
pending: import("vue").ComputedRef<boolean>;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type { FunctionArgs,
|
|
1
|
+
import type { FunctionArgs, FunctionReturnType } from 'convex/server';
|
|
2
2
|
import type { OptimisticUpdate } from 'convex/browser';
|
|
3
3
|
import { type MaybeRefOrGetter } from 'vue';
|
|
4
|
+
import type { ConvexRef } from '../utils/functionReference.js';
|
|
4
5
|
export type { OptimisticUpdate };
|
|
5
|
-
export interface UseConvexMutationOptions<Mutation extends
|
|
6
|
+
export interface UseConvexMutationOptions<Mutation extends ConvexRef<'mutation'>> {
|
|
6
7
|
/**
|
|
7
8
|
* Local query update applied while the mutation is in flight.
|
|
8
9
|
* Passed through to `ConvexClient.mutation` → `BaseConvexClient`.
|
|
@@ -18,7 +19,7 @@ export interface UseConvexMutationOptions<Mutation extends FunctionReference<'mu
|
|
|
18
19
|
* Pass `{ optimisticUpdate }` to apply temporary local query results while
|
|
19
20
|
* the mutation is in flight (same contract as React `withOptimisticUpdate`).
|
|
20
21
|
*/
|
|
21
|
-
export declare function useConvexMutation<Mutation extends
|
|
22
|
+
export declare function useConvexMutation<Mutation extends ConvexRef<'mutation'>>(mutation: Mutation, options?: UseConvexMutationOptions<Mutation>): {
|
|
22
23
|
mutate: (args?: MaybeRefOrGetter<FunctionArgs<Mutation>>) => Promise<FunctionReturnType<Mutation>>;
|
|
23
24
|
error: import("vue").Ref<Error | null, Error | null>;
|
|
24
25
|
pending: import("vue").ComputedRef<boolean>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FunctionArgs, FunctionReference, FunctionReturnType, PaginationOptions, PaginationResult } from 'convex/server';
|
|
1
|
+
import type { FunctionArgs, FunctionReference, FunctionReference_future, FunctionReturnType, PaginationOptions, PaginationResult } from 'convex/server';
|
|
2
2
|
import { type ComputedRef, type MaybeRefOrGetter, type Ref } from 'vue';
|
|
3
3
|
/**
|
|
4
4
|
* A query usable with {@link useConvexPaginatedQuery}.
|
|
@@ -6,6 +6,8 @@ import { type ComputedRef, type MaybeRefOrGetter, type Ref } from 'vue';
|
|
|
6
6
|
*/
|
|
7
7
|
export type PaginatedQueryReference = FunctionReference<'query', 'public', {
|
|
8
8
|
paginationOpts: PaginationOptions;
|
|
9
|
+
}, PaginationResult<unknown>> | FunctionReference_future<'query', 'public', {
|
|
10
|
+
paginationOpts: PaginationOptions;
|
|
9
11
|
}, PaginationResult<unknown>>;
|
|
10
12
|
export type PaginatedQueryArgs<Query extends PaginatedQueryReference> = Omit<FunctionArgs<Query>, 'paginationOpts'>;
|
|
11
13
|
export type PaginatedQueryItem<Query extends PaginatedQueryReference> = FunctionReturnType<Query>['page'][number];
|
|
@@ -1,32 +1,62 @@
|
|
|
1
|
-
import type { FunctionArgs,
|
|
1
|
+
import type { FunctionArgs, FunctionReturnType } from 'convex/server';
|
|
2
2
|
import { type ComputedRef, type MaybeRefOrGetter } from 'vue';
|
|
3
|
+
import type { ConvexRef } from '../utils/functionReference.js';
|
|
3
4
|
/** One entry in a {@link useConvexQueries} request map. */
|
|
4
|
-
export type ConvexQueryRequestEntry<Query extends
|
|
5
|
+
export type ConvexQueryRequestEntry<Query extends ConvexRef<'query'> = ConvexRef<'query'>> = {
|
|
5
6
|
query: Query;
|
|
6
7
|
args: FunctionArgs<Query>;
|
|
8
|
+
/**
|
|
9
|
+
* Skip this entry until Convex confirms auth (`isAuthenticated`).
|
|
10
|
+
* Overrides the top-level {@link UseConvexQueriesOptions.authenticated}
|
|
11
|
+
* flag when set.
|
|
12
|
+
*/
|
|
13
|
+
authenticated?: boolean;
|
|
7
14
|
};
|
|
8
15
|
/**
|
|
9
16
|
* Request map for {@link useConvexQueries}.
|
|
10
|
-
* Values are `{ query, args }` or `'skip'`.
|
|
17
|
+
* Values are `{ query, args, authenticated? }` or `'skip'`.
|
|
11
18
|
*/
|
|
12
19
|
export type ConvexQueriesRequest = Record<string, ConvexQueryRequestEntry | 'skip'>;
|
|
13
20
|
export type ConvexQueriesResult<Request extends ConvexQueriesRequest> = {
|
|
14
21
|
[K in keyof Request]: Request[K] extends {
|
|
15
22
|
query: infer Query;
|
|
16
23
|
args: infer _Args;
|
|
17
|
-
} ? Query extends
|
|
24
|
+
} ? Query extends ConvexRef<'query'> ? FunctionReturnType<Query> | undefined | Error : undefined : undefined;
|
|
18
25
|
};
|
|
26
|
+
export interface UseConvexQueriesOptions {
|
|
27
|
+
/**
|
|
28
|
+
* Skip every entry until Convex confirms auth (`isAuthenticated`).
|
|
29
|
+
* Prefer this over wrapping each value in `'skip'`. Per-entry
|
|
30
|
+
* `authenticated` overrides this when set.
|
|
31
|
+
*
|
|
32
|
+
* @default false
|
|
33
|
+
*/
|
|
34
|
+
authenticated?: boolean;
|
|
35
|
+
}
|
|
19
36
|
/**
|
|
20
37
|
* Subscribe to a dynamic map of Convex queries (React `useQueries` parity).
|
|
21
38
|
*
|
|
22
|
-
* Pass a reactive object whose values are `{ query, args }`
|
|
23
|
-
* Returns a computed map of the same keys → result |
|
|
24
|
-
* `Error`.
|
|
39
|
+
* Pass a reactive object whose values are `{ query, args, authenticated? }`
|
|
40
|
+
* or `'skip'`. Returns a computed map of the same keys → result |
|
|
41
|
+
* `undefined` (loading) | `Error`.
|
|
25
42
|
*
|
|
26
43
|
* Browser-only live subscriptions. During SSR every entry is `undefined`
|
|
27
44
|
* (combine with `useConvexQuery` when you need SSR for known queries).
|
|
28
45
|
*
|
|
29
|
-
* Unchanged keys (same function name + args) keep their
|
|
30
|
-
* so deep reactive churn does not tear down
|
|
46
|
+
* Unchanged keys (same function name + args + auth-skip) keep their
|
|
47
|
+
* existing subscription so deep reactive churn does not tear down
|
|
48
|
+
* WebSocket watches.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* // Gate the whole map until Convex confirms auth
|
|
53
|
+
* const results = useConvexQueries(
|
|
54
|
+
* () => ({
|
|
55
|
+
* tasks: { query: api.tasks.list, args: {} },
|
|
56
|
+
* files: showFiles.value ? { query: api.files.list, args: {} } : 'skip',
|
|
57
|
+
* }),
|
|
58
|
+
* { authenticated: true },
|
|
59
|
+
* )
|
|
60
|
+
* ```
|
|
31
61
|
*/
|
|
32
|
-
export declare function useConvexQueries<Request extends ConvexQueriesRequest>(queries: MaybeRefOrGetter<Request
|
|
62
|
+
export declare function useConvexQueries<Request extends ConvexQueriesRequest>(queries: MaybeRefOrGetter<Request>, options?: UseConvexQueriesOptions): ComputedRef<ConvexQueriesResult<Request>>;
|
|
@@ -7,13 +7,18 @@ import {
|
|
|
7
7
|
toValue,
|
|
8
8
|
watch
|
|
9
9
|
} from "vue";
|
|
10
|
+
import { resolveAuthGatedArgs } from "../utils/authGate.js";
|
|
10
11
|
import { useConvexContext } from "../utils/context.js";
|
|
11
|
-
function subscriptionSignature(query, args) {
|
|
12
|
-
return `${getFunctionName(query)}:${JSON.stringify(convexToJson(args))}`;
|
|
12
|
+
function subscriptionSignature(query, args, authSkipped) {
|
|
13
|
+
return `${getFunctionName(query)}:${JSON.stringify(convexToJson(args))}:authSkip=${authSkipped}`;
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
+
function entryRequiresAuth(entry, defaultAuthenticated) {
|
|
16
|
+
return entry.authenticated ?? defaultAuthenticated;
|
|
17
|
+
}
|
|
18
|
+
export function useConvexQueries(queries, options = {}) {
|
|
15
19
|
const ctx = useConvexContext();
|
|
16
20
|
const results = shallowRef({});
|
|
21
|
+
const defaultAuthenticated = options.authenticated ?? false;
|
|
17
22
|
if (import.meta.server || !ctx.client) {
|
|
18
23
|
return computed(() => results.value);
|
|
19
24
|
}
|
|
@@ -29,9 +34,10 @@ export function useConvexQueries(queries) {
|
|
|
29
34
|
results.value = rest;
|
|
30
35
|
}
|
|
31
36
|
};
|
|
32
|
-
const sync = (request) => {
|
|
37
|
+
const sync = (request, isAuthenticated) => {
|
|
33
38
|
const nextKeys = new Set(Object.keys(request));
|
|
34
|
-
|
|
39
|
+
const known = /* @__PURE__ */ new Set([...unsubscribers.keys(), ...signatures.keys()]);
|
|
40
|
+
for (const key of known) {
|
|
35
41
|
if (!nextKeys.has(key)) {
|
|
36
42
|
dropKey(key);
|
|
37
43
|
}
|
|
@@ -41,15 +47,33 @@ export function useConvexQueries(queries) {
|
|
|
41
47
|
dropKey(key);
|
|
42
48
|
continue;
|
|
43
49
|
}
|
|
44
|
-
const
|
|
45
|
-
const
|
|
46
|
-
|
|
50
|
+
const requireAuth = entryRequiresAuth(entry, defaultAuthenticated);
|
|
51
|
+
const effectiveArgs = resolveAuthGatedArgs(entry.args, {
|
|
52
|
+
authenticated: requireAuth,
|
|
53
|
+
isAuthenticated
|
|
54
|
+
});
|
|
55
|
+
const authSkipped = effectiveArgs === "skip";
|
|
56
|
+
const signature = subscriptionSignature(
|
|
57
|
+
entry.query,
|
|
58
|
+
entry.args,
|
|
59
|
+
authSkipped
|
|
60
|
+
);
|
|
61
|
+
if (signatures.get(key) === signature && (unsubscribers.has(key) || authSkipped)) {
|
|
47
62
|
continue;
|
|
48
63
|
}
|
|
49
64
|
unsubscribers.get(key)?.();
|
|
65
|
+
unsubscribers.delete(key);
|
|
66
|
+
if (authSkipped) {
|
|
67
|
+
signatures.set(key, signature);
|
|
68
|
+
if (key in results.value) {
|
|
69
|
+
const { [key]: _, ...rest } = results.value;
|
|
70
|
+
results.value = rest;
|
|
71
|
+
}
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
50
74
|
const unsubscribe = client.onUpdate(
|
|
51
|
-
query,
|
|
52
|
-
|
|
75
|
+
entry.query,
|
|
76
|
+
effectiveArgs,
|
|
53
77
|
(value) => {
|
|
54
78
|
results.value = { ...results.value, [key]: value };
|
|
55
79
|
},
|
|
@@ -65,9 +89,9 @@ export function useConvexQueries(queries) {
|
|
|
65
89
|
}
|
|
66
90
|
};
|
|
67
91
|
watch(
|
|
68
|
-
() => toValue(queries),
|
|
69
|
-
(request) => {
|
|
70
|
-
sync(request);
|
|
92
|
+
() => [toValue(queries), ctx.auth.isAuthenticated.value],
|
|
93
|
+
([request, isAuthenticated]) => {
|
|
94
|
+
sync(request, isAuthenticated);
|
|
71
95
|
},
|
|
72
96
|
{ immediate: true, deep: true }
|
|
73
97
|
);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type { FunctionArgs,
|
|
1
|
+
import type { FunctionArgs, FunctionReturnType } from 'convex/server';
|
|
2
|
+
import type { ConvexRef } from '../utils/functionReference.js';
|
|
2
3
|
import { type ComputedRef, type MaybeRefOrGetter, type Ref } from 'vue';
|
|
3
|
-
export type ConvexQueryArgs<Query extends
|
|
4
|
+
export type ConvexQueryArgs<Query extends ConvexRef<'query'>> = FunctionArgs<Query> | 'skip';
|
|
4
5
|
export interface UseConvexQueryOptions {
|
|
5
6
|
/**
|
|
6
7
|
* Explicit Nuxt payload/cache key.
|
|
@@ -53,4 +54,4 @@ export interface UseConvexQueryReturn<T> {
|
|
|
53
54
|
* a duplicate HTTP request. On the browser, a live `ConvexClient` subscription
|
|
54
55
|
* overlays the payload (`live ?? payload`), matching Next.js `usePreloadedQuery`.
|
|
55
56
|
*/
|
|
56
|
-
export declare function useConvexQuery<Query extends
|
|
57
|
+
export declare function useConvexQuery<Query extends ConvexRef<'query'>>(query: Query, args?: MaybeRefOrGetter<ConvexQueryArgs<Query>>, options?: UseConvexQueryOptions): Promise<UseConvexQueryReturn<FunctionReturnType<Query>>>;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { FunctionReturnType } from 'convex/server';
|
|
2
|
+
import type { ConvexRef } from '../utils/functionReference.js';
|
|
2
3
|
/**
|
|
3
4
|
* Subset of `@convex-dev/r2` `clientApi()` exports needed for client uploads.
|
|
4
5
|
* Pass `api.example` (or any module that re-exports these two mutations).
|
|
5
6
|
*/
|
|
6
7
|
export type ConvexR2UploadApi = {
|
|
7
|
-
generateUploadUrl:
|
|
8
|
-
syncMetadata:
|
|
8
|
+
generateUploadUrl: ConvexRef<'mutation'>;
|
|
9
|
+
syncMetadata: ConvexRef<'mutation'>;
|
|
9
10
|
};
|
|
10
11
|
export type ConvexR2UploadProgress = {
|
|
11
12
|
loaded: number;
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
hydrateAuthFromStorage,
|
|
8
8
|
useAuthProviderState
|
|
9
9
|
} from "./composables/useAuth.js";
|
|
10
|
+
import { setConvexAuthModuleDefaults } from "./utils/authClientOptions.js";
|
|
10
11
|
import { tryUseConvexContext } from "./utils/context.js";
|
|
11
12
|
export default defineNuxtPlugin({
|
|
12
13
|
name: "convex-nuxt-auth",
|
|
@@ -20,6 +21,14 @@ export default defineNuxtPlugin({
|
|
|
20
21
|
if (!tryUseConvexContext()) {
|
|
21
22
|
return;
|
|
22
23
|
}
|
|
24
|
+
const auth = convexConfig.auth;
|
|
25
|
+
if (auth?.provider === "convex-auth") {
|
|
26
|
+
setConvexAuthModuleDefaults({
|
|
27
|
+
storageNamespace: auth.storageNamespace,
|
|
28
|
+
storage: auth.storage,
|
|
29
|
+
shouldHandleCode: auth.shouldHandleCode
|
|
30
|
+
});
|
|
31
|
+
}
|
|
23
32
|
const pendingOAuth = hasPendingOAuthCallback();
|
|
24
33
|
if (!pendingOAuth) {
|
|
25
34
|
hydrateAuthFromStorage();
|
|
@@ -31,7 +40,7 @@ export default defineNuxtPlugin({
|
|
|
31
40
|
isAuthenticated: hasSession
|
|
32
41
|
});
|
|
33
42
|
if (pendingOAuth) {
|
|
34
|
-
void consumeOAuthCodeFromUrl().then((ok) => {
|
|
43
|
+
void consumeOAuthCodeFromUrl().catch(() => false).then((ok) => {
|
|
35
44
|
if (!ok) {
|
|
36
45
|
hydrateAuthFromStorage();
|
|
37
46
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { FunctionArgs,
|
|
1
|
+
import type { FunctionArgs, FunctionReturnType } from 'convex/server';
|
|
2
2
|
import type { H3Event } from 'h3';
|
|
3
|
+
import type { ConvexRef } from '../utils/functionReference.js';
|
|
3
4
|
export interface ConvexFetchOptions {
|
|
4
5
|
/**
|
|
5
6
|
* Deployment URL. Defaults to `NUXT_PUBLIC_CONVEX_URL` / runtimeConfig.
|
|
@@ -8,8 +9,15 @@ export interface ConvexFetchOptions {
|
|
|
8
9
|
/**
|
|
9
10
|
* JWT for this call. Prefer per-request tokens — never put JWTs in public config.
|
|
10
11
|
* When omitted and `event` is passed, falls back to `convex.auth.cookie` if set.
|
|
12
|
+
* Ignored when {@link adminToken} is set (admin auth clears user JWT).
|
|
11
13
|
*/
|
|
12
14
|
token?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Deploy / admin key for privileged server tooling (Next.js `fetchQuery`
|
|
17
|
+
* parity). Calls `ConvexHttpClient.setAdminAuth`. Never put this in public
|
|
18
|
+
* runtime config — pass per request from a server secret.
|
|
19
|
+
*/
|
|
20
|
+
adminToken?: string;
|
|
13
21
|
/**
|
|
14
22
|
* Nitro/H3 event. Used to resolve runtimeConfig and the optional auth cookie.
|
|
15
23
|
*/
|
|
@@ -30,12 +38,12 @@ export declare function resolveToken(options: ConvexFetchOptions): string | unde
|
|
|
30
38
|
* })
|
|
31
39
|
* ```
|
|
32
40
|
*/
|
|
33
|
-
export declare function fetchQuery<Query extends
|
|
41
|
+
export declare function fetchQuery<Query extends ConvexRef<'query'>>(query: Query, args?: FunctionArgs<Query>, options?: ConvexFetchOptions): Promise<FunctionReturnType<Query>>;
|
|
34
42
|
/**
|
|
35
43
|
* One-shot mutation via ConvexHttpClient. Use in Nitro routes / server middleware.
|
|
36
44
|
*/
|
|
37
|
-
export declare function fetchMutation<Mutation extends
|
|
45
|
+
export declare function fetchMutation<Mutation extends ConvexRef<'mutation'>>(mutation: Mutation, args?: FunctionArgs<Mutation>, options?: ConvexFetchOptions): Promise<FunctionReturnType<Mutation>>;
|
|
38
46
|
/**
|
|
39
47
|
* One-shot action via ConvexHttpClient. Use in Nitro routes / server middleware.
|
|
40
48
|
*/
|
|
41
|
-
export declare function fetchAction<Action extends
|
|
49
|
+
export declare function fetchAction<Action extends ConvexRef<'action'>>(action: Action, args?: FunctionArgs<Action>, options?: ConvexFetchOptions): Promise<FunctionReturnType<Action>>;
|
|
@@ -32,9 +32,11 @@ export function resolveToken(options) {
|
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
34
|
function setupClient(options = {}) {
|
|
35
|
+
const token = options.adminToken ? void 0 : resolveToken(options);
|
|
35
36
|
return createHttpClient(resolveUrl(options), {
|
|
36
|
-
token:
|
|
37
|
-
|
|
37
|
+
...token ? { token } : {},
|
|
38
|
+
...options.adminToken ? { adminToken: options.adminToken } : {},
|
|
39
|
+
...options.skipConvexDeploymentUrlCheck !== void 0 ? { skipConvexDeploymentUrlCheck: options.skipConvexDeploymentUrlCheck } : {}
|
|
38
40
|
});
|
|
39
41
|
}
|
|
40
42
|
export async function fetchQuery(query, args, options) {
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime Convex Auth client knobs (React `ConvexAuthProvider` parity).
|
|
3
|
+
*
|
|
4
|
+
* Serializable defaults also live on `convex.auth` module options
|
|
5
|
+
* (`storageNamespace`, `storage: 'localStorage' | 'inMemory'`,
|
|
6
|
+
* `shouldHandleCode: boolean`). Call {@link configureConvexAuth} from a
|
|
7
|
+
* client plugin (`enforce: 'pre'`) for `replaceURL`, function
|
|
8
|
+
* `shouldHandleCode`, or a custom {@link ConvexAuthTokenStorage}.
|
|
9
|
+
*/
|
|
10
|
+
export type ConvexAuthTokenStorage = {
|
|
11
|
+
getItem: (key: string) => string | undefined | null | Promise<string | undefined | null>;
|
|
12
|
+
setItem: (key: string, value: string) => void | Promise<void>;
|
|
13
|
+
removeItem: (key: string) => void | Promise<void>;
|
|
14
|
+
};
|
|
15
|
+
export type ConvexAuthStorageMode = 'localStorage' | 'inMemory';
|
|
16
|
+
export type ConvexAuthClientOptions = {
|
|
17
|
+
/**
|
|
18
|
+
* When `false` (or a function returning false), ignore `?code=` OAuth
|
|
19
|
+
* callbacks. Defaults to handling the code when a verifier is stored.
|
|
20
|
+
*/
|
|
21
|
+
shouldHandleCode?: boolean | (() => boolean);
|
|
22
|
+
/**
|
|
23
|
+
* Replace the URL after stripping `?code=` (JS routers). Defaults to
|
|
24
|
+
* `history.replaceState`.
|
|
25
|
+
*/
|
|
26
|
+
replaceURL?: (relativeUrl: string) => void | Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Token storage. `'localStorage'` (default), `'inMemory'`, or a custom
|
|
29
|
+
* {@link ConvexAuthTokenStorage} (e.g. `sessionStorage`, Secure Store).
|
|
30
|
+
*/
|
|
31
|
+
storage?: ConvexAuthStorageMode | ConvexAuthTokenStorage;
|
|
32
|
+
/**
|
|
33
|
+
* Namespace for storage keys (non-alphanumeric chars stripped). Defaults
|
|
34
|
+
* to the Convex deployment URL.
|
|
35
|
+
*/
|
|
36
|
+
storageNamespace?: string;
|
|
37
|
+
};
|
|
38
|
+
/** Serializable subset safe for `runtimeConfig.public.convex.auth`. */
|
|
39
|
+
export type ConvexAuthModuleClientOptions = {
|
|
40
|
+
shouldHandleCode?: boolean;
|
|
41
|
+
storage?: ConvexAuthStorageMode;
|
|
42
|
+
storageNamespace?: string;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Set runtime Convex Auth knobs. Merge is shallow — later calls override
|
|
46
|
+
* earlier keys. Prefer calling from a client plugin with `enforce: 'pre'`
|
|
47
|
+
* so options land before the auth plugin consumes OAuth codes.
|
|
48
|
+
*/
|
|
49
|
+
export declare function configureConvexAuth(options: ConvexAuthClientOptions): void;
|
|
50
|
+
/** @internal */
|
|
51
|
+
export declare function setConvexAuthModuleDefaults(options: ConvexAuthModuleClientOptions): void;
|
|
52
|
+
/** Merged module defaults + {@link configureConvexAuth} overrides. */
|
|
53
|
+
export declare function getConvexAuthClientOptions(): ConvexAuthClientOptions;
|
|
54
|
+
/** @internal */
|
|
55
|
+
export declare function resetConvexAuthClientOptionsForTests(): void;
|
|
56
|
+
/** @internal */
|
|
57
|
+
export declare function createInMemoryTokenStorage(): ConvexAuthTokenStorage;
|
|
58
|
+
/** @internal */
|
|
59
|
+
export declare function resetInMemoryTokenStorageForTests(): void;
|
|
60
|
+
/** Resolve the active token storage from merged auth options. */
|
|
61
|
+
export declare function resolveAuthTokenStorage(options?: ConvexAuthClientOptions): ConvexAuthTokenStorage;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
let runtimeOverrides = {};
|
|
2
|
+
let moduleDefaults = {};
|
|
3
|
+
export function configureConvexAuth(options) {
|
|
4
|
+
runtimeOverrides = { ...runtimeOverrides, ...options };
|
|
5
|
+
}
|
|
6
|
+
export function setConvexAuthModuleDefaults(options) {
|
|
7
|
+
moduleDefaults = { ...options };
|
|
8
|
+
}
|
|
9
|
+
export function getConvexAuthClientOptions() {
|
|
10
|
+
return {
|
|
11
|
+
...moduleDefaults,
|
|
12
|
+
...runtimeOverrides
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export function resetConvexAuthClientOptionsForTests() {
|
|
16
|
+
runtimeOverrides = {};
|
|
17
|
+
moduleDefaults = {};
|
|
18
|
+
}
|
|
19
|
+
const inMemory = /* @__PURE__ */ new Map();
|
|
20
|
+
export function createInMemoryTokenStorage() {
|
|
21
|
+
return {
|
|
22
|
+
getItem: (key) => inMemory.get(key) ?? null,
|
|
23
|
+
setItem: (key, value) => {
|
|
24
|
+
inMemory.set(key, value);
|
|
25
|
+
},
|
|
26
|
+
removeItem: (key) => {
|
|
27
|
+
inMemory.delete(key);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export function resetInMemoryTokenStorageForTests() {
|
|
32
|
+
inMemory.clear();
|
|
33
|
+
}
|
|
34
|
+
const localStorageAdapter = {
|
|
35
|
+
getItem: (key) => {
|
|
36
|
+
if (typeof window === "undefined") {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
return window.localStorage.getItem(key);
|
|
41
|
+
} catch {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
setItem: (key, value) => {
|
|
46
|
+
if (typeof window === "undefined") {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
window.localStorage.setItem(key, value);
|
|
51
|
+
} catch {
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
removeItem: (key) => {
|
|
55
|
+
if (typeof window === "undefined") {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
window.localStorage.removeItem(key);
|
|
60
|
+
} catch {
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
export function resolveAuthTokenStorage(options = getConvexAuthClientOptions()) {
|
|
65
|
+
const storage = options.storage;
|
|
66
|
+
if (storage === "inMemory") {
|
|
67
|
+
return createInMemoryTokenStorage();
|
|
68
|
+
}
|
|
69
|
+
if (storage && typeof storage === "object") {
|
|
70
|
+
return storage;
|
|
71
|
+
}
|
|
72
|
+
return localStorageAdapter;
|
|
73
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Convex Auth client storage helpers (mirrors @convex-dev/auth/react).
|
|
3
3
|
*/
|
|
4
|
+
import { type ConvexAuthStorageMode, type ConvexAuthTokenStorage } from './authClientOptions.js';
|
|
4
5
|
export declare const JWT_STORAGE_KEY = "__convexAuthJWT";
|
|
5
6
|
export declare const REFRESH_TOKEN_STORAGE_KEY = "__convexAuthRefreshToken";
|
|
6
7
|
export declare const VERIFIER_STORAGE_KEY = "__convexAuthOAuthVerifier";
|
|
@@ -24,9 +25,26 @@ export type ConvexAuthConfig = {
|
|
|
24
25
|
httpOnly?: boolean;
|
|
25
26
|
/** Readable presence cookie when `httpOnly` is set (UI only). */
|
|
26
27
|
presentCookie?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Namespace for local token keys (React `storageNamespace` parity).
|
|
30
|
+
* Non-alphanumeric characters are stripped. Defaults to the deployment URL.
|
|
31
|
+
*/
|
|
32
|
+
storageNamespace?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Client token storage mode. Use {@link configureConvexAuth} for a custom
|
|
35
|
+
* {@link ConvexAuthTokenStorage}. Ignored when `httpOnly` is enabled.
|
|
36
|
+
* @default 'localStorage'
|
|
37
|
+
*/
|
|
38
|
+
storage?: ConvexAuthStorageMode;
|
|
39
|
+
/**
|
|
40
|
+
* When `false`, do not consume `?code=` OAuth callbacks. For a function
|
|
41
|
+
* gate, call {@link configureConvexAuth} with `shouldHandleCode`.
|
|
42
|
+
*/
|
|
43
|
+
shouldHandleCode?: boolean;
|
|
27
44
|
};
|
|
28
|
-
export
|
|
29
|
-
export declare function
|
|
45
|
+
export type { ConvexAuthTokenStorage, ConvexAuthStorageMode };
|
|
46
|
+
export declare function storageNamespace(urlOrNamespace: string): string;
|
|
47
|
+
export declare function storageKey(base: string, urlOrNamespace: string): string;
|
|
30
48
|
/**
|
|
31
49
|
* Flatten FormData (or pass through a plain record) the same way the React
|
|
32
50
|
* Convex Auth client does before calling `auth:signIn`.
|
|
@@ -43,13 +61,36 @@ export declare function resolveAuthRefreshCookieName(auth?: ConvexAuthConfig): s
|
|
|
43
61
|
export declare function isHttpOnlyAuth(auth?: ConvexAuthConfig): boolean;
|
|
44
62
|
/** Empty / missing cookies are not a session. */
|
|
45
63
|
export declare function cookieValueToSsrToken(value: string | null | undefined): string | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* Read a stored value.
|
|
66
|
+
* Sync storage returns `string | null`. Async {@link ConvexAuthTokenStorage}
|
|
67
|
+
* returns a Promise — callers that can wait should use {@link readLocalAsync}.
|
|
68
|
+
*/
|
|
69
|
+
export declare function readStored(key: string): string | null | Promise<string | null>;
|
|
70
|
+
/** Sync read. Returns null when storage is async (use {@link readLocalAsync}). */
|
|
46
71
|
export declare function readLocal(key: string): string | null;
|
|
72
|
+
export declare function readLocalAsync(key: string): Promise<string | null>;
|
|
47
73
|
export declare function writeLocal(key: string, value: string | null): void;
|
|
74
|
+
export declare function writeLocalAsync(key: string, value: string | null): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* `storage: 'inMemory'` cannot survive the IdP redirect, so the OAuth
|
|
77
|
+
* verifier is kept in a short-lived cookie (Next.js in-memory parity).
|
|
78
|
+
* JWTs stay in memory. Other storage modes keep the verifier with the tokens.
|
|
79
|
+
*/
|
|
80
|
+
export declare function readVerifier(key: string): string | null | Promise<string | null>;
|
|
81
|
+
export declare function readVerifierAsync(key: string): Promise<string | null>;
|
|
82
|
+
export declare function writeVerifier(key: string, value: string | null): Promise<void>;
|
|
83
|
+
/** @internal */
|
|
84
|
+
export declare function readBrowserCookie(name: string): string | null;
|
|
85
|
+
/** @internal */
|
|
86
|
+
export declare function writeBrowserCookie(name: string, value: string | null, maxAgeSeconds: number): void;
|
|
48
87
|
/**
|
|
49
88
|
* Whether the current URL's `?code=` should be treated as an OAuth callback.
|
|
50
|
-
*
|
|
89
|
+
* Requires a stored verifier (we started the flow). Honors
|
|
90
|
+
* `shouldHandleCode` from module options / {@link configureConvexAuth}.
|
|
51
91
|
*/
|
|
52
92
|
export declare function shouldConsumeOAuthCode(options: {
|
|
53
93
|
code: string | null;
|
|
54
94
|
verifier: string | null;
|
|
95
|
+
shouldHandleCode?: boolean | (() => boolean);
|
|
55
96
|
}): boolean;
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getConvexAuthClientOptions,
|
|
3
|
+
resolveAuthTokenStorage
|
|
4
|
+
} from "./authClientOptions.js";
|
|
1
5
|
export const JWT_STORAGE_KEY = "__convexAuthJWT";
|
|
2
6
|
export const REFRESH_TOKEN_STORAGE_KEY = "__convexAuthRefreshToken";
|
|
3
7
|
export const VERIFIER_STORAGE_KEY = "__convexAuthOAuthVerifier";
|
|
@@ -6,11 +10,11 @@ export const DEFAULT_CONVEX_AUTH_COOKIE = "convex_jwt";
|
|
|
6
10
|
export const DEFAULT_AUTH_PRESENT_COOKIE = "convex_auth_present";
|
|
7
11
|
export const HTTPONLY_JWT_COOKIE = "__convexAuthJWT";
|
|
8
12
|
export const HTTPONLY_REFRESH_COOKIE = "__convexAuthRefreshToken";
|
|
9
|
-
export function storageNamespace(
|
|
10
|
-
return
|
|
13
|
+
export function storageNamespace(urlOrNamespace) {
|
|
14
|
+
return urlOrNamespace.replace(/[^a-z0-9]/gi, "");
|
|
11
15
|
}
|
|
12
|
-
export function storageKey(base,
|
|
13
|
-
return `${base}_${storageNamespace(
|
|
16
|
+
export function storageKey(base, urlOrNamespace) {
|
|
17
|
+
return `${base}_${storageNamespace(urlOrNamespace)}`;
|
|
14
18
|
}
|
|
15
19
|
export function flattenSignInParams(params) {
|
|
16
20
|
if (params === void 0) {
|
|
@@ -57,29 +61,96 @@ export function isHttpOnlyAuth(auth) {
|
|
|
57
61
|
export function cookieValueToSsrToken(value) {
|
|
58
62
|
return value || void 0;
|
|
59
63
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
const OAUTH_VERIFIER_MAX_AGE_SECONDS = 60 * 10;
|
|
65
|
+
function activeStorage() {
|
|
66
|
+
return resolveAuthTokenStorage(getConvexAuthClientOptions());
|
|
67
|
+
}
|
|
68
|
+
function authStorageIsInMemory() {
|
|
69
|
+
return getConvexAuthClientOptions().storage === "inMemory";
|
|
70
|
+
}
|
|
71
|
+
export function readStored(key) {
|
|
72
|
+
const value = activeStorage().getItem(key);
|
|
73
|
+
if (value instanceof Promise) {
|
|
74
|
+
return value.then((stored) => stored ?? null);
|
|
63
75
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
76
|
+
return value ?? null;
|
|
77
|
+
}
|
|
78
|
+
export function readLocal(key) {
|
|
79
|
+
const value = readStored(key);
|
|
80
|
+
if (value instanceof Promise) {
|
|
67
81
|
return null;
|
|
68
82
|
}
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
export async function readLocalAsync(key) {
|
|
86
|
+
return await readStored(key);
|
|
69
87
|
}
|
|
70
88
|
export function writeLocal(key, value) {
|
|
71
|
-
|
|
89
|
+
void writeLocalAsync(key, value);
|
|
90
|
+
}
|
|
91
|
+
export async function writeLocalAsync(key, value) {
|
|
92
|
+
const storage = activeStorage();
|
|
93
|
+
if (value === null) {
|
|
94
|
+
await storage.removeItem(key);
|
|
95
|
+
} else {
|
|
96
|
+
await storage.setItem(key, value);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
export function readVerifier(key) {
|
|
100
|
+
if (authStorageIsInMemory()) {
|
|
101
|
+
return readBrowserCookie(key);
|
|
102
|
+
}
|
|
103
|
+
return readStored(key);
|
|
104
|
+
}
|
|
105
|
+
export async function readVerifierAsync(key) {
|
|
106
|
+
return await readVerifier(key);
|
|
107
|
+
}
|
|
108
|
+
export async function writeVerifier(key, value) {
|
|
109
|
+
if (authStorageIsInMemory()) {
|
|
110
|
+
writeBrowserCookie(key, value, OAUTH_VERIFIER_MAX_AGE_SECONDS);
|
|
72
111
|
return;
|
|
73
112
|
}
|
|
113
|
+
await writeLocalAsync(key, value);
|
|
114
|
+
}
|
|
115
|
+
function escapeRegExp(value) {
|
|
116
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
117
|
+
}
|
|
118
|
+
export function readBrowserCookie(name) {
|
|
119
|
+
if (typeof document === "undefined") {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
const match = document.cookie.match(new RegExp(`(?:^|; )${escapeRegExp(name)}=([^;]*)`));
|
|
123
|
+
const raw = match?.[1];
|
|
124
|
+
if (!raw) {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
74
127
|
try {
|
|
75
|
-
|
|
76
|
-
window.localStorage.removeItem(key);
|
|
77
|
-
} else {
|
|
78
|
-
window.localStorage.setItem(key, value);
|
|
79
|
-
}
|
|
128
|
+
return decodeURIComponent(raw);
|
|
80
129
|
} catch {
|
|
130
|
+
return raw;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
export function writeBrowserCookie(name, value, maxAgeSeconds) {
|
|
134
|
+
if (typeof document === "undefined") {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const secure = typeof location !== "undefined" && location.protocol === "https:" ? "; Secure" : "";
|
|
138
|
+
if (value === null) {
|
|
139
|
+
document.cookie = `${name}=; Max-Age=0; Path=/; SameSite=Lax${secure}`;
|
|
140
|
+
return;
|
|
81
141
|
}
|
|
142
|
+
document.cookie = `${name}=${encodeURIComponent(value)}; Max-Age=${maxAgeSeconds}; Path=/; SameSite=Lax${secure}`;
|
|
82
143
|
}
|
|
83
144
|
export function shouldConsumeOAuthCode(options) {
|
|
84
|
-
|
|
145
|
+
if (options.code === null || options.verifier === null) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
const gate = options.shouldHandleCode ?? getConvexAuthClientOptions().shouldHandleCode;
|
|
149
|
+
if (gate === void 0) {
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
if (typeof gate === "function") {
|
|
153
|
+
return gate();
|
|
154
|
+
}
|
|
155
|
+
return gate;
|
|
85
156
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AuthTokenFetcher, ConvexClient, ConvexHttpClient } from 'convex/browser';
|
|
2
2
|
import type { ComputedRef, InjectionKey, Ref } from 'vue';
|
|
3
|
+
import type { CreateHttpClientOptions } from './http.js';
|
|
3
4
|
export interface ConvexAuthContext {
|
|
4
5
|
/**
|
|
5
6
|
* Whether useConvexAuth({ fetchToken }) has been called.
|
|
@@ -37,9 +38,7 @@ export interface ConvexNuxtContext {
|
|
|
37
38
|
* Create a fresh HttpClient for one-shot fetches (SSR / Nitro / refresh).
|
|
38
39
|
* Prefer a new client per call — HttpClient is stateful.
|
|
39
40
|
*/
|
|
40
|
-
createHttpClient: (options?:
|
|
41
|
-
token?: string;
|
|
42
|
-
}) => ConvexHttpClient;
|
|
41
|
+
createHttpClient: (options?: CreateHttpClientOptions) => ConvexHttpClient;
|
|
43
42
|
}
|
|
44
43
|
export declare const convexNuxtKey: InjectionKey<ConvexNuxtContext>;
|
|
45
44
|
export declare function createAuthContext(): ConvexAuthContext;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { FunctionReference, FunctionReference_future, FunctionType } from 'convex/server';
|
|
2
|
+
/**
|
|
3
|
+
* Function reference accepted by use-convex client APIs.
|
|
4
|
+
*
|
|
5
|
+
* Convex 1.46+ introduced {@link FunctionReference_future} for stricter
|
|
6
|
+
* callback argument checking. Generated `api` refs remain plain
|
|
7
|
+
* {@link FunctionReference}; library surfaces accept either kind so callers
|
|
8
|
+
* can pass both (same contract as Convex React hooks).
|
|
9
|
+
*/
|
|
10
|
+
export type ConvexRef<Type extends FunctionType> = FunctionReference<Type> | FunctionReference_future<Type>;
|
|
File without changes
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { ConvexHttpClient } from 'convex/browser';
|
|
2
2
|
export interface CreateHttpClientOptions {
|
|
3
3
|
token?: string;
|
|
4
|
+
/**
|
|
5
|
+
* Deploy / admin key for privileged HttpClient calls (Next.js
|
|
6
|
+
* `fetchQuery(..., { adminToken })` parity). Uses `Authorization: Convex …`
|
|
7
|
+
* and clears any user JWT. Prefer per-request secrets — never put this in
|
|
8
|
+
* public runtime config.
|
|
9
|
+
*/
|
|
10
|
+
adminToken?: string;
|
|
4
11
|
skipConvexDeploymentUrlCheck?: boolean;
|
|
5
12
|
}
|
|
6
13
|
/**
|
|
@@ -2,9 +2,12 @@ import { ConvexHttpClient } from "convex/browser";
|
|
|
2
2
|
export function createHttpClient(url, options = {}) {
|
|
3
3
|
const client = new ConvexHttpClient(url, {
|
|
4
4
|
skipConvexDeploymentUrlCheck: options.skipConvexDeploymentUrlCheck,
|
|
5
|
-
...options.token ? { auth: options.token } : {}
|
|
5
|
+
...options.token && !options.adminToken ? { auth: options.token } : {}
|
|
6
6
|
});
|
|
7
|
-
if (options.
|
|
7
|
+
if (options.adminToken) {
|
|
8
|
+
;
|
|
9
|
+
client.setAdminAuth(options.adminToken);
|
|
10
|
+
} else if (options.token) {
|
|
8
11
|
client.setAuth(options.token);
|
|
9
12
|
}
|
|
10
13
|
;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ConvexRef } from './functionReference.js';
|
|
2
2
|
/**
|
|
3
3
|
* Stable Nuxt payload / useAsyncData key for a Convex query.
|
|
4
4
|
*
|
|
5
5
|
* `'skip'` means "don't fetch" — it must not change the key, otherwise
|
|
6
6
|
* auth-gated queries lose the SSR payload on the client.
|
|
7
7
|
*/
|
|
8
|
-
export declare function convexQueryKey(query:
|
|
8
|
+
export declare function convexQueryKey(query: ConvexRef<'query'>, args: unknown, explicitKey?: string): string;
|
package/dist/types.d.mts
CHANGED
|
@@ -18,16 +18,20 @@ export { type ConvexR2UploadApi, type ConvexR2UploadProgress } from '../dist/run
|
|
|
18
18
|
|
|
19
19
|
export { type PaginatedQueryArgs, type PaginatedQueryItem, type PaginatedQueryReference, type PaginationStatus, type UseConvexPaginatedQueryOptions, type UseConvexPaginatedQueryReturn } from '../dist/runtime/composables/useConvexPaginatedQuery.js'
|
|
20
20
|
|
|
21
|
-
export { type ConvexQueriesRequest, type ConvexQueriesResult, type ConvexQueryRequestEntry } from '../dist/runtime/composables/useConvexQueries.js'
|
|
21
|
+
export { type ConvexQueriesRequest, type ConvexQueriesResult, type ConvexQueryRequestEntry, type UseConvexQueriesOptions } from '../dist/runtime/composables/useConvexQueries.js'
|
|
22
22
|
|
|
23
23
|
export { type ConvexFetchOptions } from '../dist/runtime/server/fetch.js'
|
|
24
24
|
|
|
25
|
+
export { type ConvexRef } from '../dist/runtime/utils/functionReference.js'
|
|
26
|
+
|
|
25
27
|
export { type ConvexAuthContext, type ConvexNuxtContext } from '../dist/runtime/utils/context.js'
|
|
26
28
|
|
|
27
29
|
export { type ConnectionState } from '../dist/runtime/composables/useConvexConnectionState.js'
|
|
28
30
|
|
|
29
31
|
export { type ConvexGate } from '../dist/runtime/composables/useConvexGate.js'
|
|
30
32
|
|
|
33
|
+
export { type ConvexAuthClientOptions, type ConvexAuthStorageMode, type ConvexAuthTokenStorage, type configureConvexAuth } from '../dist/runtime/utils/authClientOptions.js'
|
|
34
|
+
|
|
31
35
|
export { default } from './module.mjs'
|
|
32
36
|
|
|
33
37
|
export { type ModuleAuthOptions, type ModuleOptions, type ModulePublicRuntimeConfig } from './module.mjs'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "use-convex",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "First-class Convex integration for Nuxt",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@nuxt/schema": "^4.0.0",
|
|
51
51
|
"@nuxt/test-utils": "^3.23.0",
|
|
52
52
|
"@types/node": "^26.5.0",
|
|
53
|
-
"convex": "^1.
|
|
53
|
+
"convex": "^1.46.0",
|
|
54
54
|
"convex-test": "^0.0.56",
|
|
55
55
|
"happy-dom": "^20.14.0",
|
|
56
56
|
"nitropack": "^2.13.0",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"vue-tsc": "^3.0.0"
|
|
64
64
|
},
|
|
65
65
|
"peerDependencies": {
|
|
66
|
-
"convex": "^1.
|
|
66
|
+
"convex": "^1.46.0",
|
|
67
67
|
"nuxt": "^4.0.0",
|
|
68
68
|
"vue": "^3.5.0"
|
|
69
69
|
},
|