mirror of
https://github.com/nostr-protocol/nips.git
synced 2025-12-08 16:18:50 +00:00
Compare commits
27 Commits
nip-60-rel
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5d64d57fc5 | ||
|
|
a6db7917f2 | ||
|
|
97d3531c44 | ||
|
|
f310614122 | ||
|
|
a4dadca077 | ||
|
|
2a33cceff6 | ||
|
|
844c6fe15c | ||
|
|
e0a2980d7a | ||
|
|
c45f504537 | ||
|
|
d8e57865d7 | ||
|
|
f63c00213f | ||
|
|
a47c460415 | ||
|
|
45668383e3 | ||
|
|
62f0b14ae8 | ||
|
|
3ec830cd23 | ||
|
|
cc77619af8 | ||
|
|
8054526b87 | ||
|
|
520b901629 | ||
|
|
bcaad2957d | ||
|
|
6e6b9877b3 | ||
|
|
3f79b7fde2 | ||
|
|
a3c5554e34 | ||
|
|
7b24bf803f | ||
|
|
d54c426709 | ||
|
|
179e421011 | ||
|
|
74681c3c14 | ||
|
|
2ace01cf1a |
5
11.md
5
11.md
@@ -17,6 +17,7 @@ When a relay receives an HTTP(s) request with an `Accept` header of `application
|
||||
"banner": <a link to an image (e.g. in .jpg, or .png format)>,
|
||||
"icon": <a link to an icon (e.g. in .jpg, or .png format>,
|
||||
"pubkey": <administrative contact pubkey>,
|
||||
"self": <relay's own pubkey>,
|
||||
"contact": <administrative alternate contact>,
|
||||
"supported_nips": <a list of NIP numbers supported by the relay>,
|
||||
"software": <string identifying relay software URL>,
|
||||
@@ -60,6 +61,10 @@ An administrative contact may be listed with a `pubkey`, in the same format as N
|
||||
|
||||
Relay operators have no obligation to respond to direct messages.
|
||||
|
||||
### Self
|
||||
|
||||
A relay MAY maintain an identity independent from its administrator using the `self` field, which MUST be a 32-byte hex public key. This allows relays to respond to requests with events published either in advance or on demand by their own key.
|
||||
|
||||
### Contact
|
||||
|
||||
An alternative contact may be listed under the `contact` field as well, with the same purpose as `pubkey`. Use of a Nostr public key and direct message SHOULD be preferred over this. Contents of this field SHOULD be a URI, using schemes such as `mailto` or `https` to provide users with a means of contact.
|
||||
|
||||
36
17.md
36
17.md
@@ -6,9 +6,15 @@ Private Direct Messages
|
||||
|
||||
`draft` `optional`
|
||||
|
||||
This NIP defines an encrypted direct messaging scheme using [NIP-44](44.md) encryption and [NIP-59](59.md) seals and gift wraps.
|
||||
This NIP defines an encrypted chat scheme which uses [NIP-44](44.md) encryption and [NIP-59](59.md) seals and gift wraps.
|
||||
|
||||
## Direct Message Kind
|
||||
Any event sent to an encrypted chat MUST NOT be signed, and MUST be encrypted as described in [NIP-59](./59.md) and illustrated below. Omitting signatures makes messages deniable in case they are accidentally or maliciously leaked, while still allowing the recipient to authenticate them.
|
||||
|
||||
By convention, `kind 14` direct messages, `kind 15` file messages, and [`kind 7` reactions](./25.md) may be sent to an encrypted chat.
|
||||
|
||||
## Kind Definitions
|
||||
|
||||
### Chat Message
|
||||
|
||||
Kind `14` is a chat message. `p` tags identify one or more receivers of the message.
|
||||
|
||||
@@ -31,7 +37,7 @@ Kind `14` is a chat message. `p` tags identify one or more receivers of the mess
|
||||
|
||||
`.content` MUST be plain text. Fields `id` and `created_at` are required.
|
||||
|
||||
An `e` tag denotes the direct parent message this post is replying to.
|
||||
An `e` tag denotes the direct parent message this post is replying to.
|
||||
|
||||
`q` tags MAY be used when citing events in the `.content` with [NIP-21](21.md).
|
||||
|
||||
@@ -39,9 +45,7 @@ An `e` tag denotes the direct parent message this post is replying to.
|
||||
["q", "<event-id> or <event-address>", "<relay-url>", "<pubkey-if-a-regular-event>"]
|
||||
```
|
||||
|
||||
Kind `14`s MUST never be signed. If it is signed, the message might leak to relays and become **fully public**.
|
||||
|
||||
## File Message Kind
|
||||
## File Message
|
||||
|
||||
```jsonc
|
||||
{
|
||||
@@ -80,8 +84,6 @@ Kind `15` is used for sending encrypted file event messages:
|
||||
- `thumb` (optional) URL of thumbnail with same aspect ratio (encrypted with the same key, nonce)
|
||||
- `fallback` (optional) zero or more fallback file sources in case `url` fails (encrypted with the same key, nonce)
|
||||
|
||||
Just like kind `14`, kind `15`s MUST never be signed.
|
||||
|
||||
## Chat Rooms
|
||||
|
||||
The set of `pubkey` + `p` tags defines a chat room. If a new `p` tag is added or a current one is removed, a new room is created with a clean message history.
|
||||
@@ -92,7 +94,7 @@ An optional `subject` tag defines the current name/topic of the conversation. An
|
||||
|
||||
## Encrypting
|
||||
|
||||
Following [NIP-59](59.md), the **unsigned** `kind:14` & `kind:15` chat messages must be sealed (`kind:13`) and then gift-wrapped (`kind:1059`) to each receiver and the sender individually.
|
||||
Following [NIP-59](59.md), the **unsigned** chat messages must be sealed (`kind:13`) and then gift-wrapped (`kind:1059`) to each receiver and the sender individually.
|
||||
|
||||
```js
|
||||
{
|
||||
@@ -127,7 +129,7 @@ Clients SHOULD randomize `created_at` in up to two days in the past in both the
|
||||
|
||||
The gift wrap's `p` tag can be the receiver's main pubkey or an alias key created to receive DMs without exposing the receiver's identity.
|
||||
|
||||
Clients CAN offer disappearing messages by setting an `expiration` tag in the gift wrap of each receiver or by not generating a gift wrap to the sender's public key
|
||||
Clients MAY offer disappearing messages by setting an `expiration` tag in the gift wrap of each receiver or by not generating a gift wrap to the sender's public key. This tag SHOULD be included on the `kind 13` seal as well, in case it leaks.
|
||||
|
||||
## Publishing
|
||||
|
||||
@@ -145,15 +147,13 @@ Kind `10050` indicates the user's preferred relays to receive DMs. The event MUS
|
||||
}
|
||||
```
|
||||
|
||||
Clients SHOULD publish kind `14` events to the `10050`-listed relays. If that is not found that indicates the user is not ready to receive messages under this NIP and clients shouldn't try.
|
||||
Clients SHOULD publish the gift-wrapped `kind 1059` events that contain the sealed rumors to the relays listed in the recipient’s kind 10050 event. If that is not found that indicates the user is not ready to receive messages under this NIP and clients shouldn't try.
|
||||
|
||||
## Relays
|
||||
|
||||
It's advisable that relays do not serve `kind:1059` to clients other than the ones tagged in them.
|
||||
Relays MAY protect message metadata by only serving `kind:1059` events to users p-tagged on the event (enforced using [NIP 42 AUTH](./42.md)).
|
||||
|
||||
It's advisable that users choose relays that conform to these practices.
|
||||
|
||||
Clients SHOULD guide users to keep `kind:10050` lists small (1-3 relays) and SHOULD spread it to as many relays as viable.
|
||||
Clients SHOULD guide users to keep `kind:10050` lists small (1-3 relays) and SHOULD spread them to as many relays as viable.
|
||||
|
||||
## Benefits & Limitations
|
||||
|
||||
@@ -170,12 +170,6 @@ This NIP offers the following privacy and security features:
|
||||
|
||||
The main limitation of this approach is having to send a separate encrypted event to each receiver. Group chats with more than 100 participants should find a more suitable messaging scheme.
|
||||
|
||||
## Implementation
|
||||
|
||||
Clients implementing this NIP should by default only connect to the set of relays found in their `kind:10050` list. From that they should be able to load all messages both sent and received as well as get new live updates, making it for a very simple and lightweight implementation that should be fast.
|
||||
|
||||
When sending a message to anyone, clients must then connect to the relays in the receiver's `kind:10050` and send the events there but can disconnect right after unless more messages are expected to be sent (e.g. the chat tab is still selected). Clients should also send a copy of their outgoing messages to their own `kind:10050` relay set.
|
||||
|
||||
## Examples
|
||||
|
||||
This example sends the message `Hola, que tal?` from `nsec1w8udu59ydjvedgs3yv5qccshcj8k05fh3l60k9x57asjrqdpa00qkmr89m` to `nsec12ywtkplvyq5t6twdqwwygavp5lm4fhuang89c943nf2z92eez43szvn4dt`.
|
||||
|
||||
23
18.md
23
18.md
@@ -21,18 +21,12 @@ reposted.
|
||||
|
||||
## Quote Reposts
|
||||
|
||||
Quote reposts are `kind 1` events with an embedded `q` tag of the note being
|
||||
quote reposted. The `q` tag ensures quote reposts are not pulled and included
|
||||
as replies in threads. It also allows you to easily pull and count all of the
|
||||
quotes for a post.
|
||||
Mentions to [NIP-21](21.md) entities like `nevent`, `note` and `naddr` on any
|
||||
event must be converted into `q` tags. The `q` tag ensures quote reposts are
|
||||
not pulled and included as replies in threads. It also allows you to easily
|
||||
pull and count all of the quotes for a post. The syntax follows
|
||||
|
||||
`q` tags should follow the same conventions as NIP 10 `e` tags, with the exception
|
||||
of the `mark` argument.
|
||||
|
||||
`["q", <event-id>, <relay-url>, <pubkey>]`
|
||||
|
||||
Quote reposts MUST include the [NIP-21](21.md) `nevent`, `note`, or `naddr` of the
|
||||
event in the content.
|
||||
`["q", "<event-id> or <event-address>", "<relay-url>", "<pubkey-if-a-regular-event>"]`
|
||||
|
||||
## Generic Reposts
|
||||
|
||||
@@ -42,3 +36,10 @@ as a "generic repost", that can include any kind of event inside other than
|
||||
|
||||
`kind 16` reposts SHOULD contain a `"k"` tag with the stringified kind number
|
||||
of the reposted event as its value.
|
||||
|
||||
When reposting a replaceable event, the repost SHOULD include an `"a"` tag with
|
||||
the event coordinate (`kind:pubkey:d-tag`) of the reposted event.
|
||||
|
||||
If the `"a"` tag is not present, it indicates that a specific version of a replaceable
|
||||
event is being reposted, in which case the `content` field must contain the full
|
||||
JSON string of the reposted event.
|
||||
|
||||
92
34.md
92
34.md
@@ -10,7 +10,7 @@ This NIP defines all the ways code collaboration using and adjacent to [`git`](h
|
||||
|
||||
## Repository announcements
|
||||
|
||||
Git repositories are hosted in Git-enabled servers, but their existence can be announced using Nostr events, as well as their willingness to receive patches, bug reports and comments in general.
|
||||
Git repositories are hosted in Git-enabled servers, but their existence can be announced using Nostr events. By doing so the author asserts themselves as a maintainer and expresses a willingness to receive patches, bug reports and comments in general, unless `t` tag `personal-fork` is included.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
@@ -25,6 +25,7 @@ Git repositories are hosted in Git-enabled servers, but their existence can be a
|
||||
["relays", "<relay-url>", ...], // relays that this repository will monitor for patches and issues
|
||||
["r", "<earliest-unique-commit-id>", "euc"],
|
||||
["maintainers", "<other-recognized-maintainer>", ...],
|
||||
["t","personal-fork"], // optionally indicate author isn't a maintainer
|
||||
["t", "<arbitrary string>"], // hashtags labelling the repository
|
||||
]
|
||||
}
|
||||
@@ -66,9 +67,13 @@ The `refs` tag can be optionally extended to enable clients to identify how many
|
||||
}
|
||||
```
|
||||
|
||||
## Patches
|
||||
## Patches and Pull Requests (PRs)
|
||||
|
||||
Patches can be sent by anyone to any repository. Patches to a specific repository SHOULD be sent to the relays specified in that repository's announcement event's `"relays"` tag. Patch events SHOULD include an `a` tag pointing to that repository's announcement address.
|
||||
Patches and PRs can be sent by anyone to any repository. Patches and PRs to a specific repository SHOULD be sent to the relays specified in that repository's announcement event's `"relays"` tag. Patch and PR events SHOULD include an `a` tag pointing to that repository's announcement address.
|
||||
|
||||
Patches SHOULD be used if each event is under 60kb, otherwise PRs SHOULD be used.
|
||||
|
||||
### Patches
|
||||
|
||||
Patches in a patch set SHOULD include a [NIP-10](10.md) `e` `reply` tag pointing to the previous patch.
|
||||
|
||||
@@ -103,9 +108,66 @@ The first patch revision in a patch revision SHOULD include a [NIP-10](10.md) `e
|
||||
|
||||
The first patch in a series MAY be a cover letter in the format produced by `git format-patch`.
|
||||
|
||||
### Pull Requests
|
||||
|
||||
The PR or PR update tip SHOULD be successfully pushed to `refs/nostr/<[PR|PR-Update]-event-id>` in all repositories listed in its `clone` tag before the event is signed.
|
||||
|
||||
An attempt SHOULD be made to push this ref to all repositories listed in the repository's announcement event's `"clone"` tag, for which their is reason to believe the user might have write access. This includes each [grasp server](https://njump.me/naddr1qvzqqqrhnypzpgqgmmc409hm4xsdd74sf68a2uyf9pwel4g9mfdg8l5244t6x4jdqy28wumn8ghj7un9d3shjtnwva5hgtnyv4mqqpt8wfshxuqlnvh8x) which can be identified using this method: `clone` tag includes `[http|https]://<grasp-path>/<valid-npub>/<string>.git` and `relays` tag includes `[ws/wss]://<grasp-path>`.
|
||||
|
||||
Clients MAY fallback to creating a 'personal-fork' `repository announcement` listing other grasp servers, e.g. from the `User grasp list`, for the purpose of serving the specified commit(s).
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"kind": 1618,
|
||||
"content": "<markdown text>",
|
||||
"tags": [
|
||||
["a", "30617:<base-repo-owner-pubkey>:<base-repo-id>"],
|
||||
["r", "<earliest-unique-commit-id-of-repo>"] // so clients can subscribe to all PRs sent to a local git repo
|
||||
["p", "<repository-owner>"],
|
||||
["p", "<other-user>"], // optionally send the PR to another user to bring it to their attention
|
||||
|
||||
["subject", "<PR-subject>"],
|
||||
["t", "<PR-label>"], // optional
|
||||
["t", "<another-PR-label>"], // optional
|
||||
|
||||
["c", "<current-commit-id>"], // tip of the PR branch
|
||||
["clone", "<clone-url>", ...], // at least one git clone url where commit can be downloaded
|
||||
["branch-name", "<branch-name>"], // optional recommended branch name
|
||||
|
||||
["e", "<root-patch-event-id>"], // optionally indicate PR is a revision of an existing patch, which should be closed
|
||||
["merge-base", "<commit-id>"], // optional: the most recent common ancestor with the target branch
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Pull Request Updates
|
||||
|
||||
A PR Update changes the tip of a referenced PR event.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"kind": 1619,
|
||||
"content": "",
|
||||
"tags": [
|
||||
["a", "30617:<base-repo-owner-pubkey>:<base-repo-id>"],
|
||||
["r", "<earliest-unique-commit-id-of-repo>"] // so clients can subscribe to all PRs sent to a local git repo
|
||||
["p", "<repository-owner>"],
|
||||
["p", "<other-user>"], // optionally send the PR to another user to bring it to their attention
|
||||
|
||||
// NIP-22 tags
|
||||
["E", "<pull-request-event-id>"],
|
||||
["P", "<pull-request-author>"],
|
||||
|
||||
["c", "<current-commit-id>"], // updated tip of PR
|
||||
["clone", "<clone-url>", ...], // at least one git clone url where commit can be downloaded
|
||||
["merge-base", "<commit-id>"], // optional: the most recent common ancestor with the target branch
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Issues
|
||||
|
||||
Issues are Markdown text that is just human-readable conversational threads related to the repository: bug reports, feature requests, questions or comments of any kind. Like patches, these SHOULD be sent to the relays specified in that repository's announcement event's `"relays"` tag.
|
||||
Issues are Markdown text that is just human-readable conversational threads related to the repository: bug reports, feature requests, questions or comments of any kind. Like patches, these SHOULD be sent to the relays specified in that repository's announcement event's `"relays"` tag.
|
||||
|
||||
Issues may have a `subject` tag, which clients can utilize to display a header. Additionally, one or more `t` tags may be included to provide labels for the issue.
|
||||
|
||||
@@ -125,11 +187,11 @@ Issues may have a `subject` tag, which clients can utilize to display a header.
|
||||
|
||||
## Replies
|
||||
|
||||
Replies to either a `kind:1621` (_issue_) or a `kind:1617` (_patch_) event should follow [NIP-22 comment](22.md).
|
||||
Replies to either a `kind:1621` (_issue_), `kind:1617` (_patch_) or `kind:1618` (_pull request_) event should follow [NIP-22 comment](22.md).
|
||||
|
||||
## Status
|
||||
|
||||
Root Patches and Issues have a Status that defaults to 'Open' and can be set by issuing Status events.
|
||||
Root Patches, PRs and Issues have a Status that defaults to 'Open' and can be set by issuing Status events.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
@@ -139,7 +201,7 @@ Root Patches and Issues have a Status that defaults to 'Open' and can be set by
|
||||
"kind": 1633, // Draft
|
||||
"content": "<markdown text>",
|
||||
"tags": [
|
||||
["e", "<issue-or-original-root-patch-id-hex>", "", "root"],
|
||||
["e", "<issue-or-PR-or-original-root-patch-id-hex>", "", "root"],
|
||||
["e", "<accepted-revision-root-id-hex>", "", "reply"], // for when revisions applied
|
||||
["p", "<repository-owner>"],
|
||||
["p", "<root-event-author>"],
|
||||
@@ -165,8 +227,22 @@ The most recent Status event (by `created_at` date) from either the issue/patch
|
||||
|
||||
The Status of a patch-revision is to either that of the root-patch, or `1632` (_Closed_) if the root-patch's Status is `1631` (_Applied/Merged_) and the patch-revision isn't tagged in the `1631` (_Applied/Merged_) event.
|
||||
|
||||
## User grasp list
|
||||
|
||||
List of [grasp servers](https://njump.me/naddr1qvzqqqrhnypzpgqgmmc409hm4xsdd74sf68a2uyf9pwel4g9mfdg8l5244t6x4jdqy28wumn8ghj7un9d3shjtnwva5hgtnyv4mqqpt8wfshxuqlnvh8x) the user generally wishes to use for NIP-34 related activity. It is similar in function to the NIP-65 relay list and NIP-B7 blossom list.
|
||||
|
||||
The event SHOULD include a list of `g` tags with grasp service websocket URLs in order of preference.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"kind": 10317,
|
||||
"content": "",
|
||||
"tags": [
|
||||
["g", "<grasp-service-websocket-url>"], // zero or more grasp sever urls
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Possible things to be added later
|
||||
|
||||
- "branch merge" kind (specifying a URL from where to fetch the branch to be merged)
|
||||
- inline file comments kind (we probably need one for patches and a different one for merged files)
|
||||
|
||||
39
37.md
39
37.md
@@ -1,50 +1,57 @@
|
||||
NIP-37
|
||||
======
|
||||
|
||||
Draft Events
|
||||
------------
|
||||
Draft Wraps
|
||||
-----------
|
||||
|
||||
`draft` `optional`
|
||||
|
||||
This NIP defines kind `31234` as a private wrap for drafts of any other event kind.
|
||||
This NIP defines kind `31234` as an encrypted storage for unsigned draft events of any other kind.
|
||||
|
||||
The draft event is JSON-stringified, [NIP44-encrypted](44.md) to the signer's public key and placed inside the `.content` of the event.
|
||||
The draft is JSON-stringified, [NIP44-encrypted](44.md) to the signer's public key and placed inside the `.content`.
|
||||
|
||||
An additional `k` tag identifies the kind of the draft event.
|
||||
`k` tags identify the kind of the draft.
|
||||
|
||||
```js
|
||||
{
|
||||
"kind": 31234,
|
||||
"tags": [
|
||||
["d", "<identifier>"],
|
||||
["k", "<kind of the draft event>"],
|
||||
["e", "<anchor event event id>", "<relay-url>"],
|
||||
["a", "<anchor event address>", "<relay-url>"],
|
||||
["k", "<kind of the draft event>"], // required
|
||||
["expiration", "now + 90 days"] // recommended
|
||||
],
|
||||
"content": nip44Encrypt(JSON.stringify(draft_event)),
|
||||
// other fields
|
||||
}
|
||||
```
|
||||
|
||||
A blanked `.content` means this draft has been deleted by a client but relays still have the event.
|
||||
A blanked `.content` field signals that the draft has been deleted.
|
||||
|
||||
Tags `e` and `a` identify one or more anchor events, such as parent events on replies.
|
||||
[NIP-40](40.md) `expiration` tags are recommended.
|
||||
|
||||
Clients SHOULD publish kind `31234` events to relays listed on kind `10013` below.
|
||||
|
||||
## Relay List for Private Content
|
||||
|
||||
Kind `10013` indicates the user's preferred relays to store private events like Drafts. The event MUST include a list of `relay` URLs in private tags. Private tags are JSON Stringified, NIP-44-encrypted to the signer's keys and placed inside the .content of the event.
|
||||
Kind `10013` indicates the user's preferred relays to store private events like Draft Wraps.
|
||||
|
||||
The event MUST include a list of `relay` URLs in private tags. Private tags are JSON Stringified, [NIP44-encrypted](44.md) to the signer's keys and placed inside the .content of the event.
|
||||
|
||||
```js
|
||||
{
|
||||
"kind": 10013,
|
||||
"tags": [],
|
||||
"content": nip44Encrypt(JSON.stringify([
|
||||
["relay", "wss://myrelay.mydomain.com"]
|
||||
]))
|
||||
"content": nip44Encrypt(
|
||||
JSON.stringify(
|
||||
[
|
||||
["relay", "wss://myrelay.mydomain.com"]
|
||||
]
|
||||
)
|
||||
)
|
||||
//...other fields
|
||||
}
|
||||
```
|
||||
|
||||
Relays listed in this event SHOULD be authed and only allow downloads to events signed by the authed user.
|
||||
It's recommended that Private Storage relays SHOULD be [NIP-42](42.md)-authed and only allow downloads of events signed by the authed user.
|
||||
|
||||
Clients SHOULD publish kind `10013` events to the author's [NIP-65](65.md) `write` relays.
|
||||
Clients MUST publish kind `10013` events to the author's [NIP-65](65.md) `write` relays.
|
||||
|
||||
146
43.md
Normal file
146
43.md
Normal file
@@ -0,0 +1,146 @@
|
||||
NIP-43
|
||||
======
|
||||
|
||||
Relay Access Metadata and Requests
|
||||
----------------------------------
|
||||
|
||||
`draft` `optional`
|
||||
|
||||
This NIP defines a way for relays to advertise membership lists, and for clients to request admission to relays on behalf of users.
|
||||
|
||||
## Membership Lists
|
||||
|
||||
Relays MAY publish a `kind 13534` event which indicates pubkeys that have access to a given relay. This event MUST be signed by the pubkey specified in the `self` field of the relay's [NIP 11](./11.md) document.
|
||||
|
||||
The following tags are required:
|
||||
|
||||
- A [NIP 70](./70.md) `-` tag
|
||||
- A `member` tag containing a hex pubkey should be included for each member
|
||||
|
||||
This list should not be considered exhaustive or authoritative. To determine membership, both a `kind 13534` event by the relay, and a `kind 10010` event by the member should be consulted.
|
||||
|
||||
Example:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"kind": 13534,
|
||||
"pubkey": "<nip11.self>",
|
||||
"tags": [
|
||||
["-"],
|
||||
["member", "c308e1f882c1f1dff2a43d4294239ddeec04e575f2d1aad1fa21ea7684e61fb5"],
|
||||
["member", "ee1d336e13779e4d4c527b988429d96de16088f958cbf6c074676ac9cfd9c958"]
|
||||
],
|
||||
// ...other fields
|
||||
}
|
||||
```
|
||||
|
||||
## Add User
|
||||
|
||||
Relays MAY publish a `kind 8000` event when a member is added to the relay. This event MUST be signed by the pubkey specified in the `self` field of the relay's [NIP 11](./11.md) document.
|
||||
|
||||
The following tags are required:
|
||||
|
||||
- A [NIP 70](./70.md) `-` tag
|
||||
- A `p` tag indicating the member's hex pubkey
|
||||
|
||||
Example:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"kind": 8000,
|
||||
"pubkey": "<nip11.self>",
|
||||
"tags": [
|
||||
["-"],
|
||||
["p", "c308e1f882c1f1dff2a43d4294239ddeec04e575f2d1aad1fa21ea7684e61fb5"]
|
||||
],
|
||||
// ...other fields
|
||||
}
|
||||
```
|
||||
|
||||
## Remove User
|
||||
|
||||
Relays MAY publish a `kind 8001` event when a member is removed from the relay. This event MUST be signed by the pubkey specified in the `self` field of the relay's [NIP 11](./11.md) document.
|
||||
|
||||
The following tags are required:
|
||||
|
||||
- A [NIP 70](./70.md) `-` tag
|
||||
- A `p` tag indicating the member's hex pubkey
|
||||
|
||||
Example:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"kind": 8001,
|
||||
"pubkey": "<nip11.self>",
|
||||
"tags": [
|
||||
["-"],
|
||||
["p", "c308e1f882c1f1dff2a43d4294239ddeec04e575f2d1aad1fa21ea7684e61fb5"]
|
||||
],
|
||||
// ...other fields
|
||||
}
|
||||
```
|
||||
|
||||
## Join Request
|
||||
|
||||
A user MAY send a `kind 28934` to a relay in order to request admission. It MUST have a `claim` tag containing an invite code. The event's `created_at` MUST be now, plus or minus a few minutes.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"kind": 28934,
|
||||
"pubkey": "<user pubkey>",
|
||||
"tags": [
|
||||
["-"],
|
||||
["claim", "<invite code>"]
|
||||
],
|
||||
// ...other fields
|
||||
}
|
||||
```
|
||||
|
||||
Upon receiving a claim, a relay MUST notify the client as to what the status of the claim is using an `OK` message. Failed claims SHOULD use the same standard `"restricted: "` prefix specified by NIP 42.
|
||||
|
||||
Relays SHOULD update their `kind 13534` member list and MAY publish a `kind 8000` "add member" event.
|
||||
|
||||
Some examples:
|
||||
|
||||
```
|
||||
["OK", <event-id>, false, "restricted: that invite code is expired."]
|
||||
["OK", <event-id>, false, "restricted: that is an invalid invite code."]
|
||||
["OK", <event-id>, true, "duplicate: you are already a member of this relay."]
|
||||
["OK", <event-id>, true, "info: welcome to wss://relay.bunk.skunk!"]
|
||||
```
|
||||
|
||||
## Invite Request
|
||||
|
||||
Users may request a claim string from a relay by making a request for `kind 28935` events. This event MUST be signed by the pubkey specified in the `self` field of the relay's [NIP 11](./11.md) document.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"kind": 28935,
|
||||
"pubkey": "<nip11.self>",
|
||||
"tags": [
|
||||
["-"],
|
||||
["claim", "<invite code>"],
|
||||
],
|
||||
// ...other fields
|
||||
}
|
||||
```
|
||||
|
||||
Note that these events are in the `ephemeral` range, which means relays must explicitly opt-in to this behavior by generating claims on the fly when requested. This allows relays to improve security by issuing a different claim for each request, only issuing claims to certain users, or expiring claims.
|
||||
|
||||
## Leave Request
|
||||
|
||||
A user MAY send a `kind 28936` to a relay in order to request that their access be revoked. The event's `created_at` MUST be now, plus or minus a few minutes. This event MUST include a [NIP 70](./70.md) `-` tag.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"kind": 28936,
|
||||
"tags": [["-"]],
|
||||
// ...other fields
|
||||
}
|
||||
```
|
||||
|
||||
Relays SHOULD update their `kind 13534` member list and MAY publish a `kind 8001` "remove member" event.
|
||||
|
||||
## Implementation
|
||||
|
||||
Clients MUST only request `kind 28935` events from and send `kind 28934` events to relays which include this NIP in the `supported_nips` section of its [NIP 11](./11.md) relay information document.
|
||||
22
45.md
22
45.md
@@ -14,17 +14,17 @@ Some queries a client may want to execute against connected relays are prohibiti
|
||||
|
||||
## Filters and return values
|
||||
|
||||
This NIP defines the verb `COUNT`, which accepts a subscription id and filters as specified in [NIP 01](01.md) for the verb `REQ`. Multiple filters are OR'd together and aggregated into a single count result.
|
||||
This NIP defines the verb `COUNT`, which accepts a query id and filters as specified in [NIP 01](01.md) for the verb `REQ`. Multiple filters are OR'd together and aggregated into a single count result.
|
||||
|
||||
```
|
||||
["COUNT", <subscription_id>, <filters JSON>...]
|
||||
["COUNT", <query_id>, <filters JSON>...]
|
||||
```
|
||||
|
||||
Counts are returned using a `COUNT` response in the form `{"count": <integer>}`. Relays may use probabilistic counts to reduce compute requirements.
|
||||
In case a relay uses probabilistic counts, it MAY indicate it in the response with `approximate` key i.e. `{"count": <integer>, "approximate": <true|false>}`.
|
||||
|
||||
```
|
||||
["COUNT", <subscription_id>, {"count": <integer>}]
|
||||
["COUNT", <query_id>, {"count": <integer>}]
|
||||
```
|
||||
|
||||
Whenever the relay decides to refuse to fulfill the `COUNT` request, it MUST return a `CLOSED` message.
|
||||
@@ -34,27 +34,27 @@ Whenever the relay decides to refuse to fulfill the `COUNT` request, it MUST ret
|
||||
### Followers count
|
||||
|
||||
```
|
||||
["COUNT", <subscription_id>, {"kinds": [3], "#p": [<pubkey>]}]
|
||||
["COUNT", <subscription_id>, {"count": 238}]
|
||||
["COUNT", <query_id>, {"kinds": [3], "#p": [<pubkey>]}]
|
||||
["COUNT", <query_id>, {"count": 238}]
|
||||
```
|
||||
|
||||
### Count posts and reactions
|
||||
|
||||
```
|
||||
["COUNT", <subscription_id>, {"kinds": [1, 7], "authors": [<pubkey>]}]
|
||||
["COUNT", <subscription_id>, {"count": 5}]
|
||||
["COUNT", <query_id>, {"kinds": [1, 7], "authors": [<pubkey>]}]
|
||||
["COUNT", <query_id>, {"count": 5}]
|
||||
```
|
||||
|
||||
### Count posts approximately
|
||||
|
||||
```
|
||||
["COUNT", <subscription_id>, {"kinds": [1]}]
|
||||
["COUNT", <subscription_id>, {"count": 93412452, "approximate": true}]
|
||||
["COUNT", <query_id>, {"kinds": [1]}]
|
||||
["COUNT", <query_id>, {"count": 93412452, "approximate": true}]
|
||||
```
|
||||
|
||||
### Relay refuses to count
|
||||
|
||||
```
|
||||
["COUNT", <subscription_id>, {"kinds": [4], "authors": [<pubkey>], "#p": [<pubkey>]}]
|
||||
["CLOSED", <subscription_id>, "auth-required: cannot count other people's DMs"]
|
||||
["COUNT", <query_id>, {"kinds": [1059], "#p": [<pubkey>]}]
|
||||
["CLOSED", <query_id>, "auth-required: cannot count other people's DMs"]
|
||||
```
|
||||
|
||||
18
47.md
18
47.md
@@ -667,3 +667,21 @@ Here are some properties that are recognized by some NWC clients:
|
||||
"sig": "31f57b369459b5306a5353aa9e03be7fbde169bc881c3233625605dd12f53548179def16b9fe1137e6465d7e4d5bb27ce81fd6e75908c46b06269f4233c845d8"
|
||||
}
|
||||
```
|
||||
|
||||
### Deep-links
|
||||
|
||||
Wallet applications can register deeplinks in mobile systems to make it possible to create a linking UX that doesn't require the user scanning a QR code or pasting some code.
|
||||
|
||||
`nostrnwc://connect` and `nostrnwc+{app_name}://connect` can be registered by wallet apps and queried by apps that want to receive an NWC pairing code.
|
||||
|
||||
All URI parameters, MUST be URI-encoded.
|
||||
|
||||
URI parameters:
|
||||
* `appicon` -- URL to an icon of the client that wants to create a connection.
|
||||
* `appname` -- Name of the client that wants to create a connection.
|
||||
* `callback` -- URI schema the wallet should open with the connection string
|
||||
|
||||
Once a connection has been created by the wallet, it should be returned to the client by opening the callback with the following parameters
|
||||
* `value` -- NWC pairing code (e.g. `nostr+walletconnect://...`)
|
||||
|
||||
|
||||
|
||||
4
51.md
4
51.md
@@ -26,7 +26,7 @@ For example, _mute list_ can contain the public keys of spammers and bad actors
|
||||
| Mute list | 10000 | things the user doesn't want to see in their feeds | `"p"` (pubkeys), `"t"` (hashtags), `"word"` (lowercase string), `"e"` (threads) |
|
||||
| Pinned notes | 10001 | events the user intends to showcase in their profile page | `"e"` (kind:1 notes) |
|
||||
| Read/write relays | 10002 | where a user publishes to and where they expect mentions | see [NIP-65](65.md) |
|
||||
| Bookmarks | 10003 | uncategorized, "global" list of things a user wants to save | `"e"` (kind:1 notes), `"a"` (kind:30023 articles), `"t"` (hashtags), `"r"` (URLs) |
|
||||
| Bookmarks | 10003 | uncategorized, "global" list of things a user wants to save | `"e"` (kind:1 notes), `"a"` (kind:30023 articles) |
|
||||
| Communities | 10004 | [NIP-72](72.md) communities the user belongs to | `"a"` (kind:34550 community definitions) |
|
||||
| Public chats | 10005 | [NIP-28](28.md) chat channels the user is in | `"e"` (kind:40 channel definitions) |
|
||||
| Blocked relays | 10006 | relays clients should never connect to | `"relay"` (relay URLs) |
|
||||
@@ -52,7 +52,7 @@ Aside from their main identifier, the `"d"` tag, sets can optionally have a `"ti
|
||||
| --- | --- | --- | --- |
|
||||
| Follow sets | 30000 | categorized groups of users a client may choose to check out in different circumstances | `"p"` (pubkeys) |
|
||||
| Relay sets | 30002 | user-defined relay groups the user can easily pick and choose from during various operations | `"relay"` (relay URLs) |
|
||||
| Bookmark sets | 30003 | user-defined bookmarks categories , for when bookmarks must be in labeled separate groups | `"e"` (kind:1 notes), `"a"` (kind:30023 articles), `"t"` (hashtags), `"r"` (URLs) |
|
||||
| Bookmark sets | 30003 | user-defined bookmarks categories , for when bookmarks must be in labeled separate groups | `"e"` (kind:1 notes), `"a"` (kind:30023 articles) |
|
||||
| Curation sets | 30004 | groups of articles picked by users as interesting and/or belonging to the same category | `"a"` (kind:30023 articles), `"e"` (kind:1 notes) |
|
||||
| Curation sets | 30005 | groups of videos picked by users as interesting and/or belonging to the same category | `"e"` (kind:21 videos) |
|
||||
| Kind mute sets | 30007 | mute pubkeys by kinds<br>`"d"` tag MUST be the kind string | `"p"` (pubkeys) |
|
||||
|
||||
4
55.md
4
55.md
@@ -295,6 +295,8 @@ For the other types Signer Application returns the column "result"
|
||||
|
||||
If the user chose to always reject the event, signer application will return the column "rejected" and you should not open signer application
|
||||
|
||||
Clients SHOULD save the user pubkey locally and avoid calling the `get_public_key` after the user is logged in to the Client
|
||||
|
||||
#### Methods
|
||||
|
||||
- **get_public_key**
|
||||
@@ -303,7 +305,7 @@ If the user chose to always reject the event, signer application will return the
|
||||
```kotlin
|
||||
val result = context.contentResolver.query(
|
||||
Uri.parse("content://com.example.signer.GET_PUBLIC_KEY"),
|
||||
listOf("login"),
|
||||
listOf(hex_pub_key),
|
||||
null,
|
||||
null,
|
||||
null
|
||||
|
||||
2
58.md
2
58.md
@@ -11,7 +11,7 @@ user profiles:
|
||||
|
||||
1. A "Badge Definition" event is defined as an addressable event with kind `30009` having a `d` tag with a value that uniquely identifies the badge (e.g. `bravery`) published by the badge issuer. Badge definitions can be updated.
|
||||
|
||||
2. A "Badge Award" event is a kind `8` event with a single `a` tag referencing a "Badge Definition" event and one or more `p` tags, one for each pubkey the badge issuer wishes to award. Awarded badges are immutable and non-transferrable.
|
||||
2. A "Badge Award" event is a kind `8` event with a single `a` tag referencing a "Badge Definition" event and one or more `p` tags, one for each pubkey the badge issuer wishes to award. Awarded badges are immutable and non-transferable.
|
||||
|
||||
3. A "Profile Badges" event is defined as an _addressable event_ with kind `30008` with a `d` tag with the value `profile_badges`.
|
||||
Profile badges contain an ordered list of pairs of `a` and `e` tags referencing a `Badge Definition` and a `Badge Award` for each badge to be displayed.
|
||||
|
||||
5
59.md
5
59.md
@@ -97,6 +97,11 @@ To protect recipient metadata, relays SHOULD only serve `kind 1059` events inten
|
||||
When possible, clients should only send wrapped events to `read` relays for the recipient that implement
|
||||
AUTH, and refuse to serve wrapped events to non-recipients.
|
||||
|
||||
When adding expiration tags to both `seal` and `gift wrap` layers, implementations SHOULD use independent random timestamps for each layer. Using different `created_at` values increases timing variance and helps protect against metadata correlation attacks.
|
||||
|
||||
Since signing keys are random, relays SHOULD delete `kind 1059` events whose p-tag matches the signer of
|
||||
[NIP-09](09.md) deletions or [NIP-62](62.md) vanish requests.
|
||||
|
||||
## An Example
|
||||
|
||||
Let's send a wrapped `kind 1` message between two parties asking "Are you going to the party tonight?"
|
||||
|
||||
21
60.md
21
60.md
@@ -22,7 +22,7 @@ This NIP doesn't deal with users' *receiving* money from someone else, it's just
|
||||
3. A user has `kind:7376` events that represent the spending history of the wallet -- This history is for informational purposes only and is completely optional.
|
||||
|
||||
### Wallet Event
|
||||
```jsonc
|
||||
```javascript
|
||||
{
|
||||
"kind": 17375,
|
||||
"content": nip44_encrypt([
|
||||
@@ -45,11 +45,12 @@ Token events are used to record unspent proofs.
|
||||
|
||||
There can be multiple `kind:7375` events for the same mint, and multiple proofs inside each `kind:7375` event.
|
||||
|
||||
```jsonc
|
||||
```javascript
|
||||
{
|
||||
"kind": 7375,
|
||||
"content": nip44_encrypt({
|
||||
"mint": "https://stablenut.umint.cash",
|
||||
"unit": "sat",
|
||||
"proofs": [
|
||||
// one or more proofs in the default cashu format
|
||||
{
|
||||
@@ -69,6 +70,7 @@ There can be multiple `kind:7375` events for the same mint, and multiple proofs
|
||||
* `.content` is a [NIP-44](44.md) encrypted payload:
|
||||
* `mint`: The mint the proofs belong to.
|
||||
* `proofs`: unencoded proofs
|
||||
* `unit` the base unit the proofs are denominated in (eg: `sat`, `usd`, `eur`). Default: `sat` if omitted.
|
||||
* `del`: token-ids that were destroyed by the creation of this token. This assists with state transitions.
|
||||
|
||||
When one or more proofs of a token are spent, the token event should be [NIP-09](09.md)-deleted and, if some proofs are unspent from the same token event, a new token event should be created rolling over the unspent proofs and adding any change outputs to the new token event (the change output should include a `del` field).
|
||||
@@ -78,12 +80,13 @@ The `kind:5` _delete event_ created in the [NIP-09](09.md) process MUST have a t
|
||||
### Spending History Event
|
||||
Clients SHOULD publish `kind:7376` events to create a transaction history when their balance changes.
|
||||
|
||||
```jsonc
|
||||
```javascript
|
||||
{
|
||||
"kind": 7376,
|
||||
"content": nip44_encrypt([
|
||||
[ "direction", "in" ], // in = received, out = sent
|
||||
[ "amount", "1" ],
|
||||
[ "unit", "sat" ],
|
||||
[ "e", "<event-id-of-created-token>", "", "created" ]
|
||||
]),
|
||||
"tags": [
|
||||
@@ -93,6 +96,7 @@ Clients SHOULD publish `kind:7376` events to create a transaction history when t
|
||||
```
|
||||
|
||||
* `direction` - The direction of the transaction; `in` for received funds, `out` for sent funds.
|
||||
* `unit` the base unit of the amount (eg: `sat`, `usd`, `eur`). Default: `sat` if omitted.
|
||||
|
||||
Clients MUST add `e` tags to create references of destroyed and created token events along with the marker of the meaning of the tag:
|
||||
* `created` - A new token event was created.
|
||||
@@ -115,12 +119,13 @@ From those relays, the client should fetch wallet and token events.
|
||||
|
||||
### Spending token
|
||||
If Alice spends 4 sats from this token event
|
||||
```jsonc
|
||||
```javascript
|
||||
{
|
||||
"kind": 7375,
|
||||
"id": "event-id-1",
|
||||
"content": nip44_encrypt({
|
||||
"mint": "https://stablenut.umint.cash",
|
||||
"unit": "sat",
|
||||
"proofs": [
|
||||
{ "id": "1", "amount": 1 },
|
||||
{ "id": "2", "amount": 2 },
|
||||
@@ -134,12 +139,13 @@ If Alice spends 4 sats from this token event
|
||||
|
||||
Her client:
|
||||
* MUST roll over the unspent proofs:
|
||||
```jsonc
|
||||
```javascript
|
||||
{
|
||||
"kind": 7375,
|
||||
"id": "event-id-2",
|
||||
"content": nip44_encrypt({
|
||||
"mint": "https://stablenut.umint.cash",
|
||||
"unit": "sat",
|
||||
"proofs": [
|
||||
{ "id": "1", "amount": 1 },
|
||||
{ "id": "2", "amount": 2 },
|
||||
@@ -153,12 +159,13 @@ Her client:
|
||||
* MUST delete event `event-id-1`
|
||||
* SHOULD add the `event-id-1` to the `del` array of deleted token-ids.
|
||||
* SHOULD create a `kind:7376` event to record the spend
|
||||
```jsonc
|
||||
```javascript
|
||||
{
|
||||
"kind": 7376,
|
||||
"content": nip44_encrypt([
|
||||
[ "direction", "out" ],
|
||||
[ "amount", "4" ],
|
||||
[ "unit", "sat" ],
|
||||
[ "e", "<event-id-1>", "", "destroyed" ],
|
||||
[ "e", "<event-id-2>", "", "created" ],
|
||||
]),
|
||||
@@ -171,7 +178,7 @@ When creating a quote at a mint, an event can be used to keep the state of the q
|
||||
|
||||
However, application developers SHOULD use local state when possible and only publish this event when it makes sense in the context of their application.
|
||||
|
||||
```jsonc
|
||||
```javascript
|
||||
{
|
||||
"kind": 7374,
|
||||
"content": nip44_encrypt("quote-id"),
|
||||
|
||||
3
61.md
3
61.md
@@ -51,6 +51,7 @@ Clients MUST prefix the public key they P2PK-lock with `"02"` (for nostr<>cashu
|
||||
"pubkey": "<sender-pubkey>",
|
||||
"tags": [
|
||||
[ "proof", "{\"amount\":1,\"C\":\"02277c66191736eb72fce9d975d08e3191f8f96afb73ab1eec37e4465683066d3f\",\"id\":\"000a93d6f8a1d2c4\",\"secret\":\"[\\\"P2PK\\\",{\\\"nonce\\\":\\\"b00bdd0467b0090a25bdf2d2f0d45ac4e355c482c1418350f273a04fedaaee83\\\",\\\"data\\\":\\\"02eaee8939e3565e48cc62967e2fde9d8e2a4b3ec0081f29eceff5c64ef10ac1ed\\\"}]\"}" ],
|
||||
[ "unit", "sat" ],
|
||||
[ "u", "https://stablenut.umint.cash" ],
|
||||
[ "e", "<nutzapped-event-id>", "<relay-hint>" ],
|
||||
[ "k", "<nutzapped-kind>"],
|
||||
@@ -62,6 +63,7 @@ Clients MUST prefix the public key they P2PK-lock with `"02"` (for nostr<>cashu
|
||||
* `.content` is an optional comment for the nutzap
|
||||
* `.tags`:
|
||||
* `proof` is one or more proofs P2PK-locked to the public key the recipient specified in their `kind:10019` event and including a DLEQ proof.
|
||||
* `unit` the base unit the proofs are denominated in (eg: `sat`, `usd`, `eur`). Default: `sat` if omitted.
|
||||
* `u` is the mint the URL of the mint EXACTLY as specified by the recipient's `kind:10019`.
|
||||
* `p` is the Nostr identity public key of nutzap recipient.
|
||||
* `e` is the event that is being nutzapped, if any.
|
||||
@@ -95,6 +97,7 @@ Multiple `kind:9321` events can be tagged in the same `kind:7376` event.
|
||||
"content": nip44_encrypt([
|
||||
[ "direction", "in" ], // in = received, out = sent
|
||||
[ "amount", "1" ],
|
||||
[ "unit", "sat" ],
|
||||
[ "e", "<7375-event-id>", "<relay-hint>", "created" ] // new token event that was created
|
||||
]),
|
||||
"tags": [
|
||||
|
||||
2
66.md
2
66.md
@@ -53,7 +53,7 @@ Example:
|
||||
["g", "ww8p1r4t8"],
|
||||
["l", "en", "ISO-639-1"],
|
||||
["t", "nsfw" ],
|
||||
["rtt-open", 234 ]
|
||||
["rtt-open", "234" ]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
8
69.md
8
69.md
@@ -41,7 +41,8 @@ Events are [addressable events](01.md#kinds) and use `38383` as event kind, a p2
|
||||
["name", "Nakamoto"],
|
||||
["g", "<geohash>"],
|
||||
["bond", "0"],
|
||||
["expiration", "1719391096"],
|
||||
["expires_at", "1719391096"],
|
||||
["expiration", "1719995896"],
|
||||
["y", "lnp2pbot"],
|
||||
["z", "order"]
|
||||
],
|
||||
@@ -55,7 +56,7 @@ Events are [addressable events](01.md#kinds) and use `38383` as event kind, a p2
|
||||
- `d` < Order ID >: A unique identifier for the order.
|
||||
- `k` < Order type >: `sell` or `buy`.
|
||||
- `f` < Currency >: The asset being traded, using the [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) standard.
|
||||
- `s` < Status >: `pending`, `canceled`, `in-progress`, `success`.
|
||||
- `s` < Status >: `pending`, `canceled`, `in-progress`, `success`, `expired`.
|
||||
- `amt` < Amount >: The amount of Bitcoin to be traded, the amount is defined in satoshis, if `0` means that the amount of satoshis will be obtained from a public API after the taker accepts the order.
|
||||
- `fa` < Fiat amount >: The fiat amount being traded, for range orders two values are expected, the minimum and maximum amount.
|
||||
- `pm` < Payment method >: The payment method used for the trade, if the order has multiple payment methods, they should be separated by a comma.
|
||||
@@ -67,7 +68,8 @@ Events are [addressable events](01.md#kinds) and use `38383` as event kind, a p2
|
||||
- `name` [Name]: The name of the maker.
|
||||
- `g` [Geohash]: The geohash of the operation, it can be useful in a face to face trade.
|
||||
- `bond` [Bond]: The bond amount, the bond is a security deposit that both parties must pay.
|
||||
- `expiration` < Expiration\>: The expiration date of the order ([NIP-40](40.md)).
|
||||
- `expires_at` < Expires At\>: The expiration date of the event being published in `pending` status, after this time the event status SHOULD be changed to `expired`.
|
||||
- `expiration` < Expiration\>: The expiration date of the event, after this time the relay SHOULD delete it ([NIP-40](40.md)).
|
||||
- `y` < Platform >: The platform that created the order.
|
||||
- `z` < Document >: `order`.
|
||||
|
||||
|
||||
12
71.md
12
71.md
@@ -26,6 +26,11 @@ The primary source of video information is the `imeta` tags which is defined in
|
||||
|
||||
Each `imeta` tag can be used to specify a variant of the video by the `dim` & `m` properties.
|
||||
|
||||
This NIP defines the following additional `imeta` properties aside form those listen in [NIP-92](92.md) & [NIP-94](94.md):
|
||||
|
||||
* `duration` (recommended) the duration of the video/audio in seconds (floating point number)
|
||||
* `bitrate` (recommended) the average bitrate of the video/audio in bits/sec
|
||||
|
||||
Example:
|
||||
```json
|
||||
[
|
||||
@@ -39,6 +44,8 @@ Example:
|
||||
"fallback https://myotherserver.com/1080/12345.mp4",
|
||||
"fallback https://andanotherserver.com/1080/12345.mp4",
|
||||
"service nip96",
|
||||
"bitrate 3000000",
|
||||
"duration 29.223"
|
||||
],
|
||||
["imeta",
|
||||
"dim 1280x720",
|
||||
@@ -50,6 +57,8 @@ Example:
|
||||
"fallback https://myotherserver.com/720/12345.mp4",
|
||||
"fallback https://andanotherserver.com/720/12345.mp4",
|
||||
"service nip96",
|
||||
"bitrate 2000000",
|
||||
"duration 29.24"
|
||||
],
|
||||
["imeta",
|
||||
"dim 1280x720",
|
||||
@@ -61,6 +70,7 @@ Example:
|
||||
"fallback https://myotherserver.com/720/12345.m3u8",
|
||||
"fallback https://andanotherserver.com/720/12345.m3u8",
|
||||
"service nip96",
|
||||
"duration 29.21"
|
||||
],
|
||||
]
|
||||
```
|
||||
@@ -74,7 +84,6 @@ Additionally `service nip96` may be included to allow clients to search the auth
|
||||
### Other tags:
|
||||
* `title` (required) title of the video
|
||||
* `published_at`, for the timestamp in unix seconds (stringified) of the first time the video was published
|
||||
* `duration` (optional) video duration in seconds
|
||||
* `text-track` (optional, repeated) link to WebVTT file for video, type of supplementary information (captions/subtitles/chapters/metadata), optional language code
|
||||
* `content-warning` (optional) warning about content of NSFW video
|
||||
* `alt` (optional) description for accessibility
|
||||
@@ -108,7 +117,6 @@ Additionally `service nip96` may be included to allow clients to search the auth
|
||||
"service nip96",
|
||||
],
|
||||
|
||||
["duration", "<duration of video in seconds>"],
|
||||
["text-track", "<encoded `kind 6000` event>", "<recommended relay urls>"],
|
||||
["content-warning", "<reason>"],
|
||||
["segment", <start>, <end>, "<title>", "<thumbnail URL>"],
|
||||
|
||||
137
BE.md
Normal file
137
BE.md
Normal file
@@ -0,0 +1,137 @@
|
||||
NIP-BE
|
||||
======
|
||||
|
||||
Nostr BLE Communications Protocol
|
||||
---------------------------------
|
||||
|
||||
`draft` `optional`
|
||||
|
||||
This NIP specifies how Nostr apps can use BLE to communicate and synchronize with each other. The BLE protocol follows a client-server pattern, so this NIP emulates the WS structure in a similar way, but with some adaptations to its limitations.
|
||||
|
||||
## Device advertisement
|
||||
A device advertises itself with:
|
||||
- Service UUID: `0000180f-0000-1000-8000-00805f9b34fb`
|
||||
- Data: Device UUID in ByteArray format
|
||||
|
||||
## GATT service
|
||||
The device exposes a Nordic UART Service with the following characteristics:
|
||||
|
||||
1. Write Characteristic
|
||||
- UUID: `87654321-0000-1000-8000-00805f9b34fb`
|
||||
- Properties: Write
|
||||
|
||||
2. Read Characteristic
|
||||
- UUID: `12345678-0000-1000-8000-00805f9b34fb`
|
||||
- Properties: Notify, Read
|
||||
|
||||
## Role assignment
|
||||
|
||||
When one device initially finds another advertising the service, it will read the service's data to get the device UUID and compare it with its own advertised device UUID. For this communication, the device with the highest ID will take the role of GATT Server (Relay), the other will be considered the GATT Client (Client) and will proceed to establish the connection.
|
||||
|
||||
For devices whose purpose will require a single role, its device UUID will always be:
|
||||
|
||||
- GATT Server: `FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF`
|
||||
- GATT Client: `00000000-0000-0000-0000-000000000000`
|
||||
|
||||
## Messages
|
||||
|
||||
All messages will follow [NIP-01](/01.md) message structure. For a given message, a compression stream (DEFLATE) is applied to the message to generate a byte array. Depending on the BLE version, the byte array can be too large for a single message (20-23 bytes in BLE 4.2, 256 bytes in BLE > 4.2). In that case, this byte array is split into any number of batches following the structure:
|
||||
|
||||
```
|
||||
[batch index (first 2 bytes)][batch n][is last batch (last byte)]
|
||||
```
|
||||
After reception of all batches, the other device can then join them and decompress. To ensure reliability, only 1 message will be read/written at a time. MTU can be negotiated in advance. The maximum size for a message is 64KB; bigger messages will be rejected.
|
||||
|
||||
## Examples
|
||||
|
||||
This example implements a function to split and compress a byte array into chunks, as well as another function to join and decompress them in order to obtain the initial result:
|
||||
|
||||
```kotlin
|
||||
fun splitInChunks(message: ByteArray): Array<ByteArray> {
|
||||
val chunkSize = 500 // define the chunk size
|
||||
var byteArray = compressByteArray(message)
|
||||
val numChunks = (byteArray.size + chunkSize - 1) / chunkSize // calculate the number of chunks
|
||||
var chunkIndex = 0
|
||||
val chunks = Array(numChunks) { ByteArray(0) }
|
||||
|
||||
for (i in 0 until numChunks) {
|
||||
val start = i * chunkSize
|
||||
val end = minOf((i + 1) * chunkSize, byteArray.size)
|
||||
val chunk = byteArray.copyOfRange(start, end)
|
||||
|
||||
// add chunk index to the first 2 bytes and last chunk flag to the last byte
|
||||
val chunkWithIndex = ByteArray(chunk.size + 2)
|
||||
chunkWithIndex[0] = chunkIndex.toByte() // chunk index
|
||||
chunk.copyInto(chunkWithIndex, 1)
|
||||
chunkWithIndex[chunkWithIndex.size - 1] = numChunks.toByte()
|
||||
|
||||
// store the chunk in the array
|
||||
chunks[i] = chunkWithIndex
|
||||
|
||||
chunkIndex++
|
||||
}
|
||||
|
||||
return chunks
|
||||
}
|
||||
|
||||
fun joinChunks(chunks: Array<ByteArray>): ByteArray {
|
||||
val sortedChunks = chunks.sortedBy { it[0] }
|
||||
var reassembledByteArray = ByteArray(0)
|
||||
for (chunk in sortedChunks) {
|
||||
val chunkData = chunk.copyOfRange(1, chunk.size - 1)
|
||||
reassembledByteArray = reassembledByteArray.copyOf(reassembledByteArray.size + chunkData.size)
|
||||
chunkData.copyInto(reassembledByteArray, reassembledByteArray.size - chunkData.size)
|
||||
}
|
||||
|
||||
return decompressByteArray(reassembledByteArray)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Workflows
|
||||
|
||||
### Client to relay
|
||||
|
||||
- Any message the client wants to send to a relay will be a write message.
|
||||
- Any message the client receives from a relay will be a read message.
|
||||
|
||||
### Relay to client
|
||||
|
||||
The relay should notify the client about any new event matching subscription's filters by using the Notify action of the Read Characteristic. After that, the client can proceed to read messages from the relay.
|
||||
|
||||
### Device synchronization
|
||||
|
||||
Given the nature of BLE, it is expected that the direct connection between two devices might be extremely intermittent, with gaps of hours or even days. That's why it's crucial to define a synchronization process by following [NIP-77](./77.md) but with an adaptation to the limitations of the technology.
|
||||
|
||||
After two devices have successfully connected and established the Client-Server roles, the devices will use half-duplex communication to intermittently send and receive messages.
|
||||
|
||||
#### Half-duplex synchronization
|
||||
|
||||
Right after the 2 devices connect, the Client starts the workflow by sending the first message.
|
||||
|
||||
1. Client - Writes ["NEG-OPEN"](/77.md#initial-message-client-to-relay) message.
|
||||
2. Server - Sends `write-success`.
|
||||
3. Client - Sends `read-message`.
|
||||
4. Server - Responds with ["NEG-MSG"](./77.md#subsequent-messages-bidirectional) message.
|
||||
5. Client -
|
||||
1. If the Client has messages missing on the Server, it writes one `EVENT`.
|
||||
2. If the Client doesn't have any messages missing on the Server, it writes `EOSE`. In this case, subsequent messages to the Server will be empty while the Server claims to have more notes for the Client.
|
||||
6. Server - Sends `write-success`.
|
||||
7. Client - Sends `read-message`.
|
||||
8. Server -
|
||||
1. If the Server has messages missing on the Client, it responds with one `EVENT`.
|
||||
2. If the Client doesn't have any messages missing on the Server, it responds with `EOSE`. In this case, subsequent responses to the Client will be empty.
|
||||
9. If the Client detects that the devices are not synchronized yet, jump to step 5.
|
||||
10. After the two devices detect that there are no more missing events on both ends, the workflow will pause at this point.
|
||||
|
||||
#### Half-duplex event spread
|
||||
|
||||
While two devices are connected and synchronized, it might happen that one of them receives a new message from another connected peer. Devices MUST keep track of which notes have been sent to its peers while they are connected. If the newly received event is detected as missing in one of the connected and synchronized peers:
|
||||
|
||||
1. If the peer is a Server:
|
||||
1. Client - It writes the `EVENT`.
|
||||
2. Server - Sends `write-success`.
|
||||
2. If the peer is a Client:
|
||||
1. Server - It will send an empty notification to the Client.
|
||||
2. Client - Sends `read-message`.
|
||||
3. Server - Responds with the `EVENT`.
|
||||
4
C0.md
4
C0.md
@@ -23,9 +23,9 @@ The `.content` field contains the actual code snippet text.
|
||||
- `extension` - File extension (without the dot). Examples: "js", "py", "rs"
|
||||
- `description` - Brief description of what the code does
|
||||
- `runtime` - Runtime or environment specification (e.g., "node v18.15.0", "python 3.11")
|
||||
- `license` - License under which the code is shared (e.g., "MIT", "GPL-3.0", "Apache-2.0")
|
||||
- `license` - License under which the code (along with any related data contained within the event, when available, such as the description) is shared. This MUST be a standard [SPDX](https://spdx.org/licenses/) short identifier (e.g., "MIT", "GPL-3.0-or-later", "Apache-2.0") when available. An additional parameter containing a reference to the actual text of the license MAY be provided. This tag can be repeated, to indicate multi-licensing, allowing recipients to use the code under any license of choosing among the referenced ones
|
||||
- `dep` - Dependency required for the code to run (can be repeated)
|
||||
- `repo` - Reference to a repository where this code originates
|
||||
- `repo` - Reference to a repository where this code originates. This MUST be a either standard URL or, alternatively, the address of a [NIP-34](34.md) Git repository announcement event in the form `"30617:<32-bytes hex a pubkey>:<d tag value>"`. If a repository announcement is referenced, a recommended relay URL where to find the event should be provided as an additional parameter
|
||||
|
||||
## Format
|
||||
|
||||
|
||||
6
EE.md
6
EE.md
@@ -1,6 +1,8 @@
|
||||
# NIP-EE
|
||||
NIP-EE
|
||||
======
|
||||
|
||||
## E2EE Messaging using the Messaging Layer Security (MLS) Protocol
|
||||
E2EE Messaging using the Messaging Layer Security (MLS) Protocol
|
||||
----------------------------------------------------------------
|
||||
|
||||
`draft` `optional`
|
||||
|
||||
|
||||
13
README.md
13
README.md
@@ -58,6 +58,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
- [NIP-39: External Identities in Profiles](39.md)
|
||||
- [NIP-40: Expiration Timestamp](40.md)
|
||||
- [NIP-42: Authentication of clients to relays](42.md)
|
||||
- [NIP-43: Relay Access Metadata and Requests](43.md)
|
||||
- [NIP-44: Encrypted Payloads (Versioned)](44.md)
|
||||
- [NIP-45: Counting results](45.md)
|
||||
- [NIP-46: Nostr Remote Signing](46.md)
|
||||
@@ -104,6 +105,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
- [NIP-A0: Voice Messages](A0.md)
|
||||
- [NIP-B0: Web Bookmarks](B0.md)
|
||||
- [NIP-B7: Blossom](B7.md)
|
||||
- [NIP-BE: Nostr BLE Communications Protocol](BE.md)
|
||||
- [NIP-C0: Code Snippets](C0.md)
|
||||
- [NIP-C7: Chats](C7.md)
|
||||
- [NIP-EE: E2EE Messaging using MLS Protocol](EE.md)
|
||||
@@ -160,6 +162,8 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
| `1311` | Live Chat Message | [53](53.md) |
|
||||
| `1337` | Code Snippet | [C0](C0.md) |
|
||||
| `1617` | Patches | [34](34.md) |
|
||||
| `1618` | Pull Requests | [34](34.md) |
|
||||
| `1619` | Pull Request Updates | [34](34.md) |
|
||||
| `1621` | Issues | [34](34.md) |
|
||||
| `1622` | Git Replies (deprecated) | [34](34.md) |
|
||||
| `1630`-`1633` | Status | [34](34.md) |
|
||||
@@ -180,6 +184,8 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
| `7376` | Cashu Wallet History | [60](60.md) |
|
||||
| `7516` | Geocache log | [geocaching][geocaching] |
|
||||
| `7517` | Geocache proof of find | [geocaching][geocaching] |
|
||||
| `8000` | Add User | [43](43.md) |
|
||||
| `8001` | Remove User | [43](43.md) |
|
||||
| `9000`-`9030` | Group Control Events | [29](29.md) |
|
||||
| `9041` | Zap Goal | [75](75.md) |
|
||||
| `9321` | Nutzap | [61](61.md) |
|
||||
@@ -211,6 +217,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
| `10377` | Proxy Announcement | [Nostr Epoxy][nostr-epoxy] |
|
||||
| `11111` | Transport Method Announcement | [Nostr Epoxy][nostr-epoxy] |
|
||||
| `13194` | Wallet Info | [47](47.md) |
|
||||
| `13534` | Membership Lists | [43](43.md) |
|
||||
| `17375` | Cashu Wallet Event | [60](60.md) |
|
||||
| `21000` | Lightning Pub RPC | [Lightning.Pub][lnpub] |
|
||||
| `22242` | Client Authentication | [42](42.md) |
|
||||
@@ -219,6 +226,9 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
| `24133` | Nostr Connect | [46](46.md) |
|
||||
| `24242` | Blobs stored on mediaservers | [Blossom][blossom] |
|
||||
| `27235` | HTTP Auth | [98](98.md) |
|
||||
| `28934` | Join Request | [43](43.md) |
|
||||
| `28935` | Invite Request | [43](43.md) |
|
||||
| `28936` | Leave Request | [43](43.md) |
|
||||
| `30000` | Follow sets | [51](51.md) |
|
||||
| `30001` | Generic lists | 51 (deprecated) |
|
||||
| `30002` | Relay sets | [51](51.md) |
|
||||
@@ -317,6 +327,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
| ----------------- | ------------------------------------ | ------------------------------- | -------------------------------------------------- |
|
||||
| `a` | coordinates to an event | relay URL | [01](01.md) |
|
||||
| `A` | root address | relay URL | [22](22.md) |
|
||||
| `c` | commit id | | [34](34.md) |
|
||||
| `d` | identifier | -- | [01](01.md) |
|
||||
| `e` | event id (hex) | relay URL, marker, pubkey (hex) | [01](01.md), [10](10.md) |
|
||||
| `E` | root event id | relay URL | [22](22.md) |
|
||||
@@ -345,6 +356,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
| `alt` | summary | -- | [31](31.md) |
|
||||
| `amount` | millisatoshis, stringified | -- | [57](57.md) |
|
||||
| `bolt11` | `bolt11` invoice | -- | [57](57.md) |
|
||||
| `branch-name` | branch name suggestion | -- | [34](34.md) |
|
||||
| `challenge` | challenge string | -- | [42](42.md) |
|
||||
| `client` | name, address | relay URL | [89](89.md) |
|
||||
| `clone` | git clone URL | -- | [34](34.md) |
|
||||
@@ -358,6 +370,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
| `expiration` | unix timestamp (string) | -- | [40](40.md) |
|
||||
| `file` | full path (string) | -- | [35](35.md) |
|
||||
| `goal` | event id (hex) | relay URL | [75](75.md) |
|
||||
| `merge-base` | commit id | | [34](34.md) |
|
||||
| `HEAD` | `ref: refs/heads/<branch-name>` | | [34](34.md) |
|
||||
| `image` | image URL | dimensions in pixels | [23](23.md), [52](52.md), [58](58.md) |
|
||||
| `imeta` | inline metadata | -- | [92](92.md) |
|
||||
|
||||
Reference in New Issue
Block a user