الانتقال إلى المحتوى الرئيسي
Logic functions are server-side TypeScript functions that run on the Twenty platform. They can be triggered by HTTP requests, cron schedules, or database events — and can also be exposed as tools for AI agents.
كل ملف وظيفة يستخدم defineLogicFunction() لتصدير تكوين مع معالج ومشغّلات اختيارية.
src/logic-functions/createPostCard.logic-function.ts
import { defineLogicFunction } from 'twenty-sdk/define';
import type { DatabaseEventPayload, ObjectRecordCreateEvent, CronPayload, RoutePayload } from 'twenty-sdk/define';
import { CoreApiClient, type Person } from 'twenty-client-sdk/core';

const handler = async (params: RoutePayload) => {
  const client = new CoreApiClient();
  const name = 'name' in params.queryStringParameters
    ? params.queryStringParameters.name ?? process.env.DEFAULT_RECIPIENT_NAME ?? 'Hello world'
    : 'Hello world';

  const result = await client.mutation({
    createPostCard: {
      __args: { data: { name } },
      id: true,
      name: true,
    },
  });
  return result;
};

export default defineLogicFunction({
  universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf',
  name: 'create-new-post-card',
  timeoutSeconds: 2,
  handler,
  httpRouteTriggerSettings: {
    path: '/post-card/create',
    httpMethod: 'GET',
    isAuthRequired: true,
  },
  /*databaseEventTriggerSettings: {
    eventName: 'people.created',
  },*/
  /*cronTriggerSettings: {
    pattern: '0 0 1 1 *',
  },*/
});
أنواع المشغّلات المتاحة:
  • httpRoute: يعرِض وظيفتك على مسار وطريقة HTTP تحت نقطة النهاية /s/:
مثال: path: '/post-card/create' يمكن استدعاؤه عبر https://your-twenty-server.com/s/post-card/create
  • cron: يشغّل وظيفتك على جدول باستخدام تعبير CRON.
  • databaseEvent: يعمل على أحداث دورة حياة كائنات مساحة العمل. عندما تكون عملية الحدث هي updated، يمكن تحديد الحقول المحددة المراد الاستماع إليها في مصفوفة updatedFields. إذا تُركت غير معرّفة أو فارغة، فسيؤدي أي تحديث إلى تشغيل الدالة.
مثال: person.updated، *.created، company.*
يمكنك أيضًا تنفيذ دالة يدويًا باستخدام CLI:
yarn twenty exec -n create-new-post-card -p '{"key": "value"}'
yarn twenty exec -y e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf
يمكنك متابعة السجلات باستخدام:
yarn twenty logs

حمولة مشغل المسار

عندما يستدعي مُشغِّل المسار وظيفتك المنطقية، فإنها تتلقّى كائن RoutePayload الذي يتبع صيغة AWS HTTP API v2. استورد نوع RoutePayload من twenty-sdk:
import { defineLogicFunction, type RoutePayload } from 'twenty-sdk/define';

const handler = async (event: RoutePayload) => {
  const { headers, queryStringParameters, pathParameters, body } = event;
  const { method, path } = event.requestContext.http;

  return { message: 'Success' };
};
يحتوي نوع RoutePayload على البنية التالية:
الخاصيةالنوعالوصفمثال
headersRecord\<string, string | undefined>رؤوس HTTP (فقط تلك المدرجة في forwardedRequestHeaders)انظر القسم أدناه
queryStringParametersRecord\<string, string | undefined>معلمات سلسلة الاستعلام (تُضمّ القيم المتعددة باستخدام فواصل)/users?ids=1&ids=2&ids=3&name=Alice -> { ids: '1,2,3', name: 'Alice' }
pathParametersRecord\<string, string | undefined>معلمات المسار المستخرجة من نمط المسار/users/:id, /users/123 -> { id: '123' }
المحتوىobject | nullجسم الطلب المُحلَّل (JSON){ id: 1 } -> { id: 1 }
isBase64Encodedقيمة منطقيةما إذا كان جسم الطلب مُرمَّزًا بترميز base64
requestContext.http.methodstringطريقة HTTP (GET, POST, PUT, PATCH, DELETE)
requestContext.http.pathstringالمسار الخام للطلب

forwardedRequestHeaders

