# Models

## Error

```json
{
  "type": "object",
  "properties": {
    "error": {
      "type": "string"
    }
  },
  "required": [
    "error"
  ]
}
```

## FingerprintEnvelope

```json
{
  "type": "object",
  "properties": {
    "fingerprint": {
      "$ref": "#/components/schemas/Fingerprint"
    }
  },
  "required": [
    "fingerprint"
  ]
}
```

## Fingerprint

```json
{
  "type": "object",
  "description": "Нативний FingerprintConfig. Задокументовані підоб'єкти; найпоширеніші;\nоб'єкт відкритий і зберігається ендпоінтами створення\nдослівно, тому будь-яке поле тут буде передано без змін.\n",
  "additionalProperties": true,
  "properties": {
    "name": {
      "type": "string"
    },
    "notes": {
      "type": "string"
    },
    "seed": {
      "type": "integer",
      "description": "0 = режим лише перевизначень (типовий випадок)."
    },
    "navigator": {
      "type": "object",
      "additionalProperties": true,
      "properties": {
        "user_agent": {
          "type": "string"
        },
        "platform": {
          "type": "string",
          "example": "Win32"
        },
        "hardware_concurrency": {
          "type": "integer",
          "example": 12
        },
        "device_memory": {
          "type": "integer",
          "enum": [
            8,
            16,
            32
          ],
          "example": 16
        },
        "language": {
          "type": "string"
        },
        "do_not_track": {
          "type": "boolean"
        }
      }
    },
    "screen": {
      "type": "object",
      "additionalProperties": true,
      "properties": {
        "width": {
          "type": "integer"
        },
        "height": {
          "type": "integer"
        },
        "avail_width": {
          "type": "integer"
        },
        "avail_height": {
          "type": "integer"
        },
        "color_depth": {
          "type": "integer",
          "example": 24
        },
        "device_pixel_ratio": {
          "type": "number",
          "example": 2
        },
        "color_gamut": {
          "type": "string",
          "enum": [
            "",
            "srgb",
            "p3",
            "rec2020"
          ]
        },
        "refresh_rate": {
          "type": "integer",
          "minimum": 24,
          "maximum": 480,
          "example": 60,
          "description": "Заявлена частота оновлення екрана. Якщо поле не вказано, використовується 60. Див. поле `refresh_rate` у запитах створення та редагування."
        }
      }
    },
    "client_hints": {
      "type": "object",
      "description": "Сімейство Sec-CH-UA (у browser.vision називається `hints`).",
      "additionalProperties": true,
      "properties": {
        "platform": {
          "type": "string"
        },
        "platform_version": {
          "type": "string"
        },
        "architecture": {
          "type": "string",
          "example": "x86"
        },
        "bitness": {
          "type": "string",
          "example": "64"
        },
        "mobile": {
          "type": "boolean"
        }
      }
    },
    "webgl": {
      "type": "object",
      "additionalProperties": true,
      "properties": {
        "unmasked_vendor": {
          "type": "string"
        },
        "unmasked_renderer": {
          "type": "string"
        }
      }
    },
    "webgpu": {
      "type": "object",
      "additionalProperties": true
    },
    "webrtc": {
      "type": "string",
      "description": "Режим обробки WebRTC.",
      "enum": [
        "auto",
        "tcp_only",
        "block"
      ]
    },
    "noise": {
      "$ref": "#/components/schemas/NoisePrefs"
    },
    "network": {
      "type": "object",
      "properties": {
        "blocked_ports": {
          "type": "array",
          "items": {
            "type": "integer"
          },
          "description": "Захист від сканування портів локальної мережі (ports_protection)."
        }
      }
    },
    "timezone": {
      "type": "string",
      "description": "Ім'я за IANA або \"auto\"; буде визначено через прив'язаний проксі при запуску."
    }
  }
}
```

## NoisePrefs

