Reformat files

This commit is contained in:
Roj Serbest 2021-10-29 11:08:21 +03:00
parent ac75a8c210
commit d7cd8ac6f9
35 changed files with 1563 additions and 1557 deletions

View File

@ -1,11 +1,10 @@
{ {
"fmt": { "fmt": {
"files": { "files": {
"include": ["socialvoid", "examples", "generators"] "include": ["socialvoid", "examples", "generators"]
}, },
"options": { "options": {
"indentWidth": 4, "lineWidth": 100
"lineWidth": 100
}
} }
}
} }

View File

@ -1,25 +1,25 @@
async function login(client, greet = true) { async function login(client, greet = true) {
if (!client.sessionExists) { if (!client.sessionExists) {
await client.newSession(); await client.newSession();
} }
const session = await client.session.get(); const session = await client.session.get();
if (!session.authenticated) { if (!session.authenticated) {
const username = prompt("Enter your username."); const username = prompt("Enter your username.");
const password = prompt("Enter your password."); const password = prompt("Enter your password.");
const otp = prompt("Enter your OTP (if set)."); const otp = prompt("Enter your OTP (if set).");
await client.session.authenticateUser( await client.session.authenticateUser(
username, username,
password, password,
otp == "" ? undefined : otp, otp == "" ? undefined : otp,
); );
} }
const me = await client.network.getMe(); const me = await client.network.getMe();
if (greet) { if (greet) {
alert(`Hello, ${me.name}!`); alert(`Hello, ${me.name}!`);
} }
} }

View File

@ -1,25 +1,25 @@
async function login(client, greet = true) { async function login(client, greet = true) {
if (!client.sessionExists) { if (!client.sessionExists) {
await client.newSession(); await client.newSession();
} }
const session = await client.session.get(); const session = await client.session.get();
if (!session.authenticated) { if (!session.authenticated) {
const username = prompt("Enter your username."); const username = prompt("Enter your username.");
const password = prompt("Enter your password."); const password = prompt("Enter your password.");
const otp = prompt("Enter your OTP (if set)."); const otp = prompt("Enter your OTP (if set).");
await client.session.authenticateUser( await client.session.authenticateUser(
username, username,
password, password,
otp == "" ? undefined : otp, otp == "" ? undefined : otp,
); );
} }
const me = await client.network.getMe(); const me = await client.network.getMe();
if (greet) { if (greet) {
alert(`Hello, ${me.name}!`); alert(`Hello, ${me.name}!`);
} }
} }

View File

@ -3,17 +3,17 @@ import { Client } from "../../socialvoid/mod.ts";
export const client = new Client(); export const client = new Client();
export async function login() { export async function login() {
if (!client.sessionExists) { if (!client.sessionExists) {
await client.newSession(); await client.newSession();
} }
const session = await client.session.get(); const session = await client.session.get();
if (!session.authenticated) { if (!session.authenticated) {
await client.session.authenticateUser( await client.session.authenticateUser(
prompt("Username:")!, prompt("Username:")!,
prompt("Password:")!, prompt("Password:")!,
prompt("OTP (if set):")!, prompt("OTP (if set):")!,
); );
} }
} }

View File

@ -2,12 +2,12 @@ const { writeFileSync } = require("fs");
const { client, login, prompt } = require("./"); const { client, login, prompt } = require("./");
(async () => { (async () => {
await login(); await login();
const id = prompt("ID of the document to be downloaded:"); const id = prompt("ID of the document to be downloaded:");
const data = await client.cdn.download(id); const data = await client.cdn.download(id);
writeFileSync(id, new Uint8Array(data)); writeFileSync(id, new Uint8Array(data));
console.log("Downloaded successfully."); console.log("Downloaded successfully.");
})(); })();

View File

@ -2,31 +2,31 @@ const { createInterface } = require("readline");
const { Client } = require("../../dist/mod.js"); const { Client } = require("../../dist/mod.js");
const readline = createInterface({ const readline = createInterface({
input: process.stdin, input: process.stdin,
output: process.stdout, output: process.stdout,
}); });
const client = new Client(); const client = new Client();
function prompt(query) { function prompt(query) {
return new Promise((resolve) => { return new Promise((resolve) => {
readline.question(query + " ", resolve); readline.question(query + " ", resolve);
}); });
} }
async function login() { async function login() {
if (!client.sessionExists) { if (!client.sessionExists) {
await client.newSession(); await client.newSession();
} }
const session = await client.session.get(); const session = await client.session.get();
if (!session.authenticated) { if (!session.authenticated) {
await client.session.authenticateUser( await client.session.authenticateUser(
prompt("Username:"), prompt("Username:"),
prompt("Password:"), prompt("Password:"),
prompt("OTP (if set):"), prompt("OTP (if set):"),
); );
} }
} }
module.exports = { client, login, prompt }; module.exports = { client, login, prompt };

View File

@ -1,10 +1,10 @@
const { client, login } = require("./"); const { client, login } = require("./");
(async () => { (async () => {
await login(); await login();
const me = await client.network.getMe(); const me = await client.network.getMe();
console.log("Logged in as", me.name + "."); console.log("Logged in as", me.name + ".");
console.log(`${me.name}s username is`, me.username + "."); console.log(`${me.name}s username is`, me.username + ".");
console.log(`@${me.username}s ID is`, me.id + "."); console.log(`@${me.username}s ID is`, me.id + ".");
})(); })();

View File

@ -2,11 +2,11 @@ const { createReadStream } = require("fs");
const { client, login, prompt } = require("./"); const { client, login, prompt } = require("./");
(async () => { (async () => {
await login(); await login();
const file = prompt("Path of the file to be uploaded:"); const file = prompt("Path of the file to be uploaded:");
const document = await client.cdn.upload(createReadStream(file)); const document = await client.cdn.upload(createReadStream(file));
console.log("Uploaded successfully."); console.log("Uploaded successfully.");
console.log("Document ID:", document.id); console.log("Document ID:", document.id);
})(); })();

View File

@ -1,178 +1,178 @@
{ {
"validation": { "validation": {
"8448": { "8448": {
"_": "InvalidUsername", "_": "InvalidUsername",
"description": "The given username is invalid and does not meet the specification" "description": "The given username is invalid and does not meet the specification"
},
"8449": {
"_": "InvalidPassword",
"description": "The given password is insecure, see the message for further details"
},
"8450": {
"_": "InvalidFirstName",
"description": "The First Name provided contains invalid characters and or is too long, see the message for further details"
},
"8451": {
"_": "InvalidLastName",
"description": "The Last Name provided contains invalid characters and or is too long, see the message for further details "
},
"8452": {
"_": "InvalidBiography",
"description": "The Biography is too long or contains invalid characters, see the message for further details"
},
"8453": {
"_": "UsernameAlreadyExists",
"description": "The username is already registered in the network and cannot be used "
},
"8454": {
"_": "InvalidPeerInput",
"description": "The client provided an invalid peer identification as input"
},
"8455": {
"_": "InvalidPostText",
"description": "The post contains invalid characters or is too long, see the message for further details"
},
"8456": {
"_": "InvalidClientPublicHash",
"description": "The client's public hash is invalid and cannot be identified as a sha256"
},
"8457": {
"_": "InvalidClientPrivateHash",
"description": "The client's private hash is invalid and cannot be identified as a sha256"
},
"8458": {
"_": "InvalidPlatform",
"description": "The platform name contains invalid characters or is too long, see the message for further details"
},
"8459": {
"_": "InvalidVersion",
"description": "The version is invalid or is too long, see the message for further details"
},
"8460": {
"_": "InvalidClientName",
"description": "The client name contains invalid characters or is too long, see the message for further details"
},
"8461": {
"_": "InvalidSessionIdentification",
"description": "The session identification object is invalid, see the message for further details"
},
"8462": {
"_": "InvalidFileForProfilePicture",
"description": "The given file is invalid for a profile picture"
},
"8463": {
"_": "FileTooLarge",
"description": "The given file is too large to be processed"
},
"8464": {
"_": "InvalidHelpDocumentId",
"description": "The given Help Document ID is invalid"
},
"8465": {
"_": "AgreementRequired",
"description": "The client/user must agree to the condition to invoke the method"
},
"8468": {
"_": "InvalidUrlValue",
"description": "The given URL input is invalid"
}
}, },
"server": { "8449": {
"16384": { "_": "InvalidPassword",
"_": "InternalServerError", "description": "The given password is insecure, see the message for further details"
"description": "Raised when there was an unexpected error while trying to process your request"
},
"16385": {
"_": "DocumentUpload",
"description": "Raised when there was an error while trying to process the document upload"
}
}, },
"network": { "8450": {
"12544": { "_": "InvalidFirstName",
"_": "PeerNotFound", "description": "The First Name provided contains invalid characters and or is too long, see the message for further details"
"description": "The requested user entity was not found in the network"
},
"12545": {
"_": "PostNotFound",
"description": "Raised when the client requested a post that isn't found"
},
"12546": {
"_": "PostDeleted",
"description": "Raised when the client requested a post that was deleted"
},
"12547": {
"_": "AlreadyReposted",
"description": "Raised when the client attempts to repost a post that has already been reposted"
},
"12548": {
"_": "FileUploadError",
"description": "Raised when there was an error while trying to upload one or more files to the network"
},
"12549": {
"_": "DocumentNotFound",
"description": "The requested Document ID was not found on the server"
},
"12550": {
"_": "AccessDenied",
"description": "The authenticated peer does not have sufficient permissions to access the requested resource or to invoke a restricted method"
},
"12551": {
"_": "BlockedByPeer",
"description": "Blocked by the peer which attempted to interact with"
},
"12552": {
"_": "BlockedPeer",
"description": "Attempted to interact with a blocked peer"
},
"12553": {
"_": "SelfInteractionNotPermitted",
"description": "Cannot interact with self"
}
}, },
"authentication": { "8451": {
"8704": { "_": "InvalidLastName",
"_": "IncorrectLoginCredentials", "description": "The Last Name provided contains invalid characters and or is too long, see the message for further details "
"description": "The given login credentials are incorrect" },
}, "8452": {
"8705": { "_": "InvalidBiography",
"_": "IncorrectTwoFactorAuthenticationCode", "description": "The Biography is too long or contains invalid characters, see the message for further details"
"description": "The given two-factor authentication code is incorrect" },
}, "8453": {
"8706": { "_": "UsernameAlreadyExists",
"_": "AuthenticationNotApplicable", "description": "The username is already registered in the network and cannot be used "
"description": "Raised when the user does not support this method of authentication, see the message for further details" },
}, "8454": {
"8707": { "_": "InvalidPeerInput",
"_": "SessionNotFound", "description": "The client provided an invalid peer identification as input"
"description": "Raised when the requested session was not found in the network" },
}, "8455": {
"8708": { "_": "InvalidPostText",
"_": "NotAuthenticated", "description": "The post contains invalid characters or is too long, see the message for further details"
"description": "Raised when the client attempts to invoke a method that requires authentication" },
}, "8456": {
"8709": { "_": "InvalidClientPublicHash",
"_": "PrivateAccessTokenRequired", "description": "The client's public hash is invalid and cannot be identified as a sha256"
"description": "Raised when the user/entity uses a Private Access Token to authenticate and the client attempted to authenticate in another way" },
}, "8457": {
"8710": { "_": "InvalidClientPrivateHash",
"_": "AuthenticationFailure", "description": "The client's private hash is invalid and cannot be identified as a sha256"
"description": "The authentication process failed for some unexpected reason, see the message for further details" },
}, "8458": {
"8711": { "_": "InvalidPlatform",
"_": "BadSessionChallengeAnswer", "description": "The platform name contains invalid characters or is too long, see the message for further details"
"description": "The given session challenge answer is incorrect or out of sync" },
}, "8459": {
"8712": { "_": "InvalidVersion",
"_": "TwoFactorAuthenticationRequired", "description": "The version is invalid or is too long, see the message for further details"
"description": "Two-Factor Authentication is required, the client must repeat the same request but provide a Two-Factor authentication code as well" },
}, "8460": {
"8713": { "_": "InvalidClientName",
"_": "AlreadyAuthenticated", "description": "The client name contains invalid characters or is too long, see the message for further details"
"description": "The client is attempting to authenticate when already authenticated" },
}, "8461": {
"8714": { "_": "InvalidSessionIdentification",
"_": "SessionExpired", "description": "The session identification object is invalid, see the message for further details"
"description": "Raised when trying to use a session that has expired" },
} "8462": {
"_": "InvalidFileForProfilePicture",
"description": "The given file is invalid for a profile picture"
},
"8463": {
"_": "FileTooLarge",
"description": "The given file is too large to be processed"
},
"8464": {
"_": "InvalidHelpDocumentId",
"description": "The given Help Document ID is invalid"
},
"8465": {
"_": "AgreementRequired",
"description": "The client/user must agree to the condition to invoke the method"
},
"8468": {
"_": "InvalidUrlValue",
"description": "The given URL input is invalid"
} }
},
"server": {
"16384": {
"_": "InternalServerError",
"description": "Raised when there was an unexpected error while trying to process your request"
},
"16385": {
"_": "DocumentUpload",
"description": "Raised when there was an error while trying to process the document upload"
}
},
"network": {
"12544": {
"_": "PeerNotFound",
"description": "The requested user entity was not found in the network"
},
"12545": {
"_": "PostNotFound",
"description": "Raised when the client requested a post that isn't found"
},
"12546": {
"_": "PostDeleted",
"description": "Raised when the client requested a post that was deleted"
},
"12547": {
"_": "AlreadyReposted",
"description": "Raised when the client attempts to repost a post that has already been reposted"
},
"12548": {
"_": "FileUploadError",
"description": "Raised when there was an error while trying to upload one or more files to the network"
},
"12549": {
"_": "DocumentNotFound",
"description": "The requested Document ID was not found on the server"
},
"12550": {
"_": "AccessDenied",
"description": "The authenticated peer does not have sufficient permissions to access the requested resource or to invoke a restricted method"
},
"12551": {
"_": "BlockedByPeer",
"description": "Blocked by the peer which attempted to interact with"
},
"12552": {
"_": "BlockedPeer",
"description": "Attempted to interact with a blocked peer"
},
"12553": {
"_": "SelfInteractionNotPermitted",
"description": "Cannot interact with self"
}
},
"authentication": {
"8704": {
"_": "IncorrectLoginCredentials",
"description": "The given login credentials are incorrect"
},
"8705": {
"_": "IncorrectTwoFactorAuthenticationCode",
"description": "The given two-factor authentication code is incorrect"
},
"8706": {
"_": "AuthenticationNotApplicable",
"description": "Raised when the user does not support this method of authentication, see the message for further details"
},
"8707": {
"_": "SessionNotFound",
"description": "Raised when the requested session was not found in the network"
},
"8708": {
"_": "NotAuthenticated",
"description": "Raised when the client attempts to invoke a method that requires authentication"
},
"8709": {
"_": "PrivateAccessTokenRequired",
"description": "Raised when the user/entity uses a Private Access Token to authenticate and the client attempted to authenticate in another way"
},
"8710": {
"_": "AuthenticationFailure",
"description": "The authentication process failed for some unexpected reason, see the message for further details"
},
"8711": {
"_": "BadSessionChallengeAnswer",
"description": "The given session challenge answer is incorrect or out of sync"
},
"8712": {
"_": "TwoFactorAuthenticationRequired",
"description": "Two-Factor Authentication is required, the client must repeat the same request but provide a Two-Factor authentication code as well"
},
"8713": {
"_": "AlreadyAuthenticated",
"description": "The client is attempting to authenticate when already authenticated"
},
"8714": {
"_": "SessionExpired",
"description": "Raised when trying to use a session that has expired"
}
}
} }

