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

# JavaScript-Client-Bibliothek

> Installieren, initialisieren, Methoden auf Endpoints abbilden und Fehler mit dem offiziellen JavaScript-SDK octoparse-client behandeln.

`octoparse-client` ist der offizielle JavaScript/TypeScript-Client für Data Hub. Er kapselt nur die öffentliche `/v1` REST API. Methoden entsprechen eins zu eins den Endpoints, Parameternamen stimmen mit REST überein, und Rückgabewerte sind der rohe `data`-Payload. Erfordert Node.js 18+ oder eine moderne Browser-Laufzeit mit `fetch`.

## Installation

```bash theme={null}
npm install octoparse-client
```

## Initialisierung

```js theme={null}
import { Client } from "octoparse-client";

const client = new Client({ apiKey: "<your API key>" });
```

| Option    | Beschreibung                                                                                                                                                         |
| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `apiKey`  | Data Hub API-Schlüssel. Ohne Angabe wird `OCTOPARSE_API_KEY` gelesen. Fehlt er weiterhin, ist der Client anonym und kann nur anonyme Endpoints aufrufen.             |
| `baseUrl` | Service-URL. Ohne Angabe wird `OCTOPARSE_BASE_URL` gelesen, Standard ist `https://api-datahub.octoparse.com`. Für lokale oder Staging-Umgebungen explizit übergeben. |
| `timeout` | Per-request HTTP timeout in Millisekunden. Standard 90000.                                                                                                           |

## Methoden-zu-Endpoint-Zuordnung

| Methode                                                             | Endpoint                                  | Hinweise                                          |
| ------------------------------------------------------------------- | ----------------------------------------- | ------------------------------------------------- |
| `meta()`                                                            | `GET /v1/meta`                            | Plattform-Konstanten                              |
| `search(q, { limit, offset, ... })`                                 | `GET /v1/data-apps`                       | Eine Seite Karten, inkl. `pagination`             |
| `getApp(appId)`                                                     | `GET /v1/data-apps/{app_id}`              | Vollständiges App-Detail                          |
| `run(appId, inputs, { wait, maxRecords, version, build })`          | `POST /v1/data-apps/{app_id}/runs`        | Run starten                                       |
| `call(appId, inputs, { maxRecords, timeout, raiseOnFailure, ... })` | `POST` + Poll                             | Blocking-Helper: warten bis terminal oder Timeout |
| `getRun(runId, { wait })`                                           | `GET /v1/runs/{run_id}`                   | Status- und Abrechnungs-Snapshot                  |
| `listRunsPage(filters)`                                             | `GET /v1/runs`                            | Eine Seite Runs, inkl. `pagination`               |
| `listRuns(filters)`                                                 | `GET /v1/runs`                            | Eine Seite Runs, nur Items                        |
| `iterateRuns(filters)`                                              | `GET /v1/runs`                            | Async-Iterator, der automatisch paginiert         |
| `cancel(runId)`                                                     | `POST /v1/runs/{run_id}/cancel`           | Run abbrechen                                     |
| `getRecords(runId, { offset, limit, fields })`                      | `GET /v1/runs/{run_id}/records`           | Eine Seite Ergebnisdatensätze                     |
| `iterateRecords(runId, { batch, fields })`                          | `GET /v1/runs/{run_id}/records`           | Async-Iterator, der automatisch paginiert         |
| `exportRecords(runId, format)`                                      | `GET /v1/runs/{run_id}/records`           | Voller Export als `jsonl`/`csv`-Text              |
| `listDatasets({ offset, limit })`                                   | `GET /v1/datasets`                        | Dataset-Liste                                     |
| `setDatasetRetention(datasetId, retained)`                          | `PUT /v1/datasets/{dataset_id}/retention` | Retention-Flag setzen                             |
| `getDatasetRecords(datasetId, { offset, limit, fields })`           | `GET /v1/datasets/{dataset_id}/records`   | Eine Seite Dataset-Datensätze                     |
| `iterateDatasetRecords(datasetId, { batch, fields })`               | `GET /v1/datasets/{dataset_id}/records`   | Async-Iterator, der automatisch paginiert         |
| `account()`                                                         | `GET /v1/account`                         | Kontoinfo und kumulierter Spend                   |
| `billing({ groupBy, createdFrom, createdTo, tzOffset })`            | `GET /v1/billing`                         | Abrechnungsaggregation                            |

