Skip to main content
Aplicațiile sunt în prezent în testare alfa. Caracteristica funcționează, dar este încă în dezvoltare.
Pachetul twenty-sdk oferă blocuri de construcție tipizate pentru a crea aplicația. Această pagină acoperă toate tipurile de entități și clienții API disponibili în SDK.

Funcții DefineEntity

SDK-ul oferă funcții pentru definirea entităților aplicației. Trebuie să folosiți export default defineEntity({...}) pentru ca SDK-ul să detecteze entitățile. Aceste funcții validează configurația în timpul build-ului și oferă completare automată în IDE și siguranța tipurilor.
Organizarea fișierelor ține de dvs. Detectarea entităților este bazată pe AST — SDK-ul găsește apelurile export default defineEntity(...) indiferent unde se află fișierul. Gruparea fișierelor după tip (de exemplu, logic-functions/, roles/) este doar o convenție pentru organizarea codului, nu o cerință.
Rolurile încapsulează permisiuni asupra obiectelor și acțiunilor din spațiul dvs. de lucru.
restricted-company-role.ts
Fiecare aplicație trebuie să aibă exact un apel defineApplication care descrie:
  • Identitate: identificatori, nume de afișare și descriere.
  • Permisiuni: ce rol folosesc funcțiile și componentele front-end ale acesteia.
  • (Opțional) Variabile: perechi cheie–valoare expuse funcțiilor ca variabile de mediu.
  • (Opțional) funcții de pre-instalare / post-instalare: funcții logice care rulează înainte sau după instalare.
src/application-config.ts
Notițe:
  • Câmpurile universalIdentifier sunt ID-uri deterministe pe care le dețineți. Generați-le o singură dată și mențineți-le stabile între sincronizări.
  • applicationVariables devin variabile de mediu pentru funcțiile și componentele front-end (de exemplu, DEFAULT_RECIPIENT_NAME este disponibil ca process.env.DEFAULT_RECIPIENT_NAME).
  • defaultRoleUniversalIdentifier trebuie să facă referire la un rol definit cu defineRole() (vezi mai sus).
  • Funcțiile de pre-instalare și post-instalare sunt detectate automat în timpul construirii manifestului — nu trebuie să le referiți în defineApplication().

Metadate pentru marketplace

Dacă intenționați să publicați aplicația, aceste câmpuri opționale controlează modul în care apare în marketplace:

Roluri și permisiuni

Câmpul defaultRoleUniversalIdentifier din application-config.ts desemnează rolul implicit utilizat de funcțiile logice și componentele front-end ale aplicației. Consultați defineRole mai sus pentru detalii.
  • Tokenul de runtime injectat ca TWENTY_APP_ACCESS_TOKEN este derivat din acest rol.
  • Clientul tipizat este restricționat la permisiunile acordate acelui rol.
  • Respectați principiul celui mai mic privilegiu: creați un rol dedicat doar cu permisiunile de care au nevoie funcțiile.
Rol implicit pentru funcții
Când generați o aplicație nouă, CLI creează un fișier de rol implicit:
src/roles/default-role.ts
universalIdentifier al acestui rol este apoi referențiat în application-config.ts ca defaultRoleUniversalIdentifier.
  • *.role.ts definește ce poate face rolul.
  • application-config.ts indică acel rol, astfel încât funcțiile moștenesc permisiunile lui.
Notițe:
  • Porniți de la rolul generat, apoi restrângeți-l progresiv urmând principiul celui mai mic privilegiu.
  • Înlocuiți objectPermissions și fieldPermissions cu obiectele și câmpurile de care au nevoie efectiv funcțiile.
  • permissionFlags controlează accesul la capabilități la nivelul platformei. Mențineți-le la minimum.
  • Vedeți un exemplu funcțional: hello-world/src/roles/function-role.ts.
Obiectele personalizate descriu atât schema, cât și comportamentul înregistrărilor din spațiul dvs. de lucru. Utilizați defineObject() pentru a defini obiecte cu validare încorporată:
postCard.object.ts
Puncte cheie:
  • Folosiți defineObject() pentru validare încorporată și suport mai bun în IDE.
  • universalIdentifier trebuie să fie unic și stabil între implementări.
  • Fiecare câmp necesită un name, un type, un label și propriul universalIdentifier stabil.
  • Matricea fields este opțională — puteți defini obiecte fără câmpuri personalizate.
  • Puteți genera obiecte noi folosind yarn twenty add, care vă ghidează prin denumire, câmpuri și relații.
