rspack-plugin-mock 0.4.0 → 0.4.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.
@@ -1,3 +1,197 @@
1
+ // src/core/transform.ts
2
+ import {
3
+ isEmptyObject,
4
+ isFunction,
5
+ isObject as isObject2,
6
+ sortBy,
7
+ toArray
8
+ } from "@pengzhanbo/utils";
9
+
10
+ // src/core/utils.ts
11
+ import fs from "fs";
12
+ import os from "os";
13
+ import path from "path";
14
+ import { parse as queryParse } from "querystring";
15
+ import { fileURLToPath, URL as URL2 } from "url";
16
+ import Debug from "debug";
17
+ import { createFsFromVolume, Volume } from "memfs";
18
+ import { match } from "path-to-regexp";
19
+ var packageDir = getDirname(import.meta.url);
20
+ var vfs = createFsFromVolume(new Volume());
21
+ function isStream(stream) {
22
+ return stream !== null && typeof stream === "object" && typeof stream.pipe === "function";
23
+ }
24
+ function isReadableStream(stream) {
25
+ return isStream(stream) && stream.readable !== false && typeof stream._read === "function" && typeof stream._readableState === "object";
26
+ }
27
+ function getDirname(importMetaUrl) {
28
+ return path.dirname(fileURLToPath(importMetaUrl));
29
+ }
30
+ var debug = Debug("rspack:mock");
31
+ function lookupFile(dir, formats, options) {
32
+ for (const format of formats) {
33
+ const fullPath = path.join(dir, format);
34
+ if (fs.existsSync(fullPath) && fs.statSync(fullPath).isFile()) {
35
+ const result = options?.pathOnly ? fullPath : fs.readFileSync(fullPath, "utf-8");
36
+ if (!options?.predicate || options.predicate(result))
37
+ return result;
38
+ }
39
+ }
40
+ const parentDir = path.dirname(dir);
41
+ if (parentDir !== dir && (!options?.rootDir || parentDir.startsWith(options?.rootDir))) {
42
+ return lookupFile(parentDir, formats, options);
43
+ }
44
+ }
45
+ function doesProxyContextMatchUrl(context, url, req) {
46
+ if (typeof context === "function") {
47
+ return context(url, req);
48
+ }
49
+ return context[0] === "^" && new RegExp(context).test(url) || url.startsWith(context);
50
+ }
51
+ function parseParams(pattern, url) {
52
+ const urlMatch = match(pattern, { decode: decodeURIComponent })(url) || {
53
+ params: {}
54
+ };
55
+ return urlMatch.params || {};
56
+ }
57
+ function urlParse(input) {
58
+ const url = new URL2(input, "http://example.com");
59
+ const pathname = decodeURIComponent(url.pathname);
60
+ const query = queryParse(url.search.replace(/^\?/, ""));
61
+ return { pathname, query };
62
+ }
63
+ var windowsSlashRE = /\\/g;
64
+ var isWindows = os.platform() === "win32";
65
+ function slash(p) {
66
+ return p.replace(windowsSlashRE, "/");
67
+ }
68
+ function normalizePath(id) {
69
+ return path.posix.normalize(isWindows ? slash(id) : id);
70
+ }
71
+ function waitingFor(onSuccess, maxRetry = 5) {
72
+ return function wait(getter, retry = 0) {
73
+ const value = getter();
74
+ if (value) {
75
+ onSuccess(value);
76
+ } else if (retry < maxRetry) {
77
+ setTimeout(() => wait(getter, retry + 1), 100);
78
+ }
79
+ };
80
+ }
81
+
82
+ // src/core/validator.ts
83
+ import { isArray, isObject } from "@pengzhanbo/utils";
84
+ function validate(request, validator) {
85
+ return isObjectSubset(request.headers, validator.headers) && isObjectSubset(request.body, validator.body) && isObjectSubset(request.params, validator.params) && isObjectSubset(request.query, validator.query) && isObjectSubset(request.refererQuery, validator.refererQuery);
86
+ }
87
+ function isObjectSubset(source, target) {
88
+ if (!target)
89
+ return true;
90
+ for (const key in target) {
91
+ if (!isIncluded(source[key], target[key]))
92
+ return false;
93
+ }
94
+ return true;
95
+ }
96
+ function isIncluded(source, target) {
97
+ if (isArray(source) && isArray(target)) {
98
+ const seen = /* @__PURE__ */ new Set();
99
+ return target.every(
100
+ (ti) => source.some((si, i) => {
101
+ if (seen.has(i))
102
+ return false;
103
+ const included = isIncluded(si, ti);
104
+ if (included)
105
+ seen.add(i);
106
+ return included;
107
+ })
108
+ );
109
+ }
110
+ if (isObject(source) && isObject(target))
111
+ return isObjectSubset(source, target);
112
+ return Object.is(source, target);
113
+ }
114
+
115
+ // src/core/transform.ts
116
+ function transformRawData(rawData) {
117
+ return rawData.filter((item) => item[0]).map(([raw, __filepath__]) => {
118
+ let mockConfig;
119
+ if (raw.default) {
120
+ if (Array.isArray(raw.default)) {
121
+ mockConfig = raw.default.map((item) => ({ ...item, __filepath__ }));
122
+ } else {
123
+ mockConfig = { ...raw.default, __filepath__ };
124
+ }
125
+ } else if ("url" in raw) {
126
+ mockConfig = { ...raw, __filepath__ };
127
+ } else {
128
+ mockConfig = [];
129
+ Object.keys(raw || {}).forEach((key) => {
130
+ if (Array.isArray(raw[key])) {
131
+ mockConfig.push(...raw[key].map((item) => ({ ...item, __filepath__ })));
132
+ } else {
133
+ mockConfig.push({ ...raw[key], __filepath__ });
134
+ }
135
+ });
136
+ }
137
+ return mockConfig;
138
+ });
139
+ }
140
+ function transformMockData(mockList) {
141
+ const list = [];
142
+ for (const [, handle] of mockList.entries()) {
143
+ if (handle)
144
+ list.push(...toArray(handle));
145
+ }
146
+ const mocks = {};
147
+ list.filter((mock) => isObject2(mock) && mock.enabled !== false && mock.url).forEach((mock) => {
148
+ const { pathname, query } = urlParse(mock.url);
149
+ const list2 = mocks[pathname] ??= [];
150
+ const current = { ...mock, url: pathname };
151
+ if (current.ws !== true) {
152
+ const validator = current.validator;
153
+ if (!isEmptyObject(query)) {
154
+ if (isFunction(validator)) {
155
+ current.validator = function(request) {
156
+ return isObjectSubset(request.query, query) && validator(request);
157
+ };
158
+ } else if (validator) {
159
+ current.validator = { ...validator };
160
+ current.validator.query = current.validator.query ? { ...query, ...current.validator.query } : query;
161
+ } else {
162
+ current.validator = { query };
163
+ }
164
+ }
165
+ }
166
+ list2.push(current);
167
+ });
168
+ Object.keys(mocks).forEach((key) => {
169
+ mocks[key] = sortByValidator(mocks[key]);
170
+ });
171
+ return mocks;
172
+ }
173
+ function sortByValidator(mocks) {
174
+ return sortBy(mocks, (item) => {
175
+ if (item.ws === true)
176
+ return 0;
177
+ const { validator } = item;
178
+ if (!validator || isEmptyObject(validator))
179
+ return 2;
180
+ if (isFunction(validator))
181
+ return 0;
182
+ const count = Object.keys(validator).reduce(
183
+ (prev, key) => prev + keysCount(validator[key]),
184
+ 0
185
+ );
186
+ return 1 / count;
187
+ });
188
+ }
189
+ function keysCount(obj) {
190
+ if (!obj)
191
+ return 0;
192
+ return Object.keys(obj).length;
193
+ }
194
+
1
195
  // src/core/requestRecovery.ts
