---
order: 5
section: guides
title: Runtime API
description: >-
  تعرف على دالة createScribe وواجهة العميل الكاملة: دوال القراءة، ومساعدات
  التوجيه، والعلاقات، وخريطة الموقع، وعمليات إعادة التوجيه، وكيفية التكامل مع
  أطر العمل.
noindex: false
canonicalPath: /ar/docs/runtime-api
---
```ts
import { createScribe } from "scribe-cms/runtime";
import config from "./scribe.config";

const scribe = createScribe(config);
```

تُرجع دالة `createScribe()` عميلاً مكتوباً (typed client) يوفر دالة وصول (accessor) واحدة لكل نوع من أنواع المحتوى (مثل `scribe.blog`، و `scribe.author`، وغيرها)، بالإضافة إلى `scribe.sitemap()`. تتم جميع عمليات القراءة بشكل متزامن ومن داخل الذاكرة: حيث يُحمَّل المحتوى مرة واحدة، ويُخزَّن مؤقتاً، ويُعاد التحقق منه (أثناء التطوير) عند حدوث أي تغيير في الملفات أو في مخزن الترجمات.

العميل مبني على بيئة Node النقية، ولا يعتمد على أي إطار عمل محدد. سيعمل بكفاءة تامة سواء استخدمته مع Next.js، أو Astro، أو Remix، أو SvelteKit، أو حتى في سكريبت بناء مستقل (build script)؛ والأمثلة المذكورة أدناه تستخدم نمط Next.js لغرض التوضيح فقط.

تأخذ المستندات الشكل التالي، مع العلم أن `frontmatter` يأخذ هيكله (typed) من مخطط Zod الخاص بك:

```ts
{
  slug: string;        // الـ slug في لغة المستند الحالية
  enSlug: string;      // الـ slug للمستند الإنجليزي الأصل (وهو نفسه الـ slug للمستندات الإنجليزية)
  locale: string;
  frontmatter: { ... };
  content: string;     // محتوى MDX الخام
  publishedAt?: string;
  updatedAt?: string;
  noindex: boolean;
}
```

## القراءة (Reading)

### `list(locale?, options?)`

تجلب جميع المستندات الخاصة بلغة معينة (الافتراضي: اللغة الافتراضية للنظام)، مرتبة بناءً على خاصية `orderBy` المحددة لهذا النوع من المحتوى.

```ts
scribe.blog.list("fr");
scribe.blog.list("fr", { limit: 3 });
scribe.blog.list("fr", { orderBy: "slug" });   // تجاوز الإعداد الافتراضي في هذا الاستدعاء فقط
```

تُرجع مصفوفة فارغة `[]` إذا لم تكن هناك مستندات متاحة لهذه اللغة.

### `get(slug, locale?)`

بحث دقيق باستخدام الـ slug في لغة واحدة فقط. لا تعتمد هذه الدالة على أي لغة بديلة (fallback) ولا تتعامل مع عمليات إعادة التوجيه. تُرجع المستند المطلوب، أو `null` إذا لم يُعثر عليه.

### `resolve(slug, locale)`

تتولى هذه الدالة المعالجة الشاملة لمسار الطلب، ويُفضل استخدامها داخل الصفحات:

```ts
const r = scribe.blog.resolve(slug, locale);
// {
//   document: BlogDoc | null,
//   actualLocale: string,        // "en" عند تفعيل اللغة الإنجليزية كبديل
//   shouldRedirectTo?: string,   // مسار التوجيه 301 (لتصحيح الـ slug بلغة خاطئة)
//   canonicalPath?: string,      // المسار المخصص للغة الخاصة بهذا المستند
// }
```

