npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@funded-labs/cap-js

v0.0.8

Published

Cap client library

Downloads

12

Readme

A client library for the CAP Open Internet Service (OIS), implemented in JavaScript. The interface is based on the candid file Cap Candid allowing dApps to interact with the main canister. In addition, this client library will support endpoint caching using Kyasshu.

The CAP-js library is utilized to integrate UIs/FEs/Apps to CAP to query & surface data from CAP. Any frontend can query the transaction/activity history for any Token or NFTs that uses CAP. (Instead of having to integrate manually with each asset!)

IMPORTANT: CAP is currently in development 🚧 and will release in the first week of November, thus it is not on mainnet or usable yet. You might see our documentation is light on the SDK/Main repo still. We're delayed in this to focus on testing, but will soon update this page with guides & detailed examples for developers.

Table of Contents

Getting Started

⚠️ ⚠️ Library not stable, will stay unstable until Cap is finalized ⚠️ ⚠️

Install

yarn add @psychedelic/cap-js

Usage

To interface with Router and Root toolkits, you have to instantiate them in the client application.

The Router instance is long lived and can persist across your application lifetime, as the Canister Id it depends on is of fixed value (e.g. calls to the method get_index_canisters will be sent to the same canister id in the network you're connected to). For this reason, it's recommended ⚡️ to create the instance in the application top-level and reuse during the application lifetime.

The Root instance in the other hand is short-lived and only useful during the token contract use cases (e.g. calls to the method get_transaction are sent to the particular token contract canister id which is unique). As such, it's necessary 🤝 to create a new instance for each token contract canister id and reuse the instance in the context of the token contract.

These are available as:

import { CapRouter, CapRoot } from '@psychedelic/cap-js';

Here's an example of how to instantiate the CapRouter, which is similar to CapRoot:

import { CapRouter } from '@psychedelic/cap-js';

const getCapRouterInstance = async ({
  canisterId,
  host,
}: {
  canisterId?: string,
  host?: string,
}) => await CapRouter.init({
  host,
  canisterId,
});

// On a hypotetical application top-level or entry-point
(async () => {
	const capRouter = new getCapRouterInstance({
		canisterId: 'rrkah-fqaaa-aaaaa-aaaaq-cai',
		host: 'http://localhost:8000',
	});
})();

💡 The root canister id and host can be computed by an environment variable. Although, these parameters can be omited and the mainnet values are set by default.

Also, there's a Hosts object that can be used to retrieve defaults:

import { Hosts } from '@psychedelic/cap-js';

// The Mainnet
const mainnetHost = Hosts.mainnet;

Similarily, a CAP CanisterInfo object is available that provides defaults:

import { CanisterInfo } from '@psychedelic/cap-js';

// The `ic-history-router` mainnet canister id
const ICHistoryRouterCanisterId = CanisterInfo['ic-history-router'].mainnet;

Quick usage examples

In order to get transactions of a particular token (e.g: XTC token):

const tokenId = 'aanaa-xaaaa-aaaah-aaeiq-cai'	// XTC Canister Id

const { canister: rootTokenId } = capRouter.get_token_contract_root_bucket({canister: tokenId, witness})

const capRootXTC = await CapRoot.init({
  canisterId: rootTokenId[0],
})

const xtcTransactions = await capRootXTC.get_transactions()

Or instead, pass an instance of capRouter to have the inner call to get_token_contract_root_bucket handled for you:

const tokenId = 'aanaa-xaaaa-aaaah-aaeiq-cai'	// XTC Canister Id

const capRootXTC = await CapRoot.init({ tokenId, router: capRouter })

const xtcTransactions = await capRootXTC.get_transactions()

Alternatively, for the case where you don't have a CapRouter instance:

const tokenId = 'aanaa-xaaaa-aaaah-aaeiq-cai'	// XTC Canister Id

const capRootXTC = await CapRoot.init({
	tokenId,
	routerCanisterId: 'rrkah-fqaaa-aaaaa-aaaaq-cai',
	host: 'http://localhost:8000'
})

const xtcTransactions = await capRootXTC.get_transactions()

You're advised to understand Candid, the interface description language for the Dfinity Internet Computer Services, because ultimately, that's where the latest method signatures for the Service endpoints are defined, to avoid any typos described in the documentation.

Once you start looking at the original source-code, you might start questioning some decisions.

For example, why cap-js at time of writing is wrapping the Actor methods which are accessible directly in the actor (e.g. capRoot.actor.get_transactions())?

As it's mainly a wrapper to original method accessible in the actor and that's for your own convenience (e.g. provides default values) it also provides a chance to the Cache layer to intercept and handle those requests.

Since Cache is available (optionally) it helps to have a common API to switch between.

const tnx = await caRoot.get_transactions(...);
const tnx = await capCache.get_transactions(...);

Find more about here

Router Canister

capRouter.get_index_canisters(witness)

Return all Cap index canisters (Router and any replicas, when scaled)

Parameters

| Name | Type | Description | | ---- | ---- | ----------- | | witness | boolean? | The optional Certified response, defaults to false |

Returns

| Type | Description | | ---- | ----------- | | GetIndexCanistersResponse | An object returning all index canisters. If witness = true the certified response will be appended to the response |

Example

const indexCanisters = await capRouter.get_index_canisters(false);
console.log(indexCanisters);
{
	witness: [] | [Witness];
	canisters: Array<Principal>;
}

capRouter.get_token_contract_root_bucket({canister, witness})

For a given token contract, return the entry root bucket

Parameters

| Name | Type | Description | | ---- | ---- | ----------- | | canister | Principal | The canister Id of the requested root bucket | | witness | boolean? | The optional witness for the Certified response |

Returns

| Type | Description | | ---- | ----------- | | GetTokenContractRootBucketResponse | An object returning root canister for a given token. If witness = true the certified response will be appended to the response |

Example

const tokenRootBucket = await capRouter.get_token_contract_root_bucket({
 canister: "aaaa-aa",
 witness: false,
});
console.log(tokenRootBucket);
{
	witness: [] | [Witness];
	canister: [] | [Principal];
}

capRouter.get_user_root_buckets({user, witness})

query a users root bucket, each user root bucket exposes an interface to interact with and get transactions

Parameters

| Name | Type | Description | | ---- | ---- | ----------- | | user | Principal | The user Id of the requested root bucket | | witness | boolean? | The optional witness for the Certified response |

Returns

| Type | Description | | ---- | ----------- | | GetUserRootBucketsResponse | An object returning root canister for a given user. If witness = true the certified response will be appended to the response |

Example

const userRootBucket = await capRouter.get_user_root_buckets({
 user: "avesb-mgo2l-ds25i-g7kd4-3he5l-z7ary-3biiq-sojiw-xjgbk-ich5l-mae",
 witness: false,
});
console.log(userRootBucket);
{
	witness: [] | [Witness];
	contracts: Array<Principal>;
}

capRouter.insert_new_users(contractId, users)

insert new users for a token contract

Parameters

| Name | Type | Description | | ---- | ---- | ----------- | | contractId | Principal | The token contract Id | | users | Array of Principal | A list of user principal |

Returns

| Type | Description | | ---- | ----------- | | Promise<undefined> | an empty response () |

capRouter.install_bucket_code(principal)

instantiate a new bucket canister for a token

Parameters

| Name | Type | Description | | ---- | ---- | ----------- | | principal | Principal | principal Id of a newly created empty canister |

Returns

| Type | Description | | ---- | ----------- | | Promise<undefined> | an empty response () |

Example

# create root bucket canister
dfx canister --wallet=$(dfx identity get-wallet) call aaaaa-aa create_canister "(record { cycles=(4_000_000_000_000:nat64); controller=(opt principal \"$(dfx identity get-principal)\") })"

# set cap as the controller for the root bucket
dfx canister --wallet=$(dfx identity get-wallet) call aaaaa-aa update_settings "(record { canister_id=(principal \"r7inp-6aaaa-aaaaa-aaabq-cai\"); settings=(record { controller = opt principal \"rrkah-fqaaa-aaaaa-aaaaq-cai\"; null; null; null; }) })"

# Check controller of bucket canister
dfx canister info r7inp-6aaaa-aaaaa-aaabq-cai

Notes

  • It is better to programmatically execute this install_bucket_code from your canister or through DFX.

Root Canister

capRoot.get_transaction(id, witness)

Return a specifc transaction based on global transaction Id from a token contract (tokenId)

Parameters

| Name | Type | Description | | ---- | ---- | ----------- | | id | bigint | The global txnId of a transaction to return | | witness | boolean? | The optional witness for the Certified response |

Returns

| Type | Description | | ---- | ----------- | | GetTransactionResponse | An object returning either Delegate or Found. If witness = true the certified response will be appended to the response |

Example

const transaction = await capRoot.get_transaction(
	BigInt(1), 
	false,
)
console.log(transaction);
{
	Delegate: [Principal, [] | [Witness]];
}
# or
{ 
	Found: [[] | [Event], [] | [Witness]] 
}

Notes

  • Unstable endpoint

capRoot.get_transactions({page, witness})

Get all transactions for a single token contract

Parameters

| Name | Type | Description | | ---- | ---- | ----------- | | page | number? | The optional number of the page to query for transctions, each page can hold up to 64 transactions. Defaults to page 0. | | witness | boolean? | The optional witness for the Certified response |

Returns

| Type | Description | | ---- | ----------- | | GetTransactionsResponseBorrowed | An object returning an array of data as well as the page queried. If witness = true the certified response will be appended to the response |

Example

const tokenTxns = await capRoot.get_transactions({
 page: 4,
 witness: false,
});

// or

const tokenTxns = await capRoot.get_transactions({
 witness: false,
}); // this will default to page 0

console.log(tokenTxns);
{
	data: Array<Event>;
	page: number;
	witness: [] | [Witness];
}

Notes

  • If no page param provided, we will query the first page, this is oppposite to what the main canister does which is query the last page transactions.

capRoot.get_user_transactions(({page, user, witness})

Get all user transactions for the token contract

| Name | Type | Description | | ---- | ---- | ----------- | | page | number? | The optional number of the page to query for transctions, each page can hold up to 64 transactions. Defaults to page 0. | | user | Principal | The user principal of the requested transactions | witness | boolean? | The optional witness for the Certified response |

Returns

| Type | Description | | ---- | ----------- | | GetTransactionsResponseBorrowed | An object returning an array of data as well as the page queried. If witness = true the certified response will be appended to the response |

Example

import { cap } from '@psychedelic/cap-js'

const userTxns = await capRoot.get_user_transactions({
 userId: "avesb-mgo2l-ds25i-g7kd4-3he5l-z7ary-3biiq-sojiw-xjgbk-ich5l-mae",
 page: 4,
 witness: false,
});

// or

const userTxns = await capRoot.get_user_transactions({
 userId: "avesb-mgo2l-ds25i-g7kd4-3he5l-z7ary-3biiq-sojiw-xjgbk-ich5l-mae",
}); // this will default to page `0` and witness `false`

console.log(userTxns);
{
	data: Array<Event>;
	page: number;
	witness: [] | [Witness];
}

capRoot.insert({operation, caller, details})

Insert a transaction event to the token contract

| Name | Type | Description | | ---- | ---- | ----------- | | operation | operation | | caller | principal | | details | vec record

Returns

| Type | Description | | ---- | ----------- | | Promise<bigint> | a number |

Notes

  • If no page param provided, we will query the first page, this is oppposite to what the main canister does which is query the last page transactions.

capRoot.get_bucket_for({})

ToDo

capRoot.get_next_canisters({})

ToDo

time : () -> (nat64) query;

capRoot.time([options])

ToDo

Kyasshu Layer

kyasshu is a cache layer, that is originally used in the for xtc token service by utilizing lambda, sqs, redis and dynamodb. Why would you want to use Kyasshu? Because caching allows you to efficiently reuse previously retrieved data, improving your application performance.

capRoot.get_all_user_transactions(userId, LastEvaluatedKey)

Return all of the user transactions for userId, if LastEvaluatedKey is returned, you must provide it in subsequent calls to query the rest of the data.

Parameters

| Name | Type | Description | | ---- | ---- | ----------- | | userId | principal | The user Id of the requested transactions | | LastEvaluatedKey | string? | The optional LastEvaluatedKey, If LastEvaluatedKey is empty, then the "last page" of results has been processed and there is no more data to be retrieved. If LastEvaluatedKey is not empty, it does not necessarily mean that there is more data in the result set. The only way to know when you have reached the end of the result set is when LastEvaluatedKey is empty. |

Returns

| Type | Description | | ---- | ----------- | | GetTransactionsResponseBorrowed | An object returning an array of data as well as the page queried. If witness = true the certified response will be appended to the response |

Example

const capCache = new CapCache();

let userTxns = await capCache.get_all_user_transactions({
	user: Principal.from("zxt4e-ian3w-g4ll2-3n5mz-lfqkc-eyj7k-yg6jl-rsbud-f6sft-zdfq3-pae"),
});

userTxns = await capCache.get_all_user_transactions({
	user: Principal.from("zxt4e-ian3w-g4ll2-3n5mz-lfqkc-eyj7k-yg6jl-rsbud-f6sft-zdfq3-pae"),
	LastEvaluatedKey: userTxns.LastEvaluatedKey,
});

console.log(userTxns);
{
	Items?: {
			[key: string]: Event;
	}[] | undefined;
	LastEvaluatedKey?: {
			[key: string]: any;
	} | undefined;
}

Notes

  • Unstable endpoint

API

  • ToDo

Local Development

  • ToDo

Roadmap

  • Cache every endpoint with Kyasshu

  • Support update calls to the main Cap canister

Testing

  • ToDo

To run tests, run the following command

  npm run test

Roadmap

  • Cache every endpoint with Kyasshu or with a cache canister

  • Support update calls to the main Cap canister

Contributing

Contributions are always welcome!

License

MIT