Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NIP-81 - Event Copy #528

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions 81.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
NIP-81
======

Event Copy
----------

`draft` `optional` `author:arthurfranca`

An event of `kind 1006` is used to copy any event from another author (except other copies). A copy
allows its creator to keep content around even when the original gets deleted.

The `.content` of a copy event SHOULD be the stringified JSON of the whole original event,
optionally with extra fields inside a `.meta` key.
The `.content` MAY be empty to represent a deleted event.

The copy event MUST include a `published_at` tag with the same value from the original event
or with the original event's `created_at` value if its `published_at` tag is absent.

The copy event SHOULD include the following tags so to make them queriable:

- Capital `I` tag with original event's `id`;
- Capital `P` tag with original event's `pubkey`;
- Capital `K` tag with original event's `kind`;
- All original event's single-letter tags.

`I`, `P` and `K` tags are reserved. They cannot be used by any other event kind.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Example: if I'm copying an event that already has one P tag that also is a pubkey value, although with a custom meaning specific to that event kind, i end up with:

{
  // other fields
  "kind": 1006,
  "tags": [
    // other tags,
    ["P", "pubkeyA"], // copied from original event's "pubkey" field
    ["P", "pubkeyX"]  // copied from original event's one-letter tags
  ]
}

Now if I were to request one of the copies I made, and wanted a copy that had originally the pubkey field value "pubkeyX", I do ["REQ", "xyz", "{ \"kind\": 1006, \"#P\": [ \"pubkeyX\"], \"K\": .... }]. This will wrongly bring me the above event.

That's why ideally we consider I, P and K in events other than copies invalid. Don't copy these invalid events and you will not have to filter things out client-side.

For the same reason I didn't make it a parameterized replaceable event (the original could alread have a "d" tag and its worse cause maybe only the first d tag is indexed on some relay implementations, cause of what is written on NIP-33)

This is similar to the problem NIP-10 introduced. Can't request direct descendants of a specific root event without filtering out a bunch of events I don't want just because although the e tag means event id, it is used with different contexts ("root", "reply" and the legacy "mention").


## Use Cases

It is useful for any case one would benefit for owning someone else's event.

Clients can request both originals and copies to increase the chance of finding the events
they are interested in.

# Relay Event Re-publishing

It enables storing someone else's events while consuming one own event quota,
in case of relays that forbids different author event publishing.
The user can later delete it to free some quota.

# DM Inbox

The benefit comes from being able to soft-delete a received DM (by using a copy with empty `.content`),
making it possible to control one own inbox. Received DMs without copies may be considered unread.

# Group Moderation

A group admin may soft-delete events by using a copy with an empty content.
It can use a copy's `.meta.moderation.content` to take out curse words from the original content.
Clients should request group messages along with admin copies.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
| `42` | Channel Message | [28](28.md) |
| `43` | Channel Hide Message | [28](28.md) |
| `44` | Channel Mute User | [28](28.md) |
| `1006` | Event Copy | [81](81.md) |
| `1063` | File Metadata | [94](94.md) |
| `1984` | Reporting | [56](56.md) |
| `9734` | Zap Request | [57](57.md) |
Expand Down Expand Up @@ -149,6 +150,9 @@ When experimenting with kinds, keep in mind the classification introduced by [NI
| `p` | pubkey (hex) | relay URL | [1](01.md) |
| `r` | a reference (URL, etc) | -- | [12](12.md) |
| `t` | hashtag | -- | [12](12.md) |
| `I` | (reserved) copied id | -- | [81](81.md) |
| `P` | (reserved) copied pubkey | -- | [81](81.md) |
| `K` | (reserved) copied kind | -- | [81](81.md) |
| `amount` | millisats | -- | [57](57.md) |
| `bolt11` | `bolt11` invoice | -- | [57](57.md) |
| `challenge` | challenge string | -- | [42](42.md) |
Expand Down