افتراضيًا، لا تُمرَّر رؤوس HTTP من الطلبات الواردة إلى دالتك المنطقية لأسباب أمنية. للوصول إلى رؤوس محددة، أدرِجها في مصفوفة forwardedRequestHeaders:
export default defineLogicFunction({
  universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf',
  name: 'webhook-handler',
  handler,
  httpRouteTriggerSettings: {
    path: '/webhook',
    httpMethod: 'POST',
    isAuthRequired: false,
    forwardedRequestHeaders: ['x-webhook-signature', 'content-type'],
  },
});
في معالجك، يمكنك الوصول إلى الرؤوس المُمرَّرة بهذه الطريقة:
const handler = async (event: RoutePayload) => {
  const signature = event.headers['x-webhook-signature'];
  const contentType = event.headers['content-type'];

  // Validate webhook signature...
  return { received: true };
};
تُحوَّل أسماء الرؤوس إلى أحرف صغيرة. يمكنك الوصول إليها باستخدام مفاتيح بأحرف صغيرة (على سبيل المثال، event.headers['content-type']).

إتاحة دالة كأداة

يمكن إتاحة الدوال المنطقية بوصفها أدوات لوكلاء الذكاء الاصطناعي وسير العمل. عند تمييز دالة كأداة، تصبح قابلة للاكتشاف بواسطة ميزات الذكاء الاصطناعي في Twenty ويمكن استخدامها في أتمتة سير العمل.لتمييز دالة منطقية كأداة، عيِّن isTool: true:
src/logic-functions/enrich-company.logic-function.ts
import { defineLogicFunction } from 'twenty-sdk/define';
import { CoreApiClient } from 'twenty-client-sdk/core';

const handler = async (params: { companyName: string; domain?: string }) => {
  const client = new CoreApiClient();

  const result = await client.mutation({
    createTask: {
      __args: {
        data: {
          title: `Enrich data for ${params.companyName}`,
          body: `Domain: ${params.domain ?? 'unknown'}`,
        },
      },
      id: true,
    },
  });

  return { taskId: result.createTask.id };
};

export default defineLogicFunction({
  universalIdentifier: 'f47ac10b-58cc-4372-a567-0e02b2c3d479',
  name: 'enrich-company',
  description: 'Enrich a company record with external data',
  timeoutSeconds: 10,
  handler,
  isTool: true,
});
النقاط الرئيسية:
  • يمكنك دمج isTool مع المشغِّلات — إذ يمكن للدالة أن تكون أداة (قابلة للاستدعاء من قِبل وكلاء الذكاء الاصطناعي) وأن تُشغَّل بواسطة الأحداث في الوقت نفسه.
  • toolInputSchema (اختياري): كائن JSON Schema يصف المعلمات التي تقبلها دالتك. يُحسَب المخطط تلقائيًا من خلال تحليل ساكن للشيفرة المصدرية، ولكن يمكنك تعيينه صراحةً:
export default defineLogicFunction({
  ...,
  toolInputSchema: {
    type: 'object',
    properties: {
      companyName: {
        type: 'string',
        description: 'The name of the company to enrich',
      },
      domain: {
        type: 'string',
        description: 'The company website domain (optional)',
      },
    },
    required: ['companyName'],
  },
});
اكتب description جيدًا. يعتمد وكلاء الذكاء الاصطناعي على حقل description الخاص بالدالة لتحديد وقت استخدام الأداة. كن محددًا بشأن ما تفعله الأداة ومتى ينبغي استدعاؤها.
دالة ما بعد التثبيت هي دالة منطقية تعمل تلقائيًا بعد تثبيت تطبيقك على مساحة عمل. ينفّذه الخادم بعد مزامنة البيانات الوصفية للتطبيق وإنشاء عميل SDK، بحيث تكون مساحة العمل جاهزة تمامًا للاستخدام ويكون المخطط الجديد مطبَّقًا. تشمل حالات الاستخدام النموذجية تهيئة البيانات الافتراضية، وإنشاء السجلات الأولية، وتكوين إعدادات مساحة العمل، أو توفير الموارد على خدمات جهات خارجية.
src/logic-functions/post-install.ts
import { definePostInstallLogicFunction, type InstallPayload } from 'twenty-sdk/define';

const handler = async (payload: InstallPayload): Promise<void> => {
  console.log('Post install logic function executed successfully!', payload.previousVersion);
};

