# JavaScript essentials

ApplesauceOS provides JavaScript plus device automation APIs. You can call functions such as `openApp()` and `ocr()` directly; their `at.openApp()` and `at.ocr()` spellings refer to the same APIs. `UIHelper`, `ObjC`, `RemoteObjC`, `C` and `RemoteC` are also available globally and through `at`.

Runtime helpers such as `require`, `fetch`, timers and `console` are global. Do not assume every runtime property has an `at` alias.

## Variables, decisions and reusable functions

```js
function openSettings() {
  if (!openApp("com.apple.Preferences")) {
    throw new Error("Settings did not open");
  }
}
openSettings();
console.log("Current app:", frontMostAppId());
```

Use `const` for a value you will not reassign and `let` for a changing counter. An `if` chooses what to do. A function groups reusable work. `throw new Error(...)` makes a failed assumption visible in the run output.

## Units are part of the API

| Operation | Units |
| --- | --- |
| Touch positions, UIHelper rectangles, visual matching | Native screen pixels, top-left origin |
| UIHelper timeouts/intervals, tap hold, timers, async HTTP timeout | Milliseconds |
| Swipe duration, waitForApp timeout, execResult timeout, showNotice | Seconds |
| usleep / msleep / sleep | Microseconds / milliseconds / seconds |
| OCR | Points by default; request `coordinates: "pixels"` for screen touches |

[getScreenInfo()](/doc/api/getscreeninfo) reports portrait panel dimensions, not a scale field. Use current orientation when calculating screen-relative gestures. Coordinates from a resized screenshot must be mapped to the original image.

## Handle the correct error shape

```js
const [items, error] = ocr({coordinates: "pixels"});
if (error) throw new Error(error);
console.log(items.length);
```

OCR and visual search return a pair. File-writing helpers return an error string or null. UIHelper and native calls throw on failures. `execResult` returns status fields. Each reference page states the contract; do not assume all APIs return a boolean.

## Asynchronous work

Saved scripts do not support top-level `await`. Wrap asynchronous code in an async function and let failures remain visible:

```js
(async () => {
  const response = await fetch("https://example.com", {timeout: 5000});
  if (!response.ok) throw new Error("HTTP " + response.status);
  console.log(await response.text());
})().catch(error => {
  console.error(error.message);
  throw error;
});
```

Pending HTTP requests and timers keep the runtime active. Clear intervals when finished. A detached Promise with no tracked work is not a completion mechanism. Synchronous sleeps delay timer callbacks. Stop cancels pending runtime work but cannot undo an already executed native action.

MCP `run_javascript` is different: its source is an async function body, so it supports `return` and `await`. `start_script` uses the saved script/project behavior described above.

## Keep loops bounded

Prefer [waitForElement](/doc/api/uihelper-waitforelement) over fixed long sleeps. Use a timeout and a maximum number of attempts for retries or scrolling. Never catch and ignore every error: this can hide cancellation, invalid selectors and real failures.

For alerts and alternate screen states, use the [interruption-handling pattern](/doc/recovery).
