---
title: "JavaScript SDK interfaces and type aliases"
type: reference
tags: [javascript, typescript, sdk, types, reference]
created: 2026-09-17
updated: 2026-09-17
confidence: high
sources:
  - raw/docs/sdk__javascript__api.md
  - raw/docs/sdk__javascript__api__interfaces__ChoiceQuestion.md
  - raw/docs/sdk__javascript__api__interfaces__ChoiceResponse.md
  - raw/docs/sdk__javascript__api__interfaces__ScoreQuestion.md
  - raw/docs/sdk__javascript__api__interfaces__ScoreResponse.md
  - raw/docs/sdk__javascript__api__interfaces__NoulQuestion.md
  - raw/docs/sdk__javascript__api__interfaces__NoulResponse.md
  - raw/docs/sdk__javascript__api__interfaces__Questions.md
  - raw/docs/sdk__javascript__api__interfaces__SystemOneRequest.md
  - raw/docs/sdk__javascript__api__interfaces__SystemOneRequestPayload.md
  - raw/docs/sdk__javascript__api__interfaces__SystemOneResult.md
  - raw/docs/sdk__javascript__api__interfaces__Usage.md
  - raw/docs/sdk__javascript__api__interfaces__ModelCard.md
  - raw/docs/sdk__javascript__api__interfaces__Models.md
  - raw/docs/sdk__javascript__api__interfaces__WithResponse.md
  - raw/docs/sdk__javascript__api__interfaces__TypeSafeClientConfig.md
  - raw/docs/sdk__javascript__api__interfaces__Logger.md
  - raw/docs/sdk__javascript__api__type-aliases__ChoiceCriteria.md
  - raw/docs/sdk__javascript__api__type-aliases__ScoreCriteria.md
  - raw/docs/sdk__javascript__api__type-aliases__ScoreLegend.md
  - raw/docs/sdk__javascript__api__type-aliases__ScoreOf.md
  - raw/docs/sdk__javascript__api__type-aliases__ResultFor.md
  - raw/docs/sdk__javascript__api__type-aliases__Question.md
  - raw/docs/sdk__javascript__api__type-aliases__Description.md
  - raw/docs/sdk__javascript__api__type-aliases__EntryType.md
  - raw/docs/sdk__javascript__api__type-aliases__JsonValue.md
  - raw/docs/sdk__javascript__api__type-aliases__Fetch.md
  - raw/docs/sdk__javascript__api__type-aliases__EnvVar.md
  - raw/docs/sdk__javascript__api__type-aliases__LogLevel.md
  - raw/docs/sdk__javascript__api__variables__ENV.md
  - raw/docs/sdk__javascript__api__variables__LOG_LEVELS.md
  - raw/github/typesafe-sdk-js/src/types.ts
  - raw/github/typesafe-sdk-js/src/env.ts
  - raw/github/typesafe-sdk-js/src/logging.ts
  - raw/github/typesafe-sdk-js/src/api-promise.ts
  - raw/github/typesafe-sdk-js/src/resources/models.ts
jev_version: "jev-1.13.0"
sdk_js: "0.6.0"
summary: "Every interface, type alias and exported variable in @typesafe-ai/sdk 0.6.0, with per-property type/required/default tables and generics examples."
---

# JavaScript SDK interfaces and type aliases

> **TL;DR** Everything under `export type * from "./types"` in `@typesafe-ai/sdk` 0.6.0, plus `WithResponse`, `EnvVar`, `Models`, and the two exported constants `ENV` and `LOG_LEVELS`. Question types carry a `const` generic over their criteria, and `ResultFor` maps each question type to its answer type — that is the whole reason `answers.x.choice` is a literal union rather than `string`.

## Type map

