RSS3 Protocol v0.4.0-rc.1

1. Abstract

The right to create, disseminate and distribute information should not be in the hands of centralized governing. It is the basic right of cyber lives.

Gradually over the past two decades, several data superpowers have controlled contents and links to create a toxic centralized atmosphere, where privacy and freedom are sacrificed for profits. This atmosphere further hinders innovations: No matter how well you design and engineer your application, there is no way to compete with the data monopolies.

The world has been eager for a new way of information syndication. RSS used to be the pioneer of its time, now itโ€™s time for us to pick up the baton and carry on.

Derived from the best out of RSS, RSS3 is an open information syndication protocol that aims to support efficient and decentralized information distribution in Web3.

This document defines the aggregation format and communication of information for cryptographically based decentralized accounts.

2. Status of This Document

This version is a beta version, although this protocol is well established in theory, it still needs to be tested in practice, so it is not guaranteed to be compatible with subsequent versions, but breaking updates will be kept to a minimum.

3. Dependencies

4. Main Concepts

4.1. File

The RSS3 Network returns data and the user submits data in the form of RSS3-compliant JSON files. There are two types of files, Index File and their attached List File, of which you can get an overview by browsing through the Use Cases.

The mime_type of RSS3 file is application/rss3+json, it is recommended to include content-type: application/rss3+json; charset=utf-8 in the Response Headers of RSS3 file.

4.1.1. File Base

Each file has some basic properties.

type FileBase = {
    version: 'v0.4.0';
    identifier: InstanceURI | CustomItemListURI | AggregatedItemListURI | CustomLinkListURI | AggregatedLinkListURI | BacklinkListURI;
    date_created: string;
    date_updated: string;
} & (SignedBase | UnsignedBase);
4.1.1.1. version

Version of the protocol, the current is v0.4.0.

4.1.1.2. identifier

The URI of the current file, which should also contain the query if there is one.

4.1.1.3. date_created and date_updated

The creation time and update time of the file, in the format of extended ISO 8601 with 3 decimals (YYYY-MM-DDTHH:mm:ss.sssZ).

4.1.1.4. SignedBase and UnsignedBase

See Authentication.

4.1.2. Index File

The Index file is the main entry point for the instance and holds general information about the instance, including the details of profile and URIs of the links or items list, etc.

type IndexFile = FileBase & {
    profile?: Profile;
    links: LinksSet;
    items: ItemsSet;
}

4.1.3. List File

The list file is used to store the list data, including various item lists and link lists.

TypeSignedURIList Element
Custom Item ListtrueCustomItemListURIItem
Aggregated Item ListfalseAggregatedItemListURIItem
Custom Link Listtrue or falseCustomLinkListURIInstanceURI
Aggregated Link ListfalseAggregatedLinkListURIInstanceURI
Backlink ListfalseBacklinkListURIInstanceURI
type ListFile<URIType, ElementType> = FileBase & {
    identifier: URIType;
    identifier_next?: URIType;

    total: number;
    list?: ElementType[];
}

// for items
type CustomItemList = SignedBase & ListBase<CustomItemListURI, Item>;
type AggregatedItemList = UnsignedBase & ListBase<AggregatedItemListURI, Item>;

// for links
type CustomLinkList = (SignedBase | UnsignedBase) & ListBase<CustomLinkListURI, InstanceURI>;
type AggregatedLinkList = UnsignedBase & ListBase<AggregatedLinkListURI, InstanceURI>;
type BacklinkList = UnsignedBase & ListBase<BacklinkListURI, InstanceURI>;
4.1.3.1. list

List element, depending on the type of the list file, may be item, link, backlink, etc.

4.1.3.2. identifier_next

The URI used to identify the next page. If not specified, the current page is the last one by default.

For example:

{
    "identifier":      "rss3://account:[email protected]/list/note/1",
    "identifier_next": "rss3://account:[email protected]/list/note/0"
}
{
    "identifier":      "rss3://account:[email protected]/list/note?limit=5",
    "identifier_next": "rss3://account:[email protected]/list/note?limit=5&last_time=2022-01-01T00:00:00Z"
}
4.1.3.3. total

Total number of elements in this page and its next pages.

4.2. Account

In order to remain open and compatible, the protocol does not create a new account system. Instead, it is compatible with existing account systems of other platforms, including accounts of cryptography-based decentralized and centralized platforms.

