> ## Documentation Index
> Fetch the complete documentation index at: https://docs.eco.com/llms.txt
> Use this file to discover all available pages before exploring further.

# @eco-incorp/sauce-compiler API

> Every export of @eco-incorp/sauce-compiler 2.3.0: compile, ready, init and initSync, clearFunctionCache, functionCacheStats, and the CompileOptions, CompileResult, AccountManifest, AccountEntry, AccountRole, ResolveModule, ResolvePackage, SauceTarget, FnCacheStats and WasmSource types, with the package's own JSDoc.

`@eco-incorp/sauce-compiler` is the SauceScript compiler compiled to WebAssembly: a thin `wasm-bindgen` marshalling layer over the Rust compiler core, with no compiler logic of its own. The core is I/O-free, so the JS host supplies a synchronous resolver. One package ships two builds of the same wasm and picks between them by `exports` condition.

| Entry | Resolves to | Initialization |
| - | - | - |
| `@eco-incorp/sauce-compiler` in Node (`require` or ESM `import`) | CommonJS build that loads the wasm from disk | Nothing to await |
| `@eco-incorp/sauce-compiler` in browsers and bundlers | ESM build | Call the default export `init()` once before the first `compile` |
| `@eco-incorp/sauce-compiler/ready` | Either | `const { compile } = await ready();` initializes where needed and is a no-op otherwise |
| `@eco-incorp/sauce-compiler/node`, `/web` | The specific build | As above |

The package ships its own TypeScript types, so a consumer does not declare them.

<Note>
  Reproduced from `web/sauce_wasm.d.ts` and `web/ready.d.ts` in `@eco-incorp/sauce-compiler` 2.3.0. The Node build shares the same declarations. The SDK's `@eco-incorp/sauce/compiler` export re-exports `compile` and its types and adds the compact-argument codec; `ready`, `clearFunctionCache` and `functionCacheStats` are available only from this package.
</Note>

## Functions

### `compile`

Compile a SauceScript program to Sauce bytecode. The option and result shapes are `CompileOptions` and `CompileResult` below. Validation, compile and resolve failures **throw a JS `Error`**. Source diagnostics include the rule that was broken, the source line and a caret under the span; option and resolver errors may have no span. A host callback's thrown message is preserved in the chain.

```typescript theme={null}
export function compile(options: CompileOptions): CompileResult;
```

### `ready`

Get the compiler, initialising the wasm if this environment needs it. The same call in Node and in the browser: the CommonJS build is already initialised by the time it resolves, and the browser build is initialised by it. Safe to call as often as you like: initialisation happens at most once, concurrent callers share the one attempt, and a failed attempt is not cached, so a retry is a real retry. The first successful `source` is the one used; a later one is ignored, because wasm initialisation is global to the module. At run time use Node or a bundler that supports package `exports` subpaths; TypeScript's `moduleResolution` controls type lookup only.

```typescript theme={null}
import { ready } from "@eco-incorp/sauce-compiler/ready";

const { compile } = await ready();
const source = new TextEncoder().encode("function main() { return 1; }");
const { bytecode } = compile({ target: "evm", resolve: () => source });
```

```typescript theme={null}
export declare function ready(source?: WasmSource): Promise<SauceCompiler>;
```

### `init` (default export) and `initSync`

The ESM build's initializers. `init` makes a request when given a `RequestInfo` or `URL` and otherwise calls `WebAssembly.instantiate` directly; `initSync` instantiates bytes or a precompiled `WebAssembly.Module`. Passing the input directly rather than wrapped in an object is deprecated.

```typescript theme={null}
export default function __wbg_init(module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;
export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;

export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
export type SyncInitInput = BufferSource | WebAssembly.Module;
```

### `clearFunctionCache`

Empty this WASM instance's per-function lowering cache and reset its counters. The store persists across `compile` calls, is bounded and empties automatically when full. Changed source or consulted bindings invalidate reuse automatically, so clearing is for releasing cached lowerings or measuring a cold compile; it does not clear a file-content cache maintained by your resolver.

```typescript theme={null}
export function clearFunctionCache(): void;
```

### `functionCacheStats`

Read the per-function IR-lowering cache's counters, `{ hits, misses, inserts }`, for measuring warm reuse across a route sweep. Counters are cumulative until `clearFunctionCache()` resets them.

```typescript theme={null}
export function functionCacheStats(): FnCacheStats;
```

## Types

### `SauceTarget`

The engine a program is compiled for.

