better-convex-nuxt 0.1.8 → 0.2.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.
Files changed (72) hide show
  1. package/README.md +13 -2
  2. package/dist/module.d.mts +70 -10
  3. package/dist/module.json +1 -1
  4. package/dist/module.mjs +73 -14
  5. package/dist/runtime/components/ConvexAuthError.d.vue.ts +19 -0
  6. package/dist/runtime/components/ConvexAuthError.vue +18 -0
  7. package/dist/runtime/components/ConvexAuthError.vue.d.ts +19 -0
  8. package/dist/runtime/composables/index.d.ts +6 -5
  9. package/dist/runtime/composables/index.js +6 -2
  10. package/dist/runtime/composables/useConvexAction.d.ts +1 -12
  11. package/dist/runtime/composables/useConvexAction.js +80 -13
  12. package/dist/runtime/composables/useConvexAuth.d.ts +1 -0
  13. package/dist/runtime/composables/useConvexAuth.js +1 -13
  14. package/dist/runtime/composables/useConvexConnectionState.d.ts +1 -12
  15. package/dist/runtime/composables/useConvexConnectionState.js +25 -15
  16. package/dist/runtime/composables/useConvexFileUpload.d.ts +191 -0
  17. package/dist/runtime/composables/useConvexFileUpload.js +175 -0
  18. package/dist/runtime/composables/useConvexMutation.d.ts +0 -6
  19. package/dist/runtime/composables/useConvexMutation.js +84 -22
  20. package/dist/runtime/composables/useConvexPaginatedQuery.d.ts +2 -7
  21. package/dist/runtime/composables/useConvexPaginatedQuery.js +60 -59
  22. package/dist/runtime/composables/useConvexQuery.d.ts +14 -105
  23. package/dist/runtime/composables/useConvexQuery.js +226 -267
  24. package/dist/runtime/composables/useConvexStorageUrl.d.ts +82 -0
  25. package/dist/runtime/composables/useConvexStorageUrl.js +12 -0
  26. package/dist/runtime/composables/usePermissions.d.ts +2 -2
  27. package/dist/runtime/composables/usePermissions.js +10 -2
  28. package/dist/runtime/devtools/event-buffer.d.ts +29 -0
  29. package/dist/runtime/devtools/event-buffer.js +30 -0
  30. package/dist/runtime/devtools/index.d.ts +14 -0
  31. package/dist/runtime/devtools/index.js +20 -0
  32. package/dist/runtime/devtools/mutation-registry.d.ts +39 -0
  33. package/dist/runtime/devtools/mutation-registry.js +59 -0
  34. package/dist/runtime/devtools/query-registry.d.ts +77 -0
  35. package/dist/runtime/devtools/query-registry.js +55 -0
  36. package/dist/runtime/devtools/server.d.ts +2 -0
  37. package/dist/runtime/devtools/server.js +1205 -0
  38. package/dist/runtime/devtools/types.d.ts +107 -0
  39. package/dist/runtime/devtools/types.js +1 -0
  40. package/dist/runtime/plugin.client.d.ts +0 -13
  41. package/dist/runtime/plugin.client.js +187 -52
  42. package/dist/runtime/plugin.server.d.ts +1 -0
  43. package/dist/runtime/plugin.server.js +113 -50
  44. package/dist/runtime/server/api/auth/[...].d.ts +1 -1
  45. package/dist/runtime/server/api/auth/[...].js +45 -66
  46. package/dist/runtime/server/utils/auth-cache.d.ts +38 -0
  47. package/dist/runtime/server/utils/auth-cache.js +21 -0
  48. package/dist/runtime/server/utils/convex.d.ts +0 -6
  49. package/dist/runtime/server/utils/convex.js +63 -77
  50. package/dist/runtime/types.d.ts +0 -17
  51. package/dist/runtime/utils/convex-cache.d.ts +82 -27
  52. package/dist/runtime/utils/convex-cache.js +57 -41
  53. package/dist/runtime/utils/convex-shared.d.ts +48 -0
  54. package/dist/runtime/utils/convex-shared.js +42 -0
  55. package/dist/runtime/utils/logger.d.ts +101 -100
  56. package/dist/runtime/utils/logger.js +240 -39
  57. package/dist/runtime/utils/mime-type.d.ts +33 -0
  58. package/dist/runtime/utils/mime-type.js +10 -0
  59. package/dist/runtime/utils/shared-helpers.d.ts +116 -0
  60. package/dist/runtime/utils/shared-helpers.js +134 -0
  61. package/dist/runtime/utils/types.d.ts +44 -0
  62. package/dist/runtime/utils/types.js +1 -0
  63. package/dist/types.d.mts +1 -1
  64. package/package.json +6 -3
  65. package/dist/runtime/composables/useConvexCached.d.ts +0 -32
  66. package/dist/runtime/composables/useConvexCached.js +0 -7
  67. package/dist/runtime/composables/useConvexData.d.ts +0 -37
  68. package/dist/runtime/composables/useConvexData.js +0 -6
  69. package/dist/runtime/composables/useLazyConvexQuery.d.ts +0 -26
  70. package/dist/runtime/composables/useLazyConvexQuery.js +0 -7
  71. package/dist/runtime/utils/query-helpers.d.ts +0 -118
  72. package/dist/runtime/utils/query-helpers.js +0 -67