| Type | Kind | Generic | Purpose |
|---|---|---|---|
| `JsonValue` | alias | — | Any JSON-compatible value |
| `EntryType` | alias | — | The shape accepted for `state`, `instructions`, criteria entries |
| `Description` | alias | — | A criterion description (`= EntryType`) |
| `NoulQuestion` | interface | — | Yes/no question |
| `ChoiceQuestion<T>` | interface | `T extends ChoiceCriteria = ChoiceCriteria` | Named-alternative question |
| `ScoreQuestion<T>` | interface | `T extends ScoreCriteria = ScoreCriteria` | Ordered-rubric question |
| `ChoiceCriteria` | alias | — | Label → description map |
| `ScoreCriteria` | alias | — | Ordered rubric tuple, length ≥ 2 |
| `Question` | alias | — | Union of the three question interfaces |
| `Questions` | interface | — | `{ [name: string]: Question }` |
| `NoulResponse` | interface | — | Yes/no answer |
| `ChoiceResponse<T>` | interface | `T extends ChoiceCriteria = ChoiceCriteria` | Selected label + probabilities |
| `ScoreResponse<T>` | interface | `T extends ScoreCriteria = ScoreCriteria` | Expected score + legend + probabilities |
| `ScoreOf<T>` | alias | `T extends ScoreCriteria` | Score keys inferred from the rubric |
| `ScoreLegend<T>` | alias | `T extends ScoreCriteria` | Rubric descriptions keyed by score |
| `ResultFor<T>` | alias | `T extends Question` | Question type → answer type |
| `Usage` | interface | — | Token usage |
| `SystemOneRequest<Q>` | interface | `Q extends Questions = Questions` | What you pass to `systemOne()` |
| `SystemOneRequestPayload` | interface | — | The wire body, model resolved |
| `SystemOneResult<Q>` | interface | `Q extends Questions` | What `systemOne()` resolves to |
| `ModelCard` | interface | — | One model in `models.list()` |
| `Models` | interface (docs) / class (source) | — | The `client.models` resource |
| `WithResponse<T>` | interface | `T` | `.withResponse()` return shape |
| `TypeSafeClientConfig` | interface | — | Constructor options |
| `RetryPolicy` | interface | — | Retry configuration → [[reference/javascript-sdk-errors]] |
| `RequestOptions` | interface | — | Per-call options → [[reference/javascript-sdk-errors]] |
| `Fetch` | alias | — | Pluggable fetch |
| `Logger` | interface | — | Log sink |
| `LogLevel` | alias | — | Verbosity union |
| `EnvVar` | alias | — | Union of the `ENV` values |
| `ENV` | const | — | Config key → env var name |
| `LOG_LEVELS` | const | — | Ordered level list |

`RetryPolicy` and `RequestOptions` also live in `src/types.ts`, but are documented on [[reference/javascript-sdk-errors]] alongside the failure modes they govern.

## Primitive value types

### `JsonValue`

```ts
type JsonValue =
  | string
  | number
  | boolean
  | null
  | JsonValue[]
  | { [key: string]: JsonValue };
```

"A JSON-compatible value." Recursive; used only as the element type inside `EntryType`.

### `EntryType`

```ts
type EntryType = string | { [key: string]: JsonValue } | JsonValue[] | null;
```

"Text, a JSON object or array, or `null` for state, instructions, and criteria." Note it is *not* `JsonValue`: a bare `number` or `boolean` is not an `EntryType`.

### `Description`

```ts
type Description = EntryType;
```

"A criterion description; `null` leaves the label undescribed." A readability alias over `EntryType`, used in `ChoiceCriteria`.

## Questions

### `NoulQuestion`

| Property | Type | Required | Default | Description |
|---|---|---|---|---|
| `type` | `"noul"` | yes | — | Discriminant. |
| `instructions` | `EntryType` | no | `null` when built with `noul()` | The question as text, a JSON object, or an array; optional or `null`. |
| `criteria` | `{ true?: EntryType; false?: EntryType } \| null` | no | `undefined` | Optional descriptions of the yes and no outcomes. |

Nested `criteria` members:

| Member | Type | Required | Description |
|---|---|---|---|
| `true` | `EntryType` | no | Description of the yes outcome. |
| `false` | `EntryType` | no | Description of the no outcome. |

### `ChoiceQuestion<T extends ChoiceCriteria = ChoiceCriteria>`

| Property | Type | Required | Default | Description |
|---|---|---|---|---|
| `type` | `"choice"` | yes | — | Discriminant. |
| `instructions` | `EntryType` | no | — | The question as text, a JSON object, or an array; optional or `null`. |
| `criteria` | `T` | **yes** | — | Descriptions of the available outcomes. |

### `ScoreQuestion<T extends ScoreCriteria = ScoreCriteria>`

