@jsenv/core 28.5.1 → 29.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.
package/dist/main.js CHANGED
@@ -4516,7 +4516,8 @@ const jsenvPluginUrlAnalysis = ({
4516
4516
  include,
4517
4517
  supportedProtocols = ["file:", "data:", "virtual:", "http:", "https:"]
4518
4518
  }) => {
4519
- let getIncludeInfo = () => undefined;
4519
+ // eslint-disable-next-line no-unused-vars
4520
+ let getIncludeInfo = url => undefined;
4520
4521
 
4521
4522
  if (include) {
4522
4523
  const associations = URL_META.resolveAssociations({
@@ -4570,7 +4571,6 @@ const jsenvPluginUrlAnalysis = ({
4570
4571
 
4571
4572
  if (protocolIsSupported) {
4572
4573
  reference.shouldHandle = true;
4573
- return;
4574
4574
  }
4575
4575
  },
4576
4576
  transformUrlContent: {
@@ -11119,20 +11119,6 @@ const jsenvPluginAsJsClassic = ({
11119
11119
  })] : [])];
11120
11120
  };
11121
11121
 
11122
- const jsenvPluginLeadingSlash = () => {
11123
- return {
11124
- name: "jsenv:leading_slash",
11125
- appliesDuring: "*",
11126
- resolveUrl: (reference, context) => {
11127
- if (reference.specifier[0] !== "/") {
11128
- return null;
11129
- }
11130
-
11131
- return new URL(reference.specifier.slice(1), context.rootDirectoryUrl).href;
11132
- }
11133
- };
11134
- };
11135
-
11136
11122
  // duplicated from @jsenv/log to avoid the dependency
11137
11123
  const createDetailedMessage = (message, details = {}) => {
11138
11124
  let string = `${message}`;
@@ -12022,41 +12008,6 @@ const jsenvPluginImportmap = () => {
12022
12008
  };
12023
12009
  };
12024
12010
 
12025
- const jsenvPluginUrlResolution = () => {
12026
- const urlResolver = reference => {
12027
- return new URL(reference.specifier, reference.baseUrl || reference.parentUrl).href;
12028
- };
12029
-
12030
- return {
12031
- name: "jsenv:url_resolution",
12032
- appliesDuring: "*",
12033
- resolveUrl: {
12034
- "http_request": urlResolver,
12035
- // during dev
12036
- "entry_point": urlResolver,
12037
- // during build
12038
- "link_href": urlResolver,
12039
- "script_src": urlResolver,
12040
- "a_href": urlResolver,
12041
- "iframe_src": urlResolver,
12042
- "img_src": urlResolver,
12043
- "img_srcset": urlResolver,
12044
- "source_src": urlResolver,
12045
- "source_srcset": urlResolver,
12046
- "image_href": urlResolver,
12047
- "use_href": urlResolver,
12048
- "css_@import": urlResolver,
12049
- "css_url": urlResolver,
12050
- "sourcemap_comment": urlResolver,
12051
- "js_import_export": urlResolver,
12052
- "js_url_specifier": urlResolver,
12053
- "js_inline_content": urlResolver,
12054
- "webmanifest_icon_src": urlResolver,
12055
- "package_json": urlResolver
12056
- }
12057
- };
12058
- };
12059
-
12060
12011
  const isSpecifierForNodeBuiltin = specifier => {
12061
12012
  return specifier.startsWith("node:") || NODE_BUILTIN_MODULE_SPECIFIERS.includes(specifier);
12062
12013
  };
@@ -13149,7 +13100,17 @@ const mainLegacyResolvers = {
13149
13100
  return null;
13150
13101
  },
13151
13102
  browser: (packageJson, packageUrl) => {
13152
- const browserMain = typeof packageJson.browser === "string" ? packageJson.browser : typeof packageJson.browser === "object" && packageJson.browser !== null ? packageJson.browser["."] : "";
13103
+ const browserMain = (() => {
13104
+ if (typeof packageJson.browser === "string") {
13105
+ return packageJson.browser;
13106
+ }
13107
+
13108
+ if (typeof packageJson.browser === "object" && packageJson.browser !== null) {
13109
+ return packageJson.browser["."];
13110
+ }
13111
+
13112
+ return "";
13113
+ })();
13153
13114
 
13154
13115
  if (!browserMain) {
13155
13116
  if (typeof packageJson.module === "string") {
@@ -13337,136 +13298,208 @@ const getExtensionsToTry = (magicExtensions, importer) => {
13337
13298
  * if that comes from node resolution or anything else (not even magic resolution)
13338
13299
  * it should likely be an other plugin happening after the others
13339
13300
  */
13340
- const jsenvPluginNodeEsmResolution = ({
13301
+ const createNodeEsmResolver = ({
13302
+ runtimeCompat,
13341
13303
  packageConditions
13342
13304
  }) => {
13343
- const addRelationshipWithPackageJson = ({
13344
- context,
13345
- packageJsonUrl,
13346
- field,
13347
- hasVersioningEffect = false
13348
- }) => {
13349
- const referenceFound = context.referenceUtils.find(ref => ref.type === "package_json" && ref.subtype === field);
13305
+ const nodeRuntimeEnabled = Object.keys(runtimeCompat).includes("node"); // https://nodejs.org/api/esm.html#resolver-algorithm-specification
13350
13306
 
13351
- if (referenceFound) {
13352
- return;
13353
- }
13354
-
13355
- const [, packageJsonUrlInfo] = context.referenceUtils.inject({
13356
- type: "package_json",
13357
- subtype: field,
13358
- specifier: packageJsonUrl,
13359
- isImplicit: true,
13360
- hasVersioningEffect
13307
+ packageConditions = packageConditions || [...readCustomConditionsFromProcessArgs(), nodeRuntimeEnabled ? "node" : "browser", "import"];
13308
+ return (reference, context) => {
13309
+ const {
13310
+ parentUrl,
13311
+ specifier
13312
+ } = reference;
13313
+ const {
13314
+ url,
13315
+ type,
13316
+ packageUrl
13317
+ } = applyNodeEsmResolution({
13318
+ conditions: packageConditions,
13319
+ parentUrl,
13320
+ specifier
13361
13321
  });
13362
13322
 
13363
- if (packageJsonUrlInfo.type === undefined) {
13364
- const packageJsonContentAsBuffer = readFileSync$1(new URL(packageJsonUrl));
13365
- packageJsonUrlInfo.type = "json";
13366
- packageJsonUrlInfo.content = String(packageJsonContentAsBuffer);
13367
- packageJsonUrlInfo.originalContentEtag = packageJsonUrlInfo.contentEtag = bufferToEtag$1(packageJsonContentAsBuffer);
13368
- }
13369
- };
13370
-
13371
- return {
13372
- name: "jsenv:node_esm_resolution",
13373
- appliesDuring: "*",
13374
- init: context => {
13375
- const nodeRuntimeEnabled = Object.keys(context.runtimeCompat).includes("node"); // https://nodejs.org/api/esm.html#resolver-algorithm-specification
13323
+ if (context.scenarios.dev) {
13324
+ const dependsOnPackageJson = type !== "relative_specifier" && type !== "absolute_specifier" && type !== "node_builtin_specifier";
13376
13325
 
13377
- packageConditions = packageConditions || [...readCustomConditionsFromProcessArgs(), nodeRuntimeEnabled ? "node" : "browser", "import"];
13378
- },
13379
- resolveUrl: {
13380
- js_import_export: (reference, context) => {
13381
- const {
13382
- parentUrl,
13383
- specifier
13384
- } = reference;
13385
- const {
13386
- url,
13387
- type,
13388
- packageUrl
13389
- } = applyNodeEsmResolution({
13390
- conditions: packageConditions,
13391
- parentUrl,
13392
- specifier
13326
+ if (dependsOnPackageJson) {
13327
+ // this reference depends on package.json and node_modules
13328
+ // to be resolved. Each file using this specifier
13329
+ // must be invalidated when corresponding package.json changes
13330
+ addRelationshipWithPackageJson({
13331
+ reference,
13332
+ context,
13333
+ packageJsonUrl: `${packageUrl}package.json`,
13334
+ field: type.startsWith("field:") ? `#${type.slice("field:".length)}` : ""
13393
13335
  });
13336
+ }
13337
+ }
13394
13338
 
13395
- if (context.scenarios.dev) {
13396
- const dependsOnPackageJson = type !== "relative_specifier" && type !== "absolute_specifier" && type !== "node_builtin_specifier";
13339
+ if (context.scenarios.dev) {
13340
+ // without this check a file inside a project without package.json
13341
+ // could be considered as a node module if there is a ancestor package.json
13342
+ // but we want to version only node modules
13343
+ if (url.includes("/node_modules/")) {
13344
+ const packageDirectoryUrl = defaultLookupPackageScope(url);
13345
+
13346
+ if (packageDirectoryUrl && packageDirectoryUrl !== context.rootDirectoryUrl) {
13347
+ const packageVersion = defaultReadPackageJson(packageDirectoryUrl).version; // package version can be null, see https://github.com/babel/babel/blob/2ce56e832c2dd7a7ed92c89028ba929f874c2f5c/packages/babel-runtime/helpers/esm/package.json#L2
13397
13348
 
13398
- if (dependsOnPackageJson) {
13399
- // this reference depends on package.json and node_modules
13400
- // to be resolved. Each file using this specifier
13401
- // must be invalidated when corresponding package.json changes
13349
+ if (packageVersion) {
13402
13350
  addRelationshipWithPackageJson({
13403
13351
  reference,
13404
13352
  context,
13405
- packageJsonUrl: `${packageUrl}package.json`,
13406
- field: type.startsWith("field:") ? `#${type.slice("field:".length)}` : ""
13353
+ packageJsonUrl: `${packageDirectoryUrl}package.json`,
13354
+ field: "version",
13355
+ hasVersioningEffect: true
13407
13356
  });
13408
13357
  }
13409
- }
13410
13358
 
13411
- return url;
13412
- }
13413
- },
13414
- transformUrlSearchParams: (reference, context) => {
13415
- if (reference.type === "package_json") {
13416
- return null;
13359
+ reference.version = packageVersion;
13360
+ }
13417
13361
  }
13362
+ }
13418
13363
 
13419
- if (context.scenarios.build) {
13420
- return null;
13421
- }
13364
+ return url;
13365
+ };
13366
+ };
13422
13367
 
13423
- if (!reference.url.startsWith("file:")) {
13424
- return null;
13425
- } // without this check a file inside a project without package.json
13426
- // could be considered as a node module if there is a ancestor package.json
13427
- // but we want to version only node modules
13368
+ const addRelationshipWithPackageJson = ({
13369
+ context,
13370
+ packageJsonUrl,
13371
+ field,
13372
+ hasVersioningEffect = false
13373
+ }) => {
13374
+ const referenceFound = context.referenceUtils.find(ref => ref.type === "package_json" && ref.subtype === field);
13428
13375
 
13376
+ if (referenceFound) {
13377
+ return;
13378
+ }
13429
13379
 
13430
- if (!reference.url.includes("/node_modules/")) {
13431
- return null;
13432
- }
13380
+ const [, packageJsonUrlInfo] = context.referenceUtils.inject({
13381
+ type: "package_json",
13382
+ subtype: field,
13383
+ specifier: packageJsonUrl,
13384
+ isImplicit: true,
13385
+ hasVersioningEffect
13386
+ });
13433
13387
 
13434
- if (reference.searchParams.has("v")) {
13435
- return null;
13436
- }
13388
+ if (packageJsonUrlInfo.type === undefined) {
13389
+ const packageJsonContentAsBuffer = readFileSync$1(new URL(packageJsonUrl));
13390
+ packageJsonUrlInfo.type = "json";
13391
+ packageJsonUrlInfo.content = String(packageJsonContentAsBuffer);
13392
+ packageJsonUrlInfo.originalContentEtag = packageJsonUrlInfo.contentEtag = bufferToEtag$1(packageJsonContentAsBuffer);
13393
+ }
13394
+ };
13437
13395
 
13438
- const packageDirectoryUrl = defaultLookupPackageScope(reference.url);
13396
+ /*
13397
+ * This plugin is responsible to resolve urls except for a few cases:
13398
+ * - A custom plugin implements a resolveUrl hook returning something
13399
+ * - The reference.type is "filesystem" -> it is handled by jsenv_plugin_file_urls.js
13400
+ *
13401
+ * By default node esm resolution applies inside js modules
13402
+ * and the rest uses the web standard url resolution (new URL):
13403
+ * - "http_request"
13404
+ * - "entry_point"
13405
+ * - "js_import_export"
13406
+ * - "link_href"
13407
+ * - "script_src"
13408
+ * - "a_href"
13409
+ * - "iframe_src
13410
+ * - "img_src"
13411
+ * - "img_srcset"
13412
+ * - "source_src"
13413
+ * - "source_srcset"
13414
+ * - "image_href"
13415
+ * - "use_href"
13416
+ * - "css_@import"
13417
+ * - "css_url"
13418
+ * - "sourcemap_comment"
13419
+ * - "js_url_specifier"
13420
+ * - "js_inline_content"
13421
+ * - "webmanifest_icon_src"
13422
+ * - "package_json"
13423
+ */
13424
+ const jsenvPluginUrlResolution = ({
13425
+ runtimeCompat,
13426
+ clientMainFileUrl,
13427
+ urlResolution
13428
+ }) => {
13429
+ const resolveUrlUsingWebResolution = reference => {
13430
+ return new URL(reference.specifier, reference.baseUrl || reference.parentUrl).href;
13431
+ };
13439
13432
 
13440
- if (!packageDirectoryUrl) {
13441
- return null;
13442
- }
13433
+ const resolvers = {};
13434
+ Object.keys(urlResolution).forEach(referenceType => {
13435
+ const resolver = urlResolution[referenceType];
13443
13436
 
13444
- if (packageDirectoryUrl === context.rootDirectoryUrl) {
13445
- return null;
13446
- } // there is a dependency between this file and the package.json version field
13437
+ if (typeof resolver !== "object") {
13438
+ throw new Error(`Unexpected urlResolution configuration:
13439
+ "${referenceType}" resolution value must be an object, got ${resolver}`);
13440
+ }
13447
13441
 
13442
+ let {
13443
+ web,
13444
+ node_esm,
13445
+ ...rest
13446
+ } = resolver;
13447
+ const unexpectedKey = Object.keys(rest)[0];
13448
13448
 
13449
- const packageVersion = defaultReadPackageJson(packageDirectoryUrl).version;
13449
+ if (unexpectedKey) {
13450
+ throw new Error(`Unexpected urlResolution configuration:
13451
+ "${referenceType}" resolution key must be "web" or "node_esm", found "${Object.keys(rest)[0]}"`);
13452
+ }
13450
13453
 
13451
- if (!packageVersion) {
13452
- // example where it happens: https://github.com/babel/babel/blob/2ce56e832c2dd7a7ed92c89028ba929f874c2f5c/packages/babel-runtime/helpers/esm/package.json#L2
13453
- return null;
13454
+ if (node_esm === undefined) {
13455
+ node_esm = referenceType === "js_import_export";
13456
+ }
13457
+
13458
+ if (web === undefined) {
13459
+ web = true;
13460
+ }
13461
+
13462
+ if (node_esm) {
13463
+ if (node_esm === true) node_esm = {};
13464
+ const {
13465
+ packageConditions
13466
+ } = node_esm;
13467
+ resolvers[referenceType] = createNodeEsmResolver({
13468
+ runtimeCompat,
13469
+ packageConditions
13470
+ });
13471
+ } else if (web) {
13472
+ resolvers[referenceType] = resolveUrlUsingWebResolution;
13473
+ }
13474
+ });
13475
+
13476
+ if (!resolvers["js_import_export"]) {
13477
+ resolvers.js_import_export = createNodeEsmResolver({
13478
+ runtimeCompat
13479
+ });
13480
+ }
13481
+
13482
+ if (!resolvers["*"]) {
13483
+ resolvers["*"] = resolveUrlUsingWebResolution;
13484
+ }
13485
+
13486
+ return {
13487
+ name: "jsenv:url_resolution",
13488
+ appliesDuring: "*",
13489
+ resolveUrl: (reference, context) => {
13490
+ if (reference.specifier === "/") {
13491
+ return String(clientMainFileUrl);
13454
13492
  }
13455
13493
 
13456
- if (reference.type === "js_import_export") {
13457
- addRelationshipWithPackageJson({
13458
- reference,
13459
- context,
13460
- packageJsonUrl: `${packageDirectoryUrl}package.json`,
13461
- field: "version",
13462
- hasVersioningEffect: true
13463
- });
13494
+ if (reference.specifier[0] === "/") {
13495
+ return new URL(reference.specifier.slice(1), context.rootDirectoryUrl).href;
13464
13496
  }
13465
13497
 
13466
- return {
13467
- v: packageVersion
13468
- };
13498
+ const resolver = resolvers[reference.type] || resolvers["*"];
13499
+ return resolver(reference, context);
13469
13500
  },
13501
+ // when specifier is prefixed by "file:///@ignore/"
13502
+ // we return an empty js module (used by node esm)
13470
13503
  fetchUrlContent: urlInfo => {
13471
13504
  if (urlInfo.url.startsWith("file:///@ignore/")) {
13472
13505
  return {
@@ -13492,12 +13525,19 @@ const jsenvPluginUrlVersion = () => {
13492
13525
  // this goal is achieved when we reach this part of the code
13493
13526
  // We get rid of this params so that urlGraph and other parts of the code
13494
13527
  // recognize the url (it is not considered as a different url)
13495
- const urlObject = new URL(reference.url);
13496
- urlObject.searchParams.delete("v");
13497
- return urlObject.href;
13528
+ const version = reference.searchParams.get("v");
13529
+
13530
+ if (version) {
13531
+ const urlObject = new URL(reference.url);
13532
+ urlObject.searchParams.delete("v");
13533
+ reference.version = version;
13534
+ return urlObject.href;
13535
+ }
13536
+
13537
+ return null;
13498
13538
  },
13499
13539
  transformUrlSearchParams: reference => {
13500
- if (!reference.data.version) {
13540
+ if (!reference.version) {
13501
13541
  return null;
13502
13542
  }
13503
13543
 
@@ -13506,7 +13546,7 @@ const jsenvPluginUrlVersion = () => {
13506
13546
  }
13507
13547
 
13508
13548
  return {
13509
- v: reference.data.version
13549
+ v: reference.version
13510
13550
  };
13511
13551
  }
13512
13552
  };
@@ -16561,16 +16601,10 @@ const htmlNodeCanHotReload = node => {
16561
16601
  }
16562
16602
 
16563
16603
  if (isResourceHint) {
16564
- // for resource hints html will be notified the underlying resource has changed
16565
- // but we won't do anything (if the resource is deleted we should?)
16566
- return true;
16567
- }
16568
-
16569
- if (rel === "icon") {
16570
- return true;
16604
+ return false;
16571
16605
  }
16572
16606
 
16573
- return false;
16607
+ return rel === "icon";
16574
16608
  }
16575
16609
 
16576
16610
  return [// "script_src", // script src cannot hot reload
@@ -16994,8 +17028,6 @@ const jsenvPluginAutoreloadServer = ({
16994
17028
  return dependentPropagationResult;
16995
17029
  } // declined by absence of boundary, we can keep searching
16996
17030
 
16997
-
16998
- continue;
16999
17031
  }
17000
17032
 
17001
17033
  if (instructions.length === 0) {
@@ -17135,18 +17167,7 @@ const jsenvPluginCacheControl = () => {
17135
17167
  appliesDuring: "dev",
17136
17168
  augmentResponse: ({
17137
17169
  reference
17138
- }, context) => {
17139
- if (context.scenarios.test) {
17140
- // During dev, all files are put into browser cache for 1 hour because:
17141
- // 1: Browser cache is a temporary directory created by playwright
17142
- // 2: We assume source files won't be modified while tests are running
17143
- return {
17144
- headers: {
17145
- "cache-control": `private,max-age=3600,immutable`
17146
- }
17147
- };
17148
- }
17149
-
17170
+ }) => {
17150
17171
  if (reference.searchParams.has("v") && !reference.searchParams.has("hmr")) {
17151
17172
  return {
17152
17173
  headers: {
@@ -17161,62 +17182,72 @@ const jsenvPluginCacheControl = () => {
17161
17182
  };
17162
17183
  const SECONDS_IN_30_DAYS$1 = 60 * 60 * 24 * 30;
17163
17184
 
17185
+ const explorerHtmlFileUrl = new URL("./html/explorer.html", import.meta.url);
17164
17186
  const jsenvPluginExplorer = ({
17165
- groups
17187
+ groups = {
17188
+ src: {
17189
+ "./src/**/*.html": true
17190
+ },
17191
+ tests: {
17192
+ "./tests/**/*.test.html": true
17193
+ }
17194
+ },
17195
+ clientMainFileUrl
17166
17196
  }) => {
17167
- const htmlClientFileUrl = new URL("./html/explorer.html", import.meta.url);
17168
17197
  const faviconClientFileUrl = new URL("./other/jsenv.png", import.meta.url);
17169
17198
  return {
17170
17199
  name: "jsenv:explorer",
17171
17200
  appliesDuring: "dev",
17172
- serve: async (request, {
17173
- rootDirectoryUrl
17174
- }) => {
17175
- if (request.pathname !== "/") {
17176
- return null;
17177
- }
17201
+ transformUrlContent: {
17202
+ html: async (urlInfo, context) => {
17203
+ if (urlInfo.url !== clientMainFileUrl) {
17204
+ return null;
17205
+ }
17178
17206
 
17179
- const associationsForExplorable = {};
17180
- Object.keys(groups).forEach(groupName => {
17181
- const groupConfig = groups[groupName];
17182
- associationsForExplorable[groupName] = {
17183
- "**/.jsenv/": false,
17184
- // avoid visting .jsenv directory in jsenv itself
17185
- ...groupConfig
17186
- };
17187
- });
17188
- const matchingFileResultArray = await collectFiles({
17189
- directoryUrl: rootDirectoryUrl,
17190
- associations: associationsForExplorable,
17191
- predicate: meta => Object.keys(meta).some(group => Boolean(meta[group]))
17192
- });
17193
- const files = matchingFileResultArray.map(({
17194
- relativeUrl,
17195
- meta
17196
- }) => ({
17197
- relativeUrl,
17198
- meta
17199
- }));
17200
- let html = String(readFileSync$1(new URL(htmlClientFileUrl)));
17201
- html = html.replace("ignore:FAVICON_HREF", DATA_URL.stringify({
17202
- contentType: CONTENT_TYPE.fromUrlExtension(faviconClientFileUrl),
17203
- base64Flag: true,
17204
- data: readFileSync$1(new URL(faviconClientFileUrl)).toString("base64")
17205
- }));
17206
- html = html.replace("SERVER_PARAMS", JSON.stringify({
17207
- rootDirectoryUrl,
17208
- groups,
17209
- files
17210
- }, null, " "));
17211
- return {
17212
- status: 200,
17213
- headers: {
17214
- "cache-control": "no-store",
17215
- "content-type": "text/html",
17216
- "content-length": Buffer.byteLength(html)
17217
- },
17218
- body: html
17219
- };
17207
+ let html = urlInfo.content;
17208
+
17209
+ if (html.includes("ignore:FAVICON_HREF")) {
17210
+ html = html.replace("ignore:FAVICON_HREF", DATA_URL.stringify({
17211
+ contentType: CONTENT_TYPE.fromUrlExtension(faviconClientFileUrl),
17212
+ base64Flag: true,
17213
+ data: readFileSync$1(new URL(faviconClientFileUrl)).toString("base64")
17214
+ }));
17215
+ }
17216
+
17217
+ if (html.includes("SERVER_PARAMS")) {
17218
+ const associationsForExplorable = {};
17219
+ Object.keys(groups).forEach(groupName => {
17220
+ const groupConfig = groups[groupName];
17221
+ associationsForExplorable[groupName] = {
17222
+ "**/.jsenv/": false,
17223
+ // avoid visting .jsenv directory in jsenv itself
17224
+ ...groupConfig
17225
+ };
17226
+ });
17227
+ const matchingFileResultArray = await collectFiles({
17228
+ directoryUrl: context.rootDirectoryUrl,
17229
+ associations: associationsForExplorable,
17230
+ predicate: meta => Object.keys(meta).some(group => Boolean(meta[group]))
17231
+ });
17232
+ const files = matchingFileResultArray.map(({
17233
+ relativeUrl,
17234
+ meta
17235
+ }) => ({
17236
+ relativeUrl,
17237
+ meta
17238
+ }));
17239
+ html = html.replace("SERVER_PARAMS", JSON.stringify({
17240
+ rootDirectoryUrl: context.rootDirectoryUrl,
17241
+ groups,
17242
+ files
17243
+ }, null, " "));
17244
+ Object.assign(urlInfo.headers, {
17245
+ "cache-control": "no-store"
17246
+ });
17247
+ }
17248
+
17249
+ return html;
17250
+ }
17220
17251
  }
17221
17252
  };
17222
17253
  };
@@ -17225,34 +17256,41 @@ const getCorePlugins = ({
17225
17256
  rootDirectoryUrl,
17226
17257
  runtimeCompat,
17227
17258
  urlAnalysis = {},
17228
- supervisor,
17229
- nodeEsmResolution = true,
17230
- fileSystemMagicResolution,
17259
+ urlResolution = {},
17260
+ fileSystemMagicRedirection,
17231
17261
  directoryReferenceAllowed,
17262
+ supervisor,
17232
17263
  transpilation = true,
17233
17264
  minification = false,
17234
17265
  bundling = false,
17266
+ clientMainFileUrl,
17235
17267
  clientAutoreload = false,
17236
17268
  clientFileChangeCallbackList,
17237
17269
  clientFilesPruneCallbackList,
17238
17270
  explorer
17239
17271
  } = {}) => {
17240
- if (supervisor === true) {
17241
- supervisor = {};
17272
+ if (explorer === true) {
17273
+ explorer = {};
17242
17274
  }
17243
17275
 
17244
- if (nodeEsmResolution === true) {
17245
- nodeEsmResolution = {};
17276
+ if (supervisor === true) {
17277
+ supervisor = {};
17246
17278
  }
17247
17279
 
17248
- if (fileSystemMagicResolution === true) {
17249
- fileSystemMagicResolution = {};
17280
+ if (fileSystemMagicRedirection === true) {
17281
+ fileSystemMagicRedirection = {};
17250
17282
  }
17251
17283
 
17252
17284
  if (clientAutoreload === true) {
17253
17285
  clientAutoreload = {};
17254
17286
  }
17255
17287
 
17288
+ if (clientMainFileUrl === undefined) {
17289
+ clientMainFileUrl = explorer ? String(explorerHtmlFileUrl) : String(new URL("./index.html", rootDirectoryUrl));
17290
+ } else {
17291
+ clientMainFileUrl = String(clientMainFileUrl);
17292
+ }
17293
+
17256
17294
  return [jsenvPluginUrlAnalysis({
17257
17295
  rootDirectoryUrl,
17258
17296
  ...urlAnalysis
@@ -17262,14 +17300,19 @@ const getCorePlugins = ({
17262
17300
  jsenvPluginInline(), // before "file urls" to resolve and load inline urls
17263
17301
  jsenvPluginFileUrls({
17264
17302
  directoryReferenceAllowed,
17265
- ...fileSystemMagicResolution
17266
- }), jsenvPluginHttpUrls(), jsenvPluginLeadingSlash(), // before url resolution to handle "js_import_export" resolution
17267
- jsenvPluginNodeEsmResolution(nodeEsmResolution), jsenvPluginUrlResolution(), jsenvPluginUrlVersion(), jsenvPluginCommonJsGlobals(), jsenvPluginImportMetaScenarios(), jsenvPluginNodeRuntime({
17303
+ ...fileSystemMagicRedirection
17304
+ }), jsenvPluginHttpUrls(), jsenvPluginUrlResolution({
17305
+ runtimeCompat,
17306
+ urlResolution,
17307
+ clientMainFileUrl
17308
+ }), jsenvPluginUrlVersion(), jsenvPluginCommonJsGlobals(), jsenvPluginImportMetaScenarios(), jsenvPluginNodeRuntime({
17268
17309
  runtimeCompat
17269
17310
  }), jsenvPluginBundling(bundling), jsenvPluginMinification(minification), jsenvPluginImportMetaHot(), ...(clientAutoreload ? [jsenvPluginAutoreload({ ...clientAutoreload,
17270
17311
  clientFileChangeCallbackList,
17271
17312
  clientFilesPruneCallbackList
17272
- })] : []), jsenvPluginCacheControl(), ...(explorer ? [jsenvPluginExplorer(explorer)] : [])];
17313
+ })] : []), jsenvPluginCacheControl(), ...(explorer ? [jsenvPluginExplorer({ ...explorer,
17314
+ clientMainFileUrl
17315
+ })] : [])];
17273
17316
  };
17274
17317
 
17275
17318
  const HOOK_NAMES$1 = ["init", "serve", // is called only during dev/tests
@@ -18384,6 +18427,7 @@ const createKitchen = ({
18384
18427
  isResourceHint,
18385
18428
  isImplicit,
18386
18429
  hasVersioningEffect,
18430
+ version: null,
18387
18431
  injected,
18388
18432
  timing: {},
18389
18433
  // for inline resources the reference contains the content
@@ -19180,55 +19224,7 @@ const determineFileUrlForOutDirectory = ({
19180
19224
  to: context.outDirectoryUrl,
19181
19225
  preferAbsolute: true
19182
19226
  });
19183
- }; // import { getOriginalPosition } from "@jsenv/core/src/utils/sourcemap/original_position.js"
19184
- // const getUrlSite = async (
19185
- // urlInfo,
19186
- // { line, column, originalLine, originalColumn },
19187
- // ) => {
19188
- // if (typeof originalLine === "number") {
19189
- // return {
19190
- // url: urlInfo.url,
19191
- // line: originalLine,
19192
- // column: originalColumn,
19193
- // }
19194
- // }
19195
- // if (urlInfo.content === urlInfo.originalContent) {
19196
- // return {
19197
- // url: urlInfo.url,
19198
- // line,
19199
- // column,
19200
- // }
19201
- // }
19202
- // // at this point things were transformed: line and column are generated
19203
- // // no sourcemap -> cannot map back to original file
19204
- // const { sourcemap } = urlInfo
19205
- // if (!sourcemap) {
19206
- // return {
19207
- // url: urlInfo.generatedUrl,
19208
- // content: urlInfo.content,
19209
- // line,
19210
- // column,
19211
- // }
19212
- // }
19213
- // const originalPosition = await getOriginalPosition({
19214
- // sourcemap,
19215
- // line,
19216
- // column,
19217
- // })
19218
- // // cannot map back to original file
19219
- // if (!originalPosition || originalPosition.line === null) {
19220
- // return {
19221
- // url: urlInfo.generatedUrl,
19222
- // line,
19223
- // column,
19224
- // }
19225
- // }
19226
- // return {
19227
- // url: urlInfo.url,
19228
- // line: originalPosition.line,
19229
- // column: originalPosition.column,
19230
- // }
19231
- // }
19227
+ };
19232
19228
 
19233
19229
  const createUrlGraphSummary = (urlGraph, {
19234
19230
  title = "graph summary"
@@ -19828,8 +19824,8 @@ const build = async ({
19828
19824
  sourcemaps = false,
19829
19825
  sourcemapsSourcesContent,
19830
19826
  urlAnalysis = {},
19831
- nodeEsmResolution = true,
19832
- fileSystemMagicResolution,
19827
+ urlResolution,
19828
+ fileSystemMagicRedirection,
19833
19829
  directoryReferenceAllowed,
19834
19830
  transpilation = {},
19835
19831
  bundling = true,
@@ -19925,8 +19921,8 @@ build ${entryPointKeys.length} entry points`);
19925
19921
  urlGraph: rawGraph,
19926
19922
  runtimeCompat,
19927
19923
  urlAnalysis,
19928
- nodeEsmResolution,
19929
- fileSystemMagicResolution,
19924
+ urlResolution,
19925
+ fileSystemMagicRedirection,
19930
19926
  directoryReferenceAllowed,
19931
19927
  transpilation: { ...transpilation,
19932
19928
  babelHelpersAsImport: !useExplicitJsClassicConversion,
@@ -20032,11 +20028,7 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
20032
20028
  return true;
20033
20029
  }
20034
20030
 
20035
- if (rawUrlInfo.originalContent === reference.content) {
20036
- return true;
20037
- }
20038
-
20039
- return false;
20031
+ return rawUrlInfo.originalContent === reference.content;
20040
20032
  });
20041
20033
  const parentUrlInfo = finalGraph.getUrlInfo(reference.parentUrl);
20042
20034
 
@@ -20338,7 +20330,6 @@ ${ANSI.color(buildUrl, ANSI.MAGENTA)}
20338
20330
 
20339
20331
  if (bundler) {
20340
20332
  bundler.urlInfos.push(rawUrlInfo);
20341
- return;
20342
20333
  }
20343
20334
  };
20344
20335
 
@@ -21213,11 +21204,7 @@ const isUsed = urlInfo => {
21213
21204
  return true;
21214
21205
  }
21215
21206
 
21216
- if (urlInfo.dependents.size > 0) {
21217
- return true;
21218
- }
21219
-
21220
- return false;
21207
+ return urlInfo.dependents.size > 0;
21221
21208
  };
21222
21209
 
21223
21210
  const canUseVersionedUrl = urlInfo => {
@@ -21225,11 +21212,7 @@ const canUseVersionedUrl = urlInfo => {
21225
21212
  return false;
21226
21213
  }
21227
21214
 
21228
- if (urlInfo.type === "webmanifest") {
21229
- return false;
21230
- }
21231
-
21232
- return true;
21215
+ return urlInfo.type !== "webmanifest";
21233
21216
  };
21234
21217
 
21235
21218
  const createReloadableWorker = (workerFileUrl, options = {}) => {
@@ -22568,7 +22551,18 @@ const writeHead = (responseStream, {
22568
22551
  return;
22569
22552
  }
22570
22553
 
22571
- responseStream.writeHead(status, statusText, nodeHeaders);
22554
+ try {
22555
+ responseStream.writeHead(status, statusText, nodeHeaders);
22556
+ } catch (e) {
22557
+ if (e.code === "ERR_INVALID_CHAR" && e.message.includes("Invalid character in statusMessage")) {
22558
+ throw new Error(`Invalid character in statusMessage
22559
+ --- status message ---
22560
+ ${statusText}`);
22561
+ }
22562
+
22563
+ throw e;
22564
+ }
22565
+
22572
22566
  onHeadersSent({
22573
22567
  nodeHeaders,
22574
22568
  status,
@@ -23279,7 +23273,8 @@ const startServer = async ({
23279
23273
  preferIpv6
23280
23274
  });
23281
23275
  serverOrigins.externalip = createOrigin(firstExternalIp);
23282
- } else if (hostnameInfo.label === "loopback") {} else {
23276
+ } else if (hostnameInfo.label === "loopback") {// nothing
23277
+ } else {
23283
23278
  serverOrigins.local = createOrigin(hostname);
23284
23279
  }
23285
23280
  } else {
@@ -24020,6 +24015,10 @@ const startServer = async ({
24020
24015
  const removeUpgradeCallback = listenEvent(facadeServer, "upgrade", upgradeCallback);
24021
24016
  stopCallbackList.add(removeUpgradeCallback);
24022
24017
  stopCallbackList.add(() => {
24018
+ websocketClients.forEach(websocketClient => {
24019
+ websocketClient.close();
24020
+ });
24021
+ websocketClients.clear();
24023
24022
  websocketServer.close();
24024
24023
  websocketServer = null;
24025
24024
  });
@@ -25250,12 +25249,13 @@ const createFileService = ({
25250
25249
  runtimeCompat,
25251
25250
  plugins,
25252
25251
  urlAnalysis,
25252
+ urlResolution,
25253
+ fileSystemMagicRedirection,
25253
25254
  supervisor,
25254
- nodeEsmResolution,
25255
- fileSystemMagicResolution,
25256
25255
  transpilation,
25257
25256
  clientAutoreload,
25258
25257
  clientFiles,
25258
+ clientMainFileUrl,
25259
25259
  cooldownBetweenFileEvents,
25260
25260
  explorer,
25261
25261
  sourcemaps,
@@ -25360,10 +25360,11 @@ const createFileService = ({
25360
25360
  rootDirectoryUrl,
25361
25361
  runtimeCompat,
25362
25362
  urlAnalysis,
25363
+ urlResolution,
25364
+ fileSystemMagicRedirection,
25363
25365
  supervisor,
25364
- nodeEsmResolution,
25365
- fileSystemMagicResolution,
25366
25366
  transpilation,
25367
+ clientMainFileUrl,
25367
25368
  clientAutoreload,
25368
25369
  clientFileChangeCallbackList,
25369
25370
  clientFilesPruneCallbackList,
@@ -25373,7 +25374,7 @@ const createFileService = ({
25373
25374
  sourcemapsSourcesProtocol,
25374
25375
  sourcemapsSourcesContent,
25375
25376
  writeGeneratedFiles,
25376
- outDirectoryUrl: scenarios.dev ? `${rootDirectoryUrl}.jsenv/${runtimeName}@${runtimeVersion}/` : `${rootDirectoryUrl}.jsenv/${scenarios.test ? "test" : "build"}/${runtimeName}@${runtimeVersion}/`
25377
+ outDirectoryUrl: scenarios.dev ? `${rootDirectoryUrl}.jsenv/${runtimeName}@${runtimeVersion}/` : `${rootDirectoryUrl}.jsenv/build/${runtimeName}@${runtimeVersion}/`
25377
25378
  });
25378
25379
 
25379
25380
  urlGraph.createUrlInfoCallbackRef.current = urlInfo => {
@@ -25596,7 +25597,9 @@ const createFileService = ({
25596
25597
  url: reference.url,
25597
25598
  status: 200,
25598
25599
  // let the browser re-throw the syntax error
25599
- statusText: originalError.reason,
25600
+ // reason becomes the http response statusText, it must not contain invalid chars
25601
+ // https://github.com/nodejs/node/blob/0c27ca4bc9782d658afeaebcec85ec7b28f1cc35/lib/_http_common.js#L221
25602
+ statusText: e.reason,
25600
25603
  statusMessage: originalError.message,
25601
25604
  headers: {
25602
25605
  "content-type": urlInfo.contentType,
@@ -25693,12 +25696,13 @@ const startOmegaServer = async ({
25693
25696
  runtimeCompat,
25694
25697
  plugins,
25695
25698
  urlAnalysis,
25699
+ urlResolution,
25700
+ fileSystemMagicRedirection,
25696
25701
  supervisor,
25697
- nodeEsmResolution,
25698
- fileSystemMagicResolution,
25699
25702
  transpilation,
25700
25703
  clientAutoreload,
25701
25704
  clientFiles,
25705
+ clientMainFileUrl,
25702
25706
  cooldownBetweenFileEvents,
25703
25707
  explorer,
25704
25708
  sourcemaps,
@@ -25746,12 +25750,13 @@ const startOmegaServer = async ({
25746
25750
  runtimeCompat,
25747
25751
  plugins,
25748
25752
  urlAnalysis,
25753
+ urlResolution,
25754
+ fileSystemMagicRedirection,
25749
25755
  supervisor,
25750
- nodeEsmResolution,
25751
- fileSystemMagicResolution,
25752
25756
  transpilation,
25753
25757
  clientAutoreload,
25754
25758
  clientFiles,
25759
+ clientMainFileUrl,
25755
25760
  cooldownBetweenFileEvents,
25756
25761
  explorer,
25757
25762
  sourcemaps,
@@ -25846,6 +25851,7 @@ const startDevServer = async ({
25846
25851
  "./jsenv.config.mjs": true
25847
25852
  },
25848
25853
  clientAutoreload = true,
25854
+ clientMainFileUrl,
25849
25855
  devServerAutoreload = false,
25850
25856
  devServerMainFile = getCallerPosition().url,
25851
25857
  cooldownBetweenFileEvents,
@@ -25855,20 +25861,12 @@ const startDevServer = async ({
25855
25861
  runtimeCompat = defaultRuntimeCompat,
25856
25862
  plugins = [],
25857
25863
  urlAnalysis = {},
25864
+ urlResolution,
25858
25865
  supervisor = true,
25859
- nodeEsmResolution,
25860
- fileSystemMagicResolution,
25866
+ fileSystemMagicRedirection,
25861
25867
  transpilation,
25862
- explorer = {
25863
- groups: {
25864
- src: {
25865
- "./src/**/*.html": true
25866
- },
25867
- tests: {
25868
- "./tests/**/*.test.html": true
25869
- }
25870
- }
25871
- },
25868
+ explorer = true,
25869
+ // see jsenv_plugin_explorer.js
25872
25870
  // toolbar = false,
25873
25871
  sourcemaps = "inline",
25874
25872
  sourcemapsSourcesProtocol,
@@ -25948,10 +25946,7 @@ const startDevServer = async ({
25948
25946
  const messagePromise = new Promise(resolve => {
25949
25947
  worker.once("message", resolve);
25950
25948
  });
25951
- const origin = await messagePromise; // if (!keepProcessAlive) {
25952
- // worker.unref()
25953
- // }
25954
-
25949
+ const origin = await messagePromise;
25955
25950
  return {
25956
25951
  origin,
25957
25952
  stop: () => {
@@ -25983,11 +25978,12 @@ const startDevServer = async ({
25983
25978
  runtimeCompat,
25984
25979
  plugins,
25985
25980
  urlAnalysis,
25981
+ urlResolution,
25982
+ fileSystemMagicRedirection,
25986
25983
  supervisor,
25987
- nodeEsmResolution,
25988
- fileSystemMagicResolution,
25989
25984
  transpilation,
25990
25985
  clientFiles,
25986
+ clientMainFileUrl,
25991
25987
  clientAutoreload,
25992
25988
  cooldownBetweenFileEvents,
25993
25989
  explorer,
@@ -28293,7 +28289,6 @@ const createRuntimeFromPlaywright = ({
28293
28289
  });
28294
28290
  }
28295
28291
  });
28296
- return;
28297
28292
  };
28298
28293
 
28299
28294
  try {
@@ -28420,11 +28415,7 @@ const isTargetClosedError = error => {
28420
28415
  return true;
28421
28416
  }
28422
28417
 
28423
- if (error.message.includes("browserContext.close: Browser closed")) {
28424
- return true;
28425
- }
28426
-
28427
- return false;
28418
+ return error.message.includes("browserContext.close: Browser closed");
28428
28419
  };
28429
28420
 
28430
28421
  const extractTextFromConsoleMessage = consoleMessage => {