@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 CHANGED
@@ -1,9 +1,9 @@
1
- # ![](https://gitlab.com/appsemble/appsemble/-/raw/0.36.3/config/assets/logo.svg) Appsemble Node Utilities
1
+ # ![](https://gitlab.com/appsemble/appsemble/-/raw/0.36.5-test.0/config/assets/logo.svg) Appsemble Node Utilities
2
2
 
3
3
  > NodeJS utilities used by Appsemble internally.
4
4
 
5
5
  [![npm](https://img.shields.io/npm/v/@appsemble/node-utils)](https://www.npmjs.com/package/@appsemble/node-utils)
6
- [![GitLab CI](https://gitlab.com/appsemble/appsemble/badges/0.36.3/pipeline.svg)](https://gitlab.com/appsemble/appsemble/-/releases/0.36.3)
6
+ [![GitLab CI](https://gitlab.com/appsemble/appsemble/badges/0.36.5-test.0/pipeline.svg)](https://gitlab.com/appsemble/appsemble/-/releases/0.36.5-test.0)
7
7
  [![Prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](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.3/LICENSE.md) ©
29
+ [LGPL-3.0-only](https://gitlab.com/appsemble/appsemble/-/blob/0.36.5-test.0/LICENSE.md) ©
30
30
  [Appsemble](https://appsemble.com)
@@ -1,5 +1,5 @@
1
1
  import { logger } from '@appsemble/node-utils';
2
- import { AppsV1Api, CoreV1Api, HttpError, KubeConfig, } from '@kubernetes/client-node';
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 HttpError) {
27
- const { statusCode } = error;
28
- if (statusCode) {
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(name, namespace, undefined, undefined, undefined, undefined, 'Background');
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 = (await coreApi.listNamespacedPod(fromAppsemble ? appsembleNamespace : containerNamespace)).body;
55
+ pods = await coreApi.listNamespacedPod({
56
+ namespace: fromAppsemble ? appsembleNamespace : containerNamespace,
57
+ });
56
58
  }
57
59
  catch (error) {
58
60
  handleKubernetesError(error);
@@ -28,7 +28,7 @@ export async function updateNamespacedSecret(secretName, value, appName, appId)
28
28
  };
29
29
  let existing;
30
30
  try {
31
- existing = (await coreApi.readNamespacedSecret(formattedName, namespace)).body;
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 { body: updatedSecret } = await coreApi.replaceNamespacedSecret(formattedName, namespace, existing);
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 { body: secret } = await coreApi.createNamespacedSecret(namespace, secretSpec);
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 { body: secret } = await coreApi.readNamespacedSecret(secretName, namespace);
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 = (await coreApi.listNamespacedService(namespace)).body;
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 patchOptions = [
121
- // @ts-expect-error 18048 variable is possibly undefined (strictNullChecks)
122
- existing.metadata.name,
123
- namespace,
124
- [
125
- {
126
- op: 'replace',
127
- path: '/metadata',
128
- // @ts-expect-error 18048 variable is possibly undefined (strictNullChecks)
129
- value: { ...def.metadata, name: existing.metadata.name },
130
- },
131
- {
132
- op: 'replace',
133
- path: '/spec/ports/0/targetPort',
134
- value: def.port ?? 8080,
135
- },
136
- {
137
- op: 'add',
138
- path: '/metadata/labels',
139
- value: { appId },
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(...patchOptions);
152
- logger.info(`Service ${updatedService?.body?.metadata?.name} updated`);
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
- patchOptions[2] = [
161
+ const deploymentPatch = [
161
162
  {
162
163
  op: 'replace',
163
164
  path: '/metadata',
164
- // @ts-expect-error 18048 variable is possibly undefined (strictNullChecks)
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(...patchOptions);
190
- logger.info(`Deployment ${updatedDeployment?.body?.metadata?.name} updated`);
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 { body } = await coreApi.listNamespacedPod(namespace, undefined, undefined, undefined, undefined, `appId=${appId}`);
199
- if (body?.items?.length === 0) {
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 = body?.items?.find((i) => i.metadata?.labels?.app === existing.metadata?.name);
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?.metadata?.name,
224
+ name: pod.metadata.name,
214
225
  };
215
- // @ts-expect-error 2322 null is not assignable to type (strictNullChecks)
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(...patchOptions);
225
- logger.verbose(`Pod updated: ${updatedPod?.body?.metadata?.name}`);
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(namespace, deployment);
240
- logger.info(`Deployment created: ${deploymentObj.body?.metadata?.name}`);
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.body.metadata?.name}`);
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
- // @ts-expect-error 2345 argument of type is not assignable to parameter of type
270
- // (strictNullChecks)
271
- await deleteCompanionContainers(service.metadata?.name);
285
+ if (!service.metadata?.name) {
286
+ continue;
287
+ }
288
+ await deleteCompanionContainers(service.metadata.name);
272
289
  }
273
290
  }
274
291
  }
@@ -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(deploymentName, namespace, patch, undefined, undefined, undefined, undefined, undefined, { headers: { 'Content-Type': 'application/json-patch+json' } });
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 = (await appsApi.listDeploymentForAllNamespaces()).body;
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, patch, undefined, undefined, undefined, undefined, undefined, { headers: { 'Content-Type': 'application/json-patch+json' } });
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(namespace, undefined, undefined, undefined, undefined, `app=${appSelector}`);
77
- if (pods.body.items.length > 0) {
78
- isReady = pods.body?.items.every((pod) => pod.status?.conditions?.some((condition) => condition.type === 'Ready' && condition.status === 'True'));
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(deploymentName, namespace, patch, undefined, undefined, undefined, undefined, undefined, { headers: { 'Content-Type': 'application/json-patch+json' } });
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
- logger.info(`${method} ${href} ${chalk.white(ctx.ip)}`);
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",
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.3",
44
- "@appsemble/types": "0.36.3",
45
- "@appsemble/utils": "0.36.3",
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": "^0.22.2",
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": "^0.32.0",
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
package/server/types.d.ts CHANGED
@@ -118,6 +118,7 @@ declare module 'koas-parameters' {
118
118
  email: string;
119
119
  width?: number;
120
120
  height?: number;
121
+ secret: string;
121
122
  }
122
123
  }
123
124
  export type Operator = 'and' | 'not' | 'or';