configurapi 1.6.10 → 2.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/package.json +19 -8
- package/src/config.js +0 -227
- package/src/configurapi.d.ts +0 -161
- package/src/configurapi.js +0 -11
- package/src/dict.js +0 -40
- package/src/errorResponse.js +0 -39
- package/src/event.js +0 -199
- package/src/identity.js +0 -100
- package/src/logLevel.js +0 -7
- package/src/policy/policy.js +0 -44
- package/src/policy/policyHandlerLoader.js +0 -96
- package/src/request.js +0 -14
- package/src/response.js +0 -9
- package/src/result.js +0 -4
- package/src/route.js +0 -61
- package/src/service.js +0 -198
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "configurapi",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "A configurable API framework",
|
|
5
|
-
"main": "
|
|
6
|
-
"
|
|
5
|
+
"main": "dist/configurapi.js",
|
|
6
|
+
"typings": "dist/configurapi.d.ts",
|
|
7
7
|
"files": [
|
|
8
|
-
"
|
|
8
|
+
"dist/*"
|
|
9
9
|
],
|
|
10
10
|
"scripts": {
|
|
11
|
-
"test": "cd test && mocha
|
|
12
|
-
"start": "cd src && node main.js"
|
|
11
|
+
"test": "cd test && mocha --require ts-node/register *.ts",
|
|
12
|
+
"start": "cd src && node main.js",
|
|
13
|
+
"build": "tsc --outDir dist/"
|
|
13
14
|
},
|
|
14
15
|
"dependencies": {
|
|
15
|
-
"agstopwatch": "^1.1.0",
|
|
16
16
|
"events": "^3.0.0",
|
|
17
17
|
"get-parameter-names": "^0.3.0",
|
|
18
18
|
"inflection": "^1.12.0",
|
|
@@ -22,9 +22,20 @@
|
|
|
22
22
|
"uuid": "^3.3.2"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
+
"@types/chai": "^4.2.5",
|
|
26
|
+
"@types/deep-equal": "^1.0.1",
|
|
27
|
+
"@types/inflection": "^1.13.0",
|
|
28
|
+
"@types/js-yaml": "^4.0.5",
|
|
29
|
+
"@types/mocha": "^5.2.6",
|
|
30
|
+
"@types/nested-error-stacks": "^2.1.0",
|
|
31
|
+
"@types/node": "^18.11.9",
|
|
32
|
+
"@types/uuid": "^8.3.4",
|
|
25
33
|
"chai": "4.x.x",
|
|
26
34
|
"deep-equal": "^1.0.1",
|
|
27
|
-
"mocha": "6.1.x"
|
|
35
|
+
"mocha": "6.1.x",
|
|
36
|
+
"ts-node": "^8.5.2",
|
|
37
|
+
"typemoq": "^2.1.0",
|
|
38
|
+
"typescript": "^3.7.2"
|
|
28
39
|
},
|
|
29
40
|
"repository": {
|
|
30
41
|
"type": "git",
|
package/src/config.js
DELETED
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
let Dictionary = require('./dict');
|
|
2
|
-
let Route = require('./route');
|
|
3
|
-
let Policy = require('./policy/policy');
|
|
4
|
-
let LogLevel = require('./logLevel');
|
|
5
|
-
let yaml = require('js-yaml');
|
|
6
|
-
let fs = require('fs');
|
|
7
|
-
let NestedError = require('nested-error-stacks');
|
|
8
|
-
const nodePath = require('path');
|
|
9
|
-
|
|
10
|
-
function getPathParentDir(path)
|
|
11
|
-
{
|
|
12
|
-
if (!nodePath.isAbsolute(path))
|
|
13
|
-
{
|
|
14
|
-
path = nodePath.resolve(process.cwd(), path);
|
|
15
|
-
}
|
|
16
|
-
return nodePath.parse(path).dir
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
module.exports = class Config
|
|
20
|
-
{
|
|
21
|
-
constructor()
|
|
22
|
-
{
|
|
23
|
-
this.modules = [];
|
|
24
|
-
this.events = new Dictionary();
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
static load(path)
|
|
28
|
-
{
|
|
29
|
-
let content = "";
|
|
30
|
-
|
|
31
|
-
try
|
|
32
|
-
{
|
|
33
|
-
content = fs.readFileSync(path, 'utf8');
|
|
34
|
-
}
|
|
35
|
-
catch(error)
|
|
36
|
-
{
|
|
37
|
-
throw new NestedError(`Failed to load '${path}'`, error);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return this.parse(content, getPathParentDir(path));
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
static parse(content, parentDirectory)
|
|
44
|
-
{
|
|
45
|
-
|
|
46
|
-
let document = yaml.safeLoad(content);
|
|
47
|
-
|
|
48
|
-
if(document instanceof Object)
|
|
49
|
-
{
|
|
50
|
-
let config = new Config();
|
|
51
|
-
|
|
52
|
-
config.modules = this.parseImport(document, parentDirectory);
|
|
53
|
-
config.events = this.parseApi(document);
|
|
54
|
-
|
|
55
|
-
return config;
|
|
56
|
-
}
|
|
57
|
-
else
|
|
58
|
-
{
|
|
59
|
-
throw new Error("The specified config file is not an invalid yaml.");
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
static parseImport(document, parentDirectory)
|
|
64
|
-
{
|
|
65
|
-
let result = [];
|
|
66
|
-
|
|
67
|
-
//Check for an optional "import"
|
|
68
|
-
if('import' in document)
|
|
69
|
-
{
|
|
70
|
-
if(typeof document['import'][Symbol.iterator] !== 'function')
|
|
71
|
-
{
|
|
72
|
-
throw new Error(`Could not load 'import.${document['import']}' in the config document`);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
for(let module of document['import'])
|
|
76
|
-
{
|
|
77
|
-
if (module.startsWith('.'))
|
|
78
|
-
{
|
|
79
|
-
module = nodePath.resolve(parentDirectory, module);
|
|
80
|
-
}
|
|
81
|
-
result.push(module);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return result;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
static parseApi(document)
|
|
89
|
-
{
|
|
90
|
-
if('api' in document)
|
|
91
|
-
{
|
|
92
|
-
return this.parseRoutes(document.api);
|
|
93
|
-
}
|
|
94
|
-
else
|
|
95
|
-
{
|
|
96
|
-
throw new Error('Could not find \'api\' in the config document');
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
static parseRoutes(api)
|
|
101
|
-
{
|
|
102
|
-
if((api instanceof Object) && 'events' in api)
|
|
103
|
-
{
|
|
104
|
-
let result = new Dictionary();
|
|
105
|
-
|
|
106
|
-
if(typeof api.events[Symbol.iterator] !== 'function')
|
|
107
|
-
{
|
|
108
|
-
throw new Error(`Events could not be empty in the config document.`);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
let routeIndex=0;
|
|
112
|
-
for(let r of api.events)
|
|
113
|
-
{
|
|
114
|
-
let route = this.parseRoute(r, routeIndex);
|
|
115
|
-
|
|
116
|
-
if(route.enabled)
|
|
117
|
-
{
|
|
118
|
-
result.set(route.name, route);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return result;
|
|
123
|
-
}
|
|
124
|
-
else
|
|
125
|
-
{
|
|
126
|
-
throw new Error('Could not find \'api.events\' in the config document');
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
static parseRoute(route, routeIndex)
|
|
131
|
-
{
|
|
132
|
-
let result = new Route();
|
|
133
|
-
|
|
134
|
-
if(route instanceof Object && 'name' in route)
|
|
135
|
-
{
|
|
136
|
-
result.name = route.name;
|
|
137
|
-
result.logLevel = LogLevel[Object.keys(LogLevel).find(key => key.toLowerCase() === (route.logLevel || LogLevel.Trace).toLowerCase())];
|
|
138
|
-
|
|
139
|
-
if(route.when)
|
|
140
|
-
{
|
|
141
|
-
if(process.env.NODE_ENV === undefined)
|
|
142
|
-
{
|
|
143
|
-
result.enabled = false;
|
|
144
|
-
}
|
|
145
|
-
else
|
|
146
|
-
{
|
|
147
|
-
result.enabled = process.env.NODE_ENV === route.when;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
result.policies = this.parsePolicies(route, result.name);
|
|
152
|
-
|
|
153
|
-
return result;
|
|
154
|
-
}
|
|
155
|
-
else
|
|
156
|
-
{
|
|
157
|
-
throw new Error(`Could not find 'api.events[${routeIndex}].name' in the config document`);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
static parsePolicies(policies, routeName)
|
|
162
|
-
{
|
|
163
|
-
let result = [];
|
|
164
|
-
|
|
165
|
-
if(policies instanceof Object && 'policies' in policies)
|
|
166
|
-
{
|
|
167
|
-
let policyIndex=0;
|
|
168
|
-
|
|
169
|
-
if(typeof policies.policies[Symbol.iterator] !== 'function')
|
|
170
|
-
{
|
|
171
|
-
throw new Error(`Policies 'api.events[${routeName}].policies' could not be empty in the config document.`);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
for(let policy of policies.policies)
|
|
175
|
-
{
|
|
176
|
-
result.push(this.parsePolicy(policy, routeName, policyIndex));
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
return result;
|
|
180
|
-
}
|
|
181
|
-
else
|
|
182
|
-
{
|
|
183
|
-
throw new Error(`Could not find 'api.events[${routeName}].policies' in the config document`);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
static parsePolicy(policy, routeName, policyIndex)
|
|
188
|
-
{
|
|
189
|
-
let result = new Policy();
|
|
190
|
-
let policyName = this.parsePolicyName(policy);
|
|
191
|
-
|
|
192
|
-
if(!policyName)
|
|
193
|
-
{
|
|
194
|
-
throw new Error(`Could not find 'api.events[${routeName}].policies[${policyIndex}]' in the config document`);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
result.name = policyName;
|
|
198
|
-
result.parameters = this.parseParameter(policy, routeName, policyName);
|
|
199
|
-
result.logLevel = LogLevel[Object.keys(LogLevel).find(key => key.toLowerCase() === (policy.logLevel || LogLevel.Trace).toLowerCase())];
|
|
200
|
-
return result;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
static parsePolicyName(policy)
|
|
204
|
-
{
|
|
205
|
-
if(typeof policy == 'string')
|
|
206
|
-
{
|
|
207
|
-
return policy;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
for (var key in policy) {
|
|
211
|
-
if (policy.hasOwnProperty(key)) {
|
|
212
|
-
return key;
|
|
213
|
-
}
|
|
214
|
-
return undefined;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
static parseParameter(policy, routeName, policyName)
|
|
219
|
-
{
|
|
220
|
-
if (policy[policyName] instanceof Array)
|
|
221
|
-
{
|
|
222
|
-
return policy[policyName]
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
return policy.parameters || []
|
|
226
|
-
}
|
|
227
|
-
};
|
package/src/configurapi.d.ts
DELETED
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
///////////////////////////////
|
|
2
|
-
//
|
|
3
|
-
// Const
|
|
4
|
-
//
|
|
5
|
-
///////////////////////////////
|
|
6
|
-
|
|
7
|
-
export const Result: {
|
|
8
|
-
Completed: number;
|
|
9
|
-
Continue: number;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export const LogLevel : {
|
|
13
|
-
Trace:string;
|
|
14
|
-
Debug:string;
|
|
15
|
-
Log:string;
|
|
16
|
-
Error:string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
///////////////////////////////
|
|
20
|
-
//
|
|
21
|
-
// Interface
|
|
22
|
-
//
|
|
23
|
-
///////////////////////////////
|
|
24
|
-
|
|
25
|
-
export interface IConfig {}
|
|
26
|
-
|
|
27
|
-
export interface IClaim {
|
|
28
|
-
type: string;
|
|
29
|
-
value: string;
|
|
30
|
-
scope: string|string[];
|
|
31
|
-
|
|
32
|
-
//A helper property to return all scopes in an array.
|
|
33
|
-
readonly scopes: string[];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface IIdentity {
|
|
37
|
-
id: string;
|
|
38
|
-
issuer: string;
|
|
39
|
-
name: string;
|
|
40
|
-
email: string;
|
|
41
|
-
|
|
42
|
-
claims: IClaim[];
|
|
43
|
-
|
|
44
|
-
hasClaim(type:string, value:string|string[], scope?:string|string[]): boolean;
|
|
45
|
-
getClaim(type:string, value:string, scope?:string): IClaim;
|
|
46
|
-
getClaims(type:string, value:string, scope?:string): IClaim[];
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export interface IService {
|
|
50
|
-
on(type:string, listener:ServiceListener): void;
|
|
51
|
-
process(event:IEvent):Promise<void>;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export interface IEvent {
|
|
55
|
-
id: string;
|
|
56
|
-
correlationId: string;
|
|
57
|
-
params: {};
|
|
58
|
-
name: string;
|
|
59
|
-
method: string;
|
|
60
|
-
request: IRequest;
|
|
61
|
-
response: IResponse;
|
|
62
|
-
payload: any;
|
|
63
|
-
identity: IIdentity;
|
|
64
|
-
|
|
65
|
-
resolve(str:string): string;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export interface IRequest {
|
|
69
|
-
name: string;
|
|
70
|
-
method: string;
|
|
71
|
-
headers: {};
|
|
72
|
-
params: {};
|
|
73
|
-
payload: string;
|
|
74
|
-
query: string;
|
|
75
|
-
path: string;
|
|
76
|
-
pathAndQuery: string;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export interface IResponse {
|
|
80
|
-
body: any;
|
|
81
|
-
headers: {};
|
|
82
|
-
statusCode: number;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export interface ServiceListener{
|
|
86
|
-
(data:string):void;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
///////////////////////////////
|
|
90
|
-
//
|
|
91
|
-
// Implementation
|
|
92
|
-
//
|
|
93
|
-
///////////////////////////////
|
|
94
|
-
|
|
95
|
-
export class Identity implements IIdentity {
|
|
96
|
-
id: string;
|
|
97
|
-
claims: IClaim[];
|
|
98
|
-
issuer: string;
|
|
99
|
-
name: string;
|
|
100
|
-
email: string;
|
|
101
|
-
|
|
102
|
-
constructor(id:string, claims?:IClaim[]);
|
|
103
|
-
|
|
104
|
-
hasClaim(type:string, value:string|string[], scope?:string|string[]): boolean;
|
|
105
|
-
getClaim(type:string, value:string, scope?:string): IClaim;
|
|
106
|
-
getClaims(type:string, value:string, scope?:string): IClaim[];
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export class Request implements IRequest {
|
|
110
|
-
name: string;
|
|
111
|
-
method: string;
|
|
112
|
-
headers: {};
|
|
113
|
-
params: {};
|
|
114
|
-
payload: string;
|
|
115
|
-
query: string;
|
|
116
|
-
path: string;
|
|
117
|
-
pathAndQuery: string;
|
|
118
|
-
|
|
119
|
-
constructor(method:string);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
export class Event implements IEvent {
|
|
123
|
-
id: string;
|
|
124
|
-
correlationId: string;
|
|
125
|
-
params: {};
|
|
126
|
-
name: string;
|
|
127
|
-
method: string;
|
|
128
|
-
request: IRequest;
|
|
129
|
-
response: IResponse;
|
|
130
|
-
payload: any;
|
|
131
|
-
identity: IIdentity;
|
|
132
|
-
|
|
133
|
-
constructor(request:IRequest);
|
|
134
|
-
resolve(str:string): string;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
export class Response implements IResponse {
|
|
138
|
-
body: any;
|
|
139
|
-
headers: {};
|
|
140
|
-
statusCode: number;
|
|
141
|
-
|
|
142
|
-
constructor(body?:any, statusCode?:number, headers?:{});
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
export class ErrorResponse extends Response {
|
|
146
|
-
message:any;
|
|
147
|
-
details:string;
|
|
148
|
-
constructor(message:any, statusCode?:number, details?:string);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export class Config implements IConfig {
|
|
152
|
-
static load(path:string): IConfig;
|
|
153
|
-
static parse(content:string): IConfig;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
export class Service implements IService {
|
|
157
|
-
constructor(config:Config);
|
|
158
|
-
|
|
159
|
-
on(type:string, listener:ServiceListener): void;
|
|
160
|
-
process(event:IEvent):Promise<void>;
|
|
161
|
-
}
|
package/src/configurapi.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
Config: require('./config'),
|
|
3
|
-
Event: require('./event'),
|
|
4
|
-
ErrorResponse: require('./errorResponse'),
|
|
5
|
-
Request: require('./request'),
|
|
6
|
-
Response: require('./response'),
|
|
7
|
-
Result: require('./result'),
|
|
8
|
-
Service: require('./service'),
|
|
9
|
-
Identity: require('./identity'),
|
|
10
|
-
LogLevel: require('./logLevel')
|
|
11
|
-
};
|
package/src/dict.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
module.exports = class Dictionary
|
|
2
|
-
{
|
|
3
|
-
constructor()
|
|
4
|
-
{
|
|
5
|
-
this.items = {};
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
has(k)
|
|
9
|
-
{
|
|
10
|
-
return k in this.items;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
get(k)
|
|
14
|
-
{
|
|
15
|
-
return this.items[k];
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
set(k, v)
|
|
19
|
-
{
|
|
20
|
-
this.items[k] = v;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
clear()
|
|
24
|
-
{
|
|
25
|
-
this.items = {};
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
get length()
|
|
29
|
-
{
|
|
30
|
-
return Object.keys(this.items).length;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
map(f)
|
|
34
|
-
{
|
|
35
|
-
for(let k of Object.keys(this.items))
|
|
36
|
-
{
|
|
37
|
-
f(this.items[k]);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
};
|
package/src/errorResponse.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
const Response = require('./response');
|
|
2
|
-
|
|
3
|
-
module.exports = class ErrorResponse extends Response
|
|
4
|
-
{
|
|
5
|
-
|
|
6
|
-
constructor(message, statusCode = 500, details = '')
|
|
7
|
-
{
|
|
8
|
-
super('', statusCode, {'Content-Type': 'application/json'});
|
|
9
|
-
|
|
10
|
-
this.error = message;
|
|
11
|
-
this.message = message;
|
|
12
|
-
this.details = details;
|
|
13
|
-
|
|
14
|
-
if(message instanceof ErrorResponse)
|
|
15
|
-
{
|
|
16
|
-
let e = message;
|
|
17
|
-
this.message = e.message;
|
|
18
|
-
this.details = e.details;
|
|
19
|
-
this.statusCode = e.statusCode;
|
|
20
|
-
}
|
|
21
|
-
else if(message instanceof Error)
|
|
22
|
-
{
|
|
23
|
-
this.message = message.message;
|
|
24
|
-
this.details = message.stack;
|
|
25
|
-
}
|
|
26
|
-
else
|
|
27
|
-
{
|
|
28
|
-
this.message = message;
|
|
29
|
-
this.details = details;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
this.body = {'statusCode': this.statusCode, 'message': this.message, 'details': this.details};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
static isErrorResponse(obj)
|
|
36
|
-
{
|
|
37
|
-
return typeof obj === 'object' && 'statusCode' in obj && 'error' in obj && 'message' in obj && 'details' in obj && 'body' in obj;
|
|
38
|
-
}
|
|
39
|
-
};
|
package/src/event.js
DELETED
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
let Response = require("./response");
|
|
2
|
-
let uuid = require('uuid/v4');
|
|
3
|
-
|
|
4
|
-
let inflectors = require("inflection");
|
|
5
|
-
|
|
6
|
-
// Source: http://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-with-string-key
|
|
7
|
-
Object.byString = function(o, s) {
|
|
8
|
-
s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
|
|
9
|
-
s = s.replace(/^\./, ''); // strip a leading dot
|
|
10
|
-
var a = s.split('.');
|
|
11
|
-
for (var i = 0, n = a.length; i < n; ++i) {
|
|
12
|
-
var k = a[i];
|
|
13
|
-
if (k in o) {
|
|
14
|
-
o = o[k];
|
|
15
|
-
} else {
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
return o;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
module.exports = class Event
|
|
24
|
-
{
|
|
25
|
-
constructor(request)
|
|
26
|
-
{
|
|
27
|
-
this.id = uuid();
|
|
28
|
-
|
|
29
|
-
if('query' in request && 'correlationid' in request.query)
|
|
30
|
-
{
|
|
31
|
-
this.correlationId = request.query['correlationid'];
|
|
32
|
-
}
|
|
33
|
-
else if('headers' in request && 'correlation-id' in request.headers)
|
|
34
|
-
{
|
|
35
|
-
this.correlationId = request.headers['correlation-id'];
|
|
36
|
-
}
|
|
37
|
-
else
|
|
38
|
-
{
|
|
39
|
-
this.correlationId = this.id;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
this.versionRegExp = new RegExp("^v\\d+(\\.\\d+)*$");
|
|
43
|
-
this.params = {};
|
|
44
|
-
this.name = request.name || "";
|
|
45
|
-
this.request = request;
|
|
46
|
-
this.response = new Response();
|
|
47
|
-
|
|
48
|
-
this.identity = undefined;
|
|
49
|
-
|
|
50
|
-
this.payload = this.request.payload;
|
|
51
|
-
|
|
52
|
-
this.method = request.method;
|
|
53
|
-
|
|
54
|
-
let segments = request.path.split("/").filter(Boolean);
|
|
55
|
-
|
|
56
|
-
if(segments.length === 0) return;
|
|
57
|
-
|
|
58
|
-
//Extract version, if any.
|
|
59
|
-
if(this.versionRegExp.test(segments[0]))
|
|
60
|
-
{
|
|
61
|
-
this.version = segments[0];
|
|
62
|
-
segments = segments.slice(1);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
//Extract resource-resourceId pair.
|
|
66
|
-
for(let i=0, end=segments.length; i<end; i+=2)
|
|
67
|
-
{
|
|
68
|
-
let resource;
|
|
69
|
-
let resourceId = '';
|
|
70
|
-
|
|
71
|
-
if(i < end)
|
|
72
|
-
{
|
|
73
|
-
resource = segments[i];
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if(i + 1 < end)
|
|
77
|
-
{
|
|
78
|
-
resourceId = segments[i+1];
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if(resource.length === 0) break;
|
|
82
|
-
|
|
83
|
-
let singularizedResource = inflectors.singularize(resource);
|
|
84
|
-
|
|
85
|
-
//Change 'get' to 'list'
|
|
86
|
-
if(!resourceId && this.method == 'get')
|
|
87
|
-
{
|
|
88
|
-
this.method = 'list';
|
|
89
|
-
}
|
|
90
|
-
else
|
|
91
|
-
{
|
|
92
|
-
resource = singularizedResource;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
this.params[singularizedResource] = resourceId;
|
|
96
|
-
this.name += `_${resource}`;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
for(let key in request.query)
|
|
100
|
-
{
|
|
101
|
-
this.params[key] = request.query[key];
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
this.name = this.method + (this.version ? `_${this.version}`: "") + this.name;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
resolve(obj)
|
|
108
|
-
{
|
|
109
|
-
if(typeof obj === 'string')
|
|
110
|
-
{
|
|
111
|
-
return this.resolveStr(obj);
|
|
112
|
-
}
|
|
113
|
-
else if(typeof obj === 'object')
|
|
114
|
-
{
|
|
115
|
-
for(let property in obj)
|
|
116
|
-
{
|
|
117
|
-
obj[property] = this.resolve(obj[property]);
|
|
118
|
-
}
|
|
119
|
-
return obj;
|
|
120
|
-
}
|
|
121
|
-
else
|
|
122
|
-
{
|
|
123
|
-
return obj;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
resolveStr(str)
|
|
128
|
-
{
|
|
129
|
-
let regex = /\$\([^\)]*\)/g;
|
|
130
|
-
let matches = str.match(regex);
|
|
131
|
-
|
|
132
|
-
if(!matches)
|
|
133
|
-
{
|
|
134
|
-
return str;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
for(let match of matches)
|
|
138
|
-
{
|
|
139
|
-
let key = match.substr(2, match.length-3);
|
|
140
|
-
let value = undefined;
|
|
141
|
-
|
|
142
|
-
if(key.startsWith('$env.'))
|
|
143
|
-
{
|
|
144
|
-
//handle environment variables
|
|
145
|
-
let variableName = key.substr(5);
|
|
146
|
-
value = process.env[variableName];
|
|
147
|
-
}
|
|
148
|
-
else if(key.startsWith('$event.payload.') && this.payload)
|
|
149
|
-
{
|
|
150
|
-
//handle environment variables
|
|
151
|
-
let path = key.substr(15);
|
|
152
|
-
value = Object.byString(this.payload, path);
|
|
153
|
-
}
|
|
154
|
-
else if(key === '$event.payload' && this.payload)
|
|
155
|
-
{
|
|
156
|
-
value = this.payload;
|
|
157
|
-
}
|
|
158
|
-
else if(this.params[key] !== undefined)
|
|
159
|
-
{
|
|
160
|
-
value = this.params[key];
|
|
161
|
-
}
|
|
162
|
-
else if(key.indexOf('.') !== -1 || key.indexOf('[') !== -1)
|
|
163
|
-
{
|
|
164
|
-
//handle resolving object using string path such as obj.prop.subprop.list[0]
|
|
165
|
-
let index = key.indexOf('.');
|
|
166
|
-
let objSection = key.substr(0, index);
|
|
167
|
-
let propSection = key.substr(index+1);
|
|
168
|
-
|
|
169
|
-
value = this.params[objSection];
|
|
170
|
-
|
|
171
|
-
if(typeof value === 'object')
|
|
172
|
-
{
|
|
173
|
-
value = Object.byString(value, propSection);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
if(value === undefined)
|
|
178
|
-
{
|
|
179
|
-
value = match;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
str = str.replace(match, value);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
return str;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
toString()
|
|
189
|
-
{
|
|
190
|
-
let ids = [];
|
|
191
|
-
|
|
192
|
-
for(let resource in this.params)
|
|
193
|
-
{
|
|
194
|
-
ids.push(this.params[resource]);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return `${this.name}(${ids})`;
|
|
198
|
-
}
|
|
199
|
-
};
|
package/src/identity.js
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
let Dictionary = require('./dict');
|
|
2
|
-
|
|
3
|
-
module.exports = class Identity
|
|
4
|
-
{
|
|
5
|
-
get claims()
|
|
6
|
-
{
|
|
7
|
-
return this._claims;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
set claims(value)
|
|
11
|
-
{
|
|
12
|
-
this._claims = value;
|
|
13
|
-
|
|
14
|
-
this._claimsTable.clear();
|
|
15
|
-
|
|
16
|
-
for(let claim of this._claims)
|
|
17
|
-
{
|
|
18
|
-
let scopes = Array.isArray(claim.scope) ? claim.scope : [claim.scope];
|
|
19
|
-
|
|
20
|
-
for(let scope of scopes)
|
|
21
|
-
{
|
|
22
|
-
this._claimsTable.set(this.getClaimId(claim.type, claim.value, scope), claim);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
getClaimId(type, value, scope)
|
|
28
|
-
{
|
|
29
|
-
return `${scope || ''}::${type || ''}::${value || ''}`;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
constructor(id, claims = [])
|
|
33
|
-
{
|
|
34
|
-
this._claims = [];
|
|
35
|
-
this._claimsTable = new Dictionary();
|
|
36
|
-
|
|
37
|
-
this.id = id;
|
|
38
|
-
this.claims = claims;
|
|
39
|
-
this.issuer = undefined;
|
|
40
|
-
this.name = undefined;
|
|
41
|
-
this.email = undefined;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
hasClaim(type, valueOrValues, scopeOrScopes)
|
|
45
|
-
{
|
|
46
|
-
if(!this.claims) return false;
|
|
47
|
-
|
|
48
|
-
let values = Array.isArray(valueOrValues) ? [...new Set(valueOrValues)] : [valueOrValues];
|
|
49
|
-
|
|
50
|
-
let scopes = Array.isArray(scopeOrScopes) ? [...new Set(scopeOrScopes)] : [scopeOrScopes];
|
|
51
|
-
|
|
52
|
-
for(let value of values)
|
|
53
|
-
{
|
|
54
|
-
for(let scope of scopes)
|
|
55
|
-
{
|
|
56
|
-
if(this._claimsTable.has(this.getClaimId(type, value, scope)))
|
|
57
|
-
{
|
|
58
|
-
return true;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return false;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
getClaim(type, value, scope)
|
|
67
|
-
{
|
|
68
|
-
if(!this._claimsTable.has(this.getClaimId(type, value, scope))) return undefined;
|
|
69
|
-
|
|
70
|
-
return this._claimsTable.get(this.getClaimId(type, value, scope));
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
getClaims(type, value, scope)
|
|
74
|
-
{
|
|
75
|
-
if(!this.claims) return [];
|
|
76
|
-
|
|
77
|
-
let result = [];
|
|
78
|
-
|
|
79
|
-
let matchingTypeValueClaims = this.claims.filter((c) => c.type === type && c.value === value);
|
|
80
|
-
|
|
81
|
-
for(let claim of matchingTypeValueClaims)
|
|
82
|
-
{
|
|
83
|
-
if(claim.scope === scope)
|
|
84
|
-
{
|
|
85
|
-
result.push(claim);
|
|
86
|
-
continue;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
//For arrays
|
|
90
|
-
let scopes = Array.isArray(claim.scope) ? claim.scope : [claim.scope];
|
|
91
|
-
|
|
92
|
-
if(scopes.includes(scope))
|
|
93
|
-
{
|
|
94
|
-
result.push(claim);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return result;
|
|
99
|
-
}
|
|
100
|
-
};
|
package/src/logLevel.js
DELETED
package/src/policy/policy.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
const Result = require('../result');
|
|
2
|
-
const EventEmitter = require('events').EventEmitter;
|
|
3
|
-
const LogLevel = require('../logLevel')
|
|
4
|
-
|
|
5
|
-
module.exports = class Policy extends EventEmitter
|
|
6
|
-
{
|
|
7
|
-
constructor()
|
|
8
|
-
{
|
|
9
|
-
super();
|
|
10
|
-
|
|
11
|
-
this.name = "";
|
|
12
|
-
this.handler = undefined;
|
|
13
|
-
this.parameters = [];
|
|
14
|
-
this.logLevel = LogLevel.Trace
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
async process(event)
|
|
18
|
-
{
|
|
19
|
-
return new Promise(async (resolve, reject) =>{
|
|
20
|
-
|
|
21
|
-
let state = Result.complete;
|
|
22
|
-
|
|
23
|
-
let context = {
|
|
24
|
-
'continue': () => state = Result.Continue,
|
|
25
|
-
'complete': () => state = Result.Completed,
|
|
26
|
-
'catch': (error) => reject(error),
|
|
27
|
-
'emit': (level,message) => this.emit(level, `${event.id} - ${event.correlationId} - ${message}`)
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
let handlerParams = this.parameters instanceof Array ? this.parameters.slice(0) : [];
|
|
31
|
-
handlerParams.unshift(event);
|
|
32
|
-
|
|
33
|
-
try
|
|
34
|
-
{
|
|
35
|
-
await this.handler.apply(context, handlerParams);
|
|
36
|
-
resolve(state);
|
|
37
|
-
}
|
|
38
|
-
catch (error)
|
|
39
|
-
{
|
|
40
|
-
reject(error);
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
};
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const Dictionary = require('../dict');
|
|
3
|
-
const resolve = require('path').resolve;
|
|
4
|
-
const NestedError = require('nested-error-stacks');
|
|
5
|
-
|
|
6
|
-
module.exports = class PolicyHandlerLoader
|
|
7
|
-
{
|
|
8
|
-
constructor()
|
|
9
|
-
{
|
|
10
|
-
this.handlers = new Dictionary();
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
get(handlerName)
|
|
14
|
-
{
|
|
15
|
-
if(this.handlers.has(handlerName))
|
|
16
|
-
{
|
|
17
|
-
return this.handlers.get(handlerName);
|
|
18
|
-
}
|
|
19
|
-
else
|
|
20
|
-
{
|
|
21
|
-
throw new Error(`Handler '${handlerName}' could not be found.`);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
load(moduleOrFileName)
|
|
26
|
-
{
|
|
27
|
-
let exports = this._resolve(moduleOrFileName);
|
|
28
|
-
|
|
29
|
-
if(!exports)
|
|
30
|
-
{
|
|
31
|
-
throw new Error(`Cannot find '${moduleOrFileName}'`);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
this.loadHandler(exports);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
loadCustomHandlers(directory)
|
|
38
|
-
{
|
|
39
|
-
let absoultePath = resolve(process.cwd(), directory);
|
|
40
|
-
|
|
41
|
-
try
|
|
42
|
-
{
|
|
43
|
-
let paths = fs.readdirSync(absoultePath);
|
|
44
|
-
|
|
45
|
-
for(let path of paths)
|
|
46
|
-
{
|
|
47
|
-
let filePath = `${absoultePath}/${path}`;
|
|
48
|
-
let stat = fs.lstatSync(filePath);
|
|
49
|
-
if(stat.isFile() && path.match(/\.[jt]s$/i) !== null)
|
|
50
|
-
{
|
|
51
|
-
this.load(absoultePath + "/" + path.replace(/\.[jt]s$/i, ''));
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
} catch(error)
|
|
55
|
-
{
|
|
56
|
-
throw new NestedError(`Could not load '${absoultePath}'`, error);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
_resolve(path)
|
|
61
|
-
{
|
|
62
|
-
try
|
|
63
|
-
{
|
|
64
|
-
return require(path);
|
|
65
|
-
}
|
|
66
|
-
catch(e)
|
|
67
|
-
{
|
|
68
|
-
throw new NestedError(`Failed to load ${path}`, e);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return undefined;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
loadHandler(obj)
|
|
75
|
-
{
|
|
76
|
-
if(typeof obj === "function")
|
|
77
|
-
{
|
|
78
|
-
this.handlers.set(obj.name, obj);
|
|
79
|
-
}
|
|
80
|
-
else
|
|
81
|
-
{
|
|
82
|
-
for(let key in obj)
|
|
83
|
-
{
|
|
84
|
-
if(this._isHandler(obj, key))
|
|
85
|
-
{
|
|
86
|
-
this.handlers.set(key, obj[key]);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
_isHandler(obj, key)
|
|
93
|
-
{
|
|
94
|
-
return (typeof obj[key] === "function") && key.match(/handler$/i) !== null;
|
|
95
|
-
}
|
|
96
|
-
};
|
package/src/request.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
module.exports = class Request
|
|
2
|
-
{
|
|
3
|
-
constructor(method)
|
|
4
|
-
{
|
|
5
|
-
this.name = undefined;
|
|
6
|
-
this.method = (method || "get").toLowerCase();
|
|
7
|
-
this.headers = {};
|
|
8
|
-
this.params = {};
|
|
9
|
-
this.payload = "";
|
|
10
|
-
this.query = "";
|
|
11
|
-
this.path = "";
|
|
12
|
-
this.pathAndQuery = "";
|
|
13
|
-
}
|
|
14
|
-
};
|
package/src/response.js
DELETED
package/src/result.js
DELETED
package/src/route.js
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
const events = require('events');
|
|
2
|
-
const Result = require('../src/result');
|
|
3
|
-
const LogLevel = require('./logLevel');
|
|
4
|
-
|
|
5
|
-
function toLogLevelNumber(logLevel)
|
|
6
|
-
{
|
|
7
|
-
switch(logLevel)
|
|
8
|
-
{
|
|
9
|
-
case LogLevel.Debug: return 100;
|
|
10
|
-
case LogLevel.Trace: return 75;
|
|
11
|
-
case LogLevel.Warn: return 50;
|
|
12
|
-
case LogLevel.Info: return 25;
|
|
13
|
-
case LogLevel.Error: return 10;
|
|
14
|
-
default: return 1
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
module.exports = class Route extends events.EventEmitter
|
|
19
|
-
{
|
|
20
|
-
constructor()
|
|
21
|
-
{
|
|
22
|
-
super();
|
|
23
|
-
this.name = '';
|
|
24
|
-
this.enabled = true;
|
|
25
|
-
this.policies = [];
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async process(event)
|
|
29
|
-
{
|
|
30
|
-
for(let policy of this.policies)
|
|
31
|
-
{
|
|
32
|
-
let Stopwatch = require("agstopwatch");
|
|
33
|
-
|
|
34
|
-
var watch = new Stopwatch();
|
|
35
|
-
watch.start();
|
|
36
|
-
|
|
37
|
-
try
|
|
38
|
-
{
|
|
39
|
-
let result = await policy.process(event);
|
|
40
|
-
|
|
41
|
-
if(result == Result.Completed)
|
|
42
|
-
{
|
|
43
|
-
break;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
catch(error)
|
|
47
|
-
{
|
|
48
|
-
throw error;
|
|
49
|
-
}
|
|
50
|
-
finally
|
|
51
|
-
{
|
|
52
|
-
watch.stop();
|
|
53
|
-
|
|
54
|
-
if(toLogLevelNumber(policy.logLevel) >= toLogLevelNumber(LogLevel.Trace))
|
|
55
|
-
{
|
|
56
|
-
this.emit(LogLevel.Trace, `${event.id} - ${event.correlationId} - Executed ${policy.name} policy [${watch.elapsed}ms]`);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
};
|
package/src/service.js
DELETED
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
const http = require('http');
|
|
2
|
-
const Event = require('./event');
|
|
3
|
-
const PolicyHandlerLoader = require('./policy/policyHandlerLoader');
|
|
4
|
-
const Config = require('./config');
|
|
5
|
-
const ErrorResponse = require('./errorResponse');
|
|
6
|
-
const events = require('events');
|
|
7
|
-
const Route = require('./route');
|
|
8
|
-
const Stopwatch = require("agstopwatch");
|
|
9
|
-
const fs = require('fs');
|
|
10
|
-
const NestedError = require('nested-error-stacks');
|
|
11
|
-
const LogLevel = require('./logLevel');
|
|
12
|
-
var oneliner = require('one-liner');
|
|
13
|
-
const { Debug } = require('./logLevel');
|
|
14
|
-
|
|
15
|
-
function toLogLevelNumber(logLevel)
|
|
16
|
-
{
|
|
17
|
-
switch(logLevel)
|
|
18
|
-
{
|
|
19
|
-
case LogLevel.Debug: return 100;
|
|
20
|
-
case LogLevel.Trace: return 75;
|
|
21
|
-
case LogLevel.Warn: return 50;
|
|
22
|
-
case LogLevel.Info: return 25;
|
|
23
|
-
case LogLevel.Error: return 10;
|
|
24
|
-
default: return 1
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
module.exports = class Service extends events.EventEmitter
|
|
29
|
-
{
|
|
30
|
-
constructor(config)
|
|
31
|
-
{
|
|
32
|
-
super();
|
|
33
|
-
|
|
34
|
-
this.config = config;
|
|
35
|
-
|
|
36
|
-
let loader = new PolicyHandlerLoader();
|
|
37
|
-
|
|
38
|
-
for(let module of this.config.modules)
|
|
39
|
-
{
|
|
40
|
-
loader.load(module);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
let customHandlerPath = 'handlers';
|
|
44
|
-
|
|
45
|
-
if(fs.existsSync(customHandlerPath))
|
|
46
|
-
{
|
|
47
|
-
loader.loadCustomHandlers("handlers");
|
|
48
|
-
}
|
|
49
|
-
else
|
|
50
|
-
{
|
|
51
|
-
this.emit(LogLevel.Trace, `configurapi - - Warning. Custom handlers directory does not exist.`);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
this.config.events.map((route, key) =>
|
|
56
|
-
{
|
|
57
|
-
let routeLogLevel = toLogLevelNumber(route.logLevel)
|
|
58
|
-
|
|
59
|
-
for(let policy of route.policies)
|
|
60
|
-
{
|
|
61
|
-
policy.handler = loader.get(policy.name);
|
|
62
|
-
|
|
63
|
-
if(policy.logLevel)
|
|
64
|
-
{
|
|
65
|
-
let policyLogLevel = toLogLevelNumber(policy.logLevel)
|
|
66
|
-
|
|
67
|
-
if(policyLogLevel >= toLogLevelNumber(LogLevel.Trace)) policy.on(LogLevel.Trace, (s)=>this.emit(LogLevel.Trace, oneliner(s)));
|
|
68
|
-
if(policyLogLevel >= toLogLevelNumber(LogLevel.Debug)) policy.on(LogLevel.Debug, (s)=>this.emit(LogLevel.Debug, oneliner(s)));
|
|
69
|
-
if(policyLogLevel >= toLogLevelNumber(LogLevel.Error)) policy.on(LogLevel.Error, (s)=>this.emit(LogLevel.Error, oneliner(s)));
|
|
70
|
-
}
|
|
71
|
-
else
|
|
72
|
-
{
|
|
73
|
-
if(routeLogLevel >= toLogLevelNumber(LogLevel.Trace)) policy.on(LogLevel.Trace, (s)=>this.emit(LogLevel.Trace, oneliner(s)));
|
|
74
|
-
if(routeLogLevel >= toLogLevelNumber(LogLevel.Debug)) policy.on(LogLevel.Debug, (s)=>this.emit(LogLevel.Debug, oneliner(s)));
|
|
75
|
-
if(routeLogLevel >= toLogLevelNumber(LogLevel.Error)) policy.on(LogLevel.Error, (s)=>this.emit(LogLevel.Error, oneliner(s)));
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if(routeLogLevel >= toLogLevelNumber(LogLevel.Trace)) route.on(LogLevel.Trace, (s)=>this.emit(LogLevel.Trace, oneliner(s)));
|
|
80
|
-
if(routeLogLevel >= toLogLevelNumber(LogLevel.Debug)) route.on(LogLevel.Debug, (s)=>this.emit(LogLevel.Debug, oneliner(s)));
|
|
81
|
-
if(routeLogLevel >= toLogLevelNumber(LogLevel.Error)) route.on(LogLevel.Error, (s)=>this.emit(LogLevel.Error, oneliner(s)));
|
|
82
|
-
|
|
83
|
-
this.emit(LogLevel.Trace, `configurapi - - Registerd ${route.name} route.`);
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
this._handleEvent('on_start');
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
async process(event)
|
|
90
|
-
{
|
|
91
|
-
let watch = new Stopwatch();
|
|
92
|
-
|
|
93
|
-
try
|
|
94
|
-
{
|
|
95
|
-
watch.start();
|
|
96
|
-
|
|
97
|
-
await this._handleEvent('on_before_request', event);
|
|
98
|
-
|
|
99
|
-
if(await this._handleEvent(event.name, event) || await this._handleEvent(event.method, event))
|
|
100
|
-
{
|
|
101
|
-
//Great
|
|
102
|
-
}
|
|
103
|
-
else if(await this._handleEvent('catchall', event))
|
|
104
|
-
{
|
|
105
|
-
//Great
|
|
106
|
-
}
|
|
107
|
-
else
|
|
108
|
-
{
|
|
109
|
-
throw new ErrorResponse('Not Implemented.', 501, `Route for '${event.name}' event could not be found.'`);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
if(event.response && event.response instanceof ErrorResponse)
|
|
113
|
-
{
|
|
114
|
-
throw event.response;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
await this._handleEvent('on_success', event);
|
|
118
|
-
}
|
|
119
|
-
catch(error)
|
|
120
|
-
{
|
|
121
|
-
await this._handleError(event, error);
|
|
122
|
-
}
|
|
123
|
-
finally
|
|
124
|
-
{
|
|
125
|
-
try
|
|
126
|
-
{
|
|
127
|
-
await this._handleEvent('on_after_request', event);
|
|
128
|
-
}
|
|
129
|
-
catch(error)
|
|
130
|
-
{
|
|
131
|
-
await this._handleError(event, error);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
watch.stop();
|
|
135
|
-
|
|
136
|
-
let route = this.config.events.get(event.name);
|
|
137
|
-
|
|
138
|
-
if(route)
|
|
139
|
-
{
|
|
140
|
-
if(toLogLevelNumber(route.logLevel) >= toLogLevelNumber(LogLevel.Trace))
|
|
141
|
-
{
|
|
142
|
-
this.emit(LogLevel.Trace, `${event.id} - ${event.correlationId} - Handled ${event.name} [${watch.elapsed}ms]`);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
async _handleEvent(eventName, event)
|
|
149
|
-
{
|
|
150
|
-
let result = false;
|
|
151
|
-
|
|
152
|
-
if(this.config.events.has(eventName))
|
|
153
|
-
{
|
|
154
|
-
await this.config.events.get(eventName).process(event);
|
|
155
|
-
|
|
156
|
-
result = true;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
return result;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
async _handleError(event, error)
|
|
163
|
-
{
|
|
164
|
-
if(error instanceof Error)
|
|
165
|
-
{
|
|
166
|
-
this.emit(LogLevel.Error, `${event.id} - ${event.correlationId} - Failed to handle ${event.name}: ${error.message}`);
|
|
167
|
-
|
|
168
|
-
event.response = new ErrorResponse(error, error['statusCode'] || 500);
|
|
169
|
-
}
|
|
170
|
-
else if(error instanceof ErrorResponse || ErrorResponse.isErrorResponse(error))
|
|
171
|
-
{
|
|
172
|
-
this.emit(LogLevel.Error, `${event.id} - ${event.correlationId} - Failed to handle ${event.name}: ${error.error}`);
|
|
173
|
-
|
|
174
|
-
event.response = error;
|
|
175
|
-
}
|
|
176
|
-
else
|
|
177
|
-
{
|
|
178
|
-
this.emit(LogLevel.Error, `${event.id} - ${event.correlationId} - Failed to handle ${event.name}: ${error === undefined ? 'undefined' : error.toString()}`);
|
|
179
|
-
|
|
180
|
-
event.response = new ErrorResponse("Internal Server Error", 500, error.toString());
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
if(this.config.events.has('on_error'))
|
|
184
|
-
{
|
|
185
|
-
try
|
|
186
|
-
{
|
|
187
|
-
this.emit(LogLevel.Error, `${event.id} - ${event.correlationId} - Failed to handle ${event.name}: ${error}`);
|
|
188
|
-
|
|
189
|
-
await this._handleEvent('on_error', event);
|
|
190
|
-
}
|
|
191
|
-
catch(reason)
|
|
192
|
-
{
|
|
193
|
-
this.emit(LogLevel.Error, `${event.id} - ${event.correlationId} - ${reason}`);
|
|
194
|
-
}
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
};
|