kb-server 0.0.1-beta.38 → 0.0.1-beta.39

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 CHANGED
@@ -1,10 +1,10 @@
1
1
  # KB Server
2
2
 
3
- 快速创建一个 Node 服务
3
+ 快速创建一个 `Node` 服务 - 基于 `Express`
4
4
 
5
- 快速创建 API、标准错误码、Server、支持统一鉴权函数(API 级别)、自定义中间件、日志、支持SSE
5
+ 快速创建 `API`、标准错误码、`Server`、支持统一鉴权函数(API 级别)、自定义中间件、日志、支持 `SSE`
6
6
 
7
- ```javascript
7
+ ```typescript
8
8
  import { createServer } from "kb-server";
9
9
  import * as apis from "./apis";
10
10
 
@@ -18,3 +18,27 @@ server.listen(3000);
18
18
  return createServer({ apis });
19
19
  })().then((app) => app.listen(3000));
20
20
  ```
21
+
22
+ ## SSE 支持
23
+
24
+ ```typescript
25
+ import { createServer } from "kb-server";
26
+ import * as apis from "./apis";
27
+ import * as sse from "./sse";
28
+
29
+
30
+ (async () => {
31
+ // 其他的异步操作,例如:初始化数据库
32
+ return createServer({
33
+ apis,
34
+ sse: {
35
+ handlers: sse, // ...SSE处理函数
36
+ },
37
+ authFn: (action, req) => {
38
+ // ...统一鉴权函数
39
+ },
40
+ middlewares: [], // ...中间键列表
41
+ log: true, // ...框架日志
42
+ });
43
+ })().then((app) => app.listen(3000));
44
+ ```
@@ -27,7 +27,7 @@ const packAPI = (apis, options) => {
27
27
  // API 解析
28
28
  const { Action, ...params } = req.body || {};
29
29
  if (log) {
30
- logger_1.logger.log("info", `请求入参:${JSON.stringify(req.body)} - RequestId: ${requestId}`);
30
+ logger_1.logger.info(`请求入参:${JSON.stringify(req.body)} - RequestId: ${requestId}`);
31
31
  }
32
32
  // 接口未定义
33
33
  if (!Action) {
@@ -63,12 +63,12 @@ const packAPI = (apis, options) => {
63
63
  };
64
64
  // 完成响应
65
65
  took = Date.now() - start;
66
- logger_1.logger.log("info", `响应:${JSON.stringify(response)}`);
67
- logger_1.logger.log("info", `耗时:${took} ms - RequestId: ${requestId}`);
66
+ logger_1.logger.info(`响应:${JSON.stringify(response)}`);
67
+ logger_1.logger.info(`耗时:${took} ms - RequestId: ${requestId}`);
68
68
  return res.send(response);
69
69
  }
70
70
  catch (rawError) {
71
- logger_1.logger.log("error", rawError);
71
+ logger_1.logger.error(rawError);
72
72
  // 未知错误
73
73
  let error = new create_errors_1.CommonErrors.InternalError.UnknownError();
74
74
  // 可控错误
@@ -90,8 +90,8 @@ const packAPI = (apis, options) => {
90
90
  };
91
91
  // 完成响应
92
92
  took = Date.now() - start;
93
- logger_1.logger.log("info", `响应:${JSON.stringify(response)}`);
94
- logger_1.logger.log("info", `耗时:${took} ms - RequestId: ${requestId}`);
93
+ logger_1.logger.info(`响应:${JSON.stringify(response)}`);
94
+ logger_1.logger.info(`耗时:${took} ms - RequestId: ${requestId}`);
95
95
  return res.send(response);
96
96
  }
97
97
  };
@@ -1,12 +1,20 @@
1
1
  import { Class } from "utility-types";
2
2
  import { ServerContext } from "./create-api";
3
- import { Session } from "better-sse";
3
+ export type PushHandler = (data: Record<string, any>) => void;
4
+ export type CloseHandler = () => void;
5
+ export type SSEHandlers = {
6
+ /** 数据推送 */
7
+ push: PushHandler;
8
+ /** 关闭函数(调用结束要显式关闭) */
9
+ close: CloseHandler;
10
+ abortController: AbortController;
11
+ };
4
12
  export type API<P, R> = (param: P) => Promise<R>;
5
13
  export type SseExecution<P, R, A> = (
6
14
  /** 请求入参 */
7
15
  params: P,
8
- /** SSE 连接对象 */
9
- session: Session,
16
+ /** SSE相关操作函数 */
17
+ sse: SSEHandlers,
10
18
  /** 请求上下文 */
11
19
  ctx: ServerContext<A>) => Promise<R>;
12
20
  export type AnySseExecution = SseExecution<any, any, any>;
@@ -6,7 +6,7 @@ const class_validator_1 = require("class-validator");
6
6
  const create_errors_1 = require("./create-errors");
7
7
  const create_api_1 = require("./create-api");
8
8
  function createSseAPI(ParamsClass, execution) {
9
- const runtime = async (params, session, ctx) => {
9
+ const runtime = async (params, sse, ctx) => {
10
10
  if (!params) {
11
11
  throw new create_errors_1.CommonErrors.InvalidParameter.EmptyParameter();
12
12
  }
@@ -20,7 +20,7 @@ function createSseAPI(ParamsClass, execution) {
20
20
  throw new create_errors_1.CommonErrors.InvalidParameter.ValidationError(errorMessages.join("\n"));
21
21
  }
22
22
  // 执行函数
23
- return await execution(params, session, ctx);
23
+ return await execution(params, sse, ctx);
24
24
  };
25
25
  return runtime;
26
26
  }
@@ -7,5 +7,5 @@ interface IPackSSEOptions {
7
7
  log?: boolean;
8
8
  }
9
9
  export declare const packSSE: (sseHandlers: SseHandlers, options?: IPackSSEOptions) => express.RequestHandler;
10
- export declare const createSSEMessage: (event: string, message: string) => string;
10
+ export declare const createSSEMsg: (event: string, message: string) => string;
11
11
  export {};
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createSSEMessage = exports.packSSE = void 0;
4
- const better_sse_1 = require("better-sse");
3
+ exports.createSSEMsg = exports.packSSE = void 0;
5
4
  const uuid_1 = require("uuid");
6
5
  const logger_1 = require("../helper/logger");
7
6
  const create_errors_1 = require("./create-errors");
@@ -38,7 +37,7 @@ const packSSE = (sseHandlers, options) => {
38
37
  // API 解析
39
38
  const { Action, ...params } = req.body || {};
40
39
  if (log) {
41
- logger_1.logger.log("info", `请求入参:${JSON.stringify(req.body)} - RequestId: ${requestId}`);
40
+ logger_1.logger.info(`请求入参:${JSON.stringify(req.body)} - RequestId: ${requestId}`);
42
41
  }
43
42
  // 接口未定义
44
43
  if (!Action) {
@@ -63,17 +62,55 @@ const packSSE = (sseHandlers, options) => {
63
62
  if (typeof execution !== "function") {
64
63
  throw new create_errors_1.CommonErrors.ResourceNotFound.APINotFound();
65
64
  }
66
- const session = await (0, better_sse_1.createSession)(req, res);
67
- await execution(params, session, ctx);
68
- // 完成响应
69
- took = Date.now() - start;
70
- logger_1.logger.log("info", `耗时:${took} ms - RequestId: ${requestId}`);
71
- return res.end();
65
+ // 写头
66
+ res.writeHead(200, {
67
+ "Content-Type": "text/event-stream",
68
+ "Cache-Control": "no-cache",
69
+ Connection: "keep-alive",
70
+ });
71
+ const abortController = new AbortController();
72
+ // 连接断开
73
+ let isConnected = true;
74
+ res.on("close", () => {
75
+ isConnected = false;
76
+ abortController.abort();
77
+ // 完成响应
78
+ took = Date.now() - start;
79
+ logger_1.logger.info(`耗时:${took} ms - ${requestId}`);
80
+ return res.end();
81
+ });
82
+ // 推送消息
83
+ const push = (data) => {
84
+ if (!isConnected) {
85
+ logger_1.logger.warning(`连接已关闭: ${requestId}`);
86
+ return;
87
+ }
88
+ const msg = createResponseMsg(data);
89
+ try {
90
+ res.write(msg);
91
+ logger_1.logger.info(`推送数据: ${msg}`);
92
+ }
93
+ catch (error) {
94
+ if (error.code === "EPIPE" || error.code === "ECONNRESET") {
95
+ logger_1.logger.warning(`连接已关闭: ${requestId}`);
96
+ isConnected = false;
97
+ }
98
+ }
99
+ };
100
+ // 主动关闭
101
+ const close = () => {
102
+ logger_1.logger.info(`主动关闭连接: ${requestId}`);
103
+ // 完成响应
104
+ took = Date.now() - start;
105
+ logger_1.logger.info(`耗时:${took} ms - ${requestId}`);
106
+ res.end();
107
+ };
108
+ await execution(params, { push, close, abortController }, ctx);
72
109
  }
73
110
  catch (rawError) {
74
- logger_1.logger.log("error", rawError);
111
+ logger_1.logger.error(rawError);
75
112
  if (!res.headersSent) {
76
- // 写请求头
113
+ // 写头
77
114
  res.writeHead(200, {
78
115
  "Content-Type": "text/event-stream",
79
116
  "Cache-Control": "no-cache",
@@ -90,27 +127,36 @@ const packSSE = (sseHandlers, options) => {
90
127
  if (rawError?.sql) {
91
128
  error = new create_errors_1.CommonErrors.InternalError.DatabaseError();
92
129
  }
93
- const response = (0, exports.createSSEMessage)("error", JSON.stringify({
130
+ const errResponse = {
94
131
  Response: {
95
132
  Error: { Code: error.code, Message: error.message },
96
133
  RequestId: requestId,
97
134
  },
98
- }));
135
+ };
136
+ const response = (0, exports.createSSEMsg)("error", JSON.stringify(errResponse));
99
137
  // 完成响应
100
138
  took = Date.now() - start;
101
- logger_1.logger.log("info", `发送消息:\n${response}`);
102
- logger_1.logger.log("info", `耗时:${took} ms - RequestId: ${requestId}`);
103
- res.write(response);
104
- return res.end();
139
+ logger_1.logger.info(`发送消息:\n${response}`);
140
+ logger_1.logger.info(`耗时:${took} ms - ${requestId}`);
141
+ res.write(response, () => res.end());
105
142
  }
106
143
  };
107
144
  };
108
145
  exports.packSSE = packSSE;
109
- const createSSEMessage = (event, message) => {
146
+ const createSSEMsg = (event, message) => {
110
147
  const id = (0, short_id_1.shortId)();
111
148
  const idStr = `id: ${id}\n`;
112
149
  const eventStr = `event: ${event}\n`;
113
150
  const dataStr = `data: ${message}\n\n`;
114
- return idStr + eventStr + dataStr;
151
+ return `${idStr}${eventStr}${dataStr}`;
152
+ };
153
+ exports.createSSEMsg = createSSEMsg;
154
+ const createResponseMsg = (data, requestId) => {
155
+ const msg = {
156
+ Response: {
157
+ RequestId: requestId || (0, uuid_1.v4)(),
158
+ Data: data,
159
+ },
160
+ };
161
+ return JSON.stringify(msg);
115
162
  };
116
- exports.createSSEMessage = createSSEMessage;
@@ -1,6 +1,5 @@
1
1
  export declare const logger: {
2
- log: typeof log;
2
+ info: (message: unknown) => void;
3
+ error: (message: unknown) => void;
4
+ warning: (message: unknown) => void;
3
5
  };
4
- type LogLevel = "info" | "error" | "warning";
5
- declare function log(level: LogLevel, message: unknown): void;
6
- export {};
@@ -4,14 +4,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.logger = void 0;
7
- const moment_1 = __importDefault(require("moment"));
8
- exports.logger = { log };
9
- function log(level, message) {
10
- const logTime = (0, moment_1.default)().format(`YYYY-MM-DD HH:mm:ss`);
7
+ const dayjs_1 = __importDefault(require("dayjs"));
8
+ const log = (level, message) => {
9
+ const logTime = (0, dayjs_1.default)().format(`YYYY-MM-DD HH:mm:ss`);
11
10
  if (typeof message === "string") {
12
11
  console.log(`[${level}] - [${logTime}] - ${message}`);
13
12
  }
14
13
  else {
15
14
  console.log(`[${level}] - [${logTime}] - `, message);
16
15
  }
17
- }
16
+ };
17
+ const info = (message) => log("info", message);
18
+ const error = (message) => log("error", message);
19
+ const warning = (message) => log("warning", message);
20
+ exports.logger = { info, error, warning };
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "kb-server",
3
- "version": "0.0.1-beta.38",
3
+ "version": "0.0.1-beta.39",
4
4
  "description": "A fast server for Node.JS,made by express.",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
7
7
  "build": "rm -rf ./dist && tsc",
8
- "test": "echo \"Error: no test specified\" && exit 1"
8
+ "release": "npm run build && npm publish"
9
9
  },
10
10
  "keywords": [
11
11
  "2kb",
@@ -25,9 +25,9 @@
25
25
  "better-sse": "^0.13.0",
26
26
  "class-transformer": "^0.5.1",
27
27
  "class-validator": "^0.14.1",
28
+ "dayjs": "^1.11.13",
28
29
  "express": "^4.21.1",
29
30
  "is-plain-object": "^5.0.0",
30
- "moment": "^2.30.1",
31
31
  "nanoid": "^3.3.9",
32
32
  "utility-types": "^3.11.0",
33
33
  "uuid": "^11.0.3"