@onmax/nuxt-better-auth 0.0.1 → 0.0.2-alpha.2
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 +17 -170
- package/dist/module.d.mts +20 -2
- package/dist/module.json +1 -1
- package/dist/module.mjs +363 -14
- package/dist/runtime/app/components/BetterAuthState.d.vue.ts +20 -0
- package/dist/runtime/app/components/BetterAuthState.vue +8 -0
- package/dist/runtime/app/components/BetterAuthState.vue.d.ts +20 -0
- package/dist/runtime/app/composables/useUserSession.d.ts +20 -0
- package/dist/runtime/app/composables/useUserSession.js +158 -0
- package/dist/runtime/app/middleware/auth.global.d.ts +13 -0
- package/dist/runtime/app/middleware/auth.global.js +31 -0
- package/dist/runtime/app/pages/__better-auth-devtools.d.vue.ts +3 -0
- package/dist/runtime/app/pages/__better-auth-devtools.vue +426 -0
- package/dist/runtime/app/pages/__better-auth-devtools.vue.d.ts +3 -0
- package/dist/runtime/app/plugins/session.client.d.ts +2 -0
- package/dist/runtime/app/plugins/session.client.js +16 -0
- package/dist/runtime/app/plugins/session.server.d.ts +2 -0
- package/dist/runtime/app/plugins/session.server.js +23 -0
- package/dist/runtime/config.d.ts +36 -0
- package/dist/runtime/config.js +6 -0
- package/dist/runtime/server/api/_better-auth/_schema.d.ts +8 -0
- package/dist/runtime/server/api/_better-auth/_schema.js +11 -0
- package/dist/runtime/server/api/_better-auth/accounts.get.d.ts +14 -0
- package/dist/runtime/server/api/_better-auth/accounts.get.js +28 -0
- package/dist/runtime/server/api/_better-auth/config.get.d.ts +35 -0
- package/dist/runtime/server/api/_better-auth/config.get.js +46 -0
- package/dist/runtime/server/api/_better-auth/sessions.delete.d.ts +4 -0
- package/dist/runtime/server/api/_better-auth/sessions.delete.js +22 -0
- package/dist/runtime/server/api/_better-auth/sessions.get.d.ts +14 -0
- package/dist/runtime/server/api/_better-auth/sessions.get.js +34 -0
- package/dist/runtime/server/api/_better-auth/users.get.d.ts +14 -0
- package/dist/runtime/server/api/_better-auth/users.get.js +34 -0
- package/dist/runtime/server/api/auth/[...all].d.ts +2 -0
- package/dist/runtime/server/api/auth/[...all].js +6 -0
- package/dist/runtime/server/middleware/route-access.d.ts +2 -0
- package/dist/runtime/server/middleware/route-access.js +28 -0
- package/dist/runtime/server/tsconfig.json +3 -0
- package/dist/runtime/server/utils/auth.d.ts +10 -0
- package/dist/runtime/server/utils/auth.js +32 -0
- package/dist/runtime/server/utils/session.d.ts +9 -0
- package/dist/runtime/server/utils/session.js +22 -0
- package/dist/runtime/types/augment.d.ts +42 -0
- package/dist/runtime/types/augment.js +0 -0
- package/dist/runtime/types.d.ts +23 -0
- package/dist/runtime/types.js +0 -0
- package/dist/runtime/utils/match-user.d.ts +2 -0
- package/dist/runtime/utils/match-user.js +13 -0
- package/dist/types.d.mts +8 -10
- package/package.json +35 -10
- package/dist/module.d.cts +0 -2
package/README.md
CHANGED
|
@@ -1,180 +1,27 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/onmax/nuxt-better-auth/main/.github/og.png" alt="Nuxt Better Auth" width="100%">
|
|
3
|
+
<br>
|
|
4
|
+
<sub>Designed by <a href="https://github.com/HugoRCD">HugoRCD</a></sub>
|
|
5
|
+
</p>
|
|
2
6
|
|
|
3
|
-
|
|
4
|
-
[![npm downloads][npm-downloads-src]][npm-downloads-href]
|
|
5
|
-
[![License][license-src]][license-href]
|
|
6
|
-
[![Nuxt][nuxt-src]][nuxt-href]
|
|
7
|
+
<h1 align="center">@onmax/nuxt-better-auth</h1>
|
|
7
8
|
|
|
8
|
-
Nuxt module for
|
|
9
|
+
<p align="center">Nuxt module for <a href="https://better-auth.com">Better Auth</a></p>
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://npmjs.com/package/@onmax/nuxt-better-auth"><img src="https://img.shields.io/npm/v/@onmax/nuxt-better-auth/latest.svg?style=flat&colorA=020420&colorB=00DC82" alt="npm version"></a>
|
|
13
|
+
<a href="https://npm.chart.dev/@onmax/nuxt-better-auth"><img src="https://img.shields.io/npm/dm/@onmax/nuxt-better-auth.svg?style=flat&colorA=020420&colorB=00DC82" alt="npm downloads"></a>
|
|
14
|
+
<a href="https://npmjs.com/package/@onmax/nuxt-better-auth"><img src="https://img.shields.io/npm/l/@onmax/nuxt-better-auth.svg?style=flat&colorA=020420&colorB=00DC82" alt="License"></a>
|
|
15
|
+
<a href="https://nuxt.com"><img src="https://img.shields.io/badge/Nuxt-020420?logo=nuxt.js" alt="Nuxt"></a>
|
|
16
|
+
</p>
|
|
11
17
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
- **Session Management** - SSR-safe session handling with client hydration
|
|
15
|
-
- **Role-Based Access** - Support for `admin`, `user`, and custom roles
|
|
16
|
-
- **Auto-Imports** - `useUserSession`, `requireUserSession`, `getUserSession`
|
|
17
|
-
- **BetterAuthState Component** - Ready-to-use Vue component with slots
|
|
18
|
+
> [!WARNING]
|
|
19
|
+
> This library is a work in progress and not ready for production use.
|
|
18
20
|
|
|
19
|
-
##
|
|
21
|
+
## Documentation
|
|
20
22
|
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
## Quick Start
|
|
24
|
-
|
|
25
|
-
### 1. Install
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
pnpm add @onmax/nuxt-better-auth better-auth drizzle-orm @nuxthub/core
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### 2. Configure Nuxt
|
|
32
|
-
|
|
33
|
-
```ts
|
|
34
|
-
export default defineNuxtConfig({
|
|
35
|
-
modules: ['@nuxthub/core', '@onmax/nuxt-better-auth'],
|
|
36
|
-
|
|
37
|
-
hub: { database: true },
|
|
38
|
-
|
|
39
|
-
runtimeConfig: {
|
|
40
|
-
betterAuthSecret: '', // BETTER_AUTH_SECRET env var
|
|
41
|
-
public: { siteUrl: 'http://localhost:3000' },
|
|
42
|
-
},
|
|
43
|
-
|
|
44
|
-
routeRules: {
|
|
45
|
-
'/app/**': { auth: 'user' },
|
|
46
|
-
'/admin/**': { auth: { role: 'admin' } },
|
|
47
|
-
'/login': { auth: 'guest' },
|
|
48
|
-
},
|
|
49
|
-
})
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### 3. Create Server Config
|
|
53
|
-
|
|
54
|
-
Create `server/auth.config.ts`:
|
|
55
|
-
|
|
56
|
-
```ts
|
|
57
|
-
import { admin } from 'better-auth/plugins'
|
|
58
|
-
import { defineServerAuth } from '@onmax/nuxt-better-auth'
|
|
59
|
-
|
|
60
|
-
export default defineServerAuth(({ db }) => ({
|
|
61
|
-
appName: 'My App',
|
|
62
|
-
plugins: [admin()],
|
|
63
|
-
emailAndPassword: { enabled: true },
|
|
64
|
-
}))
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
> Schema is auto-generated from your plugins! No manual Drizzle schema needed.
|
|
68
|
-
|
|
69
|
-
### 4. Create Client Config
|
|
70
|
-
|
|
71
|
-
Create `app/auth.client.ts`:
|
|
72
|
-
|
|
73
|
-
```ts
|
|
74
|
-
import { adminClient } from 'better-auth/client/plugins'
|
|
75
|
-
import { createAuthClient } from 'better-auth/vue'
|
|
76
|
-
|
|
77
|
-
export function createAppAuthClient(baseURL: string) {
|
|
78
|
-
return createAuthClient({
|
|
79
|
-
baseURL,
|
|
80
|
-
plugins: [adminClient()],
|
|
81
|
-
})
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export type AppAuthClient = ReturnType<typeof createAppAuthClient>
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
### 5. Add Type Extensions
|
|
88
|
-
|
|
89
|
-
Create `shared/types/auth.d.ts`:
|
|
90
|
-
|
|
91
|
-
```ts
|
|
92
|
-
import '#nuxt-better-auth'
|
|
93
|
-
|
|
94
|
-
declare module '#nuxt-better-auth' {
|
|
95
|
-
interface AuthUser {
|
|
96
|
-
role?: string | null
|
|
97
|
-
banned?: boolean | null
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
## Route Rules
|
|
103
|
-
|
|
104
|
-
| Option | Type | Description |
|
|
105
|
-
|--------|------|-------------|
|
|
106
|
-
| `auth` | `false \| 'guest' \| 'user' \| { role: string }` | Auth requirement |
|
|
107
|
-
|
|
108
|
-
Examples:
|
|
109
|
-
- `auth: false` - Public (default)
|
|
110
|
-
- `auth: 'guest'` - Only unauthenticated users
|
|
111
|
-
- `auth: 'user'` - Any authenticated user
|
|
112
|
-
- `auth: { role: 'admin' }` - Requires specific role
|
|
113
|
-
|
|
114
|
-
## Composables
|
|
115
|
-
|
|
116
|
-
### `useUserSession()`
|
|
117
|
-
|
|
118
|
-
```ts
|
|
119
|
-
const { user, session, loggedIn, ready, client } = useUserSession()
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
### `<BetterAuthState>`
|
|
123
|
-
|
|
124
|
-
```vue
|
|
125
|
-
<BetterAuthState>
|
|
126
|
-
<template #default="{ loggedIn, user, signOut }">
|
|
127
|
-
<p v-if="loggedIn">Welcome, {{ user?.name }}</p>
|
|
128
|
-
<p v-else>Not logged in</p>
|
|
129
|
-
</template>
|
|
130
|
-
<template #placeholder>
|
|
131
|
-
<p>Loading...</p>
|
|
132
|
-
</template>
|
|
133
|
-
</BetterAuthState>
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
## Server Utils
|
|
137
|
-
|
|
138
|
-
```ts
|
|
139
|
-
// Require auth
|
|
140
|
-
const { user, session } = await requireUserSession(event)
|
|
141
|
-
|
|
142
|
-
// Require admin
|
|
143
|
-
const { user } = await requireUserSession(event, { role: 'admin' })
|
|
144
|
-
|
|
145
|
-
// Optional session
|
|
146
|
-
const session = await getUserSession(event)
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
## Module Aliases
|
|
150
|
-
|
|
151
|
-
| Alias | Points To |
|
|
152
|
-
|-------|-----------|
|
|
153
|
-
| `#auth/server` | `server/auth.config.ts` |
|
|
154
|
-
| `#auth/client` | `app/auth.client.ts` |
|
|
155
|
-
| `#nuxt-better-auth` | Module type augmentation |
|
|
156
|
-
|
|
157
|
-
## Development
|
|
158
|
-
|
|
159
|
-
```bash
|
|
160
|
-
pnpm install
|
|
161
|
-
pnpm dev:prepare
|
|
162
|
-
pnpm dev
|
|
163
|
-
```
|
|
23
|
+
**[nuxt-better-auth.onmax.me](https://nuxt-better-auth.onmax.me/)**
|
|
164
24
|
|
|
165
25
|
## License
|
|
166
26
|
|
|
167
27
|
MIT
|
|
168
|
-
|
|
169
|
-
<!-- Badges -->
|
|
170
|
-
[npm-version-src]: https://img.shields.io/npm/v/@onmax/nuxt-better-auth/latest.svg?style=flat&colorA=020420&colorB=00DC82
|
|
171
|
-
[npm-version-href]: https://npmjs.com/package/@onmax/nuxt-better-auth
|
|
172
|
-
|
|
173
|
-
[npm-downloads-src]: https://img.shields.io/npm/dm/@onmax/nuxt-better-auth.svg?style=flat&colorA=020420&colorB=00DC82
|
|
174
|
-
[npm-downloads-href]: https://npm.chart.dev/@onmax/nuxt-better-auth
|
|
175
|
-
|
|
176
|
-
[license-src]: https://img.shields.io/npm/l/@onmax/nuxt-better-auth.svg?style=flat&colorA=020420&colorB=00DC82
|
|
177
|
-
[license-href]: https://npmjs.com/package/@onmax/nuxt-better-auth
|
|
178
|
-
|
|
179
|
-
[nuxt-src]: https://img.shields.io/badge/Nuxt-020420?logo=nuxt.js
|
|
180
|
-
[nuxt-href]: https://nuxt.com
|
package/dist/module.d.mts
CHANGED
|
@@ -1,2 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
+
import { BetterAuthModuleOptions } from '../dist/runtime/config.js';
|
|
3
|
+
export { BetterAuthModuleOptions, defineClientAuth, defineServerAuth } from '../dist/runtime/config.js';
|
|
4
|
+
import { BetterAuthOptions } from 'better-auth';
|
|
5
|
+
export { Auth, AuthMeta, AuthMode, AuthRouteRules, AuthSession, AuthUser, InferSession, InferUser, RequireSessionOptions, ServerAuthContext, UserMatch } from '../dist/runtime/types.js';
|
|
6
|
+
|
|
7
|
+
declare module '@nuxt/schema' {
|
|
8
|
+
interface NuxtHooks {
|
|
9
|
+
/**
|
|
10
|
+
* Extend better-auth config with additional plugins or options.
|
|
11
|
+
* Called after user's auth.config.ts is loaded.
|
|
12
|
+
* @param config - Partial config to merge into the auth options
|
|
13
|
+
*/
|
|
14
|
+
'better-auth:config:extend': (config: Partial<BetterAuthOptions>) => void | Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
declare const _default: _nuxt_schema.NuxtModule<BetterAuthModuleOptions, BetterAuthModuleOptions, false>;
|
|
19
|
+
|
|
20
|
+
export { _default as default };
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,20 +1,369 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
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';
|
|
4
|
+
import { consola as consola$1 } from 'consola';
|
|
5
|
+
import { defu } from 'defu';
|
|
6
|
+
import { join } from 'pathe';
|
|
7
|
+
import { toRouteMatcher, createRouter } from 'radix3';
|
|
8
|
+
export { defineClientAuth, defineServerAuth } from '../dist/runtime/config.js';
|
|
2
9
|
|
|
3
|
-
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
-
|
|
10
|
+
function setupDevTools(nuxt) {
|
|
11
|
+
nuxt.hook("devtools:customTabs", (tabs) => {
|
|
12
|
+
tabs.push({
|
|
13
|
+
category: "server",
|
|
14
|
+
name: "better-auth",
|
|
15
|
+
title: "Auth",
|
|
16
|
+
icon: "simple-icons:betterauth",
|
|
17
|
+
view: {
|
|
18
|
+
type: "iframe",
|
|
19
|
+
src: "/__better-auth-devtools"
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function generateDrizzleSchema(tables, dialect) {
|
|
26
|
+
const imports = getImports(dialect);
|
|
27
|
+
const tableDefinitions = Object.entries(tables).map(([tableName, table]) => generateTable(tableName, table, dialect, tables)).join("\n\n");
|
|
28
|
+
return `${imports}
|
|
29
|
+
|
|
30
|
+
${tableDefinitions}
|
|
31
|
+
`;
|
|
32
|
+
}
|
|
33
|
+
function getImports(dialect) {
|
|
34
|
+
switch (dialect) {
|
|
35
|
+
case "sqlite":
|
|
36
|
+
return `import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'`;
|
|
37
|
+
case "postgresql":
|
|
38
|
+
return `import { boolean, pgTable, text, timestamp, integer } from 'drizzle-orm/pg-core'`;
|
|
39
|
+
case "mysql":
|
|
40
|
+
return `import { boolean, int, mysqlTable, text, timestamp, varchar } from 'drizzle-orm/mysql-core'`;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function generateTable(tableName, table, dialect, allTables) {
|
|
44
|
+
const tableFunc = dialect === "sqlite" ? "sqliteTable" : dialect === "postgresql" ? "pgTable" : "mysqlTable";
|
|
45
|
+
const dbTableName = table.modelName || tableName;
|
|
46
|
+
const fields = Object.entries(table.fields).map(([fieldName, field]) => generateField(fieldName, field, dialect, allTables)).join(",\n ");
|
|
47
|
+
const idField = generateIdField(dialect);
|
|
48
|
+
return `export const ${tableName} = ${tableFunc}('${dbTableName}', {
|
|
49
|
+
${idField},
|
|
50
|
+
${fields}
|
|
51
|
+
})`;
|
|
52
|
+
}
|
|
53
|
+
function generateIdField(dialect) {
|
|
54
|
+
switch (dialect) {
|
|
55
|
+
case "sqlite":
|
|
56
|
+
case "postgresql":
|
|
57
|
+
return `id: text('id').primaryKey()`;
|
|
58
|
+
case "mysql":
|
|
59
|
+
return `id: varchar('id', { length: 36 }).primaryKey()`;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function generateField(fieldName, field, dialect, allTables) {
|
|
63
|
+
const dbFieldName = fieldName;
|
|
64
|
+
let fieldDef = getFieldType(field.type, dialect, dbFieldName);
|
|
65
|
+
if (field.required && field.defaultValue === void 0)
|
|
66
|
+
fieldDef += ".notNull()";
|
|
67
|
+
if (field.unique)
|
|
68
|
+
fieldDef += ".unique()";
|
|
69
|
+
if (field.defaultValue !== void 0) {
|
|
70
|
+
if (typeof field.defaultValue === "boolean")
|
|
71
|
+
fieldDef += `.default(${field.defaultValue})`;
|
|
72
|
+
else if (typeof field.defaultValue === "string")
|
|
73
|
+
fieldDef += `.default('${field.defaultValue}')`;
|
|
74
|
+
else
|
|
75
|
+
fieldDef += `.default(${field.defaultValue})`;
|
|
76
|
+
if (field.required)
|
|
77
|
+
fieldDef += ".notNull()";
|
|
78
|
+
}
|
|
79
|
+
if (field.references) {
|
|
80
|
+
const refTable = field.references.model;
|
|
81
|
+
if (allTables[refTable])
|
|
82
|
+
fieldDef += `.references(() => ${refTable}.${field.references.field})`;
|
|
83
|
+
}
|
|
84
|
+
return `${fieldName}: ${fieldDef}`;
|
|
85
|
+
}
|
|
86
|
+
function getFieldType(type, dialect, fieldName) {
|
|
87
|
+
const normalizedType = Array.isArray(type) ? "string" : type;
|
|
88
|
+
switch (dialect) {
|
|
89
|
+
case "sqlite":
|
|
90
|
+
return getSqliteType(normalizedType, fieldName);
|
|
91
|
+
case "postgresql":
|
|
92
|
+
return getPostgresType(normalizedType, fieldName);
|
|
93
|
+
case "mysql":
|
|
94
|
+
return getMysqlType(normalizedType, fieldName);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function getSqliteType(type, fieldName) {
|
|
98
|
+
switch (type) {
|
|
99
|
+
case "string":
|
|
100
|
+
return `text('${fieldName}')`;
|
|
101
|
+
case "boolean":
|
|
102
|
+
return `integer('${fieldName}', { mode: 'boolean' })`;
|
|
103
|
+
case "date":
|
|
104
|
+
return `integer('${fieldName}', { mode: 'timestamp' })`;
|
|
105
|
+
case "number":
|
|
106
|
+
return `integer('${fieldName}')`;
|
|
107
|
+
default:
|
|
108
|
+
return `text('${fieldName}')`;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function getPostgresType(type, fieldName) {
|
|
112
|
+
switch (type) {
|
|
113
|
+
case "string":
|
|
114
|
+
return `text('${fieldName}')`;
|
|
115
|
+
case "boolean":
|
|
116
|
+
return `boolean('${fieldName}')`;
|
|
117
|
+
case "date":
|
|
118
|
+
return `timestamp('${fieldName}')`;
|
|
119
|
+
case "number":
|
|
120
|
+
return `integer('${fieldName}')`;
|
|
121
|
+
default:
|
|
122
|
+
return `text('${fieldName}')`;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function getMysqlType(type, fieldName) {
|
|
126
|
+
switch (type) {
|
|
127
|
+
case "string":
|
|
128
|
+
return `text('${fieldName}')`;
|
|
129
|
+
case "boolean":
|
|
130
|
+
return `boolean('${fieldName}')`;
|
|
131
|
+
case "date":
|
|
132
|
+
return `timestamp('${fieldName}')`;
|
|
133
|
+
case "number":
|
|
134
|
+
return `int('${fieldName}')`;
|
|
135
|
+
default:
|
|
136
|
+
return `text('${fieldName}')`;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async function loadUserAuthConfig(configPath) {
|
|
140
|
+
const { createJiti } = await import('jiti');
|
|
141
|
+
const jiti = createJiti(import.meta.url, { interopDefault: true });
|
|
142
|
+
try {
|
|
143
|
+
const mod = await jiti.import(configPath);
|
|
144
|
+
const configFn = mod.default || mod;
|
|
145
|
+
if (typeof configFn === "function") {
|
|
146
|
+
return configFn({ runtimeConfig: {}, db: null });
|
|
147
|
+
}
|
|
148
|
+
return {};
|
|
149
|
+
} catch (error) {
|
|
150
|
+
consola$1.error("[@onmax/nuxt-better-auth] Failed to load auth config for schema generation. Schema may be incomplete:", error);
|
|
151
|
+
return {};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const consola = consola$1.withTag("nuxt-better-auth");
|
|
156
|
+
const module$1 = defineNuxtModule({
|
|
157
|
+
meta: { name: "@onmax/nuxt-better-auth", configKey: "auth", compatibility: { nuxt: ">=3.0.0" } },
|
|
158
|
+
defaults: {
|
|
159
|
+
serverConfig: "server/auth.config",
|
|
160
|
+
clientConfig: "app/auth.config",
|
|
161
|
+
redirects: { login: "/login", guest: "/" },
|
|
162
|
+
secondaryStorage: false
|
|
7
163
|
},
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
164
|
+
async setup(options, nuxt) {
|
|
165
|
+
const resolver = createResolver(import.meta.url);
|
|
166
|
+
const serverConfigFile = options.serverConfig;
|
|
167
|
+
const clientConfigFile = options.clientConfig;
|
|
168
|
+
const serverConfigPath = resolver.resolve(nuxt.options.rootDir, serverConfigFile);
|
|
169
|
+
const clientConfigPath = resolver.resolve(nuxt.options.rootDir, clientConfigFile);
|
|
170
|
+
const serverConfigExists = existsSync(`${serverConfigPath}.ts`) || existsSync(`${serverConfigPath}.js`);
|
|
171
|
+
const clientConfigExists = existsSync(`${clientConfigPath}.ts`) || existsSync(`${clientConfigPath}.js`);
|
|
172
|
+
if (!serverConfigExists)
|
|
173
|
+
throw new Error(`[nuxt-better-auth] Missing ${serverConfigFile}.ts - create with defineServerAuth()`);
|
|
174
|
+
if (!clientConfigExists)
|
|
175
|
+
throw new Error(`[nuxt-better-auth] Missing ${clientConfigFile}.ts - export createAppAuthClient()`);
|
|
176
|
+
const hasNuxtHub = hasNuxtModule("@nuxthub/core", nuxt);
|
|
177
|
+
const hub = hasNuxtHub ? nuxt.options.hub : void 0;
|
|
178
|
+
const hasHubDb = hasNuxtHub && !!hub?.db;
|
|
179
|
+
let secondaryStorageEnabled = options.secondaryStorage ?? false;
|
|
180
|
+
if (secondaryStorageEnabled && (!hasNuxtHub || !hub?.kv)) {
|
|
181
|
+
consola.warn("secondaryStorage requires @nuxthub/core with hub.kv: true. Disabling.");
|
|
182
|
+
secondaryStorageEnabled = false;
|
|
11
183
|
}
|
|
184
|
+
nuxt.options.runtimeConfig.public = nuxt.options.runtimeConfig.public || {};
|
|
185
|
+
nuxt.options.runtimeConfig.public.auth = defu(nuxt.options.runtimeConfig.public.auth, {
|
|
186
|
+
redirects: { login: options.redirects?.login ?? "/login", guest: options.redirects?.guest ?? "/" },
|
|
187
|
+
useDatabase: hasHubDb
|
|
188
|
+
});
|
|
189
|
+
nuxt.options.runtimeConfig.betterAuthSecret ||= process.env.BETTER_AUTH_SECRET || process.env.NUXT_BETTER_AUTH_SECRET || "";
|
|
190
|
+
nuxt.options.runtimeConfig.auth = defu(nuxt.options.runtimeConfig.auth, {
|
|
191
|
+
secondaryStorage: secondaryStorageEnabled
|
|
192
|
+
});
|
|
193
|
+
nuxt.options.alias["#nuxt-better-auth"] = resolver.resolve("./runtime/types/augment");
|
|
194
|
+
nuxt.options.alias["#auth/server"] = serverConfigPath;
|
|
195
|
+
nuxt.options.alias["#auth/client"] = clientConfigPath;
|
|
196
|
+
const secondaryStorageCode = secondaryStorageEnabled ? `import { kv } from 'hub:kv'
|
|
197
|
+
export function createSecondaryStorage() {
|
|
198
|
+
return {
|
|
199
|
+
get: async (key) => kv.get(\`_auth:\${key}\`),
|
|
200
|
+
set: async (key, value, ttl) => kv.set(\`_auth:\${key}\`, value, { ttl }),
|
|
201
|
+
delete: async (key) => kv.del(\`_auth:\${key}\`),
|
|
202
|
+
}
|
|
203
|
+
}` : `export function createSecondaryStorage() { return undefined }`;
|
|
204
|
+
const secondaryStorageTemplate = addTemplate({ filename: "better-auth/secondary-storage.mjs", getContents: () => secondaryStorageCode, write: true });
|
|
205
|
+
nuxt.options.alias["#auth/secondary-storage"] = secondaryStorageTemplate.dst;
|
|
206
|
+
const hubDbPath = nuxt.options.alias["hub:db"];
|
|
207
|
+
const databaseCode = hasHubDb && hubDbPath ? `import { db, schema } from '${hubDbPath}'
|
|
208
|
+
import { drizzleAdapter } from 'better-auth/adapters/drizzle'
|
|
209
|
+
const rawDialect = '${hub?.db?.dialect ?? "sqlite"}'
|
|
210
|
+
const dialect = rawDialect === 'postgresql' ? 'pg' : rawDialect
|
|
211
|
+
export function createDatabase() { return drizzleAdapter(db, { provider: dialect, schema }) }
|
|
212
|
+
export { db }` : `export function createDatabase() { return undefined }
|
|
213
|
+
export const db = undefined`;
|
|
214
|
+
const databaseTemplate = addTemplate({ filename: "better-auth/database.mjs", getContents: () => databaseCode, write: true });
|
|
215
|
+
nuxt.options.alias["#auth/database"] = databaseTemplate.dst;
|
|
216
|
+
addTypeTemplate({
|
|
217
|
+
filename: "types/auth-secondary-storage.d.ts",
|
|
218
|
+
getContents: () => `
|
|
219
|
+
declare module '#auth/secondary-storage' {
|
|
220
|
+
interface SecondaryStorage {
|
|
221
|
+
get: (key: string) => Promise<string | null>
|
|
222
|
+
set: (key: string, value: unknown, ttl?: number) => Promise<void>
|
|
223
|
+
delete: (key: string) => Promise<void>
|
|
12
224
|
}
|
|
13
|
-
|
|
225
|
+
export function createSecondaryStorage(): SecondaryStorage | undefined
|
|
226
|
+
}
|
|
227
|
+
`
|
|
228
|
+
});
|
|
229
|
+
addTypeTemplate({
|
|
230
|
+
filename: "types/auth-database.d.ts",
|
|
231
|
+
getContents: () => `
|
|
232
|
+
declare module '#auth/database' {
|
|
233
|
+
import type { drizzleAdapter } from 'better-auth/adapters/drizzle'
|
|
234
|
+
export function createDatabase(): ReturnType<typeof drizzleAdapter> | undefined
|
|
235
|
+
export const db: unknown
|
|
236
|
+
}
|
|
237
|
+
`
|
|
238
|
+
});
|
|
239
|
+
addTypeTemplate({
|
|
240
|
+
filename: "types/nuxt-better-auth.d.ts",
|
|
241
|
+
getContents: () => `
|
|
242
|
+
export * from '${resolver.resolve("./runtime/types/augment")}'
|
|
243
|
+
export type { AuthMeta, AuthMode, AuthRouteRules, UserMatch, RequireSessionOptions, Auth, InferUser, InferSession } from '${resolver.resolve("./runtime/types")}'
|
|
244
|
+
`
|
|
245
|
+
});
|
|
246
|
+
addTypeTemplate({
|
|
247
|
+
filename: "types/nuxt-better-auth-infer.d.ts",
|
|
248
|
+
getContents: () => `
|
|
249
|
+
import type { InferUser, InferSession } from 'better-auth'
|
|
250
|
+
import type { RuntimeConfig } from 'nuxt/schema'
|
|
251
|
+
import type configFn from '${serverConfigPath}'
|
|
252
|
+
|
|
253
|
+
type _Config = ReturnType<typeof configFn>
|
|
14
254
|
|
|
15
|
-
|
|
16
|
-
|
|
255
|
+
declare module '#nuxt-better-auth' {
|
|
256
|
+
interface AuthUser extends InferUser<_Config> {}
|
|
257
|
+
interface AuthSession { session: InferSession<_Config>['session'], user: InferUser<_Config> }
|
|
258
|
+
interface ServerAuthContext {
|
|
259
|
+
runtimeConfig: RuntimeConfig
|
|
260
|
+
${hasHubDb ? `db: typeof import('hub:db')['db']` : ""}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
`
|
|
264
|
+
});
|
|
265
|
+
addTypeTemplate({
|
|
266
|
+
filename: "types/nuxt-better-auth-client.d.ts",
|
|
267
|
+
getContents: () => `
|
|
268
|
+
import type { createAppAuthClient } from '${clientConfigPath}'
|
|
269
|
+
declare module '#nuxt-better-auth' {
|
|
270
|
+
export type AppAuthClient = ReturnType<typeof createAppAuthClient>
|
|
271
|
+
}
|
|
272
|
+
`
|
|
273
|
+
});
|
|
274
|
+
addTypeTemplate({
|
|
275
|
+
filename: "types/nuxt-better-auth-nitro.d.ts",
|
|
276
|
+
getContents: () => `
|
|
277
|
+
declare module 'nitropack/types' {
|
|
278
|
+
interface NitroRouteRules {
|
|
279
|
+
auth?: import('${resolver.resolve("./runtime/types")}').AuthMeta
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
`
|
|
283
|
+
});
|
|
284
|
+
nuxt.hook("builder:watch", async (_event, relativePath) => {
|
|
285
|
+
if (relativePath.includes("auth.config")) {
|
|
286
|
+
await updateTemplates({ filter: (t) => t.filename.includes("nuxt-better-auth") });
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
addServerImportsDir(resolver.resolve("./runtime/server/utils"));
|
|
290
|
+
addServerScanDir(resolver.resolve("./runtime/server/middleware"));
|
|
291
|
+
addServerHandler({ route: "/api/auth/**", handler: resolver.resolve("./runtime/server/api/auth/[...all]") });
|
|
292
|
+
addImportsDir(resolver.resolve("./runtime/app/composables"));
|
|
293
|
+
addImportsDir(resolver.resolve("./runtime/utils"));
|
|
294
|
+
addPlugin({ src: resolver.resolve("./runtime/app/plugins/session.server"), mode: "server" });
|
|
295
|
+
addPlugin({ src: resolver.resolve("./runtime/app/plugins/session.client"), mode: "client" });
|
|
296
|
+
addComponentsDir({ path: resolver.resolve("./runtime/app/components") });
|
|
297
|
+
nuxt.hook("app:resolve", (app) => {
|
|
298
|
+
app.middleware.push({ name: "auth", path: resolver.resolve("./runtime/app/middleware/auth.global"), global: true });
|
|
299
|
+
});
|
|
300
|
+
if (hasHubDb) {
|
|
301
|
+
await setupBetterAuthSchema(nuxt, serverConfigPath);
|
|
302
|
+
}
|
|
303
|
+
if (nuxt.options.dev && process.env.NODE_ENV !== "production") {
|
|
304
|
+
setupDevTools(nuxt);
|
|
305
|
+
addServerHandler({ route: "/api/_better-auth/config", method: "get", handler: resolver.resolve("./runtime/server/api/_better-auth/config.get") });
|
|
306
|
+
if (hasHubDb) {
|
|
307
|
+
addServerHandler({ route: "/api/_better-auth/sessions", method: "get", handler: resolver.resolve("./runtime/server/api/_better-auth/sessions.get") });
|
|
308
|
+
addServerHandler({ route: "/api/_better-auth/sessions", method: "delete", handler: resolver.resolve("./runtime/server/api/_better-auth/sessions.delete") });
|
|
309
|
+
addServerHandler({ route: "/api/_better-auth/users", method: "get", handler: resolver.resolve("./runtime/server/api/_better-auth/users.get") });
|
|
310
|
+
addServerHandler({ route: "/api/_better-auth/accounts", method: "get", handler: resolver.resolve("./runtime/server/api/_better-auth/accounts.get") });
|
|
311
|
+
}
|
|
312
|
+
extendPages((pages) => {
|
|
313
|
+
pages.push({ name: "better-auth-devtools", path: "/__better-auth-devtools", file: resolver.resolve("./runtime/app/pages/__better-auth-devtools.vue") });
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
nuxt.hook("pages:extend", (pages) => {
|
|
317
|
+
const routeRules = nuxt.options.routeRules || {};
|
|
318
|
+
if (!Object.keys(routeRules).length)
|
|
319
|
+
return;
|
|
320
|
+
const matcher = toRouteMatcher(createRouter({ routes: routeRules }));
|
|
321
|
+
const applyMetaFromRules = (page) => {
|
|
322
|
+
const matches = matcher.matchAll(page.path);
|
|
323
|
+
if (!matches.length)
|
|
324
|
+
return;
|
|
325
|
+
const matchedRules = defu({}, ...matches.reverse());
|
|
326
|
+
if (matchedRules.auth !== void 0) {
|
|
327
|
+
page.meta = page.meta || {};
|
|
328
|
+
page.meta.auth = matchedRules.auth;
|
|
329
|
+
}
|
|
330
|
+
page.children?.forEach((child) => applyMetaFromRules(child));
|
|
331
|
+
};
|
|
332
|
+
pages.forEach((page) => applyMetaFromRules(page));
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
async function setupBetterAuthSchema(nuxt, serverConfigPath) {
|
|
337
|
+
const hub = nuxt.options.hub;
|
|
338
|
+
const dialect = typeof hub.db === "string" ? hub.db : hub.db?.dialect;
|
|
339
|
+
if (!dialect || !["sqlite", "postgresql", "mysql"].includes(dialect)) {
|
|
340
|
+
consola.warn(`Unsupported database dialect: ${dialect}`);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
try {
|
|
344
|
+
const configFile = `${serverConfigPath}.ts`;
|
|
345
|
+
const userConfig = await loadUserAuthConfig(configFile);
|
|
346
|
+
const extendedConfig = {};
|
|
347
|
+
await nuxt.callHook("better-auth:config:extend", extendedConfig);
|
|
348
|
+
const plugins = [...userConfig.plugins || [], ...extendedConfig.plugins || []];
|
|
349
|
+
const { getAuthTables } = await import('better-auth/db');
|
|
350
|
+
const tables = getAuthTables({ plugins });
|
|
351
|
+
const schemaCode = generateDrizzleSchema(tables, dialect);
|
|
352
|
+
const schemaDir = join(nuxt.options.buildDir, "better-auth");
|
|
353
|
+
const schemaPath = join(schemaDir, `schema.${dialect}.ts`);
|
|
354
|
+
await mkdir(schemaDir, { recursive: true });
|
|
355
|
+
await writeFile(schemaPath, schemaCode);
|
|
356
|
+
addTemplate({ filename: `better-auth/schema.${dialect}.ts`, getContents: () => schemaCode, write: true });
|
|
357
|
+
consola.info(`Generated ${dialect} schema with ${Object.keys(tables).length} tables`);
|
|
358
|
+
} catch (error) {
|
|
359
|
+
consola.error("Failed to generate schema:", error);
|
|
360
|
+
}
|
|
361
|
+
nuxt.hook("hub:db:schema:extend", ({ paths, dialect: hookDialect }) => {
|
|
362
|
+
const schemaPath = join(nuxt.options.buildDir, "better-auth", `schema.${hookDialect}.ts`);
|
|
363
|
+
if (existsSync(schemaPath)) {
|
|
364
|
+
paths.push(schemaPath);
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
}
|
|
17
368
|
|
|
18
|
-
export
|
|
19
|
-
export const defineClientAuth = _module.defineClientAuth;
|
|
20
|
-
export const defineServerAuth = _module.defineServerAuth;
|
|
369
|
+
export { module$1 as default };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
declare var __VLS_1: {
|
|
2
|
+
loggedIn: any;
|
|
3
|
+
user: any;
|
|
4
|
+
session: any;
|
|
5
|
+
signOut: any;
|
|
6
|
+
}, __VLS_3: {};
|
|
7
|
+
type __VLS_Slots = {} & {
|
|
8
|
+
default?: (props: typeof __VLS_1) => any;
|
|
9
|
+
} & {
|
|
10
|
+
placeholder?: (props: typeof __VLS_3) => any;
|
|
11
|
+
};
|
|
12
|
+
declare const __VLS_base: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
13
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
14
|
+
declare const _default: typeof __VLS_export;
|
|
15
|
+
export default _default;
|
|
16
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
17
|
+
new (): {
|
|
18
|
+
$slots: S;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
declare var __VLS_1: {
|
|
2
|
+
loggedIn: any;
|
|
3
|
+
user: any;
|
|
4
|
+
session: any;
|
|
5
|
+
signOut: any;
|
|
6
|
+
}, __VLS_3: {};
|
|
7
|
+
type __VLS_Slots = {} & {
|
|
8
|
+
default?: (props: typeof __VLS_1) => any;
|
|
9
|
+
} & {
|
|
10
|
+
placeholder?: (props: typeof __VLS_3) => any;
|
|
11
|
+
};
|
|
12
|
+
declare const __VLS_base: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
13
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
14
|
+
declare const _default: typeof __VLS_export;
|
|
15
|
+
export default _default;
|
|
16
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
17
|
+
new (): {
|
|
18
|
+
$slots: S;
|
|
19
|
+
};
|
|
20
|
+
};
|