@rvoh/psychic 2.3.9 → 3.0.0-alpha.2

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.
Files changed (52) hide show
  1. package/dist/cjs/src/controller/helpers/logIfDevelopment.js +5 -5
  2. package/dist/cjs/src/controller/index.js +117 -40
  3. package/dist/cjs/src/devtools/helpers/launchDevServer.js +0 -1
  4. package/dist/cjs/src/error/router/cannot-commit-routes-without-koa-app.js +12 -0
  5. package/dist/cjs/src/helpers/toJson.js +2 -8
  6. package/dist/cjs/src/helpers/validateOpenApiSchema.js +1 -1
  7. package/dist/cjs/src/openapi-renderer/endpoint.js +3 -1
  8. package/dist/cjs/src/openapi-renderer/helpers/OpenapiPayloadValidator.js +75 -9
  9. package/dist/cjs/src/openapi-renderer/helpers/stringify-cache.js +55 -0
  10. package/dist/cjs/src/openapi-renderer/helpers/validator-cache.js +52 -0
  11. package/dist/cjs/src/psychic-app/helpers/import/importControllers.js +1 -1
  12. package/dist/cjs/src/psychic-app/index.js +4 -16
  13. package/dist/cjs/src/router/index.js +31 -25
  14. package/dist/cjs/src/server/helpers/startPsychicServer.js +6 -2
  15. package/dist/cjs/src/server/index.js +32 -35
  16. package/dist/cjs/src/session/index.js +9 -12
  17. package/dist/esm/src/controller/helpers/logIfDevelopment.js +5 -5
  18. package/dist/esm/src/controller/index.js +117 -40
  19. package/dist/esm/src/devtools/helpers/launchDevServer.js +0 -1
  20. package/dist/esm/src/error/router/cannot-commit-routes-without-koa-app.js +12 -0
  21. package/dist/esm/src/helpers/toJson.js +2 -8
  22. package/dist/esm/src/helpers/validateOpenApiSchema.js +1 -1
  23. package/dist/esm/src/openapi-renderer/endpoint.js +3 -1
  24. package/dist/esm/src/openapi-renderer/helpers/OpenapiPayloadValidator.js +75 -9
  25. package/dist/esm/src/openapi-renderer/helpers/stringify-cache.js +55 -0
  26. package/dist/esm/src/openapi-renderer/helpers/validator-cache.js +52 -0
  27. package/dist/esm/src/psychic-app/helpers/import/importControllers.js +1 -1
  28. package/dist/esm/src/psychic-app/index.js +4 -16
  29. package/dist/esm/src/router/index.js +31 -25
  30. package/dist/esm/src/server/helpers/startPsychicServer.js +6 -2
  31. package/dist/esm/src/server/index.js +32 -35
  32. package/dist/esm/src/session/index.js +9 -12
  33. package/dist/types/src/controller/helpers/logIfDevelopment.d.ts +3 -4
  34. package/dist/types/src/controller/index.d.ts +18 -7
  35. package/dist/types/src/error/router/cannot-commit-routes-without-koa-app.d.ts +3 -0
  36. package/dist/types/src/helpers/cookieMaxAgeFromCookieOpts.d.ts +1 -1
  37. package/dist/types/src/helpers/toJson.d.ts +1 -1
  38. package/dist/types/src/helpers/validateOpenApiSchema.d.ts +5 -1
  39. package/dist/types/src/openapi-renderer/endpoint.d.ts +7 -1
  40. package/dist/types/src/openapi-renderer/helpers/OpenapiPayloadValidator.d.ts +41 -0
  41. package/dist/types/src/openapi-renderer/helpers/stringify-cache.d.ts +34 -0
  42. package/dist/types/src/openapi-renderer/helpers/validator-cache.d.ts +35 -0
  43. package/dist/types/src/psychic-app/index.d.ts +11 -14
  44. package/dist/types/src/router/index.d.ts +17 -17
  45. package/dist/types/src/router/route-manager.d.ts +4 -3
  46. package/dist/types/src/server/helpers/startPsychicServer.d.ts +3 -3
  47. package/dist/types/src/server/index.d.ts +3 -3
  48. package/dist/types/src/session/index.d.ts +13 -5
  49. package/package.json +29 -18
  50. package/dist/cjs/src/error/router/cannot-commit-routes-without-express-app.js +0 -12
  51. package/dist/esm/src/error/router/cannot-commit-routes-without-express-app.js +0 -12
  52. package/dist/types/src/error/router/cannot-commit-routes-without-express-app.d.ts +0 -3