Câmpurile de bază sunt create automat. Când definiți un obiect personalizat, Twenty adaugă automat câmpuri standard precum id, name, createdAt, updatedAt, createdBy, updatedBy și deletedAt. Nu trebuie să le definiți în tabloul fields — adăugați doar câmpurile personalizate proprii. Puteți suprascrie câmpurile implicite definind un câmp cu același nume în tabloul fields, dar acest lucru nu este recomandat.
Utilizați defineField() pentru a adăuga câmpuri la obiecte pe care nu le dețineți — cum ar fi obiectele standard Twenty (Person, Company etc.). sau obiecte din alte aplicații. Spre deosebire de câmpurile inline din defineObject(), câmpurile independente necesită un objectUniversalIdentifier pentru a specifica obiectul pe care îl extind:
src/fields/company-loyalty-tier.field.ts
Puncte cheie:
  • objectUniversalIdentifier identifică obiectul țintă. Pentru obiectele standard, utilizați STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS exportați din twenty-sdk.
  • Atunci când definiți câmpuri inline în defineObject(), nu aveți nevoie de objectUniversalIdentifier — este moștenit de la obiectul părinte.
  • defineField() este singura modalitate de a adăuga câmpuri la obiecte pe care nu le-ați creat cu defineObject().
Relațiile conectează obiectele între ele. În Twenty, relațiile sunt întotdeauna bidirecționale — definiți ambele părți, iar fiecare parte o referențiază pe cealaltă.Există două tipuri de relații:

Cum funcționează relațiile

Fiecare relație necesită două câmpuri care se referențiază reciproc:
  1. Partea MANY_TO_ONE — se află pe obiectul care deține cheia străină
  2. Partea ONE_TO_MANY — se află pe obiectul care deține colecția
Ambele câmpuri folosesc FieldType.RELATION și se referențiază încrucișat prin relationTargetFieldMetadataUniversalIdentifier.

Exemplu: Post Card are mulți destinatari

Presupuneți că un PostCard poate fi trimis către multe înregistrări PostCardRecipient. Fiecare destinatar aparține exact unui Post Card.Pasul 1: Definiți partea ONE_TO_MANY pe PostCard (partea “one”):
src/fields/post-card-recipients-on-post-card.field.ts
Pasul 2: Definiți partea MANY_TO_ONE pe PostCardRecipient (partea “many” — deține cheia străină):
src/fields/post-card-on-post-card-recipient.field.ts
Importuri circulare: Ambele câmpuri de relație se referă unul la celălalt prin universalIdentifier. Pentru a evita problemele de import circular, exportați ID-urile câmpurilor ca constante denumite din fiecare fișier și importați-le în celălalt fișier. Sistemul de build le rezolvă în timpul compilării.

Relaționarea cu obiectele standard

Pentru a crea o relație cu un obiect Twenty încorporat (Person, Company etc.), utilizați STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS:
src/fields/person-on-self-hosting-user.field.ts

Proprietăți ale câmpului de relație

Câmpuri de relație inline în defineObject

Puteți defini, de asemenea, câmpuri de relație direct în defineObject(). În acest caz, omiteți objectUniversalIdentifier — este moștenit de la obiectul părinte:
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 metodă HTTP sub endpoint-ul /s/:
de ex. path: '/post-card/create' este apelabil la https://your-twenty-server.com/s/post-card/create
  • 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.*
Puteți, de asemenea, să executați manual o funcție folosind CLI:
Puteți urmări jurnalele cu:

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:
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, listează-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']).

Expunerea unei funcții ca instrument

