Salt la conținutul principal

Prezentare generală

Funcțiile de logică sunt funcții TypeScript pe partea de server care rulează pe platforma Twenty. Acestea pot fi declanșate de solicitări HTTP, programări cron sau evenimente din baza de date — și pot fi, de asemenea, expuse ca instrumente pentru agenți AI.
Fiecare fișier de funcție folosește defineLogicFunction() pentru a exporta o configurație cu un handler și declanșatoare opționale.
src/logic-functions/createPostCard.logic-function.ts
Tipuri de declanșatoare disponibile:
  • httpRoute: Expune funcția pe o cale și o metodă HTTP. În codul aplicației, prefixează calea rutei cu /s/ când folosești RestApiClient; URL-ul implementat folosește baza injectată TWENTY_FUNCTIONS_URL (sau \<server-url>/s atunci când nu este setată).
Pentru a apela o funcție logică declanșată de o rută dintr-o componentă front-end (headless), consultă Apelarea unei funcții logice.
  • cron: Rulează funcția pe un program folosind o expresie CRON.
  • databaseEvent: Rulează la evenimentele ciclului de viață ale obiectelor din spațiul de lucru. Când operațiunea evenimentului este updated, câmpurile specifice de urmărit pot fi specificate în array-ul updatedFields. Dacă este lăsat nedefinit sau gol, orice actualizare va declanșa funcția.
de ex. person.updated, *.created, company.*
  • serverRoute: Expune o singură rută HTTP la nivelul înregistrării. O funcție de tip resolver (declarată cu serverRouteTriggerSettings) rulează în workspace-ul proprietar și fie returnează un Response sincron, fie workspace-ul țintă ȘI funcția logică de pus în coadă; pe ramura de punere în coadă, platforma confirmă cu 202 și rulează acea țintă în coada worker-ului. Consultați declanșatorul de rută de server.
Puteți, de asemenea, să executați manual o funcție folosind CLI:
Puteți urmări jurnalele cu:
În cloud, fiecare rulare consumă credite ale spațiului de lucru: o taxă fixă per apelare plus o taxă per milisecundă pentru timpul de rulare al funcției, astfel încât menținerea unui timeoutSeconds scurt și a codului rapid reduce costurile. Consultați Credite pentru tarife.

Payload-ul declanșatorului de rută

Când un declanșator de rută invocă funcția logică, aceasta primește un obiect RoutePayload care urmează AWS HTTP API v2 format. Importați tipul RoutePayload din twenty-sdk/logic-function:
Tipul RoutePayload are următoarea structură:

forwardedRequestHeaders

În mod implicit, anteturile HTTP din cererile de intrare nu sunt transmise funcției dvs. de logică din motive de securitate. Pentru a accesa anumite anteturi, listați-le explicit în array-ul forwardedRequestHeaders:
În handler, accesați anteturile transmise mai departe astfel:
Numele anteturilor sunt normalizate la litere mici. Accesați-le folosind chei cu litere mici (de exemplu, event.headers['content-type']).

Răspuns HTTP personalizat

În mod implicit, returnarea unei valori simple din handler trimite înapoi un răspuns 200 (JSON pentru obiecte, text/plain pentru șiruri). Pentru a controla codul de stare și antetele răspunsului, returnează un Response din twenty-sdk/logic-function:
Din motive de securitate, anteturile de răspuns sunt limitate la o listă de antete permise. Orice antet care nu se află pe listă (de exemplu, Set-Cookie, anteturi CORS precum Access-Control-Allow-Origin sau anteturi personalizate X-*) este eliminat în mod silențios înainte ca răspunsul să fie trimis. Anteturile de răspuns permise sunt:
  • content-type
  • content-language
  • content-disposition
  • cache-control
  • retry-after
Codul de stare trebuie să fie un cod de stare HTTP valid (între 100 și 599). Numele anteturilor de răspuns sunt comparate fără a ține cont de majuscule și minuscule.

Răspunsuri de eroare ale platformei

Pe lângă propriile răspunsuri ale handlerului tău, platforma răspunde direct la apelurile către rute în anumite situații: 404 când ruta sau funcția nu există, 403 când aplicația este oprită, 402 când spațiul de lucru și-a epuizat alocarea de credite sau nu are un abonament activ, 409 când este atinsă o limită de stocare, 429 când este atinsă o limită a ratei de execuție sau o limită de utilizare și 422 când dependencies de producție ale aplicației sunt prea mari pentru a fi instalate — vezi limite privind dimensiunea dependențelor.