Die `filters` der Run-Liste unterstützen `status`, `dataApp`, `triggeredBy`, `runKind`, `credential`, `createdFrom`, `createdTo` sowie `offset` / `limit`. Publishing-, Betriebs- und Secrets-Endpoints sind nicht gekapselt; rufen Sie REST direkt auf.

## Typische Verwendung

```js theme={null}
import { Client, ApiError, RunFailed } from "octoparse-client";

const client = new Client({ apiKey: "<your API key>" });

// Discover
const { items } = await client.search("reviews", { limit: 5 });
for (const card of items) console.log(card.app_id, card.namespace, card.app_name);
const detail = await client.getApp("carol/reviews-query");

// Run and consume. Timeouts are milliseconds. TimeoutError does not cancel the server-side run.
const run = await client.call("carol/reviews-query", { product: "p-9001" }, {
  maxRecords: 100, timeout: 120_000, raiseOnFailure: true,
});
for await (const record of client.iterateRecords(run.run_id)) {
  console.log(record);
}

// Non-blocking: start, then poll yourself
const started = await client.run("carol/reviews-query", { product: "p-9002" }, { wait: 0 });
const polled = await client.getRun(started.run_id, { wait: 60 });

// Reconcile spend
console.log(await client.billing({ groupBy: "data_app", tzOffset: 480 }));
for await (const r of client.iterateRuns({ createdFrom: "2026-09-01T00:00:00+08:00" })) {
  console.log(r.run_id, r.status, r.billing.total);
}

// Results are kept 90 days by default; mark datasets you need longer
await client.setDatasetRetention(run.dataset_id, true);
```

## Fehlerbehandlung

API-Fehlerantworten werfen `ApiError` (erweitert `Error`). Die Felder entsprechen dem REST-`error`-Objekt:

| Eigenschaft  | Bedeutung                                                                         |
| ------------ | --------------------------------------------------------------------------------- |
| `statusCode` | HTTP-Status                                                                       |
| `code`       | Stabile Fehler-ID für Verzweigungen                                               |
| `category`   | Grobe Fehlerklasse                                                                |
| `message`    | Englische Beschreibung                                                            |
| `retryable`  | Ob dieselbe Anfrage erneut versucht werden kann                                   |
| `details`    | Probleme auf Feldebene bei fehlgeschlagener Eingabevalidierung, sonst `undefined` |

```js theme={null}
import { ApiError } from "octoparse-client";

try {
  await client.run("carol/reviews-query", {});
} catch (e) {
  if (e instanceof ApiError && e.code === "invalid-input") {
    for (const d of e.details ?? []) console.log(d.path, d.message);
  } else if (e instanceof ApiError && e.retryable) {
    // back off and retry
  } else {
    throw e;
  }
}
```

`RunFailed` wird geworfen, wenn `call()` mit `raiseOnFailure: true` aufgerufen wird und der Run mit `FAILED` / `CANCELLED` / `EXPIRED` endet. Die Eigenschaft `run` enthält das vollständige Run-Objekt.

## App-Referenzen

`getApp()`, `run()`, `call()` und der Run-List-Filter `dataApp` akzeptieren beide Formen: zweisegmentig `<namespace>/<app_name>` (menschenlesbar, bricht nach Rename) und stabiles `app_id` (`app_<hex>`, überlebt Rename). Für langlebige Integrationen `app_id` speichern.
