tuffite0.1
THE CONTRACT, IN DETAIL

JavaScript & ShellAPI

Native facades and declaration contracts, straight from source.

Experimental source release. Production hardening and published SDK packages are still in progress.

Use the generated native facade#

Native methods return promises and require a matching origin capability. The following contracts are generated from the Framework’s checked-in TypeScript declarations. bigint values, opaque handles, and binary payloads retain their declared codec semantics.

javascript
import '/tuffite-shell-api.js';
const windows = await window.tuffite.window.list();

The window.tuffite bridge#

The native runtime exposes window.tuffite in eligible application and Explorer main documents. Its NativeBridge contract includes invoke(), postMessage(), addEventListener(), and removeEventListener(). Generated modules extend this same object with native facades such as tuffite.window. A normal browser tab does not provide the native bridge.

Subscribe and unsubscribe to events#

Listeners use the EventTarget API. addEventListener(type, listener, options?) accepts a capture boolean or AddEventListenerOptions, including once and signal. removeEventListener(type, listener, options?) must use the same function and matching capture value. In React, subscribe in an effect and remove the listener in its cleanup.

  • channel — native application events, with {channel, data: Uint8Array}. Decode data using your application event contract; it is not automatically JSON.
  • message — Explorer-tree JSON messages, with {data, from}. A business channel named message is still received through the channel event type.
  • navigation, open, popup, newwindow — bubbled Explorer requests with {url, disposition, userGesture, from}. dialog — an ExplorerDialogController with accept() and dismiss(). See Explorer API for propagation and ownership rules.
javascript
const onChannel = (event) => {
  const { channel, data } = event.detail; // data: Uint8Array
  if (channel === 'app:changed') {
    console.log(channel, data);
  }
};
window.tuffite.addEventListener('channel', onChannel);

// During component cleanup, use the same listener reference.
window.tuffite.removeEventListener('channel', onChannel);

Send Explorer messages#

postMessage(data, {to}?) returns Promise<boolean>. The default target is top; parent and browser-issued surface refs are also accepted. Data must be JSON-serializable. The browser validates routing and ownership. A true result reports acceptance and delivery or queueing, not a response from the recipient.

javascript
await window.tuffite.postMessage({ type: 'ready' }, { to: 'parent' });
const onMessage = ({ detail: { data, from } }) => {
  console.log(data, from);
};
window.tuffite.addEventListener('message', onMessage);
// Later:
window.tuffite.removeEventListener('message', onMessage);

Low-level binary invocation#

invoke(channel, payload) returns Promise<Uint8Array> and requires the route’s native permission. It does not route through the Explorer tree or accept a to option. Use generated typed facades for normal application calls; they handle command identities, codecs, schema fingerprints, and protocol validation.

javascript
const response = await window.tuffite.invoke(route, binaryPayload);
// binaryPayload and response are Uint8Array.

Runtime helpers and errors#

tuffite/runtime exports TuffiteError, invokeBinary(), createCommandApi(), createTypedCommandApi(), and createFrameworkApi(), plus codec and bridge types. These helpers serve generated bindings and tooling. TuffiteError provides code and optional requestId/cause. The package is served as /tuffite-runtime.js in native application packages.

JavaScript package exports#

The complete declarations below are generated from every types entry in the JavaScript package exports. This includes NativeBridge event overloads, runtime helpers, Explorer types, and the development-only Vite plugin. Filter by export path, type, or member name.

tuffite
typescript
// Generated from ../../framework/shell_api/common.d.ts, ../../framework/shell_api/dialog.d.ts, ../../framework/shell_api/path.d.ts, ../../framework/shell_api/remoting.d.ts, ../../framework/shell_api/fs.d.ts, ../../framework/shell_api/storage.d.ts, ../../framework/shell_api/log.d.ts, ../../framework/shell_api/network.d.ts, ../../framework/shell_api/utility.d.ts, ../../framework/shell_api/window.d.ts. Do not edit.

declare global {
  interface Window {
    readonly tuffite: typeof import('./dialog').tuffite & typeof import('./path').tuffite & typeof import('./remoting').tuffite & typeof import('./fs').tuffite & typeof import('./storage').tuffite & typeof import('./log').tuffite & typeof import('./network').tuffite & typeof import('./utility').tuffite & typeof import('./window').tuffite & import('../runtime').NativeBridge;
  }
}

