@unito/integration-sdk 1.0.27 → 1.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/dist/src/errors.js +4 -1
- package/dist/src/helpers.d.ts +2 -2
- package/dist/src/helpers.js +2 -2
- package/dist/src/httpErrors.d.ts +6 -0
- package/dist/src/httpErrors.js +8 -0
- package/dist/src/index.cjs +221 -209
- package/dist/src/integration.js +8 -8
- package/dist/src/middlewares/correlationId.d.ts +2 -2
- package/dist/src/middlewares/correlationId.js +3 -3
- package/dist/src/middlewares/credentials.d.ts +2 -2
- package/dist/src/middlewares/credentials.js +3 -3
- package/dist/src/middlewares/errors.d.ts +2 -2
- package/dist/src/middlewares/errors.js +3 -3
- package/dist/src/middlewares/filters.d.ts +2 -2
- package/dist/src/middlewares/filters.js +4 -4
- package/dist/src/middlewares/finish.d.ts +2 -2
- package/dist/src/middlewares/finish.js +3 -3
- package/dist/src/middlewares/logger.d.ts +2 -2
- package/dist/src/middlewares/logger.js +3 -3
- package/dist/src/middlewares/notFound.d.ts +2 -2
- package/dist/src/middlewares/notFound.js +3 -3
- package/dist/src/middlewares/secrets.d.ts +2 -2
- package/dist/src/middlewares/secrets.js +3 -3
- package/dist/src/middlewares/selects.d.ts +2 -2
- package/dist/src/middlewares/selects.js +3 -3
- package/dist/src/middlewares/signal.d.ts +2 -2
- package/dist/src/middlewares/signal.js +3 -3
- package/dist/src/middlewares/{requestStartTime.d.ts → start.d.ts} +2 -2
- package/dist/src/middlewares/{requestStartTime.js → start.js} +3 -3
- package/dist/test/errors.test.js +1 -1
- package/dist/test/middlewares/correlationId.test.js +3 -3
- package/dist/test/middlewares/credentials.test.js +4 -4
- package/dist/test/middlewares/errors.test.js +4 -4
- package/dist/test/middlewares/filters.test.js +20 -12
- package/dist/test/middlewares/finish.test.js +4 -4
- package/dist/test/middlewares/logger.test.js +5 -5
- package/dist/test/middlewares/notFound.test.js +2 -2
- package/dist/test/middlewares/secrets.test.js +3 -3
- package/dist/test/middlewares/selects.test.js +3 -3
- package/dist/test/middlewares/signal.test.js +3 -3
- package/dist/test/middlewares/start.test.d.ts +1 -0
- package/dist/test/middlewares/start.test.js +11 -0
- package/package.json +1 -1
- package/src/errors.ts +3 -1
- package/src/helpers.ts +2 -2
- package/src/httpErrors.ts +9 -0
- package/src/integration.ts +8 -8
- package/src/middlewares/correlationId.ts +3 -3
- package/src/middlewares/credentials.ts +3 -3
- package/src/middlewares/errors.ts +3 -3
- package/src/middlewares/filters.ts +4 -4
- package/src/middlewares/finish.ts +3 -3
- package/src/middlewares/logger.ts +3 -3
- package/src/middlewares/notFound.ts +3 -3
- package/src/middlewares/secrets.ts +3 -3
- package/src/middlewares/selects.ts +3 -3
- package/src/middlewares/signal.ts +3 -3
- package/src/middlewares/{requestStartTime.ts → start.ts} +3 -3
- package/test/errors.test.ts +1 -1
- package/test/middlewares/correlationId.test.ts +3 -3
- package/test/middlewares/credentials.test.ts +4 -4
- package/test/middlewares/errors.test.ts +4 -4
- package/test/middlewares/filters.test.ts +31 -12
- package/test/middlewares/finish.test.ts +4 -4
- package/test/middlewares/logger.test.ts +5 -5
- package/test/middlewares/notFound.test.ts +2 -2
- package/test/middlewares/secrets.test.ts +3 -3
- package/test/middlewares/selects.test.ts +3 -3
- package/test/middlewares/signal.test.ts +3 -3
- package/test/middlewares/start.test.ts +14 -0
|
@@ -4,8 +4,8 @@ import { OperatorType } from '@unito/integration-api';
|
|
|
4
4
|
// a subset of the symbol of another operator.
|
|
5
5
|
//
|
|
6
6
|
// For example, the symbol "=" (EQUAL) is a subset of the symbol "!=" (NOT_EQUAL).
|
|
7
|
-
const ORDERED_OPERATORS = Object.values(OperatorType).sort((o1, o2) =>
|
|
8
|
-
|
|
7
|
+
const ORDERED_OPERATORS = Object.values(OperatorType).sort((o1, o2) => o2.length - o1.length);
|
|
8
|
+
function extractFilters(req, res, next) {
|
|
9
9
|
const rawFilters = req.query.filter;
|
|
10
10
|
res.locals.filters = [];
|
|
11
11
|
if (typeof rawFilters === 'string') {
|
|
@@ -21,5 +21,5 @@ const middleware = (req, res, next) => {
|
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
next();
|
|
24
|
-
}
|
|
25
|
-
export default
|
|
24
|
+
}
|
|
25
|
+
export default extractFilters;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
function onFinish(req, res, next) {
|
|
2
2
|
if (req.originalUrl !== '/health') {
|
|
3
3
|
res.on('finish', function () {
|
|
4
4
|
const error = res.locals.error;
|
|
@@ -32,5 +32,5 @@ const middleware = (req, res, next) => {
|
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
34
|
next();
|
|
35
|
-
}
|
|
36
|
-
export default
|
|
35
|
+
}
|
|
36
|
+
export default onFinish;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Logger from '../resources/logger.js';
|
|
2
2
|
const ADDITIONAL_CONTEXT_HEADER = 'X-Unito-Additional-Logging-Context';
|
|
3
|
-
|
|
3
|
+
function injectLogger(req, res, next) {
|
|
4
4
|
const logger = new Logger({ correlation_id: res.locals.correlationId });
|
|
5
5
|
res.locals.logger = logger;
|
|
6
6
|
const rawAdditionalContext = req.header(ADDITIONAL_CONTEXT_HEADER);
|
|
@@ -14,5 +14,5 @@ const middleware = (req, res, next) => {
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
next();
|
|
17
|
-
}
|
|
18
|
-
export default
|
|
17
|
+
}
|
|
18
|
+
export default injectLogger;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { Request, Response, NextFunction } from 'express';
|
|
2
|
-
declare
|
|
3
|
-
export default
|
|
2
|
+
declare function notFound(req: Request, res: Response, _next: NextFunction): void;
|
|
3
|
+
export default notFound;
|
|
@@ -14,5 +14,5 @@ declare global {
|
|
|
14
14
|
export type Secrets = {
|
|
15
15
|
[keys: string]: unknown;
|
|
16
16
|
};
|
|
17
|
-
declare
|
|
18
|
-
export default
|
|
17
|
+
declare function extractSecrets(req: Request, res: Response, next: NextFunction): void;
|
|
18
|
+
export default extractSecrets;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BadRequestError } from '../httpErrors.js';
|
|
2
2
|
const SECRETS_HEADER = 'X-Unito-Secrets';
|
|
3
|
-
|
|
3
|
+
function extractSecrets(req, res, next) {
|
|
4
4
|
const secretsHeader = req.header(SECRETS_HEADER);
|
|
5
5
|
if (secretsHeader) {
|
|
6
6
|
let secrets;
|
|
@@ -13,5 +13,5 @@ const middleware = (req, res, next) => {
|
|
|
13
13
|
res.locals.secrets = secrets;
|
|
14
14
|
}
|
|
15
15
|
next();
|
|
16
|
-
}
|
|
17
|
-
export default
|
|
16
|
+
}
|
|
17
|
+
export default extractSecrets;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
function extractSelects(req, res, next) {
|
|
2
2
|
const rawSelect = req.query.select;
|
|
3
3
|
if (typeof rawSelect === 'string') {
|
|
4
4
|
res.locals.selects = rawSelect.split(',');
|
|
@@ -7,5 +7,5 @@ const middleware = (req, res, next) => {
|
|
|
7
7
|
res.locals.selects = [];
|
|
8
8
|
}
|
|
9
9
|
next();
|
|
10
|
-
}
|
|
11
|
-
export default
|
|
10
|
+
}
|
|
11
|
+
export default extractSelects;
|
|
@@ -11,5 +11,5 @@ declare global {
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
|
-
declare
|
|
15
|
-
export default
|
|
14
|
+
declare function extractOperationDeadline(req: Request, res: Response, next: NextFunction): void;
|
|
15
|
+
export default extractOperationDeadline;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { TimeoutError } from '../httpErrors.js';
|
|
2
2
|
const OPERATION_DEADLINE_HEADER = 'X-Unito-Operation-Deadline';
|
|
3
|
-
|
|
3
|
+
function extractOperationDeadline(req, res, next) {
|
|
4
4
|
const operationDeadlineHeader = Number(req.header(OPERATION_DEADLINE_HEADER));
|
|
5
5
|
if (operationDeadlineHeader) {
|
|
6
6
|
// `operationDeadlineHeader` represents a timestamp in the future, in seconds.
|
|
@@ -18,5 +18,5 @@ const middleware = (req, res, next) => {
|
|
|
18
18
|
res.locals.signal = AbortSignal.timeout(20000);
|
|
19
19
|
}
|
|
20
20
|
next();
|
|
21
|
-
}
|
|
22
|
-
export default
|
|
21
|
+
}
|
|
22
|
+
export default extractOperationDeadline;
|
package/dist/test/errors.test.js
CHANGED
|
@@ -5,7 +5,7 @@ import * as httpErrors from '../src/httpErrors.js';
|
|
|
5
5
|
describe('handleErrorResponse', () => {
|
|
6
6
|
it('returns correct httpError given status code', () => {
|
|
7
7
|
assert.ok(errors.buildHttpError(401, 'unauthorized') instanceof httpErrors.UnauthorizedError);
|
|
8
|
-
assert.ok(errors.buildHttpError(403, 'forbidden') instanceof httpErrors.
|
|
8
|
+
assert.ok(errors.buildHttpError(403, 'forbidden') instanceof httpErrors.ForbiddenError);
|
|
9
9
|
assert.ok(errors.buildHttpError(404, 'not found') instanceof httpErrors.NotFoundError);
|
|
10
10
|
assert.ok(errors.buildHttpError(408, 'timeout') instanceof httpErrors.TimeoutError);
|
|
11
11
|
assert.ok(errors.buildHttpError(410, 'resource gone') instanceof httpErrors.ResourceGoneError);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
2
|
import { describe, it } from 'node:test';
|
|
3
|
-
import
|
|
3
|
+
import extractCorrelationId from '../../src/middlewares/correlationId.js';
|
|
4
4
|
describe('correlationId middleware', () => {
|
|
5
5
|
it('uses header', () => {
|
|
6
6
|
const request = { header: (_key) => '123' };
|
|
7
7
|
const response = { locals: {} };
|
|
8
|
-
|
|
8
|
+
extractCorrelationId(request, response, () => { });
|
|
9
9
|
assert.deepEqual(response.locals, {
|
|
10
10
|
correlationId: '123',
|
|
11
11
|
});
|
|
@@ -13,7 +13,7 @@ describe('correlationId middleware', () => {
|
|
|
13
13
|
it('fallback', () => {
|
|
14
14
|
const request = { header: (_key) => undefined };
|
|
15
15
|
const response = { locals: {} };
|
|
16
|
-
|
|
16
|
+
extractCorrelationId(request, response, () => { });
|
|
17
17
|
assert(response.locals.correlationId);
|
|
18
18
|
});
|
|
19
19
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
2
|
import { describe, it } from 'node:test';
|
|
3
|
-
import
|
|
3
|
+
import extractCredentials from '../../src/middlewares/credentials.js';
|
|
4
4
|
import { BadRequestError } from '../../src/httpErrors.js';
|
|
5
5
|
describe('credentials middleware', () => {
|
|
6
6
|
it('generates', async () => {
|
|
@@ -9,7 +9,7 @@ describe('credentials middleware', () => {
|
|
|
9
9
|
})).toString('base64');
|
|
10
10
|
const request = { header: (_key) => credentials };
|
|
11
11
|
const response = { locals: {} };
|
|
12
|
-
|
|
12
|
+
extractCredentials(request, response, () => { });
|
|
13
13
|
assert.deepEqual(response.locals, {
|
|
14
14
|
credentials: {
|
|
15
15
|
accessToken: 'abc',
|
|
@@ -19,7 +19,7 @@ describe('credentials middleware', () => {
|
|
|
19
19
|
it('malformed header', async () => {
|
|
20
20
|
const request = { header: (_key) => 'nope' };
|
|
21
21
|
const response = { locals: {} };
|
|
22
|
-
assert.throws(() =>
|
|
22
|
+
assert.throws(() => extractCredentials(request, response, () => { }), BadRequestError);
|
|
23
23
|
});
|
|
24
24
|
it('variables', async () => {
|
|
25
25
|
const credentials = Buffer.from(JSON.stringify({
|
|
@@ -27,7 +27,7 @@ describe('credentials middleware', () => {
|
|
|
27
27
|
})).toString('base64');
|
|
28
28
|
const request = { header: (_key) => credentials };
|
|
29
29
|
const response = { locals: {} };
|
|
30
|
-
|
|
30
|
+
extractCredentials(request, response, () => { });
|
|
31
31
|
assert.deepEqual(response.locals, {
|
|
32
32
|
credentials: {
|
|
33
33
|
apiKey: 'abc',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
2
|
import { describe, it } from 'node:test';
|
|
3
|
-
import
|
|
3
|
+
import onError from '../../src/middlewares/errors.js';
|
|
4
4
|
import { HttpError } from '../../src/httpErrors.js';
|
|
5
5
|
describe('errors middleware', () => {
|
|
6
6
|
it('headers sent, do nothing', () => {
|
|
@@ -18,7 +18,7 @@ describe('errors middleware', () => {
|
|
|
18
18
|
},
|
|
19
19
|
locals: { logger: { error: () => undefined } },
|
|
20
20
|
};
|
|
21
|
-
|
|
21
|
+
onError(new Error(), {}, response, () => { });
|
|
22
22
|
assert.strictEqual(actualStatus, undefined);
|
|
23
23
|
assert.strictEqual(actualJson, undefined);
|
|
24
24
|
});
|
|
@@ -37,7 +37,7 @@ describe('errors middleware', () => {
|
|
|
37
37
|
},
|
|
38
38
|
locals: { logger: { error: () => undefined } },
|
|
39
39
|
};
|
|
40
|
-
|
|
40
|
+
onError(new HttpError('httpError', 429), {}, response, () => { });
|
|
41
41
|
assert.strictEqual(actualStatus, 429);
|
|
42
42
|
assert.deepEqual(actualJson, { code: '429', message: 'httpError' });
|
|
43
43
|
});
|
|
@@ -56,7 +56,7 @@ describe('errors middleware', () => {
|
|
|
56
56
|
},
|
|
57
57
|
locals: { logger: { error: () => undefined } },
|
|
58
58
|
};
|
|
59
|
-
|
|
59
|
+
onError(new Error('error'), {}, response, () => { });
|
|
60
60
|
assert.strictEqual(actualStatus, 500);
|
|
61
61
|
assert.strictEqual(actualJson?.code, '500');
|
|
62
62
|
assert.deepEqual(actualJson?.originalError, { code: 'Error', message: 'error' });
|
|
@@ -1,24 +1,32 @@
|
|
|
1
1
|
import { OperatorType } from '@unito/integration-api';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
import { describe, it } from 'node:test';
|
|
4
|
-
import
|
|
4
|
+
import extractFilters from '../../src/middlewares/filters.js';
|
|
5
5
|
describe('filters middleware', () => {
|
|
6
|
-
it('
|
|
7
|
-
|
|
6
|
+
it('properly parse operators', () => {
|
|
7
|
+
Object.values(OperatorType).forEach(operator => {
|
|
8
|
+
const request = {
|
|
9
|
+
query: { filter: `aKey${operator}value` },
|
|
10
|
+
};
|
|
11
|
+
const response = { locals: {} };
|
|
12
|
+
extractFilters(request, response, () => { });
|
|
13
|
+
assert.deepEqual(response.locals, {
|
|
14
|
+
filters: [{ field: 'aKey', operator, values: ['value'] }],
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
const request = {
|
|
18
|
+
query: { filter: `aKey!!` },
|
|
19
|
+
};
|
|
8
20
|
const response = { locals: {} };
|
|
9
|
-
|
|
21
|
+
extractFilters(request, response, () => { });
|
|
10
22
|
assert.deepEqual(response.locals, {
|
|
11
|
-
filters: [
|
|
12
|
-
{ field: 'status', operator: OperatorType.EQUAL, values: ['active', 'pending'] },
|
|
13
|
-
{ field: 'createdAt', operator: OperatorType.GREATER_THAN, values: ['2022-01-01'] },
|
|
14
|
-
{ field: 'email', operator: OperatorType.IS_NOT_NULL, values: [] },
|
|
15
|
-
],
|
|
23
|
+
filters: [{ field: 'aKey', operator: OperatorType.IS_NULL, values: [] }],
|
|
16
24
|
});
|
|
17
25
|
});
|
|
18
26
|
it('decodes URI components', () => {
|
|
19
|
-
const request = { query: { filter: 'status=foo%2Cbar
|
|
27
|
+
const request = { query: { filter: 'status=foo%2Cbar%21%21%2C%3Fbaz%3D!%3Equx' } };
|
|
20
28
|
const response = { locals: {} };
|
|
21
|
-
|
|
29
|
+
extractFilters(request, response, () => { });
|
|
22
30
|
assert.deepEqual(response.locals, {
|
|
23
31
|
filters: [{ field: 'status', operator: OperatorType.EQUAL, values: ['foo,bar!!,?baz=!>qux'] }],
|
|
24
32
|
});
|
|
@@ -26,7 +34,7 @@ describe('filters middleware', () => {
|
|
|
26
34
|
it('no data', () => {
|
|
27
35
|
const request = { query: {} };
|
|
28
36
|
const response = { locals: {} };
|
|
29
|
-
|
|
37
|
+
extractFilters(request, response, () => { });
|
|
30
38
|
assert.deepEqual(response.locals, {
|
|
31
39
|
filters: [],
|
|
32
40
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
2
|
import { describe, it } from 'node:test';
|
|
3
|
-
import
|
|
3
|
+
import onFinish from '../../src/middlewares/finish.js';
|
|
4
4
|
describe('finish middleware', () => {
|
|
5
5
|
it('logs info', () => {
|
|
6
6
|
let expected = '';
|
|
@@ -20,7 +20,7 @@ describe('finish middleware', () => {
|
|
|
20
20
|
},
|
|
21
21
|
statusCode: 200,
|
|
22
22
|
};
|
|
23
|
-
|
|
23
|
+
onFinish(request, response, () => { });
|
|
24
24
|
eventHandler();
|
|
25
25
|
assert.equal(expected, 'works!');
|
|
26
26
|
});
|
|
@@ -42,7 +42,7 @@ describe('finish middleware', () => {
|
|
|
42
42
|
},
|
|
43
43
|
statusCode: 500,
|
|
44
44
|
};
|
|
45
|
-
|
|
45
|
+
onFinish(request, response, () => { });
|
|
46
46
|
eventHandler();
|
|
47
47
|
assert.equal(expected, 'works!');
|
|
48
48
|
});
|
|
@@ -64,7 +64,7 @@ describe('finish middleware', () => {
|
|
|
64
64
|
},
|
|
65
65
|
statusCode: 200,
|
|
66
66
|
};
|
|
67
|
-
|
|
67
|
+
onFinish(request, response, () => { });
|
|
68
68
|
eventHandler();
|
|
69
69
|
assert.equal(expected, '');
|
|
70
70
|
});
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
2
|
import { describe, it } from 'node:test';
|
|
3
|
-
import
|
|
3
|
+
import injectLogger from '../../src/middlewares/logger.js';
|
|
4
4
|
describe('logger middleware', () => {
|
|
5
5
|
it('initializes', () => {
|
|
6
6
|
const request = { header: (_key) => undefined };
|
|
7
7
|
const response = { locals: {} };
|
|
8
|
-
|
|
8
|
+
injectLogger(request, response, () => { });
|
|
9
9
|
assert.deepEqual(response.locals.logger.getMetadata(), {
|
|
10
10
|
correlation_id: undefined,
|
|
11
11
|
});
|
|
@@ -13,7 +13,7 @@ describe('logger middleware', () => {
|
|
|
13
13
|
it('correlation id', () => {
|
|
14
14
|
const request = { header: (_key) => undefined };
|
|
15
15
|
const response = { locals: { correlationId: '123' } };
|
|
16
|
-
|
|
16
|
+
injectLogger(request, response, () => { });
|
|
17
17
|
assert.deepEqual(response.locals.logger.getMetadata(), {
|
|
18
18
|
correlation_id: '123',
|
|
19
19
|
});
|
|
@@ -24,7 +24,7 @@ describe('logger middleware', () => {
|
|
|
24
24
|
});
|
|
25
25
|
const request = { header: (_key) => additional };
|
|
26
26
|
const response = { locals: { correlationId: '123' } };
|
|
27
|
-
|
|
27
|
+
injectLogger(request, response, () => { });
|
|
28
28
|
assert.deepEqual(response.locals.logger.getMetadata(), {
|
|
29
29
|
correlation_id: '123',
|
|
30
30
|
foo: 'bar',
|
|
@@ -33,7 +33,7 @@ describe('logger middleware', () => {
|
|
|
33
33
|
it('malformed additional context', () => {
|
|
34
34
|
const request = { header: (_key) => 'nope' };
|
|
35
35
|
const response = { locals: { correlationId: '123' } };
|
|
36
|
-
|
|
36
|
+
injectLogger(request, response, () => { });
|
|
37
37
|
assert.deepEqual(response.locals.logger.getMetadata(), {
|
|
38
38
|
correlation_id: '123',
|
|
39
39
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
2
|
import { describe, it } from 'node:test';
|
|
3
|
-
import
|
|
3
|
+
import notFound from '../../src/middlewares/notFound.js';
|
|
4
4
|
describe('notFound middleware', () => {
|
|
5
5
|
it('respond with error without calling next', () => {
|
|
6
6
|
let actualStatus;
|
|
@@ -17,7 +17,7 @@ describe('notFound middleware', () => {
|
|
|
17
17
|
},
|
|
18
18
|
locals: { logger: { error: () => undefined } },
|
|
19
19
|
};
|
|
20
|
-
|
|
20
|
+
notFound({ path: 'unknownPath' }, response, () => {
|
|
21
21
|
throw new Error('next should not be called');
|
|
22
22
|
});
|
|
23
23
|
assert.strictEqual(actualStatus, 404);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
2
|
import { describe, it } from 'node:test';
|
|
3
|
-
import
|
|
3
|
+
import extractSecrets from '../../src/middlewares/secrets.js';
|
|
4
4
|
import { BadRequestError } from '../../src/httpErrors.js';
|
|
5
5
|
describe('secrets middleware', () => {
|
|
6
6
|
it('uses header', () => {
|
|
@@ -9,7 +9,7 @@ describe('secrets middleware', () => {
|
|
|
9
9
|
})).toString('base64');
|
|
10
10
|
const request = { header: (_key) => secrets };
|
|
11
11
|
const response = { locals: {} };
|
|
12
|
-
|
|
12
|
+
extractSecrets(request, response, () => { });
|
|
13
13
|
assert.deepEqual(response.locals, {
|
|
14
14
|
secrets: {
|
|
15
15
|
chut: 'abc',
|
|
@@ -19,7 +19,7 @@ describe('secrets middleware', () => {
|
|
|
19
19
|
it('malformed header', async () => {
|
|
20
20
|
const request = { header: (_key) => 'nope' };
|
|
21
21
|
const response = { locals: {} };
|
|
22
|
-
assert.throws(() =>
|
|
22
|
+
assert.throws(() => extractSecrets(request, response, () => { }), BadRequestError);
|
|
23
23
|
});
|
|
24
24
|
it('undefined', () => {
|
|
25
25
|
const response = { locals: {} };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
2
|
import { describe, it } from 'node:test';
|
|
3
|
-
import
|
|
3
|
+
import extractSelects from '../../src/middlewares/selects.js';
|
|
4
4
|
describe('selects middleware', () => {
|
|
5
5
|
it('data', () => {
|
|
6
6
|
const request = { query: { select: 'foo,bar.spam,baz' } };
|
|
7
7
|
const response = { locals: {} };
|
|
8
|
-
|
|
8
|
+
extractSelects(request, response, () => { });
|
|
9
9
|
assert.deepEqual(response.locals, {
|
|
10
10
|
selects: ['foo', 'bar.spam', 'baz'],
|
|
11
11
|
});
|
|
@@ -13,7 +13,7 @@ describe('selects middleware', () => {
|
|
|
13
13
|
it('no data', () => {
|
|
14
14
|
const request = { query: {} };
|
|
15
15
|
const response = { locals: {} };
|
|
16
|
-
|
|
16
|
+
extractSelects(request, response, () => { });
|
|
17
17
|
assert.deepEqual(response.locals, {
|
|
18
18
|
selects: [],
|
|
19
19
|
});
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
2
|
import { describe, it } from 'node:test';
|
|
3
|
-
import
|
|
3
|
+
import extractOperationDeadline from '../../src/middlewares/signal.js';
|
|
4
4
|
describe('signal middleware', () => {
|
|
5
5
|
it('uses header', () => {
|
|
6
6
|
const deadline = Math.floor((Date.now() + 5000) / 1000);
|
|
7
7
|
const request = { header: (_key) => deadline };
|
|
8
8
|
const response = { locals: {} };
|
|
9
|
-
|
|
9
|
+
extractOperationDeadline(request, response, () => { });
|
|
10
10
|
assert.ok(response.locals.signal instanceof AbortSignal);
|
|
11
11
|
assert.equal(response.locals.signal.aborted, false);
|
|
12
12
|
});
|
|
13
13
|
it('defaults', () => {
|
|
14
14
|
const request = { header: (_key) => undefined };
|
|
15
15
|
const response = { locals: {} };
|
|
16
|
-
|
|
16
|
+
extractOperationDeadline(request, response, () => { });
|
|
17
17
|
assert.ok(response.locals.signal instanceof AbortSignal);
|
|
18
18
|
assert.equal(response.locals.signal.aborted, false);
|
|
19
19
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { describe, it } from 'node:test';
|
|
3
|
+
import start from '../../src/middlewares/start.js';
|
|
4
|
+
describe('start middleware', () => {
|
|
5
|
+
it('adds request start time to locals', () => {
|
|
6
|
+
const request = {};
|
|
7
|
+
const response = { locals: {} };
|
|
8
|
+
start(request, response, () => { });
|
|
9
|
+
assert.ok(response.locals.requestStartTime);
|
|
10
|
+
});
|
|
11
|
+
});
|
package/package.json
CHANGED
package/src/errors.ts
CHANGED
|
@@ -13,8 +13,10 @@ export function buildHttpError(responseStatus: number, message: string): HttpErr
|
|
|
13
13
|
let httpError: HttpErrors.HttpError;
|
|
14
14
|
if (responseStatus === 400) {
|
|
15
15
|
httpError = new HttpErrors.BadRequestError(message);
|
|
16
|
-
} else if (responseStatus === 401
|
|
16
|
+
} else if (responseStatus === 401) {
|
|
17
17
|
httpError = new HttpErrors.UnauthorizedError(message);
|
|
18
|
+
} else if (responseStatus === 403) {
|
|
19
|
+
httpError = new HttpErrors.ForbiddenError(message);
|
|
18
20
|
} else if (responseStatus === 404) {
|
|
19
21
|
httpError = new HttpErrors.NotFoundError(message);
|
|
20
22
|
} else if (responseStatus === 408) {
|
package/src/helpers.ts
CHANGED
|
@@ -12,7 +12,7 @@ import { Filter } from './index.js';
|
|
|
12
12
|
* @param fields The schema of the item against which the filters are applied
|
|
13
13
|
* @returns The validated filters
|
|
14
14
|
*/
|
|
15
|
-
export
|
|
15
|
+
export function getApplicableFilters(context: { filters: Filter[] }, fields: FieldSchema[]): Filter[] {
|
|
16
16
|
const applicableFilters: Filter[] = [];
|
|
17
17
|
|
|
18
18
|
for (const filter of context.filters) {
|
|
@@ -34,4 +34,4 @@ export const getApplicableFilters = (context: { filters: Filter[] }, fields: Fie
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
return applicableFilters;
|
|
37
|
-
}
|
|
37
|
+
}
|
package/src/httpErrors.ts
CHANGED
|
@@ -33,6 +33,15 @@ export class UnauthorizedError extends HttpError {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Used to generate a 403 Forbidden. Usually used when user lacks sufficient permission to access a ressource.
|
|
38
|
+
*/
|
|
39
|
+
export class ForbiddenError extends HttpError {
|
|
40
|
+
constructor(message?: string) {
|
|
41
|
+
super(message || 'Forbidden', 403);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
36
45
|
/**
|
|
37
46
|
* Used to generate a 404 Not Found. Usually used when the requested `Item` is not found.
|
|
38
47
|
*/
|
package/src/integration.ts
CHANGED
|
@@ -2,18 +2,18 @@ import { Server, IncomingMessage, ServerResponse } from 'http';
|
|
|
2
2
|
import express from 'express';
|
|
3
3
|
|
|
4
4
|
import { InvalidHandler } from './errors.js';
|
|
5
|
+
import { HandlersInput, Handler } from './handler.js';
|
|
5
6
|
import correlationIdMiddleware from './middlewares/correlationId.js';
|
|
6
|
-
import loggerMiddleware from './middlewares/logger.js';
|
|
7
7
|
import credentialsMiddleware from './middlewares/credentials.js';
|
|
8
|
-
import signalMiddleware from './middlewares/signal.js';
|
|
9
|
-
import secretsMiddleware from './middlewares/secrets.js';
|
|
10
|
-
import filtersMiddleware from './middlewares/filters.js';
|
|
11
|
-
import selectsMiddleware from './middlewares/selects.js';
|
|
12
8
|
import errorsMiddleware from './middlewares/errors.js';
|
|
9
|
+
import filtersMiddleware from './middlewares/filters.js';
|
|
13
10
|
import finishMiddleware from './middlewares/finish.js';
|
|
14
11
|
import notFoundMiddleware from './middlewares/notFound.js';
|
|
15
|
-
import
|
|
16
|
-
import
|
|
12
|
+
import loggerMiddleware from './middlewares/logger.js';
|
|
13
|
+
import startMiddleware from './middlewares/start.js';
|
|
14
|
+
import secretsMiddleware from './middlewares/secrets.js';
|
|
15
|
+
import selectsMiddleware from './middlewares/selects.js';
|
|
16
|
+
import signalMiddleware from './middlewares/signal.js';
|
|
17
17
|
|
|
18
18
|
function printErrorMessage(message: string) {
|
|
19
19
|
console.error();
|
|
@@ -131,7 +131,7 @@ export default class Integration {
|
|
|
131
131
|
app.use(finishMiddleware);
|
|
132
132
|
|
|
133
133
|
// Instantiate internal middlewares.
|
|
134
|
-
app.use(
|
|
134
|
+
app.use(startMiddleware);
|
|
135
135
|
app.use(correlationIdMiddleware);
|
|
136
136
|
app.use(loggerMiddleware);
|
|
137
137
|
|
|
@@ -10,10 +10,10 @@ declare global {
|
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
function extractCorrelationId(req: Request, res: Response, next: NextFunction) {
|
|
14
14
|
res.locals.correlationId = req.header('X-Unito-Correlation-Id') ?? crypto.randomUUID();
|
|
15
15
|
|
|
16
16
|
next();
|
|
17
|
-
}
|
|
17
|
+
}
|
|
18
18
|
|
|
19
|
-
export default
|
|
19
|
+
export default extractCorrelationId;
|