@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.
@@ -1609,7 +1609,7 @@ const resolveUrl$1 = (specifier, baseUrl) => {
1609
1609
  return String(new URL(specifier, baseUrl));
1610
1610
  };
1611
1611
 
1612
- const urlIsInsideOf = (url, otherUrl) => {
1612
+ const urlIsOrIsInsideOf = (url, otherUrl) => {
1613
1613
  const urlObject = new URL(url);
1614
1614
  const otherUrlObject = new URL(otherUrl);
1615
1615
 
@@ -1620,7 +1620,7 @@ const urlIsInsideOf = (url, otherUrl) => {
1620
1620
  const urlPathname = urlObject.pathname;
1621
1621
  const otherUrlPathname = otherUrlObject.pathname;
1622
1622
  if (urlPathname === otherUrlPathname) {
1623
- return false;
1623
+ return true;
1624
1624
  }
1625
1625
 
1626
1626
  const isInside = urlPathname.startsWith(otherUrlPathname);
@@ -6255,4 +6255,4 @@ const memoizeByFirstArgument = (compute) => {
6255
6255
  return fnWithMemoization;
6256
6256
  };
6257
6257
 
6258
- export { ANSI, CONTENT_TYPE, DATA_URL, JS_QUOTES, RUNTIME_COMPAT, URL_META, applyFileSystemMagicResolution, applyNodeEsmResolution, asSpecifierWithoutSearch, asUrlWithoutSearch, assertAndNormalizeDirectoryUrl, bufferToEtag, compareFileUrls, composeTwoImportMaps, createDetailedMessage$1 as createDetailedMessage, createLogger, createTaskLog, defaultLookupPackageScope, defaultReadPackageJson, ensurePathnameTrailingSlash, ensureWindowsDriveLetter, errorToHTML, formatError, generateContentFrame, getCallerPosition, getExtensionsToTry, injectQueryParamsIntoSpecifier, isFileSystemPath, isSpecifierForNodeBuiltin, lookupPackageDirectory, memoizeByFirstArgument, moveUrl, normalizeImportMap, normalizeUrl, readCustomConditionsFromProcessArgs, readEntryStatSync, readPackageAtOrNull, registerDirectoryLifecycle, resolveImport, setUrlBasename, setUrlExtension, setUrlFilename, stringifyUrlSite, urlIsInsideOf, urlToBasename, urlToExtension$1 as urlToExtension, urlToFileSystemPath, urlToFilename$1 as urlToFilename, urlToPathname$1 as urlToPathname, urlToRelativeUrl, validateResponseIntegrity, writeFileSync };
6258
+ export { ANSI, CONTENT_TYPE, DATA_URL, JS_QUOTES, RUNTIME_COMPAT, URL_META, applyFileSystemMagicResolution, applyNodeEsmResolution, asSpecifierWithoutSearch, asUrlWithoutSearch, assertAndNormalizeDirectoryUrl, bufferToEtag, compareFileUrls, composeTwoImportMaps, createDetailedMessage$1 as createDetailedMessage, createLogger, createTaskLog, defaultLookupPackageScope, defaultReadPackageJson, ensurePathnameTrailingSlash, ensureWindowsDriveLetter, errorToHTML, formatError, generateContentFrame, getCallerPosition, getExtensionsToTry, injectQueryParamsIntoSpecifier, isFileSystemPath, isSpecifierForNodeBuiltin, lookupPackageDirectory, memoizeByFirstArgument, moveUrl, normalizeImportMap, normalizeUrl, readCustomConditionsFromProcessArgs, readEntryStatSync, readPackageAtOrNull, registerDirectoryLifecycle, resolveImport, setUrlBasename, setUrlExtension, setUrlFilename, stringifyUrlSite, urlIsOrIsInsideOf, urlToBasename, urlToExtension$1 as urlToExtension, urlToFileSystemPath, urlToFilename$1 as urlToFilename, urlToPathname$1 as urlToPathname, urlToRelativeUrl, validateResponseIntegrity, writeFileSync };
@@ -1,6 +1,6 @@
1
1
  import { WebSocketResponse, pickContentType, ServerEvents, jsenvServiceCORS, jsenvAccessControlAllowedHeaders, composeTwoResponses, serveDirectory, jsenvServiceErrorHandler, startServer } from "@jsenv/server";
2
2
  import { convertFileSystemErrorToResponseProperties } from "@jsenv/server/src/internal/convertFileSystemErrorToResponseProperties.js";
3
- import { lookupPackageDirectory, registerDirectoryLifecycle, urlToRelativeUrl, moveUrl, urlIsInsideOf, ensureWindowsDriveLetter, createDetailedMessage, stringifyUrlSite, generateContentFrame, validateResponseIntegrity, setUrlFilename, getCallerPosition, urlToBasename, urlToExtension, asSpecifierWithoutSearch, asUrlWithoutSearch, injectQueryParamsIntoSpecifier, bufferToEtag, isFileSystemPath, urlToPathname, setUrlBasename, urlToFileSystemPath, writeFileSync, createLogger, URL_META, applyNodeEsmResolution, RUNTIME_COMPAT, normalizeUrl, ANSI, CONTENT_TYPE, errorToHTML, DATA_URL, normalizeImportMap, composeTwoImportMaps, resolveImport, JS_QUOTES, defaultLookupPackageScope, defaultReadPackageJson, readCustomConditionsFromProcessArgs, readEntryStatSync, urlToFilename, ensurePathnameTrailingSlash, compareFileUrls, applyFileSystemMagicResolution, getExtensionsToTry, setUrlExtension, isSpecifierForNodeBuiltin, memoizeByFirstArgument, assertAndNormalizeDirectoryUrl, createTaskLog, formatError, readPackageAtOrNull } from "./jsenv_core_packages.js";
3
+ import { lookupPackageDirectory, registerDirectoryLifecycle, urlToRelativeUrl, moveUrl, urlIsOrIsInsideOf, ensureWindowsDriveLetter, createDetailedMessage, stringifyUrlSite, generateContentFrame, validateResponseIntegrity, setUrlFilename, getCallerPosition, urlToBasename, urlToExtension, asSpecifierWithoutSearch, asUrlWithoutSearch, injectQueryParamsIntoSpecifier, bufferToEtag, isFileSystemPath, urlToPathname, setUrlBasename, urlToFileSystemPath, writeFileSync, createLogger, URL_META, applyNodeEsmResolution, RUNTIME_COMPAT, normalizeUrl, ANSI, CONTENT_TYPE, errorToHTML, DATA_URL, normalizeImportMap, composeTwoImportMaps, resolveImport, JS_QUOTES, defaultLookupPackageScope, defaultReadPackageJson, readCustomConditionsFromProcessArgs, readEntryStatSync, ensurePathnameTrailingSlash, compareFileUrls, urlToFilename, applyFileSystemMagicResolution, getExtensionsToTry, setUrlExtension, isSpecifierForNodeBuiltin, memoizeByFirstArgument, assertAndNormalizeDirectoryUrl, createTaskLog, formatError, readPackageAtOrNull } from "./jsenv_core_packages.js";
4
4
  import { readFileSync, existsSync, readdirSync, lstatSync, realpathSync } from "node:fs";
5
5
  import { pathToFileURL } from "node:url";
6
6
  import { generateSourcemapFileUrl, createMagicSource, composeTwoSourcemaps, generateSourcemapDataUrl, SOURCEMAP } from "@jsenv/sourcemap";
@@ -165,7 +165,7 @@ const watchSourceFiles = (
165
165
 
166
166
  const WEB_URL_CONVERTER = {
167
167
  asWebUrl: (fileUrl, webServer) => {
168
- if (urlIsInsideOf(fileUrl, webServer.rootDirectoryUrl)) {
168
+ if (urlIsOrIsInsideOf(fileUrl, webServer.rootDirectoryUrl)) {
169
169
  return moveUrl({
170
170
  url: fileUrl,
171
171
  from: webServer.rootDirectoryUrl,
@@ -365,7 +365,7 @@ ${error.message}`,
365
365
  name: "TRANSFORM_URL_CONTENT_ERROR",
366
366
  code: "PARSE_ERROR",
367
367
  reason: error.message,
368
- stack: error.stack,
368
+ stack: transformError.stack,
369
369
  trace,
370
370
  asResponse: error.asResponse,
371
371
  });
@@ -590,7 +590,7 @@ const determineFileUrlForOutDirectory = (urlInfo) => {
590
590
  if (!url.startsWith("file:")) {
591
591
  return url;
592
592
  }
593
- if (!urlIsInsideOf(url, rootDirectoryUrl)) {
593
+ if (!urlIsOrIsInsideOf(url, rootDirectoryUrl)) {
594
594
  const fsRootUrl = ensureWindowsDriveLetter("file:///", url);
595
595
  url = `${rootDirectoryUrl}@fs/${url.slice(fsRootUrl.length)}`;
596
596
  }
@@ -3840,10 +3840,19 @@ const replacePlaceholders = (html, replacers) => {
3840
3840
  });
3841
3841
  };
3842
3842
 
3843
- const createPluginStore = (plugins) => {
3843
+ const createPluginStore = async (plugins) => {
3844
3844
  const allDevServerRoutes = [];
3845
+ const allDevServerServices = [];
3845
3846
  const pluginArray = [];
3846
- const addPlugin = (plugin) => {
3847
+
3848
+ const pluginPromises = [];
3849
+ const addPlugin = async (plugin) => {
3850
+ if (plugin && typeof plugin.then === "function") {
3851
+ pluginPromises.push(plugin);
3852
+ const value = await plugin;
3853
+ addPlugin(value);
3854
+ return;
3855
+ }
3847
3856
  if (Array.isArray(plugin)) {
3848
3857
  for (const subplugin of plugin) {
3849
3858
  addPlugin(subplugin);
@@ -3862,21 +3871,28 @@ const createPluginStore = (plugins) => {
3862
3871
  allDevServerRoutes.push(devServerRoute);
3863
3872
  }
3864
3873
  }
3874
+ if (plugin.devServerServices) {
3875
+ const devServerServices = plugin.devServerServices;
3876
+ for (const devServerService of devServerServices) {
3877
+ allDevServerServices.push(devServerService);
3878
+ }
3879
+ }
3865
3880
  pluginArray.push(plugin);
3866
3881
  };
3867
3882
  addPlugin(jsenvPluginHtmlSyntaxErrorFallback());
3868
3883
  for (const plugin of plugins) {
3869
3884
  addPlugin(plugin);
3870
3885
  }
3886
+ await Promise.all(pluginPromises);
3871
3887
 
3872
3888
  return {
3873
3889
  pluginArray,
3874
-
3875
3890
  allDevServerRoutes,
3891
+ allDevServerServices,
3876
3892
  };
3877
3893
  };
3878
3894
 
3879
- const createPluginController = (
3895
+ const createPluginController = async (
3880
3896
  pluginStore,
3881
3897
  kitchen,
3882
3898
  { initialPuginsMeta = {} } = {},
@@ -3899,7 +3915,7 @@ const createPluginController = (
3899
3915
  pluginCandidate.destroy?.();
3900
3916
  continue;
3901
3917
  }
3902
- const initPluginResult = initPlugin(pluginCandidate, kitchen);
3918
+ const initPluginResult = await initPlugin(pluginCandidate, kitchen);
3903
3919
  if (!initPluginResult) {
3904
3920
  pluginCandidate.destroy?.();
3905
3921
  continue;
@@ -3951,6 +3967,7 @@ const createPluginController = (
3951
3967
  key === "serverEvents" ||
3952
3968
  key === "mustStayFirst" ||
3953
3969
  key === "devServerRoutes" ||
3970
+ key === "devServerServices" ||
3954
3971
  key === "effect"
3955
3972
  ) {
3956
3973
  continue;
@@ -4124,6 +4141,7 @@ const createPluginController = (
4124
4141
  const HOOK_NAMES = [
4125
4142
  "init",
4126
4143
  "devServerRoutes", // is called only during dev/tests
4144
+ "devServerServices", // is called only during dev/tests
4127
4145
  "resolveReference",
4128
4146
  "redirectReference",
4129
4147
  "transformReferenceSearchParams",
@@ -4178,12 +4196,12 @@ const testAppliesDuring = (plugin, kitchen) => {
4178
4196
  `"appliesDuring" must be an object or a string, got ${appliesDuring}`,
4179
4197
  );
4180
4198
  };
4181
- const initPlugin = (plugin, kitchen) => {
4199
+ const initPlugin = async (plugin, kitchen) => {
4182
4200
  const { init } = plugin;
4183
4201
  if (!init) {
4184
4202
  return true;
4185
4203
  }
4186
- const initReturnValue = init(kitchen.context, { plugin });
4204
+ const initReturnValue = await init(kitchen.context, { plugin });
4187
4205
  if (initReturnValue === false) {
4188
4206
  return false;
4189
4207
  }
@@ -6043,10 +6061,7 @@ const jsenvPluginVersionSearchParam = () => {
6043
6061
 
6044
6062
  const FILE_AND_SERVER_URLS_CONVERTER = {
6045
6063
  asServerUrl: (fileUrl, serverRootDirectoryUrl) => {
6046
- if (fileUrl === serverRootDirectoryUrl) {
6047
- return "/";
6048
- }
6049
- if (urlIsInsideOf(fileUrl, serverRootDirectoryUrl)) {
6064
+ if (urlIsOrIsInsideOf(fileUrl, serverRootDirectoryUrl)) {
6050
6065
  const urlRelativeToServer = urlToRelativeUrl(
6051
6066
  fileUrl,
6052
6067
  serverRootDirectoryUrl,
@@ -6102,6 +6117,7 @@ const htmlFileUrlForDirectory = import.meta.resolve(
6102
6117
  );
6103
6118
 
6104
6119
  const jsenvPluginDirectoryListing = ({
6120
+ spa,
6105
6121
  urlMocks = false,
6106
6122
  autoreload = true,
6107
6123
  directoryContentMagicName,
@@ -6143,7 +6159,7 @@ const jsenvPluginDirectoryListing = ({
6143
6159
  return null;
6144
6160
  }
6145
6161
  }
6146
- return `${htmlFileUrlForDirectory}?url=${encodeURIComponent(url)}&enoent`;
6162
+ return `${htmlFileUrlForDirectory}?url=${encodeURIComponent(requestedUrl)}&enoent`;
6147
6163
  }
6148
6164
  const isDirectory = fsStat?.isDirectory();
6149
6165
  if (!isDirectory) {
@@ -6169,21 +6185,22 @@ const jsenvPluginDirectoryListing = ({
6169
6185
  if (urlWithoutSearch !== String(htmlFileUrlForDirectory)) {
6170
6186
  return null;
6171
6187
  }
6172
- const requestedUrl = urlInfo.searchParams.get("url");
6173
- if (!requestedUrl) {
6188
+ const urlNotFound = urlInfo.searchParams.get("url");
6189
+ if (!urlNotFound) {
6174
6190
  return null;
6175
6191
  }
6192
+
6176
6193
  urlInfo.headers["cache-control"] = "no-cache";
6177
6194
  const enoent = urlInfo.searchParams.has("enoent");
6178
6195
  if (enoent) {
6179
6196
  urlInfo.status = 404;
6180
- urlInfo.headers["cache-control"] = "no-cache";
6181
6197
  }
6182
6198
  const request = urlInfo.context.request;
6183
6199
  const { rootDirectoryUrl, mainFilePath } = urlInfo.context;
6184
6200
  const directoryListingInjections = generateDirectoryListingInjection(
6185
- requestedUrl,
6201
+ urlNotFound,
6186
6202
  {
6203
+ spa,
6187
6204
  autoreload,
6188
6205
  request,
6189
6206
  urlMocks,
@@ -6276,8 +6293,9 @@ const jsenvPluginDirectoryListing = ({
6276
6293
  };
6277
6294
 
6278
6295
  const generateDirectoryListingInjection = (
6279
- requestedUrl,
6296
+ urlNotFound,
6280
6297
  {
6298
+ spa,
6281
6299
  rootDirectoryUrl,
6282
6300
  mainFilePath,
6283
6301
  packageDirectory,
@@ -6290,7 +6308,7 @@ const generateDirectoryListingInjection = (
6290
6308
  ) => {
6291
6309
  let serverRootDirectoryUrl = rootDirectoryUrl;
6292
6310
  const firstExistingDirectoryUrl = getFirstExistingDirectoryUrl(
6293
- requestedUrl,
6311
+ urlNotFound,
6294
6312
  serverRootDirectoryUrl,
6295
6313
  );
6296
6314
  const directoryContentItems = getDirectoryContentItems({
@@ -6341,8 +6359,8 @@ const generateDirectoryListingInjection = (
6341
6359
  const { host } = new URL(request.url);
6342
6360
  const websocketUrl = `${websocketScheme}://${host}/.internal/directory_content.websocket?directory=${encodeURIComponent(directoryUrlRelativeToServer)}`;
6343
6361
 
6344
- const navItems = [];
6345
- {
6362
+ const generateBreadcrumb = () => {
6363
+ const breadcrumb = [];
6346
6364
  const lastItemUrl = firstExistingDirectoryUrl;
6347
6365
  const lastItemRelativeUrl = urlToRelativeUrl(lastItemUrl, rootDirectoryUrl);
6348
6366
  const rootDirectoryUrlName = urlToFilename(rootDirectoryUrl);
@@ -6352,7 +6370,6 @@ const generateDirectoryListingInjection = (
6352
6370
  } else {
6353
6371
  parts = [rootDirectoryUrlName];
6354
6372
  }
6355
-
6356
6373
  let i = 0;
6357
6374
  while (i < parts.length) {
6358
6375
  const part = parts[i];
@@ -6373,7 +6390,7 @@ const generateDirectoryListingInjection = (
6373
6390
  navItemUrl,
6374
6391
  serverRootDirectoryUrl,
6375
6392
  );
6376
- let urlRelativeToDocument = urlToRelativeUrl(navItemUrl, requestedUrl);
6393
+ let urlRelativeToDocument = urlToRelativeUrl(navItemUrl, urlNotFound);
6377
6394
  const isServerRootDirectory = navItemUrl === serverRootDirectoryUrl;
6378
6395
  if (isServerRootDirectory) {
6379
6396
  urlRelativeToServer = `/${directoryContentMagicName}`;
@@ -6381,7 +6398,7 @@ const generateDirectoryListingInjection = (
6381
6398
  }
6382
6399
  const name = part;
6383
6400
  const isCurrent = navItemUrl === String(firstExistingDirectoryUrl);
6384
- navItems.push({
6401
+ breadcrumb.push({
6385
6402
  url: navItemUrl,
6386
6403
  urlRelativeToServer,
6387
6404
  urlRelativeToDocument,
@@ -6391,34 +6408,47 @@ const generateDirectoryListingInjection = (
6391
6408
  });
6392
6409
  i++;
6393
6410
  }
6394
- }
6411
+ return breadcrumb;
6412
+ };
6413
+ const breadcrumb = generateBreadcrumb();
6395
6414
 
6396
6415
  let enoentDetails = null;
6397
6416
  if (enoent) {
6417
+ const buildEnoentPathInfo = (urlBase, closestExistingUrl) => {
6418
+ let filePathExisting;
6419
+ let filePathNotFound;
6420
+ const existingIndex = String(closestExistingUrl).length;
6421
+ filePathExisting = urlToRelativeUrl(
6422
+ closestExistingUrl,
6423
+ serverRootDirectoryUrl,
6424
+ );
6425
+ filePathNotFound = urlBase.slice(existingIndex);
6426
+ return [filePathExisting, filePathNotFound];
6427
+ };
6398
6428
  const fileRelativeUrl = urlToRelativeUrl(
6399
- requestedUrl,
6429
+ urlNotFound,
6400
6430
  serverRootDirectoryUrl,
6401
6431
  );
6402
- let filePathExisting;
6403
- let filePathNotFound;
6404
- const existingIndex = String(firstExistingDirectoryUrl).length;
6405
- filePathExisting = urlToRelativeUrl(
6406
- firstExistingDirectoryUrl,
6407
- serverRootDirectoryUrl,
6408
- );
6409
- filePathNotFound = requestedUrl.slice(existingIndex);
6410
6432
  enoentDetails = {
6411
- fileUrl: requestedUrl,
6433
+ fileUrl: urlNotFound,
6412
6434
  fileRelativeUrl,
6435
+ };
6436
+
6437
+ const [filePathExisting, filePathNotFound] = buildEnoentPathInfo(
6438
+ urlNotFound,
6439
+ firstExistingDirectoryUrl,
6440
+ );
6441
+ Object.assign(enoentDetails, {
6413
6442
  filePathExisting: `/${filePathExisting}`,
6414
6443
  filePathNotFound,
6415
- };
6444
+ });
6416
6445
  }
6417
6446
 
6418
6447
  return {
6419
6448
  __DIRECTORY_LISTING__: {
6449
+ spa,
6420
6450
  enoentDetails,
6421
- navItems,
6451
+ breadcrumb,
6422
6452
  urlMocks,
6423
6453
  directoryContentMagicName,
6424
6454
  directoryUrl: firstExistingDirectoryUrl,
@@ -6431,11 +6461,11 @@ const generateDirectoryListingInjection = (
6431
6461
  },
6432
6462
  };
6433
6463
  };
6434
- const getFirstExistingDirectoryUrl = (requestedUrl, serverRootDirectoryUrl) => {
6435
- let directoryUrlCandidate = new URL("./", requestedUrl);
6464
+ const getFirstExistingDirectoryUrl = (urlBase, serverRootDirectoryUrl) => {
6465
+ let directoryUrlCandidate = new URL("./", urlBase);
6436
6466
  while (!existsSync(directoryUrlCandidate)) {
6437
6467
  directoryUrlCandidate = new URL("../", directoryUrlCandidate);
6438
- if (!urlIsInsideOf(directoryUrlCandidate, serverRootDirectoryUrl)) {
6468
+ if (!urlIsOrIsInsideOf(directoryUrlCandidate, serverRootDirectoryUrl)) {
6439
6469
  directoryUrlCandidate = new URL(serverRootDirectoryUrl);
6440
6470
  break;
6441
6471
  }
@@ -6484,7 +6514,7 @@ const getDirectoryContentItems = ({
6484
6514
  };
6485
6515
 
6486
6516
  const jsenvPluginFsRedirection = ({
6487
- spa = true,
6517
+ spa,
6488
6518
  directoryContentMagicName,
6489
6519
  magicExtensions = ["inherit", ".js"],
6490
6520
  magicDirectoryIndex = true,
@@ -6643,17 +6673,12 @@ const getClosestHtmlRootFile = (requestedUrl, serverRootDirectoryUrl) => {
6643
6673
  if (existsSync(indexHtmlFileUrl)) {
6644
6674
  return indexHtmlFileUrl.href;
6645
6675
  }
6646
- const htmlFileUrlCandidate = new URL(
6647
- `${urlToFilename(directoryUrl)}.html`,
6648
- directoryUrl,
6649
- );
6676
+ const filename = urlToFilename(directoryUrl);
6677
+ const htmlFileUrlCandidate = new URL(`${filename}.html`, directoryUrl);
6650
6678
  if (existsSync(htmlFileUrlCandidate)) {
6651
6679
  return htmlFileUrlCandidate.href;
6652
6680
  }
6653
- if (
6654
- !urlIsInsideOf(directoryUrl, serverRootDirectoryUrl) ||
6655
- directoryUrl.href === serverRootDirectoryUrl
6656
- ) {
6681
+ if (!urlIsOrIsInsideOf(directoryUrl, serverRootDirectoryUrl)) {
6657
6682
  return null;
6658
6683
  }
6659
6684
  directoryUrl = new URL("../", directoryUrl);
@@ -6663,7 +6688,7 @@ const getClosestHtmlRootFile = (requestedUrl, serverRootDirectoryUrl) => {
6663
6688
  const directoryContentMagicName = "...";
6664
6689
 
6665
6690
  const jsenvPluginProtocolFile = ({
6666
- spa,
6691
+ spa = true,
6667
6692
  magicExtensions,
6668
6693
  magicDirectoryIndex,
6669
6694
  preserveSymlinks,
@@ -6731,6 +6756,7 @@ const jsenvPluginProtocolFile = ({
6731
6756
  ...(directoryListing
6732
6757
  ? [
6733
6758
  jsenvPluginDirectoryListing({
6759
+ spa,
6734
6760
  ...directoryListing,
6735
6761
  directoryContentMagicName,
6736
6762
  rootDirectoryUrl,
@@ -8060,7 +8086,7 @@ const jsenvPluginAutoreloadServer = ({
8060
8086
  serverEvents: {
8061
8087
  reload: (serverEventInfo) => {
8062
8088
  const formatUrlForClient = (url) => {
8063
- if (urlIsInsideOf(url, serverEventInfo.rootDirectoryUrl)) {
8089
+ if (urlIsOrIsInsideOf(url, serverEventInfo.rootDirectoryUrl)) {
8064
8090
  return urlToRelativeUrl(url, serverEventInfo.rootDirectoryUrl);
8065
8091
  }
8066
8092
  if (url.startsWith("file:")) {
@@ -8635,6 +8661,7 @@ const jsenvPluginChromeDevtoolsJson = () => {
8635
8661
  devServerRoutes: [
8636
8662
  {
8637
8663
  endpoint: "GET /.well-known/appspecific/com.chrome.devtools.json",
8664
+ declarationSource: import.meta.url,
8638
8665
  fetch: (request, { kitchen }) => {
8639
8666
  const { rootDirectoryUrl } = kitchen.context;
8640
8667
  return Response.json({
@@ -9307,7 +9334,7 @@ const startDevServer = async ({
9307
9334
  read: readPackageAtOrNull,
9308
9335
  };
9309
9336
 
9310
- const devServerPluginStore = createPluginStore([
9337
+ const devServerPluginStore = await createPluginStore([
9311
9338
  jsenvPluginServerEvents({ clientAutoreload }),
9312
9339
  ...plugins,
9313
9340
  ...getCorePlugins({
@@ -9333,7 +9360,7 @@ const startDevServer = async ({
9333
9360
  ribbon,
9334
9361
  }),
9335
9362
  ]);
9336
- const getOrCreateKitchen = (request) => {
9363
+ const getOrCreateKitchen = async (request) => {
9337
9364
  const { runtimeName, runtimeVersion } = parseUserAgentHeader(
9338
9365
  request.headers["user-agent"] || "",
9339
9366
  );
@@ -9455,7 +9482,7 @@ const startDevServer = async ({
9455
9482
  );
9456
9483
  },
9457
9484
  );
9458
- const devServerPluginController = createPluginController(
9485
+ const devServerPluginController = await createPluginController(
9459
9486
  devServerPluginStore,
9460
9487
  kitchen,
9461
9488
  );
@@ -9471,8 +9498,8 @@ const startDevServer = async ({
9471
9498
 
9472
9499
  finalServices.push({
9473
9500
  name: "jsenv:dev_server_routes",
9474
- augmentRouteFetchSecondArg: (request) => {
9475
- const kitchen = getOrCreateKitchen(request);
9501
+ augmentRouteFetchSecondArg: async (request) => {
9502
+ const kitchen = await getOrCreateKitchen(request);
9476
9503
  return { kitchen };
9477
9504
  },
9478
9505
  routes: [
@@ -9675,6 +9702,7 @@ const startDevServer = async ({
9675
9702
  },
9676
9703
  ],
9677
9704
  });
9705
+ finalServices.push(...devServerPluginStore.allDevServerServices);
9678
9706
  }
9679
9707
  // jsenv error handler service
9680
9708
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "40.7.0",
3
+ "version": "40.7.1",
4
4
  "description": "Tool to develop, test and build js projects",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -77,23 +77,28 @@
77
77
  "playwright:install": "npx playwright install-deps && npx playwright install",
78
78
  "https:setup": "npx @jsenv/https-local setup",
79
79
  "prepublishOnly": "npm run build",
80
+ "database:install": "npx @jsenv/database install",
81
+ "database:start": "npx @jsenv/database start",
82
+ "database:stop": "npx @jsenv/database stop",
83
+ "database:setup": "npx @jsenv/database setup",
80
84
  "oto:start": "npm run start -w oto"
81
85
  },
82
86
  "dependencies": {
83
87
  "@financial-times/polyfill-useragent-normaliser": "1.10.2",
84
- "@jsenv/ast": "6.7.3",
85
- "@jsenv/js-module-fallback": "1.4.14",
86
- "@jsenv/plugin-bundling": "2.9.7",
88
+ "@jsenv/ast": "6.7.6",
89
+ "@jsenv/js-module-fallback": "1.4.18",
90
+ "@jsenv/plugin-bundling": "2.9.8",
87
91
  "@jsenv/plugin-minification": "1.7.0",
88
- "@jsenv/plugin-supervisor": "1.7.2",
89
- "@jsenv/plugin-transpilation": "1.5.21",
92
+ "@jsenv/plugin-supervisor": "1.7.3",
93
+ "@jsenv/plugin-transpilation": "1.5.50",
90
94
  "@jsenv/server": "16.1.2",
91
- "@jsenv/sourcemap": "1.3.8"
95
+ "@jsenv/sourcemap": "1.3.9",
96
+ "react-table": "7.8.0"
92
97
  },
93
98
  "devDependencies": {
94
- "@babel/plugin-syntax-decorators": "7.25.9",
95
- "@babel/plugin-syntax-import-attributes": "7.26.0",
96
- "@babel/plugin-syntax-optional-chaining-assign": "7.25.9",
99
+ "@babel/plugin-syntax-decorators": "7.27.1",
100
+ "@babel/plugin-syntax-import-attributes": "7.27.1",
101
+ "@babel/plugin-syntax-optional-chaining-assign": "7.27.1",
97
102
  "@jsenv/abort": "workspace:*",
98
103
  "@jsenv/assert": "workspace:*",
99
104
  "@jsenv/cli": "workspace:*",
@@ -111,6 +116,7 @@
111
116
  "@jsenv/os-metrics": "workspace:*",
112
117
  "@jsenv/performance-impact": "workspace:*",
113
118
  "@jsenv/plugin-as-js-classic": "workspace:*",
119
+ "@jsenv/plugin-database-manager": "workspace:*",
114
120
  "@jsenv/router": "workspace:*",
115
121
  "@jsenv/runtime-compat": "workspace:*",
116
122
  "@jsenv/snapshot": "workspace:*",
@@ -123,12 +129,15 @@
123
129
  "@playwright/browser-firefox": "1.52.0",
124
130
  "@playwright/browser-webkit": "1.52.0",
125
131
  "babel-plugin-transform-async-to-promises": "0.8.18",
126
- "eslint": "9.25.1",
127
- "open": "10.1.1",
132
+ "eslint": "9.26.0",
133
+ "open": "10.1.2",
128
134
  "playwright": "1.52.0",
129
135
  "preact": "10.26.5",
136
+ "preact-iso": "2.9.1",
130
137
  "prettier": "3.5.3",
138
+ "prettier-plugin-embed": "0.5.0",
131
139
  "prettier-plugin-organize-imports": "4.1.0",
140
+ "prettier-plugin-sql": "0.19.0",
132
141
  "strip-ansi": "7.1.0"
133
142
  }
134
143
  }
@@ -52,7 +52,7 @@ import {
52
52
  nodeDefaultRuntimeCompat,
53
53
  } from "@jsenv/runtime-compat";
54
54
  import {
55
- urlIsInsideOf,
55
+ urlIsOrIsInsideOf,
56
56
  urlToBasename,
57
57
  urlToExtension,
58
58
  urlToFilename,
@@ -208,7 +208,7 @@ export const build = async ({
208
208
  );
209
209
  }
210
210
  }
211
- if (!urlIsInsideOf(sourceUrl, sourceDirectoryUrl)) {
211
+ if (!urlIsOrIsInsideOf(sourceUrl, sourceDirectoryUrl)) {
212
212
  throw new Error(
213
213
  `The key "${key}" in "entryPoints" is invalid: it must be inside the source directory at ${sourceDirectoryUrl}.`,
214
214
  );
@@ -259,7 +259,7 @@ export const build = async ({
259
259
  `The buildRelativeUrl "${buildRelativeUrl}"${forEntryPointOrEmpty} is invalid: it must be a relative url.`,
260
260
  );
261
261
  }
262
- if (!urlIsInsideOf(buildUrl, buildDirectoryUrl)) {
262
+ if (!urlIsOrIsInsideOf(buildUrl, buildDirectoryUrl)) {
263
263
  throw new Error(
264
264
  `The buildRelativeUrl "${buildRelativeUrl}"${forEntryPointOrEmpty} is invalid: it must be inside the build directory at ${buildDirectoryUrl}.`,
265
265
  );
@@ -552,7 +552,7 @@ export const build = async ({
552
552
  if (
553
553
  process.env.CAPTURING_SIDE_EFFECTS ||
554
554
  (!import.meta.build &&
555
- urlIsInsideOf(sourceDirectoryUrl, jsenvCoreDirectoryUrl))
555
+ urlIsOrIsInsideOf(sourceDirectoryUrl, jsenvCoreDirectoryUrl))
556
556
  ) {
557
557
  outDirectoryUrl = new URL("../.jsenv_b/", sourceDirectoryUrl).href;
558
558
  } else if (packageDirectory.url) {
@@ -761,7 +761,7 @@ export const build = async ({
761
761
  let hasSomeOutdatedSideEffectUrl = false;
762
762
  for (const packageSideEffectUrl of packageSideEffectUrlSet) {
763
763
  if (
764
- urlIsInsideOf(packageSideEffectUrl, buildDirectoryUrl) &&
764
+ urlIsOrIsInsideOf(packageSideEffectUrl, buildDirectoryUrl) &&
765
765
  !buildSideEffectUrlSet.has(packageSideEffectUrl)
766
766
  ) {
767
767
  hasSomeOutdatedSideEffectUrl = true;
@@ -1061,7 +1061,7 @@ const prepareEntryPointBuild = async (
1061
1061
  });
1062
1062
 
1063
1063
  let _getOtherEntryBuildInfo;
1064
- const rawPluginStore = createPluginStore([
1064
+ const rawPluginStore = await createPluginStore([
1065
1065
  ...(mappings ? [jsenvPluginMappings(mappings)] : []),
1066
1066
  {
1067
1067
  name: "jsenv:other_entry_point_build_during_craft",
@@ -1106,7 +1106,7 @@ const prepareEntryPointBuild = async (
1106
1106
  packageSideEffects,
1107
1107
  }),
1108
1108
  ]);
1109
- const rawPluginController = createPluginController(
1109
+ const rawPluginController = await createPluginController(
1110
1110
  rawPluginStore,
1111
1111
  rawKitchen,
1112
1112
  );
@@ -1177,7 +1177,7 @@ const prepareEntryPointBuild = async (
1177
1177
  rawKitchen.graph.getUrlInfo(entryReference.url).type === "html" &&
1178
1178
  rawKitchen.context.isSupportedOnCurrentClients("importmap"),
1179
1179
  });
1180
- const finalPluginStore = createPluginStore([
1180
+ const finalPluginStore = await createPluginStore([
1181
1181
  jsenvPluginReferenceAnalysis({
1182
1182
  ...referenceAnalysis,
1183
1183
  fetchInlineUrls: false,
@@ -1210,7 +1210,7 @@ const prepareEntryPointBuild = async (
1210
1210
  },
1211
1211
  buildSpecifierManager.jsenvPluginMoveToBuildDirectory,
1212
1212
  ]);
1213
- const finalPluginController = createPluginController(
1213
+ const finalPluginController = await createPluginController(
1214
1214
  finalPluginStore,
1215
1215
  finalKitchen,
1216
1216
  {
@@ -16,7 +16,7 @@ import {
16
16
  ensurePathnameTrailingSlash,
17
17
  injectQueryParamIntoSpecifierWithoutEncoding,
18
18
  renderUrlOrRelativeUrlFilename,
19
- urlIsInsideOf,
19
+ urlIsOrIsInsideOf,
20
20
  urlToRelativeUrl,
21
21
  } from "@jsenv/urls";
22
22
  import { CONTENT_TYPE } from "@jsenv/utils/src/content_type/content_type.js";
@@ -676,7 +676,7 @@ export const createBuildSpecifierManager = ({
676
676
  // const urlInfoInsideThisDirectorySet = new Set();
677
677
  const versionsInfluencingThisDirectorySet = new Set();
678
678
  for (const [url, urlInfo] of finalKitchen.graph.urlInfoMap) {
679
- if (!urlIsInsideOf(url, directoryUrl)) {
679
+ if (!urlIsOrIsInsideOf(url, directoryUrl)) {
680
680
  continue;
681
681
  }
682
682
  // ideally we should exclude eventual directories as the are redundant
@@ -1075,7 +1075,7 @@ export const createBuildSpecifierManager = ({
1075
1075
  }
1076
1076
  if (
1077
1077
  urlInfo.type === "asset" &&
1078
- urlIsInsideOf(urlInfo.url, buildDirectoryUrl)
1078
+ urlIsOrIsInsideOf(urlInfo.url, buildDirectoryUrl)
1079
1079
  ) {
1080
1080
  return;
1081
1081
  }
@@ -1,7 +1,7 @@
1
1
  // import { ANSI } from "@jsenv/humanize";
2
2
  import {
3
3
  injectQueryParams,
4
- urlIsInsideOf,
4
+ urlIsOrIsInsideOf,
5
5
  urlToFilename,
6
6
  urlToRelativeUrl,
7
7
  } from "@jsenv/urls";
@@ -36,7 +36,7 @@ export const createBuildUrlsGenerator = ({
36
36
  if (buildUrlFromMap) {
37
37
  return buildUrlFromMap;
38
38
  }
39
- if (urlIsInsideOf(url, buildDirectoryUrl)) {
39
+ if (urlIsOrIsInsideOf(url, buildDirectoryUrl)) {
40
40
  if (ownerUrlInfo.searchParams.has("dynamic_import_id")) {
41
41
  const ownerDirectoryPath = determineDirectoryPath({
42
42
  sourceDirectoryUrl,