There are two types of accounts

  • Main Account: the account in the instance URI, which represents the owner and signer of the file and can only be of a decentralized platform.

  • Connected Accounts: accounts in the profile.account field, which represents other accounts belonging to the instance.

An account consists of two pieces of information: the account ID and the platform to which the account belongs.

Account = <identity>@<account_platform>

For example,

4.3. Instance

An instance is an RSS3 interactive object, an RSS3 presence unit that contains an RSS3 Index file and its attached list files.

Instance = <prefix>:<identity>@<platform>

4.3.1. Account Instance

An Account Instance is an Instance created with an account.

AccountInstance = account:<account_identity>@<account_platform>

For example,

4.3.2. Item Instance

Before continuing, you may need to learn about Item Types.

An Item Instance is an Instance for Item.

ItemInstance = CustomItemInstance | IndexedItemInstance

IndexedItemInstance = {asset|note}:<metadata_proof>@<item_network>
CustomItemInstance  = {asset|note}:<account_platform>-<account_identity>-<item_date_created_timestamp>@rss3

WARNING

date_created is used to compose the unique ID, which means that no items with the same date_created can exist under the same Account Instance.

For example,

4.4. Identifier

The protocol uses a number of Uniform Resource Identifiers (URIs) that conform to the RFC 3986open in new window standard to identify things in RSS3, such as instance identifiers, item identifiers, and list identifiers. The RSS3 URI can be used by users to access the items it represents or as the target of a link.

4.4.1. Scheme

The scheme is rss3. I.e. RSS3 URI starts with rss3://.

4.4.2. Authority

The protocol uses Instance as an authority.

4.4.3. URI

The below illustrates the component of each URI.

4.4.3.1. Instance URI
InstanceURI = AccountInstanceURI | ItemInstanceURI

AccountInstanceURI = rss3://<AccountInstance>
ItemInstanceURI = rss3://<ItemInstance>

E.g.

4.4.3.2. Item List URI
CustomItemListURI     = rss3://<Instance>/list/{note|asset}/<page_index>
AggregatedItemListURI = rss3://<Instance>/list/{note|asset}[?<query_string>]

If page_index exists, then the list is Custom Item list and uses it for pagination. The starting index page_index is 0.

If page_index does not exist, then the list is an aggregated item list, which may include both Custom Items and Indexed Items.

Please refer to Item to know more.

Available queries:

KeyUsage
limitUsed for pagination, limiting the count of the returning items. There should be a maximum and minimal value when implementing.
last_timeUsed for pagination. An ISO 8601 time. If specified, returning only items before this time.
link_typeIf specified, returning only the corresponding link type of items.
filter_tagsIf specified, returning only items of the corresponding tags (filtered using the tags attribute of items). Multiple values are separated by commas.
filter_autoIf true, returning only items with auto field set to true. If false, the opposite. If not available, no filter on this effect will be applied.
filter_networkIf specified, returning only items with metadata.network field in the filter list. Multiple values are separated by commas.
filter_mime_typesIf specified, returning only items with attachments.mime_type field containing the corresponding values. Multiple values are separated by commas.

E.g.,

  • The custom note list in the second list page:

    rss3://account:[email protected]/list/note/1
    
  • The list of the first 5 notes:

    rss3://account:[email protected]/list/note?limit=5
    
  • The note list from the instance's following instances:

    rss3://account:[email protected]/list/note?link_type=following
    
CustomLinkListURI     = rss3://<Instance>/list/link/<link_type>/<page_index>
AggregatedLinkListURI = rss3://<Instance>/list/link/<link_type>[?<query_string>]

link_type is defined by RIP-5: Registered Link Types.

Available queries:

KeyUsage
limitUsed for pagination, limiting the count of the returning items. There should be a maximum and minimal value when implementing.
last_instanceUsed for pagination. If specified, returning the instances after this instance.
instanceIf specified, returning only the list containing this instance. If specified but no list satisfies, returning null.

E.g.

  • The following link list in the second list page:

    rss3://account:[email protected]/list/link/following/1
    
  • The following link list of the first 5 instances:

    rss3://account:[email protected]/list/link/following?limit=5
    
  • Query if an instance is followed by another instance:

    rss3://account:[email protected]/list/link/following?instance=0xC8b960D09C0078c18Dcbe7eB9AB9d816BcCa8944
    