Funcțiile logice pot fi expuse ca instrumente pentru agenți de IA și fluxuri de lucru. Când este marcată ca instrument, o funcție poate fi descoperită de funcționalitățile de IA ale Twenty și poate fi utilizată în automatizări ale fluxurilor de lucru.Pentru a marca o funcție logică drept instrument, setați isTool: true:
src/logic-functions/enrich-company.logic-function.ts
Puncte cheie:
  • Puteți combina isTool cu declanșatoare — o funcție poate fi atât un instrument (apelabilă de agenții AI), cât și declanșată de evenimente în același timp.
  • toolInputSchema (opțional): Un obiect JSON Schema care descrie parametrii pe care îi acceptă funcția dvs. Schema este calculată automat prin analiză statică a codului sursă, dar o puteți seta explicit:
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 ceea ce face instrumentul și când ar trebui apelat.
O funcție de pre-instalare este o funcție logică ce rulează automat înainte ca aplicația ta să fie instalată într-un spațiu de lucru. Aceasta este utilă pentru sarcini de validare, verificări ale condițiilor prealabile sau pregătirea stării spațiului de lucru înainte ca instalarea principală să continue.
src/logic-functions/pre-install.ts
Poți, de asemenea, să execuți manual funcția de pre-instalare oricând folosind CLI:
Puncte cheie:
  • Funcțiile de pre-instalare folosesc definePreInstallLogicFunction() — o variantă specializată care omite setările de declanșare (cronTriggerSettings, databaseEventTriggerSettings, httpRouteTriggerSettings, isTool).
  • Handlerul primește un InstallLogicFunctionPayload cu { previousVersion: string } — versiunea aplicației care a fost instalată anterior (sau un șir gol pentru instalări noi).
  • Este permisă o singură funcție de pre-instalare per aplicație. Construirea manifestului va genera o eroare dacă este detectată mai mult de una.
  • Proprietatea universalIdentifier a funcției este setată automat ca preInstallLogicFunctionUniversalIdentifier în manifestul aplicației în timpul build-ului — nu este nevoie să o referi în defineApplication().
  • Timpul de expirare implicit este setat la 300 de secunde (5 minute) pentru a permite sarcini de pregătire mai lungi.
O funcție post-instalare este o funcție logică care rulează automat după instalarea aplicației într-un spațiu de lucru. Aceasta este utilă pentru sarcini de configurare unice, cum ar fi popularea cu date implicite, crearea înregistrărilor inițiale sau configurarea setărilor spațiului de lucru.
src/logic-functions/post-install.ts
Poți, de asemenea, să execuți manual funcția post-instalare oricând folosind CLI:
Puncte cheie:
  • Funcțiile de post-instalare folosesc definePostInstallLogicFunction() — o variantă specializată care omite setările de declanșare (cronTriggerSettings, databaseEventTriggerSettings, httpRouteTriggerSettings, isTool).
  • Handlerul primește un InstallLogicFunctionPayload cu { previousVersion: string } — versiunea aplicației care a fost instalată anterior (sau un șir gol pentru instalări noi).
  • Este permisă o singură funcție de post-instalare per aplicație. Construirea manifestului va genera o eroare dacă este detectată mai mult de una.
  • Proprietatea universalIdentifier a funcției este setată automat ca postInstallLogicFunctionUniversalIdentifier în manifestul aplicației în timpul build-ului — nu este nevoie să o referi în defineApplication().
  • Timpul de expirare implicit este setat la 300 de secunde (5 minute) pentru a permite sarcini de configurare mai lungi, cum ar fi popularea datelor.
Componentele front-end sunt componente React care se afișează direct în interfața Twenty. Rulează într-un Web Worker izolat folosind Remote DOM — codul este izolat (sandboxed), dar se redă nativ în pagină, nu într-un iframe.

Unde pot fi utilizate componentele frontale

Componentele frontale pot fi afișate în două locații în cadrul Twenty:
  • Panou lateral — Componentele frontale care nu sunt headless se deschid în panoul lateral din dreapta. Acesta este comportamentul implicit atunci când o componentă frontală este declanșată din meniul de comenzi.
  • Widgeturi (tablouri de bord și pagini de înregistrare) — Componentele frontale pot fi încorporate ca widgeturi în machetele de pagină. La configurarea unui tablou de bord sau a machetei unei pagini de înregistrare, utilizatorii pot adăuga un widget de componentă frontală.

Exemplu de bază

Cel mai rapid mod de a vedea o componentă front-end în acțiune este să o înregistrați ca o comandă. Adăugarea unui câmp command cu isPinned: true o face să apară ca un buton de acțiune rapidă în colțul din dreapta sus al paginii — nu este nevoie de layout de pagină:
src/front-components/hello-world.tsx
După sincronizarea cu yarn twenty dev (sau prin rularea o singură dată a comenzii yarn twenty dev --once), acțiunea rapidă apare în colțul din dreapta sus al paginii:
Buton de acțiune rapidă în colțul din dreapta sus
Faceți clic pe el pentru a afișa componenta inline.

