Skip to content

Commit e03a2fa

Browse files
committed
docs: add custom bindings feature page
1 parent 278318c commit e03a2fa

File tree

2 files changed

+108
-0
lines changed

2 files changed

+108
-0
lines changed

docs/docs.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
"features/output-capture",
6565
"features/resource-limits",
6666
"features/child-processes",
67+
"features/custom-bindings",
6768
"process-isolation"
6869
]
6970
},

docs/features/custom-bindings.mdx

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
---
2+
title: Custom Bindings
3+
description: Expose host-side functions to sandboxed code.
4+
icon: "plug"
5+
---
6+
7+
Custom bindings let you give sandboxed code access to host capabilities beyond the built-in bridge — databases, caches, queues, AI models, or any custom API.
8+
9+
## Basic usage
10+
11+
Register a `bindings` object when creating the runtime. Each leaf function becomes callable from sandbox code via `SecureExec.bindings`.
12+
13+
```ts
14+
import {
15+
NodeRuntime,
16+
createNodeDriver,
17+
createNodeRuntimeDriverFactory,
18+
} from "@anthropic-ai/secure-exec";
19+
20+
const runtime = new NodeRuntime({
21+
systemDriver: createNodeDriver(),
22+
runtimeDriverFactory: createNodeRuntimeDriverFactory(),
23+
bindings: {
24+
db: {
25+
query: async (sql, params) => db.query(sql, params),
26+
insert: async (sql, values) => db.insert(sql, values),
27+
},
28+
cache: {
29+
get: async (key) => redis.get(key),
30+
set: async (key, val) => redis.set(key, val),
31+
},
32+
greet: (name) => `Hello, ${name}!`,
33+
},
34+
});
35+
```
36+
37+
Sandbox code accesses bindings through the frozen `SecureExec.bindings` global:
38+
39+
```js
40+
// Inside the sandbox
41+
const rows = await SecureExec.bindings.db.query("SELECT * FROM users", []);
42+
await SecureExec.bindings.cache.set("key", "value");
43+
const msg = SecureExec.bindings.greet("world"); // "Hello, world!"
44+
45+
// Destructure for convenience
46+
const { db, cache } = SecureExec.bindings;
47+
```
48+
49+
## Sync and async
50+
51+
Both sync and async host functions work. If the host function is `async` or returns a `Promise`, the sandbox call returns a `Promise`. Otherwise it returns the value directly.
52+
53+
```ts
54+
bindings: {
55+
// Sync — sandbox gets the return value immediately
56+
add: (a, b) => a + b,
57+
58+
// Async — sandbox must await the result
59+
fetchUser: async (id) => await db.users.findById(id),
60+
}
61+
```
62+
63+
## Serialization
64+
65+
Arguments and return values are serialized using V8 structured clone. Supported types:
66+
67+
| Type | Supported |
68+
| --- | --- |
69+
| Primitives (string, number, boolean, null, undefined) | Yes |
70+
| Plain objects and arrays | Yes |
71+
| `Uint8Array` / `ArrayBuffer` | Yes |
72+
| `Date`, `Map`, `Set`, `RegExp` | Yes |
73+
| `Error` objects | Yes |
74+
| Nested/circular references | Yes |
75+
| Functions | No |
76+
| Symbols | No |
77+
| `WeakMap` / `WeakSet` | No |
78+
79+
The same payload size limits apply as all bridge calls.
80+
81+
## Constraints
82+
83+
- **Valid identifiers**: binding keys must be valid JavaScript identifiers.
84+
- **Max depth**: nesting is limited to 4 levels.
85+
- **Max leaves**: up to 64 leaf functions per runtime.
86+
- **Reserved prefix**: keys starting with `_` are reserved for internal bridge names and will be rejected.
87+
- **Immutable**: bindings are set at runtime construction and cannot be changed. `SecureExec.bindings` is recursively frozen — sandbox code cannot mutate it.
88+
89+
## The `SecureExec` global
90+
91+
`SecureExec` is always present on `globalThis` inside the sandbox, even when no bindings are registered. It is non-writable and non-configurable.
92+
93+
```js
94+
SecureExec.bindings // user-provided bindings (empty object if none registered)
95+
```
96+
97+
## Types
98+
99+
```ts
100+
import type { BindingTree, BindingFunction } from "@anthropic-ai/secure-exec";
101+
102+
type BindingFunction = (...args: unknown[]) => unknown | Promise<unknown>;
103+
104+
interface BindingTree {
105+
[key: string]: BindingFunction | BindingTree;
106+
}
107+
```

0 commit comments

Comments
 (0)