msw 0.28.1 → 0.30.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.
Files changed (47) hide show
  1. package/cli/init.js +14 -6
  2. package/lib/esm/RequestHandler-deps.js +162 -130
  3. package/lib/esm/fetch-deps.js +306 -95
  4. package/lib/esm/graphql-deps.js +26 -19
  5. package/lib/esm/index-deps.js +2 -2
  6. package/lib/esm/index.js +5291 -710
  7. package/lib/esm/index2.js +2 -2
  8. package/lib/esm/mockServiceWorker.js +4 -3
  9. package/lib/esm/rest-deps.js +4 -4
  10. package/lib/esm/xml-deps.js +1 -217
  11. package/lib/iife/index.js +4 -4
  12. package/lib/iife/mockServiceWorker.js +4 -3
  13. package/lib/types/context/body.d.ts +1 -1
  14. package/lib/types/context/json.d.ts +1 -1
  15. package/lib/types/context/text.d.ts +1 -1
  16. package/lib/types/context/xml.d.ts +1 -1
  17. package/lib/types/handlers/GraphQLHandler.d.ts +4 -2
  18. package/lib/types/handlers/RequestHandler.d.ts +12 -8
  19. package/lib/types/handlers/RestHandler.d.ts +2 -2
  20. package/lib/types/node/glossary.d.ts +2 -1
  21. package/lib/types/response.d.ts +1 -1
  22. package/lib/types/setupWorker/glossary.d.ts +21 -16
  23. package/lib/types/setupWorker/start/createFallbackStart.d.ts +2 -0
  24. package/lib/types/setupWorker/start/createStartHandler.d.ts +2 -0
  25. package/lib/types/setupWorker/start/utils/enableMocking.d.ts +5 -0
  26. package/lib/types/setupWorker/start/utils/prepareStartHandler.d.ts +9 -0
  27. package/lib/types/setupWorker/start/utils/printStartMessage.d.ts +7 -0
  28. package/lib/types/setupWorker/start/utils/validateWorkerScope.d.ts +2 -0
  29. package/lib/types/setupWorker/stop/createFallbackStop.d.ts +2 -0
  30. package/lib/types/setupWorker/stop/createStop.d.ts +2 -2
  31. package/lib/types/setupWorker/stop/utils/printStopMessage.d.ts +3 -0
  32. package/lib/types/sharedOptions.d.ts +3 -2
  33. package/lib/types/utils/getResponse.d.ts +2 -3
  34. package/lib/types/utils/handleRequest.d.ts +27 -0
  35. package/lib/types/utils/internal/isIterable.d.ts +4 -0
  36. package/lib/types/utils/internal/tryCatch.d.ts +1 -0
  37. package/lib/types/utils/logging/prepareResponse.d.ts +3 -3
  38. package/lib/types/utils/request/parseIsomorphicRequest.d.ts +6 -0
  39. package/lib/types/utils/request/parseWorkerRequest.d.ts +4 -0
  40. package/lib/types/utils/worker/createFallbackRequestListener.d.ts +3 -0
  41. package/lib/umd/index.js +27002 -5268
  42. package/lib/umd/mockServiceWorker.js +4 -3
  43. package/native/lib/index.js +4374 -4281
  44. package/node/lib/index.js +1385 -1292
  45. package/package.json +33 -33
  46. package/lib/types/setupWorker/start/createStart.d.ts +0 -2
  47. package/lib/types/setupWorker/start/utils/activateMocking.d.ts +0 -2
package/cli/init.js CHANGED
@@ -1,13 +1,14 @@
1
1
  const fs = require('fs')
2
2
  const path = require('path')
3
3
  const chalk = require('chalk')
4
+ const { until } = require('@open-draft/until')
4
5
  const inquirer = require('inquirer')
5
6
  const invariant = require('./invariant')
6
7
  const { SERVICE_WORKER_BUILD_PATH } = require('../config/constants')
7
8
 
8
9
  const CWD = process.cwd()
9
10
 
