@jsenv/core 40.7.0 → 40.7.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.
@@ -4,7 +4,7 @@ import { jsenvPluginMinification } from "@jsenv/plugin-minification";
4
4
  import { jsenvPluginTranspilation, jsenvPluginJsModuleFallback } from "@jsenv/plugin-transpilation";
5
5
  import { memoryUsage } from "node:process";
6
6
  import { readFileSync, existsSync, readdirSync, lstatSync, realpathSync } from "node:fs";
7
- import { lookupPackageDirectory, registerDirectoryLifecycle, urlToRelativeUrl, createDetailedMessage, stringifyUrlSite, generateContentFrame, validateResponseIntegrity, urlIsInsideOf, ensureWindowsDriveLetter, setUrlFilename, moveUrl, getCallerPosition, urlToBasename, urlToExtension, asSpecifierWithoutSearch, asUrlWithoutSearch, injectQueryParamsIntoSpecifier, bufferToEtag, isFileSystemPath, urlToPathname, setUrlBasename, urlToFileSystemPath, writeFileSync, createLogger, URL_META, applyNodeEsmResolution, RUNTIME_COMPAT, normalizeUrl, ANSI, CONTENT_TYPE, urlToFilename, DATA_URL, errorToHTML, normalizeImportMap, composeTwoImportMaps, resolveImport, JS_QUOTES, defaultLookupPackageScope, defaultReadPackageJson, readCustomConditionsFromProcessArgs, readEntryStatSync, ensurePathnameTrailingSlash, compareFileUrls, applyFileSystemMagicResolution, getExtensionsToTry, setUrlExtension, isSpecifierForNodeBuiltin, renderDetails, humanizeDuration, humanizeFileSize, renderTable, renderBigSection, distributePercentages, humanizeMemory, comparePathnames, UNICODE, escapeRegexpSpecialChars, injectQueryParamIntoSpecifierWithoutEncoding, renderUrlOrRelativeUrlFilename, injectQueryParams, assertAndNormalizeDirectoryUrl, Abort, raceProcessTeardownEvents, startMonitoringCpuUsage, startMonitoringMemoryUsage, createLookupPackageDirectory, readPackageAtOrNull, inferRuntimeCompatFromClosestPackage, browserDefaultRuntimeCompat, nodeDefaultRuntimeCompat, clearDirectorySync, createTaskLog, ensureEmptyDirectory, updateJsonFileSync, createDynamicLog } from "./jsenv_core_packages.js";
7
+ import { lookupPackageDirectory, registerDirectoryLifecycle, urlToRelativeUrl, createDetailedMessage, stringifyUrlSite, generateContentFrame, validateResponseIntegrity, urlIsOrIsInsideOf, ensureWindowsDriveLetter, setUrlFilename, moveUrl, getCallerPosition, urlToBasename, urlToExtension, asSpecifierWithoutSearch, asUrlWithoutSearch, injectQueryParamsIntoSpecifier, bufferToEtag, isFileSystemPath, urlToPathname, setUrlBasename, urlToFileSystemPath, writeFileSync, createLogger, URL_META, applyNodeEsmResolution, RUNTIME_COMPAT, normalizeUrl, ANSI, CONTENT_TYPE, urlToFilename, DATA_URL, errorToHTML, normalizeImportMap, composeTwoImportMaps, resolveImport, JS_QUOTES, defaultLookupPackageScope, defaultReadPackageJson, readCustomConditionsFromProcessArgs, readEntryStatSync, ensurePathnameTrailingSlash, compareFileUrls, applyFileSystemMagicResolution, getExtensionsToTry, setUrlExtension, isSpecifierForNodeBuiltin, renderDetails, humanizeDuration, humanizeFileSize, renderTable, renderBigSection, distributePercentages, humanizeMemory, comparePathnames, UNICODE, escapeRegexpSpecialChars, injectQueryParamIntoSpecifierWithoutEncoding, renderUrlOrRelativeUrlFilename, injectQueryParams, assertAndNormalizeDirectoryUrl, Abort, raceProcessTeardownEvents, startMonitoringCpuUsage, startMonitoringMemoryUsage, createLookupPackageDirectory, readPackageAtOrNull, inferRuntimeCompatFromClosestPackage, browserDefaultRuntimeCompat, nodeDefaultRuntimeCompat, clearDirectorySync, createTaskLog, ensureEmptyDirectory, updateJsonFileSync, createDynamicLog } from "./jsenv_core_packages.js";
8
8
  import { pathToFileURL } from "node:url";
9
9
  import { generateSourcemapFileUrl, createMagicSource, composeTwoSourcemaps, generateSourcemapDataUrl, SOURCEMAP } from "@jsenv/sourcemap";
10
10
  import { performance } from "node:perf_hooks";