Câmpuri de configurare

Plasarea unei componente front-end pe o pagină

Dincolo de comenzi, puteți încorpora o componentă front-end direct într-o pagină de înregistrare adăugând-o ca widget într-un layout de pagină. Consultați secțiunea definePageLayout pentru detalii.

Headless vs non-headless

Componentele frontale au două moduri de randare controlate de opțiunea isHeadless:Non-headless (implicit) — Componenta afișează o interfață vizibilă. Când este declanșat din meniul de comenzi, se deschide în panoul lateral. Acesta este comportamentul implicit când isHeadless este false sau omis.Headless (isHeadless: true) — Componenta se montează invizibil în fundal. Nu deschide panoul lateral. Componentele headless sunt concepute pentru acțiuni care execută logică și apoi se demontează — de exemplu, rularea unei sarcini asincrone, navigarea la o pagină sau afișarea unui modal de confirmare. Se potrivesc în mod natural cu componentele Command din SDK descrise mai jos.
src/front-components/sync-tracker.tsx
Deoarece componenta returnează null, Twenty omite redarea unui container pentru ea — nu apare spațiu gol în layout. Componenta are în continuare acces la toate hook-urile și la API-ul de comunicare cu gazda.

Componentele Command din SDK

Pachetul twenty-sdk oferă patru componente ajutătoare Command, concepute pentru componente front-end headless. Fiecare componentă execută o acțiune la montare, gestionează erorile afișând o notificare snackbar și demontează automat componenta de interfață la final.Importă-le din twenty-sdk/command:
  • Command — Rulează un callback asincron prin prop-ul execute.
  • CommandLink — Navighează către o rută a aplicației. Props: to, params, queryParams, options.
  • CommandModal — Deschide un modal de confirmare. Dacă utilizatorul confirmă, execută callback-ul execute. Props: title, subtitle, execute, confirmButtonText, confirmButtonAccent.
  • CommandOpenSidePanelPage — Deschide o anumită pagină din panoul lateral. Props: page, pageTitle, pageIcon.
Iată un exemplu complet de componentă front-end headless care folosește Command pentru a rula o acțiune din meniul de comenzi:
src/front-components/run-action.tsx
Și un exemplu care folosește CommandModal pentru a cere confirmarea înainte de execuție:
src/front-components/delete-draft.tsx

Accesarea contextului de rulare

În interiorul componentei, folosiți hook-urile SDK pentru a accesa utilizatorul curent, înregistrarea curentă și instanța componentei:
src/front-components/record-info.tsx
Hook-uri disponibile:

API-ul de comunicare cu gazda

Componentele front-end pot declanșa navigare, ferestre modale și notificări folosind funcții din twenty-sdk:Iată un exemplu care folosește API-ul gazdă pentru a afișa un snackbar și a închide panoul lateral după finalizarea unei acțiuni:
src/front-components/archive-record.tsx

Opțiuni pentru comandă

Adăugarea unui câmp command la defineFrontComponent înregistrează componenta în meniul de comenzi (Cmd+K). Dacă isPinned este true, apare și ca buton de acțiune rapidă în colțul din dreapta sus al paginii.

Expresii de disponibilitate condițională

Câmpul conditionalAvailabilityExpression vă permite să controlați când este vizibilă o comandă în funcție de contextul paginii curente. Importați variabile tipizate și operatori din twenty-sdk pentru a construi expresii:
Variabile de context — acestea reprezintă starea curentă a paginii:Operatori — combinați variabilele în expresii booleene:

Resurse publice

Componentele front-end pot accesa fișiere din directorul public/ al aplicației folosind getPublicAssetUrl:
Consultați secțiunea despre resurse publice pentru detalii.

Stilizare

Componentele front-end acceptă mai multe abordări de stilizare. Puteți folosi:
  • Stiluri inlinestyle={{ color: 'red' }}
  • Componente Twenty UI — import din twenty-sdk/ui (Button, Tag, Status, Chip, Avatar și altele)
  • Emotion — CSS-in-JS cu @emotion/react
  • Styled-components — pattern-uri styled.div
  • Tailwind CSS — clase utilitare
  • Orice bibliotecă CSS-in-JS compatibilă cu React
