@maiyunnet/kebab 3.1.20 → 3.2.1

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/index.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * --- 本文件用来定义每个目录实体地址的常量 ---
6
6
  */
7
7
  /** --- 当前系统版本号 --- */
8
- export declare const VER = "3.1.20";
8
+ export declare const VER = "3.2.1";
9
9
  /** --- 框架根目录,以 / 结尾 --- */
10
10
  export declare const ROOT_PATH: string;
11
11
  export declare const LIB_PATH: string;
package/index.js CHANGED
@@ -6,7 +6,7 @@
6
6
  * --- 本文件用来定义每个目录实体地址的常量 ---
7
7
  */
8
8
  /** --- 当前系统版本号 --- */
9
- export const VER = '3.1.20';
9
+ export const VER = '3.2.1';
10
10
  // --- 服务端用的路径 ---
11
11
  const imu = decodeURIComponent(import.meta.url).replace('file://', '').replace(/^\/(\w:)/, '$1');
12
12
  /** --- /xxx/xxx --- */
package/lib/core.d.ts CHANGED
@@ -13,6 +13,7 @@ export declare const globalConfig: kebab.IConfig & {
13
13
  'debug': boolean;
14
14
  'max': number;
15
15
  'hosts': string[];
16
+ 'ind': string[];
16
17
  };
17
18
  /** --- Cookie 设置的选项 --- */
