msw 0.34.0 → 0.36.2

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 (49) hide show
  1. package/lib/esm/RequestHandler-deps.js +391 -66
  2. package/lib/esm/errors-deps.js +15 -1
  3. package/lib/esm/fetch-deps.js +9 -5
  4. package/lib/esm/graphql-deps.js +10 -6
  5. package/lib/esm/graphql.js +1 -0
  6. package/lib/esm/index-deps.js +2 -1
  7. package/lib/esm/index.js +102 -3893
  8. package/lib/esm/index2.js +1 -1
  9. package/lib/esm/mockServiceWorker.js +5 -5
  10. package/lib/esm/rest-deps.js +7 -15
  11. package/lib/esm/rest.js +1 -0
  12. package/lib/iife/index.js +3 -3
  13. package/lib/iife/mockServiceWorker.js +5 -5
  14. package/lib/types/context/data.d.ts +2 -3
  15. package/lib/types/context/extensions.d.ts +8 -0
  16. package/lib/types/context/index.d.ts +1 -0
  17. package/lib/types/graphql.d.ts +2 -1
  18. package/lib/types/handlers/GraphQLHandler.d.ts +7 -6
  19. package/lib/types/handlers/RequestHandler.d.ts +8 -8
  20. package/lib/types/handlers/RestHandler.d.ts +10 -12
  21. package/lib/types/index.d.ts +17 -7
  22. package/lib/types/native/index.d.ts +1 -1
  23. package/lib/types/node/glossary.d.ts +4 -14
  24. package/lib/types/node/index.d.ts +1 -1
  25. package/lib/types/node/setupServer.d.ts +1 -1
  26. package/lib/types/rest.d.ts +10 -9
  27. package/lib/types/setupWorker/glossary.d.ts +16 -26
  28. package/lib/types/setupWorker/start/utils/prepareStartHandler.d.ts +3 -3
  29. package/lib/types/sharedOptions.d.ts +12 -1
  30. package/lib/types/typeUtils.d.ts +5 -3
  31. package/lib/types/utils/getResponse.d.ts +1 -1
  32. package/lib/types/utils/handleRequest.d.ts +4 -4
  33. package/lib/types/utils/internal/getCallFrame.d.ts +1 -1
  34. package/lib/types/utils/internal/jsonParse.d.ts +2 -2
  35. package/lib/types/utils/internal/pipeEvents.d.ts +6 -0
  36. package/lib/types/utils/internal/requestHandlerUtils.d.ts +1 -1
  37. package/lib/types/utils/logging/prepareResponse.d.ts +1 -1
  38. package/lib/types/utils/matching/matchRequestUrl.d.ts +12 -2
  39. package/lib/types/utils/matching/normalizePath.d.ts +1 -1
  40. package/lib/types/utils/request/onUnhandledRequest.d.ts +1 -2
  41. package/lib/types/utils/request/parseBody.d.ts +2 -2
  42. package/lib/types/utils/request/parseWorkerRequest.d.ts +2 -2
  43. package/lib/types/utils/worker/createFallbackRequestListener.d.ts +2 -1
  44. package/lib/types/utils/worker/createRequestListener.d.ts +2 -1
  45. package/lib/umd/index.js +1070 -243
  46. package/lib/umd/mockServiceWorker.js +5 -5
  47. package/native/lib/index.js +501 -501
  48. package/node/lib/index.js +503 -503
  49. package/package.json +19 -19
@@ -1,4 +1,5 @@
1
1
  import { c as commonjsGlobal, l as lib$1, j as jsonParse, s as status, b as set, e as delay, f as fetch } from './fetch-deps.js';
2
+ import { getCleanUrl } from '@mswjs/interceptors/lib/utils/getCleanUrl';
2
3
 
3
4
  /*! *****************************************************************************
4
5
  Copyright (c) Microsoft Corporation.
@@ -279,25 +280,25 @@ function parseMultipartData(data, headers) {
279
280
  }
280
281
 
281
282
  /**
282
- * Parses a given request/response body based on the `Content-Type` header.
283
+ * Parses a given request/response body based on the "Content-Type" header.
283
284
  */