View File

@ -1,310 +1,310 @@
{ {
"types": { "types": {
"FileType": "\"DOCUMENT\" | \"PHOTO\" | \"VIDEO\" | \"AUDIO\"", "FileType": "\"DOCUMENT\" | \"PHOTO\" | \"VIDEO\" | \"AUDIO\"",
"PeerType": "\"USER\" | \"BOT\" | \"PROXY\"", "PeerType": "\"USER\" | \"BOT\" | \"PROXY\"",
"TextEntityType": "\"BOLD\" | \"ITALIC\" | \"CODE\" | \"STRIKE\" | \"UNDERLINE\" | \"URL\" | \"MENTION\" | \"HASHTAG\"", "TextEntityType": "\"BOLD\" | \"ITALIC\" | \"CODE\" | \"STRIKE\" | \"UNDERLINE\" | \"URL\" | \"MENTION\" | \"HASHTAG\"",
"PostType": "\"UNKNOWN\" | \"DELETED\" | \"POST\" | \"REPLY\" | \"QUOTE\" | \"REPOST\"", "PostType": "\"UNKNOWN\" | \"DELETED\" | \"POST\" | \"REPLY\" | \"QUOTE\" | \"REPOST\"",
"RelationshipType": "\"NONE\" | \"FOLLOWING\" | \"FOLLOWS_YOU\" | \"AWAITING_APPROVAL\" | \"MUTUALLY_FOLLOWING\" | \"BLOCKED\" | \"BLOCKED_YOU\"" "RelationshipType": "\"NONE\" | \"FOLLOWING\" | \"FOLLOWS_YOU\" | \"AWAITING_APPROVAL\" | \"MUTUALLY_FOLLOWING\" | \"BLOCKED\" | \"BLOCKED_YOU\""
},
"interfaces": {
"Post": {
"id": {
"type": "string",
"description": "The unique ID for the post"
},
"type": {
"type": "PostType",
"description": "The post type used to represent the true intention of the post"
},
"peer": {
"type": "Peer",
"description": "The author peer of the post, this property can be null if the post was deleted.",
"nullable": true
},
"source": {
"type": "string",
"description": "The source for where this post was composed from or collected from (eg; the client the user is using or the third-party source that the post was collected. This is determined by the server). This property can be null if the post was deleted.",
"nullable": true
},
"text": {
"type": "string",
"description": "The text content of the post source. This property can be null if the post has been deleted",
"nullable": true
},
"entities": {
"type": "TextEntity[]",
"description": "An array of entities extracted from the text, can be used by the client to highlight clickable entities that preforms an action. This property can be null if the post was deleted.",
"nullable": true
},
"mentioned_peers": {
"type": "Peer[]",
"description": "An array of resolved peers that was mentioned in the post text. This property can be null if the post was deleted",
"nullable": true
},
"reply_to_post": {
"type": "Post",
"description": "The original post that this post is replying to if applicable, otherwise null.",
"nullable": true
},
"quoted_post": {
"type": "Post",
"description": "The original post that this post is quoting if applicable, otherwise null",
"nullable": true
},
"reposted_post": {
"type": "Post",
"description": "The original post that this post is reposting if applicable, otherwise null",
"nullable": true
},
"original_thread_post": {
"type": "Post",
"description": "The original thread post, only applicable to replies. This value indicates the main thread post where all the replies originated from. This value will remain the same for all sub-replies of the main post.",
"nullable": true
},
"like_count": {
"type": "number",
"description": "The amount of likes that this post has if applicable, otherwise null",
"nullable": true
},
"reposts_count": {
"type": "number",
"description": "The amount of repost that this post has if applicable, otherwise null",
"nullable": true
},
"quotes_count": {
"type": "number",
"description": "The amount of replies that this post has if applicable, otherwise null",
"nullable": true
},
"posted_timestamp": {
"type": "number",
"description": "The Unix Timestamp for when this post was created",
"date": true
},
"flags": {
"type": "string[]",
"description": "The flags associated with this post (WIP)"
}
}, },
"interfaces": { "ServerInformation": {
"Post": { "network_name": {
"id": { "type": "string",
"type": "string", "description": "The name of the network, eg; \"Socialvoid\""
"description": "The unique ID for the post" },
}, "protocol_version": {
"type": { "type": "string",
"type": "PostType", "description": "The version of the protocol standard that the server is using, eg; \"1.0\""
"description": "The post type used to represent the true intention of the post" },
}, "cdn_server": {
"peer": { "type": "string",
"type": "Peer", "description": "The HTTP URL Endpoint for the CDN server of the network"
"description": "The author peer of the post, this property can be null if the post was deleted.", },
"nullable": true "upload_max_file_size": {
}, "type": "number",
"source": { "description": "The maximum size of a file that you can upload to the CDN Server (in bytes)"
"type": "string", },
"description": "The source for where this post was composed from or collected from (eg; the client the user is using or the third-party source that the post was collected. This is determined by the server). This property can be null if the post was deleted.", "unauthorized_session_ttl": {
"nullable": true "type": "number",
}, "description": "The maximum time-to-live (in seconds) that an unauthorized session may have. The server will often reset the expiration whenever the session is used."
"text": { },
"type": "string", "authorized_session_ttl": {
"description": "The text content of the post source. This property can be null if the post has been deleted", "type": "number",
"nullable": true "description": "The maximum time-to-live (in seconds) that an authorized session may have. The server will often reset the expiration whenever the session is used."
}, },
"entities": { "retrieve_likes_max_limit": {
"type": "TextEntity[]", "type": "number",
"description": "An array of entities extracted from the text, can be used by the client to highlight clickable entities that preforms an action. This property can be null if the post was deleted.", "description": "The maximum amount of likes a client can retrieve at once using the method `timeline.get_likes` via the `limit` parameter"
"nullable": true },
}, "retrieve_reposts_max_limit": {
"mentioned_peers": { "type": "number",
"type": "Peer[]", "description": "The maximum amount of reposts a client can retrieve at once using the method `timeline.get_reposted_peers` via the `limit` parameter"
"description": "An array of resolved peers that was mentioned in the post text. This property can be null if the post was deleted", },
"nullable": true "retrieve_replies_max_limit": {
}, "type": "number",
"reply_to_post": { "description": "The maximum amount of replies a client can retrieve at once using the method `timeline.get_replies` via the `limit` parameter"
"type": "Post", },
"description": "The original post that this post is replying to if applicable, otherwise null.", "retrieve_quotes_max_limit": {
"nullable": true "type": "number",
}, "description": "The maximum amount of quotes a client can retrieve at once using the method `timeline.get_quotes` via the `limit` parameter"
"quoted_post": { },
"type": "Post", "retrieve_followers_max_limit": {
"description": "The original post that this post is quoting if applicable, otherwise null", "type": "number",
"nullable": true "description": "The maximum amount of followers a client can retrieve at once using the method `network.get_followers` via the `limit` parameter"
}, },
"reposted_post": { "retrieve_following_max_limit": {
"type": "Post", "type": "number",
"description": "The original post that this post is reposting if applicable, otherwise null", "description": "The maximum amount of following peers a client can retrieve at once using the method `network.get_following` via the `limit` parameter"
"nullable": true }
}, },
"original_thread_post": { "Peer": {
"type": "Post", "id": {
"description": "The original thread post, only applicable to replies. This value indicates the main thread post where all the replies originated from. This value will remain the same for all sub-replies of the main post.", "type": "string",
"nullable": true "description": "The ID of the user associated to the network"
}, },
"like_count": { "type": {
"type": "number", "type": "PeerType",
"description": "The amount of likes that this post has if applicable, otherwise null", "description": "The type of the peer entity"
"nullable": true },
}, "name": {
"reposts_count": { "type": "string",
"type": "number", "description": "The display name of the peer"
"description": "The amount of repost that this post has if applicable, otherwise null", },
"nullable": true "username": {
}, "type": "string",
"quotes_count": { "description": "The username associated with this peer"
"type": "number", },
"description": "The amount of replies that this post has if applicable, otherwise null", "flags": {
"nullable": true "type": "string[]",
}, "description": "Flags associated with this peer"
"posted_timestamp": { }
"type": "number", },
"description": "The Unix Timestamp for when this post was created", "Session": {
"date": true "id": {
}, "type": "string",
"flags": { "description": "The ID of the session obtained when establishing a session"
"type": "string[]", },
"description": "The flags associated with this post (WIP)" "flags": {
} "type": "string[]",
}, "description": "An array of flags that has been set to this session"
"ServerInformation": { },
"network_name": { "authenticated": {
"type": "string", "type": "boolean",
"description": "The name of the network, eg; \"Socialvoid\"" "description": "Indicates if the session is currently authenticated to a user"
}, },
"protocol_version": { "created": {
"type": "string", "type": "number",
"description": "The version of the protocol standard that the server is using, eg; \"1.0\"" "description": "The Unix Timestamp for when this session was first created",
}, "date": true
"cdn_server": { },
"type": "string", "expires": {
"description": "The HTTP URL Endpoint for the CDN server of the network" "type": "number",
}, "description": "The Unix Timestamp for when this session expires",
"upload_max_file_size": { "date": true
"type": "number", }
"description": "The maximum size of a file that you can upload to the CDN Server (in bytes)" },
}, "Document": {
"unauthorized_session_ttl": { "id": { "type": "string", "description": "The ID of the document" },
"type": "number", "file_mime": { "type": "string", "description": "The Mime of the file" },
"description": "The maximum time-to-live (in seconds) that an unauthorized session may have. The server will often reset the expiration whenever the session is used." "file_name": {
}, "type": "string",
"authorized_session_ttl": { "description": "The original name of the file"
"type": "number", },
"description": "The maximum time-to-live (in seconds) that an authorized session may have. The server will often reset the expiration whenever the session is used." "file_size": {
}, "type": "number",
"retrieve_likes_max_limit": { "description": "The size of the file in bytes"
"type": "number", },
"description": "The maximum amount of likes a client can retrieve at once using the method `timeline.get_likes` via the `limit` parameter" "file_type": {
}, "type": "FileType",
"retrieve_reposts_max_limit": { "description": "The type of file detected by the server"
"type": "number", },
"description": "The maximum amount of reposts a client can retrieve at once using the method `timeline.get_reposted_peers` via the `limit` parameter" "flags": {
}, "type": "string[]",
"retrieve_replies_max_limit": { "description": "An array of flags associated with this document"
"type": "number", }
"description": "The maximum amount of replies a client can retrieve at once using the method `timeline.get_replies` via the `limit` parameter" },
}, "HelpDocument": {
"retrieve_quotes_max_limit": { "id": {
"type": "number", "type": "string",
"description": "The maximum amount of quotes a client can retrieve at once using the method `timeline.get_quotes` via the `limit` parameter" "description": "The ID of the document, if the document gets updated then the ID will change."
}, },
"retrieve_followers_max_limit": { "text": {
"type": "number", "type": "string",
"description": "The maximum amount of followers a client can retrieve at once using the method `network.get_followers` via the `limit` parameter" "description": "The text contents of the document"
}, },
"retrieve_following_max_limit": { "entities": {
"type": "number", "type": "TextEntity[]",
"description": "The maximum amount of following peers a client can retrieve at once using the method `network.get_following` via the `limit` parameter" "description": "An array of text entities being represented in the text"
} }
}, },
"Peer": { "DisplayPictureSize": {
"id": { "width": { "type": "number", "description": "The width of the image" },
"type": "string", "height": { "type": "number", "description": "The height of the image" },
"description": "The ID of the user associated to the network" "document": {
}, "type": "Document",
"type": { "description": "The document object that points to the display picture"
"type": "PeerType", }
"description": "The type of the peer entity" },
}, "Profile": {
"name": { "first_name": {
"type": "string", "type": "string",
"description": "The display name of the peer" "description": "The first name of the entity"
}, },
"username": { "last_name": {
"type": "string", "type": "string",
"description": "The username associated with this peer" "description": "The last name of the entity",
}, "nullable": true
"flags": { },
"type": "string[]", "name": {
"description": "Flags associated with this peer" "type": "string",
} "description": "The full display name of the entity"
}, },
"Session": { "biography": {
"id": { "type": "string",
"type": "string", "description": "A biography or description of the entity",
"description": "The ID of the session obtained when establishing a session" "nullable": true
}, },
"flags": { "location": {
"type": "string[]", "type": "string",
"description": "An array of flags that has been set to this session" "description": "The location of the entity",
}, "nullable": true
"authenticated": { },
"type": "boolean", "url": {
"description": "Indicates if the session is currently authenticated to a user" "type": "string",
}, "description": "The URL of the entity (Can be a website or a blog, etc)",
"created": { "nullable": true
"type": "number", },
"description": "The Unix Timestamp for when this session was first created", "followers_count": {
"date": true "type": "number",
}, "description": "The amount of followers that this entity has"
"expires": { },
"type": "number", "following_count": {
"description": "The Unix Timestamp for when this session expires", "type": "number",
"date": true "description": "The amount of peers that this entity is following"
} },
}, "display_picture_sizes": {
"Document": { "type": "DisplayPictureSize[]",
"id": { "type": "string", "description": "The ID of the document" }, "description": "An array of display picture size objects that represents the entity's display picture"
"file_mime": { "type": "string", "description": "The Mime of the file" }, }
"file_name": { },
"type": "string", "SessionIdentification": {
"description": "The original name of the file" "session_id": {
}, "type": "string",
"file_size": { "description": "The ID of the session obtained when establishing a session"
"type": "number", },
"description": "The size of the file in bytes" "client_public_hash": {
}, "type": "string",
"file_type": { "description": "The Public Hash of the client used when establishing the session"
"type": "FileType", },
"description": "The type of file detected by the server" "challenge_answer": {
}, "type": "string",
"flags": { "description": "The session challenge answer revolving around the client's private hash, the same client used to establish the session"
"type": "string[]", }
"description": "An array of flags associated with this document" },
} "SessionEstablished": {
}, "id": {
"HelpDocument": { "type": "string",
"id": { "description": "The ID of the session obtained when establishing a session"
"type": "string", },
"description": "The ID of the document, if the document gets updated then the ID will change." "challenge": {
}, "type": "string",
"text": { "description": "The TOTP based challenge secret"
"type": "string", }
"description": "The text contents of the document" },
}, "TextEntity": {
"entities": { "type": {
"type": "TextEntity[]", "type": "TextEntityType",
"description": "An array of text entities being represented in the text" "description": "The text entity type"
} },
}, "offset": {
"DisplayPictureSize": { "type": "number",
"width": { "type": "number", "description": "The width of the image" }, "description": "The offset for when the entity begins in the text"
"height": { "type": "number", "description": "The height of the image" }, },
"document": { "length": { "type": "number", "description": "The length of the entity" },
"type": "Document", "value": {
"description": "The document object that points to the display picture" "type": "string",
} "description": "The value of the entity, for styling entities such as `BOLD | ITALIC`, etc. this value will be null, but for values such as `MENTION | HASHTAG` & `URL` the value will contain the respective value for the entity, for example a `URL` entity will contain a value of a http URL",
}, "nullable": true
"Profile": { }
"first_name": {
"type": "string",
"description": "The first name of the entity"
},
"last_name": {
"type": "string",
"description": "The last name of the entity",
"nullable": true
},
"name": {
"type": "string",
"description": "The full display name of the entity"
},
"biography": {
"type": "string",
"description": "A biography or description of the entity",
"nullable": true
},
"location": {
"type": "string",
"description": "The location of the entity",
"nullable": true
},
"url": {
"type": "string",
"description": "The URL of the entity (Can be a website or a blog, etc)",
"nullable": true
},
"followers_count": {
"type": "number",
"description": "The amount of followers that this entity has"
},
"following_count": {
"type": "number",
"description": "The amount of peers that this entity is following"
},
"display_picture_sizes": {
"type": "DisplayPictureSize[]",
"description": "An array of display picture size objects that represents the entity's display picture"
}
},
"SessionIdentification": {
"session_id": {
"type": "string",
"description": "The ID of the session obtained when establishing a session"
},
"client_public_hash": {
"type": "string",
"description": "The Public Hash of the client used when establishing the session"
},
"challenge_answer": {
"type": "string",
"description": "The session challenge answer revolving around the client's private hash, the same client used to establish the session"
}
},
"SessionEstablished": {
"id": {
"type": "string",
"description": "The ID of the session obtained when establishing a session"
},
"challenge": {
"type": "string",
"description": "The TOTP based challenge secret"
}
},
"TextEntity": {
"type": {
"type": "TextEntityType",
"description": "The text entity type"
},
"offset": {
"type": "number",
"description": "The offset for when the entity begins in the text"
},
"length": { "type": "number", "description": "The length of the entity" },
"value": {
"type": "string",
"description": "The value of the entity, for styling entities such as `BOLD | ITALIC`, etc. this value will be null, but for values such as `MENTION | HASHTAG` & `URL` the value will contain the respective value for the entity, for example a `URL` entity will contain a value of a http URL",
"nullable": true
}
}
} }
}
} }