Abilitățile definesc instrucțiuni și capabilități reutilizabile pe care agenții AI le pot folosi în spațiul dvs. de lucru. Folosiți defineSkill() pentru a defini abilități cu validare încorporată:
src/skills/example-skill.ts
Puncte cheie:
  • name este un șir identificator unic pentru abilitate (se recomandă kebab-case).
  • label este numele lizibil afișat în interfața cu utilizatorul (UI).
  • content conține instrucțiunile abilității — acesta este textul pe care agentul AI îl folosește.
  • icon (opțional) setează pictograma afișată în UI.
  • description (opțional) oferă context suplimentar despre scopul abilității.
Agenții sunt asistenți AI care există în interiorul spațiului dvs. de lucru. Utilizați defineAgent() pentru a crea agenți cu un prompt de sistem personalizat:
src/agents/example-agent.ts
Puncte cheie:
  • name este un șir identificator unic pentru agent (se recomandă kebab-case).
  • label este numele de afișare din interfața cu utilizatorul (UI).
  • prompt conține promptul de sistem — acesta este textul de instrucțiuni care definește comportamentul agentului.
  • description (opțional) oferă context suplimentar despre scopul agentului.
  • icon (opțional) setează pictograma afișată în UI.
  • modelId (opțional) suprascrie modelul AI implicit utilizat de agent.
Vizualizările sunt configurații salvate despre cum sunt afișate înregistrările unui obiect — inclusiv ce câmpuri sunt vizibile, ordinea lor și orice filtre sau grupuri aplicate. Utilizați defineView() pentru a livra vizualizări preconfigurate împreună cu aplicația:
src/views/example-view.ts
Puncte cheie:
  • objectUniversalIdentifier specifică la ce obiect se aplică această vizualizare.
  • key determină tipul vizualizării (de ex., ViewKey.INDEX pentru vizualizarea principală de listă).
  • fields controlează ce coloane apar și ordinea acestora. Fiecare câmp face referire la un fieldMetadataUniversalIdentifier.
  • Puteți defini, de asemenea, filters, filterGroups, groups și fieldGroups pentru configurații mai avansate.
  • position controlează ordonarea atunci când există mai multe vizualizări pentru același obiect.
Elementele de meniu de navigare adaugă intrări personalizate în bara laterală a spațiului de lucru. Utilizați defineNavigationMenuItem() pentru a lega la vizualizări, URL-uri externe sau obiecte:
src/navigation-menu-items/example-navigation-menu-item.ts
Puncte cheie:
  • type determină la ce face trimitere elementul de meniu: NavigationMenuItemType.VIEW pentru o vizualizare salvată sau NavigationMenuItemType.LINK pentru un URL extern.
  • Pentru link-uri către vizualizări, setați viewUniversalIdentifier. Pentru link-uri externe, setați link.
  • position controlează ordonarea în bara laterală.
  • icon și color (opțional) personalizează aspectul.
Machetele de pagină vă permit să personalizați aspectul unei pagini de detalii a unei înregistrări — ce file apar, ce widgeturi sunt în fiecare filă și cum sunt aranjate. Utilizați definePageLayout() pentru a livra machete personalizate împreună cu aplicația:
src/page-layouts/example-record-page-layout.ts
Puncte cheie:
  • type este de obicei 'RECORD_PAGE' pentru a personaliza vizualizarea de detaliu a unui obiect specific.
  • objectUniversalIdentifier specifică la ce obiect se aplică această machetă.
  • Fiecare tab definește o secțiune a paginii cu un title, position și layoutMode (CANVAS pentru layout liber).
  • Fiecare widget dintr-o filă poate reda o componentă frontend, o listă de relații sau alte tipuri de widgeturi integrate.
  • position pe file le controlează ordinea. Folosiți valori mai mari (de ex., 50) pentru a plasa filele personalizate după cele integrate.

Resurse publice (folderul public/)