export default definePostInstallLogicFunction({
  universalIdentifier: 'f7a2b9c1-3d4e-5678-abcd-ef9876543210',
  name: 'post-install',
  description: 'Runs after installation to set up the application.',
  timeoutSeconds: 300,
  shouldRunOnVersionUpgrade: false,
  shouldRunSynchronously: false,
  handler,
});
يمكنك أيضًا تنفيذ دالة ما بعد التثبيت يدويًا في أي وقت باستخدام CLI:
yarn twenty exec --postInstall
النقاط الرئيسية:
  • تستخدم دوال ما بعد التثبيت definePostInstallLogicFunction() — وهو إصدار متخصص يستبعد إعدادات المُشغِّل (cronTriggerSettings وdatabaseEventTriggerSettings وhttpRouteTriggerSettings وisTool).
  • يتلقى المعالج InstallPayload يحتوي على { previousVersion?: string; newVersion: string } — حيث إن newVersion هو الإصدار الجاري تثبيته، وpreviousVersion هو الإصدار الذي كان مُثبّتًا سابقًا (أو undefined عند التثبيت الأولي). استخدم هذه القيم للتمييز بين عمليات التثبيت الجديدة والترقيات ولتشغيل منطق الترحيل الخاص بالإصدار.
  • موعد تشغيل الخطاف: في عمليات التثبيت الجديدة فقط، افتراضيًا. مرّر shouldRunOnVersionUpgrade: true إذا كنت تريد تشغيله أيضًا عند ترقية التطبيق من إصدار سابق. عند إغفاله، تكون القيمة الافتراضية للعلم false، وتتجاوز الترقيات هذا الخطاف.
  • نموذج التنفيذ — غير متزامن افتراضيًا، والتزامني اختياري: يتحكّم العلم shouldRunSynchronously في كيفية تنفيذ ما بعد التثبيت.
    • shouldRunSynchronously: false (الإعداد الافتراضي) — يتم إدراج الخطاف في قائمة الرسائل مع retryLimit: 3 ويعمل بشكل غير متزامن داخل عامل عمل. يعود ردّ التثبيت بمجرد وضع المهمة في الطابور، لذا فإن معالجًا بطيئًا أو متعطلًا لا يحجب المستدعي. سيُجرِّب العامل إعادة المحاولة حتى ثلاث مرات. استخدم هذا للمهام طويلة التشغيل — بَذر مجموعات بيانات كبيرة، استدعاء واجهات برمجة تطبيقات خارجية بطيئة، تهيئة موارد خارجية، أو أي شيء قد يتجاوز نافذة استجابة HTTP المعقولة.
    • shouldRunSynchronously: true — يُنفّذ الخطاف ضمن تدفّق التثبيت مباشرةً (نفس المنفِّذ كما قبل التثبيت). يَحجُب طلب التثبيت حتى ينتهي المعالج، وإذا رمى استثناءً، سيتلقى مستدعي التثبيت POST_INSTALL_ERROR. لا توجد محاولات إعادة تلقائية. استخدم هذا للمهام السريعة التي يجب إكمالها قبل الاستجابة — مثل إظهار خطأ تحقق للمستخدم، أو إعداد سريع سيعتمد عليه العميل مباشرةً بعد عودة نداء التثبيت. ضع في اعتبارك أن ترحيل البيانات الوصفية يكون قد طُبِّق بالفعل عند تشغيل ما بعد التثبيت، لذلك فإن فشل الوضع المتزامن لا يعيد التغييرات على المخطط إلى الوراء — بل يكتفي بإبراز الخطأ.
  • تأكّد من أن معالجك قابل للتنفيذ المتكرر دون آثار جانبية. في الوضع غير المتزامن قد تُعيد قائمة الانتظار المحاولة حتى ثلاث مرات؛ وفي أي من الوضعين قد يعمل الخطاف مجددًا أثناء الترقيات عند ضبط shouldRunOnVersionUpgrade: true.
  • متغيرات البيئة APPLICATION_ID وAPP_ACCESS_TOKEN وAPI_URL متاحة داخل المعالج (كما في أي دالة منطق أخرى)، لذا يمكنك استدعاء واجهة Twenty API باستخدام رمز وصول للتطبيق مقيّد بنطاق تطبيقك.
  • يُسمح بدالة ما بعد التثبيت واحدة فقط لكل تطبيق. سيُنتج إنشاء ملف البيان خطأً إذا تم اكتشاف أكثر من واحدة.
  • تُرفَق خصائص الدالة universalIdentifier وshouldRunOnVersionUpgrade وshouldRunSynchronously تلقائيًا ببيان التطبيق ضمن الحقل postInstallLogicFunction أثناء عملية البناء — ولا تحتاج إلى الإشارة إليها في defineApplication().
  • تم تعيين مهلة افتراضية إلى 300 ثانية (5 دقائق) للسماح بمهام الإعداد الأطول مثل تهيئة البيانات.
  • لا يُنفَّذ في وضع التطوير: عند تسجيل تطبيق محليًا (عبر yarn twenty dev)، يتجاوز الخادم تدفّق التثبيت بالكامل ويُزامن الملفات مباشرةً عبر مراقِب CLI — لذا لن يعمل ما بعد التثبيت في وضع التطوير مطلقًا، بغضّ النظر عن shouldRunSynchronously. استخدم yarn twenty exec --postInstall لتشغيله يدويًا على مساحة عمل قيد التشغيل.
