@volcanicminds/backend 0.2.13 → 0.2.15
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/.dockerignore +3 -2
- package/README.md +22 -2
- package/dist/lib/api/users/controller/user.js +4 -2
- package/dist/lib/api/users/controller/user.js.map +1 -1
- package/dist/lib/hooks/onRequest.js +7 -9
- package/dist/lib/hooks/onRequest.js.map +1 -1
- package/dist/lib/hooks/onResponse.js +2 -3
- package/dist/lib/hooks/onResponse.js.map +1 -1
- package/dist/lib/middleware/isAdmin.js +2 -4
- package/dist/lib/middleware/isAdmin.js.map +1 -1
- package/lib/api/users/controller/user.ts +5 -2
- package/lib/hooks/onRequest.ts +14 -15
- package/lib/hooks/onResponse.ts +2 -2
- package/lib/middleware/isAdmin.ts +2 -3
- package/package.json +2 -2
- package/types/global.d.ts +8 -8
package/.dockerignore
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
.git
|
|
2
|
+
node_modules
|
|
3
|
+
**/node_modules
|
package/README.md
CHANGED
|
@@ -33,6 +33,9 @@ NODE_ENV=development
|
|
|
33
33
|
HOST=0.0.0.0
|
|
34
34
|
PORT=2230
|
|
35
35
|
|
|
36
|
+
JWT_SECRET=yourSecret
|
|
37
|
+
JWT_EXPIRES_IN=5d
|
|
38
|
+
|
|
36
39
|
# LOG_LEVEL: trace, debug, info, warn, error, fatal
|
|
37
40
|
LOG_LEVEL=info
|
|
38
41
|
LOG_COLORIZE=true
|
|
@@ -42,6 +45,7 @@ LOG_FASTIFY=false
|
|
|
42
45
|
|
|
43
46
|
GRAPHQL=false
|
|
44
47
|
SWAGGER=true
|
|
48
|
+
SWAGGER_HOST=myawesome.backend.com
|
|
45
49
|
SWAGGER_TITLE=API Documentation
|
|
46
50
|
SWAGGER_DESCRIPTION=List of available APIs and schemes to use
|
|
47
51
|
SWAGGER_VERSION=0.1.0
|
|
@@ -130,6 +134,17 @@ const logTimestamp = yn(LOG_TIMESTAMP, true)
|
|
|
130
134
|
const logTimestampReadable = yn(LOG_TIMESTAMP_READABLE, true)
|
|
131
135
|
```
|
|
132
136
|
|
|
137
|
+
## Bearer token
|
|
138
|
+
|
|
139
|
+
```ruby
|
|
140
|
+
JWT_SECRET=yourSecret
|
|
141
|
+
JWT_EXPIRES_IN=5d
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
With `reply.jwtSign(user)` is possible obtain a fresh JWT token. Each authenticated calls must be recalled specifying in the header:
|
|
145
|
+
|
|
146
|
+
`Authorization: Bearer <generated-token>`
|
|
147
|
+
|
|
133
148
|
## Swagger
|
|
134
149
|
|
|
135
150
|
In the .env file you can change swagger settings in this way:
|
|
@@ -234,8 +249,13 @@ export async function user(req: FastifyRequest, reply: FastifyReply) {
|
|
|
234
249
|
}
|
|
235
250
|
```
|
|
236
251
|
|
|
237
|
-
|
|
238
|
-
|
|
252
|
+
Useful methods / objects:
|
|
253
|
+
|
|
254
|
+
- `req.user` to grab **user** data (validated and linked by JWT).
|
|
255
|
+
- `req.data()` to grab **query** or **body** parameters.
|
|
256
|
+
- `req.parameters()` to grab **params** data.
|
|
257
|
+
- `req.roles()` to grab **Roles** (as `string[]`) from `req.user` if compiled.
|
|
258
|
+
- `req.hasRole(role:Role)` to check if the **Role** is appliable for `req.user`.
|
|
239
259
|
|
|
240
260
|
## Roles
|
|
241
261
|
|
|
@@ -12,13 +12,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.isAdmin = exports.user = void 0;
|
|
13
13
|
function user(req, reply) {
|
|
14
14
|
return __awaiter(this, void 0, void 0, function* () {
|
|
15
|
-
|
|
15
|
+
const user = req.user;
|
|
16
|
+
reply.send(user ? Object.assign(Object.assign({}, user), { roles: req.roles() }) : {});
|
|
16
17
|
});
|
|
17
18
|
}
|
|
18
19
|
exports.user = user;
|
|
19
20
|
function isAdmin(req, reply) {
|
|
20
21
|
return __awaiter(this, void 0, void 0, function* () {
|
|
21
|
-
|
|
22
|
+
const user = req.user;
|
|
23
|
+
reply.send({ isAdmin: (user === null || user === void 0 ? void 0 : user.id) && req.hasRole(roles.admin) });
|
|
22
24
|
});
|
|
23
25
|
}
|
|
24
26
|
exports.isAdmin = isAdmin;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user.js","sourceRoot":"","sources":["../../../../../lib/api/users/controller/user.ts"],"names":[],"mappings":";;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"user.js","sourceRoot":"","sources":["../../../../../lib/api/users/controller/user.ts"],"names":[],"mappings":";;;;;;;;;;;;AAGA,SAAsB,IAAI,CAAC,GAAmB,EAAE,KAAmB;;QACjE,MAAM,IAAI,GAAkC,GAAG,CAAC,IAAI,CAAA;QACpD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,iCAAM,IAAI,KAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,IAAG,CAAC,CAAC,EAAE,CAAC,CAAA;IACzD,CAAC;CAAA;AAHD,oBAGC;AAED,SAAsB,OAAO,CAAC,GAAmB,EAAE,KAAmB;;QACpE,MAAM,IAAI,GAAkC,GAAG,CAAC,IAAI,CAAA;QACpD,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,EAAE,KAAI,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;IAC/D,CAAC;CAAA;AAHD,0BAGC"}
|
|
@@ -14,7 +14,9 @@ module.exports = (req, reply) => __awaiter(void 0, void 0, void 0, function* ()
|
|
|
14
14
|
var _a, _b, _c, _d;
|
|
15
15
|
log.i && (req.startedAt = new Date());
|
|
16
16
|
req.data = () => (0, common_1.getData)(req);
|
|
17
|
-
req.
|
|
17
|
+
req.parameters = () => (0, common_1.getParams)(req);
|
|
18
|
+
req.roles = () => ((req.user && req.user.roles) || []).map((role) => role === null || role === void 0 ? void 0 : role.code) || [];
|
|
19
|
+
req.hasRole = (r) => ((req.user && req.user.roles) || []).some((role) => (role === null || role === void 0 ? void 0 : role.code) === (r === null || r === void 0 ? void 0 : r.code));
|
|
18
20
|
const auth = ((_a = req.headers) === null || _a === void 0 ? void 0 : _a.authorization) || '';
|
|
19
21
|
const [prefix, token] = auth.split(' ');
|
|
20
22
|
if (prefix === 'Bearer' && token != null) {
|
|
@@ -22,9 +24,9 @@ module.exports = (req, reply) => __awaiter(void 0, void 0, void 0, function* ()
|
|
|
22
24
|
if (global.npmDebugServerStarted) {
|
|
23
25
|
req.user = {
|
|
24
26
|
id: userId || 123,
|
|
25
|
-
name:
|
|
27
|
+
name: name,
|
|
26
28
|
email: 'jerry@george.com',
|
|
27
|
-
password: '
|
|
29
|
+
password: 'seinfeld',
|
|
28
30
|
roles: [roles.public]
|
|
29
31
|
};
|
|
30
32
|
log.debug('Inject demo user ' + req.user.id);
|
|
@@ -32,18 +34,14 @@ module.exports = (req, reply) => __awaiter(void 0, void 0, void 0, function* ()
|
|
|
32
34
|
if (((_b = req.routeConfig.requiredRoles) === null || _b === void 0 ? void 0 : _b.length) > 0) {
|
|
33
35
|
const { method, url, requiredRoles } = req.routeConfig;
|
|
34
36
|
const userRoles = ((_d = (_c = req.user) === null || _c === void 0 ? void 0 : _c.roles) === null || _d === void 0 ? void 0 : _d.map(({ code }) => code)) || [];
|
|
35
|
-
const
|
|
36
|
-
if (!
|
|
37
|
+
const resolvedRoles = userRoles.length > 0 ? requiredRoles.filter((r) => userRoles.includes(r.code)) : [];
|
|
38
|
+
if (!resolvedRoles.length) {
|
|
37
39
|
log.w && log.warn(`Not allowed to call ${method.toUpperCase()} ${url}`);
|
|
38
40
|
return reply
|
|
39
41
|
.code(403)
|
|
40
42
|
.send({ statusCode: 403, code: 'ROLE_NOT_ALLOWED', message: 'Not allowed to call this route' });
|
|
41
43
|
}
|
|
42
44
|
}
|
|
43
|
-
if (req.user) {
|
|
44
|
-
req.user.getRoles = () => (req.user.roles || []).map((role) => role === null || role === void 0 ? void 0 : role.code) || [];
|
|
45
|
-
req.user.hasRole = (r) => (req.user.roles || []).some((role) => (role === null || role === void 0 ? void 0 : role.code) === (r === null || r === void 0 ? void 0 : r.code));
|
|
46
|
-
}
|
|
47
45
|
}
|
|
48
46
|
});
|
|
49
47
|
//# sourceMappingURL=onRequest.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"onRequest.js","sourceRoot":"","sources":["../../../lib/hooks/onRequest.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,2CAAmD;AAGnD,MAAM,CAAC,OAAO,GAAG,CAAO,GAAG,EAAE,KAAK,EAAE,EAAE;;IAEpC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,CAAA;IACrC,GAAG,CAAC,IAAI,GAAG,GAAG,EAAE,CAAC,IAAA,gBAAO,EAAC,GAAG,CAAC,CAAA;IAC7B,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"onRequest.js","sourceRoot":"","sources":["../../../lib/hooks/onRequest.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,10 +9,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
module.exports = (req, reply) => __awaiter(void 0, void 0, void 0, function* () {
|
|
12
|
-
var _a;
|
|
13
12
|
let extraMessage = '';
|
|
14
|
-
if (log.i) {
|
|
15
|
-
const elapsed = new Date().getTime() -
|
|
13
|
+
if (log.i && req.startedAt) {
|
|
14
|
+
const elapsed = new Date().getTime() - req.startedAt.getTime();
|
|
16
15
|
extraMessage = `(${elapsed}ms)`;
|
|
17
16
|
}
|
|
18
17
|
if (log.t) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"onResponse.js","sourceRoot":"","sources":["../../../lib/hooks/onResponse.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,MAAM,CAAC,OAAO,GAAG,CAAO,GAAG,EAAE,KAAK,EAAE,EAAE
|
|
1
|
+
{"version":3,"file":"onResponse.js","sourceRoot":"","sources":["../../../lib/hooks/onResponse.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,MAAM,CAAC,OAAO,GAAG,CAAO,GAAG,EAAE,KAAK,EAAE,EAAE;IACpC,IAAI,YAAY,GAAW,EAAE,CAAA;IAC7B,IAAI,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,SAAS,EAAE;QAC1B,MAAM,OAAO,GAAW,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,CAAA;QACtE,YAAY,GAAG,IAAI,OAAO,KAAK,CAAA;KAChC;IACD,IAAI,GAAG,CAAC,CAAC,EAAE;QACT,MAAM,OAAO,GAAW,OAAO,GAAG,CAAC,WAAW,IAAI,CAAC,EAAE,CAAA;QACrD,MAAM,SAAS,GAAW,KAAK,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;QAClF,YAAY,IAAI,IAAI,OAAO,GAAG,SAAS,SAAS,CAAA;KACjD;IAED,MAAM,OAAO,GAAW,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,KAAK,CAAC,UAAU,IAAI,YAAY,EAAE,CAAA;IACtF,KAAK,CAAC,UAAU,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;AAC9G,CAAC,CAAA,CAAA"}
|
|
@@ -2,13 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const log = global.log;
|
|
4
4
|
module.exports = (req, res, next) => {
|
|
5
|
-
var _a;
|
|
6
5
|
try {
|
|
7
|
-
if (req.user && req.user.id && req.
|
|
8
|
-
log.d && log.trace('isAdmin - user id ' + ((_a = req.user) === null || _a === void 0 ? void 0 : _a.id));
|
|
6
|
+
if (req.user && req.user.id && req.hasRole(roles.admin)) {
|
|
9
7
|
return next();
|
|
10
8
|
}
|
|
11
|
-
throw new Error('User
|
|
9
|
+
throw new Error('User without this privilege');
|
|
12
10
|
}
|
|
13
11
|
catch (err) {
|
|
14
12
|
log.e && log.error(`Upps, something just happened ${err}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"isAdmin.js","sourceRoot":"","sources":["../../../lib/middleware/isAdmin.ts"],"names":[],"mappings":";;AAEA,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAA;AACtB,MAAM,CAAC,OAAO,GAAG,CAAC,GAAmB,EAAE,GAAiB,EAAE,IAAS,EAAE,EAAE
|
|
1
|
+
{"version":3,"file":"isAdmin.js","sourceRoot":"","sources":["../../../lib/middleware/isAdmin.ts"],"names":[],"mappings":";;AAEA,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAA;AACtB,MAAM,CAAC,OAAO,GAAG,CAAC,GAAmB,EAAE,GAAiB,EAAE,IAAS,EAAE,EAAE;IACrE,IAAI;QACF,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE;YACvD,OAAO,IAAI,EAAE,CAAA;SACd;QACD,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAA;KAC/C;IAAC,OAAO,GAAG,EAAE;QACZ,GAAG,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,iCAAiC,GAAG,EAAE,CAAC,CAAA;QAC1D,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;KACxB;AACH,CAAC,CAAA"}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { FastifyReply, FastifyRequest } from 'fastify'
|
|
2
|
+
import { AuthenticatedUser } from '../../../../types/global'
|
|
2
3
|
|
|
3
4
|
export async function user(req: FastifyRequest, reply: FastifyReply) {
|
|
4
|
-
|
|
5
|
+
const user: AuthenticatedUser | undefined = req.user
|
|
6
|
+
reply.send(user ? { ...user, roles: req.roles() } : {})
|
|
5
7
|
}
|
|
6
8
|
|
|
7
9
|
export async function isAdmin(req: FastifyRequest, reply: FastifyReply) {
|
|
8
|
-
|
|
10
|
+
const user: AuthenticatedUser | undefined = req.user
|
|
11
|
+
reply.send({ isAdmin: user?.id && req.hasRole(roles.admin) })
|
|
9
12
|
}
|
package/lib/hooks/onRequest.ts
CHANGED
|
@@ -1,48 +1,47 @@
|
|
|
1
1
|
import { getParams, getData } from '../util/common'
|
|
2
|
-
import { Role } from '../../types/global'
|
|
2
|
+
import { AuthenticatedUser, Role } from '../../types/global'
|
|
3
3
|
|
|
4
4
|
module.exports = async (req, reply) => {
|
|
5
5
|
// request enrichment
|
|
6
6
|
log.i && (req.startedAt = new Date())
|
|
7
7
|
req.data = () => getData(req)
|
|
8
|
-
req.
|
|
8
|
+
req.parameters = () => getParams(req)
|
|
9
|
+
req.roles = () => ((req.user && req.user.roles) || []).map((role: Role) => role?.code) || []
|
|
10
|
+
req.hasRole = (r: Role) => ((req.user && req.user.roles) || []).some((role: Role) => role?.code === r?.code)
|
|
9
11
|
|
|
10
|
-
// authorization
|
|
12
|
+
// authorization check
|
|
11
13
|
const auth = req.headers?.authorization || ''
|
|
12
14
|
const [prefix, token] = auth.split(' ')
|
|
13
15
|
if (prefix === 'Bearer' && token != null) {
|
|
14
16
|
const { sub: userId, name, iat, exp } = reply.server.jwt.verify(token)
|
|
15
17
|
|
|
16
|
-
// demo
|
|
18
|
+
//TODO: demo
|
|
17
19
|
if (global.npmDebugServerStarted) {
|
|
18
20
|
req.user = {
|
|
19
21
|
id: userId || 123,
|
|
20
|
-
name:
|
|
22
|
+
name: name,
|
|
21
23
|
email: 'jerry@george.com',
|
|
22
|
-
password: '
|
|
24
|
+
password: 'seinfeld',
|
|
23
25
|
// roles: [roles.admin, roles.public]
|
|
24
26
|
roles: [roles.public]
|
|
25
|
-
}
|
|
27
|
+
} as AuthenticatedUser
|
|
28
|
+
|
|
26
29
|
log.debug('Inject demo user ' + req.user.id)
|
|
27
30
|
}
|
|
28
31
|
|
|
32
|
+
//TODO: recall plugin UserManagement for find user or error
|
|
33
|
+
|
|
29
34
|
if (req.routeConfig.requiredRoles?.length > 0) {
|
|
30
35
|
const { method, url, requiredRoles } = req.routeConfig
|
|
31
36
|
const userRoles: string[] = req.user?.roles?.map(({ code }) => code) || []
|
|
32
|
-
const
|
|
37
|
+
const resolvedRoles = userRoles.length > 0 ? requiredRoles.filter((r) => userRoles.includes(r.code)) : []
|
|
33
38
|
|
|
34
|
-
if (!
|
|
39
|
+
if (!resolvedRoles.length) {
|
|
35
40
|
log.w && log.warn(`Not allowed to call ${method.toUpperCase()} ${url}`)
|
|
36
41
|
return reply
|
|
37
42
|
.code(403)
|
|
38
43
|
.send({ statusCode: 403, code: 'ROLE_NOT_ALLOWED', message: 'Not allowed to call this route' })
|
|
39
44
|
}
|
|
40
45
|
}
|
|
41
|
-
|
|
42
|
-
// recall UserManager find / enrichment
|
|
43
|
-
if (req.user) {
|
|
44
|
-
req.user.getRoles = () => (req.user.roles || []).map((role: Role) => role?.code) || []
|
|
45
|
-
req.user.hasRole = (r: Role) => (req.user.roles || []).some((role: Role) => role?.code === r?.code)
|
|
46
|
-
}
|
|
47
46
|
}
|
|
48
47
|
}
|
package/lib/hooks/onResponse.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module.exports = async (req, reply) => {
|
|
2
2
|
let extraMessage: string = ''
|
|
3
|
-
if (log.i) {
|
|
4
|
-
const elapsed: number = new Date().getTime() -
|
|
3
|
+
if (log.i && req.startedAt) {
|
|
4
|
+
const elapsed: number = new Date().getTime() - req.startedAt.getTime()
|
|
5
5
|
extraMessage = `(${elapsed}ms)`
|
|
6
6
|
}
|
|
7
7
|
if (log.t) {
|
|
@@ -3,11 +3,10 @@ import { FastifyReply, FastifyRequest } from 'fastify'
|
|
|
3
3
|
const log = global.log
|
|
4
4
|
module.exports = (req: FastifyRequest, res: FastifyReply, next: any) => {
|
|
5
5
|
try {
|
|
6
|
-
if (req.user && req.user.id && req.
|
|
7
|
-
log.d && log.trace('isAdmin - user id ' + req.user?.id)
|
|
6
|
+
if (req.user && req.user.id && req.hasRole(roles.admin)) {
|
|
8
7
|
return next()
|
|
9
8
|
}
|
|
10
|
-
throw new Error('User
|
|
9
|
+
throw new Error('User without this privilege')
|
|
11
10
|
} catch (err) {
|
|
12
11
|
log.e && log.error(`Upps, something just happened ${err}`)
|
|
13
12
|
res.code(403).send(err)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volcanicminds/backend",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.15",
|
|
4
4
|
"codename": "turin",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "The volcanic (minds) backend",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"node": ">=16"
|
|
34
34
|
},
|
|
35
35
|
"scripts": {
|
|
36
|
-
"compile": "tsc",
|
|
36
|
+
"compile": "rm -rf ./dist && tsc",
|
|
37
37
|
"preprod": "npm run compile",
|
|
38
38
|
"prod": "node ./dist/server.js",
|
|
39
39
|
"start": "ts-node ./server.ts",
|
package/types/global.d.ts
CHANGED
|
@@ -2,10 +2,7 @@ import { FastifyRequest, FastifyReply } from 'fastify'
|
|
|
2
2
|
|
|
3
3
|
export interface AuthenticatedUser {
|
|
4
4
|
id: number
|
|
5
|
-
extra: any
|
|
6
5
|
roles: Role[]
|
|
7
|
-
getRoles(): string[]
|
|
8
|
-
hasRole(role: Role): boolean
|
|
9
6
|
}
|
|
10
7
|
|
|
11
8
|
export interface Role {
|
|
@@ -68,12 +65,13 @@ export interface ConfiguredRoute {
|
|
|
68
65
|
}
|
|
69
66
|
|
|
70
67
|
declare module 'fastify' {
|
|
71
|
-
import { FastifyRequest } from 'fastify'
|
|
72
68
|
export interface FastifyRequest {
|
|
73
69
|
user?: AuthenticatedUser
|
|
74
|
-
|
|
70
|
+
startedAt?: Date
|
|
75
71
|
data(): Data
|
|
76
|
-
|
|
72
|
+
parameters(): Data
|
|
73
|
+
roles(): string[]
|
|
74
|
+
hasRole(role: Role): boolean
|
|
77
75
|
payloadSize?: number
|
|
78
76
|
}
|
|
79
77
|
export interface FastifyReply {
|
|
@@ -83,9 +81,11 @@ declare module 'fastify' {
|
|
|
83
81
|
|
|
84
82
|
export interface FastifyRequest extends FastifyRequest {
|
|
85
83
|
user?: AuthenticatedUser
|
|
86
|
-
|
|
84
|
+
startedAt?: Date
|
|
87
85
|
data(): Data
|
|
88
|
-
|
|
86
|
+
parameters(): Data
|
|
87
|
+
roles(): string[]
|
|
88
|
+
hasRole(role: Role): boolean
|
|
89
89
|
payloadSize?: number
|
|
90
90
|
}
|
|
91
91
|
|