rspack-plugin-mock 2.0.0 → 2.2.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.
@@ -0,0 +1,1065 @@
1
+ import { DevServerProxyConfigArrayItem } from "@rspack/core";
2
+ import { CorsOptions } from "cors";
3
+ import { Options } from "co-body";
4
+ import formidable from "formidable";
5
+ import { Buffer } from "node:buffer";
6
+ import { WebSocketServer } from "ws";
7
+ import { Readable } from "node:stream";
8
+ import http from "node:http";
9
+ import { ProxyOptions } from "@rsbuild/core";
10
+ //#region src/types/cookies.d.ts
11
+ interface CookiesOption {
12
+ keys?: string[];
13
+ secure?: boolean;
14
+ }
15
+ interface SetCookieOption {
16
+ /**
17
+ * a number representing the milliseconds from `Date.now()` for expiry
18
+ *
19
+ * 表示从 `Date.now()` 起至过期的毫秒数
20
+ */
21
+ maxAge?: number;
22
+ /**
23
+ * a Date object indicating the cookie's expiration
24
+ * date (expires at the end of session by default).
25
+ *
26
+ * 一个指示cookie过期时间的 Date 对象(默认在会话结束时过期)。
27
+ */
28
+ expires?: Date;
29
+ /**
30
+ * a string indicating the path of the cookie (`/` by default).
31
+ *
32
+ * 一个指示cookie路径的字符串(默认为 `/`)。
33
+ */
34
+ path?: string;
35
+ /**
36
+ * a string indicating the domain of the cookie (no default).
37
+ *
38
+ * 表示 Cookie 域的字符串(无默认值)。
39
+ */
40
+ domain?: string;
41
+ /**
42
+ * a boolean indicating whether the cookie is only to be sent
43
+ * over HTTPS (false by default for HTTP, true by default for HTTPS).
44
+ *
45
+ * 一个布尔值,指示该 Cookie 是否仅通过 HTTPS 发送(HTTP 默认为 false,HTTPS 默认为 true)。
46
+ */
47
+ secure?: boolean;
48
+ /**
49
+ * a boolean indicating whether the cookie is only to be sent over HTTP(S),
50
+ * and not made available to client JavaScript (true by default).
51
+ *
52
+ * 一个布尔值,指示该 cookie 是否仅通过HTTP(S)发送,而不对客户端JavaScript开放(默认为true)。
53
+ */
54
+ httpOnly?: boolean;
55
+ /**
56
+ * a boolean or string indicating whether the cookie is a "same site" cookie (false by default).
57
+ * This can be set to 'strict', 'lax', or true (which maps to 'strict').
58
+ *
59
+ * 一个布尔值或字符串,用于指示该cookie是否为“同站”cookie(默认为false)。
60
+ * 可将其设置为'strict'、'lax'或true(true会映射为'strict')。
61
+ */
62
+ sameSite?: "strict" | "lax" | "none" | boolean;
63
+ /**
64
+ * a boolean indicating whether the cookie is to be signed (false by default).
65
+ * If this is true, another cookie of the same name with the .sig suffix
66
+ * appended will also be sent, with a 27-byte url-safe base64 SHA1 value
67
+ * representing the hash of cookie-name=cookie-value against the first Keygrip key.
68
+ * This signature key is used to detect tampering the next time a cookie is received.
69
+ *
70
+ * 一个布尔值,指示cookie是否需签名(默认为false)。
71
+ * 若设为true,将同时发送另一个同名但附加 `.sig` 后缀的 cookie,其值为 27 字节的URL安全型 base64 SHA1哈希值,
72
+ * 该哈希由cookie名称=cookie值的字符串与首个 Keygrip 密钥计算生成。
73
+ * 此签名密钥用于在下次接收cookie时检测数据是否被篡改。
74
+ */
75
+ signed?: boolean;
76
+ /**
77
+ * a boolean indicating whether to overwrite previously set
78
+ * cookies of the same name (false by default). If this is true,
79
+ * all cookies set during the same request with the same
80
+ * name (regardless of path or domain) are filtered out of
81
+ * the Set-Cookie header when setting this cookie.
82
+ *
83
+ * 一个布尔值,指示是否覆盖先前设置的同名Cookie(默认为false)。
84
+ * 若设为true,当设置此Cookie时,在同一请求期间设置的所有同名Cookie(无论路径或域)
85
+ * 都将从Set-Cookie标头中过滤掉。
86
+ */
87
+ overwrite?: boolean;
88
+ /**
89
+ * a string indicating the cookie priority.
90
+ * This can be set to 'low', 'medium', or 'high'.
91
+ *
92
+ * 表示Cookie优先级的字符串。可设置为'low'、'medium'或'high'。
93
+ */
94
+ priority?: "low" | "medium" | "high";
95
+ /**
96
+ * a boolean indicating whether to partition the cookie in Chrome
97
+ * for the CHIPS Update (false by default). If this is true,
98
+ * Cookies from embedded sites will be partitioned
99
+ * and only readable from the same top level site from which it was created.
100
+ *
101
+ * 一个布尔值,指示是否在Chrome中为CHIPS更新对Cookie进行分区(默认为false)。
102
+ * 若设为true,来自嵌入式站点的Cookie将被分区,且仅可从创建它的同一顶级站点读取。
103
+ */
104
+ partitioned?: boolean;
105
+ }
106
+ interface GetCookieOption {
107
+ signed: boolean;
108
+ }
109
+ //#endregion
110
+ //#region src/types/http.d.ts
111
+ type Method = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "TRACE" | "OPTIONS";
112
+ type Headers = http.IncomingHttpHeaders;
113
+ type ResponseBody = Record<string, any> | any[] | string | number | Readable | Buffer | null;
114
+ /**
115
+ * 扩展 request,添加额外的属性和方法
116
+ */
117
+ interface ExtraRequest {
118
+ /**
119
+ * The query string located after `?` in the request address has been parsed into JSON.
120
+ *
121
+ * 请求地址中位于 `?` 后面的 queryString,已解析为 json
122
+ */
123
+ query: Record<string, any>;
124
+ /**
125
+ * The queryString located after `?` in the referer request has been parsed as JSON.
126
+ *
127
+ * 请求 referer 中位于 `?` 后面的 queryString,已解析为 json
128
+ */
129
+ refererQuery: Record<string, any>;
130
+ /**
131
+ * Body data in the request
132
+ *
133
+ * 请求体中 body 数据
134
+ */
135
+ body: Record<string, any>;
136
+ /**
137
+ * The params parameter parsed from the `/api/id/:id` in the request address.
138
+ *
139
+ * 请求地址中,`/api/id/:id` 解析后的 params 参数
140
+ */
141
+ params: Record<string, any>;
142
+ /**
143
+ * headers data in the request
144
+ * 请求体中 headers
145
+ */
146
+ headers: Headers;
147
+ /**
148
+ * Get the cookie carried in the request.
149
+ *
150
+ * 获取 请求中携带的 cookie
151
+ * @see [cookies](https://github.com/pillarjs/cookies#cookiesgetname--options)
152
+ */
153
+ getCookie: (name: string, options?: GetCookieOption) => string | void;
154
+ }
155
+ type MockRequest = http.IncomingMessage & ExtraRequest;
156
+ type MockResponse = http.ServerResponse<http.IncomingMessage> & {
157
+ /**
158
+ * Set cookie in response
159
+ *
160
+ * 向请求响应中设置 cookie
161
+ * @see [cookies](https://github.com/pillarjs/cookies#cookiessetname--values--options)
162
+ */
163
+ setCookie: (name: string, value: string, options?: SetCookieOption) => void;
164
+ };
165
+ type NextFunction = (err?: any) => void;
166
+ type SimpleHandleFunction = (req: http.IncomingMessage, res: http.ServerResponse) => Promise<void>;
167
+ type NextHandleFunction = (req: http.IncomingMessage, res: http.ServerResponse, next: NextFunction) => Promise<void>;
168
+ type HandleFunction = SimpleHandleFunction | NextHandleFunction;
169
+ //#endregion
170
+ //#region src/types/record.d.ts
171
+ /**
172
+ * Record configuration options
173
+ *
174
+ * 录制配置选项
175
+ */
176
+ interface RecordOptions {
177
+ /**
178
+ * Whether to enable the record feature
179
+ * - true: Enable, automatically record proxy responses
180
+ * - false: Disable (default)
181
+ *
182
+ * 是否启用录制功能
183
+ * - true: 启用,自动录制 proxy 响应
184
+ * - false: 禁用(默认)
185
+ *
186
+ * @default false
187
+ */
188
+ enabled?: boolean;
189
+ /**
190
+ * Filter requests to record
191
+ * - Function: Custom filter function, return true to record
192
+ * - Object: Include/exclude patterns with glob or path-to-regexp mode
193
+ *
194
+ * 过滤要录制的请求
195
+ * - 函数:自定义过滤函数,返回 true 表示录制
196
+ * - 对象:包含/排除模式,支持 glob 或 path-to-regexp 模式
197
+ *
198
+ * @example
199
+ * ```ts
200
+ * // Record all requests
201
+ * filter: (req) => true
202
+ * // Record requests using glob pattern
203
+ * filter: { mode: 'glob', include: '/api/**' }
204
+ * // Record requests using path-to-regexp pattern
205
+ * filter: { mode: 'path-to-regexp', include: '/api/:id' }
206
+ * ```
207
+ */
208
+ filter?: ((req: RecordedReq) => boolean) | {
209
+ /**
210
+ * Include the request links that need to be recorded
211
+ *
212
+ * String: Glob pattern or path-to-regexp pattern
213
+ * (Use the mode option to set the mode, default is glob)
214
+ *
215
+ * 包含需要录制的请求链接
216
+ *
217
+ * glob 模式或 path-to-regexp 模式
218
+ * (使用 mode 选项设置模式,默认为 glob)
219
+ */
220
+ include?: string | string[];
221
+ /**
222
+ * Exclude request links that do not need to be recorded
223
+ *
224
+ * String: Glob pattern or path-to-regexp pattern
225
+ * (Use the mode option to set the mode, default is glob)
226
+ *
227
+ * 排除不需要录制的请求链接
228
+ *
229
+ * glob 模式或 path-to-regexp 模式
230
+ * (使用 mode 选项设置模式,默认为 glob)
231
+ */
232
+ exclude?: string | string[];
233
+ /**
234
+ * Matching mode for include/exclude patterns
235
+ * - 'glob': Glob pattern matching (default)
236
+ * - 'path-to-regexp': Path-to-regexp pattern matching
237
+ *
238
+ * 包含/排除模式的匹配模式
239
+ * - 'glob': glob 模式匹配(默认)
240
+ * - 'path-to-regexp': path-to-regexp 模式匹配
241
+ */
242
+ mode: "glob" | "path-to-regexp";
243
+ };
244
+ /**
245
+ * Directory to store recorded data
246
+ * Relative to project root
247
+ *
248
+ * 录制数据存储目录
249
+ * 相对于项目根目录
250
+ *
251
+ * @default 'mock/.recordings'
252
+ */
253
+ dir?: string;
254
+ /**
255
+ * Whether to overwrite existing recorded data
256
+ * - true: Overwrite old data for the same request (default)
257
+ * - false: Keep old data, do not record new data
258
+ *
259
+ * 是否覆盖已有录制数据
260
+ * - true: 相同请求覆盖旧数据(默认)
261
+ * - false: 保留旧数据,不录制新数据
262
+ *
263
+ * @default true
264
+ */
265
+ overwrite?: boolean;
266
+ /**
267
+ * Expiration time for recorded data in seconds
268
+ * - 0: Never expire (default)
269
+ * - Positive number: Expire after specified seconds
270
+ *
271
+ * 录制数据过期时间(秒)
272
+ * - 0: 永不过期(默认)
273
+ * - 正数:指定秒数后过期
274
+ *
275
+ * @default 0
276
+ */
277
+ expires?: number;
278
+ /**
279
+ * Status codes to record
280
+ * - Empty array: Record all status codes (default)
281
+ * - Specify one or more status codes to filter
282
+ *
283
+ * 要录制的状态码
284
+ * - 为空数组时记录所有状态码(默认)
285
+ * - 指定一个或多个状态码进行过滤
286
+ *
287
+ * @default []
288
+ */
289
+ status?: number | number[];
290
+ /**
291
+ * Should a .gitignore be added to the recording directory
292
+ * - true: Add (default)
293
+ * - false: Do not add
294
+ *
295
+ * 是否在录制目录中添加 .gitignore
296
+ * - true: 添加(默认)
297
+ * - false: 不添加
298
+ *
299
+ * @default true
300
+ */
301
+ gitignore?: boolean;
302
+ }
303
+ interface RecordedMeta {
304
+ /**
305
+ * Recording timestamp
306
+ *
307
+ * 录制数据创建时间戳
308
+ */
309
+ timestamp: number;
310
+ /**
311
+ * Recorded data create time
312
+ *
313
+ * 录制数据创建时间
314
+ */
315
+ createAt: string;
316
+ /**
317
+ * Recorded data file path
318
+ *
319
+ * 录制数据文件路径
320
+ */
321
+ filepath: string;
322
+ /**
323
+ * Reference the source of the original request
324
+ *
325
+ * 对原始请求的来源引用
326
+ */
327
+ referer?: string;
328
+ }
329
+ interface RecordedReq {
330
+ /**
331
+ * Request method
332
+ *
333
+ * 请求方法
334
+ */
335
+ method: string;
336
+ /**
337
+ * Request pathname
338
+ *
339
+ * 请求路径
340
+ */
341
+ pathname: string;
342
+ /**
343
+ * Request query parameters
344
+ *
345
+ * 请求参数
346
+ */
347
+ query: Record<string, any>;
348
+ /**
349
+ * Request body
350
+ *
351
+ * 请求体
352
+ */
353
+ body: unknown;
354
+ /**
355
+ * Request body type
356
+ *
357
+ * 请求体类型
358
+ */
359
+ bodyType: string;
360
+ }
361
+ interface RecordedRes {
362
+ /**
363
+ * Response status code
364
+ *
365
+ * 响应状态码
366
+ */
367
+ status: number;
368
+ /**
369
+ * Response status text
370
+ *
371
+ * 响应状态文本
372
+ */
373
+ statusText: string;
374
+ /**
375
+ * Response headers
376
+ *
377
+ * 响应头
378
+ */
379
+ headers: Record<string, string>;
380
+ /**
381
+ * Response body
382
+ *
383
+ * 响应体
384
+ */
385
+ body: string;
386
+ }
387
+ /**
388
+ * Recorded request data structure
389
+ *
390
+ * 录制的请求数据结构
391
+ */
392
+ interface RecordedRequest {
393
+ /**
394
+ * Recorded request metadata
395
+ *
396
+ * 录制请求元数据
397
+ */
398
+ meta: RecordedMeta;
399
+ /**
400
+ * Recorded request data
401
+ *
402
+ * 录制请求数据
403
+ */
404
+ req: RecordedReq;
405
+ /**
406
+ * Recorded response data
407
+ *
408
+ * 录制响应数据
409
+ */
410
+ res: RecordedRes;
411
+ }
412
+ /**
413
+ * Resolved record options with all fields required
414
+ *
415
+ * 解析后的录制配置选项,所有字段为必填
416
+ */
417
+ interface ResolvedRecordOptions extends Omit<Required<RecordOptions>, "status"> {
418
+ cwd: string;
419
+ status: number[];
420
+ }
421
+ //#endregion
422
+ //#region src/types/options.d.ts
423
+ type BodyParserOptions = Options & {
424
+ jsonLimit?: string | number;
425
+ formLimit?: string | number;
426
+ textLimit?: string | number;
427
+ };
428
+ type LogType = "info" | "warn" | "error" | "debug";
429
+ type LogLevel = LogType | "silent";
430
+ interface ServerBuildOption {
431
+ /**
432
+ * Service startup port
433
+ *
434
+ * 服务启动端口
435
+ * @default 8080
436
+ */
437
+ serverPort?: number;
438
+ /**
439
+ * Service application output directory
440
+ *
441
+ * 服务应用输出目录
442
+ * @default 'dist/mockServer'
443
+ */
444
+ dist?: string;
445
+ /**
446
+ * Service application log level
447
+ *
448
+ * 服务应用日志级别
449
+ * @default 'error'
450
+ */
451
+ log?: LogLevel;
452
+ /**
453
+ * Whether to include record files in the build output
454
+ *
455
+ * 是否在构建输出中包含录制文件
456
+ *
457
+ * @default true
458
+ */
459
+ includeRecord?: boolean;
460
+ }
461
+ interface MockMatchPriority {
462
+ /**
463
+ * The priority of matching rules is global.
464
+ * The rules declared in this option will take priority over the default rules.
465
+ * The higher the position of the rule in the array, the higher the priority.
466
+ *
467
+ * Do not declare general rules in this option, such as /api/(.*),
468
+ * as it will prevent subsequent rules from taking effect.
469
+ * Unless you are clear about the priority of the rules,
470
+ * most of the time you do not need to configure this option.
471
+ *
472
+ * 匹配规则优先级, 全局生效。
473
+ * 声明在该选项中的规则将优先于默认规则生效。
474
+ * 规则在数组越靠前的位置,优先级越高。
475
+ *
476
+ * 不要在此选项中声明通用性的规则,比如 `/api/(.*)`,这将导致后续的规则无法生效。
477
+ * 除非你明确知道规则的优先级,否则大多数情况下都不需要配置该选项。
478
+ * @default []
479
+ */
480
+ global?: string[];
481
+ /**
482
+ * For some special cases where the priority of certain rules needs to be adjusted,
483
+ * this option can be used. For example, when a request matches both Rule A and Rule B,
484
+ * and Rule A has a higher priority than Rule B, but it is desired for Rule B to take effect.
485
+ *
486
+ * 对于一些特殊情况,需要调整部分规则的优先级,可以使用此选项。
487
+ * 比如一个请求同时命中了规则 A 和 B,且 A 比 B 优先级高, 但期望规则 B 生效时。
488
+ *
489
+ * @example
490
+ * ```ts
491
+ * {
492
+ * special: {
493
+ * // /api/a/:b/c 优先级将提升到 /api/a/b/:c 前面
494
+ * // The /api/a/:b/c priority is promoted to /api/a/b/:c
495
+ * '/api/a/:b/c': ['/api/a/b/:c'],
496
+ * // 仅在请求满足 /api/a/b/c 时生效
497
+ * // Only when the request satisfies /api/a/b/c
498
+ * '/api/:a/b/c': {
499
+ * rules: ['/api/a/:b/c'],
500
+ * when: ['/api/a/b/c']
501
+ * }
502
+ * }
503
+ * }
504
+ * ```
505
+ */
506
+ special?: MockMatchSpecialPriority;
507
+ }
508
+ interface MockMatchSpecialPriority {
509
+ /**
510
+ * When both A and B or C match, and B or C is at the top of the sort order,
511
+ * insert A into the top position.The `when` option is used to further constrain
512
+ * the priority adjustment to be effective only for certain requests.
513
+ *
514
+ * 当 A 与 B或 C 同时满足匹配,`B` 或 `C` 在排序首位时,将A插入到首位。
515
+ * when 选项用于进一步约束该优先级调整仅针对哪些请求有效。
516
+ *
517
+ * @example
518
+ * ```ts
519
+ * {
520
+ * A: ['B', 'C'],
521
+ * A: { rules: ['B', 'C'], when: ['/api/a/b/c'] }
522
+ * }
523
+ * ```
524
+ */
525
+ [key: string]: string[] | {
526
+ rules: string[];
527
+ when: string[];
528
+ };
529
+ }
530
+ /**
531
+ * Configure plugin
532
+ *
533
+ * 插件配置项
534
+ */
535
+ interface MockServerPluginOptions {
536
+ /**
537
+ * To configure the path matching rules for http mock services,
538
+ * any request path starting with prefix will be intercepted and proxied.
539
+ * If the prefix starts with `^`, it will be recognized as a `RegExp`.
540
+ *
541
+ * 为 http mock 服务配置 路径匹配规则,任何请求路径以 prefix 开头的都将被拦截代理。
542
+ * 如果 prefix 以 `^` 开头,将被识别为 `RegExp`。
543
+ * @default []
544
+ * @example ['^/api']
545
+ */
546
+ prefix?: string | string[];
547
+ /**
548
+ * Configure path matching rules for WebSocket mock service.
549
+ * Any ws/wss requests with a request path starting with wsPrefix
550
+ * will be intercepted by the proxy.
551
+ * If wsPrefix starts with `^`, it will be recognized as a `RegExp`.
552
+ *
553
+ * 为 websocket mock 服务配置 路径匹配规则, 任何请求路径以 wsPrefix 开头的 ws/wss请求,
554
+ * 都将被代理拦截。
555
+ * 如果 wsPrefix 以 `^` 开头,将被识别为 `RegExp`。
556
+ * @default []
557
+ * @example ['/socket.io']
558
+ */
559
+ wsPrefix?: string | string[];
560
+ /**
561
+ * Whether to enable mock server
562
+ *
563
+ * 是否开启 mock 服务
564
+ * @default true
565
+ */
566
+ enabled?: boolean;
567
+ /**
568
+ * Configure the matching context for `include` and `exclude`.
569
+ *
570
+ * 配置 `include` 和 `exclude` 的匹配上下文
571
+ *
572
+ * @default process.cwd()
573
+ */
574
+ cwd?: string;
575
+ /**
576
+ * The directory to store mock files
577
+ *
578
+ * 存储 mock 文件的目录
579
+ *
580
+ * @default 'mock'
581
+ */
582
+ dir?: string;
583
+ /**
584
+ * glob string matching mock includes files
585
+ *
586
+ * glob 字符串匹配 mock 包含的文件
587
+ * @see [picomatch](https://github.com/micromatch/picomatch#globbing-features)
588
+ * @default []
589
+ */
590
+ include?: string | string[];
591
+ /**
592
+ * glob string matching mock excluded files
593
+ *
594
+ * glob 字符串匹配 mock 排除的文件
595
+ * @see [picomatch](https://github.com/micromatch/picomatch#globbing-features)
596
+ */
597
+ exclude?: string | string[];
598
+ /**
599
+ * Enable log and configure log level
600
+ *
601
+ * 开启日志,或配置 日志级别
602
+ * @default 'info'
603
+ */
604
+ log?: boolean | LogLevel;
605
+ /**
606
+ * When the mock resource is hot updated, only the data content is updated,
607
+ * but the page is not refreshed by default.
608
+ * If you want to refresh the page every time you modify a mock file,
609
+ * you can open this option.
610
+ *
611
+ * mock资源热更新时,仅更新了数据内容,但是默认不重新刷新页面。
612
+ * 当你希望每次修改mock文件都刷新页面时,可以打开此选项。
613
+ * @default false
614
+ */
615
+ reload?: boolean;
616
+ /**
617
+ * Configure to `cors`
618
+ *
619
+ * 配置 `cors`
620
+ * @default true
621
+ * @see [cors](https://github.com/expressjs/cors#configuration-options)
622
+ */
623
+ cors?: boolean | CorsOptions;
624
+ /**
625
+ * formidable options
626
+ * @see [formidable](https://github.com/node-formidable/formidable#options)
627
+ */
628
+ formidableOptions?: formidable.Options;
629
+ /**
630
+ * cookies options
631
+ * @see [cookies](https://github.com/pillarjs/cookies#new-cookiesrequest-response--options)
632
+ */
633
+ cookiesOptions?: CookiesOption;
634
+ /**
635
+ * Configure to `co-body`
636
+ *
637
+ * 配置 `co-body`
638
+ *
639
+ * @see [co-body](https://github.com/cojs/co-body#options)
640
+ */
641
+ bodyParserOptions?: BodyParserOptions;
642
+ /**
643
+ * When you need to build a small mock service, you can configure this option.
644
+ *
645
+ * 当需要构建一个小型mock服务时,可配置此项
646
+ * @default false
647
+ */
648
+ build?: boolean | ServerBuildOption;
649
+ /**
650
+ * Priority sorting for path matching rules is valid only for rules containing dynamic parameters.
651
+ * In most cases, the default sorting rules can meet the needs.
652
+ * However, in some cases where custom sorting rules are required, this option can be used.
653
+ *
654
+ * 路径匹配规则优先级排序,仅对包含动态参数的规则有效。
655
+ * 大部分情况下默认的排序规则都可以满足需求。
656
+ * 但有些情况下,需要自定义排序规则时,可以使用此选项。
657
+ *
658
+ * @example
659
+ * ```ts
660
+ * export default {
661
+ * priority: {
662
+ * global: ['/api/:a/b/c', '/api/a/:b/c', '/api/a/b/:c'],
663
+ * special: {
664
+ * '/api/:a/:b/c': {
665
+ * rules: ['/api/a/:b/:c', '/api/a/b/:c'],
666
+ * when: ['/api/a/b/c']
667
+ * }
668
+ * }
669
+ * }
670
+ * }
671
+ * ```
672
+ */
673
+ priority?: MockMatchPriority;
674
+ /**
675
+ * Active scenario(s) for filtering mocks.
676
+ * Only mocks whose `scene` intersects with this value (or have no `scene` configured)
677
+ * will be considered for matching.
678
+ * Can be overridden per-request via the `X-Mock-Scene` header.
679
+ *
680
+ * 当前激活的场景,用于过滤 mock。
681
+ * 只有 `scene` 与此有交集的 mock(或未配置 `scene` 的 mock)才会被考虑匹配。
682
+ * 可通过 `X-Mock-Scene` 请求头按请求覆盖。
683
+ */
684
+ activeScene?: string | string[];
685
+ /**
686
+ * Record and replay configuration
687
+ * Can be abbreviated as: record: true
688
+ *
689
+ * 录制回放配置
690
+ * 可简写为:record: true
691
+ *
692
+ * @default false
693
+ *
694
+ * @example
695
+ * ```ts
696
+ * // Enable with default settings
697
+ * record: true
698
+ *
699
+ * // Or with custom configuration
700
+ * record: {
701
+ * enabled: true,
702
+ * dir: 'mock/.recordings',
703
+ * overwrite: true,
704
+ * }
705
+ * ```
706
+ */
707
+ record?: boolean | RecordOptions;
708
+ /**
709
+ * Replay recorded requests, default enabled when record enabled
710
+ *
711
+ * 回放已记录的请求,默认请求录制启用时自动启用回放功能
712
+ */
713
+ replay?: boolean;
714
+ }
715
+ //#endregion
716
+ //#region src/types/basicConfig.d.ts
717
+ type ResponseBodyFn = (request: MockRequest) => ResponseBody | Promise<ResponseBody>;
718
+ type ResponseHeaderFn = (request: MockRequest) => Headers | Promise<Headers>;
719
+ type CookieValue = string | [string, SetCookieOption];
720
+ type ResponseCookies = Record<string, CookieValue>;
721
+ type ResponseCookiesFn = (request: MockRequest) => ResponseCookies | Promise<ResponseCookies>;
722
+ interface MockBaseItem {
723
+ /**
724
+ * The interface address that needs to be mocked,
725
+ * supported by `path-to-regexp@8.3.0` for path matching.
726
+ *
727
+ * 需要进行 mock 的接口地址, 由 `path-to-regexp@8.3.0` 提供路径匹配支持
728
+ * @see [path-to-regexp](https://github.com/pillarjs/path-to-regexp)
729
+ * @example
730
+ * ```txt
731
+ * /api/login
732
+ * /api/post/:id
733
+ * /api/users{/:id}
734
+ * /api/files/*path
735
+ * ```
736
+ */
737
+ url: string;
738
+ /**
739
+ * Enable WebSocket interface simulation
740
+ *
741
+ * 开启 websocket 接口模拟
742
+ *
743
+ * @default false
744
+ */
745
+ ws?: boolean;
746
+ /**
747
+ * Whether to enable mock for this interface.
748
+ * In most scenerios, we only need to mock some interfaces instead of all requests that
749
+ * have been configured with mock.
750
+ * Therefore, it is important to be able to configure whether to enable it or not.
751
+ *
752
+ * 是否启动对该接口的mock,在多数场景下,我们仅需要对部分接口进行 mock,
753
+ * 而不是对所有配置了mock的请求进行全量mock,所以是否能够配置是否启用很重要
754
+ * @default true
755
+ */
756
+ enabled?: boolean;
757
+ /**
758
+ * Enable log and configure log level
759
+ *
760
+ * 开启日志,或配置 日志级别
761
+ * @default 'info'
762
+ */
763
+ log?: boolean | LogLevel;
764
+ /**
765
+ * Scenario identifier for this mock.
766
+ * When not configured, the mock is universal and always matches regardless of active scenario.
767
+ * When configured, the mock only matches when at least one of its scenarios matches
768
+ * one of the active scenarios.
769
+ *
770
+ * 该 mock 的场景标识。
771
+ * 未配置时,该 mock 为全场景通用,不受 activeScene 限制。
772
+ * 配置后,只有 scene 中任意一项与 activeScene 中任意一项匹配时,该 mock 才会激活。
773
+ */
774
+ scene?: string | string[];
775
+ }
776
+ //#endregion
777
+ //#region src/types/httpConfig.d.ts
778
+ interface MockErrorConfig {
779
+ /**
780
+ * Error probability (0-1), default is 0.5
781
+ *
782
+ * 错误概率(0-1),默认 0.5
783
+ * @default 0.5
784
+ */
785
+ probability?: number;
786
+ /**
787
+ * Error status code, default is 500
788
+ *
789
+ * 错误状态码,默认 500
790
+ * @default 500
791
+ */
792
+ status?: number;
793
+ /**
794
+ * Error status text
795
+ *
796
+ * 错误状态文本
797
+ */
798
+ statusText?: string;
799
+ /**
800
+ * Custom error response body, suitable for when the status is 200, but the response body needs to simulate an error scenario
801
+ *
802
+ * 自定义错误响应体,适用于 status 为 200,但响应体需要模拟错误场景
803
+ * @example
804
+ * { code: 500, msg: 'Internal Server Error', result: null }
805
+ */
806
+ body?: ResponseBody | ResponseBodyFn;
807
+ }
808
+ interface MockHttpItem extends MockBaseItem {
809
+ /**
810
+ * The interface allows request methods, and by default allows both GET and POST.
811
+ *
812
+ * 该接口允许的 请求方法,默认同时支持 GET 和 POST
813
+ * @default ['POST','GET']
814
+ */
815
+ method?: Method | Method[];
816
+ /**
817
+ * Configure the response body headers
818
+ *
819
+ * 配置响应体 headers
820
+ * @default
821
+ * ```json
822
+ * { "Content-Type": "application/json" }
823
+ * ```
824
+ */
825
+ headers?: Headers | ResponseHeaderFn;
826
+ /**
827
+ * Configure Response Header Status Code
828
+ *
829
+ * 配置 响应头状态码
830
+ * @default 200
831
+ */
832
+ status?: number;
833
+ /**
834
+ * Configure response header status text
835
+ *
836
+ * 配置响应头状态文本
837
+ * @default 'OK'
838
+ */
839
+ statusText?: string;
840
+ /**
841
+ * Configure response delay time,
842
+ * If an array is passed in, it represents the range of delay time.
843
+ * unit: `ms`
844
+ *
845
+ * 配置响应延迟时间, 如果传入的是一个数组,则代表延迟时间的范围
846
+ * 单位: `ms`
847
+ * @default 0
848
+ */
849
+ delay?: number | [number, number];
850
+ /**
851
+ * Configure response body cookies
852
+ *
853
+ * 设置响应体 cookies
854
+ * @example
855
+ * ```ts
856
+ * export default {
857
+ * cookies: {
858
+ * 'token1': '1234567',
859
+ * 'token2': ['1234567', { path: '/' }],
860
+ * },
861
+ * }
862
+ * ```
863
+ * @example
864
+ * ```ts
865
+ * export default {
866
+ * cookies: function (request) {
867
+ * return {
868
+ * 'token1': '1234567',
869
+ * 'token2': ['1234567', { path: '/' }],
870
+ * }
871
+ * },
872
+ * }
873
+ * ```
874
+ */
875
+ cookies?: ResponseCookies | ResponseCookiesFn;
876
+ /**
877
+ * Response body data type, optional values include `text, json, buffer`.
878
+ *
879
+ * And also support types included in `mime-db`.
880
+ * When the response body returns a file and you are not sure which type to use,
881
+ * you can pass the file name as the value. The plugin will internally search for matching
882
+ * `content-type` based on the file name suffix.
883
+ *
884
+ * However, if it is a TypeScript file such as `a.ts`, it may not be correctly matched
885
+ * as a JavaScript script. You need to modify `a.ts` to `a.js` as the value passed
886
+ * in order to recognize it correctly.
887
+ *
888
+ * 响应体数据类型, 可选值包括 `text, json, buffer`,
889
+ *
890
+ * 还支持`mime-db`中的包含的类型。
891
+ * 当响应体返回的是一个文件,而你不确定应该使用哪个类型时,可以将文件名作为值传入,
892
+ * 插件内部会根据文件名后缀查找匹配的`content-type`。
893
+ *
894
+ * 但如果是 `typescript`文件如 `a.ts`,可能不会被正确匹配为 `javascript`脚本,
895
+ * 你需要将 `a.ts` 修改为 `a.js`作为值传入才能正确识别。
896
+ * @see [mime-db](https://github.com/jshttp/mime-db)
897
+ * @default 'json'
898
+ * @example
899
+ * ```txt
900
+ * json
901
+ * buffer
902
+ * my-app.dmg
903
+ * music.mp4
904
+ * ```
905
+ */
906
+ type?: "text" | "json" | "buffer" | string;
907
+ /**
908
+ * Configure response body data content
909
+ *
910
+ * 配置响应体数据内容
911
+ * @default ''
912
+ * @example
913
+ * ```ts
914
+ * export default {
915
+ * body: { a: 1 },
916
+ * }
917
+ * ```
918
+ * @example
919
+ * ```ts
920
+ * export default {
921
+ * body: function(request) {
922
+ * return { a: 1, query: request.query }
923
+ * },
924
+ * }
925
+ * ```
926
+ */
927
+ body?: ResponseBody | ResponseBodyFn;
928
+ /**
929
+ * If you need to set complex response content, you can use the response method,
930
+ * which is a middleware. Here, you can get information such as req
931
+ * and res of the http request,
932
+ * and then return response data through res.write() | res.end().
933
+ * Otherwise, you need to execute next() method.
934
+ * In `req`, you can also get parsed request information such as
935
+ * `query`, `params`, `body` and `refererQuery`.
936
+ *
937
+ * 如果需要设置复杂的响应内容,可以使用 response 方法,
938
+ * 该方法是一个 middleware,你可以在这里拿到 http 请求的 req、res等信息,
939
+ * 然后通过 res.write() | res.end() 返回响应数据, 否则需要执行 next() 方法。
940
+ * 在 `req` 中,还可以拿到 query、params、body, refererQuery 等已解析的请求信息。
941
+ *
942
+ * @see [connect](https://github.com/senchalabs/connect#appusefn)
943
+ * @example
944
+ * ```ts
945
+ * export default {
946
+ * response(req, res) {
947
+ * res.setHeader('Content-Type', 'application/json')
948
+ * res.end(JSON.stringify({ a: 1 }))
949
+ * },
950
+ * }
951
+ * ```
952
+ *
953
+ */
954
+ response?: (req: MockRequest, res: MockResponse, next: NextFunction) => void | Promise<void>;
955
+ /**
956
+ * Request Validator
957
+ *
958
+ * Sometimes, for the same API request, data needs to be returned based
959
+ * on different request parameters.
960
+ * However, if all of this is written in a single mock's body or response,
961
+ * the content can become cumbersome and difficult to manage.
962
+ * The function of a validator allows you to configure multiple mocks with
963
+ * the same URL simultaneously and determine which mock should be used through validation.
964
+ *
965
+ * 请求验证器
966
+ *
967
+ * 有时候,一个相同的API请求,需要根据不同的请求参数,来决定返回数据,
968
+ * 但全部都在单个 mock中的 body或者 response 中写,内容会很庞杂,不好管理,
969
+ * 验证器的功能,允许你同时配置多条相同url的mock,通过验证器来判断使哪个mock生效。
970
+ * @example
971
+ * ```ts
972
+ * export default {
973
+ * validator: {
974
+ * query: { id: 123 }
975
+ * }
976
+ * }
977
+ * ```
978
+ * @example
979
+ * ```ts
980
+ * export default {
981
+ * validator: function(request) {
982
+ * return request.query.id === 123
983
+ * }
984
+ * }
985
+ * ```
986
+ */
987
+ validator?: Partial<Omit<ExtraRequest, "getCookie">> | ((request: ExtraRequest) => boolean);
988
+ /**
989
+ * Configure error simulation
990
+ *
991
+ * 配置错误模拟
992
+ * @example
993
+ * ```ts
994
+ * export default {
995
+ * error: {
996
+ * probability: 0.5,
997
+ * status: 500,
998
+ * message: 'Internal Server Error'
999
+ * }
1000
+ * }
1001
+ * ```
1002
+ */
1003
+ error?: MockErrorConfig;
1004
+ ws?: false;
1005
+ }
1006
+ //#endregion
1007
+ //#region src/types/wsConfig.d.ts
1008
+ interface MockWebsocketItem extends MockBaseItem {
1009
+ ws: true;
1010
+ /**
1011
+ * Configure Websocket Server
1012
+ *
1013
+ * 配置 Websocket Server
1014
+ * @example
1015
+ * ```ts
1016
+ * export default {
1017
+ * ws: true
1018
+ * setup: (wss, { onCleanup }) => {
1019
+ * wss.on('connection', (ws,req) => {
1020
+ * ws.on('message', (raw) => console.log(raw))
1021
+ * const timer = setInterval(
1022
+ * () => ws.send(JSON.stringify({ type: 'connected' })),
1023
+ * 1000,
1024
+ * )
1025
+ * onCleanup(() => clearInterval(timer))
1026
+ * })
1027
+ * wss.on('error', (error) => console.error(error))
1028
+ * }
1029
+ * }
1030
+ * ```
1031
+ */
1032
+ setup: (wss: WebSocketServer, context: WebSocketSetupContext) => void;
1033
+ }
1034
+ interface WebSocketSetupContext {
1035
+ /**
1036
+ * When defining WSS, you may perform some automatic or looping tasks.
1037
+ * However, when hot updating, the plugin will re-execute `setup()`,
1038
+ * which may result in duplicate registration of listening events and looping tasks
1039
+ * such as setTimeout. You can use `onCleanup()` to clear these automatic or looping tasks.
1040
+ *
1041
+ * 当你在定义 WSS 时,可能会执行一些自动任务或循环任务,
1042
+ * 但是当热更新时,插件内部会重新执行 setup() ,
1043
+ * 这可能导致出现 重复注册监听事件 和 循环任务如 `setTimeout` 等。
1044
+ * 通过 `onCleanup()` 可以来清除这些自动任务或循环任务。
1045
+ * @example
1046
+ * ``` ts
1047
+ * onCleanup(() => clearTimeout(timeId))
1048
+ * ```
1049
+ */
1050
+ onCleanup: (cleanup: () => void) => void;
1051
+ }
1052
+ //#endregion
1053
+ //#region src/types/config.d.ts
1054
+ type MockOptions = (MockHttpItem | MockWebsocketItem)[];
1055
+ //#endregion
1056
+ //#region src/types/internal.d.ts
1057
+ /** @internal */
1058
+ type PathFilter = string | ((pathname: string, req: http.IncomingMessage) => boolean | string | RegExpMatchArray | null);
1059
+ /** @internal */
1060
+ type HttpProxyPlugin = NonNullable<(DevServerProxyConfigArrayItem & ProxyOptions)["plugins"]>[number];
1061
+ //#endregion
1062
+ //#region src/types/index.d.ts
1063
+ type FormidableFile = formidable.File | formidable.File[];
1064
+ //#endregion
1065
+ export { ResponseBody as A, HandleFunction as C, MockResponse as D, MockRequest as E, CookiesOption as M, GetCookieOption as N, NextFunction as O, SetCookieOption as P, ExtraRequest as S, Method as T, RecordedMeta as _, MockWebsocketItem as a, RecordedRes as b, MockHttpItem as c, LogType as d, MockMatchPriority as f, RecordOptions as g, ServerBuildOption as h, MockOptions as i, SimpleHandleFunction as j, NextHandleFunction as k, BodyParserOptions as l, MockServerPluginOptions as m, HttpProxyPlugin as n, WebSocketSetupContext as o, MockMatchSpecialPriority as p, PathFilter as r, MockErrorConfig as s, FormidableFile as t, LogLevel as u, RecordedReq as v, Headers as w, ResolvedRecordOptions as x, RecordedRequest as y };