|
| 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