draft
mandatory
NIP ini mendefinisikan protokol dasar yang harus diterapkan oleh semua orang. NIP baru dapat menambahkan bidang dan pesan serta fitur opsional (atau wajib) baru ke struktur dan alur yang dijelaskan di sini.
Setiap pengguna memiliki pasangan kunci. Tanda tangan, kunci publik, dan pengkodean dilakukan sesuai dengan Standar tanda tangan Schnorr untuk kurva secp256k1
.
Satu-satunya tipe objek yang ada adalah event
yang memiliki format berikut pada kabelnya:
{
"id": <32-bytes lowercase hex-encoded sha256 of the serialized event data>,
"pubkey": <32-bytes lowercase hex-encoded public key of the event creator>,
"created_at": <unix timestamp in seconds>,
"kind": <integer between 0 and 65535>,
"tags": (
(<arbitrary string>...),
// ...
),
"content": <arbitrary string>,
"sig": <64-bytes lowercase hex of the signature of the sha256 hash of the serialized event data, which is the same as the "id" field>
}
Untuk mendapatkan event.id
Kami sha256
acara berseri. Serialisasi dilakukan melalui string serial JSON UTF-8 (yang dijelaskan di bawah) dengan struktur berikut:
Untuk mencegah perbedaan implementasi dari pembuatan ID peristiwa yang berbeda untuk peristiwa yang sama, aturan berikut HARUS diikuti saat membuat serial:
- UTF-8 harus digunakan untuk pengkodean.
- Spasi, jeda baris, atau pemformatan lain yang tidak perlu tidak boleh disertakan dalam output JSON.
- Karakter berikut dalam bidang konten harus di-escape seperti yang ditunjukkan, dan semua karakter lainnya harus disertakan kata demi kata:
- Jeda baris (
0x0A
), menggunakann
- Kutipan ganda (
0x22
), menggunakan"
- Garis miring terbalik (
0x5C
), menggunakan\
- Kereta kembali (
0x0D
), menggunakanr
- Karakter tab (
0x09
), menggunakant
- Spasi mundur, (
0x08
), menggunakanb
- Umpan formulir, (
0x0C
), menggunakanf
- Jeda baris (
Setiap tag adalah larik yang terdiri dari satu atau lebih string, dengan beberapa konvensi di sekelilingnya. Lihatlah contoh di bawah ini:
{
"tags": (
("e", "5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36", "wss://nostr.example.com"),
("p", "f7234bd4c1394dda46d09f35bd384dd30cc552ad5541990f98844fb06676e9ca"),
("a", "30023:f7234bd4c1394dda46d09f35bd384dd30cc552ad5541990f98844fb06676e9ca:abcd", "wss://nostr.example.com"),
("alt", "reply"),
// ...
),
// ...
}
Elemen pertama dari array tag disebut sebagai tag nama atau kunci dan yang kedua sebagai tag nilai. Jadi kita dapat dengan aman mengatakan bahwa peristiwa di atas memiliki e
tag disetel ke "5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36"
sebuah alt
tag disetel ke "reply"
dan sebagainya. Semua elemen setelah elemen kedua tidak memiliki nama konvensional.
NIP ini mendefinisikan 3 tag standar yang dapat digunakan di semua jenis acara dengan arti yang sama. Mereka adalah sebagai berikut:
- Itu
e
tag, digunakan untuk merujuk pada suatu peristiwa:("e", <32-bytes lowercase hex of the id of another event>,
) - Itu
p
tag, digunakan untuk merujuk ke pengguna lain:("p", <32-bytes lowercase hex of a pubkey>,
) - Itu
a
tag, digunakan untuk merujuk pada peristiwa yang dapat dialamatkan atau diganti- untuk acara yang dapat dialamatkan:
("a",
:<32-bytes lowercase hex of a pubkey>: , ) - untuk kejadian normal yang dapat diganti:
("a",
:<32-bytes lowercase hex of a pubkey>:, )
- untuk acara yang dapat dialamatkan:
Sebagai konvensi, semua tag kunci satu huruf (hanya huruf alfabet Inggris: az, AZ) diharapkan diindeks oleh relai, sehingga memungkinkan, misalnya, untuk menanyakan atau berlangganan peristiwa yang mereferensikan peristiwa tersebut "5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36"
dengan menggunakan {"#e": ("5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36")}
menyaring. Hanya nilai pertama dalam tag tertentu yang diindeks.
Jenis menentukan bagaimana klien harus menafsirkan arti dari setiap peristiwa dan bidang lain dari setiap peristiwa (misalnya an "r"
tag mungkin memiliki arti dalam peristiwa jenis 1 dan arti yang sama sekali berbeda dalam peristiwa jenis 10002). Setiap NIP dapat mendefinisikan arti dari serangkaian jenis yang tidak didefinisikan di tempat lain. NIP ini mendefinisikan dua jenis dasar:
0
: metadata pengguna: itucontent
diatur ke objek JSON yang dirangkai{name:
menggambarkan pengguna yang membuat acara. Bidang metadata tambahan mungkin disetel. Relai dapat menghapus peristiwa lama setelah mendapatkan peristiwa baru untuk kunci pub yang sama., about: , picture: } 1
: catatan teks: itucontent
diatur ke teks biasa isi catatan (apa pun yang ingin dikatakan pengguna). Konten yang harus diurai, seperti Markdown dan HTML, tidak boleh digunakan. Klien juga tidak boleh mengurai konten seperti itu.
Dan juga konvensi untuk rentang jenis yang memungkinkan eksperimen lebih mudah dan fleksibilitas implementasi relai:
- untuk jenis
n
seperti yang1000 <= n < 10000 || 4 <= n < 45 || n == 1 || n == 2
acara adalah biasayang berarti semuanya diharapkan disimpan oleh relay. - untuk jenis
n
seperti yang10000 <= n < 20000 || n == 0 || n == 3
acara adalah tergantikanyang artinya, untuk setiap kombinasipubkey
Dankind
hanya event terbaru yang HARUS disimpan oleh relay, versi lama MUNGKIN dibuang. - untuk jenis
n
seperti yang20000 <= n < 30000
acara adalah tdk kekalyang berarti mereka tidak diharapkan untuk disimpan oleh relay. - untuk jenis
n
seperti yang30000 <= n < 40000
acara adalah dapat dialamatkan oleh merekakind
,pubkey
Dand
nilai tag — yang berarti, untuk setiap kombinasikind
,pubkey
dan itud
nilai tag, hanya event terbaru yang HARUS disimpan oleh relay, versi lama MUNGKIN dibuang.
Jika ada peristiwa yang dapat diganti dengan stempel waktu yang sama, peristiwa dengan id terendah (yang pertama dalam urutan leksikal) harus dipertahankan, dan yang lainnya dibuang.
Saat menjawab REQ
pesan untuk acara yang dapat diganti seperti {"kinds":(0),"authors":(
bahkan jika relai menyimpan lebih dari satu versi, relai HARUS mengembalikan versi terbaru saja.
Ini hanyalah konvensi dan implementasi relai mungkin berbeda.
Relai mengekspos titik akhir soket web tempat klien dapat terhubung. Klien HARUS membuka satu koneksi websocket ke setiap relay dan menggunakannya untuk semua langganan mereka. Relai MUNGKIN membatasi jumlah koneksi dari IP/klien/dll tertentu.
Klien dapat mengirim 3 jenis pesan, yang harus berupa array JSON, sesuai dengan pola berikut:
("EVENT",
digunakan untuk mempublikasikan acara.) ("REQ",
digunakan untuk meminta acara dan berlangganan pembaruan baru., , , ...) ("CLOSE",
digunakan untuk menghentikan langganan sebelumnya.)
adalah string sembarang dan tidak kosong dengan panjang maksimal 64 karakter. Ini mewakili langganan per koneksi. Relai HARUS dikelola
s secara independen untuk setiap koneksi WebSocket.
s tidak dijamin unik secara global.
adalah objek JSON yang menentukan peristiwa apa yang akan dikirim dalam langganan itu, ia dapat memiliki atribut berikut:
Setelah menerima a REQ
pesan, relai HARUS mengembalikan peristiwa yang cocok dengan filter. Setiap peristiwa baru yang diterimanya HARUS dikirim ke soket web yang sama hingga koneksi ditutup, a CLOSE
acara diterima dengan hal yang sama
atau yang baru REQ
dikirim menggunakan yang sama
(dalam hal ini langganan baru dibuat, menggantikan langganan lama).
Filter atribut yang berisi daftar (ids
, authors
, kinds
dan tag filter seperti #e
) adalah array JSON dengan satu atau lebih nilai. Setidaknya salah satu nilai array harus cocok dengan bidang yang relevan dalam suatu peristiwa agar kondisi tersebut dianggap cocok. Untuk atribut peristiwa skalar seperti authors
Dan kind
atribut dari acara tersebut harus terdapat dalam daftar filter. Dalam hal atribut tag seperti #e
dimana suatu peristiwa mungkin memiliki beberapa nilai, nilai kondisi peristiwa dan filter harus memiliki setidaknya satu item yang sama.
Itu ids
, authors
, #e
Dan #p
daftar filter HARUS berisi nilai hex huruf kecil 64 karakter yang tepat.
Itu since
Dan until
properti dapat digunakan untuk menentukan rentang waktu peristiwa yang dikembalikan dalam langganan. Jika filter menyertakan since
properti, acara dengan created_at
lebih besar atau sama dengan since
dianggap cocok dengan filter. Itu until
properti serupa kecuali itu created_at
harus kurang dari atau sama dengan until
. Singkatnya, suatu peristiwa cocok dengan filter jika since <= created_at <= until
memegang.
Semua kondisi filter yang ditentukan harus cocok dengan suatu peristiwa agar dapat lolos filter, yaitu, beberapa kondisi diinterpretasikan sebagai &&
kondisi.
A REQ
pesan mungkin berisi beberapa filter. Dalam hal ini, peristiwa yang cocok dengan salah satu filter akan dikembalikan, yaitu, beberapa filter harus diinterpretasikan sebagai ||
kondisi.
Itu limit
properti filter hanya valid untuk kueri awal dan HARUS diabaikan setelahnya. Kapan limit: n
hadir, diasumsikan bahwa peristiwa yang dikembalikan dalam kueri awal akan menjadi yang terakhir n
acara yang dipesan oleh created_at
. Peristiwa yang lebih baru harus muncul terlebih dahulu, dan dalam kasus ikatan, peristiwa dengan id terendah (pertama dalam urutan leksikal) harus menjadi yang pertama. Aman untuk mengembalikan lebih sedikit acara daripada limit
ditentukan, tetapi relai diharapkan tidak mengembalikan (lebih) lebih banyak peristiwa daripada yang diminta sehingga klien tidak kewalahan oleh data yang tidak perlu.
Relai dapat mengirim 5 jenis pesan, yang juga harus berupa array JSON, sesuai dengan pola berikut:
("EVENT",
digunakan untuk mengirim acara yang diminta oleh klien., ) ("OK",
digunakan untuk menunjukkan penerimaan atau penolakan suatu, , ) EVENT
pesan.("EOSE",
digunakan untuk menunjukkan akhir acara yang disimpan dan awal acara yang baru diterima secara real-time.) ("CLOSED",
digunakan untuk menunjukkan bahwa langganan telah diakhiri di sisi server., ) ("NOTICE",
digunakan untuk mengirim pesan kesalahan yang dapat dibaca manusia atau hal lain ke klien.)
NIP ini tidak menjelaskan aturan bagaimana caranya NOTICE
pesan harus dikirim atau diperlakukan.
EVENT
pesan HARUS dikirim hanya dengan ID langganan yang terkait dengan langganan yang sebelumnya dimulai oleh klien (menggunakanREQ
pesan di atas).OK
pesan HARUS dikirim sebagai tanggapanEVENT
pesan yang diterima dari klien, mereka harus menyetel parameter ke-3true
ketika suatu kejadian telah diterima oleh relay,false
jika tidak. Parameter ke-4 HARUS selalu ada, tetapi MUNGKIN berupa string kosong jika parameter ke-3 adatrue
jika tidak maka HARUS berupa string yang dibentuk oleh awalan satu kata yang dapat dibaca mesin diikuti dengan a:
dan kemudian pesan yang dapat dibaca manusia. Beberapa contoh:("OK", "b1a649ebe8...", true, "")
("OK", "b1a649ebe8...", true, "pow: difficulty 25>=24")
("OK", "b1a649ebe8...", true, "duplicate: already have this event")
("OK", "b1a649ebe8...", false, "blocked: you are banned from posting here")
("OK", "b1a649ebe8...", false, "blocked: please register your pubkey at
("OK", "b1a649ebe8...", false, "rate-limited: slow down there chief")
("OK", "b1a649ebe8...", false, "invalid: event creation date is too far off from the current time")
("OK", "b1a649ebe8...", false, "pow: difficulty 26 is less than 30")
("OK", "b1a649ebe8...", false, "error: could not connect to the database")
CLOSED
pesan HARUS dikirim sebagai tanggapan terhadap aREQ
ketika relay menolak untuk memenuhinya. Itu juga dapat dikirim ketika relai memutuskan untuk mematikan langganan di sisinya sebelum klien memutus atau mengirim aCLOSE
. Pesan ini menggunakan pola yang samaOK
pesan dengan awalan yang dapat dibaca mesin dan pesan yang dapat dibaca manusia. Beberapa contoh:("CLOSED", "sub1", "unsupported: filter contains unknown elements")
("CLOSED", "sub1", "error: could not connect to the database")
("CLOSED", "sub1", "error: shutting down idle subscription")
- Awalan standar yang dapat dibaca mesin untuk
OK
DanCLOSED
adalah:duplicate
,pow
,blocked
,rate-limited
,invalid
Danerror
karena ketika tidak ada yang cocok.