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": {
"files": {
"include": ["socialvoid", "examples", "generators"]
},
"options": {
"indentWidth": 4,
"lineWidth": 100
}
"fmt": {
"files": {
"include": ["socialvoid", "examples", "generators"]
},
"options": {
"lineWidth": 100
}
}
}

View File

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

View File

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

View File

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

View File

@ -2,12 +2,12 @@ const { writeFileSync } = require("fs");
const { client, login, prompt } = require("./");
(async () => {
await login();
await login();
const id = prompt("ID of the document to be downloaded:");
const data = await client.cdn.download(id);
const id = prompt("ID of the document to be downloaded:");
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 readline = createInterface({
input: process.stdin,
output: process.stdout,
input: process.stdin,
output: process.stdout,
});
const client = new Client();
function prompt(query) {
return new Promise((resolve) => {
readline.question(query + " ", resolve);
});
return new Promise((resolve) => {
readline.question(query + " ", resolve);
});
}
async function login() {
if (!client.sessionExists) {
await client.newSession();
}
if (!client.sessionExists) {
await client.newSession();
}
const session = await client.session.get();
const session = await client.session.get();
if (!session.authenticated) {
await client.session.authenticateUser(
prompt("Username:"),
prompt("Password:"),
prompt("OTP (if set):"),
);
}
if (!session.authenticated) {
await client.session.authenticateUser(
prompt("Username:"),
prompt("Password:"),
prompt("OTP (if set):"),
);
}
}
module.exports = { client, login, prompt };

View File

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

View File

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

View File

@ -1,178 +1,178 @@
{
"validation": {
"8448": {
"_": "InvalidUsername",
"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"
}
"validation": {
"8448": {
"_": "InvalidUsername",
"description": "The given username is invalid and does not meet the specification"
},
"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"
}
"8449": {
"_": "InvalidPassword",
"description": "The given password is insecure, see the message for further details"
},
"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"
}
"8450": {
"_": "InvalidFirstName",
"description": "The First Name provided contains invalid characters and or is too long, see the message for further details"
},
"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"
}
"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": {
"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": {
"FileType": "\"DOCUMENT\" | \"PHOTO\" | \"VIDEO\" | \"AUDIO\"",
"PeerType": "\"USER\" | \"BOT\" | \"PROXY\"",
"TextEntityType": "\"BOLD\" | \"ITALIC\" | \"CODE\" | \"STRIKE\" | \"UNDERLINE\" | \"URL\" | \"MENTION\" | \"HASHTAG\"",
"PostType": "\"UNKNOWN\" | \"DELETED\" | \"POST\" | \"REPLY\" | \"QUOTE\" | \"REPOST\"",
"RelationshipType": "\"NONE\" | \"FOLLOWING\" | \"FOLLOWS_YOU\" | \"AWAITING_APPROVAL\" | \"MUTUALLY_FOLLOWING\" | \"BLOCKED\" | \"BLOCKED_YOU\""
"types": {
"FileType": "\"DOCUMENT\" | \"PHOTO\" | \"VIDEO\" | \"AUDIO\"",
"PeerType": "\"USER\" | \"BOT\" | \"PROXY\"",
"TextEntityType": "\"BOLD\" | \"ITALIC\" | \"CODE\" | \"STRIKE\" | \"UNDERLINE\" | \"URL\" | \"MENTION\" | \"HASHTAG\"",
"PostType": "\"UNKNOWN\" | \"DELETED\" | \"POST\" | \"REPLY\" | \"QUOTE\" | \"REPOST\"",
"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": {
"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)"
}
},
"ServerInformation": {
"network_name": {
"type": "string",
"description": "The name of the network, eg; \"Socialvoid\""
},
"protocol_version": {
"type": "string",
"description": "The version of the protocol standard that the server is using, eg; \"1.0\""
},
"cdn_server": {
"type": "string",
"description": "The HTTP URL Endpoint for the CDN server of the network"
},
"upload_max_file_size": {
"type": "number",
"description": "The maximum size of a file that you can upload to the CDN Server (in bytes)"
},
"unauthorized_session_ttl": {
"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."
},
"authorized_session_ttl": {
"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."
},
"retrieve_likes_max_limit": {
"type": "number",
"description": "The maximum amount of likes a client can retrieve at once using the method `timeline.get_likes` via the `limit` parameter"
},
"retrieve_reposts_max_limit": {
"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"
},
"retrieve_replies_max_limit": {
"type": "number",
"description": "The maximum amount of replies a client can retrieve at once using the method `timeline.get_replies` via the `limit` parameter"
},
"retrieve_quotes_max_limit": {
"type": "number",
"description": "The maximum amount of quotes a client can retrieve at once using the method `timeline.get_quotes` via the `limit` parameter"
},
"retrieve_followers_max_limit": {
"type": "number",
"description": "The maximum amount of followers a client can retrieve at once using the method `network.get_followers` via the `limit` parameter"
},
"retrieve_following_max_limit": {
"type": "number",
"description": "The maximum amount of following peers a client can retrieve at once using the method `network.get_following` via the `limit` parameter"
}
},
"Peer": {
"id": {
"type": "string",
"description": "The ID of the user associated to the network"
},
"type": {
"type": "PeerType",
"description": "The type of the peer entity"
},
"name": {
"type": "string",
"description": "The display name of the peer"
},
"username": {
"type": "string",
"description": "The username associated with this peer"
},
"flags": {
"type": "string[]",
"description": "Flags associated with this peer"
}
},
"Session": {
"id": {
"type": "string",
"description": "The ID of the session obtained when establishing a session"
},
"flags": {
"type": "string[]",
"description": "An array of flags that has been set to this session"
},
"authenticated": {
"type": "boolean",
"description": "Indicates if the session is currently authenticated to a user"
},
"created": {
"type": "number",
"description": "The Unix Timestamp for when this session was first created",
"date": true
},
"expires": {
"type": "number",
"description": "The Unix Timestamp for when this session expires",
"date": true
}
},
"Document": {
"id": { "type": "string", "description": "The ID of the document" },
"file_mime": { "type": "string", "description": "The Mime of the file" },
"file_name": {
"type": "string",
"description": "The original name of the file"
},
"file_size": {
"type": "number",
"description": "The size of the file in bytes"
},
"file_type": {
"type": "FileType",
"description": "The type of file detected by the server"
},
"flags": {
"type": "string[]",
"description": "An array of flags associated with this document"
}
},
"HelpDocument": {
"id": {
"type": "string",
"description": "The ID of the document, if the document gets updated then the ID will change."
},
"text": {
"type": "string",
"description": "The text contents of the document"
},
"entities": {
"type": "TextEntity[]",
"description": "An array of text entities being represented in the text"
}
},
"DisplayPictureSize": {
"width": { "type": "number", "description": "The width of the image" },
"height": { "type": "number", "description": "The height of the image" },
"document": {
"type": "Document",
"description": "The document object that points to the display picture"
}
},
"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
}
}
"ServerInformation": {
"network_name": {
"type": "string",
"description": "The name of the network, eg; \"Socialvoid\""
},
"protocol_version": {
"type": "string",
"description": "The version of the protocol standard that the server is using, eg; \"1.0\""
},
"cdn_server": {
"type": "string",
"description": "The HTTP URL Endpoint for the CDN server of the network"
},
"upload_max_file_size": {
"type": "number",
"description": "The maximum size of a file that you can upload to the CDN Server (in bytes)"
},
"unauthorized_session_ttl": {
"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."
},
"authorized_session_ttl": {
"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."
},
"retrieve_likes_max_limit": {
"type": "number",
"description": "The maximum amount of likes a client can retrieve at once using the method `timeline.get_likes` via the `limit` parameter"
},
"retrieve_reposts_max_limit": {
"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"
},
"retrieve_replies_max_limit": {
"type": "number",
"description": "The maximum amount of replies a client can retrieve at once using the method `timeline.get_replies` via the `limit` parameter"
},
"retrieve_quotes_max_limit": {
"type": "number",
"description": "The maximum amount of quotes a client can retrieve at once using the method `timeline.get_quotes` via the `limit` parameter"
},
"retrieve_followers_max_limit": {
"type": "number",
"description": "The maximum amount of followers a client can retrieve at once using the method `network.get_followers` via the `limit` parameter"
},
"retrieve_following_max_limit": {
"type": "number",
"description": "The maximum amount of following peers a client can retrieve at once using the method `network.get_following` via the `limit` parameter"
}
},
"Peer": {
"id": {
"type": "string",
"description": "The ID of the user associated to the network"
},
"type": {
"type": "PeerType",
"description": "The type of the peer entity"
},
"name": {
"type": "string",
"description": "The display name of the peer"
},
"username": {
"type": "string",
"description": "The username associated with this peer"
},
"flags": {
"type": "string[]",
"description": "Flags associated with this peer"
}
},
"Session": {
"id": {
"type": "string",
"description": "The ID of the session obtained when establishing a session"
},
"flags": {
"type": "string[]",
"description": "An array of flags that has been set to this session"
},
"authenticated": {
"type": "boolean",
"description": "Indicates if the session is currently authenticated to a user"
},
"created": {
"type": "number",
"description": "The Unix Timestamp for when this session was first created",
"date": true
},
"expires": {
"type": "number",
"description": "The Unix Timestamp for when this session expires",
"date": true
}
},
"Document": {
"id": { "type": "string", "description": "The ID of the document" },
"file_mime": { "type": "string", "description": "The Mime of the file" },
"file_name": {
"type": "string",
"description": "The original name of the file"
},
"file_size": {
"type": "number",
"description": "The size of the file in bytes"
},
"file_type": {
"type": "FileType",
"description": "The type of file detected by the server"
},
"flags": {
"type": "string[]",
"description": "An array of flags associated with this document"
}
},
"HelpDocument": {
"id": {
"type": "string",
"description": "The ID of the document, if the document gets updated then the ID will change."
},
"text": {
"type": "string",
"description": "The text contents of the document"
},
"entities": {
"type": "TextEntity[]",
"description": "An array of text entities being represented in the text"
}
},
"DisplayPictureSize": {
"width": { "type": "number", "description": "The width of the image" },
"height": { "type": "number", "description": "The height of the image" },
"document": {
"type": "Document",
"description": "The document object that points to the display picture"
}
},
"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 = () =>
Deno.run({
cmd: ["deno", "fmt", "--config", "deno.json"],
cwd: "../",
stdout: "piped",
}).output();
Deno.run({
cmd: ["deno", "fmt", "--config", "deno.json"],
cwd: "../",
stdout: "piped",
}).output();

View File

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

View File

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

View File

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

View File

@ -6,117 +6,117 @@ import { throwError } from "./utils.ts";
export class NotInitialized extends Error {}
export interface Session {
id: string;
publicHash: string;
privateHash: string;
challenge: string;
id: string;
publicHash: string;
privateHash: string;
challenge: string;
}
export class BaseClient {
protected _session?: Session;
protected _session?: Session;
constructor(
public readonly rpcEndpoint: string,
) {
constructor(
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> {
throw new Error("Not implemented");
return {
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() {
if (!this._session) {
throw new Error("Session does not exist");
}
const result = parseResponses(await this.send(serializeRequests(request)));
return {
session_identification: {
session_id: this._session.id,
client_public_hash: this._session.publicHash,
challenge_answer: await answerChallenge(
this._session.privateHash,
this._session.challenge,
),
},
};
if (result && !Array.isArray(result)) {
return result.unwrap();
}
async invokeRequest(request: Request, includeSessionId?: boolean) {
if (includeSessionId) {
request.params = { ...request.params, ...(await this.sessionId()) };
}
return {};
}
const result = parseResponses(await this.send(serializeRequests(request)));
if (result && !Array.isArray(result)) {
return result.unwrap();
}
return {};
async invokeRequests(...requests: Request[]) {
if (!requests) {
throw new Error(
"The parameter `requests` cannot be `undefined` or empty",
);
}
async invokeRequests(...requests: Request[]) {
if (!requests) {
throw new Error(
"The parameter `requests` cannot be `undefined` or empty",
);
}
const toReturn = new Array<Response>();
const result = parseResponses(
await this.send(serializeRequests(...requests)),
);
const toReturn = new Array<Response>();
const result = parseResponses(
await this.send(serializeRequests(...requests)),
);
if (result) {
if (Array.isArray(result)) {
toReturn.push(...result);
} else {
toReturn.push(result);
}
}
return toReturn.map((response) => response.unwrap());
if (result) {
if (Array.isArray(result)) {
toReturn.push(...result);
} else {
toReturn.push(result);
}
}
async invokeCDNRequest(data: FormData) {
return await (await this.sendCDN(data)).json();
return toReturn.map((response) => response.unwrap());
}
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) {
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;
}
return response;
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -3,34 +3,34 @@ import { formFromObj } from "../utils.ts";
import { MethodBase } from "./method_base.ts";
export class CDN extends MethodBase {
/**
* Uploads a file.
*
* @param document The file, it can be a buffer or a readable stream.
*/
async upload(document: any): Promise<Document> {
const form = formFromObj({
action: "upload",
document,
...(await this.client.sessionId()).session_identification,
});
/**
* Uploads a file.
*
* @param document The file, it can be a buffer or a readable stream.
*/
async upload(document: any): Promise<Document> {
const form = formFromObj({
action: "upload",
document,
...(await this.client.sessionId()).session_identification,
});
return (await this.client.invokeCDNRequest(form)).results;
}
return (await this.client.invokeCDNRequest(form)).results;
}
/**
* Downloads the provided 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`.
*/
async download(document: string | Document, stream?: boolean) {
const form = formFromObj({
action: "download",
document: typeof document == "string" ? document : document.id,
...(await this.client.sessionId()).session_identification,
});
/**
* Downloads the provided 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`.
*/
async download(document: string | Document, stream?: boolean) {
const form = formFromObj({
action: "download",
document: typeof document == "string" ? document : document.id,
...(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";
export class Cloud extends MethodBase {
/**
* Resolves a document.
*
* @param document The ID or instance of the document.
*/
getDocument(document: string | Document): Promise<Document> {
document = typeof document == "string" ? document : document.id;
/**
* Resolves a document.
*
* @param document The ID or instance of the document.
*/
getDocument(document: string | Document): Promise<Document> {
document = typeof document == "string" ? document : document.id;
return this.client.invokeRequest(
new Request("cloud.get_document", {
document,
}),
true,
);
}
return this.client.invokeRequest(
new Request("cloud.get_document", {
document,
}),
true,
);
}
}

View File

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

View File

@ -1,5 +1,5 @@
import { BaseClient } from "../base_client.ts";
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";
export class Network extends MethodBase {
/**
* Gets the peer of the currently logged in account.
*/
getMe(): Promise<Peer> {
return this.client.invokeRequest(new Request("network.get_me"), true);
}
/**
* Gets the peer of the currently logged in account.
*/
getMe(): Promise<Peer> {
return this.client.invokeRequest(new Request("network.get_me"), true);
}
/**
* 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.
*/
getProfile(peer?: string | Peer): Promise<Profile> {
return this.client.invokeRequest(
new Request("network.get_profile", {
peer: typeof peer !== "undefined"
? typeof peer == "string" ? peer : peer.id
: undefined,
}),
true,
);
}
/**
* 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.
*/
getProfile(peer?: string | Peer): Promise<Profile> {
return this.client.invokeRequest(
new Request("network.get_profile", {
peer: typeof peer !== "undefined" ? typeof peer == "string" ? peer : peer.id : undefined,
}),
true,
);
}
/**
* 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 page The current page number of the return results. The default value is `1`.
*/
getFollowing(peer?: string | Peer, page?: number): Promise<Peer[]> {
return this.client.invokeRequest(
new Request("network.get_following", {
peer: typeof peer !== "undefined"
? typeof peer == "string" ? peer : peer.id
: undefined,
page,
}),
true,
);
}
/**
* 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 page The current page number of the return results. The default value is `1`.
*/
getFollowing(peer?: string | Peer, page?: number): Promise<Peer[]> {
return this.client.invokeRequest(
new Request("network.get_following", {
peer: typeof peer !== "undefined" ? typeof peer == "string" ? peer : peer.id : undefined,
page,
}),
true,
);
}
/**
* 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 page The current page number of the return results. The default value is `1`.
*/
getFollowers(peer?: string | Peer, page?: number): Promise<Peer[]> {
return this.client.invokeRequest(
new Request("network.get_followers", {
peer: typeof peer !== "undefined"
? typeof peer == "string" ? peer : peer.id
: undefined,
page,
}),
true,
);
}
/**
* 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 page The current page number of the return results. The default value is `1`.
*/
getFollowers(peer?: string | Peer, page?: number): Promise<Peer[]> {
return this.client.invokeRequest(
new Request("network.get_followers", {
peer: typeof peer !== "undefined" ? typeof peer == "string" ? peer : peer.id : undefined,
page,
}),
true,
);
}
/**
* Follows another peer on the network.
*
* @param peer The ID, handle (with a leading @) or instance of the peer to follow.
*/
followPeer(peer: string | Peer): Promise<RelationshipType> {
return this.client.invokeRequest(
new Request("network.follow_peer", {
peer: typeof peer == "string" ? peer : peer.id,
}),
true,
);
}
/**
* Follows another peer on the network.
*
* @param peer The ID, handle (with a leading @) or instance of the peer to follow.
*/
followPeer(peer: string | Peer): Promise<RelationshipType> {
return this.client.invokeRequest(
new Request("network.follow_peer", {
peer: typeof peer == "string" ? peer : peer.id,
}),
true,
);
}
/**
* Unfollows another peer on the network.
*
* @param peer The ID, handle (with a leading @) or instance of the peer to unfollow.
*/
unfollowPeer(peer: string | Peer): Promise<RelationshipType> {
return this.client.invokeRequest(
new Request("network.unfollow_peer", {
peer: typeof peer == "string" ? peer : peer.id,
}),
true,
);
}
/**
* Unfollows another peer on the network.
*
* @param peer The ID, handle (with a leading @) or instance of the peer to unfollow.
*/
unfollowPeer(peer: string | Peer): Promise<RelationshipType> {
return this.client.invokeRequest(
new Request("network.unfollow_peer", {
peer: typeof peer == "string" ? peer : peer.id,
}),
true,
);
}
}

View File

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

View File

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

View File

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

View File

@ -1,30 +1,30 @@
import { throwError } from "./utils.ts";
export class Response {
id: number;
success: boolean;
error?: { code: number; message: string };
id: number;
success: boolean;
error?: { code: number; message: string };
constructor(public data: any) {
if (!this.data.id) {
throw new Error(`Got invalid data: ${data}`);
}
this.id = data.id;
this.success = !("error" in data);
this.data = data.result;
this.error = data.error;
constructor(public data: any) {
if (!this.data.id) {
throw new Error(`Got invalid data: ${data}`);
}
unwrap() {
if (this.success) {
return this.data;
}
this.id = data.id;
this.success = !("error" in data);
this.data = data.result;
this.error = data.error;
}
if (this.error) {
throwError(this.error.code, this.error.message);
}
return undefined;
unwrap() {
if (this.success) {
return this.data;
}
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";
export class FileStore extends Store {
data: { [key: string]: any };
data: { [key: string]: any };
constructor(public readonly file: string) {
super();
constructor(public readonly file: string) {
super();
if (IS_BROWSER) {
throw new Error("Cannot use `FileStore` on browsers");
}
this.file = this.file + ".json";
try {
this.data = JSON.parse(readTextFileSync(this.file));
} catch (_) {
this.data = {};
}
if (IS_BROWSER) {
throw new Error("Cannot use `FileStore` on browsers");
}
set(key: string, value: any) {
this.data[key] = value;
}
this.file = this.file + ".json";
get(key: string) {
return this.data[key];
try {
this.data = JSON.parse(readTextFileSync(this.file));
} catch (_) {
this.data = {};
}
}
save() {
writeTextFileSync(this.file, JSON.stringify(this.data));
}
set(key: string, value: any) {
this.data[key] = value;
}
delete(key: string) {
this.data[key] = undefined;
}
get(key: string) {
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";
function resolveToBeSet(toBeSet: any) {
return JSON.stringify(toBeSet);
return JSON.stringify(toBeSet);
}
function resolveGot(got: string | null) {
return got == null ? got : JSON.parse(got);
return got == null ? got : JSON.parse(got);
}
export class LocalStorageStore extends Store {
constructor(private id = "main") {
super();
constructor(private id = "main") {
super();
if (!IS_BROWSER) {
throw new Error("`LocalStorageStore` is only for browsers");
}
if (!IS_BROWSER) {
throw new Error("`LocalStorageStore` is only for browsers");
}
}
private resolveKey(key: string) {
return key + this.id;
}
private resolveKey(key: string) {
return key + this.id;
}
set(key: string, value: any) {
localStorage.setItem(this.resolveKey(key), resolveToBeSet(value));
}
set(key: string, value: any) {
localStorage.setItem(this.resolveKey(key), resolveToBeSet(value));
}
get(key: string) {
return resolveGot(localStorage.getItem(this.resolveKey(key)));
}
get(key: string) {
return resolveGot(localStorage.getItem(this.resolveKey(key)));
}
save() {}
save() {}
delete(key: string) {
localStorage.removeItem(this.resolveKey(key));
}
delete(key: string) {
localStorage.removeItem(this.resolveKey(key));
}
}

View File

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

View File

@ -1,6 +1,6 @@
export abstract class Store {
abstract set(key: string, value: any): void;
abstract get(key: string): any;
abstract delete(key: string): void;
abstract save(): void;
abstract set(key: string, value: any): void;
abstract get(key: string): any;
abstract delete(key: string): 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 TextEntityType =
| "BOLD"
| "ITALIC"
| "CODE"
| "STRIKE"
| "UNDERLINE"
| "URL"
| "MENTION"
| "HASHTAG";
| "BOLD"
| "ITALIC"
| "CODE"
| "STRIKE"
| "UNDERLINE"
| "URL"
| "MENTION"
| "HASHTAG";
export type PostType = "UNKNOWN" | "DELETED" | "POST" | "REPLY" | "QUOTE" | "REPOST";
export type PostType =
| "UNKNOWN"
| "DELETED"
| "POST"
| "REPLY"
| "QUOTE"
| "REPOST";
export type RelationshipType =
| "NONE"
| "FOLLOWING"
| "FOLLOWS_YOU"
| "AWAITING_APPROVAL"
| "MUTUALLY_FOLLOWING"
| "BLOCKED"
| "BLOCKED_YOU";
| "NONE"
| "FOLLOWING"
| "FOLLOWS_YOU"
| "AWAITING_APPROVAL"
| "MUTUALLY_FOLLOWING"
| "BLOCKED"
| "BLOCKED_YOU";
export interface Post {
/** The unique ID for the post */
id: string;
/** The post type used to represent the true intention of the post */
type: PostType;
/** The author peer of the post, this property can be null if the post was deleted. */
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. */
source: string | null;
/** The text content of the post source. This property can be null if the post has been deleted */
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. */
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 */
mentioned_peers: Peer[] | null;
/** The original post that this post is replying to if applicable, otherwise null. */
reply_to_post: Post | null;
/** The original post that this post is quoting if applicable, otherwise null */
quoted_post: Post | null;
/** The original post that this post is reposting if applicable, otherwise 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. */
original_thread_post: Post | null;
/** The amount of likes that this post has if applicable, otherwise null */
like_count: number | null;
/** The amount of repost that this post has if applicable, otherwise null */
reposts_count: number | null;
/** The amount of replies that this post has if applicable, otherwise null */
quotes_count: number | null;
/** The Unix Timestamp for when this post was created */
posted_timestamp: number;
/** The flags associated with this post (WIP) */
flags: string[];
/** The unique ID for the post */
id: string;
/** The post type used to represent the true intention of the post */
type: PostType;
/** The author peer of the post, this property can be null if the post was deleted. */
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. */
source: string | null;
/** The text content of the post source. This property can be null if the post has been deleted */
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. */
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 */
mentioned_peers: Peer[] | null;
/** The original post that this post is replying to if applicable, otherwise null. */
reply_to_post: Post | null;
/** The original post that this post is quoting if applicable, otherwise null */
quoted_post: Post | null;
/** The original post that this post is reposting if applicable, otherwise 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. */
original_thread_post: Post | null;
/** The amount of likes that this post has if applicable, otherwise null */
like_count: number | null;
/** The amount of repost that this post has if applicable, otherwise null */
reposts_count: number | null;
/** The amount of replies that this post has if applicable, otherwise null */
quotes_count: number | null;
/** The Unix Timestamp for when this post was created */
posted_timestamp: number;
/** The flags associated with this post (WIP) */
flags: string[];
}
export interface ServerInformation {
/** The name of the network, eg; "Socialvoid" */
network_name: string;
/** The version of the protocol standard that the server is using, eg; "1.0" */
protocol_version: string;
/** The HTTP URL Endpoint for the CDN server of the network */
cdn_server: string;
/** The maximum size of a file that you can upload to the CDN Server (in bytes) */
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. */
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. */
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 */
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 */
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 */
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 */
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 */
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 */
retrieve_following_max_limit: number;
/** The name of the network, eg; "Socialvoid" */
network_name: string;
/** The version of the protocol standard that the server is using, eg; "1.0" */
protocol_version: string;
/** The HTTP URL Endpoint for the CDN server of the network */
cdn_server: string;
/** The maximum size of a file that you can upload to the CDN Server (in bytes) */
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. */
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. */
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 */
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 */
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 */
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 */
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 */
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 */
retrieve_following_max_limit: number;
}
export interface Peer {
/** The ID of the user associated to the network */
id: string;
/** The type of the peer entity */
type: PeerType;
/** The display name of the peer */
name: string;
/** The username associated with this peer */
username: string;
/** Flags associated with this peer */
flags: string[];
/** The ID of the user associated to the network */
id: string;
/** The type of the peer entity */
type: PeerType;
/** The display name of the peer */
name: string;
/** The username associated with this peer */
username: string;
/** Flags associated with this peer */
flags: string[];
}
export interface Session {
/** The ID of the session obtained when establishing a session */
id: string;
/** An array of flags that has been set to this session */
flags: string[];
/** Indicates if the session is currently authenticated to a user */
authenticated: boolean;
/** The Unix Timestamp for when this session was first created */
created: number;
/** The Unix Timestamp for when this session expires */
expires: number;
/** The ID of the session obtained when establishing a session */
id: string;
/** An array of flags that has been set to this session */
flags: string[];
/** Indicates if the session is currently authenticated to a user */
authenticated: boolean;
/** The Unix Timestamp for when this session was first created */
created: number;
/** The Unix Timestamp for when this session expires */
expires: number;
}
export interface Document {
/** The ID of the document */
id: string;
/** The Mime of the file */
file_mime: string;
/** The original name of the file */
file_name: string;
/** The size of the file in bytes */
file_size: number;
/** The type of file detected by the server */
file_type: FileType;
/** An array of flags associated with this document */
flags: string[];
/** The ID of the document */
id: string;
/** The Mime of the file */
file_mime: string;
/** The original name of the file */
file_name: string;
/** The size of the file in bytes */
file_size: number;
/** The type of file detected by the server */
file_type: FileType;
/** An array of flags associated with this document */
flags: string[];
}
export interface HelpDocument {
/** The ID of the document, if the document gets updated then the ID will change. */
id: string;
/** The text contents of the document */
text: string;
/** An array of text entities being represented in the text */
entities: TextEntity[];
/** The ID of the document, if the document gets updated then the ID will change. */
id: string;
/** The text contents of the document */
text: string;
/** An array of text entities being represented in the text */
entities: TextEntity[];
}
export interface DisplayPictureSize {
/** The width of the image */
width: number;
/** The height of the image */
height: number;
/** The document object that points to the display picture */
document: Document;
/** The width of the image */
width: number;
/** The height of the image */
height: number;
/** The document object that points to the display picture */
document: Document;
}
export interface Profile {
/** The first name of the entity */
first_name: string;
/** The last name of the entity */
last_name: string | null;
/** The full display name of the entity */
name: string;
/** A biography or description of the entity */
biography: string | null;
/** The location of the entity */
location: string | null;
/** The URL of the entity (Can be a website or a blog, etc) */
url: string | null;
/** The amount of followers that this entity has */
followers_count: number;
/** The amount of peers that this entity is following */
following_count: number;
/** An array of display picture size objects that represents the entity's display picture */
display_picture_sizes: DisplayPictureSize[];
/** The first name of the entity */
first_name: string;
/** The last name of the entity */
last_name: string | null;
/** The full display name of the entity */
name: string;
/** A biography or description of the entity */
biography: string | null;
/** The location of the entity */
location: string | null;
/** The URL of the entity (Can be a website or a blog, etc) */
url: string | null;
/** The amount of followers that this entity has */
followers_count: number;
/** The amount of peers that this entity is following */
following_count: number;
/** An array of display picture size objects that represents the entity's display picture */
display_picture_sizes: DisplayPictureSize[];
}
export interface SessionIdentification {
/** The ID of the session obtained when establishing a session */
session_id: string;
/** The Public Hash of the client used when establishing the session */
client_public_hash: string;
/** The session challenge answer revolving around the client's private hash, the same client used to establish the session */
challenge_answer: string;
/** The ID of the session obtained when establishing a session */
session_id: string;
/** The Public Hash of the client used when establishing the session */
client_public_hash: string;
/** The session challenge answer revolving around the client's private hash, the same client used to establish the session */
challenge_answer: string;
}
export interface SessionEstablished {
/** The ID of the session obtained when establishing a session */
id: string;
/** The TOTP based challenge secret */
challenge: string;
/** The ID of the session obtained when establishing a session */
id: string;
/** The TOTP based challenge secret */
challenge: string;
}
export interface TextEntity {
/** The text entity type */
type: TextEntityType;
/** The offset for when the entity begins in the text */
offset: number;
/** The length of the entity */
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 */
value: string | null;
/** The text entity type */
type: TextEntityType;
/** The offset for when the entity begins in the text */
offset: number;
/** The length of the entity */
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 */
value: string | null;
}

View File

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