@drunkcod/express-kit 0.0.12 → 0.0.14

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.
@@ -1,6 +1,8 @@
1
1
  import type express from 'express';
2
+ import { Timespan } from './stopwatch.js';
2
3
  export * from '@drunkcod/express-async';
3
4
  export * from './loggable.js';
5
+ export * from './stopwatch.js';
4
6
  type AsyncFn<T> = () => Promise<T>;
5
7
  type ExpressServer = ReturnType<express.Application['listen']>;
6
8
  export type ErrorHandler = (error: Error, request: express.Request, response: express.Response, next: express.NextFunction) => void;
@@ -17,3 +19,4 @@ export declare function closeAsync(server: {
17
19
  close: (cb: (error?: Error) => void) => void;
18
20
  }): Promise<void>;
19
21
  export declare function registerShutdown<Server extends ExpressServer = ExpressServer>(server: Server, shutdown?: () => Promise<void>): void;
22
+ export declare function requestTimingMiddleware(onRequestFinish: (req: express.Request, duration: Timespan) => void): (req: express.Request, res: express.Response, next: express.NextFunction) => void;
package/lib/cjs/index.js CHANGED
@@ -19,8 +19,11 @@ exports.mergeCallsAsync = mergeCallsAsync;
19
19
  exports.listenAsync = listenAsync;
20
20
  exports.closeAsync = closeAsync;
21
21
  exports.registerShutdown = registerShutdown;
22
+ exports.requestTimingMiddleware = requestTimingMiddleware;
23
+ const stopwatch_js_1 = require("./stopwatch.js");
22
24
  __exportStar(require("@drunkcod/express-async"), exports);
23
25
  __exportStar(require("./loggable.js"), exports);
