Latest editor's draft:
Editors:
- DIYgod (NaturalSelectionLabs)
- Joshua (NaturalSelectionLabs)
- Atlas (NaturalSelectionLabs)
Reviewers
- Zui (NaturalSelectionLabs)
- Usagi (NaturalSelectionLabs)
Participate:
Derived from the best out of RSS, RSS3 is an open protocol designed for all our cyber existence in the era of Web 3.0.
This document describes the interfaces of RSS3 files.
The proposal is being incubated in the RSS3 Network.
GitHub issues and discussions are preferred for discussion of this specification.
This version is a beta version, so it is not guaranteed to be compatible with subsequent versions, but breaking updates will be kept to a minimum.
- Persona - a user, either as an individual or as a group
- Item - An item published or experienced by a persona
- Link - One type of relationship to other personas/item from current persona/item
- Backlink - A link from other personas/items to current persona/item
- Assets - Objects currently owned by the persona
| ID | RSS3ID | RSS3CustomItemsListID | RSS3AutoItemsListID | RSS3CustomItemsListID | RSS3AutoItemsListID | RSS3LinksListID | RSS3BacklinksListID | RSS3ItemBacklinksListID |
|---|---|---|---|---|---|---|---|---|
| Format of ID | \ | ${RSS3ID}-list-items.custom-${index} |
${RSS3ID}-list-items.auto-0 |
${RSS3ID}-list-items.custom-${index} |
${RSS3ID}-list-items.auto-0 |
${RSS3ID}-list-links.${links.type}-${index} |
${RSS3ID}-list-backlinks.${backlinks.type}-0 |
${RSS3ID}-list-item.${item.index}.backlinks.${backlinks.type}-${index} |
| Content Types | RSS3Index | RSS3CustomItemsList | RSS3AutoItemsList | RSS3CustomAssetsList | RSS3AutoItemsList | RSS3LinksList | RSS3BacklinksList | RSS3ItemBacklinksList |
// File ids
type RSS3ID = string; // Same as ethereum address
type RSS3CustomItemsListID = string; // `${RSS3ID}-list-items.custom-${index}`
type RSS3AutoItemsListID = string; // `${RSS3ID}-list-items.auto-0`
type RSS3CustomAssetsListID = string; // `${RSS3ID}-list-assets.custom-${index}`
type RSS3AutoAssetsListID = string; // `${RSS3ID}-list-assets.auto-0`
type RSS3LinksListID = string; // `${RSS3ID}-list-links.${links.id}-${index}`
type RSS3BacklinksListID = string; // `${RSS3ID}-list-backlinks.${backlinks.id}-0`
type RSS3ItemBacklinksListID = string; // `${RSS3ID}-list-item.${item.index}.backlinks.${backlinks.id}-0`
type ThirdPartyAddress = string[]; // A series of url or ipfs hash that link to an identical file
type AccountID = string; // ${platform}-${identity}, for example, EVM+-0x1234567890123456789012345678901234567890 or Twitter-rss3_
type RSS3CustomItemID = string; // `${RSS3ID}-item-custom-${index}`
type RSS3AutoItemID = string; // `${RSS3ID}-item-auto-${index}`
type RSS3List =
| RSS3CustomItemsList
| RSS3AutoItemsList
| RSS3CustomAssetsList
| RSS3AutoAssetsList
| RSS3LinksList
| RSS3BacklinksList
| RSS3ItemBacklinksList;
type RSS3ListID =
| RSS3CustomItemsListID
| RSS3AutoItemsListID
| RSS3CustomAssetsListID
| RSS3AutoAssetsListID
| RSS3LinksListID
| RSS3BacklinksListID
| RSS3ItemBacklinksListID;
type RSS3FileID = RSS3ID | RSS3ListID;
type RSS3File = RSS3Index | RSS3List;
// Common attributes for each files
interface RSS3Base {
version: "rss3.io/version/v0.3.1"; // Proposal version for current file. It should be like `rss3.io/version/v1.0.0`
id: RSS3FileID;
date_created: string; // Specifies the created date in RFC 3339 format
date_updated: string; // Specifies the updated date in RFC 3339 format
}
interface RSS3SignedBase extends RSS3Base {
signature: string; // Signed by persona's private key; The signature content is the Keccak-256 hash of the array of object sorted by alphabetical and excluding objects containing `auto: true` field and the `signature` field itself(for example {a: "1", c: "2", b: {d: "3"}, e: {auto: true}} -> [["a", "1"], ["b", ["d", "3"]], ["c", "2"]]) or the string `Hi, RSS3. I'm your agent ${agent_id}` if using agent signature; Used for the object integration verification for both server side and persona side
agent_id?: string; // A random ed25519 public key generated by the client
agent_signature?: string; // A signature signed by `agent_id`'s private key, its content is the same as `signature`
}
interface RSS3UnsignedBase extends RSS3Base {
auto: true;
}
// RSS3 index file, main entrance for a persona
interface RSS3Index extends RSS3SignedBase {
id: RSS3ID;
controller?: string; // A contract address indicating ownership of the file
profile?: {
name?: string;
avatar?: ThirdPartyAddress;
bio?: string;
accounts?: {
tags?: string[];
id: AccountID;
signature?: string; // Signature of [["address", id], ["id", account.id], ["tags", account.tags]], optional for no public-key cryptography platform
}[];
};
links?: {
tags?: string[];
id: string; // Link id, for example: following superfollowing
list?: RSS3LinksListID; // Personas who belong to this link
}[];
backlinks?: {
// Backlinks for this persona, for example: following link's backlink means followers.
auto: true;
id: string; // The same as links.id
list: RSS3BacklinksListID; // File ID of backlink list that belong to this link. See **RSS3List** for more details
}[];
items?: {
list_custom?: RSS3CustomItemsListID;
list_auto?: RSS3AutoItemsListID;
};
assets?: {
list_custom?: RSS3CustomAssetsListID;
list_auto?: RSS3AutoAssetsListID;
};
}
type RSS3Profile = Required<RSS3Index>["profile"];
type RSS3Account = Required<RSS3Profile>["accounts"][number];
type RSS3Links = Required<RSS3Index>["links"];
// RSS3 list files, used for list of links, backlinks, items, assets, itemsbacklinks
interface RSS3ListBase<IDType, ElementType> {
id: IDType;
list?: ElementType[];
list_next?: IDType;
}
type RSS3CustomItemsList = RSS3SignedBase &
RSS3ListBase<RSS3CustomItemsListID, RSS3CustomItem>;
type RSS3AutoItemsList = RSS3UnsignedBase &
RSS3ListBase<RSS3AutoItemsListID, RSS3AutoItem>;
type RSS3CustomAssetsList = RSS3SignedBase &
RSS3ListBase<RSS3CustomAssetsListID, RSS3CustomAsset>;
type RSS3AutoAssetsList = RSS3UnsignedBase &
RSS3ListBase<RSS3AutoAssetsListID, RSS3AutoAsset>;
type RSS3LinksList = RSS3SignedBase & RSS3ListBase<RSS3LinksListID, RSS3ID>;
type RSS3BacklinksList = RSS3UnsignedBase &
RSS3ListBase<RSS3BacklinksListID, RSS3ID>;
type RSS3ItemBacklinksList = RSS3UnsignedBase &
RSS3ListBase<RSS3ItemBacklinksListID, RSS3CustomItemID>;
// Asset
type RSS3Asset = RSS3CustomAsset | RSS3AutoAsset;
type RSS3CustomAsset = string; // A type of asset posted by persona itself, custom-${identity}-${type}-${uniqueID}, for example, persona's cute(q) Garage Kit(gk) (uniqueID 10035911): custom-gk-q-10035911
type RSS3AutoAsset = string; // A type of asset that is automatically generated by a node, ${platform}-${identity}-${type}-${uniqueID}, for example, a NFT(uniqueID 0x456.5) in the Ethereum chain owned by apersona's EVM+ account(0x123): EVM+-0x123-Ethereum.NFT-0x456.5
// Item
type RSS3Item = RSS3CustomItem | RSS3AutoItem;
interface RSS3ItemBase {
date_created: string; // Specifies the published date in RFC 3339 format
date_updated: string; // Specifies the modified date in RFC 3339 format
title?: string;
summary?: string;
backlinks?: {
// Interactive items from other personas.
auto: true;
id: string;
list: RSS3ItemBacklinksListID; // File ID of items list that belong to this context. See **RSS3List** for more details
}[];
}
interface RSS3CustomItem extends RSS3ItemBase {
// A type of content posted by persona itself
id: RSS3CustomItemID; // `${RSS3ID}-item-custom-${index}`
tags?: string[];
authors?: RSS3ID[];
link?: {
id: string; // Link id for the non-original item, for example: comment like
target: RSS3CustomItemID | RSS3AutoItemID; // Target of the non-original item
};
contents?: {
// Contents of current item, possibly multiple different types of content
tags?: string[];
address: ThirdPartyAddress;
mime_type: string; // [MIME type](https://en.wikipedia.org/wiki/Media_type) of current content
name?: string;
size_in_bytes?: string;
duration_in_seconds?: string;
}[];
}
interface RSS3AutoItem extends RSS3ItemBase {
// A type of content that is automatically generated by a node to represent a change of an asset
id: RSS3AutoItemID; // `${RSS3ID}-item-auto-${index}`
target: {
field: string; // 'items-auto-${AccountID}', `assets-${RSS3Asset}` 'links-following', 'profile-avatar', `profile-accounts-${RSS3Account.id}`, etc
action: {
type: "add" | "remove" | "update";
payload?: string; // If the type is `add` or `remove`, then it is the added or removed content, empty means the content is itself, if the type is `update`, then it is the content after updating
proof?: string; // Additional information used to make this target unique
};
};
}signature
- Signed by persona's private key
- Used for the object integration verification for both server side and persona side
- The content is
- The Keccak-256 hash of the array of object sorted by alphabetical and excluding
- Objects containing
auto: true - Fields that end with
_auto signatureagent_idagent_signaturesignature-related fields- For example
{a: "1", c: "2", b: {d: "3"}, e: {auto: true}, f_auto: "4"}->[["a", "1"], ["b", ["d", "3"]], ["c", "2"]]
- Objects containing
- Or the string
Hi, RSS3. I'm your agent ${agent_id}- If using agent signature
- The Keccak-256 hash of the array of object sorted by alphabetical and excluding
Objects with the auto field
- Entirely the responsibility of the hosting program
- May be modified by the hosting program at any time
- Not allowed to be modified by the persona
- Excluded when calculating signatures
Extensions
Custom objects can be used in RSS3. Names must start with an _ character. Custom objects can appear anywhere in RSS3.
Empty contents
It is strongly recommended to delete fields with empty contents, including empty strings, empty arrays, empty objects
A persona 0x1234567890123456789012345678901234567890 with a published item Hello World and a comment to it
# Index file
{
"version": "rss3.io/version/v0.3.1",
"id": "0x1234567890123456789012345678901234567890",
"date_created": "2021-01-01T00:00:00.000Z",
"date_updated": "2021-01-01T00:00:00.000Z",
"signature": "0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"profile": {
"name": "RSS3",
"avatar": ["https://example.com/rss3.jpg", "QmT1zZNHvXxdTzHesfEdvFjMPvw536Ltbup7B4ijGVib7t"],
"bio": "RSS3 is an open protocol designed for all our cyber existence in the era of Web 3.0.",
"accounts": [{
"id": "EVM+-0x1111111111111111111111111111111111111111",
"signature": "0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}]
},
"items": {
"list_custom": "0x1234567890123456789012345678901234567890-list-items.custom-0",
"list_auto": "0x1234567890123456789012345678901234567890-list-items.auto-0",
},
"assets": {
"list_custom": "0x1234567890123456789012345678901234567890-list-assets.custom-0",
"list_auto": "0x1234567890123456789012345678901234567890-list-assets.auto-0",
},
"links": [{
"id": "following",
"list": "0x1234567890123456789012345678901234567890-list-links.following-0",
}],
"backlinks": [{
"auto": true,
"id": "following",
"list": "0x1234567890123456789012345678901234567890-list-backlinks.following-0",
}],
}
# Custom items file
{
"version": "rss3.io/version/v0.3.1",
"id": "0x1234567890123456789012345678901234567890-list-items.custom-0",
"date_created": "2021-01-01T00:00:00.000Z",
"date_updated": "2021-01-01T00:00:00.000Z",
"signature": "0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"list": [{
"id": "0x1234567890123456789012345678901234567890-item-custom-1",
"summary": "Yes!!",
"date_created": "2021-01-01T00:00:00.000Z",
"date_updated": "2021-01-01T00:00:00.000Z",
"link": {
"id": "comment",
"target": "0x1234567890123456789012345678901234567890-item-custom-0"
},
}, {
"id": "0x1234567890123456789012345678901234567890-item-custom-0",
"title": "Hello World",
"summary": "Hello, this is the first item of RSS3.",
"date_created": "2021-01-01T00:00:00.000Z",
"date_updated": "2021-01-01T00:00:00.000Z",
"contents": [{
"address": ["https://example.com/rss3.jpg"],
"mime_type": "image/jpeg"
}],
"backlinks": [{
"auto": true,
"id": "comment",
"list": "0x1234567890123456789012345678901234567890-list-item.0.backlinks.comment-0"
}]
}]
}
# Auto items file
{
"version": "rss3.io/version/v0.3.1",
"id": "0x1234567890123456789012345678901234567890-list-items.auto-0",
"date_created": "2021-01-01T00:00:00.000Z",
"date_updated": "2021-01-01T00:00:00.000Z",
"auto": true,
"list": [{
"id": "0x1234567890123456789012345678901234567890-item-auto-0",
"date_created": "2021-01-01T00:00:00.000Z",
"date_updated": "2021-01-01T00:00:00.000Z",
"target": {
"field": "EVM+-0x1111111111111111111111111111111111111111-Ethereum.NFT-id0",
"action": {
"type": "update",
"payload": "0x2222222222222222222222222222222222222222",
},
},
"backlinks": [{
"auto": true,
"id": "comment",
"list": "0x1234567890123456789012345678901234567890-list-item.2.backlinks.comment-0"
}]
}]
}
# Link list file
{
"version": "rss3.io/version/v0.3.1",
"id": "0x1234567890123456789012345678901234567890-list-links.following-0",
"date_created": "2021-01-01T00:00:00.000Z",
"date_updated": "2021-01-01T00:00:00.000Z",
"signature": "0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"list": ["0x1111111111111111111111111111111111111111", "0x2222222222222222222222222222222222222222"]
}
# Custom assets list file
{
"version": "rss3.io/version/v0.3.1",
"id": "0x1234567890123456789012345678901234567890-list-assets.custom-0",
"date_created": "2021-01-01T00:00:00.000Z",
"date_updated": "2021-01-01T00:00:00.000Z",
"signature": "0xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"list": ["custom-gk-q-10035911"]
}
# Auto assets list file
{
"version": "rss3.io/version/v0.3.1",
"id": "0x1234567890123456789012345678901234567890-list-assets.auto-0",
"date_created": "2021-01-01T00:00:00.000Z",
"date_updated": "2021-01-01T00:00:00.000Z",
"auto": true,
"list": ["EVM+-0x1234567890123456789012345678901234567890-Ethereum.NFT-0xacbe98efe2d4d103e221e04c76d7c55db15c8e89.5"]
}