BacklinkListURI = rss3://<Instance>/list/backlink[?<query_string>]

Available queries:

KeyUsage
typeReturning only backlinks of this type.
limitUsed for pagination, limiting the count of the returning items. There should be a maximum and minimal value when implementing.
last_instanceUsed for pagination. If specified, returning the instances after this instance.
instanceIf specified, returning only the list containing this instance. If specified but no list satisfies, returning null.

E.g.

  • The following list of the first 5 instances:

    rss3://account:[email protected]/list/backlink?type=following&limit=5
    
  • Query if an instance is following another instance:

    rss3://account:[email protected]/list/backlink?type=following&instance=0xC8b960D09C0078c18Dcbe7eB9AB9d816BcCa8944
    
  • A noteโ€™s comments:

    rss3://account:[email protected]/notes/5591079b-1f5b-4ae9-8209-51b18f0d3be0/list/backlink/comment
    

4.5. Item

Item is an action or good that is automatically or passively generated by an instance. The protocol cannot predict what types of content there will be, so the protocol strives to define it more generically and unrestricted. It may be a blog post, an NFT, or a commodity, a game activity, etc.

4.5.1. Item Types

4.5.1.1. According to source
  • Indexed Items: Items automatically indexed by the RSS3 Network from other networks or platforms based on the Main Account and Connected Accounts, as defined in RIP-4: Registered Indexed Items.

  • Custom Items: Items signed and submitted by user themselves.

4.5.1.1. According to content
  • Assets: They are the assets owned by instances, which can also be extended and interpreted as any fixed display content according to different usage scenarios, such as an NFT, a game achievement, a physical figure, a commodity for sale, etc.

  • Notes: They are the actions or events generated by the instance, which can also be extended and interpreted as any stream content according to different usage scenarios, such as writing a blog post, getting a NFT dynamic, writing a forum post, posting a reply to other items, etc.

4.5.2. Item Overall

The structure of Items could be seen in an index file:

type ItemsSet = {
    notes: {
        identifier_custom?: CustomItemListURI;
        identifier: AggregatedItemListURI;
        filters?: Filters;
    };
    assets: {
        identifier_custom?: CustomItemListURI;
        identifier: AggregatedItemListURI;
        filters?: Filters;
    };
};
4.5.2.1. items.assets

assets are the items owned by instances, which can also be extended and interpreted as any fixed display content according to different usage scenarios, such as an NFT, a game achievement, a physical figure, a commodity for sale, etc.

4.5.2.2. items.notes

notes are the actions or events generated by the instance, which can also be extended and interpreted as any stream content according to different usage scenarios, such as writing a blog post, getting a NFT dynamic, writing a forum post, posting a reply to other items, etc.

4.5.2.3. items.x.identifier_custom

identifier_custom records the URI of the Custom Item list on the last page, and the list element is the item submitted by the user himself.

When there is only one page of content, the value of identifier_custom is rss3://<Instance>/list/{note|asset}/0 till the content exceeds the file size limit specified by the RSS3 Network. Then the new item is recorded in a new file whose URI is rss3://<Instance>/list/{note|asset}/1, and the identifier_custom field is changed to rss3://<Instance>/list/{note|asset}/1.

4.5.2.4. items.x.identifier

identifier is the URI of the aggregated item list, which contains both Custom Items and Indexed Items, sorted by date_created, the newest at the top. It supports some queries.

4.5.2.5. items.x.filters

filters are used to filter the Index Items returned by identifier to meet the needs of the user's selective display.

It filters on item.tags and item.metadata.network.

type Filters = {
    blocklist?: string[];
    allowlist?: string[];
}
4.5.2.5.1. items.x.filters.blocklist

Prevent items or backlinks containing fields in this list from being returned, e.g. blocklist: ["twitter"], in which case, items with item.tags and item.metadata.network value of twitter will not be returned by AggregatedItemListURI.

4.5.2.5.2. items.x.filters.allowlist

Only items or backlinks that contain fields in this list are allowed to be returned. If there is an allowlist, the blocklist will be invalid. For example, if allowlist: ["twitter"], then only items with item.tags and item.metadata.network value of twitter will be returned by AggregatedItemListURI.

4.5.3. Item Details