```typescript theme={null}
export type SauceTarget = "evm" | "svm";
```

### `ResolveModule`

Fetch a module's bytes. A Node `Buffer` is a `Uint8Array`. Returning `undefined` or `null` means **nothing at this path**, which is the signal the per-target arm probe relies on to fall back to a module's neutral arm (`token.ts` after `token.evm.ts` misses). A **throw** means the path names something that could not be read: it propagates rather than falling back, so a miss must not throw. Any other return type is a resolve error. A `.json` path is asked for either as a contract ABI or as a document the source imports as data (`with { type: "json" }`); both are bytes here, so serve any `.json` the program names.

```typescript theme={null}
export type ResolveModule = (path: string) => Uint8Array | undefined | null;
```

### `ResolvePackage`

Map a bare specifier (`"@sauce/token"`) to a path `resolve` accepts. `undefined` or `null` declines, falling back to using the specifier as a path; a throw means the package is not installed. `importer` is the resolved path of the importing module.

```typescript theme={null}
export type ResolvePackage = (specifier: string, importer: string) => string | undefined | null;
```

### `CompileOptions`

| Option | Type | Required | Notes from the declaration |
| - | - | - | - |
| `target` | `SauceTarget` | Yes | |
| `resolve` | `ResolveModule` | Yes | |
| `resolvePackage` | `ResolvePackage` | No | |
| `entry` | `string` | No | The entry module the resolver is asked for first. Defaults to `"main.js"`. |
| `contracts` | `Array<[name: string, path: string]>` | No | `[name, path]` pairs declaring contracts the host holds by path. Each `path` resolves as a bare `import Name from "./path.json"` would, and emits the same bytes. The same specifier under `with { type: "json" }` reads the file as data rather than as an ABI. |
| `inlineContracts` | `Array<[name: string, abi: string]>` | No | `[name, abi]` pairs declaring contracts whose ABI JSON is given directly. Applied to the entry module only, exactly like `contracts`; a name colliding with a `contracts` entry, an inline `import`, another `inlineContracts` entry, or a declared function is a compile error. |
| `ambient` | `Array<string>` | No | Module specifiers whose exports are broadcast into every module with no `import` line. An ambient module defining `main` is a compile error. Ambient always loses to user code. A module has one namespace, so an occupied name blocks the broadcast on both channels. Two different ambient modules exporting the same name is a compile error. An absolute path, a per-target arm, a subpath, or a `.json` file is refused as a broadcast root. |
| `defines` | `Array<[name: string, value: string]>` | No | Compile-time parameters injected into every module as a module-scope `const`. A value is a decimal or `0x` hex integer string with an optional trailing `n` and `_` separators; a string because a define is a 256-bit word. A define **overrides** the module's own `const` of that name, on both channels. It does not override a module-scope `let`, a declared function, a lookup table, a bound contract, a JSON data import's binding, or an import's local alias (each a compile error naming the define). The value must be assignable to the declaration's type (only `0` or `1` reaches a `boolean`). A repeated name is an error. The name is program-wide, including packages you did not write. |
| `optimize` | `boolean` | No | Enable compiler optimizations (constant folding and propagation, bounded loop unrolling, scalar expression reuse, invariant tuple-read reuse, scalar helper inlining). Defaults to `true`; validation still runs when `false`. |
| `compactArgs` | `boolean` | No | Use compact-v1 entry arguments instead of ABI encoding. Defaults to `false`. Encode arguments with the returned `entrySchema`; ABI-encoded arguments cannot be substituted. |
| `cache` | `boolean` | No | The per-function lowering cache. Defaults to `true`. Memoizes each declared function's lowering in a bounded store that empties automatically when full; changed source or consulted bindings invalidate reuse. Set `false` to bypass lookup and insertion for one compile; `clearFunctionCache()` empties the store. |

```typescript theme={null}
export interface CompileOptions {
    target: SauceTarget;
    resolve: ResolveModule;
    resolvePackage?: ResolvePackage;
    entry?: string;
    contracts?: Array<[name: string, path: string]>;
    inlineContracts?: Array<[name: string, abi: string]>;
    ambient?: Array<string>;
    defines?: Array<[name: string, value: string]>;
    optimize?: boolean;
    compactArgs?: boolean;
    cache?: boolean;
}
```

### `CompileResult`