@@ -306,7 +306,7 @@ ${error.message}`,
306
306
  name: "TRANSFORM_URL_CONTENT_ERROR",
307
307
  code: "PARSE_ERROR",
308
308
  reason: error.message,
309
- stack: error.stack,
309
+ stack: transformError.stack,
310
310
  trace,
311
311
  asResponse: error.asResponse,
312
312
  });
@@ -531,7 +531,7 @@ const determineFileUrlForOutDirectory = (urlInfo) => {
531
531
  if (!url.startsWith("file:")) {
532
532
  return url;
533
533
  }
534
- if (!urlIsInsideOf(url, rootDirectoryUrl)) {
534
+ if (!urlIsOrIsInsideOf(url, rootDirectoryUrl)) {
535
535
  const fsRootUrl = ensureWindowsDriveLetter("file:///", url);
536
536
  url = `${rootDirectoryUrl}@fs/${url.slice(fsRootUrl.length)}`;
537
537
  }
@@ -4135,10 +4135,19 @@ const replacePlaceholders = (html, replacers) => {
4135
4135
  });
4136
4136
  };
4137
4137
 
4138
- const createPluginStore = (plugins) => {
4138
+ const createPluginStore = async (plugins) => {
4139
4139
  const allDevServerRoutes = [];
4140
+ const allDevServerServices = [];
4140
4141
  const pluginArray = [];
4141
- const addPlugin = (plugin) => {
4142
+
4143
+ const pluginPromises = [];
4144
+ const addPlugin = async (plugin) => {
4145
+ if (plugin && typeof plugin.then === "function") {
4146
+ pluginPromises.push(plugin);
4147
+ const value = await plugin;
4148
+ addPlugin(value);
4149
+ return;
4150
+ }
4142
4151
  if (Array.isArray(plugin)) {
4143
4152
  for (const subplugin of plugin) {
4144
4153
  addPlugin(subplugin);
@@ -4157,21 +4166,28 @@ const createPluginStore = (plugins) => {
4157
4166
  allDevServerRoutes.push(devServerRoute);
4158
4167
  }
4159
4168
  }
4169
+ if (plugin.devServerServices) {
4170
+ const devServerServices = plugin.devServerServices;
4171
+ for (const devServerService of devServerServices) {
4172
+ allDevServerServices.push(devServerService);
4173
+ }
4174
+ }
4160
4175
  pluginArray.push(plugin);
4161
4176
  };
4162
4177
  addPlugin(jsenvPluginHtmlSyntaxErrorFallback());
4163
4178
  for (const plugin of plugins) {
4164
4179
  addPlugin(plugin);
4165
4180
  }
4181
+ await Promise.all(pluginPromises);
4166
4182
 
4167
4183
  return {
4168
4184
  pluginArray,
4169
-
4170
4185
  allDevServerRoutes,
4186
+ allDevServerServices,
4171
4187
  };
4172
4188
  };
4173
4189
 
4174
- const createPluginController = (
4190
+ const createPluginController = async (
4175
4191
  pluginStore,
4176
4192
  kitchen,
4177
4193
  { initialPuginsMeta = {} } = {},
@@ -4194,7 +4210,7 @@ const createPluginController = (
4194
4210
  pluginCandidate.destroy?.();
4195
4211
  continue;
4196
4212
  }
4197
- const initPluginResult = initPlugin(pluginCandidate, kitchen);
4213
+ const initPluginResult = await initPlugin(pluginCandidate, kitchen);
4198
4214
  if (!initPluginResult) {
4199
4215
  pluginCandidate.destroy?.();
4200
4216
  continue;
@@ -4246,6 +4262,7 @@ const createPluginController = (
4246
4262
  key === "serverEvents" ||
4247
4263
  key === "mustStayFirst" ||
4248
4264
  key === "devServerRoutes" ||
4265
+ key === "devServerServices" ||
4249
4266
  key === "effect"
4250
4267
  ) {
4251
4268
  continue;
@@ -4419,6 +4436,7 @@ const createPluginController = (
4419
4436
  const HOOK_NAMES = [
4420
4437
  "init",
4421
4438
  "devServerRoutes", // is called only during dev/tests
4439
+ "devServerServices", // is called only during dev/tests
4422
4440
  "resolveReference",
4423
4441
  "redirectReference",
4424
4442
  "transformReferenceSearchParams",
@@ -4473,12 +4491,12 @@ const testAppliesDuring = (plugin, kitchen) => {
4473
4491
  `"appliesDuring" must be an object or a string, got ${appliesDuring}`,
4474
4492
  );
4475
4493
  };
4476
- const initPlugin = (plugin, kitchen) => {
4494
+ const initPlugin = async (plugin, kitchen) => {
4477
4495
  const { init } = plugin;
4478
4496
  if (!init) {
4479
4497
  return true;
4480
4498
  }
4481
- const initReturnValue = init(kitchen.context, { plugin });
4499
+ const initReturnValue = await init(kitchen.context, { plugin });
4482
4500
  if (initReturnValue === false) {
4483
4501
  return false;
4484
4502
  }
@@ -6338,10 +6356,7 @@ const jsenvPluginVersionSearchParam = () => {
6338
6356
 
6339
6357
  const FILE_AND_SERVER_URLS_CONVERTER = {
6340
6358
  asServerUrl: (fileUrl, serverRootDirectoryUrl) => {
6341
- if (fileUrl === serverRootDirectoryUrl) {
6342
- return "/";
6343
- }
6344
- if (urlIsInsideOf(fileUrl, serverRootDirectoryUrl)) {
6359
+ if (urlIsOrIsInsideOf(fileUrl, serverRootDirectoryUrl)) {
6345
6360
  const urlRelativeToServer = urlToRelativeUrl(
6346
6361
  fileUrl,
6347
6362
  serverRootDirectoryUrl,
@@ -6397,6 +6412,7 @@ const htmlFileUrlForDirectory = import.meta.resolve(
6397
6412
  );
6398
6413
 
6399
6414
  const jsenvPluginDirectoryListing = ({
6415
+ spa,
6400
6416
  urlMocks = false,
6401
6417
  autoreload = true,
6402
6418
  directoryContentMagicName,
@@ -6438,7 +6454,7 @@ const jsenvPluginDirectoryListing = ({
6438
6454
  return null;
6439
6455
  }
6440
6456
  }
6441
- return `${htmlFileUrlForDirectory}?url=${encodeURIComponent(url)}&enoent`;
6457
+ return `${htmlFileUrlForDirectory}?url=${encodeURIComponent(requestedUrl)}&enoent`;
6442
6458
  }
6443
6459
  const isDirectory = fsStat?.isDirectory();
6444
6460
  if (!isDirectory) {
@@ -6464,21 +6480,22 @@ const jsenvPluginDirectoryListing = ({
6464
6480
  if (urlWithoutSearch !== String(htmlFileUrlForDirectory)) {
6465
6481
  return null;
6466
6482
  }
6467
- const requestedUrl = urlInfo.searchParams.get("url");
6468
- if (!requestedUrl) {
6483
+ const urlNotFound = urlInfo.searchParams.get("url");
6484
+ if (!urlNotFound) {
6469
6485
  return null;
6470
6486
  }
6487
+
6471
6488
  urlInfo.headers["cache-control"] = "no-cache";
6472
6489
  const enoent = urlInfo.searchParams.has("enoent");
6473
6490
  if (enoent) {
6474
6491
  urlInfo.status = 404;
6475
- urlInfo.headers["cache-control"] = "no-cache";
6476
6492
  }
6477
6493
  const request = urlInfo.context.request;
6478
6494
  const { rootDirectoryUrl, mainFilePath } = urlInfo.context;
6479
6495
  const directoryListingInjections = generateDirectoryListingInjection(
6480
- requestedUrl,
6496
+ urlNotFound,
6481
6497
  {
6498
+ spa,
6482
6499
  autoreload,
6483
6500
  request,
6484
6501
  urlMocks,
@@ -6571,8 +6588,9 @@ const jsenvPluginDirectoryListing = ({
6571
6588
  };
6572
6589
 
6573
6590
  const generateDirectoryListingInjection = (
6574
- requestedUrl,
6591
+ urlNotFound,
6575
6592
  {
6593
+ spa,
6576
6594
  rootDirectoryUrl,
6577
6595
  mainFilePath,
6578
6596
  packageDirectory,
@@ -6585,7 +6603,7 @@ const generateDirectoryListingInjection = (
6585
6603
  ) => {
6586
6604
  let serverRootDirectoryUrl = rootDirectoryUrl;
6587
6605
  const firstExistingDirectoryUrl = getFirstExistingDirectoryUrl(
6588
- requestedUrl,
6606
+ urlNotFound,
6589
6607
  serverRootDirectoryUrl,
6590
6608
  );
6591
6609
  const directoryContentItems = getDirectoryContentItems({
@@ -6636,8 +6654,8 @@ const generateDirectoryListingInjection = (
6636
6654
  const { host } = new URL(request.url);
6637
6655
  const websocketUrl = `${websocketScheme}://${host}/.internal/directory_content.websocket?directory=${encodeURIComponent(directoryUrlRelativeToServer)}`;
