Обзор
Функции логики — это серверные функции на TypeScript, которые выполняются на платформе Twenty. Их можно запускать HTTP-запросами, расписаниями cron или событиями базы данных — а также предоставлять как инструменты для ИИ-агентов.defineLogicFunction
Определяйте логические функции и их триггеры
defineLogicFunction
Определяйте логические функции и их триггеры
Каждый файл функции использует Доступные типы триггеров:Тип В обработчике обращайтесь к переданным заголовкам следующим образом:По соображениям безопасности заголовки ответа ограничены списком разрешенных заголовков. Любой заголовок, которого нет в этом списке (например, Конечная точка доступна по адресу:Первый сегмент — это идентификатор регистрации вашего приложения, второй — Ответ на проверочный Проверочный запрос поступает в Контракт резолвера. Тип Полезная нагрузка включает:Пример события обновления:Триггер только при обновлении email:Пример события уничтожения:Тогда обработчик получает Перед пакетированием события группируются по пользователю, который их вызвал, поэтому каждый вызов охватывает одного инициатора, а Создайте оба клиента один раз в области видимости модуля, и тогда каждый сайт вызова будет указывать используемые права доступа через вызываемый клиент. Вспомогательные функции SDK, обращающиеся к собственным ресурсам вашего приложения, всегда используют его доступ и игнорируют Основные моменты:Чтобы объявить параметры один раз и использовать их в обоих сценариях, определите одну JSON Schema (Компонент получает отображаемый вызов с помощью Компонент монтируется, как только агент завершает потоковую передачу своих аргументов, поэтому он управляет всем вызовом, а не только результатом. После установки приложения Enrich Company появляется в селекторе действий конструктора рабочих процессов. Конструктор отображает
defineLogicFunction() для экспорта конфигурации с обработчиком и необязательными триггерами.src/logic-functions/createPostCard.logic-function.ts
- httpRoute: Публикует вашу функцию по HTTP-пути и методу. В коде приложения добавляйте префикс
/s/к пути маршрута при использованииRestApiClient; развернутый URL использует внедренную базовую частьTWENTY_FUNCTIONS_URL(или\<server-url>/s, если она не задана).
Чтобы вызвать логическую функцию, запускаемую маршрутом, из фронтенд-компонента (без интерфейса), см. раздел Вызов логической функции.
- cron: Запускает вашу функцию по расписанию с использованием выражения CRON.
- databaseEvent: Запускается при событиях жизненного цикла объектов рабочего пространства. Когда операция события —
updated, можно указать конкретные поля для отслеживания в массивеupdatedFields. Если оставить не заданным или пустым, любое обновление будет вызывать функцию.
например,person.updated,*.created,company.*
- serverRoute: открывает один HTTP-маршрут в области регистрации. Функция-резолвер (объявленная с помощью
serverRouteTriggerSettings) выполняется в рабочем пространстве-владельце и либо возвращает синхронныйResponse, либо целевое рабочее пространство И логическую функцию для постановки в очередь; в случае постановки в очередь платформа отправляет подтверждение с кодом202и запускает эту целевую функцию в очереди worker. См. триггер серверного маршрута.
Вы также можете вручную выполнить функцию с помощью CLI:Вы можете просматривать логи с помощью:
В облаке каждый запуск расходует кредиты рабочего пространства: фиксированная плата за
вызов плюс плата за миллисекунду времени работы функции, поэтому
строгое значение
timeoutSeconds и быстрый код снижают затраты. См.
Кредиты для ознакомления с тарифами.Полезная нагрузка триггера маршрута
Когда триггер маршрута вызывает вашу логическую функцию, она получает объектRoutePayload, который соответствует формату AWS HTTP API v2.
Импортируйте тип RoutePayload из twenty-sdk/logic-function:RoutePayload имеет следующую структуру:forwardedRequestHeaders
По умолчанию HTTP-заголовки из входящих запросов не передаются в вашу логическую функцию по соображениям безопасности. Чтобы получить доступ к определённым заголовкам, перечислите их в массивеforwardedRequestHeaders:Имена заголовков приводятся к нижнему регистру. Обращайтесь к ним, используя ключи в нижнем регистре
(например,
event.headers['content-type']).Пользовательский HTTP-ответ
По умолчанию возврат простого значения из обработчика отправляет его обратно как ответ200 (JSON для объектов, text/plain для строк). Чтобы управлять статус-кодом и заголовками ответа, верните Response из twenty-sdk/logic-function:Set-Cookie, CORS-заголовки, такие как Access-Control-Allow-Origin, или пользовательские заголовки X-*), молчаливо удаляется перед отправкой ответа. Разрешенные заголовки ответа:content-typecontent-languagecontent-dispositioncache-controlretry-after
Код состояния должен быть допустимым кодом состояния HTTP (в диапазоне от 100 до 599).
Имена заголовков ответа сравниваются без учета регистра.
Ошибочные ответы платформы
Помимо собственных ответов вашего обработчика, платформа в некоторых ситуациях отвечает на запросы к маршрутам напрямую:404, когда маршрут или функция не существует, 403, когда приложение остановлено, 402, когда рабочее пространство исчерпало выделенные ему кредиты или не имеет активной подписки, 409, когда достигнут лимит хранилища, 429, когда достигнут предел частоты выполнения или лимит использования, и 422, когда производственные dependencies приложения слишком велики для установки — см. ограничения на размер зависимостей.Триггер серверного маршрута
httpRouteTriggerSettings предоставляет функцию по пути /s/ и определяет рабочее пространство из хоста запроса — это работает, когда у каждого рабочего пространства свой домен. Поставщики сторонних сервисов, однако, отправляют события всех арендаторов на один URL. В этом случае используйте serverRouteTriggerSettings.Триггер состоит из двух частей:-
Логическая функция-резолвер — объявляется с помощью
serverRouteTriggerSettings— выполняется в вашем рабочем пространстве-владельце (рабочем пространстве, которому принадлежит регистрация приложения). Она анализирует входящий запрос и возвращает либо:{ workspaceId, targetLogicFunctionUniversalIdentifier, payload? }— платформа ставит эту целевую функцию в очередь в определённом рабочем пространстве и отправляет подтверждение с кодом202 { queued: true }, илиResponseизtwenty-sdk/logic-function— платформа возвращает этот HTTP‑ответ синхронно и не ставит целевую функцию в очередь (используйте это для challenge‑рукопожатий, таких как Slackurl_verification).
rawBodyи переадресованным заголовкам и может отклонить запрос, не обращаясь к целевой функции. - Целевая логическая функция — обычная логическая функция на рабочее пространство — затем выполняется в определенном рабочем пространстве с полезной нагрузкой, возвращенной резолвером (или с исходной полезной нагрузкой запроса, если резолвер ее не преобразовал). Его возвращаемое значение не видит HTTP‑клиент, когда резолвер выбрал путь постановки в очередь.
src/logic-functions/resolve-server-route.logic-function.ts
src/logic-functions/handle-invoice-paid.logic-function.ts
universalIdentifier резолвера из вашего манифеста. Маршрут разрешается только в резолвер этой регистрации в рабочем пространстве её владельца. Когда ваше приложение само регистрирует вебхук, сформируйте URL внутри логической функции с помощью getServerRouteUrl; Twenty внедряет базовый URL серверных маршрутов вашего приложения как TWENTY_SERVER_ROUTES_URL:URL-адреса, содержащие только
id или universalIdentifier резолвера
(/webhooks/server/:identifier), пока всё ещё разрешаются, и оба возвращают
заголовок Deprecation. Форма universalIdentifier возвращает 409, когда две
регистрации объявляют один и тот же идентификатор. Переместите URL-адреса, зарегистрированные у ваших
провайдеров, в форму регистрации.GET. Некоторые поставщики проверяют конечную точку перед отправкой данных на неё: они отправляют GET с проверочным запросом на тот же URL, на который позднее будут POST события. Meta’s WhatsApp Cloud API — один из них. Маршрут сервера отвечает только на POST, если не указано иное, поэтому объявите оба метода:event.queryStringParameters, а возврат Response отправляет его обратно поставщику в рамках того же запроса. Строковое тело отправляется как text/plain, что и ожидают эти поставщики:httpMethods заменяет значение по умолчанию, а не дополняет его, поэтому одного ['GET'] достаточно, чтобы маршрут отклонял POST. Поддерживаются только GET и POST. Не задавайте его, если провайдеру не требуется второй метод: резолвер маршрута, объявляющего GET, будет выполняться при обращении любого неаутентифицированного вызывающего клиента, включая поисковые роботы и средства предварительного просмотра ссылок, которые отправляют GET без запроса. На всё, для чего у платформы нет метода, возвращается 405, при этом резолвер вообще не запускается.Приложение должно быть заявлено и установлено в рабочем пространстве его владельца.
Следуйте инструкциям в разделе Заявление прав на
приложение, чтобы
назначить владельца, затем установите приложение в это рабочее пространство. Пока оба условия не выполнены,
резолверу негде выполняться, и серверный маршрут возвращает
404
(LOGIC_FUNCTION_NOT_FOUND), даже если приложение установлено в другом месте.
Поиск Marketplace скрывает приложения с серверными маршрутами, пока эта настройка и все
необходимые серверные переменные не будут завершены. См. раздел затраты и
доступность рабочего пространства владельца
для получения сведений о выставлении счетов и работе.LogicFunctionConfig в SDK обеспечивает это на этапе компиляции: как только вы задаете serverRouteTriggerSettings, ваш обработчик обязан возвращать либо Response, либо { workspaceId: string; targetLogicFunctionUniversalIdentifier: string; payload?: object } (или Promise одного из этих вариантов). На пути диспетчеризации workspaceId должен указывать на рабочее пространство, в котором установлена целевая функция, иначе запрос будет отклонен с кодом 404. Результат, не соответствующий ни одному из этих форматов — включая случай, когда идентификаторы не являются UUID, — отклоняется с кодом 502.Токены Bearer. Некоторые поставщики, например Microsoft Bot Framework, подписывают каждый запрос с помощью JWT в заголовке
Authorization вместо заголовка подписи. Маршрут сервера может указать authorization в forwardedRequestHeaders, чтобы получить его, а преобразователь проверяет его, как и любую другую подпись. Платформа удаляет заголовок, если он содержит токен, выданный Twenty, поэтому маршрут сервера никогда не получает сеанс Twenty. cookie и proxy-authorization никогда не перенаправляются, а HTTP-маршруты не могут перенаправлять ни один из этих трёх заголовков.Для подписей запросов большинство провайдеров используют HMAC-SHA256; различаются имя заголовка, кодировка дайджеста и строка подписываемой полезной нагрузки. Несколько примеров:Приведенный выше пример резолвера уже показывает поток GitHub HMAC-SHA256 — адаптируйте имя заголовка, кодировку дайджеста и строку подписываемой полезной нагрузки в соответствии с провайдером, с которым вы интегрируетесь.
Когда резолвер возвращает объект диспетчеризации, маршрут отвечает
202 { queued: true }, а целевая функция запускается в очереди worker — вызывающая сторона никогда не видит задержку, результат или сбои целевой функции (они записываются в журналах выполнения). Это не позволяет повторным отправкам со стороны отправителя усиливать замедление обработки, что и требуется для приёма вебхуков.Резолвер выполняется в рабочем пространстве владельца и расходует его кредиты, поэтому маршрут отвечает 402, когда это рабочее пространство исчерпало выделенные ему кредиты или не имеет активной подписки, и 429, когда достигнут лимит использования. Отправители, повторяющие попытку при 5xx, не будут повторять эти запросы, что вам и нужно: причина отказа не исчезнет при следующей попытке.Когда вызывающей стороне нужно прочитать тело ответа в рамках того же запроса (challenge‑рукопожатия, интерактивные подтверждения), вместо этого верните Response из резолвера. Платформа синхронно эхо‑возвращает этот ответ и пропускает очередь; его заголовки проходят через тот же allow‑list, что и заголовки ответов HTTP‑маршрутов. Делайте функцию-резолвер быстрой — некоторые провайдеры (например, Slack) прерывают запрос через несколько секунд. Поскольку резолвер доступен как публичная конечная точка, защитите его с помощью ограничения частоты запросов (rate limiting) на вашем периметре (edge).Полезная нагрузка триггера события базы данных
Когда триггер события базы данных вызывает вашу функцию логики, она получает одинDatabaseEventPayload для каждой изменённой записи (или DatabaseEventBatchPayload, охватывающий несколько записей, когда включён batchMode). Полезная нагрузка объединяет метаданные о рабочем пространстве-источнике и объекте с событием на уровне записи.При логическом удалении
.deleted имеет формат обновления, поскольку изменяется поле deletedAt записи.
Для окончательного удаления используйте .destroyed.databaseEventTriggerSettings.updatedFields фильтрует, какие события обновления
запускают функцию. event.properties.updatedFields указывает, какие поля
фактически изменились в текущем событии.databaseEventTriggerSettings принимает:Пример события создания:
Пакетная обработка событий базы данных
Массовая запись одновременно генерирует множество событий: например, импорт почтового ящика может обновить тысячи записей за одну операцию, и один вызов для каждой записи переполняет очередь. УстановитеbatchMode, чтобы получать их вместе:DatabaseEventBatchPayload, содержащий те же метаданные, что и DatabaseEventPayload, но поля уровня записи заменяются массивом events:На размер пакета обработчик полагаться не может. Сервер определяет, сколько
событий содержит вызов, с ограничением в 200, а пакет содержит от одного
события до этого предела в зависимости от того, сколько событий создала исходная операция записи.
Напишите обработчик так, чтобы он перебирал
events независимо от его длины.context.workspaceMemberId сохраняет смысл. Фильтрация updatedFields применяется до пакетирования, поэтому пакет содержит только запрошенные вами записи.Без batchMode обработчик продолжает получать один DatabaseEventPayload на запись.Контекст выполнения
Обработчики универсальных функций логики получают второй аргумент, описывающий сам запуск независимо от того, что его вызвало. Если форма первого аргумента меняется в зависимости от триггера, то форма этого не меняется:userWorkspaceId и workspaceMemberId имеют значение null, когда запуск никто не вызвал: у cron-расписаний, хуков установки и неаутентифицированных вебхуков нет человека, стоящего за ними. Они также имеют значение null, когда у человека нет записи участника рабочего пространства или когда она была удалена.Контекст сообщает, кто инициировал запуск. Что запуск может делать, — это
отдельное объявление ниже.
Чьи права доступа использует вызов
Каждый клиент —CoreApiClient, MetadataApiClient и RestApiClient — действует от имени человека, вызвавшего запуск: его роль пересекается с ролью вашего приложения, поэтому вызов никогда не может сделать больше, чем позволяет любая из этих ролей. Это поведение по умолчанию, и оно означает, что человек никогда не сможет использовать ваше приложение для превышения собственных разрешений.Когда запуск никто не вызвал, нет человека, от имени которого можно действовать, поэтому тот же клиент использует права доступа самого приложения: cron-расписания, хуки установки и неаутентифицированные вебхуки не требуют специальной обработки.Некоторым вызовам обоснованно требуется собственный доступ приложения, даже когда за запуском стоит человек: для чтения записей конфигурации вашего приложения или выполнения работы, которую этот человек не мог бы выполнить самостоятельно. Создайте для них второй клиент:RestApiClient принимает тот же параметр:Запуск, который никто не вызвал, действует как ваше приложение. У cron-расписаний, хуков установки и неаутентифицированных вебхуков нет человека, стоящего за ними, поэтому клиент по умолчанию использует права доступа самого приложения и продолжает работать.
runAs: 'application' нужен только тогда, когда вам требуются эти права доступа в запуске, который вызвал человек.Проверяйте context.workspaceMemberId, когда функция ведет себя по-разному в зависимости от того, стоит ли за ней кто-то, например чтобы указать автора записи.runAs: хранилище «ключ — значение», подключения, каналы сообщений, runAgent, getPublicAssetUrl и списание кредитов.Предоставление функции в качестве инструмента ИИ или действия рабочего процесса
Функции логики могут быть представлены в двух интерфейсах, у каждого — свой триггер:toolTriggerSettings— делает функцию обнаруживаемой для возможностей ИИ Twenty (чат, MCP, вызов функций). Использует стандартную JSON Schema — формат, который модели LLM изначально понимают.workflowActionTriggerSettings— делает функцию доступной как шаг в визуальном конструкторе рабочих процессов. Использует расширеннуюInputSchemaот Twenty, чтобы конструктор мог отрисовывать корректные редакторы полей, селекторы переменных и подписи.
cronTriggerSettings, databaseEventTriggerSettings и httpRouteTriggerSettings — тот же шаблон, та же структура.Связь с действием Code рабочего процесса. Встроенное действие Code в
конструкторе рабочих процессов само является логической функцией — Twenty создаёт по одной для каждого
шага Code и отображает её редактор встроенным образом.
workflowActionTriggerSettings позволяет превратить этот разовый встроенный код в повторно используемое действие: определите функцию
один раз в своём приложении, и она станет доступной для выбора в любом рабочем процессе вместо того, чтобы
копироваться и вставляться в каждый шаг Code. См. действие Code в руководстве пользователя, чтобы увидеть, как это выглядит для конечного пользователя.src/logic-functions/enrich-company.logic-function.ts
- Функция может сочетать интерфейсы — объявите и
toolTriggerSettings, иworkflowActionTriggerSettings, чтобы сделать её доступной и в чате, и в конструкторе рабочих процессов. toolTriggerSettings.inputSchemaиworkflowActionTriggerSettings.inputSchema— обе необязательны. Если они опущены, конструктор манифеста выводит их из исходного кода обработчика (JSON Schema — для инструмента ИИ,InputSchemaот Twenty — для действия рабочего процесса). Укажите её явно, когда вам нужна более богатая типизация — например, с полями, учитывающимиFieldMetadataType, такими какCURRENCYилиRELATION, для конструктора рабочих процессов, или с полямиdescription, которые может прочитать ИИ-агент:
InputJsonSchema) и преобразуйте её для действия рабочего процесса с помощью jsonSchemaToInputSchema из twenty-sdk/logic-function. toolTriggerSettings.inputSchema принимает JSON Schema напрямую, в то время как workflowActionTriggerSettings.inputSchema ожидает InputSchema Twenty:Отрисовка вызова инструмента с помощью фронт-компонента.
По умолчанию вызов инструмента отображается в чате ИИ как строка шага: имя инструмента и индикатор загрузки, пока он не вернёт результат. Укажите вtoolTriggerSettings.frontComponentUniversalIdentifier один из ваших фронт-компонентов, и чат будет вместо этого отображать этот компонент встроенно для каждого вызова этого инструмента.useToolCall():src/front-components/invoice-preview.tsx
toolCall.status последовательно принимает значения input-available, состояния подтверждения, если оно требуется инструменту, а затем output-available, output-denied или output-error; input — это то, что предложил агент, а output — то, что вернул ваш обработчик. Отрисуйте каждое нужное вам состояние, поскольку строки шага больше нет, чтобы отображать их.И input, и output имеют тип Record\<string, unknown>, поэтому перед использованием сужайте тип каждого поля, а не выполняйте приведение типа. Это особенно важно для всего, что вы передаёте DOM: значение, которое вы помещаете в href, не проверив, что это строка, становится ссылкой, управляемой выводом инструмента.Если идентификатор не соответствует ни одному фронтенд-компоненту приложения, чат возвращается
к строке шага по умолчанию. Фронтенд-компоненты в AI-чате выполняются с той же
ролью, которую объявляет ваше приложение, поэтому виджет
может читать и записывать только то, что разрешено самому приложению.
Полный пример действия рабочего процесса
workflowActionTriggerSettings принимает четыре поля:Объединяя всё вместе — функция, представленная как действие рабочего процесса, с объявленным выходом, чтобы последующие шаги могли ссылаться на
taskId:src/logic-functions/enrich-company.logic-function.ts
companyName и domain как поля ввода (каждое может получать значения из предыдущих шагов), а последующие шаги могут ссылаться на выходные значения шага taskId и enriched.Напишите хорошее описание в поле
description. Агенты ИИ полагаются на поле description
функции, чтобы решить, когда использовать инструмент. Чётко опишите, что делает инструмент и
когда его следует вызывать.Вспомогательные функции времени выполнения.
twenty-sdk/utils повторно экспортирует небольшие вспомогательные функции времени выполнения, поэтому обработчики никогда не импортируют напрямую из twenty-shared. Например, isDefined(value) возвращает false как для null, так и для undefined — используйте её, чтобы безопасно сузить необязательные входные данные обработчика, которые могут приходить как null во время выполнения, даже если имеют тип T | undefined:Хуки установки — обработчики до установки, после установки и при удалении — используют
эту среду выполнения, но объявляются собственными функциями define и не принимают
настройки триггеров. См. раздел Install
Hooks для
definePreInstallLogicFunction, definePostInstallLogicFunction и
defineUninstallLogicFunction.Проверка работоспособности
Объявите проверку работоспособности с помощьюdefineHealthCheck, чтобы сообщать, действительно ли ваше приложение может работать. Она предназначена для того, что может знать только приложение: ключ, который существует, но отозван, аккаунт на неподходящем тарифе, вебхук, который так и не был зарегистрирован. То, что Twenty может увидеть самостоятельно — обязательная переменная, которую никто не заполнил, — обрабатывается isRequired и не требует кода.
Она выполняется на стороне сервера, поэтому читает секретные переменные, как и любая другая логическая функция. За проверкой рабочего пространства не стоит конкретный пользователь, поэтому обработчику не нужны аргументы.
src/logic-functions/health-check.ts
OK вообще не показывает баннер; при любом другом статусе заголовок отображается в баннере соответствующего цвета, поэтому выберите статус в зависимости от того, насколько пользователю необходимо действовать. Статусы — это собственный ApplicationHealthStatus Twenty, поэтому обычная строка и элемент перечисления взаимозаменяемы:
/ или #: для внешнего, начинающегося с протокола или относительного расположения кнопка удаляется, а не становится перенаправлением в другое место. Кнопка также скрывается, когда приложение сообщает об отсутствии расположения и не имеет вкладки конфигурации, к которой можно вернуться, поэтому проверка приложения без переменных и пунктов меню настроек отображает его заголовок без неработающей кнопки.
Проверка индивидуальной настройки каждого участника
Приложение объявляет одну функцию проверки работоспособности. ОпуститеrunOnUserPreferences или задайте для него значение false, чтобы запускать проверку рабочего пространства на странице настроек приложения с обработчиком без аргументов. Вместо этого задайте runOnUserPreferences: true, чтобы запускать проверку участника на его странице настроек приложений. Обработчик участника получает обязательный { userWorkspaceId: string } из аутентифицированного сеанса:
src/logic-functions/health-check.ts
{ userWorkspaceId } из аутентифицированного сеанса, а переменные с областью видимости пользователя сохраняют свои значения. Объект параметров и идентификатор обязательны для этого режима. Она не запускается в настройках приложения рабочего пространства. Передайте userWorkspaceId в listConnections(), чтобы функция возвращала только подключения этого участника. Подключение, при котором не удается обновить токен, исключается из списка, поэтому «нет подключения» также означает «переподключитесь». Кнопка без location ведет на вкладку «Общие» приложения на этой странице.
Для проверок участников требуется Twenty 2.55.0 или более поздней версии. Настройки приложений пока не включены
во всех рабочих пространствах: там, где они не включены, проверка участника никогда не запускается.
Создание действия на временной шкале
ИспользуйтеcreateTimelineActivity() для публикации явного события домена из логической функции. Сначала определите событие как тип действия на временной шкале, затем укажите тип и объекты с помощью их стабильных универсальных идентификаторов:
timelineActivityTypeUniversalIdentifier, targetObjectUniversalIdentifier и targetRecordId. Также можно указать happensAt, properties и workspaceMemberId. happensAt управляет положением события и отображаемым временем на временной шкале; по умолчанию используется время создания.
Чтобы связать с событием другую запись, укажите вместе linkedRecordId и linkedObjectMetadataUniversalIdentifier. Кроме того, можно указать linkedRecordCachedName в качестве резервного варианта отображения исторического имени:
timelineActivity. Не связывайте явные типы событий с action; тип, связанный с действием, уже получает автоматические события аудита и в противном случае создаст дублирующиеся строки.
Типизированные клиенты API (twenty-client-sdk)
Пакетtwenty-client-sdk предоставляет два типизированных клиента GraphQL для взаимодействия с API Twenty из ваших логических функций и фронт-компонентов.
CoreApiClient
Запрос и изменение данных рабочего пространства (записи, объекты)
CoreApiClient
Запрос и изменение данных рабочего пространства (записи, объекты)
CoreApiClient — основной клиент для запросов и изменений данных рабочего пространства. Он генерируется из схемы вашего рабочего пространства с помощью twenty app generate-client или после синхронизации с twenty app apply либо twenty app dev, поэтому полностью типизирован в соответствии с вашими объектами и полями.shareWith имеет значение только для объекта, записи которого являются приватными; в остальных случаях аргумент игнорируется. Для такого объекта он указывает, кто получает доступ к созданной записи: каждая запись нацелена ровно на один из workspaceMemberId, roleId или everyone: true с уровнем доступа READ, READ_WRITE или FULL. Участник рабочего пространства, создающий запись, всегда получает разрешение владельца FULL, поэтому этот аргумент для него необязателен; логическая функция, действующая как её приложение, или ключ API также получает разрешение FULL для своей роли, и такие вызывающие стороны, как и системный вызывающий объект, должны передать shareWith, иначе операция создания будет отклонена. В каждой записи должен быть указан участник или роль рабочего пространства. Логическая функция или ключ API предоставляет общий доступ через свою роль, поэтому каждый обладатель этой роли получает одинаковый доступ к создаваемым ею записям; назначьте ключу, записи которого должны оставаться доступными только ему, отдельную роль.Клиент использует синтаксис selection-set: передайте true, чтобы включить поле, используйте __args для аргументов и вкладывайте объекты для отношений. Вы получаете полное автодополнение и проверку типов на основе схемы вашего рабочего пространства.Запустите
twenty app generate-client, чтобы обновить клиент на основе GraphQL-схемы вашего рабочего пространства. twenty app apply и twenty app dev также повторно генерируют его
после синхронизации. twenty app build выполняет только локальную сборку и не генерирует
клиент.Использование CoreSchema для аннотаций типов
CoreSchema предоставляет типы TypeScript, соответствующие объектам вашего рабочего пространства — это полезно для типизации состояния компонентов или параметров функций:MetadataApiClient
Конфигурация рабочего пространства, приложения и загрузка файлов
MetadataApiClient
Конфигурация рабочего пространства, приложения и загрузка файлов
MetadataApiClient поставляется в готовом виде вместе с SDK (генерация не требуется). Он выполняет запросы к эндпоинту /metadata для получения конфигурации рабочего пространства, приложений и загрузки файлов. Он принимает тот же параметр runAs, что и CoreApiClient — см. Чьи права доступа использует вызов.Это также позволяет приложению читать и обновлять собственные переменные приложения в функции логики, как и во фронтальном компоненте. Токен приложения всегда передается только его собственному приложению в его собственной рабочей области.Пользовательская переменная находится в process.env со значением участника, инициировавшего запуск, или имеет значение по умолчанию, пока он не задаст собственное. Запуск, который никто не инициировал, не получает пользовательских переменных. Чтобы прочитать значения пользовательских переменных вашего приложения для каждого участника, например в cron-задаче, запросите myUserApplicationVariables с runAs: 'application'.Загрузка файлов
MetadataApiClient включает метод uploadFile для прикрепления файлов к полям типа файла. Файл отправляется напрямую в файловое хранилище Twenty: API предоставляет целевой адрес для загрузки, клиент отправляет туда байты, после чего API подтверждает загрузку.Основные моменты:
- Он использует
universalIdentifierполя (а не его идентификатор, специфичный для рабочего пространства), поэтому ваш код загрузки будет работать в любом рабочем пространстве, где установлено ваше приложение. - Тип MIME определяется по содержимому файла после его загрузки, поэтому объявлять ничего не нужно.
- Возвращаемый
url— это подписанный URL, который можно использовать для доступа к загруженному файлу.
Когда ваш код выполняется на Twenty (логические функции или фронт-компоненты), платформа предоставляет учётные данные в виде переменных окружения:
TWENTY_API_URL— базовый URL API TwentyTWENTY_APP_ACCESS_TOKEN— краткоживущий ключ для прав доступа по умолчанию: роль человека пересекается с ролью вашего приложения, когда за запуском кто-то стоит; если никто не стоит — используется собственная роль вашего приложения. В логической функции человек — это тот, кто вызвал запуск, а во фронтенд-компоненте — тот, кто просматривает страницу.TWENTY_APP_APPLICATION_ACCESS_TOKEN— краткоживущий ключ, ограниченный исключительно собственной ролью вашего приложения. Только для логических функций, всегда внедряется в них и используетсяrunAs: 'application'.
process.env, а в разделе Чьи права доступа использует вызов описан выбор между ними. Собственные разрешения вашего приложения определяются ролью, объявленной с помощью defineApplicationRole() (или указанной через defaultRoleUniversalIdentifier в application-config.ts); запуск, действующий от имени человека, никогда не может превысить ни эту роль, ни его собственную.