kb-server 0.0.1-beta.19 → 0.0.1-beta.20
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/README.md +1 -1
- package/dist/common/create-server.d.ts +8 -0
- package/dist/common/create-server.js +5 -1
- package/dist/common/sse-middleware.d.ts +25 -0
- package/dist/common/sse-middleware.js +124 -0
- package/dist/helper/short-id.d.ts +1 -0
- package/dist/helper/short-id.js +7 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import express from "express";
|
|
2
2
|
import { AuthFunction } from "./api-middleware";
|
|
3
3
|
import { APIs } from "./create-api";
|
|
4
|
+
import { SSEHandlers } from "./sse-middleware";
|
|
4
5
|
export interface ICreateServerParams {
|
|
5
6
|
/**
|
|
6
7
|
* API列表
|
|
7
8
|
*/
|
|
8
9
|
apis: APIs;
|
|
10
|
+
/**
|
|
11
|
+
* SSE配置
|
|
12
|
+
*/
|
|
13
|
+
sse?: {
|
|
14
|
+
handlers: SSEHandlers;
|
|
15
|
+
route?: string;
|
|
16
|
+
};
|
|
9
17
|
/**
|
|
10
18
|
* 鉴权函数
|
|
11
19
|
*
|
|
@@ -26,18 +26,22 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
26
26
|
exports.createServer = void 0;
|
|
27
27
|
const express_1 = __importStar(require("express"));
|
|
28
28
|
const api_middleware_1 = require("./api-middleware");
|
|
29
|
+
const sse_middleware_1 = require("./sse-middleware");
|
|
29
30
|
/**
|
|
30
31
|
* 创建 Server
|
|
31
32
|
*/
|
|
32
33
|
function createServer(params, options) {
|
|
33
|
-
const { apis, authFn, log, middlewares = [] } = params || {};
|
|
34
|
+
const { apis, sse, authFn, log, middlewares = [] } = params || {};
|
|
34
35
|
const { limit = "10mb" } = options || {};
|
|
36
|
+
const { handlers, route } = sse || {};
|
|
35
37
|
const app = (0, express_1.default)();
|
|
36
38
|
// POST 参数获取
|
|
37
39
|
app.use((0, express_1.urlencoded)({ extended: true, limit }));
|
|
38
40
|
app.use((0, express_1.json)({ limit }));
|
|
39
41
|
// 使用自定义中间件
|
|
40
42
|
middlewares.forEach((middleware) => app.use(middleware));
|
|
43
|
+
// 注入SSE
|
|
44
|
+
handlers && app.use((0, sse_middleware_1.packSSE)(handlers, { route }));
|
|
41
45
|
// 注入API
|
|
42
46
|
app.use((0, api_middleware_1.packAPI)(apis, { authFn, log }));
|
|
43
47
|
return app;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import express from "express";
|
|
2
|
+
import { ServerContext } from "./create-api";
|
|
3
|
+
import { AuthFunction } from "./api-middleware";
|
|
4
|
+
export type SseExecution<P, R, A> = (
|
|
5
|
+
/** 请求入参 */
|
|
6
|
+
params: P,
|
|
7
|
+
/** 请求上下文 */
|
|
8
|
+
ctx: ServerContext<A>,
|
|
9
|
+
/**
|
|
10
|
+
* 允许执行的操作
|
|
11
|
+
*/
|
|
12
|
+
operations: {
|
|
13
|
+
/** 发送消息 */
|
|
14
|
+
send: (event: string, message: string) => void;
|
|
15
|
+
}) => Promise<R>;
|
|
16
|
+
export type AnySseExecution = SseExecution<any, any, any>;
|
|
17
|
+
export type SSEHandlers = Record<string, AnySseExecution>;
|
|
18
|
+
interface IPackSSEOptions {
|
|
19
|
+
authFn?: AuthFunction;
|
|
20
|
+
route?: string;
|
|
21
|
+
log?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export declare const packSSE: (sseHandlers: SSEHandlers, options?: IPackSSEOptions) => express.RequestHandler;
|
|
24
|
+
export declare const createSSEMessage: (event: string, message: string) => string;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createSSEMessage = exports.packSSE = void 0;
|
|
4
|
+
const uuid_1 = require("uuid");
|
|
5
|
+
const logger_1 = require("../helper/logger");
|
|
6
|
+
const create_errors_1 = require("./create-errors");
|
|
7
|
+
const short_id_1 = require("../helper/short-id");
|
|
8
|
+
const packSSE = (sseHandlers, options) => {
|
|
9
|
+
const sseMap = new Map(Object.entries(sseHandlers).map(([action, execution]) => [
|
|
10
|
+
action,
|
|
11
|
+
execution,
|
|
12
|
+
]));
|
|
13
|
+
const { authFn, log = true, route = "/sse" } = options || {};
|
|
14
|
+
return async (req, res, next) => {
|
|
15
|
+
const { path } = req;
|
|
16
|
+
// 路径不是SSE的路径
|
|
17
|
+
if (path !== route) {
|
|
18
|
+
next();
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
// 请求开始时间
|
|
22
|
+
const start = Date.now();
|
|
23
|
+
let took = 0;
|
|
24
|
+
// 生成请求ID
|
|
25
|
+
const requestId = (0, uuid_1.v4)();
|
|
26
|
+
// 上下文
|
|
27
|
+
const ctx = {
|
|
28
|
+
RequestId: requestId,
|
|
29
|
+
};
|
|
30
|
+
try {
|
|
31
|
+
// API 解析
|
|
32
|
+
const { Action, ...params } = req.body || {};
|
|
33
|
+
if (log) {
|
|
34
|
+
logger_1.logger.log("info", `请求入参:${JSON.stringify(req.body)} - RequestId: ${requestId}`);
|
|
35
|
+
}
|
|
36
|
+
// 接口未定义
|
|
37
|
+
if (!Action) {
|
|
38
|
+
throw new create_errors_1.CommonErrors.InvalidParameter.EmptyAPIRequest();
|
|
39
|
+
}
|
|
40
|
+
// 处理鉴权函数
|
|
41
|
+
if (authFn !== null && authFn !== undefined) {
|
|
42
|
+
if (typeof authFn !== "function") {
|
|
43
|
+
throw new create_errors_1.CommonErrors.ResourceNotFound.AuthFunctionNotFound();
|
|
44
|
+
}
|
|
45
|
+
const authResult = await authFn(Action, req);
|
|
46
|
+
if (!authResult) {
|
|
47
|
+
throw new create_errors_1.CommonErrors.FailOperation.NoPermission();
|
|
48
|
+
}
|
|
49
|
+
if (typeof authResult !== "boolean") {
|
|
50
|
+
// 把权限信息写入上下文
|
|
51
|
+
ctx.AuthInfo = authResult || {};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// API 处理
|
|
55
|
+
const execution = sseMap.get(Action);
|
|
56
|
+
if (typeof execution !== "function") {
|
|
57
|
+
throw new create_errors_1.CommonErrors.ResourceNotFound.APINotFound();
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 开始处理SSE请求就要统计
|
|
61
|
+
*
|
|
62
|
+
* 请求处理完毕的时间
|
|
63
|
+
*
|
|
64
|
+
* 不要让 API 随意改写 req res 里面的东西
|
|
65
|
+
*
|
|
66
|
+
* 统一管理请求头
|
|
67
|
+
*
|
|
68
|
+
*/
|
|
69
|
+
// 处理SSE
|
|
70
|
+
res.writeHead(200, {
|
|
71
|
+
"Content-Type": "text/event-stream",
|
|
72
|
+
"Cache-Control": "no-cache",
|
|
73
|
+
Connection: "keep-alive",
|
|
74
|
+
});
|
|
75
|
+
const send = (event, message) => {
|
|
76
|
+
const response = (0, exports.createSSEMessage)(event, message);
|
|
77
|
+
res.write(response);
|
|
78
|
+
logger_1.logger.log("info", `发送消息:${response}`);
|
|
79
|
+
};
|
|
80
|
+
await execution(params, ctx, { send });
|
|
81
|
+
// 完成响应
|
|
82
|
+
took = Date.now() - start;
|
|
83
|
+
logger_1.logger.log("info", `耗时:${took} ms - RequestId: ${requestId}`);
|
|
84
|
+
return res.end();
|
|
85
|
+
}
|
|
86
|
+
catch (rawError) {
|
|
87
|
+
logger_1.logger.log("error", rawError);
|
|
88
|
+
// 未知错误
|
|
89
|
+
let error = new create_errors_1.CommonErrors.InternalError.UnknownError();
|
|
90
|
+
// 可控错误
|
|
91
|
+
if (rawError instanceof create_errors_1.BaseError) {
|
|
92
|
+
error = rawError;
|
|
93
|
+
}
|
|
94
|
+
// DB错误
|
|
95
|
+
if (rawError?.sql) {
|
|
96
|
+
error = new create_errors_1.CommonErrors.InternalError.DatabaseError();
|
|
97
|
+
}
|
|
98
|
+
const response = (0, exports.createSSEMessage)("error", JSON.stringify({
|
|
99
|
+
Response: {
|
|
100
|
+
Error: {
|
|
101
|
+
Code: error.code,
|
|
102
|
+
Message: error.message,
|
|
103
|
+
},
|
|
104
|
+
RequestId: requestId,
|
|
105
|
+
},
|
|
106
|
+
}));
|
|
107
|
+
// 完成响应
|
|
108
|
+
took = Date.now() - start;
|
|
109
|
+
logger_1.logger.log("info", `响应:${response}`);
|
|
110
|
+
logger_1.logger.log("info", `耗时:${took} ms - RequestId: ${requestId}`);
|
|
111
|
+
res.write(response);
|
|
112
|
+
return res.end();
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
exports.packSSE = packSSE;
|
|
117
|
+
const createSSEMessage = (event, message) => {
|
|
118
|
+
const id = (0, short_id_1.shortId)();
|
|
119
|
+
const idStr = `id: ${id}\n`;
|
|
120
|
+
const eventStr = `event: ${event}\n`;
|
|
121
|
+
const dataStr = `data: ${message}\n\n`;
|
|
122
|
+
return idStr + eventStr + dataStr;
|
|
123
|
+
};
|
|
124
|
+
exports.createSSEMessage = createSSEMessage;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const shortId: () => string;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.shortId = void 0;
|
|
4
|
+
const nanoid_1 = require("nanoid");
|
|
5
|
+
const nanoid = (0, nanoid_1.customAlphabet)("123456789abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ", 10);
|
|
6
|
+
const shortId = () => nanoid();
|
|
7
|
+
exports.shortId = shortId;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kb-server",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
3
|
+
"version": "0.0.1-beta.20",
|
|
4
4
|
"description": "A fast server for Node.JS,made by express.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"express": "^4.21.1",
|
|
25
25
|
"is-plain-object": "^5.0.0",
|
|
26
26
|
"moment": "^2.30.1",
|
|
27
|
+
"nanoid": "^5.1.3",
|
|
27
28
|
"node-fetch": "^2.7.0",
|
|
28
29
|
"utility-types": "^3.11.0",
|
|
29
30
|
"uuid": "^11.0.3"
|