@midwayjs/koa 4.0.0-beta.1 → 4.0.0-beta.10

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
@@ -9,4 +9,4 @@ Document: [https://midwayjs.org](https://midwayjs.org)
9
9
 
10
10
  ## License
11
11
 
12
- [MIT]((https://github.com/midwayjs/midway/blob/master/LICENSE))
12
+ [MIT](https://github.com/midwayjs/midway/blob/master/LICENSE)
@@ -17,6 +17,9 @@ const DefaultConfig = require("./config/config.default");
17
17
  const bodyparser_middleware_1 = require("./middleware/bodyparser.middleware");
18
18
  const fav_middleware_1 = require("./middleware/fav.middleware");
19
19
  let KoaConfiguration = class KoaConfiguration {
20
+ decoratorService;
21
+ koaFramework;
22
+ configService;
20
23
  init() {
21
24
  // register param decorator
22
25
  this.decoratorService.registerParameterHandler(core_1.WEB_ROUTER_PARAM_KEY, options => {
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import { BaseFramework, CommonFilterUnion, CommonMiddlewareUnion, IMidwayBootstrapOptions, RouterInfo } from '@midwayjs/core';
3
2
  import { IMidwayKoaApplication, IMidwayKoaConfigurationOptions, IMidwayKoaContext } from './interface';
4
3
  import type { DefaultState, Middleware, Next } from 'koa';
@@ -14,11 +13,6 @@ export declare class MidwayKoaFramework extends BaseFramework<IMidwayKoaApplicat
14
13
  * wrap controller string to middleware function
15
14
  */
16
15
  generateController(routeInfo: RouterInfo): Middleware<DefaultState, IMidwayKoaContext>;
17
- /**
18
- * @deprecated
19
- * @param middlewareId
20
- */
21
- generateMiddleware(middlewareId: any): Promise<Middleware<DefaultState, IMidwayKoaContext, any>>;
22
16
  run(): Promise<void>;
23
17
  beforeStop(): Promise<void>;
24
18
  getFrameworkName(): string;
@@ -26,5 +20,7 @@ export declare class MidwayKoaFramework extends BaseFramework<IMidwayKoaApplicat
26
20
  getPort(): string;
27
21
  useMiddleware(Middleware: CommonMiddlewareUnion<IMidwayKoaContext, Next, unknown>): void;
28
22
  useFilter(Filter: CommonFilterUnion<IMidwayKoaContext, Next, unknown>): void;
23
+ private createVersioningMiddleware;
24
+ private extractVersion;
29
25
  }
30
26
  //# sourceMappingURL=framework.d.ts.map
package/dist/framework.js CHANGED
@@ -14,8 +14,11 @@ const koa = require("koa");
14
14
  const onerror_1 = require("./onerror");
15
15
  const qs = require("qs");
16
16
  const querystring = require("querystring");
17
+ const utils_1 = require("./utils");
17
18
  const COOKIES = Symbol('context#cookies');
18
19
  class KoaControllerGenerator extends core_1.WebControllerGenerator {
20
+ app;
21
+ webRouterService;
19
22
  constructor(app, webRouterService) {
20
23
  super(app, webRouterService);
21
24
  this.app = app;
@@ -31,6 +34,9 @@ class KoaControllerGenerator extends core_1.WebControllerGenerator {
31
34
  }
32
35
  }
33
36
  let MidwayKoaFramework = class MidwayKoaFramework extends core_1.BaseFramework {
37
+ server;
38
+ generator;
39
+ webRouterService;
34
40
  configure() {
35
41
  return this.configService.getConfiguration('koa');
36
42
  }
@@ -109,7 +115,13 @@ let MidwayKoaFramework = class MidwayKoaFramework extends core_1.BaseFramework {
109
115
  return c[str];
110
116
  if (self.configurationOptions.queryParseMode) {
111
117
  // use qs module to parse query
112
- c[str] = qs.parse(str, self.configurationOptions.queryParseOptions || {});
118
+ const parseOptions = {
119
+ ...self.configurationOptions.queryParseOptions,
120
+ ...(self.configurationOptions.queryParseMode === 'first'
121
+ ? { duplicates: 'first' }
122
+ : {}),
123
+ };
124
+ c[str] = qs.parse(str, parseOptions);
113
125
  }
114
126
  else {
115
127
  // use querystring to parse query by default
@@ -136,10 +148,16 @@ let MidwayKoaFramework = class MidwayKoaFramework extends core_1.BaseFramework {
136
148
  throw new core_1.httpError.NotFoundError(`${ctx.path} Not Found`);
137
149
  }
138
150
  };
151
+ const applyMiddlewares = [notFound];
152
+ // versioning middleware
153
+ const versioningConfig = this.configurationOptions.versioning;
154
+ if (versioningConfig?.enabled) {
155
+ applyMiddlewares.push(this.createVersioningMiddleware(versioningConfig));
156
+ }
139
157
  // root middleware
140
158
  const midwayRootMiddleware = async (ctx, next) => {
141
159
  this.app.createAnonymousContext(ctx);
142
- await (await this.applyMiddleware(notFound))(ctx, next);
160
+ await (await this.applyMiddleware(applyMiddlewares))(ctx, next);
143
161
  if (ctx.body === undefined &&
144
162
  !ctx.response._explicitStatus &&
145
163
  ctx._matchedRoute) {
@@ -154,7 +172,10 @@ let MidwayKoaFramework = class MidwayKoaFramework extends core_1.BaseFramework {
154
172
  },
155
173
  ]);
156
174
  this.generator = new KoaControllerGenerator(this.app, this.webRouterService);
157
- this.defineApplicationProperties();
175
+ this.defineApplicationProperties({
176
+ generateController: this.generateController.bind(this),
177
+ getPort: this.getPort.bind(this),
178
+ });
158
179
  // hack use method
159
180
  this.app.originUse = this.app.use;
160
181
  this.app.use = this.app.useMiddleware;
@@ -172,14 +193,6 @@ let MidwayKoaFramework = class MidwayKoaFramework extends core_1.BaseFramework {
172
193
  generateController(routeInfo) {
173
194
  return this.generator.generateKoaController(routeInfo);
174
195
  }
175
- /**
176
- * @deprecated
177
- * @param middlewareId
178
- */
179
- async generateMiddleware(middlewareId) {
180
- const mwIns = await this.getApplicationContext().getAsync(middlewareId);
181
- return mwIns.resolve();
182
- }
183
196
  async run() {
184
197
  // load controller
185
198
  await this.loadMidwayController();
@@ -216,27 +229,38 @@ let MidwayKoaFramework = class MidwayKoaFramework extends core_1.BaseFramework {
216
229
  if (core_1.Types.isNumber(this.configurationOptions.serverTimeout)) {
217
230
  this.server.setTimeout(this.configurationOptions.serverTimeout);
218
231
  }
232
+ this.configurationOptions.listenOptions = {
233
+ port: this.configurationOptions.port,
234
+ host: this.configurationOptions.hostname,
235
+ ...this.configurationOptions.listenOptions,
236
+ };
219
237
  // set port and listen server
220
- const customPort = process.env.MIDWAY_HTTP_PORT ?? this.configurationOptions.port;
221
- if (customPort) {
238
+ let customPort = process.env.MIDWAY_HTTP_PORT ||
239
+ this.configurationOptions.listenOptions.port;
240
+ if (customPort === 0 || customPort === '0') {
241
+ customPort = await (0, utils_1.getFreePort)();
242
+ this.logger.info(`[midway:koa] server has auto-assigned port ${customPort}`);
243
+ }
244
+ this.configurationOptions.listenOptions.port = Number(customPort);
245
+ if (this.configurationOptions.listenOptions.port) {
222
246
  new Promise(resolve => {
223
- const args = [customPort];
224
- if (this.configurationOptions.hostname) {
225
- args.push(this.configurationOptions.hostname);
226
- }
227
- args.push(() => {
247
+ // 使用 ListenOptions 对象启动服务器
248
+ this.server.listen(this.configurationOptions.listenOptions, () => {
228
249
  resolve();
229
250
  });
230
- this.server.listen(...args);
231
- process.env.MIDWAY_HTTP_PORT = String(customPort);
251
+ // 设置环境变量
252
+ process.env.MIDWAY_HTTP_PORT = String(this.configurationOptions.listenOptions.port);
232
253
  });
254
+ this.logger.debug(`[midway:koa] server is listening on port ${customPort}`);
233
255
  }
234
256
  }
235
257
  async beforeStop() {
236
258
  if (this.server) {
237
259
  new Promise(resolve => {
238
260
  this.server.close(resolve);
261
+ process.env.MIDWAY_HTTP_PORT = '';
239
262
  });
263
+ this.logger.debug('[midway:koa] server is stopped!');
240
264
  }
241
265
  }
242
266
  getFrameworkName() {
@@ -254,6 +278,52 @@ let MidwayKoaFramework = class MidwayKoaFramework extends core_1.BaseFramework {
254
278
  useFilter(Filter) {
255
279
  this.filterManager.useFilter(Filter);
256
280
  }
281
+ createVersioningMiddleware(config) {
282
+ return async (ctx, next) => {
283
+ // 提取版本信息
284
+ const version = this.extractVersion(ctx, config);
285
+ ctx.apiVersion = version;
286
+ // 对于 URI 版本控制,重写路径
287
+ if (config.type === 'URI' && version) {
288
+ const versionPrefix = `/${config.prefix || 'v'}${version}`;
289
+ if (ctx.path.startsWith(versionPrefix)) {
290
+ ctx.originalPath = ctx.path;
291
+ ctx.path = ctx.path.replace(versionPrefix, '') || '/';
292
+ }
293
+ }
294
+ await next();
295
+ };
296
+ }
297
+ extractVersion(ctx, config) {
298
+ // 自定义提取函数优先
299
+ if (config.extractVersionFn) {
300
+ return config.extractVersionFn(ctx);
301
+ }
302
+ const type = config.type || 'URI';
303
+ switch (type) {
304
+ case 'HEADER': {
305
+ const headerName = config.header || 'x-api-version';
306
+ const headerValue = ctx.headers[headerName];
307
+ if (typeof headerValue === 'string') {
308
+ return headerValue.replace(/^v/, '');
309
+ }
310
+ return undefined;
311
+ }
312
+ case 'MEDIA_TYPE': {
313
+ const accept = ctx.headers.accept;
314
+ const paramName = config.mediaTypeParam || 'version';
315
+ const match = accept?.match(new RegExp(`${paramName}=(\\d+)`));
316
+ return match ? match[1] : undefined;
317
+ }
318
+ case 'URI': {
319
+ const prefix = config.prefix || 'v';
320
+ const uriMatch = ctx.path.match(new RegExp(`^/${prefix}(\\d+)`));
321
+ return uriMatch ? uriMatch[1] : undefined;
322
+ }
323
+ default:
324
+ return config.defaultVersion;
325
+ }
326
+ }
257
327
  };
258
328
  exports.MidwayKoaFramework = MidwayKoaFramework;
259
329
  exports.MidwayKoaFramework = MidwayKoaFramework = __decorate([
@@ -1,20 +1,18 @@
1
- /// <reference types="node" />
2
- /// <reference types="node" />
3
1
  import { IConfigurationOptions, IMidwayApplication, IMidwayContext } from '@midwayjs/core';
4
2
  import * as koa from 'koa';
5
3
  import { Context as KoaContext, DefaultState, Middleware, Next } from 'koa';
6
4
  import { RouterParamValue } from '@midwayjs/core';
7
5
  import * as qs from 'qs';
6
+ import { ListenOptions } from 'net';
8
7
  export interface State extends DefaultState {
9
8
  }
10
9
  export type IMidwayKoaContext = IMidwayContext<KoaContext>;
11
10
  export type IMidwayKoaApplication = IMidwayApplication<IMidwayKoaContext, koa<State, IMidwayKoaContext> & {
12
11
  generateController(controllerMapping: string, routeArgsInfo?: RouterParamValue[], routerResponseData?: any[]): Middleware<State, IMidwayKoaContext>;
13
12
  /**
14
- * @deprecated
15
- * @param middlewareId
13
+ * Get the port that the application is listening on
16
14
  */
17
- generateMiddleware(middlewareId: any): Promise<Middleware<State, IMidwayKoaContext>>;
15
+ getPort(): string;
18
16
  }>;
19
17
  /**
20
18
  * @deprecated use NextFunction definition
@@ -86,7 +84,47 @@ export interface IMidwayKoaConfigurationOptions extends IConfigurationOptions {
86
84
  * qs options
87
85
  */
88
86
  queryParseOptions?: qs.IParseOptions;
87
+ /**
88
+ * https/https/http2 server options
89
+ */
89
90
  serverOptions?: Record<string, any>;
91
+ /**
92
+ * listen options
93
+ */
94
+ listenOptions?: ListenOptions;
95
+ /**
96
+ * 版本控制配置
97
+ */
98
+ versioning?: {
99
+ /**
100
+ * 是否启用版本控制
101
+ */
102
+ enabled?: boolean;
103
+ /**
104
+ * 默认版本控制类型
105
+ */
106
+ type?: 'URI' | 'HEADER' | 'MEDIA_TYPE' | 'CUSTOM';
107
+ /**
108
+ * 默认版本
109
+ */
110
+ defaultVersion?: string;
111
+ /**
112
+ * URI 版本前缀,默认为 'v'
113
+ */
114
+ prefix?: string;
115
+ /**
116
+ * Header 版本控制时的 header 名称
117
+ */
118
+ header?: string;
119
+ /**
120
+ * Media Type 版本控制时的参数名
121
+ */
122
+ mediaTypeParam?: string;
123
+ /**
124
+ * 自定义版本提取函数
125
+ */
126
+ extractVersionFn?: (ctx: IMidwayKoaContext) => string | undefined;
127
+ };
90
128
  }
91
129
  export type MiddlewareParamArray = Array<Middleware<DefaultState, IMidwayKoaContext>>;
92
130
  export interface IWebMiddleware {
@@ -95,6 +133,8 @@ export interface IWebMiddleware {
95
133
  export type Application = IMidwayKoaApplication;
96
134
  export interface Context extends IMidwayKoaContext {
97
135
  state: State;
136
+ apiVersion?: string;
137
+ originalPath?: string;
98
138
  }
99
139
  export interface BodyParserOptions {
100
140
  enable?: boolean;
@@ -13,6 +13,7 @@ exports.BodyParserMiddleware = void 0;
13
13
  const koaBodyParser = require("koa-bodyparser");
14
14
  const core_1 = require("@midwayjs/core");
15
15
  let BodyParserMiddleware = class BodyParserMiddleware {
16
+ bodyparserConfig;
16
17
  resolve() {
17
18
  // use bodyparser middleware
18
19
  if (this.bodyparserConfig.enable) {
@@ -14,6 +14,7 @@ const core_1 = require("@midwayjs/core");
14
14
  const path = require('path');
15
15
  const MAX_AGE = 'public, max-age=2592000'; // 30 days
16
16
  let SiteFileMiddleware = class SiteFileMiddleware {
17
+ siteFileConfig;
17
18
  resolve() {
18
19
  // use bodyparser middleware
19
20
  if (this.siteFileConfig.enable) {
package/dist/onerror.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.setupOnError = void 0;
3
+ exports.setupOnError = setupOnError;
4
4
  const http = require("http");
5
5
  const utils_1 = require("./utils");
6
6
  const core_1 = require("@midwayjs/core");
@@ -182,5 +182,4 @@ function setupOnError(app, config, logger) {
182
182
  this.res.end(this.body);
183
183
  };
184
184
  }
185
- exports.setupOnError = setupOnError;
186
185
  //# sourceMappingURL=onerror.js.map
package/dist/utils.d.ts CHANGED
@@ -11,4 +11,5 @@ export declare const tpl = "\n<!DOCTYPE html>\n<html>\n <head>\n <title>Erro
11
11
  * @public
12
12
  */
13
13
  export declare function escapeHtml(string: any): string;
14
+ export declare function getFreePort(): Promise<number>;
14
15
  //# sourceMappingURL=utils.d.ts.map
package/dist/utils.js CHANGED
@@ -1,6 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.escapeHtml = exports.tpl = exports.isProduction = exports.sendToWormhole = exports.accepts = exports.detectStatus = void 0;
3
+ exports.tpl = void 0;
4
+ exports.detectStatus = detectStatus;
5
+ exports.accepts = accepts;
6
+ exports.sendToWormhole = sendToWormhole;
7
+ exports.isProduction = isProduction;
8
+ exports.escapeHtml = escapeHtml;
9
+ exports.getFreePort = getFreePort;
10
+ const net_1 = require("net");
4
11
  function detectStatus(err) {
5
12
  // detect status
6
13
  let status = err.status || 500;
@@ -10,13 +17,11 @@ function detectStatus(err) {
10
17
  }
11
18
  return status;
12
19
  }
13
- exports.detectStatus = detectStatus;
14
20
  function accepts(ctx) {
15
21
  if (acceptJSON(ctx))
16
22
  return 'json';
17
23
  return 'html';
18
24
  }
19
- exports.accepts = accepts;
20
25
  function acceptJSON(ctx) {
21
26
  if (ctx.path.endsWith('.json'))
22
27
  return true;
@@ -59,11 +64,9 @@ function sendToWormhole(stream) {
59
64
  stream.on('error', onError);
60
65
  });
61
66
  }
62
- exports.sendToWormhole = sendToWormhole;
63
67
  function isProduction(app) {
64
68
  return app.getEnv() !== 'local' && app.getEnv() !== 'unittest';
65
69
  }
66
- exports.isProduction = isProduction;
67
70
  exports.tpl = `
68
71
  <!DOCTYPE html>
69
72
  <html>
@@ -152,5 +155,19 @@ function escapeHtml(string) {
152
155
  }
153
156
  return lastIndex !== index ? html + str.substring(lastIndex, index) : html;
154
157
  }
155
- exports.escapeHtml = escapeHtml;
158
+ async function getFreePort() {
159
+ return new Promise((resolve, reject) => {
160
+ const server = (0, net_1.createServer)();
161
+ server.listen(0, () => {
162
+ try {
163
+ const port = server.address().port;
164
+ server.close();
165
+ resolve(port);
166
+ }
167
+ catch (err) {
168
+ reject(err);
169
+ }
170
+ });
171
+ });
172
+ }
156
173
  //# sourceMappingURL=utils.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@midwayjs/koa",
3
- "version": "4.0.0-beta.1",
3
+ "version": "4.0.0-beta.10",
4
4
  "description": "Midway Web Framework for KOA",
5
5
  "main": "dist/index.js",
6
6
  "typings": "index.d.ts",
@@ -24,20 +24,21 @@
24
24
  ],
25
25
  "license": "MIT",
26
26
  "devDependencies": {
27
- "@midwayjs/core": "^4.0.0-beta.1",
28
- "@midwayjs/mock": "^4.0.0-beta.1",
29
- "@types/koa-router": "7.4.8",
30
- "fs-extra": "11.3.0"
27
+ "@midwayjs/core": "^4.0.0-beta.10",
28
+ "@midwayjs/mock": "^4.0.0-beta.10",
29
+ "@types/koa-router": "7.4.9",
30
+ "axios": "1.12.0",
31
+ "fs-extra": "11.3.3"
31
32
  },
32
33
  "dependencies": {
33
34
  "@koa/router": "^12.0.0",
34
35
  "@midwayjs/cookies": "^1.3.0",
35
- "@midwayjs/session": "^4.0.0-beta.1",
36
- "@types/koa": "2.15.0",
36
+ "@midwayjs/session": "^4.0.0-beta.10",
37
+ "@types/koa": "3.0.0",
37
38
  "@types/qs": "6.9.18",
38
- "koa": "2.16.1",
39
+ "koa": "3.0.3",
39
40
  "koa-bodyparser": "4.4.1",
40
- "qs": "6.14.0"
41
+ "qs": "6.14.1"
41
42
  },
42
43
  "author": "Harry Chen <czy88840616@gmail.com>",
43
44
  "repository": {
@@ -45,7 +46,7 @@
45
46
  "url": "https://github.com/midwayjs/midway.git"
46
47
  },
47
48
  "engines": {
48
- "node": ">=12"
49
+ "node": ">=20"
49
50
  },
50
- "gitHead": "832961ec3aff123c033197d8c00cb2bc9bad7ff8"
51
+ "gitHead": "1b1856629913703f67304155aaf611ec936a81ac"
51
52
  }