Commands, settings, SDK functions, anything in the docs.

Reference

@ledable/sdk/app

Define an app, its settings, and what it returns.

On this page

Generated from the types of the SDK. Import from @ledable/sdk/app; an editor shows the same declarations and comments as you type.

Functions

account

A third-party account linked through AuthHub; the render receives its handle.

function account<
  const S extends Common & {
    readonly platform: "github" | "todoist" | "youtube" | "spotify";
  },
>(spec: S)

assetsPrefix

Prefix of every asset of one version; the asset path is appended after a slash.

function assetsPrefix(appId: string, version: string): string

boolean

function boolean<const S extends Common & { readonly default?: boolean }>(spec: S)

bundleKey

function bundleKey(appId: string, version: string): string

cacheTag

Digest composite application keys without exposing credentials in cache paths.

function cacheTag(...parts: readonly unknown[]): Promise<string>

colorRgb

function colorRgb<
  const S extends Common & { readonly default?: readonly [number, number, number] },
>(spec: S)

colorRgba

function colorRgba<
  const S extends Common & { readonly default?: readonly [number, number, number, number] },
>(spec: S)

country

function country<const S extends Common & { readonly default?: string }>(spec: S)

createAppCache

function createAppCache(backend: CacheBackend, scope: AppCacheScope): AppCache

createAppServer

Build a fetch handler speaking the app protocol: GET /, GET /{endpoint}, GET /{endpoint}/render, GET /{endpoint}/preview. Platform-neutral: usable as a Cloudflare Worker fetch export or with any Request/Response-based host.

function createAppServer(options: AppServerOptions): FetchHandler

createRng

function createRng(seed: number): Rng

credential

A credential the user types in, such as a personal API token, which AuthHub keeps encrypted. The render receives its handle and reads the value with `ctx.credentials.get`; an app with one checks what the user types (`verifyCredential` in ./app.ts).

function credential<const S extends Common>(spec: S)

date

function date<const S extends Common & { readonly default?: string }>(spec: S)

datetime

function datetime<const S extends Common & { readonly default?: number }>(spec: S)

defineApp

function defineApp<S extends Settings>(app: AppDefinition<S>): LedApp

fixedNumber

function fixedNumber(value: number, digits = 0): string

float

function float<const S extends Common & { readonly default?: number }>(spec: S)

hostApp

A bundle run in this process, such as in tests or a local preview, as the host serves it.

function hostApp(app: LedApp, manifest: AppManifest): HostedApp

integer

function integer<const S extends Common & { readonly default?: number }>(spec: S)

listingProblems

What a listing holds beyond `LISTING_LIMITS`, one sentence each; empty when it fits.

function listingProblems(listing: Pick<
  ReleaseManifest, "name" | "description" | "description_long" | "tags" | "screenshots"
>): string[]

location

function location<const S extends Common & { readonly default?: LocationValue }>(spec: S)

manifestKey

function manifestKey(appId: string, version: string): string

manifestToPublicDict

Mirrors models/app.py AppManifest.to_public_dict (non-repo mode).

function manifestToPublicDict(
  manifest: AppManifest,
  baseUrl: string,
  endpoint: string,
): PublicManifest

marquee

function marquee(options: MarqueeOptions): Marquee

memoryCacheBackend

In-memory backend for tests and local hosts.

function memoryCacheBackend(now: () => number = Date.now): CacheBackend

multiselect

function multiselect<
  const S extends Common & {
    readonly default?: readonly string[];
    readonly options: readonly string[];
  },
>(spec: S)

outboundRefusal

Why an app may not request `url`, or null when it may: only HTTPS on the default port to a declared host.

function outboundRefusal(url: URL, network: AppNetwork): string | null

parseFields

Resolve raw string values against the manifest fields: absent optional fields fall back to their default, absent required fields fail. Fields whose options or visibility follow another field are settled once the others are parsed; a hidden one takes its default whatever was sent.

function parseFields(
  raw: Readonly<Record<string, string>>,
  fields: Readonly<Record<string, ConfigField>>,
): AppParams

parseFieldValue

function parseFieldValue(field: ConfigField, raw: string): ConfigValue

readSettings

What the version's `settings` return, checked, and kept for as long as the app says. Throws when they fail or return what no client could show.

async function readSettings(
  app: HostedApp,
  endpoint: string,
  manifest: AppManifest,
  cacheBackend: CacheBackend,
  capabilities: SettingsCapabilities,
): Promise<ProjectSettings>

