> ## Documentation Index
> Fetch the complete documentation index at: https://help.teable.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Запустить скрипт

> Запускайте пользовательский JavaScript в защищённой песочнице для логики, выходящей за рамки встроенных действий

<Tip>
  Мы настоятельно рекомендуем создавать Автоматизации с помощью действия «Запустить скрипт», поскольку оно поддерживает все варианты поведения действий, включая те, которые иначе пришлось бы создавать вручную. Просто опишите свои требования ИИ в чате.

  Обратите внимание: если вы добавите действия вручную, ИИ не сможет распознать или изменить их позднее.
</Tip>

Действие «Запустить скрипт» позволяет писать пользовательский код JavaScript для логики, которую не поддерживают встроенные действия. Можно преобразовывать данные, вызывать внешние API, выполнять вычисления, реализовывать условное ветвление и многое другое — всё в защищённой среде-песочнице.

Скрипты получают данные из предыдущих шагов через объект `input` и передают результаты последующим шагам с помощью функции `output.set()`.

## Когда использовать «Запустить скрипт», а когда — встроенные действия

| Сценарий                                               | Использовать встроенные действия   | Использовать «Запустить скрипт»                                 |
| ------------------------------------------------------ | ---------------------------------- | --------------------------------------------------------------- |
| Создание, обновление или получение Записей             | Да                                 | Только если нужна сложная сопутствующая логика                  |
| Отправка простого письма                               | Да                                 | Нет                                                             |
| Вызов одной конечной точки API                         | Да (HTTP-запрос)                   | Только если нужна сложная обработка ответа                      |
| Преобразование данных между шагами                     | Иногда                             | Да — если нужны условная логика, циклы или операции со строками |
| Разбор сложных структур JSON                           | Нет                                | Да                                                              |
| Вычисление дат, форматирование чисел                   | Нет                                | Да                                                              |
| Объединение нескольких вызовов API с логикой в цепочку | Неудобно со встроенными действиями | Да                                                              |
| Реализация бизнес-правил с множеством условий          | Непрактично                        | Да                                                              |

В целом используйте встроенные действия, когда они соответствуют вашим потребностям. Выбирайте «Запустить скрипт», если нужна пользовательская логика, преобразование данных или сложное взаимодействие с API.

## Среда

| Свойство         | Значение                                                  |
| ---------------- | --------------------------------------------------------- |
| Язык             | JavaScript (ES6+), поддерживается `await` верхнего уровня |
| Среда выполнения | Защищённая песочница с ограничением времени 60 секунд     |
| Модули           | CommonJS (`require()`), поддерживаются пакеты npm         |
| Сеть             | HTTP-запросы через `fetch()`                              |

## Как настроить

1. Добавьте действие **Запустить скрипт** в рабочий процесс.
2. Редактор скрипта откроется с пустым холстом. Напишите здесь код JavaScript.
3. Скрипт может читать данные из предыдущих шагов с помощью объекта `input` (см. ниже).
4. Используйте `output.set(key, value)`, чтобы передать результаты последующим шагам.
5. (Необязательно) Добавьте зависимости npm на панели конфигурации, если скрипту нужны внешние библиотеки.
6. Нажмите **Тест**, чтобы запустить скрипт с реальными данными из последнего выполнения триггера.
7. Проверьте результат теста и журналы консоли, чтобы убедиться, что скрипт работает правильно.
8. Сохраните действие.

## Чтение входных данных

Объект `input` содержит данные всех предыдущих шагов рабочего процесса. Каждый шаг определяется идентификатором действия.

### Структура входных данных

```javascript theme={null}
// input — объект с ключами-идентификаторами действий
// Каждый ключ содержит результат соответствующего шага

const actionIds = Object.keys(input);
// Возможное значение actionIds: ["triggerStep1", "actionStep2", "actionStep3"]
```

### Получение данных триггера (Полей Записи)

```javascript theme={null}
const actionIds = Object.keys(input);
const triggerData = input[actionIds[0]]; // Первая запись обычно является триггером

// Для триггеров на основе Записей (создание, обновление, нажатие кнопки, отправка формы):
const recordId = triggerData.record.id;
const fields = triggerData.record.fields;

// Обращение к определённым Полям по идентификатору Поля
const customerName = fields.fldXXXXXXX;  // Замените фактическим идентификатором Поля
const orderAmount = fields.fldYYYYYYY;
```

