> ## Documentation Index
> Fetch the complete documentation index at: https://www.ayrshare.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# أحداث اكتمال الربط

> احصل على إخطار عندما يربط مستخدمك حسابًا، بدلًا من استطلاع ذلك.

export const PlansAvailable = ({plans = [], maxPackRequired}) => {
  let displayPlans = plans;
  if (plans && plans.length === 1) {
    const lowerCasePlan = plans[0].toLowerCase();
    if (lowerCasePlan === "business") {
      displayPlans = ["Launch", "Business", "Enterprise"];
    } else if (lowerCasePlan === "premium") {
      displayPlans = ["Premium", "Launch", "Business", "Enterprise"];
    }
  }
  return <Note>
Available on {displayPlans.length === 1 ? "the " : ""}
{displayPlans.join(", ").replace(/\b\w/g, l => l.toUpperCase())}{" "}
{displayPlans.length > 1 ? "plans" : "plan"}.

{maxPackRequired && <span onClick={() => window.open('https://www.ayrshare.com/docs/additional/maxpack', '_self')} className="flex items-center mt-2 cursor-pointer">
 <span className="px-1.5 py-0.5 rounded text-sm" style={{
    backgroundColor: '#C264B6',
    color: 'white',
    fontSize: '12px'
  }}>
   Max Pack required
 </span>
</span>}
</Note>;
};

<PlansAvailable plans={["business"]} maxPackRequired={false} />

عندما تفتح صفحة ربط في نافذة منبثقة، تستطيع صفحتك أنت الاستماع إلى ما يقع فيها: ربط مستخدمك
Reddit، أو تراجعه، أو فشل الربط. تحصل على حدث لكل نتيجة، فتتحدث واجهتك لحظة وقوع الأمر لا
وفق مؤقّت.

عيّن [`origin`](/docs/apis/profiles/create-link-session) عند إنشاء الرابط، وافتح `url` المُعاد في
نافذة منبثقة، واستمع. لا شيء آخر مطلوب، ولا شيء يتغير للروابط المُنشأة دون `origin` — فهي
تتصرف تمامًا كما كانت دائمًا.

<Note>
  **تستخدم [الأداة المضمّنة](/docs/multiple-users/connect-widget)؟ هذا مُهيّأ لك بالفعل.** يتلقى
  السكربت هذه الأحداث ويسلّمها إلى `connect.on("success", …)` بعد نزع البادئة `connect:` —
  دون مستمع `message`، ولا فحص أصل، ولا استطلاع `popup.closed` تكتبه. هذه الصفحة هي بروتوكول
  السلك الكامن تحت ذلك، وما تبني عليه عندما تملك **أنت** النافذة: الوضع المباشر، أو نافذة
  منبثقة تفتحها بنفسك.
</Note>

<Note>
  تُرسل الأحداث فقط إلى `origin` الفعلي الذي عيّنته على الرابط، وفقط إلى النافذة التي فتحت
  النافذة المنبثقة. تحقق دائمًا من `event.origin` في مستمعك مع ذلك: يمكن لأي صفحة إرسال رسالة
  إلى نافذتك، والأصل هو الجزء الوحيد من الرسالة الذي لا يمكن تزويره.
</Note>

## الأحداث

كل رسالة تُرسل إلى صفحتك هي كائن على شكل
`{ source: "ayrshare", version: 1, event, ... }`، ويحمل `network` كلما كان الحدث يخص شبكة.
حدثان لا يحملانها: `connect:closed` القادم من صفحة الربط المستضافة، حيث يعني أن مستخدمك ضغط
على Done لا أن عملية ربط واحدة انتهت، و`connect:ready` الخاص بالأداة (انظر أدناه). أما
النتائج التي تُركّبها شيفرتك بنفسها — نافذة منبثقة محجوبة، أو نافذة أغلقها مستخدمك — فلا
تأتي منا ولا تحمل إلا ما تعطيه لها.