View File

@ -1,6 +1,6 @@
export const format = () => export const format = () =>
Deno.run({ Deno.run({
cmd: ["deno", "fmt", "--config", "deno.json"], cmd: ["deno", "fmt", "--config", "deno.json"],
cwd: "../", cwd: "../",
stdout: "piped", stdout: "piped",
}).output(); }).output();

View File

@ -1,8 +1,8 @@
import { format } from "./format.ts"; import { format } from "./format.ts";
interface Error { interface Error {
_: string; _: string;
description: string; description: string;
} }
type ErrorGroup = { [key: string]: Error }; type ErrorGroup = { [key: string]: Error };
@ -10,7 +10,7 @@ type ErrorGroup = { [key: string]: Error };
type ErrorGroups = { [key: string]: ErrorGroup }; type ErrorGroups = { [key: string]: ErrorGroup };
const errorGroups: ErrorGroups = JSON.parse( const errorGroups: ErrorGroups = JSON.parse(
Deno.readTextFileSync("./data/errors.json"), Deno.readTextFileSync("./data/errors.json"),
); );
let map: { [key: string]: string } = {}; let map: { [key: string]: string } = {};
@ -27,27 +27,27 @@ export class SocialvoidError extends Error {
`; `;
for (const i in errorGroups) { for (const i in errorGroups) {
const name = i.charAt(0).toUpperCase() + i.slice(1) + "Error"; const name = i.charAt(0).toUpperCase() + i.slice(1) + "Error";
const errorGroup = errorGroups[i]; const errorGroup = errorGroups[i];
toWrite += ` toWrite += `
export class ${name} extends SocialvoidError {} export class ${name} extends SocialvoidError {}
`; `;
for (const i in errorGroup) { for (const i in errorGroup) {
const code = i; const code = i;
const type = errorGroup[code]._; const type = errorGroup[code]._;
map[code] = type; map[code] = type;
toWrite += `export class ${type} extends ${name} {}\n\n`; toWrite += `export class ${type} extends ${name} {}\n\n`;
} }
} }
toWrite += "const map: {[key: string]: typeof SocialvoidError} = "; toWrite += "const map: {[key: string]: typeof SocialvoidError} = ";
toWrite += JSON.stringify(map) toWrite += JSON.stringify(map)
.replaceAll('":"', '":') .replaceAll('":"', '":')
.replaceAll('",', ",") .replaceAll('",', ",")
.replace('"}', "}"); .replace('"}', "}");
toWrite += ";\n\n"; toWrite += ";\n\n";
toWrite += "export default map;"; toWrite += "export default map;";

View File

@ -2,49 +2,49 @@ import { toCamel } from "./helpers.ts";
import { format } from "./format.ts"; import { format } from "./format.ts";
interface TypeParams { interface TypeParams {
type: string; type: string;
description: string; description: string;
date?: boolean; date?: boolean;
nullable?: boolean; nullable?: boolean;
} }
type Type = { [key: string]: TypeParams }; type Type = { [key: string]: TypeParams };
type Types = { type Types = {
types: { [key: string]: string }; types: { [key: string]: string };
interfaces: { [key: string]: Type }; interfaces: { [key: string]: Type };
}; };
const types: Types = JSON.parse( const types: Types = JSON.parse(
Deno.readTextFileSync("./data/types.json"), Deno.readTextFileSync("./data/types.json"),
); );
let code = ``; let code = ``;
for (const name in types.types) { for (const name in types.types) {
const type = types.types[name]; const type = types.types[name];
code += `export type ${name} = ${type};\n\n`; code += `export type ${name} = ${type};\n\n`;
} }
for (const name in types.interfaces) { for (const name in types.interfaces) {
const params = types.interfaces[name]; const params = types.interfaces[name];
code += `export interface ${name} {`; code += `export interface ${name} {`;
for (const name in params) { for (const name in params) {
const param = params[name]; const param = params[name];
code += `\n/** ${param.description} */\n`; code += `\n/** ${param.description} */\n`;
code += `${name}: ${param.type}`; code += `${name}: ${param.type}`;
if (param.nullable) { if (param.nullable) {
code += " | null"; code += " | null";
}
code += ";";
} }
code += "}\n\n"; code += ";";
}
code += "}\n\n";
} }
await Deno.writeTextFile("../socialvoid/types.ts", code); await Deno.writeTextFile("../socialvoid/types.ts", code);

View File

@ -1,5 +1,5 @@
export const toCamel = (s: string) => { export const toCamel = (s: string) => {
return s.replace(/([-_][a-z])/gi, ($1) => { return s.replace(/([-_][a-z])/gi, ($1) => {
return $1.toUpperCase().replace("-", "").replace("_", ""); return $1.toUpperCase().replace("-", "").replace("_", "");
}); });
}; };

View File

@ -6,117 +6,117 @@ import { throwError } from "./utils.ts";
export class NotInitialized extends Error {} export class NotInitialized extends Error {}
export interface Session { export interface Session {
id: string; id: string;
publicHash: string; publicHash: string;
privateHash: string; privateHash: string;
challenge: string; challenge: string;
} }
export class BaseClient { export class BaseClient {
protected _session?: Session; protected _session?: Session;
constructor( constructor(
public readonly rpcEndpoint: string, public readonly rpcEndpoint: string,
) { ) {
}
async getCDNEndpoint(): Promise<string> {
throw new Error("Not implemented");
}
async sessionId() {
if (!this._session) {
throw new Error("Session does not exist");
} }
async getCDNEndpoint(): Promise<string> { return {
throw new Error("Not implemented"); session_identification: {
session_id: this._session.id,
client_public_hash: this._session.publicHash,
challenge_answer: await answerChallenge(
this._session.privateHash,
this._session.challenge,
),
},
};
}
async invokeRequest(request: Request, includeSessionId?: boolean) {
if (includeSessionId) {
request.params = { ...request.params, ...(await this.sessionId()) };
} }
async sessionId() { const result = parseResponses(await this.send(serializeRequests(request)));
if (!this._session) {
throw new Error("Session does not exist");
}
return { if (result && !Array.isArray(result)) {
session_identification: { return result.unwrap();
session_id: this._session.id,
client_public_hash: this._session.publicHash,
challenge_answer: await answerChallenge(
this._session.privateHash,
this._session.challenge,
),
},
};
} }
async invokeRequest(request: Request, includeSessionId?: boolean) { return {};
if (includeSessionId) { }
request.params = { ...request.params, ...(await this.sessionId()) };
}
const result = parseResponses(await this.send(serializeRequests(request))); async invokeRequests(...requests: Request[]) {
if (!requests) {
if (result && !Array.isArray(result)) { throw new Error(
return result.unwrap(); "The parameter `requests` cannot be `undefined` or empty",
} );
return {};
} }
async invokeRequests(...requests: Request[]) { const toReturn = new Array<Response>();
if (!requests) { const result = parseResponses(
throw new Error( await this.send(serializeRequests(...requests)),
"The parameter `requests` cannot be `undefined` or empty", );
);
}
const toReturn = new Array<Response>(); if (result) {
const result = parseResponses( if (Array.isArray(result)) {
await this.send(serializeRequests(...requests)), toReturn.push(...result);
); } else {
toReturn.push(result);
if (result) { }
if (Array.isArray(result)) {
toReturn.push(...result);
} else {
toReturn.push(result);
}
}
return toReturn.map((response) => response.unwrap());
} }
async invokeCDNRequest(data: FormData) { return toReturn.map((response) => response.unwrap());
return await (await this.sendCDN(data)).json(); }
async invokeCDNRequest(data: FormData) {
return await (await this.sendCDN(data)).json();
}
async invokeCDNDownloadRequest(data: FormData, stream?: boolean) {
const response = (await this.sendCDN(data));
return stream ? await response.blob() : await response.arrayBuffer();
}
async send(data: any) {
return await (
await fetch(this.rpcEndpoint, {
method: "POST",
headers: { "Content-Type": "application/json-rpc" },
body: data,
})
).json();
}
async sendCDN(data: FormData) {
const response = await fetch(await this.getCDNEndpoint(), {
method: "POST",
body: data,
});
if (response.status != 200) {
const json = await response.json();
if (
typeof json.error_code !== "undefined" &&
typeof json.message !== "undefined"
) {
throwError(json.error_code, json.message);
}
throw new Error(`Got status ${response.status}`);
} }
async invokeCDNDownloadRequest(data: FormData, stream?: boolean) { return response;
const response = (await this.sendCDN(data)); }
return stream ? await response.blob() : await response.arrayBuffer();
}
async send(data: any) {
return await (
await fetch(this.rpcEndpoint, {
method: "POST",
headers: { "Content-Type": "application/json-rpc" },
body: data,
})
).json();
}
async sendCDN(data: FormData) {
const response = await fetch(await this.getCDNEndpoint(), {
method: "POST",
body: data,
});
if (response.status != 200) {
const json = await response.json();
if (
typeof json.error_code !== "undefined" &&
typeof json.message !== "undefined"
) {
throwError(json.error_code, json.message);
}
throw new Error(`Got status ${response.status}`);
}
return response;
}
} }

View File

@ -1,90 +1,90 @@
import { IS_BROWSER } from "./constants.ts"; import { IS_BROWSER } from "./constants.ts";
import { import {
FileName, FileName,
FileStore, FileStore,
LocalStorageKey, LocalStorageKey,
LocalStorageStore, LocalStorageStore,
Memory, Memory,
MemoryStore, MemoryStore,
Store, Store,
} from "./stores/mod.ts"; } from "./stores/mod.ts";
import { Account, CDN, Cloud, Help, Network, Session, Timeline } from "./methods/mod.ts"; import { Account, CDN, Cloud, Help, Network, Session, Timeline } from "./methods/mod.ts";
import { BaseClient } from "./base_client.ts"; import { BaseClient } from "./base_client.ts";
import { newHash } from "./utils.ts"; import { newHash } from "./utils.ts";
export class Client extends BaseClient { export class Client extends BaseClient {
help = new Help(this); help = new Help(this);
cloud = new Cloud(this); cloud = new Cloud(this);
network = new Network(this); network = new Network(this);
session = new Session(this); session = new Session(this);
account = new Account(this); account = new Account(this);
cdn = new CDN(this); cdn = new CDN(this);
timeline = new Timeline(this); timeline = new Timeline(this);
private store: Store; private store: Store;
constructor( constructor(
store: Memory | FileName | LocalStorageKey | Store = "main", store: Memory | FileName | LocalStorageKey | Store = "main",
rpcEndpoint = "http://socialvoid.qlg1.com:5601", rpcEndpoint = "http://socialvoid.qlg1.com:5601",
public customCDNEndpoint?: string, public customCDNEndpoint?: string,
) { ) {
super(rpcEndpoint); super(rpcEndpoint);
this.store = typeof store === "undefined" this.store = typeof store === "undefined"
? new MemoryStore() ? new MemoryStore()
: typeof store === "string" : typeof store === "string"
? store == ":memory:" ? store == ":memory:"
? new MemoryStore() ? new MemoryStore()
: IS_BROWSER : IS_BROWSER
? new LocalStorageStore(store) ? new LocalStorageStore(store)
: new FileStore(store) : new FileStore(store)
: store; : store;
const session = this.store.get("session"); const session = this.store.get("session");
if (session) { if (session) {
this._session = session; this._session = session;
}
this.network = new Network(this);
this.help = new Help(this);
this.cloud = new Cloud(this);
} }
async getCDNEndpoint(): Promise<string> { this.network = new Network(this);
if (this.customCDNEndpoint) { this.help = new Help(this);
return this.customCDNEndpoint; this.cloud = new Cloud(this);
} }
return (await this.help.getServerInformation()).cdn_server; async getCDNEndpoint(): Promise<string> {
if (this.customCDNEndpoint) {
return this.customCDNEndpoint;
} }
async newSession() { return (await this.help.getServerInformation()).cdn_server;
if (this._session) { }
return;
}
const publicHash = newHash(); async newSession() {
const privateHash = newHash(); if (this._session) {
return;
const session = await this.session.create(publicHash, privateHash);
this._session = {
publicHash,
privateHash,
id: session.id,
challenge: session.challenge,
};
this.store.set("session", this._session);
this.store.save();
} }
deleteSession() { const publicHash = newHash();
this._session = undefined; const privateHash = newHash();
this.store.delete("session");
this.store.save();
}
get sessionExists() { const session = await this.session.create(publicHash, privateHash);
return this._session != undefined; this._session = {
} publicHash,
privateHash,
id: session.id,
challenge: session.challenge,
};
this.store.set("session", this._session);
this.store.save();
}
deleteSession() {
this._session = undefined;
this.store.delete("session");
this.store.save();
}
get sessionExists() {
return this._session != undefined;
}
} }

View File

@ -12,7 +12,7 @@ export const writeTextFileSync = isBrowser ? (...args: any) => {} : Deno.writeTe
export const readTextFileSync = isBrowser ? (...args: any) => "" : Deno.readTextFileSync; export const readTextFileSync = isBrowser ? (...args: any) => "" : Deno.readTextFileSync;
export const getRandomValues = (size: number) => { export const getRandomValues = (size: number) => {
return crypto.getRandomValues(new Uint8Array(size)).buffer; return crypto.getRandomValues(new Uint8Array(size)).buffer;
}; };
export { jsSHA, OTPAuth }; export { jsSHA, OTPAuth };

View File

@ -16,11 +16,11 @@ export const isBrowser = typeof window !== "undefined";
export const os = isBrowser ? "Browser" : process.platform; export const os = isBrowser ? "Browser" : process.platform;
export const readTextFileSync = (file: string) => { export const readTextFileSync = (file: string) => {
return readFileSync(file).toString(); return readFileSync(file).toString();
}; };
export const getRandomValues = (size: number) => { export const getRandomValues = (size: number) => {
return randomBytes(size).buffer; return randomBytes(size).buffer;
}; };
export { jsSHA, OTPAuth }; export { jsSHA, OTPAuth };

View File

@ -1,10 +1,10 @@
export class SocialvoidError extends Error { export class SocialvoidError extends Error {
message: string; message: string;
constructor(public errorCode: number, public errorMessage: string) { constructor(public errorCode: number, public errorMessage: string) {
super(); super();
this.message = `Error ${errorCode}: ${errorMessage}`; this.message = `Error ${errorCode}: ${errorMessage}`;
} }
} }
export class ValidationError extends SocialvoidError {} export class ValidationError extends SocialvoidError {}
@ -100,48 +100,48 @@ export class AlreadyAuthenticated extends AuthenticationError {}
export class SessionExpired extends AuthenticationError {} export class SessionExpired extends AuthenticationError {}
const map: { [key: string]: typeof SocialvoidError } = { const map: { [key: string]: typeof SocialvoidError } = {
"8448": InvalidUsername, "8448": InvalidUsername,
"8449": InvalidPassword, "8449": InvalidPassword,
"8450": InvalidFirstName, "8450": InvalidFirstName,
"8451": InvalidLastName, "8451": InvalidLastName,
"8452": InvalidBiography, "8452": InvalidBiography,
"8453": UsernameAlreadyExists, "8453": UsernameAlreadyExists,
"8454": InvalidPeerInput, "8454": InvalidPeerInput,
"8455": InvalidPostText, "8455": InvalidPostText,
"8456": InvalidClientPublicHash, "8456": InvalidClientPublicHash,
"8457": InvalidClientPrivateHash, "8457": InvalidClientPrivateHash,
"8458": InvalidPlatform, "8458": InvalidPlatform,
"8459": InvalidVersion, "8459": InvalidVersion,
"8460": InvalidClientName, "8460": InvalidClientName,
"8461": InvalidSessionIdentification, "8461": InvalidSessionIdentification,
"8462": InvalidFileForProfilePicture, "8462": InvalidFileForProfilePicture,
"8463": FileTooLarge, "8463": FileTooLarge,
"8464": InvalidHelpDocumentId, "8464": InvalidHelpDocumentId,
"8465": AgreementRequired, "8465": AgreementRequired,
"8468": InvalidUrlValue, "8468": InvalidUrlValue,
"8704": IncorrectLoginCredentials, "8704": IncorrectLoginCredentials,
"8705": IncorrectTwoFactorAuthenticationCode, "8705": IncorrectTwoFactorAuthenticationCode,
"8706": AuthenticationNotApplicable, "8706": AuthenticationNotApplicable,
"8707": SessionNotFound, "8707": SessionNotFound,
"8708": NotAuthenticated, "8708": NotAuthenticated,
"8709": PrivateAccessTokenRequired, "8709": PrivateAccessTokenRequired,
"8710": AuthenticationFailure, "8710": AuthenticationFailure,
"8711": BadSessionChallengeAnswer, "8711": BadSessionChallengeAnswer,
"8712": TwoFactorAuthenticationRequired, "8712": TwoFactorAuthenticationRequired,
"8713": AlreadyAuthenticated, "8713": AlreadyAuthenticated,
"8714": SessionExpired, "8714": SessionExpired,
"12544": PeerNotFound, "12544": PeerNotFound,
"12545": PostNotFound, "12545": PostNotFound,
"12546": PostDeleted, "12546": PostDeleted,
"12547": AlreadyReposted, "12547": AlreadyReposted,
"12548": FileUploadError, "12548": FileUploadError,
"12549": DocumentNotFound, "12549": DocumentNotFound,
"12550": AccessDenied, "12550": AccessDenied,
"12551": BlockedByPeer, "12551": BlockedByPeer,
"12552": BlockedPeer, "12552": BlockedPeer,
"12553": SelfInteractionNotPermitted, "12553": SelfInteractionNotPermitted,
"16384": InternalServerError, "16384": InternalServerError,
"16385": DocumentUpload, "16385": DocumentUpload,
}; };
export default map; export default map;

View File

@ -3,113 +3,113 @@ import { Document } from "../types.ts";
import { MethodBase } from "./method_base.ts"; import { MethodBase } from "./method_base.ts";
export class Account extends MethodBase { export class Account extends MethodBase {
/** /**
* Removes the profile picture of the currently logged in account. * Removes the profile picture of the currently logged in account.
*/ */
deleteProfilePicture(): Promise<boolean> { deleteProfilePicture(): Promise<boolean> {
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("account.delete_profile_picture"), new Request("account.delete_profile_picture"),
true, true,
); );
} }
/** /**
* Sets the profile picture of the currently logged in account. * Sets the profile picture of the currently logged in account.
* *
* @param document The document ID or instance of the profile picture. * @param document The document ID or instance of the profile picture.
*/ */
setProfilePicture(document: string | Document): Promise<boolean> { setProfilePicture(document: string | Document): Promise<boolean> {
document = typeof document === "string" ? document : document.id; document = typeof document === "string" ? document : document.id;
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("account.set_profile_picture", { new Request("account.set_profile_picture", {
document, document,
}), }),
true, true,
); );
} }
/** /**
* Removes the profile biography of the currently logged in account. * Removes the profile biography of the currently logged in account.
*/ */
clearProfileBiography(): Promise<boolean> { clearProfileBiography(): Promise<boolean> {
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("account.clear_profile_biography"), new Request("account.clear_profile_biography"),
true, true,
); );
} }
/** /**
* Removes the profile URL of the currently logged in account. * Removes the profile URL of the currently logged in account.
*/ */
clearProfileURL(): Promise<boolean> { clearProfileURL(): Promise<boolean> {
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("account.clear_profile_url"), new Request("account.clear_profile_url"),
true, true,
); );
} }
/** /**
* Removes the profile location of the currently logged in account. * Removes the profile location of the currently logged in account.
*/ */
clearProfileLocation(): Promise<boolean> { clearProfileLocation(): Promise<boolean> {
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("account.clear_profile_location"), new Request("account.clear_profile_location"),
true, true,
); );
} }
/** /**
* Updates the profile biography of the currently logged in account. * Updates the profile biography of the currently logged in account.
* *
* @param biography The new biography. * @param biography The new biography.
*/ */
updateProfileBiography(biography: string): Promise<boolean> { updateProfileBiography(biography: string): Promise<boolean> {
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("account.update_profile_biography", { biography }), new Request("account.update_profile_biography", { biography }),
true, true,
); );
} }
/** /**
* Updates the profile location of the currently logged in account. * Updates the profile location of the currently logged in account.
* *
* @param location The new location * @param location The new location
*/ */
updateProfileLocation(location: string): Promise<boolean> { updateProfileLocation(location: string): Promise<boolean> {
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("account.update_profile_location", { location }), new Request("account.update_profile_location", { location }),
true, true,
); );
} }
/** /**
* Updates the profile name of the currently logged in account. * Updates the profile name of the currently logged in account.
* *
* @param firstName The new first name. * @param firstName The new first name.
* @param lastName The new last name. Will get removed if not passed. * @param lastName The new last name. Will get removed if not passed.
*/ */
updateProfileName(firstName: string, lastName?: string): Promise<boolean> { updateProfileName(firstName: string, lastName?: string): Promise<boolean> {
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("account.update_profile_name", { new Request("account.update_profile_name", {
first_name: firstName, first_name: firstName,
last_name: lastName, last_name: lastName,
}), }),
true, true,
); );
} }
/** /**
* Updates the profile URL of the currently logged in account. * Updates the profile URL of the currently logged in account.
* *
* @param url The new URL. * @param url The new URL.
*/ */
updateProfileURL(url: string): Promise<boolean> { updateProfileURL(url: string): Promise<boolean> {
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("account.update_profile_url", { new Request("account.update_profile_url", {
url, url,
}), }),
true, true,
); );
} }
} }