resultWebpBlob

Mirrors models/webp.py WebpBlobMixin.get_webp_blob.

async function resultWebpBlob(
  image: ResultImage | null | undefined,
  frameMs: number,
  behavior: AnimationBehavior,
  encoder?: FrameEncoder,
): Promise<Uint8Array | null>

select

One of `options`, or with `depends_on`, one of `options_by` that field's value. The render receives a string: what is on offer is what the settings return now, which no type written in the code can promise, and the platform has already checked the value against it.

function select<const S extends SelectSpec>(spec: S)

significantNumber

Python's general format, including significant-digit rounding and exponent thresholds.

function significantNumber(value: number, digits = 4): string

stableStringify

Deterministic JSON with recursively sorted object keys.

function stableStringify(value: unknown): string

staticConfigSource

Fixed values layered over the query string; useful as a mock.

function staticConfigSource(values: Readonly<Record<string, string>>): ConfigSource

string

function string<const S extends Common & { readonly default?: string }>(spec: S)

time

function time<const S extends Common & { readonly default?: string }>(spec: S)

timezone

function timezone<const S extends Common & { readonly default?: string }>(spec: S)

verifyAppCredential

The app's verdict on a credential a user typed in, or null for a bundle without a check. The value and the app's secrets are masked in the verdict's message and in what the check throws, which means the credential could not be checked now.

async function verifyAppCredential(
  app: HostedApp,
  endpoint: string,
  credential: CredentialToVerify,
  secretsPool: Readonly<Record<string, string>>,
): Promise<CredentialVerdict | null>

versionId

function versionId(appId: string, version: string): string

Constants

APP_CATEGORIES

The store's categories. An app declares exactly one in ledable.json; the store groups its home page by them and refuses a new version without one.

const APP_CATEGORIES = [
  "clock",
  "weather",
  "finance",
  "news",
  "sports",
  "productivity",
  "developer",
  "entertainment",
  "science",
  "travel",
] as const

appCategorySchema

const appCategorySchema = z.enum(APP_CATEGORIES)

appIdSchema

Identity of a published bundle version and the write-once R2 layout the gateway reads it from (docs/architecture/app-runtime.md). The store is the only program writing these keys, so both sides share one definition.

const appIdSchema = z.string().check(z.regex(/^[a-z0-9][a-z0-9-]{0,63}$/))

appManifestSchema

const appManifestSchema

assetPathSchema

Paths of plain segments; each starts with a letter or digit, so `..` cannot occur.

const assetPathSchema = z
  .string()
  .check(
    z.maxLength(256),
    z.regex(new RegExp(`^${ASSET_SEGMENT}(/${ASSET_SEGMENT})*\\.(${ASSET_EXTENSIONS})$`)),
  )

assetRefSchema

const assetRefSchema = z.object({ path: assetPathSchema })

credentialVerdictSchema

What an app's check of a credential the user typed in found (`verifyCredential`).

const credentialVerdictSchema = z.union([
  z.object({ valid: z.literal(true) }),
  z.object({ valid: z.literal(false), message: z.string() }),
])

DEFAULT_FRAME_MS

const DEFAULT_FRAME_MS = 200

DEFAULT_HARD_TTL_MS

const DEFAULT_HARD_TTL_MS = 10 * 60 * 1000

DEFAULT_MARQUEE_FPS

const DEFAULT_MARQUEE_FPS = 50

DEFAULT_SETTINGS_TTL_MS

How long the platform keeps what `settings` returned, unless the app says otherwise.

const DEFAULT_SETTINGS_TTL_MS = 24 * 60 * 60 * 1000

DEFAULT_SOFT_TTL_MS

const DEFAULT_SOFT_TTL_MS = 5 * 60 * 1000

hostPatternSchema

`api.example.com` names one host; `*.example.com` names every subdomain of `example.com`, at any depth, but not `example.com` itself. A wildcard over a public suffix would let an app reach hosts of anyone, so `*.com` and `*.github.io` are refused, like a bare `*`.

const hostPatternSchema = z.string().check(
  z.refine(pattern => {
    const name = pattern.startsWith("*.") ? pattern.slice(2) : pattern;
    return name.length <= 253 && HOST_NAME.test(name);
  }, "Use a lowercase host name, or *. and a host name, without scheme, port or path"),
  z.refine(
    pattern => !pattern.startsWith("*.") || !isPublicSuffix(pattern.slice(2)),
    "A wildcard must not cover a public suffix such as *.com",
  ),
)

