nuxt-convex-module 0.12.3 → 0.14.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 (45) hide show
  1. package/dist/devtools-client/_nuxt/C-J9qZjr.js +3 -0
  2. package/dist/devtools-client/_nuxt/CB1p6iYX.js +1 -0
  3. package/dist/devtools-client/_nuxt/{COXexnyN.js → CtC_CmOY.js} +2 -2
  4. package/dist/devtools-client/_nuxt/{entry.DsZySRVW.css → entry.jOWrhpYd.css} +1 -1
  5. package/dist/devtools-client/index.html +1 -1
  6. package/dist/module.d.mts +18 -0
  7. package/dist/module.json +1 -1
  8. package/dist/module.mjs +129 -38
  9. package/dist/runtime/better-auth/nuxt/middleware.js +8 -2
  10. package/dist/runtime/better-auth/nuxt/no-session-vary.d.ts +38 -0
  11. package/dist/runtime/better-auth/nuxt/no-session-vary.js +21 -0
  12. package/dist/runtime/better-auth/nuxt/server.js +4 -1
  13. package/dist/runtime/better-auth/nuxt/shared-render.d.ts +9 -0
  14. package/dist/runtime/better-auth/nuxt/shared-render.js +17 -0
  15. package/dist/runtime/better-auth/vue/auth-client-loader.d.ts +17 -0
  16. package/dist/runtime/better-auth/vue/auth-client-loader.js +186 -0
  17. package/dist/runtime/better-auth/vue/client.d.ts +3 -3
  18. package/dist/runtime/better-auth/vue/cross-domain.d.ts +26 -0
  19. package/dist/runtime/better-auth/vue/cross-domain.js +52 -35
  20. package/dist/runtime/better-auth/vue/index.d.ts +2 -1
  21. package/dist/runtime/better-auth/vue/index.js +1 -0
  22. package/dist/runtime/better-auth/vue/plugin.client.js +21 -2
  23. package/dist/runtime/better-auth/vue/plugin.server.js +23 -3
  24. package/dist/runtime/better-auth/vue/token-store.js +25 -1
  25. package/dist/runtime/better-auth/vue/use-better-auth.d.ts +11 -5
  26. package/dist/runtime/better-auth/vue/use-better-auth.js +135 -32
  27. package/dist/runtime/nuxt/composables/use-async-paginated-query.d.ts +1 -1
  28. package/dist/runtime/nuxt/composables/use-async-paginated-query.js +5 -3
  29. package/dist/runtime/nuxt/composables/use-async-query.d.ts +4 -1
  30. package/dist/runtime/nuxt/composables/use-async-query.js +6 -3
  31. package/dist/runtime/nuxt/csp.d.ts +2 -1
  32. package/dist/runtime/nuxt/csp.js +9 -3
  33. package/dist/runtime/nuxt/function-name.d.ts +9 -0
  34. package/dist/runtime/nuxt/function-name.js +38 -0
  35. package/dist/runtime/nuxt/index.js +4 -3
  36. package/dist/runtime/nuxt/testing.d.ts +21 -0
  37. package/dist/runtime/nuxt/testing.js +1 -0
  38. package/dist/runtime/vue/auth/index.d.ts +2 -1
  39. package/dist/runtime/vue/auth/index.js +62 -13
  40. package/dist/runtime/vue/composables/use-upload-queue.d.ts +70 -3
  41. package/dist/runtime/vue/composables/use-upload-queue.js +74 -19
  42. package/dist/runtime/vue/index.d.ts +1 -1
  43. package/package.json +19 -12
  44. package/dist/devtools-client/_nuxt/AqohFEu1.js +0 -1
  45. package/dist/devtools-client/_nuxt/BPtiIkWa.js +0 -3
