mastercontroller 1.3.9 → 1.3.12

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.
Files changed (47) hide show
  1. package/.claude/settings.local.json +6 -1
  2. package/.eslintrc.json +50 -0
  3. package/.github/workflows/ci.yml +317 -0
  4. package/.prettierrc +10 -0
  5. package/CHANGES.md +296 -0
  6. package/DEPLOYMENT.md +956 -0
  7. package/FIXES_APPLIED.md +378 -0
  8. package/FORTUNE_500_UPGRADE.md +863 -0
  9. package/MasterAction.js +10 -263
  10. package/MasterControl.js +226 -43
  11. package/MasterRequest.js +42 -1
  12. package/MasterRouter.js +42 -37
  13. package/PERFORMANCE_SECURITY_AUDIT.md +677 -0
  14. package/README.md +602 -71
  15. package/SENIOR_ENGINEER_AUDIT.md +2477 -0
  16. package/VERIFICATION_CHECKLIST.md +726 -0
  17. package/error/README.md +2452 -0
  18. package/monitoring/HealthCheck.js +347 -0
  19. package/monitoring/PrometheusExporter.js +416 -0
  20. package/monitoring/README.md +3112 -0
  21. package/package.json +64 -11
  22. package/security/MasterValidator.js +140 -10
  23. package/security/README.md +1805 -0
  24. package/security/adapters/RedisCSRFStore.js +428 -0
  25. package/security/adapters/RedisRateLimiter.js +462 -0
  26. package/security/adapters/RedisSessionStore.js +476 -0
  27. package/MasterCors.js.tmp +0 -0
  28. package/MasterHtml.js +0 -649
  29. package/MasterPipeline.js.tmp +0 -0
  30. package/MasterRequest.js.tmp +0 -0
  31. package/MasterRouter.js.tmp +0 -0
  32. package/MasterSocket.js.tmp +0 -0
  33. package/MasterTemp.js.tmp +0 -0
  34. package/MasterTemplate.js +0 -230
  35. package/MasterTimeout.js.tmp +0 -0
  36. package/TemplateOverwrite.js +0 -41
  37. package/TemplateOverwrite.js.tmp +0 -0
  38. package/error/ErrorBoundary.js +0 -353
  39. package/error/HydrationMismatch.js +0 -265
  40. package/error/MasterError.js +0 -240
  41. package/error/MasterError.js.tmp +0 -0
  42. package/error/MasterErrorRenderer.js +0 -536
  43. package/error/MasterErrorRenderer.js.tmp +0 -0
  44. package/error/SSRErrorHandler.js +0 -273
  45. package/ssr/hydration-client.js +0 -93
  46. package/ssr/runtime-ssr.cjs +0 -553
  47. package/ssr/ssr-shims.js +0 -73