دالة ما قبل التثبيت هي دالة منطقية تعمل تلقائيًا أثناء التثبيت، قبل تطبيق ترحيل البيانات الوصفية لمساحة العمل. تتشارك نفس بنية الحمولة مع ما بعد التثبيت (InstallPayload)، لكنها موضوعة أبكر في تدفّق التثبيت كي تجهّز حالة يعتمد عليها الترحيل القادم — ومن الاستخدامات الشائعة: نسخ البيانات احتياطيًا، التحقق من التوافق مع المخطط الجديد، أو أرشفة السجلات التي ستُعاد هيكلتها أو ستُحذف.
src/logic-functions/pre-install.ts
import { definePreInstallLogicFunction, type InstallPayload } from 'twenty-sdk/define';

const handler = async (payload: InstallPayload): Promise<void> => {
  console.log('Pre install logic function executed successfully!', payload.previousVersion);
};

export default definePreInstallLogicFunction({
  universalIdentifier: 'a1b2c3d4-5678-90ab-cdef-1234567890ab',
  name: 'pre-install',
  description: 'Runs before installation to prepare the application.',
  timeoutSeconds: 300,
  shouldRunOnVersionUpgrade: true,
  handler,
});
يمكنك أيضًا تنفيذ دالة ما قبل التثبيت يدويًا في أي وقت باستخدام CLI:
yarn twenty exec --preInstall
النقاط الرئيسية:
  • تستخدم دوال ما قبل التثبيت definePreInstallLogicFunction() — نفس الإعدادات المتخصصة كما في ما بعد التثبيت، لكنها مرتبطة بموضع مختلف ضمن دورة الحياة.
  • يتلقّى كلٌّ من معالجي ما قبل التثبيت وما بعد التثبيت النوع نفسه InstallPayload: { previousVersion?: string; newVersion: string }. استورده مرة واحدة وأعد استخدامه لكلا الخطافين.
  • موعد تشغيل الخطاف: موضوع مباشرةً قبل ترحيل البيانات الوصفية لمساحة العمل (synchronizeFromManifest). قبل التنفيذ، يُشغِّل الخادم مزامنة “pared-down sync” ذات طابع إضافي فقط تقوم بتسجيل دالة ما قبل التثبيت للإصدار الجديد في البيانات الوصفية لمساحة العمل — دون لمس أي شيء آخر — ثم يُنفّذها. لأن هذه المزامنة «إضافية فقط»، تبقى كائنات وحقول وبيانات الإصدار السابق سليمة عند تشغيل معالجك: يمكنك قراءة حالة ما قبل الترحيل ونسخها احتياطيًا بأمان.
  • نموذج التنفيذ: يُنفَّذ ما قبل التثبيت بشكل متزامن ويحجب عملية التثبيت. إذا رمى المعالج استثناءً، تُلغى عملية التثبيت قبل تطبيق أي تغييرات على المخطط — وتبقى مساحة العمل على الإصدار السابق بحالة متّسقة. هذا مقصود: ما قبل التثبيت هو فرصتك الأخيرة لرفض ترقية تنطوي على مخاطر.
  • كما هو الحال مع ما بعد التثبيت، يُسمح بدالة ما قبل التثبيت واحدة فقط لكل تطبيق. تُربَط تلقائيًا ببيان التطبيق تحت preInstallLogicFunction أثناء عملية البناء.
  • لا يُنفَّذ في وضع التطوير: كما في ما بعد التثبيت — يتم تجاوز تدفّق التثبيت بالكامل للتطبيقات المسجّلة محليًا، لذا لن يعمل ما قبل التثبيت مطلقًا عند yarn twenty dev. استخدم yarn twenty exec --preInstall لتشغيله يدويًا.
