الانتقال إلى المحتوى الرئيسي

نظرة عامة

يجب أن يحتوي كل تطبيق على استدعاء واحد فقط لـ defineApplication. يحدّد ما يلي:
  • الهوية — المعرّف الشامل، واسم العرض، والوصف.
  • الأذونات — الدور الذي تعمل بموجبه دوال المنطق والمكوّنات الأمامية الخاصة به.
  • إمكانات الوسائط (اختياري): الوصول إلى الميكروفون أو الكاميرا الذي تطلبه مكوّنات الواجهة، ويُوافق عليه بشكل منفصل عن أذونات الدور.
  • المتغيرات (اختياري) — أزواج مفتاح–قيمة تُتاح لكودك كمتغيرات بيئة.
  • خطافات ما قبل التثبيت/ما بعد التثبيت/إلغاء التثبيت (اختياري) — راجع Logic Functions.
  • الفوترة (اختياري) — billing.recurring لرسوم الاشتراك التي تفرضها المنصة تلقائيًا، وbilling.operations لما تفرض عليه تطبيقك أرصدة، وbilling.description للسوق؛ راجع فرض الأرصدة.
src/application-config.ts
الملاحظات:
  • حقول universalIdentifier هي UUID تنشئها مرة واحدة وتملكها. أبقِها ثابتة عبر عمليات المزامنة. يجب أن يكون universalIdentifier الخاص بالتطبيق UUID صالحًا: يرفض الخادم بيانًا يكون معرّفه ليس UUID صالحًا. إنه فريد عبر النسخة بأكملها ومرتبط بمساحة العمل التي تملك تسجيله، لذا لا يمكن مزامنة التطبيق إلا لمساحة العمل تلك — راجع ملكية التسجيل.
  • تقبل applicationVariables قيمة label اختيارية — اسمًا سهل الاستخدام يُعرض في صفحة إعدادات التطبيق بدلًا من مفتاح المتغير الخام.
  • applicationVariables تصبح متغيرات بيئة لوظائفك ومكوّناتك الأمامية. في وظائف المنطق (على جانب الخادم)، تكون متاحة على شكل process.env.VARIABLE_NAME. في المكوّنات الأمامية، استخدم getApplicationVariable('VARIABLE_NAME') من twenty-sdk/front-component. يتم حقن المتغيّرات المعلَّمة بـ isSecret: true في وظائف المنطق فقط. المكوّنات الأمامية تتلقّى المتغيّرات غير السرّية فقط. يحتفظ متغير ذو scope: 'USER' بقيمة العضو الذي يعمل الكود لصالحه: راجع متغيرات مساحة العمل والمستخدم.
  • يمكن لتطبيقك أيضًا قراءة قيم متغيراته وتحديثها في وقت التشغيل، وهي الطريقة التي يحفظ بها مكوّن الإعدادات المخصص ما كتبه المستخدم: راجع قراءة المتغيرات وتحديثها في وقت التشغيل. لا يصل التطبيق مطلقًا إلا إلى متغيراته الخاصة، ضمن مساحة العمل الخاصة به.
  • يتم اكتشاف الدور الافتراضي تلقائيًا من ملف الدور المميز بـ defineApplicationRole() — لست بحاجة إلى الإشارة إليه من defineApplication().
  • يتم اكتشاف دوال ما قبل التثبيت وما بعد التثبيت وإلغاء التثبيت، وفحوصات السلامة، تلقائيًا أثناء بناء البيان — لا حاجة للإشارة إليها في defineApplication().
  • لا يزال تمرير defaultRoleUniversalIdentifier بشكل صريح مدعومًا من أجل التوافق مع الإصدارات السابقة، ولكنه مُهمل لصالح defineApplicationRole().
  • serverVariables هي تكوينات وأسرار بنطاق المثيل (مثل مفاتيح واجهة برمجة التطبيقات). على عكس applicationVariables، فهي لا تصرح عن أي قيمة في ملف manifest — حيث يقوم مشغّل مساحة العمل بملئها من إعدادات التطبيق، ويتم حقنها في دوال المنطق فقط بعد تعيينها.
  • يمكن للتطبيق الإبلاغ عن حالة تهيئته الخاصة باستخدام defineHealthCheck()، وذلك للأمور التي لا يعرفها إلا التطبيق نفسه — مفتاح موجود لكنه مُلغى، أو حساب تابع لجهة خارجية على الخطة الخاطئة. يغطي isRequired ما يمكن لـ Twenty رؤيته بمفرده؛ بينما يغطي فحص السلامة الباقي. عيّن runOnUserPreferences: true للتحقق من إعداد كل عضو على صفحة تفضيلات التطبيقات الخاصة به بدلًا من إعدادات تطبيق مساحة العمل. يؤدي حذف الخيار أو تعيينه إلى false إلى الإبقاء على فحص مساحة العمل الحالي.
  • يقبل كلا نوعي المتغير ‎isRequired: true‎. إذا لم تُدخل مساحة العمل قيمة متغير مطلوب بعد، فسيظل التطبيق غير مُهيأ: تعرض صفحة إعداداته لافتةً تسمي المتغيرات المفقودة، مع زر ينتقل إلى علامة التبويب حيث تُضبط هذه المتغيرات. ضع علامة «مطلوب» فقط على ما لا يمكن للتطبيق تشغيله فعليًا بدونه — يجب أن يظل المتغير الاختياري ذو القيمة الافتراضية المعقولة اختياريًا.
  • كلا نوعي المتغير يقبلان ‎isDeprecated: true‎. استخدم ذلك لإيقاف استخدام متغير بدلاً من حذفه: إبقاء المفتاح معلناً يحافظ على القيمة المخزنة (حذفه يدمّر القيمة التي أدخلها المشغّل)، ولا يزال يتم حقن المتغير، بحيث يمكن لشفرتك أن تعتمد عليه كخيار احتياطي — ‎process.env.NEW_API_KEY ?? process.env.API_KEY‎. يختفي المتغير المهمل من إعدادات التطبيق عند عدم تحديد قيمة له، ولا يؤخذ في الحسبان ضمن فحص تهيئة التطبيق، لذا تكون isDeprecated أعلى أولوية من isRequired.
  • يُعيّن Twenty هذه الأسماء لكل تشغيل لدالة منطقية، لذا فهي محجوزة: TWENTY_API_URL، TWENTY_APP_ACCESS_TOKEN، TWENTY_APP_APPLICATION_ACCESS_TOKEN، TWENTY_API_KEY، TWENTY_FUNCTIONS_URL، TWENTY_SERVER_ROUTES_URL وAPPLICATION_ID. يُحجز أيضًا كل اسم آخر يبدأ بـ TWENTY_ للمتغيرات التي يضيفها Twenty لاحقًا. يُرفض البيان الذي يعلن اسمًا محجوزًا كمتغير للتطبيق أو الخادم عند مزامنة التطبيق أو نشره.
  • لإضافة إدخالاتك الخاصة إلى قائمة إعدادات التطبيق (بدلًا من صفحة Variables المُنشأة)، صرّح بمكوّن واجهة أمامية ووجّه defineSettingsMenuItem() إليه، في ملفه الخاص. صرّح بعدد ما تحتاج إليه ورتّبها باستخدام position؛ يضع scope عنصرًا ضمن إعدادات مساحة العمل أو ضمن إعدادات كل عضو الخاصة. يأتي عنصر عام الذي يديره النظام (الترقية التلقائية، عنوان URL للتطبيق، الاتصالات) دائمًا أولًا، ولا يظهر عنوان URL للتطبيق إلا عندما يحتوي التطبيق على وظائف يتم تشغيلها عبر HTTP.