package/MasterHtml.js DELETED
@@ -1,649 +0,0 @@
1
- // version 0.0.25
2
-
3
- var fs = require('fs');
4
- var tempClass = require('./MasterTemplate');
5
- var toolClass = require('./MasterTools');
6
- var temp = new tempClass();
7
- var tools = new toolClass();
8
-
9
- // Enhanced error handling
10
- const { handleTemplateError } = require('./error/MasterBackendErrorHandler');
11
- const { safeReadFile, safeFileExists } = require('./error/MasterErrorMiddleware');
12
- const { logger } = require('./error/MasterErrorLogger');
13
-
14
- // Security - Sanitization
15
- const { sanitizeTemplateHTML, sanitizeUserHTML, escapeHTML } = require('./security/MasterSanitizer');
16
-
17
- class html {
18
-
19
- // Lazy-load master to avoid circular dependency (Google-style lazy initialization)
20
- get _master() {
21
- if (!this.__masterCache) {
22
- this.__masterCache = require('./MasterControl');
23
- }
24
- return this.__masterCache;
25
- }
26
-
27
- javaScriptSerializer(name, obj){
28
- // SECURITY: Escape closing script tags and dangerous characters
29
- const jsonStr = JSON.stringify(obj)
30
- .replace(/</g, '\\u003c')
31
- .replace(/>/g, '\\u003e')
32
- .replace(/&/g, '\\u0026')
33
- .replace(/\u2028/g, '\\u2028')
34
- .replace(/\u2029/g, '\\u2029');
35
-
36
- return `<script type="text/javascript">
37
- ${escapeHTML(name)} = ${jsonStr}
38
- </script>`;
39
- }
40
-
41
- // render partial views
42
- renderPartial(path, data){
43
- try {
44
- // SECURITY: Validate path to prevent traversal attacks
45
- if (!path || path.includes('..') || path.includes('~') || path.startsWith('/')) {
46
- logger.warn({
47
- code: 'MC_SECURITY_PATH_TRAVERSAL',
48
- message: 'Path traversal attempt blocked in renderPartial',
49
- path: path
50
- });
51
- return '<!-- Invalid path -->';
52
- }
53
-
54
- var partialViewUrl = `/app/views/${path}`;
55
- var fullPath = this._master.router.currentRoute.root + partialViewUrl;
56
-
57
- const fileResult = safeReadFile(fs, fullPath);
58
-
59
- if (!fileResult.success) {
60
- logger.warn({
61
- code: 'MC_ERR_VIEW_NOT_FOUND',
62
- message: `Partial view not found: ${path}`,
63
- file: fullPath
64
- });
65
- return `<!-- Partial view not found: ${path} -->`;
66
- }
67
-
68
- var partialView = null;
69
- if(this._master.overwrite.isTemplate){
70
- partialView = this._master.overwrite.templateRender(data, "renderPartialView");
71
- }
72
- else{
73
- partialView = temp.htmlBuilder(fileResult.content, data);
74
- }
75
-
76
- return partialView;
77
- } catch (error) {
78
- const mcError = handleTemplateError(error, path, data);
79
- logger.error({
80
- code: mcError.code,
81
- message: mcError.message,
82
- file: path,
83
- originalError: error
84
- });
85
- return `<!-- Error rendering partial: ${path} -->`;
86
- }
87
-
88
- }
89
-
90
- // render all your link tags styles given the folder location
91
- renderStyles(folderName, typeArray){
92
- // SECURITY: Validate folder name to prevent path traversal
93
- if (folderName && (folderName.includes('..') || folderName.includes('~') || folderName.startsWith('/'))) {
94
- logger.warn({
95
- code: 'MC_SECURITY_PATH_TRAVERSAL',
96
- message: 'Path traversal attempt blocked in renderStyles',
97
- folderName: folderName
98
- });
99
- return '';
100
- }
101
-
102
- var styles = [];
103
- var styleFolder = `/app/assets/stylesheets/`;
104
- var rootLocation = this._master.router.currentRoute.root;
105
- var extention = "";
106
-
107
- if(this._master.router.currentRoute.isComponent === true){
108
- extention = tools.getBackSlashBySection(this._master.router.currentRoute.root, 2, "/");
109
- }
110
-
111
- var type = typeArray === undefined ? ["css"] : typeArray;
112
-
113
- if(folderName){
114
- styleFolder = `${styleFolder}${folderName}/`;
115
- }
116
-
117
- if (fs.existsSync(`${rootLocation}${styleFolder}`)) {
118
- fs.readdirSync(`${rootLocation}${styleFolder}`).forEach(function(file){
119
-
120
- var fileExtension = file.replace(/^.*\./, '');
121
- if(type.indexOf(fileExtension) >= 0){
122
- var fileLocatoon = `${styleFolder}${file}`;
123
- if(this._master.router.currentRoute.isComponent === true){
124
- styles.push(`<link rel="stylesheet" type="text/${type}" href="/${extention}${fileLocatoon}">`);
125
- }
126
- else{
127
- styles.push(`<link rel="stylesheet" type="text/${type}" href="${fileLocatoon}">`);
128
- }
129
- }
130
- });
131
- }
132
- var partialView = null;
133
-
134
- if(this._master.overwrite.isTemplate){
135
- partialView = this._master.overwrite.templateRender({}, "renderStyles");
136
- }
137
- else{
138
- partialView = temp.htmlBuilder(styles.join(""),{});
139
- }
140
-
141
- return partialView;
142
- }
143
-
144
- // renders all scripts in main folder or folder location inside of javascript also its type specific if you provide type
145
- renderScripts(folderName, typeArray){
146
- // SECURITY: Validate folder name to prevent path traversal
147
- if (folderName && (folderName.includes('..') || folderName.includes('~') || folderName.startsWith('/'))) {
148
- logger.warn({
149
- code: 'MC_SECURITY_PATH_TRAVERSAL',
150
- message: 'Path traversal attempt blocked in renderScripts',
151
- folderName: folderName
152
- });
153
- return '';
154
- }
155
-
156
- var scripts = [];
157
- var jsFolder =`/app/assets/javascripts/`;
158
- var rootLocation = this._master.router.currentRoute.root;
159
- var extention = "";
160
- //components/auth/app/assets/javascripts/pages/changePassword.js
161
- if(this._master.router.currentRoute.isComponent === true){
162
- extention = tools.getBackSlashBySection(this._master.router.currentRoute.root, 2, "/");
163
- }
164
-
165
- var type = typeArray === undefined ? ["js"] : typeArray;
166
-
167
- if(folderName){
168
- jsFolder = `${jsFolder}${folderName}/`;
169
- }
170
-
171
- if (fs.existsSync(`${rootLocation}${jsFolder}`)) {
172
- fs.readdirSync(`${rootLocation}${jsFolder}`).forEach(function(file){
173
- var fileExtension = file.replace(/^.*\./, '');
174
- if(type.indexOf(fileExtension) >= 0){
175
- var fileLocatoon = `${jsFolder}${file}`;
176
- if(this._master.router.currentRoute.isComponent === true){
177
- scripts.push(`<script src="/${extention}${fileLocatoon}"></script>`);
178
- }
179
- else{
180
- scripts.push(`<script src="${fileLocatoon}"></script>`);
181
- }
182
- }
183
- });
184
- }
185
-
186
- var partialView = null;
187
-
188
- if(this._master.overwrite.isTemplate){
189
- partialView = this._master.overwrite.templateRender({}, "renderScripts");
190
- }
191
- else{
192
- partialView = temp.htmlBuilder(scripts.join(""),{});
193
- }
194
-
195
- return partialView;
196
- }
197
-
198
-
199
- // renders js using location
200
- renderJS(folderName, name){
201
- if(folderName === undefined && name === undefined){
202
- return "";
203
- }
204
- else{
205
- var rootLocation = this._master.router.currentRoute.root;
206
- var jsFolder = `/app/assets/javascripts/`;
207
- if(this._master.router.currentRoute.isComponent === true){
208
- rootLocation = tools.getBackSlashBySection(this._master.router.currentRoute.root, 2, "/");
209
- jsFolder = `${rootLocation}${jsFolder}`;
210
- }
211
- if(folderName){
212
- jsFolder = `${jsFolder}${folderName}/${name}`;
213
- }
214
- return `<script type="text/javascript" src="/${jsFolder}"></script>`;
215
- }
216
- }
217
-
218
- // render css directly on the page suing location name
219
- renderCss(folderName, name){
220
- if(folderName === undefined && name === undefined){
221
- return "";
222
- }
223
- else{
224
- var styleFolder = `/app/assets/stylesheets/`;
225
- var rootLocation = this._master.router.currentRoute.root;
226
- if(this._master.router.currentRoute.isComponent === true){
227
- rootLocation = tools.getBackSlashBySection(this._master.router.currentRoute.root, 2, "/");
228
- styleFolder = `${rootLocation}${styleFolder}`;
229
- }
230
-
231
- if(folderName){
232
- styleFolder = `${styleFolder}${folderName}/${name}`;
233
- }
234
- return `<link rel="stylesheet" type="text/css" href="/${styleFolder}">`;
235
- }
236
- }
237
-
238
- // return link tag
239
- linkTo(name, location){
240
- const safeName = escapeHTML(String(name));
241
- const safeLocation = escapeHTML(String(location));
242
- return `<a href="${safeLocation}">${safeName}</a>`;
243
- }
244
-
245
- // return image tag
246
- imgTag(alt, location){
247
- const safeAlt = escapeHTML(String(alt));
248
- const safeLocation = escapeHTML(String(location));
249
- return `<img src="${safeLocation}" alt="${safeAlt}">`;
250
- }
251
-
252
- // return text are tag
253
- textAreaTag(name, message, obj){
254
- const safeName = escapeHTML(String(name));
255
- const safeMessage = escapeHTML(String(message));
256
-
257
- let textArea = `<textarea name="${safeName}"`;
258
-
259
- for (const [key, value] of Object.entries(obj || {})) {
260
- const safeKey = escapeHTML(String(key));
261
- const safeValue = escapeHTML(String(value));
262
- textArea += ` ${safeKey}="${safeValue}"`;
263
- }
264
-
265
- textArea += `>${safeMessage}</textarea>`;
266
-
267
- return textArea;
268
- }
269
-
270
- // form element builder starter
271
- formTag(location, obj){
272
- const safeLocation = escapeHTML(String(location));
273
- let form = `<form action="${safeLocation}"`;
274
-
275
- for (const [key, value] of Object.entries(obj || {})) {
276
- const safeKey = escapeHTML(String(key));
277
- const safeValue = escapeHTML(String(value));
278
- form += ` ${safeKey}="${safeValue}"`;
279
- }
280
-
281
- return form + ">";
282
- }
283
-
284
- // form element builder ender
285
- formTagEnd(){
286
- return '</form>';
287
- }
288
- // return text tag
289
- passwordFieldTag(name, obj){
290
- const safeName = escapeHTML(String(name));
291
- let passwordField = `<input type="password" name="${safeName}"`;
292
-
293
- for (const [key, value] of Object.entries(obj || {})) {
294
- const safeKey = escapeHTML(String(key));
295
- const safeValue = escapeHTML(String(value));
296
- passwordField += ` ${safeKey}="${safeValue}"`;
297
- }
298
-
299
- passwordField += '/>';
300
-
301
- return passwordField;
302
- }
303
-
304
- // return password field tag
305
- textFieldTag(name, obj){
306
- const safeName = escapeHTML(String(name));
307
- let textField = `<input type="text" name="${safeName}"`;
308
-
309
- for (const [key, value] of Object.entries(obj || {})) {
310
- const safeKey = escapeHTML(String(key));
311
- const safeValue = escapeHTML(String(value));
312
- textField += ` ${safeKey}="${safeValue}"`;
313
- }
314
-
315
- textField += '/>';
316
- return textField;
317
- };
318
-
319
- // hidden field tag
320
- hiddenFieldTag(name, value, obj){
321
- const safeName = escapeHTML(String(name));
322
- const safeValue = escapeHTML(String(value));
323
-
324
- let hiddenField = `<input type="hidden" name="${safeName}" value="${safeValue}"`;
325
-
326
- for (const [key, val] of Object.entries(obj || {})) {
327
- const safeKey = escapeHTML(String(key));
328
- const safeVal = escapeHTML(String(val));
329
- hiddenField += ` ${safeKey}="${safeVal}"`;
330
- }
331
-
332
- hiddenField += '/>';
333
-
334
- return hiddenField;
335
-
336
- }
337
-
338
- // subit tag
339
- submitButton(name, obj){
340
- const safeName = escapeHTML(String(name));
341
-
342
- let submitButton = `<button type="submit" name="${safeName}"`;
343
-
344
- for (const [key, value] of Object.entries(obj || {})) {
345
- const safeKey = escapeHTML(String(key));
346
- const safeValue = escapeHTML(String(value));
347
- submitButton += ` ${safeKey}="${safeValue}"`;
348
- }
349
-
350
- submitButton += `>${safeName}</button>`;
351
-
352
- return submitButton;
353
-
354
- }
355
-
356
- // search tag
357
- searchField(name, obj){
358
- const safeName = escapeHTML(String(name));
359
-
360
- let searchField = `<input type="search" name="${safeName}"`;
361
-
362
- for (const [key, value] of Object.entries(obj || {})) {
363
- const safeKey = escapeHTML(String(key));
364
- const safeValue = escapeHTML(String(value));
365
- searchField += ` ${safeKey}="${safeValue}"`;
366
- }
367
-
368
- searchField += '/>';
369
-
370
- return searchField;
371
- }
372
-
373
- // telephone field tag
374
- telephoneField(name, obj){
375
- const safeName = escapeHTML(String(name));
376
-
377
- let telephoneField = `<input type="tel" name="${safeName}"`;
378
-
379
- for (const [key, value] of Object.entries(obj || {})) {
380
- const safeKey = escapeHTML(String(key));
381
- const safeValue = escapeHTML(String(value));
382
- telephoneField += ` ${safeKey}="${safeValue}"`;
383
- }
384
-
385
- telephoneField += '/>';
386
-
387
- return telephoneField;
388
-
389
- }
390
-
391
- // date field tag
392
- dateField(name, obj){
393
- const safeName = escapeHTML(String(name));
394
-
395
- let dateField = `<input type="date" name="${safeName}"`;
396
-
397
- for (const [key, value] of Object.entries(obj || {})) {
398
- const safeKey = escapeHTML(String(key));
399
- const safeValue = escapeHTML(String(value));
400
- dateField += ` ${safeKey}="${safeValue}"`;
401
- }
402
-
403
- dateField += '/>';
404
-
405
- return dateField;
406
- }
407
-
408
- // date time local field tag
409
- datetimeLocalField(name, obj){
410
- const safeName = escapeHTML(String(name));
411
-
412
- let datetimeLocalField = `<input type="datetime-local" name="${safeName}"`;
413
-
414
- for (const [key, value] of Object.entries(obj || {})) {
415
- const safeKey = escapeHTML(String(key));
416
- const safeValue = escapeHTML(String(value));
417
- datetimeLocalField += ` ${safeKey}="${safeValue}"`;
418
- }
419
-
420
- datetimeLocalField += '/>';
421
-
422
- return datetimeLocalField;
423
- }
424
-
425
- // date month field tag
426
- monthField(name, obj){
427
- const safeName = escapeHTML(String(name));
428
-
429
- let monthField = `<input type="month" name="${safeName}"`;
430
-
431
- for (const [key, value] of Object.entries(obj || {})) {
432
- const safeKey = escapeHTML(String(key));
433
- const safeValue = escapeHTML(String(value));
434
- monthField += ` ${safeKey}="${safeValue}"`;
435
- }
436
-
437
- monthField += '/>';
438
-
439
- return monthField;
440
- }
441
-
442
- // date week field tag
443
- weekField(name, obj){
444
- const safeName = escapeHTML(String(name));
445
-
446
- let weekField = `<input type="week" name="${safeName}"`;
447
-
448
- for (const [key, value] of Object.entries(obj || {})) {
449
- const safeKey = escapeHTML(String(key));
450
- const safeValue = escapeHTML(String(value));
451
- weekField += ` ${safeKey}="${safeValue}"`;
452
- }
453
-
454
- weekField += '/>';
455
-
456
- return weekField;
457
- }
458
-
459
- // date url field tag
460
- urlField(name, obj){
461
- const safeName = escapeHTML(String(name));
462
-
463
- let urlField = `<input type="url" name="${safeName}"`;
464
-
465
- for (const [key, value] of Object.entries(obj || {})) {
466
- const safeKey = escapeHTML(String(key));
467
- const safeValue = escapeHTML(String(value));
468
- urlField += ` ${safeKey}="${safeValue}"`;
469
- }
470
-
471
- urlField += '/>';
472
-
473
- return urlField;
474
- }
475
-
476
-
477
- // date email field tag
478
- emailField(name, obj){
479
- const safeName = escapeHTML(String(name));
480
-
481
- let emailField = `<input type="email" name="${safeName}"`;
482
-
483
- for (const [key, value] of Object.entries(obj || {})) {
484
- const safeKey = escapeHTML(String(key));
485
- const safeValue = escapeHTML(String(value));
486
- emailField += ` ${safeKey}="${safeValue}"`;
487
- }
488
-
489
- emailField += '/>';
490
-
491
- return emailField;
492
- }
493
-
494
- // date color field tag
495
- colorField(name, color, obj){
496
- const safeName = escapeHTML(String(name));
497
- const safeColor = escapeHTML(String(color));
498
-
499
- let colorField = `<input type="color" name="${safeName}" value="${safeColor}"`;
500
-
501
- for (const [key, value] of Object.entries(obj || {})) {
502
- const safeKey = escapeHTML(String(key));
503
- const safeValue = escapeHTML(String(value));
504
- colorField += ` ${safeKey}="${safeValue}"`;
505
- }
506
-
507
- colorField += '/>';
508
-
509
- return colorField;
510
- }
511
-
512
- // date time field tag
513
- timeField(name, obj){
514
- const safeName = escapeHTML(String(name));
515
-
516
- let timeField = `<input type="time" name="${safeName}"`;
517
-
518
- for (const [key, value] of Object.entries(obj || {})) {
519
- const safeKey = escapeHTML(String(key));
520
- const safeValue = escapeHTML(String(value));
521
- timeField += ` ${safeKey}="${safeValue}"`;
522
- }
523
-
524
- timeField += '/>';
525
-
526
- return timeField;
527
- }
528
-
529
- // date number field tag
530
- numberField(name, min, max, step, obj){
531
- const safeName = escapeHTML(String(name));
532
- const safeMin = escapeHTML(String(min));
533
- const safeMax = escapeHTML(String(max));
534
- const safeStep = escapeHTML(String(step));
535
-
536
- let numberField = `<input type="number" name="${safeName}" min="${safeMin}" max="${safeMax}" step="${safeStep}"`;
537
-
538
- for (const [key, value] of Object.entries(obj || {})) {
539
- const safeKey = escapeHTML(String(key));
540
- const safeValue = escapeHTML(String(value));
541
- numberField += ` ${safeKey}="${safeValue}"`;
542
- }
543
-
544
- numberField += '/>';
545
-
546
- return numberField;
547
- }
548
-
549
- // date range field tag
550
- rangeField(name, min, max, obj){
551
- const safeName = escapeHTML(String(name));
552
- const safeMin = escapeHTML(String(min));
553
- const safeMax = escapeHTML(String(max));
554
-
555
- let rangeField = `<input type="range" name="${safeName}" min="${safeMin}" max="${safeMax}"`;
556
-
557
- for (const [key, value] of Object.entries(obj || {})) {
558
- const safeKey = escapeHTML(String(key));
559
- const safeValue = escapeHTML(String(value));
560
- rangeField += ` ${safeKey}="${safeValue}"`;
561
- }
562
-
563
- rangeField += '/>';
564
-
565
- return rangeField;
566
- }
567
-
568
- // allows you to add data object to params
569
- addDataToParams(data){
570
-
571
- //loop through data and add it to new oobjects prototype
572
- if(data){
573
- var newObj = Object.create(data);
574
- newObj.prototype = newObj.__proto__;
575
- this._master.view.extend(newObj);
576
- }
577
- }
578
-
579
- // ==================== Security Methods ====================
580
-
581
- /**
582
- * Sanitize user-generated HTML content
583
- * Use this for any HTML that comes from user input
584
- * @param {string} html - HTML content to sanitize
585
- * @returns {string} - Sanitized HTML
586
- */
587
- sanitizeHTML(html) {
588
- return sanitizeUserHTML(html);
589
- }
590
-
591
- /**
592
- * Escape HTML special characters
593
- * Use this to display user input as text (not HTML)
594
- * @param {string} text - Text to escape
595
- * @returns {string} - Escaped text safe for display
596
- */
597
- escapeHTML(text) {
598
- return escapeHTML(text);
599
- }
600
-
601
- /**
602
- * Render user content safely
603
- * Sanitizes HTML and wraps in container
604
- * @param {string} content - User-generated content
605
- * @param {string} containerTag - HTML tag to wrap content (default: div)
606
- * @param {object} attrs - Attributes for container
607
- * @returns {string} - Safe HTML
608
- */
609
- renderUserContent(content, containerTag = 'div', attrs = {}) {
610
- const sanitized = sanitizeUserHTML(content);
611
-
612
- let attrStr = '';
613
- for (const [key, value] of Object.entries(attrs)) {
614
- attrStr += ` ${key}="${escapeHTML(String(value))}"`;
615
- }
616
-
617
- return `<${containerTag}${attrStr}>${sanitized}</${containerTag}>`;
618
- }
619
-
620
- /**
621
- * Create safe text node content
622
- * @param {string} text - Text content
623
- * @returns {string} - HTML-escaped text
624
- */
625
- textNode(text) {
626
- return escapeHTML(text);
627
- }
628
-
629
- /**
630
- * Create safe attribute value
631
- * @param {string} value - Attribute value
632
- * @returns {string} - Escaped and quoted value
633
- */
634
- safeAttr(value) {
635
- return `"${escapeHTML(String(value))}"`;
636
- }
637
-
638
- }
639
-
640
- // Export and lazy register (prevents circular dependency - Spring/Angular pattern)
641
- module.exports = html;
642
-
643
- setImmediate(() => {
644
- const master = require('./MasterControl');
645
- if (master && master.extendView) {
646
- master.extendView("html", html);
647
- }
648
- });
649
-
File without changes
File without changes
File without changes
File without changes
package/MasterTemp.js.tmp DELETED
File without changes