export {};
View source
tuffite/runtime
typescript
export type Codec = Readonly<Record<string, unknown>>;

export type TuffiteErrorCode =
  | "invalid_argument"
  | "incompatible_abi"
  | "invalid_handle"
  | "unavailable"
  | "resource_exhausted"
  | "internal"
  | "transport_unavailable"
  | "invalid_request"
  | "unknown_command"
  | "handler_failed"
  | "decode_error"
  | "protocol_mismatch"
  | "schema_mismatch"
  | "command_failed"
  | (string & {});

export class TuffiteError extends Error {
  readonly code: TuffiteErrorCode;
  readonly requestId?: bigint;
  readonly cause?: unknown;
  constructor(
    code: TuffiteErrorCode,
    message: string,
    options?: Readonly<{ requestId?: bigint; cause?: unknown }>,
  );
}

export interface ChannelEvent extends Event {
  readonly detail: Readonly<{ channel: string; data: Uint8Array }>;
}

export interface ExplorerMessageEvent<T = unknown> extends Event {
  readonly detail: Readonly<{ data: T; from: string }>;
}

export interface ExplorerOpenEvent extends Event {
  readonly detail: Readonly<{
    url: string;
    disposition: string;
    userGesture: boolean;
    from: string;
  }>;
}

export interface ExplorerDialogController {
  readonly type: "alert" | "confirm" | "prompt" | "beforeunload";
  readonly message: string;
  readonly defaultValue: string;
  readonly isReload: boolean;
  readonly from: string;
  accept(promptText?: string): Promise<boolean>;
  dismiss(): Promise<boolean>;
}

export interface ExplorerDialogEvent extends Event {
  readonly detail: ExplorerDialogController;
}

export type ExplorerSurfaceRef = string & {
  readonly __tuffiteExplorerSurfaceRef: unique symbol;
};
export type ExplorerMessageTarget = "parent" | "top" | ExplorerSurfaceRef;

export interface NativeBridge extends EventTarget {
  invoke(channel: string, payload: Uint8Array): Promise<Uint8Array>;
  postMessage(
    data: unknown,
    options?: Readonly<{ to?: ExplorerMessageTarget }>,
  ): Promise<boolean>;
  addEventListener(
    type: "channel",
    listener: (event: ChannelEvent) => void,
    options?: boolean | AddEventListenerOptions,
  ): void;
  removeEventListener(
    type: "channel",
    listener: (event: ChannelEvent) => void,
    options?: boolean | EventListenerOptions,
  ): void;
  addEventListener(
    type: "message",
    listener: (event: ExplorerMessageEvent) => void,
    options?: boolean | AddEventListenerOptions,
  ): void;
  removeEventListener(
    type: "message",
    listener: (event: ExplorerMessageEvent) => void,
    options?: boolean | EventListenerOptions,
  ): void;
  addEventListener(
    type: "open" | "popup" | "newwindow" | "navigation",
    listener: (event: ExplorerOpenEvent) => void,
    options?: boolean | AddEventListenerOptions,
  ): void;
  removeEventListener(
    type: "open" | "popup" | "newwindow" | "navigation",
    listener: (event: ExplorerOpenEvent) => void,
    options?: boolean | EventListenerOptions,
  ): void;
  addEventListener(
    type: "dialog",
    listener: (event: ExplorerDialogEvent) => void,
    options?: boolean | AddEventListenerOptions,
  ): void;
  removeEventListener(
    type: "dialog",
    listener: (event: ExplorerDialogEvent) => void,
    options?: boolean | EventListenerOptions,
  ): void;
}

export type CommandEntry = readonly [
  path: string,
  id: string,
  schemaFingerprint: string,
  request: readonly Codec[],
  response: Codec,
];

export type ConstantEntry = readonly [path: string, value: unknown];

export function invokeBinary(
  channel: string,
  commandId: bigint,
  schemaFingerprint: bigint,
  payload?: Uint8Array,
): Promise<Uint8Array>;

