mastercontroller 1.2.13 → 1.3.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/.claude/settings.local.json +12 -0
- package/MasterAction.js +7 -7
- package/MasterControl.js +192 -122
- package/MasterCors.js +29 -0
- package/MasterHtml.js +5 -5
- package/MasterPipeline.js +344 -0
- package/MasterRouter.js +59 -29
- package/MasterSession.js +19 -0
- package/MasterTemplate.js +3 -3
- package/MasterTimeout.js +332 -0
- package/README.md +1496 -36
- package/docs/timeout-and-error-handling.md +712 -0
- package/{MasterError.js → error/MasterError.js} +2 -2
- package/{MasterErrorLogger.js → error/MasterErrorLogger.js} +1 -1
- package/{MasterErrorMiddleware.js → error/MasterErrorMiddleware.js} +2 -2
- package/error/MasterErrorRenderer.js +529 -0
- package/{ssr → error}/SSRErrorHandler.js +2 -2
- package/{MasterCache.js → monitoring/MasterCache.js} +2 -2
- package/{MasterMemoryMonitor.js → monitoring/MasterMemoryMonitor.js} +2 -2
- package/{MasterProfiler.js → monitoring/MasterProfiler.js} +2 -2
- package/{ssr → monitoring}/PerformanceMonitor.js +2 -2
- package/package.json +5 -5
- package/{EventHandlerValidator.js → security/EventHandlerValidator.js} +3 -3
- package/{MasterSanitizer.js → security/MasterSanitizer.js} +2 -2
- package/{MasterValidator.js → security/MasterValidator.js} +2 -2
- package/{SecurityMiddleware.js → security/SecurityMiddleware.js} +75 -3
- package/{SessionSecurity.js → security/SessionSecurity.js} +2 -2
- package/ssr/hydration-client.js +3 -3
- package/ssr/runtime-ssr.cjs +9 -9
- package/MasterBenchmark.js +0 -89
- package/MasterBuildOptimizer.js +0 -376
- package/MasterBundleAnalyzer.js +0 -108
- package/ssr/HTMLUtils.js +0 -15
- /package/{ssr → error}/ErrorBoundary.js +0 -0
- /package/{ssr → error}/HydrationMismatch.js +0 -0
- /package/{MasterBackendErrorHandler.js → error/MasterBackendErrorHandler.js} +0 -0
- /package/{MasterErrorHandler.js → error/MasterErrorHandler.js} +0 -0
- /package/{CSPConfig.js → security/CSPConfig.js} +0 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
// MasterPipeline - Middleware Pipeline System
|
|
2
|
+
// version 1.0
|
|
3
|
+
|
|
4
|
+
var master = require('./MasterControl');
|
|
5
|
+
const { logger } = require('./error/MasterErrorLogger');
|
|
6
|
+
|
|
7
|
+
class MasterPipeline {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.middleware = [];
|
|
10
|
+
this.errorHandlers = [];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Use: Add middleware that processes request/response
|
|
15
|
+
*
|
|
16
|
+
* Middleware signature: async (ctx, next) => { await next(); }
|
|
17
|
+
* - ctx: Request context { request, response, params, state, ... }
|
|
18
|
+
* - next: Function to call next middleware in chain
|
|
19
|
+
*
|
|
20
|
+
* Example:
|
|
21
|
+
* master.use(async (ctx, next) => {
|
|
22
|
+
* console.log('Before');
|
|
23
|
+
* await next();
|
|
24
|
+
* console.log('After');
|
|
25
|
+
* });
|
|
26
|
+
*
|
|
27
|
+
* @param {Function} middleware - Middleware function
|
|
28
|
+
* @returns {MasterPipeline} - For chaining
|
|
29
|
+
*/
|
|
30
|
+
use(middleware) {
|
|
31
|
+
if (typeof middleware !== 'function') {
|
|
32
|
+
throw new Error('Middleware must be a function');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
this.middleware.push({
|
|
36
|
+
type: 'use',
|
|
37
|
+
handler: middleware,
|
|
38
|
+
path: null
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
return this; // Chainable
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Run: Add terminal middleware that ends the pipeline
|
|
46
|
+
*
|
|
47
|
+
* Terminal middleware signature: async (ctx) => { /* send response */ }
|
|
48
|
+
* - Does NOT call next()
|
|
49
|
+
* - Must send response
|
|
50
|
+
*
|
|
51
|
+
* Example:
|
|
52
|
+
* master.run(async (ctx) => {
|
|
53
|
+
* ctx.response.end('Hello World');
|
|
54
|
+
* });
|
|
55
|
+
*
|
|
56
|
+
* @param {Function} middleware - Terminal middleware function
|
|
57
|
+
* @returns {MasterPipeline} - For chaining
|
|
58
|
+
*/
|
|
59
|
+
run(middleware) {
|
|
60
|
+
if (typeof middleware !== 'function') {
|
|
61
|
+
throw new Error('Terminal middleware must be a function');
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
this.middleware.push({
|
|
65
|
+
type: 'run',
|
|
66
|
+
handler: middleware,
|
|
67
|
+
path: null
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
return this; // Chainable
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Map: Conditionally execute middleware based on path
|
|
75
|
+
*
|
|
76
|
+
* Map signature: (path, configure)
|
|
77
|
+
* - path: String or RegExp to match request path
|
|
78
|
+
* - configure: Function that receives a branch pipeline
|
|
79
|
+
*
|
|
80
|
+
* Example:
|
|
81
|
+
* master.map('/api/*', (api) => {
|
|
82
|
+
* api.use(authMiddleware);
|
|
83
|
+
* api.use(jsonMiddleware);
|
|
84
|
+
* });
|
|
85
|
+
*
|
|
86
|
+
* @param {String|RegExp} path - Path pattern to match
|
|
87
|
+
* @param {Function} configure - Function to configure branch pipeline
|
|
88
|
+
* @returns {MasterPipeline} - For chaining
|
|
89
|
+
*/
|
|
90
|
+
map(path, configure) {
|
|
91
|
+
if (typeof configure !== 'function') {
|
|
92
|
+
throw new Error('Map configuration must be a function');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Create sub-pipeline for this branch
|
|
96
|
+
const branch = new MasterPipeline();
|
|
97
|
+
configure(branch);
|
|
98
|
+
|
|
99
|
+
// Wrap branch in conditional middleware
|
|
100
|
+
const conditionalMiddleware = async (ctx, next) => {
|
|
101
|
+
const requestPath = ctx.pathName || ctx.request.url;
|
|
102
|
+
|
|
103
|
+
if (this._pathMatches(requestPath, path)) {
|
|
104
|
+
// Execute branch pipeline
|
|
105
|
+
await branch.execute(ctx);
|
|
106
|
+
// After branch completes, continue main pipeline
|
|
107
|
+
await next();
|
|
108
|
+
} else {
|
|
109
|
+
// Skip branch, continue main pipeline
|
|
110
|
+
await next();
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
this.middleware.push({
|
|
115
|
+
type: 'map',
|
|
116
|
+
handler: conditionalMiddleware,
|
|
117
|
+
path: path
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
return this; // Chainable
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* UseError: Add error handling middleware
|
|
125
|
+
*
|
|
126
|
+
* Error middleware signature: async (error, ctx, next) => { }
|
|
127
|
+
* - error: The caught error
|
|
128
|
+
* - ctx: Request context
|
|
129
|
+
* - next: Pass to next error handler or rethrow
|
|
130
|
+
*
|
|
131
|
+
* Example:
|
|
132
|
+
* master.useError(async (err, ctx, next) => {
|
|
133
|
+
* if (err.statusCode === 404) {
|
|
134
|
+
* ctx.response.statusCode = 404;
|
|
135
|
+
* ctx.response.end('Not Found');
|
|
136
|
+
* } else {
|
|
137
|
+
* await next(); // Pass to next error handler
|
|
138
|
+
* }
|
|
139
|
+
* });
|
|
140
|
+
*
|
|
141
|
+
* @param {Function} handler - Error handler function
|
|
142
|
+
* @returns {MasterPipeline} - For chaining
|
|
143
|
+
*/
|
|
144
|
+
useError(handler) {
|
|
145
|
+
if (typeof handler !== 'function') {
|
|
146
|
+
throw new Error('Error handler must be a function');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
this.errorHandlers.push(handler);
|
|
150
|
+
return this; // Chainable
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Execute: Run the middleware pipeline for a request
|
|
155
|
+
*
|
|
156
|
+
* Called internally by the framework for each request
|
|
157
|
+
*
|
|
158
|
+
* @param {Object} context - Request context
|
|
159
|
+
*/
|
|
160
|
+
async execute(context) {
|
|
161
|
+
let index = 0;
|
|
162
|
+
|
|
163
|
+
// Create the next function for middleware chain
|
|
164
|
+
const next = async () => {
|
|
165
|
+
// If we've run all middleware, we're done
|
|
166
|
+
if (index >= this.middleware.length) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const current = this.middleware[index++];
|
|
171
|
+
|
|
172
|
+
try {
|
|
173
|
+
if (current.type === 'run') {
|
|
174
|
+
// Terminal middleware - don't pass next
|
|
175
|
+
await current.handler(context);
|
|
176
|
+
} else {
|
|
177
|
+
// Regular middleware - pass next
|
|
178
|
+
await current.handler(context, next);
|
|
179
|
+
}
|
|
180
|
+
} catch (error) {
|
|
181
|
+
// Error occurred, run error handlers
|
|
182
|
+
await this._handleError(error, context);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
// Start the pipeline
|
|
187
|
+
await next();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Handle errors through error handler chain
|
|
192
|
+
*
|
|
193
|
+
* @param {Error} error - The error that occurred
|
|
194
|
+
* @param {Object} context - Request context
|
|
195
|
+
*/
|
|
196
|
+
async _handleError(error, context) {
|
|
197
|
+
let errorIndex = 0;
|
|
198
|
+
|
|
199
|
+
const nextError = async () => {
|
|
200
|
+
if (errorIndex >= this.errorHandlers.length) {
|
|
201
|
+
// No more error handlers, log and send generic error
|
|
202
|
+
logger.error({
|
|
203
|
+
code: 'MC_ERR_UNHANDLED',
|
|
204
|
+
message: 'Unhandled error in middleware pipeline',
|
|
205
|
+
error: error.message,
|
|
206
|
+
stack: error.stack
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
if (!context.response.headersSent) {
|
|
210
|
+
context.response.statusCode = 500;
|
|
211
|
+
context.response.end('Internal Server Error');
|
|
212
|
+
}
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const handler = this.errorHandlers[errorIndex++];
|
|
217
|
+
|
|
218
|
+
try {
|
|
219
|
+
await handler(error, context, nextError);
|
|
220
|
+
} catch (handlerError) {
|
|
221
|
+
// Error in error handler
|
|
222
|
+
logger.error({
|
|
223
|
+
code: 'MC_ERR_ERROR_HANDLER_FAILED',
|
|
224
|
+
message: 'Error handler threw an error',
|
|
225
|
+
error: handlerError.message
|
|
226
|
+
});
|
|
227
|
+
await nextError();
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
await nextError();
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Check if request path matches the map path pattern
|
|
236
|
+
*
|
|
237
|
+
* @param {String} requestPath - The request path
|
|
238
|
+
* @param {String|RegExp} pattern - The pattern to match
|
|
239
|
+
* @returns {Boolean} - True if matches
|
|
240
|
+
*/
|
|
241
|
+
_pathMatches(requestPath, pattern) {
|
|
242
|
+
// Normalize paths (ensure leading slash)
|
|
243
|
+
requestPath = '/' + requestPath.replace(/^\/|\/$/g, '');
|
|
244
|
+
|
|
245
|
+
if (typeof pattern === 'string') {
|
|
246
|
+
pattern = '/' + pattern.replace(/^\/|\/$/g, '');
|
|
247
|
+
|
|
248
|
+
// Wildcard support: /api/* matches /api/users, /api/posts, etc.
|
|
249
|
+
if (pattern.endsWith('/*')) {
|
|
250
|
+
const prefix = pattern.slice(0, -2);
|
|
251
|
+
return requestPath === prefix || requestPath.startsWith(prefix + '/');
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Exact or prefix match
|
|
255
|
+
return requestPath === pattern || requestPath.startsWith(pattern + '/');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (pattern instanceof RegExp) {
|
|
259
|
+
return pattern.test(requestPath);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Discover and load middleware from folders
|
|
267
|
+
*
|
|
268
|
+
* @param {String|Object} options - Folder path or options object
|
|
269
|
+
*/
|
|
270
|
+
discoverMiddleware(options) {
|
|
271
|
+
const fs = require('fs');
|
|
272
|
+
const path = require('path');
|
|
273
|
+
|
|
274
|
+
const folders = typeof options === 'string'
|
|
275
|
+
? [options]
|
|
276
|
+
: (options.folders || ['middleware']);
|
|
277
|
+
|
|
278
|
+
folders.forEach(folder => {
|
|
279
|
+
const dir = path.join(master.root, folder);
|
|
280
|
+
if (!fs.existsSync(dir)) {
|
|
281
|
+
console.warn(`[Middleware] Folder not found: ${folder}`);
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const files = fs.readdirSync(dir)
|
|
286
|
+
.filter(file => file.endsWith('.js'))
|
|
287
|
+
.sort(); // Alphabetical order
|
|
288
|
+
|
|
289
|
+
files.forEach(file => {
|
|
290
|
+
try {
|
|
291
|
+
const middlewarePath = path.join(dir, file);
|
|
292
|
+
const middleware = require(middlewarePath);
|
|
293
|
+
|
|
294
|
+
// Support two patterns:
|
|
295
|
+
// Pattern 1: module.exports = async (ctx, next) => {}
|
|
296
|
+
if (typeof middleware === 'function') {
|
|
297
|
+
this.use(middleware);
|
|
298
|
+
}
|
|
299
|
+
// Pattern 2: module.exports = { register: (master) => {} }
|
|
300
|
+
else if (middleware.register && typeof middleware.register === 'function') {
|
|
301
|
+
middleware.register(master);
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
console.warn(`[Middleware] Invalid export in ${folder}/${file}`);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
console.log(`[Middleware] Loaded: ${folder}/${file}`);
|
|
309
|
+
} catch (err) {
|
|
310
|
+
console.error(`[Middleware] Failed to load ${folder}/${file}:`, err.message);
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Clear all middleware (useful for testing)
|
|
318
|
+
*/
|
|
319
|
+
clear() {
|
|
320
|
+
this.middleware = [];
|
|
321
|
+
this.errorHandlers = [];
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Inspect pipeline (for debugging)
|
|
326
|
+
*
|
|
327
|
+
* @returns {Object} - Pipeline information
|
|
328
|
+
*/
|
|
329
|
+
inspect() {
|
|
330
|
+
return {
|
|
331
|
+
middlewareCount: this.middleware.length,
|
|
332
|
+
errorHandlerCount: this.errorHandlers.length,
|
|
333
|
+
middleware: this.middleware.map((m, i) => ({
|
|
334
|
+
index: i,
|
|
335
|
+
type: m.type,
|
|
336
|
+
path: m.path,
|
|
337
|
+
name: m.handler.name || 'anonymous'
|
|
338
|
+
}))
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Register with master
|
|
344
|
+
master.extend("pipeline", MasterPipeline);
|
package/MasterRouter.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// version 0.0.
|
|
1
|
+
// version 0.0.250
|
|
2
2
|
|
|
3
3
|
var master = require('./MasterControl');
|
|
4
4
|
var toolClass = require('./MasterTools');
|
|
@@ -8,13 +8,13 @@ var currentRoute = {};
|
|
|
8
8
|
var tools = new toolClass();
|
|
9
9
|
|
|
10
10
|
// Enhanced error handling
|
|
11
|
-
const { handleRoutingError, handleControllerError, sendErrorResponse } = require('./MasterBackendErrorHandler');
|
|
12
|
-
const { logger } = require('./MasterErrorLogger');
|
|
13
|
-
const { performanceTracker, errorHandlerMiddleware } = require('./MasterErrorMiddleware');
|
|
11
|
+
const { handleRoutingError, handleControllerError, sendErrorResponse } = require('./error/MasterBackendErrorHandler');
|
|
12
|
+
const { logger } = require('./error/MasterErrorLogger');
|
|
13
|
+
const { performanceTracker, errorHandlerMiddleware } = require('./error/MasterErrorMiddleware');
|
|
14
14
|
|
|
15
15
|
// Security - Input validation and sanitization
|
|
16
|
-
const { validator, detectPathTraversal, detectSQLInjection, detectCommandInjection } = require('./MasterValidator');
|
|
17
|
-
const { escapeHTML } = require('./MasterSanitizer');
|
|
16
|
+
const { validator, detectPathTraversal, detectSQLInjection, detectCommandInjection } = require('./security/MasterValidator');
|
|
17
|
+
const { escapeHTML } = require('./security/MasterSanitizer');
|
|
18
18
|
|
|
19
19
|
const isDevelopment = process.env.NODE_ENV !== 'production' && process.env.master === 'development';
|
|
20
20
|
|
|
@@ -135,10 +135,16 @@ const isDevelopment = process.env.NODE_ENV !== 'production' && process.env.maste
|
|
|
135
135
|
try {
|
|
136
136
|
requestObject.toController = routeList[item].toController;
|
|
137
137
|
requestObject.toAction = routeList[item].toAction;
|
|
138
|
-
|
|
138
|
+
|
|
139
|
+
// FIX: Create a clean copy of params for each route test to prevent parameter pollution
|
|
140
|
+
// This prevents parameters from non-matching routes from accumulating in requestObject.params
|
|
141
|
+
var testParams = Object.assign({}, requestObject.params);
|
|
142
|
+
var pathObj = normalizePaths(requestObject.pathName, routeList[item].path, testParams);
|
|
139
143
|
|
|
140
144
|
// if we find the route that matches the request
|
|
141
145
|
if(pathObj.requestPath === pathObj.routePath && routeList[item].type === requestObject.type){
|
|
146
|
+
// Only commit the extracted params if this route actually matches
|
|
147
|
+
requestObject.params = testParams;
|
|
142
148
|
|
|
143
149
|
// call Constraint
|
|
144
150
|
if(typeof routeList[item].constraint === "function"){
|
|
@@ -197,6 +203,8 @@ const isDevelopment = process.env.NODE_ENV !== 'production' && process.env.maste
|
|
|
197
203
|
|
|
198
204
|
if(pathObj.requestPath === pathObj.routePath && "options" ===requestObject.type.toLowerCase()){
|
|
199
205
|
// this means that the request is correct but its an options request means its the browser checking to see if the request is allowed
|
|
206
|
+
// Commit the params for OPTIONS requests too
|
|
207
|
+
requestObject.params = testParams;
|
|
200
208
|
requestObject.response.writeHead(200, {'Content-Type': 'application/json'});
|
|
201
209
|
requestObject.response.end(JSON.stringify({"done": "true"}));
|
|
202
210
|
return true;
|
|
@@ -238,88 +246,110 @@ var loadScopedListClasses = function(){
|
|
|
238
246
|
};
|
|
239
247
|
|
|
240
248
|
|
|
249
|
+
/**
|
|
250
|
+
* Normalize route path: lowercase segments but preserve param names
|
|
251
|
+
*
|
|
252
|
+
* @param {String} path - Route path like "/Period/:periodId/Items/:itemId"
|
|
253
|
+
* @returns {String} - Normalized: "period/:periodId/items/:itemId"
|
|
254
|
+
*/
|
|
255
|
+
function normalizeRoutePath(path) {
|
|
256
|
+
const trimmed = path.replace(/^\/|\/$/g, '');
|
|
257
|
+
const segments = trimmed.split('/');
|
|
258
|
+
|
|
259
|
+
const normalized = segments.map(segment => {
|
|
260
|
+
// Preserve parameter names (start with :)
|
|
261
|
+
if (segment.startsWith(':')) {
|
|
262
|
+
return segment;
|
|
263
|
+
}
|
|
264
|
+
// Lowercase path segments
|
|
265
|
+
return segment.toLowerCase();
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
return normalized.join('/');
|
|
269
|
+
}
|
|
270
|
+
|
|
241
271
|
class MasterRouter {
|
|
242
272
|
currentRouteName = null
|
|
243
273
|
_routes = {}
|
|
244
|
-
|
|
274
|
+
|
|
245
275
|
start(){
|
|
246
276
|
var $that = this;
|
|
247
277
|
return {
|
|
248
278
|
route : function(path, toPath, type, constraint){ // function to add to list of routes
|
|
249
|
-
|
|
279
|
+
|
|
250
280
|
var pathList = toPath.replace(/^\/|\/$/g, '').split("#");
|
|
251
|
-
|
|
281
|
+
|
|
252
282
|
var route = {
|
|
253
283
|
type: type.toLowerCase(),
|
|
254
|
-
path: path
|
|
284
|
+
path: normalizeRoutePath(path),
|
|
255
285
|
toController :pathList[0].replace(/^\/|\/$/g, ''),
|
|
256
286
|
toAction: pathList[1],
|
|
257
287
|
constraint : constraint
|
|
258
288
|
};
|
|
259
|
-
|
|
289
|
+
|
|
260
290
|
$that._routes[$that.currentRouteName].routes.push(route);
|
|
261
|
-
|
|
291
|
+
|
|
262
292
|
},
|
|
263
293
|
|
|
264
294
|
resources: function(routeName){ // function to add to list of routes using resources bulk
|
|
265
|
-
|
|
295
|
+
|
|
266
296
|
|
|
267
297
|
$that._routes[$that.currentRouteName].routes.push({
|
|
268
298
|
type: "get",
|
|
269
|
-
path: routeName
|
|
299
|
+
path: normalizeRoutePath(routeName),
|
|
270
300
|
toController :routeName,
|
|
271
301
|
toAction: "index",
|
|
272
302
|
constraint : null
|
|
273
303
|
});
|
|
274
|
-
|
|
304
|
+
|
|
275
305
|
$that._routes[$that.currentRouteName].routes.push({
|
|
276
306
|
type: "get",
|
|
277
|
-
path: routeName
|
|
307
|
+
path: normalizeRoutePath(routeName),
|
|
278
308
|
toController :routeName,
|
|
279
309
|
toAction: "new",
|
|
280
310
|
constraint : null
|
|
281
311
|
});
|
|
282
|
-
|
|
312
|
+
|
|
283
313
|
$that._routes[$that.currentRouteName].routes.push({
|
|
284
314
|
type: "post",
|
|
285
|
-
path: routeName
|
|
315
|
+
path: normalizeRoutePath(routeName),
|
|
286
316
|
toController :routeName,
|
|
287
317
|
toAction: "create",
|
|
288
318
|
constraint : null
|
|
289
319
|
});
|
|
290
|
-
|
|
320
|
+
|
|
291
321
|
$that._routes[$that.currentRouteName].routes.push({
|
|
292
322
|
// pages/3
|
|
293
323
|
type: "get",
|
|
294
|
-
path: routeName
|
|
324
|
+
path: normalizeRoutePath(routeName + "/:id"),
|
|
295
325
|
toController :routeName,
|
|
296
326
|
toAction: "show",
|
|
297
327
|
constraint : null
|
|
298
328
|
});
|
|
299
|
-
|
|
329
|
+
|
|
300
330
|
$that._routes[$that.currentRouteName].routes.push({
|
|
301
331
|
type: "get",
|
|
302
|
-
path: routeName
|
|
332
|
+
path: normalizeRoutePath(routeName + "/:id/edit"),
|
|
303
333
|
toController :routeName,
|
|
304
334
|
toAction: "edit",
|
|
305
|
-
constraint : null
|
|
335
|
+
constraint : null
|
|
306
336
|
});
|
|
307
|
-
|
|
337
|
+
|
|
308
338
|
$that._routes[$that.currentRouteName].routes.push({
|
|
309
339
|
type: "put",
|
|
310
|
-
path: routeName
|
|
340
|
+
path: normalizeRoutePath(routeName + "/:id"),
|
|
311
341
|
toController :routeName,
|
|
312
342
|
toAction: "update",
|
|
313
343
|
constraint : null
|
|
314
344
|
});
|
|
315
|
-
|
|
345
|
+
|
|
316
346
|
$that._routes[$that.currentRouteName].routes.push({
|
|
317
347
|
type: "delete",
|
|
318
|
-
path: routeName
|
|
348
|
+
path: normalizeRoutePath(routeName + "/:id"),
|
|
319
349
|
toController :routeName,
|
|
320
350
|
toAction: "destroy",
|
|
321
351
|
constraint : null
|
|
322
|
-
});
|
|
352
|
+
});
|
|
323
353
|
}
|
|
324
354
|
}
|
|
325
355
|
}
|
package/MasterSession.js
CHANGED
|
@@ -35,6 +35,11 @@ class MasterSession{
|
|
|
35
35
|
this.options.secret = TID;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
// Auto-register with pipeline if available
|
|
39
|
+
if (master.pipeline) {
|
|
40
|
+
master.pipeline.use(this.middleware());
|
|
41
|
+
}
|
|
42
|
+
|
|
38
43
|
return {
|
|
39
44
|
setPath : function(path){
|
|
40
45
|
$that.options.path = path === undefined ? '/' : path;
|
|
@@ -184,6 +189,20 @@ class MasterSession{
|
|
|
184
189
|
return -1;
|
|
185
190
|
}
|
|
186
191
|
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Get session middleware for the pipeline
|
|
195
|
+
* Sessions are accessed lazily via master.sessions in controllers
|
|
196
|
+
*/
|
|
197
|
+
middleware() {
|
|
198
|
+
var $that = this;
|
|
199
|
+
|
|
200
|
+
return async (ctx, next) => {
|
|
201
|
+
// Sessions are available via master.sessions.get/set in controllers
|
|
202
|
+
// No action needed here - just continue pipeline
|
|
203
|
+
await next();
|
|
204
|
+
};
|
|
205
|
+
}
|
|
187
206
|
}
|
|
188
207
|
|
|
189
208
|
master.extend("sessions", MasterSession);
|
package/MasterTemplate.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
// version 0.0.
|
|
1
|
+
// version 0.0.5
|
|
2
2
|
// https://github.com/WebReflection/backtick-template
|
|
3
3
|
// https://stackoverflow.com/questions/29182244/convert-a-string-to-a-template-string
|
|
4
4
|
|
|
5
5
|
// Security - Template injection prevention
|
|
6
|
-
const { escapeHTML } = require('./MasterSanitizer');
|
|
7
|
-
const { logger } = require('./MasterErrorLogger');
|
|
6
|
+
const { escapeHTML } = require('./security/MasterSanitizer');
|
|
7
|
+
const { logger } = require('./error/MasterErrorLogger');
|
|
8
8
|
|
|
9
9
|
var replace = ''.replace;
|
|
10
10
|
|