إمكانات الوسائط المطلوبة

عيّن requestedCapabilities عندما يستخدم أحد مكوّنات الواجهة navigator.mediaDevices.getUserMedia(). تقبل المصفوفة الاختيارية 'microphone' أو 'camera' أو كليهما. احذفها أو استخدم مصفوفة فارغة عندما لا يحتاج التطبيق إلى التقاط الوسائط.
تظهر الإمكانات المعلنة أثناء التثبيت. تتطلب الموافقة عضوًا في مساحة العمل يمكنه إدارة التطبيقات، وتنطبق على مساحة العمل بأكملها. تكون هذه المنح منفصلة عن أذونات دور التطبيق ولا تحل محل أذونات المتصفح أو نظام التشغيل. يوقف التطبيق المثبّت الذي لا يملك المنح المطلوبة الالتقاط ويعرض مربع حوار للموافقة عند الاستخدام الأول، بما في ذلك التطبيقات الأقدم التي لا تحتوي على تعريفات للإمكانات. يؤدي الرفض إلى بقاء الالتقاط محظورًا قبل طلب أذونات المتصفح. لا تمنح تحديثات الحزمة وصولًا إضافيًا تلقائيًا. تتلقى تطبيقات التطوير المتزامنة محليًا الإمكانات المعلنة في ملف البيان الخاص بها. راجع التقاط الوسائط لمعرفة سلوك الالتقاط ومؤشرات التسجيل.

