@docusaurus/core 3.10.1 → 3.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -53,7 +53,7 @@ function insertBanner() {
53
53
  var suggestedBaseUrl = actualHomePagePath.substr(-1) === '/'
54
54
  ? actualHomePagePath
55
55
  : actualHomePagePath + '/';
56
- suggestionContainer.innerHTML = suggestedBaseUrl;
56
+ suggestionContainer.textContent = suggestedBaseUrl;
57
57
  }
58
58
  `;
59
59
  }
@@ -109,6 +109,21 @@ async function createCLIProgram({ cli, cliArgs, siteDir, config, }) {
109
109
  .option('--no-open', 'do not open page in the browser (default: false)')
110
110
  .option('--poll [interval]', 'use polling rather than watching for reload (default: false). Can specify a poll interval in milliseconds', normalizePollValue)
111
111
  .option('--no-minify', 'build website without minimizing JS bundles (default: false)')
112
+ /*
113
+ TODO
114
+ .option(
115
+ '--https',
116
+ 'serve the dev site over HTTPS using a self-signed cert (default: false). Preferred over the HTTPS=true env var. Implied when both --ssl-cert and --ssl-key are provided.',
117
+ )
118
+ .option(
119
+ '--ssl-cert <path>',
120
+ 'path to a TLS certificate file (implies HTTPS). Preferred over the SSL_CRT_FILE env var; CLI takes precedence if both are set.',
121
+ )
122
+ .option(
123
+ '--ssl-key <path>',
124
+ 'path to a TLS private key file (implies HTTPS). Preferred over the SSL_KEY_FILE env var; CLI takes precedence if both are set.',
125
+ )
126
+ */
112
127
  .action(start_1.start);
113
128
  cli
114
129
  .command('serve [siteDir]')
@@ -19,6 +19,7 @@ const openBrowser_1 = tslib_1.__importDefault(require("./utils/openBrowser/openB
19
19
  const config_1 = require("../server/config");
20
20
  const build_1 = require("./build/build");
21
21
  const getHostPort_1 = require("../server/getHostPort");
22
+ const listenToServer_1 = require("./utils/listenToServer");
22
23
  function redirect(res, location) {
23
24
  res.writeHead(302, {
24
25
  Location: location,
@@ -84,7 +85,7 @@ async function serve(siteDirParam = '.', cliOptions = {}) {
84
85
  });
85
86
  const url = servingUrl + baseUrl;
86
87
  logger_1.default.success `Serving path=${buildDir} directory at: url=${url}`;
87
- server.listen(port);
88
+ await (0, listenToServer_1.listenToServer)({ server, host, port });
88
89
  if (cliOptions.open && !process.env.CI) {
89
90
  await (0, openBrowser_1.default)(url);
90
91
  }
@@ -41,7 +41,15 @@ function registerWebpackE2ETestHook(compiler) {
41
41
  async function createDevServerConfig({ cliOptions, props, host, port, }) {
42
42
  const { baseUrl, siteDir, siteConfig } = props;
43
43
  const pollingOptions = (0, watcher_1.createPollingOptions)(cliOptions);
44
- const httpsConfig = await (0, getHttpsConfig_1.default)();
44
+ const httpsConfig = await (0, getHttpsConfig_1.default)({
45
+ /*
46
+ TODO Docusaurus v4: wire new CLI parameters
47
+ https: cliOptions.https,
48
+ sslCert: cliOptions.sslCert,
49
+ sslKey: cliOptions.sslKey,
50
+
51
+ */
52
+ });
45
53
  // https://webpack.js.org/configuration/dev-server
46
54
  return {
47
55
  hot: cliOptions.hotOnly ? 'only' : true,
@@ -0,0 +1,5 @@
1
+ export declare function listenToServer({ server, port, host, }: {
2
+ server: import('node:http').Server;
3
+ port: number;
4
+ host: string;
5
+ }): Promise<void>;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.listenToServer = listenToServer;
4
+ /**
5
+ * Copyright (c) Facebook, Inc. and its affiliates.
6
+ *
7
+ * This source code is licensed under the MIT license found in the
8
+ * LICENSE file in the root directory of this source tree.
9
+ */
10
+ const logger_1 = require("@docusaurus/logger");
11
+ async function listenToServer({ server, port, host, }) {
12
+ return new Promise((resolve, reject) => {
13
+ server.once('listening', () => resolve());
14
+ server.once('error', (err) => {
15
+ if (err.code === 'EADDRINUSE') {
16
+ reject(new Error(logger_1.logger.interpolate `Address in use, another server is already listening on the requested port number=${port} and host name=${host}`, { cause: err }));
17
+ }
18
+ else {
19
+ reject(err);
20
+ }
21
+ });
22
+ server.listen(port, host);
23
+ });
24
+ }
@@ -352,7 +352,7 @@ exports.ConfigSchema = utils_validation_1.Joi.object({
352
352
  is: utils_validation_1.Joi.valid(true),
353
353
  then: utils_validation_1.Joi.optional(),
354
354
  otherwise: utils_validation_1.Joi.object()
355
- .pattern(/[\w-]+/, utils_validation_1.Joi.string())
355
+ .pattern(/[\w-]+/, utils_validation_1.Joi.alternatives().try(utils_validation_1.Joi.string(), utils_validation_1.Joi.boolean()))
356
356
  .required(),
357
357
  }),
358
358
  customElement: utils_validation_1.Joi.bool().default(false),
@@ -69,8 +69,7 @@ Would you like to run the app on another port instead?`),
69
69
  return shouldChangePort ? port : null;