type Item = {
    identifier: ItemInstanceURI;
    date_created: string;
    date_updated: string;

    auto?: true;
    related_urls?: string[];

    links: LinksSet;

    tags?: string[];
    authors: Account[];
    title?: string;
    summary?: string;
    attachments?: Attachment[];

    metadata?: {
        network: NetworkName;
        proof: string;

        [key: string]?: any;
    };
};
4.5.3.1. item.date_created

The time when the action or item was generated, in the format of ISO 8601, such as the time when the article was published, the time when the NFT was mint, the time when the product was put on the shelf, the time when the NFT was obtained (in the note, it indicates the time when the action was generated), etc.

4.5.3.2. item.date_updated

The time of an action or item change, in the format of ISO 8601, such as article modification time, acquisition time of NFT (in the asset, indicating the time of the item change), etc.

4.5.3.3. item.auto

If true, it means this is a Indexed Item rather than an Custom Item.

Only for Custom Items. URLs associated with the item, such as the address of the item in the indexed network.

4.5.3.5. item.identifier

identifier is the uri of the item. See Instance URI.

See Link.

4.5.3.7. item.tags

tags is an array of strings. Similar to the concept of tags commonly used in personal blogs, you can add multiple tags to an article; the Indexed Items will also have tags, indicating the type of the item, and the specific value is limited in RIP-4: Registered Indexed Items.

4.5.3.8. item.authors

authors is an array of Accounts, indicating the accounts who have produced this item, such as the author of the article, the seller of the product, etc. It can be omitted if it is the current instance address.

If the item is an Indexed Item and the author is a Connected Account, it will additionally contain the Main Account.

4.5.3.9. item.title and item.summary

The content of a summary cannot be too long, and the RSS3 Network should set a maximum length.

If it is a short content, then it is likely to only have a summary without a title, such as a Tweet from Twitter.

If it is a long article and its word count exceeds the size limit, then its summary should only be a summary or truncation of the article, and the complete content should be placed in attachments.

4.5.3.10. item.attachments

attachments records the attachments of this item, such as images of the article, etc. If it is a long article, it may also contain the full text of the article.

It is an array of attachment. Each element's structure is:

type Attachment = {
    type?: string;
    content?: string;
    address?: URI;
    mime_type: string;
    size_in_bytes?: number;
}
4.5.3.10.1. item.attachments[i].type

The type of attachment, indicating the function or classification of this attachment, such as thumbnail, detailed description, etc.

This value can be any string.

4.5.3.10.2. item.attachments[i].content and item.attachments[i].address

content is the actual content of the attachment, such as the full body of the article or the base64 string of an image. The content of this field may be very long, but the RSS3 Network should also be limited to the maximum length of the content to avoid affecting the storage efficiency of the entire network. Content that exceeds the maximum length limit should be placed in the address field using third-party storage.

address is the URI of this attachment pointing to a third-party address, such as a markdown file address or an image address.

content and address are mutually exclusive, one attachment can only have one and only one of them.

4.5.3.10.3. item.attachments[i].mime_type

This records the media type of this attachment. The format must conform to the RFC 6838 standard, such as image/png, text/markdown, etc. This is an important but easily overlooked field from an application presentation point of view, so the protocol specifies it as a required field.

4.5.3.10.4. item.attachments[i].size_in_bytes

This records the size of this attachment in bytes. It is useful for displaying large files such as videos and audios. It is also a field that is easily overlooked. The protocol recommends that the existence and accuracy of this field be ensured as much as possible.

4.5.3.11. item.metadata

This records metadata for Indexed Items, with specific values defined in RIP-4: Registered Indexed Items.

4.5.3.11.1. item.metadata.network

The network where this item is stored.

Its value is defined by RIP-3: Registered Item Networks.

4.5.3.11.2. item.metadata.proof

This records the credentials for indexing this Indexed Item, such as transaction hash and the address of a centralized platform.

This describes the relationship between two instances or items in RSS3.

4.6.1. Item Types

  • Indexed Links: Links automatically indexed by the RSS3 Network from other networks or platforms based on the Main Account and Connected Accounts.

  • Custom Links: Links signed and submitted by user themselves or automatically indexed by the Index Item Instance.

Link exists in two places, Instance and Item, both of which have a links field. In the content:

interface LinksSet {
    identifiers?: {
        type: LinkType;
        identifier_custom: CustomLinkListURI;
        identifier: AggregatedLinkListURI;
    }[];
    identifier_back: BacklinkListURI;
}

