metro 0.83.3 → 0.84.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.
Files changed (158) hide show
  1. package/package.json +28 -25
  2. package/src/Assets.js +42 -29
  3. package/src/Assets.js.flow +26 -15
  4. package/src/Bundler/util.js +25 -21
  5. package/src/Bundler/util.js.flow +2 -2
  6. package/src/Bundler.js.flow +1 -1
  7. package/src/DeltaBundler/DeltaCalculator.js +4 -4
  8. package/src/DeltaBundler/DeltaCalculator.js.flow +8 -8
  9. package/src/DeltaBundler/Graph.js +16 -16
  10. package/src/DeltaBundler/Graph.js.flow +30 -30
  11. package/src/DeltaBundler/Serializers/baseJSBundle.js.flow +1 -1
  12. package/src/DeltaBundler/Serializers/getAllFiles.js.flow +2 -2
  13. package/src/DeltaBundler/Serializers/getAssets.js.flow +2 -2
  14. package/src/DeltaBundler/Serializers/getExplodedSourceMap.js.flow +2 -2
  15. package/src/DeltaBundler/Serializers/getRamBundleInfo.js.flow +8 -8
  16. package/src/DeltaBundler/Serializers/helpers/js.js +25 -21
  17. package/src/DeltaBundler/Serializers/helpers/js.js.flow +6 -6
  18. package/src/DeltaBundler/Serializers/helpers/processModules.js.flow +3 -3
  19. package/src/DeltaBundler/Serializers/hmrJSBundle.js +25 -21
  20. package/src/DeltaBundler/Serializers/hmrJSBundle.js.flow +5 -5
  21. package/src/DeltaBundler/Serializers/sourceMapGenerator.js.flow +6 -6
  22. package/src/DeltaBundler/Serializers/sourceMapObject.js.flow +2 -2
  23. package/src/DeltaBundler/Serializers/sourceMapString.js.flow +2 -2
  24. package/src/DeltaBundler/Transformer.js.flow +3 -3
  25. package/src/DeltaBundler/Worker.flow.js.flow +1 -1
  26. package/src/DeltaBundler/WorkerFarm.js +1 -1
  27. package/src/DeltaBundler/WorkerFarm.js.flow +26 -13
  28. package/src/DeltaBundler/buildSubgraph.js +4 -4
  29. package/src/DeltaBundler/buildSubgraph.js.flow +8 -8
  30. package/src/DeltaBundler/types.js.flow +36 -34
  31. package/src/DeltaBundler.js.flow +2 -2
  32. package/src/HmrServer.js +34 -29
  33. package/src/HmrServer.js.flow +17 -12
  34. package/src/IncrementalBundler.js +29 -21
  35. package/src/IncrementalBundler.js.flow +13 -9
  36. package/src/ModuleGraph/worker/JsFileWrapping.js +25 -21
  37. package/src/ModuleGraph/worker/JsFileWrapping.js.flow +10 -5
  38. package/src/ModuleGraph/worker/collectDependencies.js +25 -21
  39. package/src/ModuleGraph/worker/collectDependencies.js.flow +27 -21
  40. package/src/ModuleGraph/worker/generateImportNames.js.flow +4 -2
  41. package/src/ModuleGraph/worker/importLocationsPlugin.js.flow +7 -3
  42. package/src/Server/MultipartResponse.js.flow +1 -1
  43. package/src/Server/symbolicate.js.flow +4 -4
  44. package/src/Server.js +139 -39
  45. package/src/Server.js.flow +158 -47
  46. package/src/cli/parseKeyValueParamArray.js.flow +1 -1
  47. package/src/cli-utils.js.flow +2 -2
  48. package/src/commands/build.js.flow +11 -10
  49. package/src/commands/dependencies.js.flow +8 -4
  50. package/src/commands/serve.js +2 -0
  51. package/src/commands/serve.js.flow +14 -9
  52. package/src/index.flow.js +30 -26
  53. package/src/index.flow.js.flow +25 -20
  54. package/src/integration_tests/basic_bundle/AssetRegistry.js.flow +1 -1
  55. package/src/integration_tests/basic_bundle/ErrorBundle.js.flow +1 -1
  56. package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-import.js.flow +1 -1
  57. package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-multi-line-import-with-escapes.js.flow +1 -1
  58. package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-multi-line-import.js.flow +1 -1
  59. package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-require-with-embedded-comment.js.flow +1 -1
  60. package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-require.js.flow +1 -1
  61. package/src/integration_tests/basic_bundle/build-errors/cannot-resolve-specifier-with-escapes.js.flow +1 -1
  62. package/src/integration_tests/basic_bundle/build-errors/inline-requires-cannot-resolve-import.js.flow +1 -1
  63. package/src/integration_tests/basic_bundle/build-errors/inline-requires-cannot-resolve-require.js.flow +1 -1
  64. package/src/integration_tests/basic_bundle/import-export/index.js +25 -21
  65. package/src/integration_tests/basic_bundle/import-export/index.js.flow +3 -3
  66. package/src/integration_tests/basic_bundle/import-export/utils.js.flow +2 -2
  67. package/src/integration_tests/basic_bundle/loadBundleAsyncForTest.js.flow +1 -1
  68. package/src/integration_tests/basic_bundle/optional-dependencies/index.js.flow +1 -1
  69. package/src/integration_tests/basic_bundle/require-context/conflict.js.flow +1 -1
  70. package/src/integration_tests/basic_bundle/require-context/empty.js.flow +1 -1
  71. package/src/integration_tests/basic_bundle/require-context/matching.js.flow +1 -1
  72. package/src/integration_tests/basic_bundle/require-context/mode-eager.js.flow +1 -1
  73. package/src/integration_tests/basic_bundle/require-context/mode-lazy-once.js.flow +1 -1
  74. package/src/integration_tests/basic_bundle/require-context/mode-lazy.js.flow +1 -1
  75. package/src/integration_tests/basic_bundle/require-context/mode-sync.js.flow +2 -2
  76. package/src/integration_tests/basic_bundle/require-context/utils.js.flow +1 -1
  77. package/src/integration_tests/basic_bundle/require-resolveWeak/import-and-resolveWeak.js.flow +1 -1
  78. package/src/integration_tests/basic_bundle/require-resolveWeak/multiple.js.flow +1 -1
  79. package/src/integration_tests/basic_bundle/require-resolveWeak/never-required.js.flow +1 -1
  80. package/src/integration_tests/basic_bundle/require-resolveWeak/require-and-resolveWeak.js.flow +1 -1
  81. package/src/integration_tests/execBundle.js.flow +1 -1
  82. package/src/lib/BatchProcessor.js +5 -2
  83. package/src/lib/BatchProcessor.js.flow +10 -7
  84. package/src/lib/CountingSet.js.flow +4 -4
  85. package/src/lib/JsonReporter.js +5 -3
  86. package/src/lib/JsonReporter.js.flow +19 -17
  87. package/src/lib/RamBundleParser.js.flow +1 -1
  88. package/src/lib/TerminalReporter.js +31 -27
  89. package/src/lib/TerminalReporter.js.flow +15 -15
  90. package/src/lib/contextModule.js.flow +1 -1
  91. package/src/lib/contextModuleTemplates.js +25 -21
  92. package/src/lib/countLines.js +4 -3
  93. package/src/lib/countLines.js.flow +3 -4
  94. package/src/lib/createWebsocketServer.js +9 -2
  95. package/src/lib/createWebsocketServer.js.flow +16 -9
  96. package/src/lib/debounceAsyncQueue.js.flow +1 -1
  97. package/src/lib/formatBundlingError.js.flow +1 -1
  98. package/src/lib/getAppendScripts.js.flow +4 -4
  99. package/src/lib/getGraphId.js.flow +1 -1
  100. package/src/lib/getPreludeCode.js +4 -0
  101. package/src/lib/getPreludeCode.js.flow +10 -3
  102. package/src/lib/getPrependedScripts.js +36 -22
  103. package/src/lib/getPrependedScripts.js.flow +10 -3
  104. package/src/lib/logToConsole.js.flow +2 -2
  105. package/src/lib/parseBundleOptionsFromBundleRequestUrl.js +25 -21
  106. package/src/lib/parseCustomResolverOptions.js.flow +2 -2
  107. package/src/lib/parseCustomTransformOptions.js.flow +1 -1
  108. package/src/lib/parseJsonBody.js.flow +11 -1
  109. package/src/lib/pathUtils.js +25 -21
  110. package/src/lib/pathUtils.js.flow +1 -1
  111. package/src/lib/reporting.js.flow +4 -4
  112. package/src/lib/transformHelpers.js +11 -9
  113. package/src/lib/transformHelpers.js.flow +17 -15
  114. package/src/node-haste/DependencyGraph/ModuleResolution.js +48 -42
  115. package/src/node-haste/DependencyGraph/ModuleResolution.js.flow +35 -32
  116. package/src/node-haste/DependencyGraph/createFileMap.js +56 -38
  117. package/src/node-haste/DependencyGraph/createFileMap.js.flow +44 -18
  118. package/src/node-haste/DependencyGraph.js +40 -31
  119. package/src/node-haste/DependencyGraph.js.flow +35 -37
  120. package/src/node-haste/lib/AssetPaths.js +2 -2
  121. package/src/node-haste/lib/AssetPaths.js.flow +4 -4
  122. package/src/node-haste/lib/parsePlatformFilePath.js +6 -6
  123. package/src/node-haste/lib/parsePlatformFilePath.js.flow +4 -4
  124. package/src/shared/output/RamBundle/as-assets.js.flow +6 -6
  125. package/src/shared/output/RamBundle/as-indexed-file.js.flow +5 -5
  126. package/src/shared/output/RamBundle/buildSourcemapWithMetadata.js.flow +5 -5
  127. package/src/shared/output/RamBundle/util.js.flow +5 -5
  128. package/src/shared/output/RamBundle/write-sourcemap.js.flow +1 -1
  129. package/src/shared/output/RamBundle.js.flow +1 -1
  130. package/src/shared/output/bundle.flow.js.flow +3 -3
  131. package/src/shared/output/meta.js +2 -2
  132. package/src/shared/output/meta.js.flow +1 -1
  133. package/src/shared/output/writeFile.js +8 -3
  134. package/src/shared/output/writeFile.js.flow +8 -2
  135. package/src/shared/types.js.flow +20 -5
  136. package/src/Asset.d.ts +0 -25
  137. package/src/Bundler.d.ts +0 -39
  138. package/src/DeltaBundler/Graph.d.ts +0 -40
  139. package/src/DeltaBundler/Serializers/getExplodedSourceMap.d.ts +0 -26
  140. package/src/DeltaBundler/Serializers/getRamBundleInfo.d.ts +0 -18
  141. package/src/DeltaBundler/Worker.d.ts +0 -45
  142. package/src/DeltaBundler/types.d.ts +0 -166
  143. package/src/DeltaBundler.d.ts +0 -58
  144. package/src/IncrementalBundler.d.ts +0 -98
  145. package/src/ModuleGraph/test-helpers.js +0 -75
  146. package/src/ModuleGraph/worker/collectDependencies.d.ts +0 -27
  147. package/src/Server/MultipartResponse.d.ts +0 -31
  148. package/src/Server/symbolicate.d.ts +0 -31
  149. package/src/Server.d.ts +0 -118
  150. package/src/index.d.ts +0 -193
  151. package/src/lib/CountingSet.d.ts +0 -48
  152. package/src/lib/TerminalReporter.d.ts +0 -27
  153. package/src/lib/contextModule.d.ts +0 -22
  154. package/src/lib/getGraphId.d.ts +0 -11
  155. package/src/lib/reporting.d.ts +0 -144
  156. package/src/node-haste/DependencyGraph.d.ts +0 -62
  157. package/src/shared/output/bundle.d.ts +0 -35
  158. package/src/shared/types.d.ts +0 -130
