@subsocial/api
Version:
JavaScript API for Subsocial blockchain.
651 lines (650 loc) • 28.2 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SubsocialSubstrateApi = void 0;
const types_1 = require("@polkadot/types");
const utils_1 = require("@subsocial/utils");
const utils_2 = require("../utils");
const filters_1 = require("../filters");
const registry_1 = __importDefault(require("../utils/registry"));
const connections_1 = require("../connections");
const U64_BYTES_SIZE = 8;
const ACCOUNT32_BYTES_SIZE = 32;
class SubsocialSubstrateApi {
constructor({ api }) {
this.getPalletQuery = (pallet) => __awaiter(this, void 0, void 0, function* () {
const api = yield this.api;
return api.query[pallet];
});
this._api = api;
}
static create(substrateNodeUrl) {
return __awaiter(this, void 0, void 0, function* () {
const api = yield (0, connections_1.getSubstrateApi)(substrateNodeUrl);
return new SubsocialSubstrateApi({ api });
});
}
get api() {
return this._api.isReady;
}
// ---------------------------------------------------------------------
// Private utils
queryPallet(params, value) {
return __awaiter(this, void 0, void 0, function* () {
const { storage, pallet } = params;
const query = yield this.getPalletQuery(pallet);
// @ts-ignore
return query[storage](value);
});
}
queryPosts(storage, value) {
return __awaiter(this, void 0, void 0, function* () {
return this.queryPallet({ pallet: 'posts', storage }, value);
});
}
querySpaces(storage, value) {
return __awaiter(this, void 0, void 0, function* () {
return this.queryPallet({ pallet: 'spaces', storage }, value);
});
}
queryProfiles(storage, value) {
return __awaiter(this, void 0, void 0, function* () {
return this.queryPallet({ pallet: 'profiles', storage }, value);
});
}
queryPalletMulti(params, value) {
return __awaiter(this, void 0, void 0, function* () {
const { storage, pallet } = params;
const query = yield this.getPalletQuery(pallet);
// @ts-ignore
return query[storage].multi(value);
});
}
isBooleanByAccount(params, accountId, subjectId) {
return __awaiter(this, void 0, void 0, function* () {
const { storage, pallet } = params;
const queryParams = new types_1.Tuple(registry_1.default, [types_1.GenericAccountId, 'u64'], [accountId, subjectId]);
const isBoolean = yield this.queryPallet({ pallet, storage }, queryParams);
return isBoolean.valueOf();
});
}
/**
* Find and load data about reaction ids from Subsocial blockchain and IPFS by a given `accountId` and
* an array of `structIds`.
*
*
* @param accountId - An account id of desired reaction ids.
*
* @param postIds - An array of post ids of desired reaction ids.
*
* @returns An array of reaction ids aggregated from Subsocial blockchain. If no corresponding reaction ids to given
* `accountId` and `structIds`, an empty array is returned.
*
*/
getReactionIdsByAccount(accountId, postIds) {
return __awaiter(this, void 0, void 0, function* () {
const queryParams = postIds.map(id => new types_1.Tuple(registry_1.default, [types_1.GenericAccountId, 'u64'], [accountId, (0, utils_1.idToBn)(id)]));
const ids = yield this.queryPalletMulti({ pallet: 'reactions', storage: 'postReactionIdByAccount' }, queryParams);
return (0, utils_1.asStringArray)(ids);
});
}
// ---------------------------------------------------------------------
// Counter
getStorageLength(params, value) {
return __awaiter(this, void 0, void 0, function* () {
const { storage, pallet, itemBytesSize } = params;
const query = yield this.getPalletQuery(pallet);
// @ts-ignore
const storageSize = yield query[storage].size(value);
return storageSize.subn(1).divn(itemBytesSize);
});
}
/**
* Find and load data about the number of posts of a space from Subsocial blockchain and IPFS by a given space id `spaceId`.
*
*
* @param spaceId - A space id.
*
*
* @returns Number of posts of a given space id `spaceId` aggregated from Subsocial blockchain in BN.
*/
postsCountBySpaceId(spaceId) {
return __awaiter(this, void 0, void 0, function* () {
return this.getStorageLength({
pallet: 'posts',
storage: 'postIdsBySpaceId',
itemBytesSize: U64_BYTES_SIZE
}, spaceId);
});
}
/**
* Find and load data about the number of shares of a post from Subsocial blockchain and IPFS by a given `postId`.
*
*
* @param postId - A post id.
*
*
* @returns Number of shares of a given `postId` aggregated from Subsocial blockchain in BN.
*/
sharesCountByPostId(postId) {
return __awaiter(this, void 0, void 0, function* () {
return this.getStorageLength({
pallet: 'posts',
storage: 'sharedPostIdsByOriginalPostId',
itemBytesSize: U64_BYTES_SIZE
}, postId);
});
}
/**
* Find and load data about the number of replies of a post from Subsocial blockchain and IPFS by a given `postId`.
*
*
* @param postId - A post id.
*
*
* @returns Number of replies of a given `postId` aggregated from Subsocial blockchain in BN.
*/
repliesCountByPostId(postId) {
return __awaiter(this, void 0, void 0, function* () {
return this.getStorageLength({
pallet: 'posts',
storage: 'replyIdsByPostId',
itemBytesSize: U64_BYTES_SIZE
}, postId);
});
}
/**
* Find and load data about the number of account followers of an account from Subsocial blockchain and IPFS by a given `accountId`.
*
*
* @param accountId - An account id.
*
*
* @returns Number of account followers of a given `accountId` aggregated from Subsocial blockchain in BN.
*/
accountFollowersCountByAccountId(accountId) {
return __awaiter(this, void 0, void 0, function* () {
return this.getStorageLength({
pallet: 'accountFollows',
storage: 'accountFollowers',
itemBytesSize: ACCOUNT32_BYTES_SIZE
}, accountId);
});
}
/**
* Find and load data about the number of account followed by an account from Subsocial blockchain and IPFS by a given `accountId`.
*
*
* @param accountId - An account id.
*
*
* @returns Number of account followers of a given `accountId` aggregated from Subsocial blockchain in BN.
*/
accountsFollowedCountByAccount(accountId) {
return __awaiter(this, void 0, void 0, function* () {
return this.getStorageLength({
pallet: 'accountFollows',
storage: 'accountsFollowedByAccount',
itemBytesSize: ACCOUNT32_BYTES_SIZE
}, accountId);
});
}
// ---------------------------------------------------------------------
// Multiple
findStructs(storageItem, ids) {
return __awaiter(this, void 0, void 0, function* () {
const storage = storageItem.storage;
try {
ids = (0, utils_2.getUniqueIds)(ids);
if ((0, utils_1.isEmptyArray)(ids)) {
logger.debug(`Nothing to load from ${storage}: no ids provided`);
return [];
}
const structs = yield this.queryPalletMulti(storageItem, ids);
const res = [];
structs.forEach((x, i) => {
if (x.isSome) {
const id = ids[i];
const item = x.unwrap();
res.push(storageItem.pallet === 'profiles'
? Object.assign({ id }, item) : item);
}
});
logger.debug(`Loaded ${(0, utils_1.pluralize)({ count: res.length, singularText: 'struct' })} from ${storage}`);
return res;
}
catch (err) {
logger.error(`Failed to load struct(s) from ${storage} by ${ids.length} id(s):`, err);
return [];
}
});
}
/**
* Find and load an array of information about spaces from Subsocial blockchain and IPFS by a given array of `ids`,
* `visibility` filter, and `content` filter.
*
* @param params - An object containing an array of space `ids`, visibility filter (`hidden` field), and `content` filter.
*
* @returns An array of data about desired spaces from Subsocial blockchain and IPFS. If no corresponding spaces to given array
* of `ids`, `content` and `visibility` filter, an empty array is returned.
*/
findSpaces(params) {
return __awaiter(this, void 0, void 0, function* () {
const { ids, visibility } = params;
const spaces = yield this.findStructs({ pallet: 'spaces', storage: 'spaceById' }, ids);
return (0, filters_1.visibilityFilter)(spaces, visibility);
});
}
/**
* Find and load an array of information about posts from Subsocial blockchain and IPFS by a given array of `ids`, `content` and
* `visibility` filter.
*
* @param params - An object containing an array of space `ids`, visibility filter (`hidden` field), and `content` filter.
*
* @returns An array of data about desired posts from Subsocial blockchain and IPFS. If no corresponding posts to given array
* of `ids`, `content` and `visibility` filter, an empty array is returned.
*/
findPosts(params) {
return __awaiter(this, void 0, void 0, function* () {
const { ids, visibility } = params;
const posts = yield this.findStructs({ pallet: 'posts', storage: 'postById' }, ids);
return (0, filters_1.visibilityFilter)(posts, visibility);
});
}
/**
* Find and load an array of information about reactions from Subsocial blockchain by a given array of reaction `ids`.
*
* @param ids - An array of ids of desired reactions.
*
* @returns An array of data about desired reactions from Subsocial blockchain. If no corresponding reactions to given
* array of `ids`, an empty array is returned.
*/
findReactions(ids) {
return __awaiter(this, void 0, void 0, function* () {
return this.findStructs({ pallet: 'reactions', storage: 'reactionById' }, ids);
});
}
// ---------------------------------------------------------------------
// Single
/**
* Find and load information about a space from Subsocial blockchain and IPFS by a given `id`, `content` and `visibility` filter.
*
* @param params - An object containing a space `id`, visibility filter (`hidden` field), and `content` filter.
*
* @returns Data about desired space from Subsocial blockchain and IPFS. If no corresponding space to given `id`, `content` and
* `visibility` filter, `undefined` is returned.
*/
findSpace(params) {
return __awaiter(this, void 0, void 0, function* () {
const { id, visibility } = params;
return (0, utils_1.getFirstOrUndefined)(yield this.findSpaces({ ids: [id], visibility }));
});
}
/**
* Find and load information about a post from Subsocial blockchain and IPFS by a given `id`, `content` and `visibility` filter.
*
* @param params - An object containing a post `id`, visibility filter (`hidden` field), and `content` filter.
*
* @returns Data about desired post from Subsocial blockchain and IPFS. If no corresponding post to given `id`, `content` and
* `visibility` filter, `undefined` is returned.
*/
findPost(params) {
return __awaiter(this, void 0, void 0, function* () {
const { id, visibility } = params;
return (0, utils_1.getFirstOrUndefined)(yield this.findPosts({ ids: [id], visibility }));
});
}
/**
* Find and load information about a reaction from Subsocial blockchain by a given reaction `id`.
*
* @param id - Id of desired reaction.
*
* @returns Data about desired reaction from Subsocial blockchain. If no corresponding reaction to given reaction `id`,
* `undefined` is returned.
*/
findReaction(id) {
return __awaiter(this, void 0, void 0, function* () {
return (0, utils_1.getFirstOrUndefined)(yield this.findReactions([id]));
});
}
/**
* Find and load data about a reaction id from Subsocial blockchain and IPFS by a given `accountId` and
* and `postId`.
*
*
* @param accountId - Id of desired account.
*
* @param postId - Id of desired post.
*
* @returns Data of reaction id aggregated from Subsocial blockchain. If no corresponding reaction id to given
* `accountId` and `postId`, undefined is returned.
*
*/
getPostReactionIdByAccount(accountId, postId) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
return (_a = (0, utils_1.getFirstOrUndefined)(yield this.getReactionIdsByAccount(accountId, [postId]))) === null || _a === void 0 ? void 0 : _a.toString();
});
}
/**
* Find and load an array of information about reaction ids from Subsocial blockchain and IPFS by a given `accountId` and
* and an array of `postIds`.
*
*
* @param accountId - Id of desired account.
*
* @param postIds - An array of ids of desired posts.
*
* @returns An array of reaction id aggregated from Subsocial blockchain. If no corresponding reaction id to given
* `accountId` and and array of `postIds`, an empty array is returned.
*
*/
getPostReactionIdsByAccount(accountId, postIds) {
return __awaiter(this, void 0, void 0, function* () {
return this.getReactionIdsByAccount(accountId, postIds);
});
}
// ---------------------------------------------------------------------
// Get id
/**
* Find and load next space id from Subsocial blockchain.
*
* @returns A string of the next space id.
*
*/
nextSpaceId() {
return __awaiter(this, void 0, void 0, function* () {
const id = yield this.querySpaces('nextSpaceId');
return (0, utils_1.asString)(id);
});
}
/**
* Find and load next post id from Subsocial blockchain.
*
* @returns A string of the next post id.
*
*/
nextPostId() {
return __awaiter(this, void 0, void 0, function* () {
const id = yield this.queryPosts('nextPostId');
return (0, utils_1.asString)(id);
});
}
/**
* Find and load an array of reply ids from Subsocial blockchain by a given post `id`.
*
* @param id - Id of desired post.
*
* @returns An array of reply id aggregated from Subsocial blockchain. If no corresponding reply id to given
* post `id`, an empty array is returned.
*
*/
getReplyIdsByPostId(id) {
return __awaiter(this, void 0, void 0, function* () {
const ids = yield this.queryPosts('replyIdsByPostId', id);
return (0, utils_1.asStringArray)(ids);
});
}
/**
* Find and load an array of space ids from Subsocial blockchain of an owner by a given account `id`.
*
* @param id - Id of desired account as spaces owner.
*
* @returns An array of space id aggregated from Subsocial blockchain. If no corresponding space id to given
* account `id`, an empty array is returned.
*
*/
spaceIdsByOwner(id) {
return __awaiter(this, void 0, void 0, function* () {
const ids = yield this.querySpaces('spaceIdsByOwner', (0, utils_2.asAccountId)(id));
return (0, utils_1.asStringArray)(ids);
});
}
/**
* Find and load an array of space ids from Subsocial blockchain followed by a given account `id`.
*
* @param id - Id of desired account as spaces follower.
*
* @returns An array of space id aggregated from Subsocial blockchain. If no corresponding space id followed by a given
* account `id`, an empty array is returned.
*
*/
spaceIdsFollowedByAccount(id) {
return __awaiter(this, void 0, void 0, function* () {
const ids = yield this.queryPallet({ pallet: 'spaceFollows', storage: 'spacesFollowedByAccount' }, (0, utils_2.asAccountId)(id));
return (0, utils_1.asStringArray)(ids);
});
}
/**
* Find and load an array of post ids from Subsocial blockchain by a given space `id`.
*
* @param id - Id of desired space.
*
* @returns An array of post id aggregated from Subsocial blockchain. If no corresponding post id to given
* space `id`, an empty array is returned.
*
*/
postIdsBySpaceId(id) {
return __awaiter(this, void 0, void 0, function* () {
const ids = yield this.queryPosts('postIdsBySpaceId', id);
return (0, utils_1.asStringArray)(ids);
});
}
/**
* Find and load profile space id from Subsocial blockchain by a given account `id`.
*
* @param accountId - Id of desired account.
*
* @returns Data of profile space id from Subsocial blockchain.
*
*/
profileSpaceIdByAccount(accountId) {
return __awaiter(this, void 0, void 0, function* () {
const id = yield this.queryProfiles('profileSpaceIdByAccount', accountId);
return (0, utils_1.asString)(id);
});
}
/**
* Find and load an array of profile space ids from Subsocial blockchain by a given array of `accountIds`.
*
* @param accountIds - An array of desired account ids.
*
* @returns An array of profile space ids aggregated from Subsocial blockchain. If no corresponding space id to given
* array of `accountIds`, an empty array is returned.
*
*/
profileSpaceIdsByAccounts(accountIds) {
return __awaiter(this, void 0, void 0, function* () {
const ids = yield this.queryPalletMulti({ pallet: 'profiles', storage: 'profileSpaceIdByAccount' }, accountIds);
return (0, utils_1.asStringArray)(ids);
});
}
// ---------------------------------------------------------------------
// Is boolean
/**
* Find and load boolean value from Subsocial blockchain by a given `myAddress` and `followedAddress`.
*
* @param myAddress - Id of own account.
*
* @param followedAddress - Id of followedAccount.
*
* @returns A boolean value whether `myAddress` is following `followedAddress` or not, retrieved from Subsocial blockchain.
*
*/
isAccountFollower(myAddress, followedAddress) {
return __awaiter(this, void 0, void 0, function* () {
const followedAccountId = (0, utils_2.asAccountId)(followedAddress);
const myAccountId = (0, utils_2.asAccountId)(myAddress);
const queryParams = new types_1.Tuple(registry_1.default, [types_1.GenericAccountId, types_1.GenericAccountId], [myAccountId, followedAccountId]);
const isFollow = yield this.queryPallet({ pallet: 'accountFollows', storage: 'accountFollowedByAccount' }, queryParams);
return isFollow.valueOf();
});
}
/**
* Find and load boolean value from Subsocial blockchain by a given `myAddress` and `spaceId`.
*
* @param myAddress - Id of own account.
*
* @param spaceId - Id of desired space.
*
* @returns A boolean value whether `myAddress` is following a given `spaceId` or not, retrieved from Subsocial blockchain.
*
*/
isSpaceFollower(myAddress, spaceId) {
return __awaiter(this, void 0, void 0, function* () {
return this.isBooleanByAccount({ pallet: 'spaceFollows', storage: 'spaceFollowedByAccount' }, myAddress, spaceId);
});
}
// ---------------------------------------------------------------------
// Roles
/**
* Find and load an array of account ids with any role from Subsocial blockchain by a given `spaceId`.
*
* @param spaceId - Id of desired space.
*
* @returns An array of string representing accounts in any role retrieved from Subsocial blockchain by a given `spaceId`.
* If no corresponding account with any role to a given `spaceId`, an empty array is returned.
*
*/
getAccountsWithAnyRoleInSpace(spaceId) {
return __awaiter(this, void 0, void 0, function* () {
const api = yield this.api;
const roleIdsCodec = yield api.query.roles.roleIdsBySpaceId(spaceId);
const roleIds = (0, utils_2.getUniqueIds)(roleIdsCodec.map(x => x.toString()));
const usersArrays = yield api.query.roles.usersByRoleId.multi(roleIds);
return usersArrays.flatMap(users => users.filter(x => x.isAccount).map(x => x.asAccount.toString()));
});
}
/**
* Find and load an array of role ids owned by a given `accountId` from Subsocial blockchain within a given space.
*
* @param accountId - Id of desired account.
*
* @returns An array of role ids retrieved from Subsocial blockchain by a given `accountId` within a space.
* If no corresponding role id to a given `accountId`, an empty array is returned.
*
*/
getSpaceIdsWithRolesByAccount(accountId) {
return __awaiter(this, void 0, void 0, function* () {
const api = yield this.api;
const roleIdsByUserInSpace = yield api.query.roles
.roleIdsByUserInSpace.entries({ Account: accountId });
return roleIdsByUserInSpace.map(([key]) => key.args[1].toString());
});
}
/**
* Find and load an array of space permissions owned by a given `accountId` from Subsocial blockchain within a given `spaceId`.
*
* @param accountId - Id of desired account.
*
* @param spaceId - Id of desired space.
*
* @returns An array of space permissions retrieved from Subsocial blockchain by a given `accountId` within a `spaceId`.
* If no corresponding space permissions to a given `accountId` within a `spaceId`, an empty array is returned.
*
*/
getSpacePermissionsByAccount(accountId, spaceId) {
return __awaiter(this, void 0, void 0, function* () {
const api = yield this.api;
const roleIdsInSpace = yield api.query.roles
.roleIdsByUserInSpace({ Account: accountId }, spaceId);
const setRolesIdsInSpace = (0, utils_2.getUniqueIds)(roleIdsInSpace.map(x => x.toString()));
const roles = yield api.query.roles.roleById.multi(setRolesIdsInSpace);
const permissions = roles.flatMap(x => { var _a; return (_a = x.toHuman()) === null || _a === void 0 ? void 0 : _a.permissions; });
return (0, utils_2.getUniqueIds)(permissions);
});
}
// ---------------------------------------------------------------------
// Domains
/**
* Find and load an array of domain names by key pairs [Owner, SpaceId] from Subsocial blockchain.
*
* @param keys - An array of keypairs [Owner, SpaceId].
*
* @returns An array of domain names retrieved from Subsocial blockchain by a given array of key pairs [Owner, SpaceId].
* If no corresponding domain name to given key pairs, an empty array is returned.
*
*/
getDomainNames(keys) {
return __awaiter(this, void 0, void 0, function* () {
const api = yield this.api;
const domainNames = yield api.query.domains.domainByInnerValue.multi(keys.map(([account, spaceId]) => ([account, { Space: spaceId }])));
return domainNames === null || domainNames === void 0 ? void 0 : domainNames.map(x => x.toHuman());
});
}
/**
* Find and load domain by a given `accountId` and `spaceId` from Subsocial blockchain.
*
* @param accountId - Id of a desired account.
*
* @param spaceId - Id of desired space.
*
* @returns Data about domain name (in string) retrieved from Subsocial blockchain by a given `accountId` and `spaceId`.
* If no corresponding domain name to given `accountId` and `spaceId`, undefined is returned.
*
*/
domainNameBySpaceId(accountId, spaceId) {
return __awaiter(this, void 0, void 0, function* () {
return (0, utils_1.getFirstOrUndefined)(yield this.getDomainNames([[accountId, spaceId]]));
});
}
/**
* Find and load an array of domain structs of registered domains by a given array of `domainNames` from Subsocial blockchain.
*
* @param domainNames - An array of desired domain names.
*
* @returns An array of information about domain structs of registered domains retrieved from Subsocial blockchain
* by a given array of `domainNames`. If no corresponding domain structs to given array of `domainNames`, an empty array is returned.
*
*/
registeredDomains(domainNames) {
return __awaiter(this, void 0, void 0, function* () {
const api = yield this.api;
const structs = yield api.query.domains.registeredDomains.multi(domainNames);
return structs.filter(x => x.isSome).map(x => x.unwrap());
});
}
/**
* Find and load information about domain structs of registered domain by a given `domainName` from Subsocial blockchain.
*
* @param domainName - A string of desired domain name.
*
* @returns Data about domain structs of a registered domain retrieved from Subsocial blockchain
* by a given `domainName`.
*
*/
registeredDomain(domainName) {
return __awaiter(this, void 0, void 0, function* () {
return this.registeredDomains([domainName]);
});
}
/**
* Find and load an array of information about domains by a given `accountId` from Subsocial blockchain.
*
* @param accountId - Id of owner of domains.
*
* @returns An array of information about domains retrieved from Subsocial blockchain by an owner `accountId`.
* If no corresponding domain to given owner `accountId`, an empty array is returned.
*
*/
domainsByOwner(accountId) {
return __awaiter(this, void 0, void 0, function* () {
const api = yield this.api;
const domains = yield api.query.domains.domainsByOwner(accountId);
return domains.toHuman();
});
}
}
exports.SubsocialSubstrateApi = SubsocialSubstrateApi;
const logger = (0, utils_1.newLogger)(SubsocialSubstrateApi.name);