كلا الخطافين جزء من تدفّق التثبيت نفسه ويتلقّيان نفس InstallPayload. الاختلاف يكمن في موعد تشغيلهما نسبةً إلى ترحيل البيانات الوصفية لمساحة العمل، وهذا يغيّر البيانات التي يمكنهما التعامل معها بأمان.
┌─────────────────────────────────────────────────────────────┐
│ install flow                                                │
│                                                             │
│   upload package → [pre-install] → metadata migration →     │
│   generate SDK → [post-install]                             │
│                                                             │
│                  old schema visible    new schema visible   │
└─────────────────────────────────────────────────────────────┘
ما قبل التثبيت دائمًا متزامن (يحجب التثبيت ويمكنه إحباطه). ما بعد التثبيت غير متزامن افتراضيًا — يُدرج على عامل مع محاولات إعادة تلقائية — لكن يمكن التبديل إلى تنفيذ متزامن عبر shouldRunSynchronously: true. راجع الأكورديون definePostInstallLogicFunction أعلاه لمعرفة متى تستخدم كل وضع.استخدم post-install لأي شيء يتطلّب وجود المخطط الجديد. وهذا هو السيناريو الشائع:
  • بَذر بيانات افتراضية (إنشاء سجلات أولية وعروض افتراضية ومحتوى تجريبي) للكائنات والحقول المضافة حديثًا.
  • تسجيل خطافات الويب مع خدمات أطراف ثالثة بعد أن حصل التطبيق على بيانات الاعتماد الخاصة به.
  • استدعاء واجهة برمجة التطبيقات الخاصة بك لإكمال إعداد يعتمد على البيانات الوصفية المتزامنة.
  • منطق idempotent لتحقيق “تأكّد من وجود هذا” والذي ينبغي مواءمة الحالة في كل ترقية — بالاقتران مع shouldRunOnVersionUpgrade: true.
مثال — بَذر سجل PostCard افتراضي بعد التثبيت:
src/logic-functions/post-install.ts
import { definePostInstallLogicFunction, type InstallPayload } from 'twenty-sdk/define';
import { createClient } from './generated/client';

const handler = async ({ previousVersion }: InstallPayload): Promise<void> => {
  if (previousVersion) return; // fresh installs only

  const client = createClient();
  await client.postCard.create({
    data: { title: 'Welcome to Postcard', content: 'Your first card!' },
  });
};

export default definePostInstallLogicFunction({
  universalIdentifier: 'f7a2b9c1-3d4e-5678-abcd-ef9876543210',
  name: 'post-install',
  description: 'Seeds a welcome post card after install.',
  timeoutSeconds: 300,
  shouldRunOnVersionUpgrade: false,
  handler,
});
استخدم pre-install عندما قد يُتلف الترحيل أو يدمّر البيانات الحالية. لأن ما قبل التثبيت يعمل مقابل المخطط السابق وفشله يُرجِع الترقية إلى الوراء، فهو المكان المناسب لأي شيء محفوف بالمخاطر:
  • نسخ البيانات احتياطيًا قبل حذفها أو إعادة هيكلتها — مثل إزالة حقل في v2 وتحتاج إلى نسخ قيمه إلى حقل آخر أو تصديرها إلى التخزين قبل تشغيل الترحيل.
  • أرشفة السجلات التي سيبطلها قيد جديد — مثل أن يصبح حقل ما NOT NULL وتحتاج أولًا إلى حذف الصفوف ذات القيم الفارغة أو إصلاحها.
  • التحقق من التوافق ورفض الترقية إذا تعذّر ترحيل البيانات الحالية بسلاسة — ارمِ من داخل المعالج وسيُلغى التثبيت دون تطبيق أي تغييرات. هذا أكثر أمانًا من اكتشاف عدم التوافق في منتصف الترحيل.
  • إعادة تسمية البيانات أو إعادة تعيين مفاتيحها قبل تغيير في المخطط قد يؤدي إلى فقدان الارتباط.
