@autofleet/node-common 2.0.1 → 4.0.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.
- package/.nvmrc +1 -0
- package/README.md +4 -48
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +21 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +40 -29
- package/src/consts/index.test.ts +26 -0
- package/{consts/index.js → src/consts/index.ts} +2 -2
- package/src/index.test.ts +18 -0
- package/src/index.ts +6 -0
- package/src/router/index.test.ts +149 -0
- package/src/router/index.ts +45 -0
- package/tsconfig.json +15 -0
- package/tsup.config.ts +13 -0
- package/vitest.config.ts +14 -0
- package/.jest.config.js +0 -8
- package/delorean-client/index.js +0 -52
- package/delorean-client/index.test.js +0 -105
- package/index.js +0 -17
- package/logger/example.js +0 -5
- package/logger/index.js +0 -114
- package/logger/index.test.js +0 -54
- package/network/index.js +0 -105
- package/network/index.test.js +0 -69
- package/queue/index.js +0 -107
- package/router/index.js +0 -45
- package/settings/example.js +0 -30
- package/settings/index.js +0 -107
- package/settings/index.test.js +0 -168
- package/settings/map.js +0 -426
package/.nvmrc
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
22.9.0
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# AutoFleet Node Common
|
|
2
|
-
This
|
|
2
|
+
This repository is made in order have as much of common code as we can.
|
|
3
3
|
|
|
4
|
-
Each line of code used in
|
|
4
|
+
Each line of code used in written in this repo will be used in the entire AutoFleet system.
|
|
5
5
|
|
|
6
6
|
Make sure you have:
|
|
7
7
|
* Tests
|
|
@@ -9,7 +9,7 @@ Make sure you have:
|
|
|
9
9
|
|
|
10
10
|
## Consts
|
|
11
11
|
|
|
12
|
-
Currently we
|
|
12
|
+
Currently we support:
|
|
13
13
|
```
|
|
14
14
|
{
|
|
15
15
|
'OK'
|
|
@@ -18,55 +18,11 @@ Currently we suppurt:
|
|
|
18
18
|
}
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
## Network
|
|
22
|
-
Server 2 Servers communication.
|
|
23
|
-
|
|
24
|
-
Implemented:
|
|
25
|
-
* Retriving service urls from environment
|
|
26
|
-
* Retry - Using https://github.com/softonic/axios-retry
|
|
27
|
-
* Caching - TBD
|
|
28
|
-
* Syntatic response for fail - TBD
|
|
29
|
-
* Circuit Breaking - TBD
|
|
30
|
-
|
|
31
|
-
The API is just like [axios](https://github.com/axios/axios) api but the creation of new instance **must** have either `serviceName` or `serviceUrl` in options.
|
|
32
|
-
|
|
33
|
-
In case `serviceName` used the constractor will look for an environment varible with the the name `<SERVICE_NAME>_SERVICE_HOST`.
|
|
34
|
-
|
|
35
|
-
For Example:
|
|
36
|
-
```
|
|
37
|
-
const { Network } = require('@autofleet/node-common');
|
|
38
|
-
|
|
39
|
-
n = new Network({ serviceName: 'TEST' });
|
|
40
|
-
|
|
41
|
-
n.get('/posts/1');
|
|
42
|
-
```
|
|
43
|
-
.env file:
|
|
44
|
-
```
|
|
45
|
-
RIDE_SERVICE_HOST=jsonplaceholder.typicode.com
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
To learn more [click here](https://blog.risingstack.com/designing-microservices-architecture-for-failure/).
|
|
49
|
-
|
|
50
|
-
## Settings
|
|
51
|
-
|
|
52
|
-
### Adding settings
|
|
53
|
-
For adding new setting you need to add it to the map.js file, please specify
|
|
54
|
-
* name - descriptive name
|
|
55
|
-
* description - few words about what it does + unit
|
|
56
|
-
* type - supportable types: 'number', 'string', 'json'
|
|
57
|
-
* defaultValue - default value
|
|
58
|
-
* context - 'security' and 'operation' will not show in the simulator configuration
|
|
59
|
-
|
|
60
|
-
See example.
|
|
61
|
-
|
|
62
|
-
## DeLorean
|
|
63
|
-
|
|
64
|
-
Use this model to mock time on server - more info TBD.
|
|
65
|
-
|
|
66
21
|
## Publish package
|
|
67
22
|
|
|
68
23
|
bump the version number in package.json
|
|
69
24
|
and run
|
|
70
25
|
```
|
|
26
|
+
node --run build
|
|
71
27
|
npm publish
|
|
72
28
|
```
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
'use strict';var express=require('express'),i=require('@autofleet/logger');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var i__default=/*#__PURE__*/_interopDefault(i);var R=["all","get","post","put","delete","patch","options","head"],f=(n,s)=>async(r,o,e)=>{try{await s(r,o,e);}catch(a){let t=a;if(n.error(t.message),t.statusCode&&t.statusCode<500){o.status(400).json({error:t.message,status:"ERROR"});return}e(t);}},u=({logger:n=i__default.default(),...s})=>{let r=express.Router({mergeParams:true,...s});return R.forEach(e=>{let a=r[e].bind(r),t=(...p)=>a(...p.map(o));r[e]=t;}),r;function o(e){return Array.isArray(e)?e.map(o):typeof e=="function"?f(n,e):e}};var m=Object.freeze({ok:"OK",error:"ERROR",fail:"FAIL"});var x=u;exports.AfRouter=u;exports.Router=x;exports.consts=m;//# sourceMappingURL=index.cjs.map
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/router/index.ts","../src/consts/index.ts","../src/index.ts"],"names":["METHODS","AfEntryPoint","logger","func","req","res","next","err","e","AfRouter","Logger","options","myRouter","Router","method","internalMethod","newMethodHandler","args","argMapper","consts"],"mappings":"2LAKaA,IAAAA,CAAAA,CAAU,CACrB,KAAA,CACA,MACA,MACA,CAAA,KAAA,CACA,QACA,CAAA,OAAA,CACA,UACA,MACF,CAAA,CAEMC,CAAe,CAAA,CAACC,EAA+BC,CAAmG,GAAA,MAAOC,CAAKC,CAAAA,CAAAA,CAAKC,IAAS,CAChL,GAAI,CACF,MAAMH,EAAKC,CAAKC,CAAAA,CAAAA,CAAKC,CAAI,EAC3B,CAAA,MAASC,EAAK,CACZ,IAAMC,CAAID,CAAAA,CAAAA,CAEV,GADAL,CAAO,CAAA,KAAA,CAAMM,CAAE,CAAA,OAAO,EAClBA,CAAE,CAAA,UAAA,EAAcA,CAAE,CAAA,UAAA,CAAa,IAAK,CACtCH,CAAAA,CAAI,MAAO,CAAA,GAAG,EAAE,IAAK,CAAA,CAAE,KAAOG,CAAAA,CAAAA,CAAE,QAAS,MAAQ,CAAA,OAAQ,CAAC,CAAA,CAC1D,MACF,CACAF,CAAAA,CAAKE,CAAC,EACR,CACF,CAGaC,CAAAA,CAAAA,CAAW,CAAC,CAAE,MAAA,CAAAP,EAASQ,kBAAO,EAAA,CAAG,GAAGC,CAAQ,IAAiE,CACxH,IAAMC,CAAWC,CAAAA,cAAAA,CAAO,CAAE,WAAa,CAAA,IAAA,CAAM,GAAGF,CAAQ,CAAC,CACzD,CAAA,OAAAX,CAAQ,CAAA,OAAA,CAASc,GAAW,CAC1B,IAAMC,CAAiBH,CAAAA,CAAAA,CAASE,CAAM,CAAE,CAAA,IAAA,CAAKF,CAAQ,CAAA,CAC/CI,EAA2C,CAAIC,GAAAA,CAAAA,GAAyBF,CAAe,CAAA,GAAGE,EAAK,GAAIC,CAAAA,CAAS,CAAa,CAC/HN,CAAAA,CAAAA,CAASE,CAAM,CAAIE,CAAAA,EACrB,CAAC,CAAA,CACMJ,EAEP,SAASM,CAAAA,CAAUD,CAAwB,CAAA,CACzC,OAAI,KAAM,CAAA,OAAA,CAAQA,CAAI,CAAA,CAAUA,EAAK,GAAIC,CAAAA,CAAS,EAC3C,OAAOD,CAAAA,EAAS,WAAahB,CAAaC,CAAAA,CAAAA,CAAQe,CAAe,CAAA,CAAIA,CAC9E,CACF,EC5CaE,IAAAA,CAAAA,CAAS,OAAO,MAAO,CAAA,CAClC,EAAI,CAAA,IAAA,CACJ,MAAO,OACP,CAAA,IAAA,CAAM,MACR,CAAC,MCCYN,CAASJ,CAAAA","file":"index.cjs","sourcesContent":["import {\n Router, type Request, type Response, type NextFunction, type Handler, type RouterOptions, type IRouterMatcher,\n} from 'express';\nimport Logger, { type LoggerInstanceManager } from '@autofleet/logger';\n\nexport const METHODS = [\n 'all',\n 'get',\n 'post',\n 'put',\n 'delete',\n 'patch',\n 'options',\n 'head',\n] as const;\n\nconst AfEntryPoint = (logger: LoggerInstanceManager, func: (req: Request, res: Response, nextFn: NextFunction) => void | PromiseLike<void>): Handler => async (req, res, next) => {\n try {\n await func(req, res, next);\n } catch (err) {\n const e = err as Error & { statusCode?: number };\n logger.error(e.message);\n if (e.statusCode && e.statusCode < 500) {\n res.status(400).json({ error: e.message, status: 'ERROR' });\n return;\n }\n next(e);\n }\n};\n\n/** @returns a monkey-patched express router that will handle async routes (and force a 400 status for codes <500) */\nexport const AfRouter = ({ logger = Logger(), ...options }: RouterOptions & { logger: LoggerInstanceManager }): Router => {\n const myRouter = Router({ mergeParams: true, ...options });\n METHODS.forEach((method) => {\n const internalMethod = myRouter[method].bind(myRouter);\n const newMethodHandler: IRouterMatcher<Router> = (...args: [...unknown[]]) => internalMethod(...args.map(argMapper) as [string]);\n myRouter[method] = newMethodHandler;\n });\n return myRouter;\n\n function argMapper(args: unknown): unknown {\n if (Array.isArray(args)) return args.map(argMapper);\n return typeof args === 'function' ? AfEntryPoint(logger, args as Handler) : args;\n }\n};\n","export const consts = Object.freeze({\n ok: 'OK',\n error: 'ERROR',\n fail: 'FAIL',\n});\n","import { AfRouter } from './router';\n\nexport { AfRouter } from './router';\nexport { consts } from './consts';\n\nexport const Router = AfRouter;\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as _autofleet_logger from '@autofleet/logger';
|
|
2
|
+
import { LoggerInstanceManager } from '@autofleet/logger';
|
|
3
|
+
import * as express from 'express';
|
|
4
|
+
import { RouterOptions, Router as Router$1 } from 'express';
|
|
5
|
+
|
|
6
|
+
/** @returns a monkey-patched express router that will handle async routes (and force a 400 status for codes <500) */
|
|
7
|
+
declare const AfRouter: ({ logger, ...options }: RouterOptions & {
|
|
8
|
+
logger: LoggerInstanceManager;
|
|
9
|
+
}) => Router$1;
|
|
10
|
+
|
|
11
|
+
declare const consts: Readonly<{
|
|
12
|
+
ok: "OK";
|
|
13
|
+
error: "ERROR";
|
|
14
|
+
fail: "FAIL";
|
|
15
|
+
}>;
|
|
16
|
+
|
|
17
|
+
declare const Router: ({ logger, ...options }: express.RouterOptions & {
|
|
18
|
+
logger: _autofleet_logger.LoggerInstanceManager;
|
|
19
|
+
}) => express.Router;
|
|
20
|
+
|
|
21
|
+
export { AfRouter, Router, consts };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as _autofleet_logger from '@autofleet/logger';
|
|
2
|
+
import { LoggerInstanceManager } from '@autofleet/logger';
|
|
3
|
+
import * as express from 'express';
|
|
4
|
+
import { RouterOptions, Router as Router$1 } from 'express';
|
|
5
|
+
|
|
6
|
+
/** @returns a monkey-patched express router that will handle async routes (and force a 400 status for codes <500) */
|
|
7
|
+
declare const AfRouter: ({ logger, ...options }: RouterOptions & {
|
|
8
|
+
logger: LoggerInstanceManager;
|
|
9
|
+
}) => Router$1;
|
|
10
|
+
|
|
11
|
+
declare const consts: Readonly<{
|
|
12
|
+
ok: "OK";
|
|
13
|
+
error: "ERROR";
|
|
14
|
+
fail: "FAIL";
|
|
15
|
+
}>;
|
|
16
|
+
|
|
17
|
+
declare const Router: ({ logger, ...options }: express.RouterOptions & {
|
|
18
|
+
logger: _autofleet_logger.LoggerInstanceManager;
|
|
19
|
+
}) => express.Router;
|
|
20
|
+
|
|
21
|
+
export { AfRouter, Router, consts };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import {Router}from'express';import i from'@autofleet/logger';var R=["all","get","post","put","delete","patch","options","head"],f=(n,s)=>async(r,o,e)=>{try{await s(r,o,e);}catch(a){let t=a;if(n.error(t.message),t.statusCode&&t.statusCode<500){o.status(400).json({error:t.message,status:"ERROR"});return}e(t);}},u=({logger:n=i(),...s})=>{let r=Router({mergeParams:true,...s});return R.forEach(e=>{let a=r[e].bind(r),t=(...p)=>a(...p.map(o));r[e]=t;}),r;function o(e){return Array.isArray(e)?e.map(o):typeof e=="function"?f(n,e):e}};var m=Object.freeze({ok:"OK",error:"ERROR",fail:"FAIL"});var x=u;export{u as AfRouter,x as Router,m as consts};//# sourceMappingURL=index.js.map
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/router/index.ts","../src/consts/index.ts","../src/index.ts"],"names":["METHODS","AfEntryPoint","logger","func","req","res","next","err","e","AfRouter","Logger","options","myRouter","Router","method","internalMethod","newMethodHandler","args","argMapper","consts"],"mappings":"8DAKaA,IAAAA,CAAAA,CAAU,CACrB,KAAA,CACA,MACA,MACA,CAAA,KAAA,CACA,QACA,CAAA,OAAA,CACA,UACA,MACF,CAAA,CAEMC,CAAe,CAAA,CAACC,EAA+BC,CAAmG,GAAA,MAAOC,CAAKC,CAAAA,CAAAA,CAAKC,IAAS,CAChL,GAAI,CACF,MAAMH,EAAKC,CAAKC,CAAAA,CAAAA,CAAKC,CAAI,EAC3B,CAAA,MAASC,EAAK,CACZ,IAAMC,CAAID,CAAAA,CAAAA,CAEV,GADAL,CAAO,CAAA,KAAA,CAAMM,CAAE,CAAA,OAAO,EAClBA,CAAE,CAAA,UAAA,EAAcA,CAAE,CAAA,UAAA,CAAa,IAAK,CACtCH,CAAAA,CAAI,MAAO,CAAA,GAAG,EAAE,IAAK,CAAA,CAAE,KAAOG,CAAAA,CAAAA,CAAE,QAAS,MAAQ,CAAA,OAAQ,CAAC,CAAA,CAC1D,MACF,CACAF,CAAAA,CAAKE,CAAC,EACR,CACF,CAGaC,CAAAA,CAAAA,CAAW,CAAC,CAAE,MAAA,CAAAP,EAASQ,CAAO,EAAA,CAAG,GAAGC,CAAQ,IAAiE,CACxH,IAAMC,CAAWC,CAAAA,MAAAA,CAAO,CAAE,WAAa,CAAA,IAAA,CAAM,GAAGF,CAAQ,CAAC,CACzD,CAAA,OAAAX,CAAQ,CAAA,OAAA,CAASc,GAAW,CAC1B,IAAMC,CAAiBH,CAAAA,CAAAA,CAASE,CAAM,CAAE,CAAA,IAAA,CAAKF,CAAQ,CAAA,CAC/CI,EAA2C,CAAIC,GAAAA,CAAAA,GAAyBF,CAAe,CAAA,GAAGE,EAAK,GAAIC,CAAAA,CAAS,CAAa,CAC/HN,CAAAA,CAAAA,CAASE,CAAM,CAAIE,CAAAA,EACrB,CAAC,CAAA,CACMJ,EAEP,SAASM,CAAAA,CAAUD,CAAwB,CAAA,CACzC,OAAI,KAAM,CAAA,OAAA,CAAQA,CAAI,CAAA,CAAUA,EAAK,GAAIC,CAAAA,CAAS,EAC3C,OAAOD,CAAAA,EAAS,WAAahB,CAAaC,CAAAA,CAAAA,CAAQe,CAAe,CAAA,CAAIA,CAC9E,CACF,EC5CaE,IAAAA,CAAAA,CAAS,OAAO,MAAO,CAAA,CAClC,EAAI,CAAA,IAAA,CACJ,MAAO,OACP,CAAA,IAAA,CAAM,MACR,CAAC,MCCYN,CAASJ,CAAAA","file":"index.js","sourcesContent":["import {\n Router, type Request, type Response, type NextFunction, type Handler, type RouterOptions, type IRouterMatcher,\n} from 'express';\nimport Logger, { type LoggerInstanceManager } from '@autofleet/logger';\n\nexport const METHODS = [\n 'all',\n 'get',\n 'post',\n 'put',\n 'delete',\n 'patch',\n 'options',\n 'head',\n] as const;\n\nconst AfEntryPoint = (logger: LoggerInstanceManager, func: (req: Request, res: Response, nextFn: NextFunction) => void | PromiseLike<void>): Handler => async (req, res, next) => {\n try {\n await func(req, res, next);\n } catch (err) {\n const e = err as Error & { statusCode?: number };\n logger.error(e.message);\n if (e.statusCode && e.statusCode < 500) {\n res.status(400).json({ error: e.message, status: 'ERROR' });\n return;\n }\n next(e);\n }\n};\n\n/** @returns a monkey-patched express router that will handle async routes (and force a 400 status for codes <500) */\nexport const AfRouter = ({ logger = Logger(), ...options }: RouterOptions & { logger: LoggerInstanceManager }): Router => {\n const myRouter = Router({ mergeParams: true, ...options });\n METHODS.forEach((method) => {\n const internalMethod = myRouter[method].bind(myRouter);\n const newMethodHandler: IRouterMatcher<Router> = (...args: [...unknown[]]) => internalMethod(...args.map(argMapper) as [string]);\n myRouter[method] = newMethodHandler;\n });\n return myRouter;\n\n function argMapper(args: unknown): unknown {\n if (Array.isArray(args)) return args.map(argMapper);\n return typeof args === 'function' ? AfEntryPoint(logger, args as Handler) : args;\n }\n};\n","export const consts = Object.freeze({\n ok: 'OK',\n error: 'ERROR',\n fail: 'FAIL',\n});\n","import { AfRouter } from './router';\n\nexport { AfRouter } from './router';\nexport { consts } from './consts';\n\nexport const Router = AfRouter;\n"]}
|
package/package.json
CHANGED
|
@@ -1,16 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autofleet/node-common",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"module": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
"import": {
|
|
11
|
+
"default": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
},
|
|
14
|
+
"require": {
|
|
15
|
+
"default": "./dist/index.cjs",
|
|
16
|
+
"types": "./dist/index.d.cts"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
5
19
|
"scripts": {
|
|
6
|
-
"coverage": "
|
|
7
|
-
"test": "
|
|
8
|
-
"
|
|
9
|
-
"linter": "
|
|
20
|
+
"coverage": "vitest --coverage",
|
|
21
|
+
"test": "vitest",
|
|
22
|
+
"build": "tsup",
|
|
23
|
+
"linter": "eslint ."
|
|
10
24
|
},
|
|
11
25
|
"jest": {
|
|
12
|
-
"
|
|
13
|
-
|
|
26
|
+
"setupFilesAfterEnv": [
|
|
27
|
+
"jest-extended"
|
|
28
|
+
],
|
|
29
|
+
"testEnvironmentOptions": {
|
|
30
|
+
"url": "http://localhost:8085/"
|
|
31
|
+
}
|
|
14
32
|
},
|
|
15
33
|
"repository": {
|
|
16
34
|
"type": "git",
|
|
@@ -22,28 +40,21 @@
|
|
|
22
40
|
"url": "https://github.com/Autofleet/node-common/issues"
|
|
23
41
|
},
|
|
24
42
|
"homepage": "https://github.com/Autofleet/node-common",
|
|
25
|
-
"dependencies": {
|
|
26
|
-
"@google-cloud/logging-winston": "^4.1.1",
|
|
27
|
-
"axios": "^0.18.0",
|
|
28
|
-
"axios-retry": "^3.1.0",
|
|
29
|
-
"dotenv": "^5.0.1",
|
|
30
|
-
"event-pubsub": "^4.3.0",
|
|
31
|
-
"express": "^4.16.2",
|
|
32
|
-
"jest": "^22.4.4",
|
|
33
|
-
"mock-socket": "^7.1.0",
|
|
34
|
-
"node-cache": "^4.2.0",
|
|
35
|
-
"node-resque": "^5.4.1",
|
|
36
|
-
"portfinder": "^1.0.13",
|
|
37
|
-
"qs": "^6.5.2",
|
|
38
|
-
"timekeeper": "^2.1.2",
|
|
39
|
-
"winston": "^3.0.0",
|
|
40
|
-
"ws": "^5.2.1"
|
|
41
|
-
},
|
|
42
43
|
"devDependencies": {
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"eslint-plugin
|
|
46
|
-
"
|
|
47
|
-
"
|
|
44
|
+
"@autofleet/logger": "^4.2.1",
|
|
45
|
+
"@types/express": "^4.17.21",
|
|
46
|
+
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
|
47
|
+
"@typescript-eslint/parser": "^7.18.0",
|
|
48
|
+
"@vitest/coverage-v8": "^3.0.6",
|
|
49
|
+
"eslint": "^8.57.0",
|
|
50
|
+
"eslint-config-airbnb-base": "^15.0.0",
|
|
51
|
+
"eslint-plugin-import": "^2.29.1",
|
|
52
|
+
"tsup": "^8.3.6",
|
|
53
|
+
"typescript": "^5.7.3",
|
|
54
|
+
"vitest": "^3.0.6"
|
|
55
|
+
},
|
|
56
|
+
"peerDependencies": {
|
|
57
|
+
"@autofleet/logger": ">=4.2.1",
|
|
58
|
+
"express": "^4.21.2"
|
|
48
59
|
}
|
|
49
60
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { consts } from '.';
|
|
3
|
+
|
|
4
|
+
describe('consts', () => {
|
|
5
|
+
it('should be an object', () => {
|
|
6
|
+
expect(typeof consts).toBe('object');
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it('should have ok', () => {
|
|
10
|
+
expect('ok' in consts).toBeTruthy();
|
|
11
|
+
expect(typeof consts.ok).toBe('string');
|
|
12
|
+
expect(consts.ok).toBe('OK');
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('should have error', () => {
|
|
16
|
+
expect('error' in consts).toBeTruthy();
|
|
17
|
+
expect(typeof consts.error).toBe('string');
|
|
18
|
+
expect(consts.error).toBe('ERROR');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should have fail', () => {
|
|
22
|
+
expect('fail' in consts).toBeTruthy();
|
|
23
|
+
expect(typeof consts.fail).toBe('string');
|
|
24
|
+
expect(consts.fail).toBe('FAIL');
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import * as nodeCommon from '.';
|
|
3
|
+
import { consts } from './consts';
|
|
4
|
+
import { AfRouter } from './router';
|
|
5
|
+
|
|
6
|
+
describe('node-common', () => {
|
|
7
|
+
it('exports consts', () => {
|
|
8
|
+
expect(nodeCommon.consts).toBe(consts);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('exports AfRouter', () => {
|
|
12
|
+
expect(nodeCommon.AfRouter).toBe(AfRouter);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('exports AFRouter aliased as Router', () => {
|
|
16
|
+
expect(nodeCommon.Router).toBe(AfRouter);
|
|
17
|
+
});
|
|
18
|
+
});
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import Logger from '@autofleet/logger';
|
|
2
|
+
import type { Request, Response, NextFunction } from 'express';
|
|
3
|
+
import {
|
|
4
|
+
describe, expect, it, vi,
|
|
5
|
+
} from 'vitest';
|
|
6
|
+
import { AfRouter, METHODS } from '.';
|
|
7
|
+
|
|
8
|
+
const logger = Logger();
|
|
9
|
+
const noop = () => null;
|
|
10
|
+
|
|
11
|
+
describe('Router', () => {
|
|
12
|
+
it('is a function', () => {
|
|
13
|
+
expect(typeof AfRouter).toBe('function');
|
|
14
|
+
expect(AfRouter.length).toBe(1);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('returns a Router instance', () => {
|
|
18
|
+
const router = AfRouter({ logger });
|
|
19
|
+
expect(typeof router).toBe('function');
|
|
20
|
+
expect(typeof router.use).toBe('function');
|
|
21
|
+
expect(typeof router.get).toBe('function');
|
|
22
|
+
expect(typeof router.post).toBe('function');
|
|
23
|
+
expect(typeof router.put).toBe('function');
|
|
24
|
+
expect(typeof router.delete).toBe('function');
|
|
25
|
+
expect(typeof router.patch).toBe('function');
|
|
26
|
+
expect(typeof router.options).toBe('function');
|
|
27
|
+
expect(typeof router.head).toBe('function');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe.each(METHODS)('Route method %s', { timeout: 1000 }, (method) => {
|
|
31
|
+
it('handles sync routes', async () => {
|
|
32
|
+
const router = AfRouter({ logger });
|
|
33
|
+
router[method]('/test', (_req, res) => {
|
|
34
|
+
res.send('ok');
|
|
35
|
+
});
|
|
36
|
+
const { promise, resolve } = Promise.withResolvers<string>();
|
|
37
|
+
const req = { method, url: '/test', baseUrl: '' };
|
|
38
|
+
const res = { send: (data: string) => resolve(data) };
|
|
39
|
+
// @ts-expect-error handle is not typed for an unclear reason.
|
|
40
|
+
router.handle(req, res, noop);
|
|
41
|
+
expect(await promise).toBe('ok');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('handles async routes', async () => {
|
|
45
|
+
const router = AfRouter({ logger });
|
|
46
|
+
router[method]('/test', async (req, res) => {
|
|
47
|
+
res.send('ok');
|
|
48
|
+
});
|
|
49
|
+
const { promise, resolve } = Promise.withResolvers<string>();
|
|
50
|
+
const req = { method, url: '/test', baseUrl: '' };
|
|
51
|
+
const res = { send: (data: string) => resolve(data) };
|
|
52
|
+
// @ts-expect-error handle is not typed for an unclear reason.
|
|
53
|
+
router.handle(req, res, noop);
|
|
54
|
+
expect(await promise).toBe('ok');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('handles arrays of handlers', async () => {
|
|
58
|
+
const router = AfRouter({ logger });
|
|
59
|
+
router[method]('/test', [
|
|
60
|
+
(_req: Request, _res: Response, next: NextFunction) => next(),
|
|
61
|
+
(_req: Request, res: Response) => res.send('ok'),
|
|
62
|
+
]);
|
|
63
|
+
const { promise, resolve } = Promise.withResolvers<string>();
|
|
64
|
+
const req = { method, url: '/test', baseUrl: '' };
|
|
65
|
+
const res = { send: (data: string) => resolve(data) };
|
|
66
|
+
// @ts-expect-error handle is not typed for an unclear reason.
|
|
67
|
+
router.handle(req, res, noop);
|
|
68
|
+
expect(await promise).toBe('ok');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('handles errors', async () => {
|
|
72
|
+
const router = AfRouter({ logger });
|
|
73
|
+
const error = new Error('test error');
|
|
74
|
+
router[method]('/test', () => {
|
|
75
|
+
throw error;
|
|
76
|
+
});
|
|
77
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
78
|
+
const next = vi.fn(resolve);
|
|
79
|
+
const req = { method, url: '/test', baseUrl: '' };
|
|
80
|
+
const res = {};
|
|
81
|
+
// @ts-expect-error handle is not typed for an unclear reason.
|
|
82
|
+
router.handle(req, res, next);
|
|
83
|
+
await promise;
|
|
84
|
+
expect(next).toHaveBeenCalledExactlyOnceWith(error);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('handles rejections', async () => {
|
|
88
|
+
const router = AfRouter({ logger });
|
|
89
|
+
const error = new Error('test error');
|
|
90
|
+
router[method]('/test', () => Promise.reject(error));
|
|
91
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
92
|
+
const next = vi.fn(resolve);
|
|
93
|
+
const req = { method, url: '/test', baseUrl: '' };
|
|
94
|
+
const res = {};
|
|
95
|
+
// @ts-expect-error handle is not typed for an unclear reason.
|
|
96
|
+
router.handle(req, res, next);
|
|
97
|
+
await promise;
|
|
98
|
+
// expect(await promise).toBe({ error: 'test error', status: "ERROR" });
|
|
99
|
+
expect(next).toHaveBeenCalledExactlyOnceWith(error);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('forces errors with status code 400 if not 500', async () => {
|
|
103
|
+
const router = AfRouter({ logger });
|
|
104
|
+
const error = Object.assign(new Error('test error'), { statusCode: 418 });
|
|
105
|
+
router[method]('/test', () => Promise.reject(error));
|
|
106
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
107
|
+
const status = vi.fn(() => ({ json: resolve }));
|
|
108
|
+
const req = { method, url: '/test', baseUrl: '' };
|
|
109
|
+
const res = { status };
|
|
110
|
+
// @ts-expect-error handle is not typed for an unclear reason.
|
|
111
|
+
router.handle(req, res, noop);
|
|
112
|
+
await promise;
|
|
113
|
+
expect(await promise).toEqual({ error: 'test error', status: 'ERROR' });
|
|
114
|
+
expect(status).toHaveBeenCalledExactlyOnceWith(400);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('keeps original errors when status code is 500', async () => {
|
|
118
|
+
const router = AfRouter({ logger });
|
|
119
|
+
const error = Object.assign(new Error('test error'), { statusCode: 500 });
|
|
120
|
+
router[method]('/test', () => Promise.reject(error));
|
|
121
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
122
|
+
const next = vi.fn(resolve);
|
|
123
|
+
const req = { method, url: '/test', baseUrl: '' };
|
|
124
|
+
const res = {};
|
|
125
|
+
// @ts-expect-error handle is not typed for an unclear reason.
|
|
126
|
+
router.handle(req, res, next);
|
|
127
|
+
await promise;
|
|
128
|
+
expect(next).toHaveBeenCalledExactlyOnceWith(error);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('defaults to mergeParams true', async () => {
|
|
132
|
+
const router = AfRouter({ mergeParams: false, logger });
|
|
133
|
+
const childRouter = AfRouter({ logger });
|
|
134
|
+
router.use('/:parentParam', childRouter);
|
|
135
|
+
childRouter[method]<{ parentParam: string; param: string; }>('/:param', (req, res) => res.send({ param: req.params.param, parentParam: req.params.parentParam }));
|
|
136
|
+
|
|
137
|
+
const { promise, resolve } = Promise.withResolvers<string>();
|
|
138
|
+
const req = { method, url: '/foo/bar', baseUrl: '' };
|
|
139
|
+
const res = { send: (data: string) => resolve(data) };
|
|
140
|
+
// @ts-expect-error handle is not typed for an unclear reason.
|
|
141
|
+
router.handle(req, res, noop);
|
|
142
|
+
expect(await promise).toEqual({ parentParam: 'foo', param: 'bar' });
|
|
143
|
+
// @ts-expect-error mergeParams is a private field
|
|
144
|
+
expect(router.mergeParams).toBeFalsy();
|
|
145
|
+
// @ts-expect-error mergeParams is a private field
|
|
146
|
+
expect(childRouter.mergeParams).toBeTruthy();
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Router, type Request, type Response, type NextFunction, type Handler, type RouterOptions, type IRouterMatcher,
|
|
3
|
+
} from 'express';
|
|
4
|
+
import Logger, { type LoggerInstanceManager } from '@autofleet/logger';
|
|
5
|
+
|
|
6
|
+
export const METHODS = [
|
|
7
|
+
'all',
|
|
8
|
+
'get',
|
|
9
|
+
'post',
|
|
10
|
+
'put',
|
|
11
|
+
'delete',
|
|
12
|
+
'patch',
|
|
13
|
+
'options',
|
|
14
|
+
'head',
|
|
15
|
+
] as const;
|
|
16
|
+
|
|
17
|
+
const AfEntryPoint = (logger: LoggerInstanceManager, func: (req: Request, res: Response, nextFn: NextFunction) => void | PromiseLike<void>): Handler => async (req, res, next) => {
|
|
18
|
+
try {
|
|
19
|
+
await func(req, res, next);
|
|
20
|
+
} catch (err) {
|
|
21
|
+
const e = err as Error & { statusCode?: number };
|
|
22
|
+
logger.error(e.message);
|
|
23
|
+
if (e.statusCode && e.statusCode < 500) {
|
|
24
|
+
res.status(400).json({ error: e.message, status: 'ERROR' });
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
next(e);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/** @returns a monkey-patched express router that will handle async routes (and force a 400 status for codes <500) */
|
|
32
|
+
export const AfRouter = ({ logger = Logger(), ...options }: RouterOptions & { logger: LoggerInstanceManager }): Router => {
|
|
33
|
+
const myRouter = Router({ mergeParams: true, ...options });
|
|
34
|
+
METHODS.forEach((method) => {
|
|
35
|
+
const internalMethod = myRouter[method].bind(myRouter);
|
|
36
|
+
const newMethodHandler: IRouterMatcher<Router> = (...args: [...unknown[]]) => internalMethod(...args.map(argMapper) as [string]);
|
|
37
|
+
myRouter[method] = newMethodHandler;
|
|
38
|
+
});
|
|
39
|
+
return myRouter;
|
|
40
|
+
|
|
41
|
+
function argMapper(args: unknown): unknown {
|
|
42
|
+
if (Array.isArray(args)) return args.map(argMapper);
|
|
43
|
+
return typeof args === 'function' ? AfEntryPoint(logger, args as Handler) : args;
|
|
44
|
+
}
|
|
45
|
+
};
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"declaration": true,
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"lib": [
|
|
11
|
+
"ESNext"
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
"include": ["src", "tsup.config.ts", "vitest.config.ts"],
|
|
15
|
+
}
|
package/tsup.config.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { defineConfig } from 'tsup';
|
|
2
|
+
|
|
3
|
+
export default defineConfig((options) => ({
|
|
4
|
+
entry: ['src/index.ts'],
|
|
5
|
+
target: 'node18.0',
|
|
6
|
+
dts: true,
|
|
7
|
+
format: ['esm', 'cjs'],
|
|
8
|
+
clean: !options.watch,
|
|
9
|
+
minify: !options.watch,
|
|
10
|
+
removeNodeProtocol: false,
|
|
11
|
+
treeshake: true,
|
|
12
|
+
sourcemap: true,
|
|
13
|
+
}));
|
package/vitest.config.ts
ADDED
package/.jest.config.js
DELETED
package/delorean-client/index.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
const tk = require('timekeeper');
|
|
2
|
-
const WebSocket = require('ws');
|
|
3
|
-
const Logger = require('../logger');
|
|
4
|
-
|
|
5
|
-
const logger = Logger();
|
|
6
|
-
|
|
7
|
-
const createWs = (host, resolve) => {
|
|
8
|
-
const ws = new WebSocket(`ws://${host}`);
|
|
9
|
-
|
|
10
|
-
ws.on('open', () => {
|
|
11
|
-
ws.send(JSON.stringify({ type: 'ping' }));
|
|
12
|
-
if (resolve) {
|
|
13
|
-
resolve(true);
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
ws.on('error', (error) => {
|
|
18
|
-
logger.error('ERROR', error);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
ws.on('message', (data) => {
|
|
22
|
-
const jsonMsg = JSON.parse(data);
|
|
23
|
-
|
|
24
|
-
if (jsonMsg.type === 'freeze') {
|
|
25
|
-
logger.info('I know you just sent me back to the future, but I\'m back.I\'m back from the future.', { goingBackTo: jsonMsg.time });
|
|
26
|
-
tk.freeze(new Date(jsonMsg.time));
|
|
27
|
-
} else if (jsonMsg.type === 'travel') {
|
|
28
|
-
tk.travel(jsonMsg.time);
|
|
29
|
-
}
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
ws.on('close', () => {
|
|
33
|
-
setTimeout(() => {
|
|
34
|
-
if (process.env.TIME_TRAVEL_MS_SERVICE_HOST === host) {
|
|
35
|
-
createWs(host, null);
|
|
36
|
-
}
|
|
37
|
-
}, 500);
|
|
38
|
-
});
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
module.exports = () => new Promise((resolve) => {
|
|
42
|
-
const { TIME_TRAVEL_MS_SERVICE_HOST, SHOULD_TIME_TRAVEL } = process.env;
|
|
43
|
-
if (TIME_TRAVEL_MS_SERVICE_HOST && SHOULD_TIME_TRAVEL) {
|
|
44
|
-
logger.info('If my calculations are correct, when this baby hits 88 miles per hour... you\'re gonna see some serious shit.', {
|
|
45
|
-
TIME_TRAVEL_MS_SERVICE_HOST,
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
createWs(TIME_TRAVEL_MS_SERVICE_HOST, resolve);
|
|
49
|
-
} else {
|
|
50
|
-
resolve(false);
|
|
51
|
-
}
|
|
52
|
-
});
|