The type of relationship, such as the following relationship of Instance, the comment relationship of Item, etc. The specific value is restricted in RIP-5: Registered Link Types.

This records the URI of the Custom Link list on the last page.

When there is only one page of content, the value of identifier_custom is rss3://<Instance>/list/link/0, until the content exceeds the file size limit specified by the RSS3 Network, then the new link is recorded in a new file whose URI is rss3://<Instance>/list/link/1, and changes the identifier_custom field to rss3://<Instance>/list/link/1.

This is the URI of the aggregated link list, which supports some queries.

This records the reverse relationship of this link. For example, if A records a following relationship to B, then the identifier_back of B will automatically record a reverse-following (i.e., followed-by) relationship of A.

type Link = {
    identifier_target: InstanceURI;
    type: LinkType;

    auto?: true;
    metadata?: Metadata;
};

The link target is an RSS3 URI, which can be an Instance URI or an Item URI. It means that the user can follow an RSS3 account, and comments on an RSS3 asset or an RSS3 note.

See links.identifier_back.

4.7. Profile

Profile is located in the profile field of an Index File, which records the basic information of the instance, including the name, avatar, profile, etc.

type Profile = {
    name?: string;
    avatars?: URI[];
    bio?: string;
    attachments?: Attachment[];

    accounts?: Accounts;

    tags?: string[];
    metadata?: Metadata;
};

4.7.1. profile.name

The name of the instance, such as the user's screen name, the asset's title.

4.7.2. profile.avatars

Instance icons, such as the user's avatar and asset images, can be set multiple at the same time, and applications should generally choose the first to display.

4.7.3. profile.bio

Textual introduction to the instance.

4.7.4. profile.attachments

When used for Item Instance, same as item.attachments.

When used for Account Instance, profile is a very flexible and diverse information. The protocol cannot predict all requirements, so only a few of the most commonly used information are defined, and it is expected to use the attachments field to record the profile information that is not clearly defined, such as websites, banner.

For example:

{
    "attachments": [
        {
            "type": "websites",
            "content": "https://rss3.io\nhttps://diygod.me",
            "mime_type": "text/uri-list",
        },
        {
            "type": "banner",
            "content": "ipfs://QmT1zZNHvXxdTzHesfEdvFjMPvw536Ltbup7B4ijGVib7t",
            "mime_type": "image/jpeg",
        }
    ]
}

4.7.5. profile.accounts

This is the other accounts used to record instance bindings, including accounts of cryptography-based decentralized and centralized platforms.

type Accounts = {
    identifier: AccountInstanceURI;
    signature?: string;
}[];
4.7.5.1. profile.accounts[i].identifier

The URI of the account. If it is a decentralized account based on cryptography, use profile.accounts[i].signature to verify ownership. If it is a centralized account that cannot be signed, the user must put the address or name (Refer to RIP-2: Registered Name Services) of the Main Account into some location in the platform's account configuration to verify ownership, as specified by RIP-1: Registered Account Platforms.

4.7.6. profile.accounts[i].signature

This is used to verify the ownership of the bound account, signed by the bound account instead of the Main Account.

profile.accounts[i].signature = sign(`[RSS3] I am adding account ${profile.accounts[i].identifier} to my RSS3 Instance ${InstanceURI}`);

4.7.7. profile.tags and profile.metadata

For Item Instance, same as item.tags and item.metadata.

4.8. Authentication

This set of verification mechanisms is used to verify the legitimacy of files. It covers the verification of user-submitted files by RSS3 Network, the synchronizing files between nodes in a decentralized implementation, and returned files by the RSS3 Network on the client side.

4.8.1. SignedBase and UnsignedBase

The files are divided into signed files and unsigned files. Each file contains a field of either SignedBase or UnsignedBase, which is used to record the authentication method of the file.

type SignedBase = {
    signature: string;
    agents?: {
        pubkey: string;
        signature: string;
        authorization: string;
        app: string;
        date_expired: string;
    }[];
    controller?: string;
}

type UnsignedBase = {
    auto: true;
}
  • The signed file uses the SignedBase type, which is used to save the data of the user's signature authentication. The client can perform signature verification. Signed files include the Index files of Account Instance and the custom item/link list files.
  • The unsigned file uses the UnsignedBase type to save the data generated by the RSS3 Network. The client needs to verify it according to the relevant signed file or metadata.proof field. Unsigned files include aggregated item/link list files, and reverse relation list files.

