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

canpack

v0.2.2

Published

Package multiple libraries into one ICP canister.

Downloads

54

Readme

canpack   npm version GitHub license

Canpack is a code generation tool which simplifies cross-language communication in Internet Computer canisters (such as calling a Rust crate from Motoko).

Note: This project is early in development; unannounced breaking changes may occur at any time.

Installation

Ensure that the following software is installed on your system:

Run the following command to install the Canpack CLI on your global system path:

npm install -g canpack

Quick Start (Motoko + Rust)

Canpack has built-in support for the Mops package manager.

In your canister's mops.toml file, add a rust-dependencies section:

[rust-dependencies]
canpack-example-hello = "^0.1"
local-crate = { path = "path/to/local-crate" }

You can also specify [rust-dependencies] in a Motoko package's mops.toml file to include Rust crates in any downstream canisters.

Next, run the following command in the directory with the mops.toml and dfx.json files:

canpack

This will configure and generate a motoko_rust canister with Candid bindings for the specified dependencies. Here is a Motoko canister which uses a function defined in the canpack-example-hello crate:

import Rust "canister:motoko_rust";

actor {
    public composite query func hello(name: Text) : async Text {
        await Rust.canpack_example_hello(name)
    } 
}

Any Rust crate with Canpack compatibility can be specified as a standard Cargo.toml dependency. See the Rust Crates section for more details.

Programmatic API

Canpack is primarily intended as a low-level building block for use in package managers and other development tools.

Add the canpack dependency to your Node.js project with the following command:

npm i --save canpack

The following example JavaScript code runs Canpack in the current working directory:

import { canpack } from 'canpack';

const directory = '.';
const config = {
    canisters: {
        my_canister: {
            type: 'rust',
            parts: [{
                package: 'canpack-example-hello',
                version: '^0.1',
            }]
        }
    }
};

await canpack(directory, config);

Advanced Usage

Pass the -v or --verbose flag to view the resolved JSON configuration for a project:

canpack --verbose

Below is a step-by-step guide for setting up a dfx project with a canpack.json config file. The goal here is to illustrate how one could use Canpack without additional tools such as Mops, which is specific to the Motoko ecosystem.

Run dfx new my_project, selecting "Motoko" for the backend and "No frontend canister" for the frontend. Once complete, run cd my_project and open in your editor of choice.

Add a new file named canpack.json in the same directory as dfx.json.

In the canpack.json file, define a Rust canister named my_project_backend_rust:

{
    "canisters": {
        "my_project_backend_rust": {
            "type": "rust",
            "parts": [{
                "package": "canpack-example-hello",
                "version": "^0.1"
            }]
        }
    }
}

Next, run the following command in this directory to generate all necessary files:

canpack

In your dfx.json file, configure the "dependencies" for the Motoko canister:

{
    "canisters": {
        "my_project_backend": {
            "dependencies": ["my_project_backend_rust"],
            "main": "src/my_project_backend/main.mo",
            "type": "motoko"
        }
    },
}

Now you can call Rust functions from Motoko using a canister import:

import Rust "canister:my_project_backend_rust";

actor {
    public func hello(name: Text) : async Text {
        await Rust.canpack_example_hello(name)
    } 
}

Run the following commands to build and deploy the dfx project on your local machine:

dfx start --background
dfx deploy

Rust Crates

It's relatively simple to add Canpack support to any IC Wasm-compatible Rust crate.

Here is the full implementation of the canpack-example-hello package:

canpack::export! {
    pub fn canpack_example_hello(name: String) -> String {
        format!("Hello, {name}!")
    }
}

If needed, you can configure the generated Candid method using a #[canpack] attribute:

canpack::export! {
    #[canpack(composite_query, rename = "canpack_example_hello")]
    pub fn hello(name: String) -> String {
        format!("Hello, {name}!")
    }
}

Note that it is possible to reference local constants, methods, etc.

const WELCOME: &str = "Welcome";

fn hello(salutation: &str, name: String) -> String {
    format!("{salutation}, {name}!")
}

canpack::export! {
    pub fn canpack_example_hello(name: String) -> String {
        hello(WELCOME, name)
    }
}

The canpack::export! shorthand requires adding canpack as a dependency in your Cargo.toml file. It's also possible to manually define Candid methods by exporting a canpack! macro:

pub fn hello(name: String) -> String {
    format!("Hello, {name}!")
}

#[macro_export]
macro_rules! canpack {
    () => {
        #[ic_cdk::query]
        #[candid::candid_method(query)]
        fn canpack_example_hello(name: String) -> String {
            $crate::hello(name)
        }
    };
}