View File

@ -3,34 +3,34 @@ import { formFromObj } from "../utils.ts";
import { MethodBase } from "./method_base.ts"; import { MethodBase } from "./method_base.ts";
export class CDN extends MethodBase { export class CDN extends MethodBase {
/** /**
* Uploads a file. * Uploads a file.
* *
* @param document The file, it can be a buffer or a readable stream. * @param document The file, it can be a buffer or a readable stream.
*/ */
async upload(document: any): Promise<Document> { async upload(document: any): Promise<Document> {
const form = formFromObj({ const form = formFromObj({
action: "upload", action: "upload",
document, document,
...(await this.client.sessionId()).session_identification, ...(await this.client.sessionId()).session_identification,
}); });
return (await this.client.invokeCDNRequest(form)).results; return (await this.client.invokeCDNRequest(form)).results;
} }
/** /**
* Downloads the provided document. * Downloads the provided document.
* *
* @param document The ID or instance of the document. * @param document The ID or instance of the document.
* @param stream Wheather to download and returns its data or stream it, returning a `Blob`. * @param stream Wheather to download and returns its data or stream it, returning a `Blob`.
*/ */
async download(document: string | Document, stream?: boolean) { async download(document: string | Document, stream?: boolean) {
const form = formFromObj({ const form = formFromObj({
action: "download", action: "download",
document: typeof document == "string" ? document : document.id, document: typeof document == "string" ? document : document.id,
...(await this.client.sessionId()).session_identification, ...(await this.client.sessionId()).session_identification,
}); });
return this.client.invokeCDNDownloadRequest(form, stream); return this.client.invokeCDNDownloadRequest(form, stream);
} }
} }