284
285
  function parseBody(body, headers) {
285
286
  // Return whatever falsey body value is given.
286
287
  if (!body) {
287
288
  return body;
288
289
  }
289
- const contentType = headers === null || headers === void 0 ? void 0 : headers.get('content-type');
290
+ const contentType = (headers === null || headers === void 0 ? void 0 : headers.get('content-type')) || '';
290
291
  // If the body has a Multipart Content-Type
291
292
  // parse it into an object.
292
- const hasMultipartContent = contentType === null || contentType === void 0 ? void 0 : contentType.startsWith('multipart/form-data');
293
+ const hasMultipartContent = contentType.startsWith('multipart/form-data');
293
294
  if (hasMultipartContent && typeof body !== 'object') {
294
- return parseMultipartData(body, headers) || body;
295
+ return parseMultipartData(body.toString(), headers) || body;
295
296
  }
296
297
  // If the intercepted request's body has a JSON Content-Type
297
298
  // parse it into an object.
298
- const hasJsonContent = contentType === null || contentType === void 0 ? void 0 : contentType.includes('json');
299
+ const hasJsonContent = contentType.includes('json');
299
300
  if (hasJsonContent && typeof body !== 'object') {
300
- return jsonParse(body) || body;
301
+ return jsonParse(body.toString()) || body;
301
302
  }
302
303
  // Otherwise leave as-is.
303
304
  return body;
@@ -361,57 +362,339 @@ function prepareResponse(res) {
361
362
  body: parseBody(res.body, responseHeaders) });
362
363
  }
363
364
 