```json
{
  "type": "object",
  "description": "Налаштування антифінгерпринт-шуму за векторами. Кожен блок: `{enabled, seed}`\n(+ специфічні параметри). `enabled:false` = наскрізна передача.\n",
  "properties": {
    "canvas": {
      "$ref": "#/components/schemas/NoiseBlock"
    },
    "webgl": {
      "allOf": [
        {
          "$ref": "#/components/schemas/NoiseBlock"
        }
      ],
      "properties": {
        "intensity": {
          "type": "number"
        }
      }
    },
    "audio": {
      "allOf": [
        {
          "$ref": "#/components/schemas/NoiseBlock"
        }
      ],
      "properties": {
        "intensity": {
          "type": "number"
        }
      }
    },
    "client_rects": {
      "allOf": [
        {
          "$ref": "#/components/schemas/NoiseBlock"
        }
      ],
      "properties": {
        "max_offset": {
          "type": "number"
        }
      }
    },
    "sensors": {
      "$ref": "#/components/schemas/NoiseBlock"
    },
    "fonts": {
      "allOf": [
        {
          "$ref": "#/components/schemas/NoiseBlock"
        }
      ],
      "description": "`enabled:true` приховує невелике детерміноване підмножество\nнесуттєвих шрифтів для кожного профілю (решта реальних шрифтів\nхоста проходять наскрізь).\n"
    }
  }
}
```

## NoiseBlock

```json
{
  "type": "object",
  "properties": {
    "enabled": {
      "type": "boolean"
    },
    "seed": {
      "type": "integer",
      "description": "Ентропія на профіль; 0 = обчислити автоматично."
    }
  }
}
```

## CreateProfileRequest