مثال — أرشف السجلات قبل ترحيل هدّام:
src/logic-functions/pre-install.ts
import { definePreInstallLogicFunction, type InstallPayload } from 'twenty-sdk/define';
import { createClient } from './generated/client';

const handler = async ({ previousVersion, newVersion }: InstallPayload): Promise<void> => {
  // Only the 1.x → 2.x upgrade drops the legacy `notes` field.
  if (!previousVersion?.startsWith('1.') || !newVersion.startsWith('2.')) {
    return;
  }

  const client = createClient();
  const legacyRecords = await client.postCard.findMany({
    where: { notes: { isNotNull: true } },
  });

  if (legacyRecords.length === 0) return;

  // Copy legacy `notes` into the new `description` field before the migration
  // drops the `notes` column. If this fails, the upgrade is aborted and the
  // workspace stays on v1 with all data intact.
  await Promise.all(
    legacyRecords.map((record) =>
      client.postCard.update({
        where: { id: record.id },
        data: { description: record.notes },
      }),
    ),
  );
};

export default definePreInstallLogicFunction({
  universalIdentifier: 'a1b2c3d4-5678-90ab-cdef-1234567890ab',
  name: 'pre-install',
  description: 'Backs up legacy notes into description before the v2 migration.',
  timeoutSeconds: 300,
  shouldRunOnVersionUpgrade: true,
  handler,
});
قاعدة عامة:
You want to…استخدام
بذر بيانات افتراضية، تهيئة مساحة العمل، تسجيل موارد خارجيةpost-install
تشغيل بذر طويل الأمد أو استدعاءات أطراف ثالثة لا ينبغي أن تحجب استجابة التثبيتpost-install (الإعداد الافتراضي — shouldRunSynchronously: false، مع محاولات إعادة من العامل)
تشغيل إعداد سريع سيعتمد عليه المستدعي مباشرةً بعد عودة نداء التثبيتpost-install مع shouldRunSynchronously: true
قراءة البيانات أو نسخها احتياطيًا والتي قد يفقدها الترحيل القادمpre-install
رفض ترقية قد تُفسد البيانات الحاليةpre-install (ارمِ من المعالج)
تنفيذ مواءمة في كل ترقيةpost-install مع shouldRunOnVersionUpgrade: true
تنفيذ إعداد لمرة واحدة في التثبيت الأول فقطpost-install مع shouldRunOnVersionUpgrade: false (الإعداد الافتراضي)
إذا ساورك الشك، فاجعل الافتراضي هو post-install. الجأ إلى ما قبل التثبيت فقط عندما يكون الترحيل نفسه هدّامًا وتحتاج إلى التقاط الحالة السابقة قبل أن تزول.

عملاء واجهة برمجة تطبيقات مضبوطة الأنواع (twenty-client-sdk)

توفر حزمة twenty-client-sdk عميلين لـ GraphQL ذوي أنواع ثابتة للتفاعل مع واجهة Twenty البرمجية من وظائفك المنطقية ومكوّنات الواجهة الأمامية.
العميلاستيرادنقطة النهايةمُولَّد؟
CoreApiClienttwenty-client-sdk/core/graphql — بيانات مساحة العمل (السجلات، الكائنات)نعم، في وقت التطوير/البناء
MetadataApiClienttwenty-client-sdk/metadata/metadata — تكوين مساحة العمل، رفع الملفاتلا، يأتي مُجهزًا مسبقًا
CoreApiClient هو العميل الرئيسي للاستعلام وتعديل بيانات مساحة العمل. يُولَّد من مخطط مساحة العمل لديك أثناء yarn twenty dev أو yarn twenty build، لذا فهو مضبوط الأنواع بالكامل ليتوافق مع كائناتك وحقولك.
import { CoreApiClient } from 'twenty-client-sdk/core';

const client = new CoreApiClient();

// Query records
const { companies } = await client.query({
  companies: {
    edges: {
      node: {
        id: true,
        name: true,
        domainName: {
          primaryLinkLabel: true,
          primaryLinkUrl: true,
        },
      },
    },
  },
});

