@dvsa/appdev-api-common 0.7.0 → 0.8.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.
@@ -0,0 +1,42 @@
1
+ import type { Logger } from "@aws-lambda-powertools/logger";
2
+ /**
3
+ * Decorator to log the duration of a method execution by passing in an accessor function to retrieve the logger.
4
+ * @param getLogger - A function that takes the class instance and returns the logger instance.
5
+ * @param {string} label - Optional label for the log message.
6
+ *
7
+ * Note: If you are already using a logger as a class property, you can use the `Timed` decorator instead.
8
+ *
9
+ * @constructor
10
+ *
11
+ * Example usage:
12
+ * class MyClass {
13
+ * @TimedWithAccessor(() => Container.get(LOGGER))
14
+ * async findAll() {} // The log name here will be [findAll]
15
+ * }
16
+ */
17
+ export declare function TimedWithAccessor<T extends {
18
+ logger: Logger;
19
+ }>(getLogger: (self: T) => Logger, label?: string): (_target: unknown, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
20
+ /**
21
+ * Decorator to log the duration of a method execution.
22
+ * @param {string} label - Optional label for the log message.
23
+ *
24
+ * Note: This decorator can be used on any class method that has a `logger` property.
25
+ * This method will throw an error if the `logger` property is not found on the class instance.
26
+ * If you are not using logger as a class property, you can use `LogDurationWithAccessor` instead.
27
+ * @constructor
28
+ *
29
+ * Example usage:
30
+ * class MyClass {
31
+ * private readonly logger = Container.get(Logger);
32
+ *
33
+ * @Timed()
34
+ * myMethod() {} // The log name here will be [myMethod]
35
+ *
36
+ * @Timed('MyClass.myMethod')
37
+ * myMethodWithOptName() {} // The log name here will be [MyClass.myMethod]
38
+ * }
39
+ */
40
+ export declare function Timed<T extends {
41
+ logger: Logger;
42
+ }>(label?: string): (_target: unknown, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor;
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TimedWithAccessor = TimedWithAccessor;
4
+ exports.Timed = Timed;
5
+ const node_perf_hooks_1 = require("node:perf_hooks");
6
+ /**
7
+ * Decorator to log the duration of a method execution by passing in an accessor function to retrieve the logger.
8
+ * @param getLogger - A function that takes the class instance and returns the logger instance.
9
+ * @param {string} label - Optional label for the log message.
10
+ *
11
+ * Note: If you are already using a logger as a class property, you can use the `Timed` decorator instead.
12
+ *
13
+ * @constructor
14
+ *
15
+ * Example usage:
16
+ * class MyClass {
17
+ * @TimedWithAccessor(() => Container.get(LOGGER))
18
+ * async findAll() {} // The log name here will be [findAll]
19
+ * }
20
+ */
21
+ function TimedWithAccessor(getLogger, label) {
22
+ return (_target, propertyKey, descriptor) => {
23
+ const originalMethod = descriptor.value;
24
+ // biome-ignore lint/suspicious/noExplicitAny: "any" is correct for this context
25
+ descriptor.value = function (...args) {
26
+ const logger = getLogger(this);
27
+ const labelToUse = label || propertyKey;
28
+ const start = node_perf_hooks_1.performance.now();
29
+ try {
30
+ const result = originalMethod.apply(this, args);
31
+ // async route, if it's a Promise.
32
+ if (result instanceof Promise) {
33
+ return result
34
+ .then((res) => {
35
+ const duration = (node_perf_hooks_1.performance.now() - start).toFixed(2);
36
+ logger.debug(`[${labelToUse}] took ${duration}ms`);
37
+ return res;
38
+ })
39
+ .catch((err) => {
40
+ const duration = (node_perf_hooks_1.performance.now() - start).toFixed(2);
41
+ logger.debug(`[${labelToUse}] failed after ${duration}ms`);
42
+ throw err;
43
+ });
44
+ }
45
+ // Otherwise, sync method: log and return
46
+ const duration = (node_perf_hooks_1.performance.now() - start).toFixed(2);
47
+ logger.debug(`[${labelToUse}] took ${duration}ms`);
48
+ return result;
49
+ }
50
+ catch (err) {
51
+ const duration = (node_perf_hooks_1.performance.now() - start).toFixed(2);
52
+ logger.debug(`[${labelToUse}] failed after ${duration}ms`);
53
+ throw err;
54
+ }
55
+ };
56
+ return descriptor;
57
+ };
58
+ }
59
+ /**
60
+ * Decorator to log the duration of a method execution.
61
+ * @param {string} label - Optional label for the log message.
62
+ *
63
+ * Note: This decorator can be used on any class method that has a `logger` property.
64
+ * This method will throw an error if the `logger` property is not found on the class instance.
65
+ * If you are not using logger as a class property, you can use `LogDurationWithAccessor` instead.
66
+ * @constructor
67
+ *
68
+ * Example usage:
69
+ * class MyClass {
70
+ * private readonly logger = Container.get(Logger);
71
+ *
72
+ * @Timed()
73
+ * myMethod() {} // The log name here will be [myMethod]
74
+ *
75
+ * @Timed('MyClass.myMethod')
76
+ * myMethodWithOptName() {} // The log name here will be [MyClass.myMethod]
77
+ * }
78
+ */
79
+ function Timed(label) {
80
+ return TimedWithAccessor((cls) => {
81
+ if (!cls.logger) {
82
+ throw new Error(`[${label}] Logger not found on decorated class.`);
83
+ }
84
+ return cls.logger;
85
+ }, label);
86
+ }
@@ -0,0 +1,36 @@
1
+ export declare class HTTPError extends Error {
2
+ response: Response;
3
+ constructor(message: string, response: Response);
4
+ }
5
+ export declare class HTTP {
6
+ /**
7
+ * Performs an HTTP GET request.
8
+ * Note: This method will throw an HTTPError if the response is not ok (status code 200-299) to emulate Axios behaviour.
9
+ * @param url
10
+ * @param options
11
+ */
12
+ static get(url: string, options?: RequestInit): Promise<Response>;
13
+ /**
14
+ * Performs an HTTP POST request.
15
+ * Note: This method will throw an HTTPError if the response is not ok (status code 200-299) to emulate Axios behaviour.
16
+ * @param url
17
+ * @param body
18
+ * @param options
19
+ */
20
+ static post<T>(url: string, body: T, options?: RequestInit): Promise<Response>;
21
+ /**
22
+ * Performs an HTTP PUT request.
23
+ * Note: This method will throw an HTTPError if the response is not ok (status code 200-299) to emulate Axios behaviour.
24
+ * @param url
25
+ * @param body
26
+ * @param options
27
+ */
28
+ static put<T>(url: string, body: T, options?: RequestInit): Promise<Response>;
29
+ /**
30
+ * Performs an HTTP DELETE request.
31
+ * Note: This method will throw an HTTPError if the response is not ok (status code 200-299) to emulate Axios behaviour.
32
+ * @param url
33
+ * @param options
34
+ */
35
+ static delete(url: string, options?: RequestInit): Promise<Response>;
36
+ }
package/http/index.js ADDED
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HTTP = exports.HTTPError = void 0;
4
+ class HTTPError extends Error {
5
+ response;
6
+ constructor(message, response) {
7
+ super(message);
8
+ this.response = response;
9
+ this.name = "HTTPError";
10
+ this.response = response;
11
+ }
12
+ }
13
+ exports.HTTPError = HTTPError;
14
+ // biome-ignore lint/complexity/noStaticOnlyClass: makes sense for an HTTP utility to encompass all methods
15
+ class HTTP {
16
+ /**
17
+ * Performs an HTTP GET request.
18
+ * Note: This method will throw an HTTPError if the response is not ok (status code 200-299) to emulate Axios behaviour.
19
+ * @param url
20
+ * @param options
21
+ */
22
+ static async get(url, options) {
23
+ const response = await fetch(url, { method: "GET", ...options });
24
+ if (!response.ok) {
25
+ throw new HTTPError(`HTTP GET request failed with status ${response.status}`, response);
26
+ }
27
+ return response;
28
+ }
29
+ /**
30
+ * Performs an HTTP POST request.
31
+ * Note: This method will throw an HTTPError if the response is not ok (status code 200-299) to emulate Axios behaviour.
32
+ * @param url
33
+ * @param body
34
+ * @param options
35
+ */
36
+ static async post(url, body, options) {
37
+ const response = await fetch(url, {
38
+ method: "POST",
39
+ headers: { "Content-Type": "application/json", ...options?.headers },
40
+ body: JSON.stringify(body),
41
+ ...options,
42
+ });
43
+ if (!response.ok) {
44
+ throw new HTTPError(`HTTP POST request failed with status ${response.status}`, response);
45
+ }
46
+ return response;
47
+ }
48
+ /**
49
+ * Performs an HTTP PUT request.
50
+ * Note: This method will throw an HTTPError if the response is not ok (status code 200-299) to emulate Axios behaviour.
51
+ * @param url
52
+ * @param body
53
+ * @param options
54
+ */
55
+ static async put(url, body, options) {
56
+ const response = await fetch(url, {
57
+ method: "PUT",
58
+ headers: { "Content-Type": "application/json", ...options?.headers },
59
+ body: JSON.stringify(body),
60
+ ...options,
61
+ });
62
+ if (!response.ok) {
63
+ throw new HTTPError(`HTTP PUT request failed with status ${response.status}`, response);
64
+ }
65
+ return response;
66
+ }
67
+ /**
68
+ * Performs an HTTP DELETE request.
69
+ * Note: This method will throw an HTTPError if the response is not ok (status code 200-299) to emulate Axios behaviour.
70
+ * @param url
71
+ * @param options
72
+ */
73
+ static async delete(url, options) {
74
+ const response = await fetch(url, { method: "DELETE", ...options });
75
+ if (!response.ok) {
76
+ throw new HTTPError(`HTTP DELETE request failed with status ${response.status}`, response);
77
+ }
78
+ return response;
79
+ }
80
+ }
81
+ exports.HTTP = HTTP;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dvsa/appdev-api-common",
3
- "version": "0.7.0",
3
+ "version": "0.8.1",
4
4
  "keywords": ["dvsa", "nodejs", "typescript"],
5
5
  "author": "DVSA",
6
6
  "description": "Utils library for common API functionality",
@@ -29,6 +29,7 @@
29
29
  "jose": "^5.9.6"
30
30
  },
31
31
  "devDependencies": {
32
+ "@aws-lambda-powertools/logger": "^2.22.0",
32
33
  "@biomejs/biome": "1.9.3",
33
34
  "@dvsa/biome-config": "0.3.0",
34
35
  "@types/aws-lambda": "^8.10.145",