@onmax/nuxt-better-auth 0.0.2-alpha.9 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +57 -17
  2. package/dist/module.d.mts +28 -1
  3. package/dist/module.json +3 -3
  4. package/dist/module.mjs +1258 -351
  5. package/dist/runtime/app/components/BetterAuthState.d.vue.ts +4 -4
  6. package/dist/runtime/app/components/BetterAuthState.vue +1 -0
  7. package/dist/runtime/app/components/BetterAuthState.vue.d.ts +4 -4
  8. package/dist/runtime/app/composables/runWithSessionRefresh.d.ts +1 -0
  9. package/dist/runtime/app/composables/runWithSessionRefresh.js +12 -0
  10. package/dist/runtime/app/composables/useAction.d.ts +2 -0
  11. package/dist/runtime/app/composables/useAction.js +6 -0
  12. package/dist/runtime/app/composables/useAuthAsyncData.d.ts +6 -0
  13. package/dist/runtime/app/composables/useAuthAsyncData.js +16 -0
  14. package/dist/runtime/app/composables/useAuthClient.d.ts +9 -0
  15. package/dist/runtime/app/composables/useAuthClient.js +34 -0
  16. package/dist/runtime/app/composables/useAuthClientAction.d.ts +3 -0
  17. package/dist/runtime/app/composables/useAuthClientAction.js +15 -0
  18. package/dist/runtime/app/composables/useAuthRequestFetch.d.ts +11 -0
  19. package/dist/runtime/app/composables/useAuthRequestFetch.js +4 -0
  20. package/dist/runtime/app/composables/useSignIn.d.ts +16 -0
  21. package/dist/runtime/app/composables/useSignIn.js +8 -0
  22. package/dist/runtime/app/composables/useSignUp.d.ts +5 -0
  23. package/dist/runtime/app/composables/useSignUp.js +8 -0
  24. package/dist/runtime/app/composables/useUserSession.d.ts +6 -5
  25. package/dist/runtime/app/composables/useUserSession.js +189 -100
  26. package/dist/runtime/app/composables/useUserSessionState.d.ts +3 -0
  27. package/dist/runtime/app/composables/useUserSessionState.js +4 -0
  28. package/dist/runtime/app/internal/auth-action-error.d.ts +3 -0
  29. package/dist/runtime/app/internal/auth-action-error.js +33 -0
  30. package/dist/runtime/app/internal/auth-action-handles.d.ts +21 -0
  31. package/dist/runtime/app/internal/auth-action-handles.js +105 -0
  32. package/dist/runtime/app/internal/redirect-helpers.d.ts +4 -0
  33. package/dist/runtime/app/internal/redirect-helpers.js +37 -0
  34. package/dist/runtime/app/internal/session-fetch.d.ts +12 -0
  35. package/dist/runtime/app/internal/session-fetch.js +56 -0
  36. package/dist/runtime/app/internal/utils.d.ts +1 -0
  37. package/dist/runtime/app/internal/utils.js +3 -0
  38. package/dist/runtime/app/internal/vue-safe-auth-proxy.d.ts +3 -0
  39. package/dist/runtime/app/internal/vue-safe-auth-proxy.js +68 -0
  40. package/dist/runtime/app/internal/wrap-auth-method.d.ts +18 -0
  41. package/dist/runtime/app/internal/wrap-auth-method.js +69 -0
  42. package/dist/runtime/app/middleware/auth.global.js +80 -15
  43. package/dist/runtime/app/pages/__better-auth-devtools.vue +293 -339
  44. package/dist/runtime/composables.d.ts +12 -0
  45. package/dist/runtime/composables.js +10 -0
  46. package/dist/runtime/config.d.ts +69 -15
  47. package/dist/runtime/config.js +9 -2
  48. package/dist/runtime/internal/auth-route-rules.d.ts +1 -0
  49. package/dist/runtime/internal/auth-route-rules.js +24 -0
  50. package/dist/runtime/server/api/_better-auth/_schema.d.ts +1 -5
  51. package/dist/runtime/server/api/_better-auth/_schema.js +2 -1
  52. package/dist/runtime/server/api/_better-auth/accounts.get.d.ts +2 -2
  53. package/dist/runtime/server/api/_better-auth/accounts.get.js +3 -2
  54. package/dist/runtime/server/api/_better-auth/config.get.d.ts +9 -3
  55. package/dist/runtime/server/api/_better-auth/config.get.js +18 -6
  56. package/dist/runtime/server/api/_better-auth/sessions.delete.js +3 -2
  57. package/dist/runtime/server/api/_better-auth/sessions.get.d.ts +5 -3
  58. package/dist/runtime/server/api/_better-auth/sessions.get.js +3 -2
  59. package/dist/runtime/server/api/_better-auth/users.get.d.ts +2 -2
  60. package/dist/runtime/server/api/_better-auth/users.get.js +3 -2
  61. package/dist/runtime/server/api/auth/[...all].js +1 -1
  62. package/dist/runtime/server/middleware/route-access.js +4 -2
  63. package/dist/runtime/server/tsconfig.json +9 -1
  64. package/dist/runtime/server/utils/auth.d.ts +16 -8
  65. package/dist/runtime/server/utils/auth.js +229 -23
  66. package/dist/runtime/server/utils/custom-secondary-storage.d.ts +6 -0
  67. package/dist/runtime/server/utils/custom-secondary-storage.js +8 -0
  68. package/dist/runtime/server/utils/session.d.ts +7 -8
  69. package/dist/runtime/server/utils/session.js +256 -5
  70. package/dist/runtime/server/virtual-modules.d.ts +27 -0
  71. package/dist/runtime/types/augment.d.ts +18 -4
  72. package/dist/runtime/types.d.ts +12 -13
  73. package/dist/types.d.mts +1 -1
  74. package/package.json +53 -47
package/dist/module.mjs CHANGED
@@ -1,15 +1,134 @@
1
- import { existsSync } from 'node:fs';
1
+ import { existsSync, statSync, writeFileSync, readFileSync } from 'node:fs';
2
2
  import { mkdir, writeFile } from 'node:fs/promises';
3
- import { defineNuxtModule, createResolver, hasNuxtModule, addTemplate, addTypeTemplate, updateTemplates, addServerImportsDir, addServerScanDir, addServerHandler, addImportsDir, addPlugin, addComponentsDir, extendPages } from '@nuxt/kit';
3
+ import { getLayerDirectories, updateTemplates, addServerImportsDir, addServerImports, addServerScanDir, addServerHandler, addImportsDir, addPlugin, addComponentsDir, extendPages, addTemplate, hasNuxtModule, addTypeTemplate, defineNuxtModule, createResolver } from '@nuxt/kit';
4
4
  import { consola as consola$1 } from 'consola';
5
+ import { isAbsolute, join, relative, dirname } from 'pathe';
5
6
  import { defu } from 'defu';
6
- import { join } from 'pathe';
7
7
  import { toRouteMatcher, createRouter } from 'radix3';
8
- import pluralize from 'pluralize';
8
+ import { generateDrizzleSchema as generateDrizzleSchema$1 } from '@better-auth/cli/api';
9
+ import { randomBytes } from 'node:crypto';
10
+ import { isCI, isTest } from 'std-env';
9
11
  export { defineClientAuth, defineServerAuth } from '../dist/runtime/config.js';
10
12
 
