# JavaScript API reference

> The global cat object of SDK 1.4: HTTP messages, events, mutation hooks, sends, external APIs, laboratory, resources and utilities.

- Language: en
- Canonical URL: https://netcattest.com/catsuite/en/docs/extensions/api
- Section: Extensions
- Updated: 2026-10-05
- Other language (pt-BR): https://netcattest.com/catsuite/docs/extensoes/api

Every extension receives the global, frozen `cat` object. `cat.apiVersion` is `1` and `cat.sdkVersion` is `"1.4.0"`. API v1 stays compatible across every SDK version.

## HTTP messages

Requests and responses arrive as `CatMessage`:

| Field | Description |
|---|---|
| `id` | message identifier |
| `source` | origin: `proxy`, `network_proxy`, `repetir`, `intruso`, `descobridor`, `extension` or `laboratory` |
| `session` | Network Proxy session, or `null` |
| `stage` | `request` or `response` |
| `url`, `method` | destination and method |
| `headers` | ordered list of `{name, value}` |
| `body` | `bytes`, `size`, `complete`, `truncated`, `available`, `mutable`, `representation` and `sha256` |
| `status`, `reason` | responses only |
| `time` | timestamp |
| `request` | original request, present on responses |

`body.representation` tells whether bytes are on the wire (`wire`) or decompressed by the client (`decoded`). The editable preview is up to 32 KiB.

## Events

Observers may be asynchronous and require `traffic.read`.

```js
cat.events.on('http.request', async message => {
  await cat.storage.set('lastUrl', message.url);
});

cat.events.on('http.response', async message => {
  if (message.status >= 500) {
    cat.log({'pt-BR': 'Falha no servidor observada.', en: 'Server failure observed.'}, 'warning');
  }
});
```

Available events: `http.request`, `http.response` and `http.complete`.

## Mutation hooks

```js
cat.proxy.onRequest(message => {
  if (cat.http.parseUrl(message.url).hostname !== 'api.aurora.test') return;
  message.headers = message.headers.filter(h => h.name.toLowerCase() !== 'x-cat-lab');
  message.headers.push({name: 'X-Cat-Lab', value: 'auditor'});
  return message;
});

cat.proxy.onResponse(message => {
  message.headers.push({name: 'X-Cat-Auditor', value: '1'});
  return message;
});
```

Hook rules, which require `traffic.modify`:

- They are synchronous and get up to 100 ms per run. Returning a Promise raises `E_HOOK_ASYNC`.
- They do not send requests, persist data or update the interface.
- Returning `undefined` keeps the message; returning the message applies the change.
- Do not change identity, origin or integrity flags. Headers do not accept line breaks.
- Compression headers cannot be changed, and only bodies with `mutable: true` can be edited.
- The effective message is validated before sending. App scopes and blocks still apply.

## HTTP sends

```js
const response = await cat.http.send({
  id: 'lookup-1',
  url: 'https://api.aurora.test/api/pedidos',
  method: 'GET',
  headers: [{name: 'Accept', value: 'application/json'}]
});
cat.http.cancel('lookup-1');
```

`cat.http.send` requires `http.send` and uses the manifest `targets`. Destinations are checked before sending and after changes, automatic redirects are disabled and TLS is validated. There are two concurrent calls per extension, a 120-second total timeout and responses up to 8 MiB. Sends to CatSuite’s own proxy are rejected with `E_PROXY_LOOP`.

## External APIs

```js
const response = await cat.external.call({
  url: 'https://advisories.aurora.test/advisories?code=CACHE-001',
  method: 'GET',
  credentialId: 'my-key'
});
```

`cat.external.call` requires `external.call` and uses `externalHosts`. The credential is configured on the extension screen, protected by Android Keystore and added by the host as `Bearer`. Your code never receives the secret value.

## Laboratory

```js
const captured = await cat.laboratory.capture({
  url: 'https://api.aurora.test/api/perfil',
  method: 'GET',
  headers: [{name: 'Accept', value: 'application/json'}]
});
```

With `settings.laboratory` set to `true`, the host simulates captured traffic from `api.aurora.test`, runs the capture and mutation hooks and also simulates `advisories.aurora.test`. The laboratory makes no external connections. Without laboratory mode the call fails with `E_LABORATORY`.

## Repeater

```js
cat.tools.repeater.open({url: 'https://api.aurora.test/api/perfil', method: 'GET', headers: []});
```

Opens the message in Repeater. Requires `repeater` and only accepts approved destinations.

## Package resources

```js
const fixtures = JSON.parse(await cat.resources.get('fixtures.json'));
const bytes = await cat.resources.get('signature.bin', 'bytes');
```

Reads files from the package itself. Text is limited to 128 KiB and binary resources to 32 KiB. There is no access to device files.

## Utilities

| Function | Description |
|---|---|
| `cat.http.parseUrl(url)` | returns `{scheme, hostname, port, pathname, query}` and rejects credentials in the URL |
| `cat.bytes.fromText(text)` | converts UTF-8 text into a byte list |
| `cat.bytes.toText(bytes)` | converts a byte list into UTF-8 text |
| `cat.i18n.locale` | `pt-BR` or `en` |
| `cat.i18n.text(value)` | picks the current language from a bilingual object |
| `cat.log(message, level)` | records `info`, `warning` or `error`, with plain or bilingual text |

## Errors

Failures use stable `E_*` codes with translated descriptions, such as `E_PERMISSION`, `E_HOST`, `E_TIMEOUT` and `E_BODY`. See the [complete list of codes](https://netcattest.com/catsuite/en/docs/reference/errors).

```js
try {
  await cat.http.send({url: 'https://out-of-scope.test/'});
} catch (error) {
  cat.log(String(error.code || error.message), 'error');
}
```
