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 CHANGED
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "configurapi",
3
- "version": "1.6.10",
3
+ "version": "2.0.0",
4
4
  "description": "A configurable API framework",
5
- "main": "src/configurapi.js",
6
- "types": "src/configurapi.d.ts",
5
+ "main": "dist/configurapi.js",
6
+ "typings": "dist/configurapi.d.ts",
7
7
  "files": [
8
- "src/*"
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
- };
@@ -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
- }
@@ -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
- };
@@ -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
@@ -1,7 +0,0 @@
1
- module.exports = {
2
- Debug : 'debug',
3
- Trace : 'trace',
4
- Info : 'info',
5
- Error : 'error',
6
- None: 'none'
7
- }
@@ -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
@@ -1,9 +0,0 @@
1
- module.exports = class Response
2
- {
3
- constructor(body = "", statusCode = 200, headers = {})
4
- {
5
- this.statusCode = statusCode;
6
- this.body = body;
7
- this.headers = headers;
8
- }
9
- };
package/src/result.js DELETED
@@ -1,4 +0,0 @@
1
- module.exports = {
2
- Continue: 1,
3
- Completed: 2
4
- };
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
- };