LISTING_LIMITS

How much a store listing holds, in characters, so every store client can lay it out. The CLI checks a project against it before it builds, and the store checks each upload again. Published versions are not held to it, so it can change without a manifest no longer reading.

const LISTING_LIMITS = {
  name: 30,
  description: 120,
  readme: 4000,
  tags: 5,
  tag: 20,
  screenshots: 6,
} as const

locationValueSchema

const locationValueSchema

MAX_MARQUEE_FRAMES

Frame choreography for scrolling content: N seconds at a fixed fps with integer pixel offsets, within the platform frame budget. A marquee may never emit more than MAX_MARQUEE_FRAMES frames — beyond that the frame time stretches so the requested duration is kept with fewer frames.

const MAX_MARQUEE_FRAMES = 600

networkSchema

const networkSchema

newsResponseSchema

const newsResponseSchema = z.extend(newsSummarySchema, {
  counts: z.record(z.string(), z.int().check(z.nonnegative())),
})

newsSummarySchema

const newsSummarySchema = z.object({
  items: z.array(z.string()),
})

numericSchema

Upstream APIs serialize decimal values as either JSON numbers or numeric strings.

const numericSchema = z.pipe(
  z.union([
    z.number(),
    z.pipe(z.string().check(z.trim(), z.regex(decimalText)), z.transform(Number)),
  ]),
  z.number(),
)

previewResultSchema

const previewResultSchema = z.extend(
  z.pick(renderResultSchema, { frameMs: true, behavior: true }),
  { image: z.nullish(resultImageSchema) },
)

PROJECT_FILE

The file at the root of every app project, which `projectSchema` reads.

const PROJECT_FILE = "ledable.json"

projectFieldSchema

const projectFieldSchema

projectSchema

The authored file contains declarations and local paths, never executable metadata.

const projectSchema

publicManifestSchema

const publicManifestSchema

queryConfigSource

const queryConfigSource: ConfigSource = ({ request }) => {
  const raw: Record<string, string> = {};
  for (const [key, value] of new URL(request.url).searchParams) {
    raw[key] = value;
  }
  return raw;
}

releaseManifestSchema

Immutable upload snapshot; local document and media paths have already been resolved. `fields` is what the bundle's settings returned when the version was checked, kept for review and for when they cannot be read.

const releaseManifestSchema

renderResultSchema

const renderResultSchema = z.object({
  ok: z.optional(z.boolean()),
  msg: optionalString,
  image: z.optional(z.nullable(resultImageSchema)),
  frameMs: z.optional(z.number()),
  behavior: z.optional(animationBehaviorSchema),
  realtime: z.optional(z.boolean()),
  softTtlMs: z.optional(z.number()),
  hardTtlMs: z.optional(z.number()),
  cacheId: optionalString,
})

REQ_HEADER_CACHE_ID

const REQ_HEADER_CACHE_ID = "LD-Cache-ID"

REQ_HEADER_DURATION

const REQ_HEADER_DURATION = "LD-Duration"

REQ_HEADER_FIRMWARE

const REQ_HEADER_FIRMWARE = "LD-Firmware"

REQ_HEADER_INSTANCE

const REQ_HEADER_INSTANCE = "LD-Instance"

REQ_HEADER_LANGUAGE

const REQ_HEADER_LANGUAGE = "LD-Language"

REQ_HEADER_MODEL

const REQ_HEADER_MODEL = "LD-Model"

REQ_HEADER_RESOLUTION

const REQ_HEADER_RESOLUTION = "LD-Resolution"

REQ_HEADER_TIMEZONE

const REQ_HEADER_TIMEZONE = "LD-Timezone"

RESP_HEADER_BEHAVIOR

const RESP_HEADER_BEHAVIOR = "LD-Behavior"

RESP_HEADER_CACHE_ID

const RESP_HEADER_CACHE_ID = "LD-Cache-ID"

RESP_HEADER_HARD_TTL

const RESP_HEADER_HARD_TTL = "LD-Hard-TTL"

RESP_HEADER_REALTIME

const RESP_HEADER_REALTIME = "LD-Realtime"

RESP_HEADER_SOFT_TTL

const RESP_HEADER_SOFT_TTL = "LD-Soft-TTL"

