All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- Agent Workbench demo: AI coding agent that builds Next.js pages live with file editing, bash execution, and HMR preview. Added to homepage demos grid.
- Vercel AI SDK demo: Streaming AI chatbot with Next.js, OpenAI, and real-time token streaming via Pages Router API route
- Express demo E2E tests: New Playwright tests for the Express server demo
vfs-requiremodule (src/frameworks/vfs-require.ts): Shared require system extracted for reuse across entry pointsnpm-servemodule (src/frameworks/npm-serve.ts): Shared/_npm/package bundling endpoint with nested exports support- CI E2E pipeline: GitHub Actions now runs Playwright E2E tests after unit tests with Chromium
- CLAUDE.md: Project instructions file for AI-assisted development
- Route group client-side navigation: Pages inside route groups (e.g.
(marketing)/about) now render correctly during client-side navigation. Replaced local path construction with server-basedresolveRoute()using extended/_next/route-infoendpoint that returns actualpageandlayoutspaths. convertToModelMessagesimport: Vercel AI SDK demo now imports fromaipackage instead of non-existent@ai-sdk/ui-utils- npm-serve nested exports: Packages with nested
exportsfield entries (e.g.ai/react,@ai-sdk/openai) now resolve correctly - TypeScript type errors: Fixed duplicate
setEnvmethod,executeApiHandlerreturn type,cpExeccallback types
- Agent Workbench guardrails removed: AI agent can now modify any project file including root page (
/app/page.tsx),package.json, andtsconfig.json. Only/pages/api/chat.tsremains protected. - E2E tests hardened: Removed try/catch fallbacks across all E2E tests for strict assertions; collect page errors for better debugging
- Convex and Vite demos refactored: Use platform's
vfs-requireandnpm-servemodules instead of inline implementations
- Centralized CDN configuration (
src/config/cdn.ts): Single source of truth for esm.sh, unpkg, and other CDN URLs used across the codebase - esm.sh version resolution:
redirectNpmImportsnow readspackage.jsondependencies and includes the major version in esm.sh URLs (e.g.ai@4/react), fixing 404s on subpath imports - Setup overlay dialogs: Convex and Vercel AI SDK demos now show an API key setup dialog on load with privacy notice ("your key stays in your browser")
- New tests:
tests/cdn-config.test.ts(12 tests) andtests/code-transforms.test.ts(11 tests)
- Renamed AI chatbot demo files:
demo-ai-chatbot.html→demo-vercel-ai-sdk.html,ai-chatbot-demo.ts→vercel-ai-sdk-demo.ts - Replaced hardcoded CDN URLs throughout codebase with imports from
src/config/cdn.ts
sentryshim (src/shims/sentry.ts): Was a no-op stub for a non-existent Node.js built-in- Custom
convexcommand inchild_process.ts: Convex now runs through the generic bin stub system like any other CLI tool - Convex-specific path remaps in
fs.ts:path.resolve()with correctcwdhandles this generically vfs:prefix stripping infs.ts: Moved to esbuild shim where the artifact originates
- Generic bin stubs:
npm installnow reads each package'sbinfield and creates executable scripts in/node_modules/.bin/. CLI tools likevitest,eslint,tsc, etc. work automatically via thenodecommand — no custom commands needed. - Streaming
container.run()API: Long-running commands supportonStdout/onStderrcallbacks andAbortControllersignal for cancellation. container.sendInput(): Send stdin data to running processes (emits bothdataandkeypressevents for readline compatibility).- Vitest demo with xterm.js: New
examples/vitest-demo.htmlshowcasing real vitest execution in the browser with watch mode, syntax-highlighted terminal output, and file editing. - E2E tests for vitest demo: 5 Playwright tests covering install, test execution, tab switching, failure detection, and watch mode restart.
rollupshim: Stub module so vitest's dependency chain resolves without errors.fs.realpathSync.native: Added as alias forrealpathSync(used by vitest internals).fs.createReadStream/fs.createWriteStream: Basic implementations using VirtualFS.path.delimiterandpath.win32: Added missing path module properties.process.getuid(),process.getgid(),process.umask(): Added missing process methods used by npm packages.util.deprecate(): Returns the original function with a no-op deprecation warning.
Object.definePropertypatch onglobalThis: Forcesconfigurable: truefor properties defined onglobalThis, so libraries that define non-configurable globals (like vitest's__vitest_index__) can be re-run without errors.- VFS adapter executable mode: Files in
/node_modules/.bin/now return0o755mode so just-bash treats them as executable. Runtime.clearCache()clears in-place: Previously created a new empty object, leaving closures referencing the stale cache. Now deletes keys in-place.- Watch mode uses restart pattern: Vitest caches modules internally (Vite's ModuleRunner), so file changes require a full vitest restart (abort + re-launch) rather than stdin-triggered re-runs.
- Custom vitest command: Deleted
src/shims/vitest-command.tsand removed vitest-specific handling fromchild_process.ts. Vitest now runs through the generic bin stub +nodecommand like any other CLI tool.
- Firefox blank preview: Fixed Vite dev server injecting
<script type="module">(React Refresh preamble) before<script type="importmap">in served HTML. Firefox strictly requires import maps to appear before any module scripts. The preamble is now injected after the last import map when one is present. (#3)
- Next.js dev server refactoring: Extracted route resolution and API handler logic into standalone modules, reducing
next-dev-server.tsfrom ~2240 to ~1360 lines (39% reduction):next-route-resolver.ts(~600 lines) — App Router/Pages Router route resolution, dynamic routes, route groups, catch-all segmentsnext-api-handler.ts(~350 lines) — mock request/response objects, cookie parsing, API handler execution, streaming support
- 115 new unit tests for the extracted modules (63 route resolver + 52 API handler)
browserfield support in module resolution: npm packages with abrowserfield in package.json now resolve to their browser-specific entry point. Supports both string form ("browser": "lib/browser/index.js") and object form ("browser": {"./lib/node.js": "./lib/browser.js"}). This fixes compatibility with packages likedepd,debug, and others that provide browser-optimized versions.
- Safari Express crash: Fixed
callSite.getFileName is not a functionerror when running Express in Safari. Thedepdpackage (an Express dependency) uses V8-specificError.captureStackTraceAPIs that don't exist in WebKit. By respecting depd's"browser"field, the no-op browser version is now loaded instead. Error.captureStackTracepolyfill improvements: AddedError.stackTraceLimitdefault,.stackgetter interception onError.prototypefor lazyprepareStackTraceevaluation, re-entrancy protection, and error logging instead of silent fallback.
- Convex CLI deployment: Full in-browser Convex deployment via the CLI bundle with 4 runtime patches (Sentry stub, crash capture, size check skip, site URL derivation)
- Next.js dev server refactoring: Extracted ~1700 lines into standalone modules:
next-shims.ts— shim string constants (~1050 lines)next-html-generator.ts— HTML template generation (~600 lines)next-config-parser.ts— AST-based config parsing with regex fallback (~140 lines)binary-encoding.ts— base64/uint8 encoding utilities
- HTTP shim improvements:
IncomingMessagenow supports readable stream interface (on('data'),on('end')), chunked transfer encoding, proper content-length tracking - WebSocket shim: Real WebSocket connectivity for Convex real-time sync (connect to
wss://endpoints, binary frame support, ping/pong handling) - Stream shim: Added
PassThroughstream implementation - Crypto shim: Added
timingSafeEqualimplementation - Convex E2E tests: 6 Playwright tests including HTTP API verification that proves modified mutations deploy and run on the Convex backend
path.resolve()must useprocess.cwd(): Was prepending/for relative paths instead of the actual working directory — caused Convex CLI to resolve'convex'→/convexinstead of/project/convex- esbuild
absWorkingDirmust useprocess.cwd(): Was defaulting to/, causing metafile paths to be relative to root instead of the project directory, resulting in doubled paths like/project/project/... - Convex
_generateddirectory: No longer deletes/convex/_generated/during deployment — the live Next.js app imports from it while the CLI only needs/project/convex/_generated/ path.join()debug logging removed: Cleaned up leftoverconsole.logcalls for_generatedpath joins
- AST-based code transforms: Replaced fragile regex-based transforms with proper AST parsing using
acornandcss-tree- CSS Modules:
css-treeAST for reliable class extraction and scoping (handles pseudo-selectors, nested rules, media queries) - ESM→CJS:
acornAST for precise import/export conversion (handles class exports, re-exports,export *, namespace imports) - React Refresh:
acornAST component detection — no longer false-detectsconst API_URL = "..."as a component - npm import redirect:
acornAST targets import/export source strings precisely, avoiding false matches in comments/strings - All transforms gracefully fall back to regex if AST parsing fails
- CSS Modules:
- Shared code-transforms module: Extracted ~350 lines of transform logic into
src/frameworks/code-transforms.ts, deduplicatingaddReactRefresh()between NextDevServer and ViteDevServer - New features: CSS Modules, App Router API Routes,
useParams, Route Groups,basePath,loading.tsx/error.tsx/not-found.tsxconvention files,next/font/local - E2E test harness: Added
examples/next-features-test.htmlande2e/next-features.spec.tswith 25 Playwright tests covering all new features
- App Router API query params: Fixed query string not being passed to App Router route handlers (
handleAppRouteHandlernow receivesurlObj.search) - E2E import paths: Fixed
examples/vite-demo.htmlandexamples/sandbox-next-demo.htmlusing wrong relative import path (./src/→../src/) - E2E test assertions: Fixed dynamic route test checking for
[id].jsxstring that never appears in generated HTML; fixed vite-error-overlay blocking clicks in navigation tests - Convex demo logging: Added key file path logging so e2e tests can verify project files
- Added
acorn(8.15.0),acorn-jsx(5.3.2),css-tree(3.1.0)
- Asset prefix support: NextDevServer now supports
assetPrefixoption for serving static assets with URL prefixes (e.g.,/marketing/images/...→/public/images/...) - Auto-detection: Automatically detects
assetPrefixfromnext.config.ts/js/mjsfiles - Binary file support: Macaly demo now supports base64-encoded binary files (images, fonts, etc.) in the virtual file system
- File extraction script: Added
scripts/extract-macaly-files.tsto load real-world Next.js projects including binary assets
- Virtual server asset routing: Service worker now forwards ALL requests from virtual contexts (images, scripts, CSS) to the virtual server, not just navigation requests. This fixes 404 errors for assets using absolute URLs.
- Double-slash URLs: Handle URLs like
/marketing//images/foo.pngthat result from concatenating assetPrefix with paths
- Transform caching: Dev servers now cache transformed JSX/TS files with content-based invalidation, improving reload performance
- Module resolution caching: Runtime caches resolved module paths for faster repeated imports
- Package.json parsing cache: Parsed package.json files are cached to avoid repeated file reads
- Processed code caching: ESM-to-CJS transformed code is cached across module cache clears
- Service Worker navigation: Plain
<a href="/path">links within virtual server context now correctly redirect to include the virtual prefix - Virtual FS mtime: File system nodes now track actual modification times instead of returning current time
- Flaky zlib test: Fixed non-deterministic test that used random bytes
- App Router navigation: Extended client-side navigation fix to also support App Router (
/appdirectory). Both Pages Router and App Router now use dynamic imports for smooth navigation.
- Next.js Link navigation: Fixed clicking
<Link>components causing full iframe reload instead of smooth client-side navigation. Now uses dynamic page imports for proper SPA-like navigation.
- Critical: Fixed browser bundle importing Node.js
urlmodule, which broke the library completely in browsers. Thesandbox-helpers.tsnow uses dynamic requires that only run in Node.js.
- CI now builds library before running tests (fixes failing tests for service worker helpers)
- Added security warning to Quick Start section in README
- Clarified that
createContainer()should not be used with untrusted code - Added "Running Untrusted Code Securely" example using
createRuntime()with sandbox - Updated repository URLs to point to macaly/almostnode
-
Vite plugin (
almostnode/vite) - Automatically serves the service worker file during developmentimport { almostnodePlugin } from 'almostnode/vite'; export default defineConfig({ plugins: [almostnodePlugin()] });
-
Next.js helpers (
almostnode/next) - Utilities for serving the service worker in Next.js appsgetServiceWorkerContent()- Returns service worker file contentgetServiceWorkerPath()- Returns path to service worker file
-
Configurable service worker URL -
initServiceWorker()now accepts optionsawait bridge.initServiceWorker({ swUrl: '/custom/__sw__.js' });
-
Service worker included in sandbox files -
generateSandboxFiles()now generates__sw__.jsalong withindex.htmlandvercel.json, making cross-origin sandbox deployment self-contained
- Updated README with comprehensive Service Worker Setup documentation covering all deployment options
- Initial release
- Virtual file system with Node.js-compatible API
- 40+ shimmed Node.js modules
- npm package installation support
- Vite and Next.js dev servers
- Hot Module Replacement with React Refresh
- Cross-origin sandbox support for secure code execution
- Web Worker runtime option