Folderul public/ din rădăcina aplicației conține fișiere statice — imagini, pictograme, fonturi sau orice alte resurse de care are nevoie aplicația la rulare. Aceste fișiere sunt incluse automat în build-uri, sincronizate în timpul modului de dezvoltare și încărcate pe server. Fișierele plasate în public/ sunt:
  • Accesibile public — odată sincronizate pe server, resursele sunt servite la un URL public. Nu este necesară autentificarea pentru a le accesa.
  • Disponibile în componentele frontend — folosiți URL-urile resurselor pentru a afișa imagini, pictograme sau orice media în componentele React.
  • Disponibile în funcțiile logice — referiți URL-urile resurselor în e-mailuri, răspunsuri API sau orice logică pe server.
  • Utilizate pentru metadatele marketplace-ului — câmpurile logoUrl și screenshots din defineApplication() fac referire la fișiere din acest folder (de ex., public/logo.png). Acestea sunt afișate în marketplace când aplicația este publicată.
  • Sincronizate automat în modul de dezvoltare — când adăugați, actualizați sau ștergeți un fișier în public/, acesta este sincronizat automat cu serverul. Nu este nevoie de repornire.
  • Incluse în build-uriyarn twenty build împachetează toate resursele publice în outputul de distribuție.

Accesarea resurselor publice cu getPublicAssetUrl

Utilizați helperul getPublicAssetUrl din twenty-sdk pentru a obține URL-ul complet al unui fișier din directorul public/. Funcționează atât în funcții logice, cât și în componente frontend. Într-o funcție logică:
src/logic-functions/send-invoice.ts
Într-o componentă frontend:
src/front-components/company-card.tsx
Argumentul path este relativ la folderul public/ al aplicației. Atât getPublicAssetUrl('logo.png'), cât și getPublicAssetUrl('public/logo.png') se rezolvă la același URL — prefixul public/ este eliminat automat dacă este prezent.

Utilizarea pachetelor npm

Puteți instala și utiliza orice pachet npm în aplicația dvs. Atât funcțiile logice, cât și componentele frontend sunt împachetate cu esbuild, care integrează toate dependențele în output — nu sunt necesare node_modules la rulare.

Instalarea unui pachet

Apoi importați-l în codul dvs.:
src/logic-functions/fetch-data.ts
Același lucru funcționează și pentru componentele frontend:
src/front-components/chart.tsx

Cum funcționează împachetarea

Pasul de build folosește esbuild pentru a produce un singur fișier autonom pentru fiecare funcție logică și pentru fiecare componentă frontend. Toate pachetele importate sunt integrate în bundle. Funcțiile logice rulează într-un mediu Node.js. Modulele built-in Node (fs, path, crypto, http etc.) sunt disponibile și nu trebuie instalate. Componentele frontend rulează într-un Web Worker. Modulele built-in Node nu sunt disponibile — doar API-urile de browser și pachetele npm care funcționează într-un mediu de browser. Ambele medii au twenty-client-sdk/core și twenty-client-sdk/metadata disponibile ca module pre-furnizate — acestea nu sunt incluse în bundle, ci sunt rezolvate la rulare de către server.

Generarea scheletului entităților cu yarn twenty add

În loc să creați manual fișiere de entități, puteți folosi generatorul interactiv (scaffolder):
Acesta vă solicită să alegeți un tip de entitate și vă ghidează prin câmpurile necesare. Generează un fișier gata de utilizare, cu un universalIdentifier stabil și apelul corect defineEntity(). Puteți de asemenea să transmiteți direct tipul de entitate pentru a sări peste primul prompt:

Tipuri de entități disponibile

Ce generează scaffolder-ul

Fiecare tip de entitate are propriul său șablon. De exemplu, yarn twenty add object solicită:
  1. Nume (singular) — de ex., invoice
  2. Nume (plural) — de ex., invoices
  3. Etichetă (singular) — completată automat din nume (de ex., Invoice)
  4. Etichetă (plural) — completată automat (de ex., Invoices)
  5. Creați o vizualizare și un element de navigare? — dacă răspundeți afirmativ, scaffolder-ul generează, de asemenea, o vizualizare corespunzătoare și un link în bara laterală pentru noul obiect.
Alte tipuri de entități au prompturi mai simple — majoritatea cer doar un nume. Tipul de entitate field este mai detaliat: solicită numele câmpului, eticheta, tipul (dintr-o listă cu toate tipurile de câmp disponibile precum TEXT, NUMBER, SELECT, RELATION etc.) și universalIdentifier al obiectului țintă.

Cale de output personalizată

Utilizați opțiunea --path pentru a plasa fișierul generat într-o locație personalizată:

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 în timpul yarn twenty dev sau yarn twenty build, astfel încât este complet tipizat pentru a corespunde obiectelor și câmpurilor dvs.
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 a tipurilor complete, pe baza schemei spațiului dvs. de lucru.
CoreApiClient este generat în timpul dev/build. Dacă îl utilizați fără a rula mai întâi yarn twenty dev sau yarn twenty build, va arunca o eroare. Generarea are loc automat — CLI inspectează schema GraphQL a spațiului dvs. de lucru și generează un client tipizat folosind @genql/cli.

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.

