نقدّم لكم حزم SDK الخاصة بـ SupDesk

SupDesk Team

كل منتج جاد يصل في نهاية المطاف إلى كتابة طبقة تكامل — سكربت يقرأ من صندوق الوارد، أو وظيفة cron تزامن لوحة عمل، أو نقطة نهاية ترصد الملاحظات القادمة من واجهتك الخاصة.

وحدة تحكّم ‏SupDesk ممتازة عندما تكون أمام لوحة المفاتيح، لكن ما إن تريد أتمتة الأمر حتى تحتاج إلى API، ولا تكون ‏API أفضل من العملاء المتاحين للحديث إليها.

واليوم نُطلق أربعة منها.

تعرّف على حزم SDK

  • JavaScript / TypeScript — حزمة supdesk على npm. تعمل دون أي تعديل على Node 18+ وDeno وBun وCloudflare Workers، ودون أي تبعيات في وقت التشغيل.
  • Python — حزمة supdesk على PyPI. عميل متزامن واحد SupDesk وعميل غير متزامن واحد AsyncSupDesk يتشاركان نواة httpx واحدة.
  • Go — حزمة github.com/rabinapps/supdesk-go. المكتبة القياسية فقط، لذلك تُبنى في أي مكان يعمل فيه Go 1.23+ — بما في ذلك Cloudflare Workers عبر GOOS=wasip1.
  • Dart — حزمة supdesk على pub.dev. مبنية على dio، لذلك تعمل الاعتراضات وCancelToken ومحوّلات الوكلاء (proxy adapters) بالطريقة التي تتوقعها أصلًا.

التثبيت

npm install supdesk
pip install supdesk
go get github.com/rabinapps/supdesk-go
dependencies:
  supdesk: ^0.1.0

API واحدة، أربع لغات

الحزم ليست أربع طبقات تغليف منفصلة؛ بل هي نفس ‏API بنفس الدلالات في كل لغة. إذا تمكنت من قراءة الإرساليات بلغة واحدة، فستقرؤها باللغات الأربع جميعًا.

الترقيم التلقائي. يُرجع list() صفحة هي أيضًا متكرِّر غير متزامن (async iterable) — تجوّل عبر كل الصفحات باستخدام for await، أو اسحب الصفحة الأولى فقط عندما يكون هذا كل ما تحتاجه.

الموارد الموجّهة بالأنواع. الإرساليات والملاحظات ومدخلات سجل التغييرات والرسائل والتسجيلات في قائمة الانتظار وبرامج الاختبار التجريبي والمختبرين ومقالات مركز المساعدة وتصنيفاته — كلٌّ منها بالطرق والمعاملات الموجّهة بالأنواع التي تتوقعها، بحيث تفشل الأخطاء المطبعية وقت الترجمة بدلًا من بيئة الإنتاج.

الأخطاء الموجّهة بالأنواع. ينحدر كل فشل من أساس واحد — SupDeskError في JS وPython، وAPIError في Go، وSupDeskException في Dart — فيكفي catch واحد للتعامل معها جميعًا بينما يظل instanceof أو errors.As يحدد الحالة الخاصة بدقة.

Webhooks. تتحقق constructEventFromRequest وconstruct_event_from_headers وConstructEvent وconstructEventFromHeaders من توقيع ‏SupDesk في وقت ثابت، حتى تطمئن إلى ما يتصرف بناءً عليه المتلقي لديك.

مرونة مدمجة. يعيد كل عميل المحاولة مع تأجيل أُسّي وتشتيت (jitter)، ويحترم Retry-After، ولا يعيد أبدًا محاولة طلب POST مُقاس ربما يكون قد قبله بالفعل — فلا تستطيع شبكة متقلبة أن تُكرّر إرسال تذكرة المستخدم.

صُممت من جهة الخادم