Declanșator de rută de server

httpRouteTriggerSettings expune o funcție sub /s/ și rezolvă spațiul de lucru din gazda cererii — ceea ce funcționează atunci când fiecare spațiu de lucru are propriul domeniu. Furnizorii terți, însă, livrează evenimentele fiecărui tenant către un singur URL. Pentru acest caz, folosiți serverRouteTriggerSettings.Declanșatorul are două părți:
  1. O funcție logică de resolver — declarată cu serverRouteTriggerSettings — rulează în workspace-ul deținător (workspace-ul care deține înregistrarea aplicației). Inspectează cererea primită și returnează fie:
    • { workspaceId, targetLogicFunctionUniversalIdentifier, payload? } — platforma pune în coadă acea țintă în workspace-ul rezolvat și confirmă cu 202 { queued: true }, sau
    • un Response de la twenty-sdk/logic-function — platforma transmite mai departe acel răspuns HTTP sincron și nu pune în coadă nicio țintă (folosiți acest lucru pentru handshake-uri de tip challenge, cum ar fi Slack url_verification).
    Resolver-ul este singurul punct de autorizare — URL-ul conține doar identificatorul resolver-ului. Acesta este locul preferat pentru a verifica semnăturile cererilor: resolver-ul rulează înaintea oricărui efect secundar, are acces la rawBody original și la headerele redirecționate și poate respinge fără a atinge vreodată ținta.
  2. O funcție logică țintă — o funcție logică obișnuită per-workspace — rulează apoi în workspace-ul rezolvat cu payload-ul returnat de resolver (sau payload-ul original al cererii dacă resolver-ul nu l-a transformat). Valoarea de returnare nu este observată de apelantul HTTP atunci când resolver-ul a ales calea de punere în coadă.