### Получение данных из шага «Получить Записи»

```javascript theme={null}
const actionIds = Object.keys(input);
const getRecordsData = input[actionIds[1]]; // Например, второй шаг

const records = getRecordsData.records;
records.forEach(record => {
  console.log(record.id, record.fields.fldName);
});
```

### Получение данных из результатов других действий

```javascript theme={null}
const actionIds = Object.keys(input);
const previousOutput = input[actionIds[2]]; // Результат третьего шага
// Структура зависит от результата этого действия
```

<Tip>Во время тестирования используйте `console.log(JSON.stringify(input, null, 2))`, чтобы увидеть точную структуру входных данных. Это самый быстрый способ понять, какие данные доступны.</Tip>

## Запись результата

Используйте `output.set(key, value)`, чтобы сделать данные доступными последующим шагам. Можно задать несколько ключей.

```javascript theme={null}
// Задать простые значения
output.set("status", "success");
output.set("count", 42);

// Задать объекты
output.set("result", {
  name: "Алиса",
  score: 95,
  passed: true
});

// Задать массивы
output.set("items", [
  { id: 1, name: "Элемент A" },
  { id: 2, name: "Элемент B" }
]);
```

Каждый заданный ключ становится отдельной переменной, к которой последующие шаги могут обратиться через средство выбора переменных **+**. Например, если вызвать `output.set("status", "success")`, следующий шаг сможет обратиться к `status` в результате этого скрипта.

## Отладка с помощью console.log

Во время разработки используйте `console.log()` для проверки данных и отслеживания хода выполнения. После нажатия **Тест** данные журнала появятся на панели тестирования.

```javascript theme={null}
const actionIds = Object.keys(input);
console.log("Идентификаторы действий:", actionIds);

const data = input[actionIds[0]];
console.log("Данные триггера:", JSON.stringify(data, null, 2));

// Записать промежуточные результаты в журнал
const processed = data.record.fields.fldName.toUpperCase();
console.log("Обработанное имя:", processed);

output.set("name", processed);
```

Журналы консоли видны только при тестировании — они не отображаются в истории запусков рабочей среды. Активно используйте их при создании скрипта.

## Управление пакетами npm

В скриптах можно использовать пакеты npm. Объявите зависимости на панели конфигурации:

```json theme={null}
[
  { "name": "lodash", "version": "4.17.21" },
  { "name": "dayjs", "version": "1.11.10" }
]
```

Затем используйте их в скрипте с помощью `require()`:

```javascript theme={null}
const _ = require("lodash");
const dayjs = require("dayjs");

const actionIds = Object.keys(input);
const records = input[actionIds[0]].records;

const grouped = _.groupBy(records, r => r.fields.fldCategory);
const today = dayjs().format("YYYY-MM-DD");

output.set("grouped", grouped);
output.set("date", today);
```

<Tip>По возможности отдавайте предпочтение встроенным возможностям JavaScript перед пакетами npm. Современный JavaScript содержит множество встроенных инструментов: `Array.map()`, `Array.filter()`, `Object.entries()`, шаблонные строки, деструктуризацию и т. д. Добавляйте пакеты npm, только если они дают существенные преимущества.</Tip>

## Встроенные переменные

| Переменная                     | Описание                                                                                           |
| ------------------------------ | -------------------------------------------------------------------------------------------------- |
| `process.env.AUTOMATION_TOKEN` | Токен Bearer для вызова API Teable. Область действия ограничена разрешениями текущей Автоматизации |
| `process.env.PUBLIC_ORIGIN`    | Базовый URL-адрес вашего экземпляра Teable (например, `https://app.teable.io`)                     |

### Безопасность: область действия AUTOMATION\_TOKEN

Токен `AUTOMATION_TOKEN` автоматически создаётся для каждого запуска Автоматизации. Он имеет те же разрешения, что и создатель Автоматизации, и действует только в рамках текущего выполнения. Основные моменты:

* Он предоставляет доступ к любой Таблице, доступной создателю Автоматизации.
* Он действителен только во время выполнения скрипта (ограничение — 60 секунд).
* Не передавайте этот токен внешним системам: он предназначен для вызова API Teable из скрипта.

