Документация Triggo
Узел Code

Справочник по узлу Code

Исчерпывающий справочник по узлу Code — входы, выходы, утилиты и лимиты.

Автоперевод — в процессе проверки

Справочник по узлу Code

Это исчерпывающий справочник. Если вы впервые видите узел Code, сначала прочтите overview.mdx.

Функция-вход

Каждый узел Code запускает одну функцию. Обработчик выбирает её, проверяя исходный код в следующем порядке:

  1. export default function <name>(...) — экспортированное имя побеждает.
  2. function run(...) — конвенциональное имя побеждает, если нет default export.
  3. Первое объявление function <name>(...) где угодно в файле — запасной вариант.

Если именованной функции не найдено, шаг падает с:

Code must define a named function (e.g. function run(inputs, utils) {... })

Стрелочные функции, присвоенные переменным, не распознаются регулярным выражением. Всегда используйте объявление function.

Каноническая форма

function run(inputs, utils) {
  // ... ваша логика ...
  return { /* output */ };
}

Песочница всегда вызывает fn(inputs, __utils) — второй аргумент подставляется безусловно, даже если обработчик передаёт null. __utils также доступен как глобал, поэтому function run(inputs) и затем __utils.uuid() работает так же хорошо.

Входы

inputs — это обычный JavaScript-объект, построенный из конфига fieldMappings узла. Каждый ключ в fieldMappings — один из ваших объявленных входов; каждое значение — шаблонное выражение, разрешённое по выходам всех завершённых узлов выше по потоку.

  • Ключи — те, что вы задали в инспекторе.
  • Значения разрешаются стандартным языком шаблонов {{...}}. Whole-template-выражение вида {{action_1}} даёт сырой объект выше по потоку; inline-выражение вроде "{{trigger.email}}" даёт интерполированную строку. Полные правила — в сопоставлении полей.
  • inputs — это не { trigger, steps }. Никаких магических ключей steps или trigger. Вы получаете ровно то, что объявили в инспекторе.

Пример

Конфиг инспектора:

{
  "fieldMappings": {
    "email": "{{trigger.email}}",
    "order": "{{action_1}}"
  }
}

Ваш код видит:

// форма inputs
{
  email: "ada@example.com",
  order: { id: "o_42", total: 9900, currency: "RUB" }
}

Если нужны и поля триггера, и поля действия выше по потоку, объявите каждое отдельно в fieldMappings.

Выходы

Возвращаемое значение функции-входа становится выходом узла. Нижестоящие узлы ссылаются на него как {{<thisNodeId>.<field>}}.

Сериализация. Песочница вызывает JSON.stringify(result) на границе с хостом перед возвратом. Применяются стандартные правила JSON.stringify:

ЗначениеПоведение
Обычный объект, массив, строка, число, булев, nullСохраняется.
undefined (верхний уровень)После round-trip становится null.
Свойство объекта со значением undefinedМолча удаляется.
ФункцияМолча удаляется (как свойство) или превращается в undefined на верхнем уровне.
Свойство с ключом-SymbolМолча удаляется.
BigIntБросает исключениеJSON.stringify не умеет сериализовать BigInt. Шаг падает.
DateПреобразуется в ISO-строку. Тип Date теряется.
Map, Set, RegExpСхлопываются в {} (без перечисляемых собственных свойств).
Циклическая ссылкаБросает исключение — шаг падает.
Buffer / типизированные массивыНе рекомендуется; форма определяется реализацией. Buffer всё равно недоступен.

Если нужно вернуть целое число, превышающее Number.MAX_SAFE_INTEGER, верните его строкой. Если хотите, чтобы поля со значением undefined выжили, явно замените их на null.

Поддержка async

Есть. Верните Promise или объявите функцию async. Песочница обнаруживает .then у возвращаемого значения и дожидается его:

async function run(inputs, utils) {
  const id = utils.uuid();
  return { id };
}

30-секундный таймаут шага покрывает и асинхронную работу — он оборачивает весь вызов песочницы, а не только синхронное выполнение. Если ваш promise не разрешается в пределах 30 с, шаг падает.

Обратите внимание: внутри promise реально выполнить I/O нельзя — fetch и таймеры удалены. Поддержка async существует, чтобы чисто CPU-работа с композицией Promise корректно разрешалась.

__utils — полный справочник

Доступно как глобал __utils и как второй аргумент функции. Источник — плюс инъекция dayjs на строке 173-182.