package/src/Server.js CHANGED
@@ -51,7 +51,6 @@ var _symbolicate = _interopRequireDefault(require("./Server/symbolicate"));
51
51
  var _types = require("./shared/types");
52
52
  var _codeFrame = require("@babel/code-frame");
53
53
  var fs = _interopRequireWildcard(require("graceful-fs"));
54
- var _invariant = _interopRequireDefault(require("invariant"));
55
54
  var jscSafeUrl = _interopRequireWildcard(require("jsc-safe-url"));
56
55
  var _metroCore = require("metro-core");
57
56
  var _mimeTypes = _interopRequireDefault(require("mime-types"));
@@ -59,28 +58,32 @@ var _nullthrows = _interopRequireDefault(require("nullthrows"));
59
58
  var _path = _interopRequireDefault(require("path"));
60
59
  var _perf_hooks = require("perf_hooks");
61
60
  var _querystring = _interopRequireDefault(require("querystring"));
62
- function _getRequireWildcardCache(e) {
63
- if ("function" != typeof WeakMap) return null;
64
- var r = new WeakMap(),
65
- t = new WeakMap();
66
- return (_getRequireWildcardCache = function (e) {
67
- return e ? t : r;
68
- })(e);
69
- }
70
- function _interopRequireWildcard(e, r) {
71
- if (!r && e && e.__esModule) return e;
72
- if (null === e || ("object" != typeof e && "function" != typeof e))
73
- return { default: e };
74
- var t = _getRequireWildcardCache(r);
75
- if (t && t.has(e)) return t.get(e);
76
- var n = { __proto__: null },
77
- a = Object.defineProperty && Object.getOwnPropertyDescriptor;
78
- for (var u in e)
79
- if ("default" !== u && {}.hasOwnProperty.call(e, u)) {
80
- var i = a ? Object.getOwnPropertyDescriptor(e, u) : null;
81
- i && (i.get || i.set) ? Object.defineProperty(n, u, i) : (n[u] = e[u]);
61
+ function _interopRequireWildcard(e, t) {
62
+ if ("function" == typeof WeakMap)
63
+ var r = new WeakMap(),
64
+ n = new WeakMap();
65
+ return (_interopRequireWildcard = function (e, t) {
66
+ if (!t && e && e.__esModule) return e;
67
+ var o,
68
+ i,
69
+ f = { __proto__: null, default: e };
70
+ if (null === e || ("object" != typeof e && "function" != typeof e))
71
+ return f;
72
+ if ((o = t ? n : r)) {
73
+ if (o.has(e)) return o.get(e);
74
+ o.set(e, f);
82
75
  }
83
- return ((n.default = e), t && t.set(e, n), n);
76
+ for (const t in e)
77
+ "default" !== t &&
78
+ {}.hasOwnProperty.call(e, t) &&
79
+ ((i =
80
+ (o = Object.defineProperty) &&
81
+ Object.getOwnPropertyDescriptor(e, t)) &&
82
+ (i.get || i.set)
83
+ ? o(f, t, i)
84
+ : (f[t] = e[t]));
85
+ return f;
86
+ })(e, t);
84
87
  }
85
88
  function _interopRequireDefault(e) {
86
89
  return e && e.__esModule ? e : { default: e };
@@ -126,6 +129,8 @@ class Server {
126
129
  ]),
127
130
  ];
128
131
  this._isEnded = false;
132
+ this._fetchTimings = [];
133
+ this._activeFetchCount = 0;
129
134
  this._createModuleId = config.serializer.createModuleIdFactory();
130
135
  this._bundler = new _IncrementalBundler.default(config, {
131
136
  hasReducedPerformance: options && options.hasReducedPerformance,
@@ -433,12 +438,14 @@ class Server {
433
438
  }),
434
439
  );
435
440
  try {
441
+ const depGraph = await this._bundler.getBundler().getDependencyGraph();
436
442
  const data = await (0, _Assets.getAsset)(
437
443
  assetPath,
438
444
  this._config.projectRoot,
439
445
  this._config.watchFolders,
440
446
  urlObj.searchParams.get("platform"),
441
447
  this._config.resolver.assetExts,
448
+ (filePath) => depGraph.doesFileExist(filePath),
442
449
  );
443
450
  if (process.env.REACT_NATIVE_ENABLE_ASSET_CACHING === true) {
444
451
  res.setHeader("Cache-Control", "max-age=31536000");
@@ -481,6 +488,13 @@ class Server {
481
488
  debug("Rewritten to: %s", req.url);
482
489
  }
483
490
  const reqHost = req.headers["x-forwarded-host"] || req.headers["host"];
491
+ debug("Request host is: %s", req.headers["host"]);
492
+ if (req.headers["x-forwarded-host"]) {
493
+ debug(
494
+ "Request x-forwarded-host is: %s",
495
+ req.headers["x-forwarded-host"],
496
+ );
497
+ }
484
498
  if (!reqHost) {
485
499
  throw new Error("No host header was found.");
486
500
  }
@@ -729,8 +743,16 @@ class Server {
729
743
  const logEntry = log(
730
744
  createActionStartEntry(createStartEntry(startContext)),
731
745
  );
746
+ const fetchTiming = {
747
+ graphId,
748
+ startTime: requestStartTimestamp,
749
+ endTime: null,
750
+ isPrefetch: req.method === "HEAD",
751
+ };
732
752
  let result;
733
753
  try {
754
+ this._fetchTimings.push(fetchTiming);
755
+ this._activeFetchCount++;
734
756
  result = await build(startContext);
735
757
  } catch (error) {
736
758
  const formattedError = (0, _formatBundlingError.default)(error);
@@ -760,6 +782,31 @@ class Server {
760
782
  debug("Bundling error", error);
761
783
  buildContext.bundlePerfLogger.end("FAIL");
762
784
  return;
785
+ } finally {
786
+ fetchTiming.endTime =
787
+ _perf_hooks.performance.timeOrigin + _perf_hooks.performance.now();
788
+ if (!fetchTiming.isPrefetch) {
789
+ buildContext.bundlePerfLogger.annotate({
790
+ bool: {
791
+ had_competing_prefetch: this._fetchTimings
792
+ .filter((t) => t.isPrefetch && t.graphId !== graphId)
793
+ .some((prefetch) => {
794
+ const prefetchEndTime =
795
+ prefetch.endTime ?? Number.MAX_SAFE_INTEGER;
796
+ const fetchEndTime =
797
+ fetchTiming.endTime ?? Number.MAX_SAFE_INTEGER;
798
+ return (
799
+ prefetch.startTime < fetchEndTime &&
800
+ prefetchEndTime > fetchTiming.startTime
801
+ );
802
+ }),
803
+ },
804
+ });
805
+ }
806
+ this._activeFetchCount--;
807
+ if (this._activeFetchCount === 0) {
808
+ this._fetchTimings = [];
809
+ }
763
810
  }
764
811
  const endContext = {
765
812
  ...startContext,
@@ -784,6 +831,7 @@ class Server {
784
831
  return {
785
832
  action_name: "Requesting bundle",
786
833
  bundle_url: context.req.url,
834
+ bundle_original_url: context.req.originalUrl ?? "unknown",
787
835
  entry_point: context.entryFile,
788
836
  bundler: "delta",
789
837
  build_id: getBuildID(context.buildNumber),
@@ -1068,6 +1116,7 @@ class Server {
1068
1116
  },
1069
1117
  });
1070
1118
  async _symbolicate(req, res) {
1119
+ const depGraph = await this._bundler.getBundler().getDependencyGraph();
1071
1120
  const getCodeFrame = (urls, symbolicatedStack) => {
1072
1121
  const allFramesCollapsed = symbolicatedStack.every(
1073
1122
  ({ collapse }) => collapse,
@@ -1085,6 +1134,13 @@ class Server {
1085
1134
  this._config.projectRoot,
1086
1135
  file ?? "",
1087
1136
  );
1137
+ if (!depGraph.doesFileExist(fileAbsolute)) {
1138
+ debug(
1139
+ "Skipping code frame for file not in dependency graph.",
1140
+ fileAbsolute,
1141
+ );
1142
+ continue;
1143
+ }
1088
1144
  try {
1089
1145
  return {
1090
1146
  content: (0, _codeFrame.codeFrameColumns)(
@@ -1115,6 +1171,7 @@ class Server {
1115
1171
  }
1116
1172
  return null;
1117
1173
  };
1174
+ let inputValidated = false;
1118
1175
  try {
1119
1176
  const symbolicatingLogEntry = log(
1120
1177
  createActionStartEntry("Symbolicating"),
@@ -1125,25 +1182,68 @@ class Server {
1125
1182
  const body = await req.rawBody;
1126
1183
  parsedBody = JSON.parse(body);
1127
1184
  } else {
1128
- parsedBody = await (0, _parseJsonBody.default)(req);
1185
+ parsedBody = await (0, _parseJsonBody.default)(req, {
1186
+ strict: false,
1187
+ });
1129
1188
  }
1130
- const rewriteAndNormalizeStackFrame = (frame, lineNumber) => {
1131
- (0, _invariant.default)(
1132
- frame != null && typeof frame === "object",
1133
- "Bad stack frame at line %d, expected object, received: %s",
1134
- lineNumber,
1135
- typeof frame,
1189
+ let validatedBody;
1190
+ if (
1191
+ parsedBody != null &&
1192
+ typeof parsedBody === "object" &&
1193
+ !Array.isArray(parsedBody) &&
1194
+ Array.isArray(parsedBody["stack"])
1195
+ ) {
1196
+ const maybeStack = parsedBody["stack"];
1197
+ const extraData = parsedBody["extraData"];
1198
+ validatedBody = {
1199
+ stack: maybeStack,
1200
+ extraData,
1201
+ };
1202
+ } else {
1203
+ throw new Error(
1204
+ `Bad symbolication input, expected object with stack array, got: ${JSON.stringify(parsedBody)}`,
1136
1205
  );
1137
- const frameFile = frame.file;
1138
- if (typeof frameFile === "string" && frameFile.includes("://")) {
1139
- return {
1140
- ...frame,
1141
- file: this._rewriteAndNormalizeUrl(frameFile),
1142
- };
1206
+ }
1207
+ const validateAndNormalizeStackFrame = (frame) => {
1208
+ if (
1209
+ frame == null ||
1210
+ typeof frame !== "object" ||
1211
+ Array.isArray(frame)
1212
+ ) {
1213
+ throw new Error("Expected frame to be a JSON object");
1143
1214
  }
1144
- return frame;
1215
+ if (frame.file != null && typeof frame.file !== "string") {
1216
+ throw new Error("Expected file to be string or nullish");
1217
+ }
1218
+ let frameFile = frame.file;
1219
+ if (frameFile != null && frameFile.includes("://")) {
1220
+ frameFile = this._rewriteAndNormalizeUrl(frameFile);
1221
+ }
1222
+ if (frame.methodName != null && typeof frame.methodName !== "string") {
1223
+ throw new Error("Expected methodName to be string or nullish");
1224
+ }
1225
+ if (frame.lineNumber != null && typeof frame.lineNumber !== "number") {
1226
+ throw new Error("Expected lineNumber to be number or nullish");
1227
+ }
1228
+ if (frame.column != null && typeof frame.column !== "number") {
1229
+ throw new Error("Expected column to be number or nullish");
1230
+ }
1231
+ return {
1232
+ ...frame,
1233
+ file: frameFile,
1234
+ lineNumber: frame.lineNumber,
1235
+ column: frame.column,
1236
+ methodName: frame.methodName,
1237
+ };
1145
1238
  };
1146
- const stack = parsedBody.stack.map(rewriteAndNormalizeStackFrame);
1239
+ const stack = validatedBody.stack.map((frame, lineNumber) => {
1240
+ try {
1241
+ return validateAndNormalizeStackFrame(frame);
1242
+ } catch (e) {
1243
+ throw new Error(`Bad frame at line ${lineNumber}: ${e.message}`);
1244
+ }
1245
+ });
1246
+ inputValidated = true;
1147
1247
  const urls = new Set();
1148
1248
  stack.forEach((frame) => {
1149
1249
  const sourceUrl = frame.file;
@@ -1169,7 +1269,7 @@ class Server {
1169
1269
  stack,
1170
1270
  zip(urls.values(), sourceMaps),
1171
1271
  this._config,
1172
- parsedBody.extraData ?? {},
1272
+ validatedBody.extraData ?? {},
1173
1273
  );
1174
1274
  debug("Symbolication done");
1175
1275
  res.end(
@@ -1183,7 +1283,7 @@ class Server {
1183
1283
  });
1184
1284
  } catch (error) {
1185
1285
  debug("Symbolication failed", error.stack || error);
1186
- res.statusCode = 500;
1286
+ res.statusCode = inputValidated ? 500 : 400;
1187
1287
  res.end(
1188
1288
  JSON.stringify({
1189
1289
  error: error.message,