src/logic-functions/resolve-server-route.logic-function.ts
src/logic-functions/handle-invoice-paid.logic-function.ts
Endpoint-ul este accesibil la:
Primul segment este ID-ul înregistrării aplicației dvs., iar al doilea este universalIdentifier al resolver-ului din manifestul dvs. O rută se rezolvă doar către un resolver al acelei înregistrări, în spațiul de lucru al proprietarului. Când aplicația dvs. înregistrează webhook-ul propriu-zis, construiți URL-ul dintr-o funcție logică folosind getServerRouteUrl; Twenty injectează URL-ul de bază al rutelor de server ale aplicației dvs. ca TWENTY_SERVER_ROUTES_URL:
URL-urile care conțin doar id sau universalIdentifier ale resolverului (/webhooks/server/:identifier) sunt încă rezolvate deocamdată, iar ambele răspund cu un antet Deprecation. Forma universalIdentifier returnează 409 atunci când două înregistrări declară același identificator. Mutați URL-urile înregistrate la furnizorii dvs. în formularul de înregistrare.
Răspunsul la un GET de verificare. Unii furnizori verifică un punct final înainte de a livra către acesta, trimițând un GET care conține o provocare la același URL către care vor trimite ulterior evenimente prin POST — WhatsApp Cloud API de la Meta este unul dintre aceștia. O rută de server răspunde numai la POST, cu excepția cazului în care specifici altfel, așa că declară ambele metode:
Provocarea ajunge în event.queryStringParameters, iar returnarea unui Response o retransmite furnizorului în aceeași cerere. Un corp de tip șir este trimis ca text/plain, ceea ce așteaptă acești furnizori:
httpMethods înlocuiește valoarea implicită, în loc să se adauge la aceasta, astfel încât doar ['GET'] face ca ruta să respingă POST. Sunt acceptate numai GET și POST. Lăsați-o nesetată, cu excepția cazului în care furnizorul are nevoie de al doilea verb: o rută care declară GET își va executa resolverul pentru orice apelant neautentificat, inclusiv pentru crawlerele și serviciile de desfășurare a linkurilor care trimit GET fără solicitare. Orice pentru care platforma nu are o metodă primește răspunsul 405, fără ca resolverul să fie vreodată executat.
Aplicația trebuie revendicată și instalată în spațiul de lucru al proprietarului său. Urmați instrucțiunile din Revendicarea aplicației dvs. pentru a atribui un proprietar, apoi instalați aplicația în acel spațiu de lucru. Până când ambele condiții sunt îndeplinite, resolver-ul nu are unde să ruleze, iar ruta serverului returnează 404 (LOGIC_FUNCTION_NOT_FOUND), chiar dacă aplicația este instalată în altă parte. Căutarea Marketplace ascunde aplicațiile cu rute de server până când această configurare și toate variabilele de server necesare sunt complete. Consultați costurile și disponibilitatea spațiului de lucru al proprietarului pentru detalii despre facturare și funcționare.
Contractul resolver-ului. Tipul LogicFunctionConfig din SDK impune acest lucru la compilare: de îndată ce setați serverRouteTriggerSettings, handler-ul este constrâns să returneze fie un Response, fie { workspaceId: string; targetLogicFunctionUniversalIdentifier: string; payload?: object } (sau un Promise al uneia dintre acestea). Pe calea de trimitere, workspaceId trebuie să fie un workspace în care funcția țintă este instalată, altfel cererea este respinsă cu 404. Un rezultat care nu corespunde niciuneia dintre forme — inclusiv unul ale cărui identificatoare nu sunt UUID-uri — este respins cu 502.
Verificarea semnăturii este responsabilitatea dvs. — verificați în resolver. Platforma nu verifică semnăturile cererilor. Resolver-ul este locul recomandat pentru a face acest lucru: rulează primul, cu acces la event.rawBody și la headerele pe care le-ați enumerat în forwardedRequestHeaders, iar o eroare aruncată (sau orice workspaceId care nu se potrivește) oprește livrarea înainte ca ținta să fie invocată. Dacă, în schimb, mutați verificarea în țintă, ținta trebuie să aibă grijă să nu piardă rawBody și headerele — adică resolver-ul nu trebuie să returneze un payload. Verificați întotdeauna înainte de orice efect secundar și folosiți o comparație în timp constant.
Tokenuri Bearer. Unii furnizori, precum Microsoft Bot Framework, semnează fiecare solicitare cu un JWT în antetul Authorization în locul unui antet de semnătură. O rută de server poate lista authorization în forwardedRequestHeaders pentru a-l primi, iar resolverul îl verifică la fel ca orice altă semnătură. Platforma elimină antetul dacă acesta conține un token emis de Twenty, astfel încât o rută de server nu primește niciodată o sesiune Twenty. cookie și proxy-authorization nu sunt niciodată redirecționate, iar rutele HTTP nu pot redirecționa niciunul dintre aceste trei anteturi.Pentru semnăturile cererilor, majoritatea furnizorilor semnează cu HMAC-SHA256; părțile care diferă sunt numele headerului, codificarea digestului și șirul de payload semnat. Câteva exemple:Exemplul de resolver de mai sus arată deja fluxul GitHub HMAC-SHA256 — adaptați numele headerului, codificarea digestului și șirul de payload semnat în funcție de furnizorul cu care vă integrați.
Când resolver-ul returnează un obiect de dispatch, ruta răspunde cu 202 { queued: true }, iar ținta rulează în coada worker-ului — apelantul nu observă niciodată latența, rezultatul sau erorile țintei (acestea sunt înregistrate în jurnalele de execuție). Acest lucru împiedică retrimiterile expeditorului să amplifice încetinirile procesării, ceea ce este de dorit pentru ingestia de webhook-uri.Resolverul rulează în spațiul de lucru al proprietarului și îi cheltuiește creditele, astfel încât ruta răspunde cu 402 când acel spațiu de lucru și-a epuizat alocarea sau nu are un abonament activ și cu 429 când este atinsă o limită de utilizare. Expeditorii care reîncearcă la 5xx nu vor reîncerca aceste răspunsuri, ceea ce este de dorit: refuzul nu va dispărea la următoarea încercare.Atunci când apelantul trebuie să citească corpul răspunsului în cadrul aceleiași cereri (challenge handshakes, confirmări interactive), returnați în schimb un Response din resolver. Platforma îl reflectă sincron și omite coada; header-ele acestuia trec prin aceeași listă de permisiuni ca răspunsurile rutelor HTTP. Mențineți resolver-ul rapid — unii furnizori (de ex. Slack) expiră după câteva secunde. Deoarece resolver-ul este accesibil ca endpoint public, protejați-l cu limitare de rată la marginea infrastructurii dvs.

Payload-ul declanșatorului de eveniment al bazei de date