الوصول إلى وسائط موقع الويب المضمّن

عيّن requestedIframeMediaPermissions عندما يضمّن مكوّن أمامي أو عنصر واجهة مستخدم لتخطيط صفحة IFRAME موقع ويب يحتاج إلى الميكروفون أو الكاميرا، مثل أداة هاتف أو فيديو. أدرج ما يصل إلى 20 موقع ويب، يكون كل منها مصدر HTTPS مطابقًا تمامًا، مع تعيين الوصول إلى الميكروفون والكاميرا بشكل منفصل. يجب أن تكون المصادر فريدة، وألا تحتوي على مسار أو رمز بديل، وأن تطلب الوصول إلى واحد على الأقل من الميكروفون أو الكاميرا.
تظهر مواقع الويب المُعلنة أثناء التثبيت. تتطلب الموافقة عضوًا في مساحة العمل يمكنه إدارة التطبيقات، وتنطبق على مساحة العمل بأكملها، للمكوّنات الأمامية الخاصة بالتطبيق وعناصر واجهة iframe الخاصة به. تنطبق موافقات أمان مساحة العمل فقط على عناصر الواجهة التي أُنشئت في مساحة العمل. تتلقى تطبيقات التطوير المتزامنة محليًا مواقع الويب المُعلنة في بيانها. لا تحل هذه المنح محل أذونات المتصفح أو نظام التشغيل. لرؤوس المتصفح حد للحجم، لذا إذا تجاوزت مواقع الويب الخاصة بمساحة العمل هذا الحد، تأتي مواقع الويب المعتمدة من مساحة العمل أولًا ولا تتلقى مواقع الويب المتبقية الوصول إلى الوسائط. تحافظ تحديثات التطبيقات المنشورة على المنح الحالية ولا تمنح تلقائيًا وصولًا إضافيًا إلى الوسائط. للموافقة على الطلبات الجديدة، يفتح عضو يمكنه إدارة التطبيقات علامة التبويب عام للتطبيق المثبّت ويحدد مراجعة الوصول إلى الوسائط ضمن الوصول إلى وسائط موقع الويب المضمّن. تستخدم هذه الموافقة تأكيدًا أصليًا من المتصفح يعرض التطبيق ومصادر مواقع الويب والوصول المطلوب إلى الميكروفون أو الكاميرا. بعد الموافقة، أعد تحميل علامات تبويب Twenty المفتوحة لتطبيق الأذونات المحدّثة. راجع مواقع الويب المضمّنة مع الوصول إلى الوسائط لمعرفة متطلبات iframe.

أنواع المتغيرات