Încărcarea fișierelor

MetadataApiClient include o metodă uploadFile pentru atașarea fișierelor la câmpuri de tip fișier:
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ă.
  • url returnat este un URL semnat pe care îl poț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ă, limitată la rolul implicit de funcție al aplicației
Nu trebuie să le transmiteți clienților — aceștia citesc automat din process.env. Permisiunile cheii API sunt determinate de rolul referențiat în defaultRoleUniversalIdentifier din application-config.ts.

Testarea aplicației

SDK-ul oferă API-uri programatice care vă permit să construiți, să distribuiți, să instalați și să dezinstalați aplicația din codul de test. Combinat cu Vitest și clienții API tipizați, puteți scrie teste de integrare care verifică faptul că aplicația funcționează cap-coadă împotriva unui server Twenty real.

Configurare

Aplicația generată (scaffolded) include deja Vitest. Dacă o configurați manual, instalați dependențele:
Creați un vitest.config.ts în rădăcina aplicației:
vitest.config.ts
Creați un fișier de configurare care verifică faptul că serverul este accesibil înainte de rularea testelor:
src/__tests__/setup-test.ts

API-uri SDK programatice

Subruta twenty-sdk/cli exportă funcții pe care le puteți apela direct din codul de test: Fiecare funcție returnează un obiect rezultat cu success: boolean și fie data, fie error.

Scrierea unui test de integrare

Iată un exemplu complet care construiește, distribuie și instalează aplicația, apoi verifică faptul că aceasta apare în spațiul de lucru:
src/__tests__/app-install.integration-test.ts

Rularea testelor

Asigurați-vă că serverul Twenty local rulează, apoi:
Sau în modul watch în timpul dezvoltării:

Verificarea tipurilor

Puteți rula și verificarea tipurilor pe aplicație fără a rula testele:
Aceasta rulează tsc --noEmit și raportează orice erori de tip.

Referință CLI

Dincolo de dev, build, add și typecheck, CLI oferă comenzi pentru executarea funcțiilor, vizualizarea jurnalelor și gestionarea instalărilor de aplicații.

Executarea funcțiilor (yarn twenty exec)

Rulați manual o funcție logică fără a o declanșa prin HTTP, cron sau eveniment de bază de date:

Vizualizarea jurnalelor funcțiilor (yarn twenty logs)

Transmiteți în flux jurnalele de execuție pentru funcțiile logice ale aplicației:
Acest lucru este diferit de yarn twenty server logs, care afișează jurnalele containerului Docker. yarn twenty logs afișează jurnalele de execuție ale funcțiilor aplicației de pe serverul Twenty.

Dezinstalarea unei aplicații (yarn twenty uninstall)

Eliminați aplicația din spațiul de lucru activ:

Gestionarea remote-urilor

Un „remote” este un server Twenty la care se conectează aplicația. În timpul configurării, generatorul de schelet creează automat unul pentru dvs. Puteți adăuga mai multe remote-uri sau comuta între ele oricând.
Acreditările dvs. sunt stocate în ~/.twenty/config.json.

CI cu GitHub Actions

Scaffolderul generează un workflow GitHub Actions gata de utilizare în .github/workflows/ci.yml. Rulează automat testele de integrare la fiecare push pe main și la pull request-uri. Workflow-ul:
  1. Preia codul
  2. Pornește un server Twenty temporar folosind acțiunea twentyhq/twenty/.github/actions/spawn-twenty-docker-image
  3. Instalează dependențele cu yarn install --immutable
  4. Rulează yarn test cu TWENTY_API_URL și TWENTY_API_KEY injectate din rezultatele acțiunii
.github/workflows/ci.yml
Nu trebuie să configurați niciun secret — acțiunea spawn-twenty-docker-image pornește un server Twenty efemer direct în runner și oferă detaliile de conectare. Secretul GITHUB_TOKEN este furnizat automat de GitHub. Pentru a fixa o versiune Twenty specifică în loc de latest, modificați variabila de mediu TWENTY_VERSION din partea de sus a workflow-ului.