Справочник по узлу Code
Исчерпывающий справочник по узлу Code — входы, выходы, утилиты и лимиты.
Справочник по узлу Code
Это исчерпывающий справочник. Если вы впервые видите узел Code, сначала прочтите overview.mdx.
Функция-вход
Каждый узел Code запускает одну функцию. Обработчик выбирает её, проверяя исходный код в следующем порядке:
export default function <name>(...)— экспортированное имя побеждает.function run(...)— конвенциональное имя побеждает, если нет default export.- Первое объявление
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.
| Имя | Сигнатура | Назначение |
|---|---|---|
dayjs | dayjs(input?): Dayjs | Полный dayjs — парсинг, форматирование, добавление/вычитание времени. Инъектируется из исходников реальной библиотеки при старте песочницы. |
uuid | uuid(): string | Генерирует UUID v4 по RFC 4122 через Math.random. Криптографически нестойкий — для чувствительных данных используйте hash(). |
pick | pick(obj: object, keys: string[]): object | Новый объект, содержащий только те keys, что существуют на obj. Отсутствующие ключи пропускаются. |
omit | omit(obj: object, keys: string[]): object | Новый объект со всеми собственными перечисляемыми ключами obj, кроме тех, что в keys. |
groupBy | groupBy(arr: T[], key: string): Record<string, T[]> | Группирует элементы массива по String(item[key]). |
keyBy | keyBy(arr: T[], key: string): Record<string, T> | Индексирует элементы массива по String(item[key]). Последующие элементы с тем же ключом перезаписывают более ранние. |
uniqBy | uniqBy(arr: T[], key: string): T[] | Возвращает элементы arr с уникальным String(item[key]); побеждает первый. |
base64Encode | base64Encode(str: string): string | UTF-8 строка → base64 строка. Реализовано на хосте через Buffer. |
base64Decode | base64Decode(str: string): string | Base64 строка → UTF-8 строка. Реализовано на хосте через Buffer. |
hash | hash(str: string, algo?: string): string | Hex-дайджест. 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
Явно удаляются бутстрап-скриптом:
fetchsetTimeout,clearTimeoutsetInterval,clearIntervalsetImmediate,clearImmediate
Никогда не присутствуют в изоляте, потому что isolated-vm их не экспонирует:
processrequire(нет загрузчика 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 (общий с таймаутом шага движка) |
| Захваченных строк логов | 1000 | MAX_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.