@@ -1 +1 @@
1
- <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><script type="importmap">{"imports":{"#entry":"/__nuxt-convex-module/_nuxt/COXexnyN.js"}}</script><link rel="stylesheet" href="/__nuxt-convex-module/_nuxt/entry.DsZySRVW.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__nuxt-convex-module/_nuxt/COXexnyN.js"><script type="module" src="/__nuxt-convex-module/_nuxt/COXexnyN.js" crossorigin></script><link rel="prefetch" as="script" crossorigin href="/__nuxt-convex-module/_nuxt/BPtiIkWa.js"></head><body><div id="__nuxt"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-convex-module",buildId:"bfa6df52-caf6-46de-a611-bdf9d975bd3f",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1793468157767,false]</script></body></html>
1
+ <!DOCTYPE html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><script type="importmap">{"imports":{"#entry":"/__nuxt-convex-module/_nuxt/CtC_CmOY.js"}}</script><link rel="stylesheet" href="/__nuxt-convex-module/_nuxt/entry.jOWrhpYd.css" crossorigin><link rel="modulepreload" as="script" crossorigin href="/__nuxt-convex-module/_nuxt/CtC_CmOY.js"><script type="module" src="/__nuxt-convex-module/_nuxt/CtC_CmOY.js" crossorigin></script><link rel="prefetch" as="script" crossorigin href="/__nuxt-convex-module/_nuxt/C-J9qZjr.js"></head><body><div id="__nuxt"></div><div id="teleports"></div><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-convex-module",buildId:"168fd639-55a2-4ae2-9c90-a285b0720204",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="application/json" data-nuxt-data="nuxt-app" data-ssr="false" id="__NUXT_DATA__">[{"prerenderedAt":1,"serverRendered":2},1794180177669,false]</script></body></html>
package/dist/module.d.mts CHANGED
@@ -2,6 +2,8 @@ import * as _nuxt_schema from '@nuxt/schema';
2
2
 
3
3
  /** The `convex.autoImports` option: every name, every name prefixed with `Convex`, or none. */
4
4
  type AutoImports = boolean | 'prefixed';
5
+ /** The `convex.exclude` option: registered names to skip, each exact or a pattern. */
6
+ type ExcludedNames = ReadonlyArray<string | RegExp>;
5
7
 
6
8
  /**
7
9
  * Configuration for the opt-in Better Auth integration.
@@ -108,6 +110,20 @@ interface ModuleOptions {
108
110
  * the subpath exports. `false` auto-imports nothing.
109
111
  */
110
112
  autoImports?: AutoImports;
113
+ /**
114
+ * Names to leave unregistered, matched against the name the app would see
115
+ * (after `prefixed` renames it): app auto-imports, Nitro auto-imports,
116
+ * components and the `convex-auth` route middleware. A string matches one
117
+ * name exactly, a `RegExp` every name it matches. Everything stays
118
+ * importable from the subpath exports. Meant for a module that builds on
119
+ * this one and registers names of its own for the same things.
120
+ *
121
+ * @example
122
+ * ```ts
123
+ * convex: { exclude: [/^useConvex/, 'ConvexImage', 'convex-auth'] }
124
+ * ```
125
+ */
126
+ exclude?: ExcludedNames;
111
127
  /**
112
128
  * Convex panel in Nuxt DevTools (dev only): connection state, live query
113
129
  * subscriptions, auth state, and client logs. Enabled by default whenever
@@ -134,6 +150,8 @@ declare module '@nuxt/schema' {
134
150
  crossDomainCallbackRoute: string;
135
151
  loginPath: string;
136
152
  authRoute: string;
153
+ /** Whether the browser may hold the Better Auth client back (PARITY D-18): only where the registration transform runs, on Vite. */
154
+ deferAuthClient: boolean;
137
155
  };
138
156
  }
139
157
  }
package/dist/module.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "compatibility": {
6
6
  "nuxt": ">=4.6.0"
7
7
  },