package/README.md CHANGED
@@ -8,7 +8,12 @@
8
8
  Full-featured [Convex](https://convex.dev) integration for [Nuxt](https://nuxt.com) with SSR, real-time subscriptions, authentication, and permissions.
9
9
 
10
10
  - [Documentation](https://better-convex-nuxt.vercel.app)
11
- - [Online Playground](https://stackblitz.com/github/lupinum-dev/better-convex-nuxt?file=playground%2Fapp.vue)
11
+
12
+ > [!NOTE]
13
+ > **Work In Progress**
14
+ > This module is rapidly evolving. While we are using it in our own apps, features and APIs are subject to change as we refine the best patterns for Nuxt + Convex.
15
+
16
+ Contributions and PRs to help improve the library, playground or docs are highly appreciated! 🙏
12
17
 
13
18
  ## Features
14
19
 
@@ -24,7 +29,7 @@ Full-featured [Convex](https://convex.dev) integration for [Nuxt](https://nuxt.c
24
29
  Install the module:
25
30
 
26
31
  ```bash
27
- npx nuxi module add better-convex-nuxt
32
+ pnpm add better-convex-nuxt
28
33
  ```
29
34
 
30
35
  Add your Convex URL to `.env`:
@@ -113,6 +118,8 @@ async function handleLogin() {
113
118
  | `useConvexMutation` | Execute mutations with optimistic updates |
114
119
  | `useConvexAction` | Execute Convex actions |
115
120
  | `useConvexPaginatedQuery` | Paginated queries with `loadMore()` |
121
+ | `useConvexFileUpload` | Upload files to Convex storage with progress |
122
+ | `useConvexStorageUrl` | Get reactive URLs for stored files |
116
123
  | `useConvexAuth` | Authentication state (user, token, isAuthenticated) |
117
124
  | `useConvexConnectionState` | WebSocket connection status |
118
125
  | `useConvexCached` | Read cached query data |
@@ -155,6 +162,10 @@ pnpm test
155
162
  pnpm lint
156
163
  ```
157
164
 
165
+ ## Acknowledgements
166
+
167
+ - File upload composables inspired by [nuxt-convex](https://github.com/onmax/nuxt-convex) by [@onmax](https://github.com/onmax)
168
+
158
169
  ## License
159
170
 
160
171
  [MIT](./LICENSE)
package/dist/module.d.mts CHANGED
@@ -1,16 +1,50 @@
1
1
  import * as _nuxt_schema from '@nuxt/schema';
2
2
 
3
- interface BetterAuthOptions {
4
- /** @deprecated Use siteUrl instead */
5
- url?: string;
3
+ interface LoggingOptions {
4
+ /**
5
+ * Enable module logging.
6
+ * - false: No logs (production default)
7
+ * - true: Info-level logs (canonical events only)
8
+ * - 'debug': Include debug-level details
9
+ * @default false
10
+ */
11
+ enabled?: boolean | 'debug';
12
+ /**
13
+ * Output format for logs.
14
+ * - 'pretty': Human-readable with icons (default)
15
+ * - 'json': Structured JSON for log aggregation
16
+ * @default 'pretty'
17
+ */
18
+ format?: 'pretty' | 'json';
19
+ }
20
+ interface AuthCacheOptions {
21
+ /**
22
+ * Enable SSR auth token caching.
23
+ * When enabled, Convex JWT tokens are cached to reduce TTFB on subsequent SSR requests.
24
+ * Uses Nitro Storage (memory by default, configurable to Redis for multi-instance deployments).
25
+ * @default false
26
+ */
27
+ enabled: boolean;
28
+ /**
29
+ * Cache TTL in seconds.
30
+ * Determines how long tokens are cached before requiring a fresh fetch.
31
+ * Shorter TTL = more security, longer TTL = better performance.
32
+ * @default 900 (15 minutes)
33
+ */
34
+ ttl?: number;
6
35
  }
7
36
  interface ModuleOptions {
8
37
  /** Convex deployment URL (WebSocket) - e.g., https://your-app.convex.cloud */
9
38
  url?: string;
10
39
  /** Convex site URL (HTTP/Auth) - e.g., https://your-app.convex.site. Auto-derived from url if not set. */
11
40
  siteUrl?: string;
12
- /** @deprecated Use siteUrl instead */
13
- auth?: BetterAuthOptions;
41
+ /**
42
+ * Additional trusted origins for CORS validation on the auth proxy.
43
+ * By default, only requests from the origin matching siteUrl are allowed.
44
+ * Supports wildcards for preview deployments (e.g., 'https://preview-*.vercel.app').
45
+ * @default []
46
+ */
47
+ trustedOrigins?: string[];
14
48
  /**
15
49
  * Enable permission composables (createPermissions factory).
16
50
  * When true, auto-imports createPermissions for building usePermissions.
@@ -18,13 +52,39 @@ interface ModuleOptions {
18
52
  */
19
53
  permissions?: boolean;
20
54
  /**
21
- * Enable verbose logging for debugging.
22
- * When true, logs detailed information about queries, mutations, auth, and SSR operations.
23
- * @default false
55
+ * Configure module logging behavior.
56
+ * Emits canonical log events for debugging SSR, auth, queries, and mutations.
57
+ */
58
+ logging?: LoggingOptions;
59
+ /**
60
+ * SSR auth token caching configuration (opt-in).
61
+ * Caches Convex JWT tokens server-side to reduce TTFB on subsequent requests.
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * // nuxt.config.ts
66
+ * export default defineNuxtConfig({
67
+ * convex: {
68
+ * authCache: {
69
+ * enabled: true,
70
+ * ttl: 900 // 15 minutes
71
+ * }
72
+ * },
73
+ * // For multi-instance deployments, configure Redis:
74
+ * nitro: {
75
+ * storage: {
76
+ * 'cache:convex:auth': {
77
+ * driver: 'redis',
78
+ * url: process.env.REDIS_URL
79
+ * }
80
+ * }
81
+ * }
82
+ * })
83
+ * ```
24
84
  */
25
- verbose?: boolean;
85
+ authCache?: AuthCacheOptions;
26
86
  }
27
87
  declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
28
88
 
29
89
  export { _default as default };
30
- export type { BetterAuthOptions, ModuleOptions };
90
+ export type { AuthCacheOptions, LoggingOptions, ModuleOptions };
package/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=3.0.0"
6
6
  },
7
- "version": "0.1.8",
7
+ "version": "0.2.0",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
10
10
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -1,6 +1,15 @@
1
- import { defineNuxtModule, createResolver, addPlugin, addServerHandler, addTemplate, addImports, addServerImports, addComponentsDir } from '@nuxt/kit';
1
+ import { useLogger, defineNuxtModule, createResolver, addPlugin, addServerHandler, addTemplate, addImports, addServerImports, addComponentsDir } from '@nuxt/kit';
2
2
  import { defu } from 'defu';
3
3
 
4
+ const logger = useLogger("better-convex-nuxt");
5
+ function isValidUrl(url) {
6
+ try {
7
+ new URL(url);
8
+ return true;
9
+ } catch {
10
+ return false;
11
+ }
12
+ }
4
13
  const module$1 = defineNuxtModule({
5
14
  meta: {
6
15
  name: "better-convex-nuxt",
@@ -12,21 +21,40 @@ const module$1 = defineNuxtModule({
12
21
  defaults: {
13
22
  url: process.env.CONVEX_URL,
14
23
  siteUrl: process.env.CONVEX_SITE_URL,
24
+ trustedOrigins: [],
15
25
  permissions: false,
16
- verbose: false
26
+ logging: {
27
+ enabled: false,
28
+ format: "pretty"
29
+ },
30
+ authCache: {
31
+ enabled: false,
32
+ ttl: 900
33
+ // 15 minutes
34
+ }
17
35
  },
18
36
  setup(options, nuxt) {
19
37
  const resolver = createResolver(import.meta.url);
20
- const derivedSiteUrl = options.siteUrl || options.auth?.url || (options.url?.replace(".convex.cloud", ".convex.site") ?? "");
38
+ if (options.url && !isValidUrl(options.url)) {
39
+ logger.warn(`Invalid Convex URL format: "${options.url}". Expected a valid URL like "https://your-app.convex.cloud"`);
40
+ }
41
+ if (options.siteUrl && !isValidUrl(options.siteUrl)) {
42
+ logger.warn(`Invalid Convex site URL format: "${options.siteUrl}". Expected a valid URL like "https://your-app.convex.site"`);
43
+ }
44
+ const derivedSiteUrl = options.siteUrl || (options.url?.replace(".convex.cloud", ".convex.site") ?? "");
21
45
  const convexConfig = defu(
22
46
  nuxt.options.runtimeConfig.public.convex,
23
47
  {
24
48
  url: options.url || "",
25
49
  siteUrl: derivedSiteUrl,
26
- verbose: options.verbose ?? false,
27
- // Keep auth.url for backwards compatibility
28
- auth: {
29
- url: options.auth?.url || derivedSiteUrl
50
+ trustedOrigins: options.trustedOrigins ?? [],
51
+ logging: {
52
+ enabled: options.logging?.enabled ?? false,
53
+ format: options.logging?.format ?? "pretty"
54
+ },
55
+ authCache: {
56
+ enabled: options.authCache?.enabled ?? false,
57
+ ttl: options.authCache?.ttl ?? 900
30
58
  }
31
59
  }
32
60
  );
@@ -75,12 +103,7 @@ export {}
75
103
  { name: "useConvexAction", from: resolver.resolve("./runtime/composables/useConvexAction") },
76
104
  { name: "useAuthClient", from: resolver.resolve("./runtime/composables/useAuthClient") },
77
105
  { name: "useConvexQuery", from: resolver.resolve("./runtime/composables/useConvexQuery") },
78
- { name: "useConvexCached", from: resolver.resolve("./runtime/composables/useConvexCached") },
79
- { name: "useConvexData", from: resolver.resolve("./runtime/composables/useConvexData") },
80
- {
81
- name: "useLazyConvexQuery",
82
- from: resolver.resolve("./runtime/composables/useLazyConvexQuery")
83
- },
106
+ { name: "getQueryKey", from: resolver.resolve("./runtime/composables/useConvexQuery") },
84
107
  {
85
108
  name: "useConvexPaginatedQuery",
86
109
  from: resolver.resolve("./runtime/composables/useConvexPaginatedQuery")
@@ -120,6 +143,15 @@ export {}
120
143
  {
121
144
  name: "deleteFromPaginatedQuery",
122
145
  from: resolver.resolve("./runtime/composables/useConvexPaginatedQuery")
146
+ },
147
+ // File upload composables
148
+ {
149
+ name: "useConvexFileUpload",
150
+ from: resolver.resolve("./runtime/composables/useConvexFileUpload")
151
+ },
152
+ {
153
+ name: "useConvexStorageUrl",
154
+ from: resolver.resolve("./runtime/composables/useConvexStorageUrl")
123
155
  }
124
156
  ]);
125
157
  if (options.permissions) {
@@ -133,7 +165,8 @@ export {}
133
165
  addServerImports([
134
166
  { name: "fetchQuery", from: resolver.resolve("./runtime/server/utils/convex") },
135
167
  { name: "fetchMutation", from: resolver.resolve("./runtime/server/utils/convex") },
136
- { name: "fetchAction", from: resolver.resolve("./runtime/server/utils/convex") }
168
+ { name: "fetchAction", from: resolver.resolve("./runtime/server/utils/convex") },
169
+ { name: "clearAuthCache", from: resolver.resolve("./runtime/server/utils/auth-cache") }
137
170
  ]);
138
171
  addComponentsDir({
139
172
  path: resolver.resolve("./runtime/components"),
@@ -144,7 +177,33 @@ export {}
144
177
  path: resolver.resolve(nuxt.options.buildDir, "types/better-convex-nuxt.d.ts")
145
178
  });
146
179
  });
180
+ if (nuxt.options.dev) {
181
+ setupDevTools(nuxt, resolver);
182
+ }
147
183
  }
148
184
  });
185
+ async function setupDevTools(nuxt, resolver) {
186
+ try {
187
+ const { addCustomTab } = await import('@nuxt/devtools-kit');
188
+ addCustomTab({
189
+ name: "convex",
190
+ title: "Convex",
191
+ icon: "carbon:data-base",
192
+ category: "app",
193
+ view: {
194
+ type: "iframe",
195
+ src: "/__convex_devtools__",
196
+ persistent: true
197
+ }
198
+ }, nuxt);
199
+ addServerHandler({
200
+ route: "/__convex_devtools__",
201
+ handler: resolver.resolve("./runtime/devtools/server")
202
+ });
203
+ logger.info("Nuxt DevTools integration enabled");
204
+ } catch {
205
+ logger.debug("Nuxt DevTools integration skipped (devtools-kit not available)");
206
+ }
207
+ }
149
208
 
150
209
  export { module$1 as default };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Retry authentication by reloading the page
3
+ */
4
+ declare function retry(): void;
5
+ declare var __VLS_1: {
6
+ retry: typeof retry;
7
+ };
8
+ type __VLS_Slots = {} & {
9
+ default?: (props: typeof __VLS_1) => any;
10
+ };
11
+ declare const __VLS_base: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
12
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
13
+ declare const _default: typeof __VLS_export;
14
+ export default _default;
15
+ type __VLS_WithSlots<T, S> = T & {
16
+ new (): {
17
+ $slots: S;
18
+ };
19
+ };
@@ -0,0 +1,18 @@
1
+ <script setup>
2
+ import { computed } from "vue";
3
+ import { useConvexAuth } from "../composables/useConvexAuth";
4
+ const { isAuthenticated, isPending, token, user } = useConvexAuth();
5
+ const hasError = computed(() => {
6
+ if (isPending.value) return false;
7
+ if (isAuthenticated.value) return false;
8
+ if (token.value && !user.value) return true;
9
+ return false;
10
+ });
11
+ function retry() {
12
+ window.location.reload();
13
+ }
14
+ </script>
15
+
16
+ <template>
17
+ <slot v-if="hasError" :retry="retry" />
18
+ </template>
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Retry authentication by reloading the page
3
+ */
4
+ declare function retry(): void;
5
+ declare var __VLS_1: {
6
+ retry: typeof retry;
7
+ };
8
+ type __VLS_Slots = {} & {
9
+ default?: (props: typeof __VLS_1) => any;
10
+ };
11
+ declare const __VLS_base: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
12
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
13
+ declare const _default: typeof __VLS_export;
14
+ export default _default;
15
+ type __VLS_WithSlots<T, S> = T & {
16
+ new (): {
17
+ $slots: S;
18
+ };
19
+ };
@@ -1,11 +1,12 @@
1
- export { useConvexAuth } from './useConvexAuth.js';
1
+ export { useConvexAuth, type ConvexUser } from './useConvexAuth.js';
2
2
  export { useConvex } from './useConvex.js';
3
- export { useConvexConnectionState, type ConnectionState, type UseConvexConnectionStateOptions, } from './useConvexConnectionState.js';
3
+ export { useConvexConnectionState, type ConnectionState, } from './useConvexConnectionState.js';
4
4
  export { useConvexMutation, type MutationStatus, type UseConvexMutationReturn, type UseConvexMutationOptions, updateQuery, setQueryData, updateAllQueries, deleteFromQuery, type UpdateQueryOptions, type SetQueryDataOptions, type UpdateAllQueriesOptions, type DeleteFromQueryOptions, } from './useConvexMutation.js';
5
5
  export type { OptimisticLocalStore } from 'convex/browser';
6
- export { useConvexAction, type ActionStatus, type UseConvexActionReturn, type UseConvexActionOptions, } from './useConvexAction.js';
6
+ export { useConvexAction, type ActionStatus, type UseConvexActionReturn, } from './useConvexAction.js';
7
7
  export { useAuthClient } from './useAuthClient.js';
8
- export { useConvexQuery, type QueryStatus, type UseConvexQueryReturn, type UseConvexQueryData, type UseConvexQueryOptions, } from './useConvexQuery.js';
9
- export { useConvexCached } from './useConvexCached.js';
8
+ export { useConvexQuery, getQueryKey, type QueryStatus, type UseConvexQueryOptions, } from './useConvexQuery.js';
10
9
  export { useConvexPaginatedQuery, type PaginationStatus, type UseConvexPaginatedQueryOptions, type UseConvexPaginatedQueryReturn, type PaginatedQueryReference, type PaginatedQueryArgs, type PaginatedQueryItem, insertAtTop, insertAtPosition, insertAtBottomIfLoaded, optimisticallyUpdateValueInPaginatedQuery, deleteFromPaginatedQuery, type InsertAtTopOptions, type InsertAtPositionOptions, type InsertAtBottomIfLoadedOptions, type UpdateInPaginatedQueryOptions, type DeleteFromPaginatedQueryOptions, } from './useConvexPaginatedQuery.js';
10
+ export { useConvexFileUpload, type UploadStatus, type UseConvexFileUploadReturn, type UseConvexFileUploadOptions, } from './useConvexFileUpload.js';
11
+ export { useConvexStorageUrl } from './useConvexStorageUrl.js';
11
12
  export { createPermissions, type PermissionContext, type Resource, type CheckPermissionFn, type CreatePermissionsOptions, type UsePermissionsReturn, type UsePermissionGuardOptions, } from './usePermissions.js';
@@ -15,9 +15,9 @@ export {
15
15
  } from "./useConvexAction.js";
16
16
  export { useAuthClient } from "./useAuthClient.js";
17
17
  export {
18
- useConvexQuery
18
+ useConvexQuery,
19
+ getQueryKey
19
20
  } from "./useConvexQuery.js";
20
- export { useConvexCached } from "./useConvexCached.js";
21
21
  export {
22
22
  useConvexPaginatedQuery,
23
23
  insertAtTop,
@@ -26,6 +26,10 @@ export {
26
26
  optimisticallyUpdateValueInPaginatedQuery,
27
27
  deleteFromPaginatedQuery
28
28
  } from "./useConvexPaginatedQuery.js";
29
+ export {
30
+ useConvexFileUpload
31
+ } from "./useConvexFileUpload.js";
32
+ export { useConvexStorageUrl } from "./useConvexStorageUrl.js";
29
33
  export {
30
34
  createPermissions
31
35
  } from "./usePermissions.js";
@@ -1,16 +1,5 @@
1
1
  import type { FunctionArgs, FunctionReference, FunctionReturnType } from 'convex/server';
2
2
  import { type Ref, type ComputedRef } from 'vue';
3
- /**
4
- * Options for useConvexAction
5
- */
6
- export interface UseConvexActionOptions {
7
- /**
8
- * Enable verbose logging for debugging.
9
- * Logs action lifecycle events: start, success, error.
10
- * @default false
11
- */
12
- verbose?: boolean;
13
- }
14
3
  /**
15
4
  * Action status representing the current state of the action
16
5
  * - 'idle': not yet called or reset
@@ -102,4 +91,4 @@ export interface UseConvexActionReturn<Args, Result> {
102
91
  * </template>
103
92
  * ```
104
93
  */
105
- export declare function useConvexAction<Action extends FunctionReference<'action'>>(action: Action, options?: UseConvexActionOptions): UseConvexActionReturn<FunctionArgs<Action>, FunctionReturnType<Action>>;
94
+ export declare function useConvexAction<Action extends FunctionReference<'action'>>(action: Action): UseConvexActionReturn<FunctionArgs<Action>, FunctionReturnType<Action>>;
@@ -1,47 +1,114 @@
1
1
  import { ref, computed } from "vue";
2
- import { createActionLogger, getVerboseFlag } from "../utils/logger.js";
2
+ import { useRuntimeConfig } from "#imports";
3
+ import { getFunctionName } from "../utils/convex-cache.js";
4
+ import { createModuleLogger, getLoggingOptions, createTimer, formatArgsPreview } from "../utils/logger.js";
3
5
  import { useConvex } from "./useConvex.js";
4
- export function useConvexAction(action, options) {
6
+ let devToolsMutationRegistryPromise = null;
7
+ let devToolsMutationRegistry = null;
8
+ if (import.meta.client && import.meta.dev) {
9
+ devToolsMutationRegistryPromise = import("../devtools/mutation-registry.js");
10
+ devToolsMutationRegistryPromise.then((module) => {
11
+ devToolsMutationRegistry = module;
12
+ }).catch(() => {
13
+ });
14
+ }
15
+ export function useConvexAction(action) {
5
16
  const config = useRuntimeConfig();
6
- const verbose = getVerboseFlag(config, options?.verbose);
7
- const log = createActionLogger(verbose, "useConvexAction", action);
8
- log("Initialized");
17
+ const loggingOptions = getLoggingOptions(config.public.convex ?? {});
18
+ const logger = createModuleLogger(loggingOptions);
19
+ const fnName = getFunctionName(action);
9
20
  const _status = ref("idle");
10
21
  const error = ref(null);
11
22
  const data = ref(void 0);
12
23
  const status = computed(() => _status.value);
13
24
  const pending = computed(() => _status.value === "pending");
14
25
  const reset = () => {
15
- log("Reset");
16
26
  _status.value = "idle";
17
27
  error.value = null;
18
28
  data.value = void 0;
19
29
  };
20
30
  const execute = async (args) => {
21
31
  const client = useConvex();
32
+ const timer = createTimer();
22
33
  if (!client) {
23
- const err = new Error(
24
- "[bcn] ConvexClient not available - actions only work on client side"
25
- );
26
- log("Error: Client not available");
34
+ const err = new Error("ConvexClient not available - actions only work on client side");
27
35
  _status.value = "error";
28
36
  error.value = err;
37
+ logger.event({
38
+ event: "operation:complete",
39
+ env: "client",
40
+ type: "action",
41
+ name: fnName,
42
+ duration_ms: timer(),
43
+ outcome: "error",
44
+ error: { type: "ClientError", message: err.message }
45
+ });
29
46
  throw err;
30
47
  }
31
- log("Starting action", args);
32
48
  _status.value = "pending";
33
49
  error.value = null;
50
+ const startTime = Date.now();
51
+ let actionId = null;
52
+ if (devToolsMutationRegistry) {
53
+ actionId = devToolsMutationRegistry.registerMutation({
54
+ name: fnName,
55
+ type: "action",
56
+ args,
57
+ state: "pending",
58
+ hasOptimisticUpdate: false,
59
+ startedAt: startTime
60
+ });
61
+ }
34
62
  try {
35
63
  const result = await client.action(action, args);
36
- log("Success", result);
37
64
  _status.value = "success";
38
65
  data.value = result;
66
+ const settledAt = Date.now();
67
+ if (devToolsMutationRegistry && actionId) {
68
+ devToolsMutationRegistry.updateMutationState(actionId, {
69
+ state: "success",
70
+ result,
71
+ settledAt,
72
+ duration: settledAt - startTime
73
+ });
74
+ }
75
+ logger.event({
76
+ event: "operation:complete",
77
+ env: "client",
78
+ type: "action",
79
+ name: fnName,
80
+ duration_ms: timer(),
81
+ outcome: "success",
82
+ args_preview: formatArgsPreview(args)
83
+ });
39
84
  return result;
40
85
  } catch (e) {
41
86
  const err = e instanceof Error ? e : new Error(String(e));
42
- log("Error", err.message);
43
87
  _status.value = "error";
44
88
  error.value = err;
89
+ const settledAt = Date.now();
90
+ if (devToolsMutationRegistry && actionId) {
91
+ devToolsMutationRegistry.updateMutationState(actionId, {
92
+ state: "error",
93
+ error: err.message,
94
+ settledAt,
95
+ duration: settledAt - startTime
96
+ });
97
+ }
98
+ logger.event({
99
+ event: "operation:complete",
100
+ env: "client",
101
+ type: "action",
102
+ name: fnName,
103
+ duration_ms: timer(),
104
+ outcome: "error",
105
+ args_preview: formatArgsPreview(args),
106
+ error: {
107
+ type: err.name,
108
+ message: err.message,
109
+ retriable: false
110
+ }
111
+ });
45
112
  throw err;
46
113
  }
47
114
  };
@@ -1,3 +1,4 @@
1
+ export type { ConvexUser } from '../utils/types.js';
1
2
  /**
2
3
  * Composable for accessing Convex authentication state.
3
4
  *
@@ -1,21 +1,9 @@
1
- import { useState, computed, readonly, useRuntimeConfig } from "#imports";
2
- import { createLogger, getVerboseFlag } from "../utils/logger.js";
1
+ import { useState, computed, readonly } from "#imports";
3
2
  export function useConvexAuth() {
4
3
  const token = useState("convex:token", () => null);
5
4
  const user = useState("convex:user", () => null);
6
5
  const isPending = useState("convex:pending", () => false);
7
6
  const isAuthenticated = computed(() => !!token.value && !!user.value);
8
- const config = useRuntimeConfig();
9
- const log = createLogger({
10
- verbose: getVerboseFlag(config),
11
- prefix: "[bcn:auth]"
12
- });
13
- log("useConvexAuth called", {
14
- hasToken: !!token.value,
15
- hasUser: !!user.value,
16
- isAuthenticated: isAuthenticated.value,
17
- isPending: isPending.value
18
- });
19
7
  return {
20
8
  /** The JWT token for Convex authentication (readonly) */
21
9
  token: readonly(token),
@@ -19,17 +19,6 @@ export interface ConnectionState {
19
19
  /** Number of pending actions */
20
20
  inflightActions: number;
21
21
  }
22
- /**
23
- * Options for useConvexConnectionState
24
- */
25
- export interface UseConvexConnectionStateOptions {
26
- /**
27
- * Enable verbose logging for debugging.
28
- * Logs connection state changes.
29
- * @default false
30
- */
31
- verbose?: boolean;
32
- }
33
22
  /**
34
23
  * Monitor the Convex WebSocket connection state.
35
24
  * Useful for showing offline/reconnecting UI.
@@ -47,7 +36,7 @@ export interface UseConvexConnectionStateOptions {
47
36
  * </template>
48
37
  * ```
49
38
  */
50
- export declare function useConvexConnectionState(options?: UseConvexConnectionStateOptions): {
39
+ export declare function useConvexConnectionState(): {
51
40
  /** Full connection state object */
52
41
  state: Readonly<import("vue").Ref<{
53
42
  readonly hasInflightRequests: boolean;