كل من applicationVariables وserverVariables يقبلان حقل type اختياريًا (ولـ SELECT / MULTI_SELECT، قائمة options). الأنواع المدعومة: TEXT (افتراضي)، BOOLEAN، NUMBER، NUMERIC، DATE، DATE_TIME، SELECT، MULTI_SELECT، ARRAY، RAW_JSON، RICH_TEXT.
src/application-config.ts
إن type يؤثر فقط على العرض والتحقق — حيث يختار حقل الإدخال المطابق في واجهة إعدادات مساحة العمل (زر تبديل، حقل أرقام، قائمة منسدلة، منتقي تاريخ، محرر JSON، …) ويسمح لعملية البناء بالتحقق من صحة إعداداتك (على سبيل المثال، يجب أن يعلن SELECT / MULTI_SELECT عن options غير فارغة). وهو لا يغيّر كيفية وصول القيمة إلى الشيفرة الخاصة بك. تُحَقَن القيم دائمًا كسلاسل نصية — فهذا جزء جوهري من متغيرات البيئة (process.env.* نصية فقط). عند تشغيل دالة المنطق الخاصة بك، يقوم المنفّذ بتسلسل كل قيمة وفقًا لـ type المعلن أثناء بناء process.env، بحيث يكون تنسيق السلسلة النصية متّسقًا بغض النظر عن كيفية تعيين القيمة (قيمة افتراضية في manifest، من واجهة الإعدادات، أو من إصدار سابق): حوّل السلسلة النصية مرة أخرى إلى النوع الذي تتوقعه:
ينطبق الأمر نفسه على مكوّنات الواجهة الأمامية التي تقرأ القيم عبر getApplicationVariable('VARIABLE_NAME') — فالقيمة المعادة هي سلسلة نصية؛ قم بتحليلها حسب الحاجة.

متغيرات مساحة العمل والمستخدم

لكل متغير تطبيق scope:
  • WORKSPACE (افتراضي): قيمة واحدة لمساحة العمل بأكملها، يعيّنها عضو يمكنه إدارة التطبيقات.
  • USER: يحتفظ كل عضو بقيمته الخاصة.
src/application-config.ts
تكون value لمتغير المستخدم هي قيمته الافتراضية: يقرأها عضو لم يعيّن قيمته الخاصة، ويمكن لإصدار جديد من تطبيقك تغييرها. لا يمكن أن يكون للمتغير السري قيمة افتراضية. من دونه، يقرأ العضو الذي لم يعيّن قيمته الخاصة سلسلة فارغة، لذا يحدد تطبيقك ما تعنيه القيمة غير المعيّنة. لا يمكن لمسؤول مساحة العمل تعيين قيمة لمتغير مستخدم: قيمه تخص كل عضو. يُعيَّن نطاق المتغير عند إنشائه ولا يمكن تغييره. لتغييرها، عرّف المتغير باستخدام universalIdentifier جديد: تحذف المزامنة المتغير القديم، بما في ذلك قيم أعضائه، وتنشئ المتغير الجديد. يمكن أن تكون متغيرات المستخدم isSecret أو isRequired أو كليهما. على سبيل المثال، يمكن لمفتاح API شخصي أن يعرّف scope: 'USER', isSecret: true, isRequired: true. تُشفَّر القيم أثناء التخزين. بالنسبة إلى متغيرات المستخدم، يصف isRequired متطلبًا لكل عضو. يرى العضو الذي ليس لديه قيمة له، سواء كانت قيمته الخاصة أو قيمة افتراضية، تطبيقك مميزًا بعلامة الإعدادات مفقودة في تفضيلات التطبيقات، مع لافتة تسمي المتغيرات. لا يؤثر ذلك في تحذير تكوين مساحة العمل، ولا شيء يفرضه في وقت التشغيل: يظل الرمز البرمجي الخاص بك هو من يقرر ما تعنيه القيمة غير المعيّنة. يُحقن متغير المستخدم بقيمة العضو الذي يعمل الكود لصالحه، أو بقيمته الافتراضية إلى أن يعيّن قيمته الخاصة:
  • في دالة منطقية، يحتوي process.env على قيم العضو الذي شغّل التنفيذ، وهو العضو نفسه الذي يعمل TWENTY_APP_ACCESS_TOKEN بصفته. لا يحصل تنفيذ لا يقف وراءه أي شخص، مثل مهمة cron أو خطاف تثبيت، على أي متغيرات مستخدم على الإطلاق.
  • في مكوّن واجهة، تُرجع getApplicationVariable قيم العضو الذي يعرضه. تُستبعد متغيرات المستخدم السرية، مثل متغيرات مساحة العمل السرية.