8
- "version": "0.12.3",
8
+ "version": "0.14.0",
9
9
  "builder": {
10
10
  "@nuxt/module-builder": "1.0.3",
11
11
  "unbuild": "unknown"
package/dist/module.mjs CHANGED
@@ -1,7 +1,7 @@
1
- import { useLogger, defineNuxtModule, createResolver, addPlugin, hasNuxtModule, addNitroPlugin, addTypeTemplate, addImports, addServerImports, addComponent, addServerHandler, extendRouteRules, addRouteMiddleware } from '@nuxt/kit';
2
- import { dirname, join, isAbsolute, basename } from 'node:path';
1
+ import { useLogger, addVitePlugin, resolvePath, defineNuxtModule, createResolver, addPlugin, hasNuxtModule, addNitroPlugin, addTypeTemplate, addImports, addServerImports, addComponent, addServerHandler, extendRouteRules, addRouteMiddleware } from '@nuxt/kit';
2
+ import path, { dirname, join, isAbsolute, basename } from 'node:path';
3
3
  import { detectAgent } from 'std-env';
4
- import { existsSync, readFileSync, statSync, writeFileSync } from 'node:fs';
4
+ import { existsSync, readFileSync, statSync, realpathSync, writeFileSync } from 'node:fs';
5
5
  import { fileURLToPath } from 'node:url';
6
6
  import { parseEnv } from 'node:util';
7
7
 
@@ -95,7 +95,7 @@ function integrationWarnings(flags, isInstalled) {
95
95
  }
96
96
  if (flags.polar && !isInstalled("@polar-sh/checkout")) {
97
97
  warnings.push(
98
- "`@convex-dev/polar` is installed but its peer `@polar-sh/checkout` is not \u2014 `<CheckoutLink>` imports it and the build fails the moment the component is used. Run `npm install @polar-sh/checkout@~0.4.0`."
98
+ "`@convex-dev/polar` is installed but its peer `@polar-sh/checkout` is not \u2014 `<CheckoutLink>` imports it and the build fails the moment the component is used. Run `npm install @polar-sh/checkout@~0.6.0`."
99
99
  );
100
100
  }
101
101
  return warnings;
@@ -206,6 +206,71 @@ function getConvexAliases(rootDir) {
206
206
  };
207
207
  }
208
208
 