70
70
  }
71
71
  catch (err) {
72
- logger_1.default.error `Could not find an open port at ${host}.`;
73
- throw err;
72
+ throw new Error(logger_1.default.interpolate `Could not find an open port at ${host}.`, { cause: err });
74
73
  }
75
74
  }
76
75
  async function getHostPort(options) {
@@ -78,6 +78,7 @@ async function loadContext(params) {
78
78
  const localizationDir = path_1.default.resolve(siteDir, i18n.path, (0, utils_1.getLocaleConfig)(i18n).path);
79
79
  const siteConfig = {
80
80
  ...initialSiteConfig,
81
+ url: localeConfig.url,
81
82
  baseUrl,
82
83
  };
83
84
  const codeTranslations = await (0, translations_1.loadSiteCodeTranslations)({ localizationDir });
@@ -4,7 +4,13 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
- export default function getHttpsConfig(): Promise<boolean | {
7
+ type HttpsConfigOptions = {
8
+ https: boolean;
9
+ sslCert: string;
10
+ sslKey: string;
11
+ };
12
+ export default function getHttpsConfig(options?: Partial<HttpsConfigOptions>): Promise<boolean | {
8
13
  cert: Buffer;
9
14
  key: Buffer;
10
15
  }>;
16
+ export {};
@@ -13,48 +13,109 @@ const path_1 = tslib_1.__importDefault(require("path"));
13
13
  const crypto_1 = tslib_1.__importDefault(require("crypto"));
14
14
  const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
15
15
  // Ensure the certificate and key provided are valid and if not
16
- // throw an easy to debug error
17
- function validateKeyAndCerts({ cert, key, keyFile, crtFile, }) {
18
- let encrypted;
16
+ // throw an easy to debug error.
17
+ //
18
+ // Works for any key type (RSA, ECDSA, EdDSA, ...) — parses both PEMs and
19
+ // checks that the public key embedded in the cert matches the public key
20
+ // derived from the private key.
21
+ function validateKeyAndCerts({ cert, key }) {
22
+ let certPublicKey;
19
23
  try {
20
- // publicEncrypt will throw an error with an invalid cert
21
- encrypted = crypto_1.default.publicEncrypt(cert, Buffer.from('test'));
24
+ certPublicKey = new crypto_1.default.X509Certificate(cert.content).publicKey;
22
25
  }
23
- catch (err) {
24
- logger_1.default.error `The certificate path=${crtFile} is invalid.`;
25
- throw err;
26
+ catch (error) {
27
+ throw new Error(logger_1.default.interpolate `The certificate path=${cert.path} is invalid.`, { cause: error });
26
28
  }
29
+ let keyPublicKey;
27
30
  try {
28
- // privateDecrypt will throw an error with an invalid key
29
- crypto_1.default.privateDecrypt(key, encrypted);
31
+ keyPublicKey = crypto_1.default.createPublicKey(crypto_1.default.createPrivateKey(key.content));
30
32
  }
31
- catch (err) {
32
- logger_1.default.error `The certificate key path=${keyFile} is invalid.`;
33
- throw err;
33
+ catch (error) {
34
+ throw new Error(logger_1.default.interpolate `The certificate key path=${key.path} is invalid.`, { cause: error });
34
35
  }
36
+ if (!certPublicKey.equals(keyPublicKey)) {
37
+ throw new Error(logger_1.default.interpolate `The certificate path=${cert.path} and key path=${key.path} do not match.`);
38
+ }
39
+ }
40
+ function getExplicitHttps(options) {
41
+ return (options.https ??
42
+ (typeof process.env.DOCUSAURUS_HTTPS !== 'undefined'
43
+ ? process.env.DOCUSAURUS_HTTPS === 'true'
44
+ : undefined) ??
45
+ (typeof process.env.HTTPS !== 'undefined'
46
+ ? process.env.HTTPS === 'true'
47
+ : undefined));
48
+ }
49
+ async function readCryptoFile(filepath, source) {
50
+ if (!(await fs_extra_1.default.pathExists(filepath))) {
51
+ throw new Error(logger_1.default.interpolate `You specified ${source}, but file at path path=${filepath} can't be found.`);
52
+ }
53
+ try {
54
+ return {
55
+ path: filepath,
56
+ source,
57
+ content: await fs_extra_1.default.readFile(filepath),
58
+ };
59
+ }
60
+ catch (error) {
61
+ throw new Error(logger_1.default.interpolate `You specified ${source}, but file at path path=${filepath} can't be read.`, { cause: error });
62
+ }
63
+ }
64
+ function getCert(options, cwd) {
65
+ if (options.sslCert) {
66
+ return readCryptoFile(path_1.default.resolve(cwd, options.sslCert), 'CLI arg --ssl-cert');
67
+ }
68
+ if (process.env.DOCUSAURUS_SSL_CRT_FILE) {
69
+ return readCryptoFile(path_1.default.resolve(cwd, process.env.DOCUSAURUS_SSL_CRT_FILE), 'env DOCUSAURUS_SSL_CRT_FILE');
70
+ }
71
+ if (process.env.SSL_CRT_FILE) {
72
+ return readCryptoFile(path_1.default.resolve(cwd, process.env.SSL_CRT_FILE), 'env SSL_CRT_FILE');
73
+ }
74
+ return null;
75
+ }
76
+ function getKeyFile(options, cwd) {
77
+ if (options.sslKey) {
78
+ return readCryptoFile(path_1.default.resolve(cwd, options.sslKey), 'CLI arg --ssl-key');
79
+ }
80
+ if (process.env.DOCUSAURUS_SSL_KEY_FILE) {
81
+ return readCryptoFile(path_1.default.resolve(cwd, process.env.DOCUSAURUS_SSL_KEY_FILE), 'env DOCUSAURUS_SSL_KEY_FILE');
82
+ }
83
+ if (process.env.SSL_KEY_FILE) {
84
+ return readCryptoFile(path_1.default.resolve(cwd, process.env.SSL_KEY_FILE), 'env SSL_KEY_FILE');
85
+ }
86
+ return null;
35
87
  }
36
- // Read file and throw an error if it doesn't exist
37
- async function readEnvFile(file, type) {
38
- if (!(await fs_extra_1.default.pathExists(file))) {
39
- throw new Error(`You specified ${type} in your env, but the file "${file}" can't be found.`);
88
+ function ensureCertKeyBothProvided(cert, key) {
89
+ if ((cert || key) && !(cert && key)) {
90
+ const fileProvided = (cert ?? key);
91
+ throw new Error(logger_1.default.interpolate `HTTPS support require proving a certificate and key at the same time.
92
+ You only provided a ${cert ? 'certificate' : 'key'} (with ${fileProvided.source}) at path path=${fileProvided.path}.`);
40
93
  }
41
- return fs_extra_1.default.readFile(file);
42
94
  }
43
95
  // Get the https config
44
- // Return cert files if provided in env, otherwise just true or false
45
- async function getHttpsConfig() {
46
- const appDirectory = await fs_extra_1.default.realpath(process.cwd());
47
- const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env;
48
- const isHttps = HTTPS === 'true';
49
- if (isHttps && SSL_CRT_FILE && SSL_KEY_FILE) {
50
- const crtFile = path_1.default.resolve(appDirectory, SSL_CRT_FILE);
51
- const keyFile = path_1.default.resolve(appDirectory, SSL_KEY_FILE);
52
- const config = {
53
- cert: await readEnvFile(crtFile, 'SSL_CRT_FILE'),
54
- key: await readEnvFile(keyFile, 'SSL_KEY_FILE'),
96
+ // Return cert files if provided via CLI or env, otherwise just true or false.
97
+ // CLI options take precedence over env vars.
98
+ async function getHttpsConfig(options = {}) {
99
+ const cwd = await fs_extra_1.default.realpath(process.cwd());
100
+ const [cert, key] = await Promise.all([
101
+ getCert(options, cwd),
102
+ getKeyFile(options, cwd),
103
+ ]);
104
+ // Providing both cert/key implies HTTPS
105
+ const inferredHttps = !!(cert && key);
106
+ const https = getExplicitHttps(options) ?? inferredHttps;
107
+ if (https && cert && key) {
108
+ validateKeyAndCerts({
109
+ cert,
110
+ key,
111
+ });
112
+ return {
113
+ cert: cert.content,
114
+ key: key.content,
55
115
  };
56
- validateKeyAndCerts({ ...config, keyFile, crtFile });
57
- return config;
58
116
  }
59
- return isHttps;
117
+ ensureCertKeyBothProvided(cert, key);
118
+ // Apparently we can have https without cert/key (historical)
119
+ // although I don't know how this works 🤷‍♂️
120
+ return https;
60
121
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@docusaurus/core",
3
3
  "description": "Easy to Maintain Open Source Documentation Websites",
4
- "version": "3.10.1",
4
+ "version": "3.10.2",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
7
7
  "access": "public"
@@ -33,13 +33,13 @@
33
33
  "url": "https://github.com/facebook/docusaurus/issues"
34
34
  },
35
35
  "dependencies": {
36
- "@docusaurus/babel": "3.10.1",
37
- "@docusaurus/bundler": "3.10.1",
38
- "@docusaurus/logger": "3.10.1",
39
- "@docusaurus/mdx-loader": "3.10.1",
40
- "@docusaurus/utils": "3.10.1",
41
- "@docusaurus/utils-common": "3.10.1",
42
- "@docusaurus/utils-validation": "3.10.1",
36
+ "@docusaurus/babel": "3.10.2",
37
+ "@docusaurus/bundler": "3.10.2",
38
+ "@docusaurus/logger": "3.10.2",
39
+ "@docusaurus/mdx-loader": "3.10.2",
40
+ "@docusaurus/utils": "3.10.2",
41
+ "@docusaurus/utils-common": "3.10.2",
42
+ "@docusaurus/utils-validation": "3.10.2",
43
43
  "boxen": "^6.2.1",
44
44
  "chalk": "^4.1.2",
45
45
  "chokidar": "^3.5.3",
@@ -47,7 +47,7 @@
47
47
  "combine-promises": "^1.1.0",
48
48
  "commander": "^5.1.0",
49
49
  "core-js": "^3.31.1",
50
- "detect-port": "^1.5.1",
50
+ "detect-port": "^2.1.0",
51
51
  "escape-html": "^1.0.3",
52
52
  "eta": "^2.2.0",
53
53
  "eval": "^0.1.8",
@@ -77,10 +77,9 @@
77
77
  "webpack-merge": "^6.0.1"
78
78
  },
79
79
  "devDependencies": {
80
- "@docusaurus/module-type-aliases": "3.10.1",
81
- "@docusaurus/types": "3.10.1",
80
+ "@docusaurus/module-type-aliases": "3.10.2",
81
+ "@docusaurus/types": "3.10.2",
82
82
  "@total-typescript/shoehorn": "^0.1.2",
83
- "@types/detect-port": "^1.3.3",
84
83
  "@types/react-dom": "^19.2.3",
85
84
  "@types/react-router-config": "^5.0.7",
86
85
  "@types/serve-handler": "^6.1.4",
@@ -104,5 +103,5 @@
104
103
  "engines": {
105
104
  "node": ">=20.0"
106
105
  },
107
- "gitHead": "41c1a458ecb07d61b6df2761ea4bc1b13db49d12"
106
+ "gitHead": "f37f9035584917a97a260b91fc2842cba4f8b94f"
108
107
  }