-
#1613
124a47aThanks @threepointone! - Introduce the first Think framework layer for convention-driven agent apps.This release adds a manifest-driven Vite plugin that discovers agents from the
agents/directory, generates a Worker entrypoint and virtual framework modules, derives stable Durable Object class names, and merges framework-owned Worker config defaults with user Wrangler config. It also keeps the Think Vite plugin usable directly in normal Vite plugin arrays.The framework now supports optional app server entries, manifest-scoped friendly agent and sub-agent routing, deterministic route surfaces, colocated skill detection, Worker Loader requirement diagnostics, and explicit diagnostics for unsupported nested sub-agent conventions. Think currently supports top-level agents and one sub-agent layer; deeper nesting is rejected with guidance so that the routing and lifecycle model can be designed deliberately.
This framework layer is experimental: both the Vite plugin (once, on build start) and the
thinkCLI (on startup) emit a notice that the API may change or be removed in any release. The core Think agent runtime is unchanged.The Think CLI now includes
think init,think inspect, andthink types.think initscaffolds a minimal Workers/Vite Think app, safely handles prompted or named target directories, refuses unsafe migrations, and installs npm dependencies by default.think inspectexposes manifest/config diagnostics in text or JSON, whilethink typesgenerates Think-owned declarations and can optionally compose with Wrangler type generation.This release also adds host-framework coverage for React Router and TanStack Start, updates examples to use the convention-first framework shape, and hardens Agents/worker-bundler virtual modules for bundled skill compatibility.
- #1584
87006e2Thanks @threepointone! - Add avirtualModulesoption tocreateWorker. Each key is an import specifier (for example"node:fs"or"virtual:app/config") and each value is JavaScript module source made available during bundling. Only applies whenbundle: true; in transform-only mode it is ignored with a warning.
-
19a4c08Thanks @threepointone! - Bumpes-module-lexerfrom^2.0.0to^2.1.0. Caret upper bound (<3.0.0) is unchanged.No API or runtime behavior change in
@cloudflare/worker-bundleritself.
-
#1334
77c8c9cThanks @threepointone! -createWorkerandcreateAppnow accept a handful of extra esbuild knobs that previously required forking or patching the package:jsx("transform" | "preserve" | "automatic")jsxImportSourcedefine(compile-time constant replacement)loader(per-extension loader overrides — e.g.{ ".svg": "text", ".wasm": "binary" }; built-in handling for.ts/.tsx/.js/.jsx/.json/.cssis preserved unless overridden, and longer extensions match first so".d.ts"wins over".ts"). The accepted values are deliberately narrowed to the portableBundlerLoaderset (js/jsx/ts/tsx/json/css/text/binary/base64/dataurl) — esbuild-specific loaders likefile/copy/empty/defaultare intentionally excluded.file/copywould silently break in this bundler today (they emit secondary output files that get discarded), and anything outside the portable set should go through the plugin escape hatch instead.conditions(package export conditions, e.g.["workerd", "worker", "browser"])
The first five are re-typed locally (
JsxMode,BundlerLoader) so the published.d.tsdoes not import fromesbuild-wasm— a future bundler swap is a refactor, not a breaking type change.For advanced consumers (RSC-style transforms, custom asset pipelines, codegen) there is also an explicit escape hatch:
__dangerouslyUseEsBuildPluginsDoNotUseOrYouWillBeFired?: unknown[]
The deliberately unwieldy name is the API contract: this option is not covered by semver, can change shape or be removed in any release, and ties the caller to esbuild's plugin shape — if this package switches bundlers, plugins authored against it will break. It is typed as
unknown[]at the public boundary (castPlugin[]fromesbuild-wasmwhen passing in) so the published types don't acquire a hard dependency on esbuild. User plugins run before the internal virtual-filesystem plugin, so theironResolve/onLoadclaims fire first.In
createApp, all of these options apply to both the server and client bundles.The internal
bundleWithEsbuildsignature was refactored from a long positional argument list to a single options object so future bundler knobs can be added without churning every call site. This is an internal change; no public API moved.Inspired by #1321 — thanks @bndkt for the draft and the RSC-on-Workers proof-of-concept that motivated it.
-
#1335
e59388dThanks @threepointone! - Fix: don't crash withCannot find package 'gojs'when imported from Node.Previously,
bundler.tsdid a top-level staticimport esbuildWasm from "./esbuild.wasm". In the Workers runtime that resolves to aWebAssembly.Modulenatively, but in Node 22+ (e.g. Vitest on GitHub Actions CI) Node's experimental ESM-WASM loader actually parses the file and tries to resolveesbuild-wasm's Go-runtime import namespacegojsas an npm package. That surfaced as the deeply confusing error reported in #1306:Cannot find package 'gojs' imported from .../@cloudflare/worker-bundler/dist/esbuild.wasmTwo changes:
- The
./esbuild.wasmimport is now lazy — it lives insideinitializeEsbuild()as a dynamicimport("./esbuild.wasm")call instead of a module-level static import. The package is now safely importable from any JavaScript runtime. - Before evaluating that dynamic import, the bundler checks
navigator.userAgent === "Cloudflare-Workers". If it's not running inside workerd, it throws an actionable error pointing the caller at@cloudflare/vitest-pool-workersinstead of letting Node surface the crypticgojsresolution failure.
A side benefit:
createWorker({ bundle: false })(transform-only mode, which never invokes esbuild) now also works in Node, because the WASM is never loaded on that code path.The README now also calls out the Workers-only requirement near the top.
While in there, sharpened a handful of unhelpful error messages to include actionable context:
- "Entry point/Server entry point/Client entry point ... not found" now lists the user-provided files in the bundle (skipping
node_modules/) so it's obvious whether the path is mistyped vs. missing entirely. - "Could not determine entry point" now spells out the full priority list it tried (
entryPointoption → wranglermain→package.json→ defaults). - npm registry errors include the package name, version, registry URL, and HTTP status text — e.g.
Registry returned 404 Not Found for "hno" at https://registry.npmjs.org/hno (package not found — check the name in package.json or set theregistryoption if it lives on a private registry). - The npm fetch-timeout error names the URL and notes the registry was slow/unreachable from the Worker.
- "Invalid package.json" includes both the path and the underlying parse error.
- "No output generated from esbuild" now names the entry point and explains the two real-world causes (a custom plugin claiming the entry without returning contents, or the entry resolving to an externalised module).
- The
-
#1277
0cd0487Thanks @zebp! - IntroduceFileSystemabstraction for all bundler APIs.The
filesoption oncreateWorkerandcreateAppnow accepts anyFileSystemimplementation in addition to a plainRecord<string, string>. This lets callers back the virtual filesystem with persistent or custom storage — for example, aDurableObjectKVFileSystemthat buffers writes in memory and flushes to Durable Object KV on demand, avoiding a KV write for every individual file operation.Three concrete implementations are exported from the package:
InMemoryFileSystem— aMap-backed filesystem suitable for tests and in-process pipelines. Accepts an optional seed object orMapof initial files.DurableObjectKVFileSystem— a Durable Object KV-backed filesystem with a write-overlay. Writes accumulate in memory and are flushed to KV in one batch whenflush()is called. Reads are served from the overlay first, so callers always observe their own writes immediately.DurableObjectRawFileSystem— a thin Durable Object KV-backed filesystem with no buffering. Every write is committed to KV synchronously. Use when per-write durability is preferred over batching.
createFileSystemSnapshotcreates anInMemoryFileSystemfrom any sync or async iterable of[path, content]pairs, bridging async storage backends (e.g.Workspacefrom@cloudflare/shell) to the synchronousFileSysteminterface.The
FileSystem.read()method returnsstring | null(null = file does not exist) rather than an empty string, eliminating the need for a separateexists()check.Plain
Record<string, string>objects continue to work unchanged — they are wrapped in anInMemoryFileSystemautomatically. -
#1277
0cd0487Thanks @zebp! - ExportinstallDependencies,hasDependencies, andInstallResultso callers can pre-warm aFileSystemwith npm packages independently ofcreateWorkerorcreateApp.When
createWorkerorcreateAppencounter aFileSystemthat already contains a package undernode_modules/, that package is skipped during installation, avoiding redundant network fetches. This makes a second call toinstallDependencies(or the internal call insidecreateWorker) a no-op for packages that were pre-installed into the sameFileSystem. -
#1277
0cd0487Thanks @zebp! - Add in-process TypeScript language service viacreateTypescriptLanguageService.createTypescriptLanguageServicewraps anyFileSystemin aTypescriptFileSystemthat mirrors every write and delete into an underlying virtual TypeScript environment. Diagnostics returned by the language service always reflect the current state of the filesystem — an edit that fixes a type error immediately clearsgetSemanticDiagnostics.TypeScript is pre-bundled as a browser-safe artifact so it runs inside the Workers runtime without Node.js APIs. Lib declarations are fetched from the TypeScript npm tarball at runtime.
Exposed under a separate
./typescriptsubpath export to keep the TypeScript bundle out of the main import path.
- #1145
94fac05Thanks @threepointone! - Separate assets from isolate:createAppnow returns assets for host-side serving instead of embedding them in the dynamic isolate. Removes DO wrapper code generation anddurableObjectoption — mounting is the caller's concern. Preview proxy replaced with Service Worker-based URL rewriting.
8fd45cfThanks @threepointone! - Initial publish (again)
18c51ecThanks @threepointone! - Initial publish