4.8.2. signature

This is located in the root path of a signed file, signed by Instance's private key. The signature message is the file's JSON string sorted by key alphabetically. The signature algorithm may vary depending on the platform. Which algorithm to use is defined in RIP-1: Registered Account Platforms.

When verifying the signature and calculating the signed message, note that the existing signature field must be removed first.

signatrue = sign(`[RSS3] I am confirming the results of changes to my file ${identifier}: ${SortedStringify(file)}`);

For example, a file like:

{
    "version": "v0.4.0",
    "identifier": "rss3://account:[email protected]",
    "signatrue": "This should not be included",

    "items": {
        "notes": 1,
        "assets": 2
    }
}

Its signature is: [RSS3] I am confirming the results of changes to my file rss3://account:[email protected]: {"items":{"assets":2,"notes":1},"version":"v0.4.0"}

4.8.3. agents

DANGER

This is a feature that may reduce security significantly. The protocol will remove it or make significant changes in future versions depending on actual usage.

It is located in the root path of a signed file. This is a function similar to remember me in Web2. You can use the signature of the Main Account to authorize a randomly local-generated proxy signature account. When modifying the file, use the proxy account for signature authorization to reduce the number of signatures of the Main Account and the cost of use.

This also means that if the private key of the proxy account is leaked or the application chooses to do evil, the file will lose its security completely. End users will have to reauthorize this feature with full trust in the application.

The encryption algorithm uses Ed25519.

4.8.3.1. agents[i].pubkey

The base64 of the public key of the proxy account, generated by the client.

4.8.3.2. agents[i].signature

The base64 of the private key of the proxy account. The signed message is the same as the signature. Similarly, existing agents[i].signature of the current agent should be removed during the calculation.

4.8.3.3. agents[i].authorization

While it is technically sufficient to use the root signature to verify the authenticity of the agent, adding agents[i].authorization can alert the user to the risk of agents by having the user sign this alert message.

The authorized signature of the Main Account to the proxy account.

agents.signatrue = sign(`[RSS3] I am well aware that this APP (name: ${app}) can use the following agent instead of me (${InstanceURI}) to modify my files and I would like to authorize this agent (${pubkey})`);
4.8.3.4. agents[i].app

The application name used to distinguish different proxy accounts.

4.8.3.5. agents[i].date_expired

The expiration time of the proxy account, the RSS3 Network should limit the maximum value. After expiration, the proxy account should be deleted.

4.8.4. controller

Reserved field, used to define the control of the file, not used for now.

The current plan is to use a contract to control the controller of the file for scenarios, such as forums that require multiple people to modify the same file together.

5. Validation

5.1. TypeScript

// Instance
type AccountInstance = string;
type ItemInstance = string;

type Instance = AccountInstance | ItemInstance;

// URI
type InstanceURI = string;

type CustomItemListURI = string;
type AggregatedItemListURI = string;

type CustomLinkListURI = string;
type AggregatedLinkListURI = string;
type BacklinkListURI = string;

type URI = string;

// Common attributes for each files
interface Base {
    version: 'v0.4.0';
    identifier: InstanceURI | CustomItemListURI | AggregatedItemListURI | CustomLinkListURI | AggregatedLinkListURI | BacklinkListURI;
    date_created: string;
    date_updated: string;
}

interface SignedBase extends Base {
    signature: string;
    agents?: {
        pubkey: string;
        signature: string;
        authorization: string;
        app: string;
        date_expired: string;
    }[];
    controller?: string;
}

interface UnsignedBase extends Base {
    auto: true;
}

// Base types
interface Attachment {
    type?: string;
    content?: string;
    address?: URI;
    mime_type: string;
    size_in_bytes?: number;
}

interface Metadata {
    network?: NetworkName;
    proof: string;

    [key: string]: any;
}

interface Filters {
    blocklist?: string[];
    allowlist?: string[];
}

interface LinksSet {
    identifiers?: {
        type: LinkType;
        identifier_custom: CustomLinkListURI;
        identifier: AggregatedLinkListURI;
    }[];
    identifier_back: BacklinkListURI;
}

// RSS3 index files, main entrance for a instance
interface Index extends SignedBase, UnsignedBase {
    identifier: InstanceURI;

