miqro 6.2.12 → 6.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.
@@ -1,5 +1,5 @@
1
1
  import { Router, newURL, Response, Request, RouterHandlerOptions, Logger, APIRoute, normalizePath, HandlerWithOptions, Handler } from "@miqro/core";
2
- import { existsSync, mkdirSync, readFile, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
2
+ import { existsSync, mkdir, readFile, readFileSync, readdirSync, statSync } from "node:fs";
3
3
  import { dirname, join, relative, resolve as pathResolve } from "node:path";
4
4
 
5
5
  import { CONTENT_TYPE_MAP, DEFAULT_CONTENT_TYPE } from "../common/content-type.js";
@@ -13,7 +13,7 @@ import { getHTTPRouterPath, getStaticFilesPath } from "../common/paths.js";
13
13
  import { setupCORS } from "./setup-cors.js";
14
14
  import { setupAUTH } from "./setup-auth.js";
15
15
  import { getRoutes } from "../services/utils/get-route.js";
16
- import { describeFilePath } from "../common/fs.js";
16
+ import { describeFilePath, mkdirASync, writeFileASync } from "../common/fs.js";
17
17
  import { inflateMD2HTML } from "./md.js";
18
18
  import { MiddlewareConfig, ServerInterface, ServerRequest } from "../types.js";
19
19
  import { setupMiddleware } from "./setup-middleware.js";
@@ -45,7 +45,7 @@ export interface StaticFileMap {
45
45
  }
46
46
  }
47
47
 