secretNameSchema

The name of a secret an app declares and its maintainers set.

const secretNameSchema = z.string().check(z.regex(/^[A-Z_][A-Z0-9_]*$/))

settingsSchema

Every setting an app returns (./settings.ts). A field may be shown only for some values of another, or take its options by another's value; that other field is a plain select or switch, so one level of rules settles every field.

const settingsSchema

versionSchema

const versionSchema = z
  .string()
  .check(z.regex(/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]{1,32})?$/))

Classes

ConfigError

class ConfigError extends Error

Interfaces

AppAssets

interface AppAssets {
  /** Raw bytes of any asset, e.g. a `.ledfont` for `decodeBitmapFont`. */
  bytes(ref: AssetRef): Promise<Uint8Array>;
  /** Decoded pixels of a still WebP asset; for an animation, its first frame. */
  image(ref: AssetRef): Promise<Framebuffer>;
  /** Every frame of a WebP asset in order; a still asset yields exactly one. */
  frames(ref: AssetRef): Promise<readonly Framebuffer[]>;
}

AppAuth

interface AppAuth {
  /** Current provider access token, or null when authorization is required. */
  getToken(handle: string): Promise<string | null>;
}

AppCache

interface AppCache {
  /** `tag` names the call site (e.g. "quote", "webp") within the app. */
  get<T>(tag: string, compute: () => Promise<CacheEntry<T>>, options?: CacheGetOptions): Promise<T>;
}

AppCacheScope

interface AppCacheScope {
  /** Endpoint name; part of the hard namespace prefix. */
  readonly appId: string;
  /** Manifest version; keys never survive an app version bump. */
  readonly version: string;
  readonly fields: readonly string[];
  readonly params: AppParams;
}

AppCredentials

The credentials users typed into the app's credential settings (./settings.ts).

interface AppCredentials {
  /** The value a credential setting's handle names, or null once it is deleted. */
  get(handle: string): Promise<string | null>;
}

AppImages

interface AppImages {
  /** Decode bounded upstream JPEG or PNG image bytes through the host's WASM codecs. */
  decode(bytes: Uint8Array): Promise<Framebuffer>;
}

AppLocations

interface AppLocations {
  /** Resolve coordinates with the platform's versioned geographic timezone dataset. */
  timezoneAt(lat: number, lng: number): Promise<string | null>;
}

AppNews

interface AppNews {
  /** Shared news summaries; provider credentials stay in the host service. */
  getSummary(): Promise<NewsResponse>;
}

AppServerOptions

interface AppServerOptions {
  readonly apps: Readonly<Record<string, HostedApp>>;
  readonly configSource?: ConfigSource;
  /** Frame compressor for WebP output; defaults to the pure-TS encoder. */
  readonly frameEncoder?: FrameEncoder;
  /**
   * Storage behind ctx.cache, the settings and the encoded WebP; the host decides where entries
   * live and how widely they are shared.
   */
  readonly cacheBackend: CacheBackend;
  /**
   * Pool of platform-held secrets available to the hosted apps. Each app only
   * ever sees the names its manifest declares.
   */
  readonly secrets?: Readonly<Record<string, string>>;
  readonly auth?: AppAuth;
  /** The credentials users typed into the hosted apps' credential settings. */
  readonly credentials?: AppCredentials;
  readonly news?: AppNews;
  readonly locations?: AppLocations;
  readonly images?: AppImages;
  /** Asset store of the hosted bundle version; previews read it too. */
  readonly assets?: AppAssets;
  readonly serverName?: string;
}

AssetRef

A build-time reference to one file published next to the bundle. `import art from "./assets/art.webp"` evaluates to this object: the bytes never enter the bundle, and the host reads them from `assets/{appId}@{version}/{path}` in the same write-once store as the bundle.

interface AssetRef {
  /**
   * Path inside this version's assets: where the file sits in its project, e.g.
   * `assets/sun.webp`, or `sdk/<package>/…` for a file of an SDK package.
   */
  readonly path: string;
}

CacheBackend

Storage backends only see opaque namespaced keys and byte payloads.

interface CacheBackend {
  get(key: string): Promise<CachedValue | null>;
  put(key: string, value: CachedValue, ttlMs: number): Promise<void>;
}

CachedValue

interface CachedValue {
  readonly kind: CachedKind;
  readonly bytes: Uint8Array;
}

CacheEntry