26
+ __exportStar(require("./stopwatch.js"), exports);
24
27
  function onceAsync(fn) {
25
28
  let p;
26
29
  return () => {
@@ -78,3 +81,10 @@ function registerShutdown(server, shutdown) {
78
81
  process.on('SIGINT', onShutdown);
79
82
  process.on('SIGTERM', onShutdown);
80
83
  }
84
+ function requestTimingMiddleware(onRequestFinish) {
85
+ return (req, res, next) => {
86
+ const s = stopwatch_js_1.Stopwatch.startNew();
87
+ res.on('finish', () => onRequestFinish(req, s.elapsed));
88
+ next();
89
+ };
90
+ }
@@ -24,9 +24,7 @@ function asLoggableCause(cause) {
24
24
  return asLoggableCause(cause.toJSON());
25
25
  if (cause instanceof Error) {
26
26
  const { message, stack, cause: innerCause, ...rest } = cause;
27
- return innerCause
28
- ? { message, stack, cause: asLoggableCause(innerCause), ...rest }
29
- : { message, stack, ...rest };
27
+ return innerCause ? { message, stack, cause: asLoggableCause(innerCause), ...rest } : { message, stack, ...rest };
30
28
  }
31
29
  if ((0, argis_1.hasOwn)(cause, 'cause')) {
32
30
  const { cause: innerCause, ...rest } = cause;
@@ -37,7 +35,7 @@ function asLoggableCause(cause) {
37
35
  function asLoggableError(error) {
38
36
  if (error instanceof Error)
39
37
  return asLoggableCause(error);
40
- const r = (error && typeof error === 'object') ? asLoggableCause(error) : { message: error };
38
+ const r = error && typeof error === 'object' ? asLoggableCause(error) : { message: error };
41
39
  Error.captureStackTrace(r, asLoggableError);
42
40
  return Object.defineProperty(r, 'stack', { enumerable: true });
43
41
  }
@@ -0,0 +1,21 @@
1
+ export declare class Stopwatch {
2
+ #private;
3
+ private constructor();
4
+ static startNew(): Stopwatch;
5
+ get elapsed(): Timespan;
6
+ }
7
+ export declare class Timespan {
8
+ #private;
9
+ constructor(value: bigint);
10
+ get hours(): number;
11
+ get minutes(): number;
12
+ get seconds(): number;
13
+ get milliseconds(): number;
14
+ static fromSeconds(seconds: number): Timespan;
15
+ static fromMilliseconds(ms: number): Timespan;
16
+ get totalMinutes(): number;
17
+ get totalSeconds(): number;
18
+ get totalMilliseconds(): number;
19
+ toString(): string;
20
+ toDuration(): string;
21
+ }
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Timespan = exports.Stopwatch = void 0;
4
+ class Stopwatch {
5
+ #startedAt;
6
+ constructor() {
7
+ this.#startedAt = process.hrtime.bigint();
8
+ }
9
+ static startNew() {
10
+ return new Stopwatch();
11
+ }
12
+ get elapsed() {
13
+ return new Timespan(process.hrtime.bigint() - this.#startedAt);
14
+ }
15
+ }
16
+ exports.Stopwatch = Stopwatch;
17
+ class Timespan {
18
+ #value;
19
+ constructor(value) {
20
+ this.#value = value;
21
+ }
22
+ get hours() {
23
+ return Number(this.#value / 1000000000n / 60n / 60n);
24
+ }
25
+ get minutes() {
26
+ return Number((this.#value / 1000000000n / 60n) % 60n);
27
+ }
28
+ get seconds() {
29
+ return Number((this.#value / 1000000000n) % 60n);
30
+ }
31
+ get milliseconds() {
32
+ return Number((this.#value / 1000000n) % 1000n);
33
+ }
34
+ static fromSeconds(seconds) {
35
+ return new Timespan(BigInt(seconds * 1e9));
36
+ }
37
+ static fromMilliseconds(ms) {
38
+ return new Timespan(BigInt(ms * 1e6));
39
+ }
40
+ get totalMinutes() {
41
+ return Number(this.#value) * (1e-9 / 60.0);
42
+ }
43
+ get totalSeconds() {
44
+ return Number(this.#value) * 1e-9;
45
+ }
46
+ get totalMilliseconds() {
47
+ return Number(this.#value) * 1e-6;
48
+ }
49
+ toString() {
50
+ const { hours, minutes, seconds, milliseconds } = this;
51
+ const padz = (x) => (x < 10 ? '0' + x : x);
52
+ return `${padz(hours)}:${padz(minutes)}:${padz(seconds)}.${('00' + milliseconds).slice(-3)}`;
53
+ }
54
+ toDuration() {
55
+ return `${this.totalSeconds}s`;
56
+ }
57
+ }
58
+ exports.Timespan = Timespan;
package/lib/index.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import type express from 'express';
2
+ import { Timespan } from './stopwatch.js';
2
3
  export * from '@drunkcod/express-async';
3
4
  export * from './loggable.js';
5
+ export * from './stopwatch.js';
4
6
  type AsyncFn<T> = () => Promise<T>;
5
7
  type ExpressServer = ReturnType<express.Application['listen']>;
6
8
  export type ErrorHandler = (error: Error, request: express.Request, response: express.Response, next: express.NextFunction) => void;
@@ -17,3 +19,4 @@ export declare function closeAsync(server: {
17
19
  close: (cb: (error?: Error) => void) => void;
18
20
  }): Promise<void>;
19
21
  export declare function registerShutdown<Server extends ExpressServer = ExpressServer>(server: Server, shutdown?: () => Promise<void>): void;
22
+ export declare function requestTimingMiddleware(onRequestFinish: (req: express.Request, duration: Timespan) => void): (req: express.Request, res: express.Response, next: express.NextFunction) => void;
package/lib/index.js CHANGED
@@ -1,5 +1,7 @@
1
+ import { Stopwatch } from './stopwatch.js';
1
2
  export * from '@drunkcod/express-async';
2
3
  export * from './loggable.js';
4
+ export * from './stopwatch.js';
3
5
  export function onceAsync(fn) {
4
6
  let p;
5
7
  return () => {
@@ -57,3 +59,10 @@ export function registerShutdown(server, shutdown) {
57
59
  process.on('SIGINT', onShutdown);
58
60
  process.on('SIGTERM', onShutdown);
59
61
  }
62
+ export function requestTimingMiddleware(onRequestFinish) {
63
+ return (req, res, next) => {
64
+ const s = Stopwatch.startNew();
65
+ res.on('finish', () => onRequestFinish(req, s.elapsed));
66
+ next();
67
+ };
68
+ }
package/lib/loggable.js CHANGED
@@ -1,4 +1,4 @@
1
- import { hasOwn } from "@drunkcod/argis";
1
+ import { hasOwn } from '@drunkcod/argis';
2
2
  export function at(message) {
3
3
  const old = Error.stackTraceLimit;
4
4
  try {
@@ -19,9 +19,7 @@ function asLoggableCause(cause) {
19
19
  return asLoggableCause(cause.toJSON());
20
20
  if (cause instanceof Error) {
21
21
  const { message, stack, cause: innerCause, ...rest } = cause;
22
- return innerCause
23
- ? { message, stack, cause: asLoggableCause(innerCause), ...rest }
24
- : { message, stack, ...rest };
22
+ return innerCause ? { message, stack, cause: asLoggableCause(innerCause), ...rest } : { message, stack, ...rest };
25
23
  }
26
24
  if (hasOwn(cause, 'cause')) {
27
25
  const { cause: innerCause, ...rest } = cause;
@@ -32,7 +30,7 @@ function asLoggableCause(cause) {
32
30
  export function asLoggableError(error) {
33
31
  if (error instanceof Error)
34
32
  return asLoggableCause(error);
35
- const r = (error && typeof error === 'object') ? asLoggableCause(error) : { message: error };
33
+ const r = error && typeof error === 'object' ? asLoggableCause(error) : { message: error };
36
34
  Error.captureStackTrace(r, asLoggableError);
37
35
  return Object.defineProperty(r, 'stack', { enumerable: true });
38
36
  }
@@ -0,0 +1,21 @@
1
+ export declare class Stopwatch {
2
+ #private;
3
+ private constructor();
4
+ static startNew(): Stopwatch;
5
+ get elapsed(): Timespan;
6
+ }
7
+ export declare class Timespan {
8
+ #private;
9
+ constructor(value: bigint);
10
+ get hours(): number;
11
+ get minutes(): number;
12
+ get seconds(): number;
13
+ get milliseconds(): number;
14
+ static fromSeconds(seconds: number): Timespan;
15
+ static fromMilliseconds(ms: number): Timespan;
16
+ get totalMinutes(): number;
17
+ get totalSeconds(): number;
18
+ get totalMilliseconds(): number;
19
+ toString(): string;
20
+ toDuration(): string;
21
+ }
@@ -0,0 +1,53 @@
1
+ export class Stopwatch {
2
+ #startedAt;
3
+ constructor() {
4
+ this.#startedAt = process.hrtime.bigint();
5
+ }
6
+ static startNew() {
7
+ return new Stopwatch();
8
+ }
9
+ get elapsed() {
10
+ return new Timespan(process.hrtime.bigint() - this.#startedAt);
11
+ }
12
+ }
13
+ export class Timespan {
14
+ #value;
15
+ constructor(value) {
16
+ this.#value = value;
17
+ }
18
+ get hours() {
19
+ return Number(this.#value / 1000000000n / 60n / 60n);
20
+ }
21
+ get minutes() {
22
+ return Number((this.#value / 1000000000n / 60n) % 60n);
23
+ }
24
+ get seconds() {
25
+ return Number((this.#value / 1000000000n) % 60n);
26
+ }
27
+ get milliseconds() {
28
+ return Number((this.#value / 1000000n) % 1000n);
29
+ }
30
+ static fromSeconds(seconds) {
31
+ return new Timespan(BigInt(seconds * 1e9));
32
+ }
33
+ static fromMilliseconds(ms) {
34
+ return new Timespan(BigInt(ms * 1e6));
35
+ }
36
+ get totalMinutes() {
37
+ return Number(this.#value) * (1e-9 / 60.0);
38
+ }
39
+ get totalSeconds() {
40
+ return Number(this.#value) * 1e-9;
41
+ }
42
+ get totalMilliseconds() {
43
+ return Number(this.#value) * 1e-6;
44
+ }
45
+ toString() {
46
+ const { hours, minutes, seconds, milliseconds } = this;
47
+ const padz = (x) => (x < 10 ? '0' + x : x);
48
+ return `${padz(hours)}:${padz(minutes)}:${padz(seconds)}.${('00' + milliseconds).slice(-3)}`;
49
+ }
50
+ toDuration() {
51
+ return `${this.totalSeconds}s`;
52
+ }
53
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@drunkcod/express-kit",
3
3
  "type": "module",
4
- "version": "0.0.12",
4
+ "version": "0.0.14",
5
5
  "description": "Express4 utility things",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/index.d.ts",
@@ -40,7 +40,7 @@
40
40
  ],
41
41
  "dependencies": {
42
42
  "@drunkcod/argis": "^0.0.7",
43
- "@drunkcod/express-async": "^0.0.11"
43
+ "@drunkcod/express-async": "^0.0.13"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@drunkcod/ts-jest-esm": "^0.0.1",