better-auth-nuxt 0.0.1 → 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.
package/README.md CHANGED
@@ -1,13 +1,4 @@
1
- <!--
2
- Get your module up and running quickly.
3
-
4
- Find and replace all on all files (CMD+SHIFT+F):
5
- - Name: My Module
6
- - Package name: my-module
7
- - Description: My new Nuxt module
8
- -->
9
-
10
- # My Module
1
+ # Better Auth Nuxt
11
2
 
12
3
  [![npm version][npm-version-src]][npm-version-href]
13
4
  [![npm downloads][npm-downloads-src]][npm-downloads-href]
@@ -71,14 +62,14 @@ That's it! You can now use My Module in your Nuxt app ✨
71
62
 
72
63
 
73
64
  <!-- Badges -->
74
- [npm-version-src]: https://img.shields.io/npm/v/my-module/latest.svg?style=flat&colorA=020420&colorB=00DC82
75
- [npm-version-href]: https://npmjs.com/package/my-module
65
+ [npm-version-src]: https://img.shields.io/npm/v/better-auth-nuxt/latest.svg?style=flat&colorA=020420&colorB=00DC82
66
+ [npm-version-href]: https://npmjs.com/package/better-auth-nuxt
76
67
 
77
- [npm-downloads-src]: https://img.shields.io/npm/dm/my-module.svg?style=flat&colorA=020420&colorB=00DC82
78
- [npm-downloads-href]: https://npm.chart.dev/my-module
68
+ [npm-downloads-src]: https://img.shields.io/npm/dm/better-auth-nuxt.svg?style=flat&colorA=020420&colorB=00DC82
69
+ [npm-downloads-href]: https://npm.chart.dev/better-auth-nuxt
79
70
 
80
- [license-src]: https://img.shields.io/npm/l/my-module.svg?style=flat&colorA=020420&colorB=00DC82
81
- [license-href]: https://npmjs.com/package/my-module
71
+ [license-src]: https://img.shields.io/npm/l/better-auth-nuxt.svg?style=flat&colorA=020420&colorB=00DC82
72
+ [license-href]: https://npmjs.com/package/better-auth-nuxt
82
73
 
83
74
  [nuxt-src]: https://img.shields.io/badge/Nuxt-020420?logo=nuxt.js
84
75
  [nuxt-href]: https://nuxt.com
package/dist/module.d.mts CHANGED
@@ -1,9 +1,48 @@
1
1
  import * as _nuxt_schema from '@nuxt/schema';
2
+ import { ClientOptions, BetterAuthOptions } from 'better-auth';
2
3
 
4
+ interface ModuleServerOptions extends Pick<BetterAuthOptions, 'appName' | 'baseURL' | 'basePath' | 'secret'> {
5
+ }
6
+ interface ModuleClientOptions extends Pick<ClientOptions, 'baseURL' | 'basePath' | 'disableDefaultFetchPlugins'> {
7
+ }
3
8
  interface ModuleOptions {
4
- baseUrl?: string;
9
+ baseUrl: string;
10
+ /**
11
+ * auth endpoint
12
+ * @default 'api/auth/**'
13
+ */
14
+ endpoint: string;
15
+ /**
16
+ * @default ['*.better-auth']
17
+ */
18
+ serverConfigs?: string[];
19
+ /**
20
+ * @default ['*.better-auth-client']
21
+ */
22
+ clientConfigs?: string[];
23
+ options: {
24
+ /**
25
+ * client options object or path to client setup script
26
+ */
27
+ client: ModuleClientOptions;
28
+ /**
29
+ * server options object or path to server setup script
30
+ */
31
+ server: ModuleServerOptions;
32
+ };
33
+ /**
34
+ * redirect options
35
+ */
36
+ redirectOptions: {
37
+ redirectUserTo: string;
38
+ redirectGuestTo: string;
39
+ redirectUnauthorizedTo: string;
40
+ };
41
+ }
42
+ interface ModulePublicRuntimeConfig {
43
+ betterAuth: ModuleOptions;
5
44
  }
6
45
  declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
7
46
 
