@rvoh/psychic 1.10.4 → 1.11.0-beta.1

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 (41) hide show
  1. package/dist/cjs/src/bin/helpers/enumsFileStr.js +1 -0
  2. package/dist/cjs/src/cli/helpers/PsychicLogos.js +38 -0
  3. package/dist/cjs/src/cli/index.js +4 -4
  4. package/dist/cjs/src/controller/helpers/httpMethodColor.js +34 -0
  5. package/dist/cjs/src/controller/helpers/logIfDevelopment.js +28 -0
  6. package/dist/cjs/src/controller/helpers/statusCodeColor.js +22 -0
  7. package/dist/cjs/src/controller/index.js +32 -13
  8. package/dist/cjs/src/generate/helpers/generateResourceControllerSpecContent.js +71 -60
  9. package/dist/cjs/src/generate/resource.js +2 -1
  10. package/dist/cjs/src/openapi-renderer/SerializerOpenapiRenderer.js +28 -29
  11. package/dist/cjs/src/openapi-renderer/endpoint.js +8 -2
  12. package/dist/cjs/src/psychic-app/index.js +2 -2
  13. package/dist/cjs/src/router/index.js +10 -19
  14. package/dist/cjs/src/server/helpers/startPsychicServer.js +17 -4
  15. package/dist/cjs/src/server/index.js +20 -3
  16. package/dist/esm/src/bin/helpers/enumsFileStr.js +1 -0
  17. package/dist/esm/src/cli/helpers/PsychicLogos.js +32 -0
  18. package/dist/esm/src/cli/index.js +4 -4
  19. package/dist/esm/src/controller/helpers/httpMethodColor.js +30 -0
  20. package/dist/esm/src/controller/helpers/logIfDevelopment.js +22 -0
  21. package/dist/esm/src/controller/helpers/statusCodeColor.js +18 -0
  22. package/dist/esm/src/controller/index.js +32 -13
  23. package/dist/esm/src/generate/helpers/generateResourceControllerSpecContent.js +71 -60
  24. package/dist/esm/src/generate/resource.js +2 -1
  25. package/dist/esm/src/openapi-renderer/SerializerOpenapiRenderer.js +28 -29
  26. package/dist/esm/src/openapi-renderer/endpoint.js +8 -2
  27. package/dist/esm/src/psychic-app/index.js +2 -2
  28. package/dist/esm/src/router/index.js +10 -19
  29. package/dist/esm/src/server/helpers/startPsychicServer.js +17 -4
  30. package/dist/esm/src/server/index.js +21 -4
  31. package/dist/types/src/cli/helpers/PsychicLogos.d.ts +3 -0
  32. package/dist/types/src/controller/helpers/httpMethodColor.d.ts +4 -0
  33. package/dist/types/src/controller/helpers/logIfDevelopment.d.ts +7 -0
  34. package/dist/types/src/controller/helpers/statusCodeColor.d.ts +3 -0
  35. package/dist/types/src/controller/index.d.ts +5 -1
  36. package/dist/types/src/helpers/EnvInternal.d.ts +2 -2
  37. package/dist/types/src/openapi-renderer/endpoint.d.ts +39 -1
  38. package/dist/types/src/server/index.d.ts +1 -1
  39. package/dist/types/src/server/params.d.ts +2 -1
  40. package/package.json +8 -7
  41. package/CHANGELOG.md +0 -314
