better-convex-nuxt 0.1.6 → 0.1.8

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/dist/module.d.mts CHANGED
@@ -17,6 +17,12 @@ interface ModuleOptions {
17
17
  * @default false
18
18
  */
19
19
  permissions?: boolean;
20
+ /**
21
+ * Enable verbose logging for debugging.
22
+ * When true, logs detailed information about queries, mutations, auth, and SSR operations.
23
+ * @default false
24
+ */
25
+ verbose?: boolean;
20
26
  }
21
27
  declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
22
28
 
package/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=3.0.0"
6
6
  },
7
- "version": "0.1.6",
7
+ "version": "0.1.8",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
10
10
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -12,7 +12,8 @@ const module$1 = defineNuxtModule({
12
12
  defaults: {
13
13
  url: process.env.CONVEX_URL,
14
14
  siteUrl: process.env.CONVEX_SITE_URL,
15
- permissions: false
15
+ permissions: false,
16
+ verbose: false
16
17
  },
17
18
  setup(options, nuxt) {
18
19
  const resolver = createResolver(import.meta.url);
@@ -22,6 +23,7 @@ const module$1 = defineNuxtModule({
22
23
  {
23
24
  url: options.url || "",
24
25
  siteUrl: derivedSiteUrl,
26
+ verbose: options.verbose ?? false,
25
27
  // Keep auth.url for backwards compatibility
26
28
  auth: {
27
29
  url: options.auth?.url || derivedSiteUrl
@@ -1,18 +1,10 @@
1
1
  import { ref, computed } from "vue";
2
- import { getFunctionName } from "../utils/convex-cache.js";
2
+ import { createActionLogger, getVerboseFlag } from "../utils/logger.js";
3
3
  import { useConvex } from "./useConvex.js";
4
4
  export function useConvexAction(action, options) {
5
- const verbose = options?.verbose ?? false;
6
- const fnName = getFunctionName(action);
7
- const log = verbose ? (message, data2) => {
8
- const prefix = `[useConvexAction] ${fnName}: `;
9
- if (data2 !== void 0) {
10
- console.log(prefix + message, data2);
11
- } else {
12
- console.log(prefix + message);
13
- }
14
- } : () => {
15
- };
5
+ const config = useRuntimeConfig();
6
+ const verbose = getVerboseFlag(config, options?.verbose);
7
+ const log = createActionLogger(verbose, "useConvexAction", action);
16
8
  log("Initialized");
17
9
  const _status = ref("idle");
18
10
  const error = ref(null);
@@ -1,20 +1,15 @@
1
- import { useState, computed, readonly } from "#imports";
2
- const log = (message, data) => {
3
- if (import.meta.dev) {
4
- const env = import.meta.server ? "[SSR]" : "[Client]";
5
- const prefix = `[bcn:auth] ${env} `;
6
- if (data !== void 0) {
7
- console.log(prefix + message, data);
8
- } else {
9
- console.log(prefix + message);
10
- }
11
- }
12
- };
1
+ import { useState, computed, readonly, useRuntimeConfig } from "#imports";
2
+ import { createLogger, getVerboseFlag } from "../utils/logger.js";
13
3
  export function useConvexAuth() {
14
4
  const token = useState("convex:token", () => null);
15
5
  const user = useState("convex:user", () => null);
16
6
  const isPending = useState("convex:pending", () => false);
17
7
  const isAuthenticated = computed(() => !!token.value && !!user.value);
8
+ const config = useRuntimeConfig();
9
+ const log = createLogger({
10
+ verbose: getVerboseFlag(config),
11
+ prefix: "[bcn:auth]"
12
+ });
18
13
  log("useConvexAuth called", {
19
14
  hasToken: !!token.value,
20
15
  hasUser: !!user.value,
@@ -1,4 +1,5 @@
1
1
  import { ref, readonly, computed, onMounted, onUnmounted } from "vue";
2
+ import { createLogger, getVerboseFlag } from "../utils/logger.js";
2
3
  import { useConvex } from "./useConvex.js";
3
4
  const DEFAULT_STATE = {
4
5
  hasInflightRequests: false,
@@ -12,16 +13,12 @@ const DEFAULT_STATE = {
12
13
  };
13
14
  export function useConvexConnectionState(options) {
14
15
  const client = useConvex();
15
- const verbose = options?.verbose ?? false;
16
- const log = verbose ? (message, data) => {
17
- const prefix = "[useConvexConnectionState]: ";
18
- if (data !== void 0) {
19
- console.log(prefix + message, data);
20
- } else {
21
- console.log(prefix + message);
22
- }
23
- } : () => {
24
- };
16
+ const config = useRuntimeConfig();
17
+ const verbose = getVerboseFlag(config, options?.verbose);
18
+ const log = createLogger({
19
+ verbose,
20
+ prefix: "[bcn:useConvexConnectionState]"
21
+ });
25
22
  log("Initialized", { hasClient: !!client, isClient: import.meta.client });
26
23
  const state = ref({ ...DEFAULT_STATE });
27
24
  const isConnected = computed(() => state.value.isWebSocketConnected);
@@ -1,5 +1,5 @@
1
1
  import { ref, computed } from "vue";
2
- import { getFunctionName } from "../utils/convex-cache.js";
2
+ import { createMutationLogger, getVerboseFlag } from "../utils/logger.js";
3
3
  import { useConvex } from "./useConvex.js";
4
4
  export function updateQuery(options) {
5
5
  const { query, args, localQueryStore, updater } = options;
@@ -44,17 +44,9 @@ function argsMatch(queryArgs, filterArgs) {
44
44
  return true;
45
45
  }
46
46
  export function useConvexMutation(mutation, options) {
47
- const verbose = options?.verbose ?? false;
48
- const fnName = getFunctionName(mutation);
49
- const log = verbose ? (message, data2) => {
50
- const prefix = `[useConvexMutation] ${fnName}: `;
51
- if (data2 !== void 0) {
52
- console.log(prefix + message, data2);
53
- } else {
54
- console.log(prefix + message);
55
- }
56
- } : () => {
57
- };
47
+ const config = useRuntimeConfig();
48
+ const verbose = getVerboseFlag(config, options?.verbose);
49
+ const log = createMutationLogger(verbose, "useConvexMutation", mutation);
58
50
  log("Initialized", { hasOptimisticUpdate: !!options?.optimisticUpdate });
59
51
  const _status = ref("idle");
60
52
  const error = ref(null);
@@ -11,6 +11,7 @@ import {
11
11
  triggerRef
12
12
  } from "vue";
13
13
  import { getFunctionName, stableStringify, getQueryKey } from "../utils/convex-cache.js";
14
+ import { getVerboseFlag } from "../utils/logger.js";
14
15
  import {
15
16
  createQueryLogger,
16
17
  fetchAuthToken,
@@ -33,7 +34,7 @@ export function useConvexPaginatedQuery(query, args, options) {
33
34
  const lazy = options?.lazy ?? false;
34
35
  const subscribe = options?.subscribe ?? true;
35
36
  const isPublic = options?.public ?? false;
36
- const verbose = options?.verbose ?? false;
37
+ const verbose = getVerboseFlag(config, options?.verbose);
37
38
  const fnName = getFunctionName(query);
38
39
  const log = createQueryLogger(verbose, "useConvexPaginatedQuery", query);
39
40
  log("Initializing", { initialNumItems, server, lazy, subscribe, public: isPublic });
@@ -23,6 +23,7 @@ import {
23
23
  removeFromSubscriptionCache,
24
24
  buildThenableResult
25
25
  } from "../utils/query-helpers.js";
26
+ import { getVerboseFlag } from "../utils/logger.js";
26
27
  export { parseConvexResponse, computeQueryStatus };
27
28
  export async function executeQueryHttp(convexUrl, functionPath, args, authToken) {
28
29
  const headers = {
@@ -59,7 +60,7 @@ export function useConvexQuery(query, args, options) {
59
60
  const lazy = options?.lazy ?? false;
60
61
  const server = options?.server ?? true;
61
62
  const subscribe = options?.subscribe ?? true;
62
- const verbose = options?.verbose ?? false;
63
+ const verbose = getVerboseFlag(config, options?.verbose);
63
64
  const isPublic = options?.public ?? false;
64
65
  const fnName = getFunctionName(query);
65
66
  const log = createQueryLogger(verbose, "useConvexQuery", query);
@@ -2,24 +2,19 @@ import { defineNuxtPlugin, useRuntimeConfig, useState } from "#app";
2
2
  import { convexClient } from "@convex-dev/better-auth/client/plugins";
3
3
  import { createAuthClient } from "better-auth/vue";
4
4
  import { ConvexClient } from "convex/browser";
5
- const log = (message, data) => {
6
- if (import.meta.dev) {
7
- const prefix = "[bcn:client] ";
8
- if (data !== void 0) {
9
- console.log(prefix + message, data);
10
- } else {
11
- console.log(prefix + message);
12
- }
13
- }
14
- };
5
+ import { createLogger, getVerboseFlag } from "./utils/logger.js";
15
6
  export default defineNuxtPlugin((nuxtApp) => {
7
+ const config = useRuntimeConfig();
8
+ const log = createLogger({
9
+ verbose: getVerboseFlag(config),
10
+ prefix: "[bcn:client]"
11
+ });
16
12
  log("Plugin starting");
17
13
  if (nuxtApp._convexInitialized) {
18
14
  log("Already initialized (HMR), skipping");
19
15
  return;
20
16
  }
21
17
  nuxtApp._convexInitialized = true;
22
- const config = useRuntimeConfig();
23
18
  const convexUrl = config.public.convex?.url;
24
19
  const siteUrl = config.public.convex?.siteUrl || config.public.convex?.auth?.url || (convexUrl?.replace(".convex.cloud", ".convex.site") ?? "");
25
20
  log("Config loaded", { convexUrl, siteUrl });
@@ -1,22 +1,17 @@
1
1
  import { defineNuxtPlugin, useState, useRuntimeConfig, useRequestEvent } from "#app";
2
- const log = (message, data) => {
3
- if (import.meta.dev) {
4
- const prefix = "[bcn:ssr] ";
5
- if (data !== void 0) {
6
- console.log(prefix + message, data);
7
- } else {
8
- console.log(prefix + message);
9
- }
10
- }
11
- };
2
+ import { createLogger, getVerboseFlag } from "./utils/logger.js";
12
3
  export default defineNuxtPlugin(async () => {
4
+ const config = useRuntimeConfig();
5
+ const log = createLogger({
6
+ verbose: getVerboseFlag(config),
7
+ prefix: "[bcn:ssr]"
8
+ });
13
9
  log("Plugin starting");
14
10
  const event = useRequestEvent();
15
11
  if (!event) {
16
12
  log("No request event available, skipping");
17
13
  return;
18
14
  }
19
- const config = useRuntimeConfig();
20
15
  const siteUrl = config.public.convex?.siteUrl || config.public.convex?.auth?.url;
21
16
  if (!siteUrl) {
22
17
  log("No siteUrl configured, skipping auth");
@@ -1,16 +1,15 @@
1
+ import { useRuntimeConfig } from "nitropack/runtime";
1
2
  import { parseConvexResponse, getFunctionName } from "../../utils/convex-cache.js";
3
+ import { createLogger, getVerboseFlag } from "../../utils/logger.js";
2
4
  export async function fetchQuery(convexUrl, query, args, options) {
3
5
  const functionPath = getFunctionName(query);
4
- const verbose = options?.verbose ?? false;
5
- const log = verbose ? (message, data) => {
6
- const prefix = `[fetchQuery] ${functionPath}: `;
7
- if (data !== void 0) {
8
- console.log(prefix + message, data);
9
- } else {
10
- console.log(prefix + message);
11
- }
12
- } : () => {
13
- };
6
+ const config = useRuntimeConfig();
7
+ const verbose = getVerboseFlag(config, options?.verbose);
8
+ const log = createLogger({
9
+ verbose,
10
+ prefix: "[bcn:fetchQuery]",
11
+ functionName: functionPath
12
+ });
14
13
  log("Starting", { args, hasAuth: !!options?.authToken });
15
14
  const headers = {
16
15
  "Content-Type": "application/json"
@@ -37,16 +36,13 @@ export async function fetchQuery(convexUrl, query, args, options) {
37
36
  }
38
37
  export async function fetchMutation(convexUrl, mutation, args, options) {
39
38
  const functionPath = getFunctionName(mutation);
40
- const verbose = options?.verbose ?? false;
41
- const log = verbose ? (message, data) => {
42
- const prefix = `[fetchMutation] ${functionPath}: `;
43
- if (data !== void 0) {
44
- console.log(prefix + message, data);
45
- } else {
46
- console.log(prefix + message);
47
- }
48
- } : () => {
49
- };
39
+ const config = useRuntimeConfig();
40
+ const verbose = getVerboseFlag(config, options?.verbose);
41
+ const log = createLogger({
42
+ verbose,
43
+ prefix: "[bcn:fetchMutation]",
44
+ functionName: functionPath
45
+ });
50
46
  log("Starting", { args, hasAuth: !!options?.authToken });
51
47
  const headers = {
52
48
  "Content-Type": "application/json"
@@ -73,16 +69,13 @@ export async function fetchMutation(convexUrl, mutation, args, options) {
73
69
  }
74
70
  export async function fetchAction(convexUrl, action, args, options) {
75
71
  const functionPath = getFunctionName(action);
76
- const verbose = options?.verbose ?? false;
77
- const log = verbose ? (message, data) => {
78
- const prefix = `[fetchAction] ${functionPath}: `;
79
- if (data !== void 0) {
80
- console.log(prefix + message, data);
81
- } else {
82
- console.log(prefix + message);
83
- }
84
- } : () => {
85
- };
72
+ const config = useRuntimeConfig();
73
+ const verbose = getVerboseFlag(config, options?.verbose);
74
+ const log = createLogger({
75
+ verbose,
76
+ prefix: "[bcn:fetchAction]",
77
+ functionName: functionPath
78
+ });
86
79
  log("Starting", { args, hasAuth: !!options?.authToken });
87
80
  const headers = {
88
81
  "Content-Type": "application/json"
@@ -10,6 +10,23 @@ declare module '#app' {
10
10
  /** Internal cache for WebSocket subscriptions (prevents duplicates) */
11
11
  _convexSubscriptions?: Record<string, () => void>
12
12
  }
13
+
14
+ interface RuntimeConfig {
15
+ public: {
16
+ convex: {
17
+ /** Convex deployment URL (WebSocket) */
18
+ url: string
19
+ /** Convex site URL (HTTP/Auth) */
20
+ siteUrl: string
21
+ /** Enable verbose logging for debugging */
22
+ verbose: boolean
23
+ /** @deprecated Use siteUrl instead */
24
+ auth?: {
25
+ url: string
26
+ }
27
+ }
28
+ }
29
+ }
13
30
  }
14
31
 
15
32
  declare module 'vue' {
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Shared logging utilities for better-convex-nuxt
3
+ *
4
+ * Provides consistent logging patterns across all composables, plugins, and utilities.
5
+ * Logs are prefixed with context information and can be enabled/disabled via config.
6
+ */
7
+ import type { FunctionReference } from 'convex/server';
8
+ /**
9
+ * Logger function type for debug logging
10
+ */
11
+ export type Logger = (message: string, data?: unknown) => void;
12
+ /**
13
+ * Options for creating a logger
14
+ */
15
+ export interface LoggerOptions {
16
+ /** Whether logging is enabled */
17
+ verbose: boolean;
18
+ /** Prefix for log messages (e.g., '[bcn:auth]', '[useConvexQuery]') */
19
+ prefix: string;
20
+ /** Optional function name to include in prefix (for query/mutation/action loggers) */
21
+ functionName?: string;
22
+ /** Optional function reference to extract name from */
23
+ functionRef?: FunctionReference<'query' | 'mutation' | 'action'>;
24
+ }
25
+ /**
26
+ * Create a logger function with consistent formatting.
27
+ *
28
+ * @param options - Logger configuration options
29
+ * @returns Logger function that logs with prefix and environment info, or no-op if verbose is false
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * // Simple logger
34
+ * const log = createLogger({
35
+ * verbose: config.public.convex?.verbose ?? false,
36
+ * prefix: '[bcn:auth]',
37
+ * })
38
+ * log('User authenticated', { userId: '123' })
39
+ *
40
+ * // Function logger (for queries/mutations)
41
+ * const log = createLogger({
42
+ * verbose: true,
43
+ * prefix: '[bcn:useConvexQuery]',
44
+ * functionRef: api.tasks.list,
45
+ * })
46
+ * log('Fetching tasks', { status: 'active' })
47
+ * ```
48
+ */
49
+ export declare function createLogger(options: LoggerOptions): Logger;
50
+ /**
51
+ * Create a logger for query composables.
52
+ * This is a convenience wrapper around createLogger with query-specific defaults.
53
+ *
54
+ * @param verbose - Whether logging is enabled
55
+ * @param composableName - Name of the composable (e.g., 'useConvexQuery')
56
+ * @param query - The Convex query function reference
57
+ * @returns Logger function
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * const log = createQueryLogger(verbose, 'useConvexQuery', api.tasks.list)
62
+ * // Logs will have prefix: [bcn:useConvexQuery] [SSR] tasks:list: ...
63
+ * log('Initializing', { lazy, server })
64
+ * ```
65
+ */
66
+ export declare function createQueryLogger(verbose: boolean, composableName: string, query: FunctionReference<'query'>): Logger;
67
+ /**
68
+ * Create a logger for mutation composables.
69
+ *
70
+ * @param verbose - Whether logging is enabled
71
+ * @param composableName - Name of the composable (e.g., 'useConvexMutation')
72
+ * @param mutation - The Convex mutation function reference
73
+ * @returns Logger function
74
+ */
75
+ export declare function createMutationLogger(verbose: boolean, composableName: string, mutation: FunctionReference<'mutation'>): Logger;
76
+ /**
77
+ * Create a logger for action composables.
78
+ *
79
+ * @param verbose - Whether logging is enabled
80
+ * @param composableName - Name of the composable (e.g., 'useConvexAction')
81
+ * @param action - The Convex action function reference
82
+ * @returns Logger function
83
+ */
84
+ export declare function createActionLogger(verbose: boolean, composableName: string, action: FunctionReference<'action'>): Logger;
85
+ /**
86
+ * Get verbose flag from runtime config with fallback.
87
+ * This is a convenience function to avoid repeating the same pattern.
88
+ *
89
+ * @param config - Runtime config from useRuntimeConfig()
90
+ * @param config.public - Public runtime config
91
+ * @param config.public.convex - Convex-specific public config
92
+ * @param config.public.convex.verbose - Verbose logging flag
93
+ * @param override - Optional override value (from options)
94
+ * @returns Whether verbose logging is enabled
95
+ */
96
+ export declare function getVerboseFlag(config: {
97
+ public?: {
98
+ convex?: {
99
+ verbose?: boolean;
100
+ };
101
+ };
102
+ }, override?: boolean): boolean;
@@ -0,0 +1,49 @@
1
+ import { getFunctionName } from "./convex-cache.js";
2
+ export function createLogger(options) {
3
+ if (!options.verbose) {
4
+ return () => {
5
+ };
6
+ }
7
+ let fnName = options.functionName;
8
+ if (!fnName && options.functionRef) {
9
+ try {
10
+ fnName = getFunctionName(options.functionRef);
11
+ } catch {
12
+ fnName = "unknown";
13
+ }
14
+ }
15
+ const env = import.meta.server ? "[SSR]" : "[Client]";
16
+ const basePrefix = options.prefix;
17
+ const fullPrefix = fnName ? `${basePrefix} ${env} ${fnName}: ` : `${basePrefix} ${env} `;
18
+ return (message, data) => {
19
+ if (data !== void 0) {
20
+ console.log(fullPrefix + message, data);
21
+ } else {
22
+ console.log(fullPrefix + message);
23
+ }
24
+ };
25
+ }
26
+ export function createQueryLogger(verbose, composableName, query) {
27
+ return createLogger({
28
+ verbose,
29
+ prefix: `[bcn:${composableName}]`,
30
+ functionRef: query
31
+ });
32
+ }
33
+ export function createMutationLogger(verbose, composableName, mutation) {
34
+ return createLogger({
35
+ verbose,
36
+ prefix: `[bcn:${composableName}]`,
37
+ functionRef: mutation
38
+ });
39
+ }
40
+ export function createActionLogger(verbose, composableName, action) {
41
+ return createLogger({
42
+ verbose,
43
+ prefix: `[bcn:${composableName}]`,
44
+ functionRef: action
45
+ });
46
+ }
47
+ export function getVerboseFlag(config, override) {
48
+ return override ?? (config.public?.convex?.verbose ?? false);
49
+ }
@@ -1,33 +1,16 @@
1
1
  import type { useNuxtApp } from '#imports';
2
- import type { FunctionReference } from 'convex/server';
2
+ import { createQueryLogger, type Logger } from './logger.js';
3
+ export type QueryLogger = Logger;
4
+ export { createQueryLogger };
3
5
  type NuxtApp = ReturnType<typeof useNuxtApp>;
4
6
  /**
5
7
  * Shared utilities for useConvexQuery and useConvexPaginatedQuery.
6
8
  * Extracted to reduce code duplication between the two composables.
7
9
  */
8
- /**
9
- * Logger function type for debug logging
10
- */
11
- export type QueryLogger = (message: string, data?: unknown) => void;
12
10
  /**
13
11
  * Subscription cache stored on NuxtApp
14
12
  */
15
13
  export type SubscriptionCache = Record<string, (() => void) | undefined>;
16
- /**
17
- * Create a debug logger for query composables.
18
- *
19
- * @param verbose - Whether logging is enabled
20
- * @param composableName - Name of the composable (e.g., 'useConvexQuery')
21
- * @param query - The Convex query function reference
22
- * @returns Logger function that logs with environment prefix
23
- *
24
- * @example
25
- * ```ts
26
- * const log = createQueryLogger(options?.verbose ?? false, 'useConvexQuery', query)
27
- * log('Initializing', { lazy, server })
28
- * ```
29
- */
30
- export declare function createQueryLogger(verbose: boolean, composableName: string, query: FunctionReference<'query'>): QueryLogger;
31
14
  export interface FetchAuthTokenOptions {
32
15
  /** Whether this is a public query (skip auth) */
33
16
  isPublic: boolean;
@@ -133,4 +116,3 @@ export declare function removeFromSubscriptionCache(nuxtApp: NuxtApp, cacheKey:
133
116
  * ```
134
117
  */
135
118
  export declare function buildThenableResult<T extends object>(resolvePromise: Promise<void>, resultData: T): T & Promise<T>;
136
- export {};
@@ -1,26 +1,6 @@
1
1
  import { useState } from "#imports";
2
- import { getFunctionName } from "./convex-cache.js";
3
- export function createQueryLogger(verbose, composableName, query) {
4
- if (!verbose) {
5
- return () => {
6
- };
7
- }
8
- let fnName;
9
- try {
10
- fnName = getFunctionName(query);
11
- } catch {
12
- fnName = "unknown";
13
- }
14
- return (message, data) => {
15
- const env = import.meta.server ? "[SSR]" : "[Client]";
16
- const prefix = `[${composableName}] ${env} ${fnName}: `;
17
- if (data !== void 0) {
18
- console.log(prefix + message, data);
19
- } else {
20
- console.log(prefix + message);
21
- }
22
- };
23
- }
2
+ import { createQueryLogger } from "./logger.js";
3
+ export { createQueryLogger };
24
4
  export async function fetchAuthToken(options) {
25
5
  const { isPublic, cookieHeader, siteUrl, log } = options;
26
6
  if (isPublic) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "better-convex-nuxt",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "Full-featured Convex integration for Nuxt with SSR, real-time subscriptions, authentication, and permissions",
5
5
  "keywords": [
6
6
  "authentication",