export function createCommandApi(
  entries: readonly (readonly [path: string, id: bigint])[],
  typed?: boolean,
  rootTarget?: object,
  channelPrefix?: string,
): object;

export function createTypedCommandApi(
  entries: readonly CommandEntry[],
  constants?: readonly ConstantEntry[],
  namespace?: string,
): object;

export type FrameworkEntry = readonly [
  path: string,
  request: readonly Codec[],
  response: Codec,
];

export function createFrameworkApi(
  entries: readonly FrameworkEntry[],
  constants?: readonly ConstantEntry[],
): object;
View source
tuffite/explorer
typescript
export type ExplorerNavigationPolicy = "emit" | "allow";
export type ExplorerDialogPolicy = "emit" | "suppress";
export type ExplorerJavaScriptWorld = "isolated" | "main";
export type ExplorerPartitionMode = "shared" | "persist" | "memory";

export interface ExplorerNavigationState {
  readonly url: string;
  readonly title: string;
  readonly documentId: string;
  readonly canGoBack: boolean;
  readonly canGoForward: boolean;
  readonly isLoading: boolean;
  readonly rendererProcess: Readonly<{
    id: number;
    ownerId: number;
    isolated: boolean;
  }>;
  readonly storagePartition: Readonly<{
    domain: string;
    name: string;
    inMemory: boolean;
    isDefault: boolean;
    mode: ExplorerPartitionMode;
    shared: boolean;
    inherited: boolean;
    requested: string;
    createdDomain: string;
    createdName: string;
    createdInMemory: boolean;
    createdIsDefault: boolean;
  }>;
}

export interface ExplorerLoadErrorState extends ExplorerNavigationState {
  readonly errorCode: number;
  readonly errorDescription: string;
}

export interface ExplorerOpenDetail {
  readonly url: string;
  readonly disposition: string;
  readonly userGesture: boolean;
  readonly from: string;
}

export interface ExplorerDialogController {
  readonly type: "alert" | "confirm" | "prompt" | "beforeunload";
  readonly message: string;
  readonly defaultValue: string;
  readonly isReload: boolean;
  readonly from: string;
  accept(promptText?: string): Promise<boolean>;
  dismiss(): Promise<boolean>;
}

export type ExplorerTransferState = "pending" | "attaching" | "transferred" | "closed";

/** Pending resources are owned by the source document, independently of GC. */
export interface ExplorerTransfer extends EventTarget {
  readonly token: string;
  readonly state: ExplorerTransferState;
  close(): Promise<void>;
  onstatechange: ((event: Event) => void) | null;
}

export interface ExplorerEventMap {
  download: CustomEvent<ExplorerDownload>;
  attached: Event;
  detached: Event;
  loadstart: CustomEvent<ExplorerNavigationState>;
  loadstop: CustomEvent<ExplorerNavigationState>;
  loadcommit: CustomEvent<ExplorerNavigationState>;
  loaderror: CustomEvent<ExplorerLoadErrorState>;
  open: CustomEvent<ExplorerOpenDetail>;
  popup: CustomEvent<ExplorerOpenDetail>;
  newwindow: CustomEvent<ExplorerOpenDetail>;
  navigation: CustomEvent<ExplorerOpenDetail>;
  dialog: CustomEvent<ExplorerDialogController>;
  message: CustomEvent<unknown>;
}

