@unito/integration-sdk 1.0.26 → 1.0.28
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/helpers.d.ts +2 -2
- package/dist/src/helpers.js +2 -2
- package/dist/src/index.cjs +267 -215
- 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/src/resources/logger.d.ts +2 -1
- package/dist/src/resources/logger.js +59 -7
- 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/dist/test/resources/logger.test.js +71 -45
- package/package.json +1 -1
- package/src/helpers.ts +2 -2
- 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/src/resources/logger.ts +66 -8
- 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
- package/test/resources/logger.test.ts +82 -47
|
@@ -21,5 +21,5 @@ export type Filter = {
|
|
|
21
21
|
operator: OperatorType;
|
|
22
22
|
values: string[] | undefined;
|
|
23
23
|
};
|
|
24
|
-
declare
|
|
25
|
-
export default
|
|
24
|
+
declare function extractFilters(req: Request, res: Response, next: NextFunction): void;
|
|
25
|
+
export default extractFilters;
|
|
@@ -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;
|
|
@@ -6,6 +6,35 @@ var LogLevel;
|
|
|
6
6
|
LogLevel["LOG"] = "log";
|
|
7
7
|
LogLevel["DEBUG"] = "debug";
|
|
8
8
|
})(LogLevel || (LogLevel = {}));
|
|
9
|
+
/**
|
|
10
|
+
* See https://docs.datadoghq.com/logs/log_collection/?tab=host#custom-log-forwarding
|
|
11
|
+
* - Datadog Agent splits at 256kB (256000 bytes)...
|
|
12
|
+
* - ... but the same docs say that "for optimal performance, it is
|
|
13
|
+
* recommended that an individual log be no greater than 25kB"
|
|
14
|
+
* -> Truncating at 25kB - a bit of wiggle room for metadata = 20kB.
|
|
15
|
+
*/
|
|
16
|
+
const MAX_LOG_MESSAGE_SIZE = parseInt(process.env.MAX_LOG_MESSAGE_SIZE ?? '20000', 10);
|
|
17
|
+
const LOG_LINE_TRUNCATED_SUFFIX = ' - LOG LINE TRUNCATED';
|
|
18
|
+
/**
|
|
19
|
+
* For *LogMeta* sanitization, we let in anything that was passed, except for clearly-problematic keys
|
|
20
|
+
*/
|
|
21
|
+
const LOGMETA_BLACKLIST = [
|
|
22
|
+
// Security
|
|
23
|
+
'access_token',
|
|
24
|
+
'bot_auth_code',
|
|
25
|
+
'client_secret',
|
|
26
|
+
'jwt',
|
|
27
|
+
'oauth_token',
|
|
28
|
+
'password',
|
|
29
|
+
'refresh_token',
|
|
30
|
+
'shared_secret',
|
|
31
|
+
'token',
|
|
32
|
+
// Privacy
|
|
33
|
+
'billing_email',
|
|
34
|
+
'email',
|
|
35
|
+
'first_name',
|
|
36
|
+
'last_name',
|
|
37
|
+
];
|
|
9
38
|
/**
|
|
10
39
|
* Logger class that can be configured with metadata add creation and when logging to add additional context to your logs.
|
|
11
40
|
*/
|
|
@@ -85,20 +114,27 @@ export default class Logger {
|
|
|
85
114
|
this.metadata = {};
|
|
86
115
|
}
|
|
87
116
|
send(logLevel, message, metadata) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
117
|
+
// We need to provide the date to Datadog. Otherwise, the date is set to when they receive the log.
|
|
118
|
+
const date = Date.now();
|
|
119
|
+
if (message.length > MAX_LOG_MESSAGE_SIZE) {
|
|
120
|
+
message = `${message.substring(0, MAX_LOG_MESSAGE_SIZE)}${LOG_LINE_TRUNCATED_SUFFIX}`;
|
|
121
|
+
}
|
|
122
|
+
let processedMetadata = Logger.snakifyKeys({ ...this.metadata, ...metadata, logMessageSize: message.length });
|
|
123
|
+
processedMetadata = Logger.pruneSensitiveMetadata(processedMetadata);
|
|
124
|
+
const processedLogs = {
|
|
125
|
+
...processedMetadata,
|
|
91
126
|
message,
|
|
127
|
+
date,
|
|
92
128
|
status: logLevel,
|
|
93
|
-
}
|
|
129
|
+
};
|
|
94
130
|
if (process.env.NODE_ENV === 'development') {
|
|
95
|
-
console[logLevel](JSON.stringify(
|
|
131
|
+
console[logLevel](JSON.stringify(processedLogs, null, 2));
|
|
96
132
|
}
|
|
97
133
|
else {
|
|
98
|
-
console[logLevel](JSON.stringify(
|
|
134
|
+
console[logLevel](JSON.stringify(processedLogs));
|
|
99
135
|
}
|
|
100
136
|
}
|
|
101
|
-
snakifyKeys(value) {
|
|
137
|
+
static snakifyKeys(value) {
|
|
102
138
|
const result = {};
|
|
103
139
|
for (const key in value) {
|
|
104
140
|
const deepValue = typeof value[key] === 'object' ? this.snakifyKeys(value[key]) : value[key];
|
|
@@ -107,4 +143,20 @@ export default class Logger {
|
|
|
107
143
|
}
|
|
108
144
|
return result;
|
|
109
145
|
}
|
|
146
|
+
static pruneSensitiveMetadata(metadata, topLevelMeta) {
|
|
147
|
+
const prunedMetadata = {};
|
|
148
|
+
for (const key in metadata) {
|
|
149
|
+
if (LOGMETA_BLACKLIST.includes(key)) {
|
|
150
|
+
prunedMetadata[key] = '[REDACTED]';
|
|
151
|
+
(topLevelMeta ?? prunedMetadata).has_sensitive_attribute = true;
|
|
152
|
+
}
|
|
153
|
+
else if (typeof metadata[key] === 'object') {
|
|
154
|
+
prunedMetadata[key] = Logger.pruneSensitiveMetadata(metadata[key], topLevelMeta ?? prunedMetadata);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
prunedMetadata[key] = metadata[key];
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return prunedMetadata;
|
|
161
|
+
}
|
|
110
162
|
}
|
|
@@ -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
|
+
});
|