@onmax/nuxt-better-auth 0.0.2-alpha.11 → 0.0.2-alpha.12

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 CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=3.0.0"
6
6
  },
7
- "version": "0.0.2-alpha.11",
7
+ "version": "0.0.2-alpha.12",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "1.0.2",
10
10
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -213,6 +213,7 @@ const consola = consola$1.withTag("nuxt-better-auth");
213
213
  const module$1 = defineNuxtModule({
214
214
  meta: { name: "@onmax/nuxt-better-auth", configKey: "auth", compatibility: { nuxt: ">=3.0.0" } },
215
215
  defaults: {
216
+ clientOnly: false,
216
217
  serverConfig: "server/auth.config",
217
218
  clientConfig: "app/auth.config",
218
219
  redirects: { login: "/login", guest: "/" },
@@ -220,47 +221,63 @@ const module$1 = defineNuxtModule({
220
221
  },
221
222
  async setup(options, nuxt) {
222
223
  const resolver = createResolver(import.meta.url);
224
+ const clientOnly = options.clientOnly;
223
225
  const serverConfigFile = options.serverConfig;
224
226
  const clientConfigFile = options.clientConfig;
225
227
  const serverConfigPath = resolver.resolve(nuxt.options.rootDir, serverConfigFile);
226
228
  const clientConfigPath = resolver.resolve(nuxt.options.rootDir, clientConfigFile);
227
229
  const serverConfigExists = existsSync(`${serverConfigPath}.ts`) || existsSync(`${serverConfigPath}.js`);
228
230
  const clientConfigExists = existsSync(`${clientConfigPath}.ts`) || existsSync(`${clientConfigPath}.js`);
229
- if (!serverConfigExists)
231
+ if (!clientOnly && !serverConfigExists)
230
232
  throw new Error(`[nuxt-better-auth] Missing ${serverConfigFile}.ts - create with defineServerAuth()`);
231
233
  if (!clientConfigExists)
232
234
  throw new Error(`[nuxt-better-auth] Missing ${clientConfigFile}.ts - export createAppAuthClient()`);
233
235
  const hasNuxtHub = hasNuxtModule("@nuxthub/core", nuxt);
234
236
  const hub = hasNuxtHub ? nuxt.options.hub : void 0;
235
- const hasHubDb = hasNuxtHub && !!hub?.db;
237
+ const hasHubDb = !clientOnly && hasNuxtHub && !!hub?.db;
236
238
  let secondaryStorageEnabled = options.secondaryStorage ?? false;
237
- if (secondaryStorageEnabled && (!hasNuxtHub || !hub?.kv)) {
239
+ if (secondaryStorageEnabled && clientOnly) {
240
+ consola.warn("secondaryStorage is not available in clientOnly mode. Disabling.");
241
+ secondaryStorageEnabled = false;
242
+ } else if (secondaryStorageEnabled && (!hasNuxtHub || !hub?.kv)) {
238
243
  consola.warn("secondaryStorage requires @nuxthub/core with hub.kv: true. Disabling.");
239
244
  secondaryStorageEnabled = false;
240
245
  }
241
246
  nuxt.options.runtimeConfig.public = nuxt.options.runtimeConfig.public || {};
242
247
  nuxt.options.runtimeConfig.public.auth = defu(nuxt.options.runtimeConfig.public.auth, {
243
248
  redirects: { login: options.redirects?.login ?? "/login", guest: options.redirects?.guest ?? "/" },
244
- useDatabase: hasHubDb
249
+ useDatabase: hasHubDb,
250
+ clientOnly
245
251
  });
246
- const betterAuthSecret = process.env.BETTER_AUTH_SECRET || process.env.NUXT_BETTER_AUTH_SECRET || nuxt.options.runtimeConfig.betterAuthSecret || "";
247
- if (!nuxt.options.dev && !betterAuthSecret) {
248
- throw new Error("[nuxt-better-auth] BETTER_AUTH_SECRET is required in production. Set BETTER_AUTH_SECRET or NUXT_BETTER_AUTH_SECRET environment variable.");
252
+ if (clientOnly) {
253
+ const siteUrl = process.env.NUXT_PUBLIC_SITE_URL || nuxt.options.runtimeConfig.public.siteUrl;
254
+ if (!siteUrl) {
255
+ consola.warn("clientOnly mode: NUXT_PUBLIC_SITE_URL should be set to your frontend URL");
256
+ }
257
+ consola.info("clientOnly mode enabled - server utilities (serverAuth, getUserSession, requireUserSession) are not available");
249
258
  }
250
- if (betterAuthSecret && betterAuthSecret.length < 32) {
251
- throw new Error("[nuxt-better-auth] BETTER_AUTH_SECRET must be at least 32 characters for security");
259
+ if (!clientOnly) {
260
+ const betterAuthSecret = process.env.BETTER_AUTH_SECRET || process.env.NUXT_BETTER_AUTH_SECRET || nuxt.options.runtimeConfig.betterAuthSecret || "";
261
+ if (!nuxt.options.dev && !betterAuthSecret) {
262
+ throw new Error("[nuxt-better-auth] BETTER_AUTH_SECRET is required in production. Set BETTER_AUTH_SECRET or NUXT_BETTER_AUTH_SECRET environment variable.");
263
+ }
264
+ if (betterAuthSecret && betterAuthSecret.length < 32) {
265
+ throw new Error("[nuxt-better-auth] BETTER_AUTH_SECRET must be at least 32 characters for security");
266
+ }
267
+ nuxt.options.runtimeConfig.betterAuthSecret = betterAuthSecret;
268
+ nuxt.options.runtimeConfig.auth = defu(nuxt.options.runtimeConfig.auth, {
269
+ secondaryStorage: secondaryStorageEnabled
270
+ });
252
271
  }
253
- nuxt.options.runtimeConfig.betterAuthSecret = betterAuthSecret;
254
- nuxt.options.runtimeConfig.auth = defu(nuxt.options.runtimeConfig.auth, {
255
- secondaryStorage: secondaryStorageEnabled
256
- });
257
272
  nuxt.options.alias["#nuxt-better-auth"] = resolver.resolve("./runtime/types/augment");
258
- nuxt.options.alias["#auth/server"] = serverConfigPath;
273
+ if (!clientOnly)
274
+ nuxt.options.alias["#auth/server"] = serverConfigPath;
259
275
  nuxt.options.alias["#auth/client"] = clientConfigPath;
260
- if (secondaryStorageEnabled && !nuxt.options.alias["hub:kv"]) {
261
- throw new Error("[nuxt-better-auth] hub:kv not found. Ensure @nuxthub/core is loaded before this module and hub.kv is enabled.");
262
- }
263
- const secondaryStorageCode = secondaryStorageEnabled ? `import { kv } from '../hub/kv.mjs'
276
+ if (!clientOnly) {
277
+ if (secondaryStorageEnabled && !nuxt.options.alias["hub:kv"]) {
278
+ throw new Error("[nuxt-better-auth] hub:kv not found. Ensure @nuxthub/core is loaded before this module and hub.kv is enabled.");
279
+ }
280
+ const secondaryStorageCode = secondaryStorageEnabled ? `import { kv } from '../hub/kv.mjs'
264
281
  export function createSecondaryStorage() {
265
282
  return {
266
283
  get: async (key) => kv.get(\`_auth:\${key}\`),
@@ -268,24 +285,24 @@ export function createSecondaryStorage() {
268
285
  delete: async (key) => kv.del(\`_auth:\${key}\`),
269
286
  }
270
287
  }` : `export function createSecondaryStorage() { return undefined }`;
271
- const secondaryStorageTemplate = addTemplate({ filename: "better-auth/secondary-storage.mjs", getContents: () => secondaryStorageCode, write: true });
272
- nuxt.options.alias["#auth/secondary-storage"] = secondaryStorageTemplate.dst;
273
- if (hasHubDb && !nuxt.options.alias["hub:db"]) {
274
- throw new Error("[nuxt-better-auth] hub:db not found. Ensure @nuxthub/core is loaded before this module and hub.db is configured.");
275
- }
276
- const hubDialect = getHubDialect(hub) ?? "sqlite";
277
- const databaseCode = hasHubDb ? `import { db, schema } from '../hub/db.mjs'
288
+ const secondaryStorageTemplate = addTemplate({ filename: "better-auth/secondary-storage.mjs", getContents: () => secondaryStorageCode, write: true });
289
+ nuxt.options.alias["#auth/secondary-storage"] = secondaryStorageTemplate.dst;
290
+ if (hasHubDb && !nuxt.options.alias["hub:db"]) {
291
+ throw new Error("[nuxt-better-auth] hub:db not found. Ensure @nuxthub/core is loaded before this module and hub.db is configured.");
292
+ }
293
+ const hubDialect = getHubDialect(hub) ?? "sqlite";
294
+ const databaseCode = hasHubDb ? `import { db, schema } from '../hub/db.mjs'
278
295
  import { drizzleAdapter } from 'better-auth/adapters/drizzle'
279
296
  const rawDialect = '${hubDialect}'
280
297
  const dialect = rawDialect === 'postgresql' ? 'pg' : rawDialect
281
298
  export function createDatabase() { return drizzleAdapter(db, { provider: dialect, schema }) }
282
299
  export { db }` : `export function createDatabase() { return undefined }
283
300
  export const db = undefined`;
284
- const databaseTemplate = addTemplate({ filename: "better-auth/database.mjs", getContents: () => databaseCode, write: true });
285
- nuxt.options.alias["#auth/database"] = databaseTemplate.dst;
286
- addTypeTemplate({
287
- filename: "types/auth-secondary-storage.d.ts",
288
- getContents: () => `
301
+ const databaseTemplate = addTemplate({ filename: "better-auth/database.mjs", getContents: () => databaseCode, write: true });
302
+ nuxt.options.alias["#auth/database"] = databaseTemplate.dst;
303
+ addTypeTemplate({
304
+ filename: "types/auth-secondary-storage.d.ts",
305
+ getContents: () => `
289
306
  declare module '#auth/secondary-storage' {
290
307
  interface SecondaryStorage {
291
308
  get: (key: string) => Promise<string | null>
@@ -295,28 +312,21 @@ declare module '#auth/secondary-storage' {
295
312
  export function createSecondaryStorage(): SecondaryStorage | undefined
296
313
  }
297
314
  `
298
- });
299
- addTypeTemplate({
300
- filename: "types/auth-database.d.ts",
301
- getContents: () => `
315
+ });
316
+ addTypeTemplate({
317
+ filename: "types/auth-database.d.ts",
318
+ getContents: () => `
302
319
  declare module '#auth/database' {
303
320
  import type { drizzleAdapter } from 'better-auth/adapters/drizzle'
304
321
  export function createDatabase(): ReturnType<typeof drizzleAdapter> | undefined
305
322
  export const db: unknown
306
323
  }
307
324
  `
308
- });
309
- addTypeTemplate({
310
- filename: "types/nuxt-better-auth.d.ts",
311
- getContents: () => `
312
- export * from '${resolver.resolve("./runtime/types/augment")}'
313
- export type { AuthMeta, AuthMode, AuthRouteRules, UserMatch, RequireSessionOptions, Auth, InferUser, InferSession } from '${resolver.resolve("./runtime/types")}'
314
- `
315
- });
316
- addTypeTemplate({
317
- filename: "types/nuxt-better-auth-infer.d.ts",
318
- getContents: () => `
319
- import type { InferUser, InferSession } from 'better-auth'
325
+ });
326
+ addTypeTemplate({
327
+ filename: "types/nuxt-better-auth-infer.d.ts",
328
+ getContents: () => `
329
+ import type { InferUser, InferSession, InferPluginTypes } from 'better-auth'
320
330
  import type { RuntimeConfig } from 'nuxt/schema'
321
331
  import type configFn from '${serverConfigPath}'
322
332
 
@@ -324,11 +334,12 @@ type _Config = ReturnType<typeof configFn>
324
334
 
325
335
  declare module '#nuxt-better-auth' {
326
336
  interface AuthUser extends InferUser<_Config> {}
327
- interface AuthSession { session: InferSession<_Config>['session'], user: InferUser<_Config> }
337
+ interface AuthSession extends InferSession<_Config> {}
328
338
  interface ServerAuthContext {
329
339
  runtimeConfig: RuntimeConfig
330
340
  ${hasHubDb ? `db: typeof import('hub:db')['db']` : ""}
331
341
  }
342
+ type PluginTypes = InferPluginTypes<_Config>
332
343
  }
333
344
 
334
345
  // Augment the config module to use the extended ServerAuthContext
@@ -343,19 +354,10 @@ declare module '@onmax/nuxt-better-auth/config' {
343
354
  export function defineServerAuth<T extends ServerAuthConfig>(config: (ctx: _AugmentedServerAuthContext) => T): (ctx: _AugmentedServerAuthContext) => T
344
355
  }
345
356
  `
346
- });
347
- addTypeTemplate({
348
- filename: "types/nuxt-better-auth-client.d.ts",
349
- getContents: () => `
350
- import type { createAppAuthClient } from '${clientConfigPath}'
351
- declare module '#nuxt-better-auth' {
352
- export type AppAuthClient = ReturnType<typeof createAppAuthClient>
353
- }
354
- `
355
- });
356
- addTypeTemplate({
357
- filename: "types/nuxt-better-auth-nitro.d.ts",
358
- getContents: () => `
357
+ });
358
+ addTypeTemplate({
359
+ filename: "types/nuxt-better-auth-nitro.d.ts",
360
+ getContents: () => `
359
361
  declare module 'nitropack' {
360
362
  interface NitroRouteRules {
361
363
  auth?: import('${resolver.resolve("./runtime/types")}').AuthMeta
@@ -374,19 +376,39 @@ declare module 'nitropack/types' {
374
376
  }
375
377
  export {}
376
378
  `
377
- }, { nuxt: true, nitro: true, node: true });
379
+ }, { nuxt: true, nitro: true, node: true });
380
+ }
381
+ addTypeTemplate({
382
+ filename: "types/nuxt-better-auth.d.ts",
383
+ getContents: () => `
384
+ export * from '${resolver.resolve("./runtime/types/augment")}'
385
+ export type { AuthMeta, AuthMode, AuthRouteRules, UserMatch, RequireSessionOptions, Auth, InferUser, InferSession } from '${resolver.resolve("./runtime/types")}'
386
+ `
387
+ });
388
+ addTypeTemplate({
389
+ filename: "types/nuxt-better-auth-client.d.ts",
390
+ getContents: () => `
391
+ import type { createAppAuthClient } from '${clientConfigPath}'
392
+ declare module '#nuxt-better-auth' {
393
+ export type AppAuthClient = ReturnType<typeof createAppAuthClient>
394
+ }
395
+ `
396
+ });
378
397
  nuxt.hook("builder:watch", async (_event, relativePath) => {
379
398
  if (relativePath.includes("auth.config")) {
380
399
  await updateTemplates({ filter: (t) => t.filename.includes("nuxt-better-auth") });
381
400
  }
382
401
  });
383
- addServerImportsDir(resolver.resolve("./runtime/server/utils"));
384
- addServerImports([{ name: "defineServerAuth", from: resolver.resolve("./runtime/config") }]);
385
- addServerScanDir(resolver.resolve("./runtime/server/middleware"));
386
- addServerHandler({ route: "/api/auth/**", handler: resolver.resolve("./runtime/server/api/auth/[...all]") });
402
+ if (!clientOnly) {
403
+ addServerImportsDir(resolver.resolve("./runtime/server/utils"));
404
+ addServerImports([{ name: "defineServerAuth", from: resolver.resolve("./runtime/config") }]);
405
+ addServerScanDir(resolver.resolve("./runtime/server/middleware"));
406
+ addServerHandler({ route: "/api/auth/**", handler: resolver.resolve("./runtime/server/api/auth/[...all]") });
407
+ }
387
408
  addImportsDir(resolver.resolve("./runtime/app/composables"));
388
409
  addImportsDir(resolver.resolve("./runtime/utils"));
389
- addPlugin({ src: resolver.resolve("./runtime/app/plugins/session.server"), mode: "server" });
410
+ if (!clientOnly)
411
+ addPlugin({ src: resolver.resolve("./runtime/app/plugins/session.server"), mode: "server" });
390
412
  addPlugin({ src: resolver.resolve("./runtime/app/plugins/session.client"), mode: "client" });
391
413
  addComponentsDir({ path: resolver.resolve("./runtime/app/components") });
392
414
  nuxt.hook("app:resolve", (app) => {
@@ -396,7 +418,7 @@ export {}
396
418
  await setupBetterAuthSchema(nuxt, serverConfigPath, options);
397
419
  }
398
420
  const isProduction = process.env.NODE_ENV === "production" || !nuxt.options.dev;
399
- if (!isProduction) {
421
+ if (!isProduction && !clientOnly) {
400
422
  setupDevTools(nuxt);
401
423
  addServerHandler({ route: "/api/_better-auth/config", method: "get", handler: resolver.resolve("./runtime/server/api/_better-auth/config.get") });
402
424
  if (hasHubDb) {
@@ -1,4 +1,5 @@
1
1
  <script setup>
2
+ import { useUserSession } from "#imports";
2
3
  const { loggedIn, user, session, signOut, ready } = useUserSession();
3
4
  </script>
4
5
 
@@ -1,5 +1,4 @@
1
- import { defineNuxtPlugin } from "#imports";
2
- import { useUserSession } from "../composables/useUserSession.js";
1
+ import { defineNuxtPlugin, useUserSession } from "#imports";
3
2
  export default defineNuxtPlugin(async (nuxtApp) => {
4
3
  const { fetchSession } = useUserSession();
5
4
  const safeFetch = async () => {
@@ -13,6 +13,8 @@ type ClientAuthConfig = Omit<ClientOptions, 'baseURL'> & {
13
13
  export type ServerAuthConfigFn = (ctx: ServerAuthContext) => ServerAuthConfig;
14
14
  export type ClientAuthConfigFn = (ctx: ClientAuthContext) => ClientAuthConfig;
15
15
  export interface BetterAuthModuleOptions {
16
+ /** Client-only mode - skip server setup for external auth backends */
17
+ clientOnly?: boolean;
16
18
  /** Server config path relative to rootDir. Default: 'server/auth.config' */
17
19
  serverConfig?: string;
18
20
  /** Client config path relative to rootDir. Default: 'app/auth.config' */
@@ -36,6 +38,8 @@ export interface AuthRuntimeConfig {
36
38
  login: string;
37
39
  guest: string;
38
40
  };
41
+ useDatabase: boolean;
42
+ clientOnly: boolean;
39
43
  }
40
44
  export interface AuthPrivateRuntimeConfig {
41
45
  secondaryStorage: boolean;
@@ -1,7 +1,7 @@
1
1
  import type { NitroRouteRules } from 'nitropack/types';
2
2
  import type { AuthSession, AuthUser } from './types/augment.js';
3
3
  export type { AuthSession, AuthUser, ServerAuthContext, UserSessionComposable } from './types/augment.js';
4
- export type { Auth, InferSession, InferUser } from 'better-auth';
4
+ export type { Auth, InferPluginTypes, InferSession, InferUser } from 'better-auth';
5
5
  export type AuthMode = 'guest' | 'user';
6
6
  export type UserMatch<T> = {
7
7
  [K in keyof T]?: T[K] | T[K][];
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.11",
4
+ "version": "0.0.2-alpha.12",
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",