13
+ const version = "0.0.3";
14
+
15
+ const CONFIG_EXTENSIONS = [".ts", ".js"];
16
+ const CONFIG_EXTENSION_RE = /\.(?:ts|js)$/;
17
+ const DEFAULT_CONFIG_FILES = {
18
+ server: "server/auth.config",
19
+ client: "app/auth.config"
20
+ };
21
+ const OPTION_KEY_BY_KIND = {
22
+ server: "serverConfig",
23
+ client: "clientConfig"
24
+ };
25
+ function stripConfigExtension(path) {
26
+ return path.replace(CONFIG_EXTENSION_RE, "");
27
+ }
28
+ function defaultConfigExists(path) {
29
+ return CONFIG_EXTENSIONS.some((ext) => existsSync(`${path}${ext}`));
30
+ }
31
+ function getLayerDirectoriesWithConfigs(nuxt) {
32
+ const directories = getLayerDirectories(nuxt);
33
+ const layers = nuxt.options._layers;
34
+ return directories.map((directory, index) => ({ directory, layer: layers[index] }));
35
+ }
36
+ function getProjectDirectory(nuxt) {
37
+ return getLayerDirectories(nuxt)[0];
38
+ }
39
+ function getDefaultConfigPath(nuxt, kind) {
40
+ const project = getProjectDirectory(nuxt);
41
+ return kind === "server" ? join(project.server, "auth.config") : join(project.app, "auth.config");
42
+ }
43
+ function getLayerDefaultConfigPath(nuxt, kind, configExists) {
44
+ for (const { directory } of getLayerDirectoriesWithConfigs(nuxt)) {
45
+ const candidate = kind === "server" ? join(directory.server, "auth.config") : join(directory.app, "auth.config");
46
+ if (configExists(candidate)) {
47
+ return {
48
+ path: candidate,
49
+ declaringLayerRoot: directory.root
50
+ };
51
+ }
52
+ }
53
+ }
54
+ function resolveDeclaringLayerRoot(nuxt, kind, file) {
55
+ const optionKey = OPTION_KEY_BY_KIND[kind];
56
+ for (const { directory, layer } of getLayerDirectoriesWithConfigs(nuxt)) {
57
+ const declared = layer?.config?.auth?.[optionKey];
58
+ if (typeof declared === "string" && stripConfigExtension(declared) === file)
59
+ return directory.root;
60
+ }
61
+ return getProjectDirectory(nuxt).root;
62
+ }
63
+ function getRelativeConfigFile(nuxt, path) {
64
+ return relative(getProjectDirectory(nuxt).root, path);
65
+ }
66
+ function getEffectiveModuleConfigFile(nuxt, kind) {
67
+ const optionKey = OPTION_KEY_BY_KIND[kind];
68
+ const authOptions = nuxt.options.auth;
69
+ return authOptions?.[optionKey] ?? DEFAULT_CONFIG_FILES[kind];
70
+ }
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);
77
+ return {
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
87
+ };
88
+ }
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
+ return {
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
105
+ };
106
+ }
107
+ const declaringLayerRoot = resolveDeclaringLayerRoot(nuxt, kind, configuredFile);
108
+ const path = join(declaringLayerRoot, configuredFile);
109
+ const exists = configExists(path);
110
+ return {
111
+ kind,
112
+ configuredFile,
113
+ file: getRelativeConfigFile(nuxt, path),
114
+ path,
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)
126
+ };
127
+ }
128
+
11
129
  function setupDevTools(nuxt) {
12
- nuxt.hook("devtools:customTabs", (tabs) => {
130
+ const hookable = nuxt;
131
+ hookable.hook("devtools:customTabs", (tabs) => {
13
132
  tabs.push({
14
133
  category: "server",
15
134
  name: "better-auth",
@@ -23,152 +142,177 @@ function setupDevTools(nuxt) {
23
142
  });
24
143
  }
25
144
 
26
- function toSnakeCase(str) {
27
- return str.replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").replace(/([a-z\d])([A-Z])/g, "$1_$2").toLowerCase();
145
+ function registerTemplateHmrHook(nuxt) {
146
+ nuxt.hook("builder:watch", async (_event, relativePath) => {
147
+ if (relativePath.includes("auth.config"))
148
+ await updateTemplates({ filter: (t) => t.filename.includes("nuxt-better-auth") });
149
+ });
150
+ }
151
+ function registerServerRuntime(input) {
152
+ const { clientOnly, resolve } = input;
153
+ if (!clientOnly) {
154
+ addServerImportsDir(resolve("./runtime/server/utils"));
155
+ addServerImports([{ name: "defineServerAuth", from: resolve("./runtime/config") }]);
156
+ addServerScanDir(resolve("./runtime/server/middleware"));
157
+ addServerHandler({ route: "/api/auth/**", handler: resolve("./runtime/server/api/auth/[...all]") });
158
+ }
159
+ addImportsDir(resolve("./runtime/app/composables"));
160
+ addImportsDir(resolve("./runtime/utils"));
161
+ if (!clientOnly)
162
+ addPlugin({ src: resolve("./runtime/app/plugins/session.server"), mode: "server" });
163
+ addPlugin({ src: resolve("./runtime/app/plugins/session.client"), mode: "client" });
164
+ addComponentsDir({ path: resolve("./runtime/app/components") });
165
+ }
166
+ function registerAuthMiddlewareHook(nuxt, resolve) {
167
+ nuxt.hook("app:resolve", (app) => {
168
+ app.middleware.push({ name: "auth", path: resolve("./runtime/app/middleware/auth.global"), global: true });
169
+ });
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
+ }
222
+ async function registerDevtools(input) {
223
+ const { nuxt, clientOnly, hasHubDb, resolve } = input;
224
+ const isProduction = process.env.NODE_ENV === "production" || !nuxt.options.dev;
225
+ if (isProduction || clientOnly)
226
+ return;
227
+ setupDevTools(nuxt);
228
+ addServerHandler({ route: "/api/_better-auth/config", method: "get", handler: resolve("./runtime/server/api/_better-auth/config.get") });
229
+ if (hasHubDb) {
230
+ const handlers = [
231
+ { route: "/api/_better-auth/sessions", method: "get", handler: resolve("./runtime/server/api/_better-auth/sessions.get") },
232
+ { route: "/api/_better-auth/sessions", method: "delete", handler: resolve("./runtime/server/api/_better-auth/sessions.delete") },
233
+ { route: "/api/_better-auth/users", method: "get", handler: resolve("./runtime/server/api/_better-auth/users.get") },
234
+ { route: "/api/_better-auth/accounts", method: "get", handler: resolve("./runtime/server/api/_better-auth/accounts.get") }
235
+ ];
236
+ handlers.forEach((handler) => addServerHandler(handler));
237
+ }
238
+ extendPages((pages) => {
239
+ pages.push({ name: "better-auth-devtools", path: "/__better-auth-devtools", file: resolve("./runtime/app/pages/__better-auth-devtools.vue"), meta: { layout: false } });
240
+ });
241
+ }
242
+ function registerRouteRulesMetaHook(nuxt) {
243
+ nuxt.hook("pages:extend", (pages) => {
244
+ const options = nuxt.options;
245
+ const routeRules = options.nitro?.routeRules || options.routeRules || {};
246
+ if (!Object.keys(routeRules).length)
247
+ return;
248
+ const matcher = toRouteMatcher(createRouter({ routes: routeRules }));
249
+ const applyMetaFromRules = (page) => {
250
+ const matches = matcher.matchAll(page.path);
251
+ if (!matches.length)
252
+ return;
253
+ const matchedRules = defu({}, ...matches.reverse());
254
+ if (matchedRules.auth !== void 0) {
255
+ page.meta = page.meta || {};
256
+ page.meta.auth = matchedRules.auth;
257
+ }
258
+ page.children?.forEach((child) => applyMetaFromRules(child));
259
+ };
260
+ pages.forEach((page) => applyMetaFromRules(page));
261
+ });
28
262
  }
29
- function generateDrizzleSchema(tables, dialect, options) {
30
- const typedTables = tables;
31
- const imports = getImports(dialect, options);
32
- const tableDefinitions = Object.entries(typedTables).map(([tableName, table]) => generateTable(tableName, table, dialect, typedTables, options)).join("\n\n");
33
- return `${imports}
34
263
 
35
- ${tableDefinitions}
36
- `;
264
+ function dialectToProvider(dialect) {
265
+ return dialect === "postgresql" ? "pg" : dialect;
37
266
  }
38
- function getImports(dialect, options) {
39
- switch (dialect) {
40
- case "sqlite":
41
- return `import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'`;
42
- case "postgresql":
43
- return options?.useUuid ? `import { boolean, integer, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core'` : `import { boolean, integer, pgTable, text, timestamp } from 'drizzle-orm/pg-core'`;
44
- case "mysql":
45
- return `import { boolean, int, mysqlTable, text, timestamp, varchar } from 'drizzle-orm/mysql-core'`;
46
- }
47
- }
48
- function generateTable(tableName, table, dialect, allTables, options) {
49
- const tableFunc = dialect === "sqlite" ? "sqliteTable" : dialect === "postgresql" ? "pgTable" : "mysqlTable";
50
- const hasCustomModelName = table.modelName && table.modelName !== tableName;
51
- let dbTableName = hasCustomModelName ? table.modelName : tableName;
52
- if (options?.casing === "snake_case" && !hasCustomModelName)
53
- dbTableName = toSnakeCase(dbTableName);
54
- if (options?.usePlural && !hasCustomModelName)
55
- dbTableName = pluralize(dbTableName);
56
- const fields = Object.entries(table.fields).map(([fieldName, field]) => generateField(fieldName, field, dialect, allTables, options)).join(",\n ");
57
- const idField = generateIdField(dialect, options);
58
- return `export const ${tableName} = ${tableFunc}('${dbTableName}', {
59
- ${idField},
60
- ${fields}
61
- })`;
62
- }
63
- function generateIdField(dialect, options) {
64
- switch (dialect) {
65
- case "sqlite":
66
- if (options?.useUuid)
67
- consola$1.warn("[@onmax/nuxt-better-auth] useUuid ignored for SQLite (no native uuid type). Using text.");
68
- return `id: text('id').primaryKey()`;
69
- case "postgresql":
70
- return options?.useUuid ? `id: uuid('id').defaultRandom().primaryKey()` : `id: text('id').primaryKey()`;
71
- case "mysql":
72
- return `id: varchar('id', { length: 36 }).primaryKey()`;
73
- }
74
- }
75
- function generateField(fieldName, field, dialect, allTables, options) {
76
- const dbFieldName = options?.casing === "snake_case" ? toSnakeCase(fieldName) : fieldName;
77
- const isFkToId = options?.useUuid && field.references?.field === "id";
78
- let fieldDef;
79
- if (isFkToId && dialect === "postgresql")
80
- fieldDef = `uuid('${dbFieldName}')`;
81
- else if (isFkToId && dialect === "mysql")
82
- fieldDef = `varchar('${dbFieldName}', { length: 36 })`;
83
- else
84
- fieldDef = getFieldType(field.type, dialect, dbFieldName);
85
- if (field.required && field.defaultValue === void 0)
86
- fieldDef += ".notNull()";
87
- if (field.unique)
88
- fieldDef += ".unique()";
89
- if (field.defaultValue !== void 0) {
90
- if (typeof field.defaultValue === "boolean")
91
- fieldDef += `.default(${field.defaultValue})`;
92
- else if (typeof field.defaultValue === "string")
93
- fieldDef += `.default('${field.defaultValue}')`;
94
- else if (typeof field.defaultValue === "function")
95
- fieldDef += `.$defaultFn(${field.defaultValue})`;
96
- else
97
- fieldDef += `.default(${field.defaultValue})`;
98
- if (field.required)
99
- fieldDef += ".notNull()";
100
- }
101
- if (typeof field.onUpdate === "function" && field.type === "date")
102
- fieldDef += `.$onUpdate(${field.onUpdate})`;
103
- if (field.references) {
104
- const refTable = field.references.model;
105
- if (allTables[refTable])
106
- fieldDef += `.references(() => ${refTable}.${field.references.field})`;
107
- }
108
- return `${fieldName}: ${fieldDef}`;
109
- }
110
- function getFieldType(type, dialect, fieldName) {
111
- const normalizedType = Array.isArray(type) ? "string" : type;
112
- switch (dialect) {
113
- case "sqlite":
114
- return getSqliteType(normalizedType, fieldName);
115
- case "postgresql":
116
- return getPostgresType(normalizedType, fieldName);
117
- case "mysql":
118
- return getMysqlType(normalizedType, fieldName);
119
- }
120
- }
121
- function getSqliteType(type, fieldName) {
122
- switch (type) {
123
- case "string":
124
- return `text('${fieldName}')`;
125
- case "boolean":
126
- return `integer('${fieldName}', { mode: 'boolean' })`;
127
- case "date":
128
- return `integer('${fieldName}', { mode: 'timestamp' })`;
129
- case "number":
130
- return `integer('${fieldName}')`;
131
- default:
132
- return `text('${fieldName}')`;
133
- }
134
- }
135
- function getPostgresType(type, fieldName) {
136
- switch (type) {
137
- case "string":
138
- return `text('${fieldName}')`;
139
- case "boolean":
140
- return `boolean('${fieldName}')`;
141
- case "date":
142
- return `timestamp('${fieldName}')`;
143
- case "number":
144
- return `integer('${fieldName}')`;
145
- default:
146
- return `text('${fieldName}')`;
147
- }
148
- }
149
- function getMysqlType(type, fieldName) {
150
- switch (type) {
151
- case "string":
152
- return `text('${fieldName}')`;
153
- case "boolean":
154
- return `boolean('${fieldName}')`;
155
- case "date":
156
- return `timestamp('${fieldName}')`;
157
- case "number":
158
- return `int('${fieldName}')`;
159
- default:
160
- return `text('${fieldName}')`;
161
- }
162
- }
163
- async function loadUserAuthConfig(configPath, throwOnError = false) {
267
+ async function generateDrizzleSchema(authOptions, dialect, schemaOptions) {
268
+ const provider = dialectToProvider(dialect);
269
+ const options = {
270
+ ...authOptions,
271
+ advanced: {
272
+ ...authOptions.advanced,
273
+ database: {
274
+ ...authOptions.advanced?.database,
275
+ ...schemaOptions?.useUuid && { generateId: "uuid" }
276
+ }
277
+ }
278
+ };
279
+ const adapter = {
280
+ id: "drizzle",
281
+ options: {
282
+ provider,
283
+ camelCase: schemaOptions?.casing !== "snake_case",
284
+ adapterConfig: { usePlural: schemaOptions?.usePlural ?? false }
285
+ }
286
+ };
287
+ const result = await generateDrizzleSchema$1({
288
+ adapter,
289
+ options
290
+ });
291
+ if (!result.code) {
292
+ throw new Error(`Schema generation returned empty result for ${dialect}`);
293
+ }
294
+ return result.code;
295
+ }
296
+ async function loadUserAuthConfig(configPath, throwOnError = false, alias, runtimeConfig = {}) {
164
297
  const { createJiti } = await import('jiti');
165
- const jiti = createJiti(import.meta.url, { interopDefault: true });
298
+ const { defineServerAuth: runtimeDefineServerAuth } = await import('../dist/runtime/config.js');
299
+ const jiti = createJiti(import.meta.url, { interopDefault: true, moduleCache: false, alias });
300
+ const schemaGlobals = globalThis;
301
+ if (!schemaGlobals.__nuxtBetterAuthDefineServerAuth) {
302
+ runtimeDefineServerAuth._count = 0;
303
+ schemaGlobals.__nuxtBetterAuthDefineServerAuth = runtimeDefineServerAuth;
304
+ }
305
+ if (!schemaGlobals.defineServerAuth) {
306
+ schemaGlobals.defineServerAuth = schemaGlobals.__nuxtBetterAuthDefineServerAuth;
307
+ }
308
+ schemaGlobals.__nuxtBetterAuthDefineServerAuth._count++;
166
309
  try {
167
310
  const mod = await jiti.import(configPath);
168
- const configFn = typeof mod === "object" && mod !== null && "default" in mod ? mod.default : mod;
311
+ const configFn = mod.default;
169
312
  if (typeof configFn === "function") {
170
- return configFn({ runtimeConfig: {}, db: null });
313
+ return configFn({ runtimeConfig, db: null });
171
314
  }
315
+ consola$1.warn("[@onmax/nuxt-better-auth] auth.config.ts does not export default. Expected: export default defineServerAuth(...)");
172
316
  if (throwOnError) {
173
317
  throw new Error("auth.config.ts must export default defineServerAuth(...)");
174
318
  }
@@ -179,6 +323,17 @@ async function loadUserAuthConfig(configPath, throwOnError = false) {
179
323
  }
180
324
  consola$1.error("[@onmax/nuxt-better-auth] Failed to load auth config for schema generation. Schema may be incomplete:", error);
181
325
  return {};
326
+ } finally {
327
+ const sharedDefineServerAuth = schemaGlobals.__nuxtBetterAuthDefineServerAuth;
328
+ if (sharedDefineServerAuth) {
329
+ sharedDefineServerAuth._count--;
330
+ if (!sharedDefineServerAuth._count) {
331
+ schemaGlobals.__nuxtBetterAuthDefineServerAuth = void 0;
332
+ if (schemaGlobals.defineServerAuth === sharedDefineServerAuth) {
333
+ schemaGlobals.defineServerAuth = void 0;
334
+ }
335
+ }
336
+ }
182
337
  }
183
338
  }
184
339
 
@@ -196,85 +351,532 @@ function getHubCasing(hub) {
196
351
  return void 0;
197
352
  return hub.db.casing;
198
353
  }
199
- const consola = consola$1.withTag("nuxt-better-auth");
200
- const module$1 = defineNuxtModule({
201
- meta: { name: "@onmax/nuxt-better-auth", configKey: "auth", compatibility: { nuxt: ">=3.0.0" } },
202
- defaults: {
203
- serverConfig: "server/auth.config",
204
- clientConfig: "app/auth.config",
205
- redirects: { login: "/login", guest: "/" },
206
- secondaryStorage: false
207
- },
208
- async setup(options, nuxt) {
209
- const resolver = createResolver(import.meta.url);
210
- const serverConfigFile = options.serverConfig;
211
- const clientConfigFile = options.clientConfig;
212
- const serverConfigPath = resolver.resolve(nuxt.options.rootDir, serverConfigFile);
213
- const clientConfigPath = resolver.resolve(nuxt.options.rootDir, clientConfigFile);
214
- const serverConfigExists = existsSync(`${serverConfigPath}.ts`) || existsSync(`${serverConfigPath}.js`);
215
- const clientConfigExists = existsSync(`${clientConfigPath}.ts`) || existsSync(`${clientConfigPath}.js`);
216
- if (!serverConfigExists)
217
- throw new Error(`[nuxt-better-auth] Missing ${serverConfigFile}.ts - create with defineServerAuth()`);
218
- if (!clientConfigExists)
219
- throw new Error(`[nuxt-better-auth] Missing ${clientConfigFile}.ts - export createAppAuthClient()`);
220
- const hasNuxtHub = hasNuxtModule("@nuxthub/core", nuxt);
221
- const hub = hasNuxtHub ? nuxt.options.hub : void 0;
222
- const hasHubDb = hasNuxtHub && !!hub?.db;
223
- let secondaryStorageEnabled = options.secondaryStorage ?? false;
224
- if (secondaryStorageEnabled && (!hasNuxtHub || !hub?.kv)) {
225
- consola.warn("secondaryStorage requires @nuxthub/core with hub.kv: true. Disabling.");
226
- secondaryStorageEnabled = false;
354
+
355
+ const NODE_MODULES_SEGMENT_RE = /[\\/]/;
356
+ function resolveSchemaSecondaryStorageInjection(hubSecondaryStorage, userHasSecondaryStorage, isProduction) {
357
+ if (hubSecondaryStorage === true)
358
+ return { inject: false };
359
+ if (hubSecondaryStorage !== "custom")
360
+ return { inject: false };
361
+ if (userHasSecondaryStorage)
362
+ return { inject: true };
363
+ const message = '[nuxt-better-auth] hubSecondaryStorage: "custom" requires secondaryStorage in defineServerAuth() to omit the session table from the generated schema.';
364
+ if (isProduction)
365
+ return { inject: false, error: message };
366
+ return { inject: false, warn: message };
367
+ }
368
+ function isInsideNodeModules(path) {
369
+ return path.split(NODE_MODULES_SEGMENT_RE).includes("node_modules");
370
+ }
371
+ function resolveHubSchemaPath(buildDir, rootDir, dialect, exists = existsSync) {
372
+ const rootTsPath = join(rootDir, ".nuxt", "better-auth", `schema.${dialect}.ts`);
373
+ if (isInsideNodeModules(buildDir) && exists(rootTsPath))
374
+ return rootTsPath;
375
+ const tsPath = join(buildDir, "better-auth", `schema.${dialect}.ts`);
376
+ if (exists(tsPath))
377
+ return tsPath;
378
+ const mjsPath = join(buildDir, "better-auth", `schema.${dialect}.mjs`);
379
+ if (exists(mjsPath))
380
+ return mjsPath;
381
+ return null;
382
+ }
383
+ async function loadAuthOptions(context) {
384
+ const isProduction = !context.nuxt.options.dev;
385
+ const configFile = `${context.serverConfigPath}.ts`;
386
+ const alias = Object.fromEntries(
387
+ Object.entries(context.nuxt.options.alias).filter(([, value]) => typeof value === "string").map(([key, value]) => [key, value])
388
+ );
389
+ const userConfig = await loadUserAuthConfig(configFile, isProduction, alias, context.nuxt.options.runtimeConfig);
390
+ const extendedConfig = {};
391
+ await context.nuxt.callHook("better-auth:config:extend", extendedConfig);
392
+ const plugins = [...userConfig.plugins || [], ...extendedConfig.plugins || []];
393
+ return { userConfig, plugins };
394
+ }
395
+ async function setupBetterAuthSchema(nuxt, serverConfigPath, options, consola, hubSecondaryStorage) {
396
+ const hub = nuxt.options.hub;
397
+ const dialect = getHubDialect(hub);
398
+ if (!dialect || !["sqlite", "postgresql", "mysql"].includes(dialect)) {
399
+ consola.warn(`Unsupported database dialect: ${dialect}`);
400
+ return;
401
+ }
402
+ const context = { nuxt, serverConfigPath };
403
+ try {
404
+ const { userConfig, plugins } = await loadAuthOptions(context);
405
+ const userHasSecondaryStorage = userConfig.secondaryStorage != null;
406
+ const secondaryStorageResolution = resolveSchemaSecondaryStorageInjection(hubSecondaryStorage, userHasSecondaryStorage, !nuxt.options.dev);
407
+ if (secondaryStorageResolution.error)
408
+ throw new Error(secondaryStorageResolution.error);
409
+ if (secondaryStorageResolution.warn)
410
+ consola.warn(secondaryStorageResolution.warn);
411
+ const authOptions = {
412
+ ...userConfig,
413
+ plugins,
414
+ secondaryStorage: secondaryStorageResolution.inject ? { get: async (_key) => null, set: async (_key, _value, _ttl) => {
415
+ }, delete: async (_key) => {
416
+ } } : void 0
417
+ };
418
+ const hubCasing = getHubCasing(hub);
419
+ const schemaOptions = { ...options.schema, useUuid: userConfig.advanced?.database?.generateId === "uuid", casing: options.schema?.casing ?? hubCasing };
420
+ const schemaCode = await generateDrizzleSchema(authOptions, dialect, schemaOptions);
421
+ const schemaDir = join(nuxt.options.buildDir, "better-auth");
422
+ const schemaPathTs = join(schemaDir, `schema.${dialect}.ts`);
423
+ const schemaPathMjs = join(schemaDir, `schema.${dialect}.mjs`);
424
+ await mkdir(schemaDir, { recursive: true });
425
+ await writeFile(schemaPathTs, schemaCode);
426
+ await writeFile(schemaPathMjs, schemaCode);
427
+ if (isInsideNodeModules(nuxt.options.buildDir)) {
428
+ const rootSchemaDir = join(nuxt.options.rootDir, ".nuxt", "better-auth");
429
+ const rootSchemaPathTs = join(rootSchemaDir, `schema.${dialect}.ts`);
430
+ await mkdir(rootSchemaDir, { recursive: true });
431
+ await writeFile(rootSchemaPathTs, schemaCode);
227
432
  }
228
- nuxt.options.runtimeConfig.public = nuxt.options.runtimeConfig.public || {};
229
- nuxt.options.runtimeConfig.public.auth = defu(nuxt.options.runtimeConfig.public.auth, {
230
- redirects: { login: options.redirects?.login ?? "/login", guest: options.redirects?.guest ?? "/" },
231
- useDatabase: hasHubDb
433
+ addTemplate({ filename: `better-auth/schema.${dialect}.ts`, getContents: () => schemaCode, write: true });
434
+ addTemplate({ filename: `better-auth/schema.${dialect}.mjs`, getContents: () => schemaCode, write: true });
435
+ consola.info(`Generated ${dialect} schema (.ts + .mjs)`);
436
+ const nuxtWithHubHooks = nuxt;
437
+ nuxtWithHubHooks.hook("hub:db:schema:extend", ({ paths, dialect: hookDialect }) => {
438
+ const schemaPath = resolveHubSchemaPath(nuxt.options.buildDir, nuxt.options.rootDir, hookDialect);
439
+ if (schemaPath)
440
+ paths.unshift(schemaPath);
232
441
  });
233
- const betterAuthSecret = process.env.BETTER_AUTH_SECRET || process.env.NUXT_BETTER_AUTH_SECRET || nuxt.options.runtimeConfig.betterAuthSecret || "";
234
- if (!nuxt.options.dev && !betterAuthSecret) {
235
- throw new Error("[nuxt-better-auth] BETTER_AUTH_SECRET is required in production. Set BETTER_AUTH_SECRET or NUXT_BETTER_AUTH_SECRET environment variable.");
236
- }
237
- if (betterAuthSecret && betterAuthSecret.length < 32) {
238
- throw new Error("[nuxt-better-auth] BETTER_AUTH_SECRET must be at least 32 characters for security");
442
+ } catch (error) {
443
+ const isProduction = !nuxt.options.dev;
444
+ if (isProduction)
445
+ throw error;
446
+ consola.error("Failed to generate schema:", error);
447
+ throw error;
448
+ }
449
+ }
450
+
451
+ const DEFAULT_SECRET_ENV = "NUXT_BETTER_AUTH_SECRET";
452
+ const FALLBACK_SECRET_ENV = "BETTER_AUTH_SECRET";
453
+ const generateSecret = () => randomBytes(32).toString("hex");
454
+ function readEnvFile(rootDir) {
455
+ const envPath = join(rootDir, ".env");
456
+ return existsSync(envPath) ? readFileSync(envPath, "utf-8") : "";
457
+ }
458
+ function hasEnvSecret(rootDir) {
459
+ const envFile = readEnvFile(rootDir);
460
+ return [DEFAULT_SECRET_ENV, FALLBACK_SECRET_ENV].some((name) => {
461
+ const match = envFile.match(new RegExp(`^${name}=(.+)$`, "m"));
462
+ return !!match && !!match[1] && match[1].trim().length > 0;
463
+ });
464
+ }
465
+ function appendSecretToEnv(rootDir, secret) {
466
+ const envPath = join(rootDir, ".env");
467
+ let content = readEnvFile(rootDir);
468
+ if (content.length > 0 && !content.endsWith("\n"))
469
+ content += "\n";
470
+ content += `${DEFAULT_SECRET_ENV}=${secret}
471
+ `;
472
+ writeFileSync(envPath, content, "utf-8");
473
+ }
474
+ async function promptForSecret(rootDir, consola, options = {}) {
475
+ const configuredSecret = options.configuredSecret?.trim();
476
+ if (configuredSecret)
477
+ return void 0;
478
+ if (process.env.NUXT_BETTER_AUTH_SECRET || process.env.BETTER_AUTH_SECRET || hasEnvSecret(rootDir))
479
+ return void 0;
480
+ const hasTty = Boolean(process.stdin.isTTY && process.stdout.isTTY);
481
+ if (options.prepare || !hasTty) {
482
+ consola.warn("[nuxt-better-auth] Skipping NUXT_BETTER_AUTH_SECRET prompt (non-interactive). Set NUXT_BETTER_AUTH_SECRET or BETTER_AUTH_SECRET.");
483
+ return void 0;
484
+ }
485
+ if (isCI || isTest) {
486
+ const secret2 = generateSecret();
487
+ appendSecretToEnv(rootDir, secret2);
488
+ consola.info("Generated NUXT_BETTER_AUTH_SECRET and added to .env (CI/test mode)");
489
+ return secret2;
490
+ }
491
+ consola.box("NUXT_BETTER_AUTH_SECRET is required for authentication.\nThis will be appended to your .env file.\nBETTER_AUTH_SECRET is still supported as a fallback.");
492
+ const choice = await consola.prompt("How do you want to set it?", {
493
+ type: "select",
494
+ options: [
495
+ { label: "Generate for me", value: "generate", hint: "uses crypto.randomBytes(32)" },
496
+ { label: "Enter manually", value: "paste" },
497
+ { label: "Skip", value: "skip", hint: "will fail in production" }
498
+ ],
499
+ cancel: "null"
500
+ });
501
+ if (typeof choice === "symbol" || choice === "skip") {
502
+ consola.warn("Skipping NUXT_BETTER_AUTH_SECRET. Auth will fail without it in production.");
503
+ return void 0;
504
+ }
505
+ let secret;
506
+ if (choice === "generate") {
507
+ secret = generateSecret();
508
+ } else {
509
+ const input = await consola.prompt("Paste your secret (min 32 chars):", { type: "text", cancel: "null" });
510
+ if (typeof input === "symbol" || !input || input.length < 32) {
511
+ consola.warn("Invalid secret. Skipping.");
512
+ return void 0;
239
513
  }
240
- nuxt.options.runtimeConfig.betterAuthSecret = betterAuthSecret;
241
- nuxt.options.runtimeConfig.auth = defu(nuxt.options.runtimeConfig.auth, {
242
- secondaryStorage: secondaryStorageEnabled
243
- });
244
- nuxt.options.alias["#nuxt-better-auth"] = resolver.resolve("./runtime/types/augment");
245
- nuxt.options.alias["#auth/server"] = serverConfigPath;
246
- nuxt.options.alias["#auth/client"] = clientConfigPath;
247
- const hubKVPath = nuxt.options.alias["hub:kv"];
248
- if (secondaryStorageEnabled && !hubKVPath) {
249
- throw new Error("[nuxt-better-auth] hub:kv alias not found. Ensure @nuxthub/core is loaded before this module.");
514
+ secret = input;
515
+ }
516
+ const preview = `${secret.slice(0, 8)}...${secret.slice(-4)}`;
517
+ const confirm = await consola.prompt(`Add to .env:
518
+ ${DEFAULT_SECRET_ENV}=${preview}
519
+ Proceed?`, { type: "confirm", initial: true, cancel: "null" });
520
+ if (typeof confirm === "symbol" || !confirm) {
521
+ consola.info("Cancelled. Secret not written.");
522
+ return void 0;
523
+ }
524
+ appendSecretToEnv(rootDir, secret);
525
+ consola.success("Added NUXT_BETTER_AUTH_SECRET to .env");
526
+ return secret;
527
+ }
528
+
529
+ function resolveDatabaseProvider(input) {
530
+ const enabledProviders = Object.entries(input.providers).filter(([_id, provider]) => provider.isEnabled?.(input.context) ?? true);
531
+ if (!enabledProviders.length) {
532
+ throw new Error("[nuxt-better-auth] No database provider is enabled. Register one with the better-auth:database:providers hook.");
533
+ }
534
+ enabledProviders.sort((a, b) => (b[1].priority ?? 0) - (a[1].priority ?? 0));
535
+ const [id, definition] = enabledProviders[0];
536
+ return { id, definition };
537
+ }
538
+
539
+ function resolveSecondaryStorage(input) {
540
+ const { options, clientOnly, hasNuxtHub, hub } = input;
541
+ const opt = options.hubSecondaryStorage ?? false;
542
+ const useHubKV = opt === true;
543
+ const secondaryStorageEnabled = opt === true || opt === "custom";
544
+ if (secondaryStorageEnabled && clientOnly) {
545
+ throw new Error("[nuxt-better-auth] hubSecondaryStorage is not available in clientOnly mode. Either disable clientOnly or remove auth.hubSecondaryStorage.");
546
+ }
547
+ if (useHubKV && (!hasNuxtHub || !hub?.kv)) {
548
+ 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.");
549
+ }
550
+ return { useHubKV, secondaryStorageEnabled };
551
+ }
552
+ function setupRuntimeConfig(input) {
553
+ const { nuxt, options, clientOnly, databaseProvider, consola } = input;
554
+ const { useHubKV, secondaryStorageEnabled } = resolveSecondaryStorage(input);
555
+ nuxt.options.runtimeConfig.public = nuxt.options.runtimeConfig.public || {};
556
+ const configuredSiteUrl = nuxt.options.runtimeConfig.public.siteUrl;
557
+ if (!configuredSiteUrl && process.env.NUXT_PUBLIC_SITE_URL)
558
+ nuxt.options.runtimeConfig.public.siteUrl = process.env.NUXT_PUBLIC_SITE_URL;
559
+ nuxt.options.runtimeConfig.public.auth = defu(nuxt.options.runtimeConfig.public.auth, {
560
+ redirects: {
561
+ login: options.redirects?.login ?? "/login",
562
+ guest: options.redirects?.guest ?? "/",
563
+ authenticated: options.redirects?.authenticated,
564
+ logout: options.redirects?.logout
565
+ },
566
+ preserveRedirect: options.preserveRedirect ?? true,
567
+ redirectQueryKey: options.redirectQueryKey ?? "redirect",
568
+ useDatabase: databaseProvider !== "none",
569
+ databaseProvider,
570
+ clientOnly,
571
+ session: {
572
+ skipHydratedSsrGetSession: options.session?.skipHydratedSsrGetSession ?? false
250
573
  }
251
- const secondaryStorageCode = secondaryStorageEnabled ? `import { kv } from '${hubKVPath}'
574
+ });
575
+ if (clientOnly) {
576
+ const siteUrl = nuxt.options.runtimeConfig.public.siteUrl;
577
+ if (!siteUrl)
578
+ consola.warn("clientOnly mode: set runtimeConfig.public.siteUrl (or NUXT_PUBLIC_SITE_URL) to your frontend URL");
579
+ consola.info("clientOnly mode enabled - server utilities (serverAuth, getRequestSession, getUserSession, requireUserSession) are not available");
580
+ return { useHubKV, secondaryStorageEnabled };
581
+ }
582
+ const currentSecret = nuxt.options.runtimeConfig.betterAuthSecret;
583
+ nuxt.options.runtimeConfig.betterAuthSecret = currentSecret || process.env.NUXT_BETTER_AUTH_SECRET || process.env.BETTER_AUTH_SECRET || "";
584
+ const betterAuthSecret = nuxt.options.runtimeConfig.betterAuthSecret;
585
+ if (!nuxt.options.dev && !nuxt.options._prepare && !betterAuthSecret) {
586
+ 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.");
587
+ }
588
+ if (betterAuthSecret && betterAuthSecret.length < 32) {
589
+ throw new Error("[nuxt-better-auth] NUXT_BETTER_AUTH_SECRET must be at least 32 characters for security");
590
+ }
591
+ nuxt.options.runtimeConfig.auth = defu(nuxt.options.runtimeConfig.auth, {
592
+ hubSecondaryStorage: options.hubSecondaryStorage ?? false
593
+ });
594
+ return { useHubKV, secondaryStorageEnabled };
595
+ }
596
+
597
+ function buildSecondaryStorageCode(useHubKV) {
598
+ if (!useHubKV)
599
+ return "export function createSecondaryStorage() { return undefined }";
600
+ return `import { kv } from '@nuxthub/kv'
252
601
  export function createSecondaryStorage() {
253
602
  return {
254
603
  get: async (key) => kv.get(\`_auth:\${key}\`),
255
604
  set: async (key, value, ttl) => kv.set(\`_auth:\${key}\`, value, { ttl }),
256
605
  delete: async (key) => kv.del(\`_auth:\${key}\`),
257
606
  }
258
- }` : `export function createSecondaryStorage() { return undefined }`;
259
- const secondaryStorageTemplate = addTemplate({ filename: "better-auth/secondary-storage.mjs", getContents: () => secondaryStorageCode, write: true });
260
- nuxt.options.alias["#auth/secondary-storage"] = secondaryStorageTemplate.dst;
261
- const hubDbPath = nuxt.options.alias["hub:db"];
262
- if (hasHubDb && !hubDbPath) {
263
- throw new Error("[nuxt-better-auth] hub:db alias not found. Ensure @nuxthub/core is loaded before this module.");
607
+ }`;
608
+ }
609
+ function buildDatabaseCode(input) {
610
+ if (input.provider === "nuxthub") {
611
+ if (input.hubDialect === "postgresql") {
612
+ return `import { db } from '@nuxthub/db'
613
+ import * as schema from './schema.${input.hubDialect}.mjs'
614
+ import { drizzleAdapter } from 'better-auth/adapters/drizzle'
615
+ import { drizzle } from 'drizzle-orm/postgres-js'
616
+ import postgres from 'postgres'
617
+
618
+ const dialect = 'pg'
619
+ const requestDatabaseKey = Symbol.for('nuxt-better-auth.requestDatabase')
620
+ const fallbackRequestDatabaseContext = new WeakMap()
621
+
622
+ function getRequestDatabaseContext(event) {
623
+ const eventWithContext = event
624
+ if (eventWithContext?.context && typeof eventWithContext.context === 'object')
625
+ return eventWithContext.context
626
+
627
+ let context = fallbackRequestDatabaseContext.get(event)
628
+ if (!context) {
629
+ context = {}
630
+ fallbackRequestDatabaseContext.set(event, context)
631
+ }
632
+ return context
633
+ }
634
+
635
+ function createHyperdriveAdapter(client) {
636
+ return drizzleAdapter(drizzle({ client, schema }), { provider: dialect, schema, usePlural: ${input.usePlural}, camelCase: ${input.camelCase} })
637
+ }
638
+
639
+ function getCloudflareContext(event) {
640
+ return event?.context?.cloudflare
641
+ }
642
+
643
+ function resolveHyperdrive(event) {
644
+ const cloudflareEnv = getCloudflareContext(event)?.env
645
+ return cloudflareEnv?.POSTGRES || process.env.POSTGRES || globalThis.__env__?.POSTGRES || globalThis.POSTGRES
646
+ }
647
+
648
+ function scheduleCleanup(event, cleanup) {
649
+ const cloudflareContext = getCloudflareContext(event)
650
+ if (typeof cloudflareContext?.context?.waitUntil === 'function') {
651
+ cloudflareContext.context.waitUntil(cleanup)
652
+ return
653
+ }
654
+
655
+ if (typeof event?.context?.waitUntil === 'function') {
656
+ event.context.waitUntil(cleanup)
657
+ return
658
+ }
659
+
660
+ const waitUntil = event?.waitUntil || event?.req?.waitUntil || event?.node?.req?.waitUntil
661
+ if (typeof waitUntil === 'function')
662
+ waitUntil.call(event?.req || event?.node?.req || event, cleanup)
663
+ else
664
+ void cleanup
665
+ }
666
+
667
+ function registerClientCleanup(event, client) {
668
+ const response = event?.node?.res
669
+ if (!response || typeof response.once !== 'function')
670
+ return
671
+
672
+ let closed = false
673
+
674
+ const cleanup = () => {
675
+ if (closed)
676
+ return
677
+
678
+ closed = true
679
+ const close = client.end({ timeout: 0 }).catch(() => {})
680
+ scheduleCleanup(event, close)
681
+ }
682
+
683
+ response.once('finish', cleanup)
684
+ response.once('close', cleanup)
685
+ }
686
+
687
+ export function createDatabase(event) {
688
+ const hyperdrive = resolveHyperdrive(event)
689
+ if (!hyperdrive?.connectionString)
690
+ return drizzleAdapter(db, { provider: dialect, schema, usePlural: ${input.usePlural}, camelCase: ${input.camelCase} })
691
+
692
+ if (event) {
693
+ const context = getRequestDatabaseContext(event)
694
+ const cached = context[requestDatabaseKey]
695
+ if (cached)
696
+ return cached
697
+
698
+ const client = postgres(hyperdrive.connectionString, {
699
+ prepare: false,
700
+ onnotice: () => {},
701
+ max: 1,
702
+ })
703
+ const database = createHyperdriveAdapter(client)
704
+
705
+ context[requestDatabaseKey] = database
706
+ registerClientCleanup(event, client)
707
+ return database
708
+ }
709
+ const client = postgres(hyperdrive.connectionString, {
710
+ prepare: false,
711
+ onnotice: () => {},
712
+ max: 1,
713
+ })
714
+
715
+ return createHyperdriveAdapter(client)
716
+ }
717
+ export { db }`;
264
718
  }
265
- const hubDialect = getHubDialect(hub) ?? "sqlite";
266
- const databaseCode = hasHubDb && hubDbPath ? `import { db, schema } from '${hubDbPath}'
719
+ return `import { db } from '@nuxthub/db'
720
+ import * as schema from './schema.${input.hubDialect}.mjs'
267
721
  import { drizzleAdapter } from 'better-auth/adapters/drizzle'
268
- const rawDialect = '${hubDialect}'
722
+ const rawDialect = '${input.hubDialect}'
269
723
  const dialect = rawDialect === 'postgresql' ? 'pg' : rawDialect
270
- export function createDatabase() { return drizzleAdapter(db, { provider: dialect, schema }) }
271
- export { db }` : `export function createDatabase() { return undefined }
724
+ export function createDatabase() { return drizzleAdapter(db, { provider: dialect, schema, usePlural: ${input.usePlural}, camelCase: ${input.camelCase} }) }
725
+ export { db }`;
726
+ }
727
+ return `export function createDatabase() { return undefined }
272
728
  export const db = undefined`;
273
- const databaseTemplate = addTemplate({ filename: "better-auth/database.mjs", getContents: () => databaseCode, write: true });
274
- nuxt.options.alias["#auth/database"] = databaseTemplate.dst;
275
- addTypeTemplate({
276
- filename: "types/auth-secondary-storage.d.ts",
277
- getContents: () => `
729
+ }
730
+ function buildSchemaExportCode(hasHubDb, hubDialect) {
731
+ if (!hasHubDb)
732
+ return "export const schema = undefined\n";
733
+ return `export * from './schema.${hubDialect}.mjs'
734
+ import * as schema from './schema.${hubDialect}.mjs'
735
+ export { schema }
736
+ `;
737
+ }
738
+ function buildAuthRouteRulesCode(authRouteRules) {
739
+ return `export const authRouteRules = ${JSON.stringify(authRouteRules, null, 2)}
740
+ `;
741
+ }
742
+
743
+ function assertConfigPresence(configs, clientOnly) {
744
+ if (!clientOnly && !configs.server.exists)
745
+ throw new Error(`[nuxt-better-auth] Missing ${configs.server.file}.ts - export default defineServerAuth(...)`);
746
+ if (!configs.client.exists)
747
+ throw new Error(`[nuxt-better-auth] Missing ${configs.client.file}.ts - export default defineClientAuth(...)`);
748
+ }
749
+ function createDefaultDatabaseProviders(buildContext) {
750
+ return {
751
+ nuxthub: {
752
+ priority: 100,
753
+ isEnabled: ({ hasHubDbAvailable: enabled }) => enabled,
754
+ buildDatabaseCode: () => buildDatabaseCode({
755
+ provider: "nuxthub",
756
+ ...buildContext
757
+ })
758
+ },
759
+ none: {
760
+ priority: 0,
761
+ buildDatabaseCode: () => buildDatabaseCode({
762
+ provider: "none",
763
+ ...buildContext
764
+ })
765
+ }
766
+ };
767
+ }
768
+ function collectAuthRouteRules(nuxt) {
769
+ const runtimeRouteRulesSource = nuxt.options.nitro?.routeRules || nuxt.options.routeRules || {};
770
+ return Object.fromEntries(
771
+ Object.entries(runtimeRouteRulesSource).flatMap(([path, rule]) => {
772
+ if (!rule || typeof rule !== "object" || !("auth" in rule))
773
+ return [];
774
+ return [[path, { auth: rule.auth }]];
775
+ })
776
+ );
777
+ }
778
+ async function resolveAuthModuleSetup(input, dependencies = {}) {
779
+ const { nuxt, options, runtimeTypesAugmentPath, consola } = input;
780
+ const hasNuxtModuleFn = dependencies.hasNuxtModule ?? hasNuxtModule;
781
+ const clientOnly = options.clientOnly ?? false;
782
+ const configs = resolveAuthConfigDescriptors(nuxt, {
783
+ server: options.serverConfig,
784
+ client: options.clientConfig
785
+ }, {
786
+ configExists: dependencies.configExists
787
+ });
788
+ assertConfigPresence(configs, clientOnly);
789
+ const aliases = {
790
+ "#nuxt-better-auth": runtimeTypesAugmentPath,
791
+ "#auth/server": clientOnly ? void 0 : configs.server.path,
792
+ "#auth/client": configs.client.path
793
+ };
794
+ nuxt.options.alias["#nuxt-better-auth"] = aliases["#nuxt-better-auth"];
795
+ if (aliases["#auth/server"])
796
+ nuxt.options.alias["#auth/server"] = aliases["#auth/server"];
797
+ nuxt.options.alias["#auth/client"] = aliases["#auth/client"];
798
+ const hasNuxtHub = hasNuxtModuleFn("@nuxthub/core", nuxt);
799
+ const hub = hasNuxtHub ? nuxt.options.hub : void 0;
800
+ const hasHubDbAvailable = !clientOnly && hasNuxtHub && !!hub?.db;
801
+ const hubDialect = getHubDialect(hub) ?? "sqlite";
802
+ const usePlural = options.schema?.usePlural ?? false;
803
+ const camelCase = (options.schema?.casing ?? getHubCasing(hub)) !== "snake_case";
804
+ let providerId = "none";
805
+ let providerDefinition;
806
+ if (!clientOnly) {
807
+ const buildContext = { hubDialect, usePlural, camelCase };
808
+ const providers = createDefaultDatabaseProviders(buildContext);
809
+ const enabledContext = {
810
+ nuxt,
811
+ options,
812
+ clientOnly,
813
+ hasHubDbAvailable
814
+ };
815
+ await nuxt.callHook("better-auth:database:providers", providers);
816
+ const resolvedProvider = resolveDatabaseProvider({
817
+ providers,
818
+ context: enabledContext
819
+ });
820
+ providerId = resolvedProvider.id;
821
+ providerDefinition = resolvedProvider.definition;
822
+ }
823
+ const runtime = setupRuntimeConfig({
824
+ nuxt,
825
+ options,
826
+ clientOnly,
827
+ databaseProvider: providerId,
828
+ hasNuxtHub,
829
+ hub,
830
+ consola
831
+ });
832
+ if (runtime.useHubKV && !nuxt.options.alias["hub:kv"]) {
833
+ throw new Error("[nuxt-better-auth] hub:kv not found. Ensure @nuxthub/core is loaded before this module and hub.kv is enabled.");
834
+ }
835
+ const hasHubDb = providerId === "nuxthub";
836
+ if (hasHubDb && !nuxt.options.alias["hub:db"]) {
837
+ throw new Error("[nuxt-better-auth] hub:db not found. Ensure @nuxthub/core is loaded before this module and hub.db is configured.");
838
+ }
839
+ return {
840
+ clientOnly,
841
+ configs,
842
+ aliases,
843
+ hub: {
844
+ hasNuxtHub,
845
+ options: hub,
846
+ hasHubDbAvailable
847
+ },
848
+ database: {
849
+ providerId,
850
+ hasHubDb,
851
+ providerDefinition,
852
+ buildContext: clientOnly ? void 0 : { hubDialect, usePlural, camelCase }
853
+ },
854
+ runtime,
855
+ prepareTypes: clientOnly ? void 0 : {
856
+ serverDir: dirname(configs.server.path),
857
+ hasHubDb
858
+ },
859
+ serverTypes: clientOnly ? void 0 : {
860
+ serverConfigPath: configs.server.path,
861
+ hasHubDb
862
+ },
863
+ sharedTypes: {
864
+ clientConfigPath: configs.client.path
865
+ },
866
+ schemaGeneration: hasHubDb ? {
867
+ serverConfigPath: configs.server.path,
868
+ hubSecondaryStorage: options.hubSecondaryStorage ?? false,
869
+ externalizeNuxtHubDatabase: true
870
+ } : void 0
871
+ };
872
+ }
873
+
874
+ function registerServerTypeTemplates(input) {
875
+ const { serverConfigPath, hasHubDb, runtimeTypesPath, sharedServerConfigSafe } = input;
876
+ const serverConfigTypeTemplateOptions = sharedServerConfigSafe ? { nuxt: true, nitro: true, node: true, shared: true } : { nuxt: true, nitro: true, node: true };
877
+ addTypeTemplate({
878
+ filename: "types/auth-secondary-storage.d.ts",
879
+ getContents: () => `
278
880
  declare module '#auth/secondary-storage' {
279
881
  interface SecondaryStorage {
280
882
  get: (key: string) => Promise<string | null>
@@ -284,187 +886,492 @@ declare module '#auth/secondary-storage' {
284
886
  export function createSecondaryStorage(): SecondaryStorage | undefined
285
887
  }
286
888
  `
287
- });
288
- addTypeTemplate({
289
- filename: "types/auth-database.d.ts",
290
- getContents: () => `
889
+ }, { nitro: true });
890
+ addTypeTemplate({
891
+ filename: "types/auth-database.d.ts",
892
+ getContents: () => `
291
893
  declare module '#auth/database' {
292
- import type { drizzleAdapter } from 'better-auth/adapters/drizzle'
293
- export function createDatabase(): ReturnType<typeof drizzleAdapter> | undefined
294
- export const db: unknown
894
+ import type { BetterAuthOptions } from 'better-auth'
895
+ export function createDatabase(event?: import('h3').H3Event): BetterAuthOptions['database']
896
+ export const db: ${hasHubDb ? `typeof import('@nuxthub/db')['db']` : "undefined"}
295
897
  }
296
898
  `
297
- });
298
- addTypeTemplate({
299
- filename: "types/nuxt-better-auth.d.ts",
300
- getContents: () => `
301
- export * from '${resolver.resolve("./runtime/types/augment")}'
302
- export type { AuthMeta, AuthMode, AuthRouteRules, UserMatch, RequireSessionOptions, Auth, InferUser, InferSession } from '${resolver.resolve("./runtime/types")}'
899
+ }, { nitro: true });
900
+ addTypeTemplate({
901
+ filename: "types/auth-schema.d.ts",
902
+ getContents: () => `
903
+ declare module '#auth/schema' {
904
+ export const user: any
905
+ export const session: any
906
+ export const account: any
907
+ export const verification: any
908
+ export const schema: {
909
+ user: any
910
+ session: any
911
+ account: any
912
+ verification: any
913
+ [key: string]: any
914
+ } | undefined
915
+ }
303
916
  `
304
- });
305
- addTypeTemplate({
306
- filename: "types/nuxt-better-auth-infer.d.ts",
307
- getContents: () => `
308
- import type { InferUser, InferSession } from 'better-auth'
309
- import type { RuntimeConfig } from 'nuxt/schema'
310
- import type configFn from '${serverConfigPath}'
917
+ }, { nitro: true });
918
+ addTypeTemplate({
919
+ filename: "types/nuxt-better-auth-server-context.d.ts",
920
+ getContents: () => `
921
+ /// <reference path="./nitro-imports.d.ts" />
922
+ /// <reference path="./auth-database.d.ts" />
923
+ /// <reference path="./auth-schema.d.ts" />
924
+ /// <reference path="./auth-secondary-storage.d.ts" />
925
+ ${hasHubDb ? '/// <reference path="../hub/db.d.ts" />' : ""}
311
926
 
312
- type _Config = ReturnType<typeof configFn>
927
+ export {}
928
+ `
929
+ }, { node: true });
930
+ addTypeTemplate({
931
+ filename: "types/nuxt-better-auth-config-context.d.ts",
932
+ getContents: () => `
933
+ import type { RuntimeConfig } from 'nuxt/schema'
313
934
 
314
- declare module '#nuxt-better-auth' {
315
- interface AuthUser extends InferUser<_Config> {}
316
- interface AuthSession { session: InferSession<_Config>['session'], user: InferUser<_Config> }
317
- interface ServerAuthContext {
935
+ declare module '@onmax/nuxt-better-auth/config' {
936
+ interface ServerAuthContextExtension {
318
937
  runtimeConfig: RuntimeConfig
319
- ${hasHubDb ? `db: typeof import('hub:db')['db']` : ""}
938
+ db: ${hasHubDb ? `typeof import('@nuxthub/db')['db']` : "undefined"}
939
+ requestOrigin?: string
320
940
  }
321
941
  }
322
942
 
323
- // Augment the config module to use the extended ServerAuthContext
324
- interface _AugmentedServerAuthContext {
325
- runtimeConfig: RuntimeConfig
326
- ${hasHubDb ? `db: typeof import('hub:db')['db']` : "db: unknown"}
943
+ `
944
+ }, { nuxt: true, nitro: true, node: true, shared: true });
945
+ addTypeTemplate({
946
+ filename: "types/nuxt-better-auth-infer.d.ts",
947
+ getContents: () => `
948
+ import type { BetterAuthOptions, BetterAuthPlugin, InferPluginTypes, UnionToIntersection } from 'better-auth'
949
+ import type { InferFieldsOutput } from 'better-auth/db'
950
+ import type createServerAuth from '${serverConfigPath}'
951
+
952
+ type _RawConfig = ReturnType<typeof createServerAuth>
953
+ type _RawPlugins = _RawConfig extends { plugins: infer P } ? P : _RawConfig extends { plugins?: infer P } ? P : []
954
+ type _NormalizedPlugins = _RawPlugins extends readonly (infer T)[]
955
+ ? Array<T & BetterAuthPlugin>
956
+ : _RawPlugins extends (infer T)[]
957
+ ? Array<T & BetterAuthPlugin>
958
+ : BetterAuthPlugin[]
959
+ type _Config = Omit<BetterAuthOptions, 'plugins'> & Omit<_RawConfig, 'plugins'> & {
960
+ plugins?: _NormalizedPlugins
327
961
  }
328
962
 
329
- declare module '@onmax/nuxt-better-auth/config' {
330
- import type { BetterAuthOptions } from 'better-auth'
331
- type ServerAuthConfig = Omit<BetterAuthOptions, 'database' | 'secret' | 'baseURL'>
332
- export function defineServerAuth<T extends ServerAuthConfig>(config: (ctx: _AugmentedServerAuthContext) => T): (ctx: _AugmentedServerAuthContext) => T
963
+ type _InferModelFieldsFromPlugins<P, M extends string> = P extends readonly (infer Plugin)[]
964
+ ? UnionToIntersection<Plugin extends { schema: { [K in M]: { fields: infer F } } } ? InferFieldsOutput<F> : {}>
965
+ : P extends (infer Plugin)[]
966
+ ? UnionToIntersection<Plugin extends { schema: { [K in M]: { fields: infer F } } } ? InferFieldsOutput<F> : {}>
967
+ : {}
968
+
969
+ type _InferModelFieldsFromOptions<C, M extends 'user' | 'session'> = C extends { [K in M]: { additionalFields: infer F } }
970
+ ? InferFieldsOutput<F>
971
+ : {}
972
+
973
+ type _UserFallback = _InferModelFieldsFromPlugins<_RawPlugins, 'user'> & _InferModelFieldsFromOptions<_RawConfig, 'user'>
974
+ type _SessionFallback = _InferModelFieldsFromPlugins<_RawPlugins, 'session'> & _InferModelFieldsFromOptions<_RawConfig, 'session'>
975
+
976
+ declare module '#nuxt-better-auth' {
977
+ interface AuthUser extends _UserFallback {}
978
+ interface AuthSession extends _SessionFallback {}
979
+ type PluginTypes = InferPluginTypes<_Config>
333
980
  }
334
981
  `
335
- });
336
- addTypeTemplate({
337
- filename: "types/nuxt-better-auth-client.d.ts",
338
- getContents: () => `
339
- import type { createAppAuthClient } from '${clientConfigPath}'
982
+ }, serverConfigTypeTemplateOptions);
983
+ addTypeTemplate({
984
+ filename: "types/nuxt-better-auth-social-providers.d.ts",
985
+ getContents: () => `
986
+ import type createServerAuth from '${serverConfigPath}'
987
+
988
+ type _RawConfig = ReturnType<typeof createServerAuth>
989
+ type _RawSocialProviders = _RawConfig extends { socialProviders: infer S } ? S : _RawConfig extends { socialProviders?: infer S } ? S : {}
990
+ type _SocialProviderIds = Extract<keyof NonNullable<_RawSocialProviders>, string>
991
+
340
992
  declare module '#nuxt-better-auth' {
341
- export type AppAuthClient = ReturnType<typeof createAppAuthClient>
993
+ interface AuthSocialProviderRegistry {
994
+ ids: _SocialProviderIds
995
+ }
342
996
  }
343
997
  `
344
- });
345
- addTypeTemplate({
346
- filename: "types/nuxt-better-auth-nitro.d.ts",
347
- getContents: () => `
998
+ }, serverConfigTypeTemplateOptions);
999
+ addTypeTemplate({
1000
+ filename: "types/nuxt-better-auth-nitro.d.ts",
1001
+ getContents: () => `
1002
+ import type createServerAuth from '${serverConfigPath}'
1003
+ import type { BetterAuthOptions } from 'better-auth'
1004
+ import type { getEndpoints } from 'better-auth/api'
1005
+ import type { Serialize, Simplify } from 'nitropack/types'
1006
+ import type { FetchError } from 'ofetch'
1007
+
1008
+ type _RawConfig = ReturnType<typeof createServerAuth>
1009
+ type _RawPlugins = _RawConfig extends { plugins: infer P } ? P : _RawConfig extends { plugins?: infer P } ? P : []
1010
+ type _Config = Omit<BetterAuthOptions, 'plugins'> & Omit<_RawConfig, 'plugins'> & {
1011
+ plugins?: _RawPlugins
1012
+ }
1013
+
1014
+ type _AuthApi = ReturnType<typeof getEndpoints<_Config>>['api']
1015
+ type _NormalizeMethod<M extends string> = M extends '*' ? 'default' : Lowercase<M>
1016
+ type _RouteMethodFromOption<M> = M extends readonly (infer T)[]
1017
+ ? _NormalizeMethod<Extract<T, string>>
1018
+ : M extends string
1019
+ ? _NormalizeMethod<M>
1020
+ : 'default'
1021
+ type _RouteMethodFromEndpoint<E> = E extends { options: { method: infer M } } ? _RouteMethodFromOption<M> : 'default'
1022
+ type _RoutePathFromEndpoint<E> = E extends { path: infer P extends string }
1023
+ ? string extends P
1024
+ ? never
1025
+ : \`/api/auth\${P}\`
1026
+ : never
1027
+ type _RouteResponseFromEndpoint<E> = E extends (...args: any[]) => Promise<infer R> ? Simplify<Serialize<Awaited<R>>> : never
1028
+ type _RouteDefaultResponse<E> = never
1029
+ type _UnionToIntersection<U> = (U extends unknown ? (value: U) => void : never) extends (value: infer I) => void ? I : never
1030
+
1031
+ type _CoreAuthInternalApi = {
1032
+ [K in keyof _AuthApi as _RoutePathFromEndpoint<_AuthApi[K]>]: {
1033
+ [M in _RouteMethodFromEndpoint<_AuthApi[K]> | 'default']: M extends 'default' ? _RouteDefaultResponse<_AuthApi[K]> : _RouteResponseFromEndpoint<_AuthApi[K]>
1034
+ }
1035
+ }
1036
+ type _PluginEndpointMaps<Plugins> = Plugins extends readonly (infer Plugin)[]
1037
+ ? Plugin extends { endpoints: infer Endpoints extends Record<string, unknown> }
1038
+ ? {
1039
+ [K in keyof Endpoints as _RoutePathFromEndpoint<Endpoints[K]>]: {
1040
+ [M in _RouteMethodFromEndpoint<Endpoints[K]> | 'default']: M extends 'default' ? _RouteDefaultResponse<Endpoints[K]> : _RouteResponseFromEndpoint<Endpoints[K]>
1041
+ }
1042
+ }
1043
+ : {}
1044
+ : Plugins extends (infer Plugin)[]
1045
+ ? Plugin extends { endpoints: infer Endpoints extends Record<string, unknown> }
1046
+ ? {
1047
+ [K in keyof Endpoints as _RoutePathFromEndpoint<Endpoints[K]>]: {
1048
+ [M in _RouteMethodFromEndpoint<Endpoints[K]> | 'default']: M extends 'default' ? _RouteDefaultResponse<Endpoints[K]> : _RouteResponseFromEndpoint<Endpoints[K]>
1049
+ }
1050
+ }
1051
+ : {}
1052
+ : {}
1053
+ type _PluginAuthInternalApi = _UnionToIntersection<_PluginEndpointMaps<_RawPlugins>>
1054
+ type _GeneratedAuthInternalApi = _CoreAuthInternalApi & _PluginAuthInternalApi
1055
+
1056
+ type _RoutePathToRequestPath<Path extends string> = Path extends \`\${infer Prefix}:\${string}/\${infer Rest}\`
1057
+ ? \`\${Prefix}\${string}/\${_RoutePathToRequestPath<Rest>}\`
1058
+ : Path extends \`\${infer Prefix}:\${string}\`
1059
+ ? \`\${Prefix}\${string}\`
1060
+ : Path
1061
+ type _AuthApiPatternPath = Extract<keyof _GeneratedAuthInternalApi, string>
1062
+ type _AuthApiRequestPath = _RoutePathToRequestPath<_AuthApiPatternPath>
1063
+ type _AuthPatternFromRequestPath<Path extends string> = {
1064
+ [Pattern in _AuthApiPatternPath]: Path extends _RoutePathToRequestPath<Pattern> ? Pattern : never
1065
+ }[_AuthApiPatternPath]
1066
+ type _AuthEndpointMethod<Path extends _AuthApiRequestPath> = Extract<keyof _GeneratedAuthInternalApi[_AuthPatternFromRequestPath<Path>], string>
1067
+
1068
+ type _AuthFetchMethod<Path extends _AuthApiRequestPath> = Extract<Exclude<import('nitropack/types').NitroFetchOptions<Path>['method'], undefined>, string>
1069
+ type _AuthFetchDefaultMethod<Path extends _AuthApiRequestPath> = 'get'
1070
+ type _AuthFetchResolvedMethod<Path extends _AuthApiRequestPath, Method extends string> = Lowercase<Method> extends _AuthEndpointMethod<Path>
1071
+ ? Lowercase<Method>
1072
+ : never
1073
+ type _AuthFetchResult<Path extends _AuthApiRequestPath, Method extends string> = _GeneratedAuthInternalApi[_AuthPatternFromRequestPath<Path>][_AuthFetchResolvedMethod<Path, Method>]
1074
+
1075
+ declare module '#nuxt-better-auth' {
1076
+ export type AuthApiInternalRoutes = _GeneratedAuthInternalApi
1077
+ export type AuthApiEndpointPatternPath = _AuthApiPatternPath
1078
+ export type AuthApiEndpointPath = _AuthApiRequestPath
1079
+ export type AuthApiEndpointMethod<Path extends AuthApiEndpointPath> = _AuthEndpointMethod<Path>
1080
+ export type AuthApiEndpointResponse<
1081
+ Path extends AuthApiEndpointPath,
1082
+ Method extends AuthApiEndpointMethod<Path> = AuthApiEndpointMethod<Path>,
1083
+ > = AuthApiInternalRoutes[_AuthPatternFromRequestPath<Path>][Method]
1084
+ }
1085
+
1086
+ declare module 'nuxt/dist/app/composables/fetch' {
1087
+ export function useFetch<
1088
+ ErrorT = FetchError,
1089
+ Path extends import('#nuxt-better-auth').AuthApiEndpointPath = import('#nuxt-better-auth').AuthApiEndpointPath,
1090
+ Method extends _AuthFetchMethod<Path> = _AuthFetchDefaultMethod<Path>,
1091
+ _ResT = _AuthFetchResult<Path, Method>,
1092
+ DataT = _ResT,
1093
+ PickKeys extends import('nuxt/dist/app/composables/asyncData').KeysOf<DataT> = import('nuxt/dist/app/composables/asyncData').KeysOf<DataT>,
1094
+ DefaultT = undefined,
1095
+ >(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>
1096
+ export function useFetch<
1097
+ ErrorT = FetchError,
1098
+ Path extends import('#nuxt-better-auth').AuthApiEndpointPath = import('#nuxt-better-auth').AuthApiEndpointPath,
1099
+ Method extends _AuthFetchMethod<Path> = _AuthFetchDefaultMethod<Path>,
1100
+ _ResT = _AuthFetchResult<Path, Method>,
1101
+ DataT = _ResT,
1102
+ PickKeys extends import('nuxt/dist/app/composables/asyncData').KeysOf<DataT> = import('nuxt/dist/app/composables/asyncData').KeysOf<DataT>,
1103
+ DefaultT = DataT,
1104
+ >(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>
1105
+ export function useFetch(request: string | import('vue').Ref<string> | (() => string), opts?: any): any
1106
+
1107
+ export function useLazyFetch<
1108
+ ErrorT = FetchError,
1109
+ Path extends import('#nuxt-better-auth').AuthApiEndpointPath = import('#nuxt-better-auth').AuthApiEndpointPath,
1110
+ Method extends _AuthFetchMethod<Path> = _AuthFetchDefaultMethod<Path>,
1111
+ _ResT = _AuthFetchResult<Path, Method>,
1112
+ DataT = _ResT,
1113
+ PickKeys extends import('nuxt/dist/app/composables/asyncData').KeysOf<DataT> = import('nuxt/dist/app/composables/asyncData').KeysOf<DataT>,
1114
+ DefaultT = undefined,
1115
+ >(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>
1116
+ export function useLazyFetch<
1117
+ ErrorT = FetchError,
1118
+ Path extends import('#nuxt-better-auth').AuthApiEndpointPath = import('#nuxt-better-auth').AuthApiEndpointPath,
1119
+ Method extends _AuthFetchMethod<Path> = _AuthFetchDefaultMethod<Path>,
1120
+ _ResT = _AuthFetchResult<Path, Method>,
1121
+ DataT = _ResT,
1122
+ PickKeys extends import('nuxt/dist/app/composables/asyncData').KeysOf<DataT> = import('nuxt/dist/app/composables/asyncData').KeysOf<DataT>,
1123
+ DefaultT = DataT,
1124
+ >(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>
1125
+ export function useLazyFetch(request: string | import('vue').Ref<string> | (() => string), opts?: any): any
1126
+ }
1127
+
1128
+ declare module 'nuxt/app' {
1129
+ export function useFetch<
1130
+ ErrorT = FetchError,
1131
+ Path extends import('#nuxt-better-auth').AuthApiEndpointPath = import('#nuxt-better-auth').AuthApiEndpointPath,
1132
+ Method extends _AuthFetchMethod<Path> = _AuthFetchDefaultMethod<Path>,
1133
+ _ResT = _AuthFetchResult<Path, Method>,
1134
+ DataT = _ResT,
1135
+ PickKeys extends import('nuxt/dist/app/composables/asyncData').KeysOf<DataT> = import('nuxt/dist/app/composables/asyncData').KeysOf<DataT>,
1136
+ DefaultT = undefined,
1137
+ >(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>
1138
+ export function useFetch<
1139
+ ErrorT = FetchError,
1140
+ Path extends import('#nuxt-better-auth').AuthApiEndpointPath = import('#nuxt-better-auth').AuthApiEndpointPath,
1141
+ Method extends _AuthFetchMethod<Path> = _AuthFetchDefaultMethod<Path>,
1142
+ _ResT = _AuthFetchResult<Path, Method>,
1143
+ DataT = _ResT,
1144
+ PickKeys extends import('nuxt/dist/app/composables/asyncData').KeysOf<DataT> = import('nuxt/dist/app/composables/asyncData').KeysOf<DataT>,
1145
+ DefaultT = DataT,
1146
+ >(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>
1147
+ export function useFetch(request: string | import('vue').Ref<string> | (() => string), opts?: any): any
1148
+
1149
+ export function useLazyFetch<
1150
+ ErrorT = FetchError,
1151
+ Path extends import('#nuxt-better-auth').AuthApiEndpointPath = import('#nuxt-better-auth').AuthApiEndpointPath,
1152
+ Method extends _AuthFetchMethod<Path> = _AuthFetchDefaultMethod<Path>,
1153
+ _ResT = _AuthFetchResult<Path, Method>,
1154
+ DataT = _ResT,
1155
+ PickKeys extends import('nuxt/dist/app/composables/asyncData').KeysOf<DataT> = import('nuxt/dist/app/composables/asyncData').KeysOf<DataT>,
1156
+ DefaultT = undefined,
1157
+ >(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>
1158
+ export function useLazyFetch<
1159
+ ErrorT = FetchError,
1160
+ Path extends import('#nuxt-better-auth').AuthApiEndpointPath = import('#nuxt-better-auth').AuthApiEndpointPath,
1161
+ Method extends _AuthFetchMethod<Path> = _AuthFetchDefaultMethod<Path>,
1162
+ _ResT = _AuthFetchResult<Path, Method>,
1163
+ DataT = _ResT,
1164
+ PickKeys extends import('nuxt/dist/app/composables/asyncData').KeysOf<DataT> = import('nuxt/dist/app/composables/asyncData').KeysOf<DataT>,
1165
+ DefaultT = DataT,
1166
+ >(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>
1167
+ export function useLazyFetch(request: string | import('vue').Ref<string> | (() => string), opts?: any): any
1168
+ }
1169
+
348
1170
  declare module 'nitropack' {
349
1171
  interface NitroRouteRules {
350
- auth?: import('${resolver.resolve("./runtime/types")}').AuthMeta
1172
+ auth?: import('${runtimeTypesPath}').AuthMeta
351
1173
  }
352
1174
  interface NitroRouteConfig {
353
- auth?: import('${resolver.resolve("./runtime/types")}').AuthMeta
1175
+ auth?: import('${runtimeTypesPath}').AuthMeta
354
1176
  }
1177
+ interface InternalApi extends _GeneratedAuthInternalApi {}
355
1178
  }
356
1179
  declare module 'nitropack/types' {
357
1180
  interface NitroRouteRules {
358
- auth?: import('${resolver.resolve("./runtime/types")}').AuthMeta
1181
+ auth?: import('${runtimeTypesPath}').AuthMeta
359
1182
  }
360
1183
  interface NitroRouteConfig {
361
- auth?: import('${resolver.resolve("./runtime/types")}').AuthMeta
1184
+ auth?: import('${runtimeTypesPath}').AuthMeta
362
1185
  }
1186
+ interface InternalApi extends _GeneratedAuthInternalApi {}
1187
+ }
1188
+ declare module 'nitro/types' {
1189
+ interface NitroRouteRules {
1190
+ auth?: import('${runtimeTypesPath}').AuthMeta
1191
+ }
1192
+ interface NitroRouteConfig {
1193
+ auth?: import('${runtimeTypesPath}').AuthMeta
1194
+ }
1195
+ interface InternalApi extends _GeneratedAuthInternalApi {}
363
1196
  }
364
1197
  export {}
365
1198
  `
366
- }, { nuxt: true, nitro: true, node: true });
367
- nuxt.hook("builder:watch", async (_event, relativePath) => {
368
- if (relativePath.includes("auth.config")) {
369
- await updateTemplates({ filter: (t) => t.filename.includes("nuxt-better-auth") });
370
- }
371
- });
372
- addServerImportsDir(resolver.resolve("./runtime/server/utils"));
373
- addServerScanDir(resolver.resolve("./runtime/server/middleware"));
374
- addServerHandler({ route: "/api/auth/**", handler: resolver.resolve("./runtime/server/api/auth/[...all]") });
375
- addImportsDir(resolver.resolve("./runtime/app/composables"));
376
- addImportsDir(resolver.resolve("./runtime/utils"));
377
- addPlugin({ src: resolver.resolve("./runtime/app/plugins/session.server"), mode: "server" });
378
- addPlugin({ src: resolver.resolve("./runtime/app/plugins/session.client"), mode: "client" });
379
- addComponentsDir({ path: resolver.resolve("./runtime/app/components") });
380
- nuxt.hook("app:resolve", (app) => {
381
- app.middleware.push({ name: "auth", path: resolver.resolve("./runtime/app/middleware/auth.global"), global: true });
1199
+ }, { nitro: true, node: true });
1200
+ }
1201
+ function registerSharedTypeTemplates(input) {
1202
+ addTypeTemplate({
1203
+ filename: "types/nuxt-better-auth.d.ts",
1204
+ getContents: () => `
1205
+ import type { AppSession } from '${input.runtimeTypesAugmentPath}'
1206
+ export * from '${input.runtimeTypesAugmentPath}'
1207
+ export type { AuthMeta, AuthMode, AuthRouteRules, AuthSocialProviderId, Auth, InferUser, InferSession } from '${input.runtimeTypesPath}'
1208
+ declare module 'h3' {
1209
+ interface H3EventContext {
1210
+ requestSession?: AppSession | null
1211
+ }
1212
+ }
1213
+ `
1214
+ });
1215
+ addTypeTemplate({
1216
+ filename: "types/nuxt-better-auth-client.d.ts",
1217
+ getContents: () => `
1218
+ import type createAppAuthClient from '${input.clientConfigPath}'
1219
+ declare module '#nuxt-better-auth' {
1220
+ export type AppAuthClient = ReturnType<typeof createAppAuthClient>
1221
+ }
1222
+ `
1223
+ });
1224
+ }
1225
+
1226
+ const consola = consola$1.withTag("nuxt-better-auth");
1227
+ const serverAliasImportRE = /from\s+['"]#server/;
1228
+ const layersAliasImportRE = /from\s+['"]#layers\//;
1229
+ const rootAliasImportRE = /from\s+['"]~~/;
1230
+ const workspaceAliasImportRE = /from\s+['"]@@/;
1231
+ const dbIdentifierRE = /\bdb\b/;
1232
+ const sessionHookAfterIdentifierRE = /\bsessionHookAfter\b/;
1233
+ const nuxtHubDbImportRE = /@nuxthub\/db/;
1234
+ function isServerConfigSharedTypeSafe(serverConfigPath) {
1235
+ const resolvedPath = [
1236
+ serverConfigPath,
1237
+ `${serverConfigPath}.ts`,
1238
+ `${serverConfigPath}.mts`,
1239
+ `${serverConfigPath}.cts`,
1240
+ `${serverConfigPath}.js`,
1241
+ `${serverConfigPath}.mjs`,
1242
+ `${serverConfigPath}.cjs`
1243
+ ].find((path) => existsSync(path));
1244
+ if (!resolvedPath)
1245
+ return false;
1246
+ const contents = readFileSync(resolvedPath, "utf8");
1247
+ return !(serverAliasImportRE.test(contents) || layersAliasImportRE.test(contents) || rootAliasImportRE.test(contents) || workspaceAliasImportRE.test(contents) || dbIdentifierRE.test(contents) || sessionHookAfterIdentifierRE.test(contents) || nuxtHubDbImportRE.test(contents));
1248
+ }
1249
+ async function createDefaultAuthConfigFiles(nuxt) {
1250
+ const configs = resolveAuthConfigDescriptors(nuxt);
1251
+ const serverTemplate = `import { defineServerAuth } from '@onmax/nuxt-better-auth/config'
1252
+
1253
+ export default defineServerAuth({
1254
+ emailAndPassword: { enabled: true },
1255
+ })
1256
+ `;
1257
+ const clientTemplate = `import { defineClientAuth } from '@onmax/nuxt-better-auth/config'
1258
+
1259
+ export default defineClientAuth({})
1260
+ `;
1261
+ if (configs.server.shouldCreateDefaultFile) {
1262
+ const serverPath = `${configs.server.path}.ts`;
1263
+ await mkdir(dirname(serverPath), { recursive: true });
1264
+ await writeFile(serverPath, serverTemplate);
1265
+ consola.success(`Created ${relative(configs.server.declaringLayerRoot, serverPath)}`);
1266
+ }
1267
+ if (configs.client.shouldCreateDefaultFile) {
1268
+ const clientPath = `${configs.client.path}.ts`;
1269
+ await mkdir(dirname(clientPath), { recursive: true });
1270
+ await writeFile(clientPath, clientTemplate);
1271
+ consola.success(`Created ${relative(configs.client.declaringLayerRoot, clientPath)}`);
1272
+ }
1273
+ }
1274
+ const module$1 = defineNuxtModule({
1275
+ meta: { name: "@onmax/nuxt-better-auth", version, configKey: "auth", compatibility: { nuxt: ">=4.0.0" } },
1276
+ defaults: {
1277
+ clientOnly: false,
1278
+ serverConfig: "server/auth.config",
1279
+ clientConfig: "app/auth.config",
1280
+ redirects: { login: "/login", guest: "/" },
1281
+ preserveRedirect: true,
1282
+ redirectQueryKey: "redirect",
1283
+ hubSecondaryStorage: false
1284
+ },
1285
+ async onInstall(nuxt) {
1286
+ const configuredSecret = nuxt.options.runtimeConfig?.betterAuthSecret;
1287
+ const generatedSecret = await promptForSecret(nuxt.options.rootDir, consola, { configuredSecret, prepare: Boolean(nuxt.options._prepare) });
1288
+ if (generatedSecret)
1289
+ process.env.NUXT_BETTER_AUTH_SECRET = generatedSecret;
1290
+ await createDefaultAuthConfigFiles(nuxt);
1291
+ },
1292
+ async setup(options, nuxt) {
1293
+ const resolver = createResolver(import.meta.url);
1294
+ const setup = await resolveAuthModuleSetup({
1295
+ nuxt,
1296
+ options,
1297
+ runtimeTypesAugmentPath: resolver.resolve("./runtime/types/augment"),
1298
+ consola
382
1299
  });
383
- if (hasHubDb) {
384
- await setupBetterAuthSchema(nuxt, serverConfigPath, options);
1300
+ nuxt.options.alias["#nuxt-better-auth"] = setup.aliases["#nuxt-better-auth"];
1301
+ if (setup.aliases["#auth/server"])
1302
+ nuxt.options.alias["#auth/server"] = setup.aliases["#auth/server"];
1303
+ nuxt.options.alias["#auth/client"] = setup.aliases["#auth/client"];
1304
+ if (!setup.clientOnly) {
1305
+ const secondaryStorageTemplate = addTemplate({
1306
+ filename: "better-auth/secondary-storage.mjs",
1307
+ getContents: () => buildSecondaryStorageCode(setup.runtime.useHubKV),
1308
+ write: true
1309
+ });
1310
+ nuxt.options.alias["#auth/secondary-storage"] = secondaryStorageTemplate.dst;
1311
+ const databaseTemplate = addTemplate({
1312
+ filename: "better-auth/database.mjs",
1313
+ getContents: () => setup.database.providerDefinition.buildDatabaseCode(setup.database.buildContext),
1314
+ write: true
1315
+ });
1316
+ nuxt.options.alias["#auth/database"] = databaseTemplate.dst;
1317
+ const schemaTemplate = addTemplate({
1318
+ filename: "better-auth/schema.mjs",
1319
+ getContents: () => buildSchemaExportCode(setup.database.hasHubDb, setup.database.buildContext?.hubDialect ?? "sqlite"),
1320
+ write: true
1321
+ });
1322
+ nuxt.options.alias["#auth/schema"] = schemaTemplate.dst;
385
1323
  }
386
- const isProduction = process.env.NODE_ENV === "production" || !nuxt.options.dev;
387
- if (!isProduction) {
388
- setupDevTools(nuxt);
389
- addServerHandler({ route: "/api/_better-auth/config", method: "get", handler: resolver.resolve("./runtime/server/api/_better-auth/config.get") });
390
- if (hasHubDb) {
391
- addServerHandler({ route: "/api/_better-auth/sessions", method: "get", handler: resolver.resolve("./runtime/server/api/_better-auth/sessions.get") });
392
- addServerHandler({ route: "/api/_better-auth/sessions", method: "delete", handler: resolver.resolve("./runtime/server/api/_better-auth/sessions.delete") });
393
- addServerHandler({ route: "/api/_better-auth/users", method: "get", handler: resolver.resolve("./runtime/server/api/_better-auth/users.get") });
394
- addServerHandler({ route: "/api/_better-auth/accounts", method: "get", handler: resolver.resolve("./runtime/server/api/_better-auth/accounts.get") });
395
- }
396
- extendPages((pages) => {
397
- pages.push({ name: "better-auth-devtools", path: "/__better-auth-devtools", file: resolver.resolve("./runtime/app/pages/__better-auth-devtools.vue") });
1324
+ if (setup.prepareTypes) {
1325
+ registerPrepareTypesHook({
1326
+ nuxt,
1327
+ serverDir: setup.prepareTypes.serverDir,
1328
+ hasHubDb: setup.prepareTypes.hasHubDb
398
1329
  });
399
1330
  }
400
- nuxt.hook("pages:extend", (pages) => {
401
- const routeRules = nuxt.options.routeRules || {};
402
- if (!Object.keys(routeRules).length)
403
- return;
404
- const matcher = toRouteMatcher(createRouter({ routes: routeRules }));
405
- const applyMetaFromRules = (page) => {
406
- const matches = matcher.matchAll(page.path);
407
- if (!matches.length)
408
- return;
409
- const matchedRules = defu({}, ...matches.reverse());
410
- if (matchedRules.auth !== void 0) {
411
- page.meta = page.meta || {};
412
- page.meta.auth = matchedRules.auth;
413
- }
414
- page.children?.forEach((child) => applyMetaFromRules(child));
1331
+ if (setup.database.providerDefinition) {
1332
+ const setupCtx = {
1333
+ nuxt,
1334
+ options,
1335
+ clientOnly: setup.clientOnly
415
1336
  };
416
- pages.forEach((page) => applyMetaFromRules(page));
417
- });
418
- }
419
- });
420
- async function setupBetterAuthSchema(nuxt, serverConfigPath, options) {
421
- const hub = nuxt.options.hub;
422
- const dialect = getHubDialect(hub);
423
- if (!dialect || !["sqlite", "postgresql", "mysql"].includes(dialect)) {
424
- consola.warn(`Unsupported database dialect: ${dialect}`);
425
- return;
426
- }
427
- const isProduction = !nuxt.options.dev;
428
- try {
429
- const configFile = `${serverConfigPath}.ts`;
430
- const userConfig = await loadUserAuthConfig(configFile, isProduction);
431
- const extendedConfig = {};
432
- await nuxt.callHook("better-auth:config:extend", extendedConfig);
433
- const plugins = [...userConfig.plugins || [], ...extendedConfig.plugins || []];
434
- const { getAuthTables } = await import('better-auth/db');
435
- const tables = getAuthTables({
436
- plugins,
437
- secondaryStorage: options.secondaryStorage ? {
438
- get: async (_key) => null,
439
- set: async (_key, _value, _ttl) => {
440
- },
441
- delete: async (_key) => {
442
- }
443
- } : void 0
1337
+ await setup.database.providerDefinition.setup?.(setupCtx);
1338
+ }
1339
+ const authRouteRulesTemplate = addTemplate({
1340
+ filename: "better-auth/route-rules.mjs",
1341
+ getContents: () => buildAuthRouteRulesCode(collectAuthRouteRules(nuxt)),
1342
+ write: true
444
1343
  });
445
- const useUuid = userConfig.advanced?.database?.generateId === "uuid";
446
- const hubCasing = getHubCasing(hub);
447
- const schemaOptions = { ...options.schema, useUuid, casing: options.schema?.casing ?? hubCasing };
448
- const schemaCode = generateDrizzleSchema(tables, dialect, schemaOptions);
449
- const schemaDir = join(nuxt.options.buildDir, "better-auth");
450
- const schemaPath = join(schemaDir, `schema.${dialect}.ts`);
451
- await mkdir(schemaDir, { recursive: true });
452
- await writeFile(schemaPath, schemaCode);
453
- addTemplate({ filename: `better-auth/schema.${dialect}.ts`, getContents: () => schemaCode, write: true });
454
- consola.info(`Generated ${dialect} schema with ${Object.keys(tables).length} tables`);
455
- } catch (error) {
456
- if (isProduction) {
457
- throw error;
1344
+ nuxt.options.alias["#auth/route-rules"] = authRouteRulesTemplate.dst;
1345
+ if (setup.serverTypes) {
1346
+ registerServerTypeTemplates({
1347
+ serverConfigPath: setup.serverTypes.serverConfigPath,
1348
+ hasHubDb: setup.serverTypes.hasHubDb,
1349
+ runtimeTypesPath: resolver.resolve("./runtime/types"),
1350
+ sharedServerConfigSafe: isServerConfigSharedTypeSafe(setup.serverTypes.serverConfigPath)
1351
+ });
458
1352
  }
459
- consola.error("Failed to generate schema:", error);
460
- }
461
- const nuxtWithHubHooks = nuxt;
462
- nuxtWithHubHooks.hook("hub:db:schema:extend", ({ paths, dialect: hookDialect }) => {
463
- const schemaPath = join(nuxt.options.buildDir, "better-auth", `schema.${hookDialect}.ts`);
464
- if (existsSync(schemaPath)) {
465
- paths.unshift(schemaPath);
1353
+ if (setup.schemaGeneration) {
1354
+ if (setup.schemaGeneration.externalizeNuxtHubDatabase)
1355
+ registerNuxtHubDatabaseExternalHook(nuxt);
1356
+ await setupBetterAuthSchema(
1357
+ nuxt,
1358
+ setup.schemaGeneration.serverConfigPath,
1359
+ options,
1360
+ consola,
1361
+ setup.schemaGeneration.hubSecondaryStorage
1362
+ );
466
1363
  }
467
- });
468
- }
1364
+ registerSharedTypeTemplates({
1365
+ runtimeTypesAugmentPath: setup.aliases["#nuxt-better-auth"],
1366
+ runtimeTypesPath: resolver.resolve("./runtime/types"),
1367
+ clientConfigPath: setup.sharedTypes.clientConfigPath
1368
+ });
1369
+ registerTemplateHmrHook(nuxt);
1370
+ registerServerRuntime({ clientOnly: setup.clientOnly, resolve: resolver.resolve });
1371
+ registerAuthMiddlewareHook(nuxt, resolver.resolve);
1372
+ await registerDevtools({ nuxt, clientOnly: setup.clientOnly, hasHubDb: setup.database.hasHubDb, resolve: resolver.resolve });
1373
+ registerRouteRulesMetaHook(nuxt);
1374
+ }
1375
+ });
469
1376
 
470
1377
  export { module$1 as default };