Package Information
Available Nodes
Documentation generating…
Documentation
n8n-nodes-ydb
Нода для n8n, которая подключается к Yandex Database (YDB) — serverless или выделенной базе в Yandex Cloud — и выполняет YQL-запросы.
Поддерживаемые операции:
- Execute Query — произвольный YQL-запрос (
SELECT,UPSERT,DDLи т.д.) с именованными параметрами, выполняется по одному разу на каждый входящий item; - Bulk Upsert — вставка/обновление всех входящих items в таблицу одним пакетным запросом (
UPSERT ... SELECT * FROM AS_TABLE($rows)).
Авторизация — через IAM Yandex Cloud:
- IAM Token — статичный токен (
yc iam create-token), самый простой способ, но токен нужно обновлять вручную раз в ~12 часов; - Service Account Key (JSON) — авторизованный ключ сервисного аккаунта (
yc iam key create), нода сама получает и обновляет IAM-токен — рекомендуется для продакшен-workflow.
Под капотом используется официальный современный SDK @ydbjs/* (@ydbjs/core, @ydbjs/query, @ydbjs/auth, @ydbjs/auth-yandex-cloud), который сейчас продвигается самой Yandex Cloud в консоли и документации YDB.
Требования
- n8n (self-hosted, community-ноды устанавливаются только в self-hosted инсталляции; в n8n Cloud community-ноды недоступны);
- Node.js >= 20.19 (требование
@ydbjs/*; актуальные self-hosted версии n8n этому требованию удовлетворяют).
Установка
Вариант 1 — через интерфейс n8n
Settings → Community Nodes → Install → указать n8n-nodes-ydb.
Вариант 2 — вручную (если ставите из исходников)
# в папке проекта
npm install
npm run build
Скопируйте содержимое папки dist/ (или весь пакет целиком) в директорию с community-нодами вашего n8n, либо опубликуйте пакет в npm и установите его как обычно через Community Nodes.
Настройка credentials
- В консоли Yandex Cloud откройте карточку вашей базы YDB и скопируйте значения Endpoint (например,
grpcs://ydb.serverless.yandexcloud.net:2135) и Database (например,/ru-central1/b1g.../etn...). - В n8n создайте credentials типа Yandex Database API, вставьте Endpoint и Database Path.
- Выберите способ авторизации:
- IAM Token — выполните
yc iam create-tokenи вставьте полученную строку; - Service Account Key (JSON) — выполните
yc iam key create --folder-id <folder-id> --service-account-name <sa-name> --output key.jsonи вставьте содержимое файлаkey.jsonцеликом.
- IAM Token — выполните
У сервисного аккаунта должна быть роль, дающая доступ к базе (например, ydb.editor на нужную базу или каталог).
Использование ноды
Execute Query
- Query — YQL-запрос, например:
SELECT id, name FROM users WHERE id = $id; - Query Parameters — JSON-объект с параметрами, например
{"id": 42}. Объявлять параметры черезDECLAREне нужно — SDK делает это автоматически на основе переданных значений.
Каждая строка результата запроса становится отдельным item на выходе ноды. Если запрос не возвращает строк (например, UPSERT или CREATE TABLE), на выходе будет один item { "success": true }.
Поле Query и Query Parameters можно наполнять expressions ({{ $json.id }} и т.п.) — нода выполняется по одному разу на каждый входящий item.
Bulk Upsert
- Table — путь к таблице (например,
usersилиdir/users).
Все входящие items (их поля json) одним запросом загружаются в таблицу через UPSERT INTO ... SELECT * FROM AS_TABLE($rows). На выходе — один item { "success": true, "upserted": N }.
Особенности и ограничения
Значения
Int64/Uint64из YDB приходят как JavaScriptBigInt; нода автоматически конвертирует их в обычные числа, если они укладываются в диапазонNumber.isSafeInteger, иначе — в строку, чтобы не терять точность.Строки:
Utf8vsString. Значения колонок типаUtf8возвращаются как обычные JS-строки. Колонки типаString/Bytesвозвращаются как base64-строки — так сохраняется точность для бинарных данных (хеши, произвольные ID, любые байты), которые могут не быть валидным UTF-8. Если нужно получить именно текст из колонкиString, приведите её в самом запросе:CAST(col AS Utf8). Имейте в виду и обратное: строковые литералы'...'в YQL по умолчанию имеют типString, а неUtf8— чтобы получитьUtf8из литерала, пишитеUtf8('...')илиCAST('...' AS Utf8).Bulk Upsert: как это работает. Нода выполняет настоящий
UPSERT(колонки, которых нет во входных items, сохраняют прежние значения — в отличие отREPLACE, который перезаписывает строку целиком). Массив items передаётся через интерполяцию тегированного шаблона SDK (sql`...AS_TABLE(${rows})`). SDK выводит тип каждого поля из JS-значения и оборачивает все поля вOptional<...>, а YDB не принимаетOptional<Int32>в NOT NULL колонку (в том числе первичный ключ) — поэтому нода автоматически оборачивает каждую колонку вUnwrap(...): итоговый запрос выглядит так (см. блок ниже). Благодаря этому работают и NOT NULL, и nullable целевые колонки.DECLARE $p0 AS List<Struct<id:Optional<Int32>,name:Optional<Utf8>>>; UPSERT INTO `t` SELECT Unwrap(`id`) AS `id`, Unwrap(`name`) AS `name` FROM AS_TABLE($p0);Bulk Upsert: требования к данным. (1) У всех items должен быть одинаковый набор полей. (2) Значения
null/undefinedне поддерживаются (Unwrapупал бы на NULL) — для строк с NULL используйтеExecute Query. (3) Имена полей должны совпадать с колонками таблицы.Bulk Upsert: числовые типы. Тип выводится из JS-значения: целое число →
Int32, дробное →Double, строка →Utf8. YDB неявно расширяетInt32доInt64, но, например,Int32→Uint64/Timestamp/Uint8может датьType annotation. Если целевая колонка неInt32/Int64/Double/Utf8— используйтеExecute Queryс явнымCASTв запросе.Пакеты
@ydbjs/*— чистый ESM; нода загружает их через динамическийimport(), поэтому сама нода собирается и работает как обычный CommonJS-модуль n8n без дополнительной настройки.Версии
@ydbjs/*вpackage.jsonзафиксированы точно (без^), а не диапазоном: это активно развивающийся SDK, и разные патч-версии заметно отличались поведением параметров/типов. Перед осознанным обновлением версии — прогоняйтеnpm testи вручную проверяйтеBulk Upsertна реальной базе.Bulk Upsertсобирает все входящие items в один запрос — для очень больших объёмов (десятки тысяч строк за одно выполнение) может потребоваться предварительно разбить данные на батчи черезSplit In Batches.Bulk Upsertвыполняется одной операцией на весь набор items (а не по одному item, какExecute Query): при включённом «Continue On Fail» ошибка одного упавшего batch-запроса помечает все items как failed — частичного результата внутри одного вызова не будет.Query Parameters(дляExecute Query) должен быть JSON-объектом ({"id": 1}), а не массивом или скалярным значением.Имя таблицы (
Table) не должно содержать обратные кавычки (`) или управляющие символы — под капотом оно подставляется вUPSERT INTO `table`. Дефисы и другие символы, допустимые в путях YDB, разрешены.IAM-токен (
IAM Tokenв credentials) не обновляется автоматически — для длительно работающих production-workflow используйтеService Account Key (JSON).Соединение с YDB открывается один раз в начале выполнения ноды и переиспользуется для всех items, а закрывается по завершении (даже если выполнение упало с ошибкой).
Changelog
0.2.1
- Исправлен
ERESOLVE-конфликт при чистой установке (rm -rf node_modules package-lock.json && npm install), возникавший послеnpm audit fix --force:vitest@5.0.2требует@types/node >=22, что конфликтовало с зафиксированной^20.14.0. vitestобновлён^2.1.4→^3.2.7, добавлен явный devDependencyvite: ^7.3.6— устраняет исходную уязвимость вesbuild(была вvite@5.x, который тянулvitest@2.x), не требуя@types/node >=22.n8n-workflow(devDependency) обновлён^1.70.0→^1.120.31— намеренно не^2.x, обоснование см. в разделе «Поддержка зависимостей (dev-only) иnpm audit».- Добавлен
overrides.form-data: "^4.0.6"— закрывает критическую уязвimость вform-data, которую транзитивно тянетn8n-workflow@1.x. - Один пункт
npm audit(@vitest/mocker, moderate) осознанно оставлен открытым — dev-only, не используется в тестах проекта, полноценный фикс требуетvitest@5.x. Подробности в README. - Никаких изменений в коде ноды/credentials — только dev-инструментарий и
package.json.
0.2.0
- Нода теперь может использоваться как AI-инструмент для узла AI Agent (
usableAsTool: true), без отдельного пакета/ноды-инструмента. ПоляQuery,Query Parameters,Tableможно заполнять через$fromAI(...), при этом ручной ввод в обычном режиме работает как раньше (см. раздел «Использование как AI-инструмент (Tool)»). Operationнамеренно осталась фиксированной на экземпляр ноды (см. обоснование в том же разделе) — для доступа агента к обеим операциям нужно добавить ноду дважды.- Field descriptions для
Query/Query Parameters/Tableпереведены на английский (n8n-конвенция для полей, которые видит в том числе AI-модель). - Добавлены регрессионные тесты, проверяющие
usableAsTool,noDataExpressionнаoperationи наличие$fromAI(...)в дефолтах трёх полей. - ⚠️ Не проверено на живом n8n с реальным AI Agent — см. предупреждение в README.
0.1.2
- Исправлен
Bulk Upsertдля таблиц с NOT NULL первичным ключом (BAD_REQUEST, ERROR(1030): Type annotation): SDK выводит для всех полейOptional<...>, а YDB не приводит его кInt32 NOT NULL. Теперь каждая колонка оборачивается вUnwrap(...)вSELECT. Операция остаётся настоящимUPSERT(частичные строки не затирают остальные колонки). - Добавлены понятные ошибки: разный набор полей у items и
null/undefinedзначения. - Тесты на генерацию запроса против реального
@ydbjs/query.
0.1.1
- Исправлен
Bulk Upsert: запросUPSERT ... SELECT * FROM AS_TABLE($rows)мог падать сGENERIC_ERROR, Issues: ERROR(0): Unknown name: $rows, если резолвилась версия@ydbjs/queryс иным поведением.parameter(). ТеперьBulk Upsertстроит запрос через настоящую интерполяцию тегированного шаблона SDK, что и есть официально задокументированный способ передаватьAS_TABLE-параметры, и версии@ydbjs/*зафиксированы точно, чтобы исключить дрейф версий. - Добавлен регрессионный тест на этот сценарий (
test/GenericFunctions.test.ts). Execute Queryне менялся — параметры через.parameter()там по-прежнему работают штатно (YDB сам выводит скалярные типы из контекста запроса).
Использование как AI-инструмент (Tool)
Начиная с версии 0.2.0 эту же ноду можно подключить к порту Tools узла AI Agent — без отдельного пакета или отдельной ноды-инструмента. Обычный режим работы (workflow → нода → workflow) при этом не меняется.
Требование к окружению
Community-ноды по умолчанию не могут использоваться как AI-инструменты. На инстансе n8n должна быть выставлена переменная окружения:
N8N_COMMUNITY_PACKAGES_ALLOW_TOOL_USAGE=true
Без неё нода не появится в списке доступных инструментов у AI Agent, даже если она установлена.
Как это работает
- Поля Query, Query Parameters и Table по умолчанию содержат выражение вида
={{ $fromAI('query', 'описание для агента', 'string', '') }}. Это официальный механизм n8n: когда нода вызывается агентом,$fromAI(key, ...)возвращает значение, которое агент передал для параметраkey; при обычном (не-agent) выполнении — четвёртый аргумент (fallback), в точности как раньше было пустое значение по умолчанию. Так одно и то же поле остаётся удобным для ручного ввода и одновременно доступно агенту: если вы вводите в поле своё значение — оно просто заменяет это выражение целиком, как с любым дефолтным значением. - Operation остаётся зафиксированной для конкретного экземпляра ноды. Поле
Operation— этоnoDataExpression: trueвыпадающий список, а$fromAI(...)можно использовать только внутри выражения — то есть агент не может «на лету» переключать Execute Query / Bulk Upsert в рамках одного и того же инстанса ноды на холсте. Чтобы дать агенту выбор между двумя операциями, добавьте ноду дважды: один экземпляр сOperation = Execute Query, второй — сOperation = Bulk Upsert, и переименуйте каждый (черезRenameи/или переопределение имени/описания инструмента в настройках подключения к Tools), чтобы агент понимал, какой инструмент для чего. Это стандартный n8n-паттерн для нод с несколькими режимами работы, а не обходной путь. - Ошибки (некорректный SQL, несуществующая таблица и т.п.) при обычном выполнении по-прежнему обрабатываются через
continueOnFail(), как описано выше. При вызове со стороны AI Agent сама обёртка n8n перехватывает исключение и возвращает агенту текст ошибки как результат вызова инструмента, не прерывая работу агента целиком — это стандартное поведениеusableAsTool, а не логика, реализованная в этой ноде.
⚠️ Не проверено на живом n8n
Я не смог протестировать это на реальном инстансе n8n с AI Agent (в этой среде разработки нет доступа к запущенному n8n). Реализация основана на официальном публичном API n8n-workflow (usableAsTool, $fromAI, FromAIArgument) и его исходном коде — но перед продакшен-использованием обязательно проверьте вручную:
- Нода появляется в списке инструментов при подключении к AI Agent (с
N8N_COMMUNITY_PACKAGES_ALLOW_TOOL_USAGE=true). - Агент действительно может вызвать инструмент, заполнить
Query/Query Parameters/Table, и результат приходит в разумном виде. - При обычном (не-agent) использовании поведение не изменилось: пустая строка в
Queryпо-прежнему считается пустой (ошибка «Query не может быть пустым»), а не выражением, зависшим в expression-режиме.
Поддержка зависимостей (dev-only) и npm audit
Не запускайте npm audit fix --force в этом проекте не глядя — именно эта команда однажды привела к ERESOLVE-конфликту (vitest@5 требует @types/node >=22, а в проекте была ^20.14.0) после того, как форсированно подняла vitest и n8n-workflow на несовместимые мажорные версии. --force игнорирует peer-зависимости и берёт «последнюю подходящую по уязвимости» версию, не проверяя, ломает ли она граф зависимостей или требования к окружению — если аудит находит уязвимость, разбирайтесь, что конкретно предлагается обновить, и обновляйте осознанно, а не через --force.
Что зафиксировано в devDependencies и почему:
n8n-workflow: ^1.120.31, а не^2.x.n8n-workflowобъявлен какpeerDependencies: "*"— в реальном n8n-инстансе его версию всегда предоставляет хост, наш devDependency нужен только для локальной типизации/тестов и никогда не публикуется и не попадает к пользователям пакета (files: ["dist"]). При этомn8n-workflow@2.x(через@n8n/expression-runtime) тянет нативныйisolated-vm, которому нужен Node.js >= 24 — то есть просто ради типов пришлось бы поднимать требование к окружению для контрибьюторов вдвое выше, чем реально нужно этому проекту (engines.node: ">=20.19", продиктовано@ydbjs/*). Ради нуля функциональной пользы это не оправдано; линейка1.xдаёт нам ровно те же интерфейсы (INodeType,NodeConnectionTypes,usableAsTool,$fromAI/FromAIArgumentи т.д.), которые мы используем — они не менялись в мажорном бампе.vitest: ^3.2.7+ явныйvite: ^7.3.6, а не^2.x(был раньше) и не^5.x(то, что форсированно поставилaudit fix --force). Исходная уязвимость вesbuild(GHSA-67mh-4wv8-2f99, dev-сервер) живёт вesbuild < 0.25.0, который тянется вместе сvite@5.x(используетсяvitest@2.xпо умолчанию).vitest@3.2.7поддерживаетvite@6/7, поэтому мы явно фиксируемvite@^7.3.6(несётesbuild@^0.25.0, уже без этой уязвимости), не поднимаясь доvitest@5, которому для этого пришлось бы требовать@types/node >=22.overrides.form-data: "^4.0.6".n8n-workflow@1.xтянетform-data@4.0.0, попадающий в диапазон двух реальных уязвимостей (GHSA-fjxv-7rqg-78g4,GHSA-hmw2-7cc7-3qxx).npm overridesфорсирует патч-версию4.0.6для всех вложенных зависимостей без необходимости ждать обновленияn8n-workflowи без смены его мажорной версии.
Один пункт npm audit осознанно не закрыт: @vitest/mocker (moderate, path traversal через vi.mock()-редирект, GHSA-82fw-gwwq-j7x9) исправлен только в версии, жёстко привязанной к vitest@5.x (vitest@3.2.7 пинит @vitest/mocker на точную 3.2.7, а не диапазон — переопределять через overrides несовместимую мажорную версию внутреннего, точно запиненного пакета рискованно и может незаметно сломать мокинг). Тесты этого проекта не используют vi.mock() вовсе, а сама уязвимость — dev-only и не публикуется вместе с пакетом, так что риск для пользователей ноды нулевой. Если по какой-то причине понадобится закрыть и этот пункт — единственный чистый путь — переход на vitest@5.x, что означает синхронный бамп @types/node до >=22.
Разработка
npm install
npm run build # tsc + копирование иконки в dist/
npm test # vitest: unit-тесты чистых функций (sanitizeForOutput, assertSafeIdentifier)
npm pack --dry-run # проверить, что в npm-пакет попадает только dist/, LICENSE, README, package.json
В репозитории есть минимальный GitHub Actions workflow (.github/workflows/ci.yml), который на каждый push/PR прогоняет build + test + pack --dry-run.
Перед публикацией в npm замените плейсхолдеры your-org / Your Name / you@example.com в package.json на реальные данные (поля author, homepage, repository, bugs).
Лицензия
MIT — см. файл LICENSE.