AeroNyx Chat Relay クライアント統合

AeroNyx2026年6月19日約5分で読めます31 回表示

Blind relay messaging、相互 contact presence、reciprocal read receipt、encrypted reaction、offline queue、resumable encrypted media の client contract。

このページは AeroNyx 互換 chat client を実装する App、frontend、backend、AI coding agent 向けの正式な frame / media API contract です。Relay は ciphertext だけを route し、ユーザー内容を理解しません。

妥協できないプライバシー不変条件

Relay は chat plaintext、reaction 内容、voice/media plaintext、decrypt key、nonce、waveform、filename、transcript、MemChain plaintext、packet payload、DNS、destination、URL、history、wallet traffic、private identity seed を解析・保存・推論してはいけません。内容は client を離れる前に E2E 暗号化します。

E2E content は payload_b64payload_sig に入ります。Relay-visible metadata は type、IDs、receiver/group、bounded timestamp、delivery state、blob size/expiry、access mode、aggregate counters に限定します。

プレゼンスのプライバシー不変条件

Online と last seen を購読できるのは、削除されていない相互 P2PContact のみです。Backend は両方向を確認し、public key scan による online status 収集を防ぎます。ユーザーは presence と exact last seen を別々に無効化できます。

Hidden result は onlinelast_seen_ts を含まず、reason=not_mutual_contact または reason=presence_hidden だけを返します。

プロフィールのプライバシー API

Client は接続後に profile privacy flags を読み、local UI を backend enforcement と一致させます。PATCH は nested privacy と後方互換の top-level fields を受け付けます。

http
GET /api/relay/profile/
PATCH /api/relay/profile/
Authorization: Relay <pubkey>:<timestamp>:<signature>
json
{
  "privacy": {
    "presence_enabled": true,
    "last_seen_enabled": false,
    "read_receipts_enabled": false
  }
}

プレゼンスフレーム

presence_subscribe は contact list にだけ送ります。last_seen_enabled=false なら UI は「recently」のような曖昧表示か非表示にし、別の signal から exact status を推測しません。

json
{
  "type": "presence_subscribe",
  "pubkeys": ["contact-pubkey-a", "contact-pubkey-b"]
}
json
{
  "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
}

既読通知の相互ルール

Read receipt は reciprocal です。無効化した client は message_read を送らず、peer read も表示しません。どちらかが無効、または mutual contact でなければ backend が suppress します。Frame は metadata only です。

json
{
  "type": "message_read",
  "msg_id": "message-id",
  "receiver_pubkey": "original-sender-pubkey",
  "timestamp": 1780000200
}
json
{
  "type": "message_read_ack",
  "msg_id": "message-id",
  "delivered": false,
  "suppressed": true,
  "reason": "receiver_read_receipts_disabled"
}

Suppression reason は client_disablednot_mutual_contactreader_read_receipts_disabledreceiver_read_receipts_disabled。Offline pull にも同じ gate を適用します。

絵文字リアクション

Reaction も E2E ciphertext です。Relay は receiver または group membership に基づいて route し、reaction_id で deduplicate、offline 時は store-and-forward します。Reaction aggregate state は client が保持します。

json
{
  "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"
}

Signature discriminant は 12reaction_id は idempotency / offline ACK key、ACK は message_reaction_ack。Group は group_message_reactiongroup_idkey_version を使います。

暗号化メディア blob モデル

Voice、large image、video、file は client で暗号化してから ciphertext を upload します。blob_id、key、nonce、duration、waveform、display filename、preview metadata は relay_send.payload_b64 内に置き、blob API の plaintext field にしません。

json
{
  "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
}

シンプルな暗号化 blob アップロード

Short voice と small image は multipart single upload を使えます。Server は encrypted bytes だけを受け取り、TTL は default 7 日・policy 1〜30 日です。Download は unguessable capability または P2P public key 指定 authenticated mode です。

http
POST /api/relay/blob/
Authorization: Relay <pubkey>:<timestamp>:<signature>
Content-Type: multipart/form-data
fieldrequiredvalue
filetrueciphertext
media_kindfalsevoice, image, video, file, avatar, other
media_typefalseMIME
ttl_daysfalse1..30
access_modefalsecapability, authenticated
allowed_downloadersfalseJSON P2P pubkey array

Single limit は 10 MB。超過時は HTTP 413error_code=blob_too_largechunked_max_bytes=104857600 を返します。

再開可能な暗号化 blob アップロード

Single limit を超える場合は chunk session を使います。Ciphertext total は 100 MB まで。同じ chunk index は安全に retry でき、client は upload_idchunk_size、completed indexes を local に保存します。

1. アップロードセッションの作成

http
POST /api/relay/blob/session/
Authorization: Relay <pubkey>:<timestamp>:<signature>
Content-Type: application/json
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. チャンクのアップロード

http
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。同じ index の retry は既存 chunk を置換する idempotent operation です。

3. 通信中断後の再開

http
GET /api/relay/blob/session/{upload_id}/
Authorization: Relay <pubkey>:<timestamp>:<signature>

missing_chunks を読み、不足 index だけを upload します。Upload session は 24 時間有効です。

4. アップロードの完了

http
POST /api/relay/blob/session/{upload_id}/complete/
Authorization: Relay <pubkey>:<timestamp>:<signature>

Complete は全 chunks と total bytes を検証します。安全な retry は既存 final blob を返し、duplicate を作りません。

5. アップロードのキャンセル

http
DELETE /api/relay/blob/session/{upload_id}/
Authorization: Relay <pubkey>:<timestamp>:<signature>

暗号化 blob のダウンロード

Capability mode は UUID 自体が bearer capability なので RelayAuth 不要です。Authenticated mode は署名が必要で、uploader または allowed_downloaders だけが取得できます。Expired blob は access 時に lazy cleanup されます。

http
GET /api/relay/blob/{blob_id}/
HTTPerror_code
400blob_id_invalid
401auth_required
403download_forbidden
404blob_not_found
410blob_expired
413blob_too_large, blob_total_size_too_large, chunk_too_large
409upload_incomplete

クライアント UX ガイド

Small file は single upload、max_bytes 超過時だけ chunked を使用します。App restart 後は missing_chunks を取得し、不足分だけ送ります。Media secret は E2E payload 内に残し、410 blob_expired は resend flow として扱います。

AI エージェントの統合順序

AI coding agent は RelayAuth、profile privacy、presence UI、reciprocal read receipt、reaction idempotency、single blob、chunk resume、encrypted relay_send reference の順で実装します。Relay は plaintext を検索できないため server-side chat search を追加しません。

検証済みの 2 ホップ配信

Eligible authenticated ChatRelay は network-diverse two-hop path を選べます。Source は expected terminal の signed receipt を検証してから delivery を数えます。Middle node は ciphertext だけを route します。

Node discovery と verified encrypted relay delivery