تصادق مفاتيح ‏SupDesk للـ API على هوية مشروعك بالكامل، لذلك ترفض الحزم العمل في المتصفح — ترمي مُنشئات ‏JS وDart استثناءً إذا رصدت وجود DOM أو بناءً مخصصًا للعميل، وتكون ملفات README صريحة في توضيح السبب. أبقِ المفتاح في متغير بيئة من جهة الخادم، خلف نقطة نهاية تتحكم فيها.

أمران آخران جديران بالمعرفة: تعمل القراءات على كل الخطط، بينما تتطلب الكتابات (POST/PATCH/DELETE) خطة مدفوعة؛ والمفاتيح مقيّدة بالمشروع، لذلك امنح كل بيئة مفتاحها الخاص وستتمكن من إبطال واحد منها دون المساس بالباقي.

أين يتناسب SupDesk

تُشكّل الحزم النصف الخلفي من دليل دمج ‏SupDesk لمنتجات ‏SaaS — دعم متعدد المستأجرين، ووصول عبر ‏API، وwebhooks للمنتجات التي تريد دعمًا مدمجًا في أنظمتها الخاصة. والمرجع الكامل موجود في توثيق ‏API.

ابدأ الآن

احصل على مفتاح ‏API من إعدادات مساحة العمل ← مفاتيح ‏API، وثبّت العميل المناسب لتقنيتك، ونفّذ دليل البدء السريع في هذه الصفحة. ثم استنسخ المستودع واقرأ ملف ‏README.

ابدأ على ‏supdesk.app

أدوات SDK من جانب الخادم لتكامل الواجهة الخلفية

أمثلة برمجية مباشرة مأخوذة من مستودع GitHub لكل SDK.

RabinApps/supdesk-nodeJavaScript / TypeScript
import { SupDesk } from "supdesk";

const supdesk = new SupDesk({ apiKey: process.env.SUPDESK_API_KEY! });

// Auto-pages: iterating walks every page for you.
for await (const submission of await supdesk.submissions.list({
  status: "open",
})) {
  console.log(submission.title);
}

await supdesk.submissions.create({
  type: "bug",
  title: "Export button does nothing",
  email: "user@example.com",
  body: "Clicking Export on the reports page has no effect.",
});
RabinApps/supdesk-pythonPython
from supdesk import SupDesk

supdesk = SupDesk()  # api_key=... or $SUPDESK_API_KEY

# Auto-pages: iterating walks every page for you.
for submission in supdesk.submissions.list(status="open"):
    print(submission.title)

supdesk.submissions.create(
    type="bug",
    title="Export button does nothing",
    email="user@example.com",
    body="Clicking Export on the reports page has no effect.",
)
RabinApps/supdesk-goGo
import "github.com/rabinapps/supdesk-go/supdesk"

client, err := supdesk.New(os.Getenv("SUPDESK_API_KEY"))
if err != nil {
    log.Fatal(err)
}

page, err := client.Submissions.List(ctx, supdesk.SubmissionsListParams{
    Status: ptr("open"),
})
if err != nil {
    return err
}
// Auto-pages: All walks every page for you.
for sub, err := range page.All(ctx) {
    if err != nil {
        return err
    }
    fmt.Println(sub.Title)
}

_, err = client.Submissions.Create(ctx, supdesk.SubmissionsCreateParams{
    Type:  supdesk.SubmissionTypeBug,
    Title: "Export button does nothing",
    Email: "user@example.com",
    Body:  "Clicking Export on the reports page has no effect.",
})
RabinApps/supdesk-dartDart
import 'dart:io';
import 'package:supdesk/supdesk.dart';

final supdesk = SupDesk(apiKey: Platform.environment['SUPDESK_API_KEY']!);

// Auto-pages: the stream walks every page for you.
final page = await supdesk.submissions.list(status: PostStatus.open);
await for (final submission in page.autoPaging()) {
  print(submission.title);
}

await supdesk.submissions.create(
  type: SubmissionType.bug,
  title: 'Export button does nothing',
  email: 'user@example.com',
  body: 'Clicking Export on the reports page has no effect.',
);

الوسوم

#sdk#api#developers