miqro 6.1.4 → 6.2.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/build/editor.bundle.js +10 -2
- package/build/esm/editor/components/editor.js +8 -0
- package/build/esm/editor/components/file-editor.js +1 -1
- package/build/esm/editor/components/highlight-text-area.js +2 -1
- package/build/esm/src/common/jwt.d.ts +49 -0
- package/build/esm/src/common/jwt.js +76 -0
- package/build/esm/src/inflate/inflate-sea.js +9 -8
- package/build/esm/src/inflate/setup-http.d.ts +1 -0
- package/build/esm/src/inflate/setup-http.js +8 -0
- package/build/esm/src/lib.d.ts +1 -1
- package/build/esm/src/lib.js +2 -2
- package/build/esm/src/services/app.js +5 -4
- package/build/esm/src/services/globals.js +45 -1
- package/build/esm/src/services/utils/cluster-ws.d.ts +4 -2
- package/build/esm/src/services/utils/cluster-ws.js +10 -1
- package/build/esm/src/services/utils/server-interface.d.ts +4 -30
- package/build/esm/src/services/utils/server-interface.js +44 -64
- package/build/esm/src/services/utils/websocketmanager.d.ts +3 -0
- package/build/esm/src/services/utils/websocketmanager.js +8 -2
- package/build/esm/src/types.d.ts +76 -5
- package/build/lib.cjs +2983 -362
- package/editor/components/editor.tsx +8 -0
- package/editor/components/file-editor.tsx +1 -1
- package/editor/components/highlight-text-area.tsx +2 -1
- package/package.json +4 -3
- package/sea/install-nodejs.sh +1 -1
- package/sea/node.version.tag +1 -1
- package/sea/types.json +1 -1
- package/src/common/jwt.ts +85 -0
- package/src/inflate/inflate-sea.ts +9 -8
- package/src/inflate/setup-http.ts +9 -0
- package/src/lib.ts +2 -2
- package/src/services/app.ts +6 -4
- package/src/services/globals.ts +45 -2
- package/src/services/utils/cluster-ws.ts +6 -1
- package/src/services/utils/server-interface.ts +44 -140
- package/src/services/utils/websocketmanager.ts +10 -2
- package/src/types/cookie.d.ts +2 -0
- package/src/types/jose.d.ts +2 -0
- package/src/types/miqro.d.ts +92 -2
- package/src/types/server.globals.d.ts +4 -29
- package/src/types.ts +78 -5
package/build/editor.bundle.js
CHANGED
|
@@ -8835,8 +8835,8 @@ function HighlightTextArea({ content, language, oncontentchange, tabChar, disabl
|
|
|
8835
8835
|
ev.preventDefault();
|
|
8836
8836
|
if (elementRef.current) {
|
|
8837
8837
|
if (content !== elementRef.current.textContent) {
|
|
8838
|
-
elementRef.current.innerHTML = runHighlight(elementRef.current.textContent, language);
|
|
8839
8838
|
}
|
|
8839
|
+
elementRef.current.innerHTML = runHighlight(elementRef.current.textContent, language);
|
|
8840
8840
|
}
|
|
8841
8841
|
},
|
|
8842
8842
|
onkeydown: (ev) => {
|
|
@@ -9272,7 +9272,7 @@ function FileEditor({ disableLog, disablePreview, disableReload, togglePanel, is
|
|
|
9272
9272
|
apiPreview
|
|
9273
9273
|
}
|
|
9274
9274
|
) : /* @__PURE__ */ JSX.createElement(JSX.Fragment, null),
|
|
9275
|
-
previewPath ? /* @__PURE__ */ JSX.createElement(
|
|
9275
|
+
previewPath && isPanelVisible("right") ? /* @__PURE__ */ JSX.createElement(
|
|
9276
9276
|
"div",
|
|
9277
9277
|
{
|
|
9278
9278
|
class: `file-editor-preview`,
|
|
@@ -10521,6 +10521,14 @@ function Editor(props) {
|
|
|
10521
10521
|
const { files: files2, services: services2 } = await r.json();
|
|
10522
10522
|
setfiles(files2);
|
|
10523
10523
|
setservices(services2);
|
|
10524
|
+
for (const file of files2) {
|
|
10525
|
+
if (opened[file.filePath]) {
|
|
10526
|
+
opened[file.filePath] = {
|
|
10527
|
+
content: opened[file.filePath].content,
|
|
10528
|
+
...file
|
|
10529
|
+
};
|
|
10530
|
+
}
|
|
10531
|
+
}
|
|
10524
10532
|
}
|
|
10525
10533
|
}
|
|
10526
10534
|
function isDirCollapsed(dir) {
|
|
@@ -147,6 +147,14 @@ export function Editor(props) {
|
|
|
147
147
|
const { files, services } = await r.json();
|
|
148
148
|
setfiles(files);
|
|
149
149
|
setservices(services);
|
|
150
|
+
for (const file of files) {
|
|
151
|
+
if (opened[file.filePath]) {
|
|
152
|
+
opened[file.filePath] = {
|
|
153
|
+
content: opened[file.filePath].content,
|
|
154
|
+
...file
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
}
|
|
150
158
|
}
|
|
151
159
|
}
|
|
152
160
|
function isDirCollapsed(dir) {
|
|
@@ -50,7 +50,7 @@ export function FileEditor({ disableLog, disablePreview, disableReload, togglePa
|
|
|
50
50
|
}
|
|
51
51
|
}, content: content, language: language }) : JSX.createElement("p", null, "binary data not supported")),
|
|
52
52
|
apiPreview && apiPreview.length > 0 ? JSX.createElement(APIPReview, { isPanelVisible: isPanelVisible, apiPreview: apiPreview }) : JSX.createElement(JSX.Fragment, null),
|
|
53
|
-
previewPath ? JSX.createElement("div", { class: `file-editor-preview`, style: `${!isPanelVisible("right") ? "display: none;" : ""}` },
|
|
53
|
+
previewPath && isPanelVisible("right") ? JSX.createElement("div", { class: `file-editor-preview`, style: `${!isPanelVisible("right") ? "display: none;" : ""}` },
|
|
54
54
|
JSX.createElement("div", { class: "file-editor-preview-path" },
|
|
55
55
|
JSX.createElement("a", { href: previewPath, target: "_blank" }, "open in new window")),
|
|
56
56
|
JSX.createElement("iframe", { ref: iFrameRef, src: previewPath, sandbox: "allow-scripts allow-same-origin" })) : JSX.createElement(JSX.Fragment, null))));
|
|
@@ -94,8 +94,9 @@ export function HighlightTextArea({ content, language, oncontentchange, tabChar,
|
|
|
94
94
|
if (elementRef.current) {
|
|
95
95
|
if (content !== elementRef.current.textContent) {
|
|
96
96
|
//setlastContent(String(elementRef.current.textContent));
|
|
97
|
-
elementRef.current.innerHTML = runHighlight(elementRef.current.textContent, language);
|
|
97
|
+
//elementRef.current.innerHTML = runHighlight(elementRef.current.textContent, language);
|
|
98
98
|
}
|
|
99
|
+
elementRef.current.innerHTML = runHighlight(elementRef.current.textContent, language);
|
|
99
100
|
}
|
|
100
101
|
}, onkeydown: ev => {
|
|
101
102
|
if (ev.keyCode === 9) {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { JWTDecryptOptions, JWTDecryptResult, JWTPayload, JWTVerifyOptions, JWTVerifyResult, ProtectedHeaderParameters } from "jose";
|
|
2
|
+
import { KeyObject } from "node:crypto";
|
|
3
|
+
import { EncryptJWTOptions, JWTSignOptions } from "../types.js";
|
|
4
|
+
/**
|
|
5
|
+
* creates a JWT encrypted token with jose
|
|
6
|
+
*
|
|
7
|
+
* @param payload the payload to encrypt
|
|
8
|
+
* @param secret the secret example. const secret = createSecretKey(process.env.JWT_SECRET, 'utf-8');
|
|
9
|
+
* @param options options like expiratation date, issuer and audience
|
|
10
|
+
* @returns
|
|
11
|
+
*/
|
|
12
|
+
export declare function encryptJWT(payload: JWTPayload, secret: KeyObject, options?: Partial<EncryptJWTOptions>): Promise<string>;
|
|
13
|
+
/**
|
|
14
|
+
* decrypts a JWT token with jose
|
|
15
|
+
* @param jwt the JWT token
|
|
16
|
+
* @param secret the secret example. const secret = createSecretKey(process.env.JWT_SECRET, 'utf-8');
|
|
17
|
+
* @param options options like issuer and audience
|
|
18
|
+
* @returns
|
|
19
|
+
*/
|
|
20
|
+
export declare function decryptJWT<PayloadType = JWTPayload>(jwt: string, secret: KeyObject, options?: Partial<JWTDecryptOptions>): Promise<JWTDecryptResult<PayloadType>>;
|
|
21
|
+
/**
|
|
22
|
+
* verify a JWT token with jose
|
|
23
|
+
* @param jwt the JWT token
|
|
24
|
+
* @param secret the secret example. const secret = createSecretKey(process.env.JWT_SECRET, 'utf-8');
|
|
25
|
+
* @param options options like issuer and audience
|
|
26
|
+
* @returns
|
|
27
|
+
*/
|
|
28
|
+
export declare function verifyJWT<PayloadType = JWTPayload>(jwt: string, secret: KeyObject, options?: Partial<JWTVerifyOptions>): Promise<JWTVerifyResult<PayloadType>>;
|
|
29
|
+
/**
|
|
30
|
+
* creates a signed JWT with jose
|
|
31
|
+
*
|
|
32
|
+
* @param payload the payload to encrypt
|
|
33
|
+
* @param secret the secret example. const secret = createSecretKey(process.env.JWT_SECRET, 'utf-8');
|
|
34
|
+
* @param options options like expiratation date, issuer and audience
|
|
35
|
+
* @returns
|
|
36
|
+
*/
|
|
37
|
+
export declare function signJWT(payload: JWTPayload, secret: KeyObject, options?: Partial<JWTSignOptions>): Promise<string>;
|
|
38
|
+
/**
|
|
39
|
+
* decodes a protected header with jose
|
|
40
|
+
* @param token
|
|
41
|
+
* @returns
|
|
42
|
+
*/
|
|
43
|
+
export declare function decodeProtectedHeaderJWT(token: string | object): ProtectedHeaderParameters;
|
|
44
|
+
/**
|
|
45
|
+
* decodes a jwt token
|
|
46
|
+
* @param jwt
|
|
47
|
+
* @returns
|
|
48
|
+
*/
|
|
49
|
+
export declare function decodeJWT<PayloadType = JWTPayload>(jwt: string): PayloadType & JWTPayload;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { EncryptJWT, SignJWT, decodeJwt, decodeProtectedHeader, jwtDecrypt as joseJWTDecrypt, jwtVerify } from "jose";
|
|
2
|
+
/**
|
|
3
|
+
* creates a JWT encrypted token with jose
|
|
4
|
+
*
|
|
5
|
+
* @param payload the payload to encrypt
|
|
6
|
+
* @param secret the secret example. const secret = createSecretKey(process.env.JWT_SECRET, 'utf-8');
|
|
7
|
+
* @param options options like expiratation date, issuer and audience
|
|
8
|
+
* @returns
|
|
9
|
+
*/
|
|
10
|
+
export async function encryptJWT(payload, secret, options) {
|
|
11
|
+
const en = new EncryptJWT(payload)
|
|
12
|
+
.setProtectedHeader({
|
|
13
|
+
alg: options?.alg ? options?.alg : 'dir',
|
|
14
|
+
enc: options?.enc ? options?.enc : 'A128CBC-HS256'
|
|
15
|
+
})
|
|
16
|
+
.setIssuedAt(options?.iat)
|
|
17
|
+
.setIssuer(options?.iss ? options?.iss : 'urn:example:issuer')
|
|
18
|
+
.setAudience(options?.aud ? options?.aud : 'urn:example:audience')
|
|
19
|
+
.setExpirationTime(options?.exp ? options?.exp : '2h');
|
|
20
|
+
return await en.encrypt(secret, options?.options);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* decrypts a JWT token with jose
|
|
24
|
+
* @param jwt the JWT token
|
|
25
|
+
* @param secret the secret example. const secret = createSecretKey(process.env.JWT_SECRET, 'utf-8');
|
|
26
|
+
* @param options options like issuer and audience
|
|
27
|
+
* @returns
|
|
28
|
+
*/
|
|
29
|
+
export async function decryptJWT(jwt, secret, options) {
|
|
30
|
+
return await joseJWTDecrypt(jwt, secret, options);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* verify a JWT token with jose
|
|
34
|
+
* @param jwt the JWT token
|
|
35
|
+
* @param secret the secret example. const secret = createSecretKey(process.env.JWT_SECRET, 'utf-8');
|
|
36
|
+
* @param options options like issuer and audience
|
|
37
|
+
* @returns
|
|
38
|
+
*/
|
|
39
|
+
export async function verifyJWT(jwt, secret, options) {
|
|
40
|
+
return await jwtVerify(jwt, secret, options);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* creates a signed JWT with jose
|
|
44
|
+
*
|
|
45
|
+
* @param payload the payload to encrypt
|
|
46
|
+
* @param secret the secret example. const secret = createSecretKey(process.env.JWT_SECRET, 'utf-8');
|
|
47
|
+
* @param options options like expiratation date, issuer and audience
|
|
48
|
+
* @returns
|
|
49
|
+
*/
|
|
50
|
+
export async function signJWT(payload, secret, options) {
|
|
51
|
+
const sign = new SignJWT(payload)
|
|
52
|
+
.setProtectedHeader({
|
|
53
|
+
alg: options?.alg ? options?.alg : 'HS256',
|
|
54
|
+
})
|
|
55
|
+
.setIssuedAt(options?.iat)
|
|
56
|
+
.setIssuer(options?.iss ? options?.iss : 'urn:example:issuer')
|
|
57
|
+
.setAudience(options?.aud ? options?.aud : 'urn:example:audience')
|
|
58
|
+
.setExpirationTime(options?.exp ? options?.exp : '2h');
|
|
59
|
+
return sign.sign(secret, options?.options);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* decodes a protected header with jose
|
|
63
|
+
* @param token
|
|
64
|
+
* @returns
|
|
65
|
+
*/
|
|
66
|
+
export function decodeProtectedHeaderJWT(token) {
|
|
67
|
+
return decodeProtectedHeader(token);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* decodes a jwt token
|
|
71
|
+
* @param jwt
|
|
72
|
+
* @returns
|
|
73
|
+
*/
|
|
74
|
+
export function decodeJWT(jwt) {
|
|
75
|
+
return decodeJwt(jwt);
|
|
76
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { chmodSync, constants, mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { dirname, extname, join, relative, resolve } from "node:path";
|
|
2
|
+
import { basename, dirname, extname, join, relative, resolve } from "node:path";
|
|
3
3
|
import { cwd, platform } from "node:process";
|
|
4
4
|
import { getAuthConfigPath, getCORSConfigPath, getDBConfigPath, getErrorConfigPath, getMiddlewareConfigPath, getMigrationsPath, getServerConfigPath, getWSConfigPath } from "../common/paths.js";
|
|
5
5
|
import { getAsset } from "../common/assets.js";
|
|
@@ -54,22 +54,22 @@ export async function inflateAppForSea(logger, inflateDir, services) {
|
|
|
54
54
|
})`;
|
|
55
55
|
}).join(",");
|
|
56
56
|
writeFile(logger, join(inflateDir, "sea", "package.json"), `{ "type": "module", "private": true }`);
|
|
57
|
-
writeFile(logger, join(inflateDir, "sea", "app.cjs"), `const {
|
|
57
|
+
writeFile(logger, join(inflateDir, "sea", "app.cjs"), `const { createServerInterface, ServerRequestHandler, WebSocketManager, initGlobals, DBManager, App, LoggerHandler, LogProvider, LocalCache, ClusterCache } = require("./lib.cjs");
|
|
58
58
|
|
|
59
59
|
async function main() {
|
|
60
60
|
const PORT = process.env["PORT"] ? process.env["PORT"] : 8080;
|
|
61
|
-
const
|
|
61
|
+
const loggerProvider = new LogProvider();
|
|
62
62
|
const localCache = new LocalCache();
|
|
63
63
|
const cache = new ClusterCache();
|
|
64
64
|
const webSocketManager = new WebSocketManager();
|
|
65
65
|
const dbManager = new DBManager();
|
|
66
66
|
await initGlobals();
|
|
67
|
-
const serverInterface =
|
|
67
|
+
const serverInterface = createServerInterface({
|
|
68
68
|
cache,
|
|
69
69
|
localCache,
|
|
70
|
-
|
|
70
|
+
loggerProvider,
|
|
71
71
|
wsManager: webSocketManager,
|
|
72
|
-
logger:
|
|
72
|
+
logger: loggerProvider.getLogger("server"),
|
|
73
73
|
dbManager,
|
|
74
74
|
port: PORT
|
|
75
75
|
});
|
|
@@ -118,9 +118,10 @@ ${Object.keys(serviceRouteFileMap)
|
|
|
118
118
|
.map(filePath => serviceRouteFileMap[filePath])
|
|
119
119
|
.filter(data => data.previewMethod === "api")
|
|
120
120
|
.map(data => data.routes.map(r => {
|
|
121
|
-
const rPath =
|
|
121
|
+
const rPath = join(relative(cwd(), dirname(data.filePath)), basename(data.filePath));
|
|
122
122
|
if (rPath) {
|
|
123
|
-
const
|
|
123
|
+
const rPathExt = extname(rPath);
|
|
124
|
+
const apiInflatedPath = join("..", "..", rPath.substring(0, rPath.length - rPathExt.length) + ".js");
|
|
124
125
|
return ` await appendAPIModule(router, "../../${service}/http", "./${apiInflatedPath}", (await import("./${apiInflatedPath}")).default);`;
|
|
125
126
|
}
|
|
126
127
|
else {
|
|
@@ -55,6 +55,7 @@ function createStaticRoute(service, logger, router, dir, file, inflateDir, route
|
|
|
55
55
|
path: normalizePath(path)
|
|
56
56
|
}],
|
|
57
57
|
service,
|
|
58
|
+
filePath: file.filePath,
|
|
58
59
|
previewMethod: "html"
|
|
59
60
|
};
|
|
60
61
|
if (inflateDir) {
|
|
@@ -137,6 +138,7 @@ async function createRouterFromDirectory(server, hotreload, service, logger, dir
|
|
|
137
138
|
routeFileMap[file.filePath] = {
|
|
138
139
|
routes,
|
|
139
140
|
service,
|
|
141
|
+
filePath: file.filePath,
|
|
140
142
|
previewMethod: "api"
|
|
141
143
|
};
|
|
142
144
|
const inflatedCode = inflateDir ? await inflateJSX(file.filePath, {
|
|
@@ -175,6 +177,7 @@ async function createRouterFromDirectory(server, hotreload, service, logger, dir
|
|
|
175
177
|
routeFileMap[file.filePath] = {
|
|
176
178
|
routes,
|
|
177
179
|
service,
|
|
180
|
+
filePath: file.filePath,
|
|
178
181
|
previewMethod: "html"
|
|
179
182
|
};
|
|
180
183
|
for (const r of routes) {
|
|
@@ -228,6 +231,7 @@ async function createRouterFromDirectory(server, hotreload, service, logger, dir
|
|
|
228
231
|
const routes = getRoutes(join("/", dirname(relative(dir, file.filePath))), file.subName + ".html", module.apiOptions);
|
|
229
232
|
routeFileMap[file.filePath] = {
|
|
230
233
|
routes,
|
|
234
|
+
filePath: file.filePath,
|
|
231
235
|
service,
|
|
232
236
|
previewMethod: "html"
|
|
233
237
|
};
|
|
@@ -296,6 +300,7 @@ async function createRouterFromDirectory(server, hotreload, service, logger, dir
|
|
|
296
300
|
method: "GET",
|
|
297
301
|
path
|
|
298
302
|
}],
|
|
303
|
+
filePath: file.filePath,
|
|
299
304
|
service,
|
|
300
305
|
previewMethod: "html"
|
|
301
306
|
};
|
|
@@ -345,6 +350,7 @@ async function createRouterFromDirectory(server, hotreload, service, logger, dir
|
|
|
345
350
|
path
|
|
346
351
|
}],
|
|
347
352
|
service,
|
|
353
|
+
filePath: file.filePath,
|
|
348
354
|
previewMethod: "html"
|
|
349
355
|
};
|
|
350
356
|
if (inflateDir) {
|
|
@@ -402,6 +408,7 @@ async function createRouterFromDirectory(server, hotreload, service, logger, dir
|
|
|
402
408
|
method: "GET",
|
|
403
409
|
path
|
|
404
410
|
}],
|
|
411
|
+
filePath: file.filePath,
|
|
405
412
|
service,
|
|
406
413
|
previewMethod: "html"
|
|
407
414
|
};
|
|
@@ -459,6 +466,7 @@ async function createRouterFromDirectory(server, hotreload, service, logger, dir
|
|
|
459
466
|
path
|
|
460
467
|
}],
|
|
461
468
|
service,
|
|
469
|
+
filePath: file.filePath,
|
|
462
470
|
previewMethod: "html"
|
|
463
471
|
};
|
|
464
472
|
if (inflateDir) {
|
package/build/esm/src/lib.d.ts
CHANGED
|
@@ -8,6 +8,6 @@ export { LogProvider, LogProviderOptions } from "./services/utils/log.js";
|
|
|
8
8
|
export { Miqro, MiqroOptions, ServerRequestHandler } from "./services/app.js";
|
|
9
9
|
export { initGlobals, assertGlobalTampered } from "./services/globals.js";
|
|
10
10
|
export { appendAPIModule } from "./inflate/utils/sea-utils.js";
|
|
11
|
-
export {
|
|
11
|
+
export { createServerInterface, ServerInterfaceImplOptions } from "./services/utils/server-interface.js";
|
|
12
12
|
export { App, LoggerHandler, Router } from "@miqro/core";
|
|
13
13
|
export { migration } from "@miqro/query";
|
package/build/esm/src/lib.js
CHANGED
|
@@ -9,8 +9,8 @@ export { DBManager } from "./services/utils/db-manager.js";
|
|
|
9
9
|
export { LogProvider } from "./services/utils/log.js";
|
|
10
10
|
export { Miqro, ServerRequestHandler } from "./services/app.js";
|
|
11
11
|
export { initGlobals, assertGlobalTampered } from "./services/globals.js";
|
|
12
|
-
export { appendAPIModule } from "./inflate/utils/sea-utils.js";
|
|
13
12
|
//exported for --inflate-sea
|
|
14
|
-
export {
|
|
13
|
+
export { appendAPIModule } from "./inflate/utils/sea-utils.js";
|
|
14
|
+
export { createServerInterface } from "./services/utils/server-interface.js";
|
|
15
15
|
export { App, LoggerHandler, Router } from "@miqro/core";
|
|
16
16
|
export { migration } from "@miqro/query";
|
|
@@ -19,7 +19,7 @@ import { initAssets } from "../common/assets.js";
|
|
|
19
19
|
import { setupExitHandlers } from "../common/exit.js";
|
|
20
20
|
import { inflateDBConfig, inflateDBMigrations } from "../inflate/setup-db.js";
|
|
21
21
|
import { getServicePath } from "../common/paths.js";
|
|
22
|
-
import {
|
|
22
|
+
import { createServerInterface } from "./utils/server-interface.js";
|
|
23
23
|
import { getPORT, importMiqroJSON } from "../common/arguments.js";
|
|
24
24
|
import { createLogProviderOptions } from "./utils/log-transport.js";
|
|
25
25
|
import { createAdminInterface } from "./utils/admin-interface.js";
|
|
@@ -90,6 +90,7 @@ export class Miqro {
|
|
|
90
90
|
this.localCache = new LocalCache(`MiqroApplicationLocalCache[${this.options.name}]`, this.logger);
|
|
91
91
|
this.webSocketManager = new WebSocketManager({
|
|
92
92
|
logger: this.logger,
|
|
93
|
+
loggerProvider: this.loggerProvider,
|
|
93
94
|
name: `MiqroApplicationWebsocketManager[${this.options.name}]`,
|
|
94
95
|
avoidLogSocket: this.options.editor
|
|
95
96
|
});
|
|
@@ -100,11 +101,11 @@ export class Miqro {
|
|
|
100
101
|
loggerProvider: this.loggerProvider,
|
|
101
102
|
logger: this.logger
|
|
102
103
|
});
|
|
103
|
-
this.serverInterface =
|
|
104
|
+
this.serverInterface = createServerInterface({
|
|
104
105
|
cache: this.cache,
|
|
105
|
-
localCache: this.localCache,
|
|
106
106
|
dbManager: this.dbManager,
|
|
107
|
-
|
|
107
|
+
localCache: this.localCache,
|
|
108
|
+
webSocketManager: this.webSocketManager,
|
|
108
109
|
app: this,
|
|
109
110
|
logger: this.logger,
|
|
110
111
|
loggerProvider: this.loggerProvider,
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
//@ts-ignore
|
|
2
2
|
import { ReadBuffer, URLEncodedParser, JSONParser, TextParser, CORS, SessionHandler } from "@miqro/core";
|
|
3
|
+
import cluster from "node:cluster";
|
|
3
4
|
import { strictEqual } from "node:assert";
|
|
4
5
|
import { HTMLEncode } from "@miqro/jsx-node";
|
|
5
6
|
import { createElement as realCreateElement, enableDebugLog, useRuntime, Link, Router, usePathname, Fragment, useEffect, useRef, useState, useQuery, useRefresh, useElement, createContext, useContext } from "@miqro/jsx";
|
|
6
7
|
import { jsx2HTML } from "../common/jsx.js";
|
|
7
8
|
import { inflateMD2HTML } from "../inflate/md.js";
|
|
8
9
|
import { EXIT_CODES } from "../common/constants.js";
|
|
10
|
+
import { ClusterCache, LocalCache } from "../lib.js";
|
|
11
|
+
import { decodeJWT, decodeProtectedHeaderJWT, decryptJWT, encryptJWT, signJWT, verifyJWT } from "../common/jwt.js";
|
|
12
|
+
import { createSecretKey } from "node:crypto";
|
|
13
|
+
import { Parser } from "@miqro/parser";
|
|
9
14
|
/*const globaljsx: any = Object.freeze({
|
|
10
15
|
useContext,
|
|
11
16
|
useRuntime,
|
|
@@ -80,7 +85,46 @@ const globalServer = Object.freeze({
|
|
|
80
85
|
session: SessionHandler
|
|
81
86
|
}),
|
|
82
87
|
encodeHTML: HTMLEncode,
|
|
83
|
-
inflateMDtoHTML: inflateMD2HTML
|
|
88
|
+
inflateMDtoHTML: inflateMD2HTML,
|
|
89
|
+
createSecretKey,
|
|
90
|
+
newParser() {
|
|
91
|
+
return new Parser();
|
|
92
|
+
},
|
|
93
|
+
newClusterCache(name, logger) {
|
|
94
|
+
return new ClusterCache(name, logger);
|
|
95
|
+
},
|
|
96
|
+
newLocalCache(name, logger) {
|
|
97
|
+
return new LocalCache(name, logger);
|
|
98
|
+
},
|
|
99
|
+
getWorkerNumber() {
|
|
100
|
+
return cluster.isPrimary || process.env["CLUSTER_NODE_NUMBER"] === undefined ? 0 : parseInt(process.env["CLUSTER_NODE_NUMBER"], 10);
|
|
101
|
+
},
|
|
102
|
+
getWorkerCount() {
|
|
103
|
+
return cluster.isPrimary || process.env["CLUSTER_NODE_NUMBER"] === undefined || process.env["CLUSTER_COUNT"] === undefined ? 1 : parseInt(process.env["CLUSTER_COUNT"], 10);
|
|
104
|
+
},
|
|
105
|
+
isPrimaryWorker() {
|
|
106
|
+
return cluster.isPrimary || process.env["CLUSTER_NODE_NUMBER"] === "0";
|
|
107
|
+
},
|
|
108
|
+
jwt: {
|
|
109
|
+
decode(jwt) {
|
|
110
|
+
return decodeJWT(jwt);
|
|
111
|
+
},
|
|
112
|
+
decodeProtectedHeader(token) {
|
|
113
|
+
return decodeProtectedHeaderJWT(token);
|
|
114
|
+
},
|
|
115
|
+
decrypt(jwt, secret, options) {
|
|
116
|
+
return decryptJWT(jwt, secret, options);
|
|
117
|
+
},
|
|
118
|
+
encrypt(payload, secret, options) {
|
|
119
|
+
return encryptJWT(payload, secret, options);
|
|
120
|
+
},
|
|
121
|
+
sign(payload, secret, options) {
|
|
122
|
+
return signJWT(payload, secret, options);
|
|
123
|
+
},
|
|
124
|
+
verify(jwt, secret, options) {
|
|
125
|
+
return verifyJWT(jwt, secret, options);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
84
128
|
});
|
|
85
129
|
export function browserJSXGlobals(inFile, jsxPath = false, useExport = true) {
|
|
86
130
|
const PRE = `import { enableDebugLog, useRuntime, Link, usePathname, createContext, useContext, useElement, useRefresh, useQuery, define, Router, useState, useEffect, useRef, createElement, Fragment } from "${jsxPath}";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { WebSocketServer, WebSocketServerOptions } from "@miqro/core";
|
|
1
|
+
import { Logger, WebSocketServer, WebSocketServerOptions } from "@miqro/core";
|
|
2
2
|
import { Serializable } from "node:child_process";
|
|
3
3
|
declare const ClusterWebSocketServer2MessageType = "$$$$ClusterWebSocketServer2Message$$$$$";
|
|
4
4
|
export interface ClusterWebSocketServer2Message {
|
|
@@ -13,9 +13,11 @@ export interface ClusterWebSocketServer2Message {
|
|
|
13
13
|
}
|
|
14
14
|
export declare class ClusterWebSocketServer2 extends WebSocketServer {
|
|
15
15
|
protected name: string;
|
|
16
|
+
path: string;
|
|
17
|
+
logger: Logger | Console;
|
|
16
18
|
remoteClients: Set<string>;
|
|
17
19
|
listener: (data: any) => Promise<void>;
|
|
18
|
-
constructor(name: string, options: WebSocketServerOptions);
|
|
20
|
+
constructor(name: string, path: string, logger: Logger | Console, options: WebSocketServerOptions);
|
|
19
21
|
connect(): void;
|
|
20
22
|
dispose(): void;
|
|
21
23
|
broadcast(payload: string, fromUUID?: string): Promise<void>;
|
|
@@ -2,14 +2,17 @@ import { WebSocketServer } from "@miqro/core";
|
|
|
2
2
|
const ClusterWebSocketServer2MessageType = "$$$$ClusterWebSocketServer2Message$$$$$";
|
|
3
3
|
export class ClusterWebSocketServer2 extends WebSocketServer {
|
|
4
4
|
name;
|
|
5
|
+
path;
|
|
6
|
+
logger;
|
|
5
7
|
remoteClients = new Set();
|
|
6
8
|
listener;
|
|
7
|
-
constructor(name, options) {
|
|
9
|
+
constructor(name, path, logger, options) {
|
|
8
10
|
super({
|
|
9
11
|
...options,
|
|
10
12
|
validate: (req) => {
|
|
11
13
|
if (this.options.maxConnections !== undefined &&
|
|
12
14
|
this.clients.size + this.remoteClients.size >= this.options.maxConnections) {
|
|
15
|
+
this.logger?.warn("[%s] max web socket connection reached! connection refused from [%s]", req.uuid, req.socket.remoteAddress);
|
|
13
16
|
return false;
|
|
14
17
|
}
|
|
15
18
|
else {
|
|
@@ -27,6 +30,8 @@ export class ClusterWebSocketServer2 extends WebSocketServer {
|
|
|
27
30
|
errorMessage: error.message
|
|
28
31
|
});
|
|
29
32
|
}
|
|
33
|
+
this.logger?.error("[%s] error from (%s) error [%s]", req.uuid, req.req.socket.remoteAddress, error);
|
|
34
|
+
this.logger?.error(error);
|
|
30
35
|
if (options.onError) {
|
|
31
36
|
options.onError(req, error);
|
|
32
37
|
}
|
|
@@ -41,6 +46,7 @@ export class ClusterWebSocketServer2 extends WebSocketServer {
|
|
|
41
46
|
clientUUID: req.uuid
|
|
42
47
|
});
|
|
43
48
|
}
|
|
49
|
+
this.logger?.log("[%s] new web socket connection from (%s)", req.uuid, req.req.socket.remoteAddress);
|
|
44
50
|
if (options.onConnection) {
|
|
45
51
|
options.onConnection(req);
|
|
46
52
|
}
|
|
@@ -55,12 +61,15 @@ export class ClusterWebSocketServer2 extends WebSocketServer {
|
|
|
55
61
|
clientUUID: req.uuid
|
|
56
62
|
});
|
|
57
63
|
}
|
|
64
|
+
this.logger?.log("[%s] [%s] web socket disconnection from (%s)", req.uuid, this.path, req.req.socket.remoteAddress);
|
|
58
65
|
if (options.onDisconnect) {
|
|
59
66
|
options.onDisconnect(req);
|
|
60
67
|
}
|
|
61
68
|
}
|
|
62
69
|
});
|
|
63
70
|
this.name = name;
|
|
71
|
+
this.path = path;
|
|
72
|
+
this.logger = logger;
|
|
64
73
|
this.listener = async (data) => {
|
|
65
74
|
try {
|
|
66
75
|
const msg = data;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { CacheInterface, MigrateOptions, NamedMigration, ServerInterface } from "../../types.js";
|
|
1
|
+
import { Logger } from "@miqro/core";
|
|
2
|
+
import { CacheInterface, ServerInterface } from "../../types.js";
|
|
4
3
|
import { DBManager } from "./db-manager.js";
|
|
5
4
|
import { Miqro } from "../app.js";
|
|
6
5
|
import { WebSocketManager } from "./websocketmanager.js";
|
|
@@ -9,35 +8,10 @@ export interface ServerInterfaceImplOptions {
|
|
|
9
8
|
cache: CacheInterface;
|
|
10
9
|
localCache: CacheInterface;
|
|
11
10
|
dbManager: DBManager;
|
|
12
|
-
|
|
11
|
+
webSocketManager: WebSocketManager;
|
|
13
12
|
logger?: Logger;
|
|
14
13
|
app?: Miqro;
|
|
15
14
|
port?: string;
|
|
16
15
|
loggerProvider?: LogProvider;
|
|
17
16
|
}
|
|
18
|
-
export declare
|
|
19
|
-
cache: CacheInterface;
|
|
20
|
-
localCache: CacheInterface;
|
|
21
|
-
logger?: Logger;
|
|
22
|
-
port?: string;
|
|
23
|
-
db: {
|
|
24
|
-
get(name: string): Database | null;
|
|
25
|
-
getMigrations(): NamedMigration[];
|
|
26
|
-
migrate(options: MigrateOptions): Promise<void>;
|
|
27
|
-
};
|
|
28
|
-
ws: {
|
|
29
|
-
get(path: string): WebSocketServer | undefined;
|
|
30
|
-
disconnectAll(path: string): void;
|
|
31
|
-
};
|
|
32
|
-
loggerProvider?: LogProvider;
|
|
33
|
-
openBrowser: (path: string) => void;
|
|
34
|
-
constructor(options: ServerInterfaceImplOptions);
|
|
35
|
-
getWorkerNumber(): number;
|
|
36
|
-
getWorkerCount(): number;
|
|
37
|
-
isPrimaryWorker(): boolean;
|
|
38
|
-
getLogger(identifier: string, options?: {
|
|
39
|
-
level?: any;
|
|
40
|
-
transports?: any[];
|
|
41
|
-
formatter?: any;
|
|
42
|
-
}): Logger;
|
|
43
|
-
}
|
|
17
|
+
export declare function createServerInterface(options: ServerInterfaceImplOptions): ServerInterface;
|