2
196
  import { Buffer } from "buffer";
3
197
  var requestCollectCache = /* @__PURE__ */ new WeakMap();
@@ -26,8 +220,8 @@ function rewriteRequest(proxyReq, req) {
26
220
  import { Buffer as Buffer2 } from "buffer";
27
221
  import {
28
222
  isArray as isArray3,
29
- isEmptyObject as isEmptyObject2,
30
- isFunction,
223
+ isEmptyObject as isEmptyObject3,
224
+ isFunction as isFunction2,
31
225
  random,
32
226
  sleep,
33
227
  timestamp
@@ -40,10 +234,10 @@ import colors from "picocolors";
40
234
 
41
235
  // src/core/matchingWeight.ts
42
236
  import {
43
- isArray,
44
- isEmptyObject,
237
+ isArray as isArray2,
238
+ isEmptyObject as isEmptyObject2,
45
239
  isString,
46
- sortBy,
240
+ sortBy as sortBy2,
47
241
  uniq
48
242
  } from "@pengzhanbo/utils";
49
243
  import { parse, pathToRegexp } from "path-to-regexp";
@@ -95,12 +289,12 @@ function preSort(rules) {
95
289
  preMatch[len].push(rule);
96
290
  }
97
291
  for (const match2 of preMatch.filter((v) => v && v.length > 0))
98
- matched = [...matched, ...sortBy(match2, sortFn).reverse()];
292
+ matched = [...matched, ...sortBy2(match2, sortFn).reverse()];
99
293
  return matched;
100
294
  }
101
295
  function defaultPriority(rules) {
102
296
  const highest = getHighest(rules);
103
- return sortBy(rules, (rule) => {
297
+ return sortBy2(rules, (rule) => {
104
298
  const tokens = getTokens(rule);
105
299
  const dym = tokens.filter((token) => typeof token !== "string");
106
300
  if (dym.length === 0)
@@ -148,14 +342,14 @@ function matchingWeight(rules, url, priority) {
148
342
  preSort(rules.filter((rule) => pathToRegexp(rule).test(url)))
149
343
  );
150
344
  const { global = [], special = {} } = priority;
151
- if (global.length === 0 && isEmptyObject(special) || matched.length === 0)
345
+ if (global.length === 0 && isEmptyObject2(special) || matched.length === 0)
152
346
  return matched;
153
347
  const [statics, dynamics] = twoPartMatch(matched);
154
348
  const globalMatch = global.filter((rule) => dynamics.includes(rule));
155
349
  if (globalMatch.length > 0) {
156
350
  matched = uniq([...statics, ...globalMatch, ...dynamics]);
157
351
  }
158
- if (isEmptyObject(special))
352
+ if (isEmptyObject2(special))
159
353
  return matched;
160
354
  const specialRule = Object.keys(special).filter(
161
355
  (rule) => matched.includes(rule)
@@ -163,7 +357,7 @@ function matchingWeight(rules, url, priority) {
163
357
  if (!specialRule)
164
358
  return matched;
165
359
  const options = special[specialRule];
166
- const { rules: lowerRules, when } = isArray(options) ? { rules: options, when: [] } : options;
360
+ const { rules: lowerRules, when } = isArray2(options) ? { rules: options, when: [] } : options;
167
361
  if (lowerRules.includes(matched[0])) {
168
362
  if (when.length === 0 || when.some((path2) => pathToRegexp(path2).test(url))) {
169
363
  matched = uniq([specialRule, ...matched]);
@@ -232,111 +426,6 @@ async function parseMultipart(req, options) {
232
426
  });
233
427
  }
234
428
 
235
- // src/core/utils.ts
236
- import fs from "fs";
237
- import path from "path";
238
- import { parse as queryParse } from "querystring";
239
- import { URL as URL2, fileURLToPath } from "url";
240
- import os from "os";
241
- import Debug from "debug";
242
- import { match } from "path-to-regexp";
243
- import { Volume, createFsFromVolume } from "memfs";
244
- var packageDir = getDirname(import.meta.url);
245
- var vfs = createFsFromVolume(new Volume());
246
- function isStream(stream) {
247
- return stream !== null && typeof stream === "object" && typeof stream.pipe === "function";
248
- }
249
- function isReadableStream(stream) {
250
- return isStream(stream) && stream.readable !== false && typeof stream._read === "function" && typeof stream._readableState === "object";
251
- }
252
- function getDirname(importMetaUrl) {
253
- return path.dirname(fileURLToPath(importMetaUrl));
254
- }
255
- var debug = Debug("rspack:mock");
256
- function lookupFile(dir, formats, options) {
257
- for (const format of formats) {
258
- const fullPath = path.join(dir, format);
259
- if (fs.existsSync(fullPath) && fs.statSync(fullPath).isFile()) {
260
- const result = options?.pathOnly ? fullPath : fs.readFileSync(fullPath, "utf-8");
261
- if (!options?.predicate || options.predicate(result))
262
- return result;
263
- }
264
- }
265
- const parentDir = path.dirname(dir);
266
- if (parentDir !== dir && (!options?.rootDir || parentDir.startsWith(options?.rootDir))) {
267
- return lookupFile(parentDir, formats, options);
268
- }
269
- }
270
- function doesProxyContextMatchUrl(context, url, req) {
271
- if (typeof context === "function") {
272
- return context(url, req);
273
- }
274
- return context[0] === "^" && new RegExp(context).test(url) || url.startsWith(context);
275
- }
276
- function parseParams(pattern, url) {
277
- const urlMatch = match(pattern, { decode: decodeURIComponent })(url) || {
278
- params: {}
279
- };
280
- return urlMatch.params || {};
281
- }
282
- function urlParse(input) {
283
- const url = new URL2(input, "http://example.com");
284
- const pathname = decodeURIComponent(url.pathname);
285
- const query = queryParse(url.search.replace(/^\?/, ""));
286
- return { pathname, query };
287
- }
288
- var windowsSlashRE = /\\/g;
289
- var isWindows = os.platform() === "win32";
290
- function slash(p) {
291
- return p.replace(windowsSlashRE, "/");
292
- }
293
- function normalizePath(id) {
294
- return path.posix.normalize(isWindows ? slash(id) : id);
295
- }
296
- function waitingFor(onSuccess, maxRetry = 5) {
297
- return function wait(getter, retry = 0) {
298
- const value = getter();
299
- if (value) {
300
- onSuccess(value);
301
- } else if (retry < maxRetry) {
302
- setTimeout(() => wait(getter, retry + 1), 100);
303
- }
304
- };
305
- }
306
-
307
- // src/core/validator.ts
308
- import { isArray as isArray2, isObject } from "@pengzhanbo/utils";
309
- function validate(request, validator) {
310
- return isObjectSubset(request.headers, validator.headers) && isObjectSubset(request.body, validator.body) && isObjectSubset(request.params, validator.params) && isObjectSubset(request.query, validator.query) && isObjectSubset(request.refererQuery, validator.refererQuery);
311
- }
312
- function isObjectSubset(source, target) {
313
- if (!target)
314
- return true;
315
- for (const key in target) {
316
- if (!isIncluded(source[key], target[key]))
317
- return false;
318
- }
319
- return true;
320
- }
321
- function isIncluded(source, target) {
322
- if (isArray2(source) && isArray2(target)) {
323
- const seen = /* @__PURE__ */ new Set();
324
- return target.every(
325
- (ti) => source.some((si, i) => {
326
- if (seen.has(i))
327
- return false;
328
- const included = isIncluded(si, ti);
329
- if (included)
330
- seen.add(i);
331
- return included;
332
- })
333
- );
334
- }
335
- if (isObject(source) && isObject(target))
336
- return isObjectSubset(source, target);
337
- return Object.is(source, target);
338
- }
339
-
340
429
  // src/core/baseMiddleware.ts
341
430
  function baseMiddleware(compiler, {
342
431
  formidableOptions = {},
@@ -425,7 +514,7 @@ function baseMiddleware(compiler, {
425
514
  );
426
515
  if (body) {
427
516
  try {
428
- const content = isFunction(body) ? await body(request) : body;
517
+ const content = isFunction2(body) ? await body(request) : body;
429
518
  await realDelay(startTime, delay);
430
519
  sendData(response, content, type);
431
520
  } catch (e) {
@@ -477,7 +566,7 @@ function fineMock(mockList, logger, {
477
566
  const hasMock = pathToRegexp2(mock.url).test(pathname);
478
567
  if (hasMock && mock.validator) {
479
568
  const params = parseParams(mock.url, pathname);
480
- if (isFunction(mock.validator)) {
569
+ if (isFunction2(mock.validator)) {
481
570
  return mock.validator({ params, ...request });
482
571
  } else {
483
572
  try {
@@ -516,7 +605,7 @@ async function provideHeaders(req, res, mock, logger) {
516
605
  if (!headers)
517
606
  return;
518
607
  try {
519
- const raw = isFunction(headers) ? await headers(req) : headers;
608
+ const raw = isFunction2(headers) ? await headers(req) : headers;
520
609
  Object.keys(raw).forEach((key) => {
521
610
  res.setHeader(key, raw[key]);
522
611
  });
@@ -537,7 +626,7 @@ async function provideCookies(req, res, mock, logger) {
537
626
  if (!cookies)
538
627
  return;
539
628
  try {
540
- const raw = isFunction(cookies) ? await cookies(req) : cookies;
629
+ const raw = isFunction2(cookies) ? await cookies(req) : cookies;
541
630
  Object.keys(raw).forEach((key) => {
542
631
  const cookie = raw[key];
543
632
  if (isArray3(cookie)) {
@@ -590,7 +679,7 @@ function requestLog(request, filepath) {
590
679
  let { pathname } = new URL(url, "http://example.com");
591
680
  pathname = colors.green(decodeURIComponent(pathname));
592
681
  const format = (prefix, data) => {
593
- return !data || isEmptyObject2(data) ? "" : ` ${colors.gray(`${prefix}:`)}${JSON.stringify(data)}`;
682
+ return !data || isEmptyObject3(data) ? "" : ` ${colors.gray(`${prefix}:`)}${JSON.stringify(data)}`;
594
683
  };
595
684
  const ms = colors.magenta(colors.bold(method));
596
685
  const qs = format("query", query);
@@ -600,138 +689,10 @@ function requestLog(request, filepath) {
600
689
  return `${ms} ${pathname}${qs}${ps}${bs}${file}`;
601
690
  }
602
691
 
603
- // src/core/logger.ts
604
- import { isBoolean } from "@pengzhanbo/utils";
605
- import colors2 from "picocolors";
606
- var logLevels = {
607
- silent: 0,
608
- error: 1,
609
- warn: 2,
610
- info: 3,
611
- debug: 4
612
- };
613
- function createLogger(prefix, defaultLevel = "info") {
614
- prefix = `[${prefix}]`;
615
- function output(type, msg, level) {
616
- level = isBoolean(level) ? level ? defaultLevel : "error" : level;
617
- const thresh = logLevels[level];
618
- if (thresh >= logLevels[type]) {
619
- const method = type === "info" || type === "debug" ? "log" : type;
620
- const tag = type === "debug" ? colors2.magenta(colors2.bold(prefix)) : type === "info" ? colors2.cyan(colors2.bold(prefix)) : type === "warn" ? colors2.yellow(colors2.bold(prefix)) : colors2.red(colors2.bold(prefix));
621
- const format = `${colors2.dim(
622
- (/* @__PURE__ */ new Date()).toLocaleTimeString()
623
- )} ${tag} ${msg}`;
624
- console[method](format);
625
- }
626
- }
627
- const logger = {
628
- debug(msg, level = defaultLevel) {
629
- output("debug", msg, level);
630
- },
631
- info(msg, level = defaultLevel) {
632
- output("info", msg, level);
633
- },
634
- warn(msg, level = defaultLevel) {
635
- output("warn", msg, level);
636
- },
637
- error(msg, level = defaultLevel) {
638
- output("error", msg, level);
639
- }
640
- };
641
- return logger;
642
- }
643
-
644
- // src/core/transform.ts
645
- import {
646
- isEmptyObject as isEmptyObject3,
647
- isFunction as isFunction2,
648
- isObject as isObject2,
649
- sortBy as sortBy2,
650
- toArray
651
- } from "@pengzhanbo/utils";
652
- function transformRawData(rawData) {
653
- return rawData.filter((item) => item[0]).map(([raw, __filepath__]) => {
654
- let mockConfig;
655
- if (raw.default) {
656
- if (Array.isArray(raw.default)) {
657
- mockConfig = raw.default.map((item) => ({ ...item, __filepath__ }));
658
- } else {
659
- mockConfig = { ...raw.default, __filepath__ };
660
- }
661
- } else if ("url" in raw) {
662
- mockConfig = { ...raw, __filepath__ };
663
- } else {
664
- mockConfig = [];
665
- Object.keys(raw || {}).forEach((key) => {
666
- if (Array.isArray(raw[key])) {
667
- mockConfig.push(...raw[key].map((item) => ({ ...item, __filepath__ })));
668
- } else {
669
- mockConfig.push({ ...raw[key], __filepath__ });
670
- }
671
- });
672
- }
673
- return mockConfig;
674
- });
675
- }
676
- function transformMockData(mockList) {
677
- const list = [];
678
- for (const [, handle] of mockList.entries()) {
679
- if (handle)
680
- list.push(...toArray(handle));
681
- }
682
- const mocks = {};
683
- list.filter((mock) => isObject2(mock) && mock.enabled !== false && mock.url).forEach((mock) => {
684
- const { pathname, query } = urlParse(mock.url);
685
- const list2 = mocks[pathname] ??= [];
686
- const current = { ...mock, url: pathname };
687
- if (current.ws !== true) {
688
- const validator = current.validator;
689
- if (!isEmptyObject3(query)) {
690
- if (isFunction2(validator)) {
691
- current.validator = function(request) {
692
- return isObjectSubset(request.query, query) && validator(request);
693
- };
694
- } else if (validator) {
695
- current.validator = { ...validator };
696
- current.validator.query = current.validator.query ? { ...query, ...current.validator.query } : query;
697
- } else {
698
- current.validator = { query };
699
- }
700
- }
701
- }
702
- list2.push(current);
703
- });
704
- Object.keys(mocks).forEach((key) => {
705
- mocks[key] = sortByValidator(mocks[key]);
706
- });
707
- return mocks;
708
- }
709
- function sortByValidator(mocks) {
710
- return sortBy2(mocks, (item) => {
711
- if (item.ws === true)
712
- return 0;
713
- const { validator } = item;
714
- if (!validator || isEmptyObject3(validator))
715
- return 2;
716
- if (isFunction2(validator))
717
- return 0;
718
- const count = Object.keys(validator).reduce(
719
- (prev, key) => prev + keysCount(validator[key]),
720
- 0
721
- );
722
- return 1 / count;
723
- });
724
- }
725
- function keysCount(obj) {
726
- if (!obj)
727
- return 0;
728
- return Object.keys(obj).length;
729
- }
730
-
731
692
  // src/core/mockWebsocket.ts
732
693
  import Cookies2 from "cookies";
733
694
  import { pathToRegexp as pathToRegexp3 } from "path-to-regexp";
734
- import colors3 from "picocolors";
695
+ import colors2 from "picocolors";
735
696
  import { WebSocketServer } from "ws";
736
697
  function mockWebSocket(compiler, httpServer, {
737
698
  wsProxies: proxies,
@@ -759,7 +720,7 @@ function mockWebSocket(compiler, httpServer, {
759
720
  wss.on("close", () => wssMap.delete(pathname));
760
721
  wss.on("error", (e) => {
761
722
  logger.error(
762
- `${colors3.red(
723
+ `${colors2.red(
763
724
  `WebSocket mock error at ${wss.path}`
764
725
  )}
765
726
  ${e}
@@ -769,7 +730,7 @@ ${e}
769
730
  });
770
731
  } catch (e) {
771
732
  logger.error(
772
- `${colors3.red(
733
+ `${colors2.red(
773
734
  `WebSocket mock error at ${wss.path}`
774
735
  )}
775
736
  ${e}
@@ -843,9 +804,9 @@ ${e}
843
804
  request.getCookie = cookies.get.bind(cookies);
844
805
  wss.handleUpgrade(request, socket, head, (ws) => {
845
806
  logger.info(
846
- `${colors3.magenta(colors3.bold("WebSocket"))} ${colors3.green(
807
+ `${colors2.magenta(colors2.bold("WebSocket"))} ${colors2.green(
847
808
  req.url
848
- )} connected ${colors3.dim(`(${filepath})`)}`,
809
+ )} connected ${colors2.dim(`(${filepath})`)}`,
849
810
  mock.log
850
811
  );
851
812
  wssContext.connectionList.push({ req: request, ws });
@@ -885,6 +846,47 @@ function cleanupRunner(cleanupList) {
885
846
  cleanup?.();
886
847
  }
887
848
 
849
+ // src/core/logger.ts
850
+ import { isBoolean } from "@pengzhanbo/utils";
851
+ import colors3 from "picocolors";
852
+ var logLevels = {
853
+ silent: 0,
854
+ error: 1,
855
+ warn: 2,
856
+ info: 3,
857
+ debug: 4
858
+ };
859
+ function createLogger(prefix, defaultLevel = "info") {
860
+ prefix = `[${prefix}]`;
861
+ function output(type, msg, level) {
862
+ level = isBoolean(level) ? level ? defaultLevel : "error" : level;
863
+ const thresh = logLevels[level];
864
+ if (thresh >= logLevels[type]) {
865
+ const method = type === "info" || type === "debug" ? "log" : type;
866
+ const tag = type === "debug" ? colors3.magenta(colors3.bold(prefix)) : type === "info" ? colors3.cyan(colors3.bold(prefix)) : type === "warn" ? colors3.yellow(colors3.bold(prefix)) : colors3.red(colors3.bold(prefix));
867
+ const format = `${colors3.dim(
868
+ (/* @__PURE__ */ new Date()).toLocaleTimeString()
869
+ )} ${tag} ${msg}`;
870
+ console[method](format);
871
+ }
872
+ }
873
+ const logger = {
874
+ debug(msg, level = defaultLevel) {
875
+ output("debug", msg, level);
876
+ },
877
+ info(msg, level = defaultLevel) {
878
+ output("info", msg, level);
879
+ },
880
+ warn(msg, level = defaultLevel) {
881
+ output("warn", msg, level);
882
+ },
883
+ error(msg, level = defaultLevel) {
884
+ output("error", msg, level);
885
+ }
886
+ };
887
+ return logger;
888
+ }
889
+
888
890
  export {
889
891
  packageDir,
890
892
  vfs,
@@ -893,12 +895,12 @@ export {
893
895
  urlParse,
894
896
  normalizePath,
895
897
  waitingFor,
896
- rewriteRequest,
897
- baseMiddleware,
898
- logLevels,
899
- createLogger,
900
898
  transformRawData,
901
899
  transformMockData,
902
900
  sortByValidator,
903
- mockWebSocket
901
+ rewriteRequest,
902
+ baseMiddleware,
903
+ mockWebSocket,
904
+ logLevels,
905
+ createLogger
904
906
  };