@@ -62,7 +62,7 @@ class PsychicApp {
62
62
  */
63
63
  static async init(cb, dreamCb, opts = {}) {
64
64
  let psychicApp;
65
- await dream_1.DreamApp.init(dreamCb, { bypassModelIntegrityCheck: opts.bypassModelIntegrityCheck }, async (dreamApp) => {
65
+ await dream_1.DreamApp.init(dreamCb, opts, async (dreamApp) => {
66
66
  psychicApp = new PsychicApp();
67
67
  await cb(psychicApp);
68
68
  if (!psychicApp.loadedControllers)
@@ -97,7 +97,7 @@ class PsychicApp {
97
97
  dreamApp.set('logger', psychicApp.logger);
98
98
  dreamApp.set('packageManager', psychicApp.packageManager);
99
99
  (0, cache_js_1.cachePsychicApp)(psychicApp);
100
- if (!opts.bypassModelIntegrityCheck) {
100
+ if (!opts.bypassDreamIntegrityChecks) {
101
101
  // routes _must_ be built before openapi
102
102
  // cache can be processed
103
103
  await psychicApp.buildRoutesCache();
@@ -266,7 +266,7 @@ suggested fix: "${(0, helpers_js_1.convertRouteParams)(path)}"
266
266
  async handle(controller, action, { req, res, }) {
267
267
  const controllerInstance = this._initializeController(controller, req, res, action);
268
268
  if (typeof controllerInstance[action] !== 'function') {
269
- res.sendStatus(404);
269
+ controllerInstance['expressSendStatus'](404);
270
270
  return;
271
271
  }
272
272
  try {
@@ -274,25 +274,23 @@ suggested fix: "${(0, helpers_js_1.convertRouteParams)(path)}"
274
274
  }
275
275
  catch (error) {
276
276
  const err = error;
277
- if (!EnvInternal_js_1.default.isTest)
278
- index_js_1.default.logWithLevel('error', err.message);
279
277
  if ((0, errorIsRescuableHttpError_js_1.default)(err)) {
280
278
  const httpErr = err;
281
279
  if (httpErr.data) {
282
- res.status(httpErr.status).json(httpErr.data);
280
+ controllerInstance['expressSendJson'](httpErr.data, httpErr.status);
283
281
  }
284
282
  else {
285
- res.sendStatus(httpErr.status);
283
+ controllerInstance['expressSendStatus'](httpErr.status);
286
284
  }
287
285
  }
288
286
  else if (err instanceof dream_1.RecordNotFound) {
289
- res.sendStatus(404);
287
+ controllerInstance['expressSendStatus'](404);
290
288
  }
291
289
  else if (err instanceof dream_1.DataIncompatibleWithDatabaseField) {
292
290
  /**
293
291
  * See comment at top of this method for philosophy of 400
294
292
  */
295
- res.sendStatus(400);
293
+ controllerInstance['expressSendStatus'](400);
296
294
  }
297
295
  else if (err instanceof dream_1.ValidationError) {
298
296
  if (this.validationErrorLoggingEnabled) {
@@ -304,7 +302,7 @@ suggested fix: "${(0, helpers_js_1.convertRouteParams)(path)}"
304
302
  /**
305
303
  * See comment at top of this method for philosophy of 400
306
304
  */
307
- res.sendStatus(400);
305
+ controllerInstance['expressSendStatus'](400);
308
306
  }
309
307
  else if (err instanceof OpenapiRequestValidationFailure_js_1.default) {
310
308
  if (this.validationErrorLoggingEnabled) {
@@ -317,7 +315,7 @@ suggested fix: "${(0, helpers_js_1.convertRouteParams)(path)}"
317
315
  /**
318
316
  * See comment at top of this method for philosophy of 400
319
317
  */
320
- res.sendStatus(400);
318
+ controllerInstance['expressSendStatus'](400);
321
319
  }
322
320
  else if (err instanceof ParamValidationError_js_1.default) {
323
321
  if (this.validationErrorLoggingEnabled) {
@@ -331,7 +329,7 @@ suggested fix: "${(0, helpers_js_1.convertRouteParams)(path)}"
331
329
  /**
332
330
  * See comment at top of this method for philosophy of 400
333
331
  */
334
- res.sendStatus(400);
332
+ controllerInstance['expressSendStatus'](400);
335
333
  }
336
334
  else if (err instanceof ParamValidationErrors_js_1.default) {
337
335
  if (this.validationErrorLoggingEnabled) {
@@ -343,17 +341,10 @@ suggested fix: "${(0, helpers_js_1.convertRouteParams)(path)}"
343
341
  /**
344
342
  * See comment at top of this method for philosophy of 400
345
343
  */
346
- res.sendStatus(400);
344
+ controllerInstance['expressSendStatus'](400);
347
345
  }
348
346
  else {
349
- // by default, ts-node will mask these errors for no good reason, causing us
350
- // to have to apply an ugly and annoying try-catch pattern to our controllers
351
- // and manually console log the error to determine what the actual error was.
352
- // this block enables us to not have to do that anymore.
353
- if (EnvInternal_js_1.default.isTest && !EnvInternal_js_1.default.boolean('PSYCHIC_EXPECTING_INTERNAL_SERVER_ERROR')) {
354
- index_js_1.default.log('ATTENTION: a server error was detected:');
355
- index_js_1.default.logWithLevel('error', err);
356
- }
347
+ index_js_1.default.logWithLevel('error', err);
357
348
  if (index_js_1.default.getOrFail().specialHooks.serverError.length) {
358
349
  try {
359
350
  for (const hook of index_js_1.default.getOrFail().specialHooks.serverError) {
@@ -32,8 +32,10 @@ const dream_1 = require("@rvoh/dream");
32
32
  const fs = __importStar(require("node:fs"));
33
33
  const http = __importStar(require("node:http"));
34
34
  const https = __importStar(require("node:https"));
35
+ const colorize_js_1 = __importDefault(require("../../cli/helpers/colorize.js"));
35
36
  const EnvInternal_js_1 = __importDefault(require("../../helpers/EnvInternal.js"));
36
- const index_js_1 = __importDefault(require("../../server/index.js"));
37
+ const index_js_1 = __importDefault(require("../../psychic-app/index.js"));
38
+ const PsychicLogos_js_1 = __importDefault(require("../../cli/helpers/PsychicLogos.js"));
37
39
  async function startPsychicServer({ app, port, sslCredentials, }) {
38
40
  return await new Promise(accept => {
39
41
  const httpOrHttps = createPsychicHttpInstance(app, sslCredentials);
@@ -55,9 +57,20 @@ function createPsychicHttpInstance(app, sslCredentials) {
55
57
  }
56
58
  }
57
59
  function welcomeMessage({ port }) {
58
- if (!EnvInternal_js_1.default.isTest) {
59
- dream_1.DreamCLI.logger.log('starting psychic server...');
60
- dream_1.DreamCLI.logger.log(index_js_1.default.asciiLogo(), { logPrefix: '' });
60
+ if (EnvInternal_js_1.default.isDevelopment) {
61
+ dream_1.DreamCLI.logger.log((0, colorize_js_1.default)(PsychicLogos_js_1.default.babyAster(), { color: 'greenBright' }), {
62
+ logPrefix: '',
63
+ });
64
+ dream_1.DreamCLI.logger.log('', { logPrefix: '' });
65
+ dream_1.DreamCLI.logger.log((0, colorize_js_1.default)('✺ ' + index_js_1.default.getOrFail().appName, { color: 'greenBright' }), {
66
+ logPrefix: '',
67
+ });
68
+ dream_1.DreamCLI.logger.log((0, colorize_js_1.default)(`└─ http://localhost:${port.toString()}`, { color: 'greenBright' }), {
69
+ logPrefix: '',
70
+ });
71
+ dream_1.DreamCLI.logger.log('', { logPrefix: '' });
72
+ }
73
+ else {
61
74
  dream_1.DreamCLI.logger.log(`psychic dev server started at port ${port}`);
62
75
  }
63
76
  }
@@ -34,6 +34,7 @@ const EnvInternal_js_1 = __importDefault(require("../helpers/EnvInternal.js"));
34
34
  const index_js_1 = __importDefault(require("../psychic-app/index.js"));
35
35
  const index_js_2 = __importDefault(require("../router/index.js"));
36
36
  const startPsychicServer_js_1 = __importStar(require("./helpers/startPsychicServer.js"));
37
+ const logIfDevelopment_js_1 = __importDefault(require("../controller/helpers/logIfDevelopment.js"));
37
38
  // const debugEnabled = debuglog('psychic').enabled
38
39
  class PsychicServer {
39
40
  static async startPsychicServer(opts) {
@@ -42,9 +43,6 @@ class PsychicServer {
42
43
  static createPsychicHttpInstance(app, sslCredentials) {
43
44
  return (0, startPsychicServer_js_1.createPsychicHttpInstance)(app, sslCredentials);
44
45
  }
45
- static asciiLogo() {
46
- return dream_1.DreamLogos.colorful();
47
- }
48
46
  expressApp;
49
47
  httpServer;
50
48
  booted = false;
@@ -92,9 +90,28 @@ class PsychicServer {
92
90
  for (const afterRoutesHook of index_js_1.default.getOrFail().specialHooks.serverInitAfterRoutes) {
93
91
  await afterRoutesHook(this);
94
92
  }
93
+ this.applyNotFoundMiddleware();
95
94
  this.booted = true;
96
95
  return true;
97
96
  }
97
+ applyNotFoundMiddleware() {
98
+ if (!EnvInternal_js_1.default.isDevelopment)
99
+ return;
100
+ this.expressApp.use((req, res, next) => {
101
+ // express by default will set the 200 status code. If a user explicitly
102
+ // provides anything other than 200, we should assume that a prior middleware
103
+ // would have have sent headers, which would prevent any of this from happening.
104
+ // this means that if we are here, we should not be sending a 200. Future middleware
105
+ // by express will automatically pick this up and turn it into a 404, so we are
106
+ // going to automatically set the status to 404 now, so that our logger can
107
+ // pick up the correct status code.
108
+ if (res.statusCode === 200)
109
+ res.status(404);
110
+ (0, logIfDevelopment_js_1.default)({ req, res, startTime: Date.now(), fallbackStatusCode: 404 });
111
+ // call next to let express handle sending the 404
112
+ next();
113
+ });
114
+ }
98
115
  setSecureDefaultHeaders() {
99
116
  this.expressApp.disable('x-powered-by');
100
117
  this.expressApp.use((_, res, next) => {
@@ -14,6 +14,7 @@ export const ${exportedTypeName} = [
14
14
  .map(val => `'${val}'`)
15
15
  .join(',\n ')}
16
16
  ] as const
17
+ export type ${exportedTypeName.replace(/Values^/, '')} = (typeof ${exportedTypeName})[number]
17
18
 
18
19
  `;
19
20
  });
@@ -0,0 +1,32 @@
1
+ import colorize from './colorize.js';
2
+ export default class PsychicLogos {
3
+ static babyAster() {
4
+ const g = (str) => colorize(str, { color: 'green' });
5
+ return `
6
+ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
7
+ ░░░░░░█▀█░█▀▀░█░█░█▀▀░█░█░▀█▀░█▀▀░░░░░░░░░
8
+ ░░░░░░█▀▀░▀▀█░░█░░█░░░█▀█░░█░░█░░░░░░░░░░░
9
+ ░░░░░░▀░░░▀▀▀░░▀░░▀▀▀░▀░▀░▀▀▀░▀▀▀░░░░░░░░░
10
+ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
11
+ ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠿⣿⣿⣿⣿⣿⣿⣿⣿⠟⢉⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
12
+ ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⣀⡀⠈⠻⠿⡿⠿⠛⠉⠁⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
13
+ ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠀⠀⠹⠀⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
14
+ ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠿⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
15
+ ⣿⣿⣿⣿⣿⣿⣿⣿⠟⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
16
+ ⣿⠿⠛⠋⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢴⣲⠀⠀⠀⠋⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
17
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
18
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣤⡀⠀⢀⣠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
19
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
20
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
21
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
22
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
23
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀
24
+ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿
25
+ ⠀⠀⠀⠀⠀⠀⣀⠀⠀⠀⠀⠀⠀⠀⢸▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓
26
+ ⠀⠀⠀⠀⢠▓⣿⠀⠀⠀⣿ ⠀ ⣸⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿
27
+ ⠀⠀⠀⢠▓⣿▓⣦⠀⠀⣿▓⠀⠀⠋▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓
28
+ ⠀⠀⠀⢸⣿▓⣿▓⡄⠀⠈⠙⣄⣀⣠⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿
29
+ ⠀⠀⠀⠺▓⣿▓⣿▓⣄⣀⣤⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓⣿▓\
30
+ `.replace(/▓/g, g('▓'));
31
+ }
32
+ }
@@ -67,7 +67,7 @@ export default class PsychicCLI {
67
67
  .argument('<modelName>', 'the name of the model to create, e.g. Post or Settings/CommunicationPreferences')
68
68
  .argument('[columnsWithTypes...]', columnsWithTypesDescription)
69
69
  .action(async (route, modelName, columnsWithTypes, options) => {
70
- await initializePsychicApp();
70
+ await initializePsychicApp({ bypassDreamIntegrityChecks: true });
71
71
  await PsychicBin.generateResource(route, modelName, columnsWithTypes, options);
72
72
  process.exit();
73
73
  });
@@ -78,7 +78,7 @@ export default class PsychicCLI {
78
78
  .argument('<controllerName>', 'the name of the controller to create, including namespaces, e.g. Posts or Api/V1/Posts')
79
79
  .argument('[actions...]', 'the names of controller actions to create')
80
80
  .action(async (controllerName, actions) => {
81
- await initializePsychicApp();
81
+ await initializePsychicApp({ bypassDreamIntegrityChecks: true });
82
82
  await PsychicBin.generateController(controllerName, actions);
83
83
  process.exit();
84
84
  });
@@ -135,7 +135,7 @@ export default class PsychicCLI {
135
135
  .description('sync introspects your database, updating your schema to reflect, and then syncs the new schema with the installed dream node module, allowing it provide your schema to the underlying kysely integration')
136
136
  .option('--schema-only')
137
137
  .action(async (options = {}) => {
138
- await initializePsychicApp();
138
+ await initializePsychicApp({ bypassDreamIntegrityChecks: !!options.schemaOnly });
139
139
  await PsychicBin.sync(options);
140
140
  process.exit();
141
141
  });
@@ -144,7 +144,7 @@ export default class PsychicCLI {
144
144
  .description('watches your app for changes, and re-syncs any time they happen')
145
145
  .argument('[dir]', 'the folder you want to watch, defaults to ./src')
146
146
  .action(async (dir) => {
147
- await initializePsychicApp();
147
+ await initializePsychicApp({ bypassDreamIntegrityChecks: true });
148
148
  Watcher.watch(dir);
149
149
  });
150
150
  program
@@ -0,0 +1,30 @@
1
+ export default function httpMethodColor(httpMethod) {
2
+ switch (httpMethod) {
3
+ case 'delete':
4
+ return 'red';
5
+ case 'options':
6
+ return 'gray';
7
+ case 'patch':
8
+ case 'put':
9
+ return 'magentaBright';
10
+ case 'post':
11
+ return 'greenBright';
12
+ default:
13
+ return 'blue';
14
+ }
15
+ }
16
+ export function httpMethodBgColor(httpMethod) {
17
+ switch (httpMethod) {
18
+ case 'delete':
19
+ return 'bgRed';
20
+ case 'options':
21
+ return 'bgWhite';
22
+ case 'patch':
23
+ case 'put':
24
+ return 'bgMagentaBright';
25
+ case 'post':
26
+ return 'bgGreen';
27
+ default:
28
+ return 'bgBlue';
29
+ }
30
+ }
@@ -0,0 +1,22 @@
1
+ import { DreamCLI } from '@rvoh/dream';
2
+ import colorize from '../../cli/helpers/colorize.js';
3
+ import EnvInternal from '../../helpers/EnvInternal.js';
4
+ import { httpMethodBgColor } from './httpMethodColor.js';
5
+ import { statusCodeBgColor } from './statusCodeColor.js';
6
+ export default function logIfDevelopment({ req, res, startTime, fallbackStatusCode = 200, }) {
7
+ if (!EnvInternal.isDevelopment)
8
+ return;
9
+ const method = colorize(` ${req.method.toUpperCase()} `, {
10
+ color: 'black',
11
+ bgColor: httpMethodBgColor(req.method.toLowerCase()),
12
+ });
13
+ const computedStatus = res.statusCode || fallbackStatusCode;
14
+ const statusBgColor = statusCodeBgColor(computedStatus);
15
+ const status = colorize(` ${computedStatus} `, {
16
+ color: 'black',
17
+ bgColor: statusBgColor,
18
+ });
19
+ const url = colorize(req.url, { color: 'green' });
20
+ const benchmark = colorize(`${Date.now() - startTime}ms`, { color: 'gray' });
21
+ DreamCLI.logger.log(`${method} ${url} ${status} ${benchmark}`, { logPrefix: '' });
22
+ }
@@ -0,0 +1,18 @@
1
+ export default function statusCodeColor(statusCode) {
2
+ if (statusCode >= 200 && statusCode < 300)
3
+ return 'green';
4
+ if (statusCode >= 300 && statusCode < 400)
5
+ return 'yellow';
6
+ if (statusCode >= 400 && statusCode < 500)
7
+ return 'red';
8
+ return 'redBright';
9
+ }
10
+ export function statusCodeBgColor(statusCode) {
11
+ if (statusCode >= 200 && statusCode < 300)
12
+ return 'bgGreen';
13
+ if (statusCode >= 300 && statusCode < 400)
14
+ return 'bgYellow';
15
+ if (statusCode >= 400 && statusCode < 500)
16
+ return 'bgRed';
17
+ return 'bgRedBright';
18
+ }
@@ -37,7 +37,9 @@ import PsychicApp from '../psychic-app/index.js';
37
37
  import Params from '../server/params.js';
38
38
  import Session from '../session/index.js';
39
39
  import isPaginatedResult from './helpers/isPaginatedResult.js';
40
+ import logIfDevelopment from './helpers/logIfDevelopment.js';
40
41
  import renderDreamOrVewModel from './helpers/renderDreamOrViewModel.js';
42
+ import EnvInternal from '../helpers/EnvInternal.js';
41
43
  export const PsychicParamsPrimitiveLiterals = [
42
44
  'bigint',
43
45
  'bigint[]',
@@ -171,7 +173,9 @@ export default class PsychicController {
171
173
  session;
172
174
  action;
173
175
  renderOpts;
176
+ startTime;
174
177
  constructor(req, res, { action, }) {
178
+ this.startTime = Date.now();
175
179
  this.req = req;
176
180
  this.res = res;
177
181
  this.session = new Session(req, res);
@@ -422,7 +426,26 @@ export default class PsychicController {
422
426
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
423
427
  data) {
424
428
  this.validateOpenapiResponseBody(data);
425
- this.res.type('json').send(toJson(data, PsychicApp.getOrFail().sanitizeResponseJson));
429
+ this.expressSendJson(data);
430
+ }
431
+ expressSendJson(
432
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
433
+ data, statusCode = this.res.statusCode) {
434
+ this.res.type('json').status(statusCode).send(toJson(data, PsychicApp.getOrFail().sanitizeResponseJson));
435
+ this.logIfDevelopment();
436
+ }
437
+ expressSendStatus(statusCode) {
438
+ this.res.sendStatus(statusCode);
439
+ this.logIfDevelopment();
440
+ }
441
+ expressRedirect(statusCode, newLocation) {
442
+ this.res.redirect(statusCode, newLocation);
443
+ this.logIfDevelopment();
444
+ }
445
+ logIfDevelopment() {
446
+ if (!EnvInternal.isDevelopment)
447
+ return;
448
+ logIfDevelopment({ req: this.req, res: this.res, startTime: this.startTime });
426
449
  }
427
450
  defaultSerializerPassthrough = {};
428
451
  serializerPassthrough(passthrough) {
@@ -469,15 +492,15 @@ export default class PsychicController {
469
492
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
470
493
  nonAuthoritativeInformation(message = undefined) {
471
494
  if (message) {
472
- this.res.status(203).json(message);
495
+ this.expressSendJson(message, 203);
473
496
  }
474
497
  else {
475
- this.res.sendStatus(203);
498
+ this.expressSendStatus(203);
476
499
  }
477
500
  }
478
501
  // 204
479
502
  noContent() {
480
- this.res.sendStatus(204);
503
+ this.expressSendStatus(204);
481
504
  }
482
505
  // 205
483
506
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -493,27 +516,23 @@ export default class PsychicController {
493
516
  }
494
517
  // 301
495
518
  movedPermanently(newLocation) {
496
- this.res.redirect(301, newLocation);
519
+ this.expressRedirect(301, newLocation);
497
520
  }
498
521
  // 302
499
522
  found(newLocation) {
500
- this.res.redirect(302, newLocation);
523
+ this.expressRedirect(302, newLocation);
501
524
  }
502
525
  // 303
503
526
  seeOther(newLocation) {
504
- this.res.redirect(303, newLocation);
505
- }
506
- // 304
507
- notModified(newLocation) {
508
- this.res.redirect(304, newLocation);
527
+ this.expressRedirect(303, newLocation);
509
528
  }
510
529
  // 307
511
530
  temporaryRedirect(newLocation) {
512
- this.res.redirect(307, newLocation);
531
+ this.expressRedirect(307, newLocation);
513
532
  }
514
533
  // 308
515
534
  permanentRedirect(newLocation) {
516
- this.res.redirect(308, newLocation);
535
+ this.expressRedirect(308, newLocation);
517
536
  }
518
537
  // 400
519
538
  // eslint-disable-next-line @typescript-eslint/no-explicit-any