export interface HTMLExplorerElement extends HTMLElement {
  src: string;
  /** Empty selects the parent's partition; `shared` is not an element value. */
  partition: string;
  navigation: ExplorerNavigationPolicy;
  dialogs: ExplorerDialogPolicy;
  contextMenuEnabled: boolean;
  deferred: boolean;
  detach(): Promise<ExplorerTransfer>;
  attach(token: string): Promise<void>;
  ondetached: ((event: Event) => void) | null;
  onattached: ((event: Event) => void) | null;
  /** Starts navigation; completion is reported by load events. */
  load(url: string): void;
  download(url: string): Promise<boolean>;
  getDownloads(): Promise<ExplorerDownload[]>;
  cancelDownload(id: number): Promise<boolean>;
  /** Base64 bytes of an owned completed download, bounded to 64 MiB. */
  readDownload(id: number): Promise<string>;
  /** A compositor PNG data URL, or an empty string when unavailable. */
  capturePreview(): Promise<string>;
  back(): Promise<boolean>;
  forward(): Promise<boolean>;
  go(offset: number): Promise<boolean>;
  reload(options?: Readonly<{ bypassCache?: boolean }>): Promise<boolean>;
  stop(): Promise<boolean>;
  getNavigationState(): Promise<ExplorerNavigationState>;
  /** The caller must validate the JSON-representable result at runtime. */
  executeJavaScript(
    source: string,
    options?: Readonly<{
      world?: ExplorerJavaScriptWorld;
      expectedDocumentId?: string;
    }>,
  ): Promise<unknown>;
  postMessage(data: unknown): Promise<boolean>;
  addEventListener<K extends keyof ExplorerEventMap>(
    type: K,
    listener: (this: HTMLExplorerElement, event: ExplorerEventMap[K]) => void,
    options?: boolean | AddEventListenerOptions,
  ): void;
  removeEventListener<K extends keyof ExplorerEventMap>(
    type: K,
    listener: (this: HTMLExplorerElement, event: ExplorerEventMap[K]) => void,
    options?: boolean | EventListenerOptions,
  ): void;
}

declare global {
  interface HTMLElementTagNameMap {
    explorer: HTMLExplorerElement;
  }
}

export type ExplorerDownload = {
  id: number;
  url: string;
  filename: string;
  path: string;
  mimeType: string;
  state: "in-progress" | "complete" | "cancelled" | "interrupted";
  receivedBytes: number;
  totalBytes: number;
  error: number;
  navigation: boolean;
};
View source
tuffite/vite
typescript
export interface TuffiteViteOptions {
  manifest?: string;
  root?: string;
  static?: Readonly<Record<string, string>>;
  shellApi?: false | Readonly<{ url: string; file: string }>;
}

export function tuffite(options?: TuffiteViteOptions): import("vite").Plugin;
export function findManifest(start: string): string | undefined;
export function contentTypeForPath(path: string): string | undefined;
export function decodeRequestPath(requestUrl: string | undefined): string | undefined;
export function resolveConfinedFile(root: string, path: string): Promise<string | undefined>;
View source

Framework modules#

Expand a module to inspect its complete source declaration, including argument and return models.

tuffite.common0 methods
typescript
/** Filesystem roots accepted by path and fs APIs. */
export enum BaseDirectory {
  Resource = "resource",
  Data = "data",
  Cache = "cache",
  Temp = "temp",
}
tuffite.dialog2 methods
openFile(options?: OpenFileDialogOptions): Promise<string | undefined>;
openDirectory(options?: OpenDirectoryDialogOptions): Promise<string | undefined>;
typescript
export interface OpenFileDialogOptions {
  readonly title?: string;
  readonly defaultPath?: string;
  /** Extension groups without leading dots, for example [["html", "htm"], ["md"]]. */
  readonly extensions?: string[][];
}

export interface OpenDirectoryDialogOptions {
  readonly title?: string;
}

export declare namespace tuffite {
  export namespace dialog {
    export function openFile(options?: OpenFileDialogOptions): Promise<string | undefined>;
    export function openDirectory(options?: OpenDirectoryDialogOptions): Promise<string | undefined>;
  }
}
tuffite.fs5 methods
readFile(base: BaseDirectory, path: string): Promise<Uint8Array>;
writeFile( base: BaseDirectory, path: string, contents: Uint8Array, ): Promise<void>;
exists(base: BaseDirectory, path: string): Promise<boolean>;
createDir(base: BaseDirectory, path: string): Promise<void>;
removeFile(base: BaseDirectory, path: string): Promise<void>;
typescript
export declare namespace tuffite {
  export namespace fs {
    export function readFile(base: BaseDirectory, path: string): Promise<Uint8Array>;
    export function writeFile(
      base: BaseDirectory,
      path: string,
      contents: Uint8Array,
    ): Promise<void>;
    export function exists(base: BaseDirectory, path: string): Promise<boolean>;
    export function createDir(base: BaseDirectory, path: string): Promise<void>;
    export function removeFile(base: BaseDirectory, path: string): Promise<void>;
  }
}
tuffite.log5 methods
trace(message: string): Promise<void>;
debug(message: string): Promise<void>;
info(message: string): Promise<void>;
warn(message: string): Promise<void>;
error(message: string): Promise<void>;
typescript
export declare namespace tuffite {
  export namespace log {
    export function trace(message: string): Promise<void>;
    export function debug(message: string): Promise<void>;
    export function info(message: string): Promise<void>;
    export function warn(message: string): Promise<void>;
    export function error(message: string): Promise<void>;
  }
}
tuffite.network1 methods
request(url: string): Promise<NetworkResponse>;
typescript
export interface NetworkResponse {
  readonly status: number;
  readonly body: Uint8Array;
}