209
+ const SCRIPT_EXTENSION = /\.(?:[cm]?[jt]sx?|vue)$/;
210
+ const posix = (file) => file.replaceAll("\\", "/");
211
+ function sameModule(file, target) {
212
+ if (SCRIPT_EXTENSION.test(target)) return posix(file) === posix(target);
213
+ return posix(file).replace(SCRIPT_EXTENSION, "") === posix(target);
214
+ }
215
+ function manifestKeyMatches(key, root, target, paths = path) {
216
+ return sameModule(key, paths.relative(root, target));
217
+ }
218
+ function real(file) {
219
+ try {
220
+ return realpathSync(file);
221
+ } catch {
222
+ return file;
223
+ }
224
+ }
225
+ function authClientFiles(nuxt) {
226
+ let files;
227
+ return () => files ??= (async () => {
228
+ const target = nuxt.options.alias["#convex/auth-client"];
229
+ if (!target) return [];
230
+ const resolved = await resolvePath(target, { fallbackToOriginal: true });
231
+ return [...new Set(resolved === target ? [target, real(target)] : [resolved, real(resolved)])];
232
+ })();
233
+ }
234
+ function authClientRegistration(file, loader) {
235
+ return [
236
+ "",
237
+ "// nuxt-convex-module (PARITY D-18): tell the loader this client has evaluated.",
238
+ `import { registerEvaluatedAuthClient as __convexRegisterAuthClient } from ${JSON.stringify(loader)}`,
239
+ `import * as __convexAuthClientModule from ${JSON.stringify(`./${basename(file)}`)}`,
240
+ "__convexRegisterAuthClient(__convexAuthClientModule.authClient)",
241
+ ""
242
+ ].join("\n");
243
+ }
244
+ function registerAuthClientOnEvaluation(resolver, nuxt) {
245
+ const loader = resolver.resolve("./runtime/better-auth/vue/auth-client-loader");
246
+ const files = authClientFiles(nuxt);
247
+ addVitePlugin({
248
+ name: "nuxt-convex-module:auth-client-registration",
249
+ async transform(code, id, transformOptions) {
250
+ if (transformOptions?.ssr) return;
251
+ const file = id.split("?")[0];
252
+ if (!(await files()).some((target) => sameModule(file, target))) return;
253
+ return { code: code + authClientRegistration(file, loader), map: null };
254
+ }
255
+ }, { server: false });
256
+ }
257
+ function keepAuthClientOffPrefetch(nuxt) {
258
+ const files = authClientFiles(nuxt);
259
+ nuxt.hook("build:manifest", async (manifest) => {
260
+ const targets = await files();
261
+ if (targets.length === 0) return;
262
+ const root = nuxt.options.vite?.root ?? nuxt.options.srcDir;
263
+ const roots = [.../* @__PURE__ */ new Set([root, real(root)])];
264
+ const isAuthClient = (key) => roots.some((base) => targets.some((target) => manifestKeyMatches(manifest[key]?.src ?? key, base, target)));
265
+ const keys = new Set(Object.keys(manifest).filter(isAuthClient));
266
+ if (keys.size === 0) return;
267
+ for (const chunk of Object.values(manifest)) {
268
+ chunk.dynamicImports &&= chunk.dynamicImports.filter((key) => !keys.has(key));
269
+ }
270
+ for (const key of keys) manifest[key].prefetch = false;
271
+ });
272
+ }
273
+
209
274
  function watchConvexCodegen(nuxt) {
210
275
  if (!nuxt.options.dev) return;
211
276
  const generatedDir = join(nuxt.options.rootDir, resolveFunctionsDir(nuxt.options.rootDir), "_generated");
@@ -253,6 +318,17 @@ function autoImportedAs(name, mode, registered) {
253
318
  const prefixed = prefixedName(name);
254
319
  return prefixed !== name && registered.includes(prefixed) ? void 0 : prefixed;
255
320
  }
321
+ function isExcluded(name, exclude) {
322
+ return exclude.some((rule) => {
323
+ if (typeof rule === "string") return rule === name;
324
+ rule.lastIndex = 0;
325
+ return rule.test(name);
326
+ });
327
+ }
328
+ function registeredAs(name, policy, registered) {
329
+ const as = autoImportedAs(name, policy.autoImports, registered);
330
+ return as === void 0 || isExcluded(as, policy.exclude) ? void 0 : as;
331
+ }
256
332
  const vue = (file) => `runtime/vue/${file}`;
257
333
  const composable = (file) => vue(`composables/${file}`);
258
334
  const asyncQuery = "runtime/nuxt/composables/use-async-query";
@@ -300,6 +376,7 @@ const APP_IMPORTS = {
300
376
  ],
301
377
  betterAuth: [
302
378
  { name: "useBetterAuth", from: "runtime/better-auth/vue/use-better-auth" },
379
+ { name: "loadAuthClient", from: "runtime/better-auth/vue/auth-client-loader" },
303
380
  { name: "usePreloadedAuthQuery", from: "runtime/better-auth/vue/hydration" },
304
381
  { name: "resolveAuthRedirect", from: "runtime/better-auth/vue/redirect" }
305
382
  ],
@@ -383,7 +460,7 @@ const module$1 = defineNuxtModule({
383
460
  // with no extra entry on the consumer's side. The Convex-aware CSP is applied
384
461
  // at runtime (see `registerSecurity`), so module order is irrelevant. Nothing
385
462
  // is declared otherwise: kit fails the build resolving an absent package.
386
- moduleDependencies: (nuxt) => resolveSecurityState(nuxt, readSecurityOption(nuxt)).enabled ? { "nuxt-security": {} } : {},
463
+ moduleDependencies: (nuxt) => resolveSecurityState(nuxt, readSecurityOption(nuxt)).enabled ? { "nuxt-security": nuxt.options.dev ? { defaults: DEV_SECURITY_DEFAULTS } : {} } : {},
387
464
  async setup(options, nuxt) {
388
465
  const resolver = createResolver(import.meta.url);
389
466
  nuxt.options.build.transpile.push(resolver.resolve("./runtime"));
@@ -403,13 +480,16 @@ const module$1 = defineNuxtModule({
403
480
  for (const message of diagnostics.warnings) logger.warn(message);
404
481
  nuxt.options.runtimeConfig.public.convex.loginPath = diagnostics.loginPath;
405
482
  nuxt.options.runtimeConfig.public.convex.authRoute = diagnostics.authRoute;
483
+ nuxt.options.runtimeConfig.public.convex.deferAuthClient = nuxt.options.builder === "@nuxt/vite-builder";
406
484
  registerAuthClientAlias(resolver, nuxt, options);
485
+ keepAuthClientOffPrefetch(nuxt);
486
+ registerAuthClientOnEvaluation(resolver, nuxt);
407
487
  registerConvexAliases(nuxt);
408
488
  registerConvexTypeFallback(nuxt);
409
- const autoImports = options.autoImports ?? true;
410
- registerVueComposables(resolver, autoImports);
411
- registerAuthComponents(resolver, autoImports);
412
- const integrations = registerIntegrations(resolver, nuxt, options, autoImports, diagnostics.authRoute);
489
+ const policy = { autoImports: options.autoImports ?? true, exclude: options.exclude ?? [] };
490
+ registerVueComposables(resolver, policy);
491
+ registerAuthComponents(resolver, policy);
492
+ const integrations = registerIntegrations(resolver, nuxt, options, policy, diagnostics.authRoute);
413
493
  watchConvexCodegen(nuxt);
414
494
  if (nuxt.options.dev && options.devtools !== false && isDevtoolsUiEnabled(nuxt)) {
415
495
  const { setupDevtools } = await import('./chunks/index.mjs');
@@ -444,7 +524,7 @@ function isDevtoolsUiEnabled(nuxt) {
444
524
  const devtools = nuxt.options.devtools;
445
525
  return typeof devtools === "boolean" ? devtools : devtools?.enabled !== false;
446
526
  }
447
- function registerIntegrations(resolver, nuxt, options, autoImports, authRoute) {
527
+ function registerIntegrations(resolver, nuxt, options, policy, authRoute) {
448
528
  const report = (key, pkg, state) => {
449
529
  if (state.missingPackage) {
450
530
  logger.error(`\`convex.${key}\` is enabled but \`${pkg}\` is not installed. Run \`npm install ${pkg}\` or remove the option.`);
@@ -455,21 +535,21 @@ function registerIntegrations(resolver, nuxt, options, autoImports, authRoute) {
455
535
  const resolve = (key, pkg) => report(key, pkg, resolveIntegrationState(options[key], isPackageInstalled(pkg, rootDir), isDeclaredDependency(pkg, rootDir)));
456
536
  const betterAuth = resolve("betterAuth", "@convex-dev/better-auth");
457
537
  if (betterAuth) {
458
- registerBetterAuth(resolver, authRoute, autoImports);
538
+ registerBetterAuth(resolver, authRoute, policy);
459
539
  } else {
460
540
  registerBaseConvexClient(resolver);
461
541
  }
462
542
  const clerk = resolve("clerk", "@clerk/vue");
463
543
  if (clerk) {
464
- registerClerk(resolver, autoImports);
544
+ registerClerk(resolver, policy);
465
545
  }
466
546
  const auth0 = resolve("auth0", "@auth0/auth0-vue");
467
547
  if (auth0) {
468
- registerAuth0(resolver, autoImports);
548
+ registerAuth0(resolver, policy);
469
549
  }
470
550
  const polar = resolve("polar", "@convex-dev/polar");
471
551
  if (polar) {
472
- registerPolarComponents(resolver, autoImports);
552
+ registerPolarComponents(resolver, policy);
473
553
  }
474
554
  const security = report("security", "nuxt-security", resolveSecurityState(nuxt, options.security));
475
555
  if (security) {
@@ -486,6 +566,13 @@ function registerIntegrations(resolver, nuxt, options, autoImports, authRoute) {
486
566
  }
487
567
  return flags;
488
568
  }
569
+ const DEV_SECURITY_DEFAULTS = {
570
+ rateLimiter: false,
571
+ headers: {
572
+ contentSecurityPolicy: { "upgrade-insecure-requests": false },
573
+ strictTransportSecurity: false
574
+ }
575
+ };
489
576
  function readSecurityOption(nuxt) {
490
577
  const opts = nuxt.options;
491
578
  return opts.convex?.security;
@@ -570,15 +657,15 @@ function registerConvexTypeFallback(nuxt) {
570
657
  dependsOn: (change) => change.path.replace(/\\/g, "/").includes("_generated/api")
571
658
  }, { nuxt: true, nitro: true });
572
659
  }
573
- function registerVueComposables(resolver, autoImports) {
574
- registerIntegrationImports(resolver, "core", autoImports);
660
+ function registerVueComposables(resolver, policy) {
661
+ registerIntegrationImports(resolver, "core", policy);
575
662
  }
576
- function registerAuthComponents(resolver, autoImports) {
577
- registerComponents(resolver, "core", autoImports);
663
+ function registerAuthComponents(resolver, policy) {
664
+ registerComponents(resolver, "core", policy);
578
665
  }
579
- function registerIntegrationImports(resolver, integration, autoImports) {
666
+ function registerIntegrationImports(resolver, integration, policy) {
580
667
  const kept = (entries) => entries.flatMap((entry) => {
581
- const as = autoImportedAs(entry.name, autoImports, entries.map((e) => e.name));
668
+ const as = registeredAs(entry.name, policy, entries.map((e) => e.name));
582
669
  return as ? [{ ...entry, as, from: resolver.resolve(`./${entry.from}`) }] : [];
583
670
  });
584
671
  const app = kept(APP_IMPORTS[integration]);
@@ -586,10 +673,10 @@ function registerIntegrationImports(resolver, integration, autoImports) {
586
673
  if (app.length > 0) addImports(app);
587
674
  if (server.length > 0) addServerImports(server);
588
675
  }
589
- function registerComponents(resolver, integration, autoImports) {
676
+ function registerComponents(resolver, integration, policy) {
590
677
  const entries = APP_COMPONENTS[integration];
591
678
  for (const { name, from } of entries) {
592
- const as = autoImportedAs(name, autoImports, entries.map((e) => e.name));
679
+ const as = registeredAs(name, policy, entries.map((e) => e.name));
593
680
  if (as) addComponent({ name: as, filePath: resolver.resolve(`./${from}`), export: name });
594
681
  }
595
682
  }
@@ -597,11 +684,13 @@ const AUTH_PROXY_SECURITY_RULES = {
597
684
  xssValidator: false,
598
685
  allowedMethodsRestricter: { methods: ["GET", "HEAD", "POST", "OPTIONS"] }
599
686
  };
600
- function registerBetterAuth(resolver, authRoute, autoImports) {
687
+ function registerBetterAuth(resolver, authRoute, policy) {
601
688
  addPlugin(resolver.resolve("./runtime/better-auth/vue/plugin.client"));
602
689
  addPlugin(resolver.resolve("./runtime/better-auth/vue/plugin.server"));
603
- registerIntegrationImports(resolver, "betterAuth", autoImports);
604
- registerComponents(resolver, "betterAuth", autoImports);
690
+ const noSessionVary = resolver.resolve("./runtime/better-auth/nuxt/no-session-vary");
691
+ addNitroPlugin({ nitro2: noSessionVary, nitro3: noSessionVary });
692
+ registerIntegrationImports(resolver, "betterAuth", policy);
693
+ registerComponents(resolver, "betterAuth", policy);
605
694
  addServerHandler({
606
695
  route: `${authRoute}/**`,
607
696
  handler: { nuxt: resolver.resolve("./runtime/better-auth/nuxt/proxy") }
@@ -611,25 +700,27 @@ function registerBetterAuth(resolver, authRoute, autoImports) {
611
700
  prerender: false,
612
701
  security: AUTH_PROXY_SECURITY_RULES
613
702
  });
614
- addRouteMiddleware({
615
- name: "convex-auth",
616
- path: resolver.resolve("./runtime/better-auth/nuxt/middleware"),
617
- global: false
618
- });
703
+ if (!isExcluded("convex-auth", policy.exclude)) {
704
+ addRouteMiddleware({
705
+ name: "convex-auth",
706
+ path: resolver.resolve("./runtime/better-auth/nuxt/middleware"),
707
+ global: false
708
+ });
709
+ }
619
710
  }
620
711
  function registerBaseConvexClient(resolver) {
621
712
  addPlugin(resolver.resolve("./runtime/vue/plugin"));
622
713
  }
623
- function registerClerk(resolver, autoImports) {
624
- registerIntegrationImports(resolver, "clerk", autoImports);
625
- registerComponents(resolver, "clerk", autoImports);
714
+ function registerClerk(resolver, policy) {
715
+ registerIntegrationImports(resolver, "clerk", policy);
716
+ registerComponents(resolver, "clerk", policy);
626
717
  }
627
- function registerAuth0(resolver, autoImports) {
628
- registerIntegrationImports(resolver, "auth0", autoImports);
629
- registerComponents(resolver, "auth0", autoImports);
718
+ function registerAuth0(resolver, policy) {
719
+ registerIntegrationImports(resolver, "auth0", policy);
720
+ registerComponents(resolver, "auth0", policy);
630
721
  }
631
- function registerPolarComponents(resolver, autoImports) {
632
- registerComponents(resolver, "polar", autoImports);
722
+ function registerPolarComponents(resolver, policy) {
723
+ registerComponents(resolver, "polar", policy);
633
724
  }
634
725
 
635
726
  export { module$1 as default };
@@ -1,6 +1,7 @@
1
1
  import { defineNuxtRouteMiddleware, navigateTo, useRuntimeConfig } from "#app";
2
2
  import { watch } from "vue";
3
- import { useBetterAuth } from "../vue/use-better-auth.js";
3
+ import { clientSessionSettled, useBetterAuth } from "../vue/use-better-auth.js";
4
+ import { loadedAuthClient } from "../vue/auth-client-loader.js";
4
5
  import { loginTarget, serverGuard } from "./server-guard.js";
5
6
  function waitForSession(isPending) {
6
7
  return new Promise((resolve) => {
@@ -21,7 +22,12 @@ export default defineNuxtRouteMiddleware(async (to) => {
21
22
  if (import.meta.server) {
22
23
  return serverGuard(to, loginPath);
23
24
  }
24
- const { session } = useBetterAuth();
25
+ const { session, isAuthenticated } = useBetterAuth();
26
+ await clientSessionSettled();
27
+ if (!loadedAuthClient()) {
28
+ if (!isAuthenticated.value && to.path !== loginPath) return navigateTo(loginTarget(to, loginPath));
29
+ return;
30
+ }
25
31
  if (session.value.isPending) {
26
32
  await waitForSession(() => session.value.isPending);
27
33
  }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * The slice of a response event this plugin reads and writes: Nitro 2's node
3
+ * response, or Nitro 3's web headers. Typed locally, so the published types
4
+ * don't depend on how the app resolves `nitropack`.
5
+ */
6
+ export interface NoSessionResponseEvent {
7
+ context: Record<string, unknown>;
8
+ node?: {
9
+ res?: {
10
+ getHeader?: (name: string) => unknown;
11
+ setHeader?: (name: string, value: string) => unknown;
12
+ };
13
+ };
14
+ res?: {
15
+ headers?: {
16
+ get: (name: string) => string | null;
17
+ set: (name: string, value: string) => void;
18
+ };
19
+ };
20
+ }
21
+ /** The Nitro app hook this plugin listens on. */
22
+ export interface NoSessionNitroApp {
23
+ hooks: {
24
+ hook: (name: 'beforeResponse', fn: (event: NoSessionResponseEvent) => void) => unknown;
25
+ };
26
+ }
27
+ /** `vary` with `Cookie` in it, keeping what it named already. */
28
+ export declare function withCookieVary(vary: unknown): string;
29
+ /**
30
+ * Nitro plugin: a response whose payload says the server saw no session, made
31
+ * cacheable after the page rendered (a `render:response` hook, a header set
32
+ * once the payload was written), varies on `Cookie`. The payload can no
33
+ * longer change by then; varying keeps a shared cache from handing that
34
+ * cookie-less render to a visitor whose request carries a session cookie.
35
+ * Runs on `beforeResponse`, after every `render:response` hook and the
36
+ * headers they set.
37
+ */
38
+ export default function noSessionVaryPlugin(nitroApp: NoSessionNitroApp): void;
@@ -0,0 +1,21 @@
1
+ import { CACHING_HEADERS, isSharedRender, NO_SESSION_CONTEXT_KEY } from "./shared-render.js";
2
+ function readHeader(event, name) {
3
+ return event.node?.res?.getHeader?.(name) ?? event.res?.headers?.get(name) ?? void 0;
4
+ }
5
+ function writeHeader(event, name, value) {
6
+ if (event.node?.res?.setHeader) event.node.res.setHeader(name, value);
7
+ else event.res?.headers?.set(name, value);
8
+ }
9
+ export function withCookieVary(vary) {
10
+ const names = (Array.isArray(vary) ? vary.join(",") : typeof vary === "string" ? vary : "").split(",").map((name) => name.trim()).filter(Boolean);
11
+ if (names.includes("*") || names.some((name) => name.toLowerCase() === "cookie")) return names.join(", ");
12
+ return [...names, "Cookie"].join(", ");
13
+ }
14
+ export default function noSessionVaryPlugin(nitroApp) {
15
+ nitroApp.hooks.hook("beforeResponse", (event) => {
16
+ if (event.context[NO_SESSION_CONTEXT_KEY] !== true) return;
17
+ const headers = Object.fromEntries(CACHING_HEADERS.map((name) => [name, readHeader(event, name)]));
18
+ if (!isSharedRender({ headers })) return;
19
+ writeHeader(event, "vary", withCookieVary(readHeader(event, "vary")));
20
+ });
21
+ }
@@ -1,6 +1,7 @@
1
1
  import { getToken } from "@convex-dev/better-auth/utils";
2
2
  import { getConvexRuntimeConfig } from "../../nuxt/config.js";
3
3
  import { fetchAction, fetchMutation, fetchQuery, preloadQuery } from "../../nuxt/index.js";
4
+ import { withoutFunctionName } from "../../nuxt/function-name.js";
4
5
  const parseConvexSiteUrl = (url) => {
5
6
  if (!url) {
6
7
  throw new Error(
@@ -44,6 +45,8 @@ const handler = async (request, siteUrl) => {
44
45
  headers.delete("connection");
45
46
  headers.set("accept-encoding", "application/json");
46
47
  headers.set("host", new URL(siteUrl).host);
48
+ headers.delete("x-forwarded-host");
49
+ headers.delete("x-forwarded-proto");
47
50
  headers.set("x-better-auth-forwarded-host", requestUrl.host);
48
51
  headers.set("x-better-auth-forwarded-proto", requestUrl.protocol.replace(/:$/, ""));
49
52
  const init = {
@@ -105,7 +108,7 @@ export function convexAuth(event, opts) {
105
108
  try {
106
109
  return await fn(token?.token);
107
110
  } catch (error) {
108
- if (!opts?.jwtCache?.enabled || token.isFresh || !opts.jwtCache.isAuthError(error)) {
111
+ if (!opts?.jwtCache?.enabled || token.isFresh || !withoutFunctionName(error, opts.jwtCache.isAuthError.bind(opts.jwtCache))) {
109
112
  throw error;
110
113
  }
111
114
  const newToken = await cachedGetToken({ forceRefresh: true });
@@ -0,0 +1,9 @@
1
+ /** The parts of a request event `isSharedRender` reads. */
2
+ export interface RenderContext {
3
+ /** Nitro's matched route rules (`event.context._nitro.routeRules`), `swr`/`isr` normalised into `cache`. */
4
+ routeRules?: Record<string, unknown>;
5
+ /** Set by Nitro's cached handler on the render it caches (`event.context.cache`). */
6
+ cache?: unknown;
7
+ /** The response's caching headers as the render sees them, by lower-case name. */
8
+ headers?: Record<string, unknown>;
9
+ }
@@ -0,0 +1,17 @@
1
+ export const NO_SESSION_CONTEXT_KEY = "convexNoSession";
2
+ export const CACHING_HEADERS = ["cache-control", "cdn-cache-control", "surrogate-control"];
3
+ function headerText(value) {
4
+ if (Array.isArray(value)) return value.join(",");
5
+ return typeof value === "string" || typeof value === "number" ? String(value) : "";
6
+ }
7
+ function storesForOthers(name, value) {
8
+ const directives = value.toLowerCase().split(",").map((directive) => directive.trim().split("=")[0]).filter(Boolean);
9
+ if (directives.length === 0 || directives.includes("private") || directives.includes("no-store")) return false;
10
+ if (name !== "cache-control") return true;
11
+ return directives.includes("public") || directives.includes("s-maxage") || directives.includes("max-age");
12
+ }
13
+ export function isSharedRender({ routeRules = {}, cache, headers = {} }) {
14
+ if (cache || routeRules.cache || routeRules.swr || routeRules.isr || routeRules.prerender || routeRules.payload) return true;
15
+ const ruleHeaders = Object.fromEntries(Object.entries(routeRules.headers ?? {}).map(([name, value]) => [name.toLowerCase(), value]));
16
+ return CACHING_HEADERS.some((name) => storesForOthers(name, headerText(headers[name])) || storesForOthers(name, headerText(ruleHeaders[name])));
17
+ }
@@ -0,0 +1,17 @@
1
+ import type { AuthClient } from '#convex/auth-client';
2
+ /**
3
+ * The app's Better Auth client (`#convex/auth-client`), loading it on the
4
+ * first call. Every call resolves to the same instance, the one a static
5
+ * `import { authClient } from 'nuxt-convex-module/better-auth/client'` holds.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * async function signOut() {
10
+ * const client = await loadAuthClient()
11
+ * await client.signOut()
12
+ * }
13
+ * ```
14
+ *
15
+ * @public
16
+ */
17
+ export declare function loadAuthClient(): Promise<AuthClient>;