نظرة عامة
الاتصالات هي بيانات اعتماد يحتفظ بها المستخدم لخدمة خارجية (Linear وGitHub وSlack، …). يحدّد تطبيقك كيف يتم الحصول على تلك بيانات الاعتماد — موفّر اتصال — ويستخدمها وقت التشغيل لإجراء استدعاءات مُصادَقة إلى واجهة برمجة تطبيقات الطرف الثالث. OAuth 2.0 مدمج. تستخدم الخدمات التي لها تدفق اتصال خاص بها — صفحة تسجيل دخول مستضافة، ومعرّف حساب يُسلَّم عبر webhook — موفّرcustom، حيث يقود تطبيقك التدفق ويحتفظ Twenty بالمستخدم ومساحة العمل والاتصال المحفوظ. ستندمج الأنواع المستقبلية من بيانات الاعتماد (رموز الوصول الشخصية، مفاتيح API، المصادقة الأساسية) مع نفس الواجهة — التطبيقات التي تستخدم بالفعل defineConnectionProvider({ type: 'oauth', ... }) لن تحتاج إلى الترحيل.
defineConnectionProvider
عرّف كيفية الحصول على اتصالات تطبيقك
defineConnectionProvider
عرّف كيفية الحصول على اتصالات تطبيقك
WORKSPACE (الافتراضي)، ينقر أحد الأعضاء على “إضافة اتصال” في إعدادات تطبيقك، ويُكمل شاشة موافقة الموفّر، ثم يُنشأ صف ConnectedAccount في مساحة عمله. راجع “اتصالات مساحة العمل أو الاتصالات الشخصية” لموفّري USER.يتطلّب الإعداد العملي ملفّين — موفّر الاتصال، وتصريح serverVariables مطابق في defineApplication يحتفظ ببيانات اعتماد عميل OAuth.nameهي سلسلة المعرّف الفريدة المستخدمة فيlistConnections({ providerName })(بصيغة kebab-case، ويجب أن تطابق^[a-z][a-z0-9-]*$).- يظهر
displayNameفي علامة التبويب عام الخاصة بالتطبيق وفي قائمة أدوات الذكاء الاصطناعي. - يحدّد
scopeمن يتصل:'WORKSPACE'(الافتراضي) للاتصالات المشتركة مع مساحة العمل بأكملها، و'USER'للاتصالات التي ينشئها كل عضو لنفسه. راجع “اتصالات مساحة العمل أو الاتصالات الشخصية” أدناه. logoهو مسار إلى أصل مُضمَّن في مجلدpublic/لتطبيقك، ويُقدَّم عبر الأصول العامة للتطبيق. عند حذفه، تعود علامة التبويب عام إلى عنصر نائب مُنشأ منdisplayName.clientIdVariable/clientSecretVariableهي أسماء، وليست قيماً — ويجب أن تطابق المفاتيح المصرَّح بها فيdefineApplication.serverVariables. يُدخِل مسؤول الخادم القيم الفعليةclient_idوclient_secretعبر واجهة تسجيل التطبيق، ولا تُضمَّن أبدًا في مستودعك.- استخدم
serverVariables(وليسapplicationVariables) — بيانات اعتماد OAuth على مستوى الخادم، ويوجد تطبيق OAuth واحد لكل خادم Twenty. - إلى أن يتم ملء كلا
serverVariables، تعرض علامة التبويب عام الخاصة بالتطبيق تلميح “بحاجة إلى مسؤول الخادم” ويكون زر “إضافة اتصال” معطّلًا. typeهو'oauth'(مع كتلةoauth) أو'custom'(مع كتلةcustom، راجع “تدفقات الاتصال المخصصة”). المميِّز متوافق مع الإصدارات المستقبلية: الأنواع المستقبلية ('pat'،'api-key'، …) ستضيف كتل تهيئة فرعية جديدة إلى جانب هذه.
تدفقات اتصال مخصصة
وصّل الخدمات التي ليست موفري OAuth
تدفقات اتصال مخصصة
وصّل الخدمات التي ليست موفري OAuth
type: 'custom' ودالتَي منطق:authorizeLogicFunction باستخدام callbackUrl يحملها. أعِد المكان الذي يجب إرسال المستخدم إليه:callbackUrl إلى الخدمة دون تغيير. يقبله Twenty كإعادة توجيه من المتصفح (GET) وكإشعار من الخادم (POST)، ويشغّل callbackLogicFunction لكل طلب باستخدام طريقته ومعلمات الاستعلام (من دون state) والرؤوس والنص المُحلل وrawBody (بايتات الطلب الدقيقة، وnull في GET). أعِد الحساب الذي يثبته الطلب، أو null عندما لا يحمل أي حساب — وعادةً ما يكون ذلك عند عودة المتصفح بينما ينتقل معرّف الحساب عبر إشعار:callbackUrl فقط أن الطلب يحمل عنوان URL ذلك، وليس أن الخدمة أرسلته. عندما توقّع الخدمة إشعاراتها، تحقّق من التوقيع على rawBody قبل الوثوق بالنص. تُحوَّل الرؤوس إلى أحرف صغيرة، ولا يتم تمرير cookie وauthorization وproxy-authorization أبداً:onConnectLogicFunction. تعمل onConnectLogicFunction عند إنشاء اتصال أو إعادة اتصاله أو استعادته، ولا تعمل مجدداً عندما تُبلغ الخدمة عن حساب متصل بالفعل. تنتهي صلاحية الحالة بعد ساعة، لذا يُرفض الإشعار الذي يصل لاحقاً. تعيد الخدمات عادةً محاولة الإشعارات: يؤدي تكرار لحساب متصل بالفعل إلى تحديث ذلك الاتصال، لذا من الآمن إعادة الحساب نفسه مرة أخرى.لا يقوم Twenty بتحديث الاتصالات المخصصة أو إلغائها. حرّر ما تحتفظ به الخدمة للحساب في onDisconnectLogicFunction.لا يمكن تغيير type لموفر، مثل scope الخاص به، بعد مزامنته: لنقل خدمة بين oauth وcustom، عرّف موفراً جديداً باستخدام universalIdentifier جديد.تتوفر الموفرات المخصصة مع Twenty 2.52.0.تحديد الحساب المتصل
منع إعادة الاتصال من التبديل بصمت بين الحسابات المصدر
تحديد الحساب المتصل
منع إعادة الاتصال من التبديل بصمت بين الحسابات المصدر
identifyAccountLogicFunction إلى دالة منطقية في التطبيق نفسه تُرجع معرّفًا ثابتًا للحساب المرتبط بالرمز المميز الصادر حديثًا:timeoutSeconds للدالة بـ 10، بغض النظر عما يعلنه البيان؛ اجعلها طلبًا واحدًا إلى نقطة نهاية “من أنا” الخاصة بالموفر. يستمر تشغيل خطاف on-connect، إن وُجد، بعد ذلك، بمجرد حفظ الاتصال.الحمولة. يتلقى المعالج رمز الوصول المؤقت. لم يُحفَظ بعد، لذا لا يمكن لـ getConnection إرجاعه؛ استخدمه مباشرةً ولا تسجّله.- يجب أن يكون
externalAccountIdثابتًا طوال عمر الحساب المصدر (معرّف فريق أو معرّف مؤسسة أو معرّف مستخدم)، وألا يكون أبدًا اسمًا يمكن للمستخدم تغييره. يقوم Twenty بتشذيبه وتخزينه في الاتصال عند أول اتصال. - يستبدل
handle، عند إرجاعه، المعالج الذي كان Twenty سيستنتجه بخلاف ذلك (بريد OIDC الإلكتروني فيid_token، أو بريد المستخدم الذي يجري الاتصال). أعد شيئًا يتعرّف عليه المستخدم، مثل اسم مساحة عمل Slack. - أعد
{ externalAccountId: null }عندما لا يملك الموفر معرّفًا ثابتًا لتقديمه. يتصرف Twenty حينها كما لو لم يتم الإعلان عن دالة تعريف: لا يُخزَّن أي معرّف، وتؤدي إعادة الاتصال إلى مسح أي معرّف مخزن سابقًا، ولا يتم التحقق من عمليات إعادة الاتصال. يُعاملnullالمجرد أو عدم وجود قيمة معادة على أنه خطأ، لذلك لا يمكن لمعالج ينسى الإرجاع تعطيل التحقق بصمت. - إذا أطلقت الدالة استثناءً، أو انتهت مهلتها، أو أعادت أي شيء آخر، فلن يُحفظ الاتصال وسيعود المستخدم إلى صفحة الإعدادات مع ظهور خطأ. أطلق استثناءً فقط عندما يتعذر عليك فعلًا تحديد الحساب.
externalAccountId المعادة بتلك المخزنة في الاتصال. إذا اختلفا، يُرفض رد الاتصال قبل كتابة أي شيء: تبقى الرموز المميزة والمقبض والنطاق الحالية كما كانت، ولا يُشغَّل خطاف عند الاتصال، ويرى المستخدم الحساب الذي منح له التفويض والحساب الذي ينتمي إليه الاتصال. لا تحتوي الاتصالات التي أُنشئت قبل أن يعلن تطبيقك عن الدالة على معرّف مخزن بعد؛ وتخزنه عند إعادة اتصالها التالية.لا يزيل Twenty التكرارات استنادًا إلى externalAccountId: يؤدي ربط الحساب المصدر نفسه مرتين عبر إضافة اتصال إلى إنشاء اتصالين. يُكشف عن المعرّف في listConnections وgetConnection، لذا يمكن للتطبيق الذي يريد اتصالًا واحدًا لكل حساب مصدر اكتشاف التكرارات بنفسه (على سبيل المثال في خطاف on-connect الخاص به).كتابة الدالة. يكشف معظم الموفرين عن نقطة نهاية واحدة تصف الرمز الحالي. بالنسبة إلى Slack، تكون هذه auth.test، التي تعيد مساحة العمل (team_id، team) والمستخدم المرتبط بالرمز:String(id).تتوفر ميزة التعريف في Twenty 2.48.0. إذا كان تطبيقك يعتمد عليها، فأعلن عن "engines": { "twenty": ">=2.48.0" } في package.json الخاص به.تشغيل دالة منطقية عند الاتصال
التفاعل فور إنشاء الاتصال
تشغيل دالة منطقية عند الاتصال
التفاعل فور إنشاء الاتصال
team_id الخاص بمساحة العمل الذي ستُربط به الأحداث الواردة. عيِّن onConnectLogicFunction للإشارة إلى دالة منطقية في التطبيق نفسه (حسب universalIdentifier الخاص بها)، وسيتم تشغيلها مباشرة بعد إنشاء ConnectedAccount.getConnection(connectedAccountId) لقراءة رمز الوصول الجديد واستدعاء واجهة برمجة تطبيقات المزوّد (على سبيل المثال، Slack auth.test) أو حفظ تعيين باستخدام مخزن المفاتيح والقيم.تشغيل دالة منطقية عند قطع الاتصال
نظّف عند فصل اتصال أو إزالته
تشغيل دالة منطقية عند قطع الاتصال
نظّف عند فصل اتصال أو إزالته
team_id عند الاتصال تحرير تلك المطالبة حتى تتمكن مساحة عمل أخرى من ربط فريق Slack نفسه. عيّن onDisconnectLogicFunction للإشارة إلى دالة منطقية في التطبيق نفسه، ويتم تشغيلها عند فصل الاتصال ومرة أخرى عند حذفه.ConnectedAccount ورمزه المميز موجودين، لذا تُرجع getConnection(connectedAccountId) نتيجة ويمكن للمعالج تحرير أي شيء سجّله عن بُعد. عند الحذف، قد تكون بيانات الاعتماد قد اختفت بالفعل (يمكن للعضو حذف اتصال فصله سابقًا)، لذا اجعل المعالج آمنًا لإعادة التنفيذ واحتفظ بالحالة التي يحتاجها (مثل team_id أو معرّف اشتراك خارجي) في مخزن المفاتيح والقيم، وتُكتب عند وقت الاتصال وتُفهرس بواسطة connectedAccountId. اجعله قصيرًا: فهو يعمل ضمن الطلب، لذا فإن timeoutSeconds يمثل الحد الأقصى لمدة استغراق هذا الطلب.يتم تشغيل الخطاف عند قطع اتصال أو إزالته من تلقاء نفسه. يؤدي إلغاء تثبيت التطبيق إلى حذف اتصالاته عبر حذف متسلسل في قاعدة البيانات، لذلك لا يتم تشغيل الخطاف في هذه الحالة. صرّح عن uninstallLogicFunction على defineApplication لذلك المسار: يتم تشغيله قبل حذف بيانات التعريف الخاصة بالتطبيق، لذا لا يزال بإمكانه استدعاء listConnections وتنظيف أي شيء متبقٍّ.listConnections / getConnection
استخدم الاتصالات من دالة منطقية
listConnections / getConnection
استخدم الاتصالات من دالة منطقية
listConnections({ providerName }) صفوف ConnectedAccount الخاصة بهذا التطبيق للمزوّد المحدَّد، مع رموز وصول محدَّثة.- مرّر
{ providerName }للتصفية حسب المزوّد؛ واحذفه للحصول على كل الاتصالات التي يملكها هذا التطبيق عبر جميع المزوّدين. - يقوم الخادم بتحديث رمز الوصول بشفافية قبل الإرجاع. يرى معالجك دائمًا رمزًا صالحًا للاستخدام (أو سيكون
authFailedAtمُعيّنًا). getConnection(id)هي المعادِل لصف واحد.
reportConnectionAuthFailure
أبلغ المنصة بأن بيانات الاعتماد لم تعد صالحة
reportConnectionAuthFailure
أبلغ المنصة بأن بيانات الاعتماد لم تعد صالحة
authFailedAt من تلقاء نفسها فقط عند فشل تجديد OAuth. يفشل المزوّدون الذين لا تُجدَّد رموزهم المميزة مطلقًا (مثل رمز روبوت Slack المميز) فقط في وقت الاستدعاء داخل معالجاتك، لذا سيظل صف الاتصال في الإعدادات يعرض متصل بينما يفشل كل استدعاء. عندما يواجه رمزك رفضًا نهائيًا للمصادقة، أبلغ عنه:authFailedAt والسبب الاختياري على الاتصال. يتحول صف الإعدادات إلى يلزم إعادة الاتصال مع زر «إعادة الاتصال»، وتعرض صفحة تفاصيل الاتصال السبب، ويبدأ getConnection في إطلاق AppConnectionAuthFailedError لذلك الصف. يُمسح العَلَم والسبب تلقائيًا عندما يعيد المستخدم الاتصال. يُرفض reason الذي يزيد طوله على 1000 حرف، لذا اقتطع حمولات المزوّد قبل تمريرها.أبلغ فقط عن الإخفاقات التي ستُصلحها إعادة الاتصال فعليًا (رفض من فئة invalid_auth من المزوّد)، ولا تُبلغ أبدًا عن أخطاء الشبكة العابرة. لا يمكن للتطبيق إلا الإبلاغ عن اتصالاته الخاصة، ولا يمكن لمستخدم الطلب إلا الإبلاغ عن بيانات اعتماده الشخصية.تتوفر عملية التعديل وراء هذا المساعد مع Twenty 2.40.0، لذا يفشل استدعاؤها على خادم أقدم. إذا كان تطبيقك يستخدمها، فصرّح بالاعتماد في package.json: "engines": { "twenty": ">=2.40.0" }.اتصالات مساحة العمل أو الاتصالات الشخصية
اختر من يتصل باستخدام نطاق الموفّر
اتصالات مساحة العمل أو الاتصالات الشخصية
اختر من يتصل باستخدام نطاق الموفّر
- مشتركة على مستوى مساحة العمل (
'WORKSPACE') — يمكن لأي عضو في مساحة العمل استخدام بيانات الاعتماد. يمكن لمشغّلات cron/قاعدة البيانات رؤيتها أيضًا، لأنها لا تملك مستخدم طلب. - لي فقط (
'USER') — بيانات الاعتماد تتبع للعضو الذي يجري الاتصال. في عمليات التشغيل التي تُنفَّذ نيابةً عن عضو (مشغّل مسار HTTP معisAuthRequired: true)، تُرجعlistConnectionsالاتصالات المشتركة بالإضافة إلى اتصالات ذلك العضو الخاصة، وتختارfindConnectionForRequestاتصال العضو الشخصي، مع الرجوع إلى اتصال مشترك عند عدم وجود أي اتصال لديه. في عمليات التشغيل التي لا تتضمن مستخدم طلب (مثل مشغّلات cron)، تُرجعlistConnectionsكل اتصال، بما في ذلك الاتصالات الشخصية لكل عضو.
scope الخاص بالموفّر أيّهما تحصل عليه اتصالاته الجديدة:scope: 'WORKSPACE'(الافتراضي) — يعمل التطبيق مع الاتصالات المشتركة مع مساحة العمل. يؤدي إضافة اتصال في إعدادات مساحة عمل التطبيق إلى إنشاء اتصال مشترك في مساحة العمل.scope: 'USER'— يتصل كل عضو بحسابه الخاص، مما ينشئ اتصالات شخصية. يضيف الأعضاء التطبيقات ويعيدون ربطها ويزيلونها من صفحة التطبيق ضمن الإعدادات > المستخدم > تفضيلات التطبيقات، الأمر الذي يتطلب إذن تطبيقات المستخدم. لا تحتوي إعدادات مساحة عمل التطبيق على زر إضافة اتصال لموفّرUSER.
USER، لذا لا تعتمد على اتصال واحد من أجل
ميزة تحتاجها كل مساحة عمل الآن.scope لموفر موجود، ويُرفض التحديث إذا حاول ذلك. لنقل خدمة من نطاق إلى آخر، عرّف موفرًا جديدًا باستخدام universalIdentifier جديد وأزل الموفر القديم. يؤدي التحديث بعد ذلك إلى حذف الموفر القديم وكل اتصال أُنشئ به عبر مسار قطع الاتصال المعتاد (onDisconnectLogicFunction، وإلغاء الرمز المميز، وتنظيف القناة)، ثم يعيد الأعضاء الاتصال عبر الموفر الجديد.تتطلب إضافة اتصال لي فقط أو إعادة ربطه إذن تطبيقات المستخدم، بينما تتطلب إضافة اتصال مشترك لمساحة العمل أو إعادة ربطه إذن تطبيقات مساحة العمل.استخدم الاتصال المناسب لكل معالج:scope، فأعلن "engines": { "twenty": ">=2.49.0" } في package.json الخاص به. في الإصدار نفسه، يستبدل scope الخاص بالاتصال visibility الخاص به، والذي يظل متاحًا كاسم مستعار مهمل بأحرف صغيرة. يقرأ listConnections وgetConnection من twenty-sdk 2.49.0 قيمة scope، لذا تحتاج التطبيقات المنشأة به إلى خادم 2.49.0.إعداد المزوّد لمرة واحدة
سجّل تطبيق OAuth الخاص بك لدى خدمة الطرف الثالث
إعداد المزوّد لمرة واحدة
سجّل تطبيق OAuth الخاص بك لدى خدمة الطرف الثالث
- انتقل إلى إعدادات المطوّر لدى المزوّد (مثل https://linear.app/settings/api/applications/new).
- عيّن Redirect URI إلى
\<SERVER_URL>/auth/apps/callback. - انسخ Client ID وClient Secret المُنشأين.
- افتح التطبيق المُثبَّت في Twenty كمسؤول خادم → عيّن القيم على
serverVariablesالمقابلة. - يمكن لأعضاء مساحة العمل بعد ذلك إضافة اتصالات إلى موفّري
WORKSPACEمن قسم الاتصالات الخاص بكل تطبيق.