6638
6656
 
6639
- const navItems = [];
6640
- {
6657
+ const generateBreadcrumb = () => {
6658
+ const breadcrumb = [];
6641
6659
  const lastItemUrl = firstExistingDirectoryUrl;
6642
6660
  const lastItemRelativeUrl = urlToRelativeUrl(lastItemUrl, rootDirectoryUrl);
6643
6661
  const rootDirectoryUrlName = urlToFilename(rootDirectoryUrl);
@@ -6647,7 +6665,6 @@ const generateDirectoryListingInjection = (
6647
6665
  } else {
6648
6666
  parts = [rootDirectoryUrlName];
6649
6667
  }
6650
-
6651
6668
  let i = 0;
6652
6669
  while (i < parts.length) {
6653
6670
  const part = parts[i];
@@ -6668,7 +6685,7 @@ const generateDirectoryListingInjection = (
6668
6685
  navItemUrl,
6669
6686
  serverRootDirectoryUrl,
6670
6687
  );
6671
- let urlRelativeToDocument = urlToRelativeUrl(navItemUrl, requestedUrl);
6688
+ let urlRelativeToDocument = urlToRelativeUrl(navItemUrl, urlNotFound);
6672
6689
  const isServerRootDirectory = navItemUrl === serverRootDirectoryUrl;
6673
6690
  if (isServerRootDirectory) {
6674
6691
  urlRelativeToServer = `/${directoryContentMagicName}`;
@@ -6676,7 +6693,7 @@ const generateDirectoryListingInjection = (
6676
6693
  }
6677
6694
  const name = part;
6678
6695
  const isCurrent = navItemUrl === String(firstExistingDirectoryUrl);
6679
- navItems.push({
6696
+ breadcrumb.push({
6680
6697
  url: navItemUrl,
6681
6698
  urlRelativeToServer,
6682
6699
  urlRelativeToDocument,
@@ -6686,34 +6703,47 @@ const generateDirectoryListingInjection = (
6686
6703
  });
6687
6704
  i++;
6688
6705
  }
6689
- }
6706
+ return breadcrumb;
6707
+ };
6708
+ const breadcrumb = generateBreadcrumb();
6690
6709
 
6691
6710
  let enoentDetails = null;
6692
6711
  if (enoent) {
6712
+ const buildEnoentPathInfo = (urlBase, closestExistingUrl) => {
6713
+ let filePathExisting;
6714
+ let filePathNotFound;
6715
+ const existingIndex = String(closestExistingUrl).length;
6716
+ filePathExisting = urlToRelativeUrl(
6717
+ closestExistingUrl,
6718
+ serverRootDirectoryUrl,
6719
+ );
6720
+ filePathNotFound = urlBase.slice(existingIndex);
6721
+ return [filePathExisting, filePathNotFound];
6722
+ };
6693
6723
  const fileRelativeUrl = urlToRelativeUrl(
6694
- requestedUrl,
6724
+ urlNotFound,
6695
6725
  serverRootDirectoryUrl,
6696
6726
  );
6697
- let filePathExisting;
6698
- let filePathNotFound;
6699
- const existingIndex = String(firstExistingDirectoryUrl).length;
6700
- filePathExisting = urlToRelativeUrl(
6701
- firstExistingDirectoryUrl,
6702
- serverRootDirectoryUrl,
6703
- );
6704
- filePathNotFound = requestedUrl.slice(existingIndex);
6705
6727
  enoentDetails = {
6706
- fileUrl: requestedUrl,
6728
+ fileUrl: urlNotFound,
6707
6729
  fileRelativeUrl,
6730
+ };
6731
+
6732
+ const [filePathExisting, filePathNotFound] = buildEnoentPathInfo(
6733
+ urlNotFound,
6734
+ firstExistingDirectoryUrl,
6735
+ );
6736
+ Object.assign(enoentDetails, {
6708
6737
  filePathExisting: `/${filePathExisting}`,
6709
6738
  filePathNotFound,
6710
- };
6739
+ });
6711
6740
  }
6712
6741
 
6713
6742
  return {
6714
6743
  __DIRECTORY_LISTING__: {
6744
+ spa,
6715
6745
  enoentDetails,
6716
- navItems,
6746
+ breadcrumb,
6717
6747
  urlMocks,
6718
6748
  directoryContentMagicName,
6719
6749
  directoryUrl: firstExistingDirectoryUrl,
@@ -6726,11 +6756,11 @@ const generateDirectoryListingInjection = (
6726
6756
  },
6727
6757
  };
6728
6758
  };
6729
- const getFirstExistingDirectoryUrl = (requestedUrl, serverRootDirectoryUrl) => {
6730
- let directoryUrlCandidate = new URL("./", requestedUrl);
6759
+ const getFirstExistingDirectoryUrl = (urlBase, serverRootDirectoryUrl) => {
6760
+ let directoryUrlCandidate = new URL("./", urlBase);
6731
6761
  while (!existsSync(directoryUrlCandidate)) {
6732
6762
  directoryUrlCandidate = new URL("../", directoryUrlCandidate);
6733
- if (!urlIsInsideOf(directoryUrlCandidate, serverRootDirectoryUrl)) {
6763
+ if (!urlIsOrIsInsideOf(directoryUrlCandidate, serverRootDirectoryUrl)) {
6734
6764
  directoryUrlCandidate = new URL(serverRootDirectoryUrl);
6735
6765
  break;
6736
6766
  }
@@ -6779,7 +6809,7 @@ const getDirectoryContentItems = ({
6779
6809
  };
6780
6810
 
6781
6811
  const jsenvPluginFsRedirection = ({
6782
- spa = true,
6812
+ spa,
6783
6813
  directoryContentMagicName,
6784
6814
  magicExtensions = ["inherit", ".js"],
6785
6815
  magicDirectoryIndex = true,
@@ -6938,17 +6968,12 @@ const getClosestHtmlRootFile = (requestedUrl, serverRootDirectoryUrl) => {
6938
6968
  if (existsSync(indexHtmlFileUrl)) {
6939
6969
  return indexHtmlFileUrl.href;
6940
6970
  }
6941
- const htmlFileUrlCandidate = new URL(
6942
- `${urlToFilename(directoryUrl)}.html`,
6943
- directoryUrl,
6944
- );
6971
+ const filename = urlToFilename(directoryUrl);
6972
+ const htmlFileUrlCandidate = new URL(`${filename}.html`, directoryUrl);
6945
6973
  if (existsSync(htmlFileUrlCandidate)) {
6946
6974
  return htmlFileUrlCandidate.href;
6947
6975
  }
6948
- if (
6949
- !urlIsInsideOf(directoryUrl, serverRootDirectoryUrl) ||
6950
- directoryUrl.href === serverRootDirectoryUrl
6951
- ) {
6976
+ if (!urlIsOrIsInsideOf(directoryUrl, serverRootDirectoryUrl)) {
6952
6977
  return null;
6953
6978
  }
6954
6979
  directoryUrl = new URL("../", directoryUrl);
@@ -6958,7 +6983,7 @@ const getClosestHtmlRootFile = (requestedUrl, serverRootDirectoryUrl) => {
6958
6983
  const directoryContentMagicName = "...";
6959
6984
 
6960
6985
  const jsenvPluginProtocolFile = ({
6961
- spa,
6986
+ spa = true,
6962
6987
  magicExtensions,
6963
6988
  magicDirectoryIndex,
6964
6989
  preserveSymlinks,
@@ -7026,6 +7051,7 @@ const jsenvPluginProtocolFile = ({
7026
7051
  ...(directoryListing
7027
7052
  ? [
7028
7053
  jsenvPluginDirectoryListing({
7054
+ spa,
7029
7055
  ...directoryListing,
7030
7056
  directoryContentMagicName,
7031
7057
  rootDirectoryUrl,
@@ -8020,7 +8046,7 @@ const jsenvPluginAutoreloadServer = ({
8020
8046
  serverEvents: {
8021
8047
  reload: (serverEventInfo) => {
8022
8048
  const formatUrlForClient = (url) => {
8023
- if (urlIsInsideOf(url, serverEventInfo.rootDirectoryUrl)) {
8049
+ if (urlIsOrIsInsideOf(url, serverEventInfo.rootDirectoryUrl)) {
8024
8050
  return urlToRelativeUrl(url, serverEventInfo.rootDirectoryUrl);
8025
8051
  }
8026
8052
  if (url.startsWith("file:")) {
@@ -8595,6 +8621,7 @@ const jsenvPluginChromeDevtoolsJson = () => {
8595
8621
  devServerRoutes: [
8596
8622
  {
8597
8623
  endpoint: "GET /.well-known/appspecific/com.chrome.devtools.json",
8624
+ declarationSource: import.meta.url,
8598
8625
  fetch: (request, { kitchen }) => {
8599
8626
  const { rootDirectoryUrl } = kitchen.context;
8600
8627
  return Response.json({
@@ -9983,7 +10010,7 @@ const createBuildSpecifierManager = ({
9983
10010
  // const urlInfoInsideThisDirectorySet = new Set();
9984
10011
  const versionsInfluencingThisDirectorySet = new Set();
9985
10012
  for (const [url, urlInfo] of finalKitchen.graph.urlInfoMap) {
9986
- if (!urlIsInsideOf(url, directoryUrl)) {
10013
+ if (!urlIsOrIsInsideOf(url, directoryUrl)) {
9987
10014
  continue;
9988
10015
  }
9989
10016
  // ideally we should exclude eventual directories as the are redundant
@@ -10382,7 +10409,7 @@ const createBuildSpecifierManager = ({
10382
10409
  }
10383
10410
  if (
10384
10411
  urlInfo.type === "asset" &&
10385
- urlIsInsideOf(urlInfo.url, buildDirectoryUrl)
10412
+ urlIsOrIsInsideOf(urlInfo.url, buildDirectoryUrl)
10386
10413
  ) {
10387
10414
  return;
10388
10415
  }
@@ -10697,7 +10724,7 @@ const createBuildUrlsGenerator = ({
10697
10724
  if (buildUrlFromMap) {
10698
10725
  return buildUrlFromMap;
10699
10726
  }
10700
- if (urlIsInsideOf(url, buildDirectoryUrl)) {
10727
+ if (urlIsOrIsInsideOf(url, buildDirectoryUrl)) {
10701
10728
  if (ownerUrlInfo.searchParams.has("dynamic_import_id")) {
10702
10729
  const ownerDirectoryPath = determineDirectoryPath({
10703
10730
  sourceDirectoryUrl,
@@ -11112,7 +11139,7 @@ const build = async ({
11112
11139
  );
11113
11140
  }
11114
11141
  }
11115
- if (!urlIsInsideOf(sourceUrl, sourceDirectoryUrl)) {
11142
+ if (!urlIsOrIsInsideOf(sourceUrl, sourceDirectoryUrl)) {
11116
11143
  throw new Error(
11117
11144
  `The key "${key}" in "entryPoints" is invalid: it must be inside the source directory at ${sourceDirectoryUrl}.`,
11118
11145
  );
@@ -11163,7 +11190,7 @@ const build = async ({
11163
11190
  `The buildRelativeUrl "${buildRelativeUrl}"${forEntryPointOrEmpty} is invalid: it must be a relative url.`,
11164
11191
  );
11165
11192
  }
11166
- if (!urlIsInsideOf(buildUrl, buildDirectoryUrl)) {
11193
+ if (!urlIsOrIsInsideOf(buildUrl, buildDirectoryUrl)) {
11167
11194
  throw new Error(
11168
11195
  `The buildRelativeUrl "${buildRelativeUrl}"${forEntryPointOrEmpty} is invalid: it must be inside the build directory at ${buildDirectoryUrl}.`,
11169
11196
  );
@@ -11663,7 +11690,7 @@ const build = async ({
11663
11690
  let hasSomeOutdatedSideEffectUrl = false;
11664
11691
  for (const packageSideEffectUrl of packageSideEffectUrlSet) {
11665
11692
  if (
11666
- urlIsInsideOf(packageSideEffectUrl, buildDirectoryUrl) &&
11693
+ urlIsOrIsInsideOf(packageSideEffectUrl, buildDirectoryUrl) &&
11667
11694
  !buildSideEffectUrlSet.has(packageSideEffectUrl)
11668
11695
  ) {
11669
11696
  hasSomeOutdatedSideEffectUrl = true;
@@ -11963,7 +11990,7 @@ const prepareEntryPointBuild = async (
11963
11990
  });
11964
11991
 
11965
11992
  let _getOtherEntryBuildInfo;
11966
- const rawPluginStore = createPluginStore([
11993
+ const rawPluginStore = await createPluginStore([
11967
11994
  ...(mappings ? [jsenvPluginMappings(mappings)] : []),
11968
11995
  {
11969
11996
  name: "jsenv:other_entry_point_build_during_craft",
@@ -12008,7 +12035,7 @@ const prepareEntryPointBuild = async (
12008
12035
  packageSideEffects,
12009
12036
  }),
12010
12037
  ]);
12011
- const rawPluginController = createPluginController(
12038
+ const rawPluginController = await createPluginController(
12012
12039
  rawPluginStore,
12013
12040
  rawKitchen,
12014
12041
  );
@@ -12079,7 +12106,7 @@ const prepareEntryPointBuild = async (
12079
12106
  rawKitchen.graph.getUrlInfo(entryReference.url).type === "html" &&
12080
12107
  rawKitchen.context.isSupportedOnCurrentClients("importmap"),
12081
12108
  });
12082
- const finalPluginStore = createPluginStore([
12109
+ const finalPluginStore = await createPluginStore([
12083
12110
  jsenvPluginReferenceAnalysis({
12084
12111
  ...referenceAnalysis,
12085
12112
  fetchInlineUrls: false,
@@ -12112,7 +12139,7 @@ const prepareEntryPointBuild = async (
12112
12139
  },
12113
12140
  buildSpecifierManager.jsenvPluginMoveToBuildDirectory,
12114
12141
  ]);
12115
- const finalPluginController = createPluginController(
12142
+ const finalPluginController = await createPluginController(
12116
12143
  finalPluginStore,
12117
12144
  finalKitchen,
12118
12145
  {
@@ -2304,7 +2304,7 @@ const resolveUrl$1 = (specifier, baseUrl) => {
2304
2304
  return String(new URL(specifier, baseUrl));
2305
2305
  };
2306
2306
 
2307
- const urlIsInsideOf = (url, otherUrl) => {
2307
+ const urlIsOrIsInsideOf = (url, otherUrl) => {
2308
2308
  const urlObject = new URL(url);
2309
2309
  const otherUrlObject = new URL(otherUrl);
2310
2310
 
@@ -2315,7 +2315,7 @@ const urlIsInsideOf = (url, otherUrl) => {
2315
2315
  const urlPathname = urlObject.pathname;
2316
2316
  const otherUrlPathname = otherUrlObject.pathname;
2317
2317
  if (urlPathname === otherUrlPathname) {
2318
- return false;
2318
+ return true;
2319
2319
  }
2320
2320
 
2321
2321
  const isInside = urlPathname.startsWith(otherUrlPathname);
@@ -10933,4 +10933,4 @@ const escapeRegexpSpecialChars = (string) => {
10933
10933
  });
10934
10934
  };
10935
10935
 
10936
- export { ANSI, Abort, CONTENT_TYPE, DATA_URL, JS_QUOTES, RUNTIME_COMPAT, UNICODE, URL_META, applyFileSystemMagicResolution, applyNodeEsmResolution, asSpecifierWithoutSearch, asUrlWithoutSearch, assertAndNormalizeDirectoryUrl, browserDefaultRuntimeCompat, bufferToEtag, clearDirectorySync, compareFileUrls, comparePathnames, composeTwoImportMaps, createDetailedMessage$1 as createDetailedMessage, createDynamicLog, createLogger, createLookupPackageDirectory, createTaskLog, defaultLookupPackageScope, defaultReadPackageJson, distributePercentages, ensureEmptyDirectory, ensurePathnameTrailingSlash, ensureWindowsDriveLetter, errorToHTML, escapeRegexpSpecialChars, generateContentFrame, getCallerPosition, getExtensionsToTry, humanizeDuration, humanizeFileSize, humanizeMemory, inferRuntimeCompatFromClosestPackage, injectQueryParamIntoSpecifierWithoutEncoding, injectQueryParams, injectQueryParamsIntoSpecifier, isFileSystemPath, isSpecifierForNodeBuiltin, lookupPackageDirectory, moveUrl, nodeDefaultRuntimeCompat, normalizeImportMap, normalizeUrl, raceProcessTeardownEvents, readCustomConditionsFromProcessArgs, readEntryStatSync, readPackageAtOrNull, registerDirectoryLifecycle, renderBigSection, renderDetails, renderTable, renderUrlOrRelativeUrlFilename, resolveImport, setUrlBasename, setUrlExtension, setUrlFilename, startMonitoringCpuUsage, startMonitoringMemoryUsage, stringifyUrlSite, updateJsonFileSync, urlIsInsideOf, urlToBasename, urlToExtension$1 as urlToExtension, urlToFileSystemPath, urlToFilename$1 as urlToFilename, urlToPathname$1 as urlToPathname, urlToRelativeUrl, validateResponseIntegrity, writeFileSync };
10936
+ export { ANSI, Abort, CONTENT_TYPE, DATA_URL, JS_QUOTES, RUNTIME_COMPAT, UNICODE, URL_META, applyFileSystemMagicResolution, applyNodeEsmResolution, asSpecifierWithoutSearch, asUrlWithoutSearch, assertAndNormalizeDirectoryUrl, browserDefaultRuntimeCompat, bufferToEtag, clearDirectorySync, compareFileUrls, comparePathnames, composeTwoImportMaps, createDetailedMessage$1 as createDetailedMessage, createDynamicLog, createLogger, createLookupPackageDirectory, createTaskLog, defaultLookupPackageScope, defaultReadPackageJson, distributePercentages, ensureEmptyDirectory, ensurePathnameTrailingSlash, ensureWindowsDriveLetter, errorToHTML, escapeRegexpSpecialChars, generateContentFrame, getCallerPosition, getExtensionsToTry, humanizeDuration, humanizeFileSize, humanizeMemory, inferRuntimeCompatFromClosestPackage, injectQueryParamIntoSpecifierWithoutEncoding, injectQueryParams, injectQueryParamsIntoSpecifier, isFileSystemPath, isSpecifierForNodeBuiltin, lookupPackageDirectory, moveUrl, nodeDefaultRuntimeCompat, normalizeImportMap, normalizeUrl, raceProcessTeardownEvents, readCustomConditionsFromProcessArgs, readEntryStatSync, readPackageAtOrNull, registerDirectoryLifecycle, renderBigSection, renderDetails, renderTable, renderUrlOrRelativeUrlFilename, resolveImport, setUrlBasename, setUrlExtension, setUrlFilename, startMonitoringCpuUsage, startMonitoringMemoryUsage, stringifyUrlSite, updateJsonFileSync, urlIsOrIsInsideOf, urlToBasename, urlToExtension$1 as urlToExtension, urlToFileSystemPath, urlToFilename$1 as urlToFilename, urlToPathname$1 as urlToPathname, urlToRelativeUrl, validateResponseIntegrity, writeFileSync };
@@ -4,7 +4,7 @@ const directoryIconUrl = new URL("../other/dir.png", import.meta.url).href;
4
4
  const fileIconUrl = new URL("../other/file.png", import.meta.url).href;
5
5
  const homeIconUrl = new URL("../other/home.svg#root", import.meta.url).href;
6
6
  let {
7
- navItems,
7
+ breadcrumb,
8
8
  mainFilePath,
9
9
  directoryContentItems,
10
10
  enoentDetails,
@@ -36,45 +36,60 @@ const DirectoryListing = () => {
36
36
  return directoryContentItems;
37
37
  });
38
38
  return u(k, {
39
- children: [enoentDetails ? u(ErrorMessage, {}) : null, u(Nav, {}), u(DirectoryContent, {
39
+ children: [enoentDetails ? u(ErrorMessage, {}) : null, u(Breadcrumb, {
40
+ items: breadcrumb
41
+ }), u(DirectoryContent, {
40
42
  items: directoryItems
41
43
  })]
42
44
  });
43
45
  };
44
46
  const ErrorMessage = () => {
45
47
  const {
46
- fileUrl,
47
48
  filePathExisting,
48
49
  filePathNotFound
49
50
  } = enoentDetails;
50
- return u("p", {
51
- className: "error_message",
51
+ let errorText;
52
+ let errorSuggestion;
53
+ errorText = u(k, {
54
+ children: [u("strong", {
55
+ children: "File not found:"
56
+ }), "\xA0", u("code", {
57
+ children: [u("span", {
58
+ className: "file_path_good",
59
+ children: filePathExisting
60
+ }), u("span", {
61
+ className: "file_path_bad",
62
+ children: filePathNotFound
63
+ })]
64
+ }), " ", "does not exist on the server."]
65
+ });
66
+ errorSuggestion = u(k, {
52
67
  children: [u("span", {
68
+ className: "icon",
69
+ children: "\uD83D\uDD0D"
70
+ }), " Check available routes in", " ", u("a", {
71
+ href: "/.internal/route_inspector",
72
+ children: "route inspector"
73
+ })]
74
+ });
75
+ return u("div", {
76
+ className: "error_message",
77
+ children: [u("p", {
53
78
  className: "error_text",
54
- children: ["No filesystem entry at", " ", u("code", {
55
- title: fileUrl,
56
- children: [u("span", {
57
- className: "file_path_good",
58
- children: filePathExisting
59
- }), u("span", {
60
- className: "file_path_bad",
61
- children: filePathNotFound
62
- })]
63
- }), "."]
64
- }), u("br", {}), u("span", {
65
- className: "error_text",
66
- style: "font-size: 70%;",
67
- children: ["See also available routes in the", " ", u("a", {
68
- href: "/.internal/route_inspector",
69
- children: "route inspector"
70
- }), "."]
79
+ children: errorText
80
+ }), u("p", {
81
+ className: "error_suggestion",
82
+ style: "font-size: 0.8em; margin-top: 10px;",
83
+ children: errorSuggestion
71
84
  })]
72
85
  });
73
86
  };
74
- const Nav = () => {
87
+ const Breadcrumb = ({
88
+ items
89
+ }) => {
75
90
  return u("h1", {
76
91
  className: "nav",
77
- children: navItems.map(navItem => {
92
+ children: items.map(navItem => {
78
93
  const {
79
94
  url,
80
95
  urlRelativeToServer,
@@ -84,7 +99,7 @@ const Nav = () => {
84
99
  } = navItem;
85
100
  const isDirectory = new URL(url).pathname.endsWith("/");
86
101
  return u(k, {
87
- children: [u(NavItem, {
102
+ children: [u(BreadcrumbItem, {
88
103
  url: urlRelativeToServer,
89
104
  isCurrent: isCurrent,
90
105
  iconImageUrl: isServerRootDirectory ? homeIconUrl : "",
@@ -98,7 +113,7 @@ const Nav = () => {
98
113
  })
99
114
  });
100
115
  };
101
- const NavItem = ({
116
+ const BreadcrumbItem = ({
102
117
  url,
103
118
  iconImageUrl,
104
119
  iconLinkUrl,
@@ -1,43 +1,46 @@
1
1
  const injectRibbon = ({ text }) => {
2
2
  const css = /* css */ `
3
- #jsenv_ribbon_container {
4
- position: fixed;
5
- z-index: 1001;
6
- top: 0;
7
- right: 0;
8
- width: 100px;
9
- height: 100px;
10
- overflow: hidden;
11
- opacity: 0.5;
12
- pointer-events: none;
13
- }
14
- #jsenv_ribbon {
15
- position: absolute;
16
- top: -10px;
17
- right: -10px;
18
- width: 100%;
19
- height: 100%;
20
- }
21
- #jsenv_ribbon_text {
22
- position: absolute;
23
- left: 0px;
24
- top: 20px;
25
- transform: rotate(45deg);
26
- display: block;
27
- width: 125px;
28
- line-height: 36px;
29
- background-color: orange;
30
- color: rgb(55, 7, 7);
31
- box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);
32
- font-weight: 700;
33
- font-size: 16px;
34
- font-family: "Lato", sans-serif;
35
- text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
36
- text-align: center;
37
- user-select: none;
38
- }`;
3
+ #jsenv_ribbon_container {
4
+ position: fixed;
5
+ z-index: 1001;
6
+ top: 0;
7
+ right: 0;
8
+ width: 100px;
9
+ height: 100px;
10
+ overflow: hidden;
11
+ opacity: 0.5;
12
+ pointer-events: none;
13
+ }
14
+ #jsenv_ribbon {
15
+ position: absolute;
16
+ top: -10px;
17
+ right: -10px;
18
+ width: 100%;
19
+ height: 100%;
20
+ }
21
+ #jsenv_ribbon_text {
22
+ position: absolute;
23
+ left: 0px;
24
+ top: 20px;
25
+ transform: rotate(45deg);
26
+ display: block;
27
+ width: 125px;
28
+ line-height: 36px;
29
+ background-color: orange;
30
+ color: rgb(55, 7, 7);
31
+ box-shadow: 0 5px 10px rgba(0, 0, 0, 0.1);
32
+ font-weight: 700;
33
+ font-size: 16px;
34
+ font-family: "Lato", sans-serif;
35
+ text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
36
+ text-align: center;
37
+ user-select: none;
38
+ }
39
+ `;
39
40
  const html = /* html */ `<div id="jsenv_ribbon_container">
40
- <style>${css}</style>
41
+ <style>
42
+ ${css}
43
+ </style>
41
44
  <div id="jsenv_ribbon">
42
45
  <div id="jsenv_ribbon_text">${text}</div>
43
46
  </div>