8
47
  export { _default as default };
9
- export type { ModuleOptions };
48
+ export type { ModuleClientOptions, ModuleOptions, ModulePublicRuntimeConfig, ModuleServerOptions };
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "better-auth",
3
3
  "configKey": "betterAuth",
4
- "version": "0.0.1",
4
+ "version": "0.0.3",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.1",
7
7
  "unbuild": "3.5.0"
package/dist/module.mjs CHANGED
@@ -1,4 +1,150 @@
1
- import { defineNuxtModule, createResolver, addPlugin } from '@nuxt/kit';
1
+ import fs from 'node:fs';
2
+ import { defineNuxtModule, createResolver, logger, addServerHandler, addTypeTemplate, addServerImports, addImports, addRouteMiddleware, addPlugin, addTemplate } from '@nuxt/kit';
3
+ import { defu } from 'defu';
4
+ import { resolve } from 'pathe';
5
+ import { hash } from 'ohash';
6
+ import { glob } from 'tinyglobby';
7
+ import { pascalCase } from 'scule';
8
+
9
+ async function serverAuth({ options }) {
10
+ return [
11
+ 'import mergeDeep from "@fastify/deepmerge"',
12
+ 'import { betterAuth } from "better-auth"',
13
+ ...options.configs.map((config) => {
14
+ return `import ${config.key} from "${config.path}"`;
15
+ }),
16
+ "const betterAuthConfigs = mergeDeep({all: true})({},",
17
+ ...options.configs.map((config) => {
18
+ return `${config.key},`;
19
+ }),
20
+ ")",
21
+ "",
22
+ "let _auth",
23
+ "",
24
+ "export function useAuth() {",
25
+ " if (!_auth) {",
26
+ " _auth = betterAuth(betterAuthConfigs)",
27
+ " }",
28
+ " return _auth",
29
+ "}",
30
+ "",
31
+ "export const auth = useAuth()",
32
+ ""
33
+ ].join("\n");
34
+ }
35
+
36
+ async function useUserSession({ options }) {
37
+ return [
38
+ "import { createAuthClient } from 'better-auth/vue'",
39
+ ...options.configs.map((config) => {
40
+ return `import ${config.key} from "${config.path}"`;
41
+ }),
42
+ "import { defu } from 'defu'",
43
+ "import { computed, ref } from 'vue'",
44
+ "import { navigateTo, useRequestHeaders, useRequestURL, useRuntimeConfig, useState } from '#app'",
45
+ "",
46
+ "let _authInstance",
47
+ "",
48
+ "export function createAuthInstance() {",
49
+ " const url = useRequestURL()",
50
+ " const headers = import.meta.server ? useRequestHeaders() : undefined",
51
+ " const config = useRuntimeConfig()",
52
+ "",
53
+ " const authClient = createAuthClient({",
54
+ " baseURL: url.origin,",
55
+ " fetchOptions: {",
56
+ ...options.configs.map((config) => {
57
+ return ` ...${config.key}?.fetchOptions || {},`;
58
+ }),
59
+ " headers,",
60
+ " },",
61
+ ...options.configs.map((config) => {
62
+ return ` ${config.key},`;
63
+ }),
64
+ " plugins: [",
65
+ ...options.configs.map((config) => {
66
+ return ` ...${config.key}?.plugins || [],`;
67
+ }),
68
+ " ],",
69
+ " })",
70
+ "",
71
+ " const options = defu(config.public.betterAuth.redirectOptions || {}, {",
72
+ " redirectUserTo: '/profile',",
73
+ " redirectGuestTo: '/signin',",
74
+ " redirectUnauthorizedTo: '/401',",
75
+ " })",
76
+ "",
77
+ " const session = useState('auth:session', () => null)",
78
+ " const user = useState('auth:user', () => null)",
79
+ " const sessionFetching = import.meta.server ? ref(false) : useState('auth:sessionFetching', () => false)",
80
+ "",
81
+ " const fetchSession = async () => {",
82
+ " if (sessionFetching.value) {",
83
+ " return",
84
+ " }",
85
+ " sessionFetching.value = true",
86
+ " const { data } = await authClient.getSession({",
87
+ " fetchOptions: {",
88
+ " headers,",
89
+ " },",
90
+ " })",
91
+ " session.value = data?.session || null",
92
+ " user.value = data?.user || null",
93
+ " sessionFetching.value = false",
94
+ " return data",
95
+ " }",
96
+ "",
97
+ " return {",
98
+ " session,",
99
+ " user,",
100
+ " loggedIn: computed(() => !!session.value),",
101
+ " signIn: authClient.signIn,",
102
+ " signUp: authClient.signUp,",
103
+ " options,",
104
+ " fetchSession,",
105
+ " client: authClient,",
106
+ " signOut: async (options = {}) => {",
107
+ " try {",
108
+ " await authClient.signOut()",
109
+ " if (options.redirectTo)",
110
+ " await navigateTo(options.redirectTo)",
111
+ " }",
112
+ " catch (error) {",
113
+ " console.error('Sign out failed:', error)",
114
+ " throw error",
115
+ " }",
116
+ " },",
117
+ " }",
118
+ "}",
119
+ "",
120
+ "// Setup session listener for client-side updates",
121
+ "function setupSessionListener(client) {",
122
+ " if (!import.meta.client)",
123
+ " return",
124
+ "",
125
+ " client.$store.listen('$sessionSignal', async (signal) => {",
126
+ " if (!signal)",
127
+ " return",
128
+ " await client.useSession($fetch)",
129
+ " })",
130
+ "}",
131
+ "",
132
+ "export function useUserSession() {",
133
+ " if (_authInstance && import.meta.client)",
134
+ " return _authInstance",
135
+ "",
136
+ " const auth = createAuthInstance()",
137
+ "",
138
+ " if (import.meta.client) {",
139
+ " setupSessionListener(auth.client)",
140
+ " _authInstance = auth",
141
+ " }",
142
+ "",
143
+ " return auth",
144
+ "}",
145
+ ""
146
+ ].join("\n");
147
+ }
2
148
 
