Skip to content

Commit

Permalink
feat: clarinet sdk browser (#1448)
Browse files Browse the repository at this point in the history
* feat: split clarinet-sdk into web and node

* ci: add-clarinet sdk ci (#1496)

* docs: improve build and contributing steps in readmes

* fix: address review

* tests: add compilation in the pretest script

* address review
  • Loading branch information
hugocaillard authored Jul 12, 2024
1 parent b60ee86 commit 1982441
Show file tree
Hide file tree
Showing 75 changed files with 1,949 additions and 1,165 deletions.
File renamed without changes.
68 changes: 68 additions & 0 deletions .github/workflows/ci-sdk.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: CI - Clarinet SDK
on:
pull_request:
branches:
- main
paths-ignore:
- "**/CHANGELOG.md"
push:
branches:
- main
paths-ignore:
- "**/CHANGELOG.md"

# Cancel previous runs for the same workflow
concurrency:
group: "${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}"
cancel-in-progress: true

jobs:
build_and_test_sdk:
name: Build and test clarinet-sdk packages
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Rust toolchain
run: |
rustup toolchain install stable --profile minimal --component rustfmt
rustup target add wasm32-unknown-unknown
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Setup cache keys
run: |
echo "RUST_VERSION_HASH=$(rustc --version | sha256sum | awk '{print $1}')" >> $GITHUB_ENV
echo "NODE_VERSION_HASH=$(node --version | sha256sum | awk '{print $1}')" >> $GITHUB_ENV
- name: Cache cargo
uses: actions/cache@v4
with:
path: |
~/.cargo/
~/target/release/build/
~/target/wasm32-unknown-unknown/build/
key: clarinet-sdk-cargo-${{ runner.os }}-${{ env.RUST_VERSION_HASH }}-${{ hashFiles('./Cargo.lock') }}

- name: Cache npm
uses: actions/cache@v4
with:
path: |
~/node_modules/
key: clarinet-sdk-npm-${{ runner.os }}-${{ env.NODE_VERSION_HASH }}-${{ hashFiles('./package-lock.json') }}

- name: Install wasm-pack
run: npm install -g wasm-pack

- name: Build Wasm packages
run: npm run build:wasm

- name: Install dependencies
run: npm ci

- name: Run tests
run: npm run test
5 changes: 2 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion components/clarinet-deployments/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version.workspace = true
edition = "2021"

[dependencies]
colored = "2.0.4"
colored = "2.1.0"
serde = "1"
serde_json = "1"
serde_derive = "1"
Expand Down
14 changes: 7 additions & 7 deletions components/clarinet-deployments/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ fn update_session_with_genesis_accounts(
wallet.balance.try_into().unwrap(),
);
if wallet.name == "deployer" {
session.set_tx_sender(wallet.address.to_address());
session.set_tx_sender(&wallet.address.to_string());
}
}
}
Expand Down Expand Up @@ -186,11 +186,11 @@ pub fn update_session_with_deployment_plan(

fn handle_stx_transfer(session: &mut Session, tx: &StxTransferSpecification) {
let default_tx_sender = session.get_tx_sender();
session.set_tx_sender(tx.expected_sender.to_string());
session.set_tx_sender(&tx.expected_sender.to_string());

let _ = session.stx_transfer(tx.mstx_amount, &tx.recipient.to_string());

session.set_tx_sender(default_tx_sender);
session.set_tx_sender(&default_tx_sender);
}

fn handle_emulated_contract_publish(
Expand All @@ -201,7 +201,7 @@ fn handle_emulated_contract_publish(
code_coverage_enabled: bool,
) -> Result<ExecutionResult, Vec<Diagnostic>> {
let default_tx_sender = session.get_tx_sender();
session.set_tx_sender(tx.emulated_sender.to_string());
session.set_tx_sender(&tx.emulated_sender.to_string());

let contract = ClarityContract {
code_source: ClarityCodeSource::ContractInMemory(tx.source.clone()),
Expand All @@ -217,7 +217,7 @@ fn handle_emulated_contract_publish(
};
let result = session.deploy_contract(&contract, None, false, test_name, contract_ast);

session.set_tx_sender(default_tx_sender);
session.set_tx_sender(&default_tx_sender);
result
}

Expand All @@ -236,7 +236,7 @@ fn handle_emulated_contract_call(
tx: &EmulatedContractCallSpecification,
) -> Result<ExecutionResult, Vec<Diagnostic>> {
let default_tx_sender = session.get_tx_sender();
session.set_tx_sender(tx.emulated_sender.to_string());
session.set_tx_sender(&tx.emulated_sender.to_string());

let params: Vec<SymbolicExpression> = tx
.parameters
Expand All @@ -257,7 +257,7 @@ fn handle_emulated_contract_call(
println!("error: {:?}", errors.first().unwrap().message);
}

session.set_tx_sender(default_tx_sender);
session.set_tx_sender(&default_tx_sender);
result
}

Expand Down
2 changes: 1 addition & 1 deletion components/clarinet-files/src/wasm_fs_accessor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use js_sys::{Function as JsFunction, Promise};
use serde::{Deserialize, Serialize};
use serde_wasm_bindgen::{from_value as decode_from_js, to_value as encode_to_js};
use std::collections::HashMap;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsValue;
use wasm_bindgen_futures::JsFuture;

#[derive(Serialize, Deserialize)]
Expand Down
2 changes: 2 additions & 0 deletions components/clarinet-sdk-wasm/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
pkg
pkg-browser
pkg-node
15 changes: 14 additions & 1 deletion components/clarinet-sdk-wasm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[package]
name = "clarinet-sdk-wasm"
version.workspace = true
# version.workspace = true
version = "2.8.0-beta1"
edition = "2021"
license = "GPL-3.0"
repository = "https://github.com/hirosystems/clarinet"
Expand Down Expand Up @@ -74,3 +75,15 @@ wasm-opt = ['-Oz']
debug-js-glue = false
demangle-name-section = true
dwarf-debug-info = false

# profiling
[profile.profiling]
debug = 1

[package.metadata.wasm-pack.profile.profiling]
wasm-opt = ['-g', '-O']

[package.metadata.wasm-pack.profile.profiling.wasm-bindgen]
debug-js-glue = false
demangle-name-section = true
dwarf-debug-info = false
43 changes: 39 additions & 4 deletions components/clarinet-sdk-wasm/README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,50 @@
# Clarity SDK WASM

This package is built with wasm-pack.
It powers [@hirosystems/clarinet-sdk](https://www.npmjs.com/package/@hirosystems/clarinet-sdk).

This component exposes Clarinet features to a JS interface through wasm-bindgen.
It's built with wasm-pack.
It powers [@hirosystems/clarinet-sdk](https://npmjs.com/package/@hirosystems/clarinet-sdk) and
[@hirosystems/clarinet-sdk-browser](https://npmjs.com/package/@hirosystems/clarinet-sdk-browser).

## Contributing

### Build package

Install [wasm-pack](https://rustwasm.github.io/wasm-pack/installer/).

In the root directory of Clarinet, run the following command to build the packages for Node.js and the browser.
Under the hood, it will run `wasm-pack build` twice, once for each target.

```sh
npm run build:wasm
```

Alternatively, it's also possible to build the packages separately. It should only be done for development purpose.

**Build for node**

```sh
wasm-pack build --release --scope hirosystems --out-dir pkg-node --target nodejs
```

**Build for the browser**

```sh
wasm-pack build --release --scope hirosystems --out-dir pkg-browser --target web
```

### Release

The package is built twice with `wasm-pack` as it can't target `node` and `web` at the same time.
The following script will build for both target, it will also rename the package name for the
browser build.

```sh
npm run build:wasm
```

Once built, the packages can be released by running the following command. Note that by default we
release with the beta tag.

```sh
wasm-pack build --release --target=nodejs --scope hirosystems
npm run publish:sdk-wasm
```
115 changes: 115 additions & 0 deletions components/clarinet-sdk-wasm/build.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#!/usr/bin/node

import { spawn } from "node:child_process";
import fs from "node:fs/promises";
import path from "node:path";

// directory of the current file
const rootDir = new URL(".", import.meta.url).pathname;

/**
* build
*/
async function build() {
console.log("Deleting pkg-node");
await rmIfExists(path.join(rootDir, "pkg-node"));
console.log("Deleting pkg-browser");
await rmIfExists(path.join(rootDir, "pkg-browser"));

await Promise.all([
execCommand("wasm-pack", [
"build",
"--release",
"--scope",
"hirosystems",
"--out-dir",
"pkg-node",
"--target",
"nodejs",
]),
execCommand("wasm-pack", [
"build",
"--release",
"--scope",
"hirosystems",
"--out-dir",
"pkg-browser",
"--target",
"web",
]),
]);

await updatePackageName();
}

/**
* execCommand
* @param {string} command
* @param {string[]} args
* @returns
*/
export const execCommand = async (command, args) => {
console.log(`Building ${args[5]}`);
return new Promise((resolve, reject) => {
const childProcess = spawn(command, args, {
cwd: rootDir,
});
childProcess.stdout.on("data", (data) => {
process.stdout.write(data.toString());
});
childProcess.stderr.on("data", (data) => {
process.stderr.write(data.toString());
});
childProcess.on("error", (error) => {
reject(error);
});
childProcess.on("exit", (code) => {
if (code === 0) {
resolve();
} else {
reject(new Error(`❌ Command exited with code ${code}.`));
}
});
});
};

/**
* rmIfExists
* @param {string} dirPath
*/
async function rmIfExists(dirPath) {
try {
await fs.rm(dirPath, { recursive: true, force: true });
} catch (error) {
if (error.code !== "ENOENT") {
throw error;
}
}
}

/**
* updatePackageName
*/
async function updatePackageName() {
const filePath = path.join(rootDir, "pkg-browser/package.json");

const fileData = await fs.readFile(filePath, "utf-8");
const updatedData = fileData.replace(
'"name": "@hirosystems/clarinet-sdk-wasm"',
'"name": "@hirosystems/clarinet-sdk-wasm-browser"',
);
await fs.writeFile(filePath, updatedData, "utf-8");
console.log("✅ Package name updated successfully.");
}

try {
await build();
console.log("\n✅ Project successfully built.\n🚀 Ready to publish.");
console.log("Run the following commands to publish");
console.log("\n```");
console.log("$ npm run publish:sdk-wasm");
console.log("```\n");
} catch (error) {
console.error("❌ Error building:", error);
throw error;
}
Loading

0 comments on commit 1982441

Please sign in to comment.