@telia-ace/alliance-internal-node-utilities 1.0.3-next.1 → 1.0.3-next.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.
- package/CHANGELOG.md +6 -0
- package/dist/auth/auth.middleware.d.ts +2 -1
- package/dist/constants/config.d.ts +2 -2
- package/dist/exceptions/alliance-gql.exception.d.ts +7 -0
- package/dist/exceptions/codes.d.ts +2 -1
- package/dist/exceptions/index.d.ts +1 -0
- package/dist/index.cjs +40 -13
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +39 -14
- package/package.json +6 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @telia-ace/alliance-internal-node-utilities
|
|
2
2
|
|
|
3
|
+
## 1.0.3-next.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- f2aafe4: Store user session in Redis cache to avoid hitting cookie size limits (https://github.com/telia-company/ace-alliance-sdk/issues/377).
|
|
8
|
+
|
|
3
9
|
## 1.0.3-next.1
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
|
@@ -8,6 +8,7 @@ type Settings = {
|
|
|
8
8
|
authRequired?: ConfigParams['authRequired'];
|
|
9
9
|
authorizationParams?: ConfigParams['authorizationParams'];
|
|
10
10
|
afterCallback?: ConfigParams['afterCallback'];
|
|
11
|
+
issuerBaseURL?: ConfigParams['issuerBaseURL'];
|
|
11
12
|
};
|
|
12
|
-
export declare function authMiddleware(configService: ConfigService, { baseURL, clientSecret, clientID, authRequired, authorizationParams, afterCallback, }?: Settings): RequestHandler;
|
|
13
|
+
export declare function authMiddleware(configService: ConfigService, { baseURL, clientSecret, clientID, authRequired, authorizationParams, afterCallback, issuerBaseURL, }?: Settings): RequestHandler;
|
|
13
14
|
export {};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export declare enum SharedConfigKeys {
|
|
2
|
-
AuthAuthority = "AUTH_AUTHORITY",
|
|
3
2
|
AuthCookieName = "AUTH_COOKIE_NAME",
|
|
4
3
|
AuthCookieSecret = "AUTH_COOKIE_SECRET",
|
|
5
4
|
DbEndpoint = "DB_ENDPOINT",
|
|
6
5
|
JwtPrivateKey = "JWT_PRIVATE_KEY",
|
|
7
6
|
ServiceLogLevel = "SERVICE_LOG_LEVEL",
|
|
8
|
-
ServicePort = "SERVICE_PORT"
|
|
7
|
+
ServicePort = "SERVICE_PORT",
|
|
8
|
+
RedisHost = "REDIS_HOST"
|
|
9
9
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { GraphQLError } from 'graphql';
|
|
2
|
+
import { ErrorCodes } from './codes';
|
|
3
|
+
export declare class AllianceGqlException extends GraphQLError {
|
|
4
|
+
info: string;
|
|
5
|
+
code: ErrorCodes;
|
|
6
|
+
constructor(code: ErrorCodes, variables?: Record<string, string>, extensions?: any);
|
|
7
|
+
}
|
|
@@ -18,7 +18,8 @@ export declare enum DatabasesErrorCodes {
|
|
|
18
18
|
NoAuthHeader = 11001,
|
|
19
19
|
FailedFileStore = 11002,
|
|
20
20
|
FailedFileRead = 11003,
|
|
21
|
-
NoRecord = 11004
|
|
21
|
+
NoRecord = 11004,
|
|
22
|
+
UniqueConstrain = 11005
|
|
22
23
|
}
|
|
23
24
|
export declare enum PortalErrorCodes {
|
|
24
25
|
NoObjectId = 12000
|
package/dist/index.cjs
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const nestjsPino = require('nestjs-pino');
|
|
4
|
+
const RedisStore = require('connect-redis');
|
|
4
5
|
const expressOpenidConnect = require('express-openid-connect');
|
|
6
|
+
const redis = require('redis');
|
|
5
7
|
const jsonwebtoken = require('jsonwebtoken');
|
|
6
8
|
const jsonschema = require('jsonschema');
|
|
7
9
|
const node_path = require('node:path');
|
|
8
10
|
const node_fs = require('node:fs');
|
|
11
|
+
const graphql = require('graphql');
|
|
9
12
|
const common = require('@nestjs/common');
|
|
10
13
|
const config = require('@nestjs/config');
|
|
11
14
|
const _slugify = require('slugify');
|
|
@@ -13,16 +16,17 @@ const promises = require('node:stream/promises');
|
|
|
13
16
|
|
|
14
17
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
15
18
|
|
|
19
|
+
const RedisStore__default = /*#__PURE__*/_interopDefaultCompat(RedisStore);
|
|
16
20
|
const _slugify__default = /*#__PURE__*/_interopDefaultCompat(_slugify);
|
|
17
21
|
|
|
18
22
|
var SharedConfigKeys = /* @__PURE__ */ ((SharedConfigKeys2) => {
|
|
19
|
-
SharedConfigKeys2["AuthAuthority"] = "AUTH_AUTHORITY";
|
|
20
23
|
SharedConfigKeys2["AuthCookieName"] = "AUTH_COOKIE_NAME";
|
|
21
24
|
SharedConfigKeys2["AuthCookieSecret"] = "AUTH_COOKIE_SECRET";
|
|
22
25
|
SharedConfigKeys2["DbEndpoint"] = "DB_ENDPOINT";
|
|
23
26
|
SharedConfigKeys2["JwtPrivateKey"] = "JWT_PRIVATE_KEY";
|
|
24
27
|
SharedConfigKeys2["ServiceLogLevel"] = "SERVICE_LOG_LEVEL";
|
|
25
28
|
SharedConfigKeys2["ServicePort"] = "SERVICE_PORT";
|
|
29
|
+
SharedConfigKeys2["RedisHost"] = "REDIS_HOST";
|
|
26
30
|
return SharedConfigKeys2;
|
|
27
31
|
})(SharedConfigKeys || {});
|
|
28
32
|
|
|
@@ -39,8 +43,16 @@ function authMiddleware(configService, {
|
|
|
39
43
|
clientID = " ",
|
|
40
44
|
authRequired = true,
|
|
41
45
|
authorizationParams = {},
|
|
42
|
-
afterCallback
|
|
46
|
+
afterCallback,
|
|
47
|
+
issuerBaseURL = "https://127.0.0.1"
|
|
43
48
|
} = {}) {
|
|
49
|
+
const redisClient = redis.createClient({
|
|
50
|
+
url: configService.getOrThrow(SharedConfigKeys.RedisHost)
|
|
51
|
+
});
|
|
52
|
+
redisClient.connect().catch(console.error);
|
|
53
|
+
const redisStore = new RedisStore__default({
|
|
54
|
+
client: redisClient
|
|
55
|
+
});
|
|
44
56
|
return expressOpenidConnect.auth({
|
|
45
57
|
baseURL,
|
|
46
58
|
clientSecret,
|
|
@@ -48,12 +60,11 @@ function authMiddleware(configService, {
|
|
|
48
60
|
authRequired,
|
|
49
61
|
authorizationParams,
|
|
50
62
|
afterCallback,
|
|
51
|
-
issuerBaseURL
|
|
52
|
-
SharedConfigKeys.AuthAuthority
|
|
53
|
-
)}/.well-known/openid-configuration`,
|
|
63
|
+
issuerBaseURL,
|
|
54
64
|
secret: configService.getOrThrow(SharedConfigKeys.AuthCookieSecret),
|
|
55
65
|
session: {
|
|
56
|
-
name: configService.getOrThrow(SharedConfigKeys.AuthCookieName)
|
|
66
|
+
name: configService.getOrThrow(SharedConfigKeys.AuthCookieName),
|
|
67
|
+
store: redisStore
|
|
57
68
|
},
|
|
58
69
|
routes: {
|
|
59
70
|
callback: "/signin-oidc"
|
|
@@ -539,6 +550,7 @@ var DatabasesErrorCodes = /* @__PURE__ */ ((DatabasesErrorCodes2) => {
|
|
|
539
550
|
DatabasesErrorCodes2[DatabasesErrorCodes2["FailedFileStore"] = 11002] = "FailedFileStore";
|
|
540
551
|
DatabasesErrorCodes2[DatabasesErrorCodes2["FailedFileRead"] = 11003] = "FailedFileRead";
|
|
541
552
|
DatabasesErrorCodes2[DatabasesErrorCodes2["NoRecord"] = 11004] = "NoRecord";
|
|
553
|
+
DatabasesErrorCodes2[DatabasesErrorCodes2["UniqueConstrain"] = 11005] = "UniqueConstrain";
|
|
542
554
|
return DatabasesErrorCodes2;
|
|
543
555
|
})(DatabasesErrorCodes || {});
|
|
544
556
|
var PortalErrorCodes = /* @__PURE__ */ ((PortalErrorCodes2) => {
|
|
@@ -616,6 +628,10 @@ const allianceErrors = {
|
|
|
616
628
|
httpCode: common.HttpStatus.INTERNAL_SERVER_ERROR,
|
|
617
629
|
message: "Missing database record."
|
|
618
630
|
},
|
|
631
|
+
[11005 /* UniqueConstrain */]: {
|
|
632
|
+
httpCode: common.HttpStatus.CONFLICT,
|
|
633
|
+
message: "Field has to be unique."
|
|
634
|
+
},
|
|
619
635
|
// portal
|
|
620
636
|
[12e3 /* NoObjectId */]: {
|
|
621
637
|
httpCode: common.HttpStatus.UNAUTHORIZED,
|
|
@@ -623,6 +639,22 @@ const allianceErrors = {
|
|
|
623
639
|
}
|
|
624
640
|
};
|
|
625
641
|
|
|
642
|
+
function parseTemplates$1(message, variables) {
|
|
643
|
+
return Object.entries(variables).reduce((acc, [key, value]) => {
|
|
644
|
+
return acc.replaceAll(`{{${key}}}`, value);
|
|
645
|
+
}, message);
|
|
646
|
+
}
|
|
647
|
+
class AllianceGqlException extends graphql.GraphQLError {
|
|
648
|
+
constructor(code, variables = {}, extensions) {
|
|
649
|
+
const { message } = allianceErrors[code];
|
|
650
|
+
super(parseTemplates$1(message, variables), {
|
|
651
|
+
extensions
|
|
652
|
+
});
|
|
653
|
+
this.code = code;
|
|
654
|
+
this.info = `https://github.com/telia-company/ace-alliance-sdk/wiki/error-codes#${code}`;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
|
|
626
658
|
function parseTemplates(message, variables) {
|
|
627
659
|
return Object.entries(variables).reduce((acc, [key, value]) => {
|
|
628
660
|
return acc.replaceAll(`{{${key}}}`, value);
|
|
@@ -717,13 +749,7 @@ exports.LoggerModule = class LoggerModule {
|
|
|
717
749
|
useFactory: async (configService) => ({
|
|
718
750
|
pinoHttp: {
|
|
719
751
|
level: logLevel || configService.get(SharedConfigKeys.ServiceLogLevel) || "silent",
|
|
720
|
-
redact: redact ? [
|
|
721
|
-
"authorization",
|
|
722
|
-
"headers.authorization",
|
|
723
|
-
"req.headers.authorization",
|
|
724
|
-
"req.remoteAddress",
|
|
725
|
-
"req.remotePort"
|
|
726
|
-
] : [],
|
|
752
|
+
redact: redact ? ["authorization", "headers.authorization", "req", "res"] : [],
|
|
727
753
|
transport: {
|
|
728
754
|
target: "pino-pretty",
|
|
729
755
|
options: {
|
|
@@ -787,6 +813,7 @@ function viteCssImportPlugin(outFilePath, relativePath = false) {
|
|
|
787
813
|
|
|
788
814
|
exports.LoggerErrorInterceptor = nestjsPino.LoggerErrorInterceptor;
|
|
789
815
|
exports.AllianceException = AllianceException;
|
|
816
|
+
exports.AllianceGqlException = AllianceGqlException;
|
|
790
817
|
exports.AllianceHeaders = AllianceHeaders;
|
|
791
818
|
exports.DatabasesErrorCodes = DatabasesErrorCodes;
|
|
792
819
|
exports.GatewayErrorCodes = GatewayErrorCodes;
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export { LoggerErrorInterceptor } from 'nestjs-pino';
|
|
|
2
2
|
export { authMiddleware, createBearerToken, createSystemUserToken, getPrivateKey } from './auth';
|
|
3
3
|
export { AllianceHeaders, SharedConfigKeys } from './constants';
|
|
4
4
|
export { createPublicDistributionFiles } from './distribution';
|
|
5
|
-
export { AllianceException, AllianceExceptionFilter, DatabasesErrorCodes, GatewayErrorCodes, PortalErrorCodes, } from './exceptions';
|
|
5
|
+
export { AllianceException, AllianceExceptionFilter, AllianceGqlException, DatabasesErrorCodes, GatewayErrorCodes, PortalErrorCodes, } from './exceptions';
|
|
6
6
|
export { getAppManifests } from './get-app-manifests';
|
|
7
7
|
export { LoggerModule, LoggerService } from './logging';
|
|
8
8
|
export { slugify } from './slugify';
|
package/dist/index.mjs
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
import { InjectPinoLogger, LoggerModule as LoggerModule$1 } from 'nestjs-pino';
|
|
2
2
|
export { LoggerErrorInterceptor } from 'nestjs-pino';
|
|
3
|
+
import RedisStore from 'connect-redis';
|
|
3
4
|
import { auth } from 'express-openid-connect';
|
|
5
|
+
import { createClient } from 'redis';
|
|
4
6
|
import { sign } from 'jsonwebtoken';
|
|
5
7
|
import { validate } from 'jsonschema';
|
|
6
8
|
import { resolve, dirname, relative } from 'node:path';
|
|
7
9
|
import { readFileSync, writeFileSync, rmSync, existsSync, mkdirSync, createWriteStream, createReadStream, renameSync } from 'node:fs';
|
|
10
|
+
import { GraphQLError } from 'graphql';
|
|
8
11
|
import { HttpStatus, HttpException, Catch, Injectable, Module } from '@nestjs/common';
|
|
9
12
|
import { ConfigModule, ConfigService } from '@nestjs/config';
|
|
10
13
|
import _slugify from 'slugify';
|
|
11
14
|
import { pipeline } from 'node:stream/promises';
|
|
12
15
|
|
|
13
16
|
var SharedConfigKeys = /* @__PURE__ */ ((SharedConfigKeys2) => {
|
|
14
|
-
SharedConfigKeys2["AuthAuthority"] = "AUTH_AUTHORITY";
|
|
15
17
|
SharedConfigKeys2["AuthCookieName"] = "AUTH_COOKIE_NAME";
|
|
16
18
|
SharedConfigKeys2["AuthCookieSecret"] = "AUTH_COOKIE_SECRET";
|
|
17
19
|
SharedConfigKeys2["DbEndpoint"] = "DB_ENDPOINT";
|
|
18
20
|
SharedConfigKeys2["JwtPrivateKey"] = "JWT_PRIVATE_KEY";
|
|
19
21
|
SharedConfigKeys2["ServiceLogLevel"] = "SERVICE_LOG_LEVEL";
|
|
20
22
|
SharedConfigKeys2["ServicePort"] = "SERVICE_PORT";
|
|
23
|
+
SharedConfigKeys2["RedisHost"] = "REDIS_HOST";
|
|
21
24
|
return SharedConfigKeys2;
|
|
22
25
|
})(SharedConfigKeys || {});
|
|
23
26
|
|
|
@@ -34,8 +37,16 @@ function authMiddleware(configService, {
|
|
|
34
37
|
clientID = " ",
|
|
35
38
|
authRequired = true,
|
|
36
39
|
authorizationParams = {},
|
|
37
|
-
afterCallback
|
|
40
|
+
afterCallback,
|
|
41
|
+
issuerBaseURL = "https://127.0.0.1"
|
|
38
42
|
} = {}) {
|
|
43
|
+
const redisClient = createClient({
|
|
44
|
+
url: configService.getOrThrow(SharedConfigKeys.RedisHost)
|
|
45
|
+
});
|
|
46
|
+
redisClient.connect().catch(console.error);
|
|
47
|
+
const redisStore = new RedisStore({
|
|
48
|
+
client: redisClient
|
|
49
|
+
});
|
|
39
50
|
return auth({
|
|
40
51
|
baseURL,
|
|
41
52
|
clientSecret,
|
|
@@ -43,12 +54,11 @@ function authMiddleware(configService, {
|
|
|
43
54
|
authRequired,
|
|
44
55
|
authorizationParams,
|
|
45
56
|
afterCallback,
|
|
46
|
-
issuerBaseURL
|
|
47
|
-
SharedConfigKeys.AuthAuthority
|
|
48
|
-
)}/.well-known/openid-configuration`,
|
|
57
|
+
issuerBaseURL,
|
|
49
58
|
secret: configService.getOrThrow(SharedConfigKeys.AuthCookieSecret),
|
|
50
59
|
session: {
|
|
51
|
-
name: configService.getOrThrow(SharedConfigKeys.AuthCookieName)
|
|
60
|
+
name: configService.getOrThrow(SharedConfigKeys.AuthCookieName),
|
|
61
|
+
store: redisStore
|
|
52
62
|
},
|
|
53
63
|
routes: {
|
|
54
64
|
callback: "/signin-oidc"
|
|
@@ -534,6 +544,7 @@ var DatabasesErrorCodes = /* @__PURE__ */ ((DatabasesErrorCodes2) => {
|
|
|
534
544
|
DatabasesErrorCodes2[DatabasesErrorCodes2["FailedFileStore"] = 11002] = "FailedFileStore";
|
|
535
545
|
DatabasesErrorCodes2[DatabasesErrorCodes2["FailedFileRead"] = 11003] = "FailedFileRead";
|
|
536
546
|
DatabasesErrorCodes2[DatabasesErrorCodes2["NoRecord"] = 11004] = "NoRecord";
|
|
547
|
+
DatabasesErrorCodes2[DatabasesErrorCodes2["UniqueConstrain"] = 11005] = "UniqueConstrain";
|
|
537
548
|
return DatabasesErrorCodes2;
|
|
538
549
|
})(DatabasesErrorCodes || {});
|
|
539
550
|
var PortalErrorCodes = /* @__PURE__ */ ((PortalErrorCodes2) => {
|
|
@@ -611,6 +622,10 @@ const allianceErrors = {
|
|
|
611
622
|
httpCode: HttpStatus.INTERNAL_SERVER_ERROR,
|
|
612
623
|
message: "Missing database record."
|
|
613
624
|
},
|
|
625
|
+
[11005 /* UniqueConstrain */]: {
|
|
626
|
+
httpCode: HttpStatus.CONFLICT,
|
|
627
|
+
message: "Field has to be unique."
|
|
628
|
+
},
|
|
614
629
|
// portal
|
|
615
630
|
[12e3 /* NoObjectId */]: {
|
|
616
631
|
httpCode: HttpStatus.UNAUTHORIZED,
|
|
@@ -618,6 +633,22 @@ const allianceErrors = {
|
|
|
618
633
|
}
|
|
619
634
|
};
|
|
620
635
|
|
|
636
|
+
function parseTemplates$1(message, variables) {
|
|
637
|
+
return Object.entries(variables).reduce((acc, [key, value]) => {
|
|
638
|
+
return acc.replaceAll(`{{${key}}}`, value);
|
|
639
|
+
}, message);
|
|
640
|
+
}
|
|
641
|
+
class AllianceGqlException extends GraphQLError {
|
|
642
|
+
constructor(code, variables = {}, extensions) {
|
|
643
|
+
const { message } = allianceErrors[code];
|
|
644
|
+
super(parseTemplates$1(message, variables), {
|
|
645
|
+
extensions
|
|
646
|
+
});
|
|
647
|
+
this.code = code;
|
|
648
|
+
this.info = `https://github.com/telia-company/ace-alliance-sdk/wiki/error-codes#${code}`;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
621
652
|
function parseTemplates(message, variables) {
|
|
622
653
|
return Object.entries(variables).reduce((acc, [key, value]) => {
|
|
623
654
|
return acc.replaceAll(`{{${key}}}`, value);
|
|
@@ -712,13 +743,7 @@ let LoggerModule = class {
|
|
|
712
743
|
useFactory: async (configService) => ({
|
|
713
744
|
pinoHttp: {
|
|
714
745
|
level: logLevel || configService.get(SharedConfigKeys.ServiceLogLevel) || "silent",
|
|
715
|
-
redact: redact ? [
|
|
716
|
-
"authorization",
|
|
717
|
-
"headers.authorization",
|
|
718
|
-
"req.headers.authorization",
|
|
719
|
-
"req.remoteAddress",
|
|
720
|
-
"req.remotePort"
|
|
721
|
-
] : [],
|
|
746
|
+
redact: redact ? ["authorization", "headers.authorization", "req", "res"] : [],
|
|
722
747
|
transport: {
|
|
723
748
|
target: "pino-pretty",
|
|
724
749
|
options: {
|
|
@@ -780,4 +805,4 @@ function viteCssImportPlugin(outFilePath, relativePath = false) {
|
|
|
780
805
|
};
|
|
781
806
|
}
|
|
782
807
|
|
|
783
|
-
export { AllianceException, AllianceExceptionFilter, AllianceHeaders, DatabasesErrorCodes, GatewayErrorCodes, LoggerModule, LoggerService, PortalErrorCodes, SharedConfigKeys, authMiddleware, createBearerToken, createPublicDistributionFiles, createSystemUserToken, getAppManifests, getPrivateKey, slugify, viteCssImportPlugin };
|
|
808
|
+
export { AllianceException, AllianceExceptionFilter, AllianceGqlException, AllianceHeaders, DatabasesErrorCodes, GatewayErrorCodes, LoggerModule, LoggerService, PortalErrorCodes, SharedConfigKeys, authMiddleware, createBearerToken, createPublicDistributionFiles, createSystemUserToken, getAppManifests, getPrivateKey, slugify, viteCssImportPlugin };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@telia-ace/alliance-internal-node-utilities",
|
|
3
|
-
"version": "1.0.3-next.
|
|
3
|
+
"version": "1.0.3-next.2",
|
|
4
4
|
"description": "Utilities used internally by packages developed by team Alliance.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"author": "Telia Company AB",
|
|
@@ -16,16 +16,21 @@
|
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@nestjs/common": "^10.1.0",
|
|
18
18
|
"@nestjs/config": "^3.0.0",
|
|
19
|
+
"connect-redis": "^7.1.0",
|
|
19
20
|
"express-openid-connect": "^2.16.0",
|
|
21
|
+
"express-session": "^1.17.3",
|
|
22
|
+
"graphql": "^16.7.1",
|
|
20
23
|
"jsonschema": "^1.4.1",
|
|
21
24
|
"jsonwebtoken": "^9.0.1",
|
|
22
25
|
"nestjs-pino": "^3.3.0",
|
|
23
26
|
"pino-http": "^8.3.3",
|
|
24
27
|
"pino-pretty": "^10.1.0",
|
|
28
|
+
"redis": "^4.6.8",
|
|
25
29
|
"slugify": "^1.6.6"
|
|
26
30
|
},
|
|
27
31
|
"devDependencies": {
|
|
28
32
|
"@types/express": "^4.17.17",
|
|
33
|
+
"@types/express-session": "^1.17.1",
|
|
29
34
|
"@types/jsonwebtoken": "^9.0.2",
|
|
30
35
|
"@types/node": "^20.4.2",
|
|
31
36
|
"minimist": "^1.2.8",
|