Atunci când un declanșator de eveniment al bazei de date invocă funcția logică, aceasta primește câte un DatabaseEventPayload pentru fiecare înregistrare modificată (sau un DatabaseEventBatchPayload care acoperă mai multe înregistrări atunci când batchMode este activat). Payload-ul combină metadatele despre spațiul de lucru și obiectul sursă cu evenimentul la nivel de înregistrare.
Payload-ul include:Pentru ștergeri logice (soft delete), .deleted urmează structura de tip update deoarece câmpul deletedAt al înregistrării se modifică. Pentru ștergeri permanente, folosiți .destroyed.
databaseEventTriggerSettings.updatedFields filtrează ce evenimente de actualizare declanșează funcția. event.properties.updatedFields vă indică ce câmpuri s-au modificat efectiv în evenimentul curent.
databaseEventTriggerSettings acceptă:Exemplu de eveniment de creare:
Exemplu de eveniment de actualizare:
Declanșare doar la actualizări ale e-mailului:
Exemplu de eveniment de ștergere:

Gruparea în loturi a evenimentelor bazei de date

O scriere în masă emite multe evenimente simultan: de exemplu, importarea unei cutii poștale poate actualiza mii de înregistrări într-o singură operație, iar un apel pentru fiecare înregistrare inundă coada. Setați batchMode pentru a le primi împreună:
Funcția de gestionare primește apoi un DatabaseEventBatchPayload, care conține aceleași metadate ca DatabaseEventPayload, dar înlocuiește câmpurile de la nivelul înregistrării cu o matrice events:
Dimensiunea lotului nu este ceva pe care o funcție de gestionare se poate baza. Serverul decide câte evenimente conține un apel, cu o limită de 200, iar un lot conține de la un singur eveniment până la această limită, în funcție de câte a produs scrierea inițială. Scrieți funcția de gestionare astfel încât să parcurgă events, indiferent de lungimea sa.
Evenimentele sunt grupate după utilizatorul care le-a provocat înainte de a fi incluse în loturi, astfel încât fiecare apel acoperă un singur actor, iar context.workspaceMemberId rămâne relevant. Filtrarea updatedFields se aplică înainte de gruparea în loturi, astfel încât un lot conține numai înregistrările solicitate.Fără batchMode, funcția de gestionare continuă să primească un DatabaseEventPayload pentru fiecare înregistrare.

Contextul execuției

Handler-ele funcțiilor logice generice primesc un al doilea argument care descrie rularea în sine, indiferent de ce a declanșat-o. În timp ce primul argument își schimbă forma pentru fiecare declanșator, acesta nu se schimbă:
userWorkspaceId și workspaceMemberId sunt null atunci când nimeni nu a declanșat execuția: programările cron, hookurile de instalare și webhookurile neautentificate nu au nicio persoană în spatele lor. De asemenea, sunt null atunci când persoana nu are o înregistrare de membru al spațiului de lucru sau când aceasta a fost ștearsă.
Contextul vă indică cine a declanșat rularea. Ce poate face rularea este o declarație separată, mai jos.

Ale cui accesări le utilizează un apel

Fiecare client — CoreApiClient, MetadataApiClient și RestApiClient — acționează ca persoana care a declanșat execuția: rolul acesteia se intersectează cu cel al aplicației dvs., astfel încât apelul nu poate face niciodată mai mult decât poate face oricare dintre voi. Acesta este comportamentul implicit și înseamnă că o persoană nu poate folosi niciodată aplicația dvs. pentru a-și depăși propriile permisiuni.Când nimeni nu a declanșat execuția, nu există nicio persoană în numele căreia să se acționeze, astfel încât același client revine la accesul propriu al aplicației dvs.: programările cron, hookurile de instalare și webhookurile neautentificate nu necesită o gestionare specială.Unele apeluri au nevoie în mod legitim de propriul acces al aplicației chiar și atunci când o persoană se află în spatele rulării — pentru a citi înregistrările de configurare ale aplicației dvs. sau pentru a efectua operațiuni pe care acea persoană nu le-ar putea face singură. Creați un al doilea client pentru acestea:
Creați-le pe amândouă o singură dată, la nivel de modul, iar fiecare loc de apel indică apoi accesul utilizat prin clientul pe care îl apelează. RestApiClient acceptă aceeași opțiune:
O execuție pe care nu a declanșat-o nimeni acționează ca aplicația dvs. Programările cron, hookurile de instalare și webhookurile neautentificate nu au nicio persoană în spatele lor, astfel încât clientul implicit revine la accesul propriu al aplicației dvs. și continuă să funcționeze. runAs: 'application' este necesar doar când doriți acel acces într-o execuție pe care o persoană a declanșat-o.Verificați context.workspaceMemberId atunci când o funcție se comportă diferit în funcție de existența unei persoane în spatele ei, de exemplu pentru a atribui o înregistrare.
Funcțiile ajutătoare SDK care accesează propriile resurse ale aplicației dvs. folosesc întotdeauna accesul acesteia și ignoră runAs: stocarea cheie-valoare, conexiunile, canalele de mesagerie, runAgent, getPublicAssetUrl și taxarea creditelor. ai.generate urmează în schimb clienții impliciți: acționează ca persoana care a declanșat execuția, în cadrul rolului aplicației tale, sau ca aplicația ta atunci când nu a făcut-o nimeni.

