@onmax/nuxt-better-auth 0.0.2-alpha.31 → 0.0.2-alpha.32
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/README.md +60 -17
- package/dist/module.json +2 -2
- package/dist/module.mjs +580 -261
- package/dist/runtime/app/components/BetterAuthState.d.vue.ts +4 -4
- package/dist/runtime/app/components/BetterAuthState.vue +1 -1
- package/dist/runtime/app/components/BetterAuthState.vue.d.ts +4 -4
- package/dist/runtime/app/composables/useAuthClient.d.ts +9 -0
- package/dist/runtime/app/composables/useAuthClient.js +34 -0
- package/dist/runtime/app/composables/useAuthClientAction.d.ts +1 -3
- package/dist/runtime/app/composables/useAuthClientAction.js +2 -2
- package/dist/runtime/app/composables/useAuthRequestFetch.d.ts +1 -1
- package/dist/runtime/app/composables/useSignIn.js +2 -2
- package/dist/runtime/app/composables/useSignUp.js +2 -2
- package/dist/runtime/app/composables/useUserSession.d.ts +5 -4
- package/dist/runtime/app/composables/useUserSession.js +62 -69
- package/dist/runtime/app/composables/useUserSessionState.d.ts +3 -0
- package/dist/runtime/app/composables/useUserSessionState.js +4 -0
- package/dist/runtime/app/internal/session-fetch.d.ts +1 -1
- package/dist/runtime/app/internal/vue-safe-auth-proxy.d.ts +3 -0
- package/dist/runtime/app/internal/vue-safe-auth-proxy.js +68 -0
- package/dist/runtime/app/middleware/auth.global.js +5 -4
- package/dist/runtime/app/plugins/session.client.js +2 -1
- package/dist/runtime/composables.d.ts +11 -0
- package/dist/runtime/composables.js +9 -0
- package/dist/runtime/config.d.ts +4 -2
- package/dist/runtime/server/api/_better-auth/_schema.d.ts +1 -5
- package/dist/runtime/server/api/_better-auth/accounts.get.d.ts +2 -2
- package/dist/runtime/server/api/_better-auth/config.get.js +1 -1
- package/dist/runtime/server/api/_better-auth/sessions.get.d.ts +2 -2
- package/dist/runtime/server/api/_better-auth/users.get.d.ts +2 -2
- package/dist/runtime/server/middleware/route-access.js +1 -1
- package/dist/runtime/server/utils/auth.d.ts +13 -2
- package/dist/runtime/server/utils/auth.js +42 -16
- package/dist/runtime/server/utils/session.d.ts +3 -1
- package/dist/runtime/server/utils/session.js +175 -1
- package/dist/runtime/server/virtual-modules.d.ts +5 -0
- package/dist/runtime/types/augment.d.ts +1 -3
- package/dist/runtime/types.d.ts +1 -1
- package/package.json +28 -12
package/dist/module.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, writeFileSync, readFileSync } from 'node:fs';
|
|
1
|
+
import { existsSync, statSync, writeFileSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { mkdir, writeFile } from 'node:fs/promises';
|
|
3
3
|
import { getLayerDirectories, updateTemplates, addServerImportsDir, addServerImports, addServerScanDir, addServerHandler, addImportsDir, addPlugin, addComponentsDir, hasNuxtModule, installModule, extendPages, addTemplate, addTypeTemplate, defineNuxtModule, createResolver } from '@nuxt/kit';
|
|
4
4
|
import { consola as consola$1 } from 'consola';
|
|
@@ -10,17 +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.
|
|
14
|
-
|
|
15
|
-
function resolveDatabaseProvider(input) {
|
|
16
|
-
const enabledProviders = Object.entries(input.providers).filter(([_id, provider]) => provider.isEnabled?.(input.context) ?? true);
|
|
17
|
-
if (!enabledProviders.length) {
|
|
18
|
-
throw new Error("[nuxt-better-auth] No database provider is enabled. Register one with the better-auth:database:providers hook.");
|
|
19
|
-
}
|
|
20
|
-
enabledProviders.sort((a, b) => (b[1].priority ?? 0) - (a[1].priority ?? 0));
|
|
21
|
-
const [id, definition] = enabledProviders[0];
|
|
22
|
-
return { id, definition };
|
|
23
|
-
}
|
|
13
|
+
const version = "0.0.2-alpha.32";
|
|
24
14
|
|
|
25
15
|
const CONFIG_EXTENSIONS = [".ts", ".js"];
|
|
26
16
|
const CONFIG_EXTENSION_RE = /\.(?:ts|js)$/;
|
|
@@ -35,7 +25,7 @@ const OPTION_KEY_BY_KIND = {
|
|
|
35
25
|
function stripConfigExtension(path) {
|
|
36
26
|
return path.replace(CONFIG_EXTENSION_RE, "");
|
|
37
27
|
}
|
|
38
|
-
function
|
|
28
|
+
function defaultConfigExists(path) {
|
|
39
29
|
return CONFIG_EXTENSIONS.some((ext) => existsSync(`${path}${ext}`));
|
|
40
30
|
}
|
|
41
31
|
function getLayerDirectoriesWithConfigs(nuxt) {
|
|
@@ -50,11 +40,15 @@ function getDefaultConfigPath(nuxt, kind) {
|
|
|
50
40
|
const project = getProjectDirectory(nuxt);
|
|
51
41
|
return kind === "server" ? join(project.server, "auth.config") : join(project.app, "auth.config");
|
|
52
42
|
}
|
|
53
|
-
function getLayerDefaultConfigPath(nuxt, kind) {
|
|
43
|
+
function getLayerDefaultConfigPath(nuxt, kind, configExists) {
|
|
54
44
|
for (const { directory } of getLayerDirectoriesWithConfigs(nuxt)) {
|
|
55
45
|
const candidate = kind === "server" ? join(directory.server, "auth.config") : join(directory.app, "auth.config");
|
|
56
|
-
if (configExists(candidate))
|
|
57
|
-
return
|
|
46
|
+
if (configExists(candidate)) {
|
|
47
|
+
return {
|
|
48
|
+
path: candidate,
|
|
49
|
+
declaringLayerRoot: directory.root
|
|
50
|
+
};
|
|
51
|
+
}
|
|
58
52
|
}
|
|
59
53
|
}
|
|
60
54
|
function resolveDeclaringLayerRoot(nuxt, kind, file) {
|
|
@@ -74,36 +68,61 @@ function getEffectiveModuleConfigFile(nuxt, kind) {
|
|
|
74
68
|
const authOptions = nuxt.options.auth;
|
|
75
69
|
return authOptions?.[optionKey] ?? DEFAULT_CONFIG_FILES[kind];
|
|
76
70
|
}
|
|
77
|
-
function
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
function resolveModuleConfigPath(nuxt, kind, file) {
|
|
85
|
-
const normalizedFile = stripConfigExtension(file);
|
|
86
|
-
if (isAbsolute(normalizedFile)) {
|
|
71
|
+
function resolveAuthConfigDescriptor(nuxt, kind, file = getEffectiveModuleConfigFile(nuxt, kind), dependencies = {}) {
|
|
72
|
+
const configExists = dependencies.configExists ?? defaultConfigExists;
|
|
73
|
+
const configuredFile = stripConfigExtension(file);
|
|
74
|
+
if (isAbsolute(configuredFile)) {
|
|
75
|
+
const declaringLayerRoot2 = resolveDeclaringLayerRoot(nuxt, kind, configuredFile);
|
|
76
|
+
const exists2 = configExists(configuredFile);
|
|
87
77
|
return {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
78
|
+
kind,
|
|
79
|
+
configuredFile,
|
|
80
|
+
file: configuredFile,
|
|
81
|
+
path: configuredFile,
|
|
82
|
+
declaringLayerRoot: declaringLayerRoot2,
|
|
83
|
+
isDefault: false,
|
|
84
|
+
isExplicit: true,
|
|
85
|
+
exists: exists2,
|
|
86
|
+
shouldCreateDefaultFile: false
|
|
91
87
|
};
|
|
92
88
|
}
|
|
93
|
-
if (
|
|
94
|
-
const
|
|
89
|
+
if (configuredFile === DEFAULT_CONFIG_FILES[kind]) {
|
|
90
|
+
const project = getProjectDirectory(nuxt);
|
|
91
|
+
const discovered = getLayerDefaultConfigPath(nuxt, kind, configExists);
|
|
92
|
+
const path2 = discovered?.path ?? getDefaultConfigPath(nuxt, kind);
|
|
93
|
+
const declaringLayerRoot2 = discovered?.declaringLayerRoot ?? project.root;
|
|
94
|
+
const exists2 = configExists(path2);
|
|
95
95
|
return {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
96
|
+
kind,
|
|
97
|
+
configuredFile,
|
|
98
|
+
file: getRelativeConfigFile(nuxt, path2),
|
|
99
|
+
path: path2,
|
|
100
|
+
declaringLayerRoot: declaringLayerRoot2,
|
|
101
|
+
isDefault: true,
|
|
102
|
+
isExplicit: false,
|
|
103
|
+
exists: exists2,
|
|
104
|
+
shouldCreateDefaultFile: !exists2
|
|
99
105
|
};
|
|
100
106
|
}
|
|
101
|
-
const
|
|
102
|
-
const path = join(
|
|
107
|
+
const declaringLayerRoot = resolveDeclaringLayerRoot(nuxt, kind, configuredFile);
|
|
108
|
+
const path = join(declaringLayerRoot, configuredFile);
|
|
109
|
+
const exists = configExists(path);
|
|
103
110
|
return {
|
|
111
|
+
kind,
|
|
112
|
+
configuredFile,
|
|
104
113
|
file: getRelativeConfigFile(nuxt, path),
|
|
105
114
|
path,
|
|
106
|
-
|
|
115
|
+
declaringLayerRoot,
|
|
116
|
+
isDefault: false,
|
|
117
|
+
isExplicit: true,
|
|
118
|
+
exists,
|
|
119
|
+
shouldCreateDefaultFile: false
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function resolveAuthConfigDescriptors(nuxt, files = {}, dependencies = {}) {
|
|
123
|
+
return {
|
|
124
|
+
server: resolveAuthConfigDescriptor(nuxt, "server", files.server, dependencies),
|
|
125
|
+
client: resolveAuthConfigDescriptor(nuxt, "client", files.client, dependencies)
|
|
107
126
|
};
|
|
108
127
|
}
|
|
109
128
|
|
|
@@ -149,6 +168,57 @@ function registerAuthMiddlewareHook(nuxt, resolve) {
|
|
|
149
168
|
app.middleware.push({ name: "auth", path: resolve("./runtime/app/middleware/auth.global"), global: true });
|
|
150
169
|
});
|
|
151
170
|
}
|
|
171
|
+
function registerPrepareTypesHook(input) {
|
|
172
|
+
const { nuxt, serverDir, hasHubDb } = input;
|
|
173
|
+
nuxt.hook("prepare:types", ({ nodeTsConfig, nodeReferences, sharedReferences }) => {
|
|
174
|
+
nodeTsConfig.compilerOptions ||= {};
|
|
175
|
+
nodeTsConfig.compilerOptions.paths ||= {};
|
|
176
|
+
const projectReferenceTypePaths = [
|
|
177
|
+
join(nuxt.options.buildDir, "types/nitro-imports.d.ts"),
|
|
178
|
+
join(nuxt.options.buildDir, "types/auth-database.d.ts"),
|
|
179
|
+
join(nuxt.options.buildDir, "types/auth-schema.d.ts"),
|
|
180
|
+
join(nuxt.options.buildDir, "types/auth-secondary-storage.d.ts")
|
|
181
|
+
];
|
|
182
|
+
if (hasHubDb)
|
|
183
|
+
projectReferenceTypePaths.push(join(nuxt.options.buildDir, "hub/db.d.ts"));
|
|
184
|
+
const exactNodeAliases = {
|
|
185
|
+
"#server": serverDir,
|
|
186
|
+
"#auth/server": nuxt.options.alias["#auth/server"],
|
|
187
|
+
"#auth/client": nuxt.options.alias["#auth/client"],
|
|
188
|
+
"#auth/database": nuxt.options.alias["#auth/database"],
|
|
189
|
+
"#auth/schema": nuxt.options.alias["#auth/schema"],
|
|
190
|
+
"#auth/secondary-storage": nuxt.options.alias["#auth/secondary-storage"],
|
|
191
|
+
"#auth/route-rules": nuxt.options.alias["#auth/route-rules"],
|
|
192
|
+
"#nuxt-better-auth": nuxt.options.alias["#nuxt-better-auth"]
|
|
193
|
+
};
|
|
194
|
+
for (const [key, value] of Object.entries(exactNodeAliases)) {
|
|
195
|
+
if (typeof value === "string")
|
|
196
|
+
nodeTsConfig.compilerOptions.paths[key] = [value];
|
|
197
|
+
}
|
|
198
|
+
for (const [key, value] of Object.entries(nuxt.options.alias)) {
|
|
199
|
+
if (typeof value !== "string" || !isAbsolute(value))
|
|
200
|
+
continue;
|
|
201
|
+
nodeTsConfig.compilerOptions.paths[key] ||= [value];
|
|
202
|
+
if (!key.includes("*") && existsSync(value) && statSync(value).isDirectory())
|
|
203
|
+
nodeTsConfig.compilerOptions.paths[`${key}/*`] ||= [join(value, "*")];
|
|
204
|
+
}
|
|
205
|
+
nodeTsConfig.compilerOptions.paths["#server/*"] = [join(serverDir, "*")];
|
|
206
|
+
for (const path of projectReferenceTypePaths) {
|
|
207
|
+
if (!nodeReferences.some((reference) => "path" in reference && reference.path === path))
|
|
208
|
+
nodeReferences.push({ path });
|
|
209
|
+
if (!sharedReferences.some((reference) => "path" in reference && reference.path === path))
|
|
210
|
+
sharedReferences.push({ path });
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
function registerNuxtHubDatabaseExternalHook(nuxt) {
|
|
215
|
+
nuxt.hook("nitro:config", (nitroConfig) => {
|
|
216
|
+
nitroConfig.externals ||= {};
|
|
217
|
+
nitroConfig.externals.external ||= [];
|
|
218
|
+
if (!nitroConfig.externals.external.includes("@nuxthub/db"))
|
|
219
|
+
nitroConfig.externals.external.push("@nuxthub/db");
|
|
220
|
+
});
|
|
221
|
+
}
|
|
152
222
|
async function registerDevtools(input) {
|
|
153
223
|
const { nuxt, clientOnly, hasHubDb, resolve } = input;
|
|
154
224
|
const isProduction = process.env.NODE_ENV === "production" || !nuxt.options.dev;
|
|
@@ -193,79 +263,6 @@ function registerRouteRulesMetaHook(nuxt) {
|
|
|
193
263
|
});
|
|
194
264
|
}
|
|
195
265
|
|
|
196
|
-
function getHubDialect(hub) {
|
|
197
|
-
if (!hub?.db)
|
|
198
|
-
return void 0;
|
|
199
|
-
if (typeof hub.db === "string")
|
|
200
|
-
return hub.db;
|
|
201
|
-
if (typeof hub.db === "object" && hub.db !== null)
|
|
202
|
-
return hub.db.dialect;
|
|
203
|
-
return void 0;
|
|
204
|
-
}
|
|
205
|
-
function getHubCasing(hub) {
|
|
206
|
-
if (!hub?.db || typeof hub.db !== "object" || hub.db === null)
|
|
207
|
-
return void 0;
|
|
208
|
-
return hub.db.casing;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
function resolveSecondaryStorage(input) {
|
|
212
|
-
const { options, clientOnly, hasNuxtHub, hub } = input;
|
|
213
|
-
const opt = options.hubSecondaryStorage ?? false;
|
|
214
|
-
const useHubKV = opt === true;
|
|
215
|
-
const secondaryStorageEnabled = opt === true || opt === "custom";
|
|
216
|
-
if (secondaryStorageEnabled && clientOnly) {
|
|
217
|
-
throw new Error("[nuxt-better-auth] hubSecondaryStorage is not available in clientOnly mode. Either disable clientOnly or remove auth.hubSecondaryStorage.");
|
|
218
|
-
}
|
|
219
|
-
if (useHubKV && (!hasNuxtHub || !hub?.kv)) {
|
|
220
|
-
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.");
|
|
221
|
-
}
|
|
222
|
-
return { useHubKV, secondaryStorageEnabled };
|
|
223
|
-
}
|
|
224
|
-
function setupRuntimeConfig(input) {
|
|
225
|
-
const { nuxt, options, clientOnly, databaseProvider, consola } = input;
|
|
226
|
-
const { useHubKV, secondaryStorageEnabled } = resolveSecondaryStorage(input);
|
|
227
|
-
nuxt.options.runtimeConfig.public = nuxt.options.runtimeConfig.public || {};
|
|
228
|
-
const configuredSiteUrl = nuxt.options.runtimeConfig.public.siteUrl;
|
|
229
|
-
if (!configuredSiteUrl && process.env.NUXT_PUBLIC_SITE_URL)
|
|
230
|
-
nuxt.options.runtimeConfig.public.siteUrl = process.env.NUXT_PUBLIC_SITE_URL;
|
|
231
|
-
nuxt.options.runtimeConfig.public.auth = defu(nuxt.options.runtimeConfig.public.auth, {
|
|
232
|
-
redirects: {
|
|
233
|
-
login: options.redirects?.login ?? "/login",
|
|
234
|
-
guest: options.redirects?.guest ?? "/",
|
|
235
|
-
authenticated: options.redirects?.authenticated,
|
|
236
|
-
logout: options.redirects?.logout
|
|
237
|
-
},
|
|
238
|
-
preserveRedirect: options.preserveRedirect ?? true,
|
|
239
|
-
redirectQueryKey: options.redirectQueryKey ?? "redirect",
|
|
240
|
-
useDatabase: databaseProvider !== "none",
|
|
241
|
-
databaseProvider,
|
|
242
|
-
clientOnly,
|
|
243
|
-
session: {
|
|
244
|
-
skipHydratedSsrGetSession: options.session?.skipHydratedSsrGetSession ?? false
|
|
245
|
-
}
|
|
246
|
-
});
|
|
247
|
-
if (clientOnly) {
|
|
248
|
-
const siteUrl = nuxt.options.runtimeConfig.public.siteUrl;
|
|
249
|
-
if (!siteUrl)
|
|
250
|
-
consola.warn("clientOnly mode: set runtimeConfig.public.siteUrl (or NUXT_PUBLIC_SITE_URL) to your frontend URL");
|
|
251
|
-
consola.info("clientOnly mode enabled - server utilities (serverAuth, getRequestSession, getUserSession, requireUserSession) are not available");
|
|
252
|
-
return { useHubKV, secondaryStorageEnabled };
|
|
253
|
-
}
|
|
254
|
-
const currentSecret = nuxt.options.runtimeConfig.betterAuthSecret;
|
|
255
|
-
nuxt.options.runtimeConfig.betterAuthSecret = currentSecret || process.env.NUXT_BETTER_AUTH_SECRET || process.env.BETTER_AUTH_SECRET || "";
|
|
256
|
-
const betterAuthSecret = nuxt.options.runtimeConfig.betterAuthSecret;
|
|
257
|
-
if (!nuxt.options.dev && !nuxt.options._prepare && !betterAuthSecret) {
|
|
258
|
-
throw new Error("[nuxt-better-auth] NUXT_BETTER_AUTH_SECRET is required in production. Set NUXT_BETTER_AUTH_SECRET or BETTER_AUTH_SECRET environment variable.");
|
|
259
|
-
}
|
|
260
|
-
if (betterAuthSecret && betterAuthSecret.length < 32) {
|
|
261
|
-
throw new Error("[nuxt-better-auth] NUXT_BETTER_AUTH_SECRET must be at least 32 characters for security");
|
|
262
|
-
}
|
|
263
|
-
nuxt.options.runtimeConfig.auth = defu(nuxt.options.runtimeConfig.auth, {
|
|
264
|
-
hubSecondaryStorage: options.hubSecondaryStorage ?? false
|
|
265
|
-
});
|
|
266
|
-
return { useHubKV, secondaryStorageEnabled };
|
|
267
|
-
}
|
|
268
|
-
|
|
269
266
|
function dialectToProvider(dialect) {
|
|
270
267
|
return dialect === "postgresql" ? "pg" : dialect;
|
|
271
268
|
}
|
|
@@ -298,10 +295,10 @@ async function generateDrizzleSchema(authOptions, dialect, schemaOptions) {
|
|
|
298
295
|
}
|
|
299
296
|
return result.code;
|
|
300
297
|
}
|
|
301
|
-
async function loadUserAuthConfig(configPath, throwOnError = false) {
|
|
298
|
+
async function loadUserAuthConfig(configPath, throwOnError = false, alias) {
|
|
302
299
|
const { createJiti } = await import('jiti');
|
|
303
300
|
const { defineServerAuth: runtimeDefineServerAuth } = await import('../dist/runtime/config.js');
|
|
304
|
-
const jiti = createJiti(import.meta.url, { interopDefault: true, moduleCache: false });
|
|
301
|
+
const jiti = createJiti(import.meta.url, { interopDefault: true, moduleCache: false, alias });
|
|
305
302
|
const schemaGlobals = globalThis;
|
|
306
303
|
if (!schemaGlobals.__nuxtBetterAuthDefineServerAuth) {
|
|
307
304
|
runtimeDefineServerAuth._count = 0;
|
|
@@ -342,6 +339,21 @@ async function loadUserAuthConfig(configPath, throwOnError = false) {
|
|
|
342
339
|
}
|
|
343
340
|
}
|
|
344
341
|
|
|
342
|
+
function getHubDialect(hub) {
|
|
343
|
+
if (!hub?.db)
|
|
344
|
+
return void 0;
|
|
345
|
+
if (typeof hub.db === "string")
|
|
346
|
+
return hub.db;
|
|
347
|
+
if (typeof hub.db === "object" && hub.db !== null)
|
|
348
|
+
return hub.db.dialect;
|
|
349
|
+
return void 0;
|
|
350
|
+
}
|
|
351
|
+
function getHubCasing(hub) {
|
|
352
|
+
if (!hub?.db || typeof hub.db !== "object" || hub.db === null)
|
|
353
|
+
return void 0;
|
|
354
|
+
return hub.db.casing;
|
|
355
|
+
}
|
|
356
|
+
|
|
345
357
|
const NODE_MODULES_SEGMENT_RE = /[\\/]/;
|
|
346
358
|
function resolveSchemaSecondaryStorageInjection(hubSecondaryStorage, userHasSecondaryStorage, isProduction) {
|
|
347
359
|
if (hubSecondaryStorage === true)
|
|
@@ -373,7 +385,10 @@ function resolveHubSchemaPath(buildDir, rootDir, dialect, exists = existsSync) {
|
|
|
373
385
|
async function loadAuthOptions(context) {
|
|
374
386
|
const isProduction = !context.nuxt.options.dev;
|
|
375
387
|
const configFile = `${context.serverConfigPath}.ts`;
|
|
376
|
-
const
|
|
388
|
+
const alias = Object.fromEntries(
|
|
389
|
+
Object.entries(context.nuxt.options.alias).filter(([, value]) => typeof value === "string").map(([key, value]) => [key, value])
|
|
390
|
+
);
|
|
391
|
+
const userConfig = await loadUserAuthConfig(configFile, isProduction, alias);
|
|
377
392
|
const extendedConfig = {};
|
|
378
393
|
await context.nuxt.callHook("better-auth:config:extend", extendedConfig);
|
|
379
394
|
const plugins = [...userConfig.plugins || [], ...extendedConfig.plugins || []];
|
|
@@ -513,6 +528,74 @@ Proceed?`, { type: "confirm", initial: true, cancel: "null" });
|
|
|
513
528
|
return secret;
|
|
514
529
|
}
|
|
515
530
|
|
|
531
|
+
function resolveDatabaseProvider(input) {
|
|
532
|
+
const enabledProviders = Object.entries(input.providers).filter(([_id, provider]) => provider.isEnabled?.(input.context) ?? true);
|
|
533
|
+
if (!enabledProviders.length) {
|
|
534
|
+
throw new Error("[nuxt-better-auth] No database provider is enabled. Register one with the better-auth:database:providers hook.");
|
|
535
|
+
}
|
|
536
|
+
enabledProviders.sort((a, b) => (b[1].priority ?? 0) - (a[1].priority ?? 0));
|
|
537
|
+
const [id, definition] = enabledProviders[0];
|
|
538
|
+
return { id, definition };
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
function resolveSecondaryStorage(input) {
|
|
542
|
+
const { options, clientOnly, hasNuxtHub, hub } = input;
|
|
543
|
+
const opt = options.hubSecondaryStorage ?? false;
|
|
544
|
+
const useHubKV = opt === true;
|
|
545
|
+
const secondaryStorageEnabled = opt === true || opt === "custom";
|
|
546
|
+
if (secondaryStorageEnabled && clientOnly) {
|
|
547
|
+
throw new Error("[nuxt-better-auth] hubSecondaryStorage is not available in clientOnly mode. Either disable clientOnly or remove auth.hubSecondaryStorage.");
|
|
548
|
+
}
|
|
549
|
+
if (useHubKV && (!hasNuxtHub || !hub?.kv)) {
|
|
550
|
+
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.");
|
|
551
|
+
}
|
|
552
|
+
return { useHubKV, secondaryStorageEnabled };
|
|
553
|
+
}
|
|
554
|
+
function setupRuntimeConfig(input) {
|
|
555
|
+
const { nuxt, options, clientOnly, databaseProvider, consola } = input;
|
|
556
|
+
const { useHubKV, secondaryStorageEnabled } = resolveSecondaryStorage(input);
|
|
557
|
+
nuxt.options.runtimeConfig.public = nuxt.options.runtimeConfig.public || {};
|
|
558
|
+
const configuredSiteUrl = nuxt.options.runtimeConfig.public.siteUrl;
|
|
559
|
+
if (!configuredSiteUrl && process.env.NUXT_PUBLIC_SITE_URL)
|
|
560
|
+
nuxt.options.runtimeConfig.public.siteUrl = process.env.NUXT_PUBLIC_SITE_URL;
|
|
561
|
+
nuxt.options.runtimeConfig.public.auth = defu(nuxt.options.runtimeConfig.public.auth, {
|
|
562
|
+
redirects: {
|
|
563
|
+
login: options.redirects?.login ?? "/login",
|
|
564
|
+
guest: options.redirects?.guest ?? "/",
|
|
565
|
+
authenticated: options.redirects?.authenticated,
|
|
566
|
+
logout: options.redirects?.logout
|
|
567
|
+
},
|
|
568
|
+
preserveRedirect: options.preserveRedirect ?? true,
|
|
569
|
+
redirectQueryKey: options.redirectQueryKey ?? "redirect",
|
|
570
|
+
useDatabase: databaseProvider !== "none",
|
|
571
|
+
databaseProvider,
|
|
572
|
+
clientOnly,
|
|
573
|
+
session: {
|
|
574
|
+
skipHydratedSsrGetSession: options.session?.skipHydratedSsrGetSession ?? false
|
|
575
|
+
}
|
|
576
|
+
});
|
|
577
|
+
if (clientOnly) {
|
|
578
|
+
const siteUrl = nuxt.options.runtimeConfig.public.siteUrl;
|
|
579
|
+
if (!siteUrl)
|
|
580
|
+
consola.warn("clientOnly mode: set runtimeConfig.public.siteUrl (or NUXT_PUBLIC_SITE_URL) to your frontend URL");
|
|
581
|
+
consola.info("clientOnly mode enabled - server utilities (serverAuth, getRequestSession, getUserSession, requireUserSession) are not available");
|
|
582
|
+
return { useHubKV, secondaryStorageEnabled };
|
|
583
|
+
}
|
|
584
|
+
const currentSecret = nuxt.options.runtimeConfig.betterAuthSecret;
|
|
585
|
+
nuxt.options.runtimeConfig.betterAuthSecret = currentSecret || process.env.NUXT_BETTER_AUTH_SECRET || process.env.BETTER_AUTH_SECRET || "";
|
|
586
|
+
const betterAuthSecret = nuxt.options.runtimeConfig.betterAuthSecret;
|
|
587
|
+
if (!nuxt.options.dev && !nuxt.options._prepare && !betterAuthSecret) {
|
|
588
|
+
throw new Error("[nuxt-better-auth] NUXT_BETTER_AUTH_SECRET is required in production. Set NUXT_BETTER_AUTH_SECRET or BETTER_AUTH_SECRET environment variable.");
|
|
589
|
+
}
|
|
590
|
+
if (betterAuthSecret && betterAuthSecret.length < 32) {
|
|
591
|
+
throw new Error("[nuxt-better-auth] NUXT_BETTER_AUTH_SECRET must be at least 32 characters for security");
|
|
592
|
+
}
|
|
593
|
+
nuxt.options.runtimeConfig.auth = defu(nuxt.options.runtimeConfig.auth, {
|
|
594
|
+
hubSecondaryStorage: options.hubSecondaryStorage ?? false
|
|
595
|
+
});
|
|
596
|
+
return { useHubKV, secondaryStorageEnabled };
|
|
597
|
+
}
|
|
598
|
+
|
|
516
599
|
function buildSecondaryStorageCode(useHubKV) {
|
|
517
600
|
if (!useHubKV)
|
|
518
601
|
return "export function createSecondaryStorage() { return undefined }";
|
|
@@ -527,6 +610,114 @@ export function createSecondaryStorage() {
|
|
|
527
610
|
}
|
|
528
611
|
function buildDatabaseCode(input) {
|
|
529
612
|
if (input.provider === "nuxthub") {
|
|
613
|
+
if (input.hubDialect === "postgresql") {
|
|
614
|
+
return `import { db } from '@nuxthub/db'
|
|
615
|
+
import * as schema from './schema.${input.hubDialect}.mjs'
|
|
616
|
+
import { drizzleAdapter } from 'better-auth/adapters/drizzle'
|
|
617
|
+
import { drizzle } from 'drizzle-orm/postgres-js'
|
|
618
|
+
import postgres from 'postgres'
|
|
619
|
+
|
|
620
|
+
const dialect = 'pg'
|
|
621
|
+
const requestDatabaseKey = Symbol.for('nuxt-better-auth.requestDatabase')
|
|
622
|
+
const fallbackRequestDatabaseContext = new WeakMap()
|
|
623
|
+
|
|
624
|
+
function getRequestDatabaseContext(event) {
|
|
625
|
+
const eventWithContext = event
|
|
626
|
+
if (eventWithContext?.context && typeof eventWithContext.context === 'object')
|
|
627
|
+
return eventWithContext.context
|
|
628
|
+
|
|
629
|
+
let context = fallbackRequestDatabaseContext.get(event)
|
|
630
|
+
if (!context) {
|
|
631
|
+
context = {}
|
|
632
|
+
fallbackRequestDatabaseContext.set(event, context)
|
|
633
|
+
}
|
|
634
|
+
return context
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
function createHyperdriveAdapter(client) {
|
|
638
|
+
return drizzleAdapter(drizzle({ client, schema }), { provider: dialect, schema, usePlural: ${input.usePlural}, camelCase: ${input.camelCase} })
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
function getCloudflareContext(event) {
|
|
642
|
+
return event?.context?.cloudflare
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
function resolveHyperdrive(event) {
|
|
646
|
+
const cloudflareEnv = getCloudflareContext(event)?.env
|
|
647
|
+
return cloudflareEnv?.POSTGRES || process.env.POSTGRES || globalThis.__env__?.POSTGRES || globalThis.POSTGRES
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
function scheduleCleanup(event, cleanup) {
|
|
651
|
+
const cloudflareContext = getCloudflareContext(event)
|
|
652
|
+
if (typeof cloudflareContext?.context?.waitUntil === 'function') {
|
|
653
|
+
cloudflareContext.context.waitUntil(cleanup)
|
|
654
|
+
return
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
if (typeof event?.context?.waitUntil === 'function') {
|
|
658
|
+
event.context.waitUntil(cleanup)
|
|
659
|
+
return
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
const waitUntil = event?.waitUntil || event?.req?.waitUntil || event?.node?.req?.waitUntil
|
|
663
|
+
if (typeof waitUntil === 'function')
|
|
664
|
+
waitUntil.call(event?.req || event?.node?.req || event, cleanup)
|
|
665
|
+
else
|
|
666
|
+
void cleanup
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
function registerClientCleanup(event, client) {
|
|
670
|
+
const response = event?.node?.res
|
|
671
|
+
if (!response || typeof response.once !== 'function')
|
|
672
|
+
return
|
|
673
|
+
|
|
674
|
+
let closed = false
|
|
675
|
+
|
|
676
|
+
const cleanup = () => {
|
|
677
|
+
if (closed)
|
|
678
|
+
return
|
|
679
|
+
|
|
680
|
+
closed = true
|
|
681
|
+
const close = client.end({ timeout: 0 }).catch(() => {})
|
|
682
|
+
scheduleCleanup(event, close)
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
response.once('finish', cleanup)
|
|
686
|
+
response.once('close', cleanup)
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
export function createDatabase(event) {
|
|
690
|
+
const hyperdrive = resolveHyperdrive(event)
|
|
691
|
+
if (!hyperdrive?.connectionString)
|
|
692
|
+
return drizzleAdapter(db, { provider: dialect, schema, usePlural: ${input.usePlural}, camelCase: ${input.camelCase} })
|
|
693
|
+
|
|
694
|
+
if (event) {
|
|
695
|
+
const context = getRequestDatabaseContext(event)
|
|
696
|
+
const cached = context[requestDatabaseKey]
|
|
697
|
+
if (cached)
|
|
698
|
+
return cached
|
|
699
|
+
|
|
700
|
+
const client = postgres(hyperdrive.connectionString, {
|
|
701
|
+
prepare: false,
|
|
702
|
+
onnotice: () => {},
|
|
703
|
+
max: 1,
|
|
704
|
+
})
|
|
705
|
+
const database = createHyperdriveAdapter(client)
|
|
706
|
+
|
|
707
|
+
context[requestDatabaseKey] = database
|
|
708
|
+
registerClientCleanup(event, client)
|
|
709
|
+
return database
|
|
710
|
+
}
|
|
711
|
+
const client = postgres(hyperdrive.connectionString, {
|
|
712
|
+
prepare: false,
|
|
713
|
+
onnotice: () => {},
|
|
714
|
+
max: 1,
|
|
715
|
+
})
|
|
716
|
+
|
|
717
|
+
return createHyperdriveAdapter(client)
|
|
718
|
+
}
|
|
719
|
+
export { db }`;
|
|
720
|
+
}
|
|
530
721
|
return `import { db } from '@nuxthub/db'
|
|
531
722
|
import * as schema from './schema.${input.hubDialect}.mjs'
|
|
532
723
|
import { drizzleAdapter } from 'better-auth/adapters/drizzle'
|
|
@@ -538,9 +729,153 @@ export { db }`;
|
|
|
538
729
|
return `export function createDatabase() { return undefined }
|
|
539
730
|
export const db = undefined`;
|
|
540
731
|
}
|
|
732
|
+
function buildSchemaExportCode(hasHubDb, hubDialect) {
|
|
733
|
+
if (!hasHubDb)
|
|
734
|
+
return "export const schema = undefined\n";
|
|
735
|
+
return `export * from './schema.${hubDialect}.mjs'
|
|
736
|
+
import * as schema from './schema.${hubDialect}.mjs'
|
|
737
|
+
export { schema }
|
|
738
|
+
`;
|
|
739
|
+
}
|
|
740
|
+
function buildAuthRouteRulesCode(authRouteRules) {
|
|
741
|
+
return `export const authRouteRules = ${JSON.stringify(authRouteRules, null, 2)}
|
|
742
|
+
`;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
function assertConfigPresence(configs, clientOnly) {
|
|
746
|
+
if (!clientOnly && !configs.server.exists)
|
|
747
|
+
throw new Error(`[nuxt-better-auth] Missing ${configs.server.file}.ts - export default defineServerAuth(...)`);
|
|
748
|
+
if (!configs.client.exists)
|
|
749
|
+
throw new Error(`[nuxt-better-auth] Missing ${configs.client.file}.ts - export default defineClientAuth(...)`);
|
|
750
|
+
}
|
|
751
|
+
function createDefaultDatabaseProviders(buildContext) {
|
|
752
|
+
return {
|
|
753
|
+
nuxthub: {
|
|
754
|
+
priority: 100,
|
|
755
|
+
isEnabled: ({ hasHubDbAvailable: enabled }) => enabled,
|
|
756
|
+
buildDatabaseCode: () => buildDatabaseCode({
|
|
757
|
+
provider: "nuxthub",
|
|
758
|
+
...buildContext
|
|
759
|
+
})
|
|
760
|
+
},
|
|
761
|
+
none: {
|
|
762
|
+
priority: 0,
|
|
763
|
+
buildDatabaseCode: () => buildDatabaseCode({
|
|
764
|
+
provider: "none",
|
|
765
|
+
...buildContext
|
|
766
|
+
})
|
|
767
|
+
}
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
function collectAuthRouteRules(nuxt) {
|
|
771
|
+
const runtimeRouteRulesSource = nuxt.options.nitro?.routeRules || nuxt.options.routeRules || {};
|
|
772
|
+
return Object.fromEntries(
|
|
773
|
+
Object.entries(runtimeRouteRulesSource).flatMap(([path, rule]) => {
|
|
774
|
+
if (!rule || typeof rule !== "object" || !("auth" in rule))
|
|
775
|
+
return [];
|
|
776
|
+
return [[path, { auth: rule.auth }]];
|
|
777
|
+
})
|
|
778
|
+
);
|
|
779
|
+
}
|
|
780
|
+
async function resolveAuthModuleSetup(input, dependencies = {}) {
|
|
781
|
+
const { nuxt, options, runtimeTypesAugmentPath, consola } = input;
|
|
782
|
+
const hasNuxtModuleFn = dependencies.hasNuxtModule ?? hasNuxtModule;
|
|
783
|
+
const clientOnly = options.clientOnly ?? false;
|
|
784
|
+
const configs = resolveAuthConfigDescriptors(nuxt, {
|
|
785
|
+
server: options.serverConfig,
|
|
786
|
+
client: options.clientConfig
|
|
787
|
+
}, {
|
|
788
|
+
configExists: dependencies.configExists
|
|
789
|
+
});
|
|
790
|
+
assertConfigPresence(configs, clientOnly);
|
|
791
|
+
const aliases = {
|
|
792
|
+
"#nuxt-better-auth": runtimeTypesAugmentPath,
|
|
793
|
+
"#auth/server": clientOnly ? void 0 : configs.server.path,
|
|
794
|
+
"#auth/client": configs.client.path
|
|
795
|
+
};
|
|
796
|
+
nuxt.options.alias["#nuxt-better-auth"] = aliases["#nuxt-better-auth"];
|
|
797
|
+
if (aliases["#auth/server"])
|
|
798
|
+
nuxt.options.alias["#auth/server"] = aliases["#auth/server"];
|
|
799
|
+
nuxt.options.alias["#auth/client"] = aliases["#auth/client"];
|
|
800
|
+
const hasNuxtHub = hasNuxtModuleFn("@nuxthub/core", nuxt);
|
|
801
|
+
const hub = hasNuxtHub ? nuxt.options.hub : void 0;
|
|
802
|
+
const hasHubDbAvailable = !clientOnly && hasNuxtHub && !!hub?.db;
|
|
803
|
+
const hubDialect = getHubDialect(hub) ?? "sqlite";
|
|
804
|
+
const usePlural = options.schema?.usePlural ?? false;
|
|
805
|
+
const camelCase = (options.schema?.casing ?? getHubCasing(hub)) !== "snake_case";
|
|
806
|
+
let providerId = "none";
|
|
807
|
+
let providerDefinition;
|
|
808
|
+
if (!clientOnly) {
|
|
809
|
+
const buildContext = { hubDialect, usePlural, camelCase };
|
|
810
|
+
const providers = createDefaultDatabaseProviders(buildContext);
|
|
811
|
+
const enabledContext = {
|
|
812
|
+
nuxt,
|
|
813
|
+
options,
|
|
814
|
+
clientOnly,
|
|
815
|
+
hasHubDbAvailable
|
|
816
|
+
};
|
|
817
|
+
await nuxt.callHook("better-auth:database:providers", providers);
|
|
818
|
+
const resolvedProvider = resolveDatabaseProvider({
|
|
819
|
+
providers,
|
|
820
|
+
context: enabledContext
|
|
821
|
+
});
|
|
822
|
+
providerId = resolvedProvider.id;
|
|
823
|
+
providerDefinition = resolvedProvider.definition;
|
|
824
|
+
}
|
|
825
|
+
const runtime = setupRuntimeConfig({
|
|
826
|
+
nuxt,
|
|
827
|
+
options,
|
|
828
|
+
clientOnly,
|
|
829
|
+
databaseProvider: providerId,
|
|
830
|
+
hasNuxtHub,
|
|
831
|
+
hub,
|
|
832
|
+
consola
|
|
833
|
+
});
|
|
834
|
+
if (runtime.useHubKV && !nuxt.options.alias["hub:kv"]) {
|
|
835
|
+
throw new Error("[nuxt-better-auth] hub:kv not found. Ensure @nuxthub/core is loaded before this module and hub.kv is enabled.");
|
|
836
|
+
}
|
|
837
|
+
const hasHubDb = providerId === "nuxthub";
|
|
838
|
+
if (hasHubDb && !nuxt.options.alias["hub:db"]) {
|
|
839
|
+
throw new Error("[nuxt-better-auth] hub:db not found. Ensure @nuxthub/core is loaded before this module and hub.db is configured.");
|
|
840
|
+
}
|
|
841
|
+
return {
|
|
842
|
+
clientOnly,
|
|
843
|
+
configs,
|
|
844
|
+
aliases,
|
|
845
|
+
hub: {
|
|
846
|
+
hasNuxtHub,
|
|
847
|
+
options: hub,
|
|
848
|
+
hasHubDbAvailable
|
|
849
|
+
},
|
|
850
|
+
database: {
|
|
851
|
+
providerId,
|
|
852
|
+
hasHubDb,
|
|
853
|
+
providerDefinition,
|
|
854
|
+
buildContext: clientOnly ? void 0 : { hubDialect, usePlural, camelCase }
|
|
855
|
+
},
|
|
856
|
+
runtime,
|
|
857
|
+
prepareTypes: clientOnly ? void 0 : {
|
|
858
|
+
serverDir: dirname(configs.server.path),
|
|
859
|
+
hasHubDb
|
|
860
|
+
},
|
|
861
|
+
serverTypes: clientOnly ? void 0 : {
|
|
862
|
+
serverConfigPath: configs.server.path,
|
|
863
|
+
hasHubDb
|
|
864
|
+
},
|
|
865
|
+
sharedTypes: {
|
|
866
|
+
clientConfigPath: configs.client.path
|
|
867
|
+
},
|
|
868
|
+
schemaGeneration: hasHubDb ? {
|
|
869
|
+
serverConfigPath: configs.server.path,
|
|
870
|
+
hubSecondaryStorage: options.hubSecondaryStorage ?? false,
|
|
871
|
+
externalizeNuxtHubDatabase: true
|
|
872
|
+
} : void 0
|
|
873
|
+
};
|
|
874
|
+
}
|
|
541
875
|
|
|
542
876
|
function registerServerTypeTemplates(input) {
|
|
543
|
-
const { serverConfigPath, hasHubDb, runtimeTypesPath } = input;
|
|
877
|
+
const { serverConfigPath, hasHubDb, runtimeTypesPath, sharedServerConfigSafe } = input;
|
|
878
|
+
const serverConfigTypeTemplateOptions = sharedServerConfigSafe ? { nuxt: true, nitro: true, node: true, shared: true } : { nuxt: true, nitro: true, node: true };
|
|
544
879
|
addTypeTemplate({
|
|
545
880
|
filename: "types/auth-secondary-storage.d.ts",
|
|
546
881
|
getContents: () => `
|
|
@@ -553,17 +888,17 @@ declare module '#auth/secondary-storage' {
|
|
|
553
888
|
export function createSecondaryStorage(): SecondaryStorage | undefined
|
|
554
889
|
}
|
|
555
890
|
`
|
|
556
|
-
}, { nitro: true
|
|
891
|
+
}, { nitro: true });
|
|
557
892
|
addTypeTemplate({
|
|
558
893
|
filename: "types/auth-database.d.ts",
|
|
559
894
|
getContents: () => `
|
|
560
895
|
declare module '#auth/database' {
|
|
561
896
|
import type { BetterAuthOptions } from 'better-auth'
|
|
562
|
-
export function createDatabase(): BetterAuthOptions['database']
|
|
897
|
+
export function createDatabase(event?: import('h3').H3Event): BetterAuthOptions['database']
|
|
563
898
|
export const db: ${hasHubDb ? `typeof import('@nuxthub/db')['db']` : "undefined"}
|
|
564
899
|
}
|
|
565
900
|
`
|
|
566
|
-
}, { nitro: true
|
|
901
|
+
}, { nitro: true });
|
|
567
902
|
addTypeTemplate({
|
|
568
903
|
filename: "types/auth-schema.d.ts",
|
|
569
904
|
getContents: () => `
|
|
@@ -581,13 +916,39 @@ declare module '#auth/schema' {
|
|
|
581
916
|
} | undefined
|
|
582
917
|
}
|
|
583
918
|
`
|
|
584
|
-
}, { nitro: true
|
|
919
|
+
}, { nitro: true });
|
|
920
|
+
addTypeTemplate({
|
|
921
|
+
filename: "types/nuxt-better-auth-server-context.d.ts",
|
|
922
|
+
getContents: () => `
|
|
923
|
+
/// <reference path="./nitro-imports.d.ts" />
|
|
924
|
+
/// <reference path="./auth-database.d.ts" />
|
|
925
|
+
/// <reference path="./auth-schema.d.ts" />
|
|
926
|
+
/// <reference path="./auth-secondary-storage.d.ts" />
|
|
927
|
+
${hasHubDb ? '/// <reference path="../hub/db.d.ts" />' : ""}
|
|
928
|
+
|
|
929
|
+
export {}
|
|
930
|
+
`
|
|
931
|
+
}, { node: true });
|
|
932
|
+
addTypeTemplate({
|
|
933
|
+
filename: "types/nuxt-better-auth-config-context.d.ts",
|
|
934
|
+
getContents: () => `
|
|
935
|
+
import type { RuntimeConfig } from 'nuxt/schema'
|
|
936
|
+
|
|
937
|
+
declare module '@onmax/nuxt-better-auth/config' {
|
|
938
|
+
interface ServerAuthContextExtension {
|
|
939
|
+
runtimeConfig: RuntimeConfig
|
|
940
|
+
db: ${hasHubDb ? `typeof import('@nuxthub/db')['db']` : "undefined"}
|
|
941
|
+
requestOrigin?: string
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
`
|
|
946
|
+
}, { nuxt: true, nitro: true, node: true, shared: true });
|
|
585
947
|
addTypeTemplate({
|
|
586
948
|
filename: "types/nuxt-better-auth-infer.d.ts",
|
|
587
949
|
getContents: () => `
|
|
588
950
|
import type { BetterAuthOptions, BetterAuthPlugin, InferPluginTypes, UnionToIntersection } from 'better-auth'
|
|
589
951
|
import type { InferFieldsOutput } from 'better-auth/db'
|
|
590
|
-
import type { RuntimeConfig } from 'nuxt/schema'
|
|
591
952
|
import type createServerAuth from '${serverConfigPath}'
|
|
592
953
|
|
|
593
954
|
type _RawConfig = ReturnType<typeof createServerAuth>
|
|
@@ -617,28 +978,10 @@ type _SessionFallback = _InferModelFieldsFromPlugins<_RawPlugins, 'session'> & _
|
|
|
617
978
|
declare module '#nuxt-better-auth' {
|
|
618
979
|
interface AuthUser extends _UserFallback {}
|
|
619
980
|
interface AuthSession extends _SessionFallback {}
|
|
620
|
-
interface ServerAuthContext {
|
|
621
|
-
runtimeConfig: RuntimeConfig
|
|
622
|
-
db: ${hasHubDb ? `typeof import('@nuxthub/db')['db']` : "undefined"}
|
|
623
|
-
}
|
|
624
981
|
type PluginTypes = InferPluginTypes<_Config>
|
|
625
982
|
}
|
|
626
|
-
|
|
627
|
-
interface _AugmentedServerAuthContext {
|
|
628
|
-
runtimeConfig: RuntimeConfig
|
|
629
|
-
db: ${hasHubDb ? `typeof import('@nuxthub/db')['db']` : "undefined"}
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
declare module '@onmax/nuxt-better-auth/config' {
|
|
633
|
-
import type { BetterAuthOptions, BetterAuthPlugin } from 'better-auth'
|
|
634
|
-
type ServerAuthConfig = Omit<BetterAuthOptions, 'secret' | 'baseURL'> & {
|
|
635
|
-
plugins?: readonly BetterAuthPlugin[]
|
|
636
|
-
}
|
|
637
|
-
export function defineServerAuth<const R>(config: (ctx: _AugmentedServerAuthContext) => R & ServerAuthConfig): (ctx: _AugmentedServerAuthContext) => R
|
|
638
|
-
export function defineServerAuth<const R>(config: R & ServerAuthConfig): (ctx: _AugmentedServerAuthContext) => R
|
|
639
|
-
}
|
|
640
983
|
`
|
|
641
|
-
},
|
|
984
|
+
}, serverConfigTypeTemplateOptions);
|
|
642
985
|
addTypeTemplate({
|
|
643
986
|
filename: "types/nuxt-better-auth-social-providers.d.ts",
|
|
644
987
|
getContents: () => `
|
|
@@ -654,7 +997,7 @@ declare module '#nuxt-better-auth' {
|
|
|
654
997
|
}
|
|
655
998
|
}
|
|
656
999
|
`
|
|
657
|
-
},
|
|
1000
|
+
}, serverConfigTypeTemplateOptions);
|
|
658
1001
|
addTypeTemplate({
|
|
659
1002
|
filename: "types/nuxt-better-auth-nitro.d.ts",
|
|
660
1003
|
getContents: () => `
|
|
@@ -761,6 +1104,7 @@ declare module 'nuxt/dist/app/composables/fetch' {
|
|
|
761
1104
|
PickKeys extends import('nuxt/dist/app/composables/asyncData').KeysOf<DataT> = import('nuxt/dist/app/composables/asyncData').KeysOf<DataT>,
|
|
762
1105
|
DefaultT = DataT,
|
|
763
1106
|
>(request: import('vue').Ref<Path> | Path | (() => Path), opts?: import('nuxt/dist/app/composables/fetch').UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, Path, Method>): import('nuxt/dist/app/composables/asyncData').AsyncData<import('nuxt/dist/app/composables/asyncData').PickFrom<DataT, PickKeys> | DefaultT, ErrorT | undefined>
|
|
1107
|
+
export function useFetch(request: string | import('vue').Ref<string> | (() => string), opts?: any): any
|
|
764
1108
|
|
|
765
1109
|
export function useLazyFetch<
|
|
766
1110
|
ErrorT = FetchError,
|
|
@@ -780,6 +1124,7 @@ declare module 'nuxt/dist/app/composables/fetch' {
|
|
|
780
1124
|
PickKeys extends import('nuxt/dist/app/composables/asyncData').KeysOf<DataT> = import('nuxt/dist/app/composables/asyncData').KeysOf<DataT>,
|
|
781
1125
|
DefaultT = DataT,
|
|
782
1126
|
>(request: import('vue').Ref<Path> | Path | (() => Path), opts?: Omit<import('nuxt/dist/app/composables/fetch').UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, Path, Method>, 'lazy'>): import('nuxt/dist/app/composables/asyncData').AsyncData<import('nuxt/dist/app/composables/asyncData').PickFrom<DataT, PickKeys> | DefaultT, ErrorT | undefined>
|
|
1127
|
+
export function useLazyFetch(request: string | import('vue').Ref<string> | (() => string), opts?: any): any
|
|
783
1128
|
}
|
|
784
1129
|
|
|
785
1130
|
declare module 'nuxt/app' {
|
|
@@ -801,6 +1146,7 @@ declare module 'nuxt/app' {
|
|
|
801
1146
|
PickKeys extends import('nuxt/dist/app/composables/asyncData').KeysOf<DataT> = import('nuxt/dist/app/composables/asyncData').KeysOf<DataT>,
|
|
802
1147
|
DefaultT = DataT,
|
|
803
1148
|
>(request: import('vue').Ref<Path> | Path | (() => Path), opts?: import('nuxt/dist/app/composables/fetch').UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, Path, Method>): import('nuxt/dist/app/composables/asyncData').AsyncData<import('nuxt/dist/app/composables/asyncData').PickFrom<DataT, PickKeys> | DefaultT, ErrorT | undefined>
|
|
1149
|
+
export function useFetch(request: string | import('vue').Ref<string> | (() => string), opts?: any): any
|
|
804
1150
|
|
|
805
1151
|
export function useLazyFetch<
|
|
806
1152
|
ErrorT = FetchError,
|
|
@@ -820,6 +1166,7 @@ declare module 'nuxt/app' {
|
|
|
820
1166
|
PickKeys extends import('nuxt/dist/app/composables/asyncData').KeysOf<DataT> = import('nuxt/dist/app/composables/asyncData').KeysOf<DataT>,
|
|
821
1167
|
DefaultT = DataT,
|
|
822
1168
|
>(request: import('vue').Ref<Path> | Path | (() => Path), opts?: Omit<import('nuxt/dist/app/composables/fetch').UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, Path, Method>, 'lazy'>): import('nuxt/dist/app/composables/asyncData').AsyncData<import('nuxt/dist/app/composables/asyncData').PickFrom<DataT, PickKeys> | DefaultT, ErrorT | undefined>
|
|
1169
|
+
export function useLazyFetch(request: string | import('vue').Ref<string> | (() => string), opts?: any): any
|
|
823
1170
|
}
|
|
824
1171
|
|
|
825
1172
|
declare module 'nitropack' {
|
|
@@ -840,9 +1187,18 @@ declare module 'nitropack/types' {
|
|
|
840
1187
|
}
|
|
841
1188
|
interface InternalApi extends _GeneratedAuthInternalApi {}
|
|
842
1189
|
}
|
|
1190
|
+
declare module 'nitro/types' {
|
|
1191
|
+
interface NitroRouteRules {
|
|
1192
|
+
auth?: import('${runtimeTypesPath}').AuthMeta
|
|
1193
|
+
}
|
|
1194
|
+
interface NitroRouteConfig {
|
|
1195
|
+
auth?: import('${runtimeTypesPath}').AuthMeta
|
|
1196
|
+
}
|
|
1197
|
+
interface InternalApi extends _GeneratedAuthInternalApi {}
|
|
1198
|
+
}
|
|
843
1199
|
export {}
|
|
844
1200
|
`
|
|
845
|
-
}, {
|
|
1201
|
+
}, { nitro: true, node: true });
|
|
846
1202
|
}
|
|
847
1203
|
function registerSharedTypeTemplates(input) {
|
|
848
1204
|
addTypeTemplate({
|
|
@@ -870,13 +1226,30 @@ declare module '#nuxt-better-auth' {
|
|
|
870
1226
|
}
|
|
871
1227
|
|
|
872
1228
|
const consola = consola$1.withTag("nuxt-better-auth");
|
|
1229
|
+
const serverAliasImportRE = /from\s+['"]#server/;
|
|
1230
|
+
const layersAliasImportRE = /from\s+['"]#layers\//;
|
|
1231
|
+
const rootAliasImportRE = /from\s+['"]~~/;
|
|
1232
|
+
const workspaceAliasImportRE = /from\s+['"]@@/;
|
|
1233
|
+
const dbIdentifierRE = /\bdb\b/;
|
|
1234
|
+
const sessionHookAfterIdentifierRE = /\bsessionHookAfter\b/;
|
|
1235
|
+
const nuxtHubDbImportRE = /@nuxthub\/db/;
|
|
1236
|
+
function isServerConfigSharedTypeSafe(serverConfigPath) {
|
|
1237
|
+
const resolvedPath = [
|
|
1238
|
+
serverConfigPath,
|
|
1239
|
+
`${serverConfigPath}.ts`,
|
|
1240
|
+
`${serverConfigPath}.mts`,
|
|
1241
|
+
`${serverConfigPath}.cts`,
|
|
1242
|
+
`${serverConfigPath}.js`,
|
|
1243
|
+
`${serverConfigPath}.mjs`,
|
|
1244
|
+
`${serverConfigPath}.cjs`
|
|
1245
|
+
].find((path) => existsSync(path));
|
|
1246
|
+
if (!resolvedPath)
|
|
1247
|
+
return false;
|
|
1248
|
+
const contents = readFileSync(resolvedPath, "utf8");
|
|
1249
|
+
return !(serverAliasImportRE.test(contents) || layersAliasImportRE.test(contents) || rootAliasImportRE.test(contents) || workspaceAliasImportRE.test(contents) || dbIdentifierRE.test(contents) || sessionHookAfterIdentifierRE.test(contents) || nuxtHubDbImportRE.test(contents));
|
|
1250
|
+
}
|
|
873
1251
|
async function createDefaultAuthConfigFiles(nuxt) {
|
|
874
|
-
const
|
|
875
|
-
const rootDir = project.root;
|
|
876
|
-
const serverPath = join(project.server, "auth.config.ts");
|
|
877
|
-
const clientPath = join(project.app, "auth.config.ts");
|
|
878
|
-
const serverConfigFile = getEffectiveModuleConfigFile(nuxt, "server");
|
|
879
|
-
const clientConfigFile = getEffectiveModuleConfigFile(nuxt, "client");
|
|
1252
|
+
const configs = resolveAuthConfigDescriptors(nuxt);
|
|
880
1253
|
const serverTemplate = `import { defineServerAuth } from '@onmax/nuxt-better-auth/config'
|
|
881
1254
|
|
|
882
1255
|
export default defineServerAuth({
|
|
@@ -887,15 +1260,17 @@ export default defineServerAuth({
|
|
|
887
1260
|
|
|
888
1261
|
export default defineClientAuth({})
|
|
889
1262
|
`;
|
|
890
|
-
if (
|
|
1263
|
+
if (configs.server.shouldCreateDefaultFile) {
|
|
1264
|
+
const serverPath = `${configs.server.path}.ts`;
|
|
891
1265
|
await mkdir(dirname(serverPath), { recursive: true });
|
|
892
1266
|
await writeFile(serverPath, serverTemplate);
|
|
893
|
-
consola.success(`Created ${relative(
|
|
1267
|
+
consola.success(`Created ${relative(configs.server.declaringLayerRoot, serverPath)}`);
|
|
894
1268
|
}
|
|
895
|
-
if (
|
|
1269
|
+
if (configs.client.shouldCreateDefaultFile) {
|
|
1270
|
+
const clientPath = `${configs.client.path}.ts`;
|
|
896
1271
|
await mkdir(dirname(clientPath), { recursive: true });
|
|
897
1272
|
await writeFile(clientPath, clientTemplate);
|
|
898
|
-
consola.success(`Created ${relative(
|
|
1273
|
+
consola.success(`Created ${relative(configs.client.declaringLayerRoot, clientPath)}`);
|
|
899
1274
|
}
|
|
900
1275
|
}
|
|
901
1276
|
const module$1 = defineNuxtModule({
|
|
@@ -918,141 +1293,85 @@ const module$1 = defineNuxtModule({
|
|
|
918
1293
|
},
|
|
919
1294
|
async setup(options, nuxt) {
|
|
920
1295
|
const resolver = createResolver(import.meta.url);
|
|
921
|
-
const
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
if (
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
const hasNuxtHub = hasNuxtModule("@nuxthub/core", nuxt);
|
|
933
|
-
const hub = hasNuxtHub ? nuxt.options.hub : void 0;
|
|
934
|
-
const hasHubDbAvailable = !clientOnly && hasNuxtHub && !!hub?.db;
|
|
935
|
-
let databaseProvider = "none";
|
|
936
|
-
let hasHubDb = false;
|
|
937
|
-
nuxt.options.alias["#nuxt-better-auth"] = resolver.resolve("./runtime/types/augment");
|
|
938
|
-
if (!clientOnly)
|
|
939
|
-
nuxt.options.alias["#auth/server"] = serverConfigPath;
|
|
940
|
-
nuxt.options.alias["#auth/client"] = clientConfigPath;
|
|
941
|
-
if (clientOnly) {
|
|
942
|
-
setupRuntimeConfig({
|
|
943
|
-
nuxt,
|
|
944
|
-
options,
|
|
945
|
-
clientOnly,
|
|
946
|
-
databaseProvider,
|
|
947
|
-
hasNuxtHub,
|
|
948
|
-
hub,
|
|
949
|
-
consola
|
|
950
|
-
});
|
|
951
|
-
} else {
|
|
952
|
-
const hubDialect = getHubDialect(hub) ?? "sqlite";
|
|
953
|
-
const usePlural = options.schema?.usePlural ?? false;
|
|
954
|
-
const camelCase = (options.schema?.casing ?? getHubCasing(hub)) !== "snake_case";
|
|
955
|
-
const providers = {
|
|
956
|
-
nuxthub: {
|
|
957
|
-
priority: 100,
|
|
958
|
-
isEnabled: ({ hasHubDbAvailable: hasHubDbAvailable2 }) => hasHubDbAvailable2,
|
|
959
|
-
buildDatabaseCode: () => buildDatabaseCode({
|
|
960
|
-
provider: "nuxthub",
|
|
961
|
-
hubDialect,
|
|
962
|
-
usePlural,
|
|
963
|
-
camelCase
|
|
964
|
-
})
|
|
965
|
-
},
|
|
966
|
-
none: {
|
|
967
|
-
priority: 0,
|
|
968
|
-
buildDatabaseCode: () => buildDatabaseCode({
|
|
969
|
-
provider: "none",
|
|
970
|
-
hubDialect,
|
|
971
|
-
usePlural,
|
|
972
|
-
camelCase
|
|
973
|
-
})
|
|
974
|
-
}
|
|
975
|
-
};
|
|
976
|
-
const enabledCtx = { nuxt, options, clientOnly, hasHubDbAvailable };
|
|
977
|
-
await nuxt.callHook("better-auth:database:providers", providers);
|
|
978
|
-
const resolvedProvider = resolveDatabaseProvider({ providers, context: enabledCtx });
|
|
979
|
-
databaseProvider = resolvedProvider.id;
|
|
980
|
-
hasHubDb = databaseProvider === "nuxthub";
|
|
981
|
-
const { useHubKV } = setupRuntimeConfig({
|
|
982
|
-
nuxt,
|
|
983
|
-
options,
|
|
984
|
-
clientOnly,
|
|
985
|
-
databaseProvider,
|
|
986
|
-
hasNuxtHub,
|
|
987
|
-
hub,
|
|
988
|
-
consola
|
|
989
|
-
});
|
|
990
|
-
if (useHubKV && !nuxt.options.alias["hub:kv"]) {
|
|
991
|
-
throw new Error("[nuxt-better-auth] hub:kv not found. Ensure @nuxthub/core is loaded before this module and hub.kv is enabled.");
|
|
992
|
-
}
|
|
1296
|
+
const setup = await resolveAuthModuleSetup({
|
|
1297
|
+
nuxt,
|
|
1298
|
+
options,
|
|
1299
|
+
runtimeTypesAugmentPath: resolver.resolve("./runtime/types/augment"),
|
|
1300
|
+
consola
|
|
1301
|
+
});
|
|
1302
|
+
nuxt.options.alias["#nuxt-better-auth"] = setup.aliases["#nuxt-better-auth"];
|
|
1303
|
+
if (setup.aliases["#auth/server"])
|
|
1304
|
+
nuxt.options.alias["#auth/server"] = setup.aliases["#auth/server"];
|
|
1305
|
+
nuxt.options.alias["#auth/client"] = setup.aliases["#auth/client"];
|
|
1306
|
+
if (!setup.clientOnly) {
|
|
993
1307
|
const secondaryStorageTemplate = addTemplate({
|
|
994
1308
|
filename: "better-auth/secondary-storage.mjs",
|
|
995
|
-
getContents: () => buildSecondaryStorageCode(useHubKV),
|
|
1309
|
+
getContents: () => buildSecondaryStorageCode(setup.runtime.useHubKV),
|
|
996
1310
|
write: true
|
|
997
1311
|
});
|
|
998
1312
|
nuxt.options.alias["#auth/secondary-storage"] = secondaryStorageTemplate.dst;
|
|
999
|
-
if (hasHubDb && !nuxt.options.alias["hub:db"]) {
|
|
1000
|
-
throw new Error("[nuxt-better-auth] hub:db not found. Ensure @nuxthub/core is loaded before this module and hub.db is configured.");
|
|
1001
|
-
}
|
|
1002
|
-
const setupCtx = { nuxt, options, clientOnly };
|
|
1003
|
-
await resolvedProvider.definition.setup?.(setupCtx);
|
|
1004
|
-
const buildCtx = { hubDialect, usePlural, camelCase };
|
|
1005
1313
|
const databaseTemplate = addTemplate({
|
|
1006
1314
|
filename: "better-auth/database.mjs",
|
|
1007
|
-
getContents: () =>
|
|
1315
|
+
getContents: () => setup.database.providerDefinition.buildDatabaseCode(setup.database.buildContext),
|
|
1008
1316
|
write: true
|
|
1009
1317
|
});
|
|
1010
1318
|
nuxt.options.alias["#auth/database"] = databaseTemplate.dst;
|
|
1011
1319
|
const schemaTemplate = addTemplate({
|
|
1012
1320
|
filename: "better-auth/schema.mjs",
|
|
1013
|
-
getContents: () =>
|
|
1014
|
-
if (!hasHubDb)
|
|
1015
|
-
return "export const schema = undefined\n";
|
|
1016
|
-
return `export * from './schema.${hubDialect}.mjs'
|
|
1017
|
-
import * as schema from './schema.${hubDialect}.mjs'
|
|
1018
|
-
export { schema }
|
|
1019
|
-
`;
|
|
1020
|
-
},
|
|
1321
|
+
getContents: () => buildSchemaExportCode(setup.database.hasHubDb, setup.database.buildContext?.hubDialect ?? "sqlite"),
|
|
1021
1322
|
write: true
|
|
1022
1323
|
});
|
|
1023
1324
|
nuxt.options.alias["#auth/schema"] = schemaTemplate.dst;
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1325
|
+
}
|
|
1326
|
+
if (setup.prepareTypes) {
|
|
1327
|
+
registerPrepareTypesHook({
|
|
1328
|
+
nuxt,
|
|
1329
|
+
serverDir: setup.prepareTypes.serverDir,
|
|
1330
|
+
hasHubDb: setup.prepareTypes.hasHubDb
|
|
1028
1331
|
});
|
|
1029
|
-
if (hasHubDb)
|
|
1030
|
-
await setupBetterAuthSchema(nuxt, serverConfigPath, options, consola, options.hubSecondaryStorage ?? false);
|
|
1031
1332
|
}
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
if (!rule || typeof rule !== "object" || !("auth" in rule))
|
|
1041
|
-
return [];
|
|
1042
|
-
return [[path, { auth: rule.auth }]];
|
|
1043
|
-
})
|
|
1044
|
-
);
|
|
1333
|
+
if (setup.database.providerDefinition) {
|
|
1334
|
+
const setupCtx = {
|
|
1335
|
+
nuxt,
|
|
1336
|
+
options,
|
|
1337
|
+
clientOnly: setup.clientOnly
|
|
1338
|
+
};
|
|
1339
|
+
await setup.database.providerDefinition.setup?.(setupCtx);
|
|
1340
|
+
}
|
|
1045
1341
|
const authRouteRulesTemplate = addTemplate({
|
|
1046
1342
|
filename: "better-auth/route-rules.mjs",
|
|
1047
|
-
getContents: () =>
|
|
1048
|
-
`,
|
|
1343
|
+
getContents: () => buildAuthRouteRulesCode(collectAuthRouteRules(nuxt)),
|
|
1049
1344
|
write: true
|
|
1050
1345
|
});
|
|
1051
1346
|
nuxt.options.alias["#auth/route-rules"] = authRouteRulesTemplate.dst;
|
|
1347
|
+
if (setup.serverTypes) {
|
|
1348
|
+
registerServerTypeTemplates({
|
|
1349
|
+
serverConfigPath: setup.serverTypes.serverConfigPath,
|
|
1350
|
+
hasHubDb: setup.serverTypes.hasHubDb,
|
|
1351
|
+
runtimeTypesPath: resolver.resolve("./runtime/types"),
|
|
1352
|
+
sharedServerConfigSafe: isServerConfigSharedTypeSafe(setup.serverTypes.serverConfigPath)
|
|
1353
|
+
});
|
|
1354
|
+
}
|
|
1355
|
+
if (setup.schemaGeneration) {
|
|
1356
|
+
if (setup.schemaGeneration.externalizeNuxtHubDatabase)
|
|
1357
|
+
registerNuxtHubDatabaseExternalHook(nuxt);
|
|
1358
|
+
await setupBetterAuthSchema(
|
|
1359
|
+
nuxt,
|
|
1360
|
+
setup.schemaGeneration.serverConfigPath,
|
|
1361
|
+
options,
|
|
1362
|
+
consola,
|
|
1363
|
+
setup.schemaGeneration.hubSecondaryStorage
|
|
1364
|
+
);
|
|
1365
|
+
}
|
|
1366
|
+
registerSharedTypeTemplates({
|
|
1367
|
+
runtimeTypesAugmentPath: setup.aliases["#nuxt-better-auth"],
|
|
1368
|
+
runtimeTypesPath: resolver.resolve("./runtime/types"),
|
|
1369
|
+
clientConfigPath: setup.sharedTypes.clientConfigPath
|
|
1370
|
+
});
|
|
1052
1371
|
registerTemplateHmrHook(nuxt);
|
|
1053
|
-
registerServerRuntime({ clientOnly, resolve: resolver.resolve });
|
|
1372
|
+
registerServerRuntime({ clientOnly: setup.clientOnly, resolve: resolver.resolve });
|
|
1054
1373
|
registerAuthMiddlewareHook(nuxt, resolver.resolve);
|
|
1055
|
-
await registerDevtools({ nuxt, clientOnly, hasHubDb, resolve: resolver.resolve });
|
|
1374
|
+
await registerDevtools({ nuxt, clientOnly: setup.clientOnly, hasHubDb: setup.database.hasHubDb, resolve: resolver.resolve });
|
|
1056
1375
|
registerRouteRulesMetaHook(nuxt);
|
|
1057
1376
|
}
|
|
1058
1377
|
});
|