Skip to content

Commit 5342703

Browse files
committed
examples/worker, docs: opt shell commands in by import
Update the worker example and the worker-backend docs to the import-based command selection. The example imports the curl and sqlite groups and passes them to WorkerBackend's commands option, demonstrating that opting a command in is a single import and opting out is deleting it. The package README, the example README, and docs/12_worker_backend.md describe the always-on core, the per-command groups published at @cloudflare/computer/shell/*, the commands option, and the assembleShellModules helper for callers that build the Loader callback by hand.
1 parent 807aff5 commit 5342703

4 files changed

Lines changed: 94 additions & 16 deletions

File tree

docs/12_worker_backend.md

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -249,22 +249,58 @@ network-bound `git` subcommands do. See
249249
- `src/index.ts` holds the DO and the HTTP surface (the
250250
`/c/<name>/file/...` and `/c/<name>/exec` routes the container
251251
example also exposes).
252-
- No Dockerfile, no build script. The shell bundle ships with
253-
`@cloudflare/computer/backends/worker-shell` as `SHELL_MODULES`
254-
(a record of module name → source covering the entry plus
255-
every code-split chunk); the backend hands the whole record
256-
to the Loader callback itself.
252+
- No Dockerfile, no build script. The shell ships with
253+
`@cloudflare/computer/backends/worker-shell` as feature groups: an
254+
always-on core (`SHELL_CORE_MODULES`) plus one optional group per
255+
command at `@cloudflare/computer/shell/<feature>`. The backend
256+
assembles core with whatever groups you opt into and hands the
257+
result to the Loader callback itself.
257258

258-
The DO's backend wiring fits in three lines:
259+
The DO's backend wiring:
259260

260261
```ts
262+
import curlModules from "@cloudflare/computer/shell/curl";
263+
import sqliteModules from "@cloudflare/computer/shell/sqlite";
264+
261265
new WorkerShellBackend({
262266
loader: env.LOADER,
263267
workspace: { binding: "ContainerExample", id: ctx.id.toString() },
264268
ctx,
269+
commands: [curlModules, sqliteModules],
265270
})
266271
```
267272

268273
Run with `npm run dev --workspace @example/computer-worker`.
269-
The same `curl` recipes from the container example work without
270-
changes.
274+
The same `curl` recipes from the container example work once
275+
`curlModules` is passed to `commands`.
276+
277+
## Optional shell commands
278+
279+
Core carries the always-on command set (`cat`, `ls`, `grep`, `sed`,
280+
`awk`, `sort`, …). The heavier commands are split into optional
281+
groups that are opt-in by import: import a group from
282+
`@cloudflare/computer/shell/<feature>` and pass it to the
283+
`commands` option, and only then does its code enter your bundle.
284+
285+
```ts
286+
import curlModules from "@cloudflare/computer/shell/curl";
287+
import htmlToMarkdownModules from "@cloudflare/computer/shell/html-to-markdown";
288+
289+
// commands: [curlModules, htmlToMarkdownModules]
290+
```
291+
292+
A group you never import is unreachable in your module graph, so
293+
the bundler drops it — there is no build-time flag to set and no
294+
default-on cost to opt out of. The full set of optional groups is
295+
`curl`, `html-to-markdown`, `python`, `sqlite`, `js-exec`, `yq`,
296+
`file`, `xan`, and `jq`.
297+
298+
`curl` runs on a `SecureFetch` adapter over the isolate's global
299+
`fetch``undici` is redirected to a throwing stub at build time
300+
and never ships. Egress stays governed by the Dynamic Worker's
301+
`globalOutbound` (left `null`, i.e. closed), not by the shell, so
302+
enabling `curl` does not by itself open the network.
303+
304+
Consumers that build the Loader callback by hand (the `fetcher`
305+
path) assemble the modules table themselves with
306+
`assembleShellModules([...groups])` from the same package.

examples/worker-shell/README.md

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,32 @@ POST /c/<name>/exec { command | argv, cwd?, encoding? }
101101

102102
## Run it locally
103103

