wok-server 0.1.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/LICENSE +21 -0
- package/README.md +47 -0
- package/dist/cache/cache.js +94 -0
- package/dist/cache/config.js +19 -0
- package/dist/cache/index.js +27 -0
- package/dist/cache/purge-task.js +56 -0
- package/dist/cache/stat.js +47 -0
- package/dist/config/convert.js +36 -0
- package/dist/config/exception.js +14 -0
- package/dist/config/index.js +67 -0
- package/dist/http-client/index.js +132 -0
- package/dist/i18n/ar.js +17 -0
- package/dist/i18n/de.js +17 -0
- package/dist/i18n/en-us.js +17 -0
- package/dist/i18n/es.js +17 -0
- package/dist/i18n/fr.js +17 -0
- package/dist/i18n/i18n.js +231 -0
- package/dist/i18n/index.js +52 -0
- package/dist/i18n/ja.js +17 -0
- package/dist/i18n/ko.js +17 -0
- package/dist/i18n/msg.js +2 -0
- package/dist/i18n/pt.js +17 -0
- package/dist/i18n/ru.js +17 -0
- package/dist/i18n/tag.js +18 -0
- package/dist/i18n/zh-HK.js +17 -0
- package/dist/i18n/zh-TW.js +17 -0
- package/dist/i18n/zh-cn.js +17 -0
- package/dist/index.js +13 -0
- package/dist/log/config.js +28 -0
- package/dist/log/date.js +21 -0
- package/dist/log/file.js +79 -0
- package/dist/log/index.js +109 -0
- package/dist/log/level.js +39 -0
- package/dist/log/store.js +16 -0
- package/dist/mongodb/collection.js +2 -0
- package/dist/mongodb/config.js +34 -0
- package/dist/mongodb/doc.js +2 -0
- package/dist/mongodb/exception.js +14 -0
- package/dist/mongodb/index.js +58 -0
- package/dist/mongodb/manager/base.js +563 -0
- package/dist/mongodb/manager/index.js +63 -0
- package/dist/mongodb/manager/tx-strict.js +84 -0
- package/dist/mongodb/manager/tx.js +30 -0
- package/dist/mongodb/migration.js +52 -0
- package/dist/mvc/access-log.js +31 -0
- package/dist/mvc/config.js +20 -0
- package/dist/mvc/exchange.js +113 -0
- package/dist/mvc/handler/index.js +6 -0
- package/dist/mvc/handler/json.js +33 -0
- package/dist/mvc/handler/restful.js +35 -0
- package/dist/mvc/handler/upload.js +33 -0
- package/dist/mvc/index.js +316 -0
- package/dist/mvc/interceptor.js +2 -0
- package/dist/mvc/query.js +43 -0
- package/dist/mvc/render/file.js +177 -0
- package/dist/mvc/render/html/html.js +90 -0
- package/dist/mvc/render/html/index.js +18 -0
- package/dist/mvc/render/html/style.js +2 -0
- package/dist/mvc/render/index.js +7 -0
- package/dist/mvc/render/json.js +26 -0
- package/dist/mvc/render/text.js +16 -0
- package/dist/mvc/router.js +2 -0
- package/dist/mysql/config.js +49 -0
- package/dist/mysql/exception.js +14 -0
- package/dist/mysql/index.js +85 -0
- package/dist/mysql/manager/base.js +233 -0
- package/dist/mysql/manager/index.js +107 -0
- package/dist/mysql/manager/ops/count.js +20 -0
- package/dist/mysql/manager/ops/criteria.js +326 -0
- package/dist/mysql/manager/ops/delete.js +65 -0
- package/dist/mysql/manager/ops/exist.js +26 -0
- package/dist/mysql/manager/ops/find.js +111 -0
- package/dist/mysql/manager/ops/index.js +14 -0
- package/dist/mysql/manager/ops/insert.js +101 -0
- package/dist/mysql/manager/ops/modify.js +10 -0
- package/dist/mysql/manager/ops/paginate.js +23 -0
- package/dist/mysql/manager/ops/query.js +9 -0
- package/dist/mysql/manager/ops/update.js +201 -0
- package/dist/mysql/manager/tx-strict.js +98 -0
- package/dist/mysql/manager/tx.js +30 -0
- package/dist/mysql/manager/utils.js +56 -0
- package/dist/mysql/migration.js +136 -0
- package/dist/mysql/table-info.js +8 -0
- package/dist/task/daily.js +58 -0
- package/dist/task/fixed-delay.js +33 -0
- package/dist/task/fixed-rate.js +37 -0
- package/dist/task/index.js +9 -0
- package/dist/task/task.js +39 -0
- package/dist/validation/exception.js +44 -0
- package/dist/validation/index.js +29 -0
- package/dist/validation/validator/array.js +38 -0
- package/dist/validation/validator/enum.js +28 -0
- package/dist/validation/validator/index.js +14 -0
- package/dist/validation/validator/length.js +40 -0
- package/dist/validation/validator/max-length.js +35 -0
- package/dist/validation/validator/max.js +29 -0
- package/dist/validation/validator/min-length.js +33 -0
- package/dist/validation/validator/min.js +29 -0
- package/dist/validation/validator/not-blank.js +33 -0
- package/dist/validation/validator/not-null.js +21 -0
- package/dist/validation/validator/plain-obj.js +32 -0
- package/dist/validation/validator/regexp.js +30 -0
- package/documentation/en/index.md +1 -0
- package/documentation/zh-cn/cache.md +59 -0
- package/documentation/zh-cn/config.md +68 -0
- package/documentation/zh-cn/http-client.md +33 -0
- package/documentation/zh-cn/i18n.md +154 -0
- package/documentation/zh-cn/index.md +25 -0
- package/documentation/zh-cn/log.md +40 -0
- package/documentation/zh-cn/mongodb.md +262 -0
- package/documentation/zh-cn/mvc.md +430 -0
- package/documentation/zh-cn/mysql.md +389 -0
- package/documentation/zh-cn/task.md +50 -0
- package/documentation/zh-cn/test.md +57 -0
- package/documentation/zh-cn/validate.md +125 -0
- package/package.json +46 -0
- package/types/cache/cache.d.ts +52 -0
- package/types/cache/config.d.ts +32 -0
- package/types/cache/index.d.ts +2 -0
- package/types/cache/purge-task.d.ts +11 -0
- package/types/cache/stat.d.ts +26 -0
- package/types/config/convert.d.ts +6 -0
- package/types/config/exception.d.ts +7 -0
- package/types/config/index.d.ts +15 -0
- package/types/http-client/index.d.ts +71 -0
- package/types/i18n/ar.d.ts +2 -0
- package/types/i18n/de.d.ts +2 -0
- package/types/i18n/en-us.d.ts +2 -0
- package/types/i18n/es.d.ts +2 -0
- package/types/i18n/fr.d.ts +2 -0
- package/types/i18n/i18n.d.ts +102 -0
- package/types/i18n/index.d.ts +9 -0
- package/types/i18n/ja.d.ts +2 -0
- package/types/i18n/ko.d.ts +2 -0
- package/types/i18n/msg.d.ts +50 -0
- package/types/i18n/pt.d.ts +2 -0
- package/types/i18n/ru.d.ts +2 -0
- package/types/i18n/tag.d.ts +11 -0
- package/types/i18n/zh-HK.d.ts +2 -0
- package/types/i18n/zh-TW.d.ts +2 -0
- package/types/i18n/zh-cn.d.ts +2 -0
- package/types/index.d.ts +10 -0
- package/types/log/config.d.ts +27 -0
- package/types/log/date.d.ts +2 -0
- package/types/log/file.d.ts +5 -0
- package/types/log/index.d.ts +34 -0
- package/types/log/level.d.ts +15 -0
- package/types/log/store.d.ts +12 -0
- package/types/mongodb/collection.d.ts +25 -0
- package/types/mongodb/config.d.ts +45 -0
- package/types/mongodb/doc.d.ts +11 -0
- package/types/mongodb/exception.d.ts +7 -0
- package/types/mongodb/index.d.ts +29 -0
- package/types/mongodb/manager/base.d.ts +188 -0
- package/types/mongodb/manager/index.d.ts +38 -0
- package/types/mongodb/manager/tx-strict.d.ts +41 -0
- package/types/mongodb/manager/tx.d.ts +21 -0
- package/types/mongodb/migration.d.ts +12 -0
- package/types/mvc/access-log.d.ts +7 -0
- package/types/mvc/config.d.ts +30 -0
- package/types/mvc/exchange.d.ts +72 -0
- package/types/mvc/handler/index.d.ts +3 -0
- package/types/mvc/handler/json.d.ts +23 -0
- package/types/mvc/handler/restful.d.ts +11 -0
- package/types/mvc/handler/upload.d.ts +40 -0
- package/types/mvc/index.d.ts +49 -0
- package/types/mvc/interceptor.d.ts +11 -0
- package/types/mvc/query.d.ts +13 -0
- package/types/mvc/render/file.d.ts +10 -0
- package/types/mvc/render/html/html.d.ts +98 -0
- package/types/mvc/render/html/index.d.ts +11 -0
- package/types/mvc/render/html/style.d.ts +1201 -0
- package/types/mvc/render/index.d.ts +4 -0
- package/types/mvc/render/json.d.ts +17 -0
- package/types/mvc/render/text.d.ts +10 -0
- package/types/mvc/router.d.ts +11 -0
- package/types/mysql/config.d.ts +86 -0
- package/types/mysql/exception.d.ts +7 -0
- package/types/mysql/index.d.ts +16 -0
- package/types/mysql/manager/base.d.ts +158 -0
- package/types/mysql/manager/index.d.ts +36 -0
- package/types/mysql/manager/ops/count.d.ts +13 -0
- package/types/mysql/manager/ops/criteria.d.ts +120 -0
- package/types/mysql/manager/ops/delete.d.ts +46 -0
- package/types/mysql/manager/ops/exist.d.ts +6 -0
- package/types/mysql/manager/ops/find.d.ts +66 -0
- package/types/mysql/manager/ops/index.d.ts +10 -0
- package/types/mysql/manager/ops/insert.d.ts +18 -0
- package/types/mysql/manager/ops/modify.d.ts +3 -0
- package/types/mysql/manager/ops/paginate.d.ts +36 -0
- package/types/mysql/manager/ops/query.d.ts +3 -0
- package/types/mysql/manager/ops/update.d.ts +70 -0
- package/types/mysql/manager/tx-strict.d.ts +34 -0
- package/types/mysql/manager/tx.d.ts +15 -0
- package/types/mysql/manager/utils.d.ts +17 -0
- package/types/mysql/migration.d.ts +8 -0
- package/types/mysql/table-info.d.ts +36 -0
- package/types/task/daily.d.ts +15 -0
- package/types/task/fixed-delay.d.ts +8 -0
- package/types/task/fixed-rate.d.ts +8 -0
- package/types/task/index.d.ts +4 -0
- package/types/task/task.d.ts +33 -0
- package/types/validation/exception.d.ts +43 -0
- package/types/validation/index.d.ts +32 -0
- package/types/validation/validator/array.d.ts +5 -0
- package/types/validation/validator/enum.d.ts +8 -0
- package/types/validation/validator/index.d.ts +11 -0
- package/types/validation/validator/length.d.ts +10 -0
- package/types/validation/validator/max-length.d.ts +8 -0
- package/types/validation/validator/max.d.ts +7 -0
- package/types/validation/validator/min-length.d.ts +6 -0
- package/types/validation/validator/min.d.ts +7 -0
- package/types/validation/validator/not-blank.d.ts +7 -0
- package/types/validation/validator/not-null.d.ts +6 -0
- package/types/validation/validator/plain-obj.d.ts +7 -0
- package/types/validation/validator/regexp.d.ts +8 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Peak Tai
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# node 后端框架
|
|
2
|
+
|
|
3
|
+
一个简洁易用的 Nodejs 后端框架,使用 Typescript 开发,有完整的类型约束和定义,注释详细,文档齐全,支持国际化。
|
|
4
|
+
|
|
5
|
+
主要功能:配置,日志,国际化,校验,缓存,MVC,mysql,mongodb ,周期任务 。
|
|
6
|
+
|
|
7
|
+
[查看文档](./documentation/zh-cn/index.md)
|
|
8
|
+
|
|
9
|
+
## 优点
|
|
10
|
+
|
|
11
|
+
- 学习成本较低,函数式为主,少量面向对象,未使用代理和装饰器等增强技术
|
|
12
|
+
- 功能简单,使用方便,保持克制,不引入太多特性
|
|
13
|
+
- 轻量封装,最大限度兼容已有生态,支持集成第三方 http 相关的库来处理请求
|
|
14
|
+
- 支持国际化,自带多种语言的支持,国际化内容支持扩展
|
|
15
|
+
- 有完整的类型约束和定义,结合 IDE 的代码补全功能,开发效率高
|
|
16
|
+
- 注释详细,文档就在代码中,方法和参数都有详细说明,可在 IDE 的辅助下方便查看
|
|
17
|
+
|
|
18
|
+
## Hello world
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
startWebServer({
|
|
22
|
+
routers: {
|
|
23
|
+
'/': async exchange => exchange.respondText('Hello world !')
|
|
24
|
+
}
|
|
25
|
+
}).catch(e => {
|
|
26
|
+
console.error('Start server failed', e)
|
|
27
|
+
})
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
上面的代码启动了 web 服务,访问路径 `http://localhost:8080` 将输出文本 “Hello world !”。
|
|
31
|
+
|
|
32
|
+
相关的设置可以通过环境变量来修改,查看[完整文档](./documentation/zh-cn/index.md)了解细节。
|
|
33
|
+
|
|
34
|
+
## 一些问题的说明
|
|
35
|
+
|
|
36
|
+
### 为什么直接集成依赖库
|
|
37
|
+
|
|
38
|
+
项目中对 mysql 客户端和 mongodb 的驱动直接打包集成了,也没有将这两个组件
|
|
39
|
+
单独拆分成一个独立的包以供按需引入。这样做是为了方便,不需要安装那么多包,安装的包多了
|
|
40
|
+
之后,还有可能需要解决依赖冲突问题,找到版本匹配的包,使用和维护都麻烦。对于后端程序来说,
|
|
41
|
+
体积大一些问题也不大。
|
|
42
|
+
|
|
43
|
+
### 为什么部分可选功能需要第三方库,而又没有集成
|
|
44
|
+
|
|
45
|
+
对于 wesocket 和文件上传等功能,框架没有实现,而是需要使用者引入第三方库,框架没有集成这些库。
|
|
46
|
+
这些库是基于 Nodejs 内置的模块 http,不用担心与框架的兼容性问题,框架只要保持支持即可,
|
|
47
|
+
也可以充分利用已有的生态,不需要专门为框架编写扩展。
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Cache = void 0;
|
|
4
|
+
const config_1 = require("./config");
|
|
5
|
+
class Cache {
|
|
6
|
+
valueMap;
|
|
7
|
+
stat;
|
|
8
|
+
/**
|
|
9
|
+
* promise 表,作用是处理异步并发问题,如果有相同的 key 同时请求,保证异步的 provider 只执行一次
|
|
10
|
+
*/
|
|
11
|
+
promiseMap = new Map();
|
|
12
|
+
constructor(valueMap, stat) {
|
|
13
|
+
this.valueMap = valueMap;
|
|
14
|
+
this.stat = stat;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 放入缓存
|
|
18
|
+
* @param key
|
|
19
|
+
* @param val
|
|
20
|
+
* @param expiresInSeconds
|
|
21
|
+
*/
|
|
22
|
+
put(key, val, expiresInSeconds) {
|
|
23
|
+
const finalExpiresInSeconds = typeof expiresInSeconds === 'number' ? expiresInSeconds : config_1.config.defaultExpireInSeconds;
|
|
24
|
+
this.valueMap.set(key, {
|
|
25
|
+
val,
|
|
26
|
+
expireAt: new Date().getTime() + finalExpiresInSeconds * 1000
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* 获取缓存值
|
|
31
|
+
* @param key
|
|
32
|
+
* @returns
|
|
33
|
+
*/
|
|
34
|
+
get(key) {
|
|
35
|
+
const content = this.valueMap.get(key);
|
|
36
|
+
if (!content) {
|
|
37
|
+
this.stat.addGet(false);
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
if (content.expireAt < new Date().getTime()) {
|
|
41
|
+
this.stat.addGet(false);
|
|
42
|
+
this.valueMap.delete(key);
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
this.stat.addGet(true);
|
|
46
|
+
return content.val;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 清除所有缓存
|
|
50
|
+
*/
|
|
51
|
+
clear() {
|
|
52
|
+
this.valueMap.clear();
|
|
53
|
+
this.stat.clear();
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 删除.
|
|
57
|
+
* @param key
|
|
58
|
+
*/
|
|
59
|
+
remove(key) {
|
|
60
|
+
this.valueMap.delete(key);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 在缓存值不存在时计算缓存的值,然后放入并返回.
|
|
64
|
+
* @param key
|
|
65
|
+
* @param provider
|
|
66
|
+
* @param expiresInSeconds
|
|
67
|
+
*/
|
|
68
|
+
async computeIfAbsent(key, provider, expiresInSeconds) {
|
|
69
|
+
const content = this.valueMap.get(key);
|
|
70
|
+
if (content && content.expireAt >= new Date().getTime()) {
|
|
71
|
+
this.stat.addGet(true);
|
|
72
|
+
return content.val;
|
|
73
|
+
}
|
|
74
|
+
this.stat.addGet(false);
|
|
75
|
+
// 如果已经在处理中,则直接返回 promise
|
|
76
|
+
const ep = this.promiseMap.get(key);
|
|
77
|
+
if (ep) {
|
|
78
|
+
return ep;
|
|
79
|
+
}
|
|
80
|
+
// 创建新的异步流程
|
|
81
|
+
const promise = Promise.resolve().then(async () => {
|
|
82
|
+
const finalExpireInSeconds = typeof expiresInSeconds === 'number' ? expiresInSeconds : config_1.config.defaultExpireInSeconds;
|
|
83
|
+
// 计算值
|
|
84
|
+
const res = provider();
|
|
85
|
+
const val = res instanceof Promise ? await res : res;
|
|
86
|
+
this.put(key, val, finalExpireInSeconds);
|
|
87
|
+
this.promiseMap.delete(key);
|
|
88
|
+
return val;
|
|
89
|
+
});
|
|
90
|
+
this.promiseMap.set(key, promise);
|
|
91
|
+
return promise;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
exports.Cache = Cache;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.config = void 0;
|
|
4
|
+
const config_1 = require("../config");
|
|
5
|
+
const validation_1 = require("../validation");
|
|
6
|
+
const ENV_PREFIX = 'CACHE';
|
|
7
|
+
exports.config = (0, config_1.registerConfig)({
|
|
8
|
+
defaultExpireInSeconds: 60,
|
|
9
|
+
statTaskEnabled: false,
|
|
10
|
+
statInterval: 300,
|
|
11
|
+
maxElements: 1024,
|
|
12
|
+
cleaningInterval: 60
|
|
13
|
+
}, ENV_PREFIX, {
|
|
14
|
+
defaultExpireInSeconds: [(0, validation_1.notNull)(), (0, validation_1.min)(1), (0, validation_1.max)(3600)],
|
|
15
|
+
statTaskEnabled: [(0, validation_1.notNull)()],
|
|
16
|
+
statInterval: [(0, validation_1.notNull)(), (0, validation_1.min)(1), (0, validation_1.max)(3600 * 24)],
|
|
17
|
+
maxElements: [(0, validation_1.notNull)(), (0, validation_1.min)(1), (0, validation_1.max)(Number.MAX_VALUE)],
|
|
18
|
+
cleaningInterval: [(0, validation_1.notNull)(), (0, validation_1.min)(1), (0, validation_1.max)(3600)]
|
|
19
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getCache = void 0;
|
|
4
|
+
const task_1 = require("../task");
|
|
5
|
+
const cache_1 = require("./cache");
|
|
6
|
+
const config_1 = require("./config");
|
|
7
|
+
const purge_task_1 = require("./purge-task");
|
|
8
|
+
const stat_1 = require("./stat");
|
|
9
|
+
const valueMap = new Map();
|
|
10
|
+
const stat = new stat_1.CacheStat(valueMap);
|
|
11
|
+
const cache = new cache_1.Cache(valueMap, stat);
|
|
12
|
+
// 清理任务
|
|
13
|
+
(0, task_1.scheduleWithFixedDelay)(config_1.config.cleaningInterval, config_1.config.cleaningInterval, new purge_task_1.PurgeTask(valueMap));
|
|
14
|
+
// 统计任务
|
|
15
|
+
if (config_1.config.statTaskEnabled) {
|
|
16
|
+
(0, task_1.scheduleWithFixedDelay)(config_1.config.statInterval, config_1.config.statInterval, {
|
|
17
|
+
name: 'cache statistics',
|
|
18
|
+
async run() {
|
|
19
|
+
stat.log();
|
|
20
|
+
stat.clear();
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function getCache() {
|
|
25
|
+
return cache;
|
|
26
|
+
}
|
|
27
|
+
exports.getCache = getCache;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PurgeTask = void 0;
|
|
4
|
+
const log_1 = require("../log");
|
|
5
|
+
const config_1 = require("./config");
|
|
6
|
+
/**
|
|
7
|
+
* 缓存清理任务
|
|
8
|
+
*/
|
|
9
|
+
class PurgeTask {
|
|
10
|
+
valueMap;
|
|
11
|
+
name = 'cache purge';
|
|
12
|
+
constructor(valueMap) {
|
|
13
|
+
this.valueMap = valueMap;
|
|
14
|
+
}
|
|
15
|
+
async run() {
|
|
16
|
+
let removeCount = 0;
|
|
17
|
+
for (const entry of this.valueMap.entries()) {
|
|
18
|
+
const [key, value] = entry;
|
|
19
|
+
if (value.expireAt < new Date().getTime()) {
|
|
20
|
+
this.valueMap.delete(key);
|
|
21
|
+
removeCount++;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
if (removeCount > 0) {
|
|
25
|
+
if (removeCount > 1) {
|
|
26
|
+
(0, log_1.getLogger)().info(`A total of ${removeCount} expired cache records have been cleared.`);
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
(0, log_1.getLogger)().info(`A total of ${removeCount} expired cache record has been cleared.`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// 如果过期的都清理掉,但是元素总数仍然超出,则删除多余元素,删除是从头开始删除的
|
|
33
|
+
// 看上去是按put顺序清理最早的,实际上随机的,重复 set 相同的 key,key 的位置是不会变的,不保证 key 的顺序
|
|
34
|
+
// 所以,缓存是随机驱逐的
|
|
35
|
+
// 目前没有考虑支持其它的策略,因为需要额外记录信息,清理的逻辑也可能更复杂
|
|
36
|
+
// nodejs 是单线程模式的,规模上去后,可能需要执行较长的时间带来阻塞
|
|
37
|
+
if (this.valueMap.size > config_1.config.maxElements) {
|
|
38
|
+
let diff = this.valueMap.size - config_1.config.maxElements;
|
|
39
|
+
let evictedCount = 0;
|
|
40
|
+
for (const key of this.valueMap.keys()) {
|
|
41
|
+
this.valueMap.delete(key);
|
|
42
|
+
evictedCount++;
|
|
43
|
+
if (evictedCount >= diff) {
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (evictedCount > 1) {
|
|
48
|
+
(0, log_1.getLogger)().info(`A total of ${evictedCount} cache records have been evicted.`);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
(0, log_1.getLogger)().info(`A total of ${evictedCount} cache record has been evicted.`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.PurgeTask = PurgeTask;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CacheStat = void 0;
|
|
4
|
+
const log_1 = require("../log");
|
|
5
|
+
const date_1 = require("../log/date");
|
|
6
|
+
const config_1 = require("./config");
|
|
7
|
+
/**
|
|
8
|
+
* 缓存统计.
|
|
9
|
+
*/
|
|
10
|
+
class CacheStat {
|
|
11
|
+
valueMap;
|
|
12
|
+
/**
|
|
13
|
+
* 开始统计时间
|
|
14
|
+
*/
|
|
15
|
+
start;
|
|
16
|
+
totalGet = 0;
|
|
17
|
+
totalHit = 0;
|
|
18
|
+
constructor(valueMap) {
|
|
19
|
+
this.valueMap = valueMap;
|
|
20
|
+
this.start = new Date();
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 添加 get 次数
|
|
24
|
+
* @param hit 是否命中
|
|
25
|
+
*/
|
|
26
|
+
addGet(hit) {
|
|
27
|
+
this.totalGet++;
|
|
28
|
+
if (hit) {
|
|
29
|
+
this.totalHit++;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 清空统计信息,重新开始统计.
|
|
34
|
+
*/
|
|
35
|
+
clear() {
|
|
36
|
+
this.start = new Date();
|
|
37
|
+
this.totalGet = 0;
|
|
38
|
+
this.totalHit = 0;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* 输出日志
|
|
42
|
+
*/
|
|
43
|
+
log() {
|
|
44
|
+
(0, log_1.getLogger)().info(`Cache statistics,time window :${(0, date_1.formatDateTime)(this.start)} - now, hit :${this.totalHit}/${this.totalGet},capacity:${this.valueMap.size}/${config_1.config.maxElements}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
exports.CacheStat = CacheStat;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.convert = void 0;
|
|
4
|
+
const exception_1 = require("./exception");
|
|
5
|
+
/**
|
|
6
|
+
* 转换值.
|
|
7
|
+
* @param val
|
|
8
|
+
* @param defaultVal
|
|
9
|
+
*/
|
|
10
|
+
function convert(val, defaultVal) {
|
|
11
|
+
if (typeof defaultVal === 'string') {
|
|
12
|
+
return val;
|
|
13
|
+
}
|
|
14
|
+
else if (typeof defaultVal === 'number') {
|
|
15
|
+
const num = parseFloat(val);
|
|
16
|
+
if (isNaN(num)) {
|
|
17
|
+
throw new exception_1.ConfigException(`Unable to convert value to number :${val}`);
|
|
18
|
+
}
|
|
19
|
+
return num;
|
|
20
|
+
}
|
|
21
|
+
else if (typeof defaultVal === 'boolean') {
|
|
22
|
+
if (val === 'true') {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
else if (val === 'false') {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
throw new exception_1.ConfigException(`Cannot convert value to a boolean type:${val}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
throw new exception_1.ConfigException(`Unsupported conversion type :${typeof defaultVal}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.convert = convert;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConfigException = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* 配置异常.
|
|
6
|
+
*/
|
|
7
|
+
class ConfigException extends Error {
|
|
8
|
+
message;
|
|
9
|
+
constructor(message) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.message = message;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
exports.ConfigException = ConfigException;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerConfig = exports.getConfig = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const dotenv_1 = require("dotenv");
|
|
6
|
+
const validation_1 = require("../validation");
|
|
7
|
+
const convert_1 = require("./convert");
|
|
8
|
+
const exception_1 = require("./exception");
|
|
9
|
+
// 初始化 .env 文件
|
|
10
|
+
(0, dotenv_1.config)();
|
|
11
|
+
/**
|
|
12
|
+
* 环境变量配置表.
|
|
13
|
+
*/
|
|
14
|
+
const configEnvMap = new Map();
|
|
15
|
+
/**
|
|
16
|
+
* 获取配置
|
|
17
|
+
* @param envPrefix
|
|
18
|
+
*/
|
|
19
|
+
function getConfig(envPrefix) {
|
|
20
|
+
return configEnvMap.get(envPrefix);
|
|
21
|
+
}
|
|
22
|
+
exports.getConfig = getConfig;
|
|
23
|
+
/**
|
|
24
|
+
* 注册配置信息.
|
|
25
|
+
* @param defaultConfig 默认值, 模块会根据默认值来映射环境变量,默认值所有的属性都不能是 undefined,否则无法映射.
|
|
26
|
+
* @param envPrefix 环境变量前缀.
|
|
27
|
+
* @param validation 校验规则,如果有值,初始化的时候会对配置进行校验
|
|
28
|
+
* @returns 映射了环境变量后的配置
|
|
29
|
+
*/
|
|
30
|
+
function registerConfig(defaultConfig, envPrefix, validation) {
|
|
31
|
+
if (configEnvMap.has(envPrefix)) {
|
|
32
|
+
throw new exception_1.ConfigException(`The prefix "${envPrefix}" has already been registered`);
|
|
33
|
+
}
|
|
34
|
+
// 环境变量匹配
|
|
35
|
+
for (const propName in defaultConfig) {
|
|
36
|
+
const defaultVal = defaultConfig[propName];
|
|
37
|
+
const envName = buildEnvName(envPrefix, propName);
|
|
38
|
+
const envVal = process.env[envName];
|
|
39
|
+
console.log(`[CONFIG]prefix:${envPrefix},env variable:${envName} ,value:${envVal},mapping property:${propName}`);
|
|
40
|
+
if (!envVal) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const finalVal = (0, convert_1.convert)(envVal, defaultVal);
|
|
44
|
+
defaultConfig[propName] = finalVal;
|
|
45
|
+
}
|
|
46
|
+
// 校验
|
|
47
|
+
if (validation) {
|
|
48
|
+
try {
|
|
49
|
+
(0, validation_1.validate)(defaultConfig, validation);
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
console.error(e);
|
|
53
|
+
throw new exception_1.ConfigException(`Error in verifying configuration information, configuration prefix:${envPrefix}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
configEnvMap.set(envPrefix, defaultConfig);
|
|
57
|
+
return defaultConfig;
|
|
58
|
+
}
|
|
59
|
+
exports.registerConfig = registerConfig;
|
|
60
|
+
function buildEnvName(envPrefix, propName) {
|
|
61
|
+
let part2 = propName.replace(/[A-Z]+/g, subStr => `_${subStr}`);
|
|
62
|
+
if (part2.startsWith('_')) {
|
|
63
|
+
part2 = part2.substring(1);
|
|
64
|
+
}
|
|
65
|
+
return `${envPrefix.toUpperCase()}_${part2.toUpperCase()}`;
|
|
66
|
+
}
|
|
67
|
+
tslib_1.__exportStar(require("./exception"), exports);
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getJson = exports.postJson = exports.doRequest = void 0;
|
|
4
|
+
const http_1 = require("http");
|
|
5
|
+
const https_1 = require("https");
|
|
6
|
+
const url_1 = require("url");
|
|
7
|
+
/**
|
|
8
|
+
* 发送 http 请求.
|
|
9
|
+
* @param opts
|
|
10
|
+
* @returns
|
|
11
|
+
*/
|
|
12
|
+
function doRequest(opts) {
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
const url = new url_1.URL(opts.url);
|
|
15
|
+
// query
|
|
16
|
+
if (opts.query) {
|
|
17
|
+
Object.entries(opts.query).forEach(entry => {
|
|
18
|
+
const [key, val] = entry;
|
|
19
|
+
if (typeof val === 'string') {
|
|
20
|
+
url.searchParams.append(key, val);
|
|
21
|
+
}
|
|
22
|
+
else if (Array.isArray(val)) {
|
|
23
|
+
val.forEach(v => url.searchParams.append(key, v));
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
throw new Error(`The value is neither of string nor string[] type:${val}`);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const request = url.protocol === 'https:' ? https_1.request : http_1.request;
|
|
31
|
+
const req = request(url, {
|
|
32
|
+
method: opts.method,
|
|
33
|
+
headers: opts.headers,
|
|
34
|
+
timeout: opts.timeout && opts.timeout > 0 ? opts.timeout : 5000,
|
|
35
|
+
rejectUnauthorized: false
|
|
36
|
+
}, res => {
|
|
37
|
+
const chunks = [];
|
|
38
|
+
res.on('error', reject);
|
|
39
|
+
res.on('data', chunk => chunks.push(chunk));
|
|
40
|
+
res.on('end', () => {
|
|
41
|
+
// 重定向支持
|
|
42
|
+
if (opts.followRedirect) {
|
|
43
|
+
// 301、302、303、307、308
|
|
44
|
+
if (res.statusCode === 301 ||
|
|
45
|
+
res.statusCode === 302 ||
|
|
46
|
+
res.statusCode === 303 ||
|
|
47
|
+
res.statusCode === 307 ||
|
|
48
|
+
res.statusCode === 308) {
|
|
49
|
+
if (res.headers.location) {
|
|
50
|
+
// 重新请求,但是重定向标记改为 false ,只重定向一次,防止无限重定向造成死循环
|
|
51
|
+
resolve(doRequest(Object.assign({}, opts, { url: res.headers.location, followRedirect: false })));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const buffer = Buffer.concat(chunks);
|
|
57
|
+
resolve({
|
|
58
|
+
status: res.statusCode || 0,
|
|
59
|
+
body: buffer,
|
|
60
|
+
headers: res.headers
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
req.on('error', reject);
|
|
65
|
+
req.on('timeout', () => reject('Request timeout'));
|
|
66
|
+
if (opts.body) {
|
|
67
|
+
req.write(opts.body);
|
|
68
|
+
}
|
|
69
|
+
req.end();
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
exports.doRequest = doRequest;
|
|
73
|
+
/**
|
|
74
|
+
* 发送 json 格式的 post 请求,body 是未序列化的普通对象,表示要发送的请求数据.
|
|
75
|
+
* @param opts
|
|
76
|
+
*/
|
|
77
|
+
async function postJson(opts) {
|
|
78
|
+
const headers = Object.assign({}, opts.headers || {}, {
|
|
79
|
+
'Content-Type': 'application/json; charset=utf-8'
|
|
80
|
+
});
|
|
81
|
+
const res = await doRequest({
|
|
82
|
+
url: opts.url,
|
|
83
|
+
query: opts.query,
|
|
84
|
+
headers: headers,
|
|
85
|
+
timeout: opts.timeout,
|
|
86
|
+
method: 'POST',
|
|
87
|
+
body: JSON.stringify(opts.body),
|
|
88
|
+
followRedirect: false
|
|
89
|
+
});
|
|
90
|
+
if (res.status !== 200) {
|
|
91
|
+
if (res.body.byteLength < 1024) {
|
|
92
|
+
throw new Error(`Request failed,status code:${res.status},url:${opts.url},body:${res.body.toString('utf-8')}`);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
throw new Error(`Request failed,status code:${res.status},url:${opts.url}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const bodyText = res.body.toString('utf8');
|
|
99
|
+
if (!bodyText) {
|
|
100
|
+
return {};
|
|
101
|
+
}
|
|
102
|
+
return JSON.parse(bodyText);
|
|
103
|
+
}
|
|
104
|
+
exports.postJson = postJson;
|
|
105
|
+
/**
|
|
106
|
+
* get 请求获取 json 格式数据.
|
|
107
|
+
* @param opts
|
|
108
|
+
*/
|
|
109
|
+
async function getJson(opts) {
|
|
110
|
+
const res = await doRequest({
|
|
111
|
+
url: opts.url,
|
|
112
|
+
query: opts.query,
|
|
113
|
+
headers: opts.headers,
|
|
114
|
+
timeout: opts.timeout,
|
|
115
|
+
method: 'GET',
|
|
116
|
+
followRedirect: true
|
|
117
|
+
});
|
|
118
|
+
if (res.status !== 200) {
|
|
119
|
+
if (res.body.byteLength < 1024) {
|
|
120
|
+
throw new Error(`Request failed,status code:${res.status},url:${opts.url},body:${res.body.toString('utf-8')}`);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
throw new Error(`Request failed,status code:${res.status},url:${opts.url}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const bodyText = res.body.toString('utf8');
|
|
127
|
+
if (!bodyText) {
|
|
128
|
+
return {};
|
|
129
|
+
}
|
|
130
|
+
return JSON.parse(bodyText);
|
|
131
|
+
}
|
|
132
|
+
exports.getJson = getJson;
|
package/dist/i18n/ar.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ar = void 0;
|
|
4
|
+
exports.ar = {
|
|
5
|
+
'validate-err-array': 'القيمة لست مصفوفة',
|
|
6
|
+
'validate-err-enum': 'يجب أن تكون القيمة واحدة من {}',
|
|
7
|
+
'validate-err-numer': 'القيمة ليست رقمًا',
|
|
8
|
+
'validate-err-max': 'يجب ألا تكون أكبر من {}',
|
|
9
|
+
'validate-err-min': 'يجب ألا تكون أصغر من {}',
|
|
10
|
+
'validate-err-empty': 'لا يمكن أن يكونارغًا',
|
|
11
|
+
'validate-err-string': 'القيمة ليست من نوع سلسلة الحروف',
|
|
12
|
+
'validate-err-incorrect-format': 'التنسيق غير صحيح',
|
|
13
|
+
'validate-err-no-length': 'تعذر العثور على خاصية "length"',
|
|
14
|
+
'validate-err-length-not-number': 'خاصية "length" ليست رقما',
|
|
15
|
+
'validate-err-min-length': 'لا يجوز أن يكن الطول أقل من {}',
|
|
16
|
+
'validate-err-max-length': 'لا يجوز أن يكون الطول أكبر من {}'
|
|
17
|
+
};
|
package/dist/i18n/de.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.de = void 0;
|
|
4
|
+
exports.de = {
|
|
5
|
+
'validate-err-array': 'Der Wert ist kein Array',
|
|
6
|
+
'validate-err-enum': 'Der Wert muss einer von sein',
|
|
7
|
+
'validate-err-numer': 'Der Wert ist keine Zahl',
|
|
8
|
+
'validate-err-max': 'Darf nicht größer als {} sein',
|
|
9
|
+
'validate-err-min': 'f nicht kleiner als {} sein',
|
|
10
|
+
'validate-err-empty': 'Darf nicht leer',
|
|
11
|
+
'validate-err-string': 'Der Wert ist kein Zeichenketten-Typ',
|
|
12
|
+
'validate-err-incorrect-format': 'Das Format ist nicht korrekt',
|
|
13
|
+
'validate-err-no-length': 'length kann nicht gefunden werden',
|
|
14
|
+
'validate-err-length-not-number': 'Eigenschaft length ist keine zahl',
|
|
15
|
+
'validate-err-min-length': 'Die L darf nicht kleiner als {} sein',
|
|
16
|
+
'validate-err-max-length': 'Die Länge nicht größer als {} sein'
|
|
17
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.enUS = void 0;
|
|
4
|
+
exports.enUS = {
|
|
5
|
+
'validate-err-array': 'Value is not a array type.',
|
|
6
|
+
'validate-err-enum': ' Value must be one of [{}].',
|
|
7
|
+
'validate-err-numer': 'Value is not a number type.',
|
|
8
|
+
'validate-err-max': 'Not greater than {}.',
|
|
9
|
+
'validate-err-min': 'Not less than {}.',
|
|
10
|
+
'validate-err-empty': 'Cannot be empty.',
|
|
11
|
+
'validate-err-string': 'Value is not a string type.',
|
|
12
|
+
'validate-err-incorrect-format': 'Incorrect format.',
|
|
13
|
+
'validate-err-no-length': 'Unable to find length field.',
|
|
14
|
+
'validate-err-length-not-number': 'Length field is not a number type.',
|
|
15
|
+
'validate-err-min-length': 'The length should not be less than {}.',
|
|
16
|
+
'validate-err-max-length': 'The length must not exceed {}.'
|
|
17
|
+
};
|
package/dist/i18n/es.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.es = void 0;
|
|
4
|
+
exports.es = {
|
|
5
|
+
'validate-err-array': 'El valor no es un arreglo',
|
|
6
|
+
'validate-err-enum': 'El valor debe ser uno de {}',
|
|
7
|
+
'validate-err-numer': 'El valor no es un número',
|
|
8
|
+
'validate-err-max': 'No debe ser mayor que {}',
|
|
9
|
+
'validate-err-min': 'No debe ser menor que {}',
|
|
10
|
+
'validate-err-empty': 'No puede estar vacío',
|
|
11
|
+
'validate-err-string': 'El valor no es un tipo de cadena',
|
|
12
|
+
'validate-err-incorrect-format': 'El formato no es correcto',
|
|
13
|
+
'validate-err-no-length': 'No se encontró la propiedad de longitud',
|
|
14
|
+
'validate-err-length-not-number': ' propiedad de longitud no es un número',
|
|
15
|
+
'validate-err-min-length': 'La longitud no debe ser menor que {}',
|
|
16
|
+
'validate-err-max-length': 'La longitud no debe ser mayor que'
|
|
17
|
+
};
|
package/dist/i18n/fr.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fr = void 0;
|
|
4
|
+
exports.fr = {
|
|
5
|
+
'validate-err-array': "La valeur n'est pas un tableau",
|
|
6
|
+
'validate-err-enum': "La valeur doit être l'un de {}",
|
|
7
|
+
'validate-err-numer': "La n'est pas un nombre",
|
|
8
|
+
'validate-err-max': 'Ne doit pas supérieur à {}',
|
|
9
|
+
'validate-err-min': 'Ne doit pas être inférieur à {}',
|
|
10
|
+
'validate-err-empty': 'Ne doit pas être vide',
|
|
11
|
+
'validate-err-string': "La valeur n'est pas de type chaîne de caractères",
|
|
12
|
+
'validate-err-incorrect-format': 'Format incorrect',
|
|
13
|
+
'validate-err-no-length': 'Impossible de trouver la propriété "length"',
|
|
14
|
+
'validate-err-length-not-number': `propriété "length" n'est pas un nombre`,
|
|
15
|
+
'validate-err-min-length': 'La longueur ne doit pas être infure {}',
|
|
16
|
+
'validate-err-max-length': 'La longueur ne doit pas être supérieure à {}'
|
|
17
|
+
};
|