better-convex-nuxt 0.2.7 → 0.2.9

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.
Files changed (31) hide show
  1. package/dist/module.d.mts +25 -1
  2. package/dist/module.json +1 -1
  3. package/dist/module.mjs +11 -1
  4. package/dist/runtime/composables/useAuthClient.d.ts +16 -1
  5. package/dist/runtime/composables/useConvexAction.js +1 -1
  6. package/dist/runtime/composables/useConvexAuth.d.ts +33 -2
  7. package/dist/runtime/composables/useConvexAuth.js +58 -3
  8. package/dist/runtime/composables/useConvexFileUpload.js +1 -1
  9. package/dist/runtime/composables/useConvexMutation.js +1 -1
  10. package/dist/runtime/composables/useConvexPaginatedQuery.js +4 -2
  11. package/dist/runtime/composables/useConvexQuery.js +4 -2
  12. package/dist/runtime/devtools/auth-proxy-registry.d.ts +8 -0
  13. package/dist/runtime/devtools/auth-proxy-registry.js +5 -0
  14. package/dist/runtime/devtools/mutation-registry.d.ts +3 -0
  15. package/dist/runtime/devtools/mutation-registry.js +5 -0
  16. package/dist/runtime/devtools/query-registry.d.ts +3 -0
  17. package/dist/runtime/devtools/query-registry.js +5 -0
  18. package/dist/runtime/devtools/ui/dist/200.html +1 -1
  19. package/dist/runtime/devtools/ui/dist/404.html +1 -1
  20. package/dist/runtime/devtools/ui/dist/_nuxt/builds/latest.json +1 -1
  21. package/dist/runtime/devtools/ui/dist/_nuxt/builds/meta/df213a49-93a4-44f1-863e-5dc7de19c884.json +1 -0
  22. package/dist/runtime/devtools/ui/dist/index.html +1 -1
  23. package/dist/runtime/plugin.client.js +193 -38
  24. package/dist/runtime/plugin.server.js +38 -6
  25. package/dist/runtime/server/api/auth/[...].js +1 -1
  26. package/dist/runtime/types.d.ts +8 -4
  27. package/dist/runtime/utils/convex-cache.d.ts +15 -2
  28. package/dist/runtime/utils/convex-cache.js +1 -3
  29. package/dist/types.d.mts +1 -1
  30. package/package.json +1 -1
  31. package/dist/runtime/devtools/ui/dist/_nuxt/builds/meta/bb1b6fab-3dad-4ebb-bedd-8a7e8492b357.json +0 -1
package/dist/module.d.mts CHANGED
@@ -44,6 +44,24 @@ interface QueryDefaults {
44
44
  */
45
45
  public?: boolean;
46
46
  }
