miqro 7.2.7 → 7.2.9

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 (97) hide show
  1. package/build/esm/editor/auth.d.ts +6 -0
  2. package/build/esm/editor/auth.js +42 -0
  3. package/build/esm/editor/common/constants.d.ts +4 -0
  4. package/build/esm/editor/common/constants.js +20 -0
  5. package/build/esm/editor/common/constants.server.d.ts +2 -0
  6. package/build/esm/editor/common/constants.server.js +4 -0
  7. package/build/esm/editor/common/editor-index.d.ts +2 -0
  8. package/build/esm/editor/common/editor-index.js +14 -0
  9. package/build/esm/editor/common/html-encode.d.ts +1 -0
  10. package/build/esm/editor/common/html-encode.js +14 -0
  11. package/build/esm/editor/common/log-socket.d.ts +15 -0
  12. package/build/esm/editor/common/log-socket.js +71 -0
  13. package/build/esm/editor/common/templates.d.ts +11 -0
  14. package/build/esm/editor/common/templates.js +477 -0
  15. package/build/esm/editor/components/api-preview.d.ts +11 -0
  16. package/build/esm/editor/components/api-preview.js +92 -0
  17. package/build/esm/editor/components/editor.d.ts +16 -0
  18. package/build/esm/editor/components/editor.js +367 -0
  19. package/build/esm/editor/components/file-browser.d.ts +37 -0
  20. package/build/esm/editor/components/file-browser.js +127 -0
  21. package/build/esm/editor/components/file-editor-toolbar.d.ts +22 -0
  22. package/build/esm/editor/components/file-editor-toolbar.js +95 -0
  23. package/build/esm/editor/components/file-editor.d.ts +32 -0
  24. package/build/esm/editor/components/file-editor.js +61 -0
  25. package/build/esm/editor/components/filter-query.d.ts +1 -0
  26. package/build/esm/editor/components/filter-query.js +23 -0
  27. package/build/esm/editor/components/highlight-text-area.d.ts +11 -0
  28. package/build/esm/editor/components/highlight-text-area.js +127 -0
  29. package/build/esm/editor/components/log-viewer.d.ts +6 -0
  30. package/build/esm/editor/components/log-viewer.js +71 -0
  31. package/build/esm/editor/components/new-file.d.ts +10 -0
  32. package/build/esm/editor/components/new-file.js +119 -0
  33. package/build/esm/editor/components/scroll-query.d.ts +7 -0
  34. package/build/esm/editor/components/scroll-query.js +22 -0
  35. package/build/esm/editor/components/start-page.d.ts +13 -0
  36. package/build/esm/editor/components/start-page.js +32 -0
  37. package/build/esm/editor/http/admin/editor/api/fs/delete.api.d.ts +4 -0
  38. package/build/esm/editor/http/admin/editor/api/fs/delete.api.js +30 -0
  39. package/build/esm/editor/http/admin/editor/api/fs/read.api.d.ts +7 -0
  40. package/build/esm/editor/http/admin/editor/api/fs/read.api.js +50 -0
  41. package/build/esm/editor/http/admin/editor/api/fs/rename.api.d.ts +7 -0
  42. package/build/esm/editor/http/admin/editor/api/fs/rename.api.js +40 -0
  43. package/build/esm/editor/http/admin/editor/api/fs/scan.api.d.ts +26 -0
  44. package/build/esm/editor/http/admin/editor/api/fs/scan.api.js +150 -0
  45. package/build/esm/editor/http/admin/editor/api/fs/write.api.d.ts +3 -0
  46. package/build/esm/editor/http/admin/editor/api/fs/write.api.js +39 -0
  47. package/build/esm/editor/http/admin/editor/api/server/reload.api.d.ts +10 -0
  48. package/build/esm/editor/http/admin/editor/api/server/reload.api.js +46 -0
  49. package/build/esm/editor/http/admin/editor/api/server/restart.api.d.ts +10 -0
  50. package/build/esm/editor/http/admin/editor/api/server/restart.api.js +46 -0
  51. package/build/esm/editor/http/admin/editor/editor.d.ts +1 -0
  52. package/build/esm/editor/http/admin/editor/editor.js +8 -0
  53. package/build/esm/editor/http/admin/editor/index.api.d.ts +3 -0
  54. package/build/esm/editor/http/admin/editor/index.api.js +23 -0
  55. package/build/esm/editor/server.d.ts +3 -0
  56. package/build/esm/editor/server.js +49 -0
  57. package/build/esm/editor/ws.d.ts +3 -0
  58. package/build/esm/editor/ws.js +12 -0
  59. package/build/esm/src/common/admin-interface.d.ts +36 -0
  60. package/build/esm/src/common/admin-interface.js +44 -0
  61. package/build/esm/src/common/exit.js +18 -2
  62. package/build/esm/src/common/watch.js +8 -3
  63. package/build/esm/src/services/app.d.ts +1 -1
  64. package/build/esm/src/services/editor.d.ts +1 -1
  65. package/build/esm/src/services/utils/admin-interface.d.ts +1 -1
  66. package/build/esm/src/services/utils/websocketmanager.d.ts +1 -1
  67. package/build/lib.cjs +48 -20
  68. package/editor/auth.ts +52 -0
  69. package/editor/common/constants.server.ts +5 -0
  70. package/editor/common/constants.ts +21 -0
  71. package/editor/common/editor-index.tsx +17 -0
  72. package/editor/common/html-encode.ts +14 -0
  73. package/editor/common/log-socket.tsx +87 -0
  74. package/editor/common/templates.ts +481 -0
  75. package/editor/components/api-preview.tsx +118 -0
  76. package/editor/components/editor.tsx +496 -0
  77. package/editor/components/file-browser.tsx +311 -0
  78. package/editor/components/file-editor-toolbar.tsx +194 -0
  79. package/editor/components/file-editor.tsx +125 -0
  80. package/editor/components/filter-query.tsx +26 -0
  81. package/editor/components/highlight-text-area.tsx +148 -0
  82. package/editor/components/log-viewer.tsx +113 -0
  83. package/editor/components/new-file.tsx +172 -0
  84. package/editor/components/scroll-query.tsx +25 -0
  85. package/editor/components/start-page.tsx +52 -0
  86. package/editor/http/admin/editor/api/fs/delete.api.tsx +32 -0
  87. package/editor/http/admin/editor/api/fs/read.api.tsx +55 -0
  88. package/editor/http/admin/editor/api/fs/rename.api.tsx +41 -0
  89. package/editor/http/admin/editor/api/fs/scan.api.tsx +181 -0
  90. package/editor/http/admin/editor/api/fs/write.api.tsx +41 -0
  91. package/editor/http/admin/editor/api/server/reload.api.ts +53 -0
  92. package/editor/http/admin/editor/api/server/restart.api.tsx +52 -0
  93. package/editor/http/admin/editor/editor.tsx +10 -0
  94. package/editor/http/admin/editor/index.api.tsx +43 -0
  95. package/editor/server.ts +57 -0
  96. package/editor/ws.ts +17 -0
  97. package/package.json +2 -2