View File

@ -3,19 +3,19 @@ import { MethodBase } from "./method_base.ts";
import { Request } from "../request.ts"; import { Request } from "../request.ts";
export class Cloud extends MethodBase { export class Cloud extends MethodBase {
/** /**
* Resolves a document. * Resolves a document.
* *
* @param document The ID or instance of the document. * @param document The ID or instance of the document.
*/ */
getDocument(document: string | Document): Promise<Document> { getDocument(document: string | Document): Promise<Document> {
document = typeof document == "string" ? document : document.id; document = typeof document == "string" ? document : document.id;
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("cloud.get_document", { new Request("cloud.get_document", {
document, document,
}), }),
true, true,
); );
} }
} }

View File

@ -3,45 +3,45 @@ import { HelpDocument, ServerInformation } from "../types.ts";
import { MethodBase } from "./method_base.ts"; import { MethodBase } from "./method_base.ts";
export class Help extends MethodBase { export class Help extends MethodBase {
private cachedServerInformation?: ServerInformation; private cachedServerInformation?: ServerInformation;
/** /**
* Retrieves the Community Guidelines. * Retrieves the Community Guidelines.
*/ */
getCommunityGuidelines(): Promise<HelpDocument> { getCommunityGuidelines(): Promise<HelpDocument> {
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("help.get_community_guidelines"), new Request("help.get_community_guidelines"),
); );
} }
/** /**
* Retrieves the Privacy Policy. * Retrieves the Privacy Policy.
*/ */
getPrivacyPolicy(): Promise<HelpDocument> { getPrivacyPolicy(): Promise<HelpDocument> {
return this.client.invokeRequest(new Request("help.get_privacy_policy")); return this.client.invokeRequest(new Request("help.get_privacy_policy"));
} }
/* /*
* Retrieves server information. * Retrieves server information.
*/ */
async getServerInformation(force?: boolean): Promise<ServerInformation> { async getServerInformation(force?: boolean): Promise<ServerInformation> {
if (this.cachedServerInformation && !force) { if (this.cachedServerInformation && !force) {
return this.cachedServerInformation; return this.cachedServerInformation;
}
const serverInformation = await this.client.invokeRequest(
new Request("help.get_server_information"),
);
this.cachedServerInformation = serverInformation;
return serverInformation;
} }
/* const serverInformation = await this.client.invokeRequest(
new Request("help.get_server_information"),
);
this.cachedServerInformation = serverInformation;
return serverInformation;
}
/*
* Retrieves the Terms of Service. * Retrieves the Terms of Service.
*/ */
getTermsOfService(): Promise<HelpDocument> { getTermsOfService(): Promise<HelpDocument> {
return this.client.invokeRequest(new Request("help.get_terms_of_service")); return this.client.invokeRequest(new Request("help.get_terms_of_service"));
} }
} }