```json
{
  "type": "object",
  "required": [
    "fingerprint"
  ],
  "properties": {
    "name": {
      "type": "string"
    },
    "notes": {
      "type": "string"
    },
    "proxy_id": {
      "type": "string",
      "description": "Прив'язати проксі зі сховища (за id)."
    },
    "proxy": {
      "type": "string",
      "description": "Прив'язати проксі рядком (`host:port:user:pass` або\n`scheme://user:pass@host:port`). Для **постійного** профілю проксі\nдодається у сховище (дедуплікація за ендпоінтом) та проходить\nповний тест (UDP + гео), потім прив'язується за id; відображається\nу списку проксі, результат QUIC/WebRTC кешується. Для **тимчасового**\nпрофілю проксі прикріплюється інлайн (не зберігається). Ігнорується,\nякщо задано `proxy_id`.\n",
      "example": "socks5://user:pass@1.2.3.4:1080"
    },
    "folder": {
      "type": "string",
      "description": "Тег папки (ігнорується для /folders/{folder}/profiles; там пріоритет у шляху)."
    },
    "color": {
      "type": "string",
      "description": "Акцентний колір піктограми вікна профілю та мітки з його назвою в адресному рядку. Якщо поле не вказано, колір піктограми визначається за назвою, а мітка зберігає колір панелі інструментів браузера.",
      "example": "#2FCB80"
    },
    "extensions": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Ідентифікатори бібліотеки розширень (`GET /extensions`), завантажуються під час запуску. Бібліотека не має ідентифікатора 400, а не профілю, який автоматично запускається без нього."
    },
    "refresh_rate": {
      "type": "integer",
      "minimum": 24,
      "maximum": 480,
      "example": 60,
      "description": "Заявлена частота оновлення екрана, записана в `screen.refresh_rate`. Жоден веб-API не повідомляє це значення; сторінка оцінює його за часом виконання requestAnimationFrame. Якщо поле не вказано, використовується 60, а не частота екрана хоста. Кадри можна лише сповільнювати, тому фактична частота є найближчим цілим дільником частоти панелі хоста, що не перевищує вказане значення."
    },
    "fingerprint": {
      "allOf": [
        {
          "$ref": "#/components/schemas/Fingerprint"
        }
      ],
      "description": "Зберігається дослівно. Отримайте з /fingerprint/new та за потреби відредагуйте."
    }
  }
}
```

## EditProfileRequest

```json
{
  "type": "object",
  "description": "Усі поля необов'язкові; змінюється лише передане.",
  "properties": {
    "name": {
      "type": "string"
    },
    "notes": {
      "type": "string"
    },
    "folder": {
      "type": "string",
      "description": "\"\" прибирає профіль з папки (переводить до «Усі»)."
    },
    "proxy_id": {
      "type": "string",
      "description": "\"\" від'єднує проксі."
    },
    "proxy": {
      "type": "string",
      "description": "Рядок проксі; зберігається (дедуплікація) + повний тест, потім прив'язується."
    },
    "color": {
      "type": "string",
      "description": "`#rrggbb`; \"\" повертається до кольору, похідного від назви."
    },
    "extensions": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Замінює весь список; `[]` не завантажує нічого."
    },
    "refresh_rate": {
      "type": "integer",
      "minimum": 24,
      "maximum": 480,
      "example": 60,
      "description": "Заявлена частота оновлення екрана, застосована ПІСЛЯ `fingerprint` і записана в `screen.refresh_rate`. Жоден веб-API не повідомляє це значення; сторінка оцінює його за часом виконання requestAnimationFrame. Якщо поле не вказано, використовується 60, а не частота екрана хоста. Кадри можна лише сповільнювати, тому фактична частота є найближчим цілим дільником частоти панелі хоста, що не перевищує вказане значення."
    },
    "fingerprint": {
      "allOf": [
        {
          "$ref": "#/components/schemas/Fingerprint"
        }
      ],
      "description": "При наявності ЗАМІНЮЄ збережений відбиток дослівно."
    }
  }
}
```

## TempProfileRequest

```json
{
  "type": "object",
  "properties": {
    "fingerprint_id": {
      "type": "string",
      "description": "Запис бібліотеки, на основі якого створюється профіль; якщо не вказано, обирається випадковий запис для `platform`."
    },
    "platform": {
      "type": "string",
      "enum": [
        "Windows",
        "macOS",
        "Linux"
      ],
      "description": "Використовується для вибору випадкового відбитка, якщо не вказано `fingerprint_id`; якщо не вказано жодного з них, береться ОС хоста."
    },
    "proxy": {
      "type": "string",
      "description": "Інлайн-рядок проксі (не зберігається у сховищі)."
    },
    "name": {
      "type": "string"
    },
    "folder": {
      "type": "string"
    },
    "refresh_rate": {
      "type": "integer",
      "minimum": 24,
      "maximum": 480,
      "example": 60,
      "description": "Заявлена частота оновлення екрана, записана в `screen.refresh_rate`. Жоден веб-API не повідомляє це значення; сторінка оцінює його за часом виконання requestAnimationFrame. Якщо поле не вказано, використовується 60, а не частота екрана хоста. Кадри можна лише сповільнювати, тому фактична частота є найближчим цілим дільником частоти панелі хоста, що не перевищує вказане значення."
    },
    "noise": {
      "type": "object",
      "description": "Шум відбитка для кожного вектора. Вектори, яких немає в запиті, зберігають значення за замовчуванням (вимкнені).\n\nМожна поєднати два формати в одному запиті:\n\n  * скорочений: `{\"canvas\": true, \"webgl\": true}`; для `webgl` і `client_rects` також застосовується інтенсивність, яку використовує інтерфейс;\n  * повний об’єкт: `{\"canvas\": {\"enabled\": true, \"seed\": 42}}`, у форматі відповіді `GET /profiles/{id}`.\n\nПоля об’єднуються з налаштуваннями вектора, а не замінюють їх. Наприклад, `{\"webgl\": {\"intensity\": 0.001}}` не змінює `enabled`. Якщо `seed` дорівнює 0 або не вказаний, стабільне значення виводиться з ідентифікатора профілю, щоб два тимчасові профілі не отримали однаковий відбиток.",
      "additionalProperties": {
        "oneOf": [
          {
            "type": "boolean"
          },
          {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean"
              },
              "seed": {
                "type": "integer",
                "format": "int64"
              },
              "intensity": {
                "type": "number",
                "description": "Лише `webgl`."
              },
              "max_offset": {
                "type": "number",
                "description": "Лише `client_rects`."
              }
            }
          }
        ]
      },
      "properties": {
        "canvas": {},
        "webgl": {},
        "audio": {},
        "client_rects": {},
        "sensors": {},
        "fonts": {}
      },
      "example": {
        "canvas": true,
        "webgl": {
          "enabled": true,
          "intensity": 0.0005
        },
        "fonts": true
      }
    }
  }
}
```

## Extension

```json
{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "Передайте це в `extensions` профілю."
    },
    "name": {
      "type": "string"
    },
    "version": {
      "type": "string"
    },
    "description": {
      "type": "string"
    },
    "size_bytes": {
      "type": "integer",
      "format": "int64"
    },
    "added_at": {
      "type": "string",
      "description": "`@<unix_secs>`."
    },
    "icon": {
      "type": "string",
      "nullable": true,
      "description": "Найбільша піктограма, яку декларує маніфест, як URL-адреса `data:`. Null на кінцевій точці списку та на розширеннях, які не надсилають жодних."
    }
  }
}
```

## AddExtensionRequest

```json
{
  "type": "object",
  "description": "Точно один із `url` або `path`.",
  "properties": {
    "url": {
      "type": "string",
      "description": "Сторінка Веб-магазину Chrome, простий ідентифікатор розширення з 32 символів або пряме посилання на `.crx` / `.zip`.",
      "example": "https://chromewebstore.google.com/detail/rabby-wallet/acmacodkjbdgmoleebolmdjonilkdbch"
    },
    "path": {
      "type": "string",
      "description": "Локальна папка `.crx`, `.zip` або розпакована папка на машині програми запуску."
    }
  }
}
```

## Bookmark

```json
{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "format": "uuid"
    },
    "title": {
      "type": "string"
    },
    "url": {
      "type": "string"
    },
    "folder": {
      "type": "string",
      "description": "папка Launcher; порожній означає кожен профіль."
    }
  }
}
```

## BookmarkRequest

```json
{
  "type": "object",
  "required": [
    "url"
  ],
  "properties": {
    "id": {
      "type": "string",
      "description": "Якщо вказано, оновлює цю закладку; якщо не вказано, створює нову."
    },
    "url": {
      "type": "string",
      "description": "Достатньо вказати хост без схеми, до нього додається `https://`.",
      "example": "facebook.com/ads/manager"
    },
    "title": {
      "type": "string",
      "description": "Бланк використовує саму адресу."
    },
    "folder": {
      "type": "string",
      "description": "Порожній (або відсутній) означає кожен профіль."
    }
  }
}
```

## TrashEntry

```json
{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "format": "uuid"
    },
    "name": {
      "type": "string"
    },
    "folder": {
      "type": "string"
    },
    "deleted_at": {
      "type": "integer",
      "format": "int64",
      "description": "Unix секунд."
    },
    "expires_at": {
      "type": "integer",
      "format": "int64",
      "description": "Unix секунди; розгортка запуску видаляє все, що минуло."
    },
    "size_bytes": {
      "type": "integer",
      "format": "int64",
      "description": "Архів, у якому зберігається обліковий запис, а не кеш."
    }
  }
}
```

## ProfileMeta

```json
{
  "type": "object",
  "description": "Метадані профілю в лаунчері (повертаються при створенні).",
  "properties": {
    "id": {
      "type": "string",
      "format": "uuid"
    },
    "name": {
      "type": "string"
    },
    "notes": {
      "type": "string"
    },
    "proxy_id": {
      "type": "string",
      "nullable": true
    },
    "last_launched_at": {
      "type": "string",
      "nullable": true,
      "description": "ISO-8601 або null."
    },
    "created_at": {
      "type": "string",
      "nullable": true
    },
    "pinned": {
      "type": "boolean"
    },
    "folder": {
      "type": "string"
    },
    "color": {
      "type": "string",
      "nullable": true,
      "description": "Акцентний колір значка у форматі `#rrggbb`; `null` означає, що колір визначається за назвою, як у браузері, коли колір не вибрано."
    },
    "extensions": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Ідентифікатори бібліотеки розширень завантажуються під час запуску."
    }
  }
}
```

## ProfileListItem

```json
{
  "allOf": [
    {
      "$ref": "#/components/schemas/ProfileMeta"
    },
    {
      "type": "object",
      "properties": {
        "running": {
          "type": "boolean"
        },
        "pid": {
          "type": "integer",
          "format": "int64",
          "nullable": true
        },
        "cdp": {
          "nullable": true,
          "allOf": [
            {
              "$ref": "#/components/schemas/CdpInfo"
            }
          ]
        }
      }
    }
  ]
}
```

## StoredProfile

```json
{
  "type": "object",
  "description": "Повний профіль на диску: оболонка `_meta` плюс розгорнутий\nFingerprintConfig (всі поля `Fingerprint` на верхньому рівні).\n`running`/`cdp` присутні лише під час роботи профілю.\n",
  "additionalProperties": true,
  "properties": {
    "_meta": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string",
          "format": "uuid"
        },
        "proxy_id": {
          "type": "string",
          "nullable": true
        },
        "inline_proxy": {
          "nullable": true,
          "allOf": [
            {
              "$ref": "#/components/schemas/ProxyEntry"
            }
          ]
        },
        "last_launched_at": {
          "type": "string",
          "nullable": true
        },
        "created_at": {
          "type": "string",
          "nullable": true
        },
        "pinned": {
          "type": "boolean"
        },
        "folder": {
          "type": "string"
        },
        "temporary": {
          "type": "boolean"
        },
        "rev": {
          "type": "integer",
          "description": "Кожен запис збільшує номер версії. Редактор робочого столу передає номер версії, на якому було відкрито профіль, тому збереження поверх зміни, внесеної через цей API, відхиляється, а не скасовується автоматично. Зміни через API не відхиляються: профіль читається і записується назад за один крок."
        }
      }
    },
    "running": {
      "type": "boolean"
    },
    "cdp": {
      "nullable": true,
      "allOf": [
        {
          "$ref": "#/components/schemas/CdpInfo"
        }
      ]
    }
  }
}
```

## CdpInfo

```json
{
  "type": "object",
  "description": "CDP-ендпоінт запущеного профілю.",
  "properties": {
    "port": {
      "type": "integer",
      "description": "Порт remote-debugging"
    },
    "http_url": {
      "type": "string",
      "example": "http://127.0.0.1:53217",
      "description": "REST-база (/json, /json/version)."
    },
    "web_socket_debugger_url": {
      "type": "string",
      "example": "ws://127.0.0.1:53217/devtools/browser/ab12-...",
      "description": "WS-ендпоінт рівня браузера для Puppeteer/Playwright `connect`."
    }
  }
}
```

## RunningProfile

```json
{
  "type": "object",
  "properties": {
    "profile_id": {
      "type": "string"
    },
    "pid": {
      "type": "integer",
      "format": "int64"
    },
    "cdp": {
      "nullable": true,
      "allOf": [
        {
          "$ref": "#/components/schemas/CdpInfo"
        }
      ]
    }
  }
}
```

## LibraryEntry

```json
{
  "type": "object",
  "properties": {
    "id": {
      "type": "string"
    },
    "label": {
      "type": "string"
    },
    "platform": {
      "type": "string",
      "enum": [
        "Windows",
        "macOS",
        "Linux"
      ]
    },
    "chrome": {
      "type": "string",
      "description": "Рядок версії Chrome."
    },
    "gpu": {
      "type": "string"
    },
    "builtin": {
      "type": "boolean",
      "description": "Входить у поставляємий стартовий набір."
    }
  }
}
```

## AddProxyRequest

```json
{
  "type": "object",
  "description": "Рядок проксі АБО явні поля (рядок має пріоритет).",
  "properties": {
    "proxy": {
      "type": "string",
      "description": "`scheme://user:pass@host:port` або `host:port:user:pass`."
    },
    "kind": {
      "type": "string",
      "enum": [
        "socks5",
        "http",
        "https"
      ]
    },
    "host": {
      "type": "string"
    },
    "port": {
      "type": "integer"
    },
    "username": {
      "type": "string"
    },
    "password": {
      "type": "string"
    },
    "name": {
      "type": "string"
    },
    "country": {
      "type": "string"
    },
    "notes": {
      "type": "string"
    }
  }
}
```

## ProxySummary

```json
{
  "type": "object",
  "description": "Збережений проксі без облікових даних.",
  "properties": {
    "id": {
      "type": "string"
    },
    "name": {
      "type": "string"
    },
    "kind": {
      "type": "string",
      "enum": [
        "socks5",
        "http",
        "https"
      ]
    },
    "host": {
      "type": "string"
    },
    "port": {
      "type": "integer"
    },
    "country": {
      "type": "string",
      "description": "Інформаційний тег (наприклад, \"US\")."
    }
  }
}
```

## Cookie

```json
{
  "type": "object",
  "description": "Cookie у зручному для інструментів вигляді (сумісний з форматами\nEditThisCookie / Puppeteer; `httpOnly`/`sameSite` приймаються\nяк псевдоніми при імпорті).\n",
  "required": [
    "domain",
    "name",
    "value"
  ],
  "properties": {
    "domain": {
      "type": "string",
      "description": "Хост cookie (Chromium `host_key`), наприклад \".example.com\"."
    },
    "name": {
      "type": "string"
    },
    "value": {
      "type": "string"
    },
    "path": {
      "type": "string",
      "default": "/"
    },
    "expires": {
      "type": "number",
      "nullable": true,
      "description": "Unix-секунди; null/відсутній = сесійний cookie."
    },
    "secure": {
      "type": "boolean",
      "default": false
    },
    "http_only": {
      "type": "boolean",
      "default": false
    },
    "same_site": {
      "type": "string",
      "enum": [
        "Strict",
        "Lax",
        "None",
        "unspecified"
      ],
      "description": "Регістронезалежно при імпорті."
    }
  }
}
```

## ProxyEntry

```json
{
  "type": "object",
  "description": "Повний запис проксі (як вбудовано в `_meta.inline_proxy`).",
  "properties": {
    "id": {
      "type": "string"
    },
    "name": {
      "type": "string"
    },
    "kind": {
      "type": "string",
      "enum": [
        "socks5",
        "http",
        "https"
      ]
    },
    "host": {
      "type": "string"
    },
    "port": {
      "type": "integer"
    },
    "username": {
      "type": "string"
    },
    "password": {
      "type": "string"
    },
    "country": {
      "type": "string"
    },
    "notes": {
      "type": "string"
    }
  }
}
```

## AutomationBranch

```json
{
  "description": "Напрямок після виконання кроку. Для простих випадків використовується рядок, для значень з параметрами - об’єкт.",
  "oneOf": [
    {
      "type": "string",
      "enum": [
        "next",
        "stop",
        "endpass"
      ],
      "description": "`next`: перейти до наступного кроку. `stop`: завершити весь запуск профілю. `endpass`: завершити поточний прохід і почати наступний з першого кроку."
    },
    {
      "type": "object",
      "properties": {
        "goto": {
          "type": "string",
          "description": "Ідентифікатор блока для переходу. Якщо блока більше немає, використовується `next`."
        }
      }
    },
    {
      "type": "object",
      "properties": {
        "retry": {
          "type": "integer",
          "description": "Спробуйте цей самий крок ще раз, стільки разів, а потім виконайте наступний."
        }
      }
    }
  ]
}
```

## AutomationBlock

```json
{
  "type": "object",
  "description": "Один крок автоматизації. `kind` і `params` розширюються, тому модуль може додавати нові типи кроків.",
  "properties": {
    "id": {
      "type": "string"
    },
    "kind": {
      "type": "string",
      "description": "Тип вбудованої палітри (`goto`, `click`, `type`, `profile.create`, `var.set`, ...) або `module:<module id>:<block>`.\n\n**У мобільному профілі** звичайні кроки вже перетворюються на дотики: `click` виконує дотик, `rightClick` - довге натискання, `scroll` і `swipe` - жести. `hover` недоступний, оскільки на телефоні немає вказівника. Наведені нижче кроки доступні лише на мобільних профілях і відхиляються на настільних:\n\n| Тип | Параметри | Дія |\n| --- | --- | --- |\n| `touch.tap` | `selector` або `x`+`y`, `tapCount` (1-3), `timeout` | Дотик до цілі. |\n| `touch.longPress` | `selector` або `x`+`y`, `timeout` | Натиснути й утримувати. |\n| `touch.swipe` | `selector` або `x`+`y`, `dx`, `dy`, `timeout` | Провести пальцем. |\n| `touch.drag` | `selector`, `to`, `holdMs`, `timeout` | Перетягнути елемент. |\n| `touch.pinch` | `scale`, `selector` або `x`+`y` | Змінити масштаб двома пальцями. Значення понад 1 зменшує масштаб. |\n| `screen.rotate` | `angle` (0/90/180/270), `turnMs`, `into` | Повернути пристрій. `into` зберігає новий `screen.orientation.type`. |",
      "example": "click"
    },
    "label": {
      "type": "string"
    },
    "params": {
      "type": "object",
      "additionalProperties": true,
      "description": "Власні поля кроку, як їх визначає палітра."
    },
    "enabled": {
      "type": "boolean",
      "default": true
    },
    "x": {
      "type": "number",
      "description": "Положення на полотні. Лише для макета, порядок виконання визначають гілки."
    },
    "y": {
      "type": "number"
    },
    "on_done": {
      "$ref": "#/components/schemas/AutomationBranch"
    },
    "on_fail": {
      "allOf": [
        {
          "$ref": "#/components/schemas/AutomationBranch"
        }
      ],
      "description": "За замовчуванням `stop`; продовження після клацання, яке нічого не знайшло, - це те, як запуск друкує на неправильній сторінці."
    },
    "secrets": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Назви параметрів порожні під час експорту."
    }
  }
}
```

## AutomationRunSettings

```json
{
  "type": "object",
  "properties": {
    "threads": {
      "type": "integer",
      "default": 1,
      "description": "Одночасний запуск браузерів; закріплений на 1-64."
    },
    "loops": {
      "type": "integer",
      "default": 1,
      "description": "Проходить через блоки. 0 означає виконання, доки `hours` не підніметься."
    },
    "hours": {
      "type": "number",
      "description": "Має значення лише тоді, коли `loops` дорівнює 0."
    },
    "start": {
      "type": "string",
      "description": "Ідентифікатор блоку для початку; порожній означає перший."
    },
    "profiles": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Зберігається для проектів, збережених до того, як профілі стали блоками; одна нитка кожна, коли встановлено."
    }
  }
}
```

## AutomationProject

```json
{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "format": "uuid"
    },
    "name": {
      "type": "string"
    },
    "notes": {
      "type": "string"
    },
    "blocks": {
      "type": "array",
      "items": {
        "$ref": "#/components/schemas/AutomationBlock"
      }
    },
    "run": {
      "$ref": "#/components/schemas/AutomationRunSettings"
    },
    "created_at": {
      "type": "integer",
      "description": "Unix секунд."
    },
    "updated_at": {
      "type": "integer",
      "description": "Unix секунд."
    }
  }
}
```

## AutomationBundle

```json
{
  "type": "object",
  "description": "Проект на шляху до іншої машини.",
  "properties": {
    "format": {
      "type": "integer",
      "example": 1,
      "description": "Імпорт відхиляє невідомий йому номер."
    },
    "exported_at": {
      "type": "integer",
      "description": "Unix секунд."
    },
    "project": {
      "$ref": "#/components/schemas/AutomationProject"
    },
    "modules": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Ідентифікатори модулів, необхідні кроки."
    },
    "module_files": {
      "type": "array",
      "description": "Файли цих модулів містяться в пакеті, щоб імпортований проект міг працювати там, де він потрапляє. Модуль, відсутній на диску під час експорту, тут не враховується, але має назву `modules`. Під час імпорту модуль, який уже встановлено під тим самим ідентифікатором, зберігається, а не перезаписується.",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "wasm": {
            "type": "string",
            "description": ".wasm, gzip, а потім base64."
          }
        }
      }
    },
    "needs": {
      "type": "array",
      "description": "Поля, очищені під час експорту, які потрібно запросити під час імпорту.",
      "items": {
        "type": "object",
        "properties": {
          "block_id": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "params": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      }
    }
  }
}
```

## AutomationWorker

```json
{
  "type": "object",
  "description": "Один браузер у серії.",
  "properties": {
    "profile_id": {
      "type": "string"
    },
    "profile_name": {
      "type": "string"
    },
    "pass": {
      "type": "integer",
      "description": "1-основний; 0 перед початком першого проходу."
    },
    "step": {
      "type": "integer"
    },
    "steps_total": {
      "type": "integer"
    },
    "status": {
      "type": "string",
      "enum": [
        "queued",
        "starting",
        "running",
        "done",
        "failed",
        "stopped"
      ]
    },
    "note": {
      "type": "string"
    }
  }
}
```

## AutomationRun

```json
{
  "type": "object",
  "properties": {
    "project_id": {
      "type": "string",
      "format": "uuid"
    },
    "project_name": {
      "type": "string"
    },
    "started_at": {
      "type": "integer",
      "description": "Unix секунд."
    },
    "running": {
      "type": "boolean"
    },
    "workers": {
      "type": "array",
      "items": {
        "$ref": "#/components/schemas/AutomationWorker"
      }
    },
    "log": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Останні записи, показані у вікні запусків. Повний журнал зберігається в `automation-runs/`."
    }
  }
}
```

## AutomationModule

```json
{
  "type": "object",
  "properties": {
    "id": {
      "type": "string",
      "description": "стебло файлу; також префікс, який має кожен із його типів блоків."
    },
    "name": {
      "type": "string"
    },
    "path": {
      "type": "string"
    },
    "blocks": {
      "type": "array",
      "items": {
        "type": "object",
        "additionalProperties": true
      },
      "description": "Дескриптори блоків у тій самій формі, що й вбудована палітра."
    },
    "error": {
      "type": "string",
      "description": "Порожній під час завантаження модуля; інакше чому не сталося."
    }
  }
}
```