    profile?: {
        name?: string;
        avatars?: URI[];
        bio?: string;
        attachments?: Attachment[];

        accounts?: {
            identifier: InstanceURI;
            signature?: string;
        }[];

        tags?: string[];
        metadata?: Metadata;
    };

    links: LinksSet;

    items: {
        notes: {
            identifier_custom?: CustomItemListURI;
            identifier: AggregatedItemListURI;
            filters?: Filters;
        };
        assets: {
            identifier_custom?: CustomItemListURI;
            identifier: AggregatedItemListURI;
            filters?: Filters;
        };
    };
}

// items
type Item = {
    identifier: ItemInstanceURI;
    date_created: string;
    date_updated: string;

    auto?: true;
    related_urls?: string[];

    links: LinksSet;

    tags?: string[];
    authors: Account[];
    title?: string;
    summary?: string;
    attachments?: Attachment[];

    metadata?: Metadata;
};

type Link = {
    identifier_target: InstanceURI;
    type: LinkType;

    auto?: true;
    metadata?: Metadata;
};

// RSS3 list files
type ListBase<URIType, ElementType> = {
    identifier: URIType;
    identifier_next?: URIType;

    total: number;
    list?: ElementType[];
}

type CustomItemList = SignedBase & ListBase<CustomItemListURI, Item>;
type AggregatedItemList = UnsignedBase & ListBase<AggregatedItemListURI, Item>;

type CustomLinkList = (SignedBase | UnsignedBase) & ListBase<CustomLinkListURI, Link>;
type AggregatedLinkList = UnsignedBase & ListBase<AggregatedLinkListURI, Link>;
type BacklinkList = UnsignedBase & ListBase<BacklinkListURI, Link>;

5.2. JSON Schema

TODO

6. Use Cases

6.1. Index File Demo

URI rss3://account:[email protected]

{
    "version": "v0.4.0",
    "identifier": "rss3://account:[email protected]",
    "date_created": "2021-08-17T14:36:00.676Z",
    "date_updated": "2022-02-10T22:50:53.132Z",

    "signature": "0x85d66b17df7343364c6b89ede6ff15279505abfdfa7b8c70590d53a3a10db97a504b8a2536a7dcc12527af42f28f643a258d48f395b8fa5917336f06d8972be41c",
    "agents": [
        {
            "pubkey": "rrqJ2xn7oUd4wGW8VbsZk9XeacYMap4/jprIA5b35ns=",
            "signature": "PObUwUA+BEStJZJoY4xBsOkQujsRAZ4yULZIu0orDHCID2ezI5/eD8EskIK+RFNvSCp9tKTSYqurEFa2egW6Dg==",
            "authorization": "",
            "app": "Revery",
            "date_expired": "2023-02-10T22:50:53.132Z"
        }
    ],

    "profile": {
        "name": "DIYgod",
        "avatars": [
            "ipfs://QmT1zZNHvXxdTzHesfEdvFjMPvw536Ltbup7B4ijGVib7t"
        ],
        "bio": "Cofounder of RSS3.",
        "attachments": [
            {
                "type": "websites",
                "content": "https://rss3.io\nhttps://diygod.me",
                "mime_type": "text/uri-list",
            },
            {
                "type": "banner",
                "content": "ipfs://QmT1zZNHvXxdTzHesfEdvFjMPvw536Ltbup7B4ijGVib7t",
                "mime_type": "image/jpeg",
            }
        ],

        "accounts": [
            {
                "identifier": "rss3://account:[email protected]",
                "signature": "0x4828da56a162b9504dca6009864a90ed0ca3e56256d8458af451874ad7dd9cb26be4f399a56a8b69a881297ba6b6434a7f2f4a4f3557890d1efa8490769187be1b"
            },
            {
                "identifier": "rss3://account:[email protected]"
            }
        ]
    },

    "links": {
        "identifiers": [
            {
                "type": "following",
                "identifier_custom": "rss3://account:[email protected]/list/link/following/1",
                "identifier": "rss3://account:[email protected]/list/link/following"
            },
        ],
        "identifier_back": "rss3://account:[email protected]/list/backlink"
    },

    "items": {
        "notes": {
            "identifier_custom": "rss3://account:[email protected]/list/note/0",
            "identifier": "rss3://account:[email protected]/list/note",
            "filters": {
                "blocklist": [
                    "Twitter"
                ]
            }
        },
        "assets": {
            "identifier_custom": "rss3://account:[email protected]/list/asset/0",
            "identifier": "rss3://account:[email protected]/list/asset",
            "filters": {
                "allowlist": [
                    "Polygon"
                ]
            }
        }
    }
}

