# JavaScript kütüphanesi (`noluyo-bot`)

`noluyo-bot`, N'oluyo bot platformu için geliştirilmiş resmi JavaScript ve TypeScript kütüphanesidir. **Node.js 22 veya üstü** üzerinde sıfır çalışma zamanı bağımlılığıyla çalışır (yerleşik `fetch`, `WebSocket`, `FormData` ve `node:crypto` kullanır), tam `.d.ts` tip tanımlarıyla gelir ve MIT lisanslıdır.

## Kurulum

Proje klasöründe `package.json` dosyanın `"type": "module"` kullandığından emin ol ve paketi kur:

```bash
npm install noluyo-bot
# Yalnızca ses kanallarında yayın yapacaksan isteğe bağlı ek paket:
npm install @livekit/rtc-node@^1.2.1
```

> **Not:** Sıfırdan proje klasörü ve `.env` kurulumu için [Kurulum](https://noluyo.net/gelistirici/kurulum.md) rehberini adım adım izleyebilirsin.

## İlk bot

Token'ı kaynak koda yazma; `.env` dosyasındaki `BOT_TOKEN` değişkeninden oku ve `node --env-file=.env bot.mjs` ile çalıştır:

```js title=bot.mjs
import { Client, Intents } from "noluyo-bot";

const bot = new Client({
  token: process.env.BOT_TOKEN,
  intents: Intents.GUILDS | Intents.GUILD_MESSAGES | Intents.MESSAGE_CONTENT,
});

bot.on("READY", (ready, meta) => {
  console.log(`${ready.user.username} bağlandı (shard ${meta.shardId})`);
});

bot.on("MESSAGE_CREATE", async (message) => {
  if (message.author.bot) return;
  if (message.content === "!merhaba") {
    await bot.rest.createMessage(message.channel_id, { content: "Merhaba!" });
  }
});

bot.interactions.on("ping", async (i) => {
  await i.reply({ content: "Pong!", ephemeral: true });
});

await bot.login();
await bot.commands.sync([
  { name: "ping", description: "Botun yanıt verip vermediğini sınar" },
]);
```

Kapatırken açık WebSocket ve ses bağlantılarını temizlemek için `await bot.close()` çağrılır. `new Client({ token, intents, applicationId, baseUrl, presence })` yapılandırıcısı isteğe bağlı olarak `applicationId` (`bot.login()` öncesinde komut eşitlemek istersen), `baseUrl` ve başlangıç `presence` nesnesini kabul eder. İzin bitleri için `Permissions` nesnesi hem `Permissions.ModerateMembers` hem `Permissions.MODERATE_MEMBERS` biçiminde `BigInt` sabitleri sunar (`String(Permissions.ModerateMembers)` ile ondalık dizgeye çevrilir).

## Gateway olayları ve durum yönetimi

`bot.on(olayAdi, dinleyici)` ile [Gateway](https://noluyo.net/gelistirici/gateway.md) üzerindeki tüm dağıtım olaylarını dinlersin. İkinci parametre `(data, meta)` içinde `meta.shardId` ve `meta.seq` gelir:

- **Bağlantı ve sunucular:** `READY`, `RESUMED`, `GUILD_CREATE`, `GUILD_UPDATE`, `GUILD_DELETE`
- **Mesajlar ve tepkiler:** `MESSAGE_CREATE`, `MESSAGE_UPDATE`, `MESSAGE_DELETE`, `MESSAGE_REACTION_ADD`, `MESSAGE_REACTION_REMOVE`
- **Üyeler, roller ve kanallar:** `GUILD_MEMBER_ADD`, `GUILD_MEMBER_UPDATE`, `GUILD_MEMBER_REMOVE`, `CHANNEL_CREATE`, `CHANNEL_UPDATE`, `CHANNEL_DELETE`, `GUILD_ROLE_CREATE`, `GUILD_ROLE_UPDATE`, `GUILD_ROLE_DELETE`
- **Etkileşim ve ses:** `INTERACTION_CREATE`, `VOICE_STATE_UPDATE`, `VOICE_SERVER_UPDATE`, `VOICE_JOIN_ERROR`

Durum güncellemek için `bot.setPresence("online", [{ name: "/yardim", type: 0 }])`, büyük sunucuda üye aramak için `bot.requestGuildMembers(guildId, { query: "ada", limit: 25 })` yardımcılarını kullanabilirsin. İhtiyacın olan bitleri [Intent'ler](https://noluyo.net/gelistirici/intentler.md) tablosundan seçip `Intents` bayraklarıyla birleştir.

## REST çağrıları (`bot.rest`)

OpenAPI şemasındaki her `operationId`, `bot.rest` üzerinde `camelCase` adıyla hazır bir metottur. Yol parametreleri sırayla ilk argümanlar olarak, JSON gövdesi veya sorgu parametreleri son nesne olarak verilir:

```js
// Basit mesaj ve embed gönderme:
await bot.rest.createMessage(channelId, {
  content: "Haftalık özet hazır.",
  embeds: [{ title: "Özet", description: "12 yeni üye katıldı.", color: 0x3366ff }],
});

// Dosya ekiyle birlikte attachment:// görselli embed gönderme:
import { readFile } from "node:fs/promises";
await bot.rest.createMessage(channelId, {
  embeds: [{ title: "Grafik", image: { url: "attachment://grafik.png" } }],
  files: [{ name: "grafik.png", data: await readFile("./grafik.png"), contentType: "image/png" }],
});

// Üyeye rol verme ve 10 dakikalık zaman aşımı uygulama:
await bot.rest.addMemberRole(guildId, userId, roleId);
await bot.rest.updateMember(guildId, userId, {
  communication_disabled_until: new Date(Date.now() + 10 * 60_000).toISOString(),
});
```

Gateway bağlantısı açmadan yalnızca HTTP çağrısı yapmak istediğinde `import { Rest } from "noluyo-bot"` ile doğrudan `new Rest({ token: process.env.BOT_TOKEN })` oluşturabilirsin. Zengin mesaj sınırları [Embed'ler](https://noluyo.net/gelistirici/embedler.md) rehberindedir.

## Komut kaydı ve etkileşimler

`bot.commands.sync(liste)` metodu `PUT /applications/{id}/commands` rotasını çağırarak tüm küresel komutlarını tek adımda eşitler (`{ guildId }` verirsen yalnızca o sunucunun komutlarını günceller). `bot.login()` sonrasında `bot.applicationId` otomatik dolduğu için ayrıca kimlik yazman gerekmez.

`bot.interactions.on(adVeyaKalip, isleyici)` hem eğik çizgi komutlarını (`name`), hem [Bileşenler](https://noluyo.net/gelistirici/bilesenler.md) üzerindeki `custom_id` değerlerini, hem de [Formlar](https://noluyo.net/gelistirici/formlar.md) gönderimlerini yakalar; dize yerine `RegExp` (`/ ^rol:/ `) de verebilirsin:

```js
bot.interactions.on("duyuru", async (i) => {
  const baslik = i.option("baslik");
  await i.defer({ ephemeral: true });
  await bot.rest.createMessage(i.channel_id, {
    embeds: [{ title: String(baslik), description: "Yeni duyuru yayınlandı." }],
  });
  await i.editReply({ content: "Duyuru kanala gönderildi." });
});

bot.interactions.on(/^anket:/, async (i) => {
  const secim = i.data.custom_id.split(":")[1];
  await i.reply({ content: `Oyun kaydedildi: ${secim}`, ephemeral: true });
});
```

`InteractionContext` üzerindeki veri alanları (`i.id`, `i.guild_id`, `i.channel_id`, `i.member`, `i.user`, sunucu veya DM fark etmeksizin tetikleyen kullanıcıyı veren `i.person`, `i.data`) ve yardımcılar: `i.option(ad)`, `i.fields()`, `i.reply()`, `i.defer({ ephemeral })`, `i.deferUpdate()`, `i.update()`, `i.editReply()`, `i.deleteReply()`, `i.followUp()`, `i.showModal()` ve [Otomatik tamamlama](https://noluyo.net/gelistirici/otomatik-tamamlama.md) için `i.autocomplete(secenekler)`. Tüm etkileşim türlerinin kuralları [Komutlar](https://noluyo.net/gelistirici/komutlar.md) ve [Etkileşimler](https://noluyo.net/gelistirici/etkilesimler.md) sayfalarında yer alır.

## HTTP modu ve imza doğrulama

Etkileşimleri WebSocket yerine kendi HTTPS sunucundan alıyorsan ([HTTP ile teslim](https://noluyo.net/gelistirici/http-teslim.md)), gelen her isteğin Ed25519 imzasını ek paket kurmadan `verifyInteraction` ile doğrula:

```js
import { verifyInteraction } from "noluyo-bot";

const gecerli = verifyInteraction(
  process.env.NOLUYO_PUBLIC_KEY,
  req.headers["x-signature-ed25519"],
  req.headers["x-signature-timestamp"],
  rawBodyBuffer,
);
if (!gecerli) {
  res.writeHead(401).end("invalid signature");
  return;
}
```

## Ses kanallarında yayın (`bot.voice`)

`@livekit/rtc-node@^1.2.1` kurulu olduğunda `bot.voice.join(guildId, channelId)` senin yerine gateway `op 4` gönderir, `VOICE_SERVER_UPDATE` yanıtını bekler ve yayın odasına bağlanır:

```js
const conn = await bot.voice.join(guildId, voiceChannelId);
await conn.playFile("./muzik.mp3"); // Yerel ses dosyasını 48 kHz PCM olarak yayınlar
await conn.leave();
```

N'oluyo'da botlar seste **yalnızca yayın yapar** (`canSubscribe: false`); kütüphane hiçbir zaman ses aboneliği açmaz ve konuşulanları duyamaz. Ses sınırları ve `VOICE_JOIN_ERROR` kodları [Ses](https://noluyo.net/gelistirici/ses.md) rehberindedir.

## Hız sınırı kuyruğu, yeniden deneme ve shard davranışı

Kütüphane platform kurallarını varsayılan olarak uygular:

- **Kova kuyruğu:** `X-RateLimit-Bucket`, `X-RateLimit-Remaining` ve `X-RateLimit-Reset-After` başlıklarını izler; aynı kovaya giden istekleri sırayı bozmadan bekletir ([Hız sınırları](https://noluyo.net/gelistirici/rate-limit.md)).
- **`429` ve ortak tavan:** `429` yanıtında `Retry-After` süresince bekleyip isteği tekrarlar; `X-RateLimit-Scope: shared` geldiğinde tüm rotaları birlikte yavaşlatır.
- **Güvenli yeniden deneme:** `5xx` sunucu hatalarında yalnızca `GET` isteklerini en çok 3 kez yeniden dener; `POST`, `PATCH`, `PUT` ve `DELETE` yazma isteklerini çift mesaj oluşmaması için tekrarlamaz.
- **Shard ve sürdürme (`RESUME`):** `bot.login()` önerilen shard sayısını `GET /gateway/bot` ucundan alır ve `IDENTIFY` çerçevelerini en az **5,1 saniye** arayla gönderir ([Shard'lar](https://noluyo.net/gelistirici/shardlar.md)). Bağlantı koptuğunda `op 6` (`RESUME`) ile kaçan olayları tamamlar.
- **Kalıcı kapanış koruması ve token gizleme:** `4004` (geçersiz token) veya `4014` (onaysız ayrıcalıklı intent) gibi `reconnect: false` kapanış kodlarında sonsuz döngüye girmez; portal yönlendirmesi içeren `GatewayCloseError` fırlatır. Hata mesajlarında, `JSON.stringify` ve `util.inspect` çıktılarında bot token'ı otomatik olarak `[REDACTED]` ile maskelenir.

## Hata sınıfları, test ve sürüm politikası

Yakalamak için dışa aktarılan hata sınıfları:

- `ApiError`: `4xx`/`5xx` yanıtları (`err.status`, `err.code`, `err.errors`, `err.path`)
- `RateLimitedError`: yeniden deneme tavanı aşıldığında dönen `429` hatası (`err.retryAfter`, `err.scope`)
- `GatewayCloseError`: yeniden bağlanılmaması gereken gateway kapanışı (`err.code`, `err.closeName`, `err.hint`)
- `VoiceJoinError`: ses kanalına katılma reddi (`err.code`, `err.guildId`)

Birim testlerinde `new Rest({ token: "test", fetch: sahteFetch })` ile gerçek ağa çıkmadan REST çağrılarını sınayabilirsin. Kütüphane anlamsal sürümleme (SemVer) izler; OpenAPI veya olay şemasına yeni alan eklendiğinde geriye dönük uyumlu küçük sürüm (`0.x`) çıkar.

Tam çalışan örnek projeler depoda hazır bulunur:

- `sdks/examples/js/moderasyon`: sözcük süzgeci, `/sustur` zaman aşımı komutu ve denetim embed'i
- `sdks/examples/js/anket`: süreli buton oylaması
- `sdks/examples/js/muzik`: yerel ses dosyası çalan ses botu
- `sdks/examples/js/oauth-site`: PKCE tabanlı "N'oluyo ile giriş" web sunucusu

## Bu sayfayı yapay zekaya verirsen

> **İpucu:** Yapay zekaya Node.js ile N'oluyo botu yazdırırken bu sayfayı ver ve şu kuralları hatırlat:
>
> - Yalnızca `import { Client, Intents } from "noluyo-bot"` kullanılır; başka sohbet platformlarının paketleri kurulmaz.
> - Node.js 22+ yerleşik `--env-file=.env` bayrağıyla çalışır; `dotenv` bile şart değildir ve `BOT_TOKEN` asla koda yazılmaz.
> - `bot.rest.<camelCaseOperationId>` metotları doğrudan OpenAPI `operationId` adlarını taşır (`createMessage`, `editMessage`, `addMemberRole`, `updateMember`).
> - Embed görselleri yalnızca `files` dizisiyle yüklenen dosyalara `attachment://dosya.png` ile bağlanır.

## Sırada ne var

- [Hazır tarifler](https://noluyo.net/gelistirici/tarifler.md): `noluyo-bot` ile yazılmış 9 kopyala-çalıştır bot tarifi
- [Python kütüphanesi](https://noluyo.net/gelistirici/kutuphane-python.md): aynı özelliklerin Python `asyncio` karşılığı
- [Botu açık tut](https://noluyo.net/gelistirici/botu-acik-tut.md): Node.js botunu Linux sunucuda `systemd` ile 7/24 çalıştırma