@@ -2,7 +2,7 @@ import { Logger } from "@miqro/core";
2
2
  import { ClusterWebSocketServer2 } from "./cluster-ws.js";
3
3
  import { WSConfig } from "../../types.js";
4
4
  import { LogProvider } from "./log.js";
5
- import { EditorAdminInterface } from "../../../editor/common/admin-interface.js";
5
+ import { EditorAdminInterface } from "../../common/admin-interface.js";
6
6
  export interface WebSocketManagerOptions {
7
7
  logger?: Logger | Console;
8
8
  loggerProvider?: LogProvider;
package/build/lib.cjs CHANGED
@@ -2591,7 +2591,7 @@ var init_app = __esm({
2591
2591
  });
2592
2592
  });
2593
2593
  if (config?.onUpgrade) {
2594
- this.httpServer.on("upgrade", (req, socket, head) => {
2594
+ this.httpServer.on("upgrade", async (req, socket, head) => {
2595
2595
  try {
2596
2596
  const logger = loggerFactory(req.uuid, req);
2597
2597
  try {
@@ -2600,7 +2600,8 @@ var init_app = __esm({
2600
2600
  socket.destroy();
2601
2601
  } else {
2602
2602
  if (config?.onUpgrade) {
2603
- return config.onUpgrade(req, socket, head);
2603
+ const ret = await config.onUpgrade(req, socket, head);
2604
+ return ret;
2604
2605
  } else {
2605
2606
  socket.end("HTTP/1.1 400 Bad Request");
2606
2607
  socket.destroy();
@@ -2679,7 +2680,7 @@ Sec-WebSocket-Accept: ${acceptValue}${extra}\r
2679
2680
  \r
2680
2681
  `;
2681
2682
  }
2682
- function parseFrame(buffer) {
2683
+ function parseFrame(buffer, maxFrameSize = DEFAULT_MAX_FRAME_SIZE) {
2683
2684
  const firstByte = buffer.readUInt8(0);
2684
2685
  const opCode = firstByte & 15;
2685
2686
  if (opCode === OPCODES.close) {
@@ -2699,6 +2700,9 @@ function parseFrame(buffer) {
2699
2700
  payloadLength = Number(buffer.readBigUInt64BE(offset));
2700
2701
  offset += 8;
2701
2702
  }
2703
+ if (payloadLength > maxFrameSize) {
2704
+ return null;
2705
+ }
2702
2706
  const isMasked = Boolean(secondByte >>> 7 & 1);
2703
2707
  if (isMasked) {
2704
2708
  const maskingKey = buffer.readUInt32BE(offset);
@@ -2742,7 +2746,7 @@ function createFrame(payload) {
2742
2746
  buffer.write(payload, payloadBytesOffset);
2743
2747
  return buffer;
2744
2748
  }
2745
- var import_crypto3, WebSocketServer, PING, OPCODES, GUID;
2749
+ var import_crypto3, WebSocketServer, PING, OPCODES, GUID, DEFAULT_MAX_FRAME_SIZE;
2746
2750
  var init_websocket = __esm({
2747
2751
  "node_modules/@miqro/core/build/websocket.js"() {
2748
2752
  import_crypto3 = require("crypto");
@@ -2776,12 +2780,21 @@ var init_websocket = __esm({
2776
2780
  if (!client) {
2777
2781
  throw new Error("client not found");
2778
2782
  }
2783
+ if (!client.socket.writable) {
2784
+ this.clients.delete(clientUUID);
2785
+ throw new Error("socket not writable");
2786
+ }
2787
+ if (client.socket.writableLength > (this.options.maxFrameSize ?? DEFAULT_MAX_FRAME_SIZE)) {
2788
+ client.socket.destroy();
2789
+ this.clients.delete(clientUUID);
2790
+ throw new Error("client send buffer full");
2791
+ }
2779
2792
  return new Promise((resolve24, reject) => {
2780
2793
  try {
2781
- client.req.socket.write(createFrame(data), (err) => {
2794
+ client.socket.write(createFrame(data), (err) => {
2782
2795
  if (err) {
2783
2796
  try {
2784
- client.req.socket.destroy(err);
2797
+ client.socket.destroy(err);
2785
2798
  } catch (e) {
2786
2799
  console.error(e);
2787
2800
  }
@@ -2793,7 +2806,7 @@ var init_websocket = __esm({
2793
2806
  });
2794
2807
  } catch (e) {
2795
2808
  try {
2796
- client.req.socket.destroy();
2809
+ client.socket.destroy();
2797
2810
  } catch (e2) {
2798
2811
  console.error(e2);
2799
2812
  }
@@ -2840,8 +2853,8 @@ var init_websocket = __esm({
2840
2853
  };
2841
2854
  req.logger.debug("upgrading connection");
2842
2855
  socket.write(createUpgradeHeaders(acceptKey, extraHeaders));
2843
- socket.on("data", (data) => {
2844
- const frame = parseFrame(data);
2856
+ socket.on("data", async (data) => {
2857
+ const frame = parseFrame(data, this.options.maxFrameSize);
2845
2858
  if (frame === PING) {
2846
2859
  try {
2847
2860
  socket.write(Buffer.from([138, 0]));
@@ -2854,7 +2867,7 @@ var init_websocket = __esm({
2854
2867
  socket.destroy();
2855
2868
  } else {
2856
2869
  try {
2857
- this.options.onMessage(client, frame);
2870
+ await this.options.onMessage(client, frame);
2858
2871
  } catch (e) {
2859
2872
  req.logger.error(e);
2860
2873
  }
@@ -2869,23 +2882,23 @@ var init_websocket = __esm({
2869
2882
  socket.destroy();
2870
2883
  }
2871
2884
  });
2872
- socket.on("error", (error2) => {
2885
+ socket.on("error", async (error2) => {
2873
2886
  req.logger.debug("upgraded connection error!");
2874
2887
  req.logger.error(error2);
2875
2888
  if (this.options.onError) {
2876
2889
  try {
2877
- this.options.onError(client, error2);
2890
+ await this.options.onError(client, error2);
2878
2891
  } catch (e) {
2879
2892
  req.logger.error(e);
2880
2893
  }
2881
2894
  }
2882
2895
  });
2883
- socket.on("end", () => {
2896
+ socket.on("end", async () => {
2884
2897
  req.logger.debug("upgraded connection disconnected!");
2885
2898
  this.clients.delete(uuid);
2886
2899
  if (this.options.onDisconnect) {
2887
2900
  try {
2888
- this.options.onDisconnect(client);
2901
+ await this.options.onDisconnect(client);
2889
2902
  } catch (e) {
2890
2903
  req.logger.error(e);
2891
2904
  }
@@ -2895,7 +2908,7 @@ var init_websocket = __esm({
2895
2908
  this.clients.set(uuid, client);
2896
2909
  if (this.options.onConnection) {
2897
2910
  try {
2898
- this.options.onConnection(client);
2911
+ await this.options.onConnection(client);
2899
2912
  } catch (e) {
2900
2913
  req.logger.error(e);
2901
2914
  }
@@ -2908,6 +2921,7 @@ var init_websocket = __esm({
2908
2921
  PING = /* @__PURE__ */ Symbol();
2909
2922
  OPCODES = { text: 1, close: 8, ping: 9, pong: 10 };
2910
2923
  GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
2924
+ DEFAULT_MAX_FRAME_SIZE = 1024 * 1024;
2911
2925
  }
2912
2926
  });
2913
2927
 
@@ -14229,9 +14243,13 @@ async function watchAndServer(app) {
14229
14243
  try {
14230
14244
  stopWatch();
14231
14245
  setTimeout(async () => {
14232
- watchLogger?.debug("closed");
14233
- await app.reload();
14234
- reWatch();
14246
+ try {
14247
+ watchLogger?.debug("closed");
14248
+ await app.reload();
14249
+ reWatch();
14250
+ } catch (e) {
14251
+ watchLogger?.error(e);
14252
+ }
14235
14253
  }, 500);
14236
14254
  } catch (e) {
14237
14255
  watchLogger?.error(e);
@@ -14306,11 +14324,11 @@ function setupExitHandlers(app) {
14306
14324
  exceptionOccured = true;
14307
14325
  cleanJSX(app);
14308
14326
  if (app.server) {
14309
- app.stop();
14327
+ await app.stop();
14310
14328
  }
14311
14329
  process.exit(EXIT_CODES.ABNORMAL_UNCONTROLLED);
14312
14330
  });
14313
- process.on("exit", async function(code) {
14331
+ process.on("exit", function(code) {
14314
14332
  if (exceptionOccured) {
14315
14333
  app.logger?.error("Exception occured");
14316
14334
  } else {
@@ -14320,6 +14338,16 @@ function setupExitHandlers(app) {
14320
14338
  }
14321
14339
  }
14322
14340
  });
14341
+ process.on("unhandledRejection", async (reason) => {
14342
+ app.logger?.error("Unhandled rejection:");
14343
+ app.logger?.error(reason);
14344
+ exceptionOccured = true;
14345
+ cleanJSX(app);
14346
+ if (app.server) {
14347
+ await app.stop();
14348
+ }
14349
+ process.exit(EXIT_CODES.ABNORMAL_UNCONTROLLED);
14350
+ });
14323
14351
  process.on("SIGTERM", function() {
14324
14352
  app.logger?.info("SIGTERM received");
14325
14353
  process.exit(EXIT_CODES.ABNORMAL_UNCONTROLLED);
package/editor/auth.ts ADDED
@@ -0,0 +1,52 @@
1
+ import { timingSafeEqual } from "node:crypto";
2
+ import { AuthConfig, ServerRequest } from "../src/types.js";
3
+ import { AdminRequest } from "../src/common/admin-interface.js";
4
+
5
+ export const ADMIN_EDITOR_AUTH_KEY = "$$ADMIN_EDITOR_AUTH_KEY$$";
6
+
7
+ export const ADMIN_EDITOR_AUTH_QUERY = "key";
8
+ export const ADMIN_EDITOR_AUTH_COOKIE = ADMIN_EDITOR_AUTH_KEY;
9
+
10
+ export default {
11
+ authService: {
12
+ verify: async (args) => {
13
+
14
+ const adminInterface = (args.req as AdminRequest).editor;
15
+ const serverInterface = (args.req as any as ServerRequest).server;
16
+ const KEY = (adminInterface ? adminInterface.getCache() : serverInterface.cache).get<string>(ADMIN_EDITOR_AUTH_KEY);
17
+
18
+ const validSesson = {
19
+ username: "username",
20
+ account: "account",
21
+ groups: [],
22
+ token: args.token
23
+ };
24
+
25
+ const queryToken = args.req.query[ADMIN_EDITOR_AUTH_QUERY];
26
+ const cookieToken = args.req.cookies[ADMIN_EDITOR_AUTH_COOKIE];
27
+
28
+ //console.log("\n\nqueryToken[%s] cookieToken[%s] KEY[%s]\n\n", queryToken, cookieToken, KEY);
29
+
30
+ if (queryToken) {
31
+ if (typeof queryToken === "string" && timingSafeEqual(Buffer.from(queryToken), Buffer.from(KEY))) {
32
+ args.res.setCookie(ADMIN_EDITOR_AUTH_COOKIE, KEY, {
33
+ expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 31 * 12 * 500),
34
+ httpOnly: true,
35
+
36
+ //secure: true,
37
+ path: "/",
38
+ //sameSite: "strict"
39
+ });
40
+ args.req.searchParams.delete(ADMIN_EDITOR_AUTH_QUERY);
41
+ const queryString = args.req.searchParams.toString();
42
+ const redirect = args.req.path + (queryString ? "?" + queryString : "");
43
+ await args.res.redirect(redirect);
44
+ return validSesson;
45
+ }
46
+ } else if (cookieToken) {
47
+ return cookieToken === KEY ? validSesson : null;
48
+ }
49
+ return null;
50
+ },
51
+ }
52
+ } as AuthConfig;
@@ -0,0 +1,5 @@
1
+ import { resolve } from "node:path";
2
+ import { cwd } from "node:process";
3
+
4
+ export const PORT = process.env["PORT"] ? process.env["PORT"] : "8080";
5
+ export const BASE_PATH = resolve(cwd());
@@ -0,0 +1,21 @@
1
+ export const BASEEDITOR_PATH = "/admin/editor";
2
+ export const LOG_SOCKET_PATH = "/admin/socket";
3
+ export const LOG_WRITE_EVENT = "LogWrite";
4
+
5
+ export const SUPPORTED_LANGUAGES = [
6
+ "text",
7
+ "json",
8
+ "javascript",
9
+ "typescript",
10
+ "dockerfile",
11
+ "yaml",
12
+ "xml",
13
+ "html",
14
+ "css",
15
+ "scss",
16
+ "markdown",
17
+ "c",
18
+ "cpp",
19
+ "bash",
20
+ "python"
21
+ ];
@@ -0,0 +1,17 @@
1
+ import { scanDir } from "../http/admin/editor/api/fs/scan.api.js";
2
+ import { parseInflateErrors } from "../http/admin/editor/api/server/restart.api.js";
3
+ import { AdminRequest } from "../../src/common/admin-interface.js";
4
+ import { HTMLEncode } from "./html-encode.js";
5
+
6
+ export function EditorIndex(editorCSS: string, editorJS: string, enableHotReload: boolean) {
7
+ return async function editorIndex(req: AdminRequest, res) {
8
+ const admin = req.editor;
9
+
10
+ const errors = parseInflateErrors(admin ? admin.getInflateErrors() : []);
11
+ const files = scanDir(req);
12
+ const migrations = admin ? admin.getMigrations().map(m => m.name) : [];
13
+ const services = admin ? admin.getServices() : ["."];
14
+ const hotReload = enableHotReload ? (admin ? admin.getHotReloadHTML() : "") : "";
15
+ res.html(`<!DOCTYPE html><html><body><style>${editorCSS}</style><script type="module">${editorJS}</script><editor-component class="main-container" reloadstring="${req.uuid}" migrations="${HTMLEncode(JSON.stringify(migrations))}" services="${HTMLEncode(JSON.stringify(services))}" errors="${HTMLEncode(JSON.stringify(errors))}" files="${HTMLEncode(JSON.stringify(files))}"><noscript>Enable JavaScript</noscript></editor-component>${hotReload}</body></html>`)
16
+ }
17
+ }
@@ -0,0 +1,14 @@
1
+ export function HTMLEncode(str: string): string {
2
+ let i = str.length;
3
+ const aRet: string[] = [];
4
+
5
+ while (i--) {
6
+ const iC = str[i].charCodeAt(0);
7
+ if (iC < 65 || iC > 127 || (iC > 90 && iC < 97)) {
8
+ aRet[i] = '&#' + iC + ';';
9
+ } else {
10
+ aRet[i] = str[i];
11
+ }
12
+ }
13
+ return aRet.join('');
14
+ }
@@ -0,0 +1,87 @@
1
+ import * as jsx from "@miqro/jsx";
2
+
3
+ interface LogLine { out: string; identifier: string; level: "error" | "warn" | "debug" | "trace" | "info" }
4
+
5
+ export interface LogSocket {
6
+ lines: LogLine[];
7
+ clearLog: () => void;
8
+ getMaxlogsize: () => number | "unlimited";
9
+ setMaxLogSize: (val: number | "unlimited") => void;
10
+ }
11
+
12
+ export function useLogSocket(options: { disableLog?: boolean; }): LogSocket {
13
+
14
+ const [_, setmaxLogSize, getMaxlogsize] = jsx.useState<number | "unlimited">(1000000);
15
+
16
+ const [__, setlines, getLines] = jsx.useState<LogLine[]>([]);
17
+ const refresh = jsx.useRefresh();
18
+
19
+ jsx.useEffect(() => {
20
+
21
+ let timeout;
22
+
23
+ function setupSocket() {
24
+ try {
25
+ if (options.disableLog) {
26
+ return;
27
+ }
28
+ console.log("setting up log socket");
29
+ const socket = new WebSocket("/admin/socket");
30
+ socket.addEventListener("error", (err) => {
31
+ console.error(err);
32
+ clearTimeout(timeout);
33
+ timeout = setTimeout(() => {
34
+ setupSocket();
35
+ }, 1000);
36
+ });
37
+ socket.addEventListener("open", () => {
38
+ console.log("log socket open");
39
+ clearTimeout(timeout);
40
+ socket.addEventListener("message", (msg) => {
41
+ const lines = getLines();
42
+ const data = JSON.parse(msg.data);
43
+ //console.log(data.out);
44
+ const maxLogSize = getMaxlogsize();
45
+ if (maxLogSize !== "unlimited" && lines.length >= maxLogSize) {
46
+ lines.splice(0, (lines.length - maxLogSize) + 1);
47
+ }
48
+ lines.push(data);
49
+ setlines(lines);
50
+ refresh();
51
+ });
52
+ });
53
+ socket.addEventListener("close", () => {
54
+ console.log("log socket close");
55
+ clearTimeout(timeout);
56
+ timeout = setTimeout(() => {
57
+ setupSocket();
58
+ }, 1000);
59
+ });
60
+ } catch (e) {
61
+ console.error(e);
62
+ clearTimeout(timeout);
63
+ timeout = setTimeout(() => {
64
+ setupSocket();
65
+ }, 1000);
66
+ }
67
+ }
68
+
69
+ setupSocket();
70
+ }, []);
71
+
72
+ return {
73
+ lines: getLines(),
74
+ clearLog: () => {
75
+ setlines([]);
76
+ },
77
+ getMaxlogsize,
78
+ setMaxLogSize: (newValue: number | "unlimited") => {
79
+ if (newValue === "unlimited") {
80
+ setmaxLogSize(newValue);
81
+ } else {
82
+ setmaxLogSize(newValue);
83
+ }
84
+
85
+ }
86
+ }
87
+ }