Expunerea unei funcții ca instrument AI sau ca acțiune în fluxul de lucru

Funcțiile logice pot fi expuse în două locuri, fiecare cu propriul declanșator:
  • toolTriggerSettings — face funcția descoperibilă de către funcționalitățile AI ale Twenty (chat, MCP, apelarea de funcții). Folosește JSON Schema standard, formatul pe care LLM-urile îl înțeleg nativ.
  • workflowActionTriggerSettings — determină ca funcția să apară ca un pas în constructorul vizual de fluxuri de lucru. Folosește InputSchema bogat al Twenty, astfel încât constructorul să poată afișa editori de câmp adecvați, selectoare de variabile și etichete.
O funcție poate opta pentru una, cealaltă sau ambele. Acestea stau alături de cronTriggerSettings, databaseEventTriggerSettings și httpRouteTriggerSettings — același tipar, aceeași formă.
Relația cu acțiunea Code din fluxul de lucru. Acțiunea integrată Code din constructorul de fluxuri de lucru este ea însăși o funcție logică — Twenty creează câte una pentru fiecare pas Code și afișează editorul acesteia inline. workflowActionTriggerSettings este modul în care transformați acel cod inline, de unică folosință, într-o acțiune reutilizabilă: definiți funcția o singură dată în aplicația dvs. și devine selectabilă în orice flux de lucru, în loc să fie copiată și lipită în fiecare pas Code. Vezi acțiunea Code în ghidul utilizatorului pentru vizualizarea din perspectiva utilizatorului final.
src/logic-functions/enrich-company.logic-function.ts
Puncte cheie:
  • O funcție poate combina suprafețele — declară atât toolTriggerSettings, cât și workflowActionTriggerSettings pentru a o expune atât în chat, cât și în constructorul de fluxuri de lucru.
  • toolTriggerSettings.inputSchema și workflowActionTriggerSettings.inputSchema sunt ambele opționale. Când sunt omise, generatorul de manifest le deduce din codul sursă al handlerului (JSON Schema pentru instrumentul AI, InputSchema al Twenty pentru acțiunea de flux de lucru). Furnizează unul în mod explicit atunci când dorești o tipizare mai bogată — de exemplu, cu câmpuri compatibile cu FieldMetadataType, precum CURRENCY sau RELATION pentru constructorul de fluxuri de lucru, sau cu câmpuri description pe care agentul AI le poate citi:
Pentru a declara parametrii o singură dată și a deservi ambele suprafețe, definește o singură schemă JSON (InputJsonSchema) și convertește-o pentru acțiunea din fluxul de lucru cu jsonSchemaToInputSchema din twenty-sdk/logic-function. toolTriggerSettings.inputSchema primește direct schema JSON, în timp ce workflowActionTriggerSettings.inputSchema necesită InputSchema al Twenty:
Afișarea unui apel de instrument cu o componentă front.
În mod implicit, un apel de instrument apare în chatul AI ca un rând de pași: numele instrumentului și un indicator de încărcare până când acesta returnează un rezultat. Configurați toolTriggerSettings.frontComponentUniversalIdentifier să indice către una dintre componentele front, iar chatul va afișa în schimb acea componentă în linie, pentru fiecare apel al acestui instrument.
Componenta citește apelul pe care îl afișează folosind useToolCall():
src/front-components/invoice-preview.tsx
Componenta se montează imediat ce agentul a terminat transmiterea în flux a argumentelor sale, astfel încât gestionează întregul apel, nu doar rezultatul. toolCall.status trece prin input-available, stările de aprobare atunci când instrumentul are nevoie de aprobare, apoi prin output-available, output-denied sau output-error; input este ceea ce a propus agentul, iar output este ceea ce a returnat handlerul dvs. Afișați fiecare stare care vă interesează, deoarece rândul de pași nu mai este disponibil pentru a le acoperi.Atât input, cât și output sunt tipizate ca Record\<string, unknown>, așa că restrângeți tipul fiecărui câmp înainte de a-l utiliza, în loc să faceți conversii de tip. Acest lucru contează cel mai mult pentru orice transmiteți DOM-ului: o valoare pe care o introduceți într-un href fără să verificați că este un șir este un link controlat de rezultatul instrumentului.
Dacă identificatorul nu corespunde niciunei componente frontale din aplicație, chatul revine la rândul de pas implicit. Componentele frontale din chatul AI rulează sub același rol pe care îl declară aplicația dvs., astfel încât un widget poate doar să citească și să scrie ceea ce aplicația însăși are permisiunea să facă.
Un exemplu complet de acțiune de flux de lucru
workflowActionTriggerSettings acceptă patru câmpuri:Reunind totul — o funcție expusă ca o acțiune de flux de lucru, cu o ieșire declarată astfel încât pașii următori să poată face referire la taskId:
src/logic-functions/enrich-company.logic-function.ts
Odată ce aplicația este instalată, Enrich Company apare în selectorul de acțiuni al constructorului de fluxuri de lucru. Constructorul afișează companyName și domain ca câmpuri de intrare (fiecare putând prelua valori din pașii anteriori), iar pașii ulteriori pot face referire la ieșirile taskId și enriched ale pasului.
Scrieți o description bună. Agenții AI se bazează pe câmpul description al funcției pentru a decide când să folosească instrumentul. Fiți specifici cu privire la ce face instrumentul și când ar trebui apelat.
Ajutoare la rulare (runtime helpers). twenty-sdk/utils re-exportă mici ajutoare la rulare, astfel încât handlerii să nu importe niciodată direct din twenty-shared. De exemplu, isDefined(value) returnează false atât pentru null, cât și pentru undefined — folosește-l pentru a restrânge în siguranță intrările opționale ale handlerilor, care pot ajunge drept null la rulare, chiar și atunci când sunt tipate T | undefined:
Hook-urile de instalare — handlerii de preinstalare, postinstalare și dezinstalare — partajează acest runtime, dar sunt declarați cu propriile lor funcții define și nu acceptă setări de declanșare. Consultați Hook-uri de instalare pentru definePreInstallLogicFunction, definePostInstallLogicFunction și defineUninstallLogicFunction.

Verificare de sănătate a aplicației.

Declară o verificare de sănătate cu defineHealthCheck pentru a raporta dacă aplicația ta poate rula efectiv. Este pentru lucruri pe care numai aplicația le poate ști: o cheie prezentă, dar revocată, un cont cu planul greșit, un webhook care nu a fost niciodată înregistrat. Ceea ce Twenty poate vedea singur — o variabilă obligatorie pe care nimeni nu a completat-o — este acoperit de isRequired și nu necesită cod. Rulează pe partea de server, deci citește variabile secrete ca orice altă funcție logică. O verificare a spațiului de lucru nu are pe nimeni în spatele ei, deci handler-ul nu are nevoie de argumente.
src/logic-functions/health-check.ts
Rezultatul este o uniune discriminată, nu un boolean: OK nu afișează deloc un banner; orice altă stare redă titlul într-un banner colorat în funcție de aceasta, așa că alege-o pe cea care corespunde măsurii în care persoana trebuie să acționeze. Stările sunt propriile ApplicationHealthStatus ale Twenty, astfel încât șirul simplu și membrul enum sunt interschimbabile:
Twenty rulează verificarea când se deschide pagina de setări a aplicației și afișează rezultatul acolo într-un banner. Nu se stochează nimic, astfel încât ceea ce raportezi este întotdeauna ceea ce a returnat verificarea tocmai efectuată. O verificare care aruncă o excepție, expiră sau returnează o structură pe care Twenty nu o poate citi este tratată ca fiind necunoscută, niciodată ca o eroare, și nu se afișează niciun banner. O indisponibilitate a unui serviciu terț nu ar trebui să coloreze în roșu fiecare aplicație instalată — dacă ar face-o, oamenii ar învăța să ignore semnalul. Locația trebuie să rămână în Twenty, deci începe cu / sau #: una externă, relativă la protocol sau relativă își pierde butonul în loc să devină o redirecționare în altă parte. Butonul este, de asemenea, eliminat atunci când aplicația nu raportează nicio locație și nu are nicio filă de configurare la care să revină, astfel încât o verificare a unei aplicații fără variabile și fără elemente de meniu de setări îi afișează titlul fără un buton inactiv.

