social-agent-cli 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1083 @@
1
+ # Bluesky Platform Bilgisi
2
+
3
+ Bluesky, AT Protocol (Authenticated Transfer Protocol) üzerine kurulu merkezi olmayan bir sosyal ağdır.
4
+ API tamamen ücretsiz ve açıktır, herhangi bir geliştirici onayı veya OAuth uygulaması gerekmez.
5
+ Tüm işlemler XRPC (Cross-RPC) endpoint'leri üzerinden yapılır.
6
+
7
+ ---
8
+
9
+ ## 1. Kimlik Doğrulama (Authentication)
10
+
11
+ ### 1.1 createSession — Giriş Yapma
12
+
13
+ ```
14
+ POST https://bsky.social/xrpc/com.atproto.server.createSession
15
+ Content-Type: application/json
16
+
17
+ {
18
+ "identifier": "kullanici.bsky.social", // handle veya DID
19
+ "password": "xxxx-xxxx-xxxx-xxxx" // App Password önerilir
20
+ }
21
+ ```
22
+
23
+ **Yanıt:**
24
+ ```json
25
+ {
26
+ "accessJwt": "eyJ...", // 2 saat geçerli
27
+ "refreshJwt": "eyJ...", // 90 gün geçerli
28
+ "handle": "kullanici.bsky.social",
29
+ "did": "did:plc:abc123...",
30
+ "email": "user@example.com",
31
+ "emailConfirmed": true
32
+ }
33
+ ```
34
+
35
+ **Önemli notlar:**
36
+ - `identifier` alanına handle (kullanici.bsky.social) veya DID (did:plc:...) yazılabilir.
37
+ - Hesap şifresi yerine **App Password** kullanılması şiddetle önerilir. Hesap ayarları > App Passwords > Yeni oluştur.
38
+ - App Password ile 2FA (iki faktörlü doğrulama) aktifken bile giriş yapılabilir.
39
+ - App Password ile hesap silme, şifre değiştirme gibi kritik işlemler yapılamaz — güvenlik sağlar.
40
+
41
+ ### 1.2 Token Yenileme (Refresh Flow)
42
+
43
+ Access token süresi dolduğunda (2 saat), refresh token ile yenilenir:
44
+
45
+ ```
46
+ POST https://bsky.social/xrpc/com.atproto.server.refreshSession
47
+ Authorization: Bearer <refreshJwt>
48
+ ```
49
+
50
+ **Yanıt:** Yeni `accessJwt` ve `refreshJwt` döner. Eski refresh token geçersiz olur (rotation).
51
+
52
+ **Token akışı:**
53
+ 1. `createSession` ile giriş yap → accessJwt + refreshJwt al
54
+ 2. Tüm isteklerde `Authorization: Bearer <accessJwt>` kullan
55
+ 3. 401 hatası alınca `refreshSession` ile yeni token al
56
+ 4. Refresh token da süresi dolduysa tekrar `createSession` çağır
57
+
58
+ ### 1.3 Oturumu Sonlandırma
59
+
60
+ ```
61
+ POST https://bsky.social/xrpc/com.atproto.server.deleteSession
62
+ Authorization: Bearer <refreshJwt>
63
+ ```
64
+
65
+ ---
66
+
67
+ ## 2. API Endpoint'leri (XRPC)
68
+
69
+ Tüm endpoint'ler `https://bsky.social/xrpc/` altındadır. Base URL PDS (Personal Data Server) adresine göre değişebilir, ancak `bsky.social` varsayılan ve en yaygın PDS'dir.
70
+
71
+ ### 2.1 Post İşlemleri
72
+
73
+ #### Post Oluşturma
74
+
75
+ ```
76
+ POST /xrpc/com.atproto.repo.createRecord
77
+ Authorization: Bearer <accessJwt>
78
+ Content-Type: application/json
79
+
80
+ {
81
+ "repo": "<did>",
82
+ "collection": "app.bsky.feed.post",
83
+ "record": {
84
+ "$type": "app.bsky.feed.post",
85
+ "text": "Merhaba Bluesky!",
86
+ "createdAt": "2026-03-14T12:00:00.000Z",
87
+ "langs": ["tr"],
88
+ "facets": [],
89
+ "embed": null
90
+ }
91
+ }
92
+ ```
93
+
94
+ **Yanıt:**
95
+ ```json
96
+ {
97
+ "uri": "at://did:plc:abc123/app.bsky.feed.post/3k...",
98
+ "cid": "bafyrei..."
99
+ }
100
+ ```
101
+
102
+ - `uri` formatı: `at://<did>/<collection>/<rkey>`
103
+ - `rkey` (record key): URI'nin son parçası, post ID'sidir (TID formatı).
104
+ - `cid` (Content ID): Verinin hash'i, veri bütünlüğünü doğrular.
105
+ - `text` maksimum 300 karakter (grapheme cinsinden).
106
+ - `createdAt` ISO 8601 formatında zorunludur.
107
+ - `langs` opsiyonel, BCP-47 dil kodları (örn: `["tr"]`, `["en", "tr"]`).
108
+
109
+ #### Post Silme
110
+
111
+ ```
112
+ POST /xrpc/com.atproto.repo.deleteRecord
113
+ Authorization: Bearer <accessJwt>
114
+ Content-Type: application/json
115
+
116
+ {
117
+ "repo": "<did>",
118
+ "collection": "app.bsky.feed.post",
119
+ "rkey": "<rkey>"
120
+ }
121
+ ```
122
+
123
+ #### Yanıt (Reply) Post
124
+
125
+ Reply yapmak için `record.reply` alanı eklenir:
126
+
127
+ ```json
128
+ {
129
+ "record": {
130
+ "$type": "app.bsky.feed.post",
131
+ "text": "Bu bir yanıt!",
132
+ "createdAt": "2026-03-14T12:00:00.000Z",
133
+ "reply": {
134
+ "root": {
135
+ "uri": "at://did:plc:abc/app.bsky.feed.post/root123",
136
+ "cid": "bafyrei..."
137
+ },
138
+ "parent": {
139
+ "uri": "at://did:plc:abc/app.bsky.feed.post/parent456",
140
+ "cid": "bafyrei..."
141
+ }
142
+ }
143
+ }
144
+ }
145
+ ```
146
+
147
+ - `root`: Thread'in ilk postu (en üst).
148
+ - `parent`: Doğrudan yanıt verilen post.
149
+ - Tek bir posta yanıt verirken root ve parent aynı olabilir.
150
+
151
+ #### Thread Gate (Yanıt Kısıtlama)
152
+
153
+ Post oluşturulduktan sonra kimin yanıt verebileceği kısıtlanabilir:
154
+
155
+ ```json
156
+ {
157
+ "repo": "<did>",
158
+ "collection": "app.bsky.feed.threadgate",
159
+ "rkey": "<post_rkey>",
160
+ "record": {
161
+ "$type": "app.bsky.feed.threadgate",
162
+ "post": "at://did:plc:abc/app.bsky.feed.post/123",
163
+ "createdAt": "2026-03-14T12:00:00.000Z",
164
+ "allow": [
165
+ { "$type": "app.bsky.feed.threadgate#mentionRule" },
166
+ { "$type": "app.bsky.feed.threadgate#followingRule" },
167
+ { "$type": "app.bsky.feed.threadgate#listRule", "list": "at://did:plc:abc/app.bsky.graph.list/xyz" }
168
+ ]
169
+ }
170
+ }
171
+ ```
172
+
173
+ ### 2.2 Beğenme (Like)
174
+
175
+ ```
176
+ POST /xrpc/com.atproto.repo.createRecord
177
+ Authorization: Bearer <accessJwt>
178
+ Content-Type: application/json
179
+
180
+ {
181
+ "repo": "<did>",
182
+ "collection": "app.bsky.feed.like",
183
+ "record": {
184
+ "$type": "app.bsky.feed.like",
185
+ "subject": {
186
+ "uri": "at://did:plc:target/app.bsky.feed.post/abc123",
187
+ "cid": "bafyrei..."
188
+ },
189
+ "createdAt": "2026-03-14T12:00:00.000Z"
190
+ }
191
+ }
192
+ ```
193
+
194
+ Beğeniyi kaldırmak için `deleteRecord` ile like kaydı silinir.
195
+
196
+ ### 2.3 Repost
197
+
198
+ ```json
199
+ {
200
+ "repo": "<did>",
201
+ "collection": "app.bsky.feed.repost",
202
+ "record": {
203
+ "$type": "app.bsky.feed.repost",
204
+ "subject": {
205
+ "uri": "at://did:plc:target/app.bsky.feed.post/abc123",
206
+ "cid": "bafyrei..."
207
+ },
208
+ "createdAt": "2026-03-14T12:00:00.000Z"
209
+ }
210
+ }
211
+ ```
212
+
213
+ ### 2.4 Takip Etme (Follow)
214
+
215
+ ```json
216
+ {
217
+ "repo": "<did>",
218
+ "collection": "app.bsky.graph.follow",
219
+ "record": {
220
+ "$type": "app.bsky.graph.follow",
221
+ "subject": "did:plc:hedef_kullanici",
222
+ "createdAt": "2026-03-14T12:00:00.000Z"
223
+ }
224
+ }
225
+ ```
226
+
227
+ Takibi bırakmak: `deleteRecord` ile follow kaydı silinir.
228
+
229
+ ### 2.5 Engelleme (Block)
230
+
231
+ ```json
232
+ {
233
+ "repo": "<did>",
234
+ "collection": "app.bsky.graph.block",
235
+ "record": {
236
+ "$type": "app.bsky.graph.block",
237
+ "subject": "did:plc:engellenecek_kullanici",
238
+ "createdAt": "2026-03-14T12:00:00.000Z"
239
+ }
240
+ }
241
+ ```
242
+
243
+ ### 2.6 Sessize Alma (Mute)
244
+
245
+ Mute farklıdır — repo kaydı oluşturulmaz, doğrudan API çağrısı yapılır:
246
+
247
+ ```
248
+ POST /xrpc/app.bsky.graph.muteActor
249
+ Authorization: Bearer <accessJwt>
250
+ Content-Type: application/json
251
+
252
+ { "actor": "did:plc:hedef" }
253
+ ```
254
+
255
+ Unmute:
256
+ ```
257
+ POST /xrpc/app.bsky.graph.unmuteActor
258
+ { "actor": "did:plc:hedef" }
259
+ ```
260
+
261
+ ### 2.7 Medya Yükleme (Upload Blob)
262
+
263
+ ```
264
+ POST /xrpc/com.atproto.repo.uploadBlob
265
+ Authorization: Bearer <accessJwt>
266
+ Content-Type: image/png (veya image/jpeg, image/webp, image/gif)
267
+
268
+ <binary data>
269
+ ```
270
+
271
+ **Yanıt:**
272
+ ```json
273
+ {
274
+ "blob": {
275
+ "$type": "blob",
276
+ "ref": { "$link": "bafkrei..." },
277
+ "mimeType": "image/png",
278
+ "size": 45678
279
+ }
280
+ }
281
+ ```
282
+
283
+ **Önemli:**
284
+ - Maksimum dosya boyutu: **1 MB** (görsel), **50 MB** (video — ayrı endpoint).
285
+ - Yüklenen blob geçicidir; 1 saat içinde bir kayıtta (record) referans verilmezse silinir.
286
+ - Desteklenen görsel formatları: PNG, JPEG, WebP, GIF (animasyonlu GIF dahil, ancak durağan olarak gösterilir).
287
+
288
+ ### 2.8 Video Yükleme
289
+
290
+ Video yükleme ayrı bir akış gerektirir:
291
+
292
+ ```
293
+ GET /xrpc/app.bsky.video.getJobStatus?jobId=<id>
294
+ GET /xrpc/app.bsky.video.getUploadLimits
295
+ POST /xrpc/app.bsky.video.uploadVideo (Content-Type: video/mp4)
296
+ ```
297
+
298
+ - Maksimum video boyutu: **50 MB**
299
+ - Maksimum süre: **60 saniye** (bazı hesaplarda 90 saniye)
300
+ - Format: MP4 (H.264 codec önerilir)
301
+ - Video yüklendikten sonra işlenir (transcoding), `getJobStatus` ile durum takip edilir.
302
+
303
+ ---
304
+
305
+ ## 3. Rich Text Facets
306
+
307
+ Bluesky'da mention, link ve hashtag'ler `facets` dizisi ile tanımlanır.
308
+ **Kritik: Byte offset kullanılır, karakter offset değil!** UTF-8 encoding ile byte pozisyonları hesaplanmalıdır.
309
+
310
+ ### 3.1 Facet Yapısı
311
+
312
+ ```json
313
+ {
314
+ "facets": [
315
+ {
316
+ "index": {
317
+ "byteStart": 0,
318
+ "byteEnd": 14
319
+ },
320
+ "features": [
321
+ {
322
+ "$type": "app.bsky.richtext.facet#mention",
323
+ "did": "did:plc:abc123"
324
+ }
325
+ ]
326
+ }
327
+ ]
328
+ }
329
+ ```
330
+
331
+ ### 3.2 Mention (Bahsetme)
332
+
333
+ ```json
334
+ {
335
+ "$type": "app.bsky.richtext.facet#mention",
336
+ "did": "did:plc:hedef_kullanici_did"
337
+ }
338
+ ```
339
+
340
+ - Metinde `@kullanici.bsky.social` yazılır.
341
+ - Facet'te handle değil **DID** belirtilir.
342
+ - Handle → DID çözümlemek için: `GET /xrpc/com.atproto.identity.resolveHandle?handle=kullanici.bsky.social`
343
+
344
+ ### 3.3 Link
345
+
346
+ ```json
347
+ {
348
+ "$type": "app.bsky.richtext.facet#link",
349
+ "uri": "https://example.com"
350
+ }
351
+ ```
352
+
353
+ - Metindeki URL tam olarak facet aralığına denk gelmelidir.
354
+ - URI validasyonu yapılır, geçersiz URI'ler reddedilir.
355
+
356
+ ### 3.4 Hashtag (Etiket)
357
+
358
+ ```json
359
+ {
360
+ "$type": "app.bsky.richtext.facet#tag",
361
+ "tag": "bluesky"
362
+ }
363
+ ```
364
+
365
+ - Metinde `#bluesky` yazılır, facet `tag` alanında `#` olmadan sadece etiket adı verilir.
366
+ - Hashtag arama: `https://bsky.app/search?q=%23bluesky`
367
+
368
+ ### 3.5 Byte Offset Hesaplama (TypeScript)
369
+
370
+ ```typescript
371
+ const encoder = new TextEncoder(); // UTF-8
372
+
373
+ function findByteOffsets(text: string, matchStart: number, matchText: string) {
374
+ const byteStart = encoder.encode(text.substring(0, matchStart)).byteLength;
375
+ const byteEnd = byteStart + encoder.encode(matchText).byteLength;
376
+ return { byteStart, byteEnd };
377
+ }
378
+ ```
379
+
380
+ **Dikkat:** Türkçe karakterler (ş, ğ, ü, ö, ç, ı, İ) ve emoji gibi çok baytlı karakterlerde byte offset ile karakter index'i farklıdır. `TextEncoder` kullanmak zorunludur.
381
+
382
+ Örnek: `"Türkçe #test"` metninde `#test` karakter 8'de başlar ama byte 9'da başlar (ü = 2 byte).
383
+
384
+ ---
385
+
386
+ ## 4. Embed Tipleri
387
+
388
+ Post'lara görsel, link kartı, alıntı (quote) eklemek için `embed` alanı kullanılır.
389
+
390
+ ### 4.1 Görsel Embed
391
+
392
+ ```json
393
+ {
394
+ "embed": {
395
+ "$type": "app.bsky.embed.images",
396
+ "images": [
397
+ {
398
+ "alt": "Görsel açıklaması (erişilebilirlik için)",
399
+ "image": {
400
+ "$type": "blob",
401
+ "ref": { "$link": "bafkrei..." },
402
+ "mimeType": "image/jpeg",
403
+ "size": 45678
404
+ },
405
+ "aspectRatio": {
406
+ "width": 1200,
407
+ "height": 630
408
+ }
409
+ }
410
+ ]
411
+ }
412
+ }
413
+ ```
414
+
415
+ - Maksimum **4 görsel** eklenebilir.
416
+ - `alt` alanı zorunlu değil ama erişilebilirlik için önerilir.
417
+ - `aspectRatio` opsiyonel ama verilirse görsel düzgün kırpılır.
418
+
419
+ ### 4.2 Harici Link Embed (Link Kartı / OG Card)
420
+
421
+ ```json
422
+ {
423
+ "embed": {
424
+ "$type": "app.bsky.embed.external",
425
+ "external": {
426
+ "uri": "https://example.com/article",
427
+ "title": "Makale Başlığı",
428
+ "description": "Makale açıklaması...",
429
+ "thumb": {
430
+ "$type": "blob",
431
+ "ref": { "$link": "bafkrei..." },
432
+ "mimeType": "image/jpeg",
433
+ "size": 12345
434
+ }
435
+ }
436
+ }
437
+ }
438
+ ```
439
+
440
+ **Önemli:** Bluesky sunucusu link kartı otomatik oluşturmaz! Client tarafında:
441
+ 1. Hedef URL'den OG meta tag'leri çekilir (title, description, image).
442
+ 2. OG image varsa `uploadBlob` ile yüklenir.
443
+ 3. Tüm bilgiler embed'e yazılır.
444
+ 4. `thumb` opsiyoneldir, olmadan da link kartı oluşturulur (görselsiz).
445
+
446
+ ### 4.3 Alıntı Post (Quote Post)
447
+
448
+ ```json
449
+ {
450
+ "embed": {
451
+ "$type": "app.bsky.embed.record",
452
+ "record": {
453
+ "uri": "at://did:plc:abc/app.bsky.feed.post/xyz",
454
+ "cid": "bafyrei..."
455
+ }
456
+ }
457
+ }
458
+ ```
459
+
460
+ ### 4.4 Görsel + Alıntı (Kombine Embed)
461
+
462
+ ```json
463
+ {
464
+ "embed": {
465
+ "$type": "app.bsky.embed.recordWithMedia",
466
+ "record": {
467
+ "record": {
468
+ "uri": "at://did:plc:abc/app.bsky.feed.post/xyz",
469
+ "cid": "bafyrei..."
470
+ }
471
+ },
472
+ "media": {
473
+ "$type": "app.bsky.embed.images",
474
+ "images": [...]
475
+ }
476
+ }
477
+ }
478
+ ```
479
+
480
+ ### 4.5 Video Embed
481
+
482
+ ```json
483
+ {
484
+ "embed": {
485
+ "$type": "app.bsky.embed.video",
486
+ "video": {
487
+ "$type": "blob",
488
+ "ref": { "$link": "bafkrei..." },
489
+ "mimeType": "video/mp4",
490
+ "size": 5000000
491
+ },
492
+ "alt": "Video açıklaması",
493
+ "aspectRatio": {
494
+ "width": 1920,
495
+ "height": 1080
496
+ }
497
+ }
498
+ }
499
+ ```
500
+
501
+ ---
502
+
503
+ ## 5. Okuma (Read) Endpoint'leri
504
+
505
+ Bu endpoint'ler `GET` istekleri ile çalışır. Çoğu kimlik doğrulama gerektirir.
506
+
507
+ ### 5.1 Profil Bilgileri
508
+
509
+ ```
510
+ GET /xrpc/app.bsky.actor.getProfile?actor=kullanici.bsky.social
511
+ Authorization: Bearer <accessJwt>
512
+ ```
513
+
514
+ **Yanıt:** displayName, description, avatar, banner, followersCount, followsCount, postsCount, vb.
515
+
516
+ ### 5.2 Kullanıcı Arama
517
+
518
+ ```
519
+ GET /xrpc/app.bsky.actor.searchActors?q=arama_terimi&limit=25
520
+ Authorization: Bearer <accessJwt>
521
+ ```
522
+
523
+ - `q`: Arama terimi (handle veya display name)
524
+ - `limit`: Sonuç sayısı (maks 100, varsayılan 25)
525
+ - `cursor`: Sayfalama için
526
+
527
+ ### 5.3 Post Arama
528
+
529
+ ```
530
+ GET /xrpc/app.bsky.feed.searchPosts?q=arama_terimi&limit=25
531
+ Authorization: Bearer <accessJwt>
532
+ ```
533
+
534
+ - `q`: Arama terimi
535
+ - `sort`: `top` veya `latest` (varsayılan: `latest`)
536
+ - `since` / `until`: Tarih filtresi (ISO 8601)
537
+ - `author`: Belirli bir kullanıcının postlarında ara
538
+ - `lang`: Dil filtresi (örn: `tr`)
539
+ - `tag`: Hashtag filtresi
540
+
541
+ ### 5.4 Bildirimler
542
+
543
+ ```
544
+ GET /xrpc/app.bsky.notification.listNotifications?limit=50
545
+ Authorization: Bearer <accessJwt>
546
+ ```
547
+
548
+ **Bildirim türleri (reason):** `like`, `repost`, `follow`, `mention`, `reply`, `quote`, `starterpack-joined`
549
+
550
+ Bildirimleri okundu olarak işaretleme:
551
+ ```
552
+ POST /xrpc/app.bsky.notification.updateSeen
553
+ { "seenAt": "2026-03-14T12:00:00.000Z" }
554
+ ```
555
+
556
+ ### 5.5 Timeline (Akış)
557
+
558
+ ```
559
+ GET /xrpc/app.bsky.feed.getTimeline?limit=50
560
+ Authorization: Bearer <accessJwt>
561
+ ```
562
+
563
+ ### 5.6 Kullanıcının Postları
564
+
565
+ ```
566
+ GET /xrpc/app.bsky.feed.getAuthorFeed?actor=kullanici.bsky.social&limit=50
567
+ Authorization: Bearer <accessJwt>
568
+ ```
569
+
570
+ - `filter`: `posts_with_replies`, `posts_no_replies`, `posts_with_media`, `posts_and_author_threads`
571
+
572
+ ### 5.7 Post Detayı
573
+
574
+ ```
575
+ GET /xrpc/app.bsky.feed.getPosts?uris=at://did:plc:abc/app.bsky.feed.post/xyz
576
+ Authorization: Bearer <accessJwt>
577
+ ```
578
+
579
+ - Birden fazla URI virgülle ayrılarak tek istekte sorgulanabilir (maks 25).
580
+
581
+ ### 5.8 Thread Görüntüleme
582
+
583
+ ```
584
+ GET /xrpc/app.bsky.feed.getPostThread?uri=at://did:plc:abc/app.bsky.feed.post/xyz&depth=6
585
+ Authorization: Bearer <accessJwt>
586
+ ```
587
+
588
+ ### 5.9 Takipçiler ve Takip Edilenler
589
+
590
+ ```
591
+ GET /xrpc/app.bsky.graph.getFollowers?actor=kullanici.bsky.social&limit=100
592
+ GET /xrpc/app.bsky.graph.getFollows?actor=kullanici.bsky.social&limit=100
593
+ Authorization: Bearer <accessJwt>
594
+ ```
595
+
596
+ ### 5.10 Handle Çözümleme
597
+
598
+ ```
599
+ GET /xrpc/com.atproto.identity.resolveHandle?handle=kullanici.bsky.social
600
+ ```
601
+
602
+ Kimlik doğrulama gerektirmez. Yanıt: `{ "did": "did:plc:abc123" }`
603
+
604
+ ### 5.11 Beğenenler ve Repost Edenler
605
+
606
+ ```
607
+ GET /xrpc/app.bsky.feed.getLikes?uri=at://did:plc:abc/app.bsky.feed.post/xyz&limit=100
608
+ GET /xrpc/app.bsky.feed.getRepostedBy?uri=at://did:plc:abc/app.bsky.feed.post/xyz&limit=100
609
+ ```
610
+
611
+ ---
612
+
613
+ ## 6. Listeler ve Özel Akışlar (Custom Feeds)
614
+
615
+ ### 6.1 Liste Oluşturma
616
+
617
+ ```json
618
+ {
619
+ "repo": "<did>",
620
+ "collection": "app.bsky.graph.list",
621
+ "record": {
622
+ "$type": "app.bsky.graph.list",
623
+ "purpose": "app.bsky.graph.defs#curatelist",
624
+ "name": "Türk Geliştiriciler",
625
+ "description": "Türkiye'den yazılımcılar",
626
+ "createdAt": "2026-03-14T12:00:00.000Z"
627
+ }
628
+ }
629
+ ```
630
+
631
+ Liste amaçları (`purpose`):
632
+ - `app.bsky.graph.defs#curatelist` — Kürasyon listesi (takip koleksiyonu)
633
+ - `app.bsky.graph.defs#modlist` — Moderasyon listesi (toplu mute/block)
634
+
635
+ ### 6.2 Listeye Kullanıcı Ekleme
636
+
637
+ ```json
638
+ {
639
+ "repo": "<did>",
640
+ "collection": "app.bsky.graph.listitem",
641
+ "record": {
642
+ "$type": "app.bsky.graph.listitem",
643
+ "subject": "did:plc:eklenecek_kullanici",
644
+ "list": "at://did:plc:abc/app.bsky.graph.list/xyz",
645
+ "createdAt": "2026-03-14T12:00:00.000Z"
646
+ }
647
+ }
648
+ ```
649
+
650
+ ### 6.3 Custom Feed (Özel Akış / Feed Generator)
651
+
652
+ Bluesky'da herkes kendi algoritmasını oluşturabilir. Feed generator bir web servisidir:
653
+
654
+ ```
655
+ GET /xrpc/app.bsky.feed.getFeedSkeleton?feed=at://did:plc:abc/app.bsky.feed.generator/my-feed&limit=30
656
+ ```
657
+
658
+ Popüler feed'ler:
659
+ - `at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/whats-hot` — Keşfet
660
+ - `at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/with-friends` — Arkadaşlarla
661
+
662
+ Feed'leri listeleme:
663
+ ```
664
+ GET /xrpc/app.bsky.feed.getActorFeeds?actor=kullanici.bsky.social
665
+ GET /xrpc/app.bsky.feed.getSuggestedFeeds
666
+ ```
667
+
668
+ ---
669
+
670
+ ## 7. URL Yapısı
671
+
672
+ ### Web URL'leri (bsky.app)
673
+
674
+ | Sayfa | URL |
675
+ |-------|-----|
676
+ | Profil | `https://bsky.app/profile/kullanici.bsky.social` |
677
+ | Profil (DID ile) | `https://bsky.app/profile/did:plc:abc123` |
678
+ | Post | `https://bsky.app/profile/kullanici.bsky.social/post/<rkey>` |
679
+ | Post (DID ile) | `https://bsky.app/profile/did:plc:abc123/post/<rkey>` |
680
+ | Arama | `https://bsky.app/search?q=arama_terimi` |
681
+ | Hashtag arama | `https://bsky.app/search?q=%23hashtag` |
682
+ | Ayarlar | `https://bsky.app/settings` |
683
+ | Akışlar | `https://bsky.app/feeds` |
684
+ | Bildirimler | `https://bsky.app/notifications` |
685
+ | Listeler | `https://bsky.app/profile/kullanici.bsky.social/lists` |
686
+ | Belirli liste | `https://bsky.app/profile/kullanici.bsky.social/lists/<rkey>` |
687
+ | Feed | `https://bsky.app/profile/kullanici.bsky.social/feed/<rkey>` |
688
+ | Starter Pack | `https://bsky.app/starter-pack/kullanici.bsky.social/<rkey>` |
689
+
690
+ ### AT Protocol URI'leri
691
+
692
+ ```
693
+ at://did:plc:abc123/app.bsky.feed.post/3k... → Post
694
+ at://did:plc:abc123/app.bsky.feed.like/3k... → Like kaydı
695
+ at://did:plc:abc123/app.bsky.feed.repost/3k... → Repost kaydı
696
+ at://did:plc:abc123/app.bsky.graph.follow/3k... → Follow kaydı
697
+ at://did:plc:abc123/app.bsky.graph.block/3k... → Block kaydı
698
+ at://did:plc:abc123/app.bsky.graph.list/3k... → Liste
699
+ ```
700
+
701
+ ### Web URL'den AT URI'ye Dönüşüm
702
+
703
+ Post URL'si `https://bsky.app/profile/HANDLE/post/RKEY` formatındadır.
704
+ 1. Handle'ı DID'e çevir: `resolveHandle`
705
+ 2. AT URI oluştur: `at://<did>/app.bsky.feed.post/<rkey>`
706
+
707
+ ---
708
+
709
+ ## 8. Görsel Boyutları ve Öneriler
710
+
711
+ ### Post Görselleri
712
+
713
+ | Özellik | Değer |
714
+ |---------|-------|
715
+ | Önerilen boyut | 1200 x 630 px (1.91:1 oran) |
716
+ | Maksimum dosya boyutu | 1 MB (1.000.000 byte) |
717
+ | Maksimum görsel sayısı | 4 adet per post |
718
+ | Desteklenen formatlar | PNG, JPEG, WebP, GIF |
719
+ | Minimum boyut | Belirtilmemiş, çok küçük olmamalı |
720
+
721
+ ### Profil Görselleri
722
+
723
+ | Özellik | Değer |
724
+ |---------|-------|
725
+ | Avatar | 1000 x 1000 px önerilir, kare kırpılır |
726
+ | Banner | 3000 x 1000 px önerilir (3:1 oran) |
727
+ | Maks dosya boyutu | 1 MB |
728
+
729
+ ### Aspect Ratio (En-Boy Oranı)
730
+
731
+ Post'a görsel eklerken `aspectRatio` belirtilmesi önerilir:
732
+ ```json
733
+ {
734
+ "aspectRatio": {
735
+ "width": 1200,
736
+ "height": 630
737
+ }
738
+ }
739
+ ```
740
+
741
+ Yaygın oranlar:
742
+ - **1.91:1** (1200x630) — Link kartı benzeri, yatay
743
+ - **16:9** (1920x1080) — Geniş ekran
744
+ - **4:3** (1200x900) — Klasik
745
+ - **1:1** (1080x1080) — Kare
746
+ - **4:5** (1080x1350) — Dikey (en uzun desteklenen oran)
747
+
748
+ ---
749
+
750
+ ## 9. Rate Limiting (Hız Sınırlaması)
751
+
752
+ Bluesky rate limitleri çok cömerttir, diğer platformlara kıyasla oldukça rahat:
753
+
754
+ ### Puan Sistemi
755
+
756
+ | Sınır | Değer |
757
+ |-------|-------|
758
+ | Toplam bütçe | **5000 puan / saat** (kayan pencere) |
759
+ | Puan sıfırlanması | Her saat başı değil, sürekli kayan pencere |
760
+
761
+ ### İşlem Başına Puan Maliyeti
762
+
763
+ | İşlem | Puan |
764
+ |-------|------|
765
+ | `createRecord` (post, like, repost, follow) | 3 puan |
766
+ | `deleteRecord` | 1 puan |
767
+ | `uploadBlob` (görsel/video yükleme) | 25 puan |
768
+ | `createSession` | 3 puan |
769
+ | Okuma işlemleri (GET) | 1 puan |
770
+
771
+ ### Hesaplama Örneği
772
+
773
+ Saatte yapılabilecek maksimum işlemler:
774
+ - ~1666 post (sadece metin)
775
+ - ~200 görsel yükleme
776
+ - ~5000 okuma isteği
777
+ - Karma kullanım: 100 görselli post (100×25 + 100×3 = 2800 puan) + 2200 okuma
778
+
779
+ ### Rate Limit Yanıtı
780
+
781
+ Limit aşıldığında HTTP 429 döner:
782
+ ```
783
+ HTTP/1.1 429 Too Many Requests
784
+ RateLimit-Limit: 5000
785
+ RateLimit-Remaining: 0
786
+ RateLimit-Reset: 1710421200
787
+ RateLimit-Policy: 5000;w=3600
788
+ ```
789
+
790
+ Header'lardan kalan puan ve sıfırlanma zamanı okunabilir.
791
+
792
+ ---
793
+
794
+ ## 10. Etiketler ve Moderasyon (Labels)
795
+
796
+ ### 10.1 Self-Label (Kendi İçeriğini Etiketleme)
797
+
798
+ Post'a veya profil'e içerik uyarısı eklemek için:
799
+
800
+ ```json
801
+ {
802
+ "record": {
803
+ "$type": "app.bsky.feed.post",
804
+ "text": "İçerik burada",
805
+ "createdAt": "2026-03-14T12:00:00.000Z",
806
+ "labels": {
807
+ "$type": "com.atproto.label.defs#selfLabels",
808
+ "values": [
809
+ { "val": "sexual" }
810
+ ]
811
+ }
812
+ }
813
+ }
814
+ ```
815
+
816
+ ### 10.2 Yaygın Etiket Değerleri
817
+
818
+ | Etiket | Açıklama |
819
+ |--------|----------|
820
+ | `sexual` | Cinsel içerik |
821
+ | `nudity` | Çıplaklık |
822
+ | `porn` | Pornografi |
823
+ | `graphic-media` | Şiddet/rahatsız edici görsel |
824
+ | `gore` | Kanlı/şiddet içeriği |
825
+
826
+ ### 10.3 Moderasyon Servisleri
827
+
828
+ Bluesky'da moderasyon merkezi değildir. Farklı labeler servisleri içerikleri etiketler:
829
+
830
+ ```
831
+ GET /xrpc/app.bsky.labeler.getServices?dids=did:plc:labeler_did
832
+ ```
833
+
834
+ Kullanıcılar hangi moderasyon servislerine abone olacaklarını seçebilir.
835
+
836
+ ---
837
+
838
+ ## 11. Sayfalama (Pagination)
839
+
840
+ Çoğu liste endpoint'i `cursor` tabanlı sayfalama kullanır:
841
+
842
+ ```
843
+ GET /xrpc/app.bsky.feed.getTimeline?limit=50
844
+
845
+ → { "cursor": "1710421200::bafyrei...", "feed": [...] }
846
+
847
+ GET /xrpc/app.bsky.feed.getTimeline?limit=50&cursor=1710421200::bafyrei...
848
+
849
+ → { "cursor": "1710420000::bafyrei...", "feed": [...] }
850
+ ```
851
+
852
+ - `cursor` opak bir string'dir, içeriği değişebilir.
853
+ - `cursor` null veya yoksa son sayfa demektir.
854
+ - `limit` genellikle 1-100 arasıdır.
855
+
856
+ ---
857
+
858
+ ## 12. Hata Kodları
859
+
860
+ | HTTP Kodu | XRPC Hatası | Açıklama |
861
+ |-----------|-------------|----------|
862
+ | 400 | `InvalidRequest` | Geçersiz parametre veya body |
863
+ | 401 | `AuthenticationRequired` | Token geçersiz veya eksik |
864
+ | 403 | `Forbidden` | Yetkisiz işlem (engelli kullanıcıya erişim vb.) |
865
+ | 404 | `RecordNotFound` | Kayıt bulunamadı |
866
+ | 413 | `PayloadTooLarge` | Dosya çok büyük (1 MB üzeri görsel) |
867
+ | 429 | `RateLimitExceeded` | Rate limit aşıldı |
868
+ | 502 | `UpstreamFailure` | PDS veya AppView hatası |
869
+
870
+ Hata yanıt formatı:
871
+ ```json
872
+ {
873
+ "error": "InvalidRequest",
874
+ "message": "Record/text must be a string with length between 1 and 300"
875
+ }
876
+ ```
877
+
878
+ ---
879
+
880
+ ## 13. DID ve Handle Sistemi
881
+
882
+ ### DID (Decentralized Identifier)
883
+
884
+ Her Bluesky hesabı benzersiz ve kalıcı bir DID'e sahiptir:
885
+ - `did:plc:abc123...` — PLC (Public Ledger of Credentials) yöntemi, en yaygın
886
+ - `did:web:example.com` — Web tabanlı DID, kendi domain'ini handle olarak kullananlar
887
+
888
+ DID asla değişmez, handle değişse bile DID aynı kalır. Bu yüzden kayıtlarda (record) her zaman DID kullanılır.
889
+
890
+ ### Handle
891
+
892
+ Handle, kullanıcının okunabilir adıdır:
893
+ - `kullanici.bsky.social` — Varsayılan subdomain
894
+ - `kullanici.com` — Özel domain (DNS TXT kaydı ile doğrulanır)
895
+
896
+ Handle çözümleme:
897
+ ```
898
+ GET /xrpc/com.atproto.identity.resolveHandle?handle=kullanici.bsky.social
899
+ → { "did": "did:plc:abc123" }
900
+ ```
901
+
902
+ ---
903
+
904
+ ## 14. PDS (Personal Data Server) Bilgisi
905
+
906
+ Bluesky merkezi olmayan bir yapıdadır. Her kullanıcının verisi bir PDS'de tutulur:
907
+ - `bsky.social` — Bluesky'ın resmi PDS'i (çoğu kullanıcı burada)
908
+ - Üçüncü parti PDS'ler de vardır
909
+
910
+ Kullanıcının PDS'ini bulmak:
911
+ ```
912
+ GET https://plc.directory/did:plc:abc123
913
+ → { "service": [{ "serviceEndpoint": "https://pds.example.com" }] }
914
+ ```
915
+
916
+ API istekleri genelde `bsky.social`'a yapılır, PDS yönlendirmeyi otomatik yapar.
917
+
918
+ ---
919
+
920
+ ## 15. Yararlı Kod Kalıpları
921
+
922
+ ### 15.1 Post Atma (Tam Akış)
923
+
924
+ ```typescript
925
+ // 1. Giriş yap
926
+ const session = await createSession(identifier, password);
927
+
928
+ // 2. Görsel varsa yükle
929
+ const blob = await uploadBlob(session.accessJwt, imageBuffer, "image/jpeg");
930
+
931
+ // 3. Facet'leri oluştur
932
+ const facets = parseFacets(text);
933
+
934
+ // 4. Record oluştur
935
+ const record = {
936
+ $type: "app.bsky.feed.post",
937
+ text: text,
938
+ createdAt: new Date().toISOString(),
939
+ langs: ["tr"],
940
+ facets: facets,
941
+ embed: blob ? {
942
+ $type: "app.bsky.embed.images",
943
+ images: [{ alt: "", image: blob, aspectRatio: { width: 1200, height: 630 } }]
944
+ } : undefined
945
+ };
946
+
947
+ // 5. Post gönder
948
+ const result = await createRecord(session, "app.bsky.feed.post", record);
949
+ const postUrl = `https://bsky.app/profile/${session.did}/post/${result.uri.split("/").pop()}`;
950
+ ```
951
+
952
+ ### 15.2 Thread (Zincirleme Post) Atma
953
+
954
+ ```typescript
955
+ let previousUri: string | null = null;
956
+ let previousCid: string | null = null;
957
+ let rootUri: string | null = null;
958
+ let rootCid: string | null = null;
959
+
960
+ for (const text of threadTexts) {
961
+ const record: any = {
962
+ $type: "app.bsky.feed.post",
963
+ text: text,
964
+ createdAt: new Date().toISOString(),
965
+ };
966
+
967
+ if (previousUri) {
968
+ record.reply = {
969
+ root: { uri: rootUri, cid: rootCid },
970
+ parent: { uri: previousUri, cid: previousCid }
971
+ };
972
+ }
973
+
974
+ const result = await createRecord(session, "app.bsky.feed.post", record);
975
+
976
+ if (!rootUri) {
977
+ rootUri = result.uri;
978
+ rootCid = result.cid;
979
+ }
980
+ previousUri = result.uri;
981
+ previousCid = result.cid;
982
+ }
983
+ ```
984
+
985
+ ### 15.3 Post URL'sinden URI Elde Etme
986
+
987
+ ```typescript
988
+ async function postUrlToAtUri(url: string): Promise<string> {
989
+ // https://bsky.app/profile/handle.bsky.social/post/3k...
990
+ const match = url.match(/\/profile\/([^/]+)\/post\/([^/]+)/);
991
+ if (!match) throw new Error("Geçersiz post URL'si");
992
+
993
+ const [, actor, rkey] = match;
994
+
995
+ // Handle ise DID'e çevir
996
+ let did = actor;
997
+ if (!actor.startsWith("did:")) {
998
+ const res = await fetch(`https://bsky.social/xrpc/com.atproto.identity.resolveHandle?handle=${actor}`);
999
+ const data = await res.json();
1000
+ did = data.did;
1001
+ }
1002
+
1003
+ return `at://${did}/app.bsky.feed.post/${rkey}`;
1004
+ }
1005
+ ```
1006
+
1007
+ ---
1008
+
1009
+ ## 16. Limitler Özeti
1010
+
1011
+ | Limit | Değer |
1012
+ |-------|-------|
1013
+ | Post metin uzunluğu | 300 grapheme (karakter) |
1014
+ | Post başına görsel | 4 adet |
1015
+ | Görsel dosya boyutu | 1 MB |
1016
+ | Video dosya boyutu | 50 MB |
1017
+ | Video süresi | 60 saniye |
1018
+ | Bio (profil açıklaması) | 256 karakter |
1019
+ | Display name | 64 karakter |
1020
+ | Handle uzunluğu | 253 karakter |
1021
+ | Liste adı | 64 karakter |
1022
+ | Liste açıklaması | 300 karakter |
1023
+ | Rate limit | 5000 puan/saat |
1024
+ | Takip limiti | Teknik sınır yok, spam koruması var |
1025
+ | Günlük post limiti | Teknik sınır yok, rate limit dahilinde |
1026
+ | Alt text (görsel açıklama) | Teknik sınır yok |
1027
+
1028
+ ---
1029
+
1030
+ ## 17. Diğer Faydalı Endpoint'ler
1031
+
1032
+ ### Profil Güncelleme
1033
+ ```
1034
+ GET /xrpc/com.atproto.repo.getRecord?repo=<did>&collection=app.bsky.actor.profile&rkey=self
1035
+ PUT /xrpc/com.atproto.repo.putRecord (profil güncellemede putRecord kullanılır)
1036
+ ```
1037
+
1038
+ ### Tercihler (Preferences)
1039
+ ```
1040
+ GET /xrpc/app.bsky.actor.getPreferences
1041
+ POST /xrpc/app.bsky.actor.putPreferences
1042
+ ```
1043
+
1044
+ ### Önerilen Kullanıcılar
1045
+ ```
1046
+ GET /xrpc/app.bsky.actor.getSuggestions?limit=50
1047
+ ```
1048
+
1049
+ ### Popüler Feed'ler
1050
+ ```
1051
+ GET /xrpc/app.bsky.unspecced.getPopularFeedGenerators
1052
+ GET /xrpc/app.bsky.feed.getSuggestedFeeds
1053
+ ```
1054
+
1055
+ ### Starter Pack
1056
+ ```
1057
+ GET /xrpc/app.bsky.graph.getStarterPack?starterPack=at://did:plc:abc/app.bsky.graph.starterpack/xyz
1058
+ GET /xrpc/app.bsky.graph.getStarterPacks
1059
+ ```
1060
+
1061
+ ---
1062
+
1063
+ ## 18. Önemli Notlar ve İpuçları
1064
+
1065
+ 1. **Tüm yazma işlemleri `createRecord`/`deleteRecord`/`putRecord` üzerinden yapılır.** Her şey (post, like, follow, block, list) birer AT Protocol kaydıdır.
1066
+
1067
+ 2. **CID zorunluluğu:** Like ve repost gibi işlemlerde hedef postun hem `uri` hem `cid` değeri gerekir. CID almak için önce `getPosts` ile post detayını çekin.
1068
+
1069
+ 3. **createdAt zorunludur.** Tüm kayıtlarda ISO 8601 formatında `createdAt` alanı bulunmalıdır.
1070
+
1071
+ 4. **Facet byte offset hatası en sık yapılan hatadır.** Karakter index'i değil byte pozisyonu kullanılmalıdır. Türkçe karakterler ve emojiler byte offset'i kaydırır.
1072
+
1073
+ 5. **Blob geçicidir.** Yüklenen görseller 1 saat içinde bir kayıtta referans verilmezse silinir. Önce görsel yükle, sonra hemen post oluştur.
1074
+
1075
+ 6. **App Password kullanın.** Ana hesap şifresini API'de kullanmayın. Bluesky ayarlarından App Password oluşturun.
1076
+
1077
+ 7. **Rate limit cömert ama dikkatli olun.** Özellikle toplu görsel yükleme hızla puan tüketir (her biri 25 puan). 200 görselde limit dolar.
1078
+
1079
+ 8. **Bluesky API tamamen ücretsizdir.** Herhangi bir API anahtarı, geliştirici hesabı veya uygulama onayı gerekmez. createSession ile hemen başlayabilirsiniz.
1080
+
1081
+ 9. **Thread oluştururken sıralama önemlidir.** Her yanıt bir öncekinin `uri` ve `cid` değerlerini bilmelidir. Sıralı (sequential) gönderim zorunludur.
1082
+
1083
+ 10. **Silinen kayıtlar geri alınamaz.** `deleteRecord` kalıcıdır.