10
- module.exports = function init(args) {
11
+ module.exports = async function init(args) {
11
12
  const { publicDir, save } = args
12
13
 
13
14
  // When running as a part of "postinstall" script, "cwd" equals the library's directory.
@@ -18,11 +19,18 @@ module.exports = function init(args) {
18
19
  const relativePublicDir = path.relative(CWD, absolutePublicDir)
19
20
  const dirExists = fs.existsSync(absolutePublicDir)
20
21
 
21
- invariant(
22
- dirExists,
23
- 'Failed to create a Service Worker at "%s": directory does not exist.\nMake sure to include a relative path to the root directory of your server.',
24
- absolutePublicDir,
25
- )
22
+ if (!dirExists) {
23
+ // Try to create the directory if it doesn't exist
24
+ const [createDirectoryError] = await until(() =>
25
+ fs.promises.mkdir(absolutePublicDir, { recursive: true }),
26
+ )
27
+ invariant(
28
+ createDirectoryError == null,
29
+ 'Failed to create a Service Worker at "%s": directory does not exist and could not be created.\nMake sure to include a relative path to the root directory of your server.\n\nSee the original error below:\n%s',
30
+ absolutePublicDir,
31
+ createDirectoryError,
32
+ )
33
+ }
26
34
 
27
35
  console.log(
28
36
  'Initializing the Mock Service Worker at "%s"...',
@@ -1,4 +1,4 @@
1
- import { c as createCommonjsModule, a as commonjsGlobal, l as lib, j as jsonParse, s as status, b as set, d as delay, f as fetch } from './fetch-deps.js';
1
+ import { l as lib, j as jsonParse, c as commonjsGlobal, s as status, a as set, d as delay, f as fetch } from './fetch-deps.js';
2
2
 
3
3
  /*! *****************************************************************************
4
4
  Copyright (c) Microsoft Corporation.
@@ -37,9 +37,115 @@ function __awaiter(thisArg, _arguments, P, generator) {
37
37
  });
38
38
  }
39
39
 
40
+ class NetworkError extends Error {
41
+ constructor(message) {
42
+ super(message);
43
+ this.name = 'NetworkError';
44
+ }
45
+ }
46
+
47
+ function parseContentHeaders(headersString) {
48
+ var _a, _b;
49
+ const headers = lib.stringToHeaders(headersString);
50
+ const contentType = headers.get('content-type') || 'text/plain';
51
+ const disposition = headers.get('content-disposition');
52
+ if (!disposition) {
53
+ throw new Error('"Content-Disposition" header is required.');
54
+ }
55
+ const directives = disposition.split(';').reduce((acc, chunk) => {
56
+ const [name, ...rest] = chunk.trim().split('=');
57
+ acc[name] = rest.join('=');
58
+ return acc;
59
+ }, {});
60
+ const name = (_a = directives.name) === null || _a === void 0 ? void 0 : _a.slice(1, -1);
61
+ const filename = (_b = directives.filename) === null || _b === void 0 ? void 0 : _b.slice(1, -1);
62
+ return {
63
+ name,
64
+ filename,
65
+ contentType,
66
+ };
67
+ }
68
+ /**
69
+ * Parses a given string as a multipart/form-data.
70
+ * Does not throw an exception on an invalid multipart string.
71
+ */
72
+ function parseMultipartData(data, headers) {
73
+ const contentType = headers === null || headers === void 0 ? void 0 : headers.get('content-type');
74
+ if (!contentType) {
75
+ return undefined;
76
+ }
77
+ const [, ...directives] = contentType.split(/; */);
78
+ const boundary = directives
79
+ .filter((d) => d.startsWith('boundary='))
80
+ .map((s) => s.replace(/^boundary=/, ''))[0];
81
+ if (!boundary) {
82
+ return undefined;
83
+ }
84
+ const boundaryRegExp = new RegExp(`--+${boundary}`);
85
+ const fields = data
86
+ .split(boundaryRegExp)
87
+ .filter((chunk) => chunk.startsWith('\r\n') && chunk.endsWith('\r\n'))
88
+ .map((chunk) => chunk.trimStart().replace(/\r\n$/, ''));
89
+ if (!fields.length) {
90
+ return undefined;
91
+ }
92
+ const parsedBody = {};
93
+ try {
94
+ for (const field of fields) {
95
+ const [contentHeaders, ...rest] = field.split('\r\n\r\n');
96
+ const contentBody = rest.join('\r\n\r\n');
97
+ const { contentType, filename, name } = parseContentHeaders(contentHeaders);
98
+ const value = filename === undefined
99
+ ? contentBody
100
+ : new File([contentBody], filename, { type: contentType });
101
+ const parsedValue = parsedBody[name];
102
+ if (parsedValue === undefined) {
103
+ parsedBody[name] = value;
104
+ }
105
+ else if (Array.isArray(parsedValue)) {
106
+ parsedBody[name] = [...parsedValue, value];
107
+ }
108
+ else {
109
+ parsedBody[name] = [parsedValue, value];
110
+ }
111
+ }
112
+ return parsedBody;
113
+ }
114
+ catch (error) {
115
+ return undefined;
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Parses a given request/response body based on the `Content-Type` header.
121
+ */
122
+ function parseBody(body, headers) {
123
+ // Return whatever falsey body value is given.
124
+ if (!body) {
125
+ return body;
126
+ }
127
+ const contentType = headers === null || headers === void 0 ? void 0 : headers.get('content-type');
128
+ // If the body has a Multipart Content-Type
129
+ // parse it into an object.
130
+ const hasMultipartContent = contentType === null || contentType === void 0 ? void 0 : contentType.startsWith('multipart/form-data');
131
+ if (hasMultipartContent && typeof body !== 'object') {
132
+ return parseMultipartData(body, headers) || body;
133
+ }
134
+ // If the intercepted request's body has a JSON Content-Type
135
+ // parse it into an object.
136
+ const hasJsonContent = contentType === null || contentType === void 0 ? void 0 : contentType.includes('json');
137
+ if (hasJsonContent && typeof body !== 'object') {
138
+ return jsonParse(body) || body;
139
+ }
140
+ // Otherwise leave as-is.
141
+ return body;
142
+ }
143
+
144
+ var punycode$1 = {exports: {}};
145
+
40
146
  /*! https://mths.be/punycode v1.3.2 by @mathias */
41
147
 
42
- var punycode = createCommonjsModule(function (module, exports) {
148
+ (function (module, exports) {
43
149
  (function(root) {
44
150
 
45
151
  /** Detect free variables */
@@ -561,9 +667,9 @@ var punycode = createCommonjsModule(function (module, exports) {
561
667
  }
562
668
 
563
669
  }(commonjsGlobal));
564
- });
670
+ }(punycode$1, punycode$1.exports));
565
671
 
566
- var util = {
672
+ var util$1 = {
567
673
  isString: function(arg) {
568
674
  return typeof(arg) === 'string';
569
675
  },
@@ -578,7 +684,7 @@ var util = {
578
684
  }
579
685
  };
580
686
 
581
- // Copyright Joyent, Inc. and other Node contributors.
687
+ var querystring$1 = {};
582
688
 
583
689
  // If obj.hasOwnProperty has been overridden, then calling
584
690
  // obj.hasOwnProperty(prop) will break.
@@ -638,8 +744,6 @@ var decode = function(qs, sep, eq, options) {
638
744
  return obj;
639
745
  };
640
746
 
641
- // Copyright Joyent, Inc. and other Node contributors.
642
-
643
747
  var stringifyPrimitive = function(v) {
644
748
  switch (typeof v) {
645
749
  case 'string':
@@ -682,12 +786,11 @@ var encode = function(obj, sep, eq, name) {
682
786
  encodeURIComponent(stringifyPrimitive(obj));
683
787
  };
684
788
 
685
- var querystring = createCommonjsModule(function (module, exports) {
686
-
687
- exports.decode = exports.parse = decode;
688
- exports.encode = exports.stringify = encode;
689
- });
789
+ querystring$1.decode = querystring$1.parse = decode;
790
+ querystring$1.encode = querystring$1.stringify = encode;
690
791
 
792
+ var punycode = punycode$1.exports;
793
+ var util = util$1;
691
794
  var format = urlFormat;
692
795
 
693
796
  function Url() {
@@ -755,7 +858,8 @@ var protocolPattern = /^([a-z0-9.+-]+:)/i,
755
858
  'ftp:': true,
756
859
  'gopher:': true,
757
860
  'file:': true
758
- };
861
+ },
862
+ querystring = querystring$1;
759
863
 
760
864
  function urlParse(url, parseQueryString, slashesDenoteHost) {
761
865
  if (url && util.isObject(url) && url instanceof Url) return url;
@@ -1423,108 +1527,11 @@ function prepareRequest(request) {
1423
1527
  return Object.assign(Object.assign({}, request), { headers: request.headers.all() });
1424
1528
  }
1425
1529
 
1426
- function parseContentHeaders(headersString) {
1427
- var _a, _b;
1428
- const headers = lib.stringToHeaders(headersString);
1429
- const contentType = headers.get('content-type') || 'text/plain';
1430
- const disposition = headers.get('content-disposition');
1431
- if (!disposition) {
1432
- throw new Error('"Content-Disposition" header is required.');
1433
- }
1434
- const directives = disposition.split(';').reduce((acc, chunk) => {
1435
- const [name, ...rest] = chunk.trim().split('=');
1436
- acc[name] = rest.join('=');
1437
- return acc;
1438
- }, {});
1439
- const name = (_a = directives.name) === null || _a === void 0 ? void 0 : _a.slice(1, -1);
1440
- const filename = (_b = directives.filename) === null || _b === void 0 ? void 0 : _b.slice(1, -1);
1441
- return {
1442
- name,
1443
- filename,
1444
- contentType,
1445
- };
1446
- }
1447
- /**
1448
- * Parses a given string as a multipart/form-data.
1449
- * Does not throw an exception on an invalid multipart string.
1450
- */
1451
- function parseMultipartData(data, headers) {
1452
- const contentType = headers === null || headers === void 0 ? void 0 : headers.get('content-type');
1453
- if (!contentType) {
1454
- return undefined;
1455
- }
1456
- const [, ...directives] = contentType.split(/; */);
1457
- const boundary = directives
1458
- .filter((d) => d.startsWith('boundary='))
1459
- .map((s) => s.replace(/^boundary=/, ''))[0];
1460
- if (!boundary) {
1461
- return undefined;
1462
- }
1463
- const boundaryRegExp = new RegExp(`--+${boundary}`);
1464
- const fields = data
1465
- .split(boundaryRegExp)
1466
- .filter((chunk) => chunk.startsWith('\r\n') && chunk.endsWith('\r\n'))
1467
- .map((chunk) => chunk.trimStart().replace(/\r\n$/, ''));
1468
- if (!fields.length) {
1469
- return undefined;
1470
- }
1471
- const parsedBody = {};
1472
- try {
1473
- for (const field of fields) {
1474
- const [contentHeaders, ...rest] = field.split('\r\n\r\n');
1475
- const contentBody = rest.join('\r\n\r\n');
1476
- const { contentType, filename, name } = parseContentHeaders(contentHeaders);
1477
- const value = filename === undefined
1478
- ? contentBody
1479
- : new File([contentBody], filename, { type: contentType });
1480
- const parsedValue = parsedBody[name];
1481
- if (parsedValue === undefined) {
1482
- parsedBody[name] = value;
1483
- }
1484
- else if (Array.isArray(parsedValue)) {
1485
- parsedBody[name] = [...parsedValue, value];
1486
- }
1487
- else {
1488
- parsedBody[name] = [parsedValue, value];
1489
- }
1490
- }
1491
- return parsedBody;
1492
- }
1493
- catch (error) {
1494
- return undefined;
1495
- }
1496
- }
1497
-
1498
- /**
1499
- * Parses a given request/response body based on the `Content-Type` header.
1500
- */
1501
- function parseBody(body, headers) {
1502
- if (body) {
1503
- const contentType = headers === null || headers === void 0 ? void 0 : headers.get('content-type');
1504
- // If the body has a Multipart Content-Type
1505
- // parse it into an object.
1506
- const hasMultipartContent = contentType === null || contentType === void 0 ? void 0 : contentType.startsWith('multipart/form-data');
1507
- if (hasMultipartContent && typeof body !== 'object') {
1508
- return parseMultipartData(body, headers) || body;
1509
- }
1510
- // If the intercepted request's body has a JSON Content-Type
1511
- // parse it into an object.
1512
- const hasJsonContent = contentType === null || contentType === void 0 ? void 0 : contentType.includes('json');
1513
- if (hasJsonContent && typeof body !== 'object') {
1514
- return jsonParse(body) || body;
1515
- }
1516
- // Otherwise leave as-is.
1517
- return body;
1518
- }
1519
- // Return whatever falsey body value is given.
1520
- return body;
1521
- }
1522
-
1523
1530
  /**
1524
1531
  * Formats a mocked response for introspection in browser's console.
1525
1532
  */
1526
1533
  function prepareResponse(res) {
1527
- const responseHeaders = lib.listToHeaders(res.headers);
1534
+ const responseHeaders = lib.objectToHeaders(res.headers);
1528
1535
  return Object.assign(Object.assign({}, res), {
1529
1536
  // Parse a response JSON body for preview in the logs
1530
1537
  body: parseBody(res.body, responseHeaders) });
@@ -1569,9 +1576,10 @@ const match = (path, url) => {
1569
1576
  };
1570
1577
  };
1571
1578
 
1572
- var getCleanUrl_1 = createCommonjsModule(function (module, exports) {
1573
- Object.defineProperty(exports, "__esModule", { value: true });
1574
- exports.getCleanUrl = void 0;
1579
+ var getCleanUrl$1 = {};
1580
+
1581
+ Object.defineProperty(getCleanUrl$1, "__esModule", { value: true });
1582
+ var getCleanUrl_2 = getCleanUrl$1.getCleanUrl = void 0;
1575
1583
  /**
1576
1584
  * Removes query parameters and hashes from a given URL.
1577
1585
  */
@@ -1579,9 +1587,7 @@ function getCleanUrl(url, isAbsolute) {
1579
1587
  if (isAbsolute === void 0) { isAbsolute = true; }
1580
1588
  return [isAbsolute && url.origin, url.pathname].filter(Boolean).join('');
1581
1589
  }
1582
- exports.getCleanUrl = getCleanUrl;
1583
-
1584
- });
1590
+ getCleanUrl_2 = getCleanUrl$1.getCleanUrl = getCleanUrl;
1585
1591
 
1586
1592
  /**
1587
1593
  * Returns an absolute URL based on the given relative URL, if possible.
@@ -1622,7 +1628,7 @@ function getUrlByMask(mask) {
1622
1628
 
1623
1629
  function getCleanMask(resolvedMask) {
1624
1630
  return resolvedMask instanceof URL
1625
- ? getCleanUrl_1.getCleanUrl(resolvedMask)
1631
+ ? getCleanUrl_2(resolvedMask)
1626
1632
  : resolvedMask instanceof RegExp
1627
1633
  ? resolvedMask
1628
1634
  : getAbsoluteUrl(resolvedMask);
@@ -1635,7 +1641,7 @@ function getCleanMask(resolvedMask) {
1635
1641
  function matchRequestUrl(url, mask) {
1636
1642
  const resolvedMask = getUrlByMask(mask);
1637
1643
  const cleanMask = getCleanMask(resolvedMask);
1638
- const cleanRequestUrl = getCleanUrl_1.getCleanUrl(url);
1644
+ const cleanRequestUrl = getCleanUrl_2(url);
1639
1645
  return match(cleanMask, cleanRequestUrl);
1640
1646
  }
1641
1647
 
@@ -1653,13 +1659,6 @@ function compose(...fns) {
1653
1659
  };
1654
1660
  }
1655
1661
 
1656
- class NetworkError extends Error {
1657
- constructor(message) {
1658
- super(message);
1659
- this.name = 'NetworkError';
1660
- }
1661
- }
1662
-
1663
1662
  const defaultResponse = {
1664
1663
  status: 200,
1665
1664
  statusText: 'OK',
@@ -1715,6 +1714,16 @@ function getCallFrame() {
1715
1714
  return declarationPath;
1716
1715
  }
1717
1716
 
1717
+ /**
1718
+ * Determines if the given function is an iterator.
1719
+ */
1720
+ function isIterable(fn) {
1721
+ if (!fn) {
1722
+ return false;
1723
+ }
1724
+ return typeof fn[Symbol.iterator] == 'function';
1725
+ }
1726
+
1718
1727
  const defaultContext = {
1719
1728
  status,
1720
1729
  set,
@@ -1733,7 +1742,7 @@ class RequestHandler {
1733
1742
  * Parse the captured request to extract additional information from it.
1734
1743
  * Parsed result is then exposed to other methods of this request handler.
1735
1744
  */
1736
- parse(request) {
1745
+ parse(_request) {
1737
1746
  return null;
1738
1747
  }
1739
1748
  /**
@@ -1746,7 +1755,7 @@ class RequestHandler {
1746
1755
  * Derive the publicly exposed request (`req`) instance of the response resolver
1747
1756
  * from the captured request and its parsed result.
1748
1757
  */
1749
- getPublicRequest(request, parsedResult) {
1758
+ getPublicRequest(request, _parsedResult) {
1750
1759
  return request;
1751
1760
  }
1752
1761
  markAsSkipped(shouldSkip = true) {
@@ -1767,10 +1776,33 @@ class RequestHandler {
1767
1776
  return null;
1768
1777
  }
1769
1778
  const publicRequest = this.getPublicRequest(request, parsedResult);
1770
- const mockedResponse = yield this.resolver(publicRequest, response, this.ctx);
1779
+ // Create a response extraction wrapper around the resolver
1780
+ // since it can be both an async function and a generator.
1781
+ const executeResolver = this.wrapResolver(this.resolver);
1782
+ const mockedResponse = yield executeResolver(publicRequest, response, this.ctx);
1771
1783
  return this.createExecutionResult(parsedResult, publicRequest, mockedResponse);
1772
1784
  });
1773
1785
  }
1786
+ wrapResolver(resolver) {
1787
+ return (req, res, ctx) => __awaiter(this, void 0, void 0, function* () {
1788
+ const result = this.resolverGenerator || (yield resolver(req, res, ctx));
1789
+ if (isIterable(result)) {
1790
+ const { value, done } = result[Symbol.iterator]().next();
1791
+ const nextResponse = yield value;
1792
+ // If the generator is done and there is no next value,
1793
+ // return the previous generator's value.
1794
+ if (!nextResponse && done) {
1795
+ return this.resolverGeneratorResult;
1796
+ }
1797
+ if (!this.resolverGenerator) {
1798
+ this.resolverGenerator = result;
1799
+ }
1800
+ this.resolverGeneratorResult = nextResponse;
1801
+ return nextResponse;
1802
+ }
1803
+ return result;
1804
+ });
1805
+ }
1774
1806
  createExecutionResult(parsedResult, request, response) {
1775
1807
  return {
1776
1808
  handler: this,
@@ -1781,4 +1813,4 @@ class RequestHandler {
1781
1813
  }
1782
1814
  }
1783
1815
 
1784
- export { NetworkError as N, RequestHandler as R, __awaiter as _, defaultContext as a, compose as b, createResponseComposition as c, defaultResponse as d, getUrlByMask as e, prepareRequest as f, getPublicUrlFromRequest as g, prepareResponse as h, getTimestamp as i, getStatusCodeColor as j, __rest as k, matchRequestUrl as m, parseBody as p, response as r };
1816
+ export { NetworkError as N, RequestHandler as R, __awaiter as _, getCleanUrl$1 as a, defaultContext as b, createResponseComposition as c, defaultResponse as d, compose as e, getUrlByMask as f, getPublicUrlFromRequest as g, prepareRequest as h, prepareResponse as i, getTimestamp as j, getStatusCodeColor as k, __rest as l, matchRequestUrl as m, parseBody as p, response as r };