العضو الذي شغّل تنفيذًا ليس دائمًا العضو الذي يدور حوله التنفيذ: يعمل حدث قاعدة بيانات بصفته الشخص الذي حرّر السجل. عندما يكون التنفيذ متعلقًا بشخص آخر، أو بكل عضو، اقرأ القيم باستخدام myUserApplicationVariables عبر MetadataApiClient. يسرد كل عضو مع قيمه لمتغيرات مستخدم تطبيقك، ويعمل في كل تنفيذ لدالة منطقية، بما في ذلك مهام cron وخطافات الويب. يحمل كل إدخال userWorkspaceId وworkspaceMemberId وvariables الخاص بالعضو: تعريف كل متغير مستخدم (label وdescription وtype وoptions وisSecret وisRequired وisDeprecated) وقيمة العضو، أو القيمة الافتراضية إلى أن يعيّن قيمته الخاصة. استعلم عنه بصفتك التطبيق للحصول على القيم الفعلية: باستخدام رمز مميز يقف وراءه شخص، لا يُرجع إلا إدخال ذلك الشخص، مع إخفاء الأسرار.
القيم هي سلاسل، بالتنسيق نفسه الذي يستخدمه process.env (راجع أنواع المتغيرات). يحفظ updateMyUserApplicationVariable قيمة العضو الخاصة به. يأخذ applicationUniversalIdentifier الخاص بتطبيقك ويكتب قيمة الشخص الذي يقف خلف الرمز المميز: جلسة العضو نفسه، أو الرمز المميز لتطبيقك عندما يكون عضو خلفه، مثلما يحدث في مكوّن واجهة أو دالة منطقية تُشغَّل لعضو. لا يمكن لرمز تطبيقك تسمية سوى تطبيقك الخاص، ويُرفَض الرمز الذي لا يرتبط به أي شخص، كما في مهمة cron أو خطاف تثبيت. تؤدي القيمة الفارغة إلى إزالة القيمة الخاصة بالعضو، بحيث يقرأ القيمة الافتراضية مجددًا، أو سلسلة فارغة لمتغير لا يملك قيمة افتراضية. لا يتطلب إذن Workspace Apps، لكنه يتطلب User Apps: في دور العضو، وعندما يجري رمز تطبيقك المميز الاستدعاء، في الدور الافتراضي لتطبيقك أيضًا، إذا كان يعرّف واحدًا. إذا كان تطبيقك يحفظ متغيرات المستخدم، فأضف SystemPermissionFlag.USER_APPS إلى permissionFlagUniversalIdentifiers في الدور.

الدور الافتراضي للوظيفة

يتحكم الدور المعلن باستخدام defineApplicationRole() في ما يمكن لوظائف منطق التطبيق ومكوّنات الواجهة الوصول إليه:
  • رموز وقت التشغيل المحقونة في دوال المنطق لديك مستمدة من هذا الدور. تُقيَّد المكالمة التي تتصرف كشخص بشكل أكبر بما يمكن لذلك الشخص القيام به، لذا لا يمكنها أبدًا تجاوز أيٍّ منهما. راجع صلاحيات الوصول التي تستخدمها المكالمة.
  • يكون عميل واجهة برمجة التطبيقات مضبوط الأنواع مقيّدًا بالأذونات الممنوحة لذلك الدور.
  • اتبع مبدأ أقل امتياز: صرّح فقط عن الأذونات التي تحتاجها دوالك.
عند إنشاء هيكل لتطبيق جديد، ينشئ CLI ملف دور مبدئي في src/roles/default-role.ts. راجع Roles & Permissions للاطلاع على المرجع الكامل.

بيانات التعريف لسوق التطبيقات

إذا كنت تخطط لـ نشر تطبيقك، فإن هذه الحقول الاختيارية تتحكّم في كيفية ظهوره في السوق:
القيمتان logoUrl وscreenshots هما اسمَان مهملان بديلان لـlogo وgalleryImages. عناوين URLs المطلقة الخارجية (http:// أو https://) غير مدعومة لهذه الحقول: سيتم تجاهلها مع إظهار تحذير وقت البناء. بدلًا من ذلك، ضمِّن الصور في مجلد public/ الخاص بتطبيقك.