// Create a record
const { createCompany } = await client.mutation({
  createCompany: {
    __args: {
      data: {
        name: 'Acme Corp',
      },
    },
    id: true,
    name: true,
  },
});
يستخدم العميل صياغة مجموعة اختيار: مرِّر true لتضمين حقل، واستخدم __args للوسيطات، وعشّش الكائنات للعلاقات. ستحصل على إكمال تلقائي كامل وفحص للأنواع يعتمد على مخطط مساحة العمل لديك.
يتم توليد CoreApiClient في وقت التطوير/البناء. إذا استخدمته دون تشغيل yarn twenty dev أو yarn twenty build أولًا، فسيؤدي ذلك إلى خطأ. تحدث عملية التوليد تلقائيًا — إذ يستطلع CLI مخطط GraphQL لمساحة عملك وينشئ عميلًا مضبوط الأنواع باستخدام @genql/cli.

استخدام CoreSchema للتعليقات التوضيحية للأنواع

CoreSchema يوفّر أنواع TypeScript المطابقة لكائنات مساحة العمل لديك — مفيد لتعيين أنواع حالة المكوّن أو معاملات الدوال:
import { CoreApiClient, CoreSchema } from 'twenty-client-sdk/core';
import { useState } from 'react';

const [company, setCompany] = useState<
  Pick<CoreSchema.Company, 'id' | 'name'> | undefined
>(undefined);

const client = new CoreApiClient();
const result = await client.query({
  company: {
    __args: { filter: { position: { eq: 1 } } },
    id: true,
    name: true,
  },
});
setCompany(result.company);
يأتي MetadataApiClient مُجهّزًا مسبقًا مع SDK (لا حاجة للتوليد). يستعلم عن نقطة النهاية /metadata للحصول على تكوين مساحة العمل والتطبيقات ورفع الملفات.
import { MetadataApiClient } from 'twenty-client-sdk/metadata';

const metadataClient = new MetadataApiClient();

// List first 10 objects in the workspace
const { objects } = await metadataClient.query({
  objects: {
    edges: {
      node: {
        id: true,
        nameSingular: true,
        namePlural: true,
        labelSingular: true,
        isCustom: true,
      },
    },
    __args: {
      filter: {},
      paging: { first: 10 },
    },
  },
});

رفع الملفات

يتضمن MetadataApiClient طريقة uploadFile لإرفاق الملفات بالحقول من نوع الملف:
import { MetadataApiClient } from 'twenty-client-sdk/metadata';
import * as fs from 'fs';

const metadataClient = new MetadataApiClient();

const fileBuffer = fs.readFileSync('./invoice.pdf');

const uploadedFile = await metadataClient.uploadFile(
  fileBuffer,                                         // file contents as a Buffer
  'invoice.pdf',                                      // filename
  'application/pdf',                                  // MIME type
  '58a0a314-d7ea-4865-9850-7fb84e72f30b',            // field universalIdentifier
);

console.log(uploadedFile);
// { id: '...', path: '...', size: 12345, createdAt: '...', url: 'https://...' }
المعلمةالنوعالوصف
fileBufferBufferالمحتوى الخام للملف
filenamestringاسم الملف (يُستخدم للتخزين والعرض)
contentTypestringنوع MIME (القيمة الافتراضية application/octet-stream إذا لم يُحدَّد)
fieldMetadataUniversalIdentifierstringقيمة universalIdentifier لحقل نوع الملف في كائنك
النقاط الرئيسية:
  • يستخدم universalIdentifier الخاص بالحقل (وليس معرّفه الخاص بمساحة العمل)، بحيث يعمل كود الرفع لديك عبر أي مساحة عمل مُثبَّت فيها تطبيقك.
  • العنوان url المُعاد هو عنوان URL موقّع يمكنك استخدامه للوصول إلى الملف المرفوع.
عند تشغيل كودك على Twenty (وظائف منطقية أو مكوّنات أمامية)، يقوم النظام الأساسي بحقن بيانات الاعتماد كمتغيرات بيئية:
  • TWENTY_API_URL — عنوان URL الأساسي لواجهة Twenty البرمجية
  • TWENTY_APP_ACCESS_TOKEN — مفتاح قصير العمر ذو نطاق يقتصر على الدور الافتراضي لوظيفة تطبيقك
لست بحاجة إلى تمرير هذه القيم إلى العملاء — فهي تُقرأ تلقائيًا من process.env. تُحدَّد أذونات مفتاح واجهة برمجة التطبيقات بواسطة الدور المشار إليه في defaultRoleUniversalIdentifier ضمن application-config.ts.