### Вызов API Teable

```javascript theme={null}
const base = process.env.PUBLIC_ORIGIN + "/api";
const token = process.env.AUTOMATION_TOKEN;

// Пример: получить Записи из Таблицы
const res = await fetch(`${base}/table/tblXXXXXXX/record?take=10`, {
  headers: {
    Authorization: `Bearer ${token}`,
    "Content-Type": "application/json"
  }
});

const data = await res.json();
console.log("Полученные Записи:", data);
output.set("records", data);
```

### Вызов ИИ из скрипта

`POST /api/automation/runtime/ai` отправляет запрос модели ИИ вашей Базы. База определяется из контекста Автоматизации, поэтому её идентификатор не требуется. Тело принимает `prompt`, а также необязательные параметры `attachments`, `modelKey`, `temperature` и `outputType`; ответ имеет вид `{ "message": ... }`.

Вложения представляют собой элементы `{ url, mimetype, name }`: не более 10 на один вызов, каждый размером менее 20 МБ и со временем загрузки до 30 секунд. Поддерживаются изображения, PDF-файлы и документы Office. Модель чата по умолчанию может не читать изображения и подобные вложения, поэтому при отправке файлов укажите `modelKey`. Каждый вызов расходует кредиты.

## Обработка ошибок

Всегда помещайте потенциально рискованные операции в блоки try/catch, чтобы рабочий процесс мог корректно обрабатывать сбои:

```javascript theme={null}
try {
  const res = await fetch("https://api.example.com/data");
  
  if (!res.ok) {
    throw new Error(`API вернул ${res.status}: ${res.statusText}`);
  }
  
  const data = await res.json();
  output.set("success", true);
  output.set("data", data);
} catch (error) {
  console.log("Ошибка:", error.message);
  output.set("success", false);
  output.set("error", error.message);
}
```

Без обработки ошибок неудачный вызов fetch или неожиданный формат данных приведёт к аварийному завершению скрипта, и последующие шаги не получат результат.

## Полный пример: обработка и маршрутизация обращений в поддержку

```javascript theme={null}
const actionIds = Object.keys(input);
const record = input[actionIds[0]].record;

const subject = record.fields.fldSubject || "";
const body = record.fields.fldBody || "";
const email = record.fields.fldEmail || "";

// Простая маршрутизация по ключевым словам
const text = (subject + " " + body).toLowerCase();

let category = "Общее";
let priority = "Обычный";

if (text.includes("оплата") || text.includes("счёт") || text.includes("платёж")) {
  category = "Оплата";
} else if (text.includes("ошибка") || text.includes("сбой") || text.includes("авария")) {
  category = "Техническое";
  priority = "Высокий";
} else if (text.includes("отмена") || text.includes("возврат")) {
  category = "Учётная запись";
  priority = "Высокий";
}

// Проверить наличие VIP-клиентов
const vipDomains = ["bigcorp.com", "enterprise.io"];
const domain = email.split("@")[1] || "";
if (vipDomains.includes(domain)) {
  priority = "Срочный";
}

output.set("category", category);
output.set("priority", priority);
output.set("isVIP", vipDomains.includes(domain));
```

## Советы

* **Начните с console.log.** При создании нового скрипта сначала запишите в журнал весь объект `input`, чтобы понять его структуру.
* **Не перегружайте скрипты.** Лучше хорошо решить одну задачу, чем помещать в один скрипт множество задач. При необходимости объедините в цепочку несколько действий «Запустить скрипт».
* **Помните об ограничении в 60 секунд.** Продолжительные операции (обработка большого объёма данных, множество последовательных вызовов API) могут превысить ограничение времени. Разделяйте большие задачи на меньшие части.
* **Тестируйте с реальными данными.** Панель тестирования использует фактические данные последнего выполнения триггера, поэтому результаты будут реалистичными.
* **Обрабатывайте отсутствующие данные.** Используйте значения по умолчанию (оператор `||`) для Полей, которые могут быть пустыми или неопределёнными.

## Связанные материалы

* [Генерация с помощью ИИ](/ru/basic/automation/actions/ai/ai-generate) — задачи ИИ на основе запросов, не требующие пользовательского кода
* [HTTP-запрос](/ru/basic/automation/actions/logic/http-request) — простые вызовы API, не требующие скриптов
