AeroNyx Chat Relay client entegrasyonu
Blind relay, mutual-contact presence, reciprocal read receipts, encrypted reactions, offline queue ve resumable encrypted media için client contract.
AeroNyx client geliştiren App, frontend, backend ve coding agent ekipleri için resmi frame ve media API contract. Relay yalnızca ciphertext route eder, içeriği yorumlamaz.
Değiştirilemez gizlilik ilkesi
Relay chat/reaction plaintext, voice/media, key, nonce, waveform, filename, transcript, MemChain, packet payload, DNS, destination, URL, history, wallet traffic veya private seed analiz edemez, saklayamaz, çıkaramaz. Client transport öncesi E2E şifreler.
E2E content payload_b64 ve payload_sig içindedir. Visible metadata type, IDs, receiver/group, timestamps, delivery state, blob size/expiry, access mode ve counters ile sınırlıdır.
Çevrimiçi durum gizlilik ilkesi
Online ve last seen yalnızca iki yönde aktif P2PContact varsa görünür. Backend iki tarafı kontrol ederek public key scan’i önler. Presence ve exact last seen ayrı kapatılabilir.
Hidden result online veya last_seen_ts içermez; reason=not_mutual_contact ya da reason=presence_hidden döner.
Profil gizliliği API'si
Client bağlantıda profile privacy flags okur ve UI’ı backend enforcement ile uyumlu tutar. PATCH nested privacy ve eski top-level fields kabul eder.
GET /api/relay/profile/
PATCH /api/relay/profile/
Authorization: Relay <pubkey>:<timestamp>:<signature>
{
"privacy": {
"presence_enabled": true,
"last_seen_enabled": false,
"read_receipts_enabled": false
}
}
Çevrimiçi durum çerçeveleri
presence_subscribe yalnızca contacts için gönderilir. last_seen_enabled=false ise yaklaşık durum gösterin veya zamanı gizleyin; diğer sinyallerden exact status çıkarmayın.
{
"type": "presence_subscribe",
"pubkeys": ["contact-pubkey-a", "contact-pubkey-b"]
}
{
"type": "presence_subscribe_ack",
"updates": [{
"pubkey": "contact-pubkey-a",
"visible": true,
"presence_visible": true,
"last_seen_visible": true,
"online": true,
"last_seen_ts": 1780000000,
"reason": "allowed"
}],
"server_ts": 1780000001
}
Karşılıklı okundu bilgisi kuralı
Read receipts reciprocal’dır: kapatan kullanıcı message_read göndermez ve peer read göstermez. Bir taraf kapalıysa veya mutual contact yoksa backend frame’i suppress eder. Yalnız metadata içerir.
{
"type": "message_read",
"msg_id": "message-id",
"receiver_pubkey": "original-sender-pubkey",
"timestamp": 1780000200
}
{
"type": "message_read_ack",
"msg_id": "message-id",
"delivered": false,
"suppressed": true,
"reason": "receiver_read_receipts_disabled"
}
Reasons: client_disabled, not_mutual_contact, reader_read_receipts_disabled, receiver_read_receipts_disabled; offline pull aynı gate’i kullanır.
Emoji tepkileri
Reaction da E2E ciphertext’tir. Relay receiver/membership ile route eder, reaction_id ile deduplicate eder ve offline durumda store-and-forward uygular. Aggregate state client’a aittir.
{
"type": "message_reaction",
"msg_id": "target-message-id",
"receiver_pubkey": "peer-pubkey",
"reaction_id": "unique-reaction-event-id",
"timestamp": 1780000300,
"payload_b64": "e2e-ciphertext",
"payload_sig": "ed25519-signature"
}
Discriminant 12; reaction_id idempotency/offline ACK key’idir. ACK message_reaction_ack; group group_message_reaction, group_id, key_version kullanır.
Şifreli medya nesnesi modeli
Voice, image, video ve file upload’dan önce şifrelenir. blob_id, key, nonce, duration, waveform, display filename ve preview metadata relay_send.payload_b64 içinde kalır, blob API açık alanına girmez.
{
"kind": "voice",
"blob_id": "blob-uuid",
"key_b64": "inside-e2e-envelope",
"nonce_b64": "inside-e2e-envelope",
"duration_ms": 43000,
"waveform": [0, 3, 8, 6, 2],
"media_type": "audio/ogg; codecs=opus",
"file_size": 7340032
}
Basit şifreli nesne yükleme
Short voice ve small image için multipart kullanın. Server sadece encrypted bytes alır; TTL default 7 gün, policy 1–30. Download unguessable capability veya authenticated P2P key ile yapılır.
POST /api/relay/blob/
Authorization: Relay <pubkey>:<timestamp>:<signature>
Content-Type: multipart/form-data
| field | required | value |
|---|---|---|
file | true | ciphertext |
media_kind | false | voice, image, video, file, avatar, other |
media_type | false | MIME |
ttl_days | false | 1..30 |
access_mode | false | capability, authenticated |
allowed_downloaders | false | JSON P2P pubkey array |
Simple limit 10 MB; aşım HTTP 413, error_code=blob_too_large, chunked_max_bytes=104857600 döndürür.
Devam ettirilebilir şifreli nesne yükleme
Simple limit üstünde chunk session kullanın. Ciphertext total en fazla 100 MB; aynı chunk index güvenle retry edilir. upload_id, chunk_size, completed indexes local saklanır.
1. Yükleme oturumu oluşturma
POST /api/relay/blob/session/
Authorization: Relay <pubkey>:<timestamp>:<signature>
Content-Type: application/json
{
"total_size": 7340032,
"chunk_size": 1048576,
"media_type": "audio/ogg",
"media_kind": "voice",
"ttl_days": 7,
"access_mode": "authenticated",
"allowed_downloaders": ["receiver-pubkey"]
}
2. Parçaları yükleme
PUT /api/relay/blob/session/{upload_id}/chunk/{chunk_index}/
Authorization: Relay <pubkey>:<timestamp>:<signature>
Content-Type: application/octet-stream
Default chunk 1 MB, maximum 4 MB; aynı index retry eski chunk’ı değiştirir ve idempotent’tir.
3. Ağ kesintisinden sonra devam etme
GET /api/relay/blob/session/{upload_id}/
Authorization: Relay <pubkey>:<timestamp>:<signature>
missing_chunks okuyup yalnız eksik index’leri gönderin. Session 24 saat geçerlidir.
4. Yüklemeyi tamamlama
POST /api/relay/blob/session/{upload_id}/complete/
Authorization: Relay <pubkey>:<timestamp>:<signature>
Complete chunks ve total bytes doğrular; safe retry mevcut final blob döndürür, duplicate yaratmaz.
5. Yüklemeyi iptal etme
DELETE /api/relay/blob/session/{upload_id}/
Authorization: Relay <pubkey>:<timestamp>:<signature>
Şifreli nesneyi indirme
Capability UUID bearer capability olduğundan RelayAuth istemez. Authenticated imza ister ve uploader veya allowed_downloaders erişir. Expired blob access sırasında silinir.
GET /api/relay/blob/{blob_id}/
| HTTP | error_code |
|---|---|
| 400 | blob_id_invalid |
| 401 | auth_required |
| 403 | download_forbidden |
| 404 | blob_not_found |
| 410 | blob_expired |
| 413 | blob_too_large, blob_total_size_too_large, chunk_too_large |
| 409 | upload_incomplete |
İstemci UX rehberi
Small file için simple upload, max_bytes sonrası chunks kullanın. App restart sonrası missing_chunks okuyun. Secrets E2E’de kalsın; 410 blob_expired resend action olsun.
AI aracısı entegrasyon sırası
Agent sırasıyla RelayAuth, profile privacy, presence UI, reciprocal reads, reaction idempotency, simple blob, chunk resume ve relay_send reference uygular. Server-side chat search eklemez.
Doğrulanmış iki atlamalı teslimat
Eligible ChatRelay network-diverse two-hop path seçebilir. Source expected terminal signed receipt doğrulandıktan sonra delivery sayar; middle node ciphertext route eder.