18
19
  export interface ICookieOptions {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maiyunnet/kebab",
3
- "version": "3.1.20",
3
+ "version": "3.2.1",
4
4
  "description": "Simple, easy-to-use, and fully-featured Node.js framework that is ready-to-use out of the box.",
5
5
  "type": "module",
6
6
  "keywords": [
package/sys/child.js CHANGED
@@ -45,6 +45,17 @@ const linkCount = {};
45
45
  async function run() {
46
46
  // --- 加载 全局、vhosts、sni 证书 ---
47
47
  await reload();
48
+ // --- 启动随带的 ind,如果独立运行 ind 则用 --ind 命令启动 ---
49
+ for (const ind of lCore.globalConfig.ind) {
50
+ if (!await lFs.isFile(kebab.IND_CWD + ind + '/index.js')) {
51
+ lCore.display('CHILD IND ERROR', 'IND FILE "' + ind + '" NOT FOUND.');
52
+ continue;
53
+ }
54
+ // --- 载入独立文件入口 ---
55
+ import((!kebab.IND_CWD.startsWith('/') ? '/' : '') + kebab.IND_CWD + ind + '/index.js').catch((e) => {
56
+ lCore.display('CHILD IND ERROR', ind, e);
57
+ });
58
+ }
48
59
  // --- 创建服务器并启动(支持 http2/https/http/websocket) ---
49
60
  http2Server = http2.createSecureServer({
50
61
  // eslint-disable-next-line @typescript-eslint/naming-convention
@@ -203,6 +214,8 @@ async function requestHandler(req, res, https) {
203
214
  timer.timer = setTimeout(timer.callback, timer.timeout);
204
215
  // --- 设置服务器名版本 ---
205
216
  res.setHeader('Server', 'Kebab/' + kebab.VER);
217
+ res.setHeader('expires', 'Mon, 26 Jul 1994 05:00:00 GMT');
218
+ res.setHeader('cache-control', 'no-store');
206
219
  // --- 当前 uri ---
207
220
  let host = req.headers[':authority'];
208
221
  if (host === undefined || typeof host !== 'string') {
package/sys/cmd.js CHANGED
@@ -76,6 +76,7 @@ async function run() {
76
76
  config.debug ??= true;
77
77
  config.max ??= 64;
78
78
  config.hosts ??= [];
79
+ config.ind ??= [];
79
80
  // --- config - set ---
80
81
  config.set ??= {};
81
82
  config.set.timezone ??= 8;
package/sys/ctr.d.ts CHANGED
@@ -128,8 +128,8 @@ export declare class Ctr {
128
128
  * --- WebSocket 下连接被终止后会自动被调用的事件,可重写此方法 ---
129
129
  */
130
130
  onClose(): void | Promise<void>;
131
- /** --- 请求发送开始时调用,返回 false 则框架不会自动获取任何 post 内容(仅会在 middle 内触发) --- */
132
- onReqStart(): boolean | Promise<boolean>;
131
+ /** --- 请求发送开始时调用,返回 -1-流程中断,一般用于代理/反代,0-框架不会自动处理 post,1-自动处理(默认)(仅会在 middle 内触发) --- */
132
+ onReqStart(): number | Promise<number>;
133
133
  /**
134
134
  * --- 获取截止当前时间的总运行时间 ---
135
135
  * @param ms 为 true 为毫秒,否则为秒
package/sys/ctr.js CHANGED
@@ -169,9 +169,9 @@ export class Ctr {
169
169
  onClose() {
170
170
  return;
171
171
  }
172
- /** --- 请求发送开始时调用,返回 false 则框架不会自动获取任何 post 内容(仅会在 middle 内触发) --- */
172
+ /** --- 请求发送开始时调用,返回 -1-流程中断,一般用于代理/反代,0-框架不会自动处理 post,1-自动处理(默认)(仅会在 middle 内触发) --- */
173
173
  onReqStart() {
174
- return true;
174
+ return 1;
175
175
  }
176
176
  /**
177
177
  * --- 获取截止当前时间的总运行时间 ---
package/sys/route.js CHANGED
@@ -31,15 +31,6 @@ export function clearKebabConfigs() {
31
31
  * @param data 传导的数据
32
32
  */
33
33
  export async function run(data) {
34
- // --- 检测 path 是否是静态文件 ---
35
- if (/^(stc\/.*|favicon.\w+?\??.*|apple[\w-]+?\.png\??.*|[\w-]+?\.txt\??.*|[\w-]+?\.html\??.*)/.test(data.path)) {
36
- return false;
37
- }
38
- // --- 根据 res 还是 socket 进行初始化设置 ---
39
- if (data.res) {
40
- data.res.setHeader('expires', 'Mon, 26 Jul 1994 05:00:00 GMT');
41
- data.res.setHeader('cache-control', 'no-store');
42
- }
43
34
  // --- 判断 kebab config 是否已经读取过 ---
44
35
  if (!kebabConfigs[data.rootPath + 'kebab.json']) {
45
36
  const configContent = await lFs.getContent(data.rootPath + 'kebab.json', 'utf8');
@@ -80,6 +71,7 @@ export async function run(data) {
80
71
  // --- 加载 kebab config ---
81
72
  const config = {};
82
73
  const configData = kebabConfigs[data.rootPath + 'kebab.json'];
74
+ // --- 合并 configData 到 config ---
83
75
  for (const name in configData) {
84
76
  config[name] = configData[name];
85
77
  }
@@ -123,9 +115,11 @@ export async function run(data) {
123
115
  if (path === '') {
124
116
  path = '@';
125
117
  }
118
+ /** --- 不做语言跳转、不进入动态处理流程的路径 --- */
119
+ const stcPaths = /^(stc\/.*|favicon.\w+?\??.*|apple[\w-]+?\.png\??.*|[\w-]+?\.txt\??.*|[\w-]+?\.html\??.*)/;
126
120
  // --- 检测是否托管语言页面 ---
127
121
  const param = [];
128
- if (config.lang && data.res) {
122
+ if (config.lang && data.res && !stcPaths.test(path)) {
129
123
  // --- 仅仅 res 模式支持 config.lang ---
130
124
  if (path[2] !== '/') {
131
125
  // --- 不管是首页还是 @ 页,都会到此处(已经有语言目录不会到这里) ---
@@ -222,12 +216,17 @@ export async function run(data) {
222
216
  /** --- 开发者返回值 --- */
223
217
  let rtn;
224
218
  if (data.socket && data.req instanceof http.IncomingMessage) {
225
- // --- socket 模式,判断真实控制器文件是否存在 ---
226
- const filePath = config.const.wsPath + pathLeft + '.js';
219
+ // --- socket 模式 ---
220
+ // --- 判断真实控制器文件是否存在 ---
221
+ let filePath = config.const.wsPath + pathLeft + '.js';
227
222
  if (!await lFs.isFile(filePath)) {
228
223
  // --- 指定的控制器不存在 ---
229
- data.socket?.destroy();
230
- return true;
224
+ filePath = config.const.wsPath + 'handler.js';
225
+ if (!await lFs.isFile(filePath)) {
226
+ // --- 默认 handler 也不存在 ---
227
+ data.socket?.destroy();
228
+ return true;
229
+ }
231
230
  }
232
231
  // --- 加载控制器文件 ---
233
232
  const ctrCtr = (await import((!filePath.startsWith('/') ? '/' : '') + filePath)).default;
@@ -375,9 +374,19 @@ export async function run(data) {
375
374
  middle.setPrototype('_action', pathRight);
376
375
  middle.setPrototype('_headers', headers);
377
376
  middle.setPrototype('_get', get);
378
- /** --- 是否让框架自动获取 post,true 为自动(默认) --- */
377
+ /** --- 是否让框架自动获取 post,1 为自动(默认) --- */
379
378
  const reqStartRtn = await middle.onReqStart();
380
- if (reqStartRtn) {
379
+ if (reqStartRtn === -1) {
380
+ // --- 代理/反代了,什么也不管 ---
381
+ return true;
382
+ }
383
+ // --- 检测 path 是否是静态文件 ---
384
+ // --- 只能在这里做,因为 onReqStart 里面可能有反代,反代不能让 stc 等路径直连 ---
385
+ // --- 也得同时给反代走,所以 onReqStart 之后才能走到这一步判断 ---
386
+ if (stcPaths.test(data.path)) {
387
+ return false;
388
+ }
389
+ if (reqStartRtn === 1) {
381
390
  const rawPost = await getPost(data.req);
382
391
  // --- 原始 POST ---
383
392
  middle.setPrototype('_rawPost', rawPost.raw);
@@ -1,7 +1,7 @@
1
1
  import * as kebab from '#kebab/index.js';
2
2
  import * as sCtr from '#kebab/sys/ctr.js';
3
3
  export default class extends sCtr.Ctr {
4
- onReqStart(): boolean;
4
+ onReqStart(): Promise<number>;
5
5
  onLoad(): string | boolean;
6
6
  onUnload(rtn: string | boolean | kebab.DbValue[]): string | boolean | kebab.DbValue[];
7
7
  }
@@ -1,13 +1,16 @@
1
+ import * as lNet from '#kebab/lib/net.js';
1
2
  import * as sCtr from '#kebab/sys/ctr.js';
2
3
  export default class extends sCtr.Ctr {
3
- onReqStart() {
4
- if (this._config.const.path === 'test/net-mproxy1') {
5
- return false;
4
+ async onReqStart() {
5
+ if (await lNet.rproxy(this, {
6
+ 'test/net-rproxy/': 'https://cdn.jsdelivr.net/npm/deskrt@2.0.10/'
7
+ })) {
8
+ return -1;
6
9
  }
7
- if (this._config.const.path.startsWith('test/net-rproxy/')) {
8
- return false;
10
+ if (this._config.const.path === 'test/net-mproxy1') {
11
+ return 0;
9
12
  }
10
- return true;
13
+ return 1;
11
14
  }
12
15
  onLoad() {
13
16
  if (this._config.const.path !== 'test/middle') {
@@ -68,7 +68,6 @@ export default class extends sCtr.Ctr {
68
68
  netReuse(): Promise<string>;
69
69
  netError(): Promise<string>;
70
70
  netHosts(): Promise<string>;
71
- netRproxy(): Promise<string | boolean>;
72
71
  netMproxy(): Promise<string | boolean>;
73
72
  netMproxy1(): Promise<string | boolean>;
74
73
  netFilterheaders(): string;
@@ -46,7 +46,6 @@ export default class extends sCtr.Ctr {
46
46
  return true;
47
47
  }
48
48
  onReady() {
49
- lCore.display('onReady');
50
49
  return true;
51
50
  }
52
51
  onUnload(rtn) {
@@ -194,6 +193,7 @@ export default class extends sCtr.Ctr {
194
193
  '<br><br><b>Ws:</b>',
195
194
  `<br><br><a href="${this._config.const.urlBase}test/ws-server">View "test/ws-server"</a>`,
196
195
  `<br><a href="${this._config.const.urlBase}test/ws-server?ac=rproxy">View ws rproxy</a>`,
196
+ `<br><a href="${this._config.const.urlBase}test/ws-server?ac=rproxy2">View ws rproxy2 (handler)</a>`,
197
197
  `<br><a href="${this._config.const.urlBase}test/ws-client">View "test/ws-client"</a>`,
198
198
  `<br><a href="${this._config.const.urlBase}test/ws-client?ac=mproxy">View ws mproxy</a>`,
199
199
  '<br><br><b>Ssh:</b>',
@@ -1776,14 +1776,6 @@ content: <pre>${lText.htmlescape((await res.getContent())?.toString() ?? '')}</p
1776
1776
  error: <pre>${JSON.stringify(res.error, null, 4)}</pre>`);
1777
1777
  return echo.join('') + this._getEnd();
1778
1778
  }
1779
- async netRproxy() {
1780
- if (await lNet.rproxy(this, {
1781
- 'test/net-rproxy/': 'https://cdn.jsdelivr.net/npm/deskrt@2.0.10/'
1782
- })) {
1783
- return false;
1784
- }
1785
- return 'Nothing';
1786
- }
1787
1779
  async netMproxy() {
1788
1780
  const echo = [];
1789
1781
  const res = await lNet.get('https://cdn.jsdelivr.net/npm/deskrt@2.0.10/package.json', {
@@ -2701,6 +2693,7 @@ ${lTime.format(null, 'd|D|j|l|N|w|Y|y|F|M|m|H|h|i|s|T')}`;
2701
2693
  wsServer() {
2702
2694
  const echo = '<a href="' + this._config.const.urlBase + 'test/ws-server">Default</a> | ' +
2703
2695
  '<a href="' + this._config.const.urlBase + 'test/ws-server?ac=rproxy">rproxy</a> | ' +
2696
+ '<a href="' + this._config.const.urlBase + 'test/ws-server?ac=rproxy2">rproxy2</a> | ' +
2704
2697
  '<a href="' + this._config.const.urlBase + 'test">Return</a><br><br>' +
2705
2698
  `Nick: <input id="nick"> <input id="btn" type="button" value="Enter" onclick="enter()"> <input id="stop" type="button" value="Stop" onclick="stop()" disabled>
2706
2699
  <div id="list" style="border: solid 1px #000; line-height: 1.5; height: 300px; overflow-y: scroll; margin-top: 10px; padding: 10px;"></div>
@@ -2733,7 +2726,7 @@ function enter() {
2733
2726
  nickEl.disabled = true;
2734
2727
  btnEl.disabled = true;
2735
2728
  listEl.insertAdjacentHTML('afterbegin', '<div>[' + dateStr() + '] Connecting...</div>');
2736
- ws = new WebSocket('ws${this._config.const.https ? 's' : ''}://${this._config.const.host}/${this._get['ac'] === 'rproxy' ? 'rproxy' : 'test'}');
2729
+ ws = new WebSocket('ws${this._config.const.https ? 's' : ''}://${this._config.const.host}/${(this._get['ac'] === 'rproxy' || this._get['ac'] === 'rproxy2') ? this._get['ac'] : 'test'}');
2737
2730
  ws.onopen = function() {
2738
2731
  listEl.insertAdjacentHTML('afterbegin', '<div>[' + dateStr() + '] Event: onOpen.</div>');
2739
2732
  ws.send('Hello: ' + nick);
@@ -0,0 +1,4 @@
1
+ import * as sCtr from '#kebab/sys/ctr.js';
2
+ export default class extends sCtr.Ctr {
3
+ onLoad(): Promise<boolean>;
4
+ }
@@ -0,0 +1,12 @@
1
+ import * as sCtr from '#kebab/sys/ctr.js';
2
+ import * as lCore from '#kebab/lib/core.js';
3
+ import * as lWs from '#kebab/lib/ws.js';
4
+ export default class extends sCtr.Ctr {
5
+ async onLoad() {
6
+ lCore.debug('WebSocket handle test onLoad.');
7
+ if (this._config.const.path === 'rproxy2') {
8
+ await lWs.rproxy(this, `ws${this._config.const.https ? 's' : ''}://${this._config.const.host}/test`);
9
+ }
10
+ return false;
11
+ }
12
+ }