364
- /**
365
- * Converts a string path to a Regular Expression.
366
- * Transforms path parameters into named RegExp groups.
367
- */
368
- const pathToRegExp = (path) => {
369
- const pattern = path
370
- // Escape literal dots
371
- .replace(/\./g, '\\.')
372
- // Escape literal slashes
373
- .replace(/\//g, '/')
374
- // Escape literal question marks
375
- .replace(/\?/g, '\\?')
376
- // Ignore trailing slashes
377
- .replace(/\/+$/, '')
378
- // Replace wildcard with any zero-to-any character sequence
379
- .replace(/\*+/g, '.*')
380
- // Replace parameters with named capturing groups
381
- .replace(/:([^\d|^\/][a-zA-Z0-9_]*(?=(?:\/|\\.)|$))/g, (_, paramName) => `(?<${paramName}>[^\/]+?)`)
382
- // Allow optional trailing slash
383
- .concat('(\\/|$)');
384
- return new RegExp(pattern, 'gi');
385
- };
386
-
387
- /**
388
- * Matches a given url against a path.
389
- */
390
- const match = (path, url) => {
391
- const expression = path instanceof RegExp ? path : pathToRegExp(path);
392
- const match = expression.exec(url) || false;
393
- // Matches in strict mode: match string should equal to input (url)
394
- // Otherwise loose matches will be considered truthy:
395
- // match('/messages/:id', '/messages/123/users') // true
396
- const matches = path instanceof RegExp ? !!match : !!match && match[0] === match.input;
397
- return {
398
- matches,
399
- params: match && matches ? match.groups || null : null,
400
- };
401
- };
402
-
403
- var getCleanUrl$1 = {};
404
-
405
- Object.defineProperty(getCleanUrl$1, "__esModule", { value: true });
406
- var getCleanUrl_2 = getCleanUrl$1.getCleanUrl = void 0;
407
365
  /**
408
- * Removes query parameters and hashes from a given URL.
366
+ * Tokenize input string.
367
+ */
368
+ function lexer(str) {
369
+ var tokens = [];
370
+ var i = 0;
371
+ while (i < str.length) {
372
+ var char = str[i];
373
+ if (char === "*" || char === "+" || char === "?") {
374
+ tokens.push({ type: "MODIFIER", index: i, value: str[i++] });
375
+ continue;
376
+ }
377
+ if (char === "\\") {
378
+ tokens.push({ type: "ESCAPED_CHAR", index: i++, value: str[i++] });
379
+ continue;
380
+ }
381
+ if (char === "{") {
382
+ tokens.push({ type: "OPEN", index: i, value: str[i++] });
383
+ continue;
384
+ }
385
+ if (char === "}") {
386
+ tokens.push({ type: "CLOSE", index: i, value: str[i++] });
387
+ continue;
388
+ }
389
+ if (char === ":") {
390
+ var name = "";
391
+ var j = i + 1;
392
+ while (j < str.length) {
393
+ var code = str.charCodeAt(j);
394
+ if (
395
+ // `0-9`
396
+ (code >= 48 && code <= 57) ||
397
+ // `A-Z`
398
+ (code >= 65 && code <= 90) ||
399
+ // `a-z`
400
+ (code >= 97 && code <= 122) ||
401
+ // `_`
402
+ code === 95) {
403
+ name += str[j++];
404
+ continue;
405
+ }
406
+ break;
407
+ }
408
+ if (!name)
409
+ throw new TypeError("Missing parameter name at " + i);
410
+ tokens.push({ type: "NAME", index: i, value: name });
411
+ i = j;
412
+ continue;
413
+ }
414
+ if (char === "(") {
415
+ var count = 1;
416
+ var pattern = "";
417
+ var j = i + 1;
418
+ if (str[j] === "?") {
419
+ throw new TypeError("Pattern cannot start with \"?\" at " + j);
420
+ }
421
+ while (j < str.length) {
422
+ if (str[j] === "\\") {
423
+ pattern += str[j++] + str[j++];
424
+ continue;
425
+ }
426
+ if (str[j] === ")") {
427
+ count--;
428
+ if (count === 0) {
429
+ j++;
430
+ break;
431
+ }
432
+ }
433
+ else if (str[j] === "(") {
434
+ count++;
435
+ if (str[j + 1] !== "?") {
436
+ throw new TypeError("Capturing groups are not allowed at " + j);
437
+ }
438
+ }
439
+ pattern += str[j++];
440
+ }
441
+ if (count)
442
+ throw new TypeError("Unbalanced pattern at " + i);
443
+ if (!pattern)
444
+ throw new TypeError("Missing pattern at " + i);
445
+ tokens.push({ type: "PATTERN", index: i, value: pattern });
446
+ i = j;
447
+ continue;
448
+ }
449
+ tokens.push({ type: "CHAR", index: i, value: str[i++] });
450
+ }
451
+ tokens.push({ type: "END", index: i, value: "" });
452
+ return tokens;
453
+ }
454
+ /**
455
+ * Parse a string for the raw tokens.
456
+ */
457
+ function parse(str, options) {
458
+ if (options === void 0) { options = {}; }
459
+ var tokens = lexer(str);
460
+ var _a = options.prefixes, prefixes = _a === void 0 ? "./" : _a;
461
+ var defaultPattern = "[^" + escapeString(options.delimiter || "/#?") + "]+?";
462
+ var result = [];
463
+ var key = 0;
464
+ var i = 0;
465
+ var path = "";
466
+ var tryConsume = function (type) {
467
+ if (i < tokens.length && tokens[i].type === type)
468
+ return tokens[i++].value;
469
+ };
470
+ var mustConsume = function (type) {
471
+ var value = tryConsume(type);
472
+ if (value !== undefined)
473
+ return value;
474
+ var _a = tokens[i], nextType = _a.type, index = _a.index;
475
+ throw new TypeError("Unexpected " + nextType + " at " + index + ", expected " + type);
476
+ };
477
+ var consumeText = function () {
478
+ var result = "";
479
+ var value;
480
+ // tslint:disable-next-line
481
+ while ((value = tryConsume("CHAR") || tryConsume("ESCAPED_CHAR"))) {
482
+ result += value;
483
+ }
484
+ return result;
485
+ };
486
+ while (i < tokens.length) {
487
+ var char = tryConsume("CHAR");
488
+ var name = tryConsume("NAME");
489
+ var pattern = tryConsume("PATTERN");
490
+ if (name || pattern) {
491
+ var prefix = char || "";
492
+ if (prefixes.indexOf(prefix) === -1) {
493
+ path += prefix;
494
+ prefix = "";
495
+ }
496
+ if (path) {
497
+ result.push(path);
498
+ path = "";
499
+ }
500
+ result.push({
501
+ name: name || key++,
502
+ prefix: prefix,
503
+ suffix: "",
504
+ pattern: pattern || defaultPattern,
505
+ modifier: tryConsume("MODIFIER") || ""
506
+ });
507
+ continue;
508
+ }
509
+ var value = char || tryConsume("ESCAPED_CHAR");
510
+ if (value) {
511
+ path += value;
512
+ continue;
513
+ }
514
+ if (path) {
515
+ result.push(path);
516
+ path = "";
517
+ }
518
+ var open = tryConsume("OPEN");
519
+ if (open) {
520
+ var prefix = consumeText();
521
+ var name_1 = tryConsume("NAME") || "";
522
+ var pattern_1 = tryConsume("PATTERN") || "";
523
+ var suffix = consumeText();
524
+ mustConsume("CLOSE");
525
+ result.push({
526
+ name: name_1 || (pattern_1 ? key++ : ""),
527
+ pattern: name_1 && !pattern_1 ? defaultPattern : pattern_1,
528
+ prefix: prefix,
529
+ suffix: suffix,
530
+ modifier: tryConsume("MODIFIER") || ""
531
+ });
532
+ continue;
533
+ }
534
+ mustConsume("END");
535
+ }
536
+ return result;
537
+ }
538
+ /**
539
+ * Create path match function from `path-to-regexp` spec.
540
+ */
541
+ function match(str, options) {
542
+ var keys = [];
543
+ var re = pathToRegexp(str, keys, options);
544
+ return regexpToFunction(re, keys, options);
545
+ }
546
+ /**
547
+ * Create a path match function from `path-to-regexp` output.
409
548
  */
410
- function getCleanUrl(url, isAbsolute) {
411
- if (isAbsolute === void 0) { isAbsolute = true; }
412
- return [isAbsolute && url.origin, url.pathname].filter(Boolean).join('');
549
+ function regexpToFunction(re, keys, options) {
550
+ if (options === void 0) { options = {}; }
551
+ var _a = options.decode, decode = _a === void 0 ? function (x) { return x; } : _a;
552
+ return function (pathname) {
553
+ var m = re.exec(pathname);
554
+ if (!m)
555
+ return false;
556
+ var path = m[0], index = m.index;
557
+ var params = Object.create(null);
558
+ var _loop_1 = function (i) {
559
+ // tslint:disable-next-line
560
+ if (m[i] === undefined)
561
+ return "continue";
562
+ var key = keys[i - 1];
563
+ if (key.modifier === "*" || key.modifier === "+") {
564
+ params[key.name] = m[i].split(key.prefix + key.suffix).map(function (value) {
565
+ return decode(value, key);
566
+ });
567
+ }
568
+ else {
569
+ params[key.name] = decode(m[i], key);
570
+ }
571
+ };
572
+ for (var i = 1; i < m.length; i++) {
573
+ _loop_1(i);
574
+ }
575
+ return { path: path, index: index, params: params };
576
+ };
577
+ }
578
+ /**
579
+ * Escape a regular expression string.
580
+ */
581
+ function escapeString(str) {
582
+ return str.replace(/([.+*?=^!:${}()[\]|/\\])/g, "\\$1");
583
+ }
584
+ /**
585
+ * Get the flags for a regexp from the options.
586
+ */
587
+ function flags(options) {
588
+ return options && options.sensitive ? "" : "i";
589
+ }
590
+ /**
591
+ * Pull out keys from a regexp.
592
+ */
593
+ function regexpToRegexp(path, keys) {
594
+ if (!keys)
595
+ return path;
596
+ var groupsRegex = /\((?:\?<(.*?)>)?(?!\?)/g;
597
+ var index = 0;
598
+ var execResult = groupsRegex.exec(path.source);
599
+ while (execResult) {
600
+ keys.push({
601
+ // Use parenthesized substring match if available, index otherwise
602
+ name: execResult[1] || index++,
603
+ prefix: "",
604
+ suffix: "",
605
+ modifier: "",
606
+ pattern: ""
607
+ });
608
+ execResult = groupsRegex.exec(path.source);
609
+ }
610
+ return path;
611
+ }
612
+ /**
613
+ * Transform an array into a regexp.
614
+ */
615
+ function arrayToRegexp(paths, keys, options) {
616
+ var parts = paths.map(function (path) { return pathToRegexp(path, keys, options).source; });
617
+ return new RegExp("(?:" + parts.join("|") + ")", flags(options));
618
+ }
619
+ /**
620
+ * Create a path regexp from string input.
621
+ */
622
+ function stringToRegexp(path, keys, options) {
623
+ return tokensToRegexp(parse(path, options), keys, options);
624
+ }
625
+ /**
626
+ * Expose a function for taking tokens and returning a RegExp.
627
+ */
628
+ function tokensToRegexp(tokens, keys, options) {
629
+ if (options === void 0) { options = {}; }
630
+ var _a = options.strict, strict = _a === void 0 ? false : _a, _b = options.start, start = _b === void 0 ? true : _b, _c = options.end, end = _c === void 0 ? true : _c, _d = options.encode, encode = _d === void 0 ? function (x) { return x; } : _d;
631
+ var endsWith = "[" + escapeString(options.endsWith || "") + "]|$";
632
+ var delimiter = "[" + escapeString(options.delimiter || "/#?") + "]";
633
+ var route = start ? "^" : "";
634
+ // Iterate over the tokens and create our regexp string.
635
+ for (var _i = 0, tokens_1 = tokens; _i < tokens_1.length; _i++) {
636
+ var token = tokens_1[_i];
637
+ if (typeof token === "string") {
638
+ route += escapeString(encode(token));
639
+ }
640
+ else {
641
+ var prefix = escapeString(encode(token.prefix));
642
+ var suffix = escapeString(encode(token.suffix));
643
+ if (token.pattern) {
644
+ if (keys)
645
+ keys.push(token);
646
+ if (prefix || suffix) {
647
+ if (token.modifier === "+" || token.modifier === "*") {
648
+ var mod = token.modifier === "*" ? "?" : "";
649
+ route += "(?:" + prefix + "((?:" + token.pattern + ")(?:" + suffix + prefix + "(?:" + token.pattern + "))*)" + suffix + ")" + mod;
650
+ }
651
+ else {
652
+ route += "(?:" + prefix + "(" + token.pattern + ")" + suffix + ")" + token.modifier;
653
+ }
654
+ }
655
+ else {
656
+ route += "(" + token.pattern + ")" + token.modifier;
657
+ }
658
+ }
659
+ else {
660
+ route += "(?:" + prefix + suffix + ")" + token.modifier;
661
+ }
662
+ }
663
+ }
664
+ if (end) {
665
+ if (!strict)
666
+ route += delimiter + "?";
667
+ route += !options.endsWith ? "$" : "(?=" + endsWith + ")";
668
+ }
669
+ else {
670
+ var endToken = tokens[tokens.length - 1];
671
+ var isEndDelimited = typeof endToken === "string"
672
+ ? delimiter.indexOf(endToken[endToken.length - 1]) > -1
673
+ : // tslint:disable-next-line
674
+ endToken === undefined;
675
+ if (!strict) {
676
+ route += "(?:" + delimiter + "(?=" + endsWith + "))?";
677
+ }
678
+ if (!isEndDelimited) {
679
+ route += "(?=" + delimiter + "|" + endsWith + ")";
680
+ }
681
+ }
682
+ return new RegExp(route, flags(options));
683
+ }
684
+ /**
685
+ * Normalize the given path string, returning a regular expression.
686
+ *
687
+ * An empty array can be passed in for the keys, which will hold the
688
+ * placeholder key descriptions. For example, using `/user/:id`, `keys` will
689
+ * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.
690
+ */
691
+ function pathToRegexp(path, keys, options) {
692
+ if (path instanceof RegExp)
693
+ return regexpToRegexp(path, keys);
694
+ if (Array.isArray(path))
695
+ return arrayToRegexp(path, keys, options);
696
+ return stringToRegexp(path, keys, options);
413
697
  }
414
- getCleanUrl_2 = getCleanUrl$1.getCleanUrl = getCleanUrl;
415
698
 
416
699
  const REDUNDANT_CHARACTERS_EXP = /[\?|#].*$/g;
417
700
  function getSearchParams(path) {
@@ -433,9 +716,12 @@ function getAbsoluteUrl(path, baseUrl) {
433
716
  return path;
434
717
  }
435
718
  // Resolve a relative request URL against a given custom "baseUrl"
436
- // or the current location (in the case of browser/browser-like environments).
437
- const origin = baseUrl || (typeof location !== 'undefined' && location.origin);
438
- return origin ? new URL(path, origin).href : path;
719
+ // or the document baseURI (in the case of browser/browser-like environments).
720
+ const origin = baseUrl || (typeof document !== 'undefined' && document.baseURI);
721
+ return origin
722
+ ? // Encode and decode the path to preserve escaped characters.
723
+ decodeURI(new URL(encodeURI(path), origin).href)
724
+ : path;
439
725
  }
440
726
 
441
727
  /**
@@ -454,12 +740,48 @@ function normalizePath(path, baseUrl) {
454
740
  return cleanUrl(maybeAbsoluteUrl);
455
741
  }
456
742
 
743
+ /**
744
+ * Coerce a path supported by MSW into a path
745
+ * supported by "path-to-regexp".
746
+ */
747
+ function coercePath(path) {
748
+ return (path
749
+ /**
750
+ * Replace wildcards ("*") with unnamed capturing groups
751
+ * because "path-to-regexp" doesn't support wildcards.
752
+ * Ignore path parameter' modifiers (i.e. ":name*").
753
+ */
754
+ .replace(/([:a-zA-Z_-]*)(\*{1,2})+/g, (_, parameterName, wildcard) => {
755
+ const expression = '(.*)';
756
+ if (!parameterName) {
757
+ return expression;
758
+ }
759
+ return parameterName.startsWith(':')
760
+ ? `${parameterName}${wildcard}`
761
+ : `${parameterName}${expression}`;
762
+ })
763
+ /**
764
+ * Escape the protocol so that "path-to-regexp" could match
765
+ * absolute URL.
766
+ * @see https://github.com/pillarjs/path-to-regexp/issues/259
767
+ */
768
+ .replace(/^([^\/]+)(:)(?=\/\/)/g, '$1\\$2'));
769
+ }
457
770
  /**
458
771
  * Returns the result of matching given request URL against a mask.
459
772
  */
460
773
  function matchRequestUrl(url, path, baseUrl) {
461
774
  const normalizedPath = normalizePath(path, baseUrl);
462
- return match(normalizedPath, getCleanUrl_2(url));
775
+ const cleanPath = typeof normalizedPath === 'string'
776
+ ? coercePath(normalizedPath)
777
+ : normalizedPath;
778
+ const cleanUrl = getCleanUrl(url);
779
+ const result = match(cleanPath, { decode: decodeURIComponent })(cleanUrl);
780
+ const params = (result && result.params) || {};
781
+ return {
782
+ matches: result !== false,
783
+ params,
784
+ };
463
785
  }
464
786
 
465
787
  /**
@@ -508,18 +830,21 @@ const response = Object.assign(createResponseComposition(), {
508
830
  },
509
831
  });
510
832
 
833
+ const BUILD_FRAME = /(node_modules)?[\/\\]lib[\/\\](umd|esm|iief|cjs)[\/\\]|^[^\/\\]*$/;
511
834
  /**
512
835
  * Return the stack trace frame of a function's invocation.
513
836
  */
514
- function getCallFrame() {
837
+ function getCallFrame(error) {
515
838
  // In <IE11, new Error may return an undefined stack
516
- const stack = (new Error().stack || '');
517
- const frames = stack.split('\n');
839
+ const stack = error.stack;
840
+ if (!stack) {
841
+ return;
842
+ }
843
+ const frames = stack.split('\n').slice(1);
518
844
  // Get the first frame that doesn't reference the library's internal trace.
519
845
  // Assume that frame is the invocation frame.
520
- const ignoreFrameRegExp = /(node_modules)?[\/\\]lib[\/\\](umd|esm|iief|cjs)[\/\\]|^[^\/\\]*$/;
521
- const declarationFrame = frames.slice(1).find((frame) => {
522
- return !ignoreFrameRegExp.test(frame);
846
+ const declarationFrame = frames.find((frame) => {
847
+ return !BUILD_FRAME.test(frame);
523
848
  });
524
849
  if (!declarationFrame) {
525
850
  return;
@@ -552,7 +877,7 @@ class RequestHandler {
552
877
  this.shouldSkip = false;
553
878
  this.ctx = options.ctx || defaultContext;
554
879
  this.resolver = options.resolver;
555
- const callFrame = getCallFrame();
880
+ const callFrame = getCallFrame(new Error());
556
881
  this.info = Object.assign(Object.assign({}, options.info), { callFrame });
557
882
  }
558
883
  /**
@@ -630,4 +955,4 @@ class RequestHandler {
630
955
  }
631
956
  }
632
957
 
633
- export { NetworkError as N, RequestHandler as R, __awaiter as _, getCleanUrl$1 as a, defaultResponse as b, createResponseComposition as c, devUtils as d, defaultContext as e, compose as f, getPublicUrlFromRequest as g, cleanUrl as h, getSearchParams as i, prepareRequest as j, prepareResponse as k, lib as l, matchRequestUrl as m, getStatusCodeColor as n, getTimestamp as o, parseBody as p, __rest as q, response as r };
958
+ export { NetworkError as N, RequestHandler as R, __awaiter as _, defaultResponse as a, defaultContext as b, createResponseComposition as c, devUtils as d, compose as e, cleanUrl as f, getPublicUrlFromRequest as g, getSearchParams as h, prepareRequest as i, prepareResponse as j, getStatusCodeColor as k, getTimestamp as l, matchRequestUrl as m, __rest as n, parseBody as p, response as r };
@@ -41,6 +41,20 @@ const data = (payload) => {
41
41
  };
42
42
  };
43
43
 
44
+ /**
45
+ * Sets the GraphQL extensions on a given response.
46
+ * @example
47
+ * res(ctx.extensions({ tracing: { version: 1 }}))
48
+ * @see {@link https://mswjs.io/docs/api/context/extensions `ctx.extensions()`}
49
+ */
50
+ const extensions = (payload) => {
51
+ return (res) => {
52
+ const prevBody = jsonParse(res.body) || {};
53
+ const nextBody = mergeRight(prevBody, { extensions: payload });
54
+ return json(nextBody)(res);
55
+ };
56
+ };
57
+
44
58
  /**
45
59
  * Sets a given list of GraphQL errors on the mocked response.
46
60
  * @example res(ctx.errors([{ message: 'Unauthorized' }]))
@@ -57,4 +71,4 @@ const errors = (errorsList) => {
57
71
  };
58
72
  };
59
73
 
60
- export { data as d, errors as e, mergeRight as m };
74
+ export { errors as a, data as d, extensions as e, mergeRight as m };
@@ -851,12 +851,12 @@ const cookie = (name, value, options) => {
851
851
  };
852
852
 
853
853
  /**
854
- * Parses a given string into a JSON.
854
+ * Parses a given value into a JSON.
855
855
  * Does not throw an exception on an invalid JSON string.
856
856
  */
857
- function jsonParse(str) {
857
+ function jsonParse(value) {
858
858
  try {
859
- return JSON.parse(str);
859
+ return JSON.parse(value);
860
860
  }
861
861
  catch (error) {
862
862
  return undefined;
@@ -974,8 +974,12 @@ const createFetchRequestParameters = (input) => {
974
974
  if (['GET', 'HEAD'].includes(method)) {
975
975
  return requestParameters;
976
976
  }
977
- requestParameters.body =
978
- typeof body === 'object' ? JSON.stringify(body) : body;
977
+ if (typeof body === 'object' || typeof body === 'number') {
978
+ requestParameters.body = JSON.stringify(body);
979
+ }
980
+ else {
981
+ requestParameters.body = body;
982
+ }
979
983
  return requestParameters;
980
984
  };
981
985
  /**
@@ -1,6 +1,6 @@
1
1
  import { j as jsonParse, b as set, s as status, e as delay, f as fetch, d as cookie } from './fetch-deps.js';
2
- import { d as data, e as errors } from './errors-deps.js';
3
- import { g as getPublicUrlFromRequest, d as devUtils, q as __rest, R as RequestHandler, m as matchRequestUrl, j as prepareRequest, k as prepareResponse, n as getStatusCodeColor, o as getTimestamp } from './RequestHandler-deps.js';
2
+ import { d as data, e as extensions, a as errors } from './errors-deps.js';
3
+ import { g as getPublicUrlFromRequest, d as devUtils, n as __rest, R as RequestHandler, m as matchRequestUrl, i as prepareRequest, j as prepareResponse, k as getStatusCodeColor, l as getTimestamp } from './RequestHandler-deps.js';
4
4
 
5
5
  function _typeof$3(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof$3 = function _typeof(obj) { return typeof obj; }; } else { _typeof$3 = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof$3(obj); }
6
6
 
@@ -3243,6 +3243,7 @@ const graphqlContext = {
3243
3243
  delay,
3244
3244
  fetch,
3245
3245
  data,
3246
+ extensions,
3246
3247
  errors,
3247
3248
  cookie,
3248
3249
  };
@@ -3289,10 +3290,10 @@ class GraphQLHandler extends RequestHandler {
3289
3290
  if (!parsedResult) {
3290
3291
  return false;
3291
3292
  }
3292
- if (!parsedResult.operationName) {
3293
+ if (!parsedResult.operationName && this.info.operationType !== 'all') {
3293
3294
  const publicUrl = getPublicUrlFromRequest(request);
3294
3295
  devUtils.warn(`\
3295
- Failed to intercept a GraphQL request at "${request.method} ${publicUrl}": unnamed GraphQL operations are not supported.
3296
+ Failed to intercept a GraphQL request at "${request.method} ${publicUrl}": anonymous GraphQL operations are not supported.
3296
3297
 
3297
3298
  Consider naming this operation or using "graphql.operation" request handler to intercept GraphQL requests regardless of their operation name/type. Read more: https://mswjs.io/docs/api/graphql/operation\
3298
3299
  `);
@@ -3302,7 +3303,7 @@ Consider naming this operation or using "graphql.operation" request handler to i
3302
3303
  const hasMatchingOperationType = this.info.operationType === 'all' ||
3303
3304
  parsedResult.operationType === this.info.operationType;
3304
3305
  const hasMatchingOperationName = this.info.operationName instanceof RegExp
3305
- ? this.info.operationName.test(parsedResult.operationName)
3306
+ ? this.info.operationName.test(parsedResult.operationName || '')
3306
3307
  : parsedResult.operationName === this.info.operationName;
3307
3308
  return (hasMatchingUrl.matches &&
3308
3309
  hasMatchingOperationType &&
@@ -3312,7 +3313,10 @@ Consider naming this operation or using "graphql.operation" request handler to i
3312
3313
  const loggedRequest = prepareRequest(request);
3313
3314
  const loggedResponse = prepareResponse(response);
3314
3315
  const statusColor = getStatusCodeColor(response.status);
3315
- console.groupCollapsed(devUtils.formatMessage('%s %s (%c%s%c)'), getTimestamp(), `${parsedRequest === null || parsedRequest === void 0 ? void 0 : parsedRequest.operationType} ${parsedRequest === null || parsedRequest === void 0 ? void 0 : parsedRequest.operationName}`, `color:${statusColor}`, `${response.status} ${response.statusText}`, 'color:inherit');
3316
+ const requestInfo = (parsedRequest === null || parsedRequest === void 0 ? void 0 : parsedRequest.operationName)
3317
+ ? `${parsedRequest === null || parsedRequest === void 0 ? void 0 : parsedRequest.operationType} ${parsedRequest === null || parsedRequest === void 0 ? void 0 : parsedRequest.operationName}`
3318
+ : `anonymous ${parsedRequest === null || parsedRequest === void 0 ? void 0 : parsedRequest.operationType}`;
3319
+ console.groupCollapsed(devUtils.formatMessage('%s %s (%c%s%c)'), getTimestamp(), `${requestInfo}`, `color:${statusColor}`, `${response.status} ${response.statusText}`, 'color:inherit');
3316
3320
  console.log('Request:', loggedRequest);
3317
3321
  console.log('Handler:', this);
3318
3322
  console.log('Response:', loggedResponse);
@@ -2,3 +2,4 @@ export { g as graphql } from './graphql-deps.js';
2
2
  import './fetch-deps.js';
3
3
  import './errors-deps.js';
4
4
  import './RequestHandler-deps.js';
5
+ import '@mswjs/interceptors/lib/utils/getCleanUrl';
@@ -1,6 +1,6 @@
1
1
  import { s as status, b as set, d as cookie, e as delay, f as fetch, g as json } from './fetch-deps.js';
2
2
  import { b as body, t as text, x as xml } from './xml-deps.js';
3
- import { d as data, e as errors } from './errors-deps.js';
3
+ import { d as data, e as extensions, a as errors } from './errors-deps.js';
4
4
 
5
5
  var index = /*#__PURE__*/Object.freeze({
6
6
  __proto__: null,
@@ -9,6 +9,7 @@ var index = /*#__PURE__*/Object.freeze({
9
9
  cookie: cookie,
10
10
  body: body,
11
11
  data: data,
12
+ extensions: extensions,
12
13
  delay: delay,
13
14
  errors: errors,
14
15
  fetch: fetch,