export declare namespace tuffite {
  export namespace net {
    export function request(url: string): Promise<NetworkResponse>;
  }
}
tuffite.path2 methods
directories(): Promise<PathDirectories>;
resolve(base: BaseDirectory, relative?: string): Promise<string>;
typescript
export interface PathDirectories {
  readonly resource: string;
  readonly data: string;
  readonly cache: string;
  readonly temp: string;
}

export declare namespace tuffite {
  export namespace path {
    export function directories(): Promise<PathDirectories>;
    export function resolve(base: BaseDirectory, relative?: string): Promise<string>;
  }
}
tuffite.remoting9 methods
capabilities(): Promise<RemotingCapabilities>;
start(options: RemotingStartOptions): Promise<RemotingSession>;
processSignal(id: bigint, signal: RemotingSignal): Promise<void>;
takeSignals(id: bigint, afterSequence?: bigint): Promise<RemotingSignal[]>;
sendInput(id: bigint, event: RemotingInputEvent): Promise<void>;
stop(id: bigint): Promise<void>;
stats(id: bigint): Promise<RemotingStats>;
capture(screenId?: bigint): Promise<RemotingSnapshot>;
injectInput(event: RemotingInputEvent): Promise<void>;
typescript
export interface RemotingCapabilities {
  readonly available: boolean;
  readonly protocol: string;
  readonly videoCodecs: string[];
  readonly input: boolean;
  readonly clipboard: boolean;
  readonly reconnect: boolean;
  readonly snapshot: boolean;
}

export interface RemotingIceServer {
  readonly urls: string[];
  readonly username?: string;
  readonly credential?: string;
}

export interface RemotingStartOptions {
  /** Per-session secret supplied by the application's authenticated control plane. */
  readonly authKey: string;
  readonly iceServers: RemotingIceServer[];
  readonly maxBitrateKbps?: number;
  readonly targetFramerate?: number;
  readonly screenId?: bigint;
}

export interface RemotingSession {
  readonly id: bigint;
  readonly state: string;
}

export interface RemotingSessionDescription {
  readonly type: string;
  readonly sdp: string;
}

export interface RemotingIceCandidate {
  readonly mid: string;
  readonly mLineIndex: number;
  readonly candidate: string;
}

export interface RemotingSignal {
  readonly sequence: bigint;
  readonly description?: RemotingSessionDescription;
  readonly candidates: RemotingIceCandidate[];
}

export interface RemotingInputEvent {
  readonly kind: string;
  readonly pressed?: boolean;
  readonly usbKeycode?: number;
  readonly text?: string;
  readonly x?: number;
  readonly y?: number;
  readonly button?: string;
  readonly buttonDown?: boolean;
  readonly wheelDeltaX?: number;
  readonly wheelDeltaY?: number;
  readonly wheelTicksX?: number;
  readonly wheelTicksY?: number;
  readonly clipboardMimeType?: string;
  readonly clipboardData?: Uint8Array;
}

export interface RemotingStats {
  readonly state: string;
  readonly route: string;
  readonly transport: string;
  readonly latencyMs: number;
  readonly jitterMs: number;
  readonly availableBandwidthKbps: number;
  readonly packetLossPercent: number;
}

export interface RemotingSnapshot {
  readonly width: number;
  readonly height: number;
  readonly mimeType: string;
  readonly data: Uint8Array;
}

