@jsenv/core 27.8.0 → 28.0.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 (38) hide show
  1. package/dist/js/autoreload.js +2 -2
  2. package/dist/js/html_supervisor_installer.js +3 -3
  3. package/dist/js/server_events_client.js +1 -1
  4. package/dist/main.js +520 -469
  5. package/package.json +2 -2
  6. package/readme.md +1 -1
  7. package/src/build/build.js +8 -8
  8. package/src/build/{resync_ressource_hints.js → resync_resource_hints.js} +10 -12
  9. package/src/build/start_build_server.js +6 -9
  10. package/src/dev/start_dev_server.js +2 -2
  11. package/src/execute/execute.js +14 -52
  12. package/src/execute/runtimes/browsers/from_playwright.js +19 -8
  13. package/src/main.js +3 -0
  14. package/src/omega/kitchen.js +5 -5
  15. package/src/omega/omega_server.js +2 -2
  16. package/src/omega/server/file_service.js +3 -3
  17. package/src/omega/url_graph/url_graph_load.js +4 -4
  18. package/src/omega/url_graph.js +3 -3
  19. package/src/ping_server.js +30 -0
  20. package/src/plugins/autoreload/client/reload.js +2 -2
  21. package/src/plugins/autoreload/jsenv_plugin_autoreload_client.js +1 -1
  22. package/src/plugins/autoreload/jsenv_plugin_autoreload_server.js +3 -3
  23. package/src/plugins/autoreload/jsenv_plugin_hmr.js +1 -1
  24. package/src/plugins/explorer/jsenv_plugin_explorer.js +1 -1
  25. package/src/plugins/html_supervisor/client/error_formatter.js +3 -3
  26. package/src/plugins/html_supervisor/jsenv_plugin_html_supervisor.js +5 -5
  27. package/src/plugins/import_meta_hot/html_hot_dependencies.js +4 -4
  28. package/src/plugins/import_meta_scenarios/jsenv_plugin_import_meta_scenarios.js +1 -9
  29. package/src/plugins/plugin_controller.js +2 -2
  30. package/src/plugins/server_events/client/server_events_client.js +1 -1
  31. package/src/plugins/toolbar/jsenv_plugin_toolbar.js +1 -1
  32. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic.js +2 -2
  33. package/src/plugins/transpilation/as_js_classic/jsenv_plugin_as_js_classic_html.js +3 -3
  34. package/src/plugins/transpilation/babel/jsenv_plugin_babel.js +13 -0
  35. package/src/plugins/url_analysis/html/html_urls.js +2 -2
  36. package/src/plugins/url_analysis/jsenv_plugin_url_analysis.js +1 -1
  37. package/src/test/execute_plan.js +15 -68
  38. package/src/test/execute_test_plan.js +4 -26