47
+ interface ConvexDebugOptions {
48
+ /**
49
+ * Enable detailed auth flow logs on both client and server plugins.
50
+ * Requires `logging: 'debug'` to print verbose phase logs.
51
+ * @default false
52
+ */
53
+ authFlow?: boolean;
54
+ /**
55
+ * Enable detailed auth flow logs on the client plugin only.
56
+ * @default false
57
+ */
58
+ clientAuthFlow?: boolean;
59
+ /**
60
+ * Enable detailed auth flow logs on the server plugin only.
61
+ * @default false
62
+ */
63
+ serverAuthFlow?: boolean;
64
+ }
47
65
  interface ModuleOptions {
48
66
  /** Convex deployment URL (WebSocket) - e.g., https://your-app.convex.cloud */
49
67
  url?: string;
@@ -99,6 +117,12 @@ interface ModuleOptions {
99
117
  * @default false
100
118
  */
101
119
  logging?: LogLevel;
120
+ /**
121
+ * Optional debug channels for runtime plugins.
122
+ * Use this to enable high-verbosity trace logs without changing regular logger behavior.
123
+ * @default { authFlow: false, clientAuthFlow: false, serverAuthFlow: false }
124
+ */
125
+ debug?: ConvexDebugOptions;
102
126
  /**
103
127
  * SSR auth token caching configuration (opt-in).
104
128
  * Caches Convex JWT tokens server-side to reduce TTFB on subsequent requests.
@@ -148,4 +172,4 @@ interface ModuleOptions {
148
172
  declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
149
173
 
150
174
  export { _default as default };
151
- export type { AuthCacheOptions, ModuleOptions, QueryDefaults };
175
+ export type { AuthCacheOptions, ConvexDebugOptions, ModuleOptions, QueryDefaults };
package/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=3.0.0"
6
6
  },
7
- "version": "0.2.7",
7
+ "version": "0.2.9",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
10
10
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -35,6 +35,11 @@ const module$1 = defineNuxtModule({
35
35
  skipAuthRoutes: [],
36
36
  permissions: false,
37
37
  logging: false,
38
+ debug: {
39
+ authFlow: false,
40
+ clientAuthFlow: false,
41
+ serverAuthFlow: false
42
+ },
38
43
  authCache: {
39
44
  enabled: false,
40
45
  ttl: 900
@@ -72,6 +77,11 @@ const module$1 = defineNuxtModule({
72
77
  trustedOrigins: options.trustedOrigins ?? [],
73
78
  skipAuthRoutes: options.skipAuthRoutes ?? [],
74
79
  logging: options.logging ?? false,
80
+ debug: {
81
+ authFlow: options.debug?.authFlow ?? false,
82
+ clientAuthFlow: options.debug?.clientAuthFlow ?? false,
83
+ serverAuthFlow: options.debug?.serverAuthFlow ?? false
84
+ },
75
85
  authCache: {
76
86
  enabled: options.authCache?.enabled ?? false,
77
87
  ttl: options.authCache?.ttl ?? 900
@@ -91,7 +101,7 @@ const module$1 = defineNuxtModule({
91
101
  mode: "server"
92
102
  });
93
103
  addPlugin(resolver.resolve("./runtime/plugin.client"));
94
- if (isAuthEnabled && nuxt.options.ssr) {
104
+ if (isAuthEnabled) {
95
105
  addServerHandler({
96
106
  route: `${authRoute}/**`,
97
107
  handler: resolver.resolve("./runtime/server/api/auth/[...]")
@@ -12,6 +12,19 @@ type AuthClient = ReturnType<typeof createAuthClient>;
12
12
  * but this is safe because auth operations (sign in, sign out) should only
13
13
  * be triggered by user interactions which only happen on the client.
14
14
  *
15
+ * ## Important: useSession() Cost
16
+ *
17
+ * Calling `authClient.useSession()` will trigger an additional `/api/auth/get-session`
18
+ * API call, which results in ~2 extra Convex database queries per page load.
19
+ * This is because Better Auth's useSession() fetches session data independently.
20
+ *
21
+ * **Recommended alternatives:**
22
+ * - Use `useConvexAuth()` for reading auth state (token, user, isAuthenticated)
23
+ * - Use `useConvexAuth().signOut()` for logging out (clears both Better Auth and Convex state)
24
+ *
25
+ * Only use `authClient.useSession()` if you specifically need Better Auth's
26
+ * reactive session features and are okay with the extra API call.
27
+ *
15
28
  * @example
16
29
  * ```vue
17
30
  * <script setup>
@@ -26,8 +39,10 @@ type AuthClient = ReturnType<typeof createAuthClient>;
26
39
  * })
27
40
  * }
28
41
  *
42
+ * // For logout, prefer useConvexAuth().signOut() instead:
43
+ * const { signOut } = useConvexAuth()
29
44
  * async function logout() {
30
- * await authClient?.signOut()
45
+ * await signOut() // Clears both Better Auth AND Convex state
31
46
  * }
32
47
  * </script>
33
48
  * ```
@@ -13,6 +13,7 @@ export function useConvexAction(action) {
13
13
  const logLevel = getLogLevel(config.public.convex ?? {});
14
14
  const logger = createLogger(logLevel);
15
15
  const fnName = getFunctionName(action);
16
+ const client = useConvex();
16
17
  const _status = ref("idle");
17
18
  const error = ref(null);
18
19
  const data = ref(void 0);
@@ -24,7 +25,6 @@ export function useConvexAction(action) {
24
25
  data.value = void 0;
25
26
  };
26
27
  const execute = async (args) => {
27
- const client = useConvex();
28
28
  const startTime = Date.now();
29
29
  if (!client) {
30
30
  const err = new Error("ConvexClient not available - actions only work on client side");
@@ -12,12 +12,20 @@ export type { ConvexUser } from '../utils/types.js';
12
12
  * @example
13
13
  * ```vue
14
14
  * <script setup>
15
- * const { user, isAuthenticated, isPending } = useConvexAuth()
15
+ * const { user, isAuthenticated, isPending, signOut } = useConvexAuth()
16
+ *
17
+ * async function handleLogout() {
18
+ * await signOut()
19
+ * navigateTo('/login')
20
+ * }
16
21
  * </script>
17
22
  *
18
23
  * <template>
19
24
  * <div v-if="isPending">Loading...</div>
20
- * <div v-else-if="isAuthenticated">Welcome, {{ user?.name }}</div>
25
+ * <div v-else-if="isAuthenticated">
26
+ * Welcome, {{ user?.name }}
27
+ * <button @click="handleLogout">Sign out</button>
28
+ * </div>
21
29
  * <div v-else>Please log in</div>
22
30
  * </template>
23
31
  * ```
@@ -49,4 +57,27 @@ export declare function useConvexAuth(): {
49
57
  isPending: Readonly<import("vue").Ref<boolean, boolean>>;
50
58
  /** Auth error message if authentication failed (e.g., 401/403) */
51
59
  authError: Readonly<import("vue").Ref<string | null, string | null>>;
60
+ /**
61
+ * Signs out the user from both Better Auth and Convex.
62
+ * Clears local state immediately and calls Better Auth's signOut().
63
+ */
64
+ signOut: () => Promise<{
65
+ data: {
66
+ success: boolean;
67
+ };
68
+ error: null;
69
+ } | {
70
+ data: null;
71
+ error: {
72
+ code?: string | undefined | undefined;
73
+ message?: string | undefined | undefined;
74
+ status: number;
75
+ statusText: string;
76
+ };
77
+ } | null>;
78
+ /**
79
+ * Force refresh Convex auth state after login.
80
+ * Triggers fresh token fetch and updates reactive state.
81
+ */
82
+ refreshAuth: () => Promise<void>;
52
83
  };
@@ -1,10 +1,55 @@
1
- import { useState, computed, readonly } from "#imports";
1
+ import { useState, computed, readonly, useNuxtApp, watch } from "#imports";
2
2
  export function useConvexAuth() {
3
+ const nuxtApp = useNuxtApp();
3
4
  const token = useState("convex:token", () => null);
4
5
  const user = useState("convex:user", () => null);
5
- const pending = useState("convex:pending", () => false);
6
+ const pending = useState("convex:pending", () => true);
6
7
  const authError = useState("convex:authError", () => null);
7
8
  const isAuthenticated = computed(() => !!token.value && !!user.value);
9
+ const signOut = async () => {
10
+ const authClient = nuxtApp.$auth;
11
+ token.value = null;
12
+ user.value = null;
13
+ authError.value = null;
14
+ if (authClient) {
15
+ try {
16
+ return await authClient.signOut();
17
+ } catch (e) {
18
+ console.warn("signOut request failed:", e);
19
+ return null;
20
+ }
21
+ }
22
+ return null;
23
+ };
24
+ const refreshAuth = async () => {
25
+ pending.value = true;
26
+ authError.value = null;
27
+ const refreshSignal = useState("convex:refreshSignal", () => 0);
28
+ refreshSignal.value++;
29
+ await new Promise((resolve) => {
30
+ let resolved = false;
31
+ let stopWatcher = null;
32
+ const cleanup = () => {
33
+ if (!resolved) {
34
+ resolved = true;
35
+ if (stopWatcher) stopWatcher();
36
+ resolve();
37
+ }
38
+ };
39
+ stopWatcher = watch(
40
+ [token, authError],
41
+ ([newToken, newError]) => {
42
+ if (newToken) {
43
+ cleanup();
44
+ } else if (newError && resolved === false) {
45
+ cleanup();
46
+ }
47
+ }
48
+ );
49
+ setTimeout(cleanup, 5e3);
50
+ });
51
+ pending.value = false;
52
+ };
8
53
  return {
9
54
  /** The JWT token for Convex authentication (readonly) */
10
55
  token: readonly(token),
@@ -15,6 +60,16 @@ export function useConvexAuth() {
15
60
  /** Whether an auth operation is pending */
16
61
  isPending: readonly(pending),
17
62
  /** Auth error message if authentication failed (e.g., 401/403) */
18
- authError: readonly(authError)
63
+ authError: readonly(authError),
64
+ /**
65
+ * Signs out the user from both Better Auth and Convex.
66
+ * Clears local state immediately and calls Better Auth's signOut().
67
+ */
68
+ signOut,
69
+ /**
70
+ * Force refresh Convex auth state after login.
71
+ * Triggers fresh token fetch and updates reactive state.
72
+ */
73
+ refreshAuth
19
74
  };
20
75
  }
@@ -9,6 +9,7 @@ export function useConvexFileUpload(generateUploadUrlMutation, options) {
9
9
  const logLevel = getLogLevel(config.public.convex ?? {});
10
10
  const logger = createLogger(logLevel);
11
11
  const fnName = getFunctionName(generateUploadUrlMutation);
12
+ const client = useConvex();
12
13
  const _status = ref("idle");
13
14
  const error = ref(null);
14
15
  const data = ref(void 0);
@@ -33,7 +34,6 @@ export function useConvexFileUpload(generateUploadUrlMutation, options) {
33
34
  }
34
35
  });
35
36
  const upload = async (file, mutationArgs) => {
36
- const client = useConvex();
37
37
  const startTime = Date.now();
38
38
  if (!client) {
39
39
  const err = new Error("ConvexClient not available - file uploads only work on client side");
@@ -20,6 +20,7 @@ export function useConvexMutation(mutation, options) {
20
20
  const logger = createLogger(logLevel);
21
21
  const fnName = getFunctionName(mutation);
22
22
  const hasOptimisticUpdate = !!options?.optimisticUpdate;
23
+ const client = useConvex();
23
24
  const _status = ref("idle");
24
25
  const error = ref(null);
25
26
  const data = ref(void 0);
@@ -31,7 +32,6 @@ export function useConvexMutation(mutation, options) {
31
32
  data.value = void 0;
32
33
  };
33
34
  const mutate = async (args) => {
34
- const client = useConvex();
35
35
  const startTime = Date.now();
36
36
  if (!client) {
37
37
  const err = new Error("ConvexClient not available - mutations only work on client side");
@@ -1,4 +1,4 @@
1
- import { useNuxtApp, useRuntimeConfig, useRequestEvent, useAsyncData } from "#imports";
1
+ import { useNuxtApp, useRuntimeConfig, useRequestEvent, useAsyncData, useState } from "#imports";
2
2
  import {
3
3
  ref,
4
4
  computed,
@@ -75,6 +75,7 @@ export function useConvexPaginatedQuery(query, args, options) {
75
75
  const isSkipped = computed(() => getArgs() === "skip");
76
76
  const event = import.meta.server ? useRequestEvent() : null;
77
77
  const cookieHeader = event?.headers.get("cookie") || "";
78
+ const cachedToken = useState("convex:token");
78
79
  const currentPaginationId = ref(generatePaginationId());
79
80
  const pages = shallowRef([]);
80
81
  const globalError = ref(null);
@@ -108,7 +109,8 @@ export function useConvexPaginatedQuery(query, args, options) {
108
109
  authToken = await fetchAuthToken({
109
110
  isPublic,
110
111
  cookieHeader,
111
- siteUrl
112
+ siteUrl,
113
+ cachedToken
112
114
  });
113
115
  }
114
116
  return executeQueryHttp(convexUrl, functionPath, fullArgs, authToken);
@@ -1,4 +1,4 @@
1
- import { useNuxtApp, useRuntimeConfig, useRequestEvent, useAsyncData } from "#imports";
1
+ import { useNuxtApp, useRuntimeConfig, useRequestEvent, useAsyncData, useState } from "#imports";
2
2
  import { computed, watch, triggerRef, onUnmounted, toValue, isRef, isReactive } from "vue";
3
3
  import {
4
4
  getFunctionName,
@@ -74,6 +74,7 @@ export function useConvexQuery(query, args, options) {
74
74
  };
75
75
  const event = import.meta.server ? useRequestEvent() : null;
76
76
  const cookieHeader = event?.headers.get("cookie") || "";
77
+ const cachedToken = useState("convex:token");
77
78
  const asyncData = useAsyncData(
78
79
  cacheKey,
79
80
  async () => {
@@ -90,7 +91,8 @@ export function useConvexQuery(query, args, options) {
90
91
  const authToken = await fetchAuthToken({
91
92
  isPublic,
92
93
  cookieHeader,
93
- siteUrl
94
+ siteUrl,
95
+ cachedToken
94
96
  });
95
97
  const result2 = await executeQueryHttp(convexUrl, fnName, currentArgs, authToken);
96
98
  return applyTransform(result2);
@@ -1,6 +1,14 @@
1
1
  /**
2
2
  * Registry for tracking auth proxy requests in dev mode.
3
3
  * This runs on the Nitro server and stores request data in global state.
4
+ *
5
+ * WARNING: This module uses globalThis state which IS shared across SSR requests.
6
+ * This is acceptable because:
7
+ * 1. It's only used in development mode for debugging
8
+ * 2. It only stores non-sensitive timing/stats data
9
+ * 3. The data is intentionally aggregated across requests for the DevTools panel
10
+ *
11
+ * Do NOT use this pattern for user-specific data in production.
4
12
  */
5
13
  import type { AuthProxyRequest, AuthProxyStats } from './types.js';
6
14
  declare global {
@@ -1,3 +1,8 @@
1
+ if (!import.meta.dev) {
2
+ throw new Error(
3
+ "[better-convex-nuxt] auth-proxy-registry is only available in development mode."
4
+ );
5
+ }
1
6
  const MAX_REQUESTS = 20;
2
7
  function getRequests() {
3
8
  if (!globalThis.__convex_auth_proxy_requests__) {
@@ -2,6 +2,9 @@
2
2
  * Mutation registry for DevTools integration.
3
3
  * Tracks in-flight and completed mutations with timeline data.
4
4
  * In-memory only, max 50 entries with LRU eviction.
5
+ *
6
+ * This module is client-only. Importing on the server will throw an error
7
+ * to prevent SSR state leakage between requests.
5
8
  */
6
9
  import type { MutationEntry } from './types.js';
7
10
  type RegistryCallback = (entries: MutationEntry[]) => void;
@@ -1,3 +1,8 @@
1
+ if (import.meta.server) {
2
+ throw new Error(
3
+ "[better-convex-nuxt] DevTools mutation-registry must not be imported on server. This would cause state leakage between SSR requests."
4
+ );
5
+ }
1
6
  const MAX_ENTRIES = 50;
2
7
  const mutationRegistry = /* @__PURE__ */ new Map();
3
8
  const subscribers = /* @__PURE__ */ new Set();
@@ -1,6 +1,9 @@
1
1
  /**
2
2
  * Query registry for DevTools integration.
3
3
  * Tracks active queries with metadata for visualization.
4
+ *
5
+ * This module is client-only. Importing on the server will throw an error
6
+ * to prevent SSR state leakage between requests.
4
7
  */
5
8
  export type QueryStatus = 'pending' | 'success' | 'error' | 'idle';
6
9
  export type DataSource = 'ssr' | 'websocket' | 'cache';
@@ -1,3 +1,8 @@
1
+ if (import.meta.server) {
2
+ throw new Error(
3
+ "[better-convex-nuxt] DevTools query-registry must not be imported on server. This would cause state leakage between SSR requests."
4
+ );
5
+ }
1
6
  const queryRegistry = /* @__PURE__ */ new Map();
2
7
  const subscribers = /* @__PURE__ */ new Set();
3
8
  function notifySubscribers() {
@@ -1 +1 @@
1
- <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Convex DevTools</title><link rel="stylesheet" href="/__convex_devtools__/_nuxt/entry.BiOLMZBG.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__convex_devtools__/_nuxt/BhO0ov6K.js"><script type="module" src="/__convex_devtools__/_nuxt/BhO0ov6K.js" crossorigin></script><script id="unhead:payload" type="application/json">{"title":"Convex DevTools"}</script></head><body><div id="__nuxt"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__convex_devtools__",buildId:"bb1b6fab-3dad-4ebb-bedd-8a7e8492b357",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1769017710929,false]</script></body></html>
1
+ <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Convex DevTools</title><link rel="stylesheet" href="/__convex_devtools__/_nuxt/entry.BiOLMZBG.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__convex_devtools__/_nuxt/BhO0ov6K.js"><script type="module" src="/__convex_devtools__/_nuxt/BhO0ov6K.js" crossorigin></script><script id="unhead:payload" type="application/json">{"title":"Convex DevTools"}</script></head><body><div id="__nuxt"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__convex_devtools__",buildId:"df213a49-93a4-44f1-863e-5dc7de19c884",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1771229435100,false]</script></body></html>
@@ -1 +1 @@
1
- <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Convex DevTools</title><link rel="stylesheet" href="/__convex_devtools__/_nuxt/entry.BiOLMZBG.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__convex_devtools__/_nuxt/BhO0ov6K.js"><script type="module" src="/__convex_devtools__/_nuxt/BhO0ov6K.js" crossorigin></script><script id="unhead:payload" type="application/json">{"title":"Convex DevTools"}</script></head><body><div id="__nuxt"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__convex_devtools__",buildId:"bb1b6fab-3dad-4ebb-bedd-8a7e8492b357",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1769017710929,false]</script></body></html>
1
+ <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Convex DevTools</title><link rel="stylesheet" href="/__convex_devtools__/_nuxt/entry.BiOLMZBG.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__convex_devtools__/_nuxt/BhO0ov6K.js"><script type="module" src="/__convex_devtools__/_nuxt/BhO0ov6K.js" crossorigin></script><script id="unhead:payload" type="application/json">{"title":"Convex DevTools"}</script></head><body><div id="__nuxt"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__convex_devtools__",buildId:"df213a49-93a4-44f1-863e-5dc7de19c884",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1771229435101,false]</script></body></html>
@@ -1 +1 @@
1
- {"id":"bb1b6fab-3dad-4ebb-bedd-8a7e8492b357","timestamp":1769017708682}
1
+ {"id":"df213a49-93a4-44f1-863e-5dc7de19c884","timestamp":1771229432599}
@@ -0,0 +1 @@
1
+ {"id":"df213a49-93a4-44f1-863e-5dc7de19c884","timestamp":1771229432599,"matcher":{"static":{},"wildcard":{},"dynamic":{}},"prerendered":[]}
@@ -1 +1 @@
1
- <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Convex DevTools</title><link rel="stylesheet" href="/__convex_devtools__/_nuxt/entry.BiOLMZBG.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__convex_devtools__/_nuxt/BhO0ov6K.js"><script type="module" src="/__convex_devtools__/_nuxt/BhO0ov6K.js" crossorigin></script><script id="unhead:payload" type="application/json">{"title":"Convex DevTools"}</script></head><body><div id="__nuxt"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__convex_devtools__",buildId:"bb1b6fab-3dad-4ebb-bedd-8a7e8492b357",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1769017710929,false]</script></body></html>
1
+ <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Convex DevTools</title><link rel="stylesheet" href="/__convex_devtools__/_nuxt/entry.BiOLMZBG.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__convex_devtools__/_nuxt/BhO0ov6K.js"><script type="module" src="/__convex_devtools__/_nuxt/BhO0ov6K.js" crossorigin></script><script id="unhead:payload" type="application/json">{"title":"Convex DevTools"}</script></head><body><div id="__nuxt"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__convex_devtools__",buildId:"df213a49-93a4-44f1-863e-5dc7de19c884",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1771229435101,false]</script></body></html>
@@ -11,7 +11,28 @@ export default defineNuxtPlugin((nuxtApp) => {
11
11
  const logLevel = getLogLevel(config.public.convex ?? {});
12
12
  const logger = createLogger(logLevel);
13
13
  const endInit = logger.time("plugin:init (client)");
14
- if (nuxtApp._convexInitialized) return;
14
+ const debugConfig = config.public.convex?.debug;
15
+ const enableClientAuthTrace = logLevel === "debug" && (debugConfig?.authFlow === true || debugConfig?.clientAuthFlow === true);
16
+ const rawAuthLog = logger.auth.bind(logger);
17
+ logger.auth = (event) => {
18
+ rawAuthLog(event);
19
+ if (enableClientAuthTrace) {
20
+ console.log("[BCN_AUTH][client]", {
21
+ phase: event.phase,
22
+ outcome: event.outcome,
23
+ ...event.details,
24
+ error: event.error ? event.error.message : null
25
+ });
26
+ }
27
+ };
28
+ const convexAuthTraceId = useState(
29
+ "convex:authTraceId",
30
+ () => `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`
31
+ );
32
+ if (nuxtApp._convexInitialized) {
33
+ logger.debug("plugin:init (client) skipped; already initialized", { traceId: convexAuthTraceId.value });
34
+ return;
35
+ }
15
36
  nuxtApp._convexInitialized = true;
16
37
  const convexUrl = config.public.convex?.url;
17
38
  const isAuthEnabled = config.public.convex?.auth;
@@ -27,7 +48,24 @@ export default defineNuxtPlugin((nuxtApp) => {
27
48
  const convexAuthError = useState("convex:authError");
28
49
  const client = new ConvexClient(convexUrl);
29
50
  let authClient = null;
30
- const convexPending = useState("convex:pending", () => false);
51
+ const convexPending = useState("convex:pending", () => true);
52
+ let hasResolvedInitialAuth = false;
53
+ const resolveInitialAuth = () => {
54
+ if (!hasResolvedInitialAuth) {
55
+ hasResolvedInitialAuth = true;
56
+ convexPending.value = false;
57
+ }
58
+ };
59
+ const refreshSignal = useState("convex:refreshSignal", () => 0);
60
+ logger.auth({
61
+ phase: "client-init",
62
+ outcome: "success",
63
+ details: {
64
+ traceId: convexAuthTraceId.value,
65
+ serverRendered: Boolean(nuxtApp.payload?.serverRendered),
66
+ authEnabled: Boolean(isAuthEnabled)
67
+ }
68
+ });
31
69
  if (isAuthEnabled && siteUrl) {
32
70
  const rawAuthRoute = config.public.convex?.authRoute || "/api/auth";
33
71
  const authRoute = (rawAuthRoute.startsWith("/") ? rawAuthRoute : `/${rawAuthRoute}`).replace(/\/+$/, "");
@@ -43,37 +81,118 @@ export default defineNuxtPlugin((nuxtApp) => {
43
81
  const NULL_TOKEN_CACHE_MS = 5e3;
44
82
  const skipRoutes = config.public.convex?.skipAuthRoutes || [];
45
83
  const router = useRouter();
46
- let currentAuthOperation = null;
47
84
  const fetchToken = async ({
48
85
  forceRefreshToken,
49
86
  signal
50
87
  }) => {
51
- if (signal?.aborted) return null;
52
88
  const route = router.currentRoute.value;
89
+ const routePath = route.path;
90
+ logger.auth({
91
+ phase: "client-fetchToken:start",
92
+ outcome: "success",
93
+ details: {
94
+ traceId: convexAuthTraceId.value,
95
+ path: routePath,
96
+ forceRefreshToken,
97
+ hasHydratedToken: Boolean(convexToken.value),
98
+ hasHydratedUser: Boolean(convexUser.value)
99
+ }
100
+ });
101
+ if (signal?.aborted) {
102
+ logger.auth({
103
+ phase: "client-fetchToken:abort",
104
+ outcome: "skip",
105
+ details: { traceId: convexAuthTraceId.value, reason: "signal-aborted-before-start", path: routePath }
106
+ });
107
+ return null;
108
+ }
53
109
  if (route.meta?.skipConvexAuth === true) {
110
+ logger.auth({
111
+ phase: "client-fetchToken:skip",
112
+ outcome: "skip",
113
+ details: { traceId: convexAuthTraceId.value, reason: "page-meta-skip", path: routePath }
114
+ });
115
+ resolveInitialAuth();
54
116
  return null;
55
117
  }
56
118
  if (matchesSkipRoute(route.path, skipRoutes)) {
119
+ logger.auth({
120
+ phase: "client-fetchToken:skip",
121
+ outcome: "skip",
122
+ details: { traceId: convexAuthTraceId.value, reason: "skip-auth-route", path: routePath }
123
+ });
124
+ resolveInitialAuth();
57
125
  return null;
58
126
  }
59
127
  if (convexToken.value && !forceRefreshToken) {
60
128
  lastTokenValidation = Date.now();
129
+ logger.auth({
130
+ phase: "client-fetchToken:cache",
131
+ outcome: "success",
132
+ details: { traceId: convexAuthTraceId.value, source: "hydrated-token", path: routePath }
133
+ });
134
+ resolveInitialAuth();
61
135
  return convexToken.value;
62
136
  }
63
137
  const timeSinceValidation = Date.now() - lastTokenValidation;
64
138
  if (convexToken.value && forceRefreshToken && timeSinceValidation < TOKEN_CACHE_MS) {
139
+ logger.auth({
140
+ phase: "client-fetchToken:cache",
141
+ outcome: "success",
142
+ details: {
143
+ traceId: convexAuthTraceId.value,
144
+ source: "recent-token-cache",
145
+ ageMs: timeSinceValidation,
146
+ path: routePath
147
+ }
148
+ });
149
+ resolveInitialAuth();
65
150
  return convexToken.value;
66
151
  }
67
152
  const wasServerRendered = !!nuxtApp.payload?.serverRendered;
68
153
  if (wasServerRendered && !convexToken.value && !convexUser.value && !forceRefreshToken) {
154
+ logger.auth({
155
+ phase: "client-fetchToken:skip",
156
+ outcome: "skip",
157
+ details: {
158
+ traceId: convexAuthTraceId.value,
159
+ reason: "ssr-rendered-no-hydrated-session",
160
+ path: routePath
161
+ }
162
+ });
163
+ resolveInitialAuth();
69
164
  return null;
70
165
  }
71
- if (!convexToken.value && Date.now() - lastNullTokenCheck < NULL_TOKEN_CACHE_MS) {
166
+ const timeSinceNullCheck = Date.now() - lastNullTokenCheck;
167
+ if (!convexToken.value && timeSinceNullCheck < NULL_TOKEN_CACHE_MS) {
168
+ logger.auth({
169
+ phase: "client-fetchToken:cache",
170
+ outcome: "miss",
171
+ details: {
172
+ traceId: convexAuthTraceId.value,
173
+ source: "negative-cache",
174
+ ageMs: timeSinceNullCheck,
175
+ path: routePath
176
+ }
177
+ });
178
+ resolveInitialAuth();
72
179
  return null;
73
180
  }
74
181
  try {
182
+ logger.auth({
183
+ phase: "client-fetchToken:request",
184
+ outcome: "success",
185
+ details: { traceId: convexAuthTraceId.value, endpoint: `${authRoute}/convex/token`, path: routePath }
186
+ });
75
187
  const response = await authClient.convex.token();
76
- if (signal?.aborted) return null;
188
+ if (signal?.aborted) {
189
+ logger.auth({
190
+ phase: "client-fetchToken:abort",
191
+ outcome: "skip",
192
+ details: { traceId: convexAuthTraceId.value, reason: "signal-aborted-after-request", path: routePath }
193
+ });
194
+ return null;
195
+ }
77
196
  if (response.error || !response.data?.token) {
78
197
  convexToken.value = null;
79
198
  convexUser.value = null;
@@ -82,6 +201,16 @@ export default defineNuxtPlugin((nuxtApp) => {
82
201
  convexAuthError.value = errorMsg;
83
202
  }
84
203
  lastNullTokenCheck = Date.now();
204
+ logger.auth({
205
+ phase: "client-fetchToken:response",
206
+ outcome: "miss",
207
+ details: {
208
+ traceId: convexAuthTraceId.value,
209
+ path: routePath,
210
+ hasError: Boolean(response.error)
211
+ }
212
+ });
213
+ resolveInitialAuth();
85
214
  return null;
86
215
  }
87
216
  const token = response.data.token;
@@ -91,49 +220,68 @@ export default defineNuxtPlugin((nuxtApp) => {
91
220
  if (!convexUser.value) {
92
221
  convexUser.value = decodeUserFromJwt(token);
93
222
  }
223
+ logger.auth({
224
+ phase: "client-fetchToken:response",
225
+ outcome: "success",
226
+ details: {
227
+ traceId: convexAuthTraceId.value,
228
+ path: routePath,
229
+ userHydrated: Boolean(convexUser.value)
230
+ }
231
+ });
232
+ resolveInitialAuth();
94
233
  return token;
95
234
  } catch (e) {
96
- if (signal?.aborted) return null;
235
+ if (signal?.aborted) {
236
+ logger.auth({
237
+ phase: "client-fetchToken:abort",
238
+ outcome: "skip",
239
+ details: { traceId: convexAuthTraceId.value, reason: "signal-aborted-after-error", path: routePath }
240
+ });
241
+ return null;
242
+ }
97
243
  convexToken.value = null;
98
244
  convexUser.value = null;
99
245
  convexAuthError.value = e instanceof Error ? e.message : "Authentication request failed";
100
246
  lastNullTokenCheck = Date.now();
247
+ logger.auth({
248
+ phase: "client-fetchToken:response",
249
+ outcome: "error",
250
+ details: { traceId: convexAuthTraceId.value, path: routePath },
251
+ error: e instanceof Error ? e : new Error("Authentication request failed")
252
+ });
253
+ resolveInitialAuth();
101
254
  return null;
102
255
  }
103
256
  };
104
257
  client.setAuth(fetchToken, (isAuthenticated) => {
105
- logger.debug(`Auth state: ${isAuthenticated ? "authenticated" : "unauthenticated"}`);
258
+ logger.auth({
259
+ phase: "client-setAuth",
260
+ outcome: "success",
261
+ details: {
262
+ traceId: convexAuthTraceId.value,
263
+ state: isAuthenticated ? "authenticated" : "unauthenticated",
264
+ hasToken: Boolean(convexToken.value),
265
+ hasUser: Boolean(convexUser.value)
266
+ }
267
+ });
106
268
  });
107
- const session = authClient.useSession();
108
- watch(
109
- () => session.value.data,
110
- async (sessionData, oldSessionData) => {
111
- currentAuthOperation?.abort();
112
- currentAuthOperation = new AbortController();
113
- const { signal } = currentAuthOperation;
114
- const hadSession = !!oldSessionData;
115
- const hasSession = !!sessionData;
116
- if (hasSession && !hadSession) {
117
- convexPending.value = true;
118
- try {
119
- lastNullTokenCheck = 0;
120
- lastTokenValidation = 0;
121
- await fetchToken({ forceRefreshToken: true, signal });
122
- logger.auth({ phase: "login", outcome: "success" });
123
- } finally {
124
- if (!signal.aborted) {
125
- convexPending.value = false;
126
- }
127
- }
128
- } else if (!hasSession && hadSession) {
129
- convexPending.value = false;
130
- convexToken.value = null;
131
- convexUser.value = null;
132
- convexAuthError.value = null;
133
- logger.auth({ phase: "logout", outcome: "success" });
269
+ watch(refreshSignal, () => {
270
+ logger.auth({
271
+ phase: "client-refresh",
272
+ outcome: "success",
273
+ details: {
274
+ traceId: convexAuthTraceId.value,
275
+ refreshSignal: refreshSignal.value
134
276
  }
135
- }
136
- );
277
+ });
278
+ lastTokenValidation = 0;
279
+ lastNullTokenCheck = 0;
280
+ client.setAuth(fetchToken, (_isAuthenticated) => {
281
+ });
282
+ });
283
+ } else {
284
+ convexPending.value = false;
137
285
  }
138
286
  nuxtApp.provide("convex", client);
139
287
  if (authClient) {
@@ -151,7 +299,14 @@ export default defineNuxtPlugin((nuxtApp) => {
151
299
  if (convexToken.value) {
152
300
  logger.auth({ phase: "hydrate", outcome: "success", details: { source: "ssr" } });
153
301
  } else if (isAuthEnabled) {
154
- logger.debug("Client initialized (auth enabled, no session)");
302
+ logger.auth({
303
+ phase: "hydrate",
304
+ outcome: "miss",
305
+ details: {
306
+ traceId: convexAuthTraceId.value,
307
+ source: "client-init"
308
+ }
309
+ });
155
310
  } else {
156
311
  logger.debug("Client initialized (auth disabled)");
157
312
  }
@@ -21,6 +21,20 @@ export default defineNuxtPlugin(async () => {
21
21
  const logLevel = getLogLevel(config.public.convex ?? {});
22
22
  const logger = createLogger(logLevel);
23
23
  const endInit = logger.time("plugin:init (server)");
24
+ const debugConfig = config.public.convex?.debug;
25
+ const enableServerAuthTrace = logLevel === "debug" && (debugConfig?.authFlow === true || debugConfig?.serverAuthFlow === true);
26
+ const rawAuthLog = logger.auth.bind(logger);
27
+ logger.auth = (event2) => {
28
+ rawAuthLog(event2);
29
+ if (enableServerAuthTrace) {
30
+ console.log("[BCN_AUTH][server]", {
31
+ phase: event2.phase,
32
+ outcome: event2.outcome,
33
+ ...event2.details,
34
+ error: event2.error ? event2.error.message : null
35
+ });
36
+ }
37
+ };
24
38
  const isAuthEnabled = config.public.convex?.auth;
25
39
  if (!isAuthEnabled) {
26
40
  endInit();
@@ -32,6 +46,9 @@ export default defineNuxtPlugin(async () => {
32
46
  logger.auth({ phase: "init", outcome: "error", error: new Error("No request event available") });
33
47
  return;
34
48
  }
49
+ const requestPath = event.path || event.node.req.url || "(unknown)";
50
+ const requestMethod = event.method || "GET";
51
+ const requestId = crypto.randomUUID();
35
52
  const siteUrl = config.public.convex?.siteUrl;
36
53
  if (!siteUrl) {
37
54
  endInit();
@@ -39,7 +56,17 @@ export default defineNuxtPlugin(async () => {
39
56
  return;
40
57
  }
41
58
  const logAuth = (phase, outcome, details, error) => {
42
- logger.auth({ phase, outcome, details, error });
59
+ logger.auth({
60
+ phase,
61
+ outcome,
62
+ details: {
63
+ requestId,
64
+ method: requestMethod,
65
+ path: requestPath,
66
+ ...details
67
+ },
68
+ error
69
+ });
43
70
  };
44
71
  const convexToken = useState("convex:token", () => null);
45
72
  const convexUser = useState("convex:user", () => null);
@@ -48,14 +75,20 @@ export default defineNuxtPlugin(async () => {
48
75
  const waterfallStart = trackWaterfall ? Date.now() : 0;
49
76
  const phases = [];
50
77
  let cacheHit = false;
78
+ const authCacheConfig = config.public.convex?.authCache;
51
79
  const sessionCheckStart = trackWaterfall ? Date.now() : 0;
52
80
  const cookieHeader = event.headers.get("cookie");
53
81
  const sessionToken = getCookie(cookieHeader, SECURE_SESSION_COOKIE_NAME) || getCookie(cookieHeader, SESSION_COOKIE_NAME);
82
+ logAuth("server-init", "success", {
83
+ hasCookieHeader: Boolean(cookieHeader),
84
+ hasSessionToken: Boolean(sessionToken),
85
+ cacheEnabled: Boolean(authCacheConfig?.enabled)
86
+ });
54
87
  if (!cookieHeader || !sessionToken) {
55
88
  if (trackWaterfall) {
56
89
  phases.push(buildPhase("session-check", sessionCheckStart, waterfallStart, "miss", "No session cookie"));
57
90
  convexAuthWaterfall.value = {
58
- requestId: crypto.randomUUID(),
91
+ requestId,
59
92
  timestamp: waterfallStart,
60
93
  phases,
61
94
  totalDuration: Date.now() - waterfallStart,
@@ -70,7 +103,6 @@ export default defineNuxtPlugin(async () => {
70
103
  if (trackWaterfall) {
71
104
  phases.push(buildPhase("session-check", sessionCheckStart, waterfallStart, "success", "Cookie found"));
72
105
  }
73
- const authCacheConfig = config.public.convex?.authCache;
74
106
  try {
75
107
  let token = null;
76
108
  if (authCacheConfig?.enabled && sessionToken) {
@@ -89,7 +121,7 @@ export default defineNuxtPlugin(async () => {
89
121
  buildPhase("jwt-decode", decodeStart, waterfallStart, convexUser.value ? "success" : "error")
90
122
  );
91
123
  convexAuthWaterfall.value = {
92
- requestId: crypto.randomUUID(),
124
+ requestId,
93
125
  timestamp: waterfallStart,
94
126
  phases,
95
127
  totalDuration: Date.now() - waterfallStart,
@@ -161,7 +193,7 @@ export default defineNuxtPlugin(async () => {
161
193
  }
162
194
  if (trackWaterfall) {
163
195
  convexAuthWaterfall.value = {
164
- requestId: crypto.randomUUID(),
196
+ requestId,
165
197
  timestamp: waterfallStart,
166
198
  phases,
167
199
  totalDuration: Date.now() - waterfallStart,
@@ -174,7 +206,7 @@ export default defineNuxtPlugin(async () => {
174
206
  convexUser.value = null;
175
207
  if (trackWaterfall) {
176
208
  convexAuthWaterfall.value = {
177
- requestId: crypto.randomUUID(),
209
+ requestId,
178
210
  timestamp: waterfallStart,
179
211
  phases,
180
212
  totalDuration: Date.now() - waterfallStart,
@@ -34,13 +34,13 @@ export default defineEventHandler(async (event) => {
34
34
  const authRoute = (rawAuthRoute.startsWith("/") ? rawAuthRoute : `/${rawAuthRoute}`).replace(/\/+$/, "");
35
35
  const startTime = import.meta.dev ? Date.now() : 0;
36
36
  const requestId = import.meta.dev ? crypto.randomUUID() : "";
37
+ const requestUrl = getRequestURL(event);
37
38
  if (!siteUrl) {
38
39
  throw createError({
39
40
  statusCode: 500,
40
41
  message: "Convex site URL not configured"
41
42
  });
42
43
  }
43
- const requestUrl = getRequestURL(event);
44
44
  const authRoutePattern = new RegExp(`^${authRoute.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`);
45
45
  const path = requestUrl.pathname.replace(authRoutePattern, "") || "/";
46
46
  const normalizedPath = path.startsWith("/") ? path : `/${path}`;
@@ -1,5 +1,6 @@
1
1
  import type { createAuthClient } from 'better-auth/vue'
2
2
  import type { ConvexClient } from 'convex/browser'
3
+ import type { LogLevel } from './utils/logger'
3
4
 
4
5
  type AuthClient = ReturnType<typeof createAuthClient>
5
6
 
@@ -13,10 +14,13 @@ export interface ConvexPublicRuntimeConfig {
13
14
  siteUrl?: string
14
15
  /** Routes that should skip auth checks */
15
16
  skipAuthRoutes?: string[]
16
- /** Logging options */
17
- logging?: {
18
- enabled?: boolean | 'debug'
19
- format?: 'pretty' | 'json'
17
+ /** Logging level */
18
+ logging?: LogLevel
19
+ /** Optional debug channels for high-verbosity traces */
20
+ debug?: {
21
+ authFlow?: boolean
22
+ clientAuthFlow?: boolean
23
+ serverAuthFlow?: boolean
20
24
  }
21
25
  /** Index signature for compatibility with Record<string, unknown> */
22
26
  [key: string]: unknown
@@ -1,4 +1,4 @@
1
- import { type useNuxtApp } from '#app';
1
+ import type { useNuxtApp } from '#app';
2
2
  export { type QueryStatus, parseConvexResponse, computeQueryStatus, getFunctionName, hashArgs, getQueryKey, } from './convex-shared.js';
3
3
  type NuxtApp = ReturnType<typeof useNuxtApp>;
4
4
  /**
@@ -20,20 +20,33 @@ export interface FetchAuthTokenOptions {
20
20
  cookieHeader: string;
21
21
  /** Site URL for auth endpoint */
22
22
  siteUrl: string | undefined;
23
+ /** Cached token state (must be obtained at setup time via useState) */
24
+ cachedToken: {
25
+ value: string | null;
26
+ };
23
27
  }
24
28
  /**
25
29
  * Fetch auth token for SSR queries.
26
- * Uses caching via useState to avoid redundant fetches.
30
+ * Uses caching via the provided cachedToken ref to avoid redundant fetches.
31
+ *
32
+ * IMPORTANT: The cachedToken parameter must be obtained at component setup time
33
+ * using useState('convex:token') before being passed to this function.
34
+ * Calling useState inside an async function loses Vue context and will fail.
27
35
  *
28
36
  * @param options - Auth token fetch options
29
37
  * @returns The auth token if available, undefined otherwise
30
38
  *
31
39
  * @example
32
40
  * ```ts
41
+ * // At setup time (synchronous):
42
+ * const cachedToken = useState<string | null>('convex:token')
43
+ *
44
+ * // Later, in async context:
33
45
  * const authToken = await fetchAuthToken({
34
46
  * isPublic: false,
35
47
  * cookieHeader: event?.headers.get('cookie') || '',
36
48
  * siteUrl: config.public.convex?.siteUrl,
49
+ * cachedToken,
37
50
  * })
38
51
  * ```
39
52
  */
@@ -1,4 +1,3 @@
1
- import { useState } from "#app";
2
1
  export {
3
2
  parseConvexResponse,
4
3
  computeQueryStatus,
@@ -8,14 +7,13 @@ export {
8
7
  } from "./convex-shared.js";
9
8
  const subscriptionRegistry = /* @__PURE__ */ new WeakMap();
10
9
  export async function fetchAuthToken(options) {
11
- const { isPublic, cookieHeader, siteUrl } = options;
10
+ const { isPublic, cookieHeader, siteUrl, cachedToken } = options;
12
11
  if (isPublic) {
13
12
  return void 0;
14
13
  }
15
14
  if (!cookieHeader.includes("better-auth.session_token")) {
16
15
  return void 0;
17
16
  }
18
- const cachedToken = useState("convex:token");
19
17
  if (cachedToken.value) {
20
18
  return cachedToken.value;
21
19
  }
package/dist/types.d.mts CHANGED
@@ -2,4 +2,4 @@ export { type LogLevel } from '../dist/runtime/utils/logger.js'
2
2
 
3
3
  export { default } from './module.mjs'
4
4
 
5
- export { type AuthCacheOptions, type ModuleOptions, type QueryDefaults } from './module.mjs'
5
+ export { type AuthCacheOptions, type ConvexDebugOptions, type ModuleOptions, type QueryDefaults } from './module.mjs'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "better-convex-nuxt",
3
- "version": "0.2.7",
3
+ "version": "0.2.9",
4
4
  "description": "Full-featured Convex integration for Nuxt with SSR, real-time subscriptions, authentication, and permissions",
5
5
  "keywords": [
6
6
  "authentication",
@@ -1 +0,0 @@
1
- {"id":"bb1b6fab-3dad-4ebb-bedd-8a7e8492b357","timestamp":1769017708682,"matcher":{"static":{},"wildcard":{},"dynamic":{}},"prerendered":[]}