node-auth-kit 1.0.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/LICENSE +5 -0
- package/README.md +335 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +27 -0
- package/dist/src/adapters/base.adapter.d.ts +21 -0
- package/dist/src/adapters/base.adapter.js +2 -0
- package/dist/src/adapters/mongoose.adapter.d.ts +53 -0
- package/dist/src/adapters/mongoose.adapter.js +78 -0
- package/dist/src/adapters/prisma.adapter.d.ts +29 -0
- package/dist/src/adapters/prisma.adapter.js +40 -0
- package/dist/src/config/default.config.d.ts +19 -0
- package/dist/src/config/default.config.js +17 -0
- package/dist/src/config/index.d.ts +4 -0
- package/dist/src/config/index.js +23 -0
- package/dist/src/controllers/registrations.controller.d.ts +3 -0
- package/dist/src/controllers/registrations.controller.js +25 -0
- package/dist/src/controllers/sessions.controller.d.ts +3 -0
- package/dist/src/controllers/sessions.controller.js +25 -0
- package/dist/src/core/auth.service.d.ts +35 -0
- package/dist/src/core/auth.service.js +113 -0
- package/dist/src/core/password.service.d.ts +9 -0
- package/dist/src/core/password.service.js +19 -0
- package/dist/src/core/token.service.d.ts +15 -0
- package/dist/src/core/token.service.js +26 -0
- package/dist/src/deviceAuth.d.ts +32 -0
- package/dist/src/deviceAuth.js +67 -0
- package/dist/src/factories/auth-service.factory.d.ts +2 -0
- package/dist/src/factories/auth-service.factory.js +30 -0
- package/dist/src/hooks/index.d.ts +5 -0
- package/dist/src/hooks/index.js +20 -0
- package/dist/src/middlewares/authenticate.middleware.d.ts +15 -0
- package/dist/src/middlewares/authenticate.middleware.js +46 -0
- package/dist/src/middlewares/authorize.middleware.d.ts +8 -0
- package/dist/src/middlewares/authorize.middleware.js +36 -0
- package/dist/src/overrides/index.d.ts +7 -0
- package/dist/src/overrides/index.js +13 -0
- package/dist/src/routes/auth.routes.d.ts +2 -0
- package/dist/src/routes/auth.routes.js +41 -0
- package/dist/src/types/index.d.ts +11 -0
- package/dist/src/types/index.js +2 -0
- package/dist/src/utils/index.d.ts +3 -0
- package/dist/src/utils/index.js +12 -0
- package/dist/src/utils/pick.d.ts +1 -0
- package/dist/src/utils/pick.js +13 -0
- package/dist/src/utils/response.d.ts +10 -0
- package/dist/src/utils/response.js +32 -0
- package/package.json +51 -0
package/LICENSE
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
๐ # Device Auth
|
|
2
|
+
|
|
3
|
+
Device Auth is a **Devise-inspired authentication and authorization library for Node.js**.
|
|
4
|
+
|
|
5
|
+
It gives you:
|
|
6
|
+
|
|
7
|
+
- **Config-driven auth** (email + password, roles, JWT, password rules)
|
|
8
|
+
- **Plug-and-play Express routes** via `createAuthRouter`
|
|
9
|
+
- **JWT-based security** with `authenticate` middleware
|
|
10
|
+
- **Role-based authorization** with `authorize`
|
|
11
|
+
- **Database-agnostic adapter system** (`mongooseAdapter`, future Prisma, etc.)
|
|
12
|
+
- **Lifecycle hooks** (before/after register/login) for side effects
|
|
13
|
+
|
|
14
|
+
You bring your framework (Express) and database (Mongo, Prisma, SQL). Device Auth handles the rest.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## โจ Features
|
|
19
|
+
|
|
20
|
+
- **โ
JWT Authentication (Access Tokens)**
|
|
21
|
+
- **๐ Role-based Authorization**
|
|
22
|
+
- **๐งฉ Adapter Pattern (DB-agnostic)**
|
|
23
|
+
- **๐ Ready-to-use Express routes** via `createAuthRouter`
|
|
24
|
+
- **๐ Secure password hashing**
|
|
25
|
+
- **๐ฆ Mongoose adapter (Stable)**
|
|
26
|
+
- **๐งช Prisma adapter (In progress โ V2)**
|
|
27
|
+
- **๐ง Inspired by Ruby on Rails Devise**
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## ๐ฆ Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install device_auth
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
or
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
yarn add device_auth
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`device_auth` itself is DB-agnostic. Database drivers / ORMs are **optional** and only required if you use the corresponding adapter:
|
|
44
|
+
|
|
45
|
+
- For Mongoose adapter: `mongoose`
|
|
46
|
+
- For Prisma adapter (V2): `@prisma/client`
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## โก Quick Start (Express + MongoDB)
|
|
51
|
+
|
|
52
|
+
### 1๏ธโฃ Environment Variables
|
|
53
|
+
|
|
54
|
+
Create a `.env` file:
|
|
55
|
+
|
|
56
|
+
```env
|
|
57
|
+
MONGO_URL=mongodb://localhost:27017/device-auth
|
|
58
|
+
DEVICE_AUTH_JWT_SECRET=your-super-secret-key
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 2๏ธโฃ User Model (Mongoose)
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import mongoose from 'mongoose';
|
|
65
|
+
|
|
66
|
+
const UserSchema = new mongoose.Schema({
|
|
67
|
+
email: {
|
|
68
|
+
type: String,
|
|
69
|
+
unique: true,
|
|
70
|
+
required: true,
|
|
71
|
+
},
|
|
72
|
+
password: {
|
|
73
|
+
type: String,
|
|
74
|
+
required: true,
|
|
75
|
+
},
|
|
76
|
+
role: {
|
|
77
|
+
type: String,
|
|
78
|
+
enum: ['admin', 'staff', 'user'],
|
|
79
|
+
default: 'user',
|
|
80
|
+
},
|
|
81
|
+
createdAt: {
|
|
82
|
+
type: Date,
|
|
83
|
+
default: Date.now,
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
export const User = mongoose.model('User', UserSchema);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 3๏ธโฃ Express App Setup
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
import 'dotenv/config';
|
|
94
|
+
import express from 'express';
|
|
95
|
+
import mongoose from 'mongoose';
|
|
96
|
+
|
|
97
|
+
import {
|
|
98
|
+
deviceAuth,
|
|
99
|
+
mongooseAdapter,
|
|
100
|
+
createAuthRouter,
|
|
101
|
+
authenticate,
|
|
102
|
+
authorize,
|
|
103
|
+
} from 'node-auth-kit';
|
|
104
|
+
|
|
105
|
+
import { User } from './models/User';
|
|
106
|
+
|
|
107
|
+
const app = express();
|
|
108
|
+
app.use(express.json());
|
|
109
|
+
|
|
110
|
+
// 1. Connect MongoDB
|
|
111
|
+
mongoose
|
|
112
|
+
.connect(process.env.MONGO_URL)
|
|
113
|
+
.then(() => console.log('MongoDB connected'))
|
|
114
|
+
.catch(console.error);
|
|
115
|
+
|
|
116
|
+
// 2. Initialize Device Auth
|
|
117
|
+
deviceAuth
|
|
118
|
+
.init({
|
|
119
|
+
authType: 'jwt',
|
|
120
|
+
signupFields: ['email', 'password'],
|
|
121
|
+
defaultRole: 'user',
|
|
122
|
+
password: {
|
|
123
|
+
minLength: 8,
|
|
124
|
+
requireNumbers: true,
|
|
125
|
+
requireSpecialChars: true,
|
|
126
|
+
saltRounds: 10,
|
|
127
|
+
},
|
|
128
|
+
token: {
|
|
129
|
+
accessTokenTtl: '15m',
|
|
130
|
+
},
|
|
131
|
+
})
|
|
132
|
+
.useAdapter(
|
|
133
|
+
mongooseAdapter({
|
|
134
|
+
userModel: User,
|
|
135
|
+
}),
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
// 3. Mount Auth Routes
|
|
139
|
+
app.use('/auth', createAuthRouter());
|
|
140
|
+
|
|
141
|
+
// 4. Example Protected Route
|
|
142
|
+
app.get(
|
|
143
|
+
'/admin',
|
|
144
|
+
authenticate,
|
|
145
|
+
authorize('admin'),
|
|
146
|
+
(req, res) => {
|
|
147
|
+
res.json({ message: 'Admin access granted' });
|
|
148
|
+
},
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
app.listen(3000, () => {
|
|
152
|
+
console.log('Server running on http://localhost:3000');
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## ๐ Authentication Routes
|
|
159
|
+
|
|
160
|
+
The default router created by `createAuthRouter()` exposes:
|
|
161
|
+
|
|
162
|
+
| Method | Endpoint | Description |
|
|
163
|
+
| ------ | ------------- | ------------------ |
|
|
164
|
+
| POST | `/auth/register` | Register new user |
|
|
165
|
+
| POST | `/auth/login` | Login user |
|
|
166
|
+
| GET | `/auth/me` | Get current user |
|
|
167
|
+
|
|
168
|
+
You can mount it under any base path (e.g. `/api/auth`).
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
app.use('/auth', createAuthRouter());
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## ๐ Middleware
|
|
177
|
+
|
|
178
|
+
### `authenticate`
|
|
179
|
+
|
|
180
|
+
Validates the JWT from the `Authorization: Bearer <token>` header and attaches the user to `req.user`.
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
app.get('/profile', authenticate, (req, res) => {
|
|
184
|
+
res.json(req.user);
|
|
185
|
+
});
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### `authorize(...roles)`
|
|
189
|
+
|
|
190
|
+
Restricts access based on user role.
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
app.get('/admin', authenticate, authorize('admin', 'staff'), (req, res) => {
|
|
194
|
+
res.json({ message: 'Admin or staff only' });
|
|
195
|
+
});
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## ๐งฉ Adapter System
|
|
201
|
+
|
|
202
|
+
Device Auth uses a **pluggable adapter architecture**, allowing it to work with different databases without changing core logic.
|
|
203
|
+
|
|
204
|
+
Supported / planned adapters:
|
|
205
|
+
|
|
206
|
+
| Adapter | Status |
|
|
207
|
+
| -------- | -------------------------- |
|
|
208
|
+
| Mongoose | โ
Stable |
|
|
209
|
+
| Prisma | ๐ง In Progress (V2) |
|
|
210
|
+
| TypeORM | โ Planned |
|
|
211
|
+
|
|
212
|
+
The public exports you can use:
|
|
213
|
+
|
|
214
|
+
- `mongooseAdapter` โ helper for MongoDB via Mongoose
|
|
215
|
+
- `MongooseAdapter` โ underlying class (advanced use)
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## โ๏ธ Configuration
|
|
220
|
+
|
|
221
|
+
The central entry point is `deviceAuth`:
|
|
222
|
+
|
|
223
|
+
```ts
|
|
224
|
+
import { deviceAuth, defaultConfig } from 'device_auth';
|
|
225
|
+
|
|
226
|
+
deviceAuth.init({
|
|
227
|
+
...defaultConfig,
|
|
228
|
+
authType: 'jwt',
|
|
229
|
+
defaultRole: 'user',
|
|
230
|
+
signupFields: ['email', 'password'],
|
|
231
|
+
// override anything you need
|
|
232
|
+
});
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Key options:
|
|
236
|
+
|
|
237
|
+
- **`authType`**: currently `jwt`
|
|
238
|
+
- **`signupFields`**: required fields on registration
|
|
239
|
+
- **`defaultRole`**: assigned when no role is provided
|
|
240
|
+
- **`password`**:
|
|
241
|
+
- `minLength`
|
|
242
|
+
- `requireNumbers`
|
|
243
|
+
- `requireSpecialChars`
|
|
244
|
+
- `saltRounds`
|
|
245
|
+
- **`token`**:
|
|
246
|
+
- `accessTokenTtl` (e.g. `15m`, `1h`)
|
|
247
|
+
|
|
248
|
+
The merged configuration is accessible via:
|
|
249
|
+
|
|
250
|
+
```ts
|
|
251
|
+
const config = deviceAuth.config;
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## ๐ง Hooks
|
|
257
|
+
|
|
258
|
+
Hooks let you run side effects around key lifecycle events without forking core logic.
|
|
259
|
+
|
|
260
|
+
Supported hook names:
|
|
261
|
+
|
|
262
|
+
- `beforeRegister`
|
|
263
|
+
- `afterRegister`
|
|
264
|
+
- `beforeLogin`
|
|
265
|
+
- `afterLogin`
|
|
266
|
+
|
|
267
|
+
Register hooks on `deviceAuth`:
|
|
268
|
+
|
|
269
|
+
```ts
|
|
270
|
+
import { deviceAuth } from 'device_auth';
|
|
271
|
+
|
|
272
|
+
deviceAuth
|
|
273
|
+
.registerHook('beforeRegister', async (createData) => {
|
|
274
|
+
// e.g. validate extra fields, audit, etc.
|
|
275
|
+
})
|
|
276
|
+
.registerHook('afterRegister', async (user) => {
|
|
277
|
+
// e.g. send welcome email
|
|
278
|
+
})
|
|
279
|
+
.registerHook('beforeLogin', async (user) => {
|
|
280
|
+
// e.g. check if user is blocked
|
|
281
|
+
})
|
|
282
|
+
.registerHook('afterLogin', async (user) => {
|
|
283
|
+
// e.g. log login event
|
|
284
|
+
});
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Hook errors are intentionally swallowed so they **never break core auth flow**.
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## ๐ฃ๏ธ Roadmap (V2)
|
|
292
|
+
|
|
293
|
+
Planned for upcoming versions:
|
|
294
|
+
|
|
295
|
+
- ๐ Refresh tokens
|
|
296
|
+
- ๐ฑ Multi-device sessions
|
|
297
|
+
- ๐ช Logout (single device / all devices)
|
|
298
|
+
- ๐ง Forgot & reset password
|
|
299
|
+
- โ
Email verification
|
|
300
|
+
- ๐งช Stable Prisma adapter
|
|
301
|
+
- ๐ง Additional hooks & lifecycle events
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## ๐งช Testing
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
npm test
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
Postman collection โ _coming soon_.
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## ๐ค Contributing
|
|
316
|
+
|
|
317
|
+
Contributions are welcome!
|
|
318
|
+
|
|
319
|
+
1. **Fork** the repository
|
|
320
|
+
2. **Create** a new branch
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
git checkout -b feature/my-feature
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
3. **Commit** your changes
|
|
327
|
+
4. **Push** to your branch
|
|
328
|
+
5. **Open** a Pull Request
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## ๐ License
|
|
333
|
+
|
|
334
|
+
MIT License ยฉ 2025
|
|
335
|
+
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { deviceAuth } from './src/deviceAuth';
|
|
2
|
+
export type { DeviceAuthConfig } from './src/config';
|
|
3
|
+
export { defaultConfig } from './src/config';
|
|
4
|
+
export { applyControllerOverrides } from './src/overrides';
|
|
5
|
+
export type { User, Role, Adapter, Config } from './src/types';
|
|
6
|
+
export { pick } from './src/utils';
|
|
7
|
+
export type { ResponseLike } from './src/utils';
|
|
8
|
+
export { sendJson, sendError, badRequest, unauthorized, forbidden, internalError, } from './src/utils';
|
|
9
|
+
export { MongooseAdapter, mongooseAdapter } from './src/adapters/mongoose.adapter';
|
|
10
|
+
export type { MongooseAdapterOptions } from './src/adapters/mongoose.adapter';
|
|
11
|
+
export { createAuthRouter } from './src/routes/auth.routes';
|
|
12
|
+
export { authenticate } from './src/middlewares/authenticate.middleware';
|
|
13
|
+
export { authorize } from './src/middlewares/authorize.middleware';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.authorize = exports.authenticate = exports.createAuthRouter = exports.mongooseAdapter = exports.MongooseAdapter = exports.internalError = exports.forbidden = exports.unauthorized = exports.badRequest = exports.sendError = exports.sendJson = exports.pick = exports.applyControllerOverrides = exports.defaultConfig = exports.deviceAuth = void 0;
|
|
4
|
+
var deviceAuth_1 = require("./src/deviceAuth");
|
|
5
|
+
Object.defineProperty(exports, "deviceAuth", { enumerable: true, get: function () { return deviceAuth_1.deviceAuth; } });
|
|
6
|
+
var config_1 = require("./src/config");
|
|
7
|
+
Object.defineProperty(exports, "defaultConfig", { enumerable: true, get: function () { return config_1.defaultConfig; } });
|
|
8
|
+
var overrides_1 = require("./src/overrides");
|
|
9
|
+
Object.defineProperty(exports, "applyControllerOverrides", { enumerable: true, get: function () { return overrides_1.applyControllerOverrides; } });
|
|
10
|
+
var utils_1 = require("./src/utils");
|
|
11
|
+
Object.defineProperty(exports, "pick", { enumerable: true, get: function () { return utils_1.pick; } });
|
|
12
|
+
var utils_2 = require("./src/utils");
|
|
13
|
+
Object.defineProperty(exports, "sendJson", { enumerable: true, get: function () { return utils_2.sendJson; } });
|
|
14
|
+
Object.defineProperty(exports, "sendError", { enumerable: true, get: function () { return utils_2.sendError; } });
|
|
15
|
+
Object.defineProperty(exports, "badRequest", { enumerable: true, get: function () { return utils_2.badRequest; } });
|
|
16
|
+
Object.defineProperty(exports, "unauthorized", { enumerable: true, get: function () { return utils_2.unauthorized; } });
|
|
17
|
+
Object.defineProperty(exports, "forbidden", { enumerable: true, get: function () { return utils_2.forbidden; } });
|
|
18
|
+
Object.defineProperty(exports, "internalError", { enumerable: true, get: function () { return utils_2.internalError; } });
|
|
19
|
+
var mongoose_adapter_1 = require("./src/adapters/mongoose.adapter");
|
|
20
|
+
Object.defineProperty(exports, "MongooseAdapter", { enumerable: true, get: function () { return mongoose_adapter_1.MongooseAdapter; } });
|
|
21
|
+
Object.defineProperty(exports, "mongooseAdapter", { enumerable: true, get: function () { return mongoose_adapter_1.mongooseAdapter; } });
|
|
22
|
+
var auth_routes_1 = require("./src/routes/auth.routes");
|
|
23
|
+
Object.defineProperty(exports, "createAuthRouter", { enumerable: true, get: function () { return auth_routes_1.createAuthRouter; } });
|
|
24
|
+
var authenticate_middleware_1 = require("./src/middlewares/authenticate.middleware");
|
|
25
|
+
Object.defineProperty(exports, "authenticate", { enumerable: true, get: function () { return authenticate_middleware_1.authenticate; } });
|
|
26
|
+
var authorize_middleware_1 = require("./src/middlewares/authorize.middleware");
|
|
27
|
+
Object.defineProperty(exports, "authorize", { enumerable: true, get: function () { return authorize_middleware_1.authorize; } });
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type AdapterUser = Record<string, unknown>;
|
|
2
|
+
export type CreateUserData = Record<string, unknown>;
|
|
3
|
+
export type UpdateUserData = Record<string, unknown>;
|
|
4
|
+
/**
|
|
5
|
+
* Base database adapter contract for device_auth.
|
|
6
|
+
*
|
|
7
|
+
* This interface is intentionally DB-agnostic and contains no ORM types
|
|
8
|
+
* or database-specific logic. Concrete adapters (Prisma, Mongoose, SQL, etc.)
|
|
9
|
+
* must implement this contract so that device_auth can talk to any backend
|
|
10
|
+
* in a uniform way.
|
|
11
|
+
*/
|
|
12
|
+
export interface BaseAdapter {
|
|
13
|
+
/** Create a new user record. */
|
|
14
|
+
createUser(data: CreateUserData): Promise<AdapterUser>;
|
|
15
|
+
/** Look up a user by email, or return null if not found. */
|
|
16
|
+
findUserByEmail(email: string): Promise<AdapterUser | null>;
|
|
17
|
+
/** Look up a user by primary identifier, or return null if not found. */
|
|
18
|
+
findUserById(id: string | number): Promise<AdapterUser | null>;
|
|
19
|
+
/** Update an existing user and return the updated record. */
|
|
20
|
+
updateUser(id: string | number, data: UpdateUserData): Promise<AdapterUser>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { AdapterUser, BaseAdapter, CreateUserData, UpdateUserData } from './base.adapter';
|
|
2
|
+
interface MinimalMongooseModel<T = unknown> {
|
|
3
|
+
create(data: Record<string, unknown>): Promise<T>;
|
|
4
|
+
findOne(filter: Record<string, unknown>): {
|
|
5
|
+
exec(): Promise<T | null>;
|
|
6
|
+
};
|
|
7
|
+
findById(id: unknown): {
|
|
8
|
+
exec(): Promise<T | null>;
|
|
9
|
+
};
|
|
10
|
+
findByIdAndUpdate(id: unknown, data: Record<string, unknown>, options: {
|
|
11
|
+
new: boolean;
|
|
12
|
+
}): {
|
|
13
|
+
exec(): Promise<T | null>;
|
|
14
|
+
};
|
|
15
|
+
findOneAndUpdate(filter: Record<string, unknown>, data: Record<string, unknown>, options: {
|
|
16
|
+
new: boolean;
|
|
17
|
+
}): {
|
|
18
|
+
exec(): Promise<T | null>;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export interface MongooseAdapterOptions {
|
|
22
|
+
userModel: MinimalMongooseModel;
|
|
23
|
+
idField?: string;
|
|
24
|
+
emailField?: string;
|
|
25
|
+
}
|
|
26
|
+
export declare class MongooseAdapter implements BaseAdapter {
|
|
27
|
+
private readonly userModel;
|
|
28
|
+
private readonly idField;
|
|
29
|
+
private readonly emailField;
|
|
30
|
+
constructor(options: MongooseAdapterOptions);
|
|
31
|
+
createUser(data: CreateUserData): Promise<AdapterUser>;
|
|
32
|
+
findUserByEmail(email: string): Promise<AdapterUser | null>;
|
|
33
|
+
findUserById(id: string | number): Promise<AdapterUser | null>;
|
|
34
|
+
updateUser(id: string | number, data: UpdateUserData): Promise<AdapterUser>;
|
|
35
|
+
private normalize;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Mongoose adapter factory.
|
|
39
|
+
*
|
|
40
|
+
* You can use either the class-based style:
|
|
41
|
+
*
|
|
42
|
+
* ```ts
|
|
43
|
+
* adapter: new MongooseAdapter({ userModel: User });
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* or the function-based style (recommended):
|
|
47
|
+
*
|
|
48
|
+
* ```ts
|
|
49
|
+
* adapter: mongooseAdapter({ userModel: User });
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare function mongooseAdapter(options: MongooseAdapterOptions): BaseAdapter;
|
|
53
|
+
export {};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MongooseAdapter = void 0;
|
|
4
|
+
exports.mongooseAdapter = mongooseAdapter;
|
|
5
|
+
class MongooseAdapter {
|
|
6
|
+
constructor(options) {
|
|
7
|
+
this.userModel = options.userModel;
|
|
8
|
+
this.idField = options.idField ?? '_id';
|
|
9
|
+
this.emailField = options.emailField ?? 'email';
|
|
10
|
+
}
|
|
11
|
+
async createUser(data) {
|
|
12
|
+
const doc = await this.userModel.create(data);
|
|
13
|
+
return this.normalize(doc);
|
|
14
|
+
}
|
|
15
|
+
async findUserByEmail(email) {
|
|
16
|
+
const doc = await this.userModel.findOne({ [this.emailField]: email }).exec();
|
|
17
|
+
if (!doc)
|
|
18
|
+
return null;
|
|
19
|
+
return this.normalize(doc);
|
|
20
|
+
}
|
|
21
|
+
async findUserById(id) {
|
|
22
|
+
let doc;
|
|
23
|
+
if (this.idField === '_id') {
|
|
24
|
+
doc = await this.userModel.findById(id).exec();
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
doc = await this.userModel.findOne({ [this.idField]: id }).exec();
|
|
28
|
+
}
|
|
29
|
+
if (!doc)
|
|
30
|
+
return null;
|
|
31
|
+
return this.normalize(doc);
|
|
32
|
+
}
|
|
33
|
+
async updateUser(id, data) {
|
|
34
|
+
let doc;
|
|
35
|
+
if (this.idField === '_id') {
|
|
36
|
+
doc = await this.userModel.findByIdAndUpdate(id, data, { new: true }).exec();
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
doc = await this.userModel
|
|
40
|
+
.findOneAndUpdate({ [this.idField]: id }, data, { new: true })
|
|
41
|
+
.exec();
|
|
42
|
+
}
|
|
43
|
+
if (!doc) {
|
|
44
|
+
throw new Error('User not found');
|
|
45
|
+
}
|
|
46
|
+
return this.normalize(doc);
|
|
47
|
+
}
|
|
48
|
+
normalize(doc) {
|
|
49
|
+
const obj = typeof doc.toObject === 'function' ? doc.toObject() : { ...doc };
|
|
50
|
+
const adapterUser = { ...obj };
|
|
51
|
+
const rawId = obj[this.idField];
|
|
52
|
+
if (rawId != null) {
|
|
53
|
+
// Expose a normalized id field expected by core
|
|
54
|
+
adapterUser['id'] =
|
|
55
|
+
typeof rawId === 'string' || typeof rawId === 'number' ? rawId : String(rawId);
|
|
56
|
+
}
|
|
57
|
+
return adapterUser;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
exports.MongooseAdapter = MongooseAdapter;
|
|
61
|
+
/**
|
|
62
|
+
* Mongoose adapter factory.
|
|
63
|
+
*
|
|
64
|
+
* You can use either the class-based style:
|
|
65
|
+
*
|
|
66
|
+
* ```ts
|
|
67
|
+
* adapter: new MongooseAdapter({ userModel: User });
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
70
|
+
* or the function-based style (recommended):
|
|
71
|
+
*
|
|
72
|
+
* ```ts
|
|
73
|
+
* adapter: mongooseAdapter({ userModel: User });
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
76
|
+
function mongooseAdapter(options) {
|
|
77
|
+
return new MongooseAdapter(options);
|
|
78
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { AdapterUser, BaseAdapter, CreateUserData, UpdateUserData } from './base.adapter';
|
|
2
|
+
export interface PrismaDelegate<TUser> {
|
|
3
|
+
create(args: {
|
|
4
|
+
data: Record<string, unknown>;
|
|
5
|
+
}): Promise<TUser>;
|
|
6
|
+
findUnique(args: {
|
|
7
|
+
where: Record<string, unknown>;
|
|
8
|
+
}): Promise<TUser | null>;
|
|
9
|
+
update(args: {
|
|
10
|
+
where: Record<string, unknown>;
|
|
11
|
+
data: Record<string, unknown>;
|
|
12
|
+
}): Promise<TUser>;
|
|
13
|
+
}
|
|
14
|
+
export interface PrismaAdapterOptions<TUser extends Record<string, unknown>> {
|
|
15
|
+
userDelegate: PrismaDelegate<TUser>;
|
|
16
|
+
idField?: string;
|
|
17
|
+
emailField?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare class PrismaAdapter<TUser extends Record<string, unknown>> implements BaseAdapter {
|
|
20
|
+
private readonly userDelegate;
|
|
21
|
+
private readonly idField;
|
|
22
|
+
private readonly emailField;
|
|
23
|
+
constructor(options: PrismaAdapterOptions<TUser>);
|
|
24
|
+
createUser(data: CreateUserData): Promise<AdapterUser>;
|
|
25
|
+
findUserByEmail(email: string): Promise<AdapterUser | null>;
|
|
26
|
+
findUserById(id: string | number): Promise<AdapterUser | null>;
|
|
27
|
+
updateUser(id: string | number, data: UpdateUserData): Promise<AdapterUser>;
|
|
28
|
+
private normalize;
|
|
29
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PrismaAdapter = void 0;
|
|
4
|
+
class PrismaAdapter {
|
|
5
|
+
constructor(options) {
|
|
6
|
+
this.userDelegate = options.userDelegate;
|
|
7
|
+
this.idField = options.idField ?? 'id';
|
|
8
|
+
this.emailField = options.emailField ?? 'email';
|
|
9
|
+
}
|
|
10
|
+
async createUser(data) {
|
|
11
|
+
const user = await this.userDelegate.create({ data });
|
|
12
|
+
return this.normalize(user);
|
|
13
|
+
}
|
|
14
|
+
async findUserByEmail(email) {
|
|
15
|
+
const user = await this.userDelegate.findUnique({ where: { [this.emailField]: email } });
|
|
16
|
+
if (!user)
|
|
17
|
+
return null;
|
|
18
|
+
return this.normalize(user);
|
|
19
|
+
}
|
|
20
|
+
async findUserById(id) {
|
|
21
|
+
const user = await this.userDelegate.findUnique({ where: { [this.idField]: id } });
|
|
22
|
+
if (!user)
|
|
23
|
+
return null;
|
|
24
|
+
return this.normalize(user);
|
|
25
|
+
}
|
|
26
|
+
async updateUser(id, data) {
|
|
27
|
+
const user = await this.userDelegate.update({ where: { [this.idField]: id }, data });
|
|
28
|
+
return this.normalize(user);
|
|
29
|
+
}
|
|
30
|
+
normalize(user) {
|
|
31
|
+
const adapterUser = { ...user };
|
|
32
|
+
const rawId = user[this.idField];
|
|
33
|
+
if (rawId != null) {
|
|
34
|
+
adapterUser['id'] =
|
|
35
|
+
typeof rawId === 'string' || typeof rawId === 'number' ? rawId : String(rawId);
|
|
36
|
+
}
|
|
37
|
+
return adapterUser;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.PrismaAdapter = PrismaAdapter;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type AuthType = 'jwt' | 'session';
|
|
2
|
+
export interface PasswordRulesConfig {
|
|
3
|
+
minLength: number;
|
|
4
|
+
requireNumbers: boolean;
|
|
5
|
+
requireSpecialChars: boolean;
|
|
6
|
+
saltRounds: number;
|
|
7
|
+
}
|
|
8
|
+
export interface TokenConfig {
|
|
9
|
+
/** e.g. '15m', '1h' */
|
|
10
|
+
accessTokenTtl: string;
|
|
11
|
+
}
|
|
12
|
+
export interface DeviceAuthConfig {
|
|
13
|
+
signupFields: string[];
|
|
14
|
+
defaultRole: string;
|
|
15
|
+
authType: AuthType;
|
|
16
|
+
password: PasswordRulesConfig;
|
|
17
|
+
token: TokenConfig;
|
|
18
|
+
}
|
|
19
|
+
export declare const defaultConfig: DeviceAuthConfig;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defaultConfig = void 0;
|
|
4
|
+
exports.defaultConfig = {
|
|
5
|
+
signupFields: ['email', 'password'],
|
|
6
|
+
defaultRole: 'user',
|
|
7
|
+
authType: 'jwt',
|
|
8
|
+
password: {
|
|
9
|
+
minLength: 8,
|
|
10
|
+
requireNumbers: true,
|
|
11
|
+
requireSpecialChars: false,
|
|
12
|
+
saltRounds: 10,
|
|
13
|
+
},
|
|
14
|
+
token: {
|
|
15
|
+
accessTokenTtl: '15m',
|
|
16
|
+
},
|
|
17
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defaultConfig = exports.mergeConfig = void 0;
|
|
4
|
+
const default_config_1 = require("./default.config");
|
|
5
|
+
Object.defineProperty(exports, "defaultConfig", { enumerable: true, get: function () { return default_config_1.defaultConfig; } });
|
|
6
|
+
// Merge user config with defaults, including nested objects we know about
|
|
7
|
+
const mergeConfig = (userConfig) => {
|
|
8
|
+
if (!userConfig)
|
|
9
|
+
return { ...default_config_1.defaultConfig };
|
|
10
|
+
return {
|
|
11
|
+
...default_config_1.defaultConfig,
|
|
12
|
+
...userConfig,
|
|
13
|
+
password: {
|
|
14
|
+
...default_config_1.defaultConfig.password,
|
|
15
|
+
...(userConfig.password ?? {}),
|
|
16
|
+
},
|
|
17
|
+
token: {
|
|
18
|
+
...default_config_1.defaultConfig.token,
|
|
19
|
+
...(userConfig.token ?? {}),
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
exports.mergeConfig = mergeConfig;
|