<Note>
  تختلف [الأداة المضمّنة](/docs/multiple-users/connect-widget) في حدث واحد. فحدث `ready` لديها
  يعلن أن فتحة أصبحت جاهزة لا شيئًا عن شبكة، لذا لا يحمل `network` — بينما `ready` الخاص
  بالنافذة المنبثقة يُسمّي الشبكة التي فُتحت من أجلها. إذا كنت تعالج السطحين من مستمع واحد،
  فاقرأ `network` بحذر على `ready`.

  تضيف الأداة أيضًا سبب `cancelled` واحدًا لا يرسله هذا السطح أبدًا: `superseded`، عندما يحل
  استدعاء `popup()` ثانٍ محل محاولة لا تزال جارية. هنا توجد نافذة واحدة ونتيجة واحدة، فلا شيء
  يُستبدل.
</Note>

| الحدث               | حقول إضافية                  | يُرسل عندما                                                                                                                                                  |
| ------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `connect:ready`     |                              | حُمّلت الصفحة وتم التحقق من الرابط.                                                                                                                          |
| `connect:started`   |                              | أُرسل مستخدمك إلى الشبكة الاجتماعية.                                                                                                                         |
| `connect:selection` | `step`                       | مُنتقٍ أو نموذج على الشاشة — لدى مستخدمك ما يفعله.                                                                                                           |
| `connect:success`   | `refId`، ‏`displayName`      | الحساب متصل **ومحفوظ**. ‏`refId` هو User Profile الذي رُبط به. ‏`displayName` هو اسم الحساب، ويُحذف عندما لا يكون لدينا واحد بعد.                            |
| `connect:error`     | `message`، و`code` عند وجوده | فشل الربط. يطابق `code` [مرجع الأخطاء](/docs/errors/overview)؛ ويغيب عندما لا يكون للفشل رمز مفهرس، وعلى أي نتيجة يركّبها مقتطفك بنفسه، مثل نافذة منبثقة محجوبة.  |
| `connect:cancelled` | `reason`                     | تراجع مستخدمك. ‏`reason` هي `popupClosed` أو `scopesDenied` أو `userCancelled`.                                                                              |
| `connect:closed`    |                              | النافذة المنبثقة على وشك أن تُغلق نفسها. لا يحمل `network` عندما يأتي من صفحة الربط المستضافة، حيث يعني أن مستخدمك ضغط على Done لا أن عملية ربط واحدة انتهت. |

يصل واحد بالضبط من `connect:success` أو `connect:error` أو `connect:cancelled` لكل عملية
ربط. أما `connect:closed` فليس واحدًا منها — بل يتبعها، ليخبرك بأن النافذة المنبثقة أُغلقت عن
قصد.

لا يُرسل `connect:success` إلا بعد حفظ الحساب، لذا فإن استدعاء
[`GET /user`](/docs/apis/user/profile-details) بعده مباشرةً يُظهر الحساب المتصل بالفعل.

<Note>
  تبقى النافذة المنبثقة مفتوحة بعد `connect:error` حتى يتمكن مستخدمك من قراءة ما حدث من خطأ.
  وتُغلق نفسها بعد `connect:success` و`connect:cancelled`. أضف `&autoClose=false` إلى عنوان
  URL لإبقائها مفتوحة في كل الحالات أثناء التصحيح.
</Note>

## الاستماع

أمران يفعلهما هذا المقتطف يسهل إغفالهما. فهو يتحقق من `event.origin`، ويراقب النافذة
المنبثقة التي أغلقها مستخدمك يدويًا — فالنافذة المغلقة لا تستطيع إرسال أي شيء، والاستطلاع هو
السبيل الوحيد لملاحظة ذلك.

