UNPKG

@subsocial/api

Version:
651 lines (650 loc) 28.2 kB
"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);