ICBlast - Opinionated client library | undefined or [ ]?

Icblast 2.0.6 - alpha. (Not production ready) Just got released.

It is wrapping around Agentjs and provides extra convenience and functionality. It is very opinionated.
What it does: converts all input, passes it to Agentjs actor, then converts the output and returns it.

Opinions:

:thinking: Opt has to be undefined not []

The main argument against is that Opt Opt Opt Nat8 is valid candid. However, my opinion is that nobody should create APIs that differentiate opt levels. {param:[]} {param:[[]]} and {param:[[[]]]} should be treated the same.
with agentjs you had to write {parm : [[[3]]]} or {parm: []} with icblast you have to write {parm:3} or {}

Using agentjs directly:

icrc1_transfer({"to":{"owner":Principal.fromText("ryjl3-tyaaa-aaaaa-aaaba-cai"),"subaccount":[]},
"fee":[],"memo":[],"from_subaccount":[],"created_at_time":[],"amount":123})

Using icblast:

icrc1_transfer({to: {owner: "ryjl3-tyaaa-aaaaa-aaaba-cai"}, amount: 123})

Both are doing the same thing. Responses also get the same treatment.

:thinking: Err has to be thrown not returned

Using agentjs:

let resp = await can.balance();
if ("Err" in resp) throw resp.Err;
let balance = resp.Ok.e8s;

You can also write this:

let {Ok : {e8s : balance}} = await can.balance();
// balance = 123123

But then when the canister returns Err, it won’t propagate correctly and you will see something like “Error: Not found e8s in undefined” instead of “Canister error : account not found”

With Icblast:

let {e8s: balance} = await can.balance();

:thinking: Responses should be easily serializable, so they can get stored in app state

toState(…) will convert nested object values:

  • principal → string principal
  • uint8array → hex string
  • other typed arrays → array
  • biging → string bigint

toState is optional

let x = await can.get_things()
let sum = x + 1_000n;
// also handle binary data 
// when you are ready and want to put in state
setState(toState(x));
// or
console.log(JSON.stringify(toState(x))); // you will get error if trying to serialize obj with bigint without toState
// also (without toState) Uint8Array will become an object {0:123, 1:221, 3:123,...}

toState will have everything converted, serializable, and ready to be stored in state.
Without icblast’s toState, you will have uint8arrays and bigints nested in your responses which will cause trouble in state, React, Redux, etc…

:thinking: Actor has to easily handle serialized values:

Once stored in state with toState, the values can be easily used in calls.
Example: In case it stumbles upon a string hex when expecting uint8array, it will convert it automagically :unicorn:. It knows it’s looking for a Principal and it’s fed a string, so why not try to covert it? It will throw if it’s wrong

  • string principals → principals
  • string hex (accounts & subaccounts) → Uint8array
  • string bigint → bigint

This is valid:

ledger.transfer({
owner: "ryjl3-tyaaa-aaaaa-aaaba-cai",
subaccount:"ffee00"},
amount: "232423234234234"}

:thinking: The Interface description the generated idl.js has to be traversable

Currently, it’s not easily traversable.
Icblast’s explainer(idlFactory) will do some magic and return a traversable obj. Good for explorers and other advanced usages like all the conversions above.

Github: [GitHub - infu/icblast]

Try the new icblast interface at Blast [https://jglts-daaaa-aaaai-qnpma-cai.ic0.app/]

Not properly tested yet and also not tested with all versions of agentjs.
NPM package will change and dependencies will be removed.
Expect beta release soon. If you have any extra ideas, they are welcome.
For whoever is interested in how the magic works - icblast/actress.js at main · infu/icblast · GitHub

13 Likes

Checking if something is defined or not in agentjs and icblast


Blast here [Internet Computer Loading]

Destructuring nested objects is in favor of Icblast - a lot less complicated


blast here [Internet Computer Loading]