View File

@ -1,5 +1,5 @@
import { BaseClient } from "../base_client.ts"; import { BaseClient } from "../base_client.ts";
export class MethodBase { export class MethodBase {
constructor(protected client: BaseClient) {} constructor(protected client: BaseClient) {}
} }

View File

@ -3,90 +3,84 @@ import { Peer, Profile, RelationshipType } from "../types.ts";
import { MethodBase } from "./method_base.ts"; import { MethodBase } from "./method_base.ts";
export class Network extends MethodBase { export class Network extends MethodBase {
/** /**
* Gets the peer of the currently logged in account. * Gets the peer of the currently logged in account.
*/ */
getMe(): Promise<Peer> { getMe(): Promise<Peer> {
return this.client.invokeRequest(new Request("network.get_me"), true); return this.client.invokeRequest(new Request("network.get_me"), true);
} }
/** /**
* Gets the profile of a peer using its instance or ID. * Gets the profile of a peer using its instance or ID.
* *
* @param peer The ID, handle (with a leading @) or instance of the peer. The default value is the authenticated user. * @param peer The ID, handle (with a leading @) or instance of the peer. The default value is the authenticated user.
*/ */
getProfile(peer?: string | Peer): Promise<Profile> { getProfile(peer?: string | Peer): Promise<Profile> {
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("network.get_profile", { new Request("network.get_profile", {
peer: typeof peer !== "undefined" peer: typeof peer !== "undefined" ? typeof peer == "string" ? peer : peer.id : undefined,
? typeof peer == "string" ? peer : peer.id }),
: undefined, true,
}), );
true, }
);
}
/** /**
* Returns an array of peers who follow the given peer. * Returns an array of peers who follow the given peer.
* *
* @param peer The ID, handle (with a leading @) or instance of the peer. The default value is the authenticated user. * @param peer The ID, handle (with a leading @) or instance of the peer. The default value is the authenticated user.
* @param page The current page number of the return results. The default value is `1`. * @param page The current page number of the return results. The default value is `1`.
*/ */
getFollowing(peer?: string | Peer, page?: number): Promise<Peer[]> { getFollowing(peer?: string | Peer, page?: number): Promise<Peer[]> {
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("network.get_following", { new Request("network.get_following", {
peer: typeof peer !== "undefined" peer: typeof peer !== "undefined" ? typeof peer == "string" ? peer : peer.id : undefined,
? typeof peer == "string" ? peer : peer.id page,
: undefined, }),
page, true,
}), );
true, }
);
}
/** /**
* Returns an array of peers who follow the given peer. * Returns an array of peers who follow the given peer.
* *
* @param peer The ID, handle (with a leading @) or instance of the peer. The default value is the authenticated user. * @param peer The ID, handle (with a leading @) or instance of the peer. The default value is the authenticated user.
* @param page The current page number of the return results. The default value is `1`. * @param page The current page number of the return results. The default value is `1`.
*/ */
getFollowers(peer?: string | Peer, page?: number): Promise<Peer[]> { getFollowers(peer?: string | Peer, page?: number): Promise<Peer[]> {
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("network.get_followers", { new Request("network.get_followers", {
peer: typeof peer !== "undefined" peer: typeof peer !== "undefined" ? typeof peer == "string" ? peer : peer.id : undefined,
? typeof peer == "string" ? peer : peer.id page,
: undefined, }),
page, true,
}), );
true, }
);
}
/** /**
* Follows another peer on the network. * Follows another peer on the network.
* *
* @param peer The ID, handle (with a leading @) or instance of the peer to follow. * @param peer The ID, handle (with a leading @) or instance of the peer to follow.
*/ */
followPeer(peer: string | Peer): Promise<RelationshipType> { followPeer(peer: string | Peer): Promise<RelationshipType> {
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("network.follow_peer", { new Request("network.follow_peer", {
peer: typeof peer == "string" ? peer : peer.id, peer: typeof peer == "string" ? peer : peer.id,
}), }),
true, true,
); );
} }
/** /**
* Unfollows another peer on the network. * Unfollows another peer on the network.
* *
* @param peer The ID, handle (with a leading @) or instance of the peer to unfollow. * @param peer The ID, handle (with a leading @) or instance of the peer to unfollow.
*/ */
unfollowPeer(peer: string | Peer): Promise<RelationshipType> { unfollowPeer(peer: string | Peer): Promise<RelationshipType> {
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("network.unfollow_peer", { new Request("network.unfollow_peer", {
peer: typeof peer == "string" ? peer : peer.id, peer: typeof peer == "string" ? peer : peer.id,
}), }),
true, true,
); );
} }
} }

View File

@ -4,7 +4,7 @@ import { MethodBase } from "./method_base.ts";
import { NAME, PLATFORM, VERSION } from "../constants.ts"; import { NAME, PLATFORM, VERSION } from "../constants.ts";
export class Session extends MethodBase { export class Session extends MethodBase {
/* /*
* Creates a session. * Creates a session.
* *
* **Usage:** * **Usage:**
@ -14,82 +14,82 @@ export class Session extends MethodBase {
* *
* **Note:** this method does not save the session in the client, it is recommended to use `client.newSession` instead. * **Note:** this method does not save the session in the client, it is recommended to use `client.newSession` instead.
*/ */
create( create(
publicHash: string, publicHash: string,
privateHash: string, privateHash: string,
name = NAME, name = NAME,
version = VERSION, version = VERSION,
platform = PLATFORM, platform = PLATFORM,
) { ) {
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("session.create", { new Request("session.create", {
public_hash: publicHash, public_hash: publicHash,
private_hash: privateHash, private_hash: privateHash,
name, name,
version, version,
platform, platform,
}), }),
); );
} }
/* /*
* Gets information about the current session * Gets information about the current session
*/ */
get(): Promise<ISession> { get(): Promise<ISession> {
return this.client.invokeRequest(new Request("session.get"), true); return this.client.invokeRequest(new Request("session.get"), true);
} }
/** /**
* Logs out of the account associated to the session nothing if not logged in. * Logs out of the account associated to the session nothing if not logged in.
*/ */
logout() { logout() {
return this.client.invokeRequest(new Request("session.logout", true), true); return this.client.invokeRequest(new Request("session.logout", true), true);
} }
/** /**
* Logs in to an account. * Logs in to an account.
* *
* @param username The username of the target account. * @param username The username of the target account.
* @param password The password of the target account. * @param password The password of the target account.
* @param otp An optional one-time password of the target account. * @param otp An optional one-time password of the target account.
*/ */
authenticateUser(username: string, password: string, otp?: string) { authenticateUser(username: string, password: string, otp?: string) {
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("session.authenticate_user", { new Request("session.authenticate_user", {
username, username,
password, password,
otp, otp,
}), }),
true, true,
); );
} }
/** /**
* Registers an account. * Registers an account.
* *
* @param termsOfServiceId ID of Terms of Services gained from `help.getTermsOfServices`. * @param termsOfServiceId ID of Terms of Services gained from `help.getTermsOfServices`.
* @param username The username of the account. * @param username The username of the account.
* @param password The password of the account. * @param password The password of the account.
* @param firstName The first name of the account. * @param firstName The first name of the account.
* @param lastName An optional last name of the account. * @param lastName An optional last name of the account.
*/ */
register( register(
termsOfServiceId: string, termsOfServiceId: string,
username: string, username: string,
password: string, password: string,
firstName: string, firstName: string,
lastName?: string, lastName?: string,
): Promise<Peer> { ): Promise<Peer> {
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("session.register", { new Request("session.register", {
terms_of_service_id: termsOfServiceId, terms_of_service_id: termsOfServiceId,
terms_of_service_agree: true, terms_of_service_agree: true,
username, username,
password, password,
first_name: firstName, first_name: firstName,
last_name: lastName, last_name: lastName,
}), }),
true, true,
); );
} }
} }

View File

@ -3,138 +3,145 @@ import { Document, Peer, Post } from "../types.ts";
import { MethodBase } from "./method_base.ts"; import { MethodBase } from "./method_base.ts";
export class Timeline extends MethodBase { export class Timeline extends MethodBase {
/** /**
* Composes a new post to push to the timeline. * Composes a new post to push to the timeline.
* *
* @param text The text contents of the post that is to be composed. * @param text The text contents of the post that is to be composed.
* @param attachments An array of Document ID or instances to be attached to the post. * @param attachments An array of Document ID or instances to be attached to the post.
*/ */
compose(text: string, attachments?: (string | Document)[]): Promise<Post> { compose(text: string, attachments?: (string | Document)[]): Promise<Post> {
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("timeline.compose", { new Request("timeline.compose", {
text, text,
attachments: typeof attachments !== "undefined" attachments: typeof attachments !== "undefined"
? attachments.map((attachment) => { ? attachments.map((attachment) => {
if (typeof attachment === "string") { if (typeof attachment === "string") {
return attachment; return attachment;
} }
return attachment.id; return attachment.id;
}) })
: undefined, : undefined,
}), }),
true, true,
); );
} }
/** /**
* Deletes an existing post from the timeline. * Deletes an existing post from the timeline.
* *
* @param post The ID or instance of the post to be deleted. * @param post The ID or instance of the post to be deleted.
*/ */
delete(post: string | Post): Promise<Post> { delete(post: string | Post): Promise<Post> {
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("timeline.delete", { post: typeof post === "string" ? post : post.id }), new Request("timeline.delete", {
true, post: typeof post === "string" ? post : post.id,
); }),
} true,
);
}
/** /**
* Returns the peers that liked the requested post. * Returns the peers that liked the requested post.
* *
* @param post The post ID or instance to get likes from. * @param post The post ID or instance to get likes from.
* @param page The requested page number, by default the value is 1. * @param page The requested page number, by default the value is 1.
*/ */
getLikes(post: string | Post, page?: number): Promise<Peer[]> { getLikes(post: string | Post, page?: number): Promise<Peer[]> {
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("timeline.get_likes", { new Request("timeline.get_likes", {
post: typeof post === "string" ? post : post.id, post: typeof post === "string" ? post : post.id,
page, page,
}), }),
true, true,
); );
} }
/** /**
* Retrieves an existing post from the timeline. * Retrieves an existing post from the timeline.
* *
* @param post The Post ID to retrieve from the timeline. * @param post The Post ID to retrieve from the timeline.
*/ */
getPost(post: string): Promise<Post> { getPost(post: string): Promise<Post> {
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("timeline.get_post", { new Request("timeline.get_post", {
post, post,
}), }),
true, true,
); );
} }
/** /**
* Returns an array of post quotes for the selected post. * Returns an array of post quotes for the selected post.
* *
* @param post The Post ID or instance to retrieve quotes from. * @param post The Post ID or instance to retrieve quotes from.
* @param page The requested page number, by default the value is 1. * @param page The requested page number, by default the value is 1.
*/ */
getQuotes(post: string | Post, page?: number): Promise<Post[]> { getQuotes(post: string | Post, page?: number): Promise<Post[]> {
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("timeline.get_quotes", { new Request("timeline.get_quotes", {
post: typeof post === "string" ? post : post.id, post: typeof post === "string" ? post : post.id,
page, page,
}), }),
true, true,
); );
} }
/** /**
* Returns an array of posts that replied to the selected post. * Returns an array of posts that replied to the selected post.
* *
* @param post The Post ID or instance to retrieve replies from. * @param post The Post ID or instance to retrieve replies from.
* @param page The requested page number, by default the value is 1. * @param page The requested page number, by default the value is 1.
*/ */
getReplies(post: string | Post, page?: number): Promise<Post[]> { getReplies(post: string | Post, page?: number): Promise<Post[]> {
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("timeline.get_replies", { new Request("timeline.get_replies", {
post: typeof post === "string" ? post : post.id, post: typeof post === "string" ? post : post.id,
page, page,
}), }),
true, true,
); );
} }
/** /**
* Returns an array of peers that reposted the selected post. * Returns an array of peers that reposted the selected post.
* *
* @param post The post ID or instance to get reposts from. * @param post The post ID or instance to get reposts from.
* @param page The requested page number, by default the value is 1. * @param page The requested page number, by default the value is 1.
*/ */
getRepostedPeers(post: string | Post, page?: number): Promise<Peer[]> { getRepostedPeers(post: string | Post, page?: number): Promise<Peer[]> {
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("timeline.get_reposted_peers", { new Request("timeline.get_reposted_peers", {
post: typeof post === "string" ? post : post.id, post: typeof post === "string" ? post : post.id,
page, page,
}), }),
true, true,
); );
} }
/** /**
* Likes an existing post on the timeline. * Likes an existing post on the timeline.
* *
* @param post The ID or instance of the post to like. * @param post The ID or instance of the post to like.
*/ */
like(post: string | Post): Promise<Post> { like(post: string | Post): Promise<Post> {
return this.client.invokeRequest( return this.client.invokeRequest(
new Request("timeline.like", { post: typeof post === "string" ? post : post.id }), new Request("timeline.like", {
true, post: typeof post === "string" ? post : post.id,
); }),
} true,
);
}
/** /**
* Returns an array of posts from the users timeline. * Returns an array of posts from the users timeline.
* *
* @param page The requested page number, by default the value is 1. * @param page The requested page number, by default the value is 1.
*/ */
retrieveFeed(page?: number): Promise<Post[]> { retrieveFeed(page?: number): Promise<Post[]> {
return this.client.invokeRequest(new Request("timeline.retrieve_feed", { page }), true); return this.client.invokeRequest(
} new Request("timeline.retrieve_feed", { page }),
true,
);
}
} }