| Property | Type | Required | Default | Description |
|---|---|---|---|---|
| `type` | `"score"` | yes | — | Discriminant. |
| `instructions` | `EntryType` | no | — | The question as text, a JSON object, or an array; optional or `null`. |
| `criteria` | `T` | **yes** | — | Descriptions of the available outcomes (ordered rubric, length ≥ 2). |

### `ChoiceCriteria`

```ts
type ChoiceCriteria = { [label: string]: Description };
```

"Labels mapped to descriptions, or `null` for undescribed labels." The published docs render the index signature as `[label: string]: EntryType`; since `Description = EntryType`, the two spellings are identical.

### `ScoreCriteria`

```ts
type ScoreCriteria = readonly [EntryType, EntryType, ...EntryType[]];
```

"At least two descriptions indexed by score from zero; `null` leaves a score undescribed." The tuple prefix is what enforces the two-entry minimum at compile time; `validateQuestions` re-checks it at runtime.

### `Question`

```ts
type Question = NoulQuestion | ScoreQuestion | ChoiceQuestion;
```

"A question identified by its `type` field." The union members use their *default* generic arguments, so a `Question`-typed value has widened criteria.

### `Questions`

```ts
interface Questions {
  [name: string]: Question;
}
```

"Questions keyed by the names used to identify their answers." Must be nonempty at call time — `systemOne()` throws `TypeSafeError` "At least one question is required." for `{}`.

## Responses

### `NoulResponse`

| Property | Type | Readonly | Description |
|---|---|---|---|
| `type` | `"noul"` | yes | Discriminant. |
| `noul` | `number` | yes | Probability of a yes answer, from zero to one. |

### `ChoiceResponse<T extends ChoiceCriteria = ChoiceCriteria>`

| Property | Type | Readonly | Description |
|---|---|---|---|
| `type` | `"choice"` | yes | Discriminant. |
| `choice` | `keyof T & string` | yes | The selected label. |
| `confidence` | `number` | yes | Reported confidence in the selected label. |
| `probabilities` | `{ readonly [label in keyof T]: number }` | yes | Probabilities keyed by label. |

(The generated docs print `probabilities` as `{ readonly [label in string | number | symbol]: number }` — that is typedoc expanding `keyof T` for the default generic argument, not a different type.)

### `ScoreResponse<T extends ScoreCriteria = ScoreCriteria>`

| Property | Type | Readonly | Description |
|---|---|---|---|
| `type` | `"score"` | yes | Discriminant. |
| `score` | `number` | yes | Expected score, which may fall between integer rubric levels. |
| `confidence` | `number` | yes | Reported confidence in the score. |
| `legend` | `ScoreLegend<T>` | yes | Rubric descriptions keyed by score. |
| `probabilities` | `{ readonly [score in ScoreOf<T>]: number }` | yes | Probabilities keyed by score. |

(Docs print `probabilities` as `{ readonly [score in number | \`${number}\`]: number }` — again the expansion for the default generic argument.)

Because `score` is an *expectation*, it is generally not an integer: a 0–3 rubric can return `2.41`. See [[concepts/score]] and [[concepts/confidence]].

### `ScoreOf<T extends ScoreCriteria>`

```ts
type ScoreOf<T> = number extends T["length"] ? number : Extract<keyof T, `${number}`>;
```

"Score keys inferred from the rubric; a fixed-length tuple yields its indices, otherwise `number`." With `score("…", ["a", "b", "c"] as const)` you get `"0" | "1" | "2"`; with a `readonly EntryType[]` of unknown length you get `number`.

### `ScoreLegend<T extends ScoreCriteria>`

```ts
type ScoreLegend<T> = { readonly [score in ScoreOf<T>]: T[score] };
```

"Rubric descriptions keyed by score." This is the server echoing back your rubric keyed by index, so `legend["2"]` is the literal description you supplied.

### `ResultFor<T extends Question>`

```ts
type ResultFor<T> =
  T extends NoulQuestion ? NoulResponse
  : T extends ScoreQuestion<infer S> ? ScoreResponse<S>
  : T extends ChoiceQuestion<infer E> ? ChoiceResponse<E>
  : never;
```

"The answer type for a question, preserving its criteria keys." Order matters: `NoulQuestion` is tested first, then `ScoreQuestion`, then `ChoiceQuestion`; anything else resolves to `never`.

### `Usage`

