sentri 1.1.2 → 2.1.0
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 +268 -448
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +113 -107
- package/dist/index.d.ts +545 -11
- package/dist/index.js +1 -5
- package/package.json +9 -7
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/client.d.ts +0 -160
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js +0 -45
- package/dist/client.js.map +0 -1
- package/dist/errors/AuthError.d.ts +0 -99
- package/dist/errors/AuthError.d.ts.map +0 -1
- package/dist/errors/AuthError.js +0 -97
- package/dist/errors/AuthError.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/libs/config.d.ts +0 -62
- package/dist/libs/config.d.ts.map +0 -1
- package/dist/libs/config.js +0 -97
- package/dist/libs/config.js.map +0 -1
- package/dist/libs/hash.d.ts +0 -17
- package/dist/libs/hash.d.ts.map +0 -1
- package/dist/libs/hash.js +0 -22
- package/dist/libs/hash.js.map +0 -1
- package/dist/libs/token.d.ts +0 -46
- package/dist/libs/token.d.ts.map +0 -1
- package/dist/libs/token.js +0 -118
- package/dist/libs/token.js.map +0 -1
- package/dist/middleware/authorize.d.ts +0 -18
- package/dist/middleware/authorize.d.ts.map +0 -1
- package/dist/middleware/authorize.js +0 -30
- package/dist/middleware/authorize.js.map +0 -1
- package/dist/middleware/errorHandler.d.ts +0 -71
- package/dist/middleware/errorHandler.d.ts.map +0 -1
- package/dist/middleware/errorHandler.js +0 -74
- package/dist/middleware/errorHandler.js.map +0 -1
- package/dist/middleware/permit.d.ts +0 -62
- package/dist/middleware/permit.d.ts.map +0 -1
- package/dist/middleware/permit.js +0 -61
- package/dist/middleware/permit.js.map +0 -1
- package/dist/middleware/protect.d.ts +0 -31
- package/dist/middleware/protect.d.ts.map +0 -1
- package/dist/middleware/protect.js +0 -54
- package/dist/middleware/protect.js.map +0 -1
- package/dist/middleware/router.d.ts +0 -34
- package/dist/middleware/router.d.ts.map +0 -1
- package/dist/middleware/router.js +0 -264
- package/dist/middleware/router.js.map +0 -1
- package/dist/services/auth.d.ts +0 -85
- package/dist/services/auth.d.ts.map +0 -1
- package/dist/services/auth.js +0 -173
- package/dist/services/auth.js.map +0 -1
- package/dist/types/auth.d.ts +0 -450
- package/dist/types/auth.d.ts.map +0 -1
- package/dist/types/auth.js +0 -21
- package/dist/types/auth.js.map +0 -1
- package/templates/drizzle/adapter.ts +0 -154
- package/templates/drizzle/auth.ts +0 -82
- package/templates/drizzle/schema.ts +0 -47
- package/templates/prisma/adapter.ts +0 -122
- package/templates/prisma/auth.ts +0 -85
- package/templates/prisma/schema.prisma +0 -56
package/dist/types/auth.d.ts
DELETED
|
@@ -1,450 +0,0 @@
|
|
|
1
|
-
import type { SentriError, SentriErrorCode } from '../errors/AuthError.js';
|
|
2
|
-
export type { SentriError };
|
|
3
|
-
/** Standard API response envelope returned by all built-in router endpoints. */
|
|
4
|
-
export interface ApiResponse<T = null> {
|
|
5
|
-
error: boolean;
|
|
6
|
-
statusCode: number;
|
|
7
|
-
message: string;
|
|
8
|
-
data: T | null;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* @internal Extended JWT payload decoded from an access token.
|
|
12
|
-
* Includes `sessionId` which is not exposed on `req.user` but is used
|
|
13
|
-
* by `protect()` to validate that the session is still active.
|
|
14
|
-
*/
|
|
15
|
-
export interface AccessTokenPayload<TRole extends string = string> extends AuthUser<TRole> {
|
|
16
|
-
sessionId: string;
|
|
17
|
-
}
|
|
18
|
-
/** Maps a {@link SentriErrorCode} to its corresponding HTTP status code. */
|
|
19
|
-
export declare function authErrorStatus(code: SentriErrorCode): number;
|
|
20
|
-
/** Shape of a user row returned by the adapter — used internally by the library. */
|
|
21
|
-
export interface UserRecord {
|
|
22
|
-
id: string;
|
|
23
|
-
/**
|
|
24
|
-
* The credential identifier for this user (email, username, phone number, etc.).
|
|
25
|
-
* The adapter decides which column(s) this maps to.
|
|
26
|
-
*/
|
|
27
|
-
identifier: string;
|
|
28
|
-
passwordHash: string;
|
|
29
|
-
/** Role names currently assigned to the user. */
|
|
30
|
-
roles: string[];
|
|
31
|
-
}
|
|
32
|
-
/** Shape of a session row returned by the adapter. */
|
|
33
|
-
export interface SessionRecord {
|
|
34
|
-
id: string;
|
|
35
|
-
userId: string;
|
|
36
|
-
expiresAt: Date;
|
|
37
|
-
createdAt: Date;
|
|
38
|
-
}
|
|
39
|
-
/** Data the library passes to the adapter when creating a new user. */
|
|
40
|
-
export interface CreateUserData {
|
|
41
|
-
/**
|
|
42
|
-
* The credential identifier supplied at registration (email, username, phone, etc.).
|
|
43
|
-
* Store this in whichever column(s) your schema uses for login lookup.
|
|
44
|
-
*/
|
|
45
|
-
identifier: string;
|
|
46
|
-
passwordHash: string;
|
|
47
|
-
/** Validated role names to assign at creation. */
|
|
48
|
-
roles: string[];
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* The database adapter interface the library depends on.
|
|
52
|
-
*
|
|
53
|
-
* Implement this to connect the library to any ORM or data layer.
|
|
54
|
-
*
|
|
55
|
-
* The library uses a single `identifier` string for credentials — your adapter
|
|
56
|
-
* decides what that means: email column, username column, phone column, or a
|
|
57
|
-
* query across multiple columns.
|
|
58
|
-
*/
|
|
59
|
-
export interface AuthAdapter {
|
|
60
|
-
user: {
|
|
61
|
-
/**
|
|
62
|
-
* Find a user by their login identifier.
|
|
63
|
-
*
|
|
64
|
-
* The adapter decides which column(s) to query — email, username, phone,
|
|
65
|
-
* or a combined lookup (`WHERE email = $1 OR username = $1`).
|
|
66
|
-
* Returns `null` if not found.
|
|
67
|
-
*/
|
|
68
|
-
findByIdentifier(identifier: string): Promise<UserRecord | null>;
|
|
69
|
-
/** Find a user by their primary key. Returns `null` if not found. */
|
|
70
|
-
findById(id: string): Promise<UserRecord | null>;
|
|
71
|
-
/**
|
|
72
|
-
* Persist a new user with the given identifier, hashed password, and roles.
|
|
73
|
-
* The adapter maps `identifier` to the appropriate column(s) in your schema.
|
|
74
|
-
*/
|
|
75
|
-
create(data: CreateUserData): Promise<{
|
|
76
|
-
id: string;
|
|
77
|
-
}>;
|
|
78
|
-
/**
|
|
79
|
-
* Replace the complete role list for a user.
|
|
80
|
-
* Called by `assignRoles` after merging the new roles with the existing ones.
|
|
81
|
-
*/
|
|
82
|
-
updateRoles(userId: string, roles: string[]): Promise<void>;
|
|
83
|
-
};
|
|
84
|
-
session: {
|
|
85
|
-
/**
|
|
86
|
-
* Persist a new session and return its generated ID.
|
|
87
|
-
* `expiresAt` is computed from `refreshExpiresIn` in config.
|
|
88
|
-
*/
|
|
89
|
-
create(data: {
|
|
90
|
-
userId: string;
|
|
91
|
-
expiresAt: Date;
|
|
92
|
-
}): Promise<{
|
|
93
|
-
id: string;
|
|
94
|
-
}>;
|
|
95
|
-
/**
|
|
96
|
-
* Find a session by its ID, including the associated user.
|
|
97
|
-
* Returns `null` if the session does not exist (i.e. has been revoked).
|
|
98
|
-
*/
|
|
99
|
-
findById(sessionId: string): Promise<(SessionRecord & {
|
|
100
|
-
user: UserRecord;
|
|
101
|
-
}) | null>;
|
|
102
|
-
/** Delete a single session. Used during logout and token rotation. */
|
|
103
|
-
delete(sessionId: string): Promise<void>;
|
|
104
|
-
/** Delete all sessions belonging to a user. Used for "logout from all devices". */
|
|
105
|
-
deleteAllForUser(userId: string): Promise<void>;
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Custom service functions for the built-in auth router.
|
|
110
|
-
*
|
|
111
|
-
* Each key matches the internal service function name. When provided, the
|
|
112
|
-
* custom function replaces the default service call for that route while the
|
|
113
|
-
* router still handles request parsing, input validation, and response formatting.
|
|
114
|
-
*
|
|
115
|
-
* The function signatures mirror the internal services exactly but without the
|
|
116
|
-
* `config` parameter — the library passes config at bind time.
|
|
117
|
-
*
|
|
118
|
-
* @example
|
|
119
|
-
* createAuth({
|
|
120
|
-
* // ...
|
|
121
|
-
* router: {
|
|
122
|
-
* login: async (input) => {
|
|
123
|
-
* // add OTP check, custom user lookup, etc.
|
|
124
|
-
* // must return AuthResult
|
|
125
|
-
* },
|
|
126
|
-
* register: async (input) => {
|
|
127
|
-
* // send welcome email, set default profile, etc.
|
|
128
|
-
* // must return RegisterResult
|
|
129
|
-
* },
|
|
130
|
-
* },
|
|
131
|
-
* });
|
|
132
|
-
*/
|
|
133
|
-
export interface RouterHandlers {
|
|
134
|
-
/**
|
|
135
|
-
* Replaces the default register service (`POST /register`).
|
|
136
|
-
*
|
|
137
|
-
* The router validates the request body (identifier, password, roles) first,
|
|
138
|
-
* then calls this function with the parsed input. Must return a `RegisterResult`.
|
|
139
|
-
* If omitted, the library's built-in registration logic runs instead.
|
|
140
|
-
*
|
|
141
|
-
* @example
|
|
142
|
-
* register: async (input) => {
|
|
143
|
-
* const result = await defaultRegister(input);
|
|
144
|
-
* if (result.success) {
|
|
145
|
-
* await emailService.sendWelcome(input.identifier);
|
|
146
|
-
* }
|
|
147
|
-
* return result;
|
|
148
|
-
* }
|
|
149
|
-
*/
|
|
150
|
-
register?: (input: RegisterInput) => Promise<RegisterResult>;
|
|
151
|
-
/**
|
|
152
|
-
* Replaces the default login service.
|
|
153
|
-
*
|
|
154
|
-
* The router validates the request body (identifier, password) first,
|
|
155
|
-
* then calls this function with the parsed input. Must return an `AuthResult`.
|
|
156
|
-
* If omitted, the library's built-in login logic runs instead.
|
|
157
|
-
*
|
|
158
|
-
* @example
|
|
159
|
-
* login: async (input) => {
|
|
160
|
-
* // verify OTP before issuing tokens
|
|
161
|
-
* const otpValid = await redis.get(`otp:${input.identifier}`);
|
|
162
|
-
* if (!otpValid) {
|
|
163
|
-
* return { success: false, error: new SentriError('INVALID_CREDENTIALS', 'OTP required') };
|
|
164
|
-
* }
|
|
165
|
-
* return defaultLogin(input);
|
|
166
|
-
* }
|
|
167
|
-
*/
|
|
168
|
-
login?: (input: LoginInput) => Promise<AuthResult>;
|
|
169
|
-
/**
|
|
170
|
-
* Replaces the default refresh service.
|
|
171
|
-
*
|
|
172
|
-
* Receives the raw refresh token string extracted from the cookie.
|
|
173
|
-
* Must return a `RefreshResult`. If omitted, the built-in session-rotation
|
|
174
|
-
* logic runs instead.
|
|
175
|
-
*
|
|
176
|
-
* @example
|
|
177
|
-
* refresh: async (refreshToken) => {
|
|
178
|
-
* const result = await defaultRefresh(refreshToken);
|
|
179
|
-
* if (result.success) {
|
|
180
|
-
* await auditLog.record('token_rotated', result.user.id);
|
|
181
|
-
* }
|
|
182
|
-
* return result;
|
|
183
|
-
* }
|
|
184
|
-
*/
|
|
185
|
-
refresh?: (refreshToken: string) => Promise<RefreshResult>;
|
|
186
|
-
/**
|
|
187
|
-
* Replaces the default logout service.
|
|
188
|
-
*
|
|
189
|
-
* Receives the raw refresh token from the cookie, or `undefined` if no cookie
|
|
190
|
-
* was present. The router clears the cookie after this function resolves.
|
|
191
|
-
* If omitted, the built-in session deletion logic runs instead.
|
|
192
|
-
*
|
|
193
|
-
* @example
|
|
194
|
-
* logout: async (refreshToken) => {
|
|
195
|
-
* if (refreshToken) {
|
|
196
|
-
* await defaultLogout(refreshToken);
|
|
197
|
-
* await auditLog.record('logout', refreshToken);
|
|
198
|
-
* }
|
|
199
|
-
* }
|
|
200
|
-
*/
|
|
201
|
-
logout?: (refreshToken: string | undefined) => Promise<void>;
|
|
202
|
-
/**
|
|
203
|
-
* Replaces the default logoutAll service.
|
|
204
|
-
*
|
|
205
|
-
* Receives the authenticated user's ID (from `req.user`, set by `protect()`).
|
|
206
|
-
* If omitted, the built-in "delete all sessions" logic runs instead.
|
|
207
|
-
*
|
|
208
|
-
* @example
|
|
209
|
-
* logoutAll: async (userId) => {
|
|
210
|
-
* await defaultLogoutAll(userId);
|
|
211
|
-
* await notifyService.push(userId, 'You have been signed out from all devices.');
|
|
212
|
-
* }
|
|
213
|
-
*/
|
|
214
|
-
logoutAll?: (userId: string) => Promise<void>;
|
|
215
|
-
/**
|
|
216
|
-
* Replaces the default assignRoles service.
|
|
217
|
-
*
|
|
218
|
-
* The router validates the request body and params first, then calls this
|
|
219
|
-
* function with the target `userId` and the validated `roles` array.
|
|
220
|
-
* Must return an `AssignRolesResult`. If omitted, the built-in role-merge
|
|
221
|
-
* logic runs instead.
|
|
222
|
-
*
|
|
223
|
-
* @example
|
|
224
|
-
* assignRoles: async (userId, roles) => {
|
|
225
|
-
* const result = await defaultAssignRoles(userId, roles);
|
|
226
|
-
* if (result.success) {
|
|
227
|
-
* await auditLog.record('roles_assigned', { userId, roles });
|
|
228
|
-
* }
|
|
229
|
-
* return result;
|
|
230
|
-
* }
|
|
231
|
-
*/
|
|
232
|
-
assignRoles?: (userId: string, roles: string[]) => Promise<AssignRolesResult>;
|
|
233
|
-
}
|
|
234
|
-
/**
|
|
235
|
-
* Configuration passed to {@link createAuth}.
|
|
236
|
-
*
|
|
237
|
-
* Only `secret`, `validRoles`, and `adapter` are required.
|
|
238
|
-
* All other fields have sensible defaults.
|
|
239
|
-
*
|
|
240
|
-
* @example
|
|
241
|
-
* createAuth({
|
|
242
|
-
* secret: process.env.JWT_SECRET!,
|
|
243
|
-
* validRoles: ['user', 'admin'] as const,
|
|
244
|
-
* adapter: myAdapter,
|
|
245
|
-
* });
|
|
246
|
-
*/
|
|
247
|
-
export interface AuthConfig<TRole extends string = string> {
|
|
248
|
-
/** Secret used to sign JWT tokens. Must not be empty. Keep this in an env variable. */
|
|
249
|
-
secret: string;
|
|
250
|
-
/**
|
|
251
|
-
* How long access tokens are valid.
|
|
252
|
-
* Accepts a duration string (`'15m'`, `'1h'`) or seconds as a number.
|
|
253
|
-
* @default '15m'
|
|
254
|
-
*/
|
|
255
|
-
accessExpiresIn?: string | number;
|
|
256
|
-
/**
|
|
257
|
-
* How long refresh tokens / sessions are valid.
|
|
258
|
-
* Accepts a duration string (`'7d'`, `'30d'`) or seconds as a number.
|
|
259
|
-
* @default '7d'
|
|
260
|
-
*/
|
|
261
|
-
refreshExpiresIn?: string | number;
|
|
262
|
-
/**
|
|
263
|
-
* HMAC signing algorithm used for JWTs.
|
|
264
|
-
* @default 'HS256'
|
|
265
|
-
*/
|
|
266
|
-
algorithm?: 'HS256' | 'HS384' | 'HS512';
|
|
267
|
-
/**
|
|
268
|
-
* bcrypt cost factor. Higher = slower hashing but more secure.
|
|
269
|
-
* @default 12
|
|
270
|
-
*/
|
|
271
|
-
saltRounds?: number;
|
|
272
|
-
/**
|
|
273
|
-
* Exhaustive list of role names your application uses.
|
|
274
|
-
* Registration will be rejected with `INVALID_ROLE` if a role outside this list is requested.
|
|
275
|
-
* Use `as const` to get TypeScript union-type safety on `authorize()`.
|
|
276
|
-
*
|
|
277
|
-
* @example
|
|
278
|
-
* validRoles: ['user', 'admin', 'moderator'] as const
|
|
279
|
-
*/
|
|
280
|
-
validRoles: readonly TRole[];
|
|
281
|
-
/** ORM adapter that connects the library to your database. */
|
|
282
|
-
adapter: AuthAdapter;
|
|
283
|
-
/**
|
|
284
|
-
* API key required to call `POST /register`.
|
|
285
|
-
*
|
|
286
|
-
* When set, the `/register` endpoint expects an `X-Api-Key` header whose
|
|
287
|
-
* value matches this string exactly. Requests without the header, or with
|
|
288
|
-
* the wrong value, are rejected with HTTP 401 (`UNAUTHORIZED`).
|
|
289
|
-
*
|
|
290
|
-
* Use this to restrict self-registration — for example, only your own
|
|
291
|
-
* back-office service or admin panel should be able to create new accounts,
|
|
292
|
-
* so you never expose user registration to arbitrary callers.
|
|
293
|
-
*
|
|
294
|
-
* @example
|
|
295
|
-
* createAuth({
|
|
296
|
-
* // ...
|
|
297
|
-
* apiKey: process.env.REGISTER_API_KEY!,
|
|
298
|
-
* });
|
|
299
|
-
*
|
|
300
|
-
* // Client must send:
|
|
301
|
-
* // POST /auth/register
|
|
302
|
-
* // X-Api-Key: <value of REGISTER_API_KEY>
|
|
303
|
-
*/
|
|
304
|
-
apiKey?: string;
|
|
305
|
-
/**
|
|
306
|
-
* Custom service functions for individual routes in the built-in auth router.
|
|
307
|
-
*
|
|
308
|
-
* The router still handles request parsing, validation, and response formatting.
|
|
309
|
-
* Only the core service logic is replaced by your function.
|
|
310
|
-
*
|
|
311
|
-
* @example
|
|
312
|
-
* createAuth({
|
|
313
|
-
* // ...
|
|
314
|
-
* router: {
|
|
315
|
-
* login: async (input) => {
|
|
316
|
-
* // verify OTP, then delegate to default or return custom result
|
|
317
|
-
* return { success: true, accessToken, refreshToken, user };
|
|
318
|
-
* },
|
|
319
|
-
* register: async (input) => {
|
|
320
|
-
* // send welcome email after successful registration
|
|
321
|
-
* const result = await defaultRegister(input);
|
|
322
|
-
* if (result.success) await emailService.sendWelcome(input.identifier);
|
|
323
|
-
* return result;
|
|
324
|
-
* },
|
|
325
|
-
* },
|
|
326
|
-
* });
|
|
327
|
-
*/
|
|
328
|
-
router?: RouterHandlers;
|
|
329
|
-
/**
|
|
330
|
-
* When set, the built-in router (`auth.router()`) stores the refresh token
|
|
331
|
-
* in an httpOnly cookie instead of returning it in the response body.
|
|
332
|
-
*
|
|
333
|
-
* The `refreshToken` field is omitted from `/login` and `/refresh` responses.
|
|
334
|
-
* The `/logout` and `/logout-all` routes automatically clear the cookie.
|
|
335
|
-
*
|
|
336
|
-
* No extra middleware (e.g. `cookie-parser`) is required.
|
|
337
|
-
*
|
|
338
|
-
* @example
|
|
339
|
-
* createAuth({
|
|
340
|
-
* // ...
|
|
341
|
-
* cookie: { secure: process.env.NODE_ENV === 'production' },
|
|
342
|
-
* });
|
|
343
|
-
*/
|
|
344
|
-
cookie?: CookieConfig;
|
|
345
|
-
}
|
|
346
|
-
/**
|
|
347
|
-
* Cookie settings for storing the refresh token in an httpOnly cookie.
|
|
348
|
-
* All fields are optional — defaults are chosen for security.
|
|
349
|
-
*/
|
|
350
|
-
export interface CookieConfig {
|
|
351
|
-
/**
|
|
352
|
-
* Name of the cookie.
|
|
353
|
-
* @default 'refresh_token'
|
|
354
|
-
*/
|
|
355
|
-
name?: string;
|
|
356
|
-
/**
|
|
357
|
-
* Prevents JavaScript from reading the cookie (`document.cookie`).
|
|
358
|
-
* @default true
|
|
359
|
-
*/
|
|
360
|
-
httpOnly?: boolean;
|
|
361
|
-
/**
|
|
362
|
-
* Restricts the cookie to HTTPS connections.
|
|
363
|
-
* Set to `true` in production.
|
|
364
|
-
* @default false
|
|
365
|
-
*/
|
|
366
|
-
secure?: boolean;
|
|
367
|
-
/**
|
|
368
|
-
* Controls cross-site request behaviour.
|
|
369
|
-
* @default 'strict'
|
|
370
|
-
*/
|
|
371
|
-
sameSite?: 'strict' | 'lax' | 'none';
|
|
372
|
-
/**
|
|
373
|
-
* URL path the cookie is scoped to.
|
|
374
|
-
* @default '/'
|
|
375
|
-
*/
|
|
376
|
-
path?: string;
|
|
377
|
-
}
|
|
378
|
-
/**
|
|
379
|
-
* The user payload injected as `req.user` after `protect()` runs.
|
|
380
|
-
*
|
|
381
|
-
* Access tokens issued by sentri >= 1.1.0 embed a `sessionId` that is
|
|
382
|
-
* validated against the database on every request. Tokens from older
|
|
383
|
-
* versions that lack this claim are accepted but bypass session validation.
|
|
384
|
-
*/
|
|
385
|
-
export interface AuthUser<TRole extends string = string> {
|
|
386
|
-
id: string;
|
|
387
|
-
/**
|
|
388
|
-
* The credential identifier for this user (email, username, phone, etc.).
|
|
389
|
-
* Reflects whatever value was passed as `identifier` at registration or login.
|
|
390
|
-
*/
|
|
391
|
-
identifier: string;
|
|
392
|
-
roles: TRole[];
|
|
393
|
-
}
|
|
394
|
-
/** Return type of `register`. */
|
|
395
|
-
export type RegisterResult<TRole extends string = string> = {
|
|
396
|
-
success: true;
|
|
397
|
-
user: AuthUser<TRole>;
|
|
398
|
-
} | {
|
|
399
|
-
success: false;
|
|
400
|
-
error: SentriError;
|
|
401
|
-
};
|
|
402
|
-
/** Return type of `login`. */
|
|
403
|
-
export type AuthResult<TRole extends string = string> = {
|
|
404
|
-
success: true;
|
|
405
|
-
accessToken: string;
|
|
406
|
-
refreshToken: string;
|
|
407
|
-
user: AuthUser<TRole>;
|
|
408
|
-
} | {
|
|
409
|
-
success: false;
|
|
410
|
-
error: SentriError;
|
|
411
|
-
};
|
|
412
|
-
/** Return type of `assignRoles`. */
|
|
413
|
-
export type AssignRolesResult<TRole extends string = string> = {
|
|
414
|
-
success: true;
|
|
415
|
-
user: AuthUser<TRole>;
|
|
416
|
-
} | {
|
|
417
|
-
success: false;
|
|
418
|
-
error: SentriError;
|
|
419
|
-
};
|
|
420
|
-
/** Return type of `refresh`. */
|
|
421
|
-
export type RefreshResult<TRole extends string = string> = {
|
|
422
|
-
success: true;
|
|
423
|
-
accessToken: string;
|
|
424
|
-
refreshToken: string;
|
|
425
|
-
user: AuthUser<TRole>;
|
|
426
|
-
} | {
|
|
427
|
-
success: false;
|
|
428
|
-
error: SentriError;
|
|
429
|
-
};
|
|
430
|
-
/** Input for `register`. */
|
|
431
|
-
export interface RegisterInput<TRole extends string = string> {
|
|
432
|
-
/**
|
|
433
|
-
* The user's login credential — email, username, phone number, or any unique string.
|
|
434
|
-
* The adapter maps this to the appropriate column in your database.
|
|
435
|
-
*/
|
|
436
|
-
identifier: string;
|
|
437
|
-
password: string;
|
|
438
|
-
/** Roles to assign at creation. Must be a subset of `validRoles`. */
|
|
439
|
-
roles?: TRole[];
|
|
440
|
-
}
|
|
441
|
-
/** Input for `login`. */
|
|
442
|
-
export interface LoginInput {
|
|
443
|
-
/**
|
|
444
|
-
* The user's login credential — email, username, phone number, or any unique string.
|
|
445
|
-
* The adapter's `findByIdentifier` handles the lookup.
|
|
446
|
-
*/
|
|
447
|
-
identifier: string;
|
|
448
|
-
password: string;
|
|
449
|
-
}
|
|
450
|
-
//# sourceMappingURL=auth.d.ts.map
|
package/dist/types/auth.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/types/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/types/auth.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/** Maps a {@link SentriErrorCode} to its corresponding HTTP status code. */
|
|
2
|
-
export function authErrorStatus(code) {
|
|
3
|
-
switch (code) {
|
|
4
|
-
case 'UNAUTHORIZED':
|
|
5
|
-
case 'INVALID_CREDENTIALS':
|
|
6
|
-
case 'TOKEN_EXPIRED':
|
|
7
|
-
case 'TOKEN_INVALID':
|
|
8
|
-
return 401;
|
|
9
|
-
case 'FORBIDDEN':
|
|
10
|
-
return 403;
|
|
11
|
-
case 'USER_NOT_FOUND':
|
|
12
|
-
return 404;
|
|
13
|
-
case 'USER_ALREADY_EXISTS':
|
|
14
|
-
return 409;
|
|
15
|
-
case 'CONFIGURATION_ERROR':
|
|
16
|
-
return 500;
|
|
17
|
-
default:
|
|
18
|
-
return 400;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
//# sourceMappingURL=auth.js.map
|
package/dist/types/auth.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/types/auth.ts"],"names":[],"mappings":"AAqBA,4EAA4E;AAC5E,MAAM,UAAU,eAAe,CAAC,IAAqB;IACnD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,cAAc,CAAC;QACpB,KAAK,qBAAqB,CAAC;QAC3B,KAAK,eAAe,CAAC;QACrB,KAAK,eAAe;YAClB,OAAO,GAAG,CAAC;QACb,KAAK,WAAW;YACd,OAAO,GAAG,CAAC;QACb,KAAK,gBAAgB;YACnB,OAAO,GAAG,CAAC;QACb,KAAK,qBAAqB;YACxB,OAAO,GAAG,CAAC;QACb,KAAK,qBAAqB;YACxB,OAAO,GAAG,CAAC;QACb;YACE,OAAO,GAAG,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
// sentri — Drizzle adapter template
|
|
2
|
-
// Generated by: npx sentri generate drizzle
|
|
3
|
-
//
|
|
4
|
-
// Adjust the import paths to match your project structure.
|
|
5
|
-
// This template assumes tables: users, roles, userRoles, sessions.
|
|
6
|
-
// Column names follow the sentri Drizzle schema convention.
|
|
7
|
-
//
|
|
8
|
-
// Replace NodePgDatabase with the type that matches your Drizzle driver:
|
|
9
|
-
// import { type NodePgDatabase } from 'drizzle-orm/node-postgres'; (default)
|
|
10
|
-
// import { type LibSQLDatabase } from 'drizzle-orm/libsql';
|
|
11
|
-
// import { type MySql2Database } from 'drizzle-orm/mysql2';
|
|
12
|
-
|
|
13
|
-
import { eq } from 'drizzle-orm';
|
|
14
|
-
import type { NodePgDatabase } from 'drizzle-orm/node-postgres';
|
|
15
|
-
import { AuthError, type AuthAdapter } from 'sentri';
|
|
16
|
-
import { users, roles, userRoles, sessions } from './schema.js';
|
|
17
|
-
|
|
18
|
-
export function createAdapter(db: NodePgDatabase): AuthAdapter {
|
|
19
|
-
if (!db) {
|
|
20
|
-
throw new AuthError(
|
|
21
|
-
'CONFIGURATION_ERROR',
|
|
22
|
-
'createAdapter requires a Drizzle db instance. Did you forget to pass it?\n' +
|
|
23
|
-
'Example: createAdapter(db)',
|
|
24
|
-
);
|
|
25
|
-
}
|
|
26
|
-
return {
|
|
27
|
-
user: {
|
|
28
|
-
async findByIdentifier(identifier) {
|
|
29
|
-
const rows = await db
|
|
30
|
-
.select({
|
|
31
|
-
id: users.id,
|
|
32
|
-
identifier: users.identifier,
|
|
33
|
-
passwordHash: users.passwordHash,
|
|
34
|
-
roleName: roles.name,
|
|
35
|
-
})
|
|
36
|
-
.from(users)
|
|
37
|
-
.leftJoin(userRoles, eq(users.id, userRoles.userId))
|
|
38
|
-
.leftJoin(roles, eq(userRoles.roleId, roles.id))
|
|
39
|
-
.where(eq(users.identifier, identifier));
|
|
40
|
-
|
|
41
|
-
if (rows.length === 0) return null;
|
|
42
|
-
return {
|
|
43
|
-
id: rows[0]!.id,
|
|
44
|
-
identifier: rows[0]!.identifier,
|
|
45
|
-
passwordHash: rows[0]!.passwordHash,
|
|
46
|
-
roles: rows.flatMap((row) => (row.roleName ? [row.roleName] : [])),
|
|
47
|
-
};
|
|
48
|
-
},
|
|
49
|
-
|
|
50
|
-
async findById(id) {
|
|
51
|
-
const rows = await db
|
|
52
|
-
.select({
|
|
53
|
-
id: users.id,
|
|
54
|
-
identifier: users.identifier,
|
|
55
|
-
passwordHash: users.passwordHash,
|
|
56
|
-
roleName: roles.name,
|
|
57
|
-
})
|
|
58
|
-
.from(users)
|
|
59
|
-
.leftJoin(userRoles, eq(users.id, userRoles.userId))
|
|
60
|
-
.leftJoin(roles, eq(userRoles.roleId, roles.id))
|
|
61
|
-
.where(eq(users.id, id));
|
|
62
|
-
|
|
63
|
-
if (rows.length === 0) return null;
|
|
64
|
-
return {
|
|
65
|
-
id: rows[0]!.id,
|
|
66
|
-
identifier: rows[0]!.identifier,
|
|
67
|
-
passwordHash: rows[0]!.passwordHash,
|
|
68
|
-
roles: rows.flatMap((row) => (row.roleName ? [row.roleName] : [])),
|
|
69
|
-
};
|
|
70
|
-
},
|
|
71
|
-
|
|
72
|
-
async create({ identifier, passwordHash, roles: roleNames }) {
|
|
73
|
-
const [user] = await db
|
|
74
|
-
.insert(users)
|
|
75
|
-
.values({ identifier, passwordHash })
|
|
76
|
-
.returning({ id: users.id });
|
|
77
|
-
|
|
78
|
-
if (roleNames.length > 0) {
|
|
79
|
-
await Promise.all(
|
|
80
|
-
roleNames.map(async (name) => {
|
|
81
|
-
const existing = await db.select().from(roles).where(eq(roles.name, name));
|
|
82
|
-
const role = existing[0] ?? (await db.insert(roles).values({ name }).returning())[0];
|
|
83
|
-
await db.insert(userRoles).values({ userId: user!.id, roleId: role!.id });
|
|
84
|
-
}),
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
return { id: user!.id };
|
|
88
|
-
},
|
|
89
|
-
|
|
90
|
-
async updateRoles(userId, roleNames) {
|
|
91
|
-
await db.delete(userRoles).where(eq(userRoles.userId, userId));
|
|
92
|
-
await Promise.all(
|
|
93
|
-
roleNames.map(async (name) => {
|
|
94
|
-
const existing = await db.select().from(roles).where(eq(roles.name, name));
|
|
95
|
-
const role = existing[0] ?? (await db.insert(roles).values({ name }).returning())[0];
|
|
96
|
-
await db.insert(userRoles).values({ userId, roleId: role!.id });
|
|
97
|
-
}),
|
|
98
|
-
);
|
|
99
|
-
},
|
|
100
|
-
},
|
|
101
|
-
|
|
102
|
-
session: {
|
|
103
|
-
async create({ userId, expiresAt }) {
|
|
104
|
-
const [session] = await db
|
|
105
|
-
.insert(sessions)
|
|
106
|
-
.values({ userId, expiresAt })
|
|
107
|
-
.returning({ id: sessions.id });
|
|
108
|
-
return { id: session!.id };
|
|
109
|
-
},
|
|
110
|
-
|
|
111
|
-
async findById(sessionId) {
|
|
112
|
-
const rows = await db
|
|
113
|
-
.select({
|
|
114
|
-
sessionId: sessions.id,
|
|
115
|
-
sessionUserId: sessions.userId,
|
|
116
|
-
sessionExpiresAt: sessions.expiresAt,
|
|
117
|
-
sessionCreatedAt: sessions.createdAt,
|
|
118
|
-
userId: users.id,
|
|
119
|
-
identifier: users.identifier,
|
|
120
|
-
passwordHash: users.passwordHash,
|
|
121
|
-
roleName: roles.name,
|
|
122
|
-
})
|
|
123
|
-
.from(sessions)
|
|
124
|
-
.innerJoin(users, eq(sessions.userId, users.id))
|
|
125
|
-
.leftJoin(userRoles, eq(users.id, userRoles.userId))
|
|
126
|
-
.leftJoin(roles, eq(userRoles.roleId, roles.id))
|
|
127
|
-
.where(eq(sessions.id, sessionId));
|
|
128
|
-
|
|
129
|
-
if (rows.length === 0) return null;
|
|
130
|
-
const first = rows[0]!;
|
|
131
|
-
return {
|
|
132
|
-
id: first.sessionId,
|
|
133
|
-
userId: first.sessionUserId,
|
|
134
|
-
expiresAt: first.sessionExpiresAt,
|
|
135
|
-
createdAt: first.sessionCreatedAt,
|
|
136
|
-
user: {
|
|
137
|
-
id: first.userId,
|
|
138
|
-
identifier: first.identifier,
|
|
139
|
-
passwordHash: first.passwordHash,
|
|
140
|
-
roles: rows.flatMap((row) => (row.roleName ? [row.roleName] : [])),
|
|
141
|
-
},
|
|
142
|
-
};
|
|
143
|
-
},
|
|
144
|
-
|
|
145
|
-
async delete(sessionId) {
|
|
146
|
-
await db.delete(sessions).where(eq(sessions.id, sessionId));
|
|
147
|
-
},
|
|
148
|
-
|
|
149
|
-
async deleteAllForUser(userId) {
|
|
150
|
-
await db.delete(sessions).where(eq(sessions.userId, userId));
|
|
151
|
-
},
|
|
152
|
-
},
|
|
153
|
-
};
|
|
154
|
-
}
|