@jsenv/core 27.8.1 → 28.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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/{wrapper.mjs → ws.js} +0 -0
  4. package/dist/main.js +540 -481
  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 +21 -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/node_esm_resolution/jsenv_plugin_node_esm_resolution.js +2 -13
  30. package/src/plugins/plugin_controller.js +2 -2
  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;
@@ -12862,7 +12862,7 @@ const jsenvPluginNodeEsmResolution = ({
12862
12862
  }
12863
12863
  },
12864
12864
  resolveUrl: {
12865
- js_import_export: (reference, context) => {
12865
+ js_import_export: reference => {
12866
12866
  const {
12867
12867
  parentUrl,
12868
12868
  specifier
@@ -12882,16 +12882,7 @@ const jsenvPluginNodeEsmResolution = ({
12882
12882
  // changes
12883
12883
 
12884
12884
  const dependsOnPackageJson = type !== "relative_specifier" && type !== "absolute_specifier" && type !== "node_builtin_specifier";
12885
- const relatedUrlInfos = context.urlGraph.getRelatedUrlInfos(reference.parentUrl);
12886
- relatedUrlInfos.forEach(relatedUrlInfo => {
12887
- if (relatedUrlInfo.dependsOnPackageJson) {
12888
- // the url may depend due to an other reference
12889
- // in that case keep dependsOnPackageJson to true
12890
- return;
12891
- }
12892
-
12893
- relatedUrlInfo.dependsOnPackageJson = dependsOnPackageJson;
12894
- });
12885
+ reference.dependsOnPackageJson = dependsOnPackageJson;
12895
12886
  return url;
12896
12887
  }
12897
12888
  },
@@ -13190,7 +13181,7 @@ const jsenvPluginHtmlSupervisor = ({
13190
13181
  name: "jsenv:html_supervisor",
13191
13182
  appliesDuring: "dev",
13192
13183
  serve: async (request, context) => {
13193
- if (request.ressource.startsWith("/__get_code_frame__/")) {
13184
+ if (request.pathname.startsWith("/__get_code_frame__/")) {
13194
13185
  const {
13195
13186
  pathname,
13196
13187
  searchParams
@@ -13249,8 +13240,8 @@ const jsenvPluginHtmlSupervisor = ({
13249
13240
  };
13250
13241
  }
13251
13242
 
13252
- if (request.ressource.startsWith("/__get_error_cause__/")) {
13253
- const file = request.ressource.slice("/__get_error_cause__/".length);
13243
+ if (request.pathname.startsWith("/__get_error_cause__/")) {
13244
+ const file = request.pathname.slice("/__get_error_cause__/".length);
13254
13245
 
13255
13246
  if (!file) {
13256
13247
  return {
@@ -13309,8 +13300,8 @@ const jsenvPluginHtmlSupervisor = ({
13309
13300
  };
13310
13301
  }
13311
13302
 
13312
- if (request.ressource.startsWith("/__open_in_editor__/")) {
13313
- const file = request.ressource.slice("/__open_in_editor__/".length);
13303
+ if (request.pathname.startsWith("/__open_in_editor__/")) {
13304
+ const file = request.pathname.slice("/__open_in_editor__/".length);
13314
13305
 
13315
13306
  if (!file) {
13316
13307
  return {
@@ -13742,7 +13733,6 @@ const jsenvPluginImportMetaScenarios = () => {
13742
13733
  });
13743
13734
  const {
13744
13735
  dev = [],
13745
- test = [],
13746
13736
  build = []
13747
13737
  } = metadata.importMetaScenarios;
13748
13738
  const replacements = [];
@@ -13759,9 +13749,6 @@ const jsenvPluginImportMetaScenarios = () => {
13759
13749
  dev.forEach(path => {
13760
13750
  replace(path, "undefined");
13761
13751
  });
13762
- test.forEach(path => {
13763
- replace(path, context.scenarios.test ? "true" : "undefined");
13764
- });
13765
13752
  build.forEach(path => {
13766
13753
  replace(path, "true");
13767
13754
  });
@@ -13773,12 +13760,6 @@ const jsenvPluginImportMetaScenarios = () => {
13773
13760
  dev.forEach(path => {
13774
13761
  replace(path, "true");
13775
13762
  });
13776
-
13777
- if (context.scenarios.test) {
13778
- test.forEach(path => {
13779
- replace(path, "true");
13780
- });
13781
- }
13782
13763
  }
13783
13764
 
13784
13765
  const magicSource = createMagicSource(urlInfo.content);
@@ -14062,6 +14043,87 @@ export default inlineContent.text`,
14062
14043
  return [asJsonModule, asCssModule, asTextModule];
14063
14044
  };
14064
14045
 
14046
+ const babelPluginInstrument = (api, {
14047
+ rootDirectoryUrl,
14048
+ useInlineSourceMaps = false,
14049
+ coverageConfig = {
14050
+ "./**/*": true
14051
+ }
14052
+ }) => {
14053
+ const {
14054
+ programVisitor
14055
+ } = requireFromJsenv("istanbul-lib-instrument");
14056
+ const {
14057
+ types
14058
+ } = api;
14059
+ const associations = URL_META.resolveAssociations({
14060
+ cover: coverageConfig
14061
+ }, rootDirectoryUrl);
14062
+
14063
+ const shouldInstrument = url => {
14064
+ return URL_META.applyAssociations({
14065
+ url,
14066
+ associations
14067
+ }).cover;
14068
+ };
14069
+
14070
+ return {
14071
+ name: "transform-instrument",
14072
+ visitor: {
14073
+ Program: {
14074
+ enter(path) {
14075
+ const {
14076
+ file
14077
+ } = this;
14078
+ const {
14079
+ opts
14080
+ } = file;
14081
+
14082
+ if (!opts.sourceFileName) {
14083
+ console.warn(`cannot instrument file when "sourceFileName" option is not set`);
14084
+ return;
14085
+ }
14086
+
14087
+ const fileUrl = fileSystemPathToUrl$1(opts.sourceFileName);
14088
+
14089
+ if (!shouldInstrument(fileUrl)) {
14090
+ return;
14091
+ }
14092
+
14093
+ this.__dv__ = null;
14094
+ let inputSourceMap;
14095
+
14096
+ if (useInlineSourceMaps) {
14097
+ // https://github.com/istanbuljs/babel-plugin-istanbul/commit/a9e15643d249a2985e4387e4308022053b2cd0ad#diff-1fdf421c05c1140f6d71444ea2b27638R65
14098
+ inputSourceMap = opts.inputSourceMap || file.inputMap ? file.inputMap.sourcemap : null;
14099
+ } else {
14100
+ inputSourceMap = opts.inputSourceMap;
14101
+ }
14102
+
14103
+ this.__dv__ = programVisitor(types, opts.filenameRelative || opts.filename, {
14104
+ coverageVariable: "__coverage__",
14105
+ inputSourceMap
14106
+ });
14107
+
14108
+ this.__dv__.enter(path);
14109
+ },
14110
+
14111
+ exit(path) {
14112
+ if (!this.__dv__) {
14113
+ return;
14114
+ }
14115
+
14116
+ const object = this.__dv__.exit(path); // object got two properties: fileCoverage and sourceMappingURL
14117
+
14118
+
14119
+ this.file.metadata.coverage = object.fileCoverage;
14120
+ }
14121
+
14122
+ }
14123
+ }
14124
+ };
14125
+ };
14126
+
14065
14127
  const versionFromValue = value => {
14066
14128
  if (typeof value === "number") {
14067
14129
  return numberToVersion(value);
@@ -15243,6 +15305,17 @@ const jsenvPluginBabel = ({
15243
15305
  getImportSpecifier
15244
15306
  });
15245
15307
 
15308
+ if (context.scenarios.dev) {
15309
+ const requestHeaders = context.request.headers;
15310
+
15311
+ if (requestHeaders["x-coverage-instanbul"]) {
15312
+ babelPluginStructure["transform-instrument"] = [babelPluginInstrument, {
15313
+ rootDirectoryUrl: context.rootDirectoryUrl,
15314
+ coverageConfig: JSON.parse(requestHeaders["x-coverage-instanbul"])
15315
+ }];
15316
+ }
15317
+ }
15318
+
15246
15319
  if (getCustomBabelPlugins) {
15247
15320
  Object.assign(babelPluginStructure, getCustomBabelPlugins(context));
15248
15321
  }
@@ -16315,7 +16388,7 @@ const htmlNodeCanHotReload = node => {
16315
16388
  if (node.nodeName === "link") {
16316
16389
  const {
16317
16390
  isStylesheet,
16318
- isRessourceHint,
16391
+ isResourceHint,
16319
16392
  rel
16320
16393
  } = analyzeLinkNode(node);
16321
16394
 
@@ -16324,9 +16397,9 @@ const htmlNodeCanHotReload = node => {
16324
16397
  return true;
16325
16398
  }
16326
16399
 
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?)
16400
+ if (isResourceHint) {
16401
+ // for resource hints html will be notified the underlying resource has changed
16402
+ // but we won't do anything (if the resource is deleted we should?)
16330
16403
  return true;
16331
16404
  }
16332
16405
 
@@ -16561,10 +16634,7 @@ import.meta.hot = createImportMetaHot(import.meta.url)
16561
16634
  const jsenvPluginHmr = () => {
16562
16635
  return {
16563
16636
  name: "jsenv:hmr",
16564
- appliesDuring: {
16565
- dev: true,
16566
- test: false
16567
- },
16637
+ appliesDuring: "dev",
16568
16638
  redirectUrl: reference => {
16569
16639
  const urlObject = new URL(reference.url);
16570
16640
 
@@ -16607,10 +16677,7 @@ const jsenvPluginAutoreloadClient = () => {
16607
16677
  const autoreloadClientFileUrl = new URL("./js/autoreload.js", import.meta.url).href;
16608
16678
  return {
16609
16679
  name: "jsenv:autoreload_client",
16610
- appliesDuring: {
16611
- dev: true,
16612
- test: false
16613
- },
16680
+ appliesDuring: "dev",
16614
16681
  transformUrlContent: {
16615
16682
  html: (htmlUrlInfo, context) => {
16616
16683
  const htmlAst = parseHtmlString(htmlUrlInfo.content);
@@ -16640,10 +16707,7 @@ const jsenvPluginAutoreloadServer = ({
16640
16707
  }) => {
16641
16708
  return {
16642
16709
  name: "jsenv:autoreload_server",
16643
- appliesDuring: {
16644
- dev: true,
16645
- test: false
16646
- },
16710
+ appliesDuring: "dev",
16647
16711
  serverEvents: {
16648
16712
  reload: ({
16649
16713
  sendServerEvent,
@@ -16805,7 +16869,7 @@ const jsenvPluginAutoreloadServer = ({
16805
16869
  firstUrlInfo
16806
16870
  }) => {
16807
16871
  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
16872
+ 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
16873
  // then if we can hot update all dependencies
16810
16874
 
16811
16875
  if (mainHotUpdate.declined) {
@@ -16852,7 +16916,7 @@ const jsenvPluginAutoreloadServer = ({
16852
16916
  rootDirectoryUrl,
16853
16917
  urlGraph
16854
16918
  }) => {
16855
- if (request.ressource === "/__graph__") {
16919
+ if (request.pathname === "/__graph__") {
16856
16920
  const graphJson = JSON.stringify(urlGraph.toJSON(rootDirectoryUrl));
16857
16921
  return {
16858
16922
  status: 200,
@@ -16922,7 +16986,7 @@ const jsenvPluginExplorer = ({
16922
16986
  serve: async (request, {
16923
16987
  rootDirectoryUrl
16924
16988
  }) => {
16925
- if (request.ressource !== "/") {
16989
+ if (request.pathname !== "/") {
16926
16990
  return null;
16927
16991
  }
16928
16992
 
@@ -17896,7 +17960,7 @@ const nodeStreamToObservable = nodeStream => {
17896
17960
  // safe measure, ensure the readable stream gets
17897
17961
  // used in the next ${readableStreamLifetimeInSeconds} otherwise destroys it
17898
17962
  const timeout = setTimeout(() => {
17899
- process.emitWarning(`Readable stream not used after ${readableStreamLifetimeInSeconds} seconds. It will be destroyed to release ressources`, {
17963
+ process.emitWarning(`Readable stream not used after ${readableStreamLifetimeInSeconds} seconds. It will be destroyed to release resources`, {
17900
17964
  CODE: "READABLE_STREAM_TIMEOUT",
17901
17965
  // url is for http client request
17902
17966
  detail: `path: ${nodeStream.path}, fd: ${nodeStream.fd}, url: ${nodeStream.url}`
@@ -17976,8 +18040,8 @@ const fromNodeRequest = (nodeRequest, {
17976
18040
  signal,
17977
18041
  http2: Boolean(nodeRequest.stream),
17978
18042
  origin: requestOrigin,
17979
- ...getPropertiesFromRessource({
17980
- ressource: nodeRequest.url,
18043
+ ...getPropertiesFromResource({
18044
+ resource: nodeRequest.url,
17981
18045
  baseUrl: requestOrigin
17982
18046
  }),
17983
18047
  method: nodeRequest.method,
@@ -17986,13 +18050,13 @@ const fromNodeRequest = (nodeRequest, {
17986
18050
  });
17987
18051
  };
17988
18052
  const applyRedirectionToRequest = (request, {
17989
- ressource,
18053
+ resource,
17990
18054
  pathname,
17991
18055
  ...rest
17992
18056
  }) => {
17993
18057
  return { ...request,
17994
- ...(ressource ? getPropertiesFromRessource({
17995
- ressource,
18058
+ ...(resource ? getPropertiesFromResource({
18059
+ resource,
17996
18060
  baseUrl: request.url
17997
18061
  }) : pathname ? getPropertiesFromPathname({
17998
18062
  pathname,
@@ -18002,16 +18066,16 @@ const applyRedirectionToRequest = (request, {
18002
18066
  };
18003
18067
  };
18004
18068
 
18005
- const getPropertiesFromRessource = ({
18006
- ressource,
18069
+ const getPropertiesFromResource = ({
18070
+ resource,
18007
18071
  baseUrl
18008
18072
  }) => {
18009
- const urlObject = new URL(ressource, baseUrl);
18073
+ const urlObject = new URL(resource, baseUrl);
18010
18074
  let pathname = urlObject.pathname;
18011
18075
  return {
18012
18076
  url: String(urlObject),
18013
18077
  pathname,
18014
- ressource
18078
+ resource
18015
18079
  };
18016
18080
  };
18017
18081
 
@@ -18019,8 +18083,8 @@ const getPropertiesFromPathname = ({
18019
18083
  pathname,
18020
18084
  baseUrl
18021
18085
  }) => {
18022
- return getPropertiesFromRessource({
18023
- ressource: `${pathname}${new URL(baseUrl).search}`,
18086
+ return getPropertiesFromResource({
18087
+ resource: `${pathname}${new URL(baseUrl).search}`,
18024
18088
  baseUrl
18025
18089
  });
18026
18090
  };
@@ -18048,11 +18112,11 @@ const createPushRequest = (request, {
18048
18112
  const getHeadersInheritedByPushRequest = request => {
18049
18113
  const headersInherited = { ...request.headers
18050
18114
  }; // 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
18115
+ // Time remains valid for request to other resources so we keep it
18052
18116
  // in child requests
18053
18117
  // delete childHeaders["if-modified-since"]
18054
18118
  // 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
18119
+ // A request made to an other resource must not inherit the eTag
18056
18120
 
18057
18121
  delete headersInherited["if-none-match"];
18058
18122
  return headersInherited;
@@ -18367,101 +18431,12 @@ const statusIsClientError = status => status >= 400 && status < 500;
18367
18431
 
18368
18432
  const statusIsServerError = status => status >= 500 && status < 600;
18369
18433
 
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
18434
  const listen = async ({
18460
18435
  signal = new AbortController().signal,
18461
18436
  server,
18462
18437
  port,
18463
18438
  portHint,
18464
- host
18439
+ hostname
18465
18440
  }) => {
18466
18441
  const listeningOperation = Abort.startOperation();
18467
18442
 
@@ -18472,7 +18447,7 @@ const listen = async ({
18472
18447
  listeningOperation.throwIfAborted();
18473
18448
  port = await findFreePort(portHint, {
18474
18449
  signal: listeningOperation.signal,
18475
- host
18450
+ hostname
18476
18451
  });
18477
18452
  }
18478
18453
 
@@ -18480,7 +18455,7 @@ const listen = async ({
18480
18455
  port = await startListening({
18481
18456
  server,
18482
18457
  port,
18483
- host
18458
+ hostname
18484
18459
  });
18485
18460
  listeningOperation.addAbortCallback(() => stopListening(server));
18486
18461
  listeningOperation.throwIfAborted();
@@ -18492,7 +18467,7 @@ const listen = async ({
18492
18467
 
18493
18468
  const findFreePort = async (initialPort = 1, {
18494
18469
  signal = new AbortController().signal,
18495
- host = "127.0.0.1",
18470
+ hostname = "127.0.0.1",
18496
18471
  min = 1,
18497
18472
  max = 65534,
18498
18473
  next = port => port + 1
@@ -18514,27 +18489,27 @@ const findFreePort = async (initialPort = 1, {
18514
18489
  const nextPort = next(port);
18515
18490
 
18516
18491
  if (nextPort > max) {
18517
- throw new Error(`${host} has no available port between ${min} and ${max}`);
18492
+ throw new Error(`${hostname} has no available port between ${min} and ${max}`);
18518
18493
  }
18519
18494
 
18520
- return testUntil(nextPort, host);
18495
+ return testUntil(nextPort, hostname);
18521
18496
  };
18522
18497
 
18523
- const freePort = await testUntil(initialPort, host);
18498
+ const freePort = await testUntil(initialPort, hostname);
18524
18499
  return freePort;
18525
18500
  } finally {
18526
18501
  await findFreePortOperation.end();
18527
18502
  }
18528
18503
  };
18529
18504
 
18530
- const portIsFree = async (port, host) => {
18505
+ const portIsFree = async (port, hostname) => {
18531
18506
  const server = createServer();
18532
18507
 
18533
18508
  try {
18534
18509
  await startListening({
18535
18510
  server,
18536
18511
  port,
18537
- host
18512
+ hostname
18538
18513
  });
18539
18514
  } catch (error) {
18540
18515
  if (error && error.code === "EADDRINUSE") {
@@ -18555,7 +18530,7 @@ const portIsFree = async (port, host) => {
18555
18530
  const startListening = ({
18556
18531
  server,
18557
18532
  port,
18558
- host
18533
+ hostname
18559
18534
  }) => {
18560
18535
  return new Promise((resolve, reject) => {
18561
18536
  server.on("error", reject);
@@ -18564,7 +18539,7 @@ const startListening = ({
18564
18539
  // https://nodejs.org/api/net.html#net_server_listen_port_host_backlog_callback
18565
18540
  resolve(server.address().port);
18566
18541
  });
18567
- server.listen(port, host);
18542
+ server.listen(port, hostname);
18568
18543
  });
18569
18544
  };
18570
18545
 
@@ -18803,6 +18778,134 @@ const STOP_REASON_PROCESS_BEFORE_EXIT = createReason("process before exit");
18803
18778
  const STOP_REASON_PROCESS_EXIT = createReason("process exit");
18804
18779
  const STOP_REASON_NOT_SPECIFIED = createReason("not specified");
18805
18780
 
18781
+ const createIpGetters = () => {
18782
+ const networkAddresses = [];
18783
+ const networkInterfaceMap = networkInterfaces();
18784
+
18785
+ for (const key of Object.keys(networkInterfaceMap)) {
18786
+ for (const networkAddress of networkInterfaceMap[key]) {
18787
+ networkAddresses.push(networkAddress);
18788
+ }
18789
+ }
18790
+
18791
+ return {
18792
+ getFirstInternalIp: ({
18793
+ preferIpv6
18794
+ }) => {
18795
+ const isPref = preferIpv6 ? isIpV6 : isIpV4;
18796
+ let firstInternalIp;
18797
+
18798
+ for (const networkAddress of networkAddresses) {
18799
+ if (networkAddress.internal) {
18800
+ firstInternalIp = networkAddress.address;
18801
+
18802
+ if (isPref(networkAddress)) {
18803
+ break;
18804
+ }
18805
+ }
18806
+ }
18807
+
18808
+ return firstInternalIp;
18809
+ },
18810
+ getFirstExternalIp: ({
18811
+ preferIpv6
18812
+ }) => {
18813
+ const isPref = preferIpv6 ? isIpV6 : isIpV4;
18814
+ let firstExternalIp;
18815
+
18816
+ for (const networkAddress of networkAddresses) {
18817
+ if (!networkAddress.internal) {
18818
+ firstExternalIp = networkAddress.address;
18819
+
18820
+ if (isPref(networkAddress)) {
18821
+ break;
18822
+ }
18823
+ }
18824
+ }
18825
+
18826
+ return firstExternalIp;
18827
+ }
18828
+ };
18829
+ };
18830
+
18831
+ const isIpV4 = networkAddress => {
18832
+ // node 18.5
18833
+ if (typeof networkAddress.family === "number") {
18834
+ return networkAddress.family === 4;
18835
+ }
18836
+
18837
+ return networkAddress.family === "IPv4";
18838
+ };
18839
+
18840
+ const isIpV6 = networkAddress => !isIpV4(networkAddress);
18841
+
18842
+ const parseHostname = hostname => {
18843
+ if (hostname === "0.0.0.0") {
18844
+ return {
18845
+ type: "ip",
18846
+ label: "unspecified",
18847
+ version: 4
18848
+ };
18849
+ }
18850
+
18851
+ if (hostname === "::" || hostname === "0000:0000:0000:0000:0000:0000:0000:0000") {
18852
+ return {
18853
+ type: "ip",
18854
+ label: "unspecified",
18855
+ version: 6
18856
+ };
18857
+ }
18858
+
18859
+ if (hostname === "127.0.0.1") {
18860
+ return {
18861
+ type: "ip",
18862
+ label: "loopback",
18863
+ version: 4
18864
+ };
18865
+ }
18866
+
18867
+ if (hostname === "::1" || hostname === "0000:0000:0000:0000:0000:0000:0000:0001") {
18868
+ return {
18869
+ type: "ip",
18870
+ label: "loopback",
18871
+ version: 6
18872
+ };
18873
+ }
18874
+
18875
+ const ipVersion = isIP(hostname);
18876
+
18877
+ if (ipVersion === 0) {
18878
+ return {
18879
+ type: "hostname"
18880
+ };
18881
+ }
18882
+
18883
+ return {
18884
+ type: "ip",
18885
+ version: ipVersion
18886
+ };
18887
+ };
18888
+
18889
+ const applyDnsResolution = async (hostname, {
18890
+ verbatim = false
18891
+ } = {}) => {
18892
+ const dnsResolution = await new Promise((resolve, reject) => {
18893
+ lookup(hostname, {
18894
+ verbatim
18895
+ }, (error, address, family) => {
18896
+ if (error) {
18897
+ reject(error);
18898
+ } else {
18899
+ resolve({
18900
+ address,
18901
+ family
18902
+ });
18903
+ }
18904
+ });
18905
+ });
18906
+ return dnsResolution;
18907
+ };
18908
+
18806
18909
  const startServer = async ({
18807
18910
  signal = new AbortController().signal,
18808
18911
  logLevel,
@@ -18814,7 +18917,8 @@ const startServer = async ({
18814
18917
  redirectHttpToHttps,
18815
18918
  allowHttpRequestOnHttps = false,
18816
18919
  acceptAnyIp = false,
18817
- host = acceptAnyIp ? undefined : "localhost",
18920
+ preferIpv6,
18921
+ hostname = "localhost",
18818
18922
  port = 0,
18819
18923
  // assign a random available port
18820
18924
  portHint,
@@ -18839,11 +18943,15 @@ const startServer = async ({
18839
18943
  requestWaitingMs
18840
18944
  }) => {
18841
18945
  warn(createDetailedMessage$1(`still no response found for request after ${requestWaitingMs} ms`, {
18842
- "request url": `${request.origin}${request.ressource}`,
18946
+ "request url": request.url,
18843
18947
  "request headers": JSON.stringify(request.headers, null, " ")
18844
18948
  }));
18845
18949
  }
18846
18950
  } = {}) => {
18951
+ const logger = createLogger({
18952
+ logLevel
18953
+ });
18954
+
18847
18955
  if (protocol !== "http" && protocol !== "https") {
18848
18956
  throw new Error(`protocol must be http or https, got ${protocol}`);
18849
18957
  }
@@ -18862,10 +18970,6 @@ const startServer = async ({
18862
18970
  throw new Error(`http2 needs "https" but protocol is "${protocol}"`);
18863
18971
  }
18864
18972
 
18865
- const logger = createLogger({
18866
- logLevel
18867
- });
18868
-
18869
18973
  if (redirectHttpToHttps === undefined && protocol === "https" && !allowHttpRequestOnHttps) {
18870
18974
  redirectHttpToHttps = true;
18871
18975
  }
@@ -18898,6 +19002,10 @@ const startServer = async ({
18898
19002
  let nodeServer;
18899
19003
  const startServerOperation = Abort.startOperation();
18900
19004
  const stopCallbackList = createCallbackListNotifiedOnce();
19005
+ const serverOrigins = {
19006
+ local: "" // favors hostname when possible
19007
+
19008
+ };
18901
19009
 
18902
19010
  try {
18903
19011
  startServerOperation.addAbortSignal(signal);
@@ -18925,12 +19033,85 @@ const startServer = async ({
18925
19033
  nodeServer.unref();
18926
19034
  }
18927
19035
 
19036
+ const createOrigin = hostname => {
19037
+ if (isIP(hostname) === 6) {
19038
+ return `${protocol}://[${hostname}]`;
19039
+ }
19040
+
19041
+ return `${protocol}://${hostname}`;
19042
+ };
19043
+
19044
+ const ipGetters = createIpGetters();
19045
+ let hostnameToListen;
19046
+
19047
+ if (acceptAnyIp) {
19048
+ const firstInternalIp = ipGetters.getFirstInternalIp({
19049
+ preferIpv6
19050
+ });
19051
+ serverOrigins.local = createOrigin(firstInternalIp);
19052
+ serverOrigins.localip = createOrigin(firstInternalIp);
19053
+ const firstExternalIp = ipGetters.getFirstExternalIp({
19054
+ preferIpv6
19055
+ });
19056
+ serverOrigins.externalip = createOrigin(firstExternalIp);
19057
+ hostnameToListen = preferIpv6 ? "::" : "0.0.0.0";
19058
+ } else {
19059
+ hostnameToListen = hostname;
19060
+ }
19061
+
19062
+ const hostnameInfo = parseHostname(hostname);
19063
+
19064
+ if (hostnameInfo.type === "ip") {
19065
+ if (acceptAnyIp) {
19066
+ throw new Error(`hostname cannot be an ip when acceptAnyIp is enabled, got ${hostname}`);
19067
+ }
19068
+
19069
+ preferIpv6 = hostnameInfo.version === 6;
19070
+ const firstInternalIp = ipGetters.getFirstInternalIp({
19071
+ preferIpv6
19072
+ });
19073
+ serverOrigins.local = createOrigin(firstInternalIp);
19074
+ serverOrigins.localip = createOrigin(firstInternalIp);
19075
+
19076
+ if (hostnameInfo.label === "unspecified") {
19077
+ const firstExternalIp = ipGetters.getFirstExternalIp({
19078
+ preferIpv6
19079
+ });
19080
+ serverOrigins.externalip = createOrigin(firstExternalIp);
19081
+ } else if (hostnameInfo.label === "loopback") {} else {
19082
+ serverOrigins.local = createOrigin(hostname);
19083
+ }
19084
+ } else {
19085
+ const hostnameDnsResolution = await applyDnsResolution(hostname, {
19086
+ verbatim: true
19087
+ });
19088
+
19089
+ if (hostnameDnsResolution) {
19090
+ const hostnameIp = hostnameDnsResolution.address;
19091
+ serverOrigins.localip = createOrigin(hostnameIp);
19092
+ serverOrigins.local = createOrigin(hostname);
19093
+ } else {
19094
+ const firstInternalIp = ipGetters.getFirstInternalIp({
19095
+ preferIpv6
19096
+ }); // fallback to internal ip because there is no ip
19097
+ // associated to this hostname on operating system (in hosts file)
19098
+
19099
+ hostname = firstInternalIp;
19100
+ hostnameToListen = firstInternalIp;
19101
+ serverOrigins.local = createOrigin(firstInternalIp);
19102
+ }
19103
+ }
19104
+
18928
19105
  port = await listen({
18929
19106
  signal: startServerOperation.signal,
18930
19107
  server: nodeServer,
18931
19108
  port,
18932
19109
  portHint,
18933
- host
19110
+ hostname: hostnameToListen
19111
+ }); // normalize origins (remove :80 when port is 80 for instance)
19112
+
19113
+ Object.keys(serverOrigins).forEach(key => {
19114
+ serverOrigins[key] = new URL(`${serverOrigins[key]}:${port}`).origin;
18934
19115
  });
18935
19116
  serviceController.callHooks("serverListening", {
18936
19117
  port
@@ -18941,12 +19122,23 @@ const startServer = async ({
18941
19122
  startServerOperation.throwIfAborted();
18942
19123
  } finally {
18943
19124
  await startServerOperation.end();
18944
- } // now the server is started (listening) it cannot be aborted anymore
19125
+ } // the main server origin
19126
+ // - when protocol is http
19127
+ // node-fetch do not apply local dns resolution to map localhost back to 127.0.0.1
19128
+ // despites localhost being mapped so we prefer to use the internal ip
19129
+ // (127.0.0.1)
19130
+ // - when protocol is https
19131
+ // using the hostname becomes important because the certificate is generated
19132
+ // for hostnames, not for ips
19133
+ // so we prefer https://locahost or https://local_hostname
19134
+ // over the ip
19135
+
19136
+
19137
+ const serverOrigin = serverOrigins.local; // now the server is started (listening) it cannot be aborted anymore
18945
19138
  // (otherwise an AbortError is thrown to the code calling "startServer")
18946
19139
  // we can proceed to create a stop function to stop it gacefully
18947
19140
  // and add a request handler
18948
19141
 
18949
-
18950
19142
  stopCallbackList.add(({
18951
19143
  reason
18952
19144
  }) => {
@@ -18984,12 +19176,6 @@ const startServer = async ({
18984
19176
  };
18985
19177
 
18986
19178
  status = "opened";
18987
- const serverOrigins = await getServerOrigins({
18988
- protocol,
18989
- host,
18990
- port
18991
- });
18992
- const serverOrigin = serverOrigins.local;
18993
19179
  const removeConnectionErrorListener = listenServerConnectionError(nodeServer, onError);
18994
19180
  stopCallbackList.add(removeConnectionErrorListener);
18995
19181
  const connectionsTracker = trackServerPendingConnections(nodeServer, {
@@ -19181,7 +19367,7 @@ const startServer = async ({
19181
19367
  const onPushStreamError = e => {
19182
19368
  addRequestLog(requestNode, {
19183
19369
  type: "error",
19184
- value: createDetailedMessage$1(`An error occured while pushing a stream to the response for ${request.ressource}`, {
19370
+ value: createDetailedMessage$1(`An error occured while pushing a stream to the response for ${request.resource}`, {
19185
19371
  "error stack": e.stack
19186
19372
  })
19187
19373
  });
@@ -19285,7 +19471,7 @@ const startServer = async ({
19285
19471
 
19286
19472
  addRequestLog(requestNode, {
19287
19473
  type: "info",
19288
- value: request.parent ? `Push ${request.ressource}` : `${request.method} ${request.origin}${request.ressource}`
19474
+ value: request.parent ? `Push ${request.resource}` : `${request.method} ${request.url}`
19289
19475
  });
19290
19476
 
19291
19477
  const warn = value => {
@@ -19605,11 +19791,11 @@ const startServer = async ({
19605
19791
  const websocketClients = new Set();
19606
19792
  const {
19607
19793
  WebSocketServer
19608
- } = await import("./js/wrapper.mjs");
19794
+ } = await import("./js/ws.js");
19609
19795
  let websocketServer = new WebSocketServer({
19610
19796
  noServer: true
19611
19797
  });
19612
- const websocketOrigin = protocol === "https" ? `wss://${host}:${port}` : `ws://${host}:${port}`;
19798
+ const websocketOrigin = protocol === "https" ? `wss://${hostname}:${port}` : `ws://${hostname}:${port}`;
19613
19799
  server.websocketOrigin = websocketOrigin;
19614
19800
 
19615
19801
  const upgradeCallback = (nodeRequest, socket, head) => {
@@ -19650,6 +19836,7 @@ const startServer = async ({
19650
19836
  Object.assign(server, {
19651
19837
  getStatus: () => status,
19652
19838
  port,
19839
+ hostname,
19653
19840
  origin: serverOrigin,
19654
19841
  origins: serverOrigins,
19655
19842
  nodeServer,
@@ -20102,7 +20289,7 @@ const fetchFileSystem = async (filesystemUrl, {
20102
20289
 
20103
20290
  rootDirectoryUrl = rootDirectoryUrlString;
20104
20291
  } // 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)
20292
+ // but no-cache means resource can be cache but must be revalidated (yeah naming is strange)
20106
20293
  // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#Cacheability
20107
20294
 
20108
20295
 
@@ -20243,7 +20430,7 @@ const getClientCacheResponse = async ({
20243
20430
  sourceUrl
20244
20431
  }) => {
20245
20432
  // 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)
20433
+ // but no-cache means resource can be cache but must be revalidated (yeah naming is strange)
20247
20434
  // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#Cacheability
20248
20435
  if (headers["cache-control"] === "no-store" || // let's disable it on no-cache too
20249
20436
  headers["cache-control"] === "no-cache") {
@@ -20951,8 +21138,8 @@ const flattenAndFilterPlugins = (plugins, {
20951
21138
  }
20952
21139
 
20953
21140
  if (typeof appliesDuring === "string") {
20954
- if (!["dev", "test", "build"].includes(appliesDuring)) {
20955
- throw new Error(`"appliesDuring" must be "dev", "test" or "build", got ${appliesDuring}`);
21141
+ if (!["dev", "build"].includes(appliesDuring)) {
21142
+ throw new Error(`"appliesDuring" must be "dev" or "build", got ${appliesDuring}`);
20956
21143
  }
20957
21144
 
20958
21145
  if (scenarios[appliesDuring]) {
@@ -21644,7 +21831,7 @@ const validateResponseIntegrity = ({
21644
21831
  return true;
21645
21832
  }
21646
21833
 
21647
- const error = new Error(`Integrity validation failed for ressource "${url}". The integrity found for this ressource is "${strongestAlgo}-${actualBase64Value}"`);
21834
+ const error = new Error(`Integrity validation failed for resource "${url}". The integrity found for this resource is "${strongestAlgo}-${actualBase64Value}"`);
21648
21835
  error.code = "EINTEGRITY";
21649
21836
  error.algorithm = strongestAlgo;
21650
21837
  error.found = actualBase64Value;
@@ -21756,7 +21943,8 @@ const createKitchen = ({
21756
21943
  isEntryPoint = false,
21757
21944
  isInline = false,
21758
21945
  injected = false,
21759
- isRessourceHint = false,
21946
+ isResourceHint = false,
21947
+ dependsOnPackageJson,
21760
21948
  content,
21761
21949
  contentType,
21762
21950
  assert,
@@ -21794,8 +21982,9 @@ const createKitchen = ({
21794
21982
  isEntryPoint,
21795
21983
  isInline,
21796
21984
  injected,
21797
- isRessourceHint,
21798
- // for inline ressources the reference contains the content
21985
+ isResourceHint,
21986
+ dependsOnPackageJson,
21987
+ // for inline resources the reference contains the content
21799
21988
  content,
21800
21989
  contentType,
21801
21990
  timing: {},
@@ -21846,8 +22035,8 @@ const createKitchen = ({
21846
22035
  // And this is because this hook inject query params used to:
21847
22036
  // - bypass browser cache (?v)
21848
22037
  // - convey information (?hmr)
21849
- // But do not represent an other ressource, it is considered as
21850
- // the same ressource under the hood
22038
+ // But do not represent an other resource, it is considered as
22039
+ // the same resource under the hood
21851
22040
 
21852
22041
  pluginController.callHooks("transformUrlSearchParams", reference, kitchenContext, returnValue => {
21853
22042
  Object.keys(returnValue).forEach(key => {
@@ -22427,6 +22616,21 @@ const applyReferenceEffectsOnUrlInfo = (reference, urlInfo, context) => {
22427
22616
  urlInfo.originalContent = context.scenarios.build ? urlInfo.originalContent === undefined ? reference.content : urlInfo.originalContent : reference.content;
22428
22617
  urlInfo.content = reference.content;
22429
22618
  }
22619
+
22620
+ const {
22621
+ dependsOnPackageJson
22622
+ } = reference;
22623
+ urlInfo.dependsOnPackageJson = dependsOnPackageJson;
22624
+ const relatedUrlInfos = context.urlGraph.getRelatedUrlInfos(reference.parentUrl);
22625
+ relatedUrlInfos.forEach(relatedUrlInfo => {
22626
+ if (relatedUrlInfo.dependsOnPackageJson) {
22627
+ // the url may depend due to an other reference
22628
+ // in that case keep dependsOnPackageJson to true
22629
+ return;
22630
+ }
22631
+
22632
+ relatedUrlInfo.dependsOnPackageJson = dependsOnPackageJson;
22633
+ });
22430
22634
  };
22431
22635
 
22432
22636
  const adjustUrlSite = (urlInfo, {
@@ -22656,11 +22860,11 @@ const loadUrlGraph = async ({
22656
22860
  references
22657
22861
  } = urlInfo;
22658
22862
  references.forEach(reference => {
22659
- // we don't cook ressource hints
22660
- // because they might refer to ressource that will be modified during build
22863
+ // we don't cook resource hints
22864
+ // because they might refer to resource that will be modified during build
22661
22865
  // 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) {
22866
+ // so that the preload is deleted by "resync_resource_hints.js" otherwise
22867
+ if (reference.isResourceHint) {
22664
22868
  return;
22665
22869
  } // we use reference.generatedUrl to mimic what a browser would do:
22666
22870
  // do a fetch to the specifier as found in the file
@@ -23325,23 +23529,23 @@ self.serviceWorkerUrls = ${JSON.stringify(serviceWorkerUrls, null, " ")};
23325
23529
  /*
23326
23530
  * Update <link rel="preload"> and friends after build (once we know everything)
23327
23531
  *
23328
- * - Used to remove ressource hint targeting an url that is no longer used:
23532
+ * - Used to remove resource hint targeting an url that is no longer used:
23329
23533
  * - Happens because of import assertions transpilation (file is inlined into JS)
23330
23534
  */
23331
- const resyncRessourceHints = async ({
23535
+ const resyncResourceHints = async ({
23332
23536
  logger,
23333
23537
  finalGraphKitchen,
23334
23538
  finalGraph,
23335
23539
  rawUrls,
23336
23540
  postBuildRedirections
23337
23541
  }) => {
23338
- const ressourceHintActions = [];
23542
+ const resourceHintActions = [];
23339
23543
  GRAPH.forEach(finalGraph, urlInfo => {
23340
23544
  if (urlInfo.type !== "html") {
23341
23545
  return;
23342
23546
  }
23343
23547
 
23344
- ressourceHintActions.push(async () => {
23548
+ resourceHintActions.push(async () => {
23345
23549
  const htmlAst = parseHtmlString(urlInfo.content, {
23346
23550
  storeOriginalPositions: false
23347
23551
  });
@@ -23353,9 +23557,9 @@ const resyncRessourceHints = async ({
23353
23557
  }
23354
23558
 
23355
23559
  const rel = getHtmlNodeAttribute(linkNode, "rel");
23356
- const isRessourceHint = ["preconnect", "dns-prefetch", "prefetch", "preload", "modulepreload"].includes(rel);
23560
+ const isresourceHint = ["preconnect", "dns-prefetch", "prefetch", "preload", "modulepreload"].includes(rel);
23357
23561
 
23358
- if (!isRessourceHint) {
23562
+ if (!isresourceHint) {
23359
23563
  return;
23360
23564
  }
23361
23565
 
@@ -23369,7 +23573,7 @@ const resyncRessourceHints = async ({
23369
23573
  }
23370
23574
 
23371
23575
  if (!buildUrl) {
23372
- logger.warn(`remove ressource hint because cannot find "${href}"`);
23576
+ logger.warn(`remove resource hint because cannot find "${href}"`);
23373
23577
  actions.push(() => {
23374
23578
  removeHtmlNode(linkNode);
23375
23579
  });
@@ -23380,7 +23584,7 @@ const resyncRessourceHints = async ({
23380
23584
  const urlInfo = finalGraph.getUrlInfo(buildUrl);
23381
23585
 
23382
23586
  if (!urlInfo) {
23383
- logger.warn(`remove ressource hint because cannot find "${buildUrl}" in the graph`);
23587
+ logger.warn(`remove resource hint because cannot find "${buildUrl}" in the graph`);
23384
23588
  actions.push(() => {
23385
23589
  removeHtmlNode(linkNode);
23386
23590
  });
@@ -23388,7 +23592,7 @@ const resyncRessourceHints = async ({
23388
23592
  }
23389
23593
 
23390
23594
  if (urlInfo.dependents.size === 0) {
23391
- logger.info(`remove ressource hint because "${href}" not used anymore`);
23595
+ logger.info(`remove resource hint because "${href}" not used anymore`);
23392
23596
  actions.push(() => {
23393
23597
  removeHtmlNode(linkNode);
23394
23598
  });
@@ -23420,7 +23624,7 @@ const resyncRessourceHints = async ({
23420
23624
  }
23421
23625
  });
23422
23626
  });
23423
- await Promise.all(ressourceHintActions.map(ressourceHintAction => ressourceHintAction()));
23627
+ await Promise.all(resourceHintActions.map(resourceHintAction => resourceHintAction()));
23424
23628
  };
23425
23629
 
23426
23630
  /*
@@ -23701,10 +23905,10 @@ build ${entryPointKeys.length} entry points`);
23701
23905
  addToBundlerIfAny(dependencyUrlInfo);
23702
23906
  });
23703
23907
  rawUrlInfo.references.forEach(reference => {
23704
- if (reference.isRessourceHint && reference.expectedType === "js_module") {
23908
+ if (reference.isResourceHint && reference.expectedType === "js_module") {
23705
23909
  const referencedUrlInfo = rawGraph.getUrlInfo(reference.url);
23706
23910
 
23707
- if (referencedUrlInfo && // something else than the ressource hint is using this url
23911
+ if (referencedUrlInfo && // something else than the resource hint is using this url
23708
23912
  referencedUrlInfo.dependents.size > 0) {
23709
23913
  addToBundlerIfAny(referencedUrlInfo);
23710
23914
  }
@@ -23997,7 +24201,7 @@ build ${entryPointKeys.length} entry points`);
23997
24201
  throw new Error(`urls should be inside build directory at this stage, found "${reference.url}"`);
23998
24202
  }
23999
24203
 
24000
- if (reference.isRessourceHint) {
24204
+ if (reference.isResourceHint) {
24001
24205
  // return the raw url, we will resync at the end
24002
24206
  return rawUrls[reference.url];
24003
24207
  } // remove eventual search params and hash
@@ -24101,7 +24305,7 @@ build ${entryPointKeys.length} entry points`);
24101
24305
  kitchen: finalGraphKitchen,
24102
24306
  outDirectoryUrl: new URL(".jsenv/postbuild/", rootDirectoryUrl),
24103
24307
  writeGeneratedFiles,
24104
- skipRessourceHint: true,
24308
+ skipResourceHint: true,
24105
24309
  startLoading: cookEntryFile => {
24106
24310
  entryUrls.forEach(entryUrl => {
24107
24311
  const [, postBuildEntryUrlInfo] = cookEntryFile({
@@ -24173,7 +24377,7 @@ ${Array.from(finalGraph.urlInfoMap.keys()).join("\n")}`);
24173
24377
  urlInfo.data.buildUrlIsVersioned = useVersionedUrl;
24174
24378
  urlInfo.data.buildUrlSpecifier = buildUrlSpecifier;
24175
24379
  });
24176
- await resyncRessourceHints({
24380
+ await resyncResourceHints({
24177
24381
  logger,
24178
24382
  finalGraphKitchen,
24179
24383
  finalGraph,
@@ -24517,7 +24721,7 @@ const applyUrlVersioning = async ({
24517
24721
  return null;
24518
24722
  }
24519
24723
 
24520
- if (reference.isRessourceHint) {
24724
+ if (reference.isResourceHint) {
24521
24725
  return null;
24522
24726
  } // specifier comes from "normalize" hook done a bit earlier in this file
24523
24727
  // we want to get back their build url to access their infos
@@ -24578,7 +24782,7 @@ const applyUrlVersioning = async ({
24578
24782
  operation: buildOperation,
24579
24783
  urlGraph: finalGraph,
24580
24784
  kitchen: versioningKitchen,
24581
- skipRessourceHint: true,
24785
+ skipResourceHint: true,
24582
24786
  writeGeneratedFiles,
24583
24787
  startLoading: cookEntryFile => {
24584
24788
  postBuildEntryUrls.forEach(postBuildEntryUrl => {
@@ -25060,7 +25264,7 @@ const createFileService = ({
25060
25264
 
25061
25265
  return async request => {
25062
25266
  // serve file inside ".jsenv" directory
25063
- const requestFileUrl = new URL(request.ressource.slice(1), rootDirectoryUrl).href;
25267
+ const requestFileUrl = new URL(request.resource.slice(1), rootDirectoryUrl).href;
25064
25268
 
25065
25269
  if (urlIsInsideOf(requestFileUrl, jsenvDirectoryUrl)) {
25066
25270
  return fetchFileSystem(requestFileUrl, {
@@ -25084,7 +25288,7 @@ const createFileService = ({
25084
25288
  const parentUrl = inferParentFromRequest(request, rootDirectoryUrl);
25085
25289
 
25086
25290
  if (parentUrl) {
25087
- reference = urlGraph.inferReference(request.ressource, parentUrl);
25291
+ reference = urlGraph.inferReference(request.resource, parentUrl);
25088
25292
  }
25089
25293
 
25090
25294
  if (!reference) {
@@ -25094,7 +25298,7 @@ const createFileService = ({
25094
25298
  },
25095
25299
  parentUrl: parentUrl || rootDirectoryUrl,
25096
25300
  type: "http_request",
25097
- specifier: request.ressource
25301
+ specifier: request.resource
25098
25302
  });
25099
25303
  reference = entryPoint[0];
25100
25304
  }
@@ -25261,7 +25465,7 @@ const startOmegaServer = async ({
25261
25465
  privateKey,
25262
25466
  certificate,
25263
25467
  acceptAnyIp,
25264
- host,
25468
+ hostname,
25265
25469
  port = 0,
25266
25470
  keepProcessAlive = false,
25267
25471
  onStop = () => {},
@@ -25302,7 +25506,7 @@ const startOmegaServer = async ({
25302
25506
  certificate,
25303
25507
  privateKey,
25304
25508
  acceptAnyIp,
25305
- host,
25509
+ hostname,
25306
25510
  port,
25307
25511
  requestWaitingMs: 60_1000,
25308
25512
  services: [jsenvServiceCORS({
@@ -25408,7 +25612,7 @@ const startDevServer = async ({
25408
25612
  http2 = false,
25409
25613
  certificate,
25410
25614
  privateKey,
25411
- host,
25615
+ hostname,
25412
25616
  port = 3456,
25413
25617
  acceptAnyIp,
25414
25618
  keepProcessAlive = true,
@@ -25548,7 +25752,7 @@ const startDevServer = async ({
25548
25752
  http2,
25549
25753
  certificate,
25550
25754
  privateKey,
25551
- host,
25755
+ hostname,
25552
25756
  port,
25553
25757
  services,
25554
25758
  rootDirectoryUrl,
@@ -25651,87 +25855,6 @@ const generateCoverageTextLog = (coverage, {
25651
25855
  report.execute(context);
25652
25856
  };
25653
25857
 
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
25858
  const readNodeV8CoverageDirectory = async ({
25736
25859
  logger,
25737
25860
  signal,
@@ -26424,6 +26547,41 @@ const run = async ({
26424
26547
  }
26425
26548
  };
26426
26549
 
26550
+ const pingServer = async url => {
26551
+ const server = createServer();
26552
+ const {
26553
+ hostname,
26554
+ port
26555
+ } = new URL(url);
26556
+
26557
+ try {
26558
+ await new Promise((resolve, reject) => {
26559
+ server.on("error", reject);
26560
+ server.on("listening", () => {
26561
+ resolve();
26562
+ });
26563
+ server.listen(port, hostname);
26564
+ });
26565
+ } catch (error) {
26566
+ if (error && error.code === "EADDRINUSE") {
26567
+ return true;
26568
+ }
26569
+
26570
+ if (error && error.code === "EACCES") {
26571
+ return true;
26572
+ }
26573
+
26574
+ throw error;
26575
+ }
26576
+
26577
+ await new Promise((resolve, reject) => {
26578
+ server.on("error", reject);
26579
+ server.on("close", resolve);
26580
+ server.close();
26581
+ });
26582
+ return false;
26583
+ };
26584
+
26427
26585
  const ensureGlobalGc = () => {
26428
26586
  if (!global.gc) {
26429
26587
  v8.setFlagsFromString("--expose_gc");
@@ -26859,8 +27017,8 @@ const executePlan = async (plan, {
26859
27017
  completedExecutionLogMerging,
26860
27018
  completedExecutionLogAbbreviation,
26861
27019
  rootDirectoryUrl,
27020
+ devServerOrigin,
26862
27021
  keepRunning,
26863
- services,
26864
27022
  defaultMsAllocatedPerExecution,
26865
27023
  maxExecutionsInParallel,
26866
27024
  failFast,
@@ -26873,18 +27031,6 @@ const executePlan = async (plan, {
26873
27031
  coverageMethodForNodeJs,
26874
27032
  coverageV8ConflictWarning,
26875
27033
  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
27034
  beforeExecutionCallback = () => {},
26889
27035
  afterExecutionCallback = () => {}
26890
27036
  } = {}) => {
@@ -26908,7 +27054,7 @@ const executePlan = async (plan, {
26908
27054
  if (runtime) {
26909
27055
  runtimes[runtime.name] = runtime.version;
26910
27056
 
26911
- if (runtime.needsServer) {
27057
+ if (runtime.type === "browser") {
26912
27058
  someNeedsServer = true;
26913
27059
  }
26914
27060
 
@@ -26999,6 +27145,7 @@ const executePlan = async (plan, {
26999
27145
 
27000
27146
  let runtimeParams = {
27001
27147
  rootDirectoryUrl,
27148
+ devServerOrigin,
27002
27149
  coverageEnabled,
27003
27150
  coverageConfig,
27004
27151
  coverageMethodForBrowsers,
@@ -27007,48 +27154,15 @@ const executePlan = async (plan, {
27007
27154
  };
27008
27155
 
27009
27156
  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
- }
27157
+ if (!devServerOrigin) {
27158
+ throw new TypeError(`devServerOrigin is required when running tests on browser(s)`);
27159
+ }
27039
27160
 
27040
- return {};
27041
- }
27042
- },
27043
- sourcemaps,
27044
- writeGeneratedFiles
27045
- });
27046
- multipleExecutionsOperation.addEndCallback(async () => {
27047
- await server.stop();
27048
- });
27049
- runtimeParams = { ...runtimeParams,
27050
- server
27051
- };
27161
+ const devServerStarted = await pingServer(devServerOrigin);
27162
+
27163
+ if (!devServerStarted) {
27164
+ throw new Error(`dev server not started at ${devServerOrigin}. It is required to run tests`);
27165
+ }
27052
27166
  }
27053
27167
 
27054
27168
  logger.debug(`Generate executions`);
@@ -27391,9 +27505,10 @@ const executeInParallel = async ({
27391
27505
  };
27392
27506
 
27393
27507
  /**
27394
- * Execute a list of files and log how it goes
27508
+ * Execute a list of files and log how it goes.
27395
27509
  * @param {Object} testPlanParameters
27396
27510
  * @param {string|url} testPlanParameters.rootDirectoryUrl Root directory of the project
27511
+ * @param {string|url} [testPlanParameters.serverOrigin=undefined] Jsenv dev server origin; required when executing test on browsers
27397
27512
  * @param {Object} testPlanParameters.testPlan Object associating patterns leading to files to runtimes where they should be executed
27398
27513
  * @param {boolean} [testPlanParameters.completedExecutionLogAbbreviation=false] Abbreviate completed execution information to shorten terminal output
27399
27514
  * @param {boolean} [testPlanParameters.completedExecutionLogMerging=false] Merge completed execution logs to shorten terminal output
@@ -27420,6 +27535,7 @@ const executeTestPlan = async ({
27420
27535
  completedExecutionLogAbbreviation = false,
27421
27536
  completedExecutionLogMerging = false,
27422
27537
  rootDirectoryUrl,
27538
+ devServerOrigin,
27423
27539
  testPlan,
27424
27540
  updateProcessExitCode = true,
27425
27541
  maxExecutionsInParallel = 1,
@@ -27450,17 +27566,7 @@ const executeTestPlan = async ({
27450
27566
  coverageReportSkipFull = false,
27451
27567
  coverageReportTextLog = true,
27452
27568
  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
27569
+ coverageReportHtmlDirectory = process.env.CI ? "./.coverage/" : null
27464
27570
  }) => {
27465
27571
  const logger = createLogger({
27466
27572
  logLevel
@@ -27520,6 +27626,7 @@ const executeTestPlan = async ({
27520
27626
  completedExecutionLogMerging,
27521
27627
  completedExecutionLogAbbreviation,
27522
27628
  rootDirectoryUrl,
27629
+ devServerOrigin,
27523
27630
  maxExecutionsInParallel,
27524
27631
  defaultMsAllocatedPerExecution,
27525
27632
  failFast,
@@ -27532,21 +27639,7 @@ const executeTestPlan = async ({
27532
27639
  coverageMethodForBrowsers,
27533
27640
  coverageMethodForNodeJs,
27534
27641
  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
27642
+ coverageTempDirectoryRelativeUrl
27550
27643
  });
27551
27644
 
27552
27645
  if (updateProcessExitCode && result.planSummary.counters.total !== result.planSummary.counters.completed) {
@@ -27664,8 +27757,7 @@ const createRuntimeFromPlaywright = ({
27664
27757
  const runtime = {
27665
27758
  type: "browser",
27666
27759
  name: browserName,
27667
- version: browserVersion,
27668
- needsServer: true
27760
+ version: browserVersion
27669
27761
  };
27670
27762
  let browserAndContextPromise;
27671
27763
 
@@ -27674,7 +27766,7 @@ const createRuntimeFromPlaywright = ({
27674
27766
  logger,
27675
27767
  rootDirectoryUrl,
27676
27768
  fileRelativeUrl,
27677
- server,
27769
+ devServerOrigin,
27678
27770
  // measurePerformance,
27679
27771
  collectPerformance,
27680
27772
  coverageEnabled = false,
@@ -27749,7 +27841,13 @@ const createRuntimeFromPlaywright = ({
27749
27841
  await disconnected;
27750
27842
  };
27751
27843
 
27752
- const page = await browserContext.newPage();
27844
+ const coverageInHeaders = coverageEnabled && (!coveragePlaywrightAPIAvailable || coverageMethodForBrowsers !== "playwright_api");
27845
+ const page = await browserContext.newPage({
27846
+ extraHTTPHeaders: { ...(coverageInHeaders ? {
27847
+ "x-coverage-istanbul": JSON.stringify(coverageConfig)
27848
+ } : {})
27849
+ }
27850
+ });
27753
27851
 
27754
27852
  const closePage = async () => {
27755
27853
  try {
@@ -27777,7 +27875,7 @@ const createRuntimeFromPlaywright = ({
27777
27875
  const v8CoveragesWithFsUrls = v8CoveragesWithWebUrls.map(v8CoveragesWithWebUrl => {
27778
27876
  const fsUrl = moveUrl({
27779
27877
  url: v8CoveragesWithWebUrl.url,
27780
- from: `${server.origin}/`,
27878
+ from: `${devServerOrigin}/`,
27781
27879
  to: rootDirectoryUrl,
27782
27880
  preferAbsolute: true
27783
27881
  });
@@ -27848,7 +27946,7 @@ const createRuntimeFromPlaywright = ({
27848
27946
  });
27849
27947
  }
27850
27948
 
27851
- const fileClientUrl = new URL(fileRelativeUrl, `${server.origin}/`).href; // https://github.com/GoogleChrome/puppeteer/blob/v1.4.0/docs/api.md#event-console
27949
+ const fileClientUrl = new URL(fileRelativeUrl, `${devServerOrigin}/`).href; // https://github.com/GoogleChrome/puppeteer/blob/v1.4.0/docs/api.md#event-console
27852
27950
 
27853
27951
  const removeConsoleListener = registerEvent({
27854
27952
  object: page,
@@ -27962,7 +28060,7 @@ const createRuntimeFromPlaywright = ({
27962
28060
  } = returnValue;
27963
28061
  const error = evalException(exceptionSource, {
27964
28062
  rootDirectoryUrl,
27965
- server,
28063
+ devServerOrigin,
27966
28064
  transformErrorHook
27967
28065
  });
27968
28066
  cb({
@@ -28198,7 +28296,7 @@ const registerEvent = ({
28198
28296
 
28199
28297
  const evalException = (exceptionSource, {
28200
28298
  rootDirectoryUrl,
28201
- server,
28299
+ devServerOrigin,
28202
28300
  transformErrorHook
28203
28301
  }) => {
28204
28302
  const script = new Script(exceptionSource, {
@@ -28207,7 +28305,7 @@ const evalException = (exceptionSource, {
28207
28305
  const error = script.runInThisContext();
28208
28306
 
28209
28307
  if (error && error instanceof Error) {
28210
- const remoteRootRegexp = new RegExp(escapeRegexpSpecialChars(`${server.origin}/`), "g");
28308
+ const remoteRootRegexp = new RegExp(escapeRegexpSpecialChars(`${devServerOrigin}/`), "g");
28211
28309
  error.stack = error.stack.replace(remoteRootRegexp, rootDirectoryUrl);
28212
28310
  error.message = error.message.replace(remoteRootRegexp, rootDirectoryUrl);
28213
28311
  }
@@ -29205,7 +29303,7 @@ const startBuildServer = async ({
29205
29303
  certificate,
29206
29304
  privateKey,
29207
29305
  acceptAnyIp,
29208
- host,
29306
+ hostname,
29209
29307
  port = 9779,
29210
29308
  services = [],
29211
29309
  keepProcessAlive = true,
@@ -29342,7 +29440,7 @@ const startBuildServer = async ({
29342
29440
  certificate,
29343
29441
  privateKey,
29344
29442
  acceptAnyIp,
29345
- host,
29443
+ hostname,
29346
29444
  port,
29347
29445
  serverTiming: true,
29348
29446
  requestWaitingMs: 60_000,
@@ -29387,15 +29485,15 @@ const createBuildFilesService = ({
29387
29485
  buildIndexPath
29388
29486
  }) => {
29389
29487
  return request => {
29390
- const urlIsVersioned = new URL(request.ressource, request.origin).searchParams.has("v");
29488
+ const urlIsVersioned = new URL(request.url).searchParams.has("v");
29391
29489
 
29392
- if (buildIndexPath && request.ressource === "/") {
29490
+ if (buildIndexPath && request.resource === "/") {
29393
29491
  request = { ...request,
29394
- ressource: `/${buildIndexPath}`
29492
+ resource: `/${buildIndexPath}`
29395
29493
  };
29396
29494
  }
29397
29495
 
29398
- return fetchFileSystem(new URL(request.ressource.slice(1), buildDirectoryUrl), {
29496
+ return fetchFileSystem(new URL(request.resource.slice(1), buildDirectoryUrl), {
29399
29497
  headers: request.headers,
29400
29498
  cacheControl: urlIsVersioned ? `private,max-age=${SECONDS_IN_30_DAYS},immutable` : "private,max-age=0,must-revalidate",
29401
29499
  etagEnabled: true,
@@ -29413,32 +29511,17 @@ const execute = async ({
29413
29511
  handleSIGINT = true,
29414
29512
  logLevel,
29415
29513
  rootDirectoryUrl,
29514
+ devServerOrigin,
29416
29515
  fileRelativeUrl,
29417
29516
  allocatedMs,
29418
29517
  mirrorConsole = true,
29419
29518
  keepRunning = false,
29420
- services,
29421
29519
  collectConsole,
29422
29520
  collectCoverage,
29423
29521
  coverageTempDirectoryUrl,
29424
29522
  collectPerformance = false,
29425
29523
  runtime,
29426
29524
  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
29525
  ignoreError = false
29443
29526
  }) => {
29444
29527
  const logger = createLogger({
@@ -29460,45 +29543,21 @@ const execute = async ({
29460
29543
 
29461
29544
  runtimeParams = {
29462
29545
  rootDirectoryUrl,
29546
+ devServerOrigin,
29463
29547
  fileRelativeUrl,
29464
29548
  ...runtimeParams
29465
29549
  };
29466
29550
 
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
- };
29551
+ if (runtime.type === "browser") {
29552
+ if (!devServerOrigin) {
29553
+ throw new TypeError(`devServerOrigin is required when running tests on browser(s)`);
29554
+ }
29497
29555
 
29498
- resultTransformer = result => {
29499
- result.server = server;
29500
- return result;
29501
- };
29556
+ const devServerStarted = await pingServer(devServerOrigin);
29557
+
29558
+ if (!devServerStarted) {
29559
+ throw new Error(`dev server not started at ${devServerOrigin}. It is required to run tests`);
29560
+ }
29502
29561
  }
29503
29562
 
29504
29563
  let result = await run({
@@ -29620,4 +29679,4 @@ const jsenvPluginInjectGlobals = urlAssociations => {
29620
29679
  };
29621
29680
  };
29622
29681
 
29623
- export { build, chromium, chromiumIsolatedTab, execute, executeTestPlan, firefox, firefoxIsolatedTab, jsenvPluginInjectGlobals, nodeChildProcess, nodeWorkerThread, startBuildServer, startDevServer, webkit, webkitIsolatedTab };
29682
+ export { build, chromium, chromiumIsolatedTab, execute, executeTestPlan, firefox, firefoxIsolatedTab, jsenvPluginInjectGlobals, nodeChildProcess, nodeWorkerThread, pingServer, startBuildServer, startDevServer, webkit, webkitIsolatedTab };