| Property | Type | Readonly | Description |
|---|---|---|---|
| `input_tokens` | `number` | yes | Number of input tokens used. |
| `output_tokens` | `number` | yes | Number of output tokens used. |

Snake_case, matching the wire format in [[reference/http-api]].

## Requests and results

### `SystemOneRequest<Q extends Questions = Questions>`

"State and named questions for `systemOne`. Additional properties on a request variable are forwarded, including `null` values."

| Property | Type | Required | Default | Description |
|---|---|---|---|---|
| `state` | `EntryType` | **yes** | — | Text, a JSON object or array, or `null` to evaluate. |
| `questions` | `Q` | **yes** | — | Nonempty questions keyed by the names used to identify their answers. |
| `model` | `string` | no | client `defaultModel` (`jev-latest` unless overridden) | Model override. |

The "additional properties are forwarded" note is a consequence of TypeScript's excess-property check applying only to object *literals*: pass a pre-declared variable with extra keys and the SDK spreads them into the request body. Treat that as a way to send fields the SDK does not model yet, and as a footgun otherwise.

### `SystemOneRequestPayload`

`extends SystemOneRequest` (with the default `Questions`), overriding `model`:

| Property | Type | Required | Description |
|---|---|---|---|
| `state` | `EntryType` | yes | Inherited. |
| `questions` | `Questions` | yes | Inherited. |
| `model` | `string` | **yes** | Model resolved by the client; no longer optional. |

"Request body for `POST /v1/systemone`, with the model resolved." You rarely construct one — `systemOne()` builds it as `{...request, model: request.model ?? this.defaultModel}` — but it is the exact JSON shape that goes on the wire.

### `SystemOneResult<Q extends Questions>`

| Property | Type | Readonly | Description |
|---|---|---|---|
| `model` | `string` | yes | The model used to answer the request (resolved alias, e.g. `jev-1.13.0`). |
| `answers` | `{ readonly [K in keyof Q]: ResultFor<Q[K]> }` | yes | Answers with types inferred from the supplied questions. |
| `usage` | `Usage` | yes | Token usage for the request. |

Note that `Q` has **no default** here, unlike `SystemOneRequest<Q>` — you always write `SystemOneResult<typeof questions>` or let inference supply it.

### `ModelCard`

| Property | Type | Readonly | Description |
|---|---|---|---|
| `name` | `string` | yes | (undocumented in the source docstring) Model name. |
| `description` | `string` | yes | (undocumented in the source docstring) |
| `release_date` | `string` | yes | (undocumented in the source docstring) ISO date (inferred). |

"Metadata for an available model." The three fields carry no per-field docstrings in either docs or source.

### `Models`

| Method | Signature | Description |
|---|---|---|
| `list` | `list(options?: RequestOptions): APIPromise<ModelCard[]>` | List the models available to the account. `options` defaults to `{}`. |

"Access to the Models API resource." Reached as `client.models`; exported as a type only.

### `WithResponse<T>`

| Property | Type | Readonly | Description |
|---|---|---|---|
| `data` | `T` | no | The parsed response body. |
| `response` | `Response` | no | The HTTP response, with its body consumed by parsing. |
| `requestId` | `string \| undefined` | no | Request ID from `x-typesafe-request-id`, or `undefined` when absent. |

Returned by `APIPromise#withResponse()`; exported from `src/api-promise.ts`, not `src/types.ts`.

## Configuration types

### `TypeSafeClientConfig`

"Client options. Explicit values take precedence over environment variables, then SDK defaults." Every property is optional.

| Property | Type | Required | Default | Description |
|---|---|---|---|---|
| `apiKey` | `string` | no | `TYPESAFE_API_KEY` | Required API key; falls back to the env var. |
| `baseURL` | `string` | no | `TYPESAFE_BASE_URL`, then `https://api.typesafe.ai` | API root. |
| `defaultModel` | `string` | no | `TYPESAFE_DEFAULT_MODEL`, then `jev-latest` | Default model. |
| `logLevel` | `LogLevel` | no | `TYPESAFE_LOG_LEVEL`, then `warn` | `info` logs request summaries; `debug` adds headers and bodies. Known credential headers are redacted; bodies are not. |
| `logger` | `Logger` | no | prefixed `console` | Logger filtered to `logLevel` and above. |
| `retry` | `Partial<RetryPolicy>` | no | `RetryPolicy` defaults | Retry overrides. |
| `timeout` | `number` | no | `10000` | Timeout per attempt in milliseconds, without a total retry budget. |
| `defaultHeaders` | `Record<string, string>` | no | `{}` | Additional request headers; per-call headers take precedence. |
| `dangerouslyAllowBrowser` | `boolean` | no | `false` | Allow browser use, exposing the API key to page users. |
| `fetch` | `Fetch` | no | global `fetch` | Custom HTTP fetch implementation for transport configuration or tests. |