View File

@ -1,11 +1,11 @@
export class Request { export class Request {
id?: string; id?: string;
constructor( constructor(
public method: string, public method: string,
public params?: any, public params?: any,
public notification = false, public notification = false,
) { ) {
this.id = notification ? undefined : String(Date.now()); this.id = notification ? undefined : String(Date.now());
} }
} }

View File

@ -1,30 +1,30 @@
import { throwError } from "./utils.ts"; import { throwError } from "./utils.ts";
export class Response { export class Response {
id: number; id: number;
success: boolean; success: boolean;
error?: { code: number; message: string }; error?: { code: number; message: string };
constructor(public data: any) { constructor(public data: any) {
if (!this.data.id) { if (!this.data.id) {
throw new Error(`Got invalid data: ${data}`); throw new Error(`Got invalid data: ${data}`);
}
this.id = data.id;
this.success = !("error" in data);
this.data = data.result;
this.error = data.error;
} }
unwrap() { this.id = data.id;
if (this.success) { this.success = !("error" in data);
return this.data; this.data = data.result;
} this.error = data.error;
}
if (this.error) { unwrap() {
throwError(this.error.code, this.error.message); if (this.success) {
} return this.data;
return undefined;
} }
if (this.error) {
throwError(this.error.code, this.error.message);
}
return undefined;
}
} }

View File

@ -3,37 +3,37 @@ import { Store } from "./store.ts";
import { readTextFileSync, writeTextFileSync } from "../deps.deno.ts"; import { readTextFileSync, writeTextFileSync } from "../deps.deno.ts";
export class FileStore extends Store { export class FileStore extends Store {
data: { [key: string]: any }; data: { [key: string]: any };
constructor(public readonly file: string) { constructor(public readonly file: string) {
super(); super();
if (IS_BROWSER) { if (IS_BROWSER) {
throw new Error("Cannot use `FileStore` on browsers"); throw new Error("Cannot use `FileStore` on browsers");
}
this.file = this.file + ".json";
try {
this.data = JSON.parse(readTextFileSync(this.file));
} catch (_) {
this.data = {};
}
} }
set(key: string, value: any) { this.file = this.file + ".json";
this.data[key] = value;
}
get(key: string) { try {
return this.data[key]; this.data = JSON.parse(readTextFileSync(this.file));
} catch (_) {
this.data = {};
} }
}
save() { set(key: string, value: any) {
writeTextFileSync(this.file, JSON.stringify(this.data)); this.data[key] = value;
} }
delete(key: string) { get(key: string) {
this.data[key] = undefined; return this.data[key];
} }
save() {
writeTextFileSync(this.file, JSON.stringify(this.data));
}
delete(key: string) {
this.data[key] = undefined;
}
} }

View File

@ -2,37 +2,37 @@ import { IS_BROWSER } from "../constants.ts";
import { Store } from "./store.ts"; import { Store } from "./store.ts";
function resolveToBeSet(toBeSet: any) { function resolveToBeSet(toBeSet: any) {
return JSON.stringify(toBeSet); return JSON.stringify(toBeSet);
} }
function resolveGot(got: string | null) { function resolveGot(got: string | null) {
return got == null ? got : JSON.parse(got); return got == null ? got : JSON.parse(got);
} }
export class LocalStorageStore extends Store { export class LocalStorageStore extends Store {
constructor(private id = "main") { constructor(private id = "main") {
super(); super();
if (!IS_BROWSER) { if (!IS_BROWSER) {
throw new Error("`LocalStorageStore` is only for browsers"); throw new Error("`LocalStorageStore` is only for browsers");
}
} }
}
private resolveKey(key: string) { private resolveKey(key: string) {
return key + this.id; return key + this.id;
} }
set(key: string, value: any) { set(key: string, value: any) {
localStorage.setItem(this.resolveKey(key), resolveToBeSet(value)); localStorage.setItem(this.resolveKey(key), resolveToBeSet(value));
} }
get(key: string) { get(key: string) {
return resolveGot(localStorage.getItem(this.resolveKey(key))); return resolveGot(localStorage.getItem(this.resolveKey(key)));
} }
save() {} save() {}
delete(key: string) { delete(key: string) {
localStorage.removeItem(this.resolveKey(key)); localStorage.removeItem(this.resolveKey(key));
} }
} }

View File

@ -1,24 +1,24 @@
import { Store } from "./store.ts"; import { Store } from "./store.ts";
export class MemoryStore extends Store { export class MemoryStore extends Store {
private data: { [key: string]: any }; private data: { [key: string]: any };
constructor() { constructor() {
super(); super();
this.data = {}; this.data = {};
} }
set(key: string, value: any) { set(key: string, value: any) {
this.data[key] = value; this.data[key] = value;
} }
get(key: string) { get(key: string) {
return this.data[key]; return this.data[key];
} }
save() {} save() {}
delete(key: string) { delete(key: string) {
this.data[key] = undefined; this.data[key] = undefined;
} }
} }

View File

@ -1,6 +1,6 @@
export abstract class Store { export abstract class Store {
abstract set(key: string, value: any): void; abstract set(key: string, value: any): void;
abstract get(key: string): any; abstract get(key: string): any;
abstract delete(key: string): void; abstract delete(key: string): void;
abstract save(): void; abstract save(): void;
} }

View File

