morphit/node_modules/@beblurt/dblurt/lib/helpers/condenser.js
Morphit Team 24240cef4c
Some checks failed
morphit-release / Build + publish release tarball (push) Has been cancelled
Reputation flags clearable across all four signals; names and avatars stop vanishing
2026-07-23 14:28:04 -07:00

371 lines
15 KiB
JavaScript

"use strict";
/**
* @file Blurt Condenser API helpers.
* @author BeBlurt <https://beblurt.com/@beblurt>
* @description adaptation from Johan Nordberg <code@johan-nordberg.com> Database API helpers.
* @license
* Copyright (c) 2022 BeBlurt. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You acknowledge that this software is not designed, licensed or intended for use
* in the design, construction, operation or maintenance of any military facility.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.CondenserAPI = void 0;
const authority_1 = require("../authority");
class CondenserAPI {
constructor(client) {
this.client = client;
}
/** Convenience for calling `condenser_api`. */
call(method, params) {
return this.client.call('condenser_api', method, params);
}
/**
* Returns one or more account history objects for account operations
*
* @param account The account to fetch
* @param from The starting index
* @param limit The maximum number of results to return
* @param operation_bitmask Generated by utils.makeBitMaskFilter() - see example below (not yet usable)
* @example
* ```typescript
* import { utils } from "@beblurt/dblurt"
* const op = dblurt.utils.operationOrders
* const operationsBitmask = dblurt.utils.makeBitMaskFilter([
* op.vote,
* op.comment,
* op.delete_comment,
* op.comment_options,
* op.claim_reward_balance,
* op.author_reward,
* op.curation_reward,
* op.comment_reward,
* op.producer_reward,
* ])
* const accountHistory = await client.condenser.getAccountHistory('beblurt', -1, 10, operationsBitmask)
* ```
*/
getAccountHistory(account, from, limit, operation_bitmask) {
// const params = [account, from, limit]
// Future usage when filter will be availabe
let params = [account, from, limit];
if (operation_bitmask && Array.isArray(operation_bitmask)) {
if (operation_bitmask.length !== 2) {
throw Error('operation_bitmask should be generated by the helper function');
}
else {
params = operation_bitmask[1] ? [...params, operation_bitmask[0], operation_bitmask[1]] : [...params, operation_bitmask[0]];
}
}
return this.call('get_account_history', params);
}
/**
* Return Layer 1 account state for one or more account names.
*
* Backing JSON-RPC method: `condenser_api.get_accounts`.
*
* Use this when exact account balances, authorities or chain state matter.
* For Nexus profile metadata, use `client.nexus.getProfile` instead.
*
* @param usernames Account names to fetch.
* @returns Account objects in the same order as requested names when found.
* @example
* ```js
* const accounts = await client.condenser.getAccounts(['beblurt']);
* ```
*/
getAccounts(usernames) {
return this.call('get_accounts', [usernames]);
}
/**
* Validate whether a public/private key satisfies an account's Layer 1 posting authority.
*
* This helper reads the account through `condenser_api.get_accounts`, follows
* delegated account authorities through their posting authorities, and returns
* an explanatory result without broadcasting or signing anything.
*/
async validatePostingAuthority(accountName, key) {
const accounts = new Map();
const fetched = new Set();
const fetchAccount = async (name) => {
const existing = accounts.get(name);
if (existing) {
return existing;
}
if (fetched.has(name)) {
throw new Error(`account not found: ${name}`);
}
fetched.add(name);
const [account] = await this.getAccounts([name]);
if (!account || account.name !== name) {
throw new Error(`account not found: ${name}`);
}
accounts.set(name, account);
return account;
};
const root = await fetchAccount(accountName);
const queue = [accountName];
let index = 0;
while (index < queue.length) {
const current = await fetchAccount(queue[index]);
index++;
for (const auth of [current.owner, current.active, current.posting]) {
for (const [delegated] of auth.account_auths || []) {
if (!accounts.has(delegated) && !queue.includes(delegated)) {
queue.push(delegated);
}
}
}
}
return (0, authority_1.validatePostingAuthority)(root, key, {
getAccount: name => accounts.get(name)
});
}
/**
* Return active Layer 1 votes for a post or comment.
*
* Backing JSON-RPC method: `condenser_api.get_active_votes`.
*
* @param author Post/comment author.
* @param permlink Post/comment permlink.
* @returns Active vote entries known by the RPC node.
* @example
* ```js
* const votes = await client.condenser.getActiveVotes(author, permlink);
* ```
*/
async getActiveVotes(author, permlink) {
return this.call('get_active_votes', [author, permlink]);
}
/** Returns the list of active witnesses */
async getActiveWitnesses() {
return this.call('get_active_witnesses', []);
}
/** Return block *blockNum*. */
getBlock(blockNum) {
return this.call('get_block', [blockNum]);
}
/** Return header for *blockNum*. */
getBlockHeader(blockNum) {
return this.call('get_block_header', [blockNum]);
}
/** Returns a list of blog entries for an account. */
getBlogEntries(account, start_entry_id, limit) {
return this.call('get_blog_entries', [account, start_entry_id, limit]);
}
/** Return median chain properties decided by witness. */
async getChainProperties() {
return this.call('get_chain_properties');
}
/** Return server config. See:
* https://gitlab.com/blurt/blurt/-/blob/master/libraries/protocol/include/blurt/protocol/config.hpp
*/
getConfig() {
return this.call('get_config', []);
}
/**
* Return a Layer 1 content object for a post or comment.
*
* Backing JSON-RPC method: `condenser_api.get_content`.
*
* This reads the chain content object. If you need social/indexed ranking,
* discovery or community context, use Nexus helpers first and then read the
* Layer 1 object with this method when exact chain content matters.
*
* @param author Post/comment author.
* @param permlink Post/comment permlink.
* @returns The content object returned by the RPC node.
*/
getContent(author, permlink) {
return this.call('get_content', [author, permlink]);
}
/** Returns a list of replies. */
getContentReplies(author, permlink) {
return this.call('get_content_replies', [author, permlink]);
}
/**
* Return current Layer 1 dynamic global properties.
*
* Backing JSON-RPC method: `condenser_api.get_dynamic_global_properties`.
*
* This is the usual source for head block number, last irreversible block,
* time and other current chain-level values.
*/
getDynamicGlobalProperties() {
return this.call('get_dynamic_global_properties');
}
/**
* Return array of discussions (a.k.a. posts).
* @param by The type of sorting for the discussions, valid options are:
* `active` `blog` `cashout` `children` `comments` `created`
* `feed` `hot` `promoted` `trending` `votes`. Note that
* for `blog` and `feed` the tag is set to a username.
*/
getDiscussions(by, query) {
return this.call(`get_discussions_by_${by}`, [query]);
}
/** return the count of followers/following for an account */
async getFollowCount(accounts) {
return this.call('get_follow_count', accounts);
}
/** return the list of the followers of an account */
async getFollowers(account, start, type, limit) {
return this.call('get_followers', [account, start, type, limit]);
}
/** return the list of accounts that are following an account */
async getFollowing(account, start, type, limit) {
return this.call('get_following', [account, start, type, limit]);
}
/** Returns the list of accounts that are reblogged a content (post). */
getRebloggedBy(author, permlink) {
return this.call('get_reblogged_by', [author, permlink]);
}
/**
* Return applied operations in a Layer 1 block.
*
* Backing JSON-RPC method: `condenser_api.get_ops_in_block`.
*
* Operation order is the order reported by the node for that block. Use an
* irreversible block number when building examples or replay tools that must
* avoid reversible chain state.
*
* @param blockNum Block number to inspect.
* @param onlyVirtual When true, return only virtual operations.
* @returns Applied operations for the requested block.
* @example
* ```js
* const operations = await client.condenser.getOperations(blockNum, false);
* ```
*/
getOperations(blockNum, onlyVirtual = false) {
return this.call('get_ops_in_block', [blockNum, onlyVirtual]);
}
/**
* Returns an array of proposals filtered by the specified parameters.
* @param start - Depends on order (see below)
* - creator - creator of the proposal (account name string)
* - start_date - start date of the proposal (date string)
* - end_date - end date of the proposal (date string)
* - total_votes - total votes of the proposal (int)
* @param limit - The maximum number of proposals to return (max 1000).
* @param order - can be one of:
* - by_creator - order by proposal creator
* - by_start_date - order by proposal start date
* - by_end_date - order by proposal end date
* - by_total_votes - order by proposal total votes
* @param order_direction - The direction in which to order the results. Can be ascending or descending
* @param status - The status of proposals to return.
* @returns A Promise that resolves to an array of Proposal objects.
*/
getProposals(start, limit, order, order_direction, status) {
return this.call('list_proposals', [start, limit, order, order_direction, status]);
}
/**
* Returns all proposal votes, starting with the specified voter or proposal.id.
* @param start - Depends on order (see below)
* - voter - voter of the proposal (account name string)
* - proposal.id - id the proposal (int)
* @param limit - The maximum number of proposals to return (max 1000).
* @param order - can be one of:
* - by_voter_proposal - order by proposal voter
* - by_proposal_voter - order by proposal.id
* @param order_direction - The direction in which to order the results. Can be ascending or descending
* @param status - The status of proposals to return.
* @returns A Promise that resolves to an array of ProposalVote objects.
*/
getProposalVotes(start, limit, order, order_direction, status) {
return this.call('list_proposal_votes', [start, limit, order, order_direction, status]);
}
/** Returns information about the current reward funds */
async getRewardFund(fund) {
return this.call('get_reward_fund', [fund]);
}
/**
* Return all of the state required for a particular url path.
* @param path Path component of url conforming to condenser's scheme
* e.g. `@beblurt` or `trending/travel`
*/
async getState(path) {
return this.call('get_state', [path]);
}
/** Returns the details of a transaction based on a transaction id. */
async getTransaction(txId) {
return this.call('get_transaction', [txId]);
}
/** return rpc node version */
async getVersion() {
return this.call('get_version', []);
}
/**
* Get list of delegations made by account.
* @param account Account delegating
* @param from Delegatee start offset, used for paging.
* @param limit Number of results, max 1000.
*/
async getVestingDelegations(account, from = '', limit = 1000) {
return this.call('get_vesting_delegations', [account, from, limit]);
}
/** Returns the current witness schedule */
async getWitnessSchedule() {
return this.call('get_witness_schedule', []);
}
/**
* Return Layer 1 witness information for an account.
*
* Backing JSON-RPC method: `condenser_api.get_witness_by_account`.
*
* Not every account is a witness. Use `getActiveWitnesses` or
* `getWitnessesByVote` when you need to discover witness accounts first.
*
* @param account Witness account name.
*/
async getWitnessByAccount(account) {
return this.call('get_witness_by_account', [account]);
}
/** Returns list of witnesses by vote */
async getWitnessesByVote(account, limit) {
return this.call('get_witnesses_by_vote', [account, limit]);
}
/** Returns the current number of witnesses */
async getWitnessesCount() {
return this.call('get_witness_count', []);
}
/** Looks up accounts starting with name */
async lookupAccounts(account, limit) {
return this.call('lookup_accounts', [account, limit]);
}
/** Looks up accounts starting with name */
async lookupWitnessAccounts(account, limit) {
return this.call('lookup_witness_accounts', [account, limit]);
}
/** Verify signed transaction. */
async verifyAuthority(stx) {
return this.call('verify_authority', [stx]);
}
}
exports.CondenserAPI = CondenserAPI;