denoland/deno
Input boundaries are argv (parsed into `Flags` by the const-table parser), environment variables and `.env` files, config files (`deno.json`/`package.json`) discovered through the workspace factory, and remote sources fetched over HTTP from JSR and npm registries. `CliFactory` owns the service graph; `ModuleGraphBuilder` builds a `deno_graph::ModuleGraph` from roots, `TypeChecker` optionally validates it against a TSC-backed cache, and `CliEmitter` transpiles TypeScript to JavaScript. At runtime, `CliModuleLoader::load` serves module source out of the prepared graph (or delegates to JS load hooks, or to an eszip), and V8 executes it. Every side-effecting op re-enters Rust through `PermissionsContainer`, which is the single state owner for capability decisions. Output boundaries are stdout/stderr (via `deno_print`/`DrawThread`), the DENO_DIR SQLite and HTTP caches, the lockfile, OpenTelemetry exporters, and for `compile`, a written executable.
- argv → `Flags` happens in `resolve_flags_and_init`, which special-cases the `COMPLETE` env var for shell completions, distinguishes `--version` from `-V` before parsing, and only then calls `flags_from_vec_with_initial_cwd`.
- `.env` files are loaded into the process environment before any service construction: `load_env_variables_from_env_files(&cwd, files, flags.log_level)` runs right after flag parsing, and `WatchEnvTracker::snapshot()` captures pre-load state when `--watch` is active.
- Unstable feature configuration is merged from three sources in order: CLI flags, `flags.unstable_config.fill_with_env(&sys)`, and the `DENO_COMPAT` env var which force-enables node compat; `DENO_CONDITIONS` similarly seeds `flags.node_conditions`.
- Module loading is two-phase: `ModuleLoadPreparer::prepare_module_load` builds the graph with npm resolution (`build_graph_roots_with_npm_resolution`), validates roots, runs `TypeChecker::check` only when `type_check_mode().is_true()` and the graph wasn't already checked, then writes the lockfile *after* type checking because checking can discover `@types/node`.
- `CliModuleLoader::load` has three source paths in priority order: an eszip loader when `maybe_eszip_loader` is set, the JS module-hook bridge (`hook_registry.push_load`) for async non-CJS loads, and otherwise the prepared graph; it records every specifier into `loaded_files` for watch-mode invalidation.
- The load-hook bridge deliberately skips CJS modules because `Module._load` already runs `executeLoadHookChain` synchronously — going through both would invoke user hooks twice.
- Remote source fetching flows through `CliFileFetcher`, which takes a `FetchPermissionsOptionRef` per call; `deploy` explicitly passes `AllowAll` plus `CacheSetting::RespectHeaders` so jsr.io's `cache-control: max-age=60` is honoured instead of pinning the first cached copy forever.
- npm resolution mode determines the read-permission checker: `create_module_loader_factory` picks `NpmRegistryReadPermissionCheckerMode::Byonm`, `::Local(node_modules_dir)`, or `::Global(npm_cache_root)` before constructing `CliModuleLoaderFactory`.
- The root permission set is derived once from config+flags: `CliFactory::root_permissions_container` builds `Permissions::from_options(desc_parser, cli_options.permissions_options()?)` and wraps it in a `PermissionsContainer` that all workers clone from.
- Worker construction pre-installs npm packages: `create_custom_worker` collects `NpmPackageReqReference`s from the main module plus preload/require modules and calls `npm_installer.add_package_reqs` with `PackageCaching::Only` under the Lazy strategy or `PackageCaching::All` otherwise.
- For an `npm:` main module, the specifier is rewritten to a resolved bin entrypoint via `resolve_npm_binary_entrypoint`, and the lockfile is flushed with `write_if_changed()` so the next run can reuse the resolution.
- Bootstrap data crosses the Rust→JS boundary as a positional array: `bootstrapMainRuntime(runtimeOptions)` destructures indices 0–19 (denoVersion, location, unstableFeatures, hasNodeModulesDir, argv0, nodeDebug, mode, servePort, serveHost, otelConfig, standalone, nodeClusterUniqueId, …) and then removes the bootstrap object from the global scope.
- Telemetry is initialised before any subcommand runs: `deno_telemetry::init(&sys, otel_runtime_config(), otel_config)` is called from `resolve_flags_and_init`, and failure paths report through `deno_telemetry::report_event("boot_failure" | "uncaught_exception", e)` in `run_script`.
- Permission decisions can be teed to an audit sink: `DENO_AUDIT_PERMISSIONS=otel` routes each access through `deno_telemetry::handle_log` with `deno.permission.{type,value,stack}` key-values, and any other value is treated as a file path opened with `File::create`.
- `deno run -` reads stdin fully into memory and injects it as a synthetic file via `file_fetcher.insert_memory_files(File { url: main_module, … })` so the type checker and graph builder can see it as a normal module.