ИмяСигнатураНазначение
dayjsdayjs(input?): DayjsПолный dayjs — парсинг, форматирование, добавление/вычитание времени. Инъектируется из исходников реальной библиотеки при старте песочницы.
uuiduuid(): stringГенерирует UUID v4 по RFC 4122 через Math.random. Криптографически нестойкий — для чувствительных данных используйте hash().
pickpick(obj: object, keys: string[]): objectНовый объект, содержащий только те keys, что существуют на obj. Отсутствующие ключи пропускаются.
omitomit(obj: object, keys: string[]): objectНовый объект со всеми собственными перечисляемыми ключами obj, кроме тех, что в keys.
groupBygroupBy(arr: T[], key: string): Record<string, T[]>Группирует элементы массива по String(item[key]).
keyBykeyBy(arr: T[], key: string): Record<string, T>Индексирует элементы массива по String(item[key]). Последующие элементы с тем же ключом перезаписывают более ранние.
uniqByuniqBy(arr: T[], key: string): T[]Возвращает элементы arr с уникальным String(item[key]); побеждает первый.
base64Encodebase64Encode(str: string): stringUTF-8 строка → base64 строка. Реализовано на хосте через Buffer.
base64Decodebase64Decode(str: string): stringBase64 строка → UTF-8 строка. Реализовано на хосте через Buffer.
hashhash(str: string, algo?: string): stringHex-дайджест. algo по умолчанию "sha256"; работает любой алгоритм, который принимает crypto.createHash в Node (например, "sha1", "sha512", "md5").

Каждая из них покрыта тестами.

Логирование через console

console.log, .warn, .error, .info, .debug — все установлены и все захватываются. Каждый вызов форматируется как [<level>] <args joined by space> и кладётся в массив, хранимый хостом.

  • Лимит: 1000 строк на выполнение. Как только в массиве 1000 записей, последующие вызовы молча отбрасываются — без ошибки, без предупреждения в выводе.
  • В конце выполнения обработчик выпускает одну запись лога на уровне info с захваченными строками в поле consoleLogs, чтобы вы могли найти их в журнале запуска.
  • console.log не является частью возвращаемого выхода узла. Это побочный поток только для отладки.

Заблокированные API

Явно удаляются бутстрап-скриптом:

  • fetch
  • setTimeout, clearTimeout
  • setInterval, clearInterval
  • setImmediate, clearImmediate

Никогда не присутствуют в изоляте, потому что isolated-vm их не экспонирует:

  • process
  • require (нет загрузчика CommonJS)
  • import — ни статические import...-выражения (отвергаются на этапе eval), ни динамический import() (нет резолвера модулей)
  • API файловой системы (fs, path и компания)
  • Сетевые API (net, http, https, dgram, DNS)
  • Buffer (используйте __utils.base64Encode/Decode)
  • Worker threads, child_process, cluster
  • Модуль Node crypto (для дайджестов используйте __utils.hash)

Всё, что вы ожидаете увидеть на globalThis в Node, но не видите здесь, — считайте отсутствующим и не пытайтесь полифиллить. Загрузчика модулей, через который можно подтянуть полифилл, нет.

Лимиты

ЛимитЗначениеИсточник
Память на выполнение64 МБDEFAULT_SANDBOX_CONFIG.memoryLimitMb
Таймаут по настенным часам30 сDEFAULT_SANDBOX_CONFIG.timeoutMs (общий с таймаутом шага движка)
Захваченных строк логов1000MAX_LOGS в code-sandbox
Переиспользование изолятаНет — свежий изолят на каждый вызовcreateCodeSandbox() + dispose() на каждый вызов

Общие для движка таймауты шага и pipeline, которые тоже применяются, — см. лимиты конструктора workflow.

Ошибки

Любая брошенная ошибка — синтаксическая, reference error (например, вызов fetch), брошенный Error или отклонённый promise — ловится обработчиком и записывается как событие step_failed:

  • error.code: всегда "CODE_EXECUTION_FAILED".
  • error.message: .message брошенной ошибки либо String(error) для не-Error бросков.
  • Stack trace: стек изолята включается в сообщение ошибки, когда isolated-vm его поднимает (например, при синтаксических ошибках и непойманных runtime-ошибках). Виден в журнале запуска.
  • step_failed_continued: если у узла выставлен continueOnFailure, запуск продолжается с выходом этого узла, установленным в payload ошибки, — так же, как и для любого другого падающего шага.

Юнит-тесты handleCodeNode подтверждают, что throw new Error("oops") из пользовательского кода приземляется как step_failed с обновлённым failedNodeIds, и обработчик возвращает true (означает: остановить эту ветвь).

Путь таймаута (код работает дольше 30 с) бросает из context.eval; обработчик ловит его так же, а сообщение ошибки приходит из isolated-vm.

Связанное

  • Обзор — модель песочницы, заблокированные API беглым взглядом, когда тянуться за узлом Code.
  • Миграция с n8n — перевод узлов Function/Code из n8n в Triggo.
  • Сопоставление полей — язык шаблонов для передачи данных в inputs.

On this page