3
149
  const module = defineNuxtModule({
4
150
  meta: {
@@ -6,9 +152,191 @@ const module = defineNuxtModule({
6
152
  configKey: "betterAuth"
7
153
  },
8
154
  // Default configuration options of the Nuxt module
9
- defaults: {},
10
- setup(_options, _nuxt) {
155
+ defaults: {
156
+ endpoint: "/api/auth/**",
157
+ serverConfigs: [],
158
+ redirectOptions: {
159
+ redirectUserTo: "/profile",
160
+ redirectGuestTo: "/signin",
161
+ redirectUnauthorizedTo: "/401"
162
+ }
163
+ },
164
+ async setup(options, nuxt) {
11
165
  const resolver = createResolver(import.meta.url);
166
+ nuxt.options.vite.optimizeDeps ??= {};
167
+ nuxt.options.vite.optimizeDeps.include ??= [];
168
+ nuxt.options.vite.optimizeDeps.include.push(...[
169
+ "better-auth/client",
170
+ "better-auth/vue"
171
+ ]);
172
+ if (!options.endpoint) {
173
+ logger.withTag("better-auth").error("Missing endpoint option");
174
+ }
175
+ nuxt.options.runtimeConfig.public.betterAuth = defu(nuxt.options.runtimeConfig.public.betterAuth, {
176
+ baseUrl: options.baseUrl,
177
+ endpoint: options.endpoint,
178
+ redirectOptions: options.redirectOptions
179
+ });
180
+ nuxt.options.alias["#better-auth"] = resolve("./runtime");
181
+ addServerHandler({
182
+ route: options.endpoint,
183
+ handler: resolver.resolve("./runtime/server/handler")
184
+ });
185
+ const registerTemplate = (options2) => {
186
+ const name = options2.filename.replace(/\.m?js$/, "");
187
+ const alias = "#" + name;
188
+ const results = addTemplate({
189
+ ...options2,
190
+ write: true
191
+ // Write to disk for Nitro to consume
192
+ });
193
+ nuxt.options.nitro.alias ||= {};
194
+ nuxt.options.nitro.externals ||= {};
195
+ nuxt.options.nitro.externals.inline ||= [];
196
+ nuxt.options.alias[alias] = results.dst;
197
+ nuxt.options.nitro.alias[alias] = nuxt.options.alias[alias];
198
+ nuxt.options.nitro.externals.inline.push(nuxt.options.alias[alias]);
199
+ nuxt.options.nitro.externals.inline.push(alias);
200
+ return results;
201
+ };
202
+ const serverConfigs = [
203
+ {
204
+ key: pascalCase(hash("better-auth-configs")),
205
+ path: resolver.resolve("./runtime/server")
206
+ }
207
+ ];
208
+ for (const layer of nuxt.options._layers) {
209
+ const paths = await glob([
210
+ "**/*.better-auth.ts",
211
+ ...options.serverConfigs?.map((pattern) => {
212
+ return `**/${pattern}.ts`;
213
+ }) || []
214
+ ], { onlyFiles: true, ignore: nuxt.options.ignore, dot: true, cwd: layer.config.rootDir, absolute: true });
215
+ const pathsJS = await glob([
216
+ "**/*.better-auth.js",
217
+ ...options.serverConfigs?.map((pattern) => {
218
+ return `**/${pattern}.js`;
219
+ }) || []
220
+ ], { cwd: layer.config.serverDir });
221
+ if (paths.length === 0 && pathsJS.length === 0) {
222
+ continue;
223
+ }
224
+ for (const path of [...paths, ...pathsJS]) {
225
+ console.log("path", path);
226
+ if (fs.existsSync(path)) {
227
+ serverConfigs.push({
228
+ key: pascalCase(hash(path)),
229
+ path
230
+ });
231
+ }
232
+ }
233
+ }
234
+ const server = registerTemplate({
235
+ filename: "better-auth/server.mjs",
236
+ getContents: serverAuth,
237
+ options: { configs: serverConfigs }
238
+ });
239
+ addTypeTemplate({
240
+ filename: "better-auth/server.d.ts",
241
+ getContents: () => {
242
+ return [
243
+ 'import { betterAuth } from "better-auth"',
244
+ 'import mergeDeep from "@fastify/deepmerge"',
245
+ ...serverConfigs.map((config) => {
246
+ return `import ${config.key} from "${config.path}"`;
247
+ }),
248
+ "const betterAuthConfigs = mergeDeep({all: true})({},",
249
+ ...serverConfigs.map((config) => {
250
+ return `${config.key},`;
251
+ }),
252
+ ")",
253
+ "export type BetterAuth = ReturnType<typeof betterAuth<typeof betterAuthConfigs>>",
254
+ "export declare const useAuth: () => BetterAuth",
255
+ "export declare const auth: BetterAuth"
256
+ ].join("\n");
257
+ }
258
+ });
259
+ const clientConfigs = [];
260
+ for (const layer of nuxt.options._layers) {
261
+ const paths = await glob([
262
+ "**/*.better-auth-client.ts",
263
+ ...options.clientConfigs?.map((pattern) => {
264
+ return `**/${pattern}.ts`;
265
+ }) || []
266
+ ], { onlyFiles: true, ignore: nuxt.options.ignore, dot: true, cwd: layer.config.rootDir, absolute: true });
267
+ const pathsJS = await glob([
268
+ "**/*.better-auth.js",
269
+ ...options.serverConfigs?.map((pattern) => {
270
+ return `**/${pattern}.js`;
271
+ }) || []
272
+ ], { cwd: layer.config.serverDir });
273
+ if (paths.length === 0 && pathsJS.length === 0) {
274
+ continue;
275
+ }
276
+ for (const path of [...paths, ...pathsJS]) {
277
+ console.log("path", path);
278
+ if (fs.existsSync(path)) {
279
+ clientConfigs.push({
280
+ key: pascalCase(hash(path)),
281
+ path
282
+ });
283
+ }
284
+ }
285
+ }
286
+ const client = registerTemplate({
287
+ filename: "better-auth/client.mjs",
288
+ getContents: useUserSession,
289
+ options: { configs: clientConfigs }
290
+ });
291
+ addTypeTemplate({
292
+ filename: "better-auth/client.d.ts",
293
+ getContents: () => {
294
+ return [
295
+ 'import { createAuthInstance } from "./client.mjs"',
296
+ 'import type { ClientOptions, InferSessionFromClient, InferUserFromClient } from "better-auth"',
297
+ 'import type { RouteLocationRaw } from "vue-router"',
298
+ 'import { Ref, ComputedRef } from "vue"',
299
+ ...clientConfigs.map((config) => {
300
+ return `import ${config.key} from "${config.path}"`;
301
+ }),
302
+ "export interface RuntimeAuthConfig {",
303
+ " redirectUserTo: RouteLocationRaw | string",
304
+ " redirectGuestTo: RouteLocationRaw | string",
305
+ " redirectUnauthorizedTo: RouteLocationRaw | string",
306
+ "}",
307
+ "export interface AuthSignOutOptions {",
308
+ " redirectTo?: RouteLocationRaw",
309
+ "}",
310
+ "export type AuthClient = ReturnType<typeof createAuthInstance>",
311
+ "export declare const useUserSession: () => AuthClient"
312
+ ].join("\n");
313
+ }
314
+ });
315
+ addServerImports([
316
+ {
317
+ from: server.dst,
318
+ name: "useAuth"
319
+ },
320
+ {
321
+ from: server.dst,
322
+ name: "auth"
323
+ }
324
+ ]);
325
+ addImports([
326
+ {
327
+ from: client.dst,
328
+ name: "useUserSession"
329
+ },
330
+ {
331
+ from: client.dst,
332
+ name: "createAuthInstance"
333
+ }
334
+ ]);
335
+ addRouteMiddleware({
336
+ name: "better-auth",
337
+ path: resolver.resolve("./runtime/middleware/auth.global"),
338
+ global: true
339
+ });
12
340
  addPlugin(resolver.resolve("./runtime/plugin"));
13
341
  }
14
342
  });
@@ -0,0 +1,27 @@
1
+ type MiddlewareOptions = false | {
2
+ /**
3
+ * Only apply auth middleware to guest or user
4
+ */
5
+ only?: 'guest' | 'user' | 'member' | 'admin';
6
+ /**
7
+ * Redirect authenticated user to this route
8
+ */
9
+ redirectUserTo?: string;
10
+ /**
11
+ * Redirect guest to this route
12
+ */
13
+ redirectGuestTo?: string;
14
+ redirectUnauthorizedTo?: string;
15
+ };
16
+ declare module '#app' {
17
+ interface PageMeta {
18
+ auth?: MiddlewareOptions;
19
+ }
20
+ }
21
+ declare module 'vue-router' {
22
+ interface RouteMeta {
23
+ auth?: MiddlewareOptions;
24
+ }
25
+ }
26
+ declare const _default: import("#app").RouteMiddleware;
27
+ export default _default;
@@ -0,0 +1,35 @@
1
+ import { defu } from "defu";
2
+ import { defineNuxtRouteMiddleware, navigateTo } from "#app";
3
+ import { useUserSession } from "#imports";
4
+ export default defineNuxtRouteMiddleware(async (to) => {
5
+ if (to.meta?.auth === false) {
6
+ return;
7
+ }
8
+ const { loggedIn, options, fetchSession, session } = useUserSession();
9
+ const { only, redirectUserTo, redirectGuestTo, redirectUnauthorizedTo } = defu(to.meta?.auth, options);
10
+ if (import.meta.client) {
11
+ await fetchSession();
12
+ }
13
+ if (loggedIn.value && to.path.startsWith("/auth/")) {
14
+ if (to.path === redirectUserTo) {
15
+ return;
16
+ }
17
+ return navigateTo(redirectUserTo);
18
+ }
19
+ if (only === "guest" && loggedIn.value) {
20
+ if (to.path === redirectUserTo) {
21
+ return;
22
+ }
23
+ return navigateTo(redirectUserTo);
24
+ }
25
+ if (only && only !== "guest" && !loggedIn.value) {
26
+ if (to.path === redirectGuestTo)
27
+ return;
28
+ return navigateTo(redirectGuestTo);
29
+ }
30
+ if (only && only !== "guest" && session.value) {
31
+ if (to.path === redirectUnauthorizedTo)
32
+ return;
33
+ return navigateTo(redirectUnauthorizedTo ?? "/401");
34
+ }
35
+ });
@@ -1,2 +1,2 @@
1
- declare const _default: import("nuxt/app").Plugin<Record<string, unknown>> & import("nuxt/app").ObjectPlugin<Record<string, unknown>>;
1
+ declare const _default: import("#app").Plugin<Record<string, unknown>> & import("#app").ObjectPlugin<Record<string, unknown>>;
2
2
  export default _default;
@@ -1,4 +1,3 @@
1
1
  import { defineNuxtPlugin } from "#app";
2
2
  export default defineNuxtPlugin((_nuxtApp) => {
3
- console.log("Plugin injected by my-module!");
4
3
  });
@@ -0,0 +1,2 @@
1
+ declare const _default: import("h3").EventHandler<import("h3").EventHandlerRequest, Promise<Response>>;
2
+ export default _default;
@@ -0,0 +1,5 @@
1
+ import { defineEventHandler, toWebRequest } from "h3";
2
+ import { auth } from "#better-auth/server";
3
+ export default defineEventHandler((event) => {
4
+ return auth.handler(toWebRequest(event));
5
+ });
@@ -0,0 +1,6 @@
1
+ declare const _default: {
2
+ disabledPaths: never[];
3
+ plugins: never[];
4
+ trustedOrigins: never[];
5
+ };
6
+ export default _default;
@@ -0,0 +1,5 @@
1
+ export default {
2
+ disabledPaths: [],
3
+ plugins: [],
4
+ trustedOrigins: []
5
+ };
package/dist/types.d.mts CHANGED
@@ -1,3 +1,9 @@
1
+ import type { ModulePublicRuntimeConfig } from './module.mjs'
2
+
3
+ declare module '@nuxt/schema' {
4
+ interface PublicRuntimeConfig extends ModulePublicRuntimeConfig {}
5
+ }
6
+
1
7
  export { default } from './module.mjs'
2
8
 
3
- export { type ModuleOptions } from './module.mjs'
9
+ export { type ModuleClientOptions, type ModuleOptions, type ModulePublicRuntimeConfig, type ModuleServerOptions } from './module.mjs'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "better-auth-nuxt",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "Better Auth Nuxt Module",
5
5
  "repository": "productdevbook/better-auth-nuxt",
6
6
  "license": "MIT",
@@ -34,8 +34,17 @@
34
34
  "test:watch": "vitest watch",
35
35
  "test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit"
36
36
  },
37
+ "peerDependencies": {
38
+ "better-auth": ">=1.2.7"
39
+ },
37
40
  "dependencies": {
38
- "@nuxt/kit": "^3.16.2"
41
+ "@fastify/deepmerge": "^3.1.0",
42
+ "@nuxt/kit": "^3.16.2",
43
+ "defu": "^6.1.4",
44
+ "ohash": "^2.0.11",
45
+ "pathe": "^2.0.3",
46
+ "scule": "^1.3.0",
47
+ "tinyglobby": "^0.2.12"
39
48
  },
40
49
  "devDependencies": {
41
50
  "@nuxt/devtools": "^2.4.0",
@@ -43,7 +52,10 @@
43
52
  "@nuxt/module-builder": "^1.0.1",
44
53
  "@nuxt/schema": "^3.16.2",
45
54
  "@nuxt/test-utils": "^3.17.2",
55
+ "@types/better-sqlite3": "^7.6.13",
46
56
  "@types/node": "latest",
57
+ "better-auth": "^1.2.7",
58
+ "better-sqlite3": "^11.9.1",
47
59
  "changelogen": "^0.6.1",
48
60
  "eslint": "^9.24.0",
49
61
  "nuxt": "^3.16.2",