UNPKG

nstdlib-nightly

Version:

Node.js standard library converted to runtime-agnostic ES modules.

796 lines (706 loc) 26.6 kB
// Source: https://github.com/nodejs/node/blob/65eff1eb/lib/internal/process/pre_execution.js import * as __hoisted_internal_v8_startup_snapshot__ from "nstdlib/lib/internal/v8/startup_snapshot"; import * as __hoisted_internal_modules_helpers__ from "nstdlib/lib/internal/modules/helpers"; import * as __hoisted_path__ from "nstdlib/lib/path"; import * as __hoisted_internal_console_global__ from "nstdlib/lib/internal/console/global"; import * as __hoisted_internal_console_constructor__ from "nstdlib/lib/internal/console/constructor"; import * as __hoisted_internal_process_warning__ from "nstdlib/lib/internal/process/warning"; import * as __hoisted_internal_bootstrap_realm__ from "nstdlib/lib/internal/bootstrap/realm"; import * as __hoisted_internal_event_target__ from "nstdlib/lib/internal/event_target"; import * as __hoisted_internal_watchdog__ from "nstdlib/lib/internal/watchdog"; import * as __hoisted_internal_process_report__ from "nstdlib/lib/internal/process/report"; import * as __hoisted_internal_util_debuglog__ from "nstdlib/lib/internal/util/debuglog"; import * as __hoisted_internal_validators__ from "nstdlib/lib/internal/validators"; import * as __hoisted_v8__ from "nstdlib/lib/v8"; import * as __hoisted_internal_process_per_thread__ from "nstdlib/lib/internal/process/per_thread"; import * as __hoisted_internal_inspector_async_hook__ from "nstdlib/lib/internal/inspector_async_hook"; import * as __hoisted_internal_inspector_network_tracking__ from "nstdlib/lib/internal/inspector_network_tracking"; import * as __hoisted_internal_util__ from "nstdlib/lib/internal/util"; import * as __hoisted_internal_util_types__ from "nstdlib/lib/internal/util/types"; import * as __hoisted_internal_assert__ from "nstdlib/lib/internal/assert"; import * as __hoisted_child_process__ from "nstdlib/lib/child_process"; import * as __hoisted_cluster__ from "nstdlib/lib/cluster"; import * as __hoisted_internal_process_permission__ from "nstdlib/lib/internal/process/permission"; import * as __hoisted_internal_modules_cjs_loader__ from "nstdlib/lib/internal/modules/cjs/loader"; import * as __hoisted_internal_modules_esm_utils__ from "nstdlib/lib/internal/modules/esm/utils"; import * as __hoisted_internal_vm_module__ from "nstdlib/lib/internal/vm/module"; import * as __hoisted_vm__ from "nstdlib/lib/vm"; import * as __hoisted_internal_source_map_source_map_cache__ from "nstdlib/lib/internal/source_map/source_map_cache"; import * as __hoisted_internal_freeze_intrinsics__ from "nstdlib/lib/internal/freeze_intrinsics"; import { getOptionValue, refreshOptions, getEmbedderOptions, } from "nstdlib/lib/internal/options"; import { reconnectZeroFillToggle } from "nstdlib/lib/internal/buffer"; import { exposeInterface, exposeLazyInterfaces, defineReplaceableLazyAttribute, setupCoverageHooks, emitExperimentalWarning, } from "nstdlib/lib/internal/util"; import { codes as __codes__ } from "nstdlib/lib/internal/errors"; import * as assert from "nstdlib/lib/internal/assert"; import { namespace as __namespace__ } from "nstdlib/lib/internal/v8/startup_snapshot"; import * as __hoisted_internal_dns_utils__ from "nstdlib/lib/internal/dns/utils"; const { Intl } = globalThis; const { ERR_INVALID_THIS, ERR_NO_CRYPTO, ERR_MISSING_OPTION, ERR_ACCESS_DENIED, } = __codes__; const { addSerializeCallback, isBuildingSnapshot } = __namespace__; function prepareMainThreadExecution( expandArgv1 = false, initializeModules = true, ) { return prepareExecution({ expandArgv1, initializeModules, isMainThread: true, }); } function prepareWorkerThreadExecution() { prepareExecution({ expandArgv1: false, initializeModules: false, isMainThread: false, }); } function prepareShadowRealmExecution() { // Patch the process object with legacy properties and normalizations. // Do not expand argv1 as it is not available in ShadowRealm. patchProcessObject(false); setupDebugEnv(); // Disable custom loaders in ShadowRealm. setupUserModules(true); const { privateSymbols: { host_defined_option_symbol }, } = require("binding/util"); const { vm_dynamic_import_default_internal } = require("binding/symbols"); // For ShadowRealm.prototype.importValue(), the referrer name is // always null, so the native ImportModuleDynamically() callback would // always fallback to look up the host-defined option from the // global object using host_defined_option_symbol. Using // vm_dynamic_import_default_internal as the host-defined option // instructs the JS-land importModuleDynamicallyCallback() to // proxy the request to defaultImportModuleDynamically(). globalThis[host_defined_option_symbol] = vm_dynamic_import_default_internal; } function prepareExecution(options) { const { expandArgv1, initializeModules, isMainThread } = options; refreshRuntimeOptions(); reconnectZeroFillToggle(); // Patch the process object and get the resolved main entry point. const mainEntry = patchProcessObject(expandArgv1); setupTraceCategoryState(); setupInspectorHooks(); setupNetworkInspection(); setupNavigator(); setupWarningHandler(); setupUndici(); setupWebCrypto(); setupSQLite(); setupWebStorage(); setupCustomEvent(); setupEventsource(); setupCodeCoverage(); setupDebugEnv(); // Process initial diagnostic reporting configuration, if present. initializeReport(); // Load permission system API initializePermission(); initializeSourceMapsHandlers(); initializeDeprecations(); __hoisted_internal_dns_utils__.initializeDns(); setupSymbolDisposePolyfill(); if (isMainThread) { assert(require("binding/worker").isMainThread); // Worker threads will get the manifest in the message handler. // Print stack trace on `SIGINT` if option `--trace-sigint` presents. setupStacktracePrinterOnSigint(); initializeReportSignalHandlers(); // Main-thread-only. initializeHeapSnapshotSignalHandlers(); // If the process is spawned with env NODE_CHANNEL_FD, it's probably // spawned by our child_process module, then initialize IPC. // This attaches some internal event listeners and creates: // process.send(), process.channel, process.connected, // process.disconnect(). setupChildProcessIpcChannel(); // If this is a worker in cluster mode, start up the communication // channel. This needs to be done before any user code gets executed // (including preload modules). initializeClusterIPC(); // TODO(joyeecheung): do this for worker threads as well. __hoisted_internal_v8_startup_snapshot__.runDeserializeCallbacks(); } else { assert(!require("binding/worker").isMainThread); // The setup should be called in LOAD_SCRIPT message handler. assert(!initializeModules); } if (initializeModules) { setupUserModules(); } return mainEntry; } function setupSymbolDisposePolyfill() { // TODO(MoLow): Remove this polyfill once Symbol.dispose and Symbol.asyncDispose are available in V8. // eslint-disable-next-line node-core/prefer-primordials if (typeof Symbol.dispose !== "symbol") { Object.defineProperty(Symbol, "dispose", { __proto__: null, configurable: false, enumerable: false, value: Symbol.for("nodejs.dispose"), writable: false, }); } // eslint-disable-next-line node-core/prefer-primordials if (typeof Symbol.asyncDispose !== "symbol") { Object.defineProperty(Symbol, "asyncDispose", { __proto__: null, configurable: false, enumerable: false, value: Symbol.for("nodejs.asyncDispose"), writable: false, }); } } function setupUserModules(forceDefaultLoader = false) { initializeCJSLoader(); initializeESMLoader(forceDefaultLoader); const { hasStartedUserCJSExecution, hasStartedUserESMExecution } = __hoisted_internal_modules_helpers__; assert(!hasStartedUserCJSExecution()); assert(!hasStartedUserESMExecution()); if (getEmbedderOptions().hasEmbedderPreload) { runEmbedderPreload(); } // Do not enable preload modules if custom loaders are disabled. // For example, loader workers are responsible for doing this themselves. // And preload modules are not supported in ShadowRealm as well. if (!forceDefaultLoader) { loadPreloadModules(); } // Need to be done after --require setup. initializeFrozenIntrinsics(); } function refreshRuntimeOptions() { refreshOptions(); } /** * Patch the process object with legacy properties and normalizations. * Replace `process.argv[0]` with `process.execPath`, preserving the original `argv[0]` value as `process.argv0`. * Replace `process.argv[1]` with the resolved absolute file path of the entry point, if found. * @param {boolean} expandArgv1 - Whether to replace `process.argv[1]` with the resolved absolute file path of * the main entry point. */ function patchProcessObject(expandArgv1) { const binding = require("binding/process_methods"); binding.patchProcessObject(process); // Since we replace process.argv[0] below, preserve the original value in case the user needs it. Object.defineProperty(process, "argv0", { __proto__: null, enumerable: true, // Only set it to true during snapshot building. configurable: isBuildingSnapshot(), value: process.argv[0], }); process.exitCode = undefined; process._exiting = false; process.argv[0] = process.execPath; /** @type {string} */ let mainEntry; // If requested, update process.argv[1] to replace whatever the user provided with the resolved absolute file path of // the entry point. if ( expandArgv1 && process.argv[1] && !String.prototype.startsWith.call(process.argv[1], "-") ) { // Expand process.argv[1] into a full path. const path = __hoisted_path__; try { mainEntry = path.resolve(process.argv[1]); process.argv[1] = mainEntry; } catch { // Continue regardless of error. } } // We need to initialize the global console here again with process.stdout // and friends for snapshot deserialization. const globalConsole = __hoisted_internal_console_global__; const { initializeGlobalConsole } = __hoisted_internal_console_constructor__; initializeGlobalConsole(globalConsole); // TODO(joyeecheung): most of these should be deprecated and removed, // except some that we need to be able to mutate during run time. addReadOnlyProcessAlias("_eval", "--eval"); addReadOnlyProcessAlias("_print_eval", "--print"); addReadOnlyProcessAlias("_syntax_check_only", "--check"); addReadOnlyProcessAlias("_forceRepl", "--interactive"); addReadOnlyProcessAlias("_preload_modules", "--require"); addReadOnlyProcessAlias("noDeprecation", "--no-deprecation"); addReadOnlyProcessAlias("noProcessWarnings", "--no-warnings"); addReadOnlyProcessAlias("traceProcessWarnings", "--trace-warnings"); addReadOnlyProcessAlias("throwDeprecation", "--throw-deprecation"); addReadOnlyProcessAlias("profProcess", "--prof-process"); addReadOnlyProcessAlias("traceDeprecation", "--trace-deprecation"); addReadOnlyProcessAlias("_breakFirstLine", "--inspect-brk", false); addReadOnlyProcessAlias("_breakNodeFirstLine", "--inspect-brk-node", false); return mainEntry; } function addReadOnlyProcessAlias(name, option, enumerable = true) { const value = getOptionValue(option); if (value) { Object.defineProperty(process, name, { __proto__: null, writable: false, configurable: true, enumerable, value, }); } } function setupWarningHandler() { const { onWarning, resetForSerialization } = __hoisted_internal_process_warning__; if (getOptionValue("--warnings") && process.env.NODE_NO_WARNINGS !== "1") { process.on("warning", onWarning); // The code above would add the listener back during deserialization, // if applicable. if (isBuildingSnapshot()) { addSerializeCallback(() => { process.removeListener("warning", onWarning); resetForSerialization(); }); } } } // https://fetch.spec.whatwg.org/ // https://websockets.spec.whatwg.org/ function setupUndici() { if (getOptionValue("--no-experimental-fetch")) { delete globalThis.fetch; delete globalThis.FormData; delete globalThis.Headers; delete globalThis.Request; delete globalThis.Response; } if (getOptionValue("--no-experimental-websocket")) { delete globalThis.WebSocket; } } // https://html.spec.whatwg.org/multipage/server-sent-events.html function setupEventsource() { if (!getOptionValue("--experimental-eventsource")) { delete globalThis.EventSource; } } // TODO(aduh95): move this to internal/bootstrap/web/* when the CLI flag is // removed. function setupNavigator() { if ( getEmbedderOptions().noBrowserGlobals || getOptionValue("--no-experimental-global-navigator") ) { return; } // https://html.spec.whatwg.org/multipage/system-state.html#the-navigator-object exposeLazyInterfaces(globalThis, "internal/navigator", ["Navigator"]); require("binding/config").language = Intl?.Collator().resolvedOptions().locale || "en-US"; defineReplaceableLazyAttribute( globalThis, "internal/navigator", ["navigator"], false, ); } // TODO(aduh95): move this to internal/bootstrap/web/* when the CLI flag is // removed. function setupWebCrypto() { if ( getEmbedderOptions().noBrowserGlobals || getOptionValue("--no-experimental-global-webcrypto") ) { return; } if (require("binding/config").hasOpenSSL) { defineReplaceableLazyAttribute( globalThis, "internal/crypto/webcrypto", ["crypto"], false, function cryptoThisCheck() { if (this !== globalThis && this != null) throw new ERR_INVALID_THIS("nullish or must be the global object"); }, ); exposeLazyInterfaces(globalThis, "internal/crypto/webcrypto", [ "Crypto", "CryptoKey", "SubtleCrypto", ]); } else { Object.defineProperty(globalThis, "crypto", { __proto__: null, ...Object.getOwnPropertyDescriptor( { get crypto() { throw new ERR_NO_CRYPTO(); }, }, "crypto", ), }); } } function setupSQLite() { if (!getOptionValue("--experimental-sqlite")) { return; } const { BuiltinModule } = __hoisted_internal_bootstrap_realm__; BuiltinModule.allowRequireByUsers("sqlite"); } function setupWebStorage() { if ( getEmbedderOptions().noBrowserGlobals || !getOptionValue("--experimental-webstorage") ) { return; } // https://html.spec.whatwg.org/multipage/webstorage.html#webstorage exposeLazyInterfaces(globalThis, "internal/webstorage", ["Storage"]); defineReplaceableLazyAttribute(globalThis, "internal/webstorage", [ "localStorage", "sessionStorage", ]); } function setupCodeCoverage() { // Resolve the coverage directory to an absolute path, and // overwrite process.env so that the original path gets passed // to child processes even when they switch cwd. Don't do anything if the // --experimental-test-coverage flag is present, as the test runner will // handle coverage. if ( process.env.NODE_V8_COVERAGE && !getOptionValue("--experimental-test-coverage") ) { process.env.NODE_V8_COVERAGE = setupCoverageHooks( process.env.NODE_V8_COVERAGE, ); } } // TODO(daeyeon): move this to internal/bootstrap/web/* when the CLI flag is // removed. function setupCustomEvent() { if ( getEmbedderOptions().noBrowserGlobals || getOptionValue("--no-experimental-global-customevent") ) { return; } const { CustomEvent } = __hoisted_internal_event_target__; exposeInterface(globalThis, "CustomEvent", CustomEvent); } function setupStacktracePrinterOnSigint() { if (!getOptionValue("--trace-sigint")) { return; } const { SigintWatchdog } = __hoisted_internal_watchdog__; const watchdog = new SigintWatchdog(); watchdog.start(); } function initializeReport() { Object.defineProperty(process, "report", { __proto__: null, enumerable: true, configurable: true, get() { const { report } = __hoisted_internal_process_report__; return report; }, }); } function setupDebugEnv() { __hoisted_internal_util_debuglog__.initializeDebugEnv(process.env.NODE_DEBUG); if (getOptionValue("--expose-internals")) { __hoisted_internal_bootstrap_realm__.BuiltinModule.exposeInternals(); } } // This has to be called after initializeReport() is called function initializeReportSignalHandlers() { if (getOptionValue("--report-on-signal")) { const { addSignalHandler } = __hoisted_internal_process_report__; addSignalHandler(); } } function initializeHeapSnapshotSignalHandlers() { const signal = getOptionValue("--heapsnapshot-signal"); const diagnosticDir = getOptionValue("--diagnostic-dir"); if (!signal) return; __hoisted_internal_validators__.validateSignalName(signal); const { writeHeapSnapshot } = __hoisted_v8__; function doWriteHeapSnapshot() { const heapSnapshotFilename = getHeapSnapshotFilename(diagnosticDir); writeHeapSnapshot(heapSnapshotFilename); } process.on(signal, doWriteHeapSnapshot); // The code above would add the listener back during deserialization, // if applicable. if (isBuildingSnapshot()) { addSerializeCallback(() => { process.removeListener(signal, doWriteHeapSnapshot); }); } } function setupTraceCategoryState() { const { isTraceCategoryEnabled } = require("binding/trace_events"); const { toggleTraceCategoryState } = __hoisted_internal_process_per_thread__; toggleTraceCategoryState(isTraceCategoryEnabled("node.async_hooks")); } function setupInspectorHooks() { // If Debugger.setAsyncCallStackDepth is sent during bootstrap, // we cannot immediately call into JS to enable the hooks, which could // interrupt the JS execution of bootstrap. So instead we save the // notification in the inspector agent if it's sent in the middle of // bootstrap, and process the notification later here. if (require("binding/config").hasInspector) { const { enable, disable } = __hoisted_internal_inspector_async_hook__; require("binding/inspector").registerAsyncHook(enable, disable); } } function setupNetworkInspection() { if ( require("binding/config").hasInspector && getOptionValue("--experimental-network-inspection") ) { const { enable, disable } = __hoisted_internal_inspector_network_tracking__; require("binding/inspector").setupNetworkTracking(enable, disable); } } // In general deprecations are initialized wherever the APIs are implemented, // this is used to deprecate APIs implemented in C++ where the deprecation // utilities are not easily accessible. function initializeDeprecations() { const { deprecate } = __hoisted_internal_util__; const pendingDeprecation = getOptionValue("--pending-deprecation"); // DEP0103: access to `process.binding('util').isX` type checkers // TODO(addaleax): Turn into a full runtime deprecation. const utilBinding = require("binding/util"); const types = __hoisted_internal_util_types__; for (const name of [ "isArrayBuffer", "isArrayBufferView", "isAsyncFunction", "isDataView", "isDate", "isExternal", "isMap", "isMapIterator", "isNativeError", "isPromise", "isRegExp", "isSet", "isSetIterator", "isTypedArray", "isUint8Array", "isAnyArrayBuffer", ]) { utilBinding[name] = pendingDeprecation ? deprecate( types[name], "Accessing native typechecking bindings of Node " + "directly is deprecated. " + `Please use \`util.types.${name}\` instead.`, "DEP0103", ) : types[name]; } // TODO(joyeecheung): this is a legacy property exposed to process. // Now that we use the config binding to carry this information, remove // it from the process. We may consider exposing it properly in // process.features. const { noBrowserGlobals } = require("binding/config"); if (noBrowserGlobals) { Object.defineProperty(process, "_noBrowserGlobals", { __proto__: null, writable: false, enumerable: true, configurable: true, value: noBrowserGlobals, }); } if (pendingDeprecation) { process.binding = deprecate( process.binding, "process.binding() is deprecated. " + "Please use public APIs instead.", "DEP0111", ); process._tickCallback = deprecate( process._tickCallback, "process._tickCallback() is deprecated", "DEP0134", ); } } function setupChildProcessIpcChannel() { if (process.env.NODE_CHANNEL_FD) { const assert = __hoisted_internal_assert__; const fd = Number.parseInt(process.env.NODE_CHANNEL_FD, 10); assert(fd >= 0); // Make sure it's not accidentally inherited by child processes. delete process.env.NODE_CHANNEL_FD; const serializationMode = process.env.NODE_CHANNEL_SERIALIZATION_MODE || "json"; delete process.env.NODE_CHANNEL_SERIALIZATION_MODE; __hoisted_child_process__._forkChild(fd, serializationMode); assert(process.send); } } function initializeClusterIPC() { if (process.argv[1] && process.env.NODE_UNIQUE_ID) { const cluster = __hoisted_cluster__; cluster._setupWorker(); // Make sure it's not accidentally inherited by child processes. delete process.env.NODE_UNIQUE_ID; } } function initializePermission() { const experimentalPermission = getOptionValue("--experimental-permission"); if (experimentalPermission) { process.binding = function binding(_module) { throw new ERR_ACCESS_DENIED("process.binding"); }; // Guarantee path module isn't monkey-patched to bypass permission model Object.freeze(__hoisted_path__); emitExperimentalWarning("Permission"); const { has } = __hoisted_internal_process_permission__; const warnFlags = [ "--allow-addons", "--allow-child-process", "--allow-wasi", "--allow-worker", ]; for (const flag of warnFlags) { if (getOptionValue(flag)) { process.emitWarning( `The flag ${flag} must be used with extreme caution. ` + "It could invalidate the permission model.", "SecurityWarning", ); } } const warnCommaFlags = ["--allow-fs-read", "--allow-fs-write"]; for (const flag of warnCommaFlags) { const value = getOptionValue(flag); if (value.length === 1 && value[0].includes(",")) { process.emitWarning( `The ${flag} CLI flag has changed. ` + "Passing a comma-separated list of paths is no longer valid. " + "Documentation can be found at " + "https://nodejs.org/api/permissions.html#file-system-permissions", "Warning", ); } } Object.defineProperty(process, "permission", { __proto__: null, enumerable: true, configurable: false, value: { has, }, }); } else { const availablePermissionFlags = [ "--allow-fs-read", "--allow-fs-write", "--allow-addons", "--allow-child-process", "--allow-wasi", "--allow-worker", ]; Array.prototype.forEach.call(availablePermissionFlags, (flag) => { const value = getOptionValue(flag); if (value.length) { throw new ERR_MISSING_OPTION("--experimental-permission"); } }); } } function initializeCJSLoader() { const { initializeCJS } = __hoisted_internal_modules_cjs_loader__; initializeCJS(); } function initializeESMLoader(forceDefaultLoader) { const { initializeESM } = __hoisted_internal_modules_esm_utils__; initializeESM(forceDefaultLoader); // Patch the vm module when --experimental-vm-modules is on. // Please update the comments in vm.js when this block changes. if (getOptionValue("--experimental-vm-modules")) { const { Module, SourceTextModule, SyntheticModule } = __hoisted_internal_vm_module__; const vm = __hoisted_vm__; vm.Module = Module; vm.SourceTextModule = SourceTextModule; vm.SyntheticModule = SyntheticModule; } } function initializeSourceMapsHandlers() { const { setSourceMapsEnabled } = __hoisted_internal_source_map_source_map_cache__; setSourceMapsEnabled(getOptionValue("--enable-source-maps")); } function initializeFrozenIntrinsics() { if (getOptionValue("--frozen-intrinsics")) { emitExperimentalWarning("Frozen intristics"); __hoisted_internal_freeze_intrinsics__(); } } function runEmbedderPreload() { require("binding/mksnapshot").runEmbedderPreload(process, require); } function loadPreloadModules() { // For user code, we preload modules if `-r` is passed const preloadModules = getOptionValue("--require"); if (preloadModules && preloadModules.length > 0) { const { Module: { _preloadModules }, } = __hoisted_internal_modules_cjs_loader__; _preloadModules(preloadModules); } } function markBootstrapComplete() { require("binding/performance").markBootstrapComplete(); } // Sequence number for diagnostic filenames let sequenceNumOfheapSnapshot = 0; // To generate the HeapSnapshotFilename while using custom diagnosticDir function getHeapSnapshotFilename(diagnosticDir) { if (!diagnosticDir) return undefined; const date = new Date(); const year = Date.prototype.getFullYear.call(date); const month = String(Date.prototype.getMonth.call(date) + 1).padStart(2, "0"); const day = String(Date.prototype.getDate.call(date)).padStart(2, "0"); const hours = String(Date.prototype.getHours.call(date)).padStart(2, "0"); const minutes = String(Date.prototype.getMinutes.call(date)).padStart(2, "0"); const seconds = String(Date.prototype.getSeconds.call(date)).padStart(2, "0"); const dateString = `${year}${month}${day}`; const timeString = `${hours}${minutes}${seconds}`; const pid = process.pid; const threadId = require("binding/worker").threadId; const fileSequence = (++sequenceNumOfheapSnapshot) .toString() .padStart(3, "0"); return `${diagnosticDir}/Heap.${dateString}.${timeString}.${pid}.${threadId}.${fileSequence}.heapsnapshot`; } export { setupUserModules }; export { prepareMainThreadExecution }; export { prepareWorkerThreadExecution }; export { prepareShadowRealmExecution }; export { markBootstrapComplete }; export { loadPreloadModules }; export { initializeFrozenIntrinsics };