@onmax/nuxt-better-auth 0.0.2-alpha.2 → 0.0.2-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.json +1 -1
- package/dist/module.mjs +105 -28
- package/dist/runtime/app/composables/useUserSession.js +11 -9
- package/dist/runtime/app/middleware/auth.global.js +7 -1
- package/dist/runtime/app/plugins/session.server.js +2 -1
- package/dist/runtime/config.d.ts +8 -0
- package/dist/runtime/server/api/_better-auth/config.get.d.ts +9 -9
- package/dist/runtime/server/api/_better-auth/config.get.js +2 -1
- package/dist/runtime/server/api/_better-auth/sessions.get.js +10 -1
- package/dist/runtime/server/utils/auth.d.ts +3 -2
- package/package.json +6 -2
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import { consola as consola$1 } from 'consola';
|
|
|
5
5
|
import { defu } from 'defu';
|
|
6
6
|
import { join } from 'pathe';
|
|
7
7
|
import { toRouteMatcher, createRouter } from 'radix3';
|
|
8
|
+
import pluralize from 'pluralize';
|
|
8
9
|
export { defineClientAuth, defineServerAuth } from '../dist/runtime/config.js';
|
|
9
10
|
|
|
10
11
|
function setupDevTools(nuxt) {
|
|
@@ -22,46 +23,65 @@ function setupDevTools(nuxt) {
|
|
|
22
23
|
});
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
function
|
|
26
|
-
|
|
27
|
-
|
|
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();
|
|
28
|
+
}
|
|
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");
|
|
28
33
|
return `${imports}
|
|
29
34
|
|
|
30
35
|
${tableDefinitions}
|
|
31
36
|
`;
|
|
32
37
|
}
|
|
33
|
-
function getImports(dialect) {
|
|
38
|
+
function getImports(dialect, options) {
|
|
34
39
|
switch (dialect) {
|
|
35
40
|
case "sqlite":
|
|
36
41
|
return `import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'`;
|
|
37
42
|
case "postgresql":
|
|
38
|
-
return `import { boolean, pgTable, text, timestamp, integer } from 'drizzle-orm/pg-core'`;
|
|
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'`;
|
|
39
44
|
case "mysql":
|
|
40
45
|
return `import { boolean, int, mysqlTable, text, timestamp, varchar } from 'drizzle-orm/mysql-core'`;
|
|
41
46
|
}
|
|
42
47
|
}
|
|
43
|
-
function generateTable(tableName, table, dialect, allTables) {
|
|
48
|
+
function generateTable(tableName, table, dialect, allTables, options) {
|
|
44
49
|
const tableFunc = dialect === "sqlite" ? "sqliteTable" : dialect === "postgresql" ? "pgTable" : "mysqlTable";
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
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);
|
|
48
58
|
return `export const ${tableName} = ${tableFunc}('${dbTableName}', {
|
|
49
59
|
${idField},
|
|
50
60
|
${fields}
|
|
51
61
|
})`;
|
|
52
62
|
}
|
|
53
|
-
function generateIdField(dialect) {
|
|
63
|
+
function generateIdField(dialect, options) {
|
|
54
64
|
switch (dialect) {
|
|
55
65
|
case "sqlite":
|
|
56
|
-
|
|
66
|
+
if (options?.useUuid)
|
|
67
|
+
consola$1.warn("[@onmax/nuxt-better-auth] useUuid ignored for SQLite (no native uuid type). Using text.");
|
|
57
68
|
return `id: text('id').primaryKey()`;
|
|
69
|
+
case "postgresql":
|
|
70
|
+
return options?.useUuid ? `id: uuid('id').defaultRandom().primaryKey()` : `id: text('id').primaryKey()`;
|
|
58
71
|
case "mysql":
|
|
59
72
|
return `id: varchar('id', { length: 36 }).primaryKey()`;
|
|
60
73
|
}
|
|
61
74
|
}
|
|
62
|
-
function generateField(fieldName, field, dialect, allTables) {
|
|
63
|
-
const dbFieldName = fieldName;
|
|
64
|
-
|
|
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);
|
|
65
85
|
if (field.required && field.defaultValue === void 0)
|
|
66
86
|
fieldDef += ".notNull()";
|
|
67
87
|
if (field.unique)
|
|
@@ -71,11 +91,15 @@ function generateField(fieldName, field, dialect, allTables) {
|
|
|
71
91
|
fieldDef += `.default(${field.defaultValue})`;
|
|
72
92
|
else if (typeof field.defaultValue === "string")
|
|
73
93
|
fieldDef += `.default('${field.defaultValue}')`;
|
|
94
|
+
else if (typeof field.defaultValue === "function")
|
|
95
|
+
fieldDef += `.$defaultFn(${field.defaultValue})`;
|
|
74
96
|
else
|
|
75
97
|
fieldDef += `.default(${field.defaultValue})`;
|
|
76
98
|
if (field.required)
|
|
77
99
|
fieldDef += ".notNull()";
|
|
78
100
|
}
|
|
101
|
+
if (typeof field.onUpdate === "function" && field.type === "date")
|
|
102
|
+
fieldDef += `.$onUpdate(${field.onUpdate})`;
|
|
79
103
|
if (field.references) {
|
|
80
104
|
const refTable = field.references.model;
|
|
81
105
|
if (allTables[refTable])
|
|
@@ -136,22 +160,42 @@ function getMysqlType(type, fieldName) {
|
|
|
136
160
|
return `text('${fieldName}')`;
|
|
137
161
|
}
|
|
138
162
|
}
|
|
139
|
-
async function loadUserAuthConfig(configPath) {
|
|
163
|
+
async function loadUserAuthConfig(configPath, throwOnError = false) {
|
|
140
164
|
const { createJiti } = await import('jiti');
|
|
141
165
|
const jiti = createJiti(import.meta.url, { interopDefault: true });
|
|
142
166
|
try {
|
|
143
167
|
const mod = await jiti.import(configPath);
|
|
144
|
-
const configFn = mod.default
|
|
168
|
+
const configFn = typeof mod === "object" && mod !== null && "default" in mod ? mod.default : mod;
|
|
145
169
|
if (typeof configFn === "function") {
|
|
146
170
|
return configFn({ runtimeConfig: {}, db: null });
|
|
147
171
|
}
|
|
172
|
+
if (throwOnError) {
|
|
173
|
+
throw new Error("auth.config.ts must export default defineServerAuth(...)");
|
|
174
|
+
}
|
|
148
175
|
return {};
|
|
149
176
|
} catch (error) {
|
|
177
|
+
if (throwOnError) {
|
|
178
|
+
throw new Error(`Failed to load auth config: ${error instanceof Error ? error.message : error}`);
|
|
179
|
+
}
|
|
150
180
|
consola$1.error("[@onmax/nuxt-better-auth] Failed to load auth config for schema generation. Schema may be incomplete:", error);
|
|
151
181
|
return {};
|
|
152
182
|
}
|
|
153
183
|
}
|
|
154
184
|
|
|
185
|
+
function getHubDialect(hub) {
|
|
186
|
+
if (!hub?.db)
|
|
187
|
+
return void 0;
|
|
188
|
+
if (typeof hub.db === "string")
|
|
189
|
+
return hub.db;
|
|
190
|
+
if (typeof hub.db === "object" && hub.db !== null)
|
|
191
|
+
return hub.db.dialect;
|
|
192
|
+
return void 0;
|
|
193
|
+
}
|
|
194
|
+
function getHubCasing(hub) {
|
|
195
|
+
if (!hub?.db || typeof hub.db !== "object" || hub.db === null)
|
|
196
|
+
return void 0;
|
|
197
|
+
return hub.db.casing;
|
|
198
|
+
}
|
|
155
199
|
const consola = consola$1.withTag("nuxt-better-auth");
|
|
156
200
|
const module$1 = defineNuxtModule({
|
|
157
201
|
meta: { name: "@onmax/nuxt-better-auth", configKey: "auth", compatibility: { nuxt: ">=3.0.0" } },
|
|
@@ -186,14 +230,25 @@ const module$1 = defineNuxtModule({
|
|
|
186
230
|
redirects: { login: options.redirects?.login ?? "/login", guest: options.redirects?.guest ?? "/" },
|
|
187
231
|
useDatabase: hasHubDb
|
|
188
232
|
});
|
|
189
|
-
|
|
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");
|
|
239
|
+
}
|
|
240
|
+
nuxt.options.runtimeConfig.betterAuthSecret = betterAuthSecret;
|
|
190
241
|
nuxt.options.runtimeConfig.auth = defu(nuxt.options.runtimeConfig.auth, {
|
|
191
242
|
secondaryStorage: secondaryStorageEnabled
|
|
192
243
|
});
|
|
193
244
|
nuxt.options.alias["#nuxt-better-auth"] = resolver.resolve("./runtime/types/augment");
|
|
194
245
|
nuxt.options.alias["#auth/server"] = serverConfigPath;
|
|
195
246
|
nuxt.options.alias["#auth/client"] = clientConfigPath;
|
|
196
|
-
const
|
|
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.");
|
|
250
|
+
}
|
|
251
|
+
const secondaryStorageCode = secondaryStorageEnabled ? `import { kv } from '${hubKVPath}'
|
|
197
252
|
export function createSecondaryStorage() {
|
|
198
253
|
return {
|
|
199
254
|
get: async (key) => kv.get(\`_auth:\${key}\`),
|
|
@@ -204,9 +259,13 @@ export function createSecondaryStorage() {
|
|
|
204
259
|
const secondaryStorageTemplate = addTemplate({ filename: "better-auth/secondary-storage.mjs", getContents: () => secondaryStorageCode, write: true });
|
|
205
260
|
nuxt.options.alias["#auth/secondary-storage"] = secondaryStorageTemplate.dst;
|
|
206
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.");
|
|
264
|
+
}
|
|
265
|
+
const hubDialect = getHubDialect(hub) ?? "sqlite";
|
|
207
266
|
const databaseCode = hasHubDb && hubDbPath ? `import { db, schema } from '${hubDbPath}'
|
|
208
267
|
import { drizzleAdapter } from 'better-auth/adapters/drizzle'
|
|
209
|
-
const rawDialect = '${
|
|
268
|
+
const rawDialect = '${hubDialect}'
|
|
210
269
|
const dialect = rawDialect === 'postgresql' ? 'pg' : rawDialect
|
|
211
270
|
export function createDatabase() { return drizzleAdapter(db, { provider: dialect, schema }) }
|
|
212
271
|
export { db }` : `export function createDatabase() { return undefined }
|
|
@@ -298,9 +357,10 @@ declare module 'nitropack/types' {
|
|
|
298
357
|
app.middleware.push({ name: "auth", path: resolver.resolve("./runtime/app/middleware/auth.global"), global: true });
|
|
299
358
|
});
|
|
300
359
|
if (hasHubDb) {
|
|
301
|
-
await setupBetterAuthSchema(nuxt, serverConfigPath);
|
|
360
|
+
await setupBetterAuthSchema(nuxt, serverConfigPath, options);
|
|
302
361
|
}
|
|
303
|
-
|
|
362
|
+
const isProduction = process.env.NODE_ENV === "production" || !nuxt.options.dev;
|
|
363
|
+
if (!isProduction) {
|
|
304
364
|
setupDevTools(nuxt);
|
|
305
365
|
addServerHandler({ route: "/api/_better-auth/config", method: "get", handler: resolver.resolve("./runtime/server/api/_better-auth/config.get") });
|
|
306
366
|
if (hasHubDb) {
|
|
@@ -333,22 +393,35 @@ declare module 'nitropack/types' {
|
|
|
333
393
|
});
|
|
334
394
|
}
|
|
335
395
|
});
|
|
336
|
-
async function setupBetterAuthSchema(nuxt, serverConfigPath) {
|
|
396
|
+
async function setupBetterAuthSchema(nuxt, serverConfigPath, options) {
|
|
337
397
|
const hub = nuxt.options.hub;
|
|
338
|
-
const dialect =
|
|
398
|
+
const dialect = getHubDialect(hub);
|
|
339
399
|
if (!dialect || !["sqlite", "postgresql", "mysql"].includes(dialect)) {
|
|
340
400
|
consola.warn(`Unsupported database dialect: ${dialect}`);
|
|
341
401
|
return;
|
|
342
402
|
}
|
|
403
|
+
const isProduction = !nuxt.options.dev;
|
|
343
404
|
try {
|
|
344
405
|
const configFile = `${serverConfigPath}.ts`;
|
|
345
|
-
const userConfig = await loadUserAuthConfig(configFile);
|
|
406
|
+
const userConfig = await loadUserAuthConfig(configFile, isProduction);
|
|
346
407
|
const extendedConfig = {};
|
|
347
408
|
await nuxt.callHook("better-auth:config:extend", extendedConfig);
|
|
348
409
|
const plugins = [...userConfig.plugins || [], ...extendedConfig.plugins || []];
|
|
349
410
|
const { getAuthTables } = await import('better-auth/db');
|
|
350
|
-
const tables = getAuthTables({
|
|
351
|
-
|
|
411
|
+
const tables = getAuthTables({
|
|
412
|
+
plugins,
|
|
413
|
+
secondaryStorage: options.secondaryStorage ? {
|
|
414
|
+
get: async (_key) => null,
|
|
415
|
+
set: async (_key, _value, _ttl) => {
|
|
416
|
+
},
|
|
417
|
+
delete: async (_key) => {
|
|
418
|
+
}
|
|
419
|
+
} : void 0
|
|
420
|
+
});
|
|
421
|
+
const useUuid = userConfig.advanced?.database?.generateId === "uuid";
|
|
422
|
+
const hubCasing = getHubCasing(hub);
|
|
423
|
+
const schemaOptions = { ...options.schema, useUuid, casing: options.schema?.casing ?? hubCasing };
|
|
424
|
+
const schemaCode = generateDrizzleSchema(tables, dialect, schemaOptions);
|
|
352
425
|
const schemaDir = join(nuxt.options.buildDir, "better-auth");
|
|
353
426
|
const schemaPath = join(schemaDir, `schema.${dialect}.ts`);
|
|
354
427
|
await mkdir(schemaDir, { recursive: true });
|
|
@@ -356,12 +429,16 @@ async function setupBetterAuthSchema(nuxt, serverConfigPath) {
|
|
|
356
429
|
addTemplate({ filename: `better-auth/schema.${dialect}.ts`, getContents: () => schemaCode, write: true });
|
|
357
430
|
consola.info(`Generated ${dialect} schema with ${Object.keys(tables).length} tables`);
|
|
358
431
|
} catch (error) {
|
|
432
|
+
if (isProduction) {
|
|
433
|
+
throw error;
|
|
434
|
+
}
|
|
359
435
|
consola.error("Failed to generate schema:", error);
|
|
360
436
|
}
|
|
361
|
-
|
|
437
|
+
const nuxtWithHubHooks = nuxt;
|
|
438
|
+
nuxtWithHubHooks.hook("hub:db:schema:extend", ({ paths, dialect: hookDialect }) => {
|
|
362
439
|
const schemaPath = join(nuxt.options.buildDir, "better-auth", `schema.${hookDialect}.ts`);
|
|
363
440
|
if (existsSync(schemaPath)) {
|
|
364
|
-
paths.
|
|
441
|
+
paths.unshift(schemaPath);
|
|
365
442
|
}
|
|
366
443
|
});
|
|
367
444
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { createAppAuthClient } from "#auth/client";
|
|
2
2
|
import { computed, nextTick, useRequestHeaders, useRequestURL, useRuntimeConfig, useState, watch } from "#imports";
|
|
3
|
-
import { consola } from "consola";
|
|
4
3
|
let _client = null;
|
|
5
4
|
function getClient(baseURL) {
|
|
6
5
|
if (!_client)
|
|
@@ -30,7 +29,8 @@ export function useUserSession() {
|
|
|
30
29
|
() => clientSession.value,
|
|
31
30
|
(newSession) => {
|
|
32
31
|
if (newSession?.data?.session && newSession?.data?.user) {
|
|
33
|
-
|
|
32
|
+
const { token: _, ...safeSession } = newSession.data.session;
|
|
33
|
+
session.value = safeSession;
|
|
34
34
|
user.value = newSession.data.user;
|
|
35
35
|
} else if (!newSession?.isPending) {
|
|
36
36
|
clearSession();
|
|
@@ -82,10 +82,11 @@ export function useUserSession() {
|
|
|
82
82
|
}
|
|
83
83
|
const signIn = client?.signIn ? new Proxy(client.signIn, {
|
|
84
84
|
get(target, prop) {
|
|
85
|
-
const
|
|
85
|
+
const targetRecord = target;
|
|
86
|
+
const method = targetRecord[prop];
|
|
86
87
|
if (typeof method !== "function")
|
|
87
88
|
return method;
|
|
88
|
-
return wrapAuthMethod((...args) =>
|
|
89
|
+
return wrapAuthMethod((...args) => targetRecord[prop](...args));
|
|
89
90
|
}
|
|
90
91
|
}) : new Proxy({}, {
|
|
91
92
|
get: (_, prop) => {
|
|
@@ -94,10 +95,11 @@ export function useUserSession() {
|
|
|
94
95
|
});
|
|
95
96
|
const signUp = client?.signUp ? new Proxy(client.signUp, {
|
|
96
97
|
get(target, prop) {
|
|
97
|
-
const
|
|
98
|
+
const targetRecord = target;
|
|
99
|
+
const method = targetRecord[prop];
|
|
98
100
|
if (typeof method !== "function")
|
|
99
101
|
return method;
|
|
100
|
-
return wrapAuthMethod((...args) =>
|
|
102
|
+
return wrapAuthMethod((...args) => targetRecord[prop](...args));
|
|
101
103
|
}
|
|
102
104
|
}) : new Proxy({}, {
|
|
103
105
|
get: (_, prop) => {
|
|
@@ -118,15 +120,15 @@ export function useUserSession() {
|
|
|
118
120
|
const result = await client.getSession({ query }, fetchOptions);
|
|
119
121
|
const data = result.data;
|
|
120
122
|
if (data?.session && data?.user) {
|
|
121
|
-
|
|
123
|
+
const { token: _, ...safeSession } = data.session;
|
|
124
|
+
session.value = safeSession;
|
|
122
125
|
user.value = data.user;
|
|
123
126
|
} else {
|
|
124
127
|
clearSession();
|
|
125
128
|
}
|
|
126
129
|
} catch (error) {
|
|
127
130
|
clearSession();
|
|
128
|
-
|
|
129
|
-
consola.error("Failed to fetch auth session:", error);
|
|
131
|
+
console.error("[nuxt-better-auth] Failed to fetch session:", error);
|
|
130
132
|
} finally {
|
|
131
133
|
if (!authReady.value)
|
|
132
134
|
authReady.value = true;
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
import { createError, defineNuxtRouteMiddleware, getRouteRules, navigateTo, useRequestHeaders, useRuntimeConfig } from "#imports";
|
|
1
|
+
import { createError, defineNuxtRouteMiddleware, getRouteRules, navigateTo, useNuxtApp, useRequestHeaders, useRuntimeConfig } from "#imports";
|
|
2
2
|
import { matchesUser } from "../../utils/match-user.js";
|
|
3
3
|
export default defineNuxtRouteMiddleware(async (to) => {
|
|
4
|
+
const nuxtApp = useNuxtApp();
|
|
5
|
+
if (import.meta.client) {
|
|
6
|
+
const isPrerendered = nuxtApp.payload.prerenderedAt || nuxtApp.payload.isCached;
|
|
7
|
+
if (isPrerendered && nuxtApp.isHydrating)
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
4
10
|
if (to.meta.auth === void 0) {
|
|
5
11
|
const rules = await getRouteRules({ path: to.path });
|
|
6
12
|
if (rules.auth !== void 0)
|
|
@@ -12,7 +12,8 @@ export default defineNuxtPlugin({
|
|
|
12
12
|
const headers = useRequestHeaders(["cookie"]);
|
|
13
13
|
const data = await $fetch("/api/auth/get-session", { headers });
|
|
14
14
|
if (data?.session && data?.user) {
|
|
15
|
-
|
|
15
|
+
const { token: _, ...safeSession } = data.session;
|
|
16
|
+
session.value = safeSession;
|
|
16
17
|
user.value = data.user;
|
|
17
18
|
}
|
|
18
19
|
} catch {
|
package/dist/runtime/config.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { BetterAuthOptions } from 'better-auth';
|
|
2
2
|
import type { ClientOptions } from 'better-auth/client';
|
|
3
|
+
import type { CasingOption } from '../schema-generator.js';
|
|
3
4
|
import type { ServerAuthContext } from './types/augment.js';
|
|
4
5
|
export type { ServerAuthContext };
|
|
5
6
|
export interface ClientAuthContext {
|
|
@@ -22,6 +23,13 @@ export interface BetterAuthModuleOptions {
|
|
|
22
23
|
};
|
|
23
24
|
/** Enable KV secondary storage for sessions. Requires hub.kv: true */
|
|
24
25
|
secondaryStorage?: boolean;
|
|
26
|
+
/** Schema generation options. Must match drizzleAdapter config. */
|
|
27
|
+
schema?: {
|
|
28
|
+
/** Plural table names: user → users. Default: false */
|
|
29
|
+
usePlural?: boolean;
|
|
30
|
+
/** Column/table name casing. Explicit value takes precedence over hub.db.casing. */
|
|
31
|
+
casing?: CasingOption;
|
|
32
|
+
};
|
|
25
33
|
}
|
|
26
34
|
export interface AuthRuntimeConfig {
|
|
27
35
|
redirects: {
|
|
@@ -9,27 +9,27 @@ declare const _default: import("h3").EventHandler<import("h3").EventHandlerReque
|
|
|
9
9
|
useDatabase: boolean;
|
|
10
10
|
};
|
|
11
11
|
server: {
|
|
12
|
-
baseURL:
|
|
13
|
-
basePath:
|
|
12
|
+
baseURL: any;
|
|
13
|
+
basePath: any;
|
|
14
14
|
socialProviders: string[];
|
|
15
|
-
plugins: any
|
|
16
|
-
trustedOrigins:
|
|
15
|
+
plugins: any;
|
|
16
|
+
trustedOrigins: any;
|
|
17
17
|
session: {
|
|
18
18
|
expiresIn: string;
|
|
19
19
|
updateAge: string;
|
|
20
|
-
cookieCache:
|
|
20
|
+
cookieCache: any;
|
|
21
21
|
};
|
|
22
22
|
emailAndPassword: boolean;
|
|
23
|
-
rateLimit:
|
|
23
|
+
rateLimit: any;
|
|
24
24
|
advanced: {
|
|
25
|
-
useSecureCookies:
|
|
26
|
-
disableCSRFCheck:
|
|
25
|
+
useSecureCookies: any;
|
|
26
|
+
disableCSRFCheck: any;
|
|
27
27
|
};
|
|
28
28
|
};
|
|
29
29
|
};
|
|
30
30
|
error?: undefined;
|
|
31
31
|
} | {
|
|
32
32
|
config: null;
|
|
33
|
-
error:
|
|
33
|
+
error: string;
|
|
34
34
|
}>>;
|
|
35
35
|
export default _default;
|
|
@@ -41,6 +41,7 @@ export default defineEventHandler(async (event) => {
|
|
|
41
41
|
}
|
|
42
42
|
};
|
|
43
43
|
} catch (error) {
|
|
44
|
-
|
|
44
|
+
console.error("[DevTools] Config fetch failed:", error);
|
|
45
|
+
return { config: null, error: "Failed to fetch configuration" };
|
|
45
46
|
}
|
|
46
47
|
});
|
|
@@ -26,7 +26,16 @@ export default defineEventHandler(async (event) => {
|
|
|
26
26
|
dbQuery.orderBy(desc(schema.session.createdAt)).limit(limit).offset(offset),
|
|
27
27
|
countQuery
|
|
28
28
|
]);
|
|
29
|
-
|
|
29
|
+
const safeSessions = sessions.map((s) => ({
|
|
30
|
+
id: s.id,
|
|
31
|
+
userId: s.userId,
|
|
32
|
+
createdAt: s.createdAt,
|
|
33
|
+
updatedAt: s.updatedAt,
|
|
34
|
+
expiresAt: s.expiresAt,
|
|
35
|
+
ipAddress: s.ipAddress,
|
|
36
|
+
userAgent: s.userAgent
|
|
37
|
+
}));
|
|
38
|
+
return { sessions: safeSessions, total: totalResult[0]?.count ?? 0, page, limit };
|
|
30
39
|
} catch (error) {
|
|
31
40
|
console.error("[DevTools] Fetch sessions failed:", error);
|
|
32
41
|
return { sessions: [], total: 0, error: "Failed to fetch sessions" };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import type { Auth } from 'better-auth';
|
|
1
2
|
import type { H3Event } from 'h3';
|
|
2
|
-
import
|
|
3
|
-
type AuthInstance = ReturnType<typeof
|
|
3
|
+
import createServerAuth from '#auth/server';
|
|
4
|
+
type AuthInstance = Auth<ReturnType<typeof createServerAuth>>;
|
|
4
5
|
declare module 'h3' {
|
|
5
6
|
interface H3EventContext {
|
|
6
7
|
_betterAuth?: AuthInstance;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onmax/nuxt-better-auth",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.2-alpha.
|
|
4
|
+
"version": "0.0.2-alpha.4",
|
|
5
5
|
"packageManager": "pnpm@10.15.1",
|
|
6
6
|
"description": "Nuxt module for Better Auth integration with NuxtHub, route protection, session management, and role-based access",
|
|
7
7
|
"author": "onmax",
|
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
"defu": "^6.1.4",
|
|
64
64
|
"jiti": "^2.4.2",
|
|
65
65
|
"pathe": "^2.0.3",
|
|
66
|
+
"pluralize": "^8.0.0",
|
|
66
67
|
"radix3": "^1.1.2"
|
|
67
68
|
},
|
|
68
69
|
"devDependencies": {
|
|
@@ -77,6 +78,7 @@
|
|
|
77
78
|
"@nuxthub/core": "^0.10.3",
|
|
78
79
|
"@types/better-sqlite3": "^7.6.13",
|
|
79
80
|
"@types/node": "latest",
|
|
81
|
+
"@types/pluralize": "^0.0.33",
|
|
80
82
|
"better-auth": "^1.4.7",
|
|
81
83
|
"better-sqlite3": "^11.9.1",
|
|
82
84
|
"bumpp": "^10.3.2",
|
|
@@ -95,9 +97,11 @@
|
|
|
95
97
|
},
|
|
96
98
|
"pnpm": {
|
|
97
99
|
"onlyBuiltDependencies": [
|
|
100
|
+
"@parcel/watcher",
|
|
98
101
|
"better-sqlite3",
|
|
99
102
|
"esbuild",
|
|
100
|
-
"
|
|
103
|
+
"sharp",
|
|
104
|
+
"workerd"
|
|
101
105
|
],
|
|
102
106
|
"patchedDependencies": {
|
|
103
107
|
"@peculiar/x509@1.14.2": "patches/@peculiar__x509@1.14.2.patch",
|