@dvsa/appdev-api-common 0.3.3 → 0.4.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.
@@ -8,7 +8,8 @@ export declare class JWTAuthChecker {
8
8
  /**
9
9
  * Perform a JWT token verification and role check
10
10
  * @param {RoutingControllersRequest} request
11
- * @param roles
11
+ * @param {string | string[]} roles
12
+ * @returns {Promise<boolean>}
12
13
  */
13
14
  static execute({ request }: Action, roles?: string | string[]): Promise<boolean>;
14
15
  }
@@ -9,7 +9,8 @@ class JWTAuthChecker {
9
9
  /**
10
10
  * Perform a JWT token verification and role check
11
11
  * @param {RoutingControllersRequest} request
12
- * @param roles
12
+ * @param {string | string[]} roles
13
+ * @returns {Promise<boolean>}
13
14
  */
14
15
  static async execute({ request }, roles = []) {
15
16
  // if running locally, skip the token auth and role check
@@ -11,9 +11,32 @@ export declare class ClientCredentials {
11
11
  private readonly scope;
12
12
  private readonly debugMode;
13
13
  private static accessToken;
14
- private static readonly grant_type;
14
+ private static readonly grantType;
15
+ /**
16
+ * Create a new instance of the ClientCredentials class
17
+ * @param tokenUrl - The URL to fetch the access token from
18
+ * @param clientId - The client id
19
+ * @param clientSecret - The client secret
20
+ * @param scope - The scope of the access token
21
+ * @param debugMode - Whether to log debug messages
22
+ */
15
23
  constructor(tokenUrl: string, clientId: string, clientSecret: string, scope: string, debugMode?: boolean);
24
+ /**
25
+ * Helper method to perform the client credentials flow and return the access token
26
+ * This method will check for the existence of the token and if it is expired, it will fetch a new one
27
+ * @returns {Promise<string>} - The access token
28
+ */
16
29
  getAccessToken(): Promise<string>;
30
+ /**
31
+ * Fetch the client credentials from the token URL
32
+ * @returns {Promise<ClientCredentialsResponse>} - The response from the token URL
33
+ * @private
34
+ */
17
35
  private fetchClientCredentials;
36
+ /**
37
+ * Check if the access token is expired
38
+ * @returns {boolean} - Whether the access token is expired
39
+ * @private
40
+ */
18
41
  private isAccessTokenExpired;
19
42
  }
@@ -10,7 +10,15 @@ class ClientCredentials {
10
10
  scope;
11
11
  debugMode;
12
12
  static accessToken;
13
- static grant_type = "client_credentials";
13
+ static grantType = "client_credentials";
14
+ /**
15
+ * Create a new instance of the ClientCredentials class
16
+ * @param tokenUrl - The URL to fetch the access token from
17
+ * @param clientId - The client id
18
+ * @param clientSecret - The client secret
19
+ * @param scope - The scope of the access token
20
+ * @param debugMode - Whether to log debug messages
21
+ */
14
22
  constructor(tokenUrl, clientId, clientSecret, scope, debugMode = false) {
15
23
  this.tokenUrl = tokenUrl;
16
24
  this.clientId = clientId;
@@ -18,6 +26,11 @@ class ClientCredentials {
18
26
  this.scope = scope;
19
27
  this.debugMode = debugMode;
20
28
  }
29
+ /**
30
+ * Helper method to perform the client credentials flow and return the access token
31
+ * This method will check for the existence of the token and if it is expired, it will fetch a new one
32
+ * @returns {Promise<string>} - The access token
33
+ */
21
34
  async getAccessToken() {
22
35
  if (!ClientCredentials.accessToken || this.isAccessTokenExpired()) {
23
36
  const { access_token } = await this.fetchClientCredentials();
@@ -30,12 +43,17 @@ class ClientCredentials {
30
43
  }
31
44
  return ClientCredentials.accessToken;
32
45
  }
46
+ /**
47
+ * Fetch the client credentials from the token URL
48
+ * @returns {Promise<ClientCredentialsResponse>} - The response from the token URL
49
+ * @private
50
+ */
33
51
  async fetchClientCredentials() {
34
52
  const response = await fetch(this.tokenUrl, {
35
53
  method: "POST",
36
54
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
37
55
  body: (0, node_querystring_1.stringify)({
38
- grant_type: ClientCredentials.grant_type,
56
+ grant_type: ClientCredentials.grantType,
39
57
  client_id: this.clientId,
40
58
  client_secret: this.clientSecret,
41
59
  scope: this.scope,
@@ -47,6 +65,11 @@ class ClientCredentials {
47
65
  }
48
66
  return (await response.json());
49
67
  }
68
+ /**
69
+ * Check if the access token is expired
70
+ * @returns {boolean} - Whether the access token is expired
71
+ * @private
72
+ */
50
73
  isAccessTokenExpired() {
51
74
  try {
52
75
  const decodedAccessToken = (0, jose_1.decodeJwt)(ClientCredentials.accessToken);
@@ -5,9 +5,14 @@ export declare class JwtAuthoriser {
5
5
  private static readonly tokenExpiryEnvExclusionList;
6
6
  private static readonly JWKS_URI;
7
7
  private static JWKS;
8
+ /**
9
+ * Create a new instance of the JwtAuthoriser class
10
+ * @param clientId - the client id to validate the token against
11
+ */
8
12
  constructor(clientId?: string | null);
9
13
  /**
10
14
  * Validate a JWT and return the decoded payload
15
+ * @param {string} token - the JWT token to validate
11
16
  * @returns {Promise<JWTPayload>}
12
17
  */
13
18
  verify(token: string): Promise<JWTPayload>;
@@ -13,11 +13,16 @@ class JwtAuthoriser {
13
13
  ];
14
14
  static JWKS_URI = new URL("https://login.microsoftonline.com/common/discovery/keys");
15
15
  static JWKS = (0, jose_1.createRemoteJWKSet)(JwtAuthoriser.JWKS_URI);
16
+ /**
17
+ * Create a new instance of the JwtAuthoriser class
18
+ * @param clientId - the client id to validate the token against
19
+ */
16
20
  constructor(clientId = null) {
17
21
  this.clientId = clientId;
18
22
  }
19
23
  /**
20
24
  * Validate a JWT and return the decoded payload
25
+ * @param {string} token - the JWT token to validate
21
26
  * @returns {Promise<JWTPayload>}
22
27
  */
23
28
  async verify(token) {
package/index.d.ts CHANGED
@@ -3,4 +3,5 @@ export * from "./auth/auth-checker";
3
3
  export * from "./auth/auth-errors";
4
4
  export * from "./auth/client-credentials";
5
5
  export * from "./auth/verify-jwt";
6
+ export * from "./utils/date-time";
6
7
  export * from "./validation/request-body";
package/index.js CHANGED
@@ -19,4 +19,5 @@ __exportStar(require("./auth/auth-checker"), exports);
19
19
  __exportStar(require("./auth/auth-errors"), exports);
20
20
  __exportStar(require("./auth/client-credentials"), exports);
21
21
  __exportStar(require("./auth/verify-jwt"), exports);
22
+ __exportStar(require("./utils/date-time"), exports);
22
23
  __exportStar(require("./validation/request-body"), exports);
package/jest.config.ts ADDED
@@ -0,0 +1,8 @@
1
+ import type { Config } from "jest";
2
+
3
+ const config: Config = {
4
+ preset: "ts-jest",
5
+ testEnvironment: "node",
6
+ };
7
+
8
+ export default config;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dvsa/appdev-api-common",
3
- "version": "0.3.3",
3
+ "version": "0.4.0",
4
4
  "keywords": [
5
5
  "dvsa",
6
6
  "nodejs",
@@ -20,12 +20,15 @@
20
20
  "lint:fix": "npm run lint -- --write",
21
21
  "build": "npm run clean && tsc",
22
22
  "build:package": "npm run build",
23
+ "test": "jest",
24
+ "test:coverage": "jest --coverage",
23
25
  "prepublishOnly": "npm run build:package && cp -r ./dist/* . && rm -rf ./dist",
24
26
  "postpublish": "git clean -fd && npm run clean:temp",
25
27
  "gitSecrets": "git secrets --scan . && git log -p -- . | scanrepo"
26
28
  },
27
29
  "dependencies": {
28
30
  "ajv": "^8.17.1",
31
+ "dayjs": "^1.11.13",
29
32
  "jose": "^5.9.6"
30
33
  },
31
34
  "devDependencies": {
@@ -0,0 +1,24 @@
1
+ import dayjs from "dayjs";
2
+ type AcceptableDate = DateTime | string | Date | null;
3
+ export declare class DateTime {
4
+ private instance;
5
+ private static readonly UKLocalDateTimeFormat;
6
+ private static readonly UKLocalDateFormat;
7
+ constructor(sourceDateTime?: AcceptableDate, format?: string | undefined);
8
+ static at(sourceDateTime: AcceptableDate, format?: string | undefined): DateTime | null;
9
+ static StandardUkLocalDateTimeAdapter(sourceDateTime: AcceptableDate): string | null;
10
+ static StandardUkLocalDateAdapter(sourceDateTime: AcceptableDate): string | null;
11
+ add(amount: number, unit: dayjs.ManipulateType): DateTime;
12
+ subtract(amount: number, unit: dayjs.ManipulateType): DateTime;
13
+ format(formatString: string): string;
14
+ day(): number;
15
+ toString(): string;
16
+ toISOString(): string;
17
+ isAfter(targetDate: AcceptableDate): boolean;
18
+ diff(targetDate: AcceptableDate, unit: dayjs.QUnitType, precise?: boolean): number;
19
+ daysDiff(targetDate: AcceptableDate): number;
20
+ compareDuration(targetDate: AcceptableDate, unit: dayjs.QUnitType): number;
21
+ isBefore(targetDate: AcceptableDate): boolean;
22
+ static today(): Date;
23
+ }
24
+ export {};
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DateTime = void 0;
7
+ const dayjs_1 = __importDefault(require("dayjs"));
8
+ const customParseFormat_1 = __importDefault(require("dayjs/plugin/customParseFormat"));
9
+ class DateTime {
10
+ instance;
11
+ static UKLocalDateTimeFormat = "DD/MM/YYYY HH:mm:ss";
12
+ static UKLocalDateFormat = "DD/MM/YYYY";
13
+ constructor(sourceDateTime, format = undefined) {
14
+ dayjs_1.default.extend(customParseFormat_1.default);
15
+ if (sourceDateTime === undefined || sourceDateTime === null) {
16
+ this.instance = (0, dayjs_1.default)();
17
+ }
18
+ else if (typeof sourceDateTime === "string" ||
19
+ sourceDateTime instanceof Date) {
20
+ this.instance = (0, dayjs_1.default)(sourceDateTime, format);
21
+ }
22
+ else {
23
+ this.instance = (0, dayjs_1.default)(sourceDateTime.instance, format);
24
+ }
25
+ }
26
+ static at(sourceDateTime, format = undefined) {
27
+ if (!sourceDateTime) {
28
+ return null;
29
+ }
30
+ return new DateTime(sourceDateTime, format);
31
+ }
32
+ static StandardUkLocalDateTimeAdapter(sourceDateTime) {
33
+ return (DateTime.at(sourceDateTime)?.format(DateTime.UKLocalDateTimeFormat) ||
34
+ null);
35
+ }
36
+ static StandardUkLocalDateAdapter(sourceDateTime) {
37
+ return (DateTime.at(sourceDateTime)?.format(DateTime.UKLocalDateFormat) || null);
38
+ }
39
+ add(amount, unit) {
40
+ this.instance = this.instance.add(amount, unit);
41
+ return this;
42
+ }
43
+ subtract(amount, unit) {
44
+ this.instance = this.instance.subtract(amount, unit);
45
+ return this;
46
+ }
47
+ format(formatString) {
48
+ return this.instance.format(formatString);
49
+ }
50
+ day() {
51
+ return this.instance.day();
52
+ }
53
+ toString() {
54
+ return this.instance.toString();
55
+ }
56
+ toISOString() {
57
+ return this.instance.toISOString();
58
+ }
59
+ isAfter(targetDate) {
60
+ const date = new DateTime(targetDate);
61
+ return this.instance.isAfter(date.instance);
62
+ }
63
+ diff(targetDate, unit, precise) {
64
+ const date = new DateTime(targetDate);
65
+ return this.instance.diff(date.instance, unit, precise);
66
+ }
67
+ daysDiff(targetDate) {
68
+ const date = new DateTime(targetDate);
69
+ return this.instance
70
+ .startOf("day")
71
+ .diff(date.instance.startOf("day"), "day");
72
+ }
73
+ compareDuration(targetDate, unit) {
74
+ const date = new DateTime(targetDate);
75
+ return date.instance.diff(this.instance, unit);
76
+ }
77
+ isBefore(targetDate) {
78
+ const date = new DateTime(targetDate);
79
+ return this.instance.isBefore(date.instance);
80
+ }
81
+ static today() {
82
+ return (0, dayjs_1.default)().toDate();
83
+ }
84
+ }
85
+ exports.DateTime = DateTime;