@onmax/nuxt-better-auth 0.0.2-alpha.26 → 0.0.2-alpha.28
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.json +1 -1
- package/dist/module.mjs +60 -26
- package/dist/runtime/app/composables/useUserSession.js +8 -2
- package/dist/runtime/app/composables/useUserSignIn.d.ts +4 -2
- package/dist/runtime/app/composables/useUserSignIn.js +5 -2
- package/dist/runtime/app/composables/useUserSignUp.d.ts +4 -2
- package/dist/runtime/app/composables/useUserSignUp.js +5 -2
- package/dist/runtime/app/internal/auth-action-handles.d.ts +1 -3
- package/dist/runtime/app/internal/auth-action-handles.js +2 -6
- package/dist/runtime/app/middleware/auth.global.js +2 -2
- package/dist/runtime/app/pages/__better-auth-devtools.vue +2 -2
- package/dist/runtime/config.d.ts +21 -3
- package/dist/runtime/server/api/_better-auth/config.get.d.ts +6 -1
- package/dist/runtime/server/api/_better-auth/config.get.js +6 -1
- package/dist/runtime/server/utils/auth.js +11 -1
- package/dist/runtime/server/utils/custom-secondary-storage.d.ts +6 -0
- package/dist/runtime/server/utils/custom-secondary-storage.js +8 -0
- package/dist/runtime/types.d.ts +1 -1
- package/package.json +1 -1
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -10,7 +10,7 @@ import { randomBytes } from 'node:crypto';
|
|
|
10
10
|
import { isCI, isTest } from 'std-env';
|
|
11
11
|
export { defineClientAuth, defineServerAuth } from '../dist/runtime/config.js';
|
|
12
12
|
|
|
13
|
-
const version = "0.0.2-alpha.
|
|
13
|
+
const version = "0.0.2-alpha.28";
|
|
14
14
|
|
|
15
15
|
function resolveDatabaseProvider(input) {
|
|
16
16
|
const enabledProviders = Object.entries(input.providers).filter(([_id, provider]) => provider.isEnabled?.(input.context) ?? true);
|
|
@@ -122,26 +122,32 @@ function getHubCasing(hub) {
|
|
|
122
122
|
return hub.db.casing;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
function
|
|
126
|
-
const { options, clientOnly, hasNuxtHub, hub
|
|
127
|
-
|
|
125
|
+
function resolveSecondaryStorage(input) {
|
|
126
|
+
const { options, clientOnly, hasNuxtHub, hub } = input;
|
|
127
|
+
const opt = options.hubSecondaryStorage ?? false;
|
|
128
|
+
const useHubKV = opt === true;
|
|
129
|
+
const secondaryStorageEnabled = opt === true || opt === "custom";
|
|
128
130
|
if (secondaryStorageEnabled && clientOnly) {
|
|
129
|
-
|
|
130
|
-
secondaryStorageEnabled = false;
|
|
131
|
-
} else if (secondaryStorageEnabled && (!hasNuxtHub || !hub?.kv)) {
|
|
132
|
-
consola.warn("secondaryStorage requires @nuxthub/core with hub.kv: true. Disabling.");
|
|
133
|
-
secondaryStorageEnabled = false;
|
|
131
|
+
throw new Error("[nuxt-better-auth] hubSecondaryStorage is not available in clientOnly mode. Either disable clientOnly or remove auth.hubSecondaryStorage.");
|
|
134
132
|
}
|
|
135
|
-
|
|
133
|
+
if (useHubKV && (!hasNuxtHub || !hub?.kv)) {
|
|
134
|
+
throw new Error("[nuxt-better-auth] hubSecondaryStorage: true requires @nuxthub/core with hub.kv: true. Either add hub.kv: true to your nuxt.config or remove auth.hubSecondaryStorage.");
|
|
135
|
+
}
|
|
136
|
+
return { useHubKV, secondaryStorageEnabled };
|
|
136
137
|
}
|
|
137
138
|
function setupRuntimeConfig(input) {
|
|
138
139
|
const { nuxt, options, clientOnly, databaseProvider, consola } = input;
|
|
139
|
-
const secondaryStorageEnabled =
|
|
140
|
+
const { useHubKV, secondaryStorageEnabled } = resolveSecondaryStorage(input);
|
|
140
141
|
nuxt.options.runtimeConfig.public = nuxt.options.runtimeConfig.public || {};
|
|
141
142
|
const configuredSiteUrl = nuxt.options.runtimeConfig.public.siteUrl;
|
|
142
143
|
if (!configuredSiteUrl && process.env.NUXT_PUBLIC_SITE_URL)
|
|
143
144
|
nuxt.options.runtimeConfig.public.siteUrl = process.env.NUXT_PUBLIC_SITE_URL;
|
|
144
145
|
nuxt.options.runtimeConfig.public.auth = defu(nuxt.options.runtimeConfig.public.auth, {
|
|
146
|
+
redirects: {
|
|
147
|
+
login: options.redirects?.login ?? "/login",
|
|
148
|
+
guest: options.redirects?.guest ?? "/",
|
|
149
|
+
logout: options.redirects?.logout
|
|
150
|
+
},
|
|
145
151
|
preserveRedirect: options.preserveRedirect ?? true,
|
|
146
152
|
redirectQueryKey: options.redirectQueryKey ?? "redirect",
|
|
147
153
|
useDatabase: databaseProvider !== "none",
|
|
@@ -156,7 +162,7 @@ function setupRuntimeConfig(input) {
|
|
|
156
162
|
if (!siteUrl)
|
|
157
163
|
consola.warn("clientOnly mode: set runtimeConfig.public.siteUrl (or NUXT_PUBLIC_SITE_URL) to your frontend URL");
|
|
158
164
|
consola.info("clientOnly mode enabled - server utilities (serverAuth, getAppSession, getUserSession, requireUserSession) are not available");
|
|
159
|
-
return { secondaryStorageEnabled };
|
|
165
|
+
return { useHubKV, secondaryStorageEnabled };
|
|
160
166
|
}
|
|
161
167
|
const currentSecret = nuxt.options.runtimeConfig.betterAuthSecret;
|
|
162
168
|
nuxt.options.runtimeConfig.betterAuthSecret = currentSecret || process.env.BETTER_AUTH_SECRET || "";
|
|
@@ -168,9 +174,9 @@ function setupRuntimeConfig(input) {
|
|
|
168
174
|
throw new Error("[nuxt-better-auth] BETTER_AUTH_SECRET must be at least 32 characters for security");
|
|
169
175
|
}
|
|
170
176
|
nuxt.options.runtimeConfig.auth = defu(nuxt.options.runtimeConfig.auth, {
|
|
171
|
-
|
|
177
|
+
hubSecondaryStorage: options.hubSecondaryStorage ?? false
|
|
172
178
|
});
|
|
173
|
-
return { secondaryStorageEnabled };
|
|
179
|
+
return { useHubKV, secondaryStorageEnabled };
|
|
174
180
|
}
|
|
175
181
|
|
|
176
182
|
function dialectToProvider(dialect) {
|
|
@@ -236,6 +242,18 @@ async function loadUserAuthConfig(configPath, throwOnError = false) {
|
|
|
236
242
|
}
|
|
237
243
|
}
|
|
238
244
|
|
|
245
|
+
function resolveSchemaSecondaryStorageInjection(hubSecondaryStorage, userHasSecondaryStorage, isProduction) {
|
|
246
|
+
if (hubSecondaryStorage === true)
|
|
247
|
+
return { inject: true };
|
|
248
|
+
if (hubSecondaryStorage !== "custom")
|
|
249
|
+
return { inject: false };
|
|
250
|
+
if (userHasSecondaryStorage)
|
|
251
|
+
return { inject: true };
|
|
252
|
+
const message = '[nuxt-better-auth] hubSecondaryStorage: "custom" requires secondaryStorage in defineServerAuth() to omit the session table from the generated schema.';
|
|
253
|
+
if (isProduction)
|
|
254
|
+
return { inject: false, error: message };
|
|
255
|
+
return { inject: false, warn: message };
|
|
256
|
+
}
|
|
239
257
|
function isInsideNodeModules(path) {
|
|
240
258
|
return path.split(/[\\/]/).includes("node_modules");
|
|
241
259
|
}
|
|
@@ -260,7 +278,7 @@ async function loadAuthOptions(context) {
|
|
|
260
278
|
const plugins = [...userConfig.plugins || [], ...extendedConfig.plugins || []];
|
|
261
279
|
return { userConfig, plugins };
|
|
262
280
|
}
|
|
263
|
-
async function setupBetterAuthSchema(nuxt, serverConfigPath, options, consola) {
|
|
281
|
+
async function setupBetterAuthSchema(nuxt, serverConfigPath, options, consola, hubSecondaryStorage) {
|
|
264
282
|
const hub = nuxt.options.hub;
|
|
265
283
|
const dialect = getHubDialect(hub);
|
|
266
284
|
if (!dialect || !["sqlite", "postgresql", "mysql"].includes(dialect)) {
|
|
@@ -270,10 +288,16 @@ async function setupBetterAuthSchema(nuxt, serverConfigPath, options, consola) {
|
|
|
270
288
|
const context = { nuxt, serverConfigPath };
|
|
271
289
|
try {
|
|
272
290
|
const { userConfig, plugins } = await loadAuthOptions(context);
|
|
291
|
+
const userHasSecondaryStorage = userConfig.secondaryStorage != null;
|
|
292
|
+
const secondaryStorageResolution = resolveSchemaSecondaryStorageInjection(hubSecondaryStorage, userHasSecondaryStorage, !nuxt.options.dev);
|
|
293
|
+
if (secondaryStorageResolution.error)
|
|
294
|
+
throw new Error(secondaryStorageResolution.error);
|
|
295
|
+
if (secondaryStorageResolution.warn)
|
|
296
|
+
consola.warn(secondaryStorageResolution.warn);
|
|
273
297
|
const authOptions = {
|
|
274
298
|
...userConfig,
|
|
275
299
|
plugins,
|
|
276
|
-
secondaryStorage:
|
|
300
|
+
secondaryStorage: secondaryStorageResolution.inject ? { get: async (_key) => null, set: async (_key, _value, _ttl) => {
|
|
277
301
|
}, delete: async (_key) => {
|
|
278
302
|
} } : void 0
|
|
279
303
|
};
|
|
@@ -328,13 +352,21 @@ function appendSecretToEnv(rootDir, secret) {
|
|
|
328
352
|
`;
|
|
329
353
|
writeFileSync(envPath, content, "utf-8");
|
|
330
354
|
}
|
|
331
|
-
async function promptForSecret(rootDir, consola) {
|
|
355
|
+
async function promptForSecret(rootDir, consola, options = {}) {
|
|
356
|
+
const configuredSecret = options.configuredSecret?.trim();
|
|
357
|
+
if (configuredSecret)
|
|
358
|
+
return void 0;
|
|
332
359
|
if (process.env.BETTER_AUTH_SECRET || hasEnvSecret(rootDir))
|
|
333
360
|
return void 0;
|
|
361
|
+
const hasTty = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
362
|
+
if (options.prepare || !hasTty) {
|
|
363
|
+
consola.warn("[nuxt-better-auth] Skipping BETTER_AUTH_SECRET prompt (non-interactive). Set BETTER_AUTH_SECRET or NUXT_BETTER_AUTH_SECRET.");
|
|
364
|
+
return void 0;
|
|
365
|
+
}
|
|
334
366
|
if (isCI || isTest) {
|
|
335
367
|
const secret2 = generateSecret();
|
|
336
368
|
appendSecretToEnv(rootDir, secret2);
|
|
337
|
-
consola.info("Generated BETTER_AUTH_SECRET and added to .env (CI mode)");
|
|
369
|
+
consola.info("Generated BETTER_AUTH_SECRET and added to .env (CI/test mode)");
|
|
338
370
|
return secret2;
|
|
339
371
|
}
|
|
340
372
|
consola.box("BETTER_AUTH_SECRET is required for authentication.\nThis will be appended to your .env file.");
|
|
@@ -375,8 +407,8 @@ Proceed?`, { type: "confirm", initial: true, cancel: "null" });
|
|
|
375
407
|
return secret;
|
|
376
408
|
}
|
|
377
409
|
|
|
378
|
-
function buildSecondaryStorageCode(
|
|
379
|
-
if (!
|
|
410
|
+
function buildSecondaryStorageCode(useHubKV) {
|
|
411
|
+
if (!useHubKV)
|
|
380
412
|
return "export function createSecondaryStorage() { return undefined }";
|
|
381
413
|
return `import { kv } from '@nuxthub/kv'
|
|
382
414
|
export function createSecondaryStorage() {
|
|
@@ -587,12 +619,14 @@ const module$1 = defineNuxtModule({
|
|
|
587
619
|
clientOnly: false,
|
|
588
620
|
serverConfig: "server/auth.config",
|
|
589
621
|
clientConfig: "app/auth.config",
|
|
622
|
+
redirects: { login: "/login", guest: "/" },
|
|
590
623
|
preserveRedirect: true,
|
|
591
624
|
redirectQueryKey: "redirect",
|
|
592
|
-
|
|
625
|
+
hubSecondaryStorage: false
|
|
593
626
|
},
|
|
594
627
|
async onInstall(nuxt) {
|
|
595
|
-
const
|
|
628
|
+
const configuredSecret = nuxt.options.runtimeConfig?.betterAuthSecret;
|
|
629
|
+
const generatedSecret = await promptForSecret(nuxt.options.rootDir, consola, { configuredSecret, prepare: Boolean(nuxt.options._prepare) });
|
|
596
630
|
if (generatedSecret)
|
|
597
631
|
process.env.BETTER_AUTH_SECRET = generatedSecret;
|
|
598
632
|
await createDefaultAuthConfigFiles(nuxt.options.rootDir, nuxt.options.srcDir);
|
|
@@ -666,7 +700,7 @@ const module$1 = defineNuxtModule({
|
|
|
666
700
|
const resolvedProvider = resolveDatabaseProvider({ providers, context: enabledCtx });
|
|
667
701
|
databaseProvider = resolvedProvider.id;
|
|
668
702
|
hasHubDb = databaseProvider === "nuxthub";
|
|
669
|
-
const {
|
|
703
|
+
const { useHubKV } = setupRuntimeConfig({
|
|
670
704
|
nuxt,
|
|
671
705
|
options,
|
|
672
706
|
clientOnly,
|
|
@@ -675,12 +709,12 @@ const module$1 = defineNuxtModule({
|
|
|
675
709
|
hub,
|
|
676
710
|
consola
|
|
677
711
|
});
|
|
678
|
-
if (
|
|
712
|
+
if (useHubKV && !nuxt.options.alias["hub:kv"]) {
|
|
679
713
|
throw new Error("[nuxt-better-auth] hub:kv not found. Ensure @nuxthub/core is loaded before this module and hub.kv is enabled.");
|
|
680
714
|
}
|
|
681
715
|
const secondaryStorageTemplate = addTemplate({
|
|
682
716
|
filename: "better-auth/secondary-storage.mjs",
|
|
683
|
-
getContents: () => buildSecondaryStorageCode(
|
|
717
|
+
getContents: () => buildSecondaryStorageCode(useHubKV),
|
|
684
718
|
write: true
|
|
685
719
|
});
|
|
686
720
|
nuxt.options.alias["#auth/secondary-storage"] = secondaryStorageTemplate.dst;
|
|
@@ -715,7 +749,7 @@ export { schema }
|
|
|
715
749
|
runtimeTypesPath: resolver.resolve("./runtime/types")
|
|
716
750
|
});
|
|
717
751
|
if (hasHubDb)
|
|
718
|
-
await setupBetterAuthSchema(nuxt, serverConfigPath, options, consola);
|
|
752
|
+
await setupBetterAuthSchema(nuxt, serverConfigPath, options, consola, options.hubSecondaryStorage ?? false);
|
|
719
753
|
}
|
|
720
754
|
registerSharedTypeTemplates({
|
|
721
755
|
runtimeTypesAugmentPath: resolver.resolve("./runtime/types/augment"),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import createAppAuthClient from "#auth/client";
|
|
2
|
-
import { computed, nextTick, useNuxtApp, useRequestHeaders, useRequestURL, useRuntimeConfig, useState, watch } from "#imports";
|
|
2
|
+
import { computed, navigateTo, nextTick, useNuxtApp, useRequestHeaders, useRequestURL, useRuntimeConfig, useState, watch } from "#imports";
|
|
3
3
|
import { normalizeAuthActionError } from "../internal/auth-action-error.js";
|
|
4
4
|
let _sessionSignalListenerBound = false;
|
|
5
5
|
let _client = null;
|
|
@@ -229,8 +229,14 @@ export function useUserSession() {
|
|
|
229
229
|
throw new Error("signOut can only be called on client-side");
|
|
230
230
|
await client.signOut();
|
|
231
231
|
clearSession();
|
|
232
|
-
if (options?.onSuccess)
|
|
232
|
+
if (options?.onSuccess) {
|
|
233
233
|
await options.onSuccess();
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const authConfig = runtimeConfig.public.auth;
|
|
237
|
+
const logoutRedirect = authConfig?.redirects?.logout;
|
|
238
|
+
if (logoutRedirect)
|
|
239
|
+
await navigateTo(logoutRedirect);
|
|
234
240
|
}
|
|
235
241
|
return {
|
|
236
242
|
client,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import type { AppAuthClient } from '#nuxt-better-auth';
|
|
2
|
-
import type {
|
|
3
|
-
|
|
2
|
+
import type { ActionHandleFor } from '../internal/auth-action-handles.js';
|
|
3
|
+
type SignIn = NonNullable<AppAuthClient>['signIn'];
|
|
4
|
+
export declare function useUserSignIn<MethodKey extends keyof SignIn>(method: MethodKey): ActionHandleFor<SignIn[MethodKey]>;
|
|
5
|
+
export {};
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { useUserSession } from "#imports";
|
|
2
2
|
import { createActionHandles } from "../internal/auth-action-handles.js";
|
|
3
|
-
export function useUserSignIn() {
|
|
4
|
-
|
|
3
|
+
export function useUserSignIn(method) {
|
|
4
|
+
if (method === void 0 || method === null)
|
|
5
|
+
throw new TypeError("useUserSignIn(method) requires a sign-in method key");
|
|
6
|
+
const handles = createActionHandles(() => useUserSession().signIn, "signIn");
|
|
7
|
+
return handles[method];
|
|
5
8
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import type { AppAuthClient } from '#nuxt-better-auth';
|
|
2
|
-
import type {
|
|
3
|
-
|
|
2
|
+
import type { ActionHandleFor } from '../internal/auth-action-handles.js';
|
|
3
|
+
type SignUp = NonNullable<AppAuthClient>['signUp'];
|
|
4
|
+
export declare function useUserSignUp<MethodKey extends keyof SignUp>(method: MethodKey): ActionHandleFor<SignUp[MethodKey]>;
|
|
5
|
+
export {};
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { useUserSession } from "#imports";
|
|
2
2
|
import { createActionHandles } from "../internal/auth-action-handles.js";
|
|
3
|
-
export function useUserSignUp() {
|
|
4
|
-
|
|
3
|
+
export function useUserSignUp(method) {
|
|
4
|
+
if (method === void 0 || method === null)
|
|
5
|
+
throw new TypeError("useUserSignUp(method) requires a sign-up method key");
|
|
6
|
+
const handles = createActionHandles(() => useUserSession().signUp, "signUp");
|
|
7
|
+
return handles[method];
|
|
5
8
|
}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Ref } from 'vue';
|
|
2
2
|
import type { AuthActionError } from '../../types.js';
|
|
3
3
|
export type UserAuthActionStatus = 'idle' | 'pending' | 'success' | 'error';
|
|
4
4
|
export interface UserAuthActionHandle<TArgs extends unknown[], TResult> {
|
|
5
5
|
execute: (...args: TArgs) => Promise<void>;
|
|
6
6
|
status: Ref<UserAuthActionStatus>;
|
|
7
|
-
pending: ComputedRef<boolean>;
|
|
8
7
|
data: Ref<TResult | null>;
|
|
9
8
|
error: Ref<AuthActionError | null>;
|
|
10
|
-
errorMessage: ComputedRef<string | null>;
|
|
11
9
|
}
|
|
12
10
|
export type ActionHandleFor<T> = T extends (...args: infer A) => Promise<infer R> ? UserAuthActionHandle<A, R> : never;
|
|
13
11
|
export type ActionHandleMap<T> = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ref } from "#imports";
|
|
2
2
|
import { normalizeAuthActionError } from "./auth-action-error.js";
|
|
3
3
|
function isRecord(value) {
|
|
4
4
|
return Boolean(value && typeof value === "object");
|
|
@@ -14,8 +14,6 @@ function createActionHandle(getMethod) {
|
|
|
14
14
|
const status = ref("idle");
|
|
15
15
|
const data = ref(null);
|
|
16
16
|
const error = ref(null);
|
|
17
|
-
const pending = computed(() => status.value === "pending");
|
|
18
|
-
const errorMessage = computed(() => error.value?.message ?? null);
|
|
19
17
|
let latestCallId = 0;
|
|
20
18
|
const run = async (...args) => {
|
|
21
19
|
const callId = ++latestCallId;
|
|
@@ -53,10 +51,8 @@ function createActionHandle(getMethod) {
|
|
|
53
51
|
return {
|
|
54
52
|
execute,
|
|
55
53
|
status,
|
|
56
|
-
pending,
|
|
57
54
|
data,
|
|
58
|
-
error
|
|
59
|
-
errorMessage
|
|
55
|
+
error
|
|
60
56
|
};
|
|
61
57
|
}
|
|
62
58
|
export function createActionHandles(getTarget, targetName) {
|
|
@@ -25,13 +25,13 @@ export default defineNuxtRouteMiddleware(async (to) => {
|
|
|
25
25
|
const redirectTo = typeof auth === "object" ? auth.redirectTo : void 0;
|
|
26
26
|
if (mode === "guest") {
|
|
27
27
|
if (loggedIn.value)
|
|
28
|
-
return navigateTo(redirectTo ?? "/");
|
|
28
|
+
return navigateTo(redirectTo ?? config?.redirects?.guest ?? "/");
|
|
29
29
|
return;
|
|
30
30
|
}
|
|
31
31
|
if (!loggedIn.value) {
|
|
32
32
|
const resolved = resolveLoginRedirect({
|
|
33
33
|
route: to,
|
|
34
|
-
loginTarget: redirectTo ?? "/login",
|
|
34
|
+
loginTarget: redirectTo ?? config?.redirects?.login ?? "/login",
|
|
35
35
|
config
|
|
36
36
|
});
|
|
37
37
|
return resolved.external ? navigateTo(resolved.to, { external: true }) : navigateTo(resolved.to);
|
|
@@ -379,8 +379,8 @@ function getAccountActions(row) {
|
|
|
379
379
|
</UBadge>
|
|
380
380
|
</div>
|
|
381
381
|
<div class="config-row">
|
|
382
|
-
<span class="config-label">KV</span><UBadge :color="configData.config.module?.
|
|
383
|
-
{{ configData.config.module?.
|
|
382
|
+
<span class="config-label">KV</span><UBadge :color="configData.config.module?.hubSecondaryStorage ? 'success' : 'neutral'" variant="subtle" size="sm">
|
|
383
|
+
{{ configData.config.module?.hubSecondaryStorage ? configData.config.module.hubSecondaryStorage === "custom" ? "Custom" : "On" : "Off" }}
|
|
384
384
|
</UBadge>
|
|
385
385
|
</div>
|
|
386
386
|
</div>
|
package/dist/runtime/config.d.ts
CHANGED
|
@@ -24,6 +24,14 @@ export interface BetterAuthModuleOptions {
|
|
|
24
24
|
serverConfig?: string;
|
|
25
25
|
/** Client config path relative to rootDir. Default: 'app/auth.config' */
|
|
26
26
|
clientConfig?: string;
|
|
27
|
+
redirects?: {
|
|
28
|
+
/** Where to redirect unauthenticated users. Default: '/login' */
|
|
29
|
+
login?: string;
|
|
30
|
+
/** Where to redirect authenticated users on guest-only routes. Default: '/' */
|
|
31
|
+
guest?: string;
|
|
32
|
+
/** Where to navigate after logout. Default: no automatic navigation */
|
|
33
|
+
logout?: string;
|
|
34
|
+
};
|
|
27
35
|
/**
|
|
28
36
|
* When redirecting unauthenticated users to the login route, append a query param
|
|
29
37
|
* containing the originally requested path (for safe "return-to" redirects).
|
|
@@ -47,8 +55,13 @@ export interface BetterAuthModuleOptions {
|
|
|
47
55
|
*/
|
|
48
56
|
skipHydratedSsrGetSession?: boolean;
|
|
49
57
|
};
|
|
50
|
-
/**
|
|
51
|
-
|
|
58
|
+
/**
|
|
59
|
+
* Enable secondary storage for sessions.
|
|
60
|
+
* - `true`: Use NuxtHub KV (requires hub.kv: true)
|
|
61
|
+
* - `'custom'`: User provides own secondaryStorage in defineServerAuth()
|
|
62
|
+
* - `false` (default): No secondary storage from module
|
|
63
|
+
*/
|
|
64
|
+
hubSecondaryStorage?: boolean | 'custom';
|
|
52
65
|
/** Schema generation options. Must match drizzleAdapter config. */
|
|
53
66
|
schema?: {
|
|
54
67
|
/** Plural table names: user → users. Default: false */
|
|
@@ -58,6 +71,11 @@ export interface BetterAuthModuleOptions {
|
|
|
58
71
|
};
|
|
59
72
|
}
|
|
60
73
|
export interface AuthRuntimeConfig {
|
|
74
|
+
redirects: {
|
|
75
|
+
login: string;
|
|
76
|
+
guest: string;
|
|
77
|
+
logout?: string;
|
|
78
|
+
};
|
|
61
79
|
preserveRedirect: boolean;
|
|
62
80
|
redirectQueryKey: string;
|
|
63
81
|
useDatabase: boolean;
|
|
@@ -68,7 +86,7 @@ export interface AuthRuntimeConfig {
|
|
|
68
86
|
};
|
|
69
87
|
}
|
|
70
88
|
export interface AuthPrivateRuntimeConfig {
|
|
71
|
-
|
|
89
|
+
hubSecondaryStorage: boolean | 'custom';
|
|
72
90
|
}
|
|
73
91
|
export declare function defineServerAuth<const R>(config: (ctx: ServerAuthContext) => R & ServerAuthConfig): (ctx: ServerAuthContext) => R;
|
|
74
92
|
export declare function defineServerAuth<const R>(config: R & ServerAuthConfig): (ctx: ServerAuthContext) => R;
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<{
|
|
2
2
|
config: {
|
|
3
3
|
module: {
|
|
4
|
+
redirects: {
|
|
5
|
+
login: string;
|
|
6
|
+
guest: string;
|
|
7
|
+
logout: string | undefined;
|
|
8
|
+
};
|
|
4
9
|
preserveRedirect: boolean;
|
|
5
10
|
redirectQueryKey: string;
|
|
6
|
-
|
|
11
|
+
hubSecondaryStorage: boolean | "custom";
|
|
7
12
|
useDatabase: boolean;
|
|
8
13
|
databaseProvider: "none" | "nuxthub";
|
|
9
14
|
};
|
|
@@ -18,9 +18,14 @@ export default defineEventHandler(async (event) => {
|
|
|
18
18
|
config: {
|
|
19
19
|
// Module config (nuxt.config.ts)
|
|
20
20
|
module: {
|
|
21
|
+
redirects: {
|
|
22
|
+
login: publicAuth?.redirects?.login ?? "/login",
|
|
23
|
+
guest: publicAuth?.redirects?.guest ?? "/",
|
|
24
|
+
logout: publicAuth?.redirects?.logout
|
|
25
|
+
},
|
|
21
26
|
preserveRedirect: publicAuth?.preserveRedirect ?? true,
|
|
22
27
|
redirectQueryKey: publicAuth?.redirectQueryKey ?? "redirect",
|
|
23
|
-
|
|
28
|
+
hubSecondaryStorage: privateAuth?.hubSecondaryStorage ?? false,
|
|
24
29
|
useDatabase: publicAuth?.useDatabase ?? false,
|
|
25
30
|
databaseProvider: publicAuth?.databaseProvider ?? "none"
|
|
26
31
|
},
|
|
@@ -5,8 +5,10 @@ import { betterAuth } from "better-auth";
|
|
|
5
5
|
import { getRequestHost, getRequestProtocol } from "h3";
|
|
6
6
|
import { useRuntimeConfig } from "nitropack/runtime";
|
|
7
7
|
import { withoutProtocol } from "ufo";
|
|
8
|
+
import { resolveCustomSecondaryStorageRequirement } from "./custom-secondary-storage.js";
|
|
8
9
|
const _authCache = /* @__PURE__ */ new Map();
|
|
9
10
|
let _baseURLInferenceLogged = false;
|
|
11
|
+
let _customSecondaryStorageMisconfigWarned = false;
|
|
10
12
|
function normalizeLoopbackOrigin(origin) {
|
|
11
13
|
if (!import.meta.dev)
|
|
12
14
|
return origin;
|
|
@@ -189,10 +191,18 @@ export function serverAuth(event) {
|
|
|
189
191
|
const database = createDatabase();
|
|
190
192
|
const userConfig = createServerAuth({ runtimeConfig, db });
|
|
191
193
|
const trustedOrigins = withDevTrustedOrigins(userConfig.trustedOrigins, Boolean(hasExplicitSiteUrl));
|
|
194
|
+
const hubSecondaryStorage = runtimeConfig.auth?.hubSecondaryStorage;
|
|
195
|
+
const customSecondaryStorage = resolveCustomSecondaryStorageRequirement(hubSecondaryStorage, userConfig.secondaryStorage != null, Boolean(import.meta.dev));
|
|
196
|
+
if (customSecondaryStorage?.shouldThrow)
|
|
197
|
+
throw new Error(customSecondaryStorage.message);
|
|
198
|
+
if (customSecondaryStorage?.shouldWarn && !_customSecondaryStorageMisconfigWarned) {
|
|
199
|
+
_customSecondaryStorageMisconfigWarned = true;
|
|
200
|
+
console.warn(customSecondaryStorage.message);
|
|
201
|
+
}
|
|
192
202
|
const auth = betterAuth({
|
|
193
203
|
...userConfig,
|
|
194
204
|
...database && { database },
|
|
195
|
-
secondaryStorage: createSecondaryStorage(),
|
|
205
|
+
...hubSecondaryStorage === true && { secondaryStorage: createSecondaryStorage() },
|
|
196
206
|
secret: runtimeConfig.betterAuthSecret,
|
|
197
207
|
baseURL: siteUrl,
|
|
198
208
|
trustedOrigins
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type HubSecondaryStorageMode = boolean | 'custom' | undefined;
|
|
2
|
+
export declare function resolveCustomSecondaryStorageRequirement(hubSecondaryStorage: HubSecondaryStorageMode, userHasSecondaryStorage: boolean, isDev: boolean): {
|
|
3
|
+
shouldThrow: boolean;
|
|
4
|
+
shouldWarn: boolean;
|
|
5
|
+
message: string;
|
|
6
|
+
} | null;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export function resolveCustomSecondaryStorageRequirement(hubSecondaryStorage, userHasSecondaryStorage, isDev) {
|
|
2
|
+
if (hubSecondaryStorage !== "custom")
|
|
3
|
+
return null;
|
|
4
|
+
if (userHasSecondaryStorage)
|
|
5
|
+
return null;
|
|
6
|
+
const message = '[nuxt-better-auth] hubSecondaryStorage: "custom" requires secondaryStorage in defineServerAuth().';
|
|
7
|
+
return { shouldThrow: !isDev, shouldWarn: isDev, message };
|
|
8
|
+
}
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import type { AuthUser, UserMatch } from '#nuxt-better-auth';
|
|
1
2
|
import type { NitroRouteRules } from 'nitropack/types';
|
|
2
|
-
import type { AuthUser, UserMatch } from './types/augment.js';
|
|
3
3
|
export type { AppSession, AuthSession, AuthUser, RequireSessionOptions, ServerAuthContext, UserMatch, UserSessionComposable } from './types/augment.js';
|
|
4
4
|
export type { Auth, InferPluginTypes, InferSessionFromClient as InferSession, InferUserFromClient as InferUser } from 'better-auth';
|
|
5
5
|
export interface AuthActionError {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onmax/nuxt-better-auth",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.2-alpha.
|
|
4
|
+
"version": "0.0.2-alpha.28",
|
|
5
5
|
"packageManager": "pnpm@10.15.1",
|
|
6
6
|
"description": "Nuxt module for Better Auth integration with NuxtHub, route protection, session management, and role-based access",
|
|
7
7
|
"author": "onmax",
|