تُعالج الطلبات بالترتيب التالي: العثور على تطابق مباشر ← إعادة توجيه إذا كان الـ slug يتبع لغة أخرى ← [سلسلة اللغات البديلة](/docs/configuration#locale-fallback-chains) (مفعلة افتراضياً) ← استخدام الإنجليزية كبديل (إذا كان `indexFallback: "en"`). عندما تُعرض الصفحة باستخدام لغة بديلة، تكون `actualLocale` هي تلك اللغة البديلة، ويعتمد تصحيح الـ slug على سلسلة اللغات المحددة. لا تتولى دالة `resolve()` معالجة عمليات نقل الـ slug أو المستندات المحذوفة، بل تُدار هذه الحالات عبر قواعد `_redirects.json` داخل خريطة التوجيه الوكيل (proxy/static redirect map) الخاصة بك. إليك مثال نموذجي لمعالجة الصفحة (موضح باستخدام Next.js):

```ts
const resolved = scribe.blog.resolve(slug, locale);
if (resolved.shouldRedirectTo) permanentRedirect(resolved.shouldRedirectTo);
if (!resolved.document) notFound();
```

## دوال التوجيه المساعدة (Routing helpers)

### `staticParams(options?)`

تُنشئ كل زوج من `{ locale, slug }` ليُعرض مسبقاً (prerender)؛ يمكنك تمريرها مباشرة إلى دالة المسارات الثابتة الخاصة بإطار عملك (مثل `generateStaticParams` في Next.js، أو `getStaticPaths` في Astro، أو `entries` في SvelteKit):

```ts
export function generateStaticParams() {
  return scribe.blog.staticParams();
}

// تقييد اللغات (مثلاً لمسار صور OG يدعم الحروف اللاتينية فقط):
scribe.blog.staticParams({ locales: ["en", "fr", "de"] });
```

بالنسبة للغات التي لا تحتوي على ترجمة، فإن الـ slug المعروض مسبقاً يُستمد من أول لغة متوفرة في [سلسلة اللغات البديلة](/docs/configuration#locale-fallback-chains) (ثم من الـ slug الإنجليزي)، وبذلك تتطابق عناوين URL المعروضة مسبقاً مع ما تُقدمه دالة `resolve()`.

### `alternates(doc)`

تُولد خريطة hreflang للمستند (اللغة ← المسار النسبي) لكل لغة تتوفر لها ترجمة (مع تضمين اللغة الافتراضية دائماً):

```ts
scribe.blog.alternates(doc);
// { en: "/blog/hello-world", fr: "/fr/blog/bonjour-le-monde" }
```

مررها إلى وسوم hreflang الخاصة بك، كاستخدام `metadata.alternates.languages` في Next.js أو عناصر الربط (link elements) المبنية يدوياً.

### `translation(doc, targetLocale)`

تُرجع المستند نفسه بلغة أخرى، أو `null` إذا لم تكن الترجمة متوفرة. وعادةً ما تلجأ الدوال المستدعية للعودة إلى المستند الأصلي في حال عدم العثور على ترجمة:

```ts
const frDoc = scribe.blog.translation(doc, "fr") ?? doc;
```

### `url(slug, locale)`

تُنشئ مساراً باستخدام قالب `path` الخاص بنوع المحتوى:

```ts
scribe.blog.url("hello-world", "fr");  // "/fr/blog/hello-world"
```

ستُظهر كل من `staticParams` و `alternates` و `url` خطأ إذا اسُتخدمت مع أنواع محتوى مرجعية فقط (التي لا تحتوي على `path`).

## العلاقات (Relations)

### `related(doc, field, locale?)`

تستدعي (Dereferences) مستندات النوع المستهدف من حقل `field.relation()` الموجود في الـ frontmatter. يُستنتج نوع الإرجاع مباشرة من المخطط (schema):

```ts
scribe.blog.related(doc, "author");        // AuthorDoc           (علاقة مفردة إلزامية)
scribe.vertical.related(doc, "blogSlug");  // BlogDoc | null      (علاقة مفردة اختيارية)
scribe.glossary.related(doc, "terms");     // GlossaryDoc[]       (متعددة)
```

- تتم عملية الاستدعاء بناءً على `locale ?? doc.locale`، مع الرجوع للمستند الإنجليزي إذا كان المستهدف غير مترجم.
- العلاقات **الإلزامية** لا تُرجع أبداً `null`: فالأمر `scribe validate` يوقف عملية البناء عند العثور على علاقات إلزامية مفقودة، وتُظهر دالة `related()` خطأ إذا تسربت إحداها.
- العلاقات الاختيارية تُرجع `null`؛ أما العلاقات المتعددة فتتجاهل بصمت أي أهداف مفقودة.
- تُعرض فقط حقول المخطط الموجودة في المستوى الأعلى (الحقول المتداخلة تُراجع أيضاً، لكن ستحتاج لاستدعائها يدوياً).

## خريطة الموقع (Sitemap)

```ts
const entries = await scribe.sitemap({
  baseUrl: "https://example.com",
  typeDefaults: {
    blog: { priority: 0.7, changeFrequency: "monthly" },
  },
});
```

تُرجع مخرجات JSON مبسطة (تشمل `url`، و `lastModified`، و `changeFrequency`، و `priority`، و `alternates.languages` للـ hreflang متضمنة `x-default`)؛ وتتوافق هذه المخرجات مباشرة مع `MetadataRoute.Sitemap` في Next.js، ويمكن تحويلها بسهولة إلى صيغة XML لأي نظام آخر. تُنشئ مُدخلة واحدة لكل مستند إنجليزي لجميع الأنواع التي تدعم التوجيه (routable)؛ مع استبعاد المستندات التي تحمل إشارة `noindex`، وعمليات إعادة التوجيه (redirect source slugs) الموجودة في `_redirects.json`.

الخيارات المتاحة: `baseUrl` (مطلوب)، `contentTypes`، `typeDefaults`، `resolveUrl`، `resolvePathname`، `excludeNoindex` (مفعل افتراضياً)، `includeXDefault` (مفعل افتراضياً).

## الفحص الذاتي (Introspection)

بالإضافة إلى دوال الوصول الخاصة بكل نوع محتوى، يُتيح العميل استعراض الإعدادات التي تم حلّها (resolved config):

```ts
scribe.config;              // يُرجع ScribeConfig المعتمد
scribe.getType("blog");     // يعرض خصائص نوع محتوى واحد
scribe.listTypes();         // يسرد جميع أنواع المحتوى
scribe.listRoutableTypes(); // يعرض فقط أنواع المحتوى التي تمتلك مساراً (path template)
```

مفيد جداً لبناء أدوات عامة، مثل تكرار أنواع المحتوى التي تدعم التوجيه لإنشاء قوائم التنقل (navigation) أو الخلاصات (feeds).

## عمليات إعادة التوجيه (Redirects)

لإدارة قواعد إعادة التوجيه المصدّرة بشكل ثابت (`_redirects.json`، ومسارات الـ slugs عبر اللغات المختلفة)، استخدم نقطة إدخال سكريبت البناء:

```ts
// scripts/generate-redirects.ts (شغّل هذا السكريبت قبل بناء التطبيق)
import {
  buildAllContentRedirects,
  createProject,
  createUrlBuilder,
  loadConfigSync,
} from "scribe-cms";

const config = loadConfigSync();
const project = createProject(config);
const urlBuilder = createUrlBuilder(project.config);
const rules = buildAllContentRedirects(project, {
  prefixedLocales: urlBuilder.prefixedLocales,
});
// [{ source, destination, permanent: true }, ...]
// تتطابق مباشرة مع إعدادات إعادة التوجيه في Next.js؛ يمكنك تعيينها لقواعد nginx أو _redirects أو
// vercel.json، أو ما يعادلها في إطار العمل الخاص بك حسب الحاجة.
```

## التصدير الخام الثابت (Static raw exports)

لإنشاء ملفات MDX خام ثابتة وصديقة لنماذج اللغة الكبيرة (LLMs) أو عناكب البحث (مثل: `/blog/my-post.mdx`):

```bash
scribe export-static --out public
```

أو يمكنك القيام بذلك برمجياً:

```ts
import { writeStaticRawExports, createProject, loadConfigSync } from "scribe-cms";

writeStaticRawExports(createProject(loadConfigSync()), { outDir: "public" });
```

تُرجع دالة `getStaticExportRoots(project)` الجذور المُدارة للأدلة لتنظيفها قبل الكتابة (مثل `blog/`، و `fr/blog/`). تُستثنى المستندات المُدرجة كمصادر لإعادة التوجيه في `_redirects.json` إذا كان الخيار `excludeRedirected` مفعّلاً (وهو الافتراضي). وتُضمَّن مستندات `noindex` ما لم يُحدد الخيار `excludeNoindex`. راجع [دليل سطر الأوامر (CLI)](/docs/cli) لمعرفة تفاصيل الأعلام (flags) المتاحة.

## دوال الطوارئ (Escape hatch)

تُرجع دالة `scribe.<type>.load()` الفهرس الخام بصيغة `Map<locale, { bySlug, byEnSlug }>` مباشرةً. نوصي باستخدام `list` أو `get` أو `resolve`؛ حيث وُجدت دالة `load()` لتخدم الأدوات المتخصصة أو أنماط الوصول غير التقليدية.

## التكامل مع أطر العمل (Framework integration)

لا يعتمد Scribe على أي إطار عمل بعينه؛ فبيئة التشغيل الخاصة به تعمل بـ Node النقية وتتناسب مع أي تقنية مبنية على الخوادم (server-rendered) أو مبنية بشكل ثابت (statically-built). هناك ثلاث قواعد رئيسية تنطبق في كل مكان:

1. عند كتابة كود التطبيق، استورد الأدوات من **`scribe-cms/runtime`** (مما يمنع أدوات التجميع من تتبع أكواد مترجم أو واجهة سطر الأوامر)؛ واستخدم `scribe-cms` ضمن سكريبتات البناء.
2. تأكد من إبقاء **`better-sqlite3`** (وهي وحدة أصلية) و Scribe كأدوات خارجية بالنسبة لأداة التجميع الخاصة بك، مثلاً استخدم `serverExternalPackages` في Next.js، أو `ssr.external` في Vite/Astro، أو `external` في esbuild.
3. قم بتخزين العميل في ذاكرة التخزين المؤقت عبر نمط module singleton:

```ts
// src/lib/scribe.ts
import { createScribe } from "scribe-cms/runtime";
import type { ScribeClient } from "scribe-cms/runtime";
import config from "../../scribe.config";

let cached: ScribeClient<typeof config> | null = null;
export function getScribe() {
  return (cached ??= createScribe(config));
}
```

اربط عمليات البناء بمدى سلامة المحتوى باستخدام الأمر: `"build": "scribe validate && <framework build>"`.

### مثال مع Next.js

```ts
// next.config.ts
const nextConfig = {
  serverExternalPackages: ["better-sqlite3", "scribe-cms", "scribe-cms/runtime"],
  // خطوة مطلوبة في Vercel: لأن Scribe يقرأ المجلدات content/ و .scribe/ في وقت التشغيل.
  outputFileTracingIncludes: {
    "/**": ["./content/**/*", "./.scribe/**/*"],
  },
  // خطوة مطلوبة أيضاً في Vercel: تمنع أداة تتبع الملفات في بيئة تشغيل Scribe 
  // من نسخ ملفات الكاش (cache) الخاصة بـ Next إلى كل دالة Serverless،
  // لتفادي تجاوز حد الـ 250 ميغابايت. حيث أن هذه الملفات غير ضرورية إطلاقاً في وقت التشغيل.
  outputFileTracingExcludes: {
    "/**": ["./.next/cache/**"],
  },
};
```

تُدمج دالة `staticParams()` مع `generateStaticParams()`، ودالة `alternates()` مع `metadata.alternates.languages`، و `scribe.sitemap()` في ملف `app/sitemap.ts`، و `buildAllContentRedirects()` ضمن `redirects()`.