export declare namespace tuffite {
  export namespace remoting {
    export function capabilities(): Promise<RemotingCapabilities>;
    export function start(options: RemotingStartOptions): Promise<RemotingSession>;
    export function processSignal(id: bigint, signal: RemotingSignal): Promise<void>;
    export function takeSignals(id: bigint, afterSequence?: bigint): Promise<RemotingSignal[]>;
    export function sendInput(id: bigint, event: RemotingInputEvent): Promise<void>;
    export function stop(id: bigint): Promise<void>;
    export function stats(id: bigint): Promise<RemotingStats>;
    export function capture(screenId?: bigint): Promise<RemotingSnapshot>;
    /** Native application callers only; renderer calls are denied by routing policy. */
    export function injectInput(event: RemotingInputEvent): Promise<void>;
  }
}
tuffite.storage4 methods
get(key: string): Promise<Uint8Array | undefined>;
set(key: string, value: Uint8Array): Promise<void>;
remove(key: string): Promise<void>;
clear(): Promise<void>;
typescript
export declare namespace tuffite {
  export namespace storage {
    export function get(key: string): Promise<Uint8Array | undefined>;
    export function set(key: string, value: Uint8Array): Promise<void>;
    export function remove(key: string): Promise<void>;
    export function clear(): Promise<void>;
  }
}
tuffite.utility2 methods
invoke( name: string, requestId: bigint, payload?: Uint8Array, ): Promise<Uint8Array>;
cancel(name: string, requestId: bigint): Promise<void>;
typescript
export declare namespace tuffite {
  export namespace utility {
    export function invoke(
      name: string,
      requestId: bigint,
      payload?: Uint8Array,
    ): Promise<Uint8Array>;
    export function cancel(name: string, requestId: bigint): Promise<void>;
  }
}
tuffite.window12 methods
current(): Promise<WindowInfo>;
list(): Promise<WindowInfo[]>;
create(options?: WindowOptions): Promise<WindowInfo>;
focus(id?: WindowId): Promise<WindowInfo>;
minimize(id?: WindowId): Promise<WindowInfo>;
maximize(id?: WindowId): Promise<WindowInfo>;
restore(id?: WindowId): Promise<WindowInfo>;
setFullscreen(fullscreen: boolean, id?: WindowId): Promise<WindowInfo>;
close(id?: WindowId): Promise<void>;
setTitle(title: string, id?: WindowId): Promise<WindowInfo>;
getBounds(id?: WindowId): Promise<WindowBounds>;
setBounds(bounds: WindowBounds, id?: WindowId): Promise<WindowInfo>;
typescript
/** Opaque browser-process identifier. It is intentionally not a native handle. */
export type WindowId = bigint;

export interface WindowBounds {
  readonly x: number;
  readonly y: number;
  readonly width: number;
  readonly height: number;
}

export interface WindowInfo {
  readonly id: WindowId;
  readonly label: string;
  readonly title: string;
  readonly url: string;
  readonly bounds: WindowBounds;
  readonly focused: boolean;
  readonly minimized: boolean;
  readonly maximized: boolean;
  readonly fullscreen: boolean;
}

export interface WindowOptions {
  readonly label?: string;
  readonly url?: string;
  readonly title?: string;
  readonly bounds?: WindowBounds;
  readonly focused?: boolean;
}

export declare namespace tuffite {
  export namespace window {
    export function current(): Promise<WindowInfo>;
    export function list(): Promise<WindowInfo[]>;
    export function create(options?: WindowOptions): Promise<WindowInfo>;
    export function focus(id?: WindowId): Promise<WindowInfo>;
    export function minimize(id?: WindowId): Promise<WindowInfo>;
    export function maximize(id?: WindowId): Promise<WindowInfo>;
    export function restore(id?: WindowId): Promise<WindowInfo>;
    export function setFullscreen(fullscreen: boolean, id?: WindowId): Promise<WindowInfo>;
    export function close(id?: WindowId): Promise<void>;
    export function setTitle(title: string, id?: WindowId): Promise<WindowInfo>;
    export function getBounds(id?: WindowId): Promise<WindowBounds>;
    export function setBounds(bounds: WindowBounds, id?: WindowId): Promise<WindowInfo>;
  }
}