İçeriğe geç
Dokümanlar

Manifest referansı

module.json dosyasının taşıyabileceği her blok. Yalnızca ilk beşi zorunlu.

Kimlik

{
  "id": "my-module",
  "name": "My Module",
  "description": "Tek satır; marketplace'te ve katalogda görünür.",
  "version": "1.0.0",
  "coreVersion": "^2.1.0",
  "category": "content",
  "icon": "Package",
  "author": "Adın"
}

id, klasör adıyla aynı olmalı ve küçük harfli bir slug olmalı. coreVersion, çekirdeğin modüle bakan API sürümü üzerinde bir semver aralığıdır; platform, çalışan çekirdeğin karşılamadığı bir aralığa sahip modülü kurmayı ve etkinleştirmeyi reddeder.

Sayfalar ve ekranlar

{
  "routes": [
    { "path": "notices", "component": "pages/page.tsx", "titleKey": "notices.pageTitle" },
    { "path": "notices/[id]", "component": "pages/[id]/page.tsx", "resolver": "lib/notice-exists.ts" }
  ],
  "adminRoutes": [
    { "path": "/notices", "component": "pages/admin/page.tsx" }
  ],
  "menu": [
    { "label": "Notices", "path": "/notices", "icon": "Megaphone", "group": "content", "section": "publishing" }
  ]
}

Dinamik bir açık route'un resolver'a ihtiyacı vardır: o adresteki şeyin var olup olmadığını söyleyen bir fonksiyon export eden dosya. Olmadığında sayfa 200 ile "burada bir şey yok" çizer, ve bu bir tarayıcıya sayfanın gerçek olduğunu söyler.

menu.group, ekranın hangi yönetim grubuna ait olduğu; menu.section ise o grubun içindeki hangi bölüme ait olduğudur. İkisini de bildirmeyen bir modül, bir operatörün ya tesadüfen bulacağı ya da hiç bulamayacağı bir çekmeceye düşer.

Endpoint'ler

{
  "api": [
    { "path": "notices", "handler": "api/route.ts", "method": "ALL",
      "rateLimit": { "maxRequests": 60, "windowMs": 60000 } },
    { "path": "webhook/acme", "handler": "api/webhook/route.ts", "providerCallback": true }
  ]
}

Veri değiştiren metodlar proxy tarafından CSRF kontrolünden geçer. Modülüne geri çağrı yapan bir sağlayıcı CSRF token taşıyamaz; bu yüzden providerCallback bildirir ve bunun yerine sabit bir ilk yol parçası alır.

İzinler ve veri

{
  "permissions": ["notices.view", "notices.manage"],
  "permissionResources": [{ "type": "notice", "label": "Notice" }],
  "userDataExport": ["Notice"]
}

İzinler, modül kurulduğunda rol düzenleyicide belirir ve kaldırıldığında oradan çıkar. userDataExport, bir kişiye ait tabloları adlandırır; böylece bir veri dışa aktarma talebi, kimsenin bu modülün varlığını hatırlamasına gerek kalmadan doğru cevaplanır.

Başka şeyleri genişletmek

{
  "hooksEmitted": [{ "name": "notice.published", "description": "Bir duyuru yayına girdikten sonra" }],
  "hookListeners": [{ "hook": "user.registered", "handler": "lib/on-register.ts" }],
  "slots": [{ "name": "notices.aboveList" }],
  "slotContents": [{ "slot": "layout.top", "component": "components/Banner.tsx" }],
  "pageBlocks": [{ "id": "notice-list", "component": "components/blocks/List.tsx", "category": "content" }],
  "cronJobs": [{ "name": "expire-notices", "schedule": "0 * * * *", "handler": "lib/expire.ts" }]
}

Bir modülün yaydığı hook tiplidir: çekirdek payload tiplerini bu bildirimlerden üretir, yani hook'un göndermediği bir alanı okuyan bir dinleyici üretimde undefined okumak yerine tip kontrolünde patlar.

Metinler

{
  "translations": {
    "en": { "notices": { "pageTitle": "Notices" } },
    "tr": { "notices": { "pageTitle": "Duyurular" } }
  }
}

Platformun getirdiği her dil, her seferinde. Kurulumda çeviri tablosuna senkronlanırlar, ve bir yöneticinin onlar üzerindeki düzenlemeleri hem güncellemeden hem kaldırmadan sağ çıkar.

Doğrulayıcı neyi reddeder

  • Klasörle eşleşmeyen ya da ayrılmış bir kelime olan id
  • İçinde /admin geçen bir yönetim yolu (öneki çekirdek ekler)
  • Modül klasörünün dışını gösteren bir dosya referansı
  • SDK yerine @/core/lib/* import etmek
  • Resolver'ı olmayan dinamik bir açık route
  • Kurulu hiçbir modülün karşılayamayacağı bir bağımlılık aralığı
  • Payload'ı, hook'un bildirdiğiyle uyuşmayan bir hook dinleyicisi