@ -3,191 +3,197 @@ export type FileType = "DOCUMENT" | "PHOTO" | "VIDEO" | "AUDIO";
export type PeerType = "USER" | "BOT" | "PROXY"; export type PeerType = "USER" | "BOT" | "PROXY";
export type TextEntityType = export type TextEntityType =
| "BOLD" | "BOLD"
| "ITALIC" | "ITALIC"
| "CODE" | "CODE"
| "STRIKE" | "STRIKE"
| "UNDERLINE" | "UNDERLINE"
| "URL" | "URL"
| "MENTION" | "MENTION"
| "HASHTAG"; | "HASHTAG";
export type PostType = "UNKNOWN" | "DELETED" | "POST" | "REPLY" | "QUOTE" | "REPOST"; export type PostType =
| "UNKNOWN"
| "DELETED"
| "POST"
| "REPLY"
| "QUOTE"
| "REPOST";
export type RelationshipType = export type RelationshipType =
| "NONE" | "NONE"
| "FOLLOWING" | "FOLLOWING"
| "FOLLOWS_YOU" | "FOLLOWS_YOU"
| "AWAITING_APPROVAL" | "AWAITING_APPROVAL"
| "MUTUALLY_FOLLOWING" | "MUTUALLY_FOLLOWING"
| "BLOCKED" | "BLOCKED"
| "BLOCKED_YOU"; | "BLOCKED_YOU";
export interface Post { export interface Post {
/** The unique ID for the post */ /** The unique ID for the post */
id: string; id: string;
/** The post type used to represent the true intention of the post */ /** The post type used to represent the true intention of the post */
type: PostType; type: PostType;
/** The author peer of the post, this property can be null if the post was deleted. */ /** The author peer of the post, this property can be null if the post was deleted. */
peer: Peer | null; peer: Peer | null;
/** The source for where this post was composed from or collected from (eg; the client the user is using or the third-party source that the post was collected. This is determined by the server). This property can be null if the post was deleted. */ /** The source for where this post was composed from or collected from (eg; the client the user is using or the third-party source that the post was collected. This is determined by the server). This property can be null if the post was deleted. */
source: string | null; source: string | null;
/** The text content of the post source. This property can be null if the post has been deleted */ /** The text content of the post source. This property can be null if the post has been deleted */
text: string | null; text: string | null;
/** An array of entities extracted from the text, can be used by the client to highlight clickable entities that preforms an action. This property can be null if the post was deleted. */ /** An array of entities extracted from the text, can be used by the client to highlight clickable entities that preforms an action. This property can be null if the post was deleted. */
entities: TextEntity[] | null; entities: TextEntity[] | null;
/** An array of resolved peers that was mentioned in the post text. This property can be null if the post was deleted */ /** An array of resolved peers that was mentioned in the post text. This property can be null if the post was deleted */
mentioned_peers: Peer[] | null; mentioned_peers: Peer[] | null;
/** The original post that this post is replying to if applicable, otherwise null. */ /** The original post that this post is replying to if applicable, otherwise null. */
reply_to_post: Post | null; reply_to_post: Post | null;
/** The original post that this post is quoting if applicable, otherwise null */ /** The original post that this post is quoting if applicable, otherwise null */
quoted_post: Post | null; quoted_post: Post | null;
/** The original post that this post is reposting if applicable, otherwise null */ /** The original post that this post is reposting if applicable, otherwise null */
reposted_post: Post | null; reposted_post: Post | null;
/** The original thread post, only applicable to replies. This value indicates the main thread post where all the replies originated from. This value will remain the same for all sub-replies of the main post. */ /** The original thread post, only applicable to replies. This value indicates the main thread post where all the replies originated from. This value will remain the same for all sub-replies of the main post. */
original_thread_post: Post | null; original_thread_post: Post | null;
/** The amount of likes that this post has if applicable, otherwise null */ /** The amount of likes that this post has if applicable, otherwise null */
like_count: number | null; like_count: number | null;
/** The amount of repost that this post has if applicable, otherwise null */ /** The amount of repost that this post has if applicable, otherwise null */
reposts_count: number | null; reposts_count: number | null;
/** The amount of replies that this post has if applicable, otherwise null */ /** The amount of replies that this post has if applicable, otherwise null */
quotes_count: number | null; quotes_count: number | null;
/** The Unix Timestamp for when this post was created */ /** The Unix Timestamp for when this post was created */
posted_timestamp: number; posted_timestamp: number;
/** The flags associated with this post (WIP) */ /** The flags associated with this post (WIP) */
flags: string[]; flags: string[];
} }
export interface ServerInformation { export interface ServerInformation {
/** The name of the network, eg; "Socialvoid" */ /** The name of the network, eg; "Socialvoid" */
network_name: string; network_name: string;
/** The version of the protocol standard that the server is using, eg; "1.0" */ /** The version of the protocol standard that the server is using, eg; "1.0" */
protocol_version: string; protocol_version: string;
/** The HTTP URL Endpoint for the CDN server of the network */ /** The HTTP URL Endpoint for the CDN server of the network */
cdn_server: string; cdn_server: string;
/** The maximum size of a file that you can upload to the CDN Server (in bytes) */ /** The maximum size of a file that you can upload to the CDN Server (in bytes) */
upload_max_file_size: number; upload_max_file_size: number;
/** The maximum time-to-live (in seconds) that an unauthorized session may have. The server will often reset the expiration whenever the session is used. */ /** The maximum time-to-live (in seconds) that an unauthorized session may have. The server will often reset the expiration whenever the session is used. */
unauthorized_session_ttl: number; unauthorized_session_ttl: number;
/** The maximum time-to-live (in seconds) that an authorized session may have. The server will often reset the expiration whenever the session is used. */ /** The maximum time-to-live (in seconds) that an authorized session may have. The server will often reset the expiration whenever the session is used. */
authorized_session_ttl: number; authorized_session_ttl: number;
/** The maximum amount of likes a client can retrieve at once using the method `timeline.get_likes` via the `limit` parameter */ /** The maximum amount of likes a client can retrieve at once using the method `timeline.get_likes` via the `limit` parameter */
retrieve_likes_max_limit: number; retrieve_likes_max_limit: number;
/** The maximum amount of reposts a client can retrieve at once using the method `timeline.get_reposted_peers` via the `limit` parameter */ /** The maximum amount of reposts a client can retrieve at once using the method `timeline.get_reposted_peers` via the `limit` parameter */
retrieve_reposts_max_limit: number; retrieve_reposts_max_limit: number;
/** The maximum amount of replies a client can retrieve at once using the method `timeline.get_replies` via the `limit` parameter */ /** The maximum amount of replies a client can retrieve at once using the method `timeline.get_replies` via the `limit` parameter */
retrieve_replies_max_limit: number; retrieve_replies_max_limit: number;
/** The maximum amount of quotes a client can retrieve at once using the method `timeline.get_quotes` via the `limit` parameter */ /** The maximum amount of quotes a client can retrieve at once using the method `timeline.get_quotes` via the `limit` parameter */
retrieve_quotes_max_limit: number; retrieve_quotes_max_limit: number;
/** The maximum amount of followers a client can retrieve at once using the method `network.get_followers` via the `limit` parameter */ /** The maximum amount of followers a client can retrieve at once using the method `network.get_followers` via the `limit` parameter */
retrieve_followers_max_limit: number; retrieve_followers_max_limit: number;
/** The maximum amount of following peers a client can retrieve at once using the method `network.get_following` via the `limit` parameter */ /** The maximum amount of following peers a client can retrieve at once using the method `network.get_following` via the `limit` parameter */
retrieve_following_max_limit: number; retrieve_following_max_limit: number;
} }
export interface Peer { export interface Peer {
/** The ID of the user associated to the network */ /** The ID of the user associated to the network */
id: string; id: string;
/** The type of the peer entity */ /** The type of the peer entity */
type: PeerType; type: PeerType;
/** The display name of the peer */ /** The display name of the peer */
name: string; name: string;
/** The username associated with this peer */ /** The username associated with this peer */
username: string; username: string;
/** Flags associated with this peer */ /** Flags associated with this peer */
flags: string[]; flags: string[];
} }
export interface Session { export interface Session {
/** The ID of the session obtained when establishing a session */ /** The ID of the session obtained when establishing a session */
id: string; id: string;
/** An array of flags that has been set to this session */ /** An array of flags that has been set to this session */
flags: string[]; flags: string[];
/** Indicates if the session is currently authenticated to a user */ /** Indicates if the session is currently authenticated to a user */
authenticated: boolean; authenticated: boolean;
/** The Unix Timestamp for when this session was first created */ /** The Unix Timestamp for when this session was first created */
created: number; created: number;
/** The Unix Timestamp for when this session expires */ /** The Unix Timestamp for when this session expires */
expires: number; expires: number;
} }
export interface Document { export interface Document {
/** The ID of the document */ /** The ID of the document */
id: string; id: string;
/** The Mime of the file */ /** The Mime of the file */
file_mime: string; file_mime: string;
/** The original name of the file */ /** The original name of the file */
file_name: string; file_name: string;
/** The size of the file in bytes */ /** The size of the file in bytes */
file_size: number; file_size: number;
/** The type of file detected by the server */ /** The type of file detected by the server */
file_type: FileType; file_type: FileType;
/** An array of flags associated with this document */ /** An array of flags associated with this document */
flags: string[]; flags: string[];
} }
export interface HelpDocument { export interface HelpDocument {
/** The ID of the document, if the document gets updated then the ID will change. */ /** The ID of the document, if the document gets updated then the ID will change. */
id: string; id: string;
/** The text contents of the document */ /** The text contents of the document */
text: string; text: string;
/** An array of text entities being represented in the text */ /** An array of text entities being represented in the text */
entities: TextEntity[]; entities: TextEntity[];
} }
export interface DisplayPictureSize { export interface DisplayPictureSize {
/** The width of the image */ /** The width of the image */
width: number; width: number;
/** The height of the image */ /** The height of the image */
height: number; height: number;
/** The document object that points to the display picture */ /** The document object that points to the display picture */
document: Document; document: Document;
} }
export interface Profile { export interface Profile {
/** The first name of the entity */ /** The first name of the entity */
first_name: string; first_name: string;
/** The last name of the entity */ /** The last name of the entity */
last_name: string | null; last_name: string | null;
/** The full display name of the entity */ /** The full display name of the entity */
name: string; name: string;
/** A biography or description of the entity */ /** A biography or description of the entity */
biography: string | null; biography: string | null;
/** The location of the entity */ /** The location of the entity */
location: string | null; location: string | null;
/** The URL of the entity (Can be a website or a blog, etc) */ /** The URL of the entity (Can be a website or a blog, etc) */
url: string | null; url: string | null;
/** The amount of followers that this entity has */ /** The amount of followers that this entity has */
followers_count: number; followers_count: number;
/** The amount of peers that this entity is following */ /** The amount of peers that this entity is following */
following_count: number; following_count: number;
/** An array of display picture size objects that represents the entity's display picture */ /** An array of display picture size objects that represents the entity's display picture */
display_picture_sizes: DisplayPictureSize[]; display_picture_sizes: DisplayPictureSize[];
} }
export interface SessionIdentification { export interface SessionIdentification {
/** The ID of the session obtained when establishing a session */ /** The ID of the session obtained when establishing a session */
session_id: string; session_id: string;
/** The Public Hash of the client used when establishing the session */ /** The Public Hash of the client used when establishing the session */
client_public_hash: string; client_public_hash: string;
/** The session challenge answer revolving around the client's private hash, the same client used to establish the session */ /** The session challenge answer revolving around the client's private hash, the same client used to establish the session */
challenge_answer: string; challenge_answer: string;
} }
export interface SessionEstablished { export interface SessionEstablished {
/** The ID of the session obtained when establishing a session */ /** The ID of the session obtained when establishing a session */
id: string; id: string;
/** The TOTP based challenge secret */ /** The TOTP based challenge secret */
challenge: string; challenge: string;
} }
export interface TextEntity { export interface TextEntity {
/** The text entity type */ /** The text entity type */
type: TextEntityType; type: TextEntityType;
/** The offset for when the entity begins in the text */ /** The offset for when the entity begins in the text */
offset: number; offset: number;
/** The length of the entity */ /** The length of the entity */
length: number; length: number;
/** The value of the entity, for styling entities such as `BOLD | ITALIC`, etc. this value will be null, but for values such as `MENTION | HASHTAG` & `URL` the value will contain the respective value for the entity, for example a `URL` entity will contain a value of a http URL */ /** The value of the entity, for styling entities such as `BOLD | ITALIC`, etc. this value will be null, but for values such as `MENTION | HASHTAG` & `URL` the value will contain the respective value for the entity, for example a `URL` entity will contain a value of a http URL */
value: string | null; value: string | null;
} }

View File

@ -5,72 +5,72 @@ import { getRandomValues, jsSHA, OTPAuth } from "./deps.deno.ts";
import map, { SocialvoidError } from "./errors.ts"; import map, { SocialvoidError } from "./errors.ts";
export function throwError(code: number, message: string) { export function throwError(code: number, message: string) {
if (code in map) { if (code in map) {
throw new map[code](code, message); throw new map[code](code, message);
} }
throw new SocialvoidError(code, message); throw new SocialvoidError(code, message);
} }
export function bufferToHex(buffer: ArrayBuffer) { export function bufferToHex(buffer: ArrayBuffer) {
return Array.from(new Uint8Array(buffer)) return Array.from(new Uint8Array(buffer))
.map((b) => b.toString(16).padStart(2, "0")) .map((b) => b.toString(16).padStart(2, "0"))
.join(""); .join("");
} }
export function answerChallenge(clientPrivateHash: string, challenge: string) { export function answerChallenge(clientPrivateHash: string, challenge: string) {
const totpCode = new OTPAuth.TOTP({ const totpCode = new OTPAuth.TOTP({
algorithm: "sha1", algorithm: "sha1",
digits: 6, digits: 6,
period: 30, period: 30,
secret: challenge, secret: challenge,
}).generate(); }).generate();
const hash = new jsSHA("SHA-1", "TEXT"); const hash = new jsSHA("SHA-1", "TEXT");
hash.update(totpCode + clientPrivateHash); hash.update(totpCode + clientPrivateHash);
return hash.getHash("HEX"); return hash.getHash("HEX");
} }
export const unixTimestampToDate = (unixTimestamp: number) => new Date(unixTimestamp * 1000); export const unixTimestampToDate = (unixTimestamp: number) => new Date(unixTimestamp * 1000);
export function parseResponses(body: any): Response | Response[] | undefined { export function parseResponses(body: any): Response | Response[] | undefined {
if (!body) { if (!body) {
return undefined; return undefined;
} }
if (body.success) { if (body.success) {
return new Response(body); return new Response(body);
} }
return Array.isArray(body) return Array.isArray(body)
? body ? body
.filter((item: any) => "id" in item) .filter((item: any) => "id" in item)
.map((item: any) => new Response(item)) .map((item: any) => new Response(item))
: "id" in body : "id" in body
? new Response(body) ? new Response(body)
: undefined; : undefined;
} }
export function serializeRequests(...requests: Request[]): string { export function serializeRequests(...requests: Request[]): string {
const toReturn: any[] = []; const toReturn: any[] = [];
for (const request of requests) { for (const request of requests) {
toReturn.push({ ...request, jsonrpc: "2.0" }); toReturn.push({ ...request, jsonrpc: "2.0" });
} }
return JSON.stringify(toReturn); return JSON.stringify(toReturn);
} }
export const newHash = () => { export const newHash = () => {
return bufferToHex(getRandomValues(32)); return bufferToHex(getRandomValues(32));
}; };
export const formFromObj = (obj: { [key: string]: any }) => { export const formFromObj = (obj: { [key: string]: any }) => {
const form = new FormData(); const form = new FormData();
for (const i in obj) { for (const i in obj) {
form.append(i, obj[i]); form.append(i, obj[i]);
} }
return form; return form;
}; };