### `Fetch`

```ts
type Fetch = (input: string, init?: RequestInit) => Promise<Response>;
```

"HTTP fetch implementation compatible with the global `fetch`." Narrower than the DOM `fetch`: `input` is a `string`, not `RequestInfo | URL`.

### `Logger`

"Log methods accepting a message and structured values; compatible with `console`." All four methods are required.

| Method | Signature | Returns |
|---|---|---|
| `debug` | `(message: string, ...args: unknown[]) => void` | `void` |
| `info` | `(message: string, ...args: unknown[]) => void` | `void` |
| `warn` | `(message: string, ...args: unknown[]) => void` | `void` |
| `error` | `(message: string, ...args: unknown[]) => void` | `void` |

### `LogLevel`

```ts
type LogLevel = "debug" | "info" | "warn" | "error" | "off";
```

"Log verbosity; `off` disables logging." Default `warn`.

### `EnvVar`

```ts
type EnvVar = (typeof ENV)[keyof typeof ENV];
```

Resolves to `"TYPESAFE_API_KEY" | "TYPESAFE_BASE_URL" | "TYPESAFE_DEFAULT_MODEL" | "TYPESAFE_LOG_LEVEL"`. The generated docs give it no description.

## Exported variables

### `ENV`

```ts
const ENV: {
  readonly apiKey: "TYPESAFE_API_KEY";
  readonly baseURL: "TYPESAFE_BASE_URL";
  readonly defaultModel: "TYPESAFE_DEFAULT_MODEL";
  readonly logLevel: "TYPESAFE_LOG_LEVEL";
};
```

"Environment variable names for client configuration. Explicit options take precedence."

| Key | Literal value | Documented effect |
|---|---|---|
| `apiKey` | `"TYPESAFE_API_KEY"` | Required API key; used when `apiKey` is omitted. |
| `baseURL` | `"TYPESAFE_BASE_URL"` | API root; defaults to `https://api.typesafe.ai`. |
| `defaultModel` | `"TYPESAFE_DEFAULT_MODEL"` | Default model name; defaults to `jev-latest`. |
| `logLevel` | `"TYPESAFE_LOG_LEVEL"` | Log level; defaults to `warn`. |

### `LOG_LEVELS`

```ts
const LOG_LEVELS: readonly LogLevel[];
```

"Supported log levels, from most to least verbose." Source value: `["debug", "info", "warn", "error", "off"]`. The published docs give the type but not the value; the value comes from `src/logging.ts`.

### `VERSION`

```ts
const VERSION: "0.6.0" = "0.6.0";
```

A literal type, not a widened `string`. See [[reference/javascript-sdk]].

## Runnable example: generics end to end

ESM, TypeScript. Nothing here is annotated except to *prove* the inferred types:

```ts
import { choice, noul, score, TypeSafeClient } from "@typesafe-ai/sdk";
import type {
  ChoiceResponse,
  NoulResponse,
  Question,
  Questions,
  ResultFor,
  ScoreResponse,
  SystemOneRequest,
  SystemOneResult,
} from "@typesafe-ai/sdk";

const client = new TypeSafeClient();

const questions = {
  isBilling: noul("Is this ticket about billing?"),
  tone: choice("What is the customer's tone?", { calm: null, frustrated: null, angry: null }),
  urgency: score("How urgent is this ticket?", ["can wait", "this week", "today", "right now"]),
} satisfies Questions;

const request: SystemOneRequest<typeof questions> = {
  state: { subject: "Charged twice", body: "Two $49 charges in August." },
  questions,
  model: "jev-latest",
};

const result: SystemOneResult<typeof questions> = await client.systemOne(request);

// ResultFor picks the answer type per question:
const billing: NoulResponse = result.answers.isBilling;
const tone: ChoiceResponse<{ calm: null; frustrated: null; angry: null }> = result.answers.tone;
const urgency: ScoreResponse<readonly ["can wait", "this week", "today", "right now"]> =
  result.answers.urgency;

console.log(billing.noul);                         // number, 0..1
console.log(tone.choice);                          // "calm" | "frustrated" | "angry"
console.log(tone.probabilities.angry);             // number
console.log(urgency.score, urgency.legend["3"]);   // number, "right now"
console.log(urgency.probabilities["0"]);           // number
console.log(result.model, result.usage.input_tokens, result.usage.output_tokens);

// Writing a generic helper: keep the `const` parameter to preserve literals.
async function ask<const Q extends Questions>(state: unknown, qs: Q) {
  const { answers } = await client.systemOne({ state: state as never, questions: qs });
  return answers;
}

// `ResultFor` is usable directly for a single question:
type ToneAnswer = ResultFor<(typeof questions)["tone"]>; // ChoiceResponse<{...}>

// A widened `Question` loses the literal keys — this is why you should not annotate:
const widened: Question = questions.tone;
type Widened = ResultFor<typeof widened>; // ChoiceResponse<ChoiceCriteria>, `choice` is `string`
```

CommonJS gets the same runtime behaviour but no type parameters at the call site unless you use `// @ts-check` with JSDoc:

```js
const { choice, TypeSafeClient } = require("@typesafe-ai/sdk");
/** @type {import("@typesafe-ai/sdk").Questions} */
const questions = { tone: choice("Tone?", { calm: null, angry: null }) };
```

## Gotchas

- **Annotating kills inference.** `const q: Questions = {...}` widens every criteria object; `answers.x.choice` becomes `string`. Use `satisfies Questions` or no annotation at all.
- **`ScoreOf` degrades to `number`** for arrays whose length TypeScript cannot see (e.g. `string[]`), which silently removes the literal keys from `legend` and `probabilities`.
- **`ChoiceResponse.choice` is `keyof T & string`**, so a criteria map built from a `Record<string, null>` yields `string`.
- **`EntryType` excludes bare numbers and booleans.** `state: 42` does not type-check; wrap it (`state: { value: 42 }`) or stringify it.
- **`Usage` uses snake_case** while everything else in the SDK is camelCase — it mirrors the HTTP response.

## Version notes

- Types described for `@typesafe-ai/sdk` 0.6.0 (repo commit `66880ccded6cb642dc1809620c2b108c33730214`, 2026-09-15).
- `ScoreCriteria` became a `readonly` tuple in 0.6.0; in 0.5.7 score criteria were a dictionary keyed by integers. See [[reference/javascript-sdk-changelog]].
- **Doc-vs-source:** `Models` is published under "Interfaces" but declared `export class Models` in `src/resources/models.ts` (re-exported as `export type { Models }`, so only the type is public).
- **Doc-vs-source (cosmetic):** the docs render `ChoiceCriteria`'s index signature as `EntryType` where source writes `Description`, and expand the mapped-type keys of `ChoiceResponse.probabilities` / `ScoreResponse.probabilities` to `string | number | symbol` and `number | \`${number}\`` respectively. These are typedoc expansions of the same types.

## Related

- [[reference/javascript-sdk]] — client, builders, examples
- [[reference/javascript-sdk-errors]] — `RetryPolicy`, `RequestOptions`, error classes
- [[reference/openapi-schemas]] — the same shapes on the wire
- [[reference/http-api]] — `POST /v1/systemone`, `GET /v1/models`
- [[concepts/primitives]] — what Choice, Score and Noul mean
- [[reference/python-sdk-questions]] — Python counterparts

## Sources

- raw/docs/sdk__javascript__api.md (https://docs.typesafe.ai/sdk/javascript/api)
- raw/docs/sdk__javascript__api__interfaces__*.md (https://docs.typesafe.ai/sdk/javascript/api/interfaces/*)
- raw/docs/sdk__javascript__api__type-aliases__*.md (https://docs.typesafe.ai/sdk/javascript/api/type-aliases/*)
- raw/docs/sdk__javascript__api__variables__ENV.md, __LOG_LEVELS.md, __VERSION.md
- raw/github/typesafe-sdk-js/src/types.ts, src/env.ts, src/logging.ts, src/api-promise.ts, src/resources/models.ts (commit 66880ccded6cb642dc1809620c2b108c33730214)
