libdeno 0.1.1

Embed the Deno runtime in Rust with direct npm: specifier support
Documentation
# npm & Module Resolution

libdeno runs the official Deno module graph pipeline end to end. Everything
the CLI's loader does — `npm:`, `jsr:`, remote modules, import maps, CJS
packages, WASM, JSON — comes from the graph.

## npm modes

`node_modules_dir` is `Auto` (the CLI default):

- **BYONM** — if a `node_modules` directory exists at the project root, it is
  used as-is. No install happens; bare imports resolve against the existing
  tree.
- **Managed** — otherwise, packages are installed into `node_modules` on
  demand (lazy caching, npm cache enabled). This is what you observe when
  running the demo: the first run of `examples/demo-app/index.js` installs
  `chalk` into `examples/demo-app/node_modules`.

npm lifecycle scripts (`preinstall`/`install`/`postinstall`) do **not** run
by default, matching the deno CLI 2.x default: installing a dependency must
never execute arbitrary shell code without an explicit opt-in. Packages that
need a build step at install time (e.g. `esbuild`) will not work out of the
box.

The npm resolution snapshot is initialized before the module graph starts
requesting packages
(`initialize_npm_resolution_if_managed`).

## Bare imports vs `npm:` specifiers

- **Bare imports** (`import chalk from "chalk"`): resolved by the node
  resolver against `package.json` dependencies, then loaded from the
  installed package.
- **`npm:` specifiers** (`import chalk from "npm:chalk@5"`): pass through the
  module loader and are resolved to the installed package file
  (`resolve_non_workspace_npm_req_ref_to_file`), with the npm: URL registered
  as a redirect alias for the concrete file URL.

## CJS support

- CJS packages are detected via the official CJS tracker, which is
  `package.json` `"type"` aware. User files outside npm packages are treated
  as ESM (`IsCjsResolutionMode::Disabled` — the CLI default; only `deno node`
  enables implicit CJS).
- CJS→ESM translation is enabled in the module loader
  (`NodeCodeTranslatorMode::ModuleLoader`).
- `require()` chains inside CJS modules that reference further CJS files are
  analyzed with `FsCjsAnalysisSourceProvider` (recursive CJS analysis).

## Lifecycle scripts

`preinstall` / `install` / `postinstall` run through the system shell exactly
like npm does:

```
sh -c <script>
```

with `INIT_CWD`, `npm_lifecycle_event`, `npm_lifecycle_script`,
`npm_package_name`, `npm_package_version` set, and the package's
`node_modules/.bin` + the root `.bin` prepended to `PATH`. Scripts that need
a runtime (`node`, `node-gyp`, ...) must be available on `PATH`.

## `child_process.fork`

The npm process state (resolution snapshot or BYONM marker, plus the
`node_modules` path) is serialized and handed to the child via
`NODE_CHANNEL_FD` (+ serialization mode), mirroring the CLI's `node_ipc_init`.
The forked child restores the npm resolution snapshot from that state.

## Module graph

- A single shared `ModuleGraph` (guarded by a mutex) is built on demand:
  `prepare_load` builds the tree rooted at the requested specifier;
  `load` reads from it. Already-loaded specifiers are not rebuilt.
- Graph building uses the official `deno_graph::ModuleGraph::build` with the
  `GraphResolver` (resolver + npm resolver) and the `DenoGraphLoader` (file
  fetcher).
- Remote modules are fetched into the HTTP cache; redirects are handled by
  the file fetcher (the HTTP client does not follow redirects).

## JSON imports

JSON imports require an import attribute, matching modern Deno:

```js
import pkg from "./pkg.json" with { type: "json" };
```

## Node builtins

`node:` builtins are served by the extension module map baked into the
snapshot — nothing is loaded from disk. The module loader returns an empty
JavaScript stub for `node:` specifiers and the real sources come from the
extension.