> ## 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 클라이언트 라이브러리

> 공식 JS/TS SDK octoparse-client.

`octoparse-client`는 Data Hub 공식 JavaScript/TypeScript 클라이언트. 공개 `/v1` REST만. 메서드 1:1, 파라미터명 REST, 반환 `data`.

## 설치

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

## 초기화

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

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

| 옵션        | 설명                                                                                       |
| --------- | ---------------------------------------------------------------------------------------- |
| `apiKey`  | Data Hub API 키. 생략 시 `OCTOPARSE_API_KEY`. 그래도 없으면 익명으로 익명 엔드포인트만.                        |
| `baseUrl` | 서비스 URL. 생략 시 `OCTOPARSE_BASE_URL`, 기본 `https://api-datahub.octoparse.com`. 로컬/스테이징은 명시. |
| `timeout` | 요청당 HTTP 타임아웃(밀리초). 기본 90000.                                                            |

## 메서드-엔드포인트 대응

| 방식                                                                  | 엔드포인트                                     | 비고                           |
| ------------------------------------------------------------------- | ----------------------------------------- | ---------------------------- |
| `meta()`                                                            | `GET /v1/meta`                            | 플랫폼 상수                       |
| `search(q, { limit, offset, ... })`                                 | `GET /v1/data-apps`                       | 카드 한 페이지(`pagination` 포함)    |
| `getApp(appId)`                                                     | `GET /v1/data-apps/{app_id}`              | 전체 App 상세                    |
| `run(appId, inputs, { wait, maxRecords, version, build })`          | `POST /v1/data-apps/{app_id}/runs`        | 실행 시작                        |
| `call(appId, inputs, { maxRecords, timeout, raiseOnFailure, ... })` | `POST` + 폴링                               | 블로킹 헬퍼: 최종 상태 또는 타임아웃까지 대기   |
| `getRun(runId, { wait })`                                           | `GET /v1/runs/{run_id}`                   | 상태와 과금 스냅샷                   |
| `listRunsPage(filters)`                                             | `GET /v1/runs`                            | 실행 한 페이지(`pagination` 포함)    |
| `listRuns(filters)`                                                 | `GET /v1/runs`                            | 실행 1페이지(items만)              |
| `iterateRuns(filters)`                                              | `GET /v1/runs`                            | 자동 페이지 비동기 이터레이터             |
| `cancel(runId)`                                                     | `POST /v1/runs/{run_id}/cancel`           | 실행 취소                        |
| `getRecords(runId, { offset, limit, fields })`                      | `GET /v1/runs/{run_id}/records`           | 결과 레코드 한 페이지                 |
| `iterateRecords(runId, { batch, fields })`                          | `GET /v1/runs/{run_id}/records`           | 자동 페이지 비동기 이터레이터             |
| `exportRecords(runId, format)`                                      | `GET /v1/runs/{run_id}/records`           | `jsonl` / `csv` 텍스트로 전체 내보내기 |
| `listDatasets({ offset, limit })`                                   | `GET /v1/datasets`                        | 데이터셋 목록                      |
| `setDatasetRetention(datasetId, retained)`                          | `PUT /v1/datasets/{dataset_id}/retention` | 보존 플래그 설정                    |
| `getDatasetRecords(datasetId, { offset, limit, fields })`           | `GET /v1/datasets/{dataset_id}/records`   | 데이터셋 레코드 한 페이지               |
| `iterateDatasetRecords(datasetId, { batch, fields })`               | `GET /v1/datasets/{dataset_id}/records`   | 자동 페이지 비동기 이터레이터             |
| `account()`                                                         | `GET /v1/account`                         | 계정 정보와 누적 지출                 |
| `billing({ groupBy, createdFrom, createdTo, tzOffset })`            | `GET /v1/billing`                         | 청구 집계                        |

실행 목록 `filters`는 `status`, `dataApp`, `triggeredBy`, `runKind`, `credential`, `createdFrom`, `createdTo`와 `offset`/`limit`. 게시·운영·시크릿 미래핑 — REST 직접.

## 일반적인 사용

```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);
```

## 오류 처리

API 오류는 `ApiError`(`Error` 확장) throw. 필드는 REST `error`와 같음:

| 속성           | 의미                                     |
| ------------ | -------------------------------------- |
| `statusCode` | HTTP 상태                                |
| `code`       | 분기용 안정 오류 id                           |
| `category`   | 대분류                                    |
| `message`    | 영문 설명                                  |
| `retryable`  | 동일 요청 재시도 가능 여부                        |
| `details`    | 입력 검증 실패 시 필드 단위 문제, 그 외에는 `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;
  }
}
```

`call()`이 `raiseOnFailure: true`이고 `FAILED` / `CANCELLED` / `EXPIRED`로 끝나면 `RunFailed`. `run`에 실행 객체 전체.

## App 참조

`getApp()`, `run()`, `call()`, 실행 목록 `dataApp` 필터는 두 형식 허용: 2단 `<namespace>/<app_name>`(가독, 이름 변경 시 깨짐)과 안정 `app_id`(`app_<hex>`, 이름 변경 생존). 장기 연동은 `app_id` 권장.