Read-through compute cache for apps. Safety-by-default keying: the cache key is derived by the framework from the app's parsed params — never from caller-supplied strings — so a call site cannot accidentally under-key user-scoped data. Sharing across users is an explicit act: `vary` narrows the key to the named manifest fields, which makes every sharing decision reviewable. The host's backend decides where entries live and how widely they are shared; the gateway's edge cache is per data centre, so each one computes its own. Values must be JSON-serializable or Uint8Array; JSON round-trips lose rich types (Date).

interface CacheEntry<T> {
  readonly value: T;
  readonly ttlMs: number;
}

CacheGetOptions

interface CacheGetOptions {
  /**
   * Manifest field names the cached value depends on. Omitted = all fields
   * (fully isolated per distinct config, the safe default). Narrowing to a
   * subset is what enables cross-user sharing.
   */
  readonly vary?: readonly string[];
}

CredentialToVerify

A credential the user typed into one of the app's credential settings, before it is kept.

interface CredentialToVerify {
  readonly field: string;
  readonly value: string;
}

HostedApp

One version as the protocol host serves it: its static snapshot, and the bundle's methods.

interface HostedApp {
  readonly manifest: AppManifest;
  settings(ctx: SettingsContext): Promise<HostedSettings>;
  render(ctx: RenderContext, params: AppParams): RenderResult | Promise<RenderResult>;
  preview(ctx: PreviewContext): PreviewResult | Promise<PreviewResult>;
  /** The app's check of a credential, unchecked; null for a bundle without one. */
  verifyCredential(ctx: VerifyContext, credential: CredentialToVerify): Promise<unknown>;
}

HostedSettings

What `settings` returned, and how long the platform may keep it. The fields come from app code, so the app server checks them before anything reads them.

interface HostedSettings {
  readonly fields: unknown;
  readonly ttlMs: number;
}

LedApp

interface LedApp<Params = AppParams> {
  /** Every setting the app has, as manifest fields (./settings.ts). */
  settings(ctx: SettingsContext): Settings | Promise<Settings>;
  /** How long the platform keeps what `settings` returned; a day unless the app says. */
  readonly settingsTtlMs?: number | undefined;
  render(ctx: RenderContext, params: Params): RenderResult | Promise<RenderResult>;
  /** Must be deterministic and must not perform network requests. */
  preview(ctx: PreviewContext): PreviewResult | Promise<PreviewResult>;
  readonly verifyCredential?: CredentialCheck | undefined;
}

Marquee

interface Marquee {
  readonly frameCount: number;
  readonly frameMs: number;
  /** Scroll offset in px for a 0-based frame; last frame reaches distancePx. */
  offsetAt(frame: number): number;
}

MarqueeOptions

interface MarqueeOptions {
  /** Total scroll distance in px (typically content width + viewport width). */
  readonly distancePx: number;
  readonly durationMs: number;
  readonly fps?: number;
}

PreviewContext

What a preview may read: its own published assets, and nothing that varies.

interface PreviewContext {
  readonly assets: AppAssets;
}

RenderContext

interface RenderContext {
  readonly auth: AppAuth;
  readonly credentials: AppCredentials;
  readonly news: AppNews;
  readonly locations: AppLocations;
  readonly images: AppImages;
  /** Published WebP assets of this bundle version. */
  readonly assets: AppAssets;
  /** Device model name (LD-Model). */
  readonly model: string;
  /** Screen resolution in pixels (LD-Resolution). */
  readonly resolution: readonly [number, number];
  /** Firmware version (LD-Firmware). */
  readonly firmware: string;
  /** Unique ID for this app instance (LD-Instance). */
  readonly instanceId: string;
  /** Previous cache ID for this app instance (LD-Cache-ID). */
  readonly cacheId: string;
  /** Language code (LD-Language). */
  readonly language: string;
  /** IANA TZ identifier (LD-Timezone). */
  readonly timezone: string;
  /** Display duration of this app in milliseconds (LD-Duration). */
  readonly durationMs: number;
  /**
   * Server-assigned render instant. Apps must read wall-clock time from here
   * (not Date.now()) so tests can pin it; preview() must not use time at all.
   */
  readonly now: Date;
  /**
   * Read-through compute cache, keyed by the framework from the app's parsed
   * params (all fields by default; narrow with `vary` to share). preview()
   * has no cache — previews are deterministic and memoized by the server.
   */
  readonly cache: AppCache;
  /** Platform-provisioned secrets, restricted to the manifest declaration. */
  readonly secrets: Readonly<Record<string, string>>;
}

