diff --git a/learn/developers/multiple-applications.mdx b/learn/developers/multiple-applications.mdx
index f329a168..9781c400 100644
--- a/learn/developers/multiple-applications.mdx
+++ b/learn/developers/multiple-applications.mdx
@@ -23,7 +23,7 @@ Harper isolates each application's module context automatically (see [What co-lo
Harper runs as a single process. Every co-located application shares that process and its worker threads, so it is worth being precise about what is isolated between applications and what is not.
-- **Module contexts are isolated.** Harper loads each application's JavaScript in its own module context using Node.js's VM module loader, giving every application a distinct module cache. One application's modules, imports, and module-scoped state are not visible to another, so two applications can depend on different packages—or different versions of the same package—without colliding.
+- **Application source is isolated; some dependencies are not.** Harper loads each application's JavaScript in its own module context using Node.js's VM module loader, giving every application a distinct module cache. One application's own modules, imports, and module-scoped state are not visible to another, so two applications can depend on different packages—or different versions of the same package—without colliding. The exception is dependencies: under the default `dependencyLoader: auto`, packages that do not declare `harper` as a dependency load through Node's loader and share its process-wide cache, so two applications resolving the same package file get the same instance and the same singleton state. Both the loader and the dependency policy are configurable—see [Module Loading](/reference/v5/components/module-loading).
- **The data layer and Harper APIs are shared.** The objects you reach through the `harper` package or as globals—`tables`, `databases`, and the rest—are the same live, process-wide objects in every application. A record written by one application is immediately visible to every other, and any application can read or write another's tables in-process. This is what makes co-location efficient, and it is why separate databases are a [namespacing convention](#namespacing-data-by-database) rather than an enforced boundary.
- **Users, roles, and sessions are instance-wide.** Harper's RBAC belongs to the instance, not to an application. Every application's `roles.yaml` reconciles into the same instance-wide role registry, and a user authenticates against the instance as a whole. See [Access control is instance-wide](#access-control-is-instance-wide).
- **The process is shared.** Because every application runs in one process, operational actions apply to all of them: restarting the instance restarts every co-located application, and applications cannot change the process working directory. Plan restarts and deployments with the whole instance in mind.
diff --git a/reference/components/javascript-environment.md b/reference/components/javascript-environment.md
index 723fd8c0..8f9b35ab 100644
--- a/reference/components/javascript-environment.md
+++ b/reference/components/javascript-environment.md
@@ -6,9 +6,11 @@ title: JavaScript Environment
# JavaScript Environment
-Harper executes component JavaScript in distinct module caches, using Node.js's VM module loader. This provides contextualized module environments that share the same Node.js runtime but have their own set of modules isolated from other applications. This means each application runs in its own module context while still being able to access Harper's full set of APIs.
+By default, Harper executes component JavaScript in distinct module caches, using Node.js's VM module loader. This provides contextualized module environments that share the same Node.js runtime but have their own set of modules isolated from other applications. This means each application runs in its own module context while still being able to access Harper's full set of APIs.
-## Module Loading
+This page covers what component code can reach: module formats, TypeScript support, the `harper` API surface, and the constrained `child_process`. How modules are loaded and isolated is configurable — see [Module Loading](./module-loading.md) for the `moduleLoader` modes, dependency loading, intrinsic lockdown, and the directory and built-in module restrictions. Everything below describes the default loader (`vm-current-context`) unless stated otherwise.
+
+## Module Formats
Harper supports both ESM and CommonJS module formats. The full set of Harper APIs are accessible by importing from the `harper` package, for example::
@@ -30,7 +32,7 @@ npm link harper
All installed components have `harper` automatically linked.
-Whether you reach them as globals or as `harper` imports, `tables`, `databases`, and the other APIs are the **same live, process-wide objects** — Harper runs as a single process, so a record written through one component is immediately visible to every other. The automatic link points `harper` at the **running** installation (not a separately-installed copy), so `import { tables } from 'harper'` resolves to that live runtime from any module Harper loads. Application module contexts are seeded from the same process globals, not given an isolated set of these objects.
+Whether you reach them as globals or as `harper` imports, `tables`, `databases`, and the other APIs are the **same live, process-wide objects** — Harper runs as a single process, so a record written through one component is immediately visible to every other. The automatic link points `harper` at the **running** installation (not a separately-installed copy), so `import { tables } from 'harper'` resolves to that live runtime from any module Harper loads. Under the default `vm-current-context` loader (and under `native`), application module contexts are seeded from the same process globals rather than given an isolated set of these objects. The `vm` and `compartment` loaders build a custom global object per application — see [Module Loader Modes](./module-loading.md#module-loader-modes).
This includes bundler-built code. A Vite **server-side-render** entry, for example, can read data straight from Harper and render it into the HTML (no client-side fetch):
@@ -214,7 +216,7 @@ const agent = spawn('datadog-agent', ['run'], {
### Which imports get the substitute
-The substitution happens in Harper's module loader, so it only reaches code that loader handles:
+The substitution happens in Harper's module loader, so it only reaches code that loader handles. Which loader runs is set by [`applications.moduleLoader`](./module-loading.md#module-loader-modes), and whether a dependency goes through it is set by [`applications.dependencyLoader`](./module-loading.md#dependency-loading):
| How the module is reached | What you get |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------- |
diff --git a/reference/components/module-loading.md b/reference/components/module-loading.md
new file mode 100644
index 00000000..fea0fc9b
--- /dev/null
+++ b/reference/components/module-loading.md
@@ -0,0 +1,166 @@
+---
+title: Module Loading
+---
+
+# Module Loading
+
+
+
+By default, Harper loads each application's JavaScript through Node.js's [VM module API](https://nodejs.org/api/vm.html) rather than a plain `import()`. Every application gets its own module cache for the modules that loader handles, so two co-located applications can depend on different packages — or different versions of the same package — without colliding, and one application's module-scoped state is not visible to another. Dependencies that Harper routes to the native loader are the exception — see [Dependency Loading](#dependency-loading).
+
+The loader is also what makes application context work. It gives each application a `harper` module scoped to that application: the `logger` it exports is tagged with the application name, and `config` reflects that application's own configuration. Under the VM loaders it additionally substitutes a constrained [`child_process`](./javascript-environment.md#child-processes) module.
+
+Everything on this page is controlled by the `applications` section of `harper-config.yaml`:
+
+```yaml
+applications:
+ lockdown: freeze-after-load # freeze-after-load (default) | freeze | ses | none
+ moduleLoader: vm-current-context # vm-current-context (default) | vm | native | compartment
+ dependencyLoader: auto # auto (default) | app | native
+ allowedDirectory: app # app (default) | any
+ allowedSpawnCommands:
+ - npm
+ - node
+ # allowedBuiltInModules: [] # if omitted, all Node.js built-ins are allowed
+```
+
+See [Configuration Options](../configuration/options.md#applications) for the settings in the context of the full configuration file.
+
+:::note Defaults changed during v5.0
+
+The defaults above are the current ones. Earlier v5.0 releases behaved differently, so check your version before reasoning about which isolation model you are on:
+
+| Setting | v5.0.0 default | Current default |
+| ------------------ | -------------- | ---------------------------------- |
+| `lockdown` | `freeze` | `freeze-after-load`, since v5.0.2 |
+| `moduleLoader` | `vm` | `vm-current-context`, since v5.1.0 |
+| `allowedDirectory` | not available | `app`, since v5.0.4 |
+
+The `moduleLoader` change matters most: on v5.0.x an application runs under `vm` with its own intrinsics, which is the mode that causes cross-context `instanceof` to fail.
+
+:::
+
+## Module Loader Modes
+
+`moduleLoader` selects how application modules are loaded. The choice determines how much isolation you get, and it has consequences beyond isolation — notably whether application context is available at all, and whether Harper's constrained `child_process` reaches your code.
+
+| Mode | Module cache | Intrinsics | Global object | Application context (`logger`, `config`) | Constrained `child_process` |
+| ------------------------------ | ------------ | ------------------ | -------------- | ---------------------------------------- | --------------------------- |
+| `vm-current-context` (default) | Per app\* | Shared with Harper | Harper's | Yes | Yes |
+| `vm` | Per app\* | Separate per app | Custom per app | Yes | Yes |
+| `native` | Shared | Shared with Harper | Harper's | No | No |
+| `compartment` | Per app\* | SES-managed | Custom per app | Yes | No |
+
+\* Applies to modules the application loader handles. Dependencies routed to the native loader share Node's process-wide cache — see [Dependency Loading](#dependency-loading).
+
+### `vm-current-context` (default)
+
+
+
+The VM module loader running in Harper's own context, and the default since v5.1.0 (v5.0.x defaulted to `vm`). Applications get their own module cache but share JavaScript intrinsics (`Object`, `Array`, `Promise`, and so on) with Harper.
+
+Sharing intrinsics gives the best compatibility with packages that perform `instanceof` or other identity checks on values crossing the application/Harper boundary. It is the right choice for almost every application.
+
+Because there is no separate global object, `tables`, `databases`, and the other Harper APIs are the same live, process-wide objects whether you reach them as globals or as `harper` imports. See [JavaScript Environment](./javascript-environment.md#module-formats) for what that means in practice.
+
+### `vm`
+
+The VM module loader running in a separate context per application, with its own intrinsics and a custom global object.
+
+This is stronger isolation, but the separate intrinsics are a common source of subtle incompatibilities: cross-context `instanceof` returning `false`, frozen-prototype mismatches, and similar. Choose it only if you specifically need per-application intrinsics.
+
+### `native`
+
+Standard Node.js `import()` with no VM loader. This restores pre-v5 behavior.
+
+The trade-off is that application context is lost: there is no per-application module cache, no application-tagged `logger`, no per-application `config`, and no constrained `child_process`. Reach for it when the VM loader causes compatibility problems you cannot otherwise resolve — and consider whether [`dependencyLoader: native`](#dependency-loading) is the narrower fix first.
+
+### `compartment`
+
+SES `Compartment`-based loading, using the [`ses`](https://www.npmjs.com/package/ses) implementation of the proposed Compartment API. One compartment per application, created on demand because it is considerably heavier than the other modes.
+
+Advanced; only needed for specialized sandboxing requirements.
+
+:::warning Compartments bypass the constrained `child_process`
+
+Compartments resolve built-in modules through Node directly. Harper's substituted `child_process` is not applied under this mode. The spawn allowlist, the mandatory `name` option, the single-process lock, and the `execSync` block all disappear together, so component code can spawn any command, once per worker thread. Keep process-spawning code under `vm-current-context` or `vm`.
+
+:::
+
+## Dependency Loading
+
+`dependencyLoader` controls whether npm packages — dependencies installed from `package.json` — go through the application module loader or Node's.
+
+- `auto` (default) — a package is loaded through the application loader only if it declares `harper` as a dependency. Everything else is loaded natively.
+- `app` — always use the application module loader for packages.
+- `native` — always use the native loader for packages, while first-party application source still goes through the VM loader.
+
+The default is a deliberate compromise: packages that depend on `harper` want application context, and packages that do not are usually better off with Node's own loader. It has a consequence worth planning around — code factored out into an npm package that does not depend on `harper` will not receive Harper's constrained `child_process`, and so gets no allowlist, no lock, and one child process per worker thread rather than one per node. See [Child Processes](./javascript-environment.md#which-imports-get-the-substitute) for the full matrix.
+
+`dependencyLoader: native` is the narrow fix when a package is incompatible with the VM loader. It keeps application context for your own code, unlike switching `moduleLoader` to `native`.
+
+## Intrinsic Lockdown
+
+`lockdown` controls whether JavaScript intrinsics are frozen, which protects against prototype pollution attacks.
+
+- `freeze-after-load` (default) — freeze intrinsics after all components have loaded, so component initialization can still modify them.
+- `freeze` — freeze intrinsics before any application code loads.
+- `ses` — full SES lockdown via the `ses` package. Strictest, and the most likely to break packages that mutate built-ins.
+- `none` — no lockdown.
+
+Under the default, application code or a dependency that modifies an intrinsic prototype at runtime — after startup — throws a `TypeError`. If a dependency does this and you need a temporary workaround, set `lockdown: none`.
+
+## Allowed Directory
+
+
+
+`allowedDirectory` restricts where application modules may be loaded from.
+
+- `app` (default) — an application may only load modules from within its own directory tree. Loading from outside it throws `Can not load module at outside of allowed path `.
+- `any` — no restriction.
+
+The check resolves symlinks before comparing against the application's own directory. It applies to imports the application module loader handles; imports that Node's loader resolves are not subject to it, so treat this as a configuration guardrail rather than a security boundary.
+
+Dev-mode installs set `allowedDirectory: any`, so local development is typically unaffected; production installs get `app`.
+
+If an application legitimately needs to load files from outside its own directory in production:
+
+```yaml
+applications:
+ allowedDirectory: any
+```
+
+## Allowed Built-in Modules
+
+`allowedBuiltInModules` restricts which Node.js built-ins applications may import. If it is omitted, all built-ins are allowed — which is the default.
+
+```yaml
+applications:
+ allowedBuiltInModules:
+ - fs
+ - path
+ - http
+```
+
+Matching strips a `node:` prefix and compares the first path segment, so allowlisting `fs` also permits `node:fs/promises`. A built-in that is not on the list throws `Module is not allowed to be imported` when the module is linked, not at the call site. The key is matched case-insensitively, so an existing `allowedBuiltinModules` in your configuration keeps working.
+
+Like `allowedDirectory`, this applies to imports the application module loader handles rather than to every import an application can make — a configuration guardrail, not a security boundary.
+
+Allowlisting `child_process` still yields Harper's constrained substitute under the VM loaders, not Node's unmodified module.
+
+## Choosing a Mode
+
+For most applications the default is the right choice, and the settings on this page are worth changing only in response to a concrete problem.
+
+- **A package breaks under the VM loader.** Try `dependencyLoader: native` first — it keeps application context for your own source. Fall back to `moduleLoader: native` only if the problem is in first-party code.
+- **A dependency mutates an intrinsic prototype and now throws.** `lockdown: none` is the temporary workaround; the durable fix is in the dependency.
+- **`instanceof` fails on a value that crossed the Harper boundary.** You are on `vm`. Move to `vm-current-context`.
+- **You need per-application intrinsics or a custom global.** `vm` is the mode that provides them; accept the compatibility cost.
+- **You need to spawn a sidecar process.** Stay on a VM loader and keep the spawning code in component source, reached with `import`. See [Child Processes](./javascript-environment.md#child-processes).
+
+## See Also
+
+- [JavaScript Environment](./javascript-environment.md) — module formats, TypeScript support, and the `harper` API surface
+- [Child Processes](./javascript-environment.md#child-processes) — the constrained `child_process` contract
+- [Configuration Options](../configuration/options.md#applications) — the `applications` section in full
+- [v5 Migration Guide](/release-notes/v5-lincoln/v5-migration#vm-module-loader) — what changed from v4 and how to cope
diff --git a/reference/configuration/options.md b/reference/configuration/options.md
index d320cab1..84b34767 100644
--- a/reference/configuration/options.md
+++ b/reference/configuration/options.md
@@ -408,19 +408,25 @@ agent:
Added in: v5.0.0
+Controls how application modules are loaded and isolated. See [Module Loading](../components/module-loading.md) for the full reference.
+
```yaml
applications:
lockdown: freeze-after-load
moduleLoader: vm-current-context
dependencyLoader: auto
+ allowedDirectory: app
allowedSpawnCommands:
- npm
- node
+ # allowedBuiltInModules: [] # if omitted, all Node.js built-ins are allowed
```
-- `lockdown` — Indicates if intrinsic/built-in objects should be locked down/frozen. This provides additional security and protection against prototype pollution attacks. The default is `freeze-after-load`, which freezes the important built-in objects once all components have loaded, so component initialization can still modify them. This can also be set to `freeze` (freeze before any application code loads), `none`, or `ses` (lockdown provided by the `ses` package, which is more strict). See [Intrinsic Lockdown](/release-notes/v5-lincoln/v5-migration#intrinsic-lockdown).
-- `moduleLoader` — The method used to load modules (and isolate the application). The default is `vm-current-context`, which uses Node's VM module loader in Harper's own context so applications share JavaScript intrinsics. This can also be set to `vm` (VM loader with a separate context and its own intrinsics per application), `native` (standard Node module loader), or `compartment`, which uses the `ses` implementation of the proposed `Compartment` functionality. See [Module Loader Modes](/release-notes/v5-lincoln/v5-migration#module-loader-modes).
-- `dependencyLoader` — The application module loader can be used to load packages/dependencies (installed as `dependencies` from the package.json). The default is 'auto', which only use the VM module loader if the package specifies `harper` as a dependency. This can also be set to `app` to always use the application module loader or `native` to always native module loader for packages.
+- `lockdown` — Indicates if intrinsic/built-in objects should be locked down/frozen. This provides additional security and protection against prototype pollution attacks. The default is `freeze-after-load` (since v5.0.2; v5.0.0 and v5.0.1 defaulted to `freeze`), which freezes the important built-in objects once all components have loaded, so component initialization can still modify them. This can also be set to `freeze` (freeze before any application code loads), `none`, or `ses` (lockdown provided by the `ses` package, which is more strict). See [Intrinsic Lockdown](../components/module-loading.md#intrinsic-lockdown).
+- `moduleLoader` — The method used to load modules (and isolate the application). The default is `vm-current-context` (since v5.1.0; v5.0.x defaulted to `vm`), which uses Node's VM module loader in Harper's own context so applications share JavaScript intrinsics. This can also be set to `vm` (VM loader with a separate context and its own intrinsics per application), `native` (standard Node module loader), or `compartment`, which uses the `ses` implementation of the proposed `Compartment` functionality. See [Module Loader Modes](../components/module-loading.md#module-loader-modes).
+- `dependencyLoader` — The application module loader can be used to load packages/dependencies (installed as `dependencies` from the package.json). The default is 'auto', which only use the VM module loader if the package specifies `harper` as a dependency. This can also be set to `app` to always use the application module loader or `native` to always native module loader for packages. See [Dependency Loading](../components/module-loading.md#dependency-loading).
+- `allowedDirectory` — Added in v5.0.4. Restricts where an application may load modules from. The default is `app`, which permits only modules within the application's own directory tree; loading from outside it throws. Set to `any` to remove the restriction. Dev-mode installs default to `any`. Applies to imports the application module loader handles, so treat it as a configuration guardrail rather than a security boundary. See [Allowed Directory](../components/module-loading.md#allowed-directory).
+- `allowedBuiltInModules` — An allowlist of the Node.js built-in modules applications may import. If omitted, all built-ins are allowed. Matching strips a `node:` prefix and compares the first path segment, so `fs` also permits `node:fs/promises`. Like `allowedDirectory`, it applies to imports the application module loader handles. See [Allowed Built-in Modules](../components/module-loading.md#allowed-built-in-modules).
- `allowedSpawnCommands` - This lists the specific commands that can be spawned by the application (using `child_process`'s `spawn()` and `execFile()` functions). You can add commands that your application will need to launch (this is to protect against malicious code spawning processes). Only the first token of the command is matched, spawning also requires a mandatory `name` option, and the call is subject to a node-wide single-process lock — see [Child Processes](../components/javascript-environment.md#child-processes) for the full contract.
## Component Configuration
diff --git a/release-notes/v5-lincoln/5.0.md b/release-notes/v5-lincoln/5.0.md
index a2458335..dc907f90 100644
--- a/release-notes/v5-lincoln/5.0.md
+++ b/release-notes/v5-lincoln/5.0.md
@@ -68,7 +68,7 @@ Harper v5.0 has upgraded the resource API with several important changes:
## Application Context Separation
-Harper now runs each application its own separate JavaScript "context", which has its own global object, top level variables, and module imports. This provides isolation of applications and access to application-specific configuration data and functionality. These contexts will limit access to certain functionality including spawning new processes. This functionality can be controlled with configuration options. Specifically, any new processes that will be spawned need to be listed in `applications.allowedShellCommands`.
+Harper now runs each application in its own separate JavaScript "context", with its own top level variables and module imports (and, under the `vm` and `compartment` loaders, its own global object). This provides isolation of applications and access to application-specific configuration data and functionality. These contexts will limit access to certain functionality including spawning new processes. This functionality can be controlled with configuration options. Specifically, any new processes that will be spawned need to be listed in `applications.allowedSpawnCommands`. See [Module Loading](/reference/v5/components/module-loading) for the current reference.
Harper will also "freeze" many of the intrinsic objects in the global object, to protect against prototype pollution type attacks and vulnerabilities.
This application context separation will also allow the logger to apply application-specific tagging to log messages, and leverage the application-specific configuration for logging.
diff --git a/release-notes/v5-lincoln/v5-migration.md b/release-notes/v5-lincoln/v5-migration.md
index 905475ab..63988897 100644
--- a/release-notes/v5-lincoln/v5-migration.md
+++ b/release-notes/v5-lincoln/v5-migration.md
@@ -131,38 +131,26 @@ applications:
allowedSpawnCommands: # see "Spawning new processes" above
- npm
- node
- # allowedBuiltinModules: [] # if omitted, all Node.js built-ins are allowed
+ # allowedBuiltInModules: [] # if omitted, all Node.js built-ins are allowed
```
-### Module Loader Modes
-
-The `moduleLoader` setting selects how application modules are loaded:
+Each of these settings is documented in full under [Module Loading](/reference/v5/components/module-loading). What follows is only what is likely to need attention when moving an application from v4.
-- `vm-current-context` (default) — the VM module loader running in Harper's own context. Applications share intrinsics with Harper, which gives the best compatibility with packages that perform `instanceof` or other identity checks across the boundary. Application-specific values (`logger`, `config`, `server`, and the rest of the `harper` API) are provided through `import ... from 'harper'` (or `require('harper')` in CommonJS).
-- `vm` — the VM module loader running in a separate context per application, with its own intrinsics and a custom global object. This provides stronger isolation between applications, but the separate intrinsics are a common source of subtle incompatibilities (cross-context `instanceof`, frozen-prototype mismatches, and similar).
-- `native` — standard Node.js `import()` with no VM loader. Application-specific context (tagged logging, per-app `config`) is not available.
-- `compartment` — SES Compartment-based loading. Advanced and considerably heavier; only needed for specialized sandboxing requirements.
+### Module Loader Modes
-For most applications the default is the right choice. Choose `vm` only if you specifically need separate per-application intrinsics, and `native` if the VM loader causes compatibility problems you cannot otherwise resolve.
+`moduleLoader` selects how application modules are loaded: `vm-current-context` (the default, sharing intrinsics with Harper), `vm` (a separate context and its own intrinsics per application), `native` (standard Node.js `import()`, with no application context), or `compartment` (SES Compartments; advanced and considerably heavier).
-> Under `lockdown: ses`, the constrained (https-only) `fetch` is applied only in `vm` mode, which gives each application its own globals. In `vm-current-context` and `native` modes application code uses the standard global `fetch`; choose `vm` mode if you require the constrained `fetch`.
+For most applications the default is the right choice. Choose `vm` only if you specifically need separate per-application intrinsics, and `native` if the VM loader causes compatibility problems you cannot otherwise resolve. See [Module Loader Modes](/reference/v5/components/module-loading#module-loader-modes) for what each mode does to isolation, application context, and the constrained `child_process`.
### Intrinsic Lockdown
The default lockdown mode (`freeze-after-load`) freezes JavaScript intrinsics (`Object`, `Array`, `Promise`, `Map`, `Set`, and others) after all application code has loaded. This prevents prototype pollution attacks. If application code or a dependency modifies intrinsic prototypes at runtime (after startup), it will throw a TypeError.
-Available lockdown modes:
-
-- `freeze-after-load` — freeze intrinsics after all components have loaded (default)
-- `freeze` — freeze intrinsics before loading any application code
-- `ses` — full SES lockdown via the `ses` package (strictest; most likely to break packages that mutate built-ins)
-- `none` — no lockdown
-
-If a dependency modifies intrinsic prototypes and you need a temporary workaround, set `lockdown: none`.
+If a dependency modifies intrinsic prototypes and you need a temporary workaround, set `lockdown: none`. The other modes (`freeze`, `ses`) are covered under [Intrinsic Lockdown](/reference/v5/components/module-loading#intrinsic-lockdown).
### Allowed Directory
-In production, applications can only load modules from within their own directory tree (`allowedDirectory: app`). Attempting to load a module from outside that directory will throw. Dev mode installs default to `allowedDirectory: any`, so local development is typically unaffected.
+In production, applications can only load modules from within their own directory tree (`allowedDirectory: app`). Attempting to load a module from outside that directory will throw. Dev mode installs default to `allowedDirectory: any`, so this usually surfaces first in production rather than during local development.
If your application legitimately needs to load files from outside its own directory in production, set:
@@ -171,22 +159,6 @@ applications:
allowedDirectory: any
```
-### Allowed Built-in Modules
-
-By default all Node.js built-in modules are accessible. To restrict which built-ins applications may import, set an explicit allowlist:
-
-```yaml
-applications:
- allowedBuiltinModules:
- - fs
- - path
- - http
-```
-
-### Dependency Loading
-
-By default (`dependencyLoader: auto`), npm packages that do not declare `harper` as a dependency are loaded with the native Node.js loader. Packages that do depend on `harper` are loaded through the VM loader so they receive application context. Set `dependencyLoader: app` to always use the VM loader for dependencies, or `native` to always use the native loader for packages.
-
### Disabling the VM Loader
If the VM loader is causing compatibility issues with existing code, it can be disabled entirely:
diff --git a/sidebarsReference.ts b/sidebarsReference.ts
index 05a5353e..adb55773 100644
--- a/sidebarsReference.ts
+++ b/sidebarsReference.ts
@@ -163,6 +163,11 @@ const sidebars: SidebarsConfig = {
id: 'components/javascript-environment',
label: 'JavaScript Environment',
},
+ {
+ type: 'doc',
+ id: 'components/module-loading',
+ label: 'Module Loading',
+ },
{
type: 'doc',
id: 'components/scheduler',