---
title: Overview
source: https://infrared.city/docs/sdk/1.0/api/typescript/
---

# TypeScript SDK

API reference for `@infrared-city/infrared-sdk-ts`, generated from the TSDoc comments in the SDK source. Start with the overview below, then the topic pages in the sidebar.

## A typical run

<figure markdown>
![A chain of seven steps from left to right: client, model (yours or public data), weather, request, preview, run and values. Only the run is billed.](../../assets/diagrams/typical-run.svg)
</figure>

This is a complete run with your own model: one tower and a thermal comfort
(UTCI) analysis. Each comment is one step of the diagram. `polygon` is a
GeoJSON polygon in longitude and latitude. `coordinates` and `indices` are
your mesh, in metres, in the local frame of the polygon. See
[Your model](../../index.md#your-inputs) and
[Coordinates](../../index.md#coordinates).

```ts
import {
  InfraredClient, initializeCore, areaGridValuesF32, type AreaResult,
} from "@infrared-city/infrared-sdk-ts";

// 1. Client. Start the core one time: in Node, runArea and runAreaAndWait
//    need it. The key comes from the option or from INFRARED_API_KEY.
await initializeCore();
const client = new InfraredClient({ apiKey: process.env.INFRARED_API_KEY });

// 2. Your model. One mesh for each building, in metres.
const buildings = { tower: { coordinates, indices } };

// 3. Weather. Find the nearest public station, then keep the hours you need.
const period = { start: { month: 7, day: 15, hour: 12 }, end: { month: 7, day: 15, hour: 16 } };
const stations = await client.weather.getWeatherFileFromLocation(48.2085, 16.3725);
const rows = await client.weather.filterWeatherData(stations[0].uuid, { period });

// 4. Request. A plain object. analysisType selects the analysis.
const input = {
  analysisType: "thermal-comfort-index",
  latitude: 48.2085, longitude: 16.3725,
  dateFilters: { period },
  weatherData: rows,
};

// 5. Preview. This sends no job. plannedJobCount is the number of billed jobs.
const preview = await client.previewAreaBatches(input, polygon, { buildings });
console.log(preview.plannedJobCount);

// 6. Run. One call plans, uploads, submits, waits and merges.
const result = await client.runAreaAndWait(input, polygon, { buildings });

// 7. Values. One 32-bit float for each cell, in degrees C. NaN means no value.
const values = areaGridValuesF32(result as AreaResult);
```

To use your own weather file, give `weather: client.weather.parseEpw(text)`
in place of `weatherData`. An analysis that needs no weather takes only
`analysisType`, for example `{ analysisType: "sky-view-factors" }`. See
[Weather and time period](../../index.md#weather-and-time-period),
[The ten analyses](../../index.md#the-ten-analyses),
[Cost and retry](../../index.md#cost-and-retry) and
[How a run works](../../index.md#how-a-run-works).

### Variant: no data yet

Read public buildings, trees and ground materials for the polygon. Give the
objects to the run as they are: then the run can check the frame and the
read margin. Buildings and ground materials need
`npm install hyparquet hyparquet-compressors`. See
[Public context](../../index.md#no-data-yet-public-context).

```ts
const buildings = await client.buildings.getBuildingsInArea(polygon);
const vegetation = await client.vegetation.getArea(polygon);
const groundMaterials = await client.groundMaterials.getArea(polygon);
const result = await client.runAreaAndWait(input, polygon,
  { buildings, vegetation, groundMaterials });
```

### Variant: facades instead of ground

Set `analysisSurfaces` to `"facades"`, `"roofs"` or `"all"`. The run gives
`SurfaceColumns`: one value for each sensor cell on your buildings, not a
ground grid. `previewAreaBatches` counts the facade jobs correctly. See
[Facade and roof runs](../../index.md#facade-and-roof-runs).

```ts
import { surfaceValuesF32, surfaceRenderBuffers, type SurfaceColumns }
  from "@infrared-city/infrared-sdk-ts";

const input = { analysisType: "sky-view-factors", analysisSurfaces: "facades", surfaceGridSize: 3 };
const preview = await client.previewAreaBatches(input, polygon, { buildings });
const columns = (await client.runAreaAndWait(input, polygon, { buildings })) as SurfaceColumns;
const values = surfaceValuesF32(columns);       // one value for each cell, NaN = no value
const buffers = surfaceRenderBuffers(columns);  // flat arrays to draw the cells
```

### Variant: submit now, merge later

`runArea` submits the jobs and returns an `AreaSchedule`. Merge when the jobs
are complete. `checkAreaState` (and `client.jobs.getStatusBatch(ids)`) asks
for up to 50 jobs in one request. Do not ask for each job in a loop. For a
facade run, merge with `mergeSurfaceAreaJobs`.

```ts
const schedule = await client.runArea(input, polygon, { buildings });
while (!(await client.checkAreaState(schedule)).isComplete) {
  await new Promise((done) => setTimeout(done, 10_000));
}
const result = await client.mergeAreaJobs(schedule);
```

### Save, reload and free

Save the layout of a facade run one time for each geometry, and the values of
each run: `layout.toBytes()` and `surfaceColumnsToBytes(columns, { layoutKey })`.
Reload with `FacadeLayout.fromBytes` and `surfaceColumnsFromBytes`, then
`attachValues`. Call `layout.free()` for each layout, `forgetSchedule` on
`client.jobs.captures` for a schedule that you will not merge, and
`client.jobs.captures.free()` when you finish. See
[Save, reload and free](../../index.md#save-reload-and-free).

## Which module does what

The package has several entry points. See [Import paths](#import-paths).

| Page | Role | Main calls |
|---|---|---|
| [Client](client.md) | The entry point and the area runs | `initializeCore`, `InfraredClient`, `runAreaAndWait`, `runArea`, `checkAreaState`, `mergeAreaJobs`, `previewArea` |
| [Run an analysis](run-an-analysis.md) | Planning and previews | `previewAreaBatches`, `AreaSchedule` |
| [Requests](requests.md) | The analysis request fields | `analysisType`, `dateFilters`, `weather` |
| [Buildings](buildings.md), [Vegetation](vegetation.md), [Ground materials](ground-materials.md) | Public context for an area | `getBuildingsInArea`, `vegetation.getArea`, `groundMaterials.getArea` |
| [Weather](weather.md) | The weather catalog and EPW text | `getWeatherFileFromLocation`, `filterWeatherData`, `parseEpw` |
| [Results and legend](results-and-legend.md) | Read and save results | `areaGridValuesF32`, `surfaceValuesF32`, `surfaceRenderBuffers`, `surfaceColumnsToBytes` |
| [Facade layout](facade-layout.md) | The outline of facade and roof results | `FacadeLayout`, `attachValues` |
| [Worker](worker.md) | The client in a Web Worker | see [Serve many users](../../index.md#serve-many-users) |
| [Errors](errors.md) | Error classes | see below |

## Errors you meet

- `CoreNotReadyError`: you called the SDK before `await initializeCore()`.
- `AreaTimeoutError`: the run passed its area timeout.
- `JobFailedError`: one job failed on the server.
- `SubmissionUncertainError`: a submit got no answer. Do not send it again by hand: the retry keys do it safely.
- `ReadMarginError`: a public layer was read with a margin that is too narrow for the analysis.

An incomplete merge throws an `Error` whose message says which tiles did not
contribute and how to recover. See [Cost and retry](../../index.md#cost-and-retry).

## Topics

- [Client](client.md)
- [Run an analysis](run-an-analysis.md)
- [Requests](requests.md)
- [Buildings](buildings.md)
- [Ground materials](ground-materials.md)
- [Vegetation](vegetation.md)
- [Weather](weather.md)
- [Tiling](tiling.md)
- [Results and legend](results-and-legend.md)
- [Geodata](geodata.md)
- [Facade layout](facade-layout.md)
- [Billing](billing.md)
- [Errors](errors.md)
- [Worker](worker.md)

## Import paths

The package has these entry points. Each symbol's page names the ones it can be imported from.

- `@infrared-city/infrared-sdk-ts`
- `@infrared-city/infrared-sdk-ts/tiling`
- `@infrared-city/infrared-sdk-ts/utilities`
- `@infrared-city/infrared-sdk-ts/geodata`
- `@infrared-city/infrared-sdk-ts/billing`
- `@infrared-city/infrared-sdk-ts/worker`