Verificarea configurației fiecărui membru

O aplicație declară o funcție de verificare a stării. Omiteți runOnUserPreferences sau setați-o la false pentru a rula o verificare a spațiului de lucru în pagina de setări a aplicației, cu un handler fără argumente. Setați runOnUserPreferences: true pentru a rula în schimb o verificare a membrului în pagina sa de preferințe Apps. Un handler de membru primește { userWorkspaceId: string } obligatoriu din sesiunea autentificată:
src/logic-functions/health-check.ts
O verificare a membrului rulează atunci când un membru deschide aplicația în pagina sa de preferințe Apps, iar numai acel membru îi vede bannerul. Rulează ca acel membru: handler-ul primește { userWorkspaceId } din sesiunea autentificată, iar variabilele cu domeniu de utilizator își păstrează valorile. Obiectul parametrului și ID-ul sunt obligatorii pentru acest mod. Nu rulează în setările aplicației pentru spațiul de lucru. Transmiteți userWorkspaceId la listConnections() pentru ca aceasta să returneze numai conexiunile acelui membru. O conexiune a cărei reîmprospătare a tokenului eșuează este omisă din listă, deci „nicio conexiune” acoperă și „reconectare”. Un buton fără location duce la fila General a aplicației din acea pagină.
Verificările membrilor necesită Twenty 2.55.0 sau o versiune ulterioară. Preferințele Apps nu sunt încă activate în fiecare spațiu de lucru: acolo unde nu sunt, o verificare a membrului nu rulează niciodată.
O aplicație poate declara o singură funcție de verificare a stării, fie în modul spațiu de lucru, fie în modul membru. Declarațiile existente își păstrează handler-ul spațiului de lucru fără argumente. Declararea unei a doua funcții face ca compilarea să eșueze.

Creați o activitate pe cronologie

Utilizați createTimelineActivity() pentru a publica un eveniment de domeniu explicit dintr-o funcție logică. Definiți mai întâi evenimentul ca tip de activitate pe cronologie, apoi faceți referire la tip și la obiecte prin identificatorii lor universali stabili:
Twenty convertește identificatorii universali în ID-urile metadatelor specifice instalării, validează că tipul de activitate pe cronologie aparține aplicației apelante și captează metadatele sale de prezentare în noua activitate. Parametrii de intrare obligatorii sunt timelineActivityTypeUniversalIdentifier, targetObjectUniversalIdentifier și targetRecordId. De asemenea, puteți furniza happensAt, properties și workspaceMemberId. happensAt controlează poziția și ora afișată a evenimentului pe cronologie; în mod implicit, este momentul creării. Pentru a asocia o altă înregistrare cu evenimentul, furnizați împreună linkedRecordId și linkedObjectMetadataUniversalIdentifier. În plus, puteți furniza linkedRecordCachedName ca alternativă istorică pentru afișare:
Rolul funcției logice trebuie să aibă permisiunea de scriere pentru obiectul standard timelineActivity. Păstrați tipurile explicite de evenimente nelegate de o action; un tip legat de o acțiune primește deja evenimente de audit automate și, în caz contrar, ar produce rânduri duplicate.

Clienți API tipizați (twenty-client-sdk)