```javascript theme={"system"}
function connectAccount(url) {
  // Derive the origin from the URL you were given rather than hard-coding one:
  // if your account uses its own linking domain, the popup runs on that.
  const popupOrigin = new URL(url).origin;

  const popup = window.open(url, "ayrshare-connect", "width=600,height=800");
  if (!popup) {
    handleOutcome({ event: "connect:error", message: "The popup was blocked." });
    return;
  }

  // Declared before anything can call `cleanup`: a message arriving early would
  // otherwise hit `poll` in its temporal dead zone and throw.
  let poll;

  const cleanup = () => {
    clearInterval(poll);
    window.removeEventListener("message", onMessage);
  };

  const onMessage = event => {
    // Both checks, not just the origin: another tab or frame on the same origin
    // could otherwise post a message your handler would believe.
    if (event.origin !== popupOrigin || event.source !== popup) return;
    const message = event.data;
    if (!message || message.source !== "ayrshare") return;

    if (["connect:success", "connect:error", "connect:cancelled"].includes(message.event)) {
      // `finally`, so your own handler throwing cannot leave the poll running —
      // it would later see the closed popup and report `cancelled` on top of the
      // outcome you already had. Cleanup also matters after `connect:error`,
      // where the popup stays open so your user can read it.
      try {
        handleOutcome(message);
      } finally {
        cleanup();
      }
    }
  };
  window.addEventListener("message", onMessage);

  // A hand-closed popup sends nothing, so watch for it. Wait a moment before
  // deciding: the popup closes itself right after sending, and the message can
  // still be in flight when you first see the window go.
  let closedAt = null;
  poll = setInterval(() => {
    if (!popup.closed) return;
    if (closedAt === null) {
      closedAt = Date.now();
      return;
    }
    if (Date.now() - closedAt < 750) return;

    cleanup();
    handleOutcome({ event: "connect:cancelled", reason: "popupClosed" });
  }, 500);
}
```

## الأخطاء

يحمل `connect:error` الرموز نفسها التي تحملها بقية API، فالرمز الذي تراه هنا يعني ما يعنيه
في كل مكان آخر. الرمز الخاص بهذا السطح وحده:

| الرمز | المعنى                                                                                                                                                                                   |
| ----- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `513` | فُتح الرابط كنافذة ربط لشبكة واحدة، لكنه لم يُنشأ لذلك. لا يمكن الوصول إليه إلا إذا بنيت عنوان URL ذلك بنفسك — فعنوان `url` الذي تعيده نقطة النهاية هذه يطابق دائمًا الرابط الذي أنشأته. |

أي شيء آخر هو فشل الشبكة الاجتماعية نفسها، يُبلَّغ عنه بالرمز الذي يحمله ذلك الفشل أصلًا —
مثل `322` لمشكلة تفويض في Instagram، وهو ما يشمل حسابًا لا يزال شخصيًا (Personal) بدلًا من
احترافي (Professional).

### الرابط الميت يصل بطريقة مختلفة

الرابط **المنتهي الصلاحية** أو **المُبطل** أو **المجهول** يُرفض قبل أن تتمكن الصفحة من معرفة
وجهة إرسال الأحداث، فلا يستطيع إرسال أي حدث. يرى مستخدمك السبب ورمزه على الشاشة، وتسمع صفحتك
`connect:cancelled` عندما يغلق النافذة.

للتمييز بينها، استطلع [الحصول على Link Session](/docs/apis/profiles/get-link-session): فهو يبلّغ
عن `expired` و`revoked` بشكل موثوق، ويعيد `502` للرابط غير الموجود.

## إذا كنت تفضّل عدم إدارة نافذة منبثقة

خياران، والثاني وحده يتخلى عن الأحداث.

**دع الأداة تملك النافذة.** تفتح [الأداة المضمّنة](/docs/multiple-users/connect-widget) النافذة
وتراقبها نيابةً عنك وتسلّم كل حدث أعلاه إلى معالجاتك. لا تزال تحصل على `success` لحظة حفظ
الحساب؛ أنت فقط لا تكتب التمديدات. كما أن إطاراتها تعني أن معظم الشبكات لا تفتح نافذة منبثقة
إطلاقًا حتى تسجيل دخول الشبكة نفسها.

**استطلع بدلًا من ذلك.** إذا كانت النافذة المنبثقة غير متاحة فعلًا — تطبيق يُعرض من الخادم،
أو تطبيق محمول يفتح الرابط في متصفح النظام — فاستطلع
[الحصول على Link Session](/docs/apis/profiles/get-link-session). فهو يبلّغ عن `completedAt`
و`completedNetworks` بمجرد حفظ الحساب، وهي اللحظة نفسها التي كان `connect:success` سيُرسل
فيها. يكتمل Telegram دائمًا بهذه الطريقة، لأنه يكتمل خارج النطاق دون أي استدعاء متصفح راجع.