URI rss3://account:[email protected]/list/link/following/1

{
    "version": "v0.4.0",
    "identifier": "rss3://account:0[email protected]/list/link/following/1",
    "identifier_next": "rss3://account:[email protected]/list/link/following/0",
    "date_created": "2021-08-17T14:36:00.676Z",
    "date_updated": "2022-02-10T22:50:53.132Z",

    "signature": "0x5b2387a7e1b2ceb1a1b0c177294ca480ec1f43a21ad627476951b0c69baece500bde043d6f3a8ff1a8e248e3216517316b397806f6a6e721df50ed43479d65651c",

    "total": 8,
    "list": [
        {
            "identifier_target": "rss3://account:[email protected]",
            "type": "following"
        },
        {
            "identifier_target": "rss3://asset:[email protected]",
            "type": "following"
        },
        {
            "identifier_target": "rss3://note:[email protected]",
            "type": "following"
        },
        {
            "identifier_target": "rss3://asset:[email protected]",
            "type": "following"
        }
    ]
}

6.3. Asset List File Demo

URI rss3://account:[email protected]/list/asset/0

{
    "version": "v0.4.0",
    "identifier": "rss3://account:[email protected]/list/asset/0",
    "date_created": "2021-08-17T14:36:00.676Z",
    "date_updated": "2022-02-10T22:50:53.132Z",

    "signature": "0x5b2387a7e1b2ceb1a1b0c177294ca480ec1f43a21ad627476951b0c69baece500bde043d6f3a8ff1a8e248e3216517316b397806f6a6e721df50ed43479d65651c",

    "total": 1,
    "list": [
        {
            "identifier": "rss3://asset:[email protected]",
            "date_created": "2021-08-17T14:36:00.676Z",
            "date_updated": "2022-02-10T22:50:53.132Z",

            "links": {
                "identifier_back": "rss3://asset:[email protected]/list/backlink"
            },
        
            "tags": [
                "Garage Kit"
            ],
            "authors": [
                "[email protected]"
            ],
            "summary": "My Garage Kit - 2233",
            "attachments": [
                {
                    "address": "ipfs://QmT1zZNHvXxdTzHesfEdvFjMPvw536Ltbup7B4ijGVib7t",
                    "mime_type": "image/jpg",
                    "size_in_bytes": 1024
                }
            ]
        }
    ]
}

6.4. Note List File Demo

URI rss3://account:[email protected]/list/note/0

{
    "version": "v0.4.0",
    "identifier": "rss3://account:[email protected]/list/note/0",
    "date_created": "2021-08-17T14:36:00.676Z",
    "date_updated": "2022-02-10T22:50:53.132Z",

    "signature": "0x5b2387a7e1b2ceb1a1b0c177294ca480ec1f43a21ad627476951b0c69baece500bde043d6f3a8ff1a8e248e3216517316b397806f6a6e721df50ed43479d65651c",

    "total": 1,
    "list": [
        {
            "identifier": "rss3://note:[email protected]",
            "date_created": "2021-08-17T14:36:00.676Z",
            "date_updated": "2022-02-10T22:50:53.132Z",

            "links": {
                "identifiers": [
                    {
                        "type": "comment",
                        "identifier_custom": "rss3://note:[email protected]/list/link/comment/0",
                        "identifier": "rss3://note:[email protected]/list/link/comment"
                    },
                ],
                "identifier_back": "rss3://note:[email protected]/list/backlink"
            },

            "authors": [
                "[email protected]",
                "[email protected]"
            ],
            "title": "RSS3 is born",
            "summary": "RSS3 is a next-generation feed standard that aims to support efficient and decentralized information distribution.",
            "attachments": [
                {
                    "content": "# I include a markdown",
                    "mime_type": "text/markdown"
                }, {
                    "address": "ipfs://QmT1zZNHvXxdTzHesfEdvFjMPvw536Ltbup7B4ijGVib7t",
                    "mime_type": "image/jpg",
                    "size_in_bytes": 1024
                }
            ]
        }
    ]
}