navis.js 3.0.2 → 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/README.md +66 -1
- package/examples/lambda-optimized.js +103 -0
- package/examples/lambda.js +30 -29
- package/examples/v4-features-demo.js +171 -0
- package/package.json +1 -1
- package/src/auth/authenticator.js +223 -0
- package/src/core/advanced-router.js +186 -0
- package/src/core/app.js +255 -176
- package/src/core/lambda-handler.js +130 -0
- package/src/errors/error-handler.js +157 -0
- package/src/index.js +62 -0
- package/src/middleware/cold-start-tracker.js +56 -0
- package/src/middleware/rate-limiter.js +159 -0
- package/src/utils/lazy-init.js +100 -0
- package/src/utils/service-client-pool.js +131 -0
- package/src/validation/validator.js +301 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Advanced Router with Parameters and Path Matching
|
|
3
|
+
* v4: Support for route parameters, wildcards, and path matching
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
class AdvancedRouter {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.routes = {
|
|
9
|
+
GET: [],
|
|
10
|
+
POST: [],
|
|
11
|
+
PUT: [],
|
|
12
|
+
DELETE: [],
|
|
13
|
+
PATCH: [],
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Register a route handler
|
|
19
|
+
* @param {string} method - HTTP method
|
|
20
|
+
* @param {string} path - Route path (supports :param and * wildcards)
|
|
21
|
+
* @param {Function} handler - Route handler function
|
|
22
|
+
*/
|
|
23
|
+
register(method, path, handler) {
|
|
24
|
+
const normalizedMethod = method.toUpperCase();
|
|
25
|
+
if (!this.routes[normalizedMethod]) {
|
|
26
|
+
throw new Error(`Unsupported HTTP method: ${method}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Parse route pattern
|
|
30
|
+
const pattern = this._parsePattern(path);
|
|
31
|
+
|
|
32
|
+
this.routes[normalizedMethod].push({
|
|
33
|
+
pattern: path,
|
|
34
|
+
regex: pattern.regex,
|
|
35
|
+
params: pattern.params,
|
|
36
|
+
handler,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Sort routes by specificity (more specific first)
|
|
40
|
+
this.routes[normalizedMethod].sort((a, b) => {
|
|
41
|
+
const aSpecificity = this._calculateSpecificity(a.pattern);
|
|
42
|
+
const bSpecificity = this._calculateSpecificity(b.pattern);
|
|
43
|
+
return bSpecificity - aSpecificity;
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Find route handler for a method and path
|
|
49
|
+
* @param {string} method - HTTP method
|
|
50
|
+
* @param {string} path - Request path
|
|
51
|
+
* @returns {Object|null} - { handler, params } or null if not found
|
|
52
|
+
*/
|
|
53
|
+
find(method, path) {
|
|
54
|
+
const normalizedMethod = method.toUpperCase();
|
|
55
|
+
const methodRoutes = this.routes[normalizedMethod] || [];
|
|
56
|
+
|
|
57
|
+
for (const route of methodRoutes) {
|
|
58
|
+
const match = path.match(route.regex);
|
|
59
|
+
if (match) {
|
|
60
|
+
// Extract parameters
|
|
61
|
+
const params = {};
|
|
62
|
+
route.params.forEach((param, index) => {
|
|
63
|
+
params[param] = match[index + 1];
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
handler: route.handler,
|
|
68
|
+
params,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Parse route pattern into regex and parameter names
|
|
78
|
+
* @private
|
|
79
|
+
*/
|
|
80
|
+
_parsePattern(pattern) {
|
|
81
|
+
const params = [];
|
|
82
|
+
const parts = pattern.split('/').filter(p => p !== ''); // Remove empty parts
|
|
83
|
+
const regexParts = [];
|
|
84
|
+
|
|
85
|
+
for (const part of parts) {
|
|
86
|
+
if (part.startsWith(':')) {
|
|
87
|
+
// Parameter
|
|
88
|
+
const paramName = part.substring(1);
|
|
89
|
+
params.push(paramName);
|
|
90
|
+
regexParts.push('([^/]+)');
|
|
91
|
+
} else if (part === '*') {
|
|
92
|
+
// Wildcard
|
|
93
|
+
regexParts.push('.*');
|
|
94
|
+
} else {
|
|
95
|
+
// Literal - escape regex special chars
|
|
96
|
+
regexParts.push(part.replace(/[.+?^${}()|[\]\\]/g, '\\$&'));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Build regex pattern
|
|
101
|
+
const regexPattern = '^/' + regexParts.join('/') + '/?$';
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
regex: new RegExp(regexPattern),
|
|
105
|
+
params,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Calculate route specificity (higher = more specific)
|
|
111
|
+
* @private
|
|
112
|
+
*/
|
|
113
|
+
_calculateSpecificity(pattern) {
|
|
114
|
+
let specificity = 0;
|
|
115
|
+
|
|
116
|
+
// Count static segments
|
|
117
|
+
const staticSegments = pattern.split('/').filter(seg =>
|
|
118
|
+
seg && !seg.startsWith(':') && seg !== '*'
|
|
119
|
+
);
|
|
120
|
+
specificity += staticSegments.length * 10;
|
|
121
|
+
|
|
122
|
+
// Count parameters (less specific)
|
|
123
|
+
const params = (pattern.match(/:[^/]+/g) || []).length;
|
|
124
|
+
specificity += params * 5;
|
|
125
|
+
|
|
126
|
+
// Wildcards are least specific
|
|
127
|
+
if (pattern.includes('*')) {
|
|
128
|
+
specificity -= 10;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return specificity;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Get all registered routes
|
|
136
|
+
* @returns {Object} - All routes grouped by method
|
|
137
|
+
*/
|
|
138
|
+
getAllRoutes() {
|
|
139
|
+
const allRoutes = {};
|
|
140
|
+
for (const method in this.routes) {
|
|
141
|
+
allRoutes[method] = this.routes[method].map(route => ({
|
|
142
|
+
pattern: route.pattern,
|
|
143
|
+
params: route.params,
|
|
144
|
+
}));
|
|
145
|
+
}
|
|
146
|
+
return allRoutes;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Register GET route
|
|
151
|
+
*/
|
|
152
|
+
get(path, handler) {
|
|
153
|
+
this.register('GET', path, handler);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Register POST route
|
|
158
|
+
*/
|
|
159
|
+
post(path, handler) {
|
|
160
|
+
this.register('POST', path, handler);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Register PUT route
|
|
165
|
+
*/
|
|
166
|
+
put(path, handler) {
|
|
167
|
+
this.register('PUT', path, handler);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Register DELETE route
|
|
172
|
+
*/
|
|
173
|
+
delete(path, handler) {
|
|
174
|
+
this.register('DELETE', path, handler);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Register PATCH route
|
|
179
|
+
*/
|
|
180
|
+
patch(path, handler) {
|
|
181
|
+
this.register('PATCH', path, handler);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
module.exports = AdvancedRouter;
|
|
186
|
+
|
package/src/core/app.js
CHANGED
|
@@ -1,177 +1,256 @@
|
|
|
1
|
-
const http = require('http');
|
|
2
|
-
const Router = require('./router');
|
|
3
|
-
const
|
|
4
|
-
const {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
this.
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
1
|
+
const http = require('http');
|
|
2
|
+
const Router = require('./router');
|
|
3
|
+
const AdvancedRouter = require('./advanced-router');
|
|
4
|
+
const { executeMiddleware } = require('./middleware');
|
|
5
|
+
const { error: errorResponse } = require('../utils/response');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* NavisApp - Main application class
|
|
9
|
+
*/
|
|
10
|
+
class NavisApp {
|
|
11
|
+
constructor(options = {}) {
|
|
12
|
+
// Use advanced router if enabled (v4)
|
|
13
|
+
this.useAdvancedRouter = options.useAdvancedRouter !== false; // Default true in v4
|
|
14
|
+
this.router = this.useAdvancedRouter ? new AdvancedRouter() : new Router();
|
|
15
|
+
this.middlewares = [];
|
|
16
|
+
this.server = null;
|
|
17
|
+
this.errorHandler = null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Register middleware
|
|
22
|
+
* @param {Function} fn - Middleware function (req, res, next)
|
|
23
|
+
*/
|
|
24
|
+
use(fn) {
|
|
25
|
+
this.middlewares.push(fn);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Register GET route
|
|
30
|
+
*/
|
|
31
|
+
get(path, handler) {
|
|
32
|
+
this.router.get(path, handler);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Register POST route
|
|
37
|
+
*/
|
|
38
|
+
post(path, handler) {
|
|
39
|
+
this.router.post(path, handler);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Register PUT route
|
|
44
|
+
*/
|
|
45
|
+
put(path, handler) {
|
|
46
|
+
this.router.put(path, handler);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Register DELETE route
|
|
51
|
+
*/
|
|
52
|
+
delete(path, handler) {
|
|
53
|
+
this.router.delete(path, handler);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Register PATCH route (v4)
|
|
58
|
+
*/
|
|
59
|
+
patch(path, handler) {
|
|
60
|
+
if (this.router.patch) {
|
|
61
|
+
this.router.patch(path, handler);
|
|
62
|
+
} else {
|
|
63
|
+
throw new Error('PATCH method requires advanced router');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Set error handler (v4)
|
|
69
|
+
* @param {Function} handler - Error handler function
|
|
70
|
+
*/
|
|
71
|
+
setErrorHandler(handler) {
|
|
72
|
+
this.errorHandler = handler;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Handle HTTP request (Node.js)
|
|
77
|
+
* @param {Object} req - Node.js HTTP request
|
|
78
|
+
* @param {Object} res - Node.js HTTP response
|
|
79
|
+
*/
|
|
80
|
+
async handleRequest(req, res) {
|
|
81
|
+
const method = req.method;
|
|
82
|
+
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
83
|
+
const path = url.pathname;
|
|
84
|
+
|
|
85
|
+
// Parse query string
|
|
86
|
+
req.query = {};
|
|
87
|
+
url.searchParams.forEach((value, key) => {
|
|
88
|
+
req.query[key] = value;
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Find route handler
|
|
92
|
+
let routeResult;
|
|
93
|
+
if (this.useAdvancedRouter) {
|
|
94
|
+
routeResult = this.router.find(method, path);
|
|
95
|
+
if (routeResult) {
|
|
96
|
+
req.params = routeResult.params || {};
|
|
97
|
+
req.handler = routeResult.handler;
|
|
98
|
+
}
|
|
99
|
+
} else {
|
|
100
|
+
const handler = this.router.find(method, path);
|
|
101
|
+
if (handler) {
|
|
102
|
+
routeResult = { handler };
|
|
103
|
+
req.params = {};
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!routeResult) {
|
|
108
|
+
if (this.errorHandler) {
|
|
109
|
+
const notFoundError = new Error('Not Found');
|
|
110
|
+
notFoundError.statusCode = 404;
|
|
111
|
+
await this.errorHandler(notFoundError, req, res, () => {});
|
|
112
|
+
} else {
|
|
113
|
+
errorResponse(res, 'Not Found', 404);
|
|
114
|
+
}
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Execute middleware chain, then route handler
|
|
119
|
+
try {
|
|
120
|
+
await executeMiddleware(
|
|
121
|
+
this.middlewares,
|
|
122
|
+
req,
|
|
123
|
+
res,
|
|
124
|
+
routeResult.handler,
|
|
125
|
+
false
|
|
126
|
+
);
|
|
127
|
+
} catch (err) {
|
|
128
|
+
if (this.errorHandler) {
|
|
129
|
+
await this.errorHandler(err, req, res, () => {});
|
|
130
|
+
} else {
|
|
131
|
+
errorResponse(res, err.message || 'Internal Server Error', err.statusCode || 500);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Handle AWS Lambda event
|
|
138
|
+
* @param {Object} event - Lambda event
|
|
139
|
+
* @returns {Object} - Lambda response
|
|
140
|
+
*/
|
|
141
|
+
async handleLambda(event) {
|
|
142
|
+
const method = event.httpMethod || event.requestContext?.http?.method || 'GET';
|
|
143
|
+
const path = event.path || event.rawPath || '/';
|
|
144
|
+
|
|
145
|
+
// Find route handler
|
|
146
|
+
let routeResult;
|
|
147
|
+
if (this.useAdvancedRouter) {
|
|
148
|
+
routeResult = this.router.find(method, path);
|
|
149
|
+
} else {
|
|
150
|
+
const handler = this.router.find(method, path);
|
|
151
|
+
if (handler) {
|
|
152
|
+
routeResult = { handler, params: {} };
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (!routeResult) {
|
|
157
|
+
return {
|
|
158
|
+
statusCode: 404,
|
|
159
|
+
headers: {
|
|
160
|
+
'Content-Type': 'application/json',
|
|
161
|
+
},
|
|
162
|
+
body: JSON.stringify({ error: 'Not Found' }),
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Create Lambda-compatible req/res objects
|
|
167
|
+
const req = {
|
|
168
|
+
method,
|
|
169
|
+
path,
|
|
170
|
+
headers: event.headers || {},
|
|
171
|
+
body: event.body ? (typeof event.body === 'string' ? JSON.parse(event.body) : event.body) : {},
|
|
172
|
+
query: event.queryStringParameters || {},
|
|
173
|
+
params: routeResult.params || {},
|
|
174
|
+
// Store original event for advanced use cases
|
|
175
|
+
event,
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const res = {
|
|
179
|
+
statusCode: 200,
|
|
180
|
+
headers: {},
|
|
181
|
+
body: null,
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// Execute middleware chain, then route handler
|
|
185
|
+
try {
|
|
186
|
+
const result = await executeMiddleware(
|
|
187
|
+
this.middlewares,
|
|
188
|
+
req,
|
|
189
|
+
res,
|
|
190
|
+
routeResult.handler,
|
|
191
|
+
true
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
// If handler returned a Lambda response directly, use it
|
|
195
|
+
if (result && result.statusCode) {
|
|
196
|
+
return result;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Otherwise, construct response from res object
|
|
200
|
+
return {
|
|
201
|
+
statusCode: res.statusCode || 200,
|
|
202
|
+
headers: {
|
|
203
|
+
'Content-Type': 'application/json',
|
|
204
|
+
...res.headers,
|
|
205
|
+
},
|
|
206
|
+
body: res.body ? JSON.stringify(res.body) : JSON.stringify(result || {}),
|
|
207
|
+
};
|
|
208
|
+
} catch (err) {
|
|
209
|
+
// Use error handler if set
|
|
210
|
+
if (this.errorHandler) {
|
|
211
|
+
// Create a mock res object for error handler
|
|
212
|
+
const errorRes = {
|
|
213
|
+
statusCode: err.statusCode || 500,
|
|
214
|
+
headers: { 'Content-Type': 'application/json' },
|
|
215
|
+
body: null,
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
await this.errorHandler(err, req, errorRes, () => {});
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
statusCode: errorRes.statusCode,
|
|
222
|
+
headers: errorRes.headers,
|
|
223
|
+
body: typeof errorRes.body === 'string' ? errorRes.body : JSON.stringify(errorRes.body || { error: err.message }),
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return {
|
|
228
|
+
statusCode: err.statusCode || 500,
|
|
229
|
+
headers: {
|
|
230
|
+
'Content-Type': 'application/json',
|
|
231
|
+
},
|
|
232
|
+
body: JSON.stringify({ error: err.message || 'Internal Server Error' }),
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Start HTTP server (Node.js)
|
|
239
|
+
* @param {number} port - Port number
|
|
240
|
+
* @param {Function} callback - Optional callback
|
|
241
|
+
*/
|
|
242
|
+
listen(port = 3000, callback) {
|
|
243
|
+
this.server = http.createServer((req, res) => {
|
|
244
|
+
this.handleRequest(req, res);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
this.server.listen(port, () => {
|
|
248
|
+
if (callback) callback();
|
|
249
|
+
console.log(`Navis.js server listening on port ${port}`);
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
return this.server;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
177
256
|
module.exports = NavisApp;
|