@@ -111,12 +111,7 @@ export default class PsychicApp {
111
111
  */
112
112
  buildOpenapiCache() {
113
113
  Object.keys(this.openapi).forEach(openapiName => {
114
- if (this.openapi[openapiName]?.validate) {
115
- this.cacheOpenapiDoc(openapiName);
116
- }
117
- else {
118
- this.ignoreOpenapiDoc(openapiName);
119
- }
114
+ this.cacheOpenapiDoc(openapiName);
120
115
  });
121
116
  }
122
117
  /**
@@ -250,7 +245,7 @@ Try setting it to something valid, like:
250
245
  get httpServerOptions() {
251
246
  return this._httpServerOptions;
252
247
  }
253
- _corsOptions = {};
248
+ _corsOptions;
254
249
  get corsOptions() {
255
250
  return this._corsOptions;
256
251
  }
@@ -274,10 +269,6 @@ Try setting it to something valid, like:
274
269
  get saltRounds() {
275
270
  return this._saltRounds;
276
271
  }
277
- _sanitizeResponseJson = false;
278
- get sanitizeResponseJson() {
279
- return this._sanitizeResponseJson;
280
- }
281
272
  _packageManager;
282
273
  get packageManager() {
283
274
  return this._packageManager;
@@ -427,7 +418,7 @@ Try setting it to something valid, like:
427
418
  const eventType = pathOrOnOrHandler;
428
419
  const handler = maybeHandler;
429
420
  const wrappedHandler = (server) => {
430
- server.expressApp.use(handler);
421
+ server.koaApp.use(handler);
431
422
  };
432
423
  switch (eventType) {
433
424
  case 'before-middleware':
@@ -446,7 +437,7 @@ Try setting it to something valid, like:
446
437
  }
447
438
  else {
448
439
  const wrappedHandler = (server) => {
449
- server.expressApp.use(pathOrOnOrHandler);
440
+ server.koaApp.use(pathOrOnOrHandler);
450
441
  };
451
442
  this.on('server:init:after-middleware', wrappedHandler);
452
443
  }
@@ -541,9 +532,6 @@ Try setting it to something valid, like:
541
532
  case 'saltRounds':
542
533
  this._saltRounds = value;
543
534
  break;
544
- case 'sanitizeResponseJson':
545
- this._sanitizeResponseJson = value;
546
- break;
547
535
  case 'openapi':
548
536
  this._openapi = {
549
537
  ...this.openapi,
@@ -1,12 +1,12 @@
1
1
  import { DataIncompatibleWithDatabaseField, RecordNotFound, ValidationError } from '@rvoh/dream/errors';
2
2
  import { camelize } from '@rvoh/dream/utils';
3
- import { Router } from 'express';
3
+ import KoaRouter from '@koa/router';
4
4
  import util, { debuglog } from 'node:util';
5
5
  import pluralize from 'pluralize-esm';
6
6
  import ParamValidationError from '../error/controller/ParamValidationError.js';
7
7
  import ParamValidationErrors from '../error/controller/ParamValidationErrors.js';
8
8
  import OpenapiRequestValidationFailure from '../error/openapi/OpenapiRequestValidationFailure.js';
9
- import CannotCommitRoutesWithoutExpressApp from '../error/router/cannot-commit-routes-without-express-app.js';
9
+ import CannotCommitRoutesWithoutKoaApp from '../error/router/cannot-commit-routes-without-koa-app.js';
10
10
  import EnvInternal from '../helpers/EnvInternal.js';
11
11
  import errorIsRescuableHttpError from '../helpers/error/errorIsRescuableHttpError.js';
12
12
  import PsychicApp from '../psychic-app/index.js';
@@ -31,19 +31,25 @@ export default class PsychicRouter {
31
31
  commit() {
32
32
  const app = this.app;
33
33
  if (!app)
34
- throw new CannotCommitRoutesWithoutExpressApp();
34
+ throw new CannotCommitRoutesWithoutKoaApp();
35
+ const router = new KoaRouter();
35
36
  this.routes.forEach(route => {
36
37
  if (route.middleware) {
37
38
  const routeConf = route;
38
- app[routeConf.httpMethod](routePath(routeConf.path), ...(Array.isArray(routeConf.middleware) ? routeConf.middleware : [routeConf.middleware]));
39
+ const middlewares = Array.isArray(routeConf.middleware)
40
+ ? routeConf.middleware
41
+ : [routeConf.middleware];
42
+ router[routeConf.httpMethod](routePath(routeConf.path), ...middlewares);
39
43
  }
40
44
  else {
41
45
  const routeConf = route;
42
- app[routeConf.httpMethod](routePath(routeConf.path), (req, res) => {
43
- this.handle(routeConf.controller, routeConf.action, { req, res }).catch(() => { });
46
+ router[routeConf.httpMethod](routePath(routeConf.path), async (ctx) => {
47
+ await this.handle(routeConf.controller, routeConf.action, { ctx });
44
48
  });
45
49
  }
46
50
  });
51
+ app.use(router.routes());
52
+ app.use(router.allowedMethods());
47
53
  }
48
54
  get(path, controller, action) {
49
55
  this.crud('get', path, controller, action);
@@ -72,7 +78,7 @@ export default class PsychicRouter {
72
78
  this.checkPathForInvalidChars(path);
73
79
  const isMiddleware = (typeof controllerOrMiddleware === 'function' || Array.isArray(controllerOrMiddleware)) &&
74
80
  !controllerOrMiddleware?.isPsychicController;
75
- // devs can provide custom express middleware which bypasses
81
+ // devs can provide custom Koa middleware which bypasses
76
82
  // the normal Controller#action paradigm.
77
83
  if (isMiddleware) {
78
84
  this.routeManager.addMiddleware({
@@ -98,7 +104,7 @@ export default class PsychicRouter {
98
104
  if (path.includes('{'))
99
105
  throw new Error(`
100
106
  The provided route "${path}" contains characters that are not supported.
101
- If you are trying to write a uri param, you will need to use expressjs
107
+ If you are trying to write a uri param, you will need to use the
102
108
  param syntax, which is a prefixing colon, rather than using brackets
103
109
  to surround the param.
104
110
 
@@ -236,10 +242,10 @@ suggested fix: "${convertRouteParams(path)}"
236
242
  * By default, do not provide an attacker with any visibility into which layer
237
243
  * of the application rejected their request.
238
244
  */
239
- async handle(controller, action, { req, res, }) {
240
- const controllerInstance = this._initializeController(controller, req, res, action);
245
+ async handle(controller, action, { ctx, }) {
246
+ const controllerInstance = this._initializeController(controller, ctx, action);
241
247
  if (typeof controllerInstance[action] !== 'function') {
242
- controllerInstance['expressSendStatus'](404);
248
+ controllerInstance['koaSendStatus'](404);
243
249
  return;
244
250
  }
245
251
  try {
@@ -250,20 +256,20 @@ suggested fix: "${convertRouteParams(path)}"
250
256
  if (errorIsRescuableHttpError(err)) {
251
257
  const httpErr = err;
252
258
  if (httpErr.data) {
253
- controllerInstance['expressSendJson'](httpErr.data, httpErr.status);
259
+ controllerInstance['koaSendJson'](httpErr.data, httpErr.status);
254
260
  }
255
261
  else {
256
- controllerInstance['expressSendStatus'](httpErr.status);
262
+ controllerInstance['koaSendStatus'](httpErr.status);
257
263
  }
258
264
  }
259
265
  else if (err instanceof RecordNotFound) {
260
- controllerInstance['expressSendStatus'](404);
266
+ controllerInstance['koaSendStatus'](404);
261
267
  }
262
268
  else if (err instanceof DataIncompatibleWithDatabaseField) {
263
269
  /**
264
270
  * See comment at top of this method for philosophy of 400
265
271
  */
266
- controllerInstance['expressSendStatus'](400);
272
+ controllerInstance['koaSendStatus'](400);
267
273
  }
268
274
  else if (err instanceof ValidationError) {
269
275
  if (this.validationErrorLoggingEnabled) {
@@ -275,7 +281,7 @@ suggested fix: "${convertRouteParams(path)}"
275
281
  /**
276
282
  * See comment at top of this method for philosophy of 400
277
283
  */
278
- controllerInstance['expressSendStatus'](400);
284
+ controllerInstance['koaSendStatus'](400);
279
285
  }
280
286
  else if (err instanceof OpenapiRequestValidationFailure) {
281
287
  if (this.validationErrorLoggingEnabled) {
@@ -288,7 +294,7 @@ suggested fix: "${convertRouteParams(path)}"
288
294
  /**
289
295
  * See comment at top of this method for philosophy of 400
290
296
  */
291
- controllerInstance['expressSendStatus'](400);
297
+ controllerInstance['koaSendStatus'](400);
292
298
  }
293
299
  else if (err instanceof ParamValidationError) {
294
300
  if (this.validationErrorLoggingEnabled) {
@@ -302,7 +308,7 @@ suggested fix: "${convertRouteParams(path)}"
302
308
  /**
303
309
  * See comment at top of this method for philosophy of 400
304
310
  */
305
- controllerInstance['expressSendStatus'](400);
311
+ controllerInstance['koaSendStatus'](400);
306
312
  }
307
313
  else if (err instanceof ParamValidationErrors) {
308
314
  if (this.validationErrorLoggingEnabled) {
@@ -314,14 +320,14 @@ suggested fix: "${convertRouteParams(path)}"
314
320
  /**
315
321
  * See comment at top of this method for philosophy of 400
316
322
  */
317
- controllerInstance['expressSendStatus'](400);
323
+ controllerInstance['koaSendStatus'](400);
318
324
  }
319
325
  else {
320
326
  PsychicApp.logWithLevel('error', util.inspect(err, { depth: ERROR_LOGGING_DEPTH }));
321
327
  if (PsychicApp.getOrFail().specialHooks.serverError.length) {
322
328
  try {
323
329
  for (const hook of PsychicApp.getOrFail().specialHooks.serverError) {
324
- await hook(err, req, res);
330
+ await hook(err, ctx);
325
331
  }
326
332
  }
327
333
  catch (error) {
@@ -348,17 +354,17 @@ suggested fix: "${convertRouteParams(path)}"
348
354
  }
349
355
  }
350
356
  }
351
- _initializeController(ControllerClass, req, res, action) {
352
- return new ControllerClass(req, res, {
357
+ _initializeController(ControllerClass, ctx, action) {
358
+ return new ControllerClass(ctx, {
353
359
  action,
354
360
  });
355
361
  }
356
362
  }
357
363
  export class PsychicNestedRouter extends PsychicRouter {
358
364
  router;
359
- constructor(expressApp, routeManager, { namespaces = [], } = {}) {
360
- super(expressApp);
361
- this.router = Router();
365
+ constructor(koaApp, routeManager, { namespaces = [], } = {}) {
366
+ super(koaApp);
367
+ this.router = new KoaRouter();
362
368
  this.currentNamespaces = namespaces;
363
369
  this.routeManager = routeManager;
364
370
  }
@@ -17,6 +17,7 @@ export default async function startPsychicServer({ app, port, sslCredentials, })
17
17
  }
18
18
  export function createPsychicHttpInstance(app, sslCredentials) {
19
19
  const psychicApp = PsychicApp.getOrFail();
20
+ const callback = app.callback();
20
21
  if (sslCredentials?.key && sslCredentials?.cert) {
21
22
  return https.createServer({
22
23
  key: fs.readFileSync(sslCredentials.key),
@@ -24,10 +25,13 @@ export function createPsychicHttpInstance(app, sslCredentials) {
24
25
  ca: sslCredentials.ca?.map(filePath => fs.readFileSync(filePath)),
25
26
  rejectUnauthorized: sslCredentials?.rejectUnauthorized,
26
27
  ...psychicApp.httpServerOptions,
27
- }, app);
28
+ },
29
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
30
+ callback);
28
31
  }
29
32
  else {
30
- return http.createServer(psychicApp.httpServerOptions, app);
33
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
34
+ return http.createServer(psychicApp.httpServerOptions, callback);
31
35
  }
32
36
  }
33
37
  function welcomeMessage({ port }) {
@@ -1,7 +1,9 @@
1
1
  import { closeAllDbConnections } from '@rvoh/dream/db';
2
- import * as cookieParser from 'cookie-parser';
3
- import * as cors from 'cors';
4
- import * as express from 'express';
2
+ import cors from '@koa/cors';
3
+ import Koa from 'koa';
4
+ import koaBodyparser from 'koa-bodyparser';
5
+ import conditional from 'koa-conditional-get';
6
+ import etag from 'koa-etag';
5
7
  import logIfDevelopment from '../controller/helpers/logIfDevelopment.js';
6
8
  import EnvInternal from '../helpers/EnvInternal.js';
7
9
  import PsychicApp from '../psychic-app/index.js';
@@ -15,14 +17,14 @@ export default class PsychicServer {
15
17
  static createPsychicHttpInstance(app, sslCredentials) {
16
18
  return createPsychicHttpInstance(app, sslCredentials);
17
19
  }
18
- expressApp;
20
+ koaApp;
19
21
  httpServer;
20
22
  booted = false;
21
23
  constructor() {
22
24
  this.buildApp();
23
25
  }
24
26
  async routes() {
25
- const r = new PsychicRouter(this.expressApp);
27
+ const r = new PsychicRouter(this.koaApp);
26
28
  await PsychicApp.getOrFail().routesCb(r);
27
29
  return r.routes;
28
30
  }
@@ -31,16 +33,19 @@ export default class PsychicServer {
31
33
  return;
32
34
  const psychicApp = PsychicApp.getOrFail();
33
35
  this.setSecureDefaultHeaders();
34
- this.expressApp.use((_, res, next) => {
36
+ this.koaApp.use(async (ctx, next) => {
35
37
  Object.keys(psychicApp.defaultResponseHeaders).forEach(key => {
36
- res.setHeader(key, psychicApp.defaultResponseHeaders[key]);
38
+ ctx.set(key, psychicApp.defaultResponseHeaders[key]);
37
39
  });
38
- next();
40
+ await next();
39
41
  });
40
42
  for (const serverInitBeforeMiddlewareHook of PsychicApp.getOrFail().specialHooks
41
43
  .serverInitBeforeMiddleware) {
42
44
  await serverInitBeforeMiddlewareHook(this);
43
45
  }
46
+ // ETag support (Express has this built-in, Koa needs middleware)
47
+ this.koaApp.use(conditional());
48
+ this.koaApp.use(etag());
44
49
  this.initializeCors();
45
50
  this.initializeJSON();
46
51
  try {
@@ -69,29 +74,23 @@ export default class PsychicServer {
69
74
  applyNotFoundMiddleware() {
70
75
  if (!EnvInternal.isDevelopment)
71
76
  return;
72
- this.expressApp.use((req, res, next) => {
73
- // express by default will set the 200 status code. If a user explicitly
74
- // provides anything other than 200, we should assume that a prior middleware
75
- // would have have sent headers, which would prevent any of this from happening.
76
- // this means that if we are here, we should not be sending a 200. Future middleware
77
- // by express will automatically pick this up and turn it into a 404, so we are
78
- // going to automatically set the status to 404 now, so that our logger can
79
- // pick up the correct status code.
80
- if (res.statusCode === 200)
81
- res.status(404);
82
- logIfDevelopment({ req, res, startTime: Date.now(), fallbackStatusCode: 404 });
83
- // call next to let express handle sending the 404
84
- next();
77
+ this.koaApp.use(async (ctx, next) => {
78
+ await next();
79
+ // Koa defaults to 404 for unmatched routes. If nothing set the body,
80
+ // log the 404 in development.
81
+ if (ctx.status === 404 && !ctx.body) {
82
+ logIfDevelopment({ ctx, startTime: Date.now(), fallbackStatusCode: 404 });
83
+ }
85
84
  });
86
85
  }
87
86
  setSecureDefaultHeaders() {
88
- this.expressApp.disable('x-powered-by');
89
- this.expressApp.use((_, res, next) => {
90
- res.setHeader('X-Content-Type-Options', 'nosniff');
87
+ // Koa doesn't send x-powered-by by default, no need to disable it.
88
+ this.koaApp.use(async (ctx, next) => {
89
+ ctx.set('X-Content-Type-Options', 'nosniff');
91
90
  if (EnvInternal.isProduction) {
92
- res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
91
+ ctx.set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
93
92
  }
94
- next();
93
+ await next();
95
94
  });
96
95
  }
97
96
  // TODO: use config helper for fetching default port
@@ -104,7 +103,7 @@ export default class PsychicServer {
104
103
  }
105
104
  else {
106
105
  const httpServer = await startPsychicServer({
107
- app: this.expressApp,
106
+ app: this.koaApp,
108
107
  port: port || psychicApp.port,
109
108
  sslCredentials: PsychicApp.getOrFail().sslCredentials,
110
109
  });
@@ -146,26 +145,24 @@ export default class PsychicServer {
146
145
  await this.boot();
147
146
  let server;
148
147
  await new Promise(accept => {
149
- server = this.expressApp.listen(port, () => accept({}));
148
+ server = this.koaApp.listen(port, () => accept({}));
150
149
  });
151
150
  await block();
152
151
  server.close();
153
152
  return true;
154
153
  }
155
154
  buildApp() {
156
- this.expressApp = express.default();
157
- this.expressApp.use(cookieParser.default());
155
+ this.koaApp = new Koa();
158
156
  }
159
157
  initializeCors() {
160
- this.expressApp.use(
161
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
162
- cors.default(PsychicApp.getOrFail().corsOptions));
158
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-argument
159
+ this.koaApp.use(cors(PsychicApp.getOrFail().corsOptions));
163
160
  }
164
161
  initializeJSON() {
165
- this.expressApp.use(express.json(PsychicApp.getOrFail().jsonOptions));
162
+ this.koaApp.use(koaBodyparser(PsychicApp.getOrFail().jsonOptions));
166
163
  }
167
164
  async buildRoutes() {
168
- const r = new PsychicRouter(this.expressApp);
165
+ const r = new PsychicRouter(this.koaApp);
169
166
  await PsychicApp.getOrFail().routesCb(r);
170
167
  r.commit();
171
168
  }
@@ -3,31 +3,28 @@ import cookieMaxAgeFromCookieOpts from '../helpers/cookieMaxAgeFromCookieOpts.js
3
3
  import EnvInternal from '../helpers/EnvInternal.js';
4
4
  import PsychicApp from '../psychic-app/index.js';
5
5
  export default class Session {
6
- req;
7
- res;
8
- constructor(req, res) {
9
- this.req = req;
10
- this.res = res;
6
+ ctx;
7
+ constructor(ctx) {
8
+ this.ctx = ctx;
11
9
  }
12
10
  getCookie(name) {
13
- const cookies = this.req.cookies;
14
- const value = cookies[name];
11
+ const value = this.ctx.cookies.get(name);
15
12
  if (value)
16
13
  return InternalEncrypt.decryptCookie(value);
17
14
  return null;
18
15
  }
19
16
  setCookie(name, data, opts = {}) {
20
- this.res.cookie(name, InternalEncrypt.encryptCookie(data), {
21
- secure: EnvInternal.isProduction,
22
- httpOnly: true,
17
+ this.ctx.cookies.set(name, InternalEncrypt.encryptCookie(data), {
23
18
  ...opts,
19
+ secure: opts.secure ?? EnvInternal.isProduction,
20
+ httpOnly: opts.httpOnly ?? true,
24
21
  maxAge: opts.maxAge
25
22
  ? cookieMaxAgeFromCookieOpts(opts.maxAge)
26
- : PsychicApp.getOrFail().cookieOptions?.maxAge,
23
+ : (PsychicApp.getOrFail().cookieOptions?.maxAge ?? cookieMaxAgeFromCookieOpts()),
27
24
  });
28
25
  }
29
26
  clearCookie(name) {
30
- this.res.clearCookie(name);
27
+ this.ctx.cookies.set(name, '', { maxAge: 0 });
31
28
  }
32
29
  daysToMilliseconds(numDays) {
33
30
  return numDays * 60 * 60 * 24 * 1000;
@@ -3,20 +3,20 @@ import colorize from '../../cli/helpers/colorize.js';
3
3
  import EnvInternal from '../../helpers/EnvInternal.js';
4
4
  import { httpMethodBgColor } from './httpMethodColor.js';
5
5
  import { statusCodeBgColor } from './statusCodeColor.js';
6
- export default function logIfDevelopment({ req, res, startTime, fallbackStatusCode = 200, }) {
6
+ export default function logIfDevelopment({ ctx, startTime, fallbackStatusCode = 200, }) {
7
7
  if (!EnvInternal.isDevelopment)
8
8
  return;
9
- const method = colorize(` ${req.method.toUpperCase()} `, {
9
+ const method = colorize(` ${ctx.method.toUpperCase()} `, {
10
10
  color: 'black',
11
- bgColor: httpMethodBgColor(req.method.toLowerCase()),
11
+ bgColor: httpMethodBgColor(ctx.method.toLowerCase()),
12
12
  });
13
- const computedStatus = res.statusCode || fallbackStatusCode;
13
+ const computedStatus = ctx.status || fallbackStatusCode;
14
14
  const statusBgColor = statusCodeBgColor(computedStatus);
15
15
  const status = colorize(` ${computedStatus} `, {
16
16
  color: 'black',
17
17
  bgColor: statusBgColor,
18
18
  });
19
- const url = colorize(req.url, { color: 'green' });
19
+ const url = colorize(ctx.url, { color: 'green' });
20
20
  const benchmark = colorize(`${Date.now() - startTime}ms`, { color: 'gray' });
21
21
  DreamCLI.logger.log(`${method} ${url} ${status} ${benchmark}`, { logPrefix: '' });
22
22
  }