wok-server 0.1.1 → 0.1.4
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
package/dist/mvc/handler/json.js
CHANGED
|
@@ -20,7 +20,12 @@ function createJsonHandler(opts) {
|
|
|
20
20
|
if (opts.validation) {
|
|
21
21
|
// 切换语言
|
|
22
22
|
(0, i18n_1.getI18n)().switchByRequest(exchange.request.headers);
|
|
23
|
-
|
|
23
|
+
if (typeof opts.validation === 'function') {
|
|
24
|
+
(0, validation_1.validate)(body, opts.validation());
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
(0, validation_1.validate)(body, opts.validation);
|
|
28
|
+
}
|
|
24
29
|
}
|
|
25
30
|
const res = await opts.handle(body, exchange);
|
|
26
31
|
if (!res) {
|
package/dist/mvc/index.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.stopWebServer = exports.startWebServer = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const fs_1 = require("fs");
|
|
6
|
+
const promises_1 = require("fs/promises");
|
|
6
7
|
const http_1 = require("http");
|
|
7
8
|
const os_1 = require("os");
|
|
8
9
|
const path_1 = require("path");
|
|
@@ -73,7 +74,7 @@ async function handleRouter(exchange, routers, staticSettings) {
|
|
|
73
74
|
const router = routers[path];
|
|
74
75
|
if (!router) {
|
|
75
76
|
// 路由找不不到,尝试静态文件
|
|
76
|
-
if (staticSettings.length) {
|
|
77
|
+
if ((exchange.request.method || '').toLowerCase() === 'get' && staticSettings.length) {
|
|
77
78
|
await handleStatic(exchange, routers, path, staticSettings);
|
|
78
79
|
}
|
|
79
80
|
else {
|
|
@@ -123,15 +124,15 @@ async function handleStatic(exchange, routers, path, staticSettings) {
|
|
|
123
124
|
respond404(exchange, routers, path);
|
|
124
125
|
return;
|
|
125
126
|
}
|
|
126
|
-
const
|
|
127
|
+
const statRes = await (0, promises_1.stat)(fullPath);
|
|
127
128
|
// 目录,寻找 index.html
|
|
128
|
-
if (
|
|
129
|
+
if (statRes.isDirectory()) {
|
|
129
130
|
const indexPath = (0, path_1.resolve)(fullPath, 'index.html');
|
|
130
131
|
if (!(0, fs_1.existsSync)(indexPath)) {
|
|
131
132
|
respond404(exchange, routers, path);
|
|
132
133
|
return;
|
|
133
134
|
}
|
|
134
|
-
const indexStat = (0,
|
|
135
|
+
const indexStat = await (0, promises_1.stat)(indexPath);
|
|
135
136
|
if (!indexStat.isFile()) {
|
|
136
137
|
respond404(exchange, routers, path);
|
|
137
138
|
return;
|
|
@@ -144,7 +145,7 @@ async function handleStatic(exchange, routers, path, staticSettings) {
|
|
|
144
145
|
return;
|
|
145
146
|
}
|
|
146
147
|
// 文件直接渲染
|
|
147
|
-
if (
|
|
148
|
+
if (statRes.isFile()) {
|
|
148
149
|
// Cache-Control
|
|
149
150
|
if (matchedSetting.cacheAge >= 0) {
|
|
150
151
|
exchange.response.setHeader('Cache-Control', matchedSetting.cacheAge === 0 ? 'no-store' : `max-age=${matchedSetting.cacheAge}`);
|
|
@@ -210,8 +211,8 @@ async function startWebServer(opts) {
|
|
|
210
211
|
if (!(0, fs_1.existsSync)(dir)) {
|
|
211
212
|
throw new Error(`Static file configuration error,path ${dir} does not exist,config dir:${setting.dir}`);
|
|
212
213
|
}
|
|
213
|
-
const
|
|
214
|
-
if (!
|
|
214
|
+
const statRes = await (0, promises_1.stat)(dir);
|
|
215
|
+
if (!statRes.isDirectory()) {
|
|
215
216
|
throw new Error(`Static file configuration error,path ${dir} is not a directory,config dir:${setting.dir}`);
|
|
216
217
|
}
|
|
217
218
|
let finalPath = path.startsWith('/') ? path : '/' + path;
|
|
@@ -243,6 +244,7 @@ async function startWebServer(opts) {
|
|
|
243
244
|
interceptors.push(...opts.interceptors);
|
|
244
245
|
}
|
|
245
246
|
SERVER = (0, http_1.createServer)((req, res) => {
|
|
247
|
+
res.setHeader('Server', 'Wok Server');
|
|
246
248
|
res.on('error', error => {
|
|
247
249
|
// 如果响应流发生错误,只能把信息记录下来
|
|
248
250
|
(0, log_1.getLogger)().error(`Response Error:${req.url}`, error);
|
|
@@ -266,7 +268,7 @@ async function startWebServer(opts) {
|
|
|
266
268
|
await new Promise((resolve, reject) => {
|
|
267
269
|
server.on('error', e => {
|
|
268
270
|
if (e.code === 'EADDRINUSE') {
|
|
269
|
-
reject(
|
|
271
|
+
reject(`Port ${config_1.config.port} is already in use.`);
|
|
270
272
|
}
|
|
271
273
|
else {
|
|
272
274
|
reject(e);
|
package/dist/mvc/render/file.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.renderFile = void 0;
|
|
4
4
|
const fs_1 = require("fs");
|
|
5
|
+
const promises_1 = require("fs/promises");
|
|
5
6
|
const json_1 = require("./json");
|
|
6
7
|
const path_1 = require("path");
|
|
7
8
|
/**
|
|
@@ -96,7 +97,7 @@ function decideContentType(fileName) {
|
|
|
96
97
|
*/
|
|
97
98
|
async function renderFile(request, response, filePath, download = false) {
|
|
98
99
|
if (!(0, fs_1.existsSync)(filePath)) {
|
|
99
|
-
(0, json_1.renderError)(response, '
|
|
100
|
+
(0, json_1.renderError)(response, 'Cannot find file.', 404);
|
|
100
101
|
return;
|
|
101
102
|
}
|
|
102
103
|
const fileName = (0, path_1.basename)(filePath);
|
|
@@ -118,10 +119,30 @@ async function renderFile(request, response, filePath, download = false) {
|
|
|
118
119
|
else if (contentType) {
|
|
119
120
|
response.setHeader('Content-Type', contentType);
|
|
120
121
|
}
|
|
122
|
+
const statRes = await (0, promises_1.stat)(filePath);
|
|
123
|
+
// 支持 If-Modified-Since
|
|
124
|
+
// 由于只是简单的文件映射,没有 etag,不能支持 If-None-Match
|
|
125
|
+
// 缓存校验只能支持时间的比对,修改时间是文件系统本来就有的
|
|
126
|
+
if (request.headers['if-modified-since']) {
|
|
127
|
+
const modifiedSince = new Date(request.headers['if-modified-since']);
|
|
128
|
+
// 判定日期是否有效
|
|
129
|
+
if (modifiedSince instanceof Date && !isNaN(modifiedSince.getTime())) {
|
|
130
|
+
// 比较更改日期,只精确到秒, UTC 格式只精确到秒,但是 mtime 是包含毫秒的
|
|
131
|
+
const { mtime } = statRes;
|
|
132
|
+
mtime.setMilliseconds(0);
|
|
133
|
+
if (modifiedSince >= mtime) {
|
|
134
|
+
response.statusCode = 304;
|
|
135
|
+
response.setHeader('Last-Modified', statRes.mtime.toUTCString());
|
|
136
|
+
response.end();
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
121
141
|
// 支持 Range
|
|
122
142
|
// https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Range
|
|
123
143
|
const rangeHeader = request.headers['range'];
|
|
124
144
|
if (!rangeHeader) {
|
|
145
|
+
response.setHeader('Last-Modified', statRes.mtime.toUTCString());
|
|
125
146
|
return streamFile(filePath, response);
|
|
126
147
|
}
|
|
127
148
|
// 解析,range 示例:bytes=200-1000, 2000-6576, 19000-
|
|
@@ -141,23 +162,22 @@ async function renderFile(request, response, filePath, download = false) {
|
|
|
141
162
|
let start = strs[0] ? parseInt(strs[0], 10) : NaN;
|
|
142
163
|
let end = strs[1] ? parseInt(strs[1], 10) : NaN;
|
|
143
164
|
// 解析文件
|
|
144
|
-
const stat = (0, fs_1.statSync)(filePath);
|
|
145
165
|
if (isNaN(start) || start < 0) {
|
|
146
166
|
// 范围不合法,返回 416
|
|
147
167
|
(0, json_1.renderError)(response, `Range not satisfiable,start is ${start}`, 416);
|
|
148
168
|
return;
|
|
149
169
|
}
|
|
150
170
|
if (isNaN(end)) {
|
|
151
|
-
end =
|
|
171
|
+
end = statRes.size - 1;
|
|
152
172
|
}
|
|
153
|
-
else if (end >
|
|
173
|
+
else if (end > statRes.size - 1) {
|
|
154
174
|
// 范围不合法,返回 416
|
|
155
|
-
(0, json_1.renderError)(response, `Range not satisfiable,end must not be greater than ${
|
|
175
|
+
(0, json_1.renderError)(response, `Range not satisfiable,end must not be greater than ${statRes.size - 1}`, 416);
|
|
156
176
|
return;
|
|
157
177
|
}
|
|
158
178
|
// 注:Range 和 Content-Range 还有 createReadStream 中的字节范围,都是前后全包含的
|
|
159
179
|
// Content-Range: bytes 42-1233/1234
|
|
160
|
-
response.setHeader('Content-Range', `bytes ${start}-${end}/${
|
|
180
|
+
response.setHeader('Content-Range', `bytes ${start}-${end}/${statRes.size}`);
|
|
161
181
|
return streamFile(filePath, response, { start, end });
|
|
162
182
|
}
|
|
163
183
|
exports.renderFile = renderFile;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MysqlTxSession = exports.BaseMysqlManager = exports.MysqlCriteria = exports.MysqlManager = void 0;
|
|
4
|
+
const exception_1 = require("../exception");
|
|
4
5
|
const base_1 = require("./base");
|
|
5
6
|
Object.defineProperty(exports, "BaseMysqlManager", { enumerable: true, get: function () { return base_1.BaseMysqlManager; } });
|
|
6
7
|
const tx_1 = require("./tx");
|
|
7
8
|
Object.defineProperty(exports, "MysqlTxSession", { enumerable: true, get: function () { return tx_1.MysqlTxSession; } });
|
|
8
|
-
const utils_1 = require("./utils");
|
|
9
9
|
const tx_strict_1 = require("./tx-strict");
|
|
10
|
-
const
|
|
10
|
+
const utils_1 = require("./utils");
|
|
11
11
|
/**
|
|
12
12
|
* mysql 管理器,封装数据库操作,提供方便使用的实体类操作方法.
|
|
13
13
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wok-server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"packageManager": "pnpm@8.9.0",
|
|
5
5
|
"description": "一个基于 NodeJs 和 TypeScript 的后端框架,轻量级、克制、简洁。A lightweight, restrained, and concise backend framework based on Node.js and TypeScript.",
|
|
6
6
|
"scripts": {
|
|
@@ -12,7 +12,7 @@ export declare function createJsonHandler<REQ, RES = void>(opts: {
|
|
|
12
12
|
/**
|
|
13
13
|
* 校验信息,可选,用于检查请求信息.对于一些特殊情况,无法使用校验器的,可以在 handle 中继续处理.
|
|
14
14
|
*/
|
|
15
|
-
validation?: ValidationOpts<REQ
|
|
15
|
+
validation?: ValidationOpts<REQ> | (() => ValidationOpts<REQ>);
|
|
16
16
|
/**
|
|
17
17
|
* 处理请求.
|
|
18
18
|
* @param body 正文内容
|