better-auth-nuxt 0.0.2 → 0.0.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.d.mts +7 -3
- package/dist/module.json +1 -1
- package/dist/module.mjs +235 -10
- package/dist/runtime/middleware/auth.d.ts +2 -0
- package/dist/runtime/middleware/auth.js +31 -0
- package/dist/runtime/plugin.d.ts +1 -1
- package/dist/runtime/server/handler.js +1 -1
- package/package.json +2 -1
- package/dist/runtime/composables/useAuth.d.ts +0 -3492
- package/dist/runtime/composables/useAuth.js +0 -81
package/dist/module.d.mts
CHANGED
|
@@ -16,6 +16,10 @@ interface ModuleOptions {
|
|
|
16
16
|
* @default ['*.better-auth']
|
|
17
17
|
*/
|
|
18
18
|
serverConfigs?: string[];
|
|
19
|
+
/**
|
|
20
|
+
* @default ['*.better-auth-client']
|
|
21
|
+
*/
|
|
22
|
+
clientConfigs?: string[];
|
|
19
23
|
options: {
|
|
20
24
|
/**
|
|
21
25
|
* client options object or path to client setup script
|
|
@@ -30,9 +34,9 @@ interface ModuleOptions {
|
|
|
30
34
|
* redirect options
|
|
31
35
|
*/
|
|
32
36
|
redirectOptions: {
|
|
33
|
-
redirectUserTo
|
|
34
|
-
redirectGuestTo
|
|
35
|
-
redirectUnauthorizedTo
|
|
37
|
+
redirectUserTo?: string;
|
|
38
|
+
redirectGuestTo?: string;
|
|
39
|
+
redirectUnauthorizedTo?: string;
|
|
36
40
|
};
|
|
37
41
|
}
|
|
38
42
|
interface ModulePublicRuntimeConfig {
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
-
import { defineNuxtModule, createResolver, logger,
|
|
2
|
+
import { defineNuxtModule, createResolver, logger, addServerHandler, addTypeTemplate, addServerImports, addImports, addRouteMiddleware, addPlugin, addTemplate } from '@nuxt/kit';
|
|
3
3
|
import { defu } from 'defu';
|
|
4
4
|
import { resolve } from 'pathe';
|
|
5
5
|
import { hash } from 'ohash';
|
|
@@ -33,6 +33,119 @@ async function serverAuth({ options }) {
|
|
|
33
33
|
].join("\n");
|
|
34
34
|
}
|
|
35
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
|
+
}
|
|
148
|
+
|
|
36
149
|
const module = defineNuxtModule({
|
|
37
150
|
meta: {
|
|
38
151
|
name: "better-auth",
|
|
@@ -43,13 +156,19 @@ const module = defineNuxtModule({
|
|
|
43
156
|
endpoint: "/api/auth/**",
|
|
44
157
|
serverConfigs: [],
|
|
45
158
|
redirectOptions: {
|
|
46
|
-
redirectUserTo: "/
|
|
47
|
-
redirectGuestTo: "/
|
|
159
|
+
redirectUserTo: "/auth/login",
|
|
160
|
+
redirectGuestTo: "/",
|
|
48
161
|
redirectUnauthorizedTo: "/401"
|
|
49
162
|
}
|
|
50
163
|
},
|
|
51
164
|
async setup(options, nuxt) {
|
|
52
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
|
+
]);
|
|
53
172
|
if (!options.endpoint) {
|
|
54
173
|
logger.withTag("better-auth").error("Missing endpoint option");
|
|
55
174
|
}
|
|
@@ -59,7 +178,6 @@ const module = defineNuxtModule({
|
|
|
59
178
|
redirectOptions: options.redirectOptions
|
|
60
179
|
});
|
|
61
180
|
nuxt.options.alias["#better-auth"] = resolve("./runtime");
|
|
62
|
-
addImportsDir(resolve("./runtime/composables"));
|
|
63
181
|
addServerHandler({
|
|
64
182
|
route: options.endpoint,
|
|
65
183
|
handler: resolver.resolve("./runtime/server/handler")
|
|
@@ -104,7 +222,6 @@ const module = defineNuxtModule({
|
|
|
104
222
|
continue;
|
|
105
223
|
}
|
|
106
224
|
for (const path of [...paths, ...pathsJS]) {
|
|
107
|
-
console.log("path", path);
|
|
108
225
|
if (fs.existsSync(path)) {
|
|
109
226
|
serverConfigs.push({
|
|
110
227
|
key: pascalCase(hash(path)),
|
|
@@ -113,13 +230,13 @@ const module = defineNuxtModule({
|
|
|
113
230
|
}
|
|
114
231
|
}
|
|
115
232
|
}
|
|
116
|
-
registerTemplate({
|
|
117
|
-
filename: "better-auth
|
|
233
|
+
const server = registerTemplate({
|
|
234
|
+
filename: "better-auth/server.mjs",
|
|
118
235
|
getContents: serverAuth,
|
|
119
236
|
options: { configs: serverConfigs }
|
|
120
237
|
});
|
|
121
238
|
addTypeTemplate({
|
|
122
|
-
filename: "better-auth
|
|
239
|
+
filename: "better-auth/server.d.ts",
|
|
123
240
|
getContents: () => {
|
|
124
241
|
return [
|
|
125
242
|
'import { betterAuth } from "better-auth"',
|
|
@@ -138,16 +255,124 @@ const module = defineNuxtModule({
|
|
|
138
255
|
].join("\n");
|
|
139
256
|
}
|
|
140
257
|
});
|
|
258
|
+
const clientConfigs = [];
|
|
259
|
+
for (const layer of nuxt.options._layers) {
|
|
260
|
+
const paths = await glob([
|
|
261
|
+
"**/*.better-auth-client.ts",
|
|
262
|
+
...options.clientConfigs?.map((pattern) => {
|
|
263
|
+
return `**/${pattern}.ts`;
|
|
264
|
+
}) || []
|
|
265
|
+
], { onlyFiles: true, ignore: nuxt.options.ignore, dot: true, cwd: layer.config.rootDir, absolute: true });
|
|
266
|
+
const pathsJS = await glob([
|
|
267
|
+
"**/*.better-auth.js",
|
|
268
|
+
...options.serverConfigs?.map((pattern) => {
|
|
269
|
+
return `**/${pattern}.js`;
|
|
270
|
+
}) || []
|
|
271
|
+
], { cwd: layer.config.serverDir });
|
|
272
|
+
if (paths.length === 0 && pathsJS.length === 0) {
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
for (const path of [...paths, ...pathsJS]) {
|
|
276
|
+
if (fs.existsSync(path)) {
|
|
277
|
+
clientConfigs.push({
|
|
278
|
+
key: pascalCase(hash(path)),
|
|
279
|
+
path
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
const client = registerTemplate({
|
|
285
|
+
filename: "better-auth/client.mjs",
|
|
286
|
+
getContents: useUserSession,
|
|
287
|
+
options: { configs: clientConfigs }
|
|
288
|
+
});
|
|
289
|
+
addTypeTemplate({
|
|
290
|
+
filename: "better-auth/client.d.ts",
|
|
291
|
+
getContents: () => {
|
|
292
|
+
return [
|
|
293
|
+
'import { createAuthInstance } from "./client.mjs"',
|
|
294
|
+
'import type { ClientOptions, InferSessionFromClient, InferUserFromClient } from "better-auth"',
|
|
295
|
+
'import type { RouteLocationRaw } from "vue-router"',
|
|
296
|
+
'import { Ref, ComputedRef } from "vue"',
|
|
297
|
+
...clientConfigs.map((config) => {
|
|
298
|
+
return `import ${config.key} from "${config.path}"`;
|
|
299
|
+
}),
|
|
300
|
+
"export interface RuntimeAuthConfig {",
|
|
301
|
+
" redirectUserTo: RouteLocationRaw | string",
|
|
302
|
+
" redirectGuestTo: RouteLocationRaw | string",
|
|
303
|
+
" redirectUnauthorizedTo: RouteLocationRaw | string",
|
|
304
|
+
"}",
|
|
305
|
+
"export interface AuthSignOutOptions {",
|
|
306
|
+
" redirectTo?: RouteLocationRaw",
|
|
307
|
+
"}",
|
|
308
|
+
"export type AuthClient = ReturnType<typeof createAuthInstance>",
|
|
309
|
+
"export declare const useUserSession: () => AuthClient"
|
|
310
|
+
].join("\n");
|
|
311
|
+
}
|
|
312
|
+
});
|
|
141
313
|
addServerImports([
|
|
142
314
|
{
|
|
143
|
-
from:
|
|
315
|
+
from: server.dst,
|
|
144
316
|
name: "useAuth"
|
|
145
317
|
},
|
|
146
318
|
{
|
|
147
|
-
from:
|
|
319
|
+
from: server.dst,
|
|
148
320
|
name: "auth"
|
|
149
321
|
}
|
|
150
322
|
]);
|
|
323
|
+
addImports([
|
|
324
|
+
{
|
|
325
|
+
from: client.dst,
|
|
326
|
+
name: "useUserSession"
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
from: client.dst,
|
|
330
|
+
name: "createAuthInstance"
|
|
331
|
+
}
|
|
332
|
+
]);
|
|
333
|
+
addRouteMiddleware({
|
|
334
|
+
name: "auth",
|
|
335
|
+
path: resolver.resolve("./runtime/middleware/auth.ts"),
|
|
336
|
+
global: true
|
|
337
|
+
});
|
|
338
|
+
addTypeTemplate({
|
|
339
|
+
filename: "types/better-auth-middleware.d.ts",
|
|
340
|
+
getContents: () => {
|
|
341
|
+
return [
|
|
342
|
+
" type MiddlewareOptions = false | {",
|
|
343
|
+
" /**",
|
|
344
|
+
" * Only apply auth middleware to guest or user",
|
|
345
|
+
" */",
|
|
346
|
+
" only?:",
|
|
347
|
+
' | "guest"',
|
|
348
|
+
' | "user"',
|
|
349
|
+
' | "member"',
|
|
350
|
+
' | "admin"',
|
|
351
|
+
" /**",
|
|
352
|
+
" * Redirect authenticated user to this route",
|
|
353
|
+
" */",
|
|
354
|
+
" redirectUserTo?: string",
|
|
355
|
+
" /**",
|
|
356
|
+
" * Redirect guest to this route",
|
|
357
|
+
" */",
|
|
358
|
+
" redirectGuestTo?: string",
|
|
359
|
+
" redirectUnauthorizedTo?: string",
|
|
360
|
+
" }",
|
|
361
|
+
' declare module "#app" {',
|
|
362
|
+
" interface PageMeta {",
|
|
363
|
+
" auth?: MiddlewareOptions",
|
|
364
|
+
" }",
|
|
365
|
+
" }",
|
|
366
|
+
' declare module "vue-router" {',
|
|
367
|
+
" interface RouteMeta {",
|
|
368
|
+
" auth?: MiddlewareOptions",
|
|
369
|
+
" }",
|
|
370
|
+
" }",
|
|
371
|
+
"export {}"
|
|
372
|
+
].join("\n");
|
|
373
|
+
},
|
|
374
|
+
write: true
|
|
375
|
+
});
|
|
151
376
|
addPlugin(resolver.resolve("./runtime/plugin"));
|
|
152
377
|
}
|
|
153
378
|
});
|
|
@@ -0,0 +1,31 @@
|
|
|
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
|
+
await fetchSession();
|
|
11
|
+
if (only === "guest" && loggedIn.value) {
|
|
12
|
+
if (to.path === redirectUserTo) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
return navigateTo(redirectUserTo);
|
|
16
|
+
}
|
|
17
|
+
if (only && only !== "guest" && !loggedIn.value) {
|
|
18
|
+
if (to.path === redirectGuestTo)
|
|
19
|
+
return;
|
|
20
|
+
return navigateTo(redirectGuestTo);
|
|
21
|
+
}
|
|
22
|
+
if (only && only !== "guest" && loggedIn.value && session.value) {
|
|
23
|
+
const userRole = session.value.role || "user";
|
|
24
|
+
const requiredRoles = Array.isArray(only) ? only : [only];
|
|
25
|
+
if (!requiredRoles.includes(userRole) && !requiredRoles.includes("user")) {
|
|
26
|
+
if (to.path === redirectUnauthorizedTo)
|
|
27
|
+
return;
|
|
28
|
+
return navigateTo(redirectUnauthorizedTo ?? "/401");
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
});
|
package/dist/runtime/plugin.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: import("
|
|
1
|
+
declare const _default: import("#app").Plugin<Record<string, unknown>> & import("#app").ObjectPlugin<Record<string, unknown>>;
|
|
2
2
|
export default _default;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "better-auth-nuxt",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Better Auth Nuxt Module",
|
|
5
5
|
"repository": "productdevbook/better-auth-nuxt",
|
|
6
6
|
"license": "MIT",
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"@nuxt/module-builder": "^1.0.1",
|
|
53
53
|
"@nuxt/schema": "^3.16.2",
|
|
54
54
|
"@nuxt/test-utils": "^3.17.2",
|
|
55
|
+
"@tailwindcss/vite": "^4.1.4",
|
|
55
56
|
"@types/better-sqlite3": "^7.6.13",
|
|
56
57
|
"@types/node": "latest",
|
|
57
58
|
"better-auth": "^1.2.7",
|