sentri 1.0.4 → 1.0.6
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 +314 -860
- package/dist/cli.js +79 -26
- package/dist/cli.js.map +1 -1
- package/dist/client.d.ts +34 -69
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +0 -6
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/libs/config.d.ts +45 -1
- package/dist/libs/config.d.ts.map +1 -1
- package/dist/libs/config.js +40 -2
- package/dist/libs/config.js.map +1 -1
- package/dist/libs/hash.d.ts +14 -0
- package/dist/libs/hash.d.ts.map +1 -1
- package/dist/libs/hash.js +14 -0
- package/dist/libs/hash.js.map +1 -1
- package/dist/libs/token.d.ts +37 -0
- package/dist/libs/token.d.ts.map +1 -1
- package/dist/libs/token.js +63 -0
- package/dist/libs/token.js.map +1 -1
- package/dist/middleware/authorize.d.ts +15 -0
- package/dist/middleware/authorize.d.ts.map +1 -1
- package/dist/middleware/authorize.js +18 -3
- package/dist/middleware/authorize.js.map +1 -1
- package/dist/middleware/permit.d.ts +8 -8
- package/dist/middleware/permit.d.ts.map +1 -1
- package/dist/middleware/permit.js +10 -10
- package/dist/middleware/permit.js.map +1 -1
- package/dist/middleware/protect.d.ts +17 -0
- package/dist/middleware/protect.d.ts.map +1 -1
- package/dist/middleware/protect.js +22 -5
- package/dist/middleware/protect.js.map +1 -1
- package/dist/middleware/router.d.ts +10 -6
- package/dist/middleware/router.d.ts.map +1 -1
- package/dist/middleware/router.js +122 -124
- package/dist/middleware/router.js.map +1 -1
- package/dist/services/auth.d.ts +78 -2
- package/dist/services/auth.d.ts.map +1 -1
- package/dist/services/auth.js +90 -5
- package/dist/services/auth.js.map +1 -1
- package/dist/types/auth.d.ts +176 -2
- package/dist/types/auth.d.ts.map +1 -1
- package/dist/types/auth.js +20 -1
- package/dist/types/auth.js.map +1 -1
- package/package.json +11 -3
- package/templates/drizzle/adapter.ts +154 -0
- package/templates/drizzle/auth.ts +47 -0
- package/templates/drizzle/schema.ts +47 -0
- package/templates/prisma/adapter.ts +122 -0
- package/templates/prisma/auth.ts +50 -0
- /package/templates/{schema.prisma → prisma/schema.prisma} +0 -0
package/dist/cli.js
CHANGED
|
@@ -1,44 +1,97 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { existsSync, copyFileSync, mkdirSync } from 'fs';
|
|
2
|
+
import { existsSync, copyFileSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
3
3
|
import { join, dirname } from 'path';
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
5
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
-
const COMMANDS = ['
|
|
6
|
+
const COMMANDS = ['generate'];
|
|
7
|
+
const ORMS = ['prisma', 'drizzle'];
|
|
7
8
|
function help() {
|
|
8
9
|
console.log(`
|
|
9
10
|
sentri — auth/authorization library for Express
|
|
10
11
|
|
|
11
12
|
Usage:
|
|
12
|
-
npx sentri <command>
|
|
13
|
+
npx sentri <command> [options]
|
|
13
14
|
|
|
14
15
|
Commands:
|
|
15
|
-
|
|
16
|
+
generate <prisma|drizzle>
|
|
17
|
+
Generate adapter, auth config, and schema templates
|
|
18
|
+
in src/lib/sentri/ and create a barrel at src/lib/index.ts
|
|
16
19
|
`);
|
|
17
20
|
}
|
|
18
|
-
function
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
function generateSchemaFile(templatePath, destination, firstLinePrefix, label) {
|
|
22
|
+
if (!existsSync(templatePath))
|
|
23
|
+
return;
|
|
24
|
+
mkdirSync(dirname(destination), { recursive: true });
|
|
25
|
+
if (!existsSync(destination)) {
|
|
26
|
+
copyFileSync(templatePath, destination);
|
|
27
|
+
console.log(`Created ${label}`);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
const templateContent = readFileSync(templatePath, 'utf-8');
|
|
31
|
+
const lines = templateContent.split('\n');
|
|
32
|
+
const firstLine = lines.findIndex((line) => line.startsWith(firstLinePrefix));
|
|
33
|
+
if (firstLine !== -1) {
|
|
34
|
+
const block = lines.slice(firstLine).join('\n').trimEnd();
|
|
35
|
+
const existing = readFileSync(destination, 'utf-8');
|
|
36
|
+
writeFileSync(destination, existing.trimEnd() + '\n\n' + block + '\n');
|
|
37
|
+
console.log(`Updated ${label} (tables appended)`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function generate(orm) {
|
|
42
|
+
if (!orm || !ORMS.includes(orm)) {
|
|
43
|
+
console.error(`Error: specify an ORM — usage: sentri generate <${ORMS.join('|')}>`);
|
|
23
44
|
process.exit(1);
|
|
24
45
|
}
|
|
25
|
-
|
|
26
|
-
|
|
46
|
+
const templateDirectory = join(__dirname, '..', 'templates', orm);
|
|
47
|
+
const destinationDirectory = join(process.cwd(), 'src', 'lib', 'sentri');
|
|
48
|
+
const adapterDestination = join(destinationDirectory, 'adapter.ts');
|
|
49
|
+
const authDestination = join(destinationDirectory, 'auth.ts');
|
|
50
|
+
const barrelDestination = join(process.cwd(), 'src', 'lib', 'index.ts');
|
|
51
|
+
if (!existsSync(templateDirectory)) {
|
|
52
|
+
console.error(`Error: templates for "${orm}" not found. Try reinstalling sentri.`);
|
|
27
53
|
process.exit(1);
|
|
28
54
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
55
|
+
if (existsSync(adapterDestination) || existsSync(authDestination)) {
|
|
56
|
+
console.error('Error: files already exist in src/lib/sentri/. Remove them first if you want to regenerate.');
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
mkdirSync(destinationDirectory, { recursive: true });
|
|
60
|
+
copyFileSync(join(templateDirectory, 'adapter.ts'), adapterDestination);
|
|
61
|
+
copyFileSync(join(templateDirectory, 'auth.ts'), authDestination);
|
|
62
|
+
console.log('Created src/lib/sentri/adapter.ts');
|
|
63
|
+
console.log('Created src/lib/sentri/auth.ts');
|
|
64
|
+
if (orm === 'prisma') {
|
|
65
|
+
generateSchemaFile(join(__dirname, '..', 'templates', 'prisma', 'schema.prisma'), join(process.cwd(), 'prisma', 'schema.prisma'), 'model ', 'prisma/schema.prisma');
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
generateSchemaFile(join(templateDirectory, 'schema.ts'), join(destinationDirectory, 'schema.ts'), 'export ', 'src/lib/sentri/schema.ts');
|
|
69
|
+
}
|
|
70
|
+
if (!existsSync(barrelDestination)) {
|
|
71
|
+
mkdirSync(dirname(barrelDestination), { recursive: true });
|
|
72
|
+
writeFileSync(barrelDestination, "export { createAdapter } from './sentri/adapter.js';\nexport { auth } from './sentri/auth.js';\n");
|
|
73
|
+
console.log('Created src/lib/index.ts');
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
console.log('Skipped src/lib/index.ts (already exists)');
|
|
77
|
+
}
|
|
78
|
+
console.log('');
|
|
79
|
+
console.log('Next steps:');
|
|
80
|
+
if (orm === 'prisma') {
|
|
81
|
+
console.log(' 1. Edit prisma/schema.prisma — change @map("email") to match your column name');
|
|
82
|
+
console.log(' 2. Set DATABASE_URL and JWT_SECRET in your .env file');
|
|
83
|
+
console.log(' 3. Run: npx prisma migrate dev && npx prisma generate');
|
|
84
|
+
console.log(' 4. Edit src/lib/sentri/auth.ts — update validRoles to match your app');
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
console.log(' 1. Edit src/lib/sentri/schema.ts — change text(\'email\') to match your column name');
|
|
88
|
+
console.log(' 2. Edit src/lib/sentri/auth.ts — update validRoles to match your app');
|
|
89
|
+
console.log(' 3. Set JWT_SECRET in your .env file');
|
|
90
|
+
}
|
|
91
|
+
console.log(' Mount the router in your Express app:');
|
|
92
|
+
console.log(" import { auth } from './lib/sentri/auth.js';");
|
|
93
|
+
console.log(" app.use('/auth', auth.router());");
|
|
94
|
+
console.log('');
|
|
42
95
|
}
|
|
43
96
|
const [, , command, ...args] = process.argv;
|
|
44
97
|
if (!command || command === '--help' || command === '-h') {
|
|
@@ -54,6 +107,6 @@ if (args.includes('--help') || args.includes('-h')) {
|
|
|
54
107
|
help();
|
|
55
108
|
process.exit(0);
|
|
56
109
|
}
|
|
57
|
-
if (command === '
|
|
58
|
-
|
|
110
|
+
if (command === 'generate')
|
|
111
|
+
generate(args[0]);
|
|
59
112
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PermitCheck, PermitOptions } from './middleware/permit.js';
|
|
2
|
-
import type { AuthConfig,
|
|
2
|
+
import type { AuthConfig, AuthUser } from './types/auth.js';
|
|
3
3
|
import type { RequestHandler, Router } from 'express';
|
|
4
4
|
/**
|
|
5
5
|
* The bound auth client returned by {@link createAuth}.
|
|
@@ -8,46 +8,9 @@ import type { RequestHandler, Router } from 'express';
|
|
|
8
8
|
* you never need to pass config around yourself.
|
|
9
9
|
*
|
|
10
10
|
* `TRole` is inferred from `validRoles` and narrows role strings to your
|
|
11
|
-
* application's exact union type everywhere (
|
|
11
|
+
* application's exact union type everywhere (authorize, req.user, etc.).
|
|
12
12
|
*/
|
|
13
13
|
export interface AuthClient<TRole extends string = string> {
|
|
14
|
-
/**
|
|
15
|
-
* Register a new user.
|
|
16
|
-
*
|
|
17
|
-
* Validates that every requested role is in `validRoles`, rejects duplicate
|
|
18
|
-
* emails, hashes the password, creates the user record, and returns a fresh
|
|
19
|
-
* access + refresh token pair.
|
|
20
|
-
*/
|
|
21
|
-
signup(input: SignupInput<TRole>): Promise<AuthResult<TRole>>;
|
|
22
|
-
/**
|
|
23
|
-
* Authenticate an existing user by email and password.
|
|
24
|
-
*
|
|
25
|
-
* On success, creates a new session and returns an access + refresh token pair.
|
|
26
|
-
* Returns `{ success: false, error }` with code `INVALID_CREDENTIALS` on any
|
|
27
|
-
* mismatch (intentionally vague to prevent user enumeration).
|
|
28
|
-
*/
|
|
29
|
-
login(input: LoginInput): Promise<AuthResult<TRole>>;
|
|
30
|
-
/**
|
|
31
|
-
* Exchange a valid refresh token for a new access + refresh token pair.
|
|
32
|
-
*
|
|
33
|
-
* Verifies the JWT, looks up the session in the database, checks expiry,
|
|
34
|
-
* then **rotates** the session: the old session is deleted and a new one is
|
|
35
|
-
* created. Old refresh tokens are immediately invalidated.
|
|
36
|
-
*/
|
|
37
|
-
refresh(refreshToken: string): Promise<RefreshResult<TRole>>;
|
|
38
|
-
/**
|
|
39
|
-
* Invalidate a single session identified by the refresh token.
|
|
40
|
-
*
|
|
41
|
-
* Safe to call even if the token is already expired — it will simply
|
|
42
|
-
* attempt a DB delete and resolve.
|
|
43
|
-
*/
|
|
44
|
-
logout(refreshToken: string): Promise<void>;
|
|
45
|
-
/**
|
|
46
|
-
* Delete all sessions for a user, effectively logging them out of every device.
|
|
47
|
-
*
|
|
48
|
-
* @param userId - The user's primary key as stored in the database.
|
|
49
|
-
*/
|
|
50
|
-
logoutAll(userId: string): Promise<void>;
|
|
51
14
|
/**
|
|
52
15
|
* Express middleware factory that enforces authentication.
|
|
53
16
|
*
|
|
@@ -71,36 +34,6 @@ export interface AuthClient<TRole extends string = string> {
|
|
|
71
34
|
* router.delete('/posts/:id', auth.protect(), auth.authorize('admin'), handler);
|
|
72
35
|
*/
|
|
73
36
|
authorize(...roles: TRole[]): RequestHandler;
|
|
74
|
-
/** Hash a plain-text password using the configured `saltRounds`. */
|
|
75
|
-
hashPassword(plain: string): Promise<string>;
|
|
76
|
-
/** Compare a plain-text password against a stored bcrypt hash. */
|
|
77
|
-
verifyPassword(plain: string, hash: string): Promise<boolean>;
|
|
78
|
-
/** Sign an access token for the given user payload. */
|
|
79
|
-
signAccessToken(payload: AuthUser<TRole>): string;
|
|
80
|
-
/** Sign a refresh token bound to a session ID. */
|
|
81
|
-
signRefreshToken(sessionId: string): string;
|
|
82
|
-
/** Verify and decode an access token. Throws `AuthError` if invalid or expired. */
|
|
83
|
-
verifyAccessToken(token: string): AuthUser<TRole>;
|
|
84
|
-
/** Verify and decode a refresh token. Throws `AuthError` if invalid or expired. */
|
|
85
|
-
verifyRefreshToken(token: string): {
|
|
86
|
-
sessionId: string;
|
|
87
|
-
};
|
|
88
|
-
/**
|
|
89
|
-
* Returns a pre-built Express Router with all standard auth endpoints mounted:
|
|
90
|
-
*
|
|
91
|
-
* - `POST /signup` — register, returns `{ accessToken, refreshToken, user }`
|
|
92
|
-
* - `POST /login` — authenticate, returns `{ accessToken, refreshToken, user }`
|
|
93
|
-
* - `POST /refresh` — rotate refresh token, returns `{ accessToken, refreshToken }`
|
|
94
|
-
* - `POST /logout` — invalidate current session
|
|
95
|
-
* - `POST /logout-all` — invalidate all sessions (requires valid access token)
|
|
96
|
-
*
|
|
97
|
-
* Requires `express.json()` to be applied before the router.
|
|
98
|
-
*
|
|
99
|
-
* @example
|
|
100
|
-
* app.use(express.json());
|
|
101
|
-
* app.use('/auth', auth.router());
|
|
102
|
-
*/
|
|
103
|
-
router(): Router;
|
|
104
37
|
/**
|
|
105
38
|
* Express middleware factory for resource-level permission checks.
|
|
106
39
|
*
|
|
@@ -134,6 +67,38 @@ export interface AuthClient<TRole extends string = string> {
|
|
|
134
67
|
*/
|
|
135
68
|
permit(check: PermitCheck): RequestHandler;
|
|
136
69
|
permit(options: PermitOptions<TRole>): RequestHandler;
|
|
70
|
+
/** Hash a plain-text password using the configured `saltRounds`. */
|
|
71
|
+
hashPassword(plain: string): Promise<string>;
|
|
72
|
+
/** Compare a plain-text password against a stored bcrypt hash. */
|
|
73
|
+
verifyPassword(plain: string, hash: string): Promise<boolean>;
|
|
74
|
+
/** Sign an access token for the given user payload. */
|
|
75
|
+
signAccessToken(payload: AuthUser<TRole>): string;
|
|
76
|
+
/** Sign a refresh token bound to a session ID. */
|
|
77
|
+
signRefreshToken(sessionId: string): string;
|
|
78
|
+
/** Verify and decode an access token. Throws `AuthError` if invalid or expired. */
|
|
79
|
+
verifyAccessToken(token: string): AuthUser<TRole>;
|
|
80
|
+
/** Verify and decode a refresh token. Throws `AuthError` if invalid or expired. */
|
|
81
|
+
verifyRefreshToken(token: string): {
|
|
82
|
+
sessionId: string;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Returns a pre-built Express Router with all standard auth endpoints mounted:
|
|
86
|
+
*
|
|
87
|
+
* - `POST /signup` — register a user, returns `{ user }`
|
|
88
|
+
* - `POST /login` — authenticate, sets refresh token cookie, returns `{ accessToken, user }`
|
|
89
|
+
* - `POST /refresh` — reads refresh token from cookie, returns `{ accessToken }`
|
|
90
|
+
* - `POST /logout` — invalidate current session
|
|
91
|
+
* - `POST /logout-all` — invalidate all sessions (requires valid access token)
|
|
92
|
+
* - `GET /me` — return the authenticated user
|
|
93
|
+
* - `POST /users/:userId/roles` — assign roles (requires admin)
|
|
94
|
+
*
|
|
95
|
+
* Requires `express.json()` to be applied before the router.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* app.use(express.json());
|
|
99
|
+
* app.use('/auth', auth.router());
|
|
100
|
+
*/
|
|
101
|
+
router(): Router;
|
|
137
102
|
}
|
|
138
103
|
/**
|
|
139
104
|
* Create a fully configured auth client for your application.
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEtD;;;;;;;;GAQG;AACH,MAAM,WAAW,UAAU,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM;IACvD;;;;;;;;;;OAUG;IACH,OAAO,IAAI,cAAc,CAAC;IAE1B;;;;;;;;;OASG;IACH,SAAS,CAAC,GAAG,KAAK,EAAE,KAAK,EAAE,GAAG,cAAc,CAAC;IAE7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACH,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,cAAc,CAAC;IAC3C,MAAM,CAAC,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,GAAG,cAAc,CAAC;IAEtD,oEAAoE;IACpE,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE7C,kEAAkE;IAClE,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAE9D,uDAAuD;IACvD,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC;IAElD,kDAAkD;IAClD,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAE5C,mFAAmF;IACnF,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAElD,mFAAmF;IACnF,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAEzD;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,IAAI,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,UAAU,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,EACtD,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC,GACxB,UAAU,CAAC,KAAK,CAAC,CAgBnB"}
|
package/dist/client.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { hashPassword, verifyPassword } from './libs/hash.js';
|
|
2
2
|
import { signAccessToken, signRefreshToken, verifyAccessToken, verifyRefreshToken } from './libs/token.js';
|
|
3
3
|
import { resolveConfig, validateConfig } from './libs/config.js';
|
|
4
|
-
import { signup, login, refresh, logout, logoutAll } from './services/auth.js';
|
|
5
4
|
import { protect } from './middleware/protect.js';
|
|
6
5
|
import { authorize } from './middleware/authorize.js';
|
|
7
6
|
import { permit } from './middleware/permit.js';
|
|
@@ -29,11 +28,6 @@ export function createAuth(config) {
|
|
|
29
28
|
validateConfig(config);
|
|
30
29
|
const resolved = resolveConfig(config);
|
|
31
30
|
return {
|
|
32
|
-
signup: (input) => signup(input, config),
|
|
33
|
-
login: (input) => login(input, config),
|
|
34
|
-
refresh: (refreshToken) => refresh(refreshToken, config),
|
|
35
|
-
logout: (refreshToken) => logout(refreshToken, config),
|
|
36
|
-
logoutAll: (userId) => logoutAll(userId, config),
|
|
37
31
|
protect: () => protect(config),
|
|
38
32
|
authorize: (...roles) => authorize(...roles),
|
|
39
33
|
hashPassword: (plain) => hashPassword(plain, resolved.saltRounds),
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC3G,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC3G,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAgH1D;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,UAAU,CACxB,MAAyB;IAEzB,cAAc,CAAC,MAAoB,CAAC,CAAC;IACrC,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAoB,CAAC,CAAC;IAErD,OAAO;QACL,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAoB,CAAC;QAC5C,SAAS,EAAE,CAAC,GAAG,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC;QAC5C,YAAY,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC;QACjE,cAAc,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC;QAC5D,eAAe,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,eAAe,CAAC,OAAmB,EAAE,MAAoB,CAAC;QACxF,gBAAgB,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,gBAAgB,CAAC,SAAS,EAAE,MAAoB,CAAC;QAClF,iBAAiB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,iBAAiB,CAAC,KAAK,EAAE,MAAoB,CAAoB;QAC/F,kBAAkB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,kBAAkB,CAAC,KAAK,EAAE,MAAoB,CAAC;QAC9E,MAAM,EAAE,GAAG,EAAE,CAAC,gBAAgB,CAAC,MAAM,CAAC;QACtC,MAAM,EAAE,CAAC,cAAkD,EAAE,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;KACvF,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ declare global {
|
|
|
6
6
|
}
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
|
-
export type { AuthConfig, CookieConfig, AuthUser,
|
|
9
|
+
export type { AuthConfig, CookieConfig, AuthUser, ApiResponse, AuthAdapter, UserRecord, SessionRecord, CreateUserData, RouterHandlers, SignupInput, LoginInput, SignupResult, AuthResult, RefreshResult, AssignRolesResult, } from './types/auth.js';
|
|
10
10
|
export type { AuthErrorCode } from './errors/AuthError.js';
|
|
11
11
|
export type { AuthClient } from './client.js';
|
|
12
12
|
export { AuthError } from './errors/AuthError.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAIhD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,UAAU,OAAO;YACf,IAAI,CAAC,EAAE,QAAQ,CAAC;SACjB;KACF;CACF;AAED,YAAY,EACV,UAAU,EACV,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,aAAa,EACb,WAAW,EACX,UAAU,EACV,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAIhD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,UAAU,OAAO;YACf,IAAI,CAAC,EAAE,QAAQ,CAAC;SACjB;KACF;CACF;AAED,YAAY,EACV,UAAU,EACV,YAAY,EACZ,QAAQ,EACR,WAAW,EACX,WAAW,EACX,UAAU,EACV,aAAa,EACb,cAAc,EACd,cAAc,EACd,WAAW,EACX,UAAU,EACV,YAAY,EACZ,UAAU,EACV,aAAa,EACb,iBAAiB,GAClB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC"}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAgCA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/libs/config.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { AuthAdapter, AuthConfig } from '../types/auth.js';
|
|
2
|
+
/**
|
|
3
|
+
* Fully-resolved configuration with all optional fields filled in by
|
|
4
|
+
* their defaults. Produced by {@link resolveConfig} and used internally
|
|
5
|
+
* wherever the library needs guaranteed values.
|
|
6
|
+
*/
|
|
2
7
|
export interface ResolvedConfig {
|
|
3
8
|
secret: string;
|
|
4
9
|
accessExpiresIn: string | number;
|
|
@@ -9,10 +14,49 @@ export interface ResolvedConfig {
|
|
|
9
14
|
adapter: AuthAdapter;
|
|
10
15
|
}
|
|
11
16
|
/**
|
|
12
|
-
*
|
|
17
|
+
* Validate configuration at startup so misconfiguration is caught immediately,
|
|
13
18
|
* not at the first login attempt.
|
|
19
|
+
*
|
|
20
|
+
* Throws {@link AuthError} with code `CONFIGURATION_ERROR` for any of:
|
|
21
|
+
* - `secret` missing or shorter than 32 characters
|
|
22
|
+
* - `saltRounds` outside the range 10–31
|
|
23
|
+
* - `validRoles` is empty or missing
|
|
24
|
+
* - `adapter` is missing
|
|
25
|
+
*
|
|
26
|
+
* @param config - The raw config passed to {@link createAuth}.
|
|
27
|
+
* @throws {AuthError} With code `CONFIGURATION_ERROR` on any invalid field.
|
|
14
28
|
*/
|
|
15
29
|
export declare function validateConfig(config: AuthConfig): void;
|
|
30
|
+
/**
|
|
31
|
+
* Merge a partial {@link AuthConfig} with library defaults and return a
|
|
32
|
+
* fully-resolved configuration object.
|
|
33
|
+
*
|
|
34
|
+
* Does **not** validate the config — call {@link validateConfig} first.
|
|
35
|
+
*
|
|
36
|
+
* Defaults applied:
|
|
37
|
+
* - `accessExpiresIn` → `'15m'`
|
|
38
|
+
* - `refreshExpiresIn` → `'7d'`
|
|
39
|
+
* - `algorithm` → `'HS256'`
|
|
40
|
+
* - `saltRounds` → `12`
|
|
41
|
+
*
|
|
42
|
+
* @param partial - The raw config passed to {@link createAuth}.
|
|
43
|
+
* @returns A {@link ResolvedConfig} with every field guaranteed to be present.
|
|
44
|
+
*/
|
|
16
45
|
export declare function resolveConfig(partial: AuthConfig): ResolvedConfig;
|
|
46
|
+
/**
|
|
47
|
+
* Convert a duration string or a number of seconds into milliseconds.
|
|
48
|
+
*
|
|
49
|
+
* Supported unit suffixes: `s` (seconds), `m` (minutes), `h` (hours),
|
|
50
|
+
* `d` (days), `w` (weeks). Numeric inputs are treated as seconds.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* parseExpiry('15m') // 900_000
|
|
54
|
+
* parseExpiry('7d') // 604_800_000
|
|
55
|
+
* parseExpiry(60) // 60_000
|
|
56
|
+
*
|
|
57
|
+
* @param expiresIn - A duration string (e.g. `'15m'`, `'7d'`) or a number of seconds.
|
|
58
|
+
* @returns The equivalent duration in milliseconds.
|
|
59
|
+
* @throws {Error} If the string format is unrecognised.
|
|
60
|
+
*/
|
|
17
61
|
export declare function parseExpiry(expiresIn: string | number): number;
|
|
18
62
|
//# sourceMappingURL=config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/libs/config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEhE,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAAC;IAClC,SAAS,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,OAAO,EAAE,WAAW,CAAC;CACtB;AAMD
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/libs/config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEhE;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAAC;IAClC,SAAS,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,OAAO,EAAE,WAAW,CAAC;CACtB;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CA0BvD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,UAAU,GAAG,cAAc,CAUjE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAkB9D"}
|
package/dist/libs/config.js
CHANGED
|
@@ -3,8 +3,17 @@ const MIN_SECRET_LENGTH = 32;
|
|
|
3
3
|
const MIN_SALT_ROUNDS = 10;
|
|
4
4
|
const MAX_SALT_ROUNDS = 31;
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Validate configuration at startup so misconfiguration is caught immediately,
|
|
7
7
|
* not at the first login attempt.
|
|
8
|
+
*
|
|
9
|
+
* Throws {@link AuthError} with code `CONFIGURATION_ERROR` for any of:
|
|
10
|
+
* - `secret` missing or shorter than 32 characters
|
|
11
|
+
* - `saltRounds` outside the range 10–31
|
|
12
|
+
* - `validRoles` is empty or missing
|
|
13
|
+
* - `adapter` is missing
|
|
14
|
+
*
|
|
15
|
+
* @param config - The raw config passed to {@link createAuth}.
|
|
16
|
+
* @throws {AuthError} With code `CONFIGURATION_ERROR` on any invalid field.
|
|
8
17
|
*/
|
|
9
18
|
export function validateConfig(config) {
|
|
10
19
|
if (!config.secret || config.secret.trim().length === 0) {
|
|
@@ -24,6 +33,21 @@ export function validateConfig(config) {
|
|
|
24
33
|
throw new AuthError('CONFIGURATION_ERROR', 'adapter is required');
|
|
25
34
|
}
|
|
26
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Merge a partial {@link AuthConfig} with library defaults and return a
|
|
38
|
+
* fully-resolved configuration object.
|
|
39
|
+
*
|
|
40
|
+
* Does **not** validate the config — call {@link validateConfig} first.
|
|
41
|
+
*
|
|
42
|
+
* Defaults applied:
|
|
43
|
+
* - `accessExpiresIn` → `'15m'`
|
|
44
|
+
* - `refreshExpiresIn` → `'7d'`
|
|
45
|
+
* - `algorithm` → `'HS256'`
|
|
46
|
+
* - `saltRounds` → `12`
|
|
47
|
+
*
|
|
48
|
+
* @param partial - The raw config passed to {@link createAuth}.
|
|
49
|
+
* @returns A {@link ResolvedConfig} with every field guaranteed to be present.
|
|
50
|
+
*/
|
|
27
51
|
export function resolveConfig(partial) {
|
|
28
52
|
return {
|
|
29
53
|
secret: partial.secret,
|
|
@@ -35,7 +59,21 @@ export function resolveConfig(partial) {
|
|
|
35
59
|
adapter: partial.adapter,
|
|
36
60
|
};
|
|
37
61
|
}
|
|
38
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Convert a duration string or a number of seconds into milliseconds.
|
|
64
|
+
*
|
|
65
|
+
* Supported unit suffixes: `s` (seconds), `m` (minutes), `h` (hours),
|
|
66
|
+
* `d` (days), `w` (weeks). Numeric inputs are treated as seconds.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* parseExpiry('15m') // 900_000
|
|
70
|
+
* parseExpiry('7d') // 604_800_000
|
|
71
|
+
* parseExpiry(60) // 60_000
|
|
72
|
+
*
|
|
73
|
+
* @param expiresIn - A duration string (e.g. `'15m'`, `'7d'`) or a number of seconds.
|
|
74
|
+
* @returns The equivalent duration in milliseconds.
|
|
75
|
+
* @throws {Error} If the string format is unrecognised.
|
|
76
|
+
*/
|
|
39
77
|
export function parseExpiry(expiresIn) {
|
|
40
78
|
if (typeof expiresIn === 'number')
|
|
41
79
|
return expiresIn * 1000;
|
package/dist/libs/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/libs/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/libs/config.ts"],"names":[],"mappings":"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"}
|
package/dist/libs/hash.d.ts
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hash a plain-text password using bcrypt.
|
|
3
|
+
*
|
|
4
|
+
* @param plain - The raw password string supplied by the user.
|
|
5
|
+
* @param saltRounds - bcrypt cost factor; higher values increase security at the cost of speed.
|
|
6
|
+
* @returns The bcrypt hash string to persist in the database.
|
|
7
|
+
*/
|
|
1
8
|
export declare function hashPassword(plain: string, saltRounds?: number): Promise<string>;
|
|
9
|
+
/**
|
|
10
|
+
* Compare a plain-text password against a stored bcrypt hash.
|
|
11
|
+
*
|
|
12
|
+
* @param plain - The raw password string to verify.
|
|
13
|
+
* @param hash - The stored bcrypt hash from the database.
|
|
14
|
+
* @returns `true` if the password matches the hash, `false` otherwise.
|
|
15
|
+
*/
|
|
2
16
|
export declare function verifyPassword(plain: string, hash: string): Promise<boolean>;
|
|
3
17
|
//# sourceMappingURL=hash.d.ts.map
|
package/dist/libs/hash.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/libs/hash.ts"],"names":[],"mappings":"AAEA,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,SAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAElF;AAED,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAElF"}
|
|
1
|
+
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/libs/hash.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,SAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAElF;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAElF"}
|
package/dist/libs/hash.js
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
import bcrypt from 'bcrypt';
|
|
2
|
+
/**
|
|
3
|
+
* Hash a plain-text password using bcrypt.
|
|
4
|
+
*
|
|
5
|
+
* @param plain - The raw password string supplied by the user.
|
|
6
|
+
* @param saltRounds - bcrypt cost factor; higher values increase security at the cost of speed.
|
|
7
|
+
* @returns The bcrypt hash string to persist in the database.
|
|
8
|
+
*/
|
|
2
9
|
export async function hashPassword(plain, saltRounds = 12) {
|
|
3
10
|
return bcrypt.hash(plain, saltRounds);
|
|
4
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Compare a plain-text password against a stored bcrypt hash.
|
|
14
|
+
*
|
|
15
|
+
* @param plain - The raw password string to verify.
|
|
16
|
+
* @param hash - The stored bcrypt hash from the database.
|
|
17
|
+
* @returns `true` if the password matches the hash, `false` otherwise.
|
|
18
|
+
*/
|
|
5
19
|
export async function verifyPassword(plain, hash) {
|
|
6
20
|
return bcrypt.compare(plain, hash);
|
|
7
21
|
}
|
package/dist/libs/hash.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hash.js","sourceRoot":"","sources":["../../src/libs/hash.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,KAAa,EAAE,UAAU,GAAG,EAAE;IAC/D,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,KAAa,EAAE,IAAY;IAC9D,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AACrC,CAAC"}
|
|
1
|
+
{"version":3,"file":"hash.js","sourceRoot":"","sources":["../../src/libs/hash.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,KAAa,EAAE,UAAU,GAAG,EAAE;IAC/D,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;AACxC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,KAAa,EAAE,IAAY;IAC9D,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AACrC,CAAC"}
|
package/dist/libs/token.d.ts
CHANGED
|
@@ -1,7 +1,44 @@
|
|
|
1
1
|
import type { AuthConfig, AuthUser } from '../types/auth.js';
|
|
2
|
+
/**
|
|
3
|
+
* Sign a short-lived access token containing the user's identity and roles.
|
|
4
|
+
*
|
|
5
|
+
* Uses the access-specific secret derived from config and the configured
|
|
6
|
+
* `accessExpiresIn` duration and HMAC algorithm.
|
|
7
|
+
*
|
|
8
|
+
* @param payload - The {@link AuthUser} payload to embed (id, identifier, roles).
|
|
9
|
+
* @param config - Auth configuration used to derive the secret and options.
|
|
10
|
+
* @returns Compact JWT string.
|
|
11
|
+
*/
|
|
2
12
|
export declare function signAccessToken(payload: AuthUser, config: AuthConfig): string;
|
|
13
|
+
/**
|
|
14
|
+
* Sign a long-lived refresh token bound to a specific session ID.
|
|
15
|
+
*
|
|
16
|
+
* Uses the refresh-specific secret derived from config and the configured
|
|
17
|
+
* `refreshExpiresIn` duration. The session ID is embedded as the sole claim
|
|
18
|
+
* so the token can be used to look up and rotate the session.
|
|
19
|
+
*
|
|
20
|
+
* @param sessionId - The database session ID to bind to this token.
|
|
21
|
+
* @param config - Auth configuration used to derive the secret and options.
|
|
22
|
+
* @returns Compact JWT string.
|
|
23
|
+
*/
|
|
3
24
|
export declare function signRefreshToken(sessionId: string, config: AuthConfig): string;
|
|
25
|
+
/**
|
|
26
|
+
* Verify an access token and return its decoded {@link AuthUser} payload.
|
|
27
|
+
*
|
|
28
|
+
* @param token - Compact JWT access token string.
|
|
29
|
+
* @param config - Auth configuration used to derive the secret and algorithm.
|
|
30
|
+
* @returns Decoded `AuthUser` payload (id, identifier, roles).
|
|
31
|
+
* @throws {AuthError} With `TOKEN_EXPIRED` if expired, `TOKEN_INVALID` otherwise.
|
|
32
|
+
*/
|
|
4
33
|
export declare function verifyAccessToken(token: string, config: AuthConfig): AuthUser;
|
|
34
|
+
/**
|
|
35
|
+
* Verify a refresh token and return the embedded session ID.
|
|
36
|
+
*
|
|
37
|
+
* @param token - Compact JWT refresh token string.
|
|
38
|
+
* @param config - Auth configuration used to derive the secret and algorithm.
|
|
39
|
+
* @returns Object with `sessionId` matching the one passed to {@link signRefreshToken}.
|
|
40
|
+
* @throws {AuthError} With `TOKEN_EXPIRED` if expired, `TOKEN_INVALID` otherwise.
|
|
41
|
+
*/
|
|
5
42
|
export declare function verifyRefreshToken(token: string, config: AuthConfig): {
|
|
6
43
|
sessionId: string;
|
|
7
44
|
};
|
package/dist/libs/token.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../src/libs/token.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../src/libs/token.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAqE7D;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAI7E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAI9E;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,QAAQ,CAI7E;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAI3F"}
|