Skip to content

Commit 480beb6

Browse files
docs: add file watching API documentation
Add comprehensive documentation for the new file watching feature: - New file-watching.mdx API reference page covering watch() method - Event types, filtering, cancellation, and use cases - Cross-links from files.mdx to file watching - Updated API index with file watching card Synced from cloudflare/sandbox-sdk PR #324
1 parent 2a27bf6 commit 480beb6

File tree

3 files changed

+294
-0
lines changed

3 files changed

+294
-0
lines changed
Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
---
2+
title: File watching
3+
pcx_content_type: concept
4+
sidebar:
5+
order: 4
6+
---
7+
8+
import { TypeScriptExample } from "~/components";
9+
10+
Monitor filesystem changes in real-time using native Linux inotify. Watch directories for file creation, modification, deletion, and moves.
11+
12+
## watch()
13+
14+
Start watching a directory for filesystem changes. Returns a `FileWatch` instance that emits events for file changes.
15+
16+
```ts
17+
const watcher = await sandbox.watch(path: string, options?: WatchOptions): Promise<WatchHandle>
18+
```
19+
20+
**Parameters**:
21+
- `path` - Absolute path to watch (for example, `/workspace/src`)
22+
- `options` (optional):
23+
- `recursive` - Watch subdirectories recursively (default: `true`)
24+
- `exclude` - Patterns to exclude (default: `['.git', 'node_modules', '.DS_Store']`)
25+
- `include` - Only emit events for files matching these patterns
26+
- `onEvent` - Callback for file change events
27+
- `onError` - Callback for watch errors
28+
- `signal` - AbortSignal for cancellation
29+
30+
**Returns**: `Promise<WatchHandle>` with:
31+
- `id` - Unique watch identifier
32+
- `path` - Watched path
33+
- `stop()` - Stop watching
34+
35+
<TypeScriptExample>
36+
```
37+
// Watch for all changes in src directory
38+
const watcher = await sandbox.watch('/workspace/src', {
39+
recursive: true,
40+
onEvent: (event) => {
41+
console.log(`${event.type}: ${event.path}`);
42+
},
43+
onError: (error) => {
44+
console.error('Watch error:', error);
45+
}
46+
});
47+
48+
// Stop watching when done
49+
await watcher.stop();
50+
```
51+
</TypeScriptExample>
52+
53+
## Event types
54+
55+
File change events contain:
56+
57+
```ts
58+
interface WatchEvent {
59+
type: 'create' | 'modify' | 'delete' | 'rename';
60+
path: string;
61+
isDirectory: boolean;
62+
timestamp: string;
63+
}
64+
```
65+
66+
Event types:
67+
- `create` - File or directory created
68+
- `modify` - File content changed
69+
- `delete` - File or directory deleted
70+
- `rename` - File or directory moved (generates two events: delete at old path, create at new path)
71+
72+
<TypeScriptExample>
73+
```
74+
const watcher = await sandbox.watch('/workspace', {
75+
onEvent: (event) => {
76+
if (event.type === 'create' && !event.isDirectory) {
77+
console.log(`New file: ${event.path}`);
78+
} else if (event.type === 'modify') {
79+
console.log(`File modified: ${event.path} at ${event.timestamp}`);
80+
} else if (event.type === 'delete') {
81+
console.log(`${event.isDirectory ? 'Directory' : 'File'} deleted: ${event.path}`);
82+
}
83+
}
84+
});
85+
```
86+
</TypeScriptExample>
87+
88+
## Filtering events
89+
90+
### Include patterns
91+
92+
Use glob-style patterns to filter which files trigger events:
93+
94+
<TypeScriptExample>
95+
```
96+
// Only watch TypeScript files
97+
const watcher = await sandbox.watch('/workspace/src', {
98+
include: ['*.ts', '*.tsx']
99+
});
100+
101+
// Watch specific file types
102+
const watcher = await sandbox.watch('/workspace', {
103+
include: ['*.json', '*.yaml', '*.yml']
104+
});
105+
```
106+
</TypeScriptExample>
107+
108+
:::note[Pattern matching]
109+
Include patterns match against the filename only (not the full path). Use `*.ts` to match all TypeScript files recursively.
110+
:::
111+
112+
### Exclude patterns
113+
114+
Exclude patterns prevent events for matching paths. Default excludes are `.git`, `node_modules`, and `.DS_Store`.
115+
116+
<TypeScriptExample>
117+
```
118+
// Custom exclusions (replaces defaults)
119+
const watcher = await sandbox.watch('/workspace', {
120+
exclude: ['.git', 'node_modules', 'dist', '.cache']
121+
});
122+
123+
// Watch everything except hidden files
124+
const watcher = await sandbox.watch('/workspace', {
125+
exclude: ['.*']
126+
});
127+
```
128+
</TypeScriptExample>
129+
130+
:::caution[Exclude replaces defaults]
131+
When you provide `exclude` patterns, they replace the default exclusions. If you want to keep the defaults, include them explicitly: `exclude: ['.git', 'node_modules', '.DS_Store', 'your-pattern']`
132+
:::
133+
134+
## Cancellation
135+
136+
Stop watching using the `stop()` method or an AbortSignal:
137+
138+
<TypeScriptExample>
139+
```
140+
// Stop explicitly
141+
const watcher = await sandbox.watch('/workspace/src');
142+
await watcher.stop();
143+
144+
// Use AbortController for cancellation
145+
const controller = new AbortController();
146+
const watcher = await sandbox.watch('/workspace/src', {
147+
signal: controller.signal,
148+
onEvent: (event) => console.log(event)
149+
});
150+
151+
// Later: cancel the watch
152+
controller.abort();
153+
```
154+
</TypeScriptExample>
155+
156+
## Watch scope
157+
158+
### Recursive watching
159+
160+
By default, watches are recursive and monitor all subdirectories:
161+
162+
<TypeScriptExample>
163+
```
164+
// Watch entire project (recursive by default)
165+
const watcher = await sandbox.watch('/workspace/myproject');
166+
167+
// Non-recursive: only watch the specified directory
168+
const watcher = await sandbox.watch('/workspace/logs', {
169+
recursive: false
170+
});
171+
```
172+
</TypeScriptExample>
173+
174+
### Multiple watches
175+
176+
You can create multiple watches simultaneously:
177+
178+
<TypeScriptExample>
179+
```
180+
// Watch different directories with different handlers
181+
const srcWatcher = await sandbox.watch('/workspace/src', {
182+
include: ['*.ts', '*.tsx'],
183+
onEvent: (e) => console.log('Source change:', e.path)
184+
});
185+
186+
const configWatcher = await sandbox.watch('/workspace', {
187+
include: ['*.json', '*.yaml'],
188+
recursive: false,
189+
onEvent: (e) => console.log('Config change:', e.path)
190+
});
191+
192+
// Clean up both
193+
await Promise.all([srcWatcher.stop(), configWatcher.stop()]);
194+
```
195+
</TypeScriptExample>
196+
197+
## Use cases
198+
199+
### Hot reload
200+
201+
Restart services when code changes:
202+
203+
<TypeScriptExample>
204+
```
205+
let serverProcess = null;
206+
207+
const watcher = await sandbox.watch('/workspace/src', {
208+
include: ['*.js', '*.ts'],
209+
onEvent: async (event) => {
210+
if (event.type === 'modify' || event.type === 'create') {
211+
console.log('Code changed, restarting server...');
212+
213+
if (serverProcess) {
214+
await serverProcess.kill();
215+
}
216+
217+
serverProcess = await sandbox.execBackground('npm start');
218+
}
219+
}
220+
});
221+
```
222+
</TypeScriptExample>
223+
224+
### Build automation
225+
226+
Trigger builds on file changes:
227+
228+
<TypeScriptExample>
229+
```
230+
const watcher = await sandbox.watch('/workspace/src', {
231+
onEvent: async (event) => {
232+
if (event.type === 'modify') {
233+
console.log('Building...');
234+
const result = await sandbox.exec('npm run build');
235+
236+
if (result.exitCode === 0) {
237+
console.log('Build complete');
238+
} else {
239+
console.error('Build failed:', result.stderr);
240+
}
241+
}
242+
}
243+
});
244+
```
245+
</TypeScriptExample>
246+
247+
### File sync monitoring
248+
249+
Track when files are written to a directory:
250+
251+
<TypeScriptExample>
252+
```
253+
const files = new Set();
254+
255+
const watcher = await sandbox.watch('/workspace/uploads', {
256+
onEvent: (event) => {
257+
if (event.type === 'create' && !event.isDirectory) {
258+
files.add(event.path);
259+
console.log(`New file uploaded: ${event.path}`);
260+
console.log(`Total files: ${files.size}`);
261+
}
262+
}
263+
});
264+
```
265+
</TypeScriptExample>
266+
267+
## Implementation details
268+
269+
File watching uses Linux inotify under the hood:
270+
- Native filesystem event notifications (not polling)
271+
- Low overhead for monitoring large directory trees
272+
- Events delivered in real-time via Server-Sent Events (SSE)
273+
- Automatic cleanup when the watch is stopped or the sandbox sleeps
274+
275+
## Limitations
276+
277+
- **Linux only**: File watching requires Linux inotify (available in all sandbox containers)
278+
- **Path must exist**: The watched path must exist before calling `watch()`
279+
- **No cross-mount watching**: Cannot watch paths that span different filesystem mounts
280+
- **Event coalescing**: Rapid changes to the same file may be coalesced into fewer events
281+
282+
## Related resources
283+
284+
- [Files API](/sandbox/api/files/) - File operations reference
285+
- [Commands API](/sandbox/api/commands/) - Execute commands including background processes

src/content/docs/sandbox/api/files.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,4 +208,5 @@ await sandbox.gitCheckout('https://github.com/user/repo', {
208208
## Related resources
209209

210210
- [Manage files guide](/sandbox/guides/manage-files/) - Detailed guide with best practices
211+
- [File watching API](/sandbox/api/file-watching/) - Monitor filesystem changes in real-time
211212
- [Commands API](/sandbox/api/commands/) - Execute commands

src/content/docs/sandbox/api/index.mdx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ The Sandbox SDK provides a comprehensive API for executing code, managing files,
3535
Read, write, and manage files in the sandbox filesystem. Includes directory operations and file metadata.
3636
</LinkTitleCard>
3737

38+
<LinkTitleCard
39+
title="File watching"
40+
href="/sandbox/api/file-watching/"
41+
icon="eye-on"
42+
>
43+
Monitor filesystem changes in real-time. Watch directories for file creation, modification, deletion, and moves.
44+
</LinkTitleCard>
45+
3846
<LinkTitleCard
3947
title="Code Interpreter"
4048
href="/sandbox/api/interpreter/"

0 commit comments

Comments
 (0)