104-
No Docker, no extra build step. The shell ships as a record of
105-
pre-bundled modules (`SHELL_MODULES`) inside
106-
`@cloudflare/computer/backends/worker-shell`; `WorkerShellBackend` spreads
107-
the whole record into the Loader callback internally so the DO
108-
constructor stays a three-line backend invocation. The entry
109-
module parses on cold start; the dynamic chunks (python, js-exec,
110-
sqlite, curl, html-to-markdown) stay cold until a script reaches
111-
for them.
104+
No Docker, no extra build step. The shell ships as pre-bundled
105+
feature groups inside `@cloudflare/computer/backends/worker-shell`: an
106+
always-on core plus one optional group per command at
107+
`@cloudflare/computer/shell/<feature>`. `WorkerShellBackend` assembles
108+
core with whatever groups you pass to its `commands` option and
109+
spreads the result into the Loader callback internally. This
110+
example opts `curl` and `sqlite` in:
111+
112+
```ts
113+
import curlModules from "@cloudflare/computer/shell/curl";
114+
import sqliteModules from "@cloudflare/computer/shell/sqlite";
115+
116+
new WorkerShellBackend({
117+
loader: env.LOADER,
118+
workspace: { binding: "ContainerExample", id: ctx.id.toString() },
119+
ctx,
120+
commands: [curlModules, sqliteModules],
121+
});
122+
```
123+
124+
A group you never import (`html-to-markdown`, `python`, `js-exec`,
125+
`yq`, `file`, `xan`, `jq`, or either of the two above) is
126+
unreachable in the bundle and the bundler drops it — opting a
127+
command in is a single import, and opting out is deleting it. The
128+
core entry module parses on cold start; each opted-in group's
129+
chunks stay cold until a script reaches for them.
112130

113131
```sh
114132
npm run dev --workspace @example/computer-worker-shell

examples/worker-shell/src/index.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ import {
3636
withWorkspace,
3737
} from "@cloudflare/computer";
3838
import { WorkerShellBackend } from "@cloudflare/computer/backends/worker-shell";
39+
// Opt-in shell commands. Each import pulls one command group into
40+
// this Worker's bundle; a group you do not import is unreachable
41+
// and the bundler drops it. Pass the ones you want to the
42+
// WorkerShellBackend `commands` option below. Other importable groups:
43+
// @cloudflare/computer/shell/{html-to-markdown,python,js-exec,yq,
44+
// file,xan,jq}.
45+
import curlModules from "@cloudflare/computer/shell/curl";
46+
import sqliteModules from "@cloudflare/computer/shell/sqlite";
3947

4048
// Re-export so the runtime can wrap WorkspaceServiceProxy into a
4149
// loopback Fetcher binding. The DO reaches the wrapped class
@@ -60,6 +68,10 @@ export class ContainerExample extends withWorkspace(class extends DurableObject<
6068
loader: env.LOADER,
6169
workspace: { binding: "ContainerExample", id: ctx.id.toString() },
6270
ctx,
71+
// Only the groups listed here ship. Core (cat, ls, grep,
72+
// sed, …) is always included; drop an import above to
73+
// shrink the bundle by that command's cost.
74+
commands: [curlModules, sqliteModules],
6375
}),
6476
],
6577
// Mount the Bucket binding at /workspace/r2. Seed it with

packages/computer/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ Worker backend:
122122
```ts
123123
import { Workspace, WorkspaceServiceProxy } from "@cloudflare/computer";
124124
import { WorkerShellBackend } from "@cloudflare/computer/backends/worker-shell";
125+
import curlModules from "@cloudflare/computer/shell/curl";
125126
import { DurableObject } from "cloudflare:workers";
126127

127128
export { WorkspaceServiceProxy };
@@ -134,6 +135,7 @@ export class WorkerExample extends DurableObject<Env> {
134135
loader: this.env.LOADER,
135136
workspace: { binding: "WorkerExample", id: this.ctx.id.toString() },
136137
ctx: this.ctx,
138+
commands: [curlModules],
137139
}),
138140
],
139141
});
@@ -145,6 +147,16 @@ export class WorkerExample extends DurableObject<Env> {
145147
}
146148
```
147149

150+
The worker shell ships as feature groups: an always-on core plus
151+
one optional group per command at
152+
`@cloudflare/computer/shell/<feature>`. Import the groups you want
153+
and pass them to `WorkerShellBackend`'s `commands` option; a group you
154+
never import is unreachable in your bundle and the bundler drops
155+
it. The optional groups are `curl`, `html-to-markdown`, `python`,
156+
`sqlite`, `js-exec`, `yq`, `file`, `xan`, and `jq`. `curl` runs on
157+
the isolate's global `fetch` (no `undici` in the bundle); egress
158+
stays governed by the Dynamic Worker's `globalOutbound`.
159+
148160
Filesystem only — no execution backend:
149161

150162
```ts

0 commit comments

Comments
 (0)