defineLogicFunction
Definisci funzioni logiche e i relativi trigger
defineLogicFunction
Definisci funzioni logiche e i relativi trigger
Ogni file di funzione usa Tipi di trigger disponibili:Il tipo
Nel tuo handler, accedi alle intestazioni inoltrate in questo modo:Per motivi di sicurezza, le intestazioni di risposta sono limitate a un elenco consentito. Qualsiasi intestazione che non è presente nell’elenco (ad esempio L’endpoint è raggiungibile all’indirizzo:L’identificatore è il Contratto del resolver. Il tipo
Per le firme delle richieste, la maggior parte dei provider firma con HMAC-SHA256; le parti che differiscono sono il nome dell’header, la codifica del digest e la stringa del payload firmato. Alcuni esempi:
L’esempio di resolver sopra mostra già il flusso HMAC-SHA256 di GitHub — adatta il nome dell’header, la codifica del digest e la stringa del payload firmato in base al provider con cui ti stai integrando.Il payload include:
Per le eliminazioni logiche, Esempio di evento “created”:Esempio di evento “updated”:Attiva solo sugli aggiornamenti dell’email:Esempio di evento “destroyed”:Punti chiave:Per dichiarare i parametri una sola volta e servire entrambi i contesti, definisci un unico JSON Schema (
Mettendo tutto insieme: una funzione esposta come azione di workflow, con un output dichiarato così che i passaggi successivi possano fare riferimento a Una volta che l’app è installata, Enrich Company appare nel selettore di azioni del generatore di workflow. Il generatore visualizza
defineLogicFunction() per esportare una configurazione con un handler e trigger opzionali.src/logic-functions/createPostCard.logic-function.ts
- httpRoute: Espone la tua funzione su un percorso HTTP e un metodo al URL di base delle funzioni del tuo workspace — il valore Twenty inietta come
TWENTY_FUNCTIONS_URL(su Twenty Cloud, un dominio dedicato per workspace
ad es.path: '/post-card/create'è invocabile suhttps://your-workspace.withtwenty.com/post-card/create
Per richiamare, da un componente front-end (headless), una funzione logica attivata da una rotta, vedi Chiamare una funzione logica.
- cron: Esegue la tua funzione secondo una pianificazione utilizzando un’espressione CRON.
- databaseEvent: Viene eseguito sugli eventi del ciclo di vita degli oggetti dello spazio di lavoro. Quando l’operazione dell’evento è
updated, è possibile specificare campi specifici da monitorare nell’arrayupdatedFields. Se lasciato non definito o vuoto, qualsiasi aggiornamento attiverà la funzione.
ad es.person.updated,*.created,company.*
- serverRoute: espone una singola route HTTP con ambito di registrazione. Una funzione di resolver (dichiarata con
serverRouteTriggerSettings) viene eseguita nel workspace proprietario e restituisce sia il workspace di destinazione SIA la funzione logica di destinazione a cui indirizzare la richiesta; la piattaforma quindi esegue tale funzione di destinazione e ne restituisce la risposta. Vedi Trigger route del server.
Puoi anche eseguire manualmente una funzione utilizzando la CLI:Puoi osservare i log con:
Payload del trigger di route
Quando un trigger di tipo route invoca la tua funzione logica, questa riceve un oggettoRoutePayload che segue il formato AWS HTTP API v2.
Importa il tipo RoutePayload da twenty-sdk/logic-function:RoutePayload ha la seguente struttura:| Proprietà | Tipo | Descrizione | Esempio |
|---|---|---|---|
headers | Record\<string, string | undefined> | Intestazioni HTTP (solo quelle elencate in forwardedRequestHeaders) | vedi la sezione sotto |
queryStringParameters | Record\<string, string | undefined> | Parametri della query string (valori multipli uniti da virgole) | /users?ids=1&ids=2&ids=3&name=Alice -> { ids: '1,2,3', name: 'Alice' } |
pathParameters | Record\<string, string | undefined> | Parametri di percorso estratti dal pattern della route | /users/:id, /users/123 -> { id: '123' } |
body | object | null | Corpo della richiesta analizzato (JSON) | { id: 1 } -> { id: 1 } |
rawBody | string | undefined | Corpo della richiesta UTF-8 originale, prima dell’analisi JSON. Utile per verificare le firme dei webhook in stile HMAC (ad es. X-Hub-Signature-256 di GitHub, Stripe). undefined quando il runtime non lo ha conservato. | |
isBase64Encoded | boolean | Indica se il corpo è codificato in base64 | |
requestContext.http.method | string | Metodo HTTP (GET, POST, PUT, PATCH, DELETE) | |
requestContext.http.path | string | Percorso della richiesta non elaborato |
forwardedRequestHeaders
Per impostazione predefinita, le intestazioni HTTP delle richieste in ingresso non vengono passate alla tua funzione logica per motivi di sicurezza. Per accedere a intestazioni specifiche, elencale nell’arrayforwardedRequestHeaders:I nomi delle intestazioni vengono normalizzati in minuscolo. Accedile usando chiavi in minuscolo (ad es.,
event.headers['content-type']).Risposta HTTP personalizzata
Per impostazione predefinita, restituire un valore semplice dal tuo handler lo invia come risposta200 (JSON per gli oggetti, text/plain per le stringhe). Per controllare il codice di stato e le intestazioni della risposta, restituisci un oggetto Response da twenty-sdk/logic-function:Set-Cookie, intestazioni CORS come Access-Control-Allow-Origin o intestazioni personalizzate X-*) viene ignorata senza segnalazione prima che la risposta venga inviata. Le intestazioni di risposta consentite sono:content-typecontent-languagecontent-dispositioncache-controlretry-after
Il codice di stato deve essere un codice di stato HTTP valido (compreso tra 100 e 599). I nomi delle intestazioni di risposta vengono confrontati senza distinzione tra maiuscole e minuscole.
Trigger route del server
httpRouteTriggerSettings espone una funzione sotto /s/ e risolve lo spazio di lavoro dall’host della richiesta — il che funziona quando ogni spazio di lavoro ha il proprio dominio. I provider di terze parti, tuttavia, inviano gli eventi di ogni tenant a un URL. Per questo caso, usa serverRouteTriggerSettings.Il trigger ha due parti:- Una funzione logica di resolver — dichiarata con
serverRouteTriggerSettings— viene eseguita nel tuo workspace proprietario (il workspace che possiede la registrazione dell’applicazione). Ispeziona la richiesta in ingresso e restituisce{ workspaceId, targetLogicFunctionUniversalIdentifier, payload? }, scegliendo sia il workspace di destinazione che la funzione di destinazione. Il resolver è l’unico punto di autorizzazione: l’URL contiene solo l’identificatore del resolver. Questo è il punto preferenziale per verificare le firme delle richieste: il resolver viene eseguito prima di qualsiasi effetto collaterale, ha accesso alrawBodyoriginale e agli header inoltrati, e può rifiutare senza toccare la destinazione. - Una funzione logica di destinazione — una normale funzione logica per-workspace — viene quindi eseguita nel workspace risolto con il payload restituito dal resolver (o il payload originale della richiesta se il resolver non lo ha trasformato). Il suo valore di ritorno diventa la risposta HTTP.
src/logic-functions/resolve-server-route.logic-function.ts
src/logic-functions/handle-invoice-paid.logic-function.ts
universalIdentifier del resolver dal tuo manifest. Registra quell’URL presso il provider.L’applicazione deve essere rivendicata e installata nel workspace del proprietario. Poiché il resolver viene eseguito nel workspace del proprietario (il workspace che possiede la registrazione dell’applicazione), un server route trigger funziona solo quando l’applicazione è stata rivendicata, cioè ha un workspace del proprietario, e quell’applicazione è installata nel workspace del proprietario. Finché entrambe non sono vere, il resolver non ha dove essere eseguito, quindi la route non può essere gestita. Un’applicazione che espone una funzione logica
serverRouteTriggerSettings quindi non può essere elencata nel marketplace finché non è stata rivendicata e installata nel workspace del proprietario.LogicFunctionConfig dell’SDK impone questo a tempo di compilazione: non appena imposti serverRouteTriggerSettings, il tuo handler è vincolato a restituire { workspaceId: string; targetLogicFunctionUniversalIdentifier: string; payload?: object } (o una Promise di questo valore). Il workspaceId deve essere un workspace in cui la funzione di destinazione è installata, altrimenti la richiesta viene rifiutata con 404.| Campo | Tipo | Note |
|---|---|---|
workspaceId | string | UUID del workspace in cui verrà eseguita la destinazione. |
targetLogicFunctionUniversalIdentifier | string | universalIdentifier della funzione logica da invocare in quel workspace. |
payload | object (opzionale) | Se impostato, sostituisce il body della richiesta inviato alla destinazione. |
| Provider | Header da inoltrare | Stringa firmata | Digest |
|---|---|---|---|
| Svix (Recall, Resend, Clerk) | webhook-id, webhook-timestamp, webhook-signature | {id}.{timestamp}.{rawBody} | base64 (il segreto è in base64 dopo aver rimosso whsec_) |
| Stripe | stripe-signature | {timestamp}.{rawBody} | esadecimale |
| GitHub | x-hub-signature-256 | {rawBody} | esadecimale (prefissato con sha256=) |
| Shopify | x-shopify-hmac-sha256 | {rawBody} | base64 |
| Slack | x-slack-signature, x-slack-request-timestamp | v0:{timestamp}:{rawBody} | esadecimale (prefissato con v0=) |
La destinazione viene eseguita in modo sincrono e il valore restituito diventa la risposta HTTP, quindi i chiamanti vedono il tuo codice di stato e possono ritentare in caso di codice non 2xx. Mantieni entrambi gli handler veloci — alcuni provider (ad es. Slack) vanno in timeout in pochi secondi. Poiché il resolver è raggiungibile come endpoint pubblico, proteggilo con rate limiting al tuo edge.
Payload del trigger di evento del database
Quando un trigger di evento del database invoca la tua funzione logica, questa riceve unDatabaseEventPayload per ogni record modificato. Il payload combina i metadati sull’area di lavoro e sull’oggetto di origine con l’evento a livello di record.| Proprietà | Descrizione |
|---|---|
name | Nome dell’evento, ad esempio person.updated. |
workspaceId | Area di lavoro in cui si è verificato l’evento. |
objectMetadata | Metadati per l’oggetto che è cambiato. |
recordId | ID del record modificato. |
userId, userWorkspaceId, workspaceMemberId | Campi dell’attore quando l’evento è stato causato da un utente dell’area di lavoro. |
properties | Dati del record per l’evento, con before, after, diff e updatedFields a seconda dell’operazione. |
| Evento | Dati del record |
|---|---|
person.created | event.properties.after |
person.updated | event.properties.before, event.properties.after, event.properties.diff, event.properties.updatedFields |
person.destroyed | event.properties.before |
.deleted segue la struttura in stile aggiornamento perché il campo deletedAt del record cambia.
Per le eliminazioni permanenti, usa .destroyed.databaseEventTriggerSettings.updatedFields filtra quali eventi di aggiornamento attivano la funzione.
event.properties.updatedFields indica quali campi sono effettivamente cambiati nell’evento corrente.Esporre una funzione come strumento di IA o come azione del flusso di lavoro
Le funzioni logiche possono essere esposte su due superfici, ciascuna con il proprio trigger:toolTriggerSettings— rende la funzione individuabile dalle funzionalità di IA di Twenty (chat, MCP, function calling). Usa lo standard JSON Schema, il formato che gli LLM comprendono nativamente.workflowActionTriggerSettings— fa apparire la funzione come un passaggio nel builder visivo dei flussi di lavoro. Usa il riccoInputSchemadi Twenty affinché il builder possa visualizzare correttamente editor di campi, selettori di variabili ed etichette.
cronTriggerSettings, databaseEventTriggerSettings e httpRouteTriggerSettings — stesso schema, stessa struttura.Relazione con l’azione Code del workflow. L’azione Code incorporata nel generatore di workflow è essa stessa una funzione logica — Twenty ne crea una per ogni passaggio Code e ne espone l’editor inline.
workflowActionTriggerSettings è il modo in cui trasformi quel codice inline una tantum in un’azione riutilizzabile: definisci la funzione una volta nella tua app e diventa selezionabile in qualsiasi workflow, invece di essere copiata e incollata in ogni passaggio Code. Consulta l’azione Code nella guida utente per la vista dell’utente finale.src/logic-functions/enrich-company.logic-function.ts
- Una funzione può combinare le superfici — dichiara sia
toolTriggerSettingssiaworkflowActionTriggerSettingsper esporla in chat E nel builder dei flussi di lavoro. toolTriggerSettings.inputSchemaeworkflowActionTriggerSettings.inputSchemasono entrambi opzionali. Se omessi, il builder del manifest li deduce dal codice sorgente dell’handler (JSON Schema per lo strumento di IA,InputSchemadi Twenty per l’azione del flusso di lavoro). Forniscine uno esplicitamente quando desideri una tipizzazione più ricca — ad esempio, con campi compatibili conFieldMetadataTypecomeCURRENCYoRELATIONper il builder dei flussi di lavoro, oppure con campidescriptionche l’agente di IA può leggere:
InputJsonSchema) e convertilo per l’azione del flusso di lavoro con jsonSchemaToInputSchema da twenty-sdk/logic-function. toolTriggerSettings.inputSchema accetta direttamente il JSON Schema, mentre workflowActionTriggerSettings.inputSchema si aspetta l’InputSchema di Twenty:Un esempio completo di azione di workflow
workflowActionTriggerSettings accetta quattro campi:| Campo | Scopo |
|---|---|
label | Nome mostrato per l’azione nel selettore di passaggi del generatore di workflow. Il valore predefinito è il name della funzione. |
icon | Icona mostrata accanto all’azione (un nome tabler-icons, ad esempio IconBuilding). |
inputSchema | Il ricco InputSchema di Twenty: ciò che il generatore visualizza come campi configurabili (con selettori di variabili). Opzionale; quando omesso viene ricavato dall’handler. |
outputSchema | Dichiara la struttura restituita dall’handler, così i passaggi successivi possono mappare ai suoi campi di output. Opzionale; senza di esso, l’output è esposto come singolo valore opaco. |
taskId:src/logic-functions/enrich-company.logic-function.ts
companyName e domain come campi di input (ognuno in grado di prelevare valori dai passaggi precedenti), e i passaggi a valle possono fare riferimento ai risultati taskId ed enriched del passaggio.Scrivi una buona
description. Gli agenti IA fanno affidamento sul campo description della funzione per decidere quando usare lo strumento. Sii specifico su cosa fa lo strumento e quando dovrebbe essere invocato.Helper di runtime.
twenty-sdk/utils riesporta piccoli helper di runtime in modo che gli handler non importino mai direttamente da twenty-shared. Per esempio, isDefined(value) restituisce false sia per null che per undefined — usalo per restringere in modo sicuro gli input opzionali degli handler, che possono arrivare come null a runtime anche quando sono tipizzati come T | undefined:Hook di installazione — i gestori di pre-installazione e post-installazione — condividono questo runtime, ma sono dichiarati con le proprie funzioni di definizione e non accettano impostazioni dei trigger. Consulta Hook di installazione per
definePreInstallLogicFunction e definePostInstallLogicFunction.Client API tipizzati (twenty-client-sdk)
Il pacchettotwenty-client-sdk fornisce due client GraphQL tipizzati per interagire con l’API di Twenty dalle tue funzioni logiche e dai componenti front-end.
| Client | Importa | Endpoint | Generato? |
|---|---|---|---|
CoreApiClient | twenty-client-sdk/core | /graphql — dati dello spazio di lavoro (record, oggetti) | Sì, in fase di dev/build |
MetadataApiClient | twenty-client-sdk/metadata | /metadata — configurazione dello spazio di lavoro, caricamenti di file | No, fornito pronto all’uso |
CoreApiClient
Esegui query e modifica i dati dello spazio di lavoro (record, oggetti)
CoreApiClient
Esegui query e modifica i dati dello spazio di lavoro (record, oggetti)
CoreApiClient è il client principale per interrogare e modificare i dati dello spazio di lavoro. Viene generato dallo schema del tuo spazio di lavoro durante yarn twenty dev o yarn twenty dev:build, quindi è completamente tipizzato per corrispondere ai tuoi oggetti e campi.true per includere un campo, usa __args per gli argomenti e annida oggetti per le relazioni. Ottieni completamento automatico e controllo dei tipi completi basati sullo schema del tuo spazio di lavoro.CoreApiClient viene generato in fase di dev/build. Se lo usi senza eseguire prima
yarn twenty dev o yarn twenty dev:build, genera un errore. La generazione avviene automaticamente — la CLI esegue l’introspezione dello schema GraphQL del tuo spazio di lavoro e genera un client tipizzato usando @genql/cli.Utilizzo di CoreSchema per le annotazioni di tipo
CoreSchema fornisce tipi TypeScript corrispondenti agli oggetti del tuo spazio di lavoro — utile per tipizzare lo stato dei componenti o i parametri delle funzioni:MetadataApiClient
Configurazione dello spazio di lavoro, applicazioni e caricamenti di file
MetadataApiClient
Configurazione dello spazio di lavoro, applicazioni e caricamenti di file
MetadataApiClient è fornito pronto all’uso con l’SDK (nessuna generazione richiesta). Interroga l’endpoint /metadata per la configurazione dello spazio di lavoro, le applicazioni e i caricamenti di file.Caricamento dei file
MetadataApiClient include un metodo uploadFile per allegare file ai campi di tipo file:| Parametro | Tipo | Descrizione |
|---|---|---|
fileBuffer | Buffer | Il contenuto grezzo del file |
filename | string | Il nome del file (utilizzato per l’archiviazione e la visualizzazione) |
contentType | string | Tipo MIME (predefinito su application/octet-stream se omesso) |
fieldMetadataUniversalIdentifier | string | L’universalIdentifier del campo di tipo file nel tuo oggetto |
- Usa l’
universalIdentifierdel campo (non il suo ID specifico dello spazio di lavoro), quindi il tuo codice di upload funziona in qualsiasi spazio di lavoro in cui la tua app è installata. - L’
urlrestituito è un URL firmato che puoi usare per accedere al file caricato.
Quando il tuo codice viene eseguito su Twenty (funzioni logiche o componenti front-end), la piattaforma inietta le credenziali come variabili d’ambiente:
TWENTY_API_URL— URL di base dell’API di TwentyTWENTY_APP_ACCESS_TOKEN— Chiave a breve durata con ambito al ruolo funzione predefinito della tua applicazione
process.env. I permessi della chiave API sono determinati dal ruolo dichiarato con defineApplicationRole() (o referenziato tramite defaultRoleUniversalIdentifier in application-config.ts).