Rng

Seeded pseudo-random source for apps. Same seed, same sequence, on every runtime — a generated animation can be reproduced (and cache-addressed) by its seed alone instead of being stored.

interface Rng {
  /** Uniform float in [0, 1). */
  next(): number;
  /** Uniform integer in [0, maxExclusive). */
  int(maxExclusive: number): number;
  /** New array with the items in shuffled order (Fisher-Yates). */
  shuffle<T>(items: readonly T[]): T[];
  /** `count` distinct items in draw order. */
  sample<T>(items: readonly T[], count: number): T[];
}

SettingsContext

What `settings` may read: nothing that belongs to one user or device.

interface SettingsContext {
  readonly now: Date;
  readonly cache: AppCache;
  readonly secrets: Readonly<Record<string, string>>;
  readonly assets: AppAssets;
}

VerifyContext

What checking a credential may read; `fetch` reaches the hosts the app declares.

interface VerifyContext {
  readonly now: Date;
  readonly secrets: Readonly<Record<string, string>>;
}

Types

AnimationBehavior

type AnimationBehavior = z.infer<typeof animationBehaviorSchema>;

AppCategory

type AppCategory = z.infer<typeof appCategorySchema>;

AppDefinition

An app as its code declares it: the render receives the parameters its settings make, and an app with a credential setting must check what users type into it.

type AppDefinition<S extends Settings> = AppBase<S> &
  (HasCredential<S> extends true ? { readonly verifyCredential: CredentialCheck } : unknown);

AppManifest

type AppManifest = Readonly<z.infer<typeof appManifestSchema>>;

AppNetwork

type AppNetwork = z.infer<typeof networkSchema>;

AppParams

type AppParams = z.infer<typeof appParamsSchema>;

AppVisibility

type AppVisibility = z.infer<typeof appVisibilitySchema>;

ConfigField

type ConfigField = Readonly<z.infer<typeof configFieldSchema>>;

ConfigSource

Where raw (unparsed string) user config values come from. The default source reads the request query string, where devices send them.

type ConfigSource = (input: {
  readonly request: Request;
  readonly endpoint: string;
  /** Context before platform capabilities and parsed params are available. */
  readonly ctx: BaseContext;
}) => Record<string, string> | Promise<Record<string, string>>;

ConfigValue

type ConfigValue = z.infer<typeof configValueSchema>;

ConfigValueType

type ConfigValueType = z.infer<typeof configValueTypeSchema>;

CredentialVerdict

type CredentialVerdict = Readonly<z.infer<typeof credentialVerdictSchema>>;

DateValue

type DateValue = Readonly<z.infer<typeof dateValueSchema>>;

FetchHandler

type FetchHandler = (request: Request) => Promise<Response>;

Field

A manifest field, typed with the value a render receives for it.

type Field<Value> = ConfigField & { readonly __value?: Value };

LocationValue

type LocationValue = Readonly<z.infer<typeof locationValueSchema>>;

NewsResponse

type NewsResponse = z.infer<typeof newsResponseSchema>;

ParamsOf

The parameters a render receives for these settings: unset is null unless it cannot be.

type ParamsOf<S extends Settings> = {
  readonly [Key in keyof S]: S[Key] extends Field<infer Value>
    ? S[Key] extends { readonly required: true } | { readonly default: unknown }
      ? Value
      : Value | null
    : never;
};

PreviewResult

type PreviewResult = Readonly<z.infer<typeof previewResultSchema>>;

ProjectConfig

type ProjectConfig = z.infer<typeof projectSchema>;

ProjectField

type ProjectField = z.infer<typeof fieldShape>;

ProjectSettings

type ProjectSettings = z.infer<typeof settingsSchema>;

PublicManifest

type PublicManifest = z.infer<typeof publicManifestSchema>;

ReleaseManifest

type ReleaseManifest = z.infer<typeof releaseManifestSchema>;

RenderResult

type RenderResult = Readonly<z.infer<typeof renderResultSchema>>;

ResultImage

type ResultImage = z.infer<typeof resultImageSchema>;

Settings

type Settings = Readonly<Record<string, Field<unknown>>>;

TimeValue

type TimeValue = Readonly<z.infer<typeof timeValueSchema>>;