@jsenv/core 41.0.7 → 41.1.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/build/jsenv_core_packages.js +16 -1
- package/dist/start_dev_server/jsenv_core_packages.js +15 -21
- package/dist/start_dev_server/start_dev_server.js +120 -16
- package/package.json +2 -3
- package/src/dev/dev_server_plugins/dev_server_plugin_serve_source_files.js +2 -5
- package/src/dev/dev_server_plugins/runtime_from_request.js +127 -0
- package/src/dev/dev_server_plugins/user_agent.js +0 -22
|
@@ -6595,6 +6595,7 @@ const browserDefaultRuntimeCompat = {
|
|
|
6595
6595
|
edge: "79",
|
|
6596
6596
|
firefox: "67",
|
|
6597
6597
|
ios: "12",
|
|
6598
|
+
ios_safari: "12",
|
|
6598
6599
|
opera: "51",
|
|
6599
6600
|
safari: "11.3",
|
|
6600
6601
|
samsung: "9.2",
|
|
@@ -6696,6 +6697,7 @@ const featuresCompatMap = {
|
|
|
6696
6697
|
safari: "10.1",
|
|
6697
6698
|
opera: "48",
|
|
6698
6699
|
ios: "10.3",
|
|
6700
|
+
ios_safari: "10.3",
|
|
6699
6701
|
android: "61",
|
|
6700
6702
|
samsung: "8.2",
|
|
6701
6703
|
},
|
|
@@ -6715,6 +6717,7 @@ const featuresCompatMap = {
|
|
|
6715
6717
|
edge: "79",
|
|
6716
6718
|
firefox: "62",
|
|
6717
6719
|
ios: "12",
|
|
6720
|
+
ios_safari: "12",
|
|
6718
6721
|
opera: "51",
|
|
6719
6722
|
safari: "11.1",
|
|
6720
6723
|
samsung: "9.2",
|
|
@@ -6732,6 +6735,7 @@ const featuresCompatMap = {
|
|
|
6732
6735
|
edge: "79",
|
|
6733
6736
|
firefox: "67",
|
|
6734
6737
|
ios: "11.3",
|
|
6738
|
+
ios_safari: "11.3",
|
|
6735
6739
|
opera: "50",
|
|
6736
6740
|
safari: "11.3",
|
|
6737
6741
|
samsung: "8.0",
|
|
@@ -6745,6 +6749,7 @@ const featuresCompatMap = {
|
|
|
6745
6749
|
safari: "15",
|
|
6746
6750
|
samsung: "15",
|
|
6747
6751
|
ios: "15",
|
|
6752
|
+
ios_safari: "15",
|
|
6748
6753
|
node: "14.8",
|
|
6749
6754
|
},
|
|
6750
6755
|
// https://caniuse.com/import-maps
|
|
@@ -6780,6 +6785,7 @@ const featuresCompatMap = {
|
|
|
6780
6785
|
opera: "11.5",
|
|
6781
6786
|
safari: "4",
|
|
6782
6787
|
ios: "5",
|
|
6788
|
+
ios_safari: "5",
|
|
6783
6789
|
android: "4.4",
|
|
6784
6790
|
},
|
|
6785
6791
|
// https://developer.mozilla.org/en-US/docs/Web/API/Worker/Worker#browser_compatibility
|
|
@@ -6797,6 +6803,7 @@ const featuresCompatMap = {
|
|
|
6797
6803
|
safari: "11.1",
|
|
6798
6804
|
opera: "27",
|
|
6799
6805
|
ios: "11.3",
|
|
6806
|
+
ios_safari: "11.3",
|
|
6800
6807
|
android: "12.12",
|
|
6801
6808
|
},
|
|
6802
6809
|
service_worker_type_module: {
|
|
@@ -6826,6 +6833,7 @@ const featuresCompatMap = {
|
|
|
6826
6833
|
safari: "12.1",
|
|
6827
6834
|
opera: "58",
|
|
6828
6835
|
ios: "12.2",
|
|
6836
|
+
ios_safari: "12.2",
|
|
6829
6837
|
android: "94",
|
|
6830
6838
|
node: "12",
|
|
6831
6839
|
},
|
|
@@ -6837,6 +6845,7 @@ const featuresCompatMap = {
|
|
|
6837
6845
|
safari: "12",
|
|
6838
6846
|
node: "10",
|
|
6839
6847
|
ios: "12",
|
|
6848
|
+
ios_safari: "12",
|
|
6840
6849
|
samsung: "8",
|
|
6841
6850
|
electron: "3",
|
|
6842
6851
|
},
|
|
@@ -6848,6 +6857,7 @@ const featuresCompatMap = {
|
|
|
6848
6857
|
opera: "28",
|
|
6849
6858
|
safari: "9",
|
|
6850
6859
|
ios: "9",
|
|
6860
|
+
ios_safari: "9",
|
|
6851
6861
|
android: "4",
|
|
6852
6862
|
node: "4",
|
|
6853
6863
|
},
|
|
@@ -6859,6 +6869,7 @@ const featuresCompatMap = {
|
|
|
6859
6869
|
safari: "10",
|
|
6860
6870
|
node: "6",
|
|
6861
6871
|
ios: "10",
|
|
6872
|
+
ios_safari: "10",
|
|
6862
6873
|
samsung: "5",
|
|
6863
6874
|
electron: "0.36",
|
|
6864
6875
|
},
|
|
@@ -6871,6 +6882,7 @@ const featuresCompatMap = {
|
|
|
6871
6882
|
node: "4",
|
|
6872
6883
|
ie: "11",
|
|
6873
6884
|
ios: "10",
|
|
6885
|
+
ios_safari: "10",
|
|
6874
6886
|
samsung: "3.4",
|
|
6875
6887
|
electron: "0.22",
|
|
6876
6888
|
},
|
|
@@ -6882,6 +6894,7 @@ const featuresCompatMap = {
|
|
|
6882
6894
|
safari: "9",
|
|
6883
6895
|
node: "4",
|
|
6884
6896
|
ios: "9",
|
|
6897
|
+
ios_safari: "9",
|
|
6885
6898
|
samsung: "4",
|
|
6886
6899
|
electron: "0.28",
|
|
6887
6900
|
},
|
|
@@ -6895,6 +6908,7 @@ const featuresCompatMap = {
|
|
|
6895
6908
|
ie: "9",
|
|
6896
6909
|
android: "4.4",
|
|
6897
6910
|
ios: "6",
|
|
6911
|
+
ios_safari: "6",
|
|
6898
6912
|
phantom: "2",
|
|
6899
6913
|
samsung: "1",
|
|
6900
6914
|
electron: "0.20",
|
|
@@ -6906,6 +6920,7 @@ const featuresCompatMap = {
|
|
|
6906
6920
|
firefox: "36",
|
|
6907
6921
|
safari: "9",
|
|
6908
6922
|
ios: "9",
|
|
6923
|
+
ios_safari: "9",
|
|
6909
6924
|
samsung: "4",
|
|
6910
6925
|
node: "0.12",
|
|
6911
6926
|
},
|
|
@@ -6992,7 +7007,7 @@ const inferRuntimeCompatFromClosestPackage = async (
|
|
|
6992
7007
|
for (const browserNameAndVersion of browserslistConfig) {
|
|
6993
7008
|
let [name, version] = browserNameAndVersion.split(" ");
|
|
6994
7009
|
if (name === "ios_saf") {
|
|
6995
|
-
name = "
|
|
7010
|
+
name = "ios_safari";
|
|
6996
7011
|
}
|
|
6997
7012
|
if (Object.keys(browserDefaultRuntimeCompat).includes(name)) {
|
|
6998
7013
|
runtimeCompat[name] = version;
|
|
@@ -5897,6 +5897,7 @@ const featuresCompatMap = {
|
|
|
5897
5897
|
safari: "10.1",
|
|
5898
5898
|
opera: "48",
|
|
5899
5899
|
ios: "10.3",
|
|
5900
|
+
ios_safari: "10.3",
|
|
5900
5901
|
android: "61",
|
|
5901
5902
|
samsung: "8.2",
|
|
5902
5903
|
},
|
|
@@ -5916,6 +5917,7 @@ const featuresCompatMap = {
|
|
|
5916
5917
|
edge: "79",
|
|
5917
5918
|
firefox: "62",
|
|
5918
5919
|
ios: "12",
|
|
5920
|
+
ios_safari: "12",
|
|
5919
5921
|
opera: "51",
|
|
5920
5922
|
safari: "11.1",
|
|
5921
5923
|
samsung: "9.2",
|
|
@@ -5933,6 +5935,7 @@ const featuresCompatMap = {
|
|
|
5933
5935
|
edge: "79",
|
|
5934
5936
|
firefox: "67",
|
|
5935
5937
|
ios: "11.3",
|
|
5938
|
+
ios_safari: "11.3",
|
|
5936
5939
|
opera: "50",
|
|
5937
5940
|
safari: "11.3",
|
|
5938
5941
|
samsung: "8.0",
|
|
@@ -5946,6 +5949,7 @@ const featuresCompatMap = {
|
|
|
5946
5949
|
safari: "15",
|
|
5947
5950
|
samsung: "15",
|
|
5948
5951
|
ios: "15",
|
|
5952
|
+
ios_safari: "15",
|
|
5949
5953
|
node: "14.8",
|
|
5950
5954
|
},
|
|
5951
5955
|
// https://caniuse.com/import-maps
|
|
@@ -5981,6 +5985,7 @@ const featuresCompatMap = {
|
|
|
5981
5985
|
opera: "11.5",
|
|
5982
5986
|
safari: "4",
|
|
5983
5987
|
ios: "5",
|
|
5988
|
+
ios_safari: "5",
|
|
5984
5989
|
android: "4.4",
|
|
5985
5990
|
},
|
|
5986
5991
|
// https://developer.mozilla.org/en-US/docs/Web/API/Worker/Worker#browser_compatibility
|
|
@@ -5998,6 +6003,7 @@ const featuresCompatMap = {
|
|
|
5998
6003
|
safari: "11.1",
|
|
5999
6004
|
opera: "27",
|
|
6000
6005
|
ios: "11.3",
|
|
6006
|
+
ios_safari: "11.3",
|
|
6001
6007
|
android: "12.12",
|
|
6002
6008
|
},
|
|
6003
6009
|
service_worker_type_module: {
|
|
@@ -6027,6 +6033,7 @@ const featuresCompatMap = {
|
|
|
6027
6033
|
safari: "12.1",
|
|
6028
6034
|
opera: "58",
|
|
6029
6035
|
ios: "12.2",
|
|
6036
|
+
ios_safari: "12.2",
|
|
6030
6037
|
android: "94",
|
|
6031
6038
|
node: "12",
|
|
6032
6039
|
},
|
|
@@ -6038,6 +6045,7 @@ const featuresCompatMap = {
|
|
|
6038
6045
|
safari: "12",
|
|
6039
6046
|
node: "10",
|
|
6040
6047
|
ios: "12",
|
|
6048
|
+
ios_safari: "12",
|
|
6041
6049
|
samsung: "8",
|
|
6042
6050
|
electron: "3",
|
|
6043
6051
|
},
|
|
@@ -6049,6 +6057,7 @@ const featuresCompatMap = {
|
|
|
6049
6057
|
opera: "28",
|
|
6050
6058
|
safari: "9",
|
|
6051
6059
|
ios: "9",
|
|
6060
|
+
ios_safari: "9",
|
|
6052
6061
|
android: "4",
|
|
6053
6062
|
node: "4",
|
|
6054
6063
|
},
|
|
@@ -6060,6 +6069,7 @@ const featuresCompatMap = {
|
|
|
6060
6069
|
safari: "10",
|
|
6061
6070
|
node: "6",
|
|
6062
6071
|
ios: "10",
|
|
6072
|
+
ios_safari: "10",
|
|
6063
6073
|
samsung: "5",
|
|
6064
6074
|
electron: "0.36",
|
|
6065
6075
|
},
|
|
@@ -6072,6 +6082,7 @@ const featuresCompatMap = {
|
|
|
6072
6082
|
node: "4",
|
|
6073
6083
|
ie: "11",
|
|
6074
6084
|
ios: "10",
|
|
6085
|
+
ios_safari: "10",
|
|
6075
6086
|
samsung: "3.4",
|
|
6076
6087
|
electron: "0.22",
|
|
6077
6088
|
},
|
|
@@ -6083,6 +6094,7 @@ const featuresCompatMap = {
|
|
|
6083
6094
|
safari: "9",
|
|
6084
6095
|
node: "4",
|
|
6085
6096
|
ios: "9",
|
|
6097
|
+
ios_safari: "9",
|
|
6086
6098
|
samsung: "4",
|
|
6087
6099
|
electron: "0.28",
|
|
6088
6100
|
},
|
|
@@ -6096,6 +6108,7 @@ const featuresCompatMap = {
|
|
|
6096
6108
|
ie: "9",
|
|
6097
6109
|
android: "4.4",
|
|
6098
6110
|
ios: "6",
|
|
6111
|
+
ios_safari: "6",
|
|
6099
6112
|
phantom: "2",
|
|
6100
6113
|
samsung: "1",
|
|
6101
6114
|
electron: "0.20",
|
|
@@ -6107,6 +6120,7 @@ const featuresCompatMap = {
|
|
|
6107
6120
|
firefox: "36",
|
|
6108
6121
|
safari: "9",
|
|
6109
6122
|
ios: "9",
|
|
6123
|
+
ios_safari: "9",
|
|
6110
6124
|
samsung: "4",
|
|
6111
6125
|
node: "0.12",
|
|
6112
6126
|
},
|
|
@@ -6286,24 +6300,4 @@ const isResponseEligibleForIntegrityValidation = (response) => {
|
|
|
6286
6300
|
return ["basic", "cors", "default"].includes(response.type);
|
|
6287
6301
|
};
|
|
6288
6302
|
|
|
6289
|
-
|
|
6290
|
-
const urlCache = new Map();
|
|
6291
|
-
|
|
6292
|
-
const fnWithMemoization = (url, ...args) => {
|
|
6293
|
-
const valueFromCache = urlCache.get(url);
|
|
6294
|
-
if (valueFromCache) {
|
|
6295
|
-
return valueFromCache;
|
|
6296
|
-
}
|
|
6297
|
-
const value = compute(url, ...args);
|
|
6298
|
-
urlCache.set(url, value);
|
|
6299
|
-
return value;
|
|
6300
|
-
};
|
|
6301
|
-
|
|
6302
|
-
fnWithMemoization.forget = () => {
|
|
6303
|
-
urlCache.clear();
|
|
6304
|
-
};
|
|
6305
|
-
|
|
6306
|
-
return fnWithMemoization;
|
|
6307
|
-
};
|
|
6308
|
-
|
|
6309
|
-
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, ensurePathnameTrailingSlash, ensureWindowsDriveLetter, errorToHTML, formatError, generateContentFrame, getCallerPosition, getExtensionsToTry, injectQueryParams, 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 };
|
|
6303
|
+
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, ensurePathnameTrailingSlash, ensureWindowsDriveLetter, errorToHTML, formatError, generateContentFrame, getCallerPosition, getExtensionsToTry, injectQueryParams, injectQueryParamsIntoSpecifier, isFileSystemPath, isSpecifierForNodeBuiltin, lookupPackageDirectory, 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, serverPluginErrorHandler, composeTwoResponses, fetchDirectory, serverPluginCORS, jsenvAccessControlAllowedHeaders, startServer } from "@jsenv/server";
|
|
2
2
|
import { readFileSync, existsSync, readdirSync, lstatSync, realpathSync } from "node:fs";
|
|
3
|
-
import { lookupPackageDirectory, readPackageAtOrNull, generateContentFrame, urlToRelativeUrl, errorToHTML, DATA_URL, CONTENT_TYPE, normalizeImportMap, composeTwoImportMaps, resolveImport, JS_QUOTES, urlToExtension, urlToBasename, applyNodeEsmResolution, URL_META, readCustomConditionsFromProcessArgs, urlIsOrIsInsideOf, registerDirectoryLifecycle, asUrlWithoutSearch, readEntryStatSync, ensurePathnameTrailingSlash, compareFileUrls, urlToFilename, applyFileSystemMagicResolution, getExtensionsToTry, setUrlExtension, createDetailedMessage, stringifyUrlSite, injectQueryParamsIntoSpecifier, isSpecifierForNodeBuiltin, injectQueryParams, urlToFileSystemPath, writeFileSync, moveUrl, ensureWindowsDriveLetter, validateResponseIntegrity, setUrlFilename, getCallerPosition, asSpecifierWithoutSearch, bufferToEtag, isFileSystemPath, urlToPathname, setUrlBasename, createLogger, normalizeUrl, ANSI, RUNTIME_COMPAT,
|
|
3
|
+
import { lookupPackageDirectory, readPackageAtOrNull, generateContentFrame, urlToRelativeUrl, errorToHTML, DATA_URL, CONTENT_TYPE, normalizeImportMap, composeTwoImportMaps, resolveImport, JS_QUOTES, urlToExtension, urlToBasename, applyNodeEsmResolution, URL_META, readCustomConditionsFromProcessArgs, urlIsOrIsInsideOf, registerDirectoryLifecycle, asUrlWithoutSearch, readEntryStatSync, ensurePathnameTrailingSlash, compareFileUrls, urlToFilename, applyFileSystemMagicResolution, getExtensionsToTry, setUrlExtension, createDetailedMessage, stringifyUrlSite, injectQueryParamsIntoSpecifier, isSpecifierForNodeBuiltin, injectQueryParams, urlToFileSystemPath, writeFileSync, moveUrl, ensureWindowsDriveLetter, validateResponseIntegrity, setUrlFilename, getCallerPosition, asSpecifierWithoutSearch, bufferToEtag, isFileSystemPath, urlToPathname, setUrlBasename, createLogger, normalizeUrl, ANSI, RUNTIME_COMPAT, formatError, assertAndNormalizeDirectoryUrl, createTaskLog } from "./jsenv_core_packages.js";
|
|
4
4
|
import { createPluginsController } from "@jsenv/server/src/plugins_controller.js";
|
|
5
5
|
import { parseHtml, parseCssUrls, getHtmlNodeAttribute, getHtmlNodePosition, getHtmlNodeAttributePosition, setHtmlNodeAttributes, parseSrcSet, getUrlForContentInsideHtml, removeHtmlNodeText, setHtmlNodeText, getHtmlNodeText, analyzeScriptNode, stringifyHtmlAst, visitHtmlNodes, parseJsUrls, getUrlForContentInsideJs, injectJsenvScript, applyBabelPlugins, analyzeLinkNode, injectHtmlNodeAsEarlyAsPossible, createHtmlNode, generateUrlForInlineContent, parseJsWithAcorn } from "@jsenv/ast";
|
|
6
6
|
import { jsenvPluginSupervisor } from "@jsenv/plugin-supervisor";
|
|
@@ -10,7 +10,6 @@ import { pathToFileURL } from "node:url";
|
|
|
10
10
|
import { bundleJsModules } from "@jsenv/plugin-bundling";
|
|
11
11
|
import { randomUUID } from "node:crypto";
|
|
12
12
|
import { convertFileSystemErrorToResponseProperties } from "@jsenv/server/src/plugins/filesystem/filesystem_error_to_response.js";
|
|
13
|
-
import { createRequire } from "node:module";
|
|
14
13
|
import "./jsenv_core_node_modules.js";
|
|
15
14
|
import "node:process";
|
|
16
15
|
import "node:os";
|
|
@@ -9560,9 +9559,83 @@ const inferUrlInfoType = (urlInfo) => {
|
|
|
9560
9559
|
return expectedType || "other";
|
|
9561
9560
|
};
|
|
9562
9561
|
|
|
9563
|
-
const
|
|
9562
|
+
const runtimeBySecChUa = new Map();
|
|
9563
|
+
const runtimeByUserAgent = new Map();
|
|
9564
9564
|
|
|
9565
|
-
const
|
|
9565
|
+
const getRuntimeFromRequest = (request) => {
|
|
9566
|
+
const secChUa = request.headers["sec-ch-ua"];
|
|
9567
|
+
if (secChUa) {
|
|
9568
|
+
const cached = runtimeBySecChUa.get(secChUa);
|
|
9569
|
+
if (cached) {
|
|
9570
|
+
return cached;
|
|
9571
|
+
}
|
|
9572
|
+
const result = parseSecChUaHeader(secChUa);
|
|
9573
|
+
if (result) {
|
|
9574
|
+
runtimeBySecChUa.set(secChUa, result);
|
|
9575
|
+
return result;
|
|
9576
|
+
}
|
|
9577
|
+
}
|
|
9578
|
+
const userAgent = request.headers["user-agent"] || "";
|
|
9579
|
+
const cached = runtimeByUserAgent.get(userAgent);
|
|
9580
|
+
if (cached) {
|
|
9581
|
+
return cached;
|
|
9582
|
+
}
|
|
9583
|
+
const result = parseUserAgentHeader(userAgent);
|
|
9584
|
+
runtimeByUserAgent.set(userAgent, result);
|
|
9585
|
+
return result;
|
|
9586
|
+
};
|
|
9587
|
+
|
|
9588
|
+
const parseSecChUaHeader = (secChUa) => {
|
|
9589
|
+
// sec-ch-ua format: "Google Chrome";v="149", "Chromium";v="149", "Not)A;Brand";v="24"
|
|
9590
|
+
const brands = [];
|
|
9591
|
+
const regex = /"([^"]+)";v="([^"]+)"/g;
|
|
9592
|
+
let match;
|
|
9593
|
+
while ((match = regex.exec(secChUa)) !== null) {
|
|
9594
|
+
const name = match[1];
|
|
9595
|
+
const version = match[2];
|
|
9596
|
+
// skip "Not X;Brand" noise entries
|
|
9597
|
+
if (!name.includes("Not") && !name.includes("Brand")) {
|
|
9598
|
+
brands.push({ name, version });
|
|
9599
|
+
}
|
|
9600
|
+
}
|
|
9601
|
+
if (brands.length === 0) {
|
|
9602
|
+
return null;
|
|
9603
|
+
}
|
|
9604
|
+
// Prefer the non-Chromium brand (e.g. "Google Chrome", "Microsoft Edge")
|
|
9605
|
+
// Fall back to "Chromium" if no specific brand found
|
|
9606
|
+
let brand = brands.find((b) => b.name !== "Chromium");
|
|
9607
|
+
if (!brand) {
|
|
9608
|
+
brand = brands[0];
|
|
9609
|
+
}
|
|
9610
|
+
const runtimeName = brandNameToRuntimeName(brand.name);
|
|
9611
|
+
const runtimeVersion = `${brand.version}.0.0`;
|
|
9612
|
+
return { runtimeName, runtimeVersion };
|
|
9613
|
+
};
|
|
9614
|
+
const brandNameToRuntimeName = (brandName) => {
|
|
9615
|
+
const lower = brandName.toLowerCase();
|
|
9616
|
+
if (lower === "google chrome") {
|
|
9617
|
+
return "chrome";
|
|
9618
|
+
}
|
|
9619
|
+
if (lower === "headlesschrome") {
|
|
9620
|
+
return "chrome";
|
|
9621
|
+
}
|
|
9622
|
+
if (lower === "microsoft edge") {
|
|
9623
|
+
return "edge";
|
|
9624
|
+
}
|
|
9625
|
+
if (lower === "opera") {
|
|
9626
|
+
return "opera";
|
|
9627
|
+
}
|
|
9628
|
+
if (lower === "samsung internet") {
|
|
9629
|
+
return "samsung";
|
|
9630
|
+
}
|
|
9631
|
+
if (lower === "chromium") {
|
|
9632
|
+
return "chrome";
|
|
9633
|
+
}
|
|
9634
|
+
// other Chromium-based browsers share Chrome's compatibility
|
|
9635
|
+
return "chrome";
|
|
9636
|
+
};
|
|
9637
|
+
|
|
9638
|
+
const parseUserAgentHeader = (userAgent) => {
|
|
9566
9639
|
if (userAgent.includes("node-fetch/")) {
|
|
9567
9640
|
// it's not really node and conceptually we can't assume the node version
|
|
9568
9641
|
// but good enough for now
|
|
@@ -9571,15 +9644,48 @@ const parseUserAgentHeader = memoizeByFirstArgument((userAgent) => {
|
|
|
9571
9644
|
runtimeVersion: process.version.slice(1),
|
|
9572
9645
|
};
|
|
9573
9646
|
}
|
|
9574
|
-
|
|
9575
|
-
|
|
9576
|
-
|
|
9577
|
-
|
|
9578
|
-
|
|
9579
|
-
|
|
9580
|
-
|
|
9581
|
-
|
|
9582
|
-
|
|
9647
|
+
// iOS Safari must be checked before Safari (UA contains both)
|
|
9648
|
+
if (userAgent.includes("Mobile") && userAgent.includes("Safari")) {
|
|
9649
|
+
const iosSafariMatch = userAgent.match(/\bOS (\d+)[._](\d+)(?:[._](\d+))?/);
|
|
9650
|
+
if (iosSafariMatch) {
|
|
9651
|
+
const major = iosSafariMatch[1];
|
|
9652
|
+
const minor = iosSafariMatch[2] || "0";
|
|
9653
|
+
const patch = iosSafariMatch[3] || "0";
|
|
9654
|
+
return {
|
|
9655
|
+
runtimeName: "ios_safari",
|
|
9656
|
+
runtimeVersion: `${major}.${minor}.${patch}`,
|
|
9657
|
+
};
|
|
9658
|
+
}
|
|
9659
|
+
}
|
|
9660
|
+
if (!userAgent.includes("Chrome") && userAgent.includes("Safari")) {
|
|
9661
|
+
const safariMatch = userAgent.match(/\bVersion\/(\d+)\.(\d+)(?:\.(\d+))?/);
|
|
9662
|
+
if (safariMatch) {
|
|
9663
|
+
const major = safariMatch[1];
|
|
9664
|
+
const minor = safariMatch[2] || "0";
|
|
9665
|
+
const patch = safariMatch[3] || "0";
|
|
9666
|
+
return {
|
|
9667
|
+
runtimeName: "safari",
|
|
9668
|
+
runtimeVersion: `${major}.${minor}.${patch}`,
|
|
9669
|
+
};
|
|
9670
|
+
}
|
|
9671
|
+
}
|
|
9672
|
+
const firefoxMatch = userAgent.match(/\bFirefox\/(\d+)\.(\d+)\b/);
|
|
9673
|
+
if (firefoxMatch) {
|
|
9674
|
+
const major = firefoxMatch[1];
|
|
9675
|
+
const minor = firefoxMatch[2] || "0";
|
|
9676
|
+
return { runtimeName: "firefox", runtimeVersion: `${major}.${minor}.0` };
|
|
9677
|
+
}
|
|
9678
|
+
// generic Chromium-based fallback (should normally be handled by sec-ch-ua)
|
|
9679
|
+
const chromeMatch = userAgent.match(
|
|
9680
|
+
/(?:HeadlessChrome|Chrome)\/(\d+)\.(\d+)\b/,
|
|
9681
|
+
);
|
|
9682
|
+
if (chromeMatch) {
|
|
9683
|
+
const major = chromeMatch[1];
|
|
9684
|
+
const minor = chromeMatch[2] || "0";
|
|
9685
|
+
return { runtimeName: "chrome", runtimeVersion: `${major}.${minor}.0` };
|
|
9686
|
+
}
|
|
9687
|
+
return { runtimeName: "unknown", runtimeVersion: "unknown" };
|
|
9688
|
+
};
|
|
9583
9689
|
|
|
9584
9690
|
const devServerPluginServeSourceFiles = ({
|
|
9585
9691
|
packageDirectory,
|
|
@@ -9620,9 +9726,7 @@ const devServerPluginServeSourceFiles = ({
|
|
|
9620
9726
|
serverStopCallbackSet.add(stopWatchingSourceFiles);
|
|
9621
9727
|
|
|
9622
9728
|
const getOrCreateKitchen = async (request) => {
|
|
9623
|
-
const { runtimeName, runtimeVersion } =
|
|
9624
|
-
request.headers["user-agent"] || "",
|
|
9625
|
-
);
|
|
9729
|
+
const { runtimeName, runtimeVersion } = getRuntimeFromRequest(request);
|
|
9626
9730
|
const runtimeId = `${runtimeName}@${runtimeVersion}`;
|
|
9627
9731
|
const existing = kitchenCache.get(runtimeId);
|
|
9628
9732
|
if (existing) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/core",
|
|
3
|
-
"version": "41.
|
|
3
|
+
"version": "41.1.1",
|
|
4
4
|
"description": "Tool to develop, test and build js projects",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -74,13 +74,12 @@
|
|
|
74
74
|
"test:snapshot_clear": "npx @jsenv/filesystem clear **/tests/**/side_effects/"
|
|
75
75
|
},
|
|
76
76
|
"dependencies": {
|
|
77
|
-
"@financial-times/polyfill-useragent-normaliser": "1.10.2",
|
|
78
77
|
"@jsenv/ast": "6.7.21",
|
|
79
78
|
"@jsenv/js-module-fallback": "1.4.29",
|
|
80
79
|
"@jsenv/plugin-bundling": "2.10.9",
|
|
81
80
|
"@jsenv/plugin-minification": "1.7.3",
|
|
82
81
|
"@jsenv/plugin-supervisor": "1.8.0",
|
|
83
|
-
"@jsenv/plugin-transpilation": "1.5.
|
|
82
|
+
"@jsenv/plugin-transpilation": "1.5.71",
|
|
84
83
|
"@jsenv/server": "17.1.1",
|
|
85
84
|
"@jsenv/sourcemap": "1.3.17",
|
|
86
85
|
"react-table": "7.8.0"
|
|
@@ -8,8 +8,7 @@ import { watchSourceFiles } from "../../helpers/watch_source_files.js";
|
|
|
8
8
|
import { WEB_URL_CONVERTER } from "../../helpers/web_url_converter.js";
|
|
9
9
|
import { createKitchen } from "../../kitchen/kitchen.js";
|
|
10
10
|
import { createJsenvPluginsController } from "../../plugins/jsenv_plugins_controller.js";
|
|
11
|
-
|
|
12
|
-
import { parseUserAgentHeader } from "./user_agent.js";
|
|
11
|
+
import { getRuntimeFromRequest } from "./runtime_from_request.js";
|
|
13
12
|
|
|
14
13
|
export const devServerPluginServeSourceFiles = ({
|
|
15
14
|
packageDirectory,
|
|
@@ -50,9 +49,7 @@ export const devServerPluginServeSourceFiles = ({
|
|
|
50
49
|
serverStopCallbackSet.add(stopWatchingSourceFiles);
|
|
51
50
|
|
|
52
51
|
const getOrCreateKitchen = async (request) => {
|
|
53
|
-
const { runtimeName, runtimeVersion } =
|
|
54
|
-
request.headers["user-agent"] || "",
|
|
55
|
-
);
|
|
52
|
+
const { runtimeName, runtimeVersion } = getRuntimeFromRequest(request);
|
|
56
53
|
const runtimeId = `${runtimeName}@${runtimeVersion}`;
|
|
57
54
|
const existing = kitchenCache.get(runtimeId);
|
|
58
55
|
if (existing) {
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
const runtimeBySecChUa = new Map();
|
|
2
|
+
const runtimeByUserAgent = new Map();
|
|
3
|
+
|
|
4
|
+
export const getRuntimeFromRequest = (request) => {
|
|
5
|
+
const secChUa = request.headers["sec-ch-ua"];
|
|
6
|
+
if (secChUa) {
|
|
7
|
+
const cached = runtimeBySecChUa.get(secChUa);
|
|
8
|
+
if (cached) {
|
|
9
|
+
return cached;
|
|
10
|
+
}
|
|
11
|
+
const result = parseSecChUaHeader(secChUa);
|
|
12
|
+
if (result) {
|
|
13
|
+
runtimeBySecChUa.set(secChUa, result);
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const userAgent = request.headers["user-agent"] || "";
|
|
18
|
+
const cached = runtimeByUserAgent.get(userAgent);
|
|
19
|
+
if (cached) {
|
|
20
|
+
return cached;
|
|
21
|
+
}
|
|
22
|
+
const result = parseUserAgentHeader(userAgent);
|
|
23
|
+
runtimeByUserAgent.set(userAgent, result);
|
|
24
|
+
return result;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const parseSecChUaHeader = (secChUa) => {
|
|
28
|
+
// sec-ch-ua format: "Google Chrome";v="149", "Chromium";v="149", "Not)A;Brand";v="24"
|
|
29
|
+
const brands = [];
|
|
30
|
+
const regex = /"([^"]+)";v="([^"]+)"/g;
|
|
31
|
+
let match;
|
|
32
|
+
while ((match = regex.exec(secChUa)) !== null) {
|
|
33
|
+
const name = match[1];
|
|
34
|
+
const version = match[2];
|
|
35
|
+
// skip "Not X;Brand" noise entries
|
|
36
|
+
if (!name.includes("Not") && !name.includes("Brand")) {
|
|
37
|
+
brands.push({ name, version });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (brands.length === 0) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
// Prefer the non-Chromium brand (e.g. "Google Chrome", "Microsoft Edge")
|
|
44
|
+
// Fall back to "Chromium" if no specific brand found
|
|
45
|
+
let brand = brands.find((b) => b.name !== "Chromium");
|
|
46
|
+
if (!brand) {
|
|
47
|
+
brand = brands[0];
|
|
48
|
+
}
|
|
49
|
+
const runtimeName = brandNameToRuntimeName(brand.name);
|
|
50
|
+
const runtimeVersion = `${brand.version}.0.0`;
|
|
51
|
+
return { runtimeName, runtimeVersion };
|
|
52
|
+
};
|
|
53
|
+
const brandNameToRuntimeName = (brandName) => {
|
|
54
|
+
const lower = brandName.toLowerCase();
|
|
55
|
+
if (lower === "google chrome") {
|
|
56
|
+
return "chrome";
|
|
57
|
+
}
|
|
58
|
+
if (lower === "headlesschrome") {
|
|
59
|
+
return "chrome";
|
|
60
|
+
}
|
|
61
|
+
if (lower === "microsoft edge") {
|
|
62
|
+
return "edge";
|
|
63
|
+
}
|
|
64
|
+
if (lower === "opera") {
|
|
65
|
+
return "opera";
|
|
66
|
+
}
|
|
67
|
+
if (lower === "samsung internet") {
|
|
68
|
+
return "samsung";
|
|
69
|
+
}
|
|
70
|
+
if (lower === "chromium") {
|
|
71
|
+
return "chrome";
|
|
72
|
+
}
|
|
73
|
+
// other Chromium-based browsers share Chrome's compatibility
|
|
74
|
+
return "chrome";
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const parseUserAgentHeader = (userAgent) => {
|
|
78
|
+
if (userAgent.includes("node-fetch/")) {
|
|
79
|
+
// it's not really node and conceptually we can't assume the node version
|
|
80
|
+
// but good enough for now
|
|
81
|
+
return {
|
|
82
|
+
runtimeName: "node",
|
|
83
|
+
runtimeVersion: process.version.slice(1),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
// iOS Safari must be checked before Safari (UA contains both)
|
|
87
|
+
if (userAgent.includes("Mobile") && userAgent.includes("Safari")) {
|
|
88
|
+
const iosSafariMatch = userAgent.match(/\bOS (\d+)[._](\d+)(?:[._](\d+))?/);
|
|
89
|
+
if (iosSafariMatch) {
|
|
90
|
+
const major = iosSafariMatch[1];
|
|
91
|
+
const minor = iosSafariMatch[2] || "0";
|
|
92
|
+
const patch = iosSafariMatch[3] || "0";
|
|
93
|
+
return {
|
|
94
|
+
runtimeName: "ios_safari",
|
|
95
|
+
runtimeVersion: `${major}.${minor}.${patch}`,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (!userAgent.includes("Chrome") && userAgent.includes("Safari")) {
|
|
100
|
+
const safariMatch = userAgent.match(/\bVersion\/(\d+)\.(\d+)(?:\.(\d+))?/);
|
|
101
|
+
if (safariMatch) {
|
|
102
|
+
const major = safariMatch[1];
|
|
103
|
+
const minor = safariMatch[2] || "0";
|
|
104
|
+
const patch = safariMatch[3] || "0";
|
|
105
|
+
return {
|
|
106
|
+
runtimeName: "safari",
|
|
107
|
+
runtimeVersion: `${major}.${minor}.${patch}`,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const firefoxMatch = userAgent.match(/\bFirefox\/(\d+)\.(\d+)\b/);
|
|
112
|
+
if (firefoxMatch) {
|
|
113
|
+
const major = firefoxMatch[1];
|
|
114
|
+
const minor = firefoxMatch[2] || "0";
|
|
115
|
+
return { runtimeName: "firefox", runtimeVersion: `${major}.${minor}.0` };
|
|
116
|
+
}
|
|
117
|
+
// generic Chromium-based fallback (should normally be handled by sec-ch-ua)
|
|
118
|
+
const chromeMatch = userAgent.match(
|
|
119
|
+
/(?:HeadlessChrome|Chrome)\/(\d+)\.(\d+)\b/,
|
|
120
|
+
);
|
|
121
|
+
if (chromeMatch) {
|
|
122
|
+
const major = chromeMatch[1];
|
|
123
|
+
const minor = chromeMatch[2] || "0";
|
|
124
|
+
return { runtimeName: "chrome", runtimeVersion: `${major}.${minor}.0` };
|
|
125
|
+
}
|
|
126
|
+
return { runtimeName: "unknown", runtimeVersion: "unknown" };
|
|
127
|
+
};
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { memoizeByFirstArgument } from "@jsenv/utils/src/memoize/memoize_by_first_argument.js";
|
|
2
|
-
|
|
3
|
-
import { requireFromJsenv } from "@jsenv/core/src/helpers/require_from_jsenv.js";
|
|
4
|
-
|
|
5
|
-
export const parseUserAgentHeader = memoizeByFirstArgument((userAgent) => {
|
|
6
|
-
if (userAgent.includes("node-fetch/")) {
|
|
7
|
-
// it's not really node and conceptually we can't assume the node version
|
|
8
|
-
// but good enough for now
|
|
9
|
-
return {
|
|
10
|
-
runtimeName: "node",
|
|
11
|
-
runtimeVersion: process.version.slice(1),
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
const UA = requireFromJsenv("@financial-times/polyfill-useragent-normaliser");
|
|
15
|
-
const { ua } = new UA(userAgent);
|
|
16
|
-
const { family, major, minor, patch } = ua;
|
|
17
|
-
return {
|
|
18
|
-
runtimeName: family.toLowerCase(),
|
|
19
|
-
runtimeVersion:
|
|
20
|
-
family === "Other" ? "unknown" : `${major}.${minor}${patch}`,
|
|
21
|
-
};
|
|
22
|
-
});
|