Pachetul twenty-client-sdk oferă doi clienți GraphQL tipați pentru a interacționa cu API-ul Twenty din funcțiile de logică și componentele Front.
CoreApiClient este clientul principal pentru interogarea și modificarea datelor din spațiul de lucru. Este generat din schema spațiului de lucru cu twenty app generate-client sau după o sincronizare cu twenty app apply ori twenty app dev, astfel încât este complet tipizat pentru a corespunde obiectelor și câmpurilor dvs.
shareWith contează numai pentru un obiect ale cărui înregistrări sunt private; în rest, argumentul este ignorat. Pentru un astfel de obiect, acesta enumeră cine primește acces la înregistrarea creată: fiecare intrare vizează exact unul dintre workspaceMemberId, roleId sau everyone: true, cu un accessLevel de READ, READ_WRITE sau FULL. Un membru al spațiului de lucru care creează o înregistrare primește întotdeauna o acordare de proprietar FULL, astfel că argumentul este opțional pentru acesta; o funcție logică care acționează ca aplicația sa sau o cheie API primește, de asemenea, o acordare FULL pentru rolul său, iar astfel de apelanți, precum un apelant de sistem, trebuie să transmită shareWith, altfel crearea este respinsă. Fiecare intrare trebuie să indice un membru sau un rol al spațiului de lucru. O funcție logică sau o cheie API partajează prin intermediul rolului său, astfel încât fiecare deținător al acelui rol primește același acces la înregistrările pe care le creează; atribuiți unei chei ale cărei înregistrări trebuie să rămână private un rol propriu.Clientul folosește o sintaxă de tip selection-set: transmiteți true pentru a include un câmp, folosiți __args pentru argumente și imbricați obiecte pentru relații. Obțineți autocompletare și verificare completă a tipurilor, pe baza schemei spațiului dvs. de lucru.
Rulați twenty app generate-client pentru a reîmprospăta clientul din schema GraphQL a spațiului de lucru. twenty app apply și twenty app dev îl regenerează, de asemenea, după sincronizare. twenty app build doar compilează local și nu generează clientul.

Folosirea CoreSchema pentru adnotări de tip

CoreSchema oferă tipuri TypeScript care corespund obiectelor din spațiul dvs. de lucru — utile pentru tiparea stării componentelor sau a parametrilor funcțiilor:
MetadataApiClient este livrat preconstruit împreună cu SDK-ul (nu este necesară generarea). Interoghează endpointul /metadata pentru configurarea spațiului de lucru, aplicații și încărcări de fișiere. Acceptă aceeași opțiune runAs ca CoreApiClient — consultați Ale cui accesări le utilizează un apel.Este, de asemenea, modul în care o aplicație citește și actualizează propriile variabile de aplicație, într-o funcție de logică, la fel ca într-o componentă front-end. Un token de aplicație ajunge doar la propria aplicație, în propriul spațiu de lucru.O variabilă de utilizator se află în process.env cu valoarea membrului care a declanșat execuția sau cu valoarea sa implicită până când acesta își setează propria valoare. O execuție pe care nu a declanșat-o nimeni nu primește variabile de utilizator. Pentru a citi valoarea variabilelor de utilizator ale aplicației dvs. pentru fiecare membru, de exemplu într-o sarcină cron, interogați myUserApplicationVariables cu runAs: 'application'.

Încărcarea fișierelor

MetadataApiClient include o metodă uploadFile pentru atașarea fișierelor la câmpuri de tip fișier. Fișierul ajunge direct în stocarea de fișiere a Twenty: API-ul emite o destinație de încărcare, clientul trimite octeții acolo, apoi API-ul confirmă încărcarea.
Puncte cheie:
  • Folosește universalIdentifier al câmpului (nu ID-ul specific spațiului de lucru), astfel încât codul dvs. de încărcare funcționează în orice spațiu de lucru în care aplicația dvs. este instalată.
  • Tipul MIME este detectat din conținutul fișierului după încărcare, deci nu există nimic de declarat.
  • url returnat este un URL semnat pe care îl puteți folosi pentru a accesa fișierul încărcat.
Când codul dvs. rulează pe Twenty (funcții de logică sau componente Front), platforma injectează acreditările ca variabile de mediu:
  • TWENTY_API_URL — URL-ul de bază al API-ului Twenty
  • TWENTY_APP_ACCESS_TOKEN — Cheie cu durată scurtă pentru accesul implicit: rolul unei persoane se intersectează cu cel al aplicației dvs. atunci când cineva se află în spatele execuției, iar rolul propriu al aplicației dvs. atunci când nu se află nimeni. Persoana este cea care a declanșat execuția într-o funcție logică sau cea care privește pagina într-o componentă front-end.
  • TWENTY_APP_APPLICATION_ACCESS_TOKEN — Cheie cu durată scurtă, limitată numai la rolul propriu al aplicației dvs. Numai funcții logice, injectată întotdeauna acolo și utilizată de runAs: 'application'.
Nu trebuie să transmiteți aceste valori clienților — aceștia citesc automat din process.env, iar Ale cui accesări le utilizează un apel explică alegerea dintre ele. Permisiunile proprii ale aplicației dvs. sunt determinate de rolul declarat cu defineApplicationRole() (sau referențiat prin defaultRoleUniversalIdentifier în application-config.ts); o execuție care acționează ca o persoană nu poate depăși niciodată acel rol sau rolul persoanei.