@appsemble/node-utils 0.36.3 → 0.36.5-test.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/container/helpers.js +11 -8
- package/container/logs.js +3 -1
- package/container/operations.js +74 -57
- package/container/scale.js +18 -7
- package/icon.js +0 -2
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/middleware/loggerMiddleware.js +7 -4
- package/package.json +6 -6
- package/requestContext.d.ts +10 -0
- package/requestContext.js +14 -0
- package/server/types.d.ts +1 -0
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
#  Appsemble Node Utilities
|
|
2
2
|
|
|
3
3
|
> NodeJS utilities used by Appsemble internally.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/@appsemble/node-utils)
|
|
6
|
-
[](https://gitlab.com/appsemble/appsemble/-/releases/0.36.5-test.0)
|
|
7
7
|
[](https://prettier.io)
|
|
8
8
|
|
|
9
9
|
## Table of Contents
|
|
@@ -26,5 +26,5 @@ compatibility is not guaranteed.
|
|
|
26
26
|
|
|
27
27
|
## License
|
|
28
28
|
|
|
29
|
-
[LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.36.
|
|
29
|
+
[LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.36.5-test.0/LICENSE.md) ©
|
|
30
30
|
[Appsemble](https://appsemble.com)
|
package/container/helpers.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { logger } from '@appsemble/node-utils';
|
|
2
|
-
import { AppsV1Api, CoreV1Api,
|
|
2
|
+
import { ApiException, AppsV1Api, CoreV1Api, KubeConfig, } from '@kubernetes/client-node';
|
|
3
3
|
export const maxCPU = process.env.MAX_CONTAINER_CPU ?? 3;
|
|
4
4
|
// In gigabytes
|
|
5
5
|
export const maxMemoryGi = process.env.MAX_CONTAINER_MEMORY ?? 3;
|
|
@@ -23,10 +23,9 @@ export function formatSecretName(appName, appId) {
|
|
|
23
23
|
return `${appName}-${appId}`.toLocaleLowerCase().replaceAll(' ', '-');
|
|
24
24
|
}
|
|
25
25
|
export function handleKubernetesError(error) {
|
|
26
|
-
if (error instanceof
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
logger.warn(`Kubernetes error with status code ${statusCode}:`);
|
|
26
|
+
if (error instanceof ApiException) {
|
|
27
|
+
if (error.code) {
|
|
28
|
+
logger.warn(`Kubernetes error with status code ${error.code}:`);
|
|
30
29
|
}
|
|
31
30
|
logger.warn(error.body);
|
|
32
31
|
return;
|
|
@@ -42,13 +41,17 @@ export async function deleteResource(type, namespace, name) {
|
|
|
42
41
|
logger.silly(`Deleting ${type} '${name}' from namespace ${namespace} ... `);
|
|
43
42
|
switch (type) {
|
|
44
43
|
case 'deployment':
|
|
45
|
-
await appsApi.deleteNamespacedDeployment(
|
|
44
|
+
await appsApi.deleteNamespacedDeployment({
|
|
45
|
+
name,
|
|
46
|
+
namespace,
|
|
47
|
+
propagationPolicy: 'Background',
|
|
48
|
+
});
|
|
46
49
|
break;
|
|
47
50
|
case 'service':
|
|
48
|
-
await coreApi.deleteNamespacedService(name, namespace);
|
|
51
|
+
await coreApi.deleteNamespacedService({ name, namespace });
|
|
49
52
|
break;
|
|
50
53
|
default:
|
|
51
|
-
await coreApi.deleteNamespacedSecret(name, namespace);
|
|
54
|
+
await coreApi.deleteNamespacedSecret({ name, namespace });
|
|
52
55
|
}
|
|
53
56
|
logger.verbose(`Deleted ${type} '${name}' from namespace ${namespace}`);
|
|
54
57
|
}
|
package/container/logs.js
CHANGED
|
@@ -52,7 +52,9 @@ export async function getLogs(deploymentName, fromAppsemble) {
|
|
|
52
52
|
}
|
|
53
53
|
logger.silly(`Using namespace ${appsembleNamespace}`);
|
|
54
54
|
try {
|
|
55
|
-
pods =
|
|
55
|
+
pods = await coreApi.listNamespacedPod({
|
|
56
|
+
namespace: fromAppsemble ? appsembleNamespace : containerNamespace,
|
|
57
|
+
});
|
|
56
58
|
}
|
|
57
59
|
catch (error) {
|
|
58
60
|
handleKubernetesError(error);
|
package/container/operations.js
CHANGED
|
@@ -28,7 +28,7 @@ export async function updateNamespacedSecret(secretName, value, appName, appId)
|
|
|
28
28
|
};
|
|
29
29
|
let existing;
|
|
30
30
|
try {
|
|
31
|
-
existing =
|
|
31
|
+
existing = await coreApi.readNamespacedSecret({ name: formattedName, namespace });
|
|
32
32
|
}
|
|
33
33
|
catch (error) {
|
|
34
34
|
handleKubernetesError(error);
|
|
@@ -40,7 +40,11 @@ export async function updateNamespacedSecret(secretName, value, appName, appId)
|
|
|
40
40
|
}
|
|
41
41
|
existing.data[secretName] = Buffer.from(value).toString('base64');
|
|
42
42
|
try {
|
|
43
|
-
const
|
|
43
|
+
const updatedSecret = await coreApi.replaceNamespacedSecret({
|
|
44
|
+
name: formattedName,
|
|
45
|
+
namespace,
|
|
46
|
+
body: existing,
|
|
47
|
+
});
|
|
44
48
|
logger.info(`Secret ${updatedSecret.metadata?.name} updated successfully`);
|
|
45
49
|
}
|
|
46
50
|
catch (error) {
|
|
@@ -50,7 +54,7 @@ export async function updateNamespacedSecret(secretName, value, appName, appId)
|
|
|
50
54
|
}
|
|
51
55
|
try {
|
|
52
56
|
logger.verbose(`Creating secret ${secretSpec.metadata?.name} ...`);
|
|
53
|
-
const
|
|
57
|
+
const secret = await coreApi.createNamespacedSecret({ namespace, body: secretSpec });
|
|
54
58
|
logger.info(`Secret ${secret.metadata?.name} created successfully`);
|
|
55
59
|
}
|
|
56
60
|
catch (error) {
|
|
@@ -66,14 +70,14 @@ export async function deleteSecret(appName, appId, key) {
|
|
|
66
70
|
const secretName = formatSecretName(appName, appId);
|
|
67
71
|
if (key) {
|
|
68
72
|
try {
|
|
69
|
-
const
|
|
73
|
+
const secret = await coreApi.readNamespacedSecret({ name: secretName, namespace });
|
|
70
74
|
logger.verbose(`Deleteing key ${key} of secret ${secretName} from namespace ${namespace} ...`);
|
|
71
75
|
if (!(secret.data && key in secret.data)) {
|
|
72
76
|
logger.warn(`Key ${key} does not exist on secret ${secret.metadata?.name}`);
|
|
73
77
|
return;
|
|
74
78
|
}
|
|
75
79
|
delete secret.data[key];
|
|
76
|
-
await coreApi.replaceNamespacedSecret(secretName, namespace, secret);
|
|
80
|
+
await coreApi.replaceNamespacedSecret({ name: secretName, namespace, body: secret });
|
|
77
81
|
logger.verbose(`Deleted key ${key} of secret ${secretName} from namespace ${namespace}.`);
|
|
78
82
|
}
|
|
79
83
|
catch (error) {
|
|
@@ -103,7 +107,7 @@ export async function updateCompanionContainers(definitions, appName, appId, reg
|
|
|
103
107
|
let services;
|
|
104
108
|
logger.silly(`Listing services in namespace ${namespace} ...`);
|
|
105
109
|
try {
|
|
106
|
-
services =
|
|
110
|
+
services = await coreApi.listNamespacedService({ namespace });
|
|
107
111
|
}
|
|
108
112
|
catch (error) {
|
|
109
113
|
logger.error(`Error listing services in namespace ${namespace}`);
|
|
@@ -117,39 +121,36 @@ export async function updateCompanionContainers(definitions, appName, appId, reg
|
|
|
117
121
|
// Update
|
|
118
122
|
if (existing) {
|
|
119
123
|
logger.verbose(`Updating resources for ${existing.metadata?.name} in namespace ${namespace}`);
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
],
|
|
142
|
-
undefined,
|
|
143
|
-
undefined,
|
|
144
|
-
undefined,
|
|
145
|
-
undefined,
|
|
146
|
-
undefined,
|
|
147
|
-
{ headers: { 'Content-Type': 'application/json-patch+json' } },
|
|
124
|
+
const existingServiceName = existing.metadata?.name;
|
|
125
|
+
if (!existingServiceName) {
|
|
126
|
+
logger.warn(`Service without metadata.name found in namespace ${namespace}, skipping ...`);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const servicePatch = [
|
|
130
|
+
{
|
|
131
|
+
op: 'replace',
|
|
132
|
+
path: '/metadata',
|
|
133
|
+
value: { ...def.metadata, name: existingServiceName },
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
op: 'replace',
|
|
137
|
+
path: '/spec/ports/0/targetPort',
|
|
138
|
+
value: def.port ?? 8080,
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
op: 'add',
|
|
142
|
+
path: '/metadata/labels',
|
|
143
|
+
value: { appId },
|
|
144
|
+
},
|
|
148
145
|
];
|
|
149
146
|
// Update service
|
|
150
147
|
try {
|
|
151
|
-
const updatedService = await coreApi.patchNamespacedService(
|
|
152
|
-
|
|
148
|
+
const updatedService = await coreApi.patchNamespacedService({
|
|
149
|
+
name: existingServiceName,
|
|
150
|
+
namespace,
|
|
151
|
+
body: servicePatch,
|
|
152
|
+
});
|
|
153
|
+
logger.info(`Service ${updatedService?.metadata?.name} updated`);
|
|
153
154
|
}
|
|
154
155
|
catch (error) {
|
|
155
156
|
logger.error('Error updating service:');
|
|
@@ -157,12 +158,11 @@ export async function updateCompanionContainers(definitions, appName, appId, reg
|
|
|
157
158
|
}
|
|
158
159
|
// Update deployment
|
|
159
160
|
const resources = validateContainerResources(def.resources);
|
|
160
|
-
|
|
161
|
+
const deploymentPatch = [
|
|
161
162
|
{
|
|
162
163
|
op: 'replace',
|
|
163
164
|
path: '/metadata',
|
|
164
|
-
|
|
165
|
-
value: { ...def.metadata, name: existing.metadata.name },
|
|
165
|
+
value: { ...def.metadata, name: existingServiceName },
|
|
166
166
|
},
|
|
167
167
|
{
|
|
168
168
|
op: 'replace',
|
|
@@ -186,8 +186,12 @@ export async function updateCompanionContainers(definitions, appName, appId, reg
|
|
|
186
186
|
},
|
|
187
187
|
];
|
|
188
188
|
try {
|
|
189
|
-
const updatedDeployment = await appsApi.patchNamespacedDeployment(
|
|
190
|
-
|
|
189
|
+
const updatedDeployment = await appsApi.patchNamespacedDeployment({
|
|
190
|
+
name: existingServiceName,
|
|
191
|
+
namespace,
|
|
192
|
+
body: deploymentPatch,
|
|
193
|
+
});
|
|
194
|
+
logger.info(`Deployment ${updatedDeployment?.metadata?.name} updated`);
|
|
191
195
|
}
|
|
192
196
|
catch (error) {
|
|
193
197
|
logger.error('Error updating deployment:');
|
|
@@ -195,12 +199,19 @@ export async function updateCompanionContainers(definitions, appName, appId, reg
|
|
|
195
199
|
}
|
|
196
200
|
// Update pod
|
|
197
201
|
try {
|
|
198
|
-
const
|
|
199
|
-
|
|
202
|
+
const podList = await coreApi.listNamespacedPod({
|
|
203
|
+
namespace,
|
|
204
|
+
labelSelector: `appId=${appId}`,
|
|
205
|
+
});
|
|
206
|
+
if (podList.items.length === 0) {
|
|
200
207
|
logger.silly(`Deployment ${serviceName} has 0 pods, skipping ...`);
|
|
201
208
|
continue;
|
|
202
209
|
}
|
|
203
|
-
const pod =
|
|
210
|
+
const pod = podList.items.find((item) => item.metadata?.labels?.app === existingServiceName);
|
|
211
|
+
if (!pod?.metadata?.name) {
|
|
212
|
+
logger.silly(`Deployment ${serviceName} has no matching pod with metadata.name, skipping`);
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
204
215
|
// Set base labels, such as selector, pod name, pod hash
|
|
205
216
|
const props = {
|
|
206
217
|
...def.metadata,
|
|
@@ -210,19 +221,21 @@ export async function updateCompanionContainers(definitions, appName, appId, reg
|
|
|
210
221
|
'pod-template-hash': pod?.metadata?.labels?.['pod-template-hash'],
|
|
211
222
|
appId,
|
|
212
223
|
},
|
|
213
|
-
name: pod
|
|
224
|
+
name: pod.metadata.name,
|
|
214
225
|
};
|
|
215
|
-
|
|
216
|
-
patchOptions[0] = pod?.metadata?.name;
|
|
217
|
-
patchOptions[2] = [
|
|
226
|
+
const podPatch = [
|
|
218
227
|
{
|
|
219
228
|
op: 'replace',
|
|
220
229
|
path: '/metadata',
|
|
221
230
|
value: props,
|
|
222
231
|
},
|
|
223
232
|
];
|
|
224
|
-
const updatedPod = await coreApi.patchNamespacedPod(
|
|
225
|
-
|
|
233
|
+
const updatedPod = await coreApi.patchNamespacedPod({
|
|
234
|
+
name: pod.metadata.name,
|
|
235
|
+
namespace,
|
|
236
|
+
body: podPatch,
|
|
237
|
+
});
|
|
238
|
+
logger.verbose(`Pod updated: ${updatedPod?.metadata?.name}`);
|
|
226
239
|
}
|
|
227
240
|
catch (error) {
|
|
228
241
|
handleKubernetesError(error);
|
|
@@ -236,16 +249,19 @@ export async function updateCompanionContainers(definitions, appName, appId, reg
|
|
|
236
249
|
if (isWhitelisted(deployment.spec?.template.spec?.containers[0].image)) {
|
|
237
250
|
logger.verbose(`Creating resources in namespace ${namespace} ...`);
|
|
238
251
|
try {
|
|
239
|
-
const deploymentObj = await appsApi.createNamespacedDeployment(
|
|
240
|
-
|
|
252
|
+
const deploymentObj = await appsApi.createNamespacedDeployment({
|
|
253
|
+
namespace,
|
|
254
|
+
body: deployment,
|
|
255
|
+
});
|
|
256
|
+
logger.info(`Deployment created: ${deploymentObj.metadata?.name}`);
|
|
241
257
|
}
|
|
242
258
|
catch (error) {
|
|
243
259
|
handleKubernetesError(error);
|
|
244
260
|
return;
|
|
245
261
|
}
|
|
246
262
|
try {
|
|
247
|
-
const serviceObj = await coreApi.createNamespacedService(namespace, service);
|
|
248
|
-
logger.info(`Service created: ${serviceObj.
|
|
263
|
+
const serviceObj = await coreApi.createNamespacedService({ namespace, body: service });
|
|
264
|
+
logger.info(`Service created: ${serviceObj.metadata?.name}`);
|
|
249
265
|
}
|
|
250
266
|
catch (error) {
|
|
251
267
|
handleKubernetesError(error);
|
|
@@ -266,9 +282,10 @@ export async function updateCompanionContainers(definitions, appName, appId, reg
|
|
|
266
282
|
service.metadata.labels[appIdLabel] === appId) {
|
|
267
283
|
const existing = definitions.find((d) => formatServiceName(d.name, appName, appId) === service.metadata?.name);
|
|
268
284
|
if (!existing) {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
285
|
+
if (!service.metadata?.name) {
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
await deleteCompanionContainers(service.metadata.name);
|
|
272
289
|
}
|
|
273
290
|
}
|
|
274
291
|
}
|
package/container/scale.js
CHANGED
|
@@ -10,7 +10,11 @@ export async function scaleDeployment(namespace, deploymentName, replicas = 0) {
|
|
|
10
10
|
});
|
|
11
11
|
try {
|
|
12
12
|
logger.verbose(`Scaling deployment ${deploymentName} to ${replicas} replicas ... `);
|
|
13
|
-
await appsApi.patchNamespacedDeployment(
|
|
13
|
+
await appsApi.patchNamespacedDeployment({
|
|
14
|
+
name: deploymentName,
|
|
15
|
+
namespace,
|
|
16
|
+
body: patch,
|
|
17
|
+
});
|
|
14
18
|
logger.verbose(`Deployment ${deploymentName} scaled to ${replicas} replicas successfully `);
|
|
15
19
|
}
|
|
16
20
|
catch (error) {
|
|
@@ -23,7 +27,7 @@ export async function stopIdleContainers(interval = 10) {
|
|
|
23
27
|
let deployments;
|
|
24
28
|
logger.verbose('Scaling containers');
|
|
25
29
|
try {
|
|
26
|
-
deployments =
|
|
30
|
+
deployments = await appsApi.listDeploymentForAllNamespaces();
|
|
27
31
|
}
|
|
28
32
|
catch (error) {
|
|
29
33
|
handleKubernetesError(error);
|
|
@@ -52,7 +56,7 @@ export async function stopIdleContainers(interval = 10) {
|
|
|
52
56
|
];
|
|
53
57
|
try {
|
|
54
58
|
logger.silly(`Updating metadata of deployment ${name}`);
|
|
55
|
-
await appsApi.patchNamespacedDeployment(name, namespace,
|
|
59
|
+
await appsApi.patchNamespacedDeployment({ name, namespace, body: patch });
|
|
56
60
|
logger.verbose(`Updated metadata of deployment ${name} successfully `);
|
|
57
61
|
}
|
|
58
62
|
catch (error) {
|
|
@@ -73,9 +77,12 @@ export async function waitForPodReadiness(namespace, appSelector, maxWait = 1000
|
|
|
73
77
|
let elapsed = 0;
|
|
74
78
|
const { coreApi } = getKubeConfig();
|
|
75
79
|
while (!isReady) {
|
|
76
|
-
const pods = await coreApi.listNamespacedPod(
|
|
77
|
-
|
|
78
|
-
|
|
80
|
+
const pods = await coreApi.listNamespacedPod({
|
|
81
|
+
namespace,
|
|
82
|
+
labelSelector: `app=${appSelector}`,
|
|
83
|
+
});
|
|
84
|
+
if (pods.items.length > 0) {
|
|
85
|
+
isReady = pods.items.every((pod) => pod.status?.conditions?.some((condition) => condition.type === 'Ready' && condition.status === 'True'));
|
|
79
86
|
}
|
|
80
87
|
if (!isReady) {
|
|
81
88
|
logger.silly(`Waiting for ${appSelector} to be ready ...`);
|
|
@@ -102,7 +109,11 @@ export async function setLastRequestAnnotation(namespace, deploymentName) {
|
|
|
102
109
|
];
|
|
103
110
|
try {
|
|
104
111
|
logger.silly(`Setting 'lastRequestTimestamp' annotation of '${deploymentName}' to ${now.toISOString()}`);
|
|
105
|
-
await appsApi.patchNamespacedDeployment(
|
|
112
|
+
await appsApi.patchNamespacedDeployment({
|
|
113
|
+
name: deploymentName,
|
|
114
|
+
namespace,
|
|
115
|
+
body: patch,
|
|
116
|
+
});
|
|
106
117
|
logger.silly(`'LastRequestTimestamp' annotation of '${deploymentName}' updated successfully`);
|
|
107
118
|
}
|
|
108
119
|
catch (error) {
|
package/icon.js
CHANGED
|
@@ -16,7 +16,6 @@ export async function serveIcon(ctx, { background, cache, fallback, height, icon
|
|
|
16
16
|
if (raw) {
|
|
17
17
|
const { format } = await img.metadata();
|
|
18
18
|
ctx.body = buffer;
|
|
19
|
-
// @ts-expect-error 2322 null is not assignable to type (strictNullChecks)
|
|
20
19
|
ctx.type = format;
|
|
21
20
|
return;
|
|
22
21
|
}
|
|
@@ -42,7 +41,6 @@ export async function serveIcon(ctx, { background, cache, fallback, height, icon
|
|
|
42
41
|
// Make the regular icon maskable
|
|
43
42
|
const actual = img;
|
|
44
43
|
const metadata = await actual.metadata();
|
|
45
|
-
// @ts-expect-error 18048 variable is possibly undefined (strictNullChecks)
|
|
46
44
|
const angle = Math.atan(metadata.height / metadata.width);
|
|
47
45
|
actual.resize({
|
|
48
46
|
// @ts-expect-error 18048 variable is possibly undefined (strictNullChecks)
|
package/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export * from './handleError.js';
|
|
|
7
7
|
export * from './interceptors.js';
|
|
8
8
|
export * from './logger.js';
|
|
9
9
|
export * from './middleware/loggerMiddleware.js';
|
|
10
|
+
export * from './requestContext.js';
|
|
10
11
|
export * from './middleware/error.js';
|
|
11
12
|
export * from './middleware/conditional.js';
|
|
12
13
|
export * from './middleware/frontend.js';
|
package/index.js
CHANGED
|
@@ -7,6 +7,7 @@ export * from './handleError.js';
|
|
|
7
7
|
export * from './interceptors.js';
|
|
8
8
|
export * from './logger.js';
|
|
9
9
|
export * from './middleware/loggerMiddleware.js';
|
|
10
|
+
export * from './requestContext.js';
|
|
10
11
|
export * from './middleware/error.js';
|
|
11
12
|
export * from './middleware/conditional.js';
|
|
12
13
|
export * from './middleware/frontend.js';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import { logger } from '../logger.js';
|
|
3
|
+
import { createRequestContext, requestStore } from '../requestContext.js';
|
|
3
4
|
function rangeFormat(value, map) {
|
|
4
5
|
// @ts-expect-error 2532 Object is possibly 'undefined'.
|
|
5
6
|
return Object.entries(map).find(([v]) => v === 'default' || value < Number(v))[1];
|
|
@@ -14,7 +15,9 @@ export function loggerMiddleware() {
|
|
|
14
15
|
const { href, res } = ctx;
|
|
15
16
|
const start = Date.now();
|
|
16
17
|
const method = chalk.bold(ctx.method);
|
|
17
|
-
|
|
18
|
+
const context = createRequestContext(ctx.method, ctx.path);
|
|
19
|
+
const reqIdPrefix = `[${context.requestId.slice(0, 8)}] `;
|
|
20
|
+
logger.info(`${reqIdPrefix}${method} ${href} — ${chalk.white(ctx.ip)}`);
|
|
18
21
|
function logResponse() {
|
|
19
22
|
res.removeListener('finish', logResponse);
|
|
20
23
|
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
@@ -40,7 +43,7 @@ export function loggerMiddleware() {
|
|
|
40
43
|
500: 'warn',
|
|
41
44
|
default: 'error',
|
|
42
45
|
});
|
|
43
|
-
logger.log(level, `${method} ${href} ${formatStatus(location ? `${s} → ${location}` : s)} ${formatDuration(`${duration}ms`)}`);
|
|
46
|
+
logger.log(level, `${reqIdPrefix}${method} ${href} ${formatStatus(location ? `${s} → ${location}` : s)} ${formatDuration(`${duration}ms`)}`);
|
|
44
47
|
}
|
|
45
48
|
function logCancel() {
|
|
46
49
|
res.removeListener('finish', logResponse);
|
|
@@ -51,11 +54,11 @@ export function loggerMiddleware() {
|
|
|
51
54
|
1000: chalk.yellow,
|
|
52
55
|
default: chalk.red,
|
|
53
56
|
});
|
|
54
|
-
logger.warn(`${method} ${href} ${chalk.grey('Cancelled')} ${formatDuration(`${duration}ms`)}`);
|
|
57
|
+
logger.warn(`${reqIdPrefix}${method} ${href} ${chalk.grey('Cancelled')} ${formatDuration(`${duration}ms`)}`);
|
|
55
58
|
}
|
|
56
59
|
res.once('finish', logResponse);
|
|
57
60
|
res.once('close', logCancel);
|
|
58
|
-
return next
|
|
61
|
+
return requestStore.run(context, next);
|
|
59
62
|
};
|
|
60
63
|
}
|
|
61
64
|
//# sourceMappingURL=loggerMiddleware.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@appsemble/node-utils",
|
|
3
|
-
"version": "0.36.
|
|
3
|
+
"version": "0.36.5-test.0",
|
|
4
4
|
"description": "NodeJS utilities used by Appsemble internally.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"app",
|
|
@@ -40,12 +40,12 @@
|
|
|
40
40
|
"test": "vitest"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@appsemble/lang-sdk": "0.36.
|
|
44
|
-
"@appsemble/types": "0.36.
|
|
45
|
-
"@appsemble/utils": "0.36.
|
|
43
|
+
"@appsemble/lang-sdk": "0.36.5-test.0",
|
|
44
|
+
"@appsemble/types": "0.36.5-test.0",
|
|
45
|
+
"@appsemble/utils": "0.36.5-test.0",
|
|
46
46
|
"@formatjs/fast-memoize": "^2.0.0",
|
|
47
47
|
"@fortawesome/fontawesome-free": "^6.0.0",
|
|
48
|
-
"@kubernetes/client-node": "
|
|
48
|
+
"@kubernetes/client-node": "1.4.0",
|
|
49
49
|
"@odata/parser": "^0.2.0",
|
|
50
50
|
"@types/koa": "^2.0.0",
|
|
51
51
|
"axios": "^1.0.0",
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
"pg": "^8.16.3",
|
|
92
92
|
"request-filtering-agent": "^3.2.0",
|
|
93
93
|
"sass": "^1.0.0",
|
|
94
|
-
"sharp": "
|
|
94
|
+
"sharp": "0.34.5",
|
|
95
95
|
"sort-keys": "^5.0.0",
|
|
96
96
|
"strip-bom": "^5.0.0",
|
|
97
97
|
"type-fest": "^4.0.0",
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
interface RequestContext {
|
|
3
|
+
requestId: string;
|
|
4
|
+
method: string;
|
|
5
|
+
path: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const requestStore: AsyncLocalStorage<RequestContext>;
|
|
8
|
+
export declare function getRequestId(): string | undefined;
|
|
9
|
+
export declare function createRequestContext(method: string, path: string): RequestContext;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
export const requestStore = new AsyncLocalStorage();
|
|
4
|
+
export function getRequestId() {
|
|
5
|
+
return requestStore.getStore()?.requestId;
|
|
6
|
+
}
|
|
7
|
+
export function createRequestContext(method, path) {
|
|
8
|
+
return {
|
|
9
|
+
requestId: randomUUID(),
|
|
10
|
+
method,
|
|
11
|
+
path,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=requestContext.js.map
|