From 82eb5d4c9ce7f4ce8d0a6ccfc87fbaef4c1a3e37 Mon Sep 17 00:00:00 2001 From: Kris Zyp Date: Wed, 10 Jun 2026 22:54:22 -0600 Subject: [PATCH] Document vm-current-context as the default module loader Harper v5 now defaults applications.moduleLoader to vm-current-context. Rewrite the VM Module Loader section to describe shared intrinsics as the default, add a Module Loader Modes reference, and note that the constrained SES fetch applies only in vm mode. Co-Authored-By: Claude Opus 4.7 --- release-notes/v5-lincoln/v5-migration.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/release-notes/v5-lincoln/v5-migration.md b/release-notes/v5-lincoln/v5-migration.md index 1b659420..ded96441 100644 --- a/release-notes/v5-lincoln/v5-migration.md +++ b/release-notes/v5-lincoln/v5-migration.md @@ -118,14 +118,14 @@ The `blob.save()` method has been removed. Please use the `saveBeforeCommit` fla ## VM Module Loader -Harper v5 loads application modules through Node.js's VM module API, giving each application its own module cache and execution context. This provides per-application context: the `logger` global/export is automatically tagged with the application name, and `config` reflects that application's own configuration. Each application's module graph is isolated from other applications and from Harper internals. +Harper v5 loads application modules through Node.js's VM module API, giving each application its own module cache and 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. By default (`vm-current-context`), applications share JavaScript intrinsics (`Object`, `Array`, `Promise`, and so on) with Harper. Sharing intrinsics avoids the compatibility problems that separate per-application intrinsics can cause — most commonly `instanceof` and other identity checks failing for values that cross the application/Harper boundary. All module loading behavior is controlled by the `applications` section in `harperdb-config.yaml`: ```yaml applications: lockdown: freeze-after-load # default; see below - moduleLoader: vm # vm (default) | native | compartment + moduleLoader: vm-current-context # vm-current-context (default) | vm | native | compartment dependencyLoader: auto # auto (default) | app | native allowedDirectory: app # app (default) | any allowedSpawnCommands: # see "Spawning new processes" above @@ -134,6 +134,19 @@ applications: # allowedBuiltinModules: [] # if omitted, all Node.js built-ins are allowed ``` +### Module Loader Modes + +The `moduleLoader` setting selects how application modules are loaded: + +- `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. + +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. + +> 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`. + ### 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.