`bytecode` is the reusable program without the caller's argument values. `isaRevision` is the instruction-set compatibility identifier, independent of the npm version. `entryEncoding` is the encoding the program expects for entry arguments; `entrySchema` is present only with compact encoding and is the exact schema to pass to the compact codec. `manifest` is the SVM account manifest; `undefined` on the EVM, which has no such concept.

```typescript theme={null}
export interface CompileResult {
    bytecode: Uint8Array;
    isaRevision: "stack-compact-v2";
    entryEncoding: "abi-v1" | "compact-v1";
    entrySchema?: Uint8Array;
    manifest?: AccountManifest;
}
```

### `AccountRole`

What a caller's account must satisfy at a declared slot: the four values of Solana's own `AccountRole`, so an SDK maps one onto an `AccountMeta` directly. It is the program author's assertion, with the trust model of an ABI declaration: the compiler cannot know what a program invoked by CPI does with the accounts it is handed, so nothing here is inferred. A bare `Account` is `"readonly"`.

```typescript theme={null}
export type AccountRole = "readonly" | "writable" | "readonly_signer" | "writable_signer";
```

### `AccountEntry`

One entry in the attach contract. A `slot` is an `Account` parameter of `main`, read by the engine at `index`, carrying the source parameter's `name` and the role it `requires` of whatever account is attached there. `remaining` is not an account but a position: it marks where the caller's own variable-length accounts begin, and `from` is the index the first of them lands at. It appears only when the program reads that tail (`svm.remainingAccount` or `svm.remainingAccounts`), and it is always last.

```typescript theme={null}
export type AccountEntry =
  | { kind: "slot"; index: number; name: string; requires: AccountRole }
  | { kind: "remaining"; from: number };
```

### `AccountManifest`

The index-to-account contract a caller attaches accounts against. SVM only.

```typescript theme={null}
export interface AccountManifest {
    accounts: AccountEntry[];
}
```

### `FnCacheStats`

The per-function IR-lowering cache's counters, from `functionCacheStats()`.

```typescript theme={null}
export interface FnCacheStats {
    hits: number;
    misses: number;
    inserts: number;
}
```

### `WasmSource` and `SauceCompiler` (from `/ready`)

What `compile` needs before it can run, where that differs by environment. Omit it and the browser build resolves the wasm next to its own module, which is what a bundler rewrites to an asset URL. Pass bytes or a URL when that does not apply. The Node build ignores it. Deliberately spelled without DOM types so the Node build typechecks for a consumer with no DOM lib; `{ href: string }` is how a `URL` is accepted structurally. A `Response` still works at run time in a browser; widen it locally if you need one: `ready(response as unknown as WasmSource)`.

```typescript theme={null}
export type WasmSource = ArrayBuffer | ArrayBufferView | { href: string } | string;

export interface SauceCompiler {
  compile(options: CompileOptions): CompileResult;
}
```

### `InitOutput`

The raw wasm-bindgen instance returned by `init` and `initSync`. Consumers use `compile`, `clearFunctionCache` and `functionCacheStats` from the module instead of the fields on this object.

```typescript theme={null}
export interface InitOutput {
    readonly memory: WebAssembly.Memory;
    readonly clearFunctionCache: () => void;
    readonly compile: (a: any) => [number, number, number];
    readonly functionCacheStats: () => [number, number, number];
    // wasm-bindgen internals omitted
}
```

## Complete example in Node

Create `src/main.ts` with this program:

```typescript main.ts theme={null}
function main(amount: Uint256): Uint256 {
  return amount + 1;
}
```

Install `@eco-incorp/sauce-compiler@2.3.0`, then run the following with Node 24 or later. If you typecheck with `tsc`, install `typescript` and `@types/node` as development dependencies.

```typescript compile.ts theme={null}
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
import { compile } from "@eco-incorp/sauce-compiler";

const root = resolve("src");
try {
  const { bytecode } = compile({
    entry: "main.ts",
    target: "evm",
    resolve: (path) => {
      try {
        return readFileSync(resolve(root, path));
      } catch (error) {
        // A missing target-specific module lets the compiler try the neutral module.
        if ((error as NodeJS.ErrnoException).code === "ENOENT") return undefined;
        throw error;
      }
    },
  });
  console.log(`Compiled ${bytecode.length} bytes`);
} catch (error) {
  console.error("Compilation failed:", error);
  process.exitCode = 1;
}
```

## Next steps

* [Append arguments and execute a program](/programmable-transactions/sauce/getting-started).
* [Read the SauceScript language reference](/programmable-transactions/sauce/saucescript).