48
- export async function setupHTTPRouter(server: ServerInterface, logger: Logger, hotreload: boolean, servicePath: string, service: string, routeFileMap: RouteFileMap, staticFileMap: StaticFileMap | null, inflateDir: string | undefined | false, inflateSea: boolean, errors: InflateError[]) {
48
+ export async function setupHTTPRouter(server: ServerInterface, logger: Logger, hotreload: boolean, servicePath: string, service: string, routeFileMap: RouteFileMap, staticFileMap: StaticFileMap | null, inflateDir: string | undefined | false, inflateSea: boolean, errors: InflateError[], inflateParallel?: number) {
49
49
  const mainRouter = new Router();
50
50
  const apiRouterPath = getHTTPRouterPath(servicePath); //resolve(process.cwd(), service, "http");
51
51
  let middlewareConfig: MiddlewareConfig | null = null;
@@ -58,14 +58,14 @@ export async function setupHTTPRouter(server: ServerInterface, logger: Logger, h
58
58
 
59
59
  if (apiRouterPath) {
60
60
  logger.trace("setting up http routes from [%s]", service);
61
- const { router: httpRouter } = await createRouterFromDirectory(server, hotreload, service, logger, apiRouterPath, errors, routeFileMap, staticFileMap, inflateDir, inflateSea);
61
+ const { router: httpRouter } = await createRouterFromDirectory(server, hotreload, service, logger, apiRouterPath, errors, routeFileMap, staticFileMap, inflateDir, inflateSea, inflateParallel);
62
62
  mainRouter.use(httpRouter);
63
63
  }
64
64
 
65
65
  const staticFilesPath = getStaticFilesPath(servicePath); //resolve(process.cwd(), service, "static");
66
66
  if (staticFilesPath) {
67
67
  logger.trace("setting up static file routes from [%s]", service);
68
- const staticRouter = createStaticRouterFromDirectory(service, logger, staticFilesPath, inflateDir, routeFileMap, staticFileMap);
68
+ const staticRouter = await createStaticRouterFromDirectory(service, logger, staticFilesPath, inflateDir, routeFileMap, staticFileMap, inflateParallel);
69
69
  mainRouter.use(staticRouter);
70
70
  }
71
71
 
@@ -78,95 +78,123 @@ export async function setupHTTPRouter(server: ServerInterface, logger: Logger, h
78
78
  return mainRouter;
79
79
  }
80
80
 
81
- function createStaticRoute(service: string, logger: Logger, router: Router, dir: string, file: ScannedFile, inflateDir?: string | undefined | false, routeFileMap?: RouteFileMap, staticFileMap?: StaticFileMap) {
82
- logger.trace("creating static route for [%s]", file.filePath);
83
- logger.trace("[%o]", {
84
- file,
85
- dir
86
- });
87
- const contentType = CONTENT_TYPE_MAP[String(file.ext).toLocaleLowerCase()];
88
- const path = join("/", relative(dir, file.filePath));
89
-
90
-
91
- routeFileMap[file.filePath] = {
92
- routes: [{
93
- method: "GET",
94
- path: normalizePath(path)
95
- }],
96
- service,
97
- filePath: file.filePath,
98
- previewMethod: "html"
99
- };
100
-
101
- if (inflateDir) {
102
- const inflatePath = join(inflateDir, service, "static", path);
103
- mkdirSync(dirname(inflatePath), {
104
- recursive: true
105
- });
106
- logger.log("writing [%s]", relative(cwd(), inflatePath));
107
- const body = readFileSync(file.filePath);
108
- writeFileSync(inflatePath, body);
109
- if (staticFileMap) {
110
- staticFileMap[file.filePath] = {
111
- contentType,
81
+ async function createStaticRoute(service: string, logger: Logger, router: Router, dir: string, file: ScannedFile, inflateDir?: string | undefined | false, routeFileMap?: RouteFileMap, staticFileMap?: StaticFileMap) {
82
+ return new Promise<void>(async (resolve, reject) => {
83
+ try {
84
+ logger.trace("creating static route for [%s]", file.filePath);
85
+ logger.trace("[%o]", {
86
+ file,
87
+ dir
88
+ });
89
+ const contentType = CONTENT_TYPE_MAP[String(file.ext).toLocaleLowerCase()];
90
+ const path = join("/", relative(dir, file.filePath));
91
+
92
+
93
+ routeFileMap[file.filePath] = {
94
+ routes: [{
95
+ method: "GET",
96
+ path: normalizePath(path)
97
+ }],
98
+ service,
112
99
  filePath: file.filePath,
113
- previewMethod: "html",
114
- method: "GET",
115
- path: normalizePath(path),
116
- body: Buffer.from(body),
117
- inflatePath: inflateDir ? join(inflateDir, service, "static", path) : undefined
100
+ previewMethod: "html"
101
+ };
102
+
103
+ if (inflateDir) {
104
+ const inflatePath = join(inflateDir, service, "static", path);
105
+ mkdir(dirname(inflatePath), {
106
+ recursive: true
107
+ }, (err) => {
108
+
109
+ })
110
+ await mkdirASync(dirname(inflatePath), {
111
+ recursive: true
112
+ });
113
+ logger.log("writing [%s]", relative(cwd(), inflatePath));
114
+ const body = readFileSync(file.filePath);
115
+ await writeFileASync(inflatePath, body);
116
+ if (staticFileMap) {
117
+ staticFileMap[file.filePath] = {
118
+ contentType,
119
+ filePath: file.filePath,
120
+ previewMethod: "html",
121
+ method: "GET",
122
+ path: normalizePath(path),
123
+ body: Buffer.from(body),
124
+ inflatePath: inflateDir ? join(inflateDir, service, "static", path) : undefined
125
+ }
126
+ }
118
127
  }
119
- }
120
- }
121
128
 
122
129
 
123
130
 
124
- router.use(assertGlobalTampered);
125
- router.get(path, async function (_req, res) {
126
- await new Promise<void>((resolve, reject) => {
127
- try {
128
- readFile(file.filePath, async (err, body) => {
129
- if (err) {
130
- reject(err);
131
- } else {
132
- try {
133
- await res.asyncEnd({
134
- status: 200,
135
- headers: {
136
- ["Content-Type"]: contentType ? contentType : DEFAULT_CONTENT_TYPE
137
- },
138
- body
139
- });
140
- resolve();
141
- } catch (e) {
142
- reject(e);
143
- }
131
+ router.use(assertGlobalTampered);
132
+ router.get(path, async function (_req, res) {
133
+ await new Promise<void>((resolve, reject) => {
134
+ try {
135
+ readFile(file.filePath, async (err, body) => {
136
+ if (err) {
137
+ reject(err);
138
+ } else {
139
+ try {
140
+ await res.asyncEnd({
141
+ status: 200,
142
+ headers: {
143
+ ["Content-Type"]: contentType ? contentType : DEFAULT_CONTENT_TYPE
144
+ },
145
+ body
146
+ });
147
+ resolve();
148
+ } catch (e) {
149
+ reject(e);
150
+ }
151
+ }
152
+ })
153
+ } catch (e) {
154
+ reject(e);
144
155
  }
145
- })
146
- } catch (e) {
147
- reject(e);
148
- }
149
- });
156
+ });
157
+ });
158
+ resolve();
159
+ } catch (e) {
160
+ reject(e);
161
+ }
150
162
  });
151
163
  }
152
164
 
153
- function createStaticRouterFromDirectory(service: string, logger: Logger, dir: string, inflateDir: string | false | undefined, routeFileMap: RouteFileMap | undefined, staticFileMap: StaticFileMap | null): Router {
165
+ async function createStaticRouterFromDirectory(service: string, logger: Logger, dir: string, inflateDir: string | false | undefined, routeFileMap: RouteFileMap | undefined, staticFileMap: StaticFileMap | null, inflateParallel?: number): Promise<Router> {
154
166
  const router = new Router();
155
- scanFiles(dir).forEach(file => {
156
- createStaticRoute(service, logger, router, dir, file, inflateDir, routeFileMap, staticFileMap);
157
- });
167
+ const maxParallel = inflateParallel ? inflateParallel : 1;
168
+ logger.debug("loading static directory with parallel [%s]", maxParallel);
169
+ let tR = [];
170
+ const files = scanFiles(dir);
171
+ for (const file of files) {
172
+ tR.push(await createStaticRoute(service, logger, router, dir, file, inflateDir, routeFileMap, staticFileMap));
173
+ if (tR.length >= maxParallel) {
174
+ await Promise.all(tR);
175
+ tR = [];
176
+ }
177
+ }
178
+ if (tR.length > 0) {
179
+ await Promise.all(tR);
180
+ tR = [];
181
+ }
158
182
  return router;
159
183
  }
160
184
 
161
- async function createRouterFromDirectory(server: ServerInterface, hotreload: boolean, service: string, logger: Logger, dir: string, errors: InflateError[] = [], routeFileMap: RouteFileMap = {}, staticFileMap: StaticFileMap | null = null, inflateDir: string | undefined | false, inflateSea: boolean): Promise<{
185
+ async function createRouterFromDirectory(server: ServerInterface, hotreload: boolean, service: string, logger: Logger, dir: string, errors: InflateError[] = [], routeFileMap: RouteFileMap = {}, staticFileMap: StaticFileMap | null = null, inflateDir: string | undefined | false, inflateSea: boolean, inflateParallel?: number): Promise<{
162
186
  router: Router;
163
187
  errors: InflateError[];
164
188
  routeFileMap: RouteFileMap;
165
189
  }> {
166
190
  const router = new Router();
191
+ const maxParallel = inflateParallel ? inflateParallel : 1;
192
+ server.logger.debug("loading http directory with parallel [%s]", maxParallel);
193
+ let tR = [];
167
194
  router.use(assertGlobalTampered);
168
- for (const file of scanFiles(dir)) {
169
- await new Promise<void>(async (resolve) => {
195
+ const files = scanFiles(dir);
196
+ for (const file of files) {
197
+ tR.push(new Promise<void>(async (resolve) => {
170
198
  try {
171
199
  switch (file.ext) {
172
200
  case ".jsx":
@@ -216,11 +244,11 @@ async function createRouterFromDirectory(server: ServerInterface, hotreload: boo
216
244
  if (inflateDir && r.defaultInflatePath && inflateSea) {
217
245
  const rPath = r.defaultInflatePath;
218
246
  const inflatePath = join(inflateDir, service, "http", rPath + ".api.cjs");
219
- mkdirSync(dirname(inflatePath), {
247
+ await mkdirASync(dirname(inflatePath), {
220
248
  recursive: true
221
249
  });
222
250
  logger.log("writing [%s]", relative(cwd(), inflatePath));
223
- writeFileSync(inflatePath, inflatedCode);
251
+ await writeFileASync(inflatePath, inflatedCode);
224
252
  }
225
253
 
226
254
 
@@ -252,7 +280,7 @@ async function createRouterFromDirectory(server: ServerInterface, hotreload: boo
252
280
  //if (r.method === "GET" || r.method === "get") {
253
281
  const rPath = r.inflatePath;
254
282
  const inflatePath = join(inflateDir, service, "static", rPath);
255
- mkdirSync(dirname(inflatePath), {
283
+ await mkdirASync(dirname(inflatePath), {
256
284
  recursive: true
257
285
  });
258
286
  if (existsSync(inflatePath) && statSync(inflatePath).isDirectory()) {
@@ -262,7 +290,7 @@ async function createRouterFromDirectory(server: ServerInterface, hotreload: boo
262
290
  const JSON_STATIC = await getJSON({ server } as ServerRequest, null, newURL(r.path), module.apiOptions?.basePath, module.default);
263
291
  //const JSON = await getJSON({ server } as ServerRequest, null, newURL(r.path), module.apiOptions?.basePath, module.default);
264
292
  logger.log("writing [%s]", relative(cwd(), inflatePath));
265
- writeFileSync(inflatePath, JSON_STATIC);
293
+ await writeFileASync(inflatePath, JSON_STATIC);
266
294
  //}
267
295
 
268
296
  if (staticFileMap && inflateSea) {
@@ -319,7 +347,7 @@ async function createRouterFromDirectory(server: ServerInterface, hotreload: boo
319
347
  //if (r.method === "GET" || r.method === "get") {
320
348
  const rPath = r.inflatePath;
321
349
  const inflatePath = join(inflateDir, service, "static", rPath);
322
- mkdirSync(dirname(inflatePath), {
350
+ await mkdirASync(dirname(inflatePath), {
323
351
  recursive: true
324
352
  });
325
353
  if (existsSync(inflatePath) && statSync(inflatePath).isDirectory()) {
@@ -330,7 +358,7 @@ async function createRouterFromDirectory(server: ServerInterface, hotreload: boo
330
358
  const HTML_STATIC = await getHTML(hotreload, { server } as ServerRequest, null, newURL(r.path), module.apiOptions?.basePath, await toRender);
331
359
 
332
360
  logger.log("writing [%s]", relative(cwd(), inflatePath));
333
- writeFileSync(inflatePath, HTML_STATIC);
361
+ await writeFileASync(inflatePath, HTML_STATIC);
334
362
  //}
335
363
 
336
364
 
@@ -390,11 +418,11 @@ async function createRouterFromDirectory(server: ServerInterface, hotreload: boo
390
418
 
391
419
  if (inflateDir) {
392
420
  const inflatePath = join(inflateDir, service, "static", path);
393
- mkdirSync(dirname(inflatePath), {
421
+ await mkdirASync(dirname(inflatePath), {
394
422
  recursive: true
395
423
  });
396
424
  logger.log("writing [%s]", relative(cwd(), inflatePath));
397
- writeFileSync(inflatePath, code);
425
+ await writeFileASync(inflatePath, code);
398
426
 
399
427
 
400
428
  if (staticFileMap && inflateSea) {
@@ -443,11 +471,11 @@ async function createRouterFromDirectory(server: ServerInterface, hotreload: boo
443
471
 
444
472
  if (inflateDir) {
445
473
  const inflatePath = join(inflateDir, service, "static", path);
446
- mkdirSync(dirname(inflatePath), {
474
+ await mkdirASync(dirname(inflatePath), {
447
475
  recursive: true
448
476
  });
449
477
  logger.log("writing [%s]", relative(cwd(), inflatePath));
450
- writeFileSync(inflatePath, code);
478
+ await writeFileASync(inflatePath, code);
451
479
  if (staticFileMap && inflateSea) {
452
480
  staticFileMap[file.filePath] = {
453
481
  contentType,
@@ -504,11 +532,11 @@ async function createRouterFromDirectory(server: ServerInterface, hotreload: boo
504
532
 
505
533
  if (inflateDir) {
506
534
  const inflatePath = join(inflateDir, service, "static", path);
507
- mkdirSync(dirname(inflatePath), {
535
+ await mkdirASync(dirname(inflatePath), {
508
536
  recursive: true
509
537
  });
510
538
  logger.log("writing [%s]", relative(cwd(), inflatePath));
511
- writeFileSync(inflatePath, code);
539
+ await writeFileASync(inflatePath, code);
512
540
  if (staticFileMap && inflateSea) {
513
541
  staticFileMap[file.filePath] = {
514
542
  contentType,
@@ -562,11 +590,11 @@ async function createRouterFromDirectory(server: ServerInterface, hotreload: boo
562
590
 
563
591
  if (inflateDir) {
564
592
  const inflatePath = join(inflateDir, service, "static", path);
565
- mkdirSync(dirname(inflatePath), {
593
+ await mkdirASync(dirname(inflatePath), {
566
594
  recursive: true
567
595
  });
568
596
  logger.log("writing [%s]", relative(cwd(), inflatePath));
569
- writeFileSync(inflatePath, code);
597
+ await writeFileASync(inflatePath, code);
570
598
  if (staticFileMap && inflateSea) {
571
599
  staticFileMap[file.filePath] = {
572
600
  contentType,
@@ -594,7 +622,7 @@ async function createRouterFromDirectory(server: ServerInterface, hotreload: boo
594
622
  }
595
623
  }
596
624
  }
597
- createStaticRoute(service, logger, router, dir, file, inflateDir, routeFileMap, staticFileMap);
625
+ await createStaticRoute(service, logger, router, dir, file, inflateDir, routeFileMap, staticFileMap);
598
626
  return resolve();
599
627
 
600
628
  }
@@ -608,7 +636,15 @@ async function createRouterFromDirectory(server: ServerInterface, hotreload: boo
608
636
  } finally {
609
637
  return resolve();
610
638
  }
611
- });
639
+ }));
640
+ if (tR.length >= maxParallel) {
641
+ await Promise.all(tR);
642
+ tR = [];
643
+ }
644
+ }
645
+ if (tR.length > 0) {
646
+ await Promise.all(tR);
647
+ tR = [];
612
648
  }
613
649
  router.use(assertGlobalTampered);
614
650
  return {
package/src/main.ts CHANGED
@@ -23,6 +23,7 @@ async function main(args: Arguments) {
23
23
  browser: args.browser,
24
24
  logFile: args.logFile,
25
25
  hotreload: args.test ? false : args.hotreload,
26
+ watch: args.test ? false : args.watch,
26
27
  https: args.test ? false : args.https,
27
28
  serverOptions: args.serverOptions,
28
29
  httpRedirect: args.test ? undefined : args.httpsRedirect
@@ -30,7 +31,9 @@ async function main(args: Arguments) {
30
31
  // check arguments
31
32
  if (args.generateDoc) {
32
33
  // --generate-doc
33
- const inflated = await app.inflate();
34
+ const inflated = await app.inflate({
35
+ inflateParallel: args.inflateParallel
36
+ });
34
37
  await generateDocs(args, app.logger, inflated);
35
38
  process.exit(EXIT_CODES.NORMAL_EXIT);
36
39
  } else if (args.migrateUp || args.migrateDown) {
@@ -44,7 +47,9 @@ async function main(args: Arguments) {
44
47
  process.exit(EXIT_CODES.NORMAL_EXIT);
45
48
  } else if (args.test) {
46
49
  // --test
47
- await app.inflate();
50
+ await app.inflate({
51
+ inflateParallel: args.inflateParallel
52
+ });
48
53
  await app.start();
49
54
  await testMain(app);
50
55
  await app.stop();
@@ -55,7 +60,8 @@ async function main(args: Arguments) {
55
60
  // --compile
56
61
  await app.inflate({
57
62
  inflateDir: args.inflateDir,
58
- inflateSea: true
63
+ inflateSea: true,
64
+ inflateParallel: args.inflateParallel
59
65
  });
60
66
  await app.dbManager.closeAll();
61
67
  await app.webSocketManager.disconnectAll();
@@ -66,14 +72,17 @@ async function main(args: Arguments) {
66
72
  // loadApp with inflateDir arg to inflate inflatable files
67
73
  await app.inflate({
68
74
  inflateDir: args.inflateDir,
69
- inflateSea: args.inflateSEA
75
+ inflateSea: args.inflateSEA,
76
+ inflateParallel: args.inflateParallel
70
77
  });
71
78
  await app.dbManager.closeAll();
72
79
  await app.webSocketManager.disconnectAll();
73
80
  process.exit(EXIT_CODES.NORMAL_EXIT);
74
81
  } else {
75
82
  // server
76
- await app.inflate();
83
+ await app.inflate({
84
+ inflateParallel: args.inflateParallel
85
+ });
77
86
  await app.start();
78
87
  }
79
88
  }
@@ -43,6 +43,7 @@ export interface MiqroOptions {
43
43
  browser?: string | boolean;
44
44
  logFile?: string | boolean;
45
45
  hotreload?: boolean;
46
+ watch?: boolean;
46
47
  serverOptions?: ServerOptions<any, any>;
47
48
  https?: boolean;
48
49
  httpRedirect?: number;
@@ -51,6 +52,7 @@ export interface MiqroOptions {
51
52
  export interface InflateOptions {
52
53
  inflateDir?: string;
53
54
  inflateSea?: boolean;
55
+ inflateParallel?: number;
54
56
  }
55
57
 
56
58
  export interface InflatedResult {
@@ -185,6 +187,7 @@ export class Miqro {
185
187
  });
186
188
  await app.inflate({
187
189
  inflateDir: miqroJSON.inflateDir ? String(miqroJSON.inflateDir) : undefined,
190
+ inflateParallel: miqroJSON.inflateParallel ? miqroJSON.inflateParallel : undefined,
188
191
  ...(inflate ? inflate : {}),
189
192
  });
190
193
  return app;
@@ -370,7 +373,8 @@ export class Miqro {
370
373
  inflateDir: options?.inflateDir,
371
374
  inflateSea: options?.inflateSea ? true : false,
372
375
  //inflateTests: options?.inflateTests ? true : false,
373
- hotreload: this.options?.hotreload ? true : false
376
+ hotreload: this.options?.hotreload ? true : false,
377
+ inflateParallel: options?.inflateParallel
374
378
  });
375
379
 
376
380
  wsConfigList.push(...serviceWSConfigList);
@@ -491,7 +495,7 @@ export class Miqro {
491
495
 
492
496
  await notifiyServerConfig(this.logger, this.serverInterface, this.adminInterface, this.inflated.serverConfigMap, "start");
493
497
 
494
- if (this.options.hotreload && (cluster.isPrimary || process.env["CLUSTER_NODE_NUMBER"] === "0")) {
498
+ if (this.options.watch && (cluster.isPrimary || process.env["CLUSTER_NODE_NUMBER"] === "0")) {
495
499
  this.watcher = await watchAndServer(this);
496
500
  }
497
501