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.
- package/dist/devtools-client/_nuxt/C-J9qZjr.js +3 -0
- package/dist/devtools-client/_nuxt/CB1p6iYX.js +1 -0
- package/dist/devtools-client/_nuxt/{COXexnyN.js → CtC_CmOY.js} +2 -2
- package/dist/devtools-client/_nuxt/{entry.DsZySRVW.css → entry.jOWrhpYd.css} +1 -1
- package/dist/devtools-client/index.html +1 -1
- package/dist/module.d.mts +18 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +129 -38
- package/dist/runtime/better-auth/nuxt/middleware.js +8 -2
- package/dist/runtime/better-auth/nuxt/no-session-vary.d.ts +38 -0
- package/dist/runtime/better-auth/nuxt/no-session-vary.js +21 -0
- package/dist/runtime/better-auth/nuxt/server.js +4 -1
- package/dist/runtime/better-auth/nuxt/shared-render.d.ts +9 -0
- package/dist/runtime/better-auth/nuxt/shared-render.js +17 -0
- package/dist/runtime/better-auth/vue/auth-client-loader.d.ts +17 -0
- package/dist/runtime/better-auth/vue/auth-client-loader.js +186 -0
- package/dist/runtime/better-auth/vue/client.d.ts +3 -3
- package/dist/runtime/better-auth/vue/cross-domain.d.ts +26 -0
- package/dist/runtime/better-auth/vue/cross-domain.js +52 -35
- package/dist/runtime/better-auth/vue/index.d.ts +2 -1
- package/dist/runtime/better-auth/vue/index.js +1 -0
- package/dist/runtime/better-auth/vue/plugin.client.js +21 -2
- package/dist/runtime/better-auth/vue/plugin.server.js +23 -3
- package/dist/runtime/better-auth/vue/token-store.js +25 -1
- package/dist/runtime/better-auth/vue/use-better-auth.d.ts +11 -5
- package/dist/runtime/better-auth/vue/use-better-auth.js +135 -32
- package/dist/runtime/nuxt/composables/use-async-paginated-query.d.ts +1 -1
- package/dist/runtime/nuxt/composables/use-async-paginated-query.js +5 -3
- package/dist/runtime/nuxt/composables/use-async-query.d.ts +4 -1
- package/dist/runtime/nuxt/composables/use-async-query.js +6 -3
- package/dist/runtime/nuxt/csp.d.ts +2 -1
- package/dist/runtime/nuxt/csp.js +9 -3
- package/dist/runtime/nuxt/function-name.d.ts +9 -0
- package/dist/runtime/nuxt/function-name.js +38 -0
- package/dist/runtime/nuxt/index.js +4 -3
- package/dist/runtime/nuxt/testing.d.ts +21 -0
- package/dist/runtime/nuxt/testing.js +1 -0
- package/dist/runtime/vue/auth/index.d.ts +2 -1
- package/dist/runtime/vue/auth/index.js +62 -13
- package/dist/runtime/vue/composables/use-upload-queue.d.ts +70 -3
- package/dist/runtime/vue/composables/use-upload-queue.js +74 -19
- package/dist/runtime/vue/index.d.ts +1 -1
- package/package.json +19 -12
- package/dist/devtools-client/_nuxt/AqohFEu1.js +0 -1
- 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/
|
|
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
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.
|
|
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
|
|
410
|
-
registerVueComposables(resolver,
|
|
411
|
-
registerAuthComponents(resolver,
|
|
412
|
-
const integrations = registerIntegrations(resolver, nuxt, options,
|
|
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,
|
|
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,
|
|
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,
|
|
544
|
+
registerClerk(resolver, policy);
|
|
465
545
|
}
|
|
466
546
|
const auth0 = resolve("auth0", "@auth0/auth0-vue");
|
|
467
547
|
if (auth0) {
|
|
468
|
-
registerAuth0(resolver,
|
|
548
|
+
registerAuth0(resolver, policy);
|
|
469
549
|
}
|
|
470
550
|
const polar = resolve("polar", "@convex-dev/polar");
|
|
471
551
|
if (polar) {
|
|
472
|
-
registerPolarComponents(resolver,
|
|
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,
|
|
574
|
-
registerIntegrationImports(resolver, "core",
|
|
660
|
+
function registerVueComposables(resolver, policy) {
|
|
661
|
+
registerIntegrationImports(resolver, "core", policy);
|
|
575
662
|
}
|
|
576
|
-
function registerAuthComponents(resolver,
|
|
577
|
-
registerComponents(resolver, "core",
|
|
663
|
+
function registerAuthComponents(resolver, policy) {
|
|
664
|
+
registerComponents(resolver, "core", policy);
|
|
578
665
|
}
|
|
579
|
-
function registerIntegrationImports(resolver, integration,
|
|
666
|
+
function registerIntegrationImports(resolver, integration, policy) {
|
|
580
667
|
const kept = (entries) => entries.flatMap((entry) => {
|
|
581
|
-
const as =
|
|
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,
|
|
676
|
+
function registerComponents(resolver, integration, policy) {
|
|
590
677
|
const entries = APP_COMPONENTS[integration];
|
|
591
678
|
for (const { name, from } of entries) {
|
|
592
|
-
const as =
|
|
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,
|
|
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
|
-
|
|
604
|
-
|
|
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
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
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,
|
|
624
|
-
registerIntegrationImports(resolver, "clerk",
|
|
625
|
-
registerComponents(resolver, "clerk",
|
|
714
|
+
function registerClerk(resolver, policy) {
|
|
715
|
+
registerIntegrationImports(resolver, "clerk", policy);
|
|
716
|
+
registerComponents(resolver, "clerk", policy);
|
|
626
717
|
}
|
|
627
|
-
function registerAuth0(resolver,
|
|
628
|
-
registerIntegrationImports(resolver, "auth0",
|
|
629
|
-
registerComponents(resolver, "auth0",
|
|
718
|
+
function registerAuth0(resolver, policy) {
|
|
719
|
+
registerIntegrationImports(resolver, "auth0", policy);
|
|
720
|
+
registerComponents(resolver, "auth0", policy);
|
|
630
721
|
}
|
|
631
|
-
function registerPolarComponents(resolver,
|
|
632
|
-
registerComponents(resolver, "polar",
|
|
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(
|
|
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>;
|