package/dist/main.js CHANGED
@@ -12,10 +12,10 @@ import { createMagicSource, composeTwoSourcemaps, getOriginalPosition, sourcemap
12
12
  import { parseHtmlString, stringifyHtmlAst, visitHtmlNodes, getHtmlNodeAttribute, analyzeScriptNode, setHtmlNodeAttributes, parseSrcSet, getHtmlNodePosition, getHtmlNodeAttributePosition, applyPostCss, postCssPluginUrlVisitor, parseJsUrls, getHtmlNodeText, setHtmlNodeText, applyBabelPlugins, injectScriptNodeAsEarlyAsPossible, createHtmlNode, findHtmlNode, removeHtmlNode, removeHtmlNodeText, transpileWithParcel, injectJsImport, minifyWithParcel, analyzeLinkNode } from "@jsenv/ast";
13
13
  import { createRequire } from "node:module";
14
14
  import babelParser from "@babel/parser";
15
+ import net, { createServer, isIP } from "node:net";
15
16
  import http from "node:http";
16
17
  import cluster from "node:cluster";
17
18
  import { performance as performance$1 } from "node:perf_hooks";
18
- import net, { createServer } from "node:net";
19
19
  import { Readable, Stream, Writable } from "node:stream";
20
20
  import { Http2ServerResponse } from "node:http2";
21
21
  import { lookup } from "node:dns";
@@ -94,7 +94,7 @@ const urlToScheme$1 = url => {
94
94
  return scheme;
95
95
  };
96
96
 
97
- const urlToRessource$1 = url => {
97
+ const urlToResource = url => {
98
98
  const scheme = urlToScheme$1(url);
99
99
 
100
100
  if (scheme === "file") {
@@ -115,25 +115,25 @@ const urlToRessource$1 = url => {
115
115
  };
116
116
 
117
117
  const urlToPathname$1 = url => {
118
- const ressource = urlToRessource$1(url);
119
- const pathname = ressourceToPathname$1(ressource);
118
+ const resource = urlToResource(url);
119
+ const pathname = resourceToPathname(resource);
120
120
  return pathname;
121
121
  };
122
122
 
123
- const ressourceToPathname$1 = ressource => {
124
- const searchSeparatorIndex = ressource.indexOf("?");
123
+ const resourceToPathname = resource => {
124
+ const searchSeparatorIndex = resource.indexOf("?");
125
125
 
126
126
  if (searchSeparatorIndex > -1) {
127
- return ressource.slice(0, searchSeparatorIndex);
127
+ return resource.slice(0, searchSeparatorIndex);
128
128
  }
129
129
 
130
- const hashIndex = ressource.indexOf("#");
130
+ const hashIndex = resource.indexOf("#");
131
131
 
132
132
  if (hashIndex > -1) {
133
- return ressource.slice(0, hashIndex);
133
+ return resource.slice(0, hashIndex);
134
134
  }
135
135
 
136
- return ressource;
136
+ return resource;
137
137
  };
138
138
 
139
139
  const urlToFilename$1 = url => {
@@ -616,8 +616,8 @@ const urlToRelativeUrl = (url, baseUrl) => {
616
616
  } = urlObject;
617
617
 
618
618
  if (pathname === "/") {
619
- const baseUrlRessourceWithoutLeadingSlash = baseUrlObject.pathname.slice(1);
620
- return baseUrlRessourceWithoutLeadingSlash;
619
+ const baseUrlResourceWithoutLeadingSlash = baseUrlObject.pathname.slice(1);
620
+ return baseUrlResourceWithoutLeadingSlash;
621
621
  }
622
622
 
623
623
  const basePathname = baseUrlObject.pathname;
@@ -2006,10 +2006,10 @@ const ensureWindowsDriveLetter = (url, baseUrl) => {
2006
2006
  return `file:///${driveLetter}:${afterProtocol}`;
2007
2007
  };
2008
2008
 
2009
- const extractDriveLetter = ressource => {
2009
+ const extractDriveLetter = resource => {
2010
2010
  // we still have the windows drive letter
2011
- if (/[a-zA-Z]/.test(ressource[1]) && ressource[2] === ":") {
2012
- return ressource[1];
2011
+ if (/[a-zA-Z]/.test(resource[1]) && resource[2] === ":") {
2012
+ return resource[1];
2013
2013
  }
2014
2014
 
2015
2015
  return null;
@@ -2136,7 +2136,7 @@ const createWatcher = (sourcePath, options) => {
2136
2136
  return watcher;
2137
2137
  };
2138
2138
 
2139
- const trackRessources = () => {
2139
+ const trackResources = () => {
2140
2140
  const callbackArray = [];
2141
2141
 
2142
2142
  const registerCleanupCallback = callback => {
@@ -2244,7 +2244,7 @@ const registerDirectoryLifecycle = (source, {
2244
2244
  return watch;
2245
2245
  };
2246
2246
 
2247
- const tracker = trackRessources();
2247
+ const tracker = trackResources();
2248
2248
  const infoMap = new Map();
2249
2249
 
2250
2250
  const readEntryInfo = url => {
@@ -2380,7 +2380,7 @@ const registerDirectoryLifecycle = (source, {
2380
2380
 
2381
2381
  if (entryInfo.type !== previousInfo.type) {
2382
2382
  // it existed and was replaced by something else
2383
- // we don't handle this as an update. We rather say the ressource
2383
+ // we don't handle this as an update. We rather say the resource
2384
2384
  // is lost and something else is found (call removed() then added())
2385
2385
  handleEntryLost(previousInfo);
2386
2386
  handleEntryFound(entryInfo);
@@ -2591,7 +2591,7 @@ const registerFileLifecycle = (source, {
2591
2591
  }
2592
2592
  }
2593
2593
 
2594
- const tracker = trackRessources();
2594
+ const tracker = trackResources();
2595
2595
 
2596
2596
  const handleFileFound = ({
2597
2597
  existent
@@ -4014,10 +4014,10 @@ const createUrlGraph = ({
4014
4014
  }
4015
4015
 
4016
4016
  references.forEach(reference => {
4017
- if (reference.isRessourceHint) {
4018
- // ressource hint are a special kind of reference.
4017
+ if (reference.isResourceHint) {
4018
+ // resource hint are a special kind of reference.
4019
4019
  // They are a sort of weak reference to an url.
4020
- // We ignore them so that url referenced only by ressource hints
4020
+ // We ignore them so that url referenced only by resource hints
4021
4021
  // have url.dependents.size === 0 and can be considered as not used
4022
4022
  // It means html won't consider url referenced solely
4023
4023
  // by <link> as dependency and it's fine
@@ -4243,7 +4243,7 @@ const parseAndTransformHtmlUrls = async (urlInfo, context) => {
4243
4243
  crossorigin,
4244
4244
  integrity
4245
4245
  } = readFetchMetas(node);
4246
- const isRessourceHint = ["preconnect", "dns-prefetch", "prefetch", "preload", "modulepreload"].includes(subtype);
4246
+ const isResourceHint = ["preconnect", "dns-prefetch", "prefetch", "preload", "modulepreload"].includes(subtype);
4247
4247
  const [reference] = referenceUtils.found({
4248
4248
  type,
4249
4249
  expectedType,
@@ -4252,7 +4252,7 @@ const parseAndTransformHtmlUrls = async (urlInfo, context) => {
4252
4252
  specifier,
4253
4253
  specifierLine: line,
4254
4254
  specifierColumn: column,
4255
- isRessourceHint,
4255
+ isResourceHint,
4256
4256
  crossorigin,
4257
4257
  integrity
4258
4258
  });
@@ -4669,7 +4669,7 @@ const jsenvPluginUrlAnalysis = ({
4669
4669
  return;
4670
4670
  }
4671
4671
 
4672
- if (reference.specifier[0] === "#" && // For Html, css and in general "#" refer to a ressource in the page
4672
+ if (reference.specifier[0] === "#" && // For Html, css and in general "#" refer to a resource in the page
4673
4673
  // so that urls must be kept intact
4674
4674
  // However for js import specifiers they have a different meaning and we want
4675
4675
  // to resolve them (https://nodejs.org/api/packages.html#imports for instance)
@@ -5825,10 +5825,10 @@ const jsenvPluginAsJsClassicHtml = ({
5825
5825
  const convertedUrls = [];
5826
5826
 
5827
5827
  const getReferenceAsJsClassic = async (reference, {
5828
- // we don't cook ressource hints
5829
- // because they might refer to ressource that will be modified during build
5828
+ // we don't cook resource hints
5829
+ // because they might refer to resource that will be modified during build
5830
5830
  // It also means something else HAVE to reference that url in order to cook it
5831
- // so that the preload is deleted by "resync_ressource_hints.js" otherwise
5831
+ // so that the preload is deleted by "resync_resource_hints.js" otherwise
5832
5832
  cookIt = false
5833
5833
  } = {}) => {
5834
5834
  const newReferenceProps = {
@@ -10451,7 +10451,7 @@ const jsenvPluginAsJsClassicConversion = ({
10451
10451
  // - import specifier (static/dynamic import + re-export)
10452
10452
  // - url specifier when inside System.register/_context.import()
10453
10453
  // (because it's the transpiled equivalent of static and dynamic imports)
10454
- // And not other references otherwise we could try to transform inline ressources
10454
+ // And not other references otherwise we could try to transform inline resources
10455
10455
  // or specifiers inside new URL()...
10456
10456
  js_import_export: propagateJsClassicSearchParam,
10457
10457
  js_url_specifier: (reference, context) => {
@@ -10468,7 +10468,7 @@ const jsenvPluginAsJsClassicConversion = ({
10468
10468
  context,
10469
10469
  searchParam: "as_js_classic",
10470
10470
  // override the expectedType to "js_module"
10471
- // because when there is ?as_js_classic it means the underlying ressource
10471
+ // because when there is ?as_js_classic it means the underlying resource
10472
10472
  // is a js_module
10473
10473
  expectedType: "js_module"
10474
10474
  });
@@ -11531,26 +11531,26 @@ const getParentUrl = url => {
11531
11531
  if (url.startsWith("file://")) {
11532
11532
  // With node.js new URL('../', 'file:///C:/').href
11533
11533
  // returns "file:///C:/" instead of "file:///"
11534
- const ressource = url.slice("file://".length);
11535
- const slashLastIndex = ressource.lastIndexOf("/");
11534
+ const resource = url.slice("file://".length);
11535
+ const slashLastIndex = resource.lastIndexOf("/");
11536
11536
 
11537
11537
  if (slashLastIndex === -1) {
11538
11538
  return url;
11539
11539
  }
11540
11540
 
11541
- const lastCharIndex = ressource.length - 1;
11541
+ const lastCharIndex = resource.length - 1;
11542
11542
 
11543
11543
  if (slashLastIndex === lastCharIndex) {
11544
- const slashBeforeLastIndex = ressource.lastIndexOf("/", slashLastIndex - 1);
11544
+ const slashBeforeLastIndex = resource.lastIndexOf("/", slashLastIndex - 1);
11545
11545
 
11546
11546
  if (slashBeforeLastIndex === -1) {
11547
11547
  return url;
11548
11548
  }
11549
11549
 
11550
- return `file://${ressource.slice(0, slashBeforeLastIndex + 1)}`;
11550
+ return `file://${resource.slice(0, slashBeforeLastIndex + 1)}`;
11551
11551
  }
11552
11552
 
11553
- return `file://${ressource.slice(0, slashLastIndex + 1)}`;
11553
+ return `file://${resource.slice(0, slashLastIndex + 1)}`;
11554
11554
  }
11555
11555
 
11556
11556
  return new URL(url.endsWith("/") ? "../" : "./", url).href;
@@ -13190,7 +13190,7 @@ const jsenvPluginHtmlSupervisor = ({
13190
13190
  name: "jsenv:html_supervisor",
13191
13191
  appliesDuring: "dev",
13192
13192
  serve: async (request, context) => {
13193
- if (request.ressource.startsWith("/__get_code_frame__/")) {
13193
+ if (request.pathname.startsWith("/__get_code_frame__/")) {
13194
13194
  const {
13195
13195
  pathname,
13196
13196
  searchParams
@@ -13249,8 +13249,8 @@ const jsenvPluginHtmlSupervisor = ({
13249
13249
  };
13250
13250
  }
13251
13251
 
13252
- if (request.ressource.startsWith("/__get_error_cause__/")) {
13253
- const file = request.ressource.slice("/__get_error_cause__/".length);
13252
+ if (request.pathname.startsWith("/__get_error_cause__/")) {
13253
+ const file = request.pathname.slice("/__get_error_cause__/".length);
13254
13254
 
13255
13255
  if (!file) {
13256
13256
  return {
@@ -13309,8 +13309,8 @@ const jsenvPluginHtmlSupervisor = ({
13309
13309
  };
13310
13310
  }
13311
13311
 
13312
- if (request.ressource.startsWith("/__open_in_editor__/")) {
13313
- const file = request.ressource.slice("/__open_in_editor__/".length);
13312
+ if (request.pathname.startsWith("/__open_in_editor__/")) {
13313
+ const file = request.pathname.slice("/__open_in_editor__/".length);
13314
13314
 
13315
13315
  if (!file) {
13316
13316
  return {
@@ -13742,7 +13742,6 @@ const jsenvPluginImportMetaScenarios = () => {
13742
13742
  });
13743
13743
  const {
13744
13744
  dev = [],
13745
- test = [],
13746
13745
  build = []
13747
13746
  } = metadata.importMetaScenarios;
13748
13747
  const replacements = [];
@@ -13759,9 +13758,6 @@ const jsenvPluginImportMetaScenarios = () => {
13759
13758
  dev.forEach(path => {
13760
13759
  replace(path, "undefined");
13761
13760
  });
13762
- test.forEach(path => {
13763
- replace(path, context.scenarios.test ? "true" : "undefined");
13764
- });
13765
13761
  build.forEach(path => {
13766
13762
  replace(path, "true");
13767
13763
  });
@@ -13773,12 +13769,6 @@ const jsenvPluginImportMetaScenarios = () => {
13773
13769
  dev.forEach(path => {
13774
13770
  replace(path, "true");
13775
13771
  });
13776
-
13777
- if (context.scenarios.test) {
13778
- test.forEach(path => {
13779
- replace(path, "true");
13780
- });
13781
- }
13782
13772
  }
13783
13773
 
13784
13774
  const magicSource = createMagicSource(urlInfo.content);
@@ -14062,6 +14052,87 @@ export default inlineContent.text`,
14062
14052
  return [asJsonModule, asCssModule, asTextModule];
14063
14053
  };
14064
14054
 
14055
+ const babelPluginInstrument = (api, {
14056
+ rootDirectoryUrl,
14057
+ useInlineSourceMaps = false,
14058
+ coverageConfig = {
14059
+ "./**/*": true
14060
+ }
14061
+ }) => {
14062
+ const {
14063
+ programVisitor
14064
+ } = requireFromJsenv("istanbul-lib-instrument");
14065
+ const {
14066
+ types
14067
+ } = api;
14068
+ const associations = URL_META.resolveAssociations({
14069
+ cover: coverageConfig
14070
+ }, rootDirectoryUrl);
14071
+
14072
+ const shouldInstrument = url => {
14073
+ return URL_META.applyAssociations({
14074
+ url,
14075
+ associations
14076
+ }).cover;
14077
+ };
14078
+
14079
+ return {
14080
+ name: "transform-instrument",
14081
+ visitor: {
14082
+ Program: {
14083
+ enter(path) {
14084
+ const {
14085
+ file
14086
+ } = this;
14087
+ const {
14088
+ opts
14089
+ } = file;
14090
+
14091
+ if (!opts.sourceFileName) {
14092
+ console.warn(`cannot instrument file when "sourceFileName" option is not set`);
14093
+ return;
14094
+ }
14095
+
14096
+ const fileUrl = fileSystemPathToUrl$1(opts.sourceFileName);
14097
+
14098
+ if (!shouldInstrument(fileUrl)) {
14099
+ return;
14100
+ }
14101
+
14102
+ this.__dv__ = null;
14103
+ let inputSourceMap;
14104
+
14105
+ if (useInlineSourceMaps) {
14106
+ // https://github.com/istanbuljs/babel-plugin-istanbul/commit/a9e15643d249a2985e4387e4308022053b2cd0ad#diff-1fdf421c05c1140f6d71444ea2b27638R65
14107
+ inputSourceMap = opts.inputSourceMap || file.inputMap ? file.inputMap.sourcemap : null;
14108
+ } else {
14109
+ inputSourceMap = opts.inputSourceMap;
14110
+ }
14111
+
14112
+ this.__dv__ = programVisitor(types, opts.filenameRelative || opts.filename, {
14113
+ coverageVariable: "__coverage__",
14114
+ inputSourceMap
14115
+ });
14116
+
14117
+ this.__dv__.enter(path);
14118
+ },
14119
+
14120
+ exit(path) {
14121
+ if (!this.__dv__) {
14122
+ return;
14123
+ }
14124
+
14125
+ const object = this.__dv__.exit(path); // object got two properties: fileCoverage and sourceMappingURL
14126
+
14127
+
14128
+ this.file.metadata.coverage = object.fileCoverage;
14129
+ }
14130
+
14131
+ }
14132
+ }
14133
+ };
14134
+ };
14135
+
14065
14136
  const versionFromValue = value => {
14066
14137
  if (typeof value === "number") {
14067
14138
  return numberToVersion(value);
@@ -15243,6 +15314,17 @@ const jsenvPluginBabel = ({
15243
15314
  getImportSpecifier
15244
15315
  });
15245
15316
 
15317
+ if (context.scenarios.dev) {
15318
+ const requestHeaders = context.request.headers;
15319
+
15320
+ if (requestHeaders["x-coverage-instanbul"]) {
15321
+ babelPluginStructure["transform-instrument"] = [babelPluginInstrument, {
15322
+ rootDirectoryUrl: context.rootDirectoryUrl,
15323
+ coverageConfig: JSON.parse(requestHeaders["x-coverage-instanbul"])
15324
+ }];
15325
+ }
15326
+ }
15327
+
15246
15328
  if (getCustomBabelPlugins) {
15247
15329
  Object.assign(babelPluginStructure, getCustomBabelPlugins(context));
15248
15330
  }
@@ -16315,7 +16397,7 @@ const htmlNodeCanHotReload = node => {
16315
16397
  if (node.nodeName === "link") {
16316
16398
  const {
16317
16399
  isStylesheet,
16318
- isRessourceHint,
16400
+ isResourceHint,
16319
16401
  rel
16320
16402
  } = analyzeLinkNode(node);
16321
16403
 
@@ -16324,9 +16406,9 @@ const htmlNodeCanHotReload = node => {
16324
16406
  return true;
16325
16407
  }
16326
16408
 
16327
- if (isRessourceHint) {
16328
- // for ressource hints html will be notified the underlying ressource has changed
16329
- // but we won't do anything (if the ressource is deleted we should?)
16409
+ if (isResourceHint) {
16410
+ // for resource hints html will be notified the underlying resource has changed
16411
+ // but we won't do anything (if the resource is deleted we should?)
16330
16412
  return true;
16331
16413
  }
16332
16414
 
@@ -16561,10 +16643,7 @@ import.meta.hot = createImportMetaHot(import.meta.url)
16561
16643
  const jsenvPluginHmr = () => {
16562
16644
  return {
16563
16645
  name: "jsenv:hmr",
16564
- appliesDuring: {
16565
- dev: true,
16566
- test: false
16567
- },
16646
+ appliesDuring: "dev",
16568
16647
  redirectUrl: reference => {
16569
16648
  const urlObject = new URL(reference.url);
16570
16649
 
@@ -16607,10 +16686,7 @@ const jsenvPluginAutoreloadClient = () => {
16607
16686
  const autoreloadClientFileUrl = new URL("./js/autoreload.js", import.meta.url).href;
16608
16687
  return {
16609
16688
  name: "jsenv:autoreload_client",
16610
- appliesDuring: {
16611
- dev: true,
16612
- test: false
16613
- },
16689
+ appliesDuring: "dev",
16614
16690
  transformUrlContent: {
16615
16691
  html: (htmlUrlInfo, context) => {
16616
16692
  const htmlAst = parseHtmlString(htmlUrlInfo.content);
@@ -16640,10 +16716,7 @@ const jsenvPluginAutoreloadServer = ({
16640
16716
  }) => {
16641
16717
  return {
16642
16718
  name: "jsenv:autoreload_server",
16643
- appliesDuring: {
16644
- dev: true,
16645
- test: false
16646
- },
16719
+ appliesDuring: "dev",
16647
16720
  serverEvents: {
16648
16721
  reload: ({
16649
16722
  sendServerEvent,
@@ -16805,7 +16878,7 @@ const jsenvPluginAutoreloadServer = ({
16805
16878
  firstUrlInfo
16806
16879
  }) => {
16807
16880
  const mainHotUpdate = propagateUpdate(firstUrlInfo);
16808
- const cause = `following files are no longer referenced: ${prunedUrlInfos.map(prunedUrlInfo => formatUrlForClient(prunedUrlInfo.url))}`; // now check if we can hot update the main ressource
16881
+ const cause = `following files are no longer referenced: ${prunedUrlInfos.map(prunedUrlInfo => formatUrlForClient(prunedUrlInfo.url))}`; // now check if we can hot update the main resource
16809
16882
  // then if we can hot update all dependencies
16810
16883
 
16811
16884
  if (mainHotUpdate.declined) {
@@ -16852,7 +16925,7 @@ const jsenvPluginAutoreloadServer = ({
16852
16925
  rootDirectoryUrl,
16853
16926
  urlGraph
16854
16927
  }) => {
16855
- if (request.ressource === "/__graph__") {
16928
+ if (request.pathname === "/__graph__") {
16856
16929
  const graphJson = JSON.stringify(urlGraph.toJSON(rootDirectoryUrl));
16857
16930
  return {
16858
16931
  status: 200,
@@ -16922,7 +16995,7 @@ const jsenvPluginExplorer = ({
16922
16995
  serve: async (request, {
16923
16996
  rootDirectoryUrl
16924
16997
  }) => {
16925
- if (request.ressource !== "/") {
16998
+ if (request.pathname !== "/") {
16926
16999
  return null;
16927
17000
  }
16928
17001
 
@@ -17896,7 +17969,7 @@ const nodeStreamToObservable = nodeStream => {
17896
17969
  // safe measure, ensure the readable stream gets
17897
17970
  // used in the next ${readableStreamLifetimeInSeconds} otherwise destroys it
17898
17971
  const timeout = setTimeout(() => {
17899
- process.emitWarning(`Readable stream not used after ${readableStreamLifetimeInSeconds} seconds. It will be destroyed to release ressources`, {
17972
+ process.emitWarning(`Readable stream not used after ${readableStreamLifetimeInSeconds} seconds. It will be destroyed to release resources`, {
17900
17973
  CODE: "READABLE_STREAM_TIMEOUT",
17901
17974
  // url is for http client request
17902
17975
  detail: `path: ${nodeStream.path}, fd: ${nodeStream.fd}, url: ${nodeStream.url}`
@@ -17976,8 +18049,8 @@ const fromNodeRequest = (nodeRequest, {
17976
18049
  signal,
17977
18050
  http2: Boolean(nodeRequest.stream),
17978
18051
  origin: requestOrigin,
17979
- ...getPropertiesFromRessource({
17980
- ressource: nodeRequest.url,
18052
+ ...getPropertiesFromResource({
18053
+ resource: nodeRequest.url,
17981
18054
  baseUrl: requestOrigin
17982
18055
  }),
17983
18056
  method: nodeRequest.method,
@@ -17986,13 +18059,13 @@ const fromNodeRequest = (nodeRequest, {
17986
18059
  });
17987
18060
  };
17988
18061
  const applyRedirectionToRequest = (request, {
17989
- ressource,
18062
+ resource,
17990
18063
  pathname,
17991
18064
  ...rest
17992
18065
  }) => {
17993
18066
  return { ...request,
17994
- ...(ressource ? getPropertiesFromRessource({
17995
- ressource,
18067
+ ...(resource ? getPropertiesFromResource({
18068
+ resource,
17996
18069
  baseUrl: request.url
17997
18070
  }) : pathname ? getPropertiesFromPathname({
17998
18071
  pathname,
@@ -18002,16 +18075,16 @@ const applyRedirectionToRequest = (request, {
18002
18075
  };
18003
18076
  };
18004
18077
 
18005
- const getPropertiesFromRessource = ({
18006
- ressource,
18078
+ const getPropertiesFromResource = ({
18079
+ resource,
18007
18080
  baseUrl
18008
18081
  }) => {
18009
- const urlObject = new URL(ressource, baseUrl);
18082
+ const urlObject = new URL(resource, baseUrl);
18010
18083
  let pathname = urlObject.pathname;
18011
18084
  return {
18012
18085
  url: String(urlObject),
18013
18086
  pathname,
18014
- ressource
18087
+ resource
18015
18088
  };
18016
18089
  };
18017
18090
 
@@ -18019,8 +18092,8 @@ const getPropertiesFromPathname = ({
18019
18092
  pathname,
18020
18093
  baseUrl
18021
18094
  }) => {
18022
- return getPropertiesFromRessource({
18023
- ressource: `${pathname}${new URL(baseUrl).search}`,
18095
+ return getPropertiesFromResource({
18096
+ resource: `${pathname}${new URL(baseUrl).search}`,
18024
18097
  baseUrl
18025
18098
  });
18026
18099
  };
@@ -18048,11 +18121,11 @@ const createPushRequest = (request, {
18048
18121
  const getHeadersInheritedByPushRequest = request => {
18049
18122
  const headersInherited = { ...request.headers
18050
18123
  }; // mtime sent by the client in request headers concerns the main request
18051
- // Time remains valid for request to other ressources so we keep it
18124
+ // Time remains valid for request to other resources so we keep it
18052
18125
  // in child requests
18053
18126
  // delete childHeaders["if-modified-since"]
18054
18127
  // eTag sent by the client in request headers concerns the main request
18055
- // A request made to an other ressource must not inherit the eTag
18128
+ // A request made to an other resource must not inherit the eTag
18056
18129
 
18057
18130
  delete headersInherited["if-none-match"];
18058
18131
  return headersInherited;
@@ -18367,101 +18440,12 @@ const statusIsClientError = status => status >= 400 && status < 500;
18367
18440
 
18368
18441
  const statusIsServerError = status => status >= 500 && status < 600;
18369
18442
 
18370
- const applyDnsResolution = async (hostname, {
18371
- verbatim = false
18372
- } = {}) => {
18373
- const dnsResolution = await new Promise((resolve, reject) => {
18374
- lookup(hostname, {
18375
- verbatim
18376
- }, (error, address, family) => {
18377
- if (error) {
18378
- reject(error);
18379
- } else {
18380
- resolve({
18381
- address,
18382
- family
18383
- });
18384
- }
18385
- });
18386
- });
18387
- return dnsResolution;
18388
- };
18389
-
18390
- const getServerOrigins = async ({
18391
- protocol,
18392
- host,
18393
- port
18394
- }) => {
18395
- const isLocal = LOOPBACK_HOSTNAMES.includes(host);
18396
- const localhostDnsResolution = await applyDnsResolution("localhost");
18397
- const localOrigin = createServerOrigin({
18398
- protocol,
18399
- hostname: localhostDnsResolution.address === "127.0.0.1" ? "localhost" : "127.0.0.1",
18400
- port
18401
- });
18402
-
18403
- if (isLocal) {
18404
- return {
18405
- local: localOrigin
18406
- };
18407
- }
18408
-
18409
- const isAnyIp = WILDCARD_HOSTNAMES.includes(host);
18410
- const networkOrigin = createServerOrigin({
18411
- protocol,
18412
- hostname: isAnyIp ? getExternalIp() : host,
18413
- port
18414
- });
18415
- return {
18416
- local: localOrigin,
18417
- network: networkOrigin
18418
- };
18419
- };
18420
- const LOOPBACK_HOSTNAMES = ["localhost", "127.0.0.1", "::1", "0000:0000:0000:0000:0000:0000:0000:0001"];
18421
- const WILDCARD_HOSTNAMES = [undefined, "0.0.0.0", "::", "0000:0000:0000:0000:0000:0000:0000:0000"];
18422
-
18423
- const createServerOrigin = ({
18424
- protocol,
18425
- hostname,
18426
- port
18427
- }) => {
18428
- const url = new URL("https://127.0.0.1:80");
18429
- url.protocol = protocol;
18430
- url.hostname = hostname;
18431
- url.port = port;
18432
- return url.origin;
18433
- };
18434
-
18435
- const getExternalIp = () => {
18436
- const networkInterfaceMap = networkInterfaces();
18437
- let internalIPV4NetworkAddress;
18438
- Object.keys(networkInterfaceMap).find(key => {
18439
- const networkAddressArray = networkInterfaceMap[key];
18440
- return networkAddressArray.find(networkAddress => {
18441
- if (networkAddress.internal) return false;
18442
- if (!isIpV4(networkAddress)) return false;
18443
- internalIPV4NetworkAddress = networkAddress;
18444
- return true;
18445
- });
18446
- });
18447
- return internalIPV4NetworkAddress ? internalIPV4NetworkAddress.address : null;
18448
- };
18449
-
18450
- const isIpV4 = networkAddress => {
18451
- // node 18+
18452
- if (typeof networkAddress.family === "number") {
18453
- return networkAddress.family === 4;
18454
- }
18455
-
18456
- return networkAddress.family === "IPv4";
18457
- };
18458
-
18459
18443
  const listen = async ({
18460
18444
  signal = new AbortController().signal,
18461
18445
  server,
18462
18446
  port,
18463
18447
  portHint,
18464
- host
18448
+ hostname
18465
18449
  }) => {
18466
18450
  const listeningOperation = Abort.startOperation();
18467
18451
 
@@ -18472,7 +18456,7 @@ const listen = async ({
18472
18456
  listeningOperation.throwIfAborted();
18473
18457
  port = await findFreePort(portHint, {
18474
18458
  signal: listeningOperation.signal,
18475
- host
18459
+ hostname
18476
18460
  });
18477
18461
  }
18478
18462
 
@@ -18480,7 +18464,7 @@ const listen = async ({
18480
18464
  port = await startListening({
18481
18465
  server,
18482
18466
  port,
18483
- host
18467
+ hostname
18484
18468
  });
18485
18469
  listeningOperation.addAbortCallback(() => stopListening(server));
18486
18470
  listeningOperation.throwIfAborted();
@@ -18492,7 +18476,7 @@ const listen = async ({
18492
18476
 
18493
18477
  const findFreePort = async (initialPort = 1, {
18494
18478
  signal = new AbortController().signal,
18495
- host = "127.0.0.1",
18479
+ hostname = "127.0.0.1",
18496
18480
  min = 1,
18497
18481
  max = 65534,
18498
18482
  next = port => port + 1
@@ -18514,27 +18498,27 @@ const findFreePort = async (initialPort = 1, {
18514
18498
  const nextPort = next(port);
18515
18499
 
18516
18500
  if (nextPort > max) {
18517
- throw new Error(`${host} has no available port between ${min} and ${max}`);
18501
+ throw new Error(`${hostname} has no available port between ${min} and ${max}`);
18518
18502
  }
18519
18503
 
18520
- return testUntil(nextPort, host);
18504
+ return testUntil(nextPort, hostname);
18521
18505
  };
18522
18506
 
18523
- const freePort = await testUntil(initialPort, host);
18507
+ const freePort = await testUntil(initialPort, hostname);
18524
18508
  return freePort;
18525
18509
  } finally {
18526
18510
  await findFreePortOperation.end();
18527
18511
  }
18528
18512
  };
18529
18513
 
18530
- const portIsFree = async (port, host) => {
18514
+ const portIsFree = async (port, hostname) => {
18531
18515
  const server = createServer();
18532
18516
 
18533
18517
  try {
18534
18518
  await startListening({
18535
18519
  server,
18536
18520
  port,
18537
- host
18521
+ hostname
18538
18522
  });
18539
18523
  } catch (error) {
18540
18524
  if (error && error.code === "EADDRINUSE") {
@@ -18555,7 +18539,7 @@ const portIsFree = async (port, host) => {
18555
18539
  const startListening = ({
18556
18540
  server,
18557
18541
  port,
18558
- host
18542
+ hostname
18559
18543
  }) => {
18560
18544
  return new Promise((resolve, reject) => {
18561
18545
  server.on("error", reject);
@@ -18564,7 +18548,7 @@ const startListening = ({
18564
18548
  // https://nodejs.org/api/net.html#net_server_listen_port_host_backlog_callback
18565
18549
  resolve(server.address().port);
18566
18550
  });
18567
- server.listen(port, host);
18551
+ server.listen(port, hostname);
18568
18552
  });
18569
18553
  };
18570
18554
 
@@ -18803,6 +18787,134 @@ const STOP_REASON_PROCESS_BEFORE_EXIT = createReason("process before exit");
18803
18787
  const STOP_REASON_PROCESS_EXIT = createReason("process exit");
18804
18788
  const STOP_REASON_NOT_SPECIFIED = createReason("not specified");
18805
18789
 
18790
+ const createIpGetters = () => {
18791
+ const networkAddresses = [];
18792
+ const networkInterfaceMap = networkInterfaces();
18793
+
18794
+ for (const key of Object.keys(networkInterfaceMap)) {
18795
+ for (const networkAddress of networkInterfaceMap[key]) {
18796
+ networkAddresses.push(networkAddress);
18797
+ }
18798
+ }
18799
+
18800
+ return {
18801
+ getFirstInternalIp: ({
18802
+ preferIpv6
18803
+ }) => {
18804
+ const isPref = preferIpv6 ? isIpV6 : isIpV4;
18805
+ let firstInternalIp;
18806
+
18807
+ for (const networkAddress of networkAddresses) {
18808
+ if (networkAddress.internal) {
18809
+ firstInternalIp = networkAddress.address;
18810
+
18811
+ if (isPref(networkAddress)) {
18812
+ break;
18813
+ }
18814
+ }
18815
+ }
18816
+
18817
+ return firstInternalIp;
18818
+ },
18819
+ getFirstExternalIp: ({
18820
+ preferIpv6
18821
+ }) => {
18822
+ const isPref = preferIpv6 ? isIpV6 : isIpV4;
18823
+ let firstExternalIp;
18824
+
18825
+ for (const networkAddress of networkAddresses) {
18826
+ if (!networkAddress.internal) {
18827
+ firstExternalIp = networkAddress.address;
18828
+
18829
+ if (isPref(networkAddress)) {
18830
+ break;
18831
+ }
18832
+ }
18833
+ }
18834
+
18835
+ return firstExternalIp;
18836
+ }
18837
+ };
18838
+ };
18839
+
18840
+ const isIpV4 = networkAddress => {
18841
+ // node 18.5
18842
+ if (typeof networkAddress.family === "number") {
18843
+ return networkAddress.family === 4;
18844
+ }
18845
+
18846
+ return networkAddress.family === "IPv4";
18847
+ };
18848
+
18849
+ const isIpV6 = networkAddress => !isIpV4(networkAddress);
18850
+
18851
+ const parseHostname = hostname => {
18852
+ if (hostname === "0.0.0.0") {
18853
+ return {
18854
+ type: "ip",
18855
+ label: "unspecified",
18856
+ version: 4
18857
+ };
18858
+ }
18859
+
18860
+ if (hostname === "::" || hostname === "0000:0000:0000:0000:0000:0000:0000:0000") {
18861
+ return {
18862
+ type: "ip",
18863
+ label: "unspecified",
18864
+ version: 6
18865
+ };
18866
+ }
18867
+
18868
+ if (hostname === "127.0.0.1") {
18869
+ return {
18870
+ type: "ip",
18871
+ label: "loopback",
18872
+ version: 4
18873
+ };
18874
+ }
18875
+
18876
+ if (hostname === "::1" || hostname === "0000:0000:0000:0000:0000:0000:0000:0001") {
18877
+ return {
18878
+ type: "ip",
18879
+ label: "loopback",
18880
+ version: 6
18881
+ };
18882
+ }
18883
+
18884
+ const ipVersion = isIP(hostname);
18885
+
18886
+ if (ipVersion === 0) {
18887
+ return {
18888
+ type: "hostname"
18889
+ };
18890
+ }
18891
+
18892
+ return {
18893
+ type: "ip",
18894
+ version: ipVersion
18895
+ };
18896
+ };
18897
+
18898
+ const applyDnsResolution = async (hostname, {
18899
+ verbatim = false
18900
+ } = {}) => {
18901
+ const dnsResolution = await new Promise((resolve, reject) => {
18902
+ lookup(hostname, {
18903
+ verbatim
18904
+ }, (error, address, family) => {
18905
+ if (error) {
18906
+ reject(error);
18907
+ } else {
18908
+ resolve({
18909
+ address,
18910
+ family
18911
+ });
18912
+ }
18913
+ });
18914
+ });
18915
+ return dnsResolution;
18916
+ };
18917
+
18806
18918
  const startServer = async ({
18807
18919
  signal = new AbortController().signal,
18808
18920
  logLevel,
@@ -18814,7 +18926,8 @@ const startServer = async ({
18814
18926
  redirectHttpToHttps,
18815
18927
  allowHttpRequestOnHttps = false,
18816
18928
  acceptAnyIp = false,
18817
- host = acceptAnyIp ? undefined : "localhost",
18929
+ preferIpv6,
18930
+ hostname = "localhost",
18818
18931
  port = 0,
18819
18932
  // assign a random available port
18820
18933
  portHint,
@@ -18839,11 +18952,15 @@ const startServer = async ({
18839
18952
  requestWaitingMs
18840
18953
  }) => {
18841
18954
  warn(createDetailedMessage$1(`still no response found for request after ${requestWaitingMs} ms`, {
18842
- "request url": `${request.origin}${request.ressource}`,
18955
+ "request url": request.url,
18843
18956
  "request headers": JSON.stringify(request.headers, null, " ")
18844
18957
  }));
18845
18958
  }
18846
18959
  } = {}) => {
18960
+ const logger = createLogger({
18961
+ logLevel
18962
+ });
18963
+
18847
18964
  if (protocol !== "http" && protocol !== "https") {
18848
18965
  throw new Error(`protocol must be http or https, got ${protocol}`);
18849
18966
  }
@@ -18862,10 +18979,6 @@ const startServer = async ({
18862
18979
  throw new Error(`http2 needs "https" but protocol is "${protocol}"`);
18863
18980
  }
18864
18981
 
18865
- const logger = createLogger({
18866
- logLevel
18867
- });
18868
-
18869
18982
  if (redirectHttpToHttps === undefined && protocol === "https" && !allowHttpRequestOnHttps) {
18870
18983
  redirectHttpToHttps = true;
18871
18984
  }
@@ -18898,6 +19011,10 @@ const startServer = async ({
18898
19011
  let nodeServer;
18899
19012
  const startServerOperation = Abort.startOperation();
18900
19013
  const stopCallbackList = createCallbackListNotifiedOnce();
19014
+ const serverOrigins = {
19015
+ local: "" // favors hostname when possible
19016
+
19017
+ };
18901
19018
 
18902
19019
  try {
18903
19020
  startServerOperation.addAbortSignal(signal);
@@ -18925,12 +19042,85 @@ const startServer = async ({
18925
19042
  nodeServer.unref();
18926
19043
  }
18927
19044
 
19045
+ const createOrigin = hostname => {
19046
+ if (isIP(hostname) === 6) {
19047
+ return `${protocol}://[${hostname}]`;
19048
+ }
19049
+
19050
+ return `${protocol}://${hostname}`;
19051
+ };
19052
+
19053
+ const ipGetters = createIpGetters();
19054
+ let hostnameToListen;
19055
+
19056
+ if (acceptAnyIp) {
19057
+ const firstInternalIp = ipGetters.getFirstInternalIp({
19058
+ preferIpv6
19059
+ });
19060
+ serverOrigins.local = createOrigin(firstInternalIp);
19061
+ serverOrigins.localip = createOrigin(firstInternalIp);
19062
+ const firstExternalIp = ipGetters.getFirstExternalIp({
19063
+ preferIpv6
19064
+ });
19065
+ serverOrigins.externalip = createOrigin(firstExternalIp);
19066
+ hostnameToListen = preferIpv6 ? "::" : "0.0.0.0";
19067
+ } else {
19068
+ hostnameToListen = hostname;
19069
+ }
19070
+
19071
+ const hostnameInfo = parseHostname(hostname);
19072
+
19073
+ if (hostnameInfo.type === "ip") {
19074
+ if (acceptAnyIp) {
19075
+ throw new Error(`hostname cannot be an ip when acceptAnyIp is enabled, got ${hostname}`);
19076
+ }
19077
+
19078
+ preferIpv6 = hostnameInfo.version === 6;
19079
+ const firstInternalIp = ipGetters.getFirstInternalIp({
19080
+ preferIpv6
19081
+ });
19082
+ serverOrigins.local = createOrigin(firstInternalIp);
19083
+ serverOrigins.localip = createOrigin(firstInternalIp);
19084
+
19085
+ if (hostnameInfo.label === "unspecified") {
19086
+ const firstExternalIp = ipGetters.getFirstExternalIp({
19087
+ preferIpv6
19088
+ });
19089
+ serverOrigins.externalip = createOrigin(firstExternalIp);
19090
+ } else if (hostnameInfo.label === "loopback") {} else {
19091
+ serverOrigins.local = createOrigin(hostname);
19092
+ }
19093
+ } else {
19094
+ const hostnameDnsResolution = await applyDnsResolution(hostname, {
19095
+ verbatim: true
19096
+ });
19097
+
19098
+ if (hostnameDnsResolution) {
19099
+ const hostnameIp = hostnameDnsResolution.address;
19100
+ serverOrigins.localip = createOrigin(hostnameIp);
19101
+ serverOrigins.local = createOrigin(hostname);
19102
+ } else {
19103
+ const firstInternalIp = ipGetters.getFirstInternalIp({
19104
+ preferIpv6
19105
+ }); // fallback to internal ip because there is no ip
19106
+ // associated to this hostname on operating system (in hosts file)
19107
+
19108
+ hostname = firstInternalIp;
19109
+ hostnameToListen = firstInternalIp;
19110
+ serverOrigins.local = createOrigin(firstInternalIp);
19111
+ }
19112
+ }
19113
+
18928
19114
  port = await listen({
18929
19115
  signal: startServerOperation.signal,
18930
19116
  server: nodeServer,
18931
19117
  port,
18932
19118
  portHint,
18933
- host
19119
+ hostname: hostnameToListen
19120
+ }); // normalize origins (remove :80 when port is 80 for instance)
19121
+
19122
+ Object.keys(serverOrigins).forEach(key => {
19123
+ serverOrigins[key] = new URL(`${serverOrigins[key]}:${port}`).origin;
18934
19124
  });
18935
19125
  serviceController.callHooks("serverListening", {
18936
19126
  port
@@ -18941,12 +19131,23 @@ const startServer = async ({
18941
19131
  startServerOperation.throwIfAborted();
18942
19132
  } finally {
18943
19133
  await startServerOperation.end();
18944
- } // now the server is started (listening) it cannot be aborted anymore
19134
+ } // the main server origin
19135
+ // - when protocol is http
19136
+ // node-fetch do not apply local dns resolution to map localhost back to 127.0.0.1
19137
+ // despites localhost being mapped so we prefer to use the internal ip
19138
+ // (127.0.0.1)
19139
+ // - when protocol is https
19140
+ // using the hostname becomes important because the certificate is generated
19141
+ // for hostnames, not for ips
19142
+ // so we prefer https://locahost or https://local_hostname
19143
+ // over the ip
19144
+
19145
+
19146
+ const serverOrigin = serverOrigins.local; // now the server is started (listening) it cannot be aborted anymore
18945
19147
  // (otherwise an AbortError is thrown to the code calling "startServer")
18946
19148
  // we can proceed to create a stop function to stop it gacefully
18947
19149
  // and add a request handler
18948
19150
 
18949
-
18950
19151
  stopCallbackList.add(({
18951
19152
  reason
18952
19153
  }) => {
@@ -18984,12 +19185,6 @@ const startServer = async ({
18984
19185
  };
18985
19186
 
18986
19187
  status = "opened";
18987
- const serverOrigins = await getServerOrigins({
18988
- protocol,
18989
- host,
18990
- port
18991
- });
18992
- const serverOrigin = serverOrigins.local;
18993
19188
  const removeConnectionErrorListener = listenServerConnectionError(nodeServer, onError);
18994
19189
  stopCallbackList.add(removeConnectionErrorListener);
18995
19190
  const connectionsTracker = trackServerPendingConnections(nodeServer, {
@@ -19181,7 +19376,7 @@ const startServer = async ({
19181
19376
  const onPushStreamError = e => {
19182
19377
  addRequestLog(requestNode, {
19183
19378
  type: "error",
19184
- value: createDetailedMessage$1(`An error occured while pushing a stream to the response for ${request.ressource}`, {
19379
+ value: createDetailedMessage$1(`An error occured while pushing a stream to the response for ${request.resource}`, {
19185
19380
  "error stack": e.stack
19186
19381
  })
19187
19382
  });
@@ -19285,7 +19480,7 @@ const startServer = async ({
19285
19480
 
19286
19481
  addRequestLog(requestNode, {
19287
19482
  type: "info",
19288
- value: request.parent ? `Push ${request.ressource}` : `${request.method} ${request.origin}${request.ressource}`
19483
+ value: request.parent ? `Push ${request.resource}` : `${request.method} ${request.url}`
19289
19484
  });
19290
19485
 
19291
19486
  const warn = value => {
@@ -19609,7 +19804,7 @@ const startServer = async ({
19609
19804
  let websocketServer = new WebSocketServer({
19610
19805
  noServer: true
19611
19806
  });
19612
- const websocketOrigin = protocol === "https" ? `wss://${host}:${port}` : `ws://${host}:${port}`;
19807
+ const websocketOrigin = protocol === "https" ? `wss://${hostname}:${port}` : `ws://${hostname}:${port}`;
19613
19808
  server.websocketOrigin = websocketOrigin;
19614
19809
 
19615
19810
  const upgradeCallback = (nodeRequest, socket, head) => {
@@ -19650,6 +19845,7 @@ const startServer = async ({
19650
19845
  Object.assign(server, {
19651
19846
  getStatus: () => status,
19652
19847
  port,
19848
+ hostname,
19653
19849
  origin: serverOrigin,
19654
19850
  origins: serverOrigins,
19655
19851
  nodeServer,
@@ -20102,7 +20298,7 @@ const fetchFileSystem = async (filesystemUrl, {
20102
20298
 
20103
20299
  rootDirectoryUrl = rootDirectoryUrlString;
20104
20300
  } // here you might be tempted to add || cacheControl === 'no-cache'
20105
- // but no-cache means ressource can be cache but must be revalidated (yeah naming is strange)
20301
+ // but no-cache means resource can be cache but must be revalidated (yeah naming is strange)
20106
20302
  // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#Cacheability
20107
20303
 
20108
20304
 
@@ -20243,7 +20439,7 @@ const getClientCacheResponse = async ({
20243
20439
  sourceUrl
20244
20440
  }) => {
20245
20441
  // here you might be tempted to add || headers["cache-control"] === "no-cache"
20246
- // but no-cache means ressource can be cache but must be revalidated (yeah naming is strange)
20442
+ // but no-cache means resource can be cache but must be revalidated (yeah naming is strange)
20247
20443
  // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#Cacheability
20248
20444
  if (headers["cache-control"] === "no-store" || // let's disable it on no-cache too
20249
20445
  headers["cache-control"] === "no-cache") {
@@ -20951,8 +21147,8 @@ const flattenAndFilterPlugins = (plugins, {
20951
21147
  }
20952
21148
 
20953
21149
  if (typeof appliesDuring === "string") {
20954
- if (!["dev", "test", "build"].includes(appliesDuring)) {
20955
- throw new Error(`"appliesDuring" must be "dev", "test" or "build", got ${appliesDuring}`);
21150
+ if (!["dev", "build"].includes(appliesDuring)) {
21151
+ throw new Error(`"appliesDuring" must be "dev" or "build", got ${appliesDuring}`);
20956
21152
  }
20957
21153
 
20958
21154
  if (scenarios[appliesDuring]) {
@@ -21644,7 +21840,7 @@ const validateResponseIntegrity = ({
21644
21840
  return true;
21645
21841
  }
21646
21842
 
21647
- const error = new Error(`Integrity validation failed for ressource "${url}". The integrity found for this ressource is "${strongestAlgo}-${actualBase64Value}"`);
21843
+ const error = new Error(`Integrity validation failed for resource "${url}". The integrity found for this resource is "${strongestAlgo}-${actualBase64Value}"`);
21648
21844
  error.code = "EINTEGRITY";
21649
21845
  error.algorithm = strongestAlgo;
21650
21846
  error.found = actualBase64Value;
@@ -21756,7 +21952,7 @@ const createKitchen = ({
21756
21952
  isEntryPoint = false,
21757
21953
  isInline = false,
21758
21954
  injected = false,
21759
- isRessourceHint = false,
21955
+ isResourceHint = false,
21760
21956
  content,
21761
21957
  contentType,
21762
21958
  assert,
@@ -21794,8 +21990,8 @@ const createKitchen = ({
21794
21990
  isEntryPoint,
21795
21991
  isInline,
21796
21992
  injected,
21797
- isRessourceHint,
21798
- // for inline ressources the reference contains the content
21993
+ isResourceHint,
21994
+ // for inline resources the reference contains the content
21799
21995
  content,
21800
21996
  contentType,
21801
21997
  timing: {},
@@ -21846,8 +22042,8 @@ const createKitchen = ({
21846
22042
  // And this is because this hook inject query params used to:
21847
22043
  // - bypass browser cache (?v)
21848
22044
  // - convey information (?hmr)
21849
- // But do not represent an other ressource, it is considered as
21850
- // the same ressource under the hood
22045
+ // But do not represent an other resource, it is considered as
22046
+ // the same resource under the hood
21851
22047
 
21852
22048
  pluginController.callHooks("transformUrlSearchParams", reference, kitchenContext, returnValue => {
21853
22049
  Object.keys(returnValue).forEach(key => {
@@ -22656,11 +22852,11 @@ const loadUrlGraph = async ({
22656
22852
  references
22657
22853
  } = urlInfo;
22658
22854
  references.forEach(reference => {
22659
- // we don't cook ressource hints
22660
- // because they might refer to ressource that will be modified during build
22855
+ // we don't cook resource hints
22856
+ // because they might refer to resource that will be modified during build
22661
22857
  // It also means something else have to reference that url in order to cook it
22662
- // so that the preload is deleted by "resync_ressource_hints.js" otherwise
22663
- if (reference.isRessourceHint) {
22858
+ // so that the preload is deleted by "resync_resource_hints.js" otherwise
22859
+ if (reference.isResourceHint) {
22664
22860
  return;
22665
22861
  } // we use reference.generatedUrl to mimic what a browser would do:
22666
22862
  // do a fetch to the specifier as found in the file
@@ -23325,23 +23521,23 @@ self.serviceWorkerUrls = ${JSON.stringify(serviceWorkerUrls, null, " ")};
23325
23521
  /*
23326
23522
  * Update <link rel="preload"> and friends after build (once we know everything)
23327
23523
  *
23328
- * - Used to remove ressource hint targeting an url that is no longer used:
23524
+ * - Used to remove resource hint targeting an url that is no longer used:
23329
23525
  * - Happens because of import assertions transpilation (file is inlined into JS)
23330
23526
  */
23331
- const resyncRessourceHints = async ({
23527
+ const resyncResourceHints = async ({
23332
23528
  logger,
23333
23529
  finalGraphKitchen,
23334
23530
  finalGraph,
23335
23531
  rawUrls,
23336
23532
  postBuildRedirections
23337
23533
  }) => {
23338
- const ressourceHintActions = [];
23534
+ const resourceHintActions = [];
23339
23535
  GRAPH.forEach(finalGraph, urlInfo => {
23340
23536
  if (urlInfo.type !== "html") {
23341
23537
  return;
23342
23538
  }
23343
23539
 
23344
- ressourceHintActions.push(async () => {
23540
+ resourceHintActions.push(async () => {
23345
23541
  const htmlAst = parseHtmlString(urlInfo.content, {
23346
23542
  storeOriginalPositions: false
23347
23543
  });
@@ -23353,9 +23549,9 @@ const resyncRessourceHints = async ({
23353
23549
  }
23354
23550
 
23355
23551
  const rel = getHtmlNodeAttribute(linkNode, "rel");
23356
- const isRessourceHint = ["preconnect", "dns-prefetch", "prefetch", "preload", "modulepreload"].includes(rel);
23552
+ const isresourceHint = ["preconnect", "dns-prefetch", "prefetch", "preload", "modulepreload"].includes(rel);
23357
23553
 
23358
- if (!isRessourceHint) {
23554
+ if (!isresourceHint) {
23359
23555
  return;
23360
23556
  }
23361
23557
 
@@ -23369,7 +23565,7 @@ const resyncRessourceHints = async ({
23369
23565
  }
23370
23566
 
23371
23567
  if (!buildUrl) {
23372
- logger.warn(`remove ressource hint because cannot find "${href}"`);
23568
+ logger.warn(`remove resource hint because cannot find "${href}"`);
23373
23569
  actions.push(() => {
23374
23570
  removeHtmlNode(linkNode);
23375
23571
  });
@@ -23380,7 +23576,7 @@ const resyncRessourceHints = async ({
23380
23576
  const urlInfo = finalGraph.getUrlInfo(buildUrl);
23381
23577
 
23382
23578
  if (!urlInfo) {
23383
- logger.warn(`remove ressource hint because cannot find "${buildUrl}" in the graph`);
23579
+ logger.warn(`remove resource hint because cannot find "${buildUrl}" in the graph`);
23384
23580
  actions.push(() => {
23385
23581
  removeHtmlNode(linkNode);
23386
23582
  });
@@ -23388,7 +23584,7 @@ const resyncRessourceHints = async ({
23388
23584
  }
23389
23585
 
23390
23586
  if (urlInfo.dependents.size === 0) {
23391
- logger.info(`remove ressource hint because "${href}" not used anymore`);
23587
+ logger.info(`remove resource hint because "${href}" not used anymore`);
23392
23588
  actions.push(() => {
23393
23589
  removeHtmlNode(linkNode);
23394
23590
  });
@@ -23420,7 +23616,7 @@ const resyncRessourceHints = async ({
23420
23616
  }
23421
23617
  });
23422
23618
  });
23423
- await Promise.all(ressourceHintActions.map(ressourceHintAction => ressourceHintAction()));
23619
+ await Promise.all(resourceHintActions.map(resourceHintAction => resourceHintAction()));
23424
23620
  };
23425
23621
 
23426
23622
  /*
@@ -23701,10 +23897,10 @@ build ${entryPointKeys.length} entry points`);
23701
23897
  addToBundlerIfAny(dependencyUrlInfo);
23702
23898
  });
23703
23899
  rawUrlInfo.references.forEach(reference => {
23704
- if (reference.isRessourceHint && reference.expectedType === "js_module") {
23900
+ if (reference.isResourceHint && reference.expectedType === "js_module") {
23705
23901
  const referencedUrlInfo = rawGraph.getUrlInfo(reference.url);
23706
23902
 
23707
- if (referencedUrlInfo && // something else than the ressource hint is using this url
23903
+ if (referencedUrlInfo && // something else than the resource hint is using this url
23708
23904
  referencedUrlInfo.dependents.size > 0) {
23709
23905
  addToBundlerIfAny(referencedUrlInfo);
23710
23906
  }
@@ -23997,7 +24193,7 @@ build ${entryPointKeys.length} entry points`);
23997
24193
  throw new Error(`urls should be inside build directory at this stage, found "${reference.url}"`);
23998
24194
  }
23999
24195
 
24000
- if (reference.isRessourceHint) {
24196
+ if (reference.isResourceHint) {
24001
24197
  // return the raw url, we will resync at the end
24002
24198
  return rawUrls[reference.url];
24003
24199
  } // remove eventual search params and hash
@@ -24101,7 +24297,7 @@ build ${entryPointKeys.length} entry points`);
24101
24297
  kitchen: finalGraphKitchen,
24102
24298
  outDirectoryUrl: new URL(".jsenv/postbuild/", rootDirectoryUrl),
24103
24299
  writeGeneratedFiles,
24104
- skipRessourceHint: true,
24300
+ skipResourceHint: true,
24105
24301
  startLoading: cookEntryFile => {
24106
24302
  entryUrls.forEach(entryUrl => {
24107
24303
  const [, postBuildEntryUrlInfo] = cookEntryFile({
@@ -24173,7 +24369,7 @@ ${Array.from(finalGraph.urlInfoMap.keys()).join("\n")}`);
24173
24369
  urlInfo.data.buildUrlIsVersioned = useVersionedUrl;
24174
24370
  urlInfo.data.buildUrlSpecifier = buildUrlSpecifier;
24175
24371
  });
24176
- await resyncRessourceHints({
24372
+ await resyncResourceHints({
24177
24373
  logger,
24178
24374
  finalGraphKitchen,
24179
24375
  finalGraph,
@@ -24517,7 +24713,7 @@ const applyUrlVersioning = async ({
24517
24713
  return null;
24518
24714
  }
24519
24715
 
24520
- if (reference.isRessourceHint) {
24716
+ if (reference.isResourceHint) {
24521
24717
  return null;
24522
24718
  } // specifier comes from "normalize" hook done a bit earlier in this file
24523
24719
  // we want to get back their build url to access their infos
@@ -24578,7 +24774,7 @@ const applyUrlVersioning = async ({
24578
24774
  operation: buildOperation,
24579
24775
  urlGraph: finalGraph,
24580
24776
  kitchen: versioningKitchen,
24581
- skipRessourceHint: true,
24777
+ skipResourceHint: true,
24582
24778
  writeGeneratedFiles,
24583
24779
  startLoading: cookEntryFile => {
24584
24780
  postBuildEntryUrls.forEach(postBuildEntryUrl => {
@@ -25060,7 +25256,7 @@ const createFileService = ({
25060
25256
 
25061
25257
  return async request => {
25062
25258
  // serve file inside ".jsenv" directory
25063
- const requestFileUrl = new URL(request.ressource.slice(1), rootDirectoryUrl).href;
25259
+ const requestFileUrl = new URL(request.resource.slice(1), rootDirectoryUrl).href;
25064
25260
 
25065
25261
  if (urlIsInsideOf(requestFileUrl, jsenvDirectoryUrl)) {
25066
25262
  return fetchFileSystem(requestFileUrl, {
@@ -25084,7 +25280,7 @@ const createFileService = ({
25084
25280
  const parentUrl = inferParentFromRequest(request, rootDirectoryUrl);
25085
25281
 
25086
25282
  if (parentUrl) {
25087
- reference = urlGraph.inferReference(request.ressource, parentUrl);
25283
+ reference = urlGraph.inferReference(request.resource, parentUrl);
25088
25284
  }
25089
25285
 
25090
25286
  if (!reference) {
@@ -25094,7 +25290,7 @@ const createFileService = ({
25094
25290
  },
25095
25291
  parentUrl: parentUrl || rootDirectoryUrl,
25096
25292
  type: "http_request",
25097
- specifier: request.ressource
25293
+ specifier: request.resource
25098
25294
  });
25099
25295
  reference = entryPoint[0];
25100
25296
  }
@@ -25261,7 +25457,7 @@ const startOmegaServer = async ({
25261
25457
  privateKey,
25262
25458
  certificate,
25263
25459
  acceptAnyIp,
25264
- host,
25460
+ hostname,
25265
25461
  port = 0,
25266
25462
  keepProcessAlive = false,
25267
25463
  onStop = () => {},
@@ -25302,7 +25498,7 @@ const startOmegaServer = async ({
25302
25498
  certificate,
25303
25499
  privateKey,
25304
25500
  acceptAnyIp,
25305
- host,
25501
+ hostname,
25306
25502
  port,
25307
25503
  requestWaitingMs: 60_1000,
25308
25504
  services: [jsenvServiceCORS({
@@ -25408,7 +25604,7 @@ const startDevServer = async ({
25408
25604
  http2 = false,
25409
25605
  certificate,
25410
25606
  privateKey,
25411
- host,
25607
+ hostname,
25412
25608
  port = 3456,
25413
25609
  acceptAnyIp,
25414
25610
  keepProcessAlive = true,
@@ -25548,7 +25744,7 @@ const startDevServer = async ({
25548
25744
  http2,
25549
25745
  certificate,
25550
25746
  privateKey,
25551
- host,
25747
+ hostname,
25552
25748
  port,
25553
25749
  services,
25554
25750
  rootDirectoryUrl,
@@ -25651,87 +25847,6 @@ const generateCoverageTextLog = (coverage, {
25651
25847
  report.execute(context);
25652
25848
  };
25653
25849
 
25654
- const babelPluginInstrument = (api, {
25655
- rootDirectoryUrl,
25656
- useInlineSourceMaps = false,
25657
- coverageConfig = {
25658
- "./**/*": true
25659
- }
25660
- }) => {
25661
- const {
25662
- programVisitor
25663
- } = requireFromJsenv("istanbul-lib-instrument");
25664
- const {
25665
- types
25666
- } = api;
25667
- const associations = URL_META.resolveAssociations({
25668
- cover: coverageConfig
25669
- }, rootDirectoryUrl);
25670
-
25671
- const shouldInstrument = url => {
25672
- return URL_META.applyAssociations({
25673
- url,
25674
- associations
25675
- }).cover;
25676
- };
25677
-
25678
- return {
25679
- name: "transform-instrument",
25680
- visitor: {
25681
- Program: {
25682
- enter(path) {
25683
- const {
25684
- file
25685
- } = this;
25686
- const {
25687
- opts
25688
- } = file;
25689
-
25690
- if (!opts.sourceFileName) {
25691
- console.warn(`cannot instrument file when "sourceFileName" option is not set`);
25692
- return;
25693
- }
25694
-
25695
- const fileUrl = fileSystemPathToUrl$1(opts.sourceFileName);
25696
-
25697
- if (!shouldInstrument(fileUrl)) {
25698
- return;
25699
- }
25700
-
25701
- this.__dv__ = null;
25702
- let inputSourceMap;
25703
-
25704
- if (useInlineSourceMaps) {
25705
- // https://github.com/istanbuljs/babel-plugin-istanbul/commit/a9e15643d249a2985e4387e4308022053b2cd0ad#diff-1fdf421c05c1140f6d71444ea2b27638R65
25706
- inputSourceMap = opts.inputSourceMap || file.inputMap ? file.inputMap.sourcemap : null;
25707
- } else {
25708
- inputSourceMap = opts.inputSourceMap;
25709
- }
25710
-
25711
- this.__dv__ = programVisitor(types, opts.filenameRelative || opts.filename, {
25712
- coverageVariable: "__coverage__",
25713
- inputSourceMap
25714
- });
25715
-
25716
- this.__dv__.enter(path);
25717
- },
25718
-
25719
- exit(path) {
25720
- if (!this.__dv__) {
25721
- return;
25722
- }
25723
-
25724
- const object = this.__dv__.exit(path); // object got two properties: fileCoverage and sourceMappingURL
25725
-
25726
-
25727
- this.file.metadata.coverage = object.fileCoverage;
25728
- }
25729
-
25730
- }
25731
- }
25732
- };
25733
- };
25734
-
25735
25850
  const readNodeV8CoverageDirectory = async ({
25736
25851
  logger,
25737
25852
  signal,
@@ -26424,6 +26539,41 @@ const run = async ({
26424
26539
  }
26425
26540
  };
26426
26541
 
26542
+ const pingServer = async url => {
26543
+ const server = createServer();
26544
+ const {
26545
+ hostname,
26546
+ port
26547
+ } = new URL(url);
26548
+
26549
+ try {
26550
+ await new Promise((resolve, reject) => {
26551
+ server.on("error", reject);
26552
+ server.on("listening", () => {
26553
+ resolve();
26554
+ });
26555
+ server.listen(port, hostname);
26556
+ });
26557
+ } catch (error) {
26558
+ if (error && error.code === "EADDRINUSE") {
26559
+ return true;
26560
+ }
26561
+
26562
+ if (error && error.code === "EACCES") {
26563
+ return true;
26564
+ }
26565
+
26566
+ throw error;
26567
+ }
26568
+
26569
+ await new Promise((resolve, reject) => {
26570
+ server.on("error", reject);
26571
+ server.on("close", resolve);
26572
+ server.close();
26573
+ });
26574
+ return false;
26575
+ };
26576
+
26427
26577
  const ensureGlobalGc = () => {
26428
26578
  if (!global.gc) {
26429
26579
  v8.setFlagsFromString("--expose_gc");
@@ -26859,8 +27009,8 @@ const executePlan = async (plan, {
26859
27009
  completedExecutionLogMerging,
26860
27010
  completedExecutionLogAbbreviation,
26861
27011
  rootDirectoryUrl,
27012
+ devServerOrigin,
26862
27013
  keepRunning,
26863
- services,
26864
27014
  defaultMsAllocatedPerExecution,
26865
27015
  maxExecutionsInParallel,
26866
27016
  failFast,
@@ -26873,18 +27023,6 @@ const executePlan = async (plan, {
26873
27023
  coverageMethodForNodeJs,
26874
27024
  coverageV8ConflictWarning,
26875
27025
  coverageTempDirectoryRelativeUrl,
26876
- scenarios,
26877
- sourcemaps,
26878
- plugins,
26879
- nodeEsmResolution,
26880
- fileSystemMagicResolution,
26881
- transpilation,
26882
- writeGeneratedFiles,
26883
- protocol,
26884
- privateKey,
26885
- certificate,
26886
- host,
26887
- port,
26888
27026
  beforeExecutionCallback = () => {},
26889
27027
  afterExecutionCallback = () => {}
26890
27028
  } = {}) => {
@@ -26908,7 +27046,7 @@ const executePlan = async (plan, {
26908
27046
  if (runtime) {
26909
27047
  runtimes[runtime.name] = runtime.version;
26910
27048
 
26911
- if (runtime.needsServer) {
27049
+ if (runtime.type === "browser") {
26912
27050
  someNeedsServer = true;
26913
27051
  }
26914
27052
 
@@ -26999,6 +27137,7 @@ const executePlan = async (plan, {
26999
27137
 
27000
27138
  let runtimeParams = {
27001
27139
  rootDirectoryUrl,
27140
+ devServerOrigin,
27002
27141
  coverageEnabled,
27003
27142
  coverageConfig,
27004
27143
  coverageMethodForBrowsers,
@@ -27007,48 +27146,15 @@ const executePlan = async (plan, {
27007
27146
  };
27008
27147
 
27009
27148
  if (someNeedsServer) {
27010
- const server = await startOmegaServer({
27011
- signal: multipleExecutionsOperation.signal,
27012
- logLevel: "warn",
27013
- keepProcessAlive: false,
27014
- port,
27015
- host,
27016
- protocol,
27017
- certificate,
27018
- privateKey,
27019
- services,
27020
- rootDirectoryUrl,
27021
- scenarios,
27022
- runtimeCompat: runtimes,
27023
- plugins,
27024
- htmlSupervisor: true,
27025
- nodeEsmResolution,
27026
- fileSystemMagicResolution,
27027
- transpilation: { ...transpilation,
27028
- getCustomBabelPlugins: ({
27029
- clientRuntimeCompat
27030
- }) => {
27031
- if (coverageEnabled && (coverageMethodForBrowsers !== "playwright_api" || Object.keys(clientRuntimeCompat)[0] !== "chrome")) {
27032
- return {
27033
- "transform-instrument": [babelPluginInstrument, {
27034
- rootDirectoryUrl,
27035
- coverageConfig
27036
- }]
27037
- };
27038
- }
27149
+ if (!devServerOrigin) {
27150
+ throw new TypeError(`devServerOrigin is required when running tests on browser(s)`);
27151
+ }
27039
27152
 
27040
- return {};
27041
- }
27042
- },
27043
- sourcemaps,
27044
- writeGeneratedFiles
27045
- });
27046
- multipleExecutionsOperation.addEndCallback(async () => {
27047
- await server.stop();
27048
- });
27049
- runtimeParams = { ...runtimeParams,
27050
- server
27051
- };
27153
+ const devServerStarted = await pingServer(devServerOrigin);
27154
+
27155
+ if (!devServerStarted) {
27156
+ throw new Error(`dev server not started at ${devServerOrigin}. It is required to run tests`);
27157
+ }
27052
27158
  }
27053
27159
 
27054
27160
  logger.debug(`Generate executions`);
@@ -27391,9 +27497,10 @@ const executeInParallel = async ({
27391
27497
  };
27392
27498
 
27393
27499
  /**
27394
- * Execute a list of files and log how it goes
27500
+ * Execute a list of files and log how it goes.
27395
27501
  * @param {Object} testPlanParameters
27396
27502
  * @param {string|url} testPlanParameters.rootDirectoryUrl Root directory of the project
27503
+ * @param {string|url} [testPlanParameters.serverOrigin=undefined] Jsenv dev server origin; required when executing test on browsers
27397
27504
  * @param {Object} testPlanParameters.testPlan Object associating patterns leading to files to runtimes where they should be executed
27398
27505
  * @param {boolean} [testPlanParameters.completedExecutionLogAbbreviation=false] Abbreviate completed execution information to shorten terminal output
27399
27506
  * @param {boolean} [testPlanParameters.completedExecutionLogMerging=false] Merge completed execution logs to shorten terminal output
@@ -27420,6 +27527,7 @@ const executeTestPlan = async ({
27420
27527
  completedExecutionLogAbbreviation = false,
27421
27528
  completedExecutionLogMerging = false,
27422
27529
  rootDirectoryUrl,
27530
+ devServerOrigin,
27423
27531
  testPlan,
27424
27532
  updateProcessExitCode = true,
27425
27533
  maxExecutionsInParallel = 1,
@@ -27450,17 +27558,7 @@ const executeTestPlan = async ({
27450
27558
  coverageReportSkipFull = false,
27451
27559
  coverageReportTextLog = true,
27452
27560
  coverageReportJsonFile = process.env.CI ? null : "./.coverage/coverage.json",
27453
- coverageReportHtmlDirectory = process.env.CI ? "./.coverage/" : null,
27454
- sourcemaps = "inline",
27455
- plugins = [],
27456
- nodeEsmResolution,
27457
- fileSystemMagicResolution,
27458
- writeGeneratedFiles = false,
27459
- protocol,
27460
- privateKey,
27461
- certificate,
27462
- host,
27463
- port
27561
+ coverageReportHtmlDirectory = process.env.CI ? "./.coverage/" : null
27464
27562
  }) => {
27465
27563
  const logger = createLogger({
27466
27564
  logLevel
@@ -27520,6 +27618,7 @@ const executeTestPlan = async ({
27520
27618
  completedExecutionLogMerging,
27521
27619
  completedExecutionLogAbbreviation,
27522
27620
  rootDirectoryUrl,
27621
+ devServerOrigin,
27523
27622
  maxExecutionsInParallel,
27524
27623
  defaultMsAllocatedPerExecution,
27525
27624
  failFast,
@@ -27532,21 +27631,7 @@ const executeTestPlan = async ({
27532
27631
  coverageMethodForBrowsers,
27533
27632
  coverageMethodForNodeJs,
27534
27633
  coverageV8ConflictWarning,
27535
- coverageTempDirectoryRelativeUrl,
27536
- scenarios: {
27537
- dev: true,
27538
- test: true
27539
- },
27540
- sourcemaps,
27541
- plugins,
27542
- nodeEsmResolution,
27543
- fileSystemMagicResolution,
27544
- writeGeneratedFiles,
27545
- protocol,
27546
- privateKey,
27547
- certificate,
27548
- host,
27549
- port
27634
+ coverageTempDirectoryRelativeUrl
27550
27635
  });
27551
27636
 
27552
27637
  if (updateProcessExitCode && result.planSummary.counters.total !== result.planSummary.counters.completed) {
@@ -27664,8 +27749,7 @@ const createRuntimeFromPlaywright = ({
27664
27749
  const runtime = {
27665
27750
  type: "browser",
27666
27751
  name: browserName,
27667
- version: browserVersion,
27668
- needsServer: true
27752
+ version: browserVersion
27669
27753
  };
27670
27754
  let browserAndContextPromise;
27671
27755
 
@@ -27674,7 +27758,7 @@ const createRuntimeFromPlaywright = ({
27674
27758
  logger,
27675
27759
  rootDirectoryUrl,
27676
27760
  fileRelativeUrl,
27677
- server,
27761
+ devServerOrigin,
27678
27762
  // measurePerformance,
27679
27763
  collectPerformance,
27680
27764
  coverageEnabled = false,
@@ -27749,7 +27833,13 @@ const createRuntimeFromPlaywright = ({
27749
27833
  await disconnected;
27750
27834
  };
27751
27835
 
27752
- const page = await browserContext.newPage();
27836
+ const coverageInHeaders = coverageEnabled && (!coveragePlaywrightAPIAvailable || coverageMethodForBrowsers !== "playwright_api");
27837
+ const page = await browserContext.newPage({
27838
+ extraHTTPHeaders: { ...(coverageInHeaders ? {
27839
+ "x-coverage-istanbul": JSON.stringify(coverageConfig)
27840
+ } : {})
27841
+ }
27842
+ });
27753
27843
 
27754
27844
  const closePage = async () => {
27755
27845
  try {
@@ -27777,7 +27867,7 @@ const createRuntimeFromPlaywright = ({
27777
27867
  const v8CoveragesWithFsUrls = v8CoveragesWithWebUrls.map(v8CoveragesWithWebUrl => {
27778
27868
  const fsUrl = moveUrl({
27779
27869
  url: v8CoveragesWithWebUrl.url,
27780
- from: `${server.origin}/`,
27870
+ from: `${devServerOrigin}/`,
27781
27871
  to: rootDirectoryUrl,
27782
27872
  preferAbsolute: true
27783
27873
  });
@@ -27848,7 +27938,7 @@ const createRuntimeFromPlaywright = ({
27848
27938
  });
27849
27939
  }
27850
27940
 
27851
- const fileClientUrl = new URL(fileRelativeUrl, `${server.origin}/`).href; // https://github.com/GoogleChrome/puppeteer/blob/v1.4.0/docs/api.md#event-console
27941
+ const fileClientUrl = new URL(fileRelativeUrl, `${devServerOrigin}/`).href; // https://github.com/GoogleChrome/puppeteer/blob/v1.4.0/docs/api.md#event-console
27852
27942
 
27853
27943
  const removeConsoleListener = registerEvent({
27854
27944
  object: page,
@@ -27962,7 +28052,7 @@ const createRuntimeFromPlaywright = ({
27962
28052
  } = returnValue;
27963
28053
  const error = evalException(exceptionSource, {
27964
28054
  rootDirectoryUrl,
27965
- server,
28055
+ devServerOrigin,
27966
28056
  transformErrorHook
27967
28057
  });
27968
28058
  cb({
@@ -28198,7 +28288,7 @@ const registerEvent = ({
28198
28288
 
28199
28289
  const evalException = (exceptionSource, {
28200
28290
  rootDirectoryUrl,
28201
- server,
28291
+ devServerOrigin,
28202
28292
  transformErrorHook
28203
28293
  }) => {
28204
28294
  const script = new Script(exceptionSource, {
@@ -28207,7 +28297,7 @@ const evalException = (exceptionSource, {
28207
28297
  const error = script.runInThisContext();
28208
28298
 
28209
28299
  if (error && error instanceof Error) {
28210
- const remoteRootRegexp = new RegExp(escapeRegexpSpecialChars(`${server.origin}/`), "g");
28300
+ const remoteRootRegexp = new RegExp(escapeRegexpSpecialChars(`${devServerOrigin}/`), "g");
28211
28301
  error.stack = error.stack.replace(remoteRootRegexp, rootDirectoryUrl);
28212
28302
  error.message = error.message.replace(remoteRootRegexp, rootDirectoryUrl);
28213
28303
  }
@@ -29205,7 +29295,7 @@ const startBuildServer = async ({
29205
29295
  certificate,
29206
29296
  privateKey,
29207
29297
  acceptAnyIp,
29208
- host,
29298
+ hostname,
29209
29299
  port = 9779,
29210
29300
  services = [],
29211
29301
  keepProcessAlive = true,
@@ -29342,7 +29432,7 @@ const startBuildServer = async ({
29342
29432
  certificate,
29343
29433
  privateKey,
29344
29434
  acceptAnyIp,
29345
- host,
29435
+ hostname,
29346
29436
  port,
29347
29437
  serverTiming: true,
29348
29438
  requestWaitingMs: 60_000,
@@ -29387,15 +29477,15 @@ const createBuildFilesService = ({
29387
29477
  buildIndexPath
29388
29478
  }) => {
29389
29479
  return request => {
29390
- const urlIsVersioned = new URL(request.ressource, request.origin).searchParams.has("v");
29480
+ const urlIsVersioned = new URL(request.url).searchParams.has("v");
29391
29481
 
29392
- if (buildIndexPath && request.ressource === "/") {
29482
+ if (buildIndexPath && request.resource === "/") {
29393
29483
  request = { ...request,
29394
- ressource: `/${buildIndexPath}`
29484
+ resource: `/${buildIndexPath}`
29395
29485
  };
29396
29486
  }
29397
29487
 
29398
- return fetchFileSystem(new URL(request.ressource.slice(1), buildDirectoryUrl), {
29488
+ return fetchFileSystem(new URL(request.resource.slice(1), buildDirectoryUrl), {
29399
29489
  headers: request.headers,
29400
29490
  cacheControl: urlIsVersioned ? `private,max-age=${SECONDS_IN_30_DAYS},immutable` : "private,max-age=0,must-revalidate",
29401
29491
  etagEnabled: true,
@@ -29413,32 +29503,17 @@ const execute = async ({
29413
29503
  handleSIGINT = true,
29414
29504
  logLevel,
29415
29505
  rootDirectoryUrl,
29506
+ devServerOrigin,
29416
29507
  fileRelativeUrl,
29417
29508
  allocatedMs,
29418
29509
  mirrorConsole = true,
29419
29510
  keepRunning = false,
29420
- services,
29421
29511
  collectConsole,
29422
29512
  collectCoverage,
29423
29513
  coverageTempDirectoryUrl,
29424
29514
  collectPerformance = false,
29425
29515
  runtime,
29426
29516
  runtimeParams,
29427
- scenarios = {
29428
- dev: true
29429
- },
29430
- plugins = [],
29431
- nodeEsmResolution,
29432
- fileSystemMagicResolution,
29433
- transpilation,
29434
- htmlSupervisor = true,
29435
- sourcemaps = "inline",
29436
- writeGeneratedFiles = false,
29437
- port,
29438
- protocol,
29439
- http2,
29440
- certificate,
29441
- privateKey,
29442
29517
  ignoreError = false
29443
29518
  }) => {
29444
29519
  const logger = createLogger({
@@ -29460,45 +29535,21 @@ const execute = async ({
29460
29535
 
29461
29536
  runtimeParams = {
29462
29537
  rootDirectoryUrl,
29538
+ devServerOrigin,
29463
29539
  fileRelativeUrl,
29464
29540
  ...runtimeParams
29465
29541
  };
29466
29542
 
29467
- if (runtime.needsServer) {
29468
- const server = await startOmegaServer({
29469
- signal: executeOperation.signal,
29470
- logLevel: "warn",
29471
- keepProcessAlive: false,
29472
- services,
29473
- port,
29474
- protocol,
29475
- http2,
29476
- certificate,
29477
- privateKey,
29478
- rootDirectoryUrl,
29479
- scenarios,
29480
- runtimeCompat: {
29481
- [runtime.name]: runtime.version
29482
- },
29483
- plugins,
29484
- htmlSupervisor,
29485
- nodeEsmResolution,
29486
- fileSystemMagicResolution,
29487
- transpilation,
29488
- sourcemaps,
29489
- writeGeneratedFiles
29490
- });
29491
- executeOperation.addEndCallback(async () => {
29492
- await server.stop("execution done");
29493
- });
29494
- runtimeParams = { ...runtimeParams,
29495
- server
29496
- };
29543
+ if (runtime.type === "browser") {
29544
+ if (!devServerOrigin) {
29545
+ throw new TypeError(`devServerOrigin is required when running tests on browser(s)`);
29546
+ }
29497
29547
 
29498
- resultTransformer = result => {
29499
- result.server = server;
29500
- return result;
29501
- };
29548
+ const devServerStarted = await pingServer(devServerOrigin);
29549
+
29550
+ if (!devServerStarted) {
29551
+ throw new Error(`dev server not started at ${devServerOrigin}. It is required to run tests`);
29552
+ }
29502
29553
  }
29503
29554
 
29504
29555
  let result = await run({
@@ -29620,4 +29671,4 @@ const jsenvPluginInjectGlobals = urlAssociations => {
29620
29671
  };
29621
29672
  };
29622
29673
 
29623
- export { build, chromium, chromiumIsolatedTab, execute, executeTestPlan, firefox, firefoxIsolatedTab, jsenvPluginInjectGlobals, nodeChildProcess, nodeWorkerThread, startBuildServer, startDevServer, webkit, webkitIsolatedTab };
29674
+ export { build, chromium, chromiumIsolatedTab, execute, executeTestPlan, firefox, firefoxIsolatedTab, jsenvPluginInjectGlobals, nodeChildProcess, nodeWorkerThread, pingServer, startBuildServer, startDevServer, webkit, webkitIsolatedTab };