diff --git a/.github/actions/setup-canister-toolchain/action.yml b/.github/actions/setup-canister-toolchain/action.yml new file mode 100644 index 0000000..7c2d1b4 --- /dev/null +++ b/.github/actions/setup-canister-toolchain/action.yml @@ -0,0 +1,41 @@ +name: Setup Canister Toolchain +description: Install ICP CLI, Motoko toolchain, Rust wasm32 target, and configure caching + +inputs: + package-manager: + description: 'Package manager to use (pnpm or bun)' + required: true + +runs: + using: composite + steps: + - name: Install ICP CLI tools + shell: bash + run: ${{ inputs.package-manager }} add -g @icp-sdk/icp-cli @icp-sdk/ic-wasm + + - name: Cache Mops + uses: actions/cache@v4 + with: + path: | + ~/.cache/mops + ~/Library/Caches/mops + .mops + key: mops-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('mops.toml') }} + + - name: Setup Motoko toolchain + shell: bash + run: | + ${{ inputs.package-manager }} add -g ic-mops + mops install + + - name: Cache Cargo + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + target + key: cargo-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/Cargo.lock') }} + + - name: Add wasm32 Rust target + shell: bash + run: rustup target add wasm32-unknown-unknown diff --git a/.github/workflows/e2e-test-nodejs.yml b/.github/workflows/e2e-test-nodejs.yml index 735068d..125d1c1 100644 --- a/.github/workflows/e2e-test-nodejs.yml +++ b/.github/workflows/e2e-test-nodejs.yml @@ -31,10 +31,10 @@ jobs: - name: Setup PNPM uses: dfinity/ci-tools/actions/setup-pnpm@main - - name: Setup DFX - uses: dfinity/setup-dfx@main + - name: Setup Canister Toolchain + uses: ./.github/actions/setup-canister-toolchain with: - dfx-version: 'auto' + package-manager: pnpm - name: Build run: pnpm run build @@ -64,10 +64,10 @@ jobs: shell: bash run: bun i --frozen-lockfile - - name: Setup DFX - uses: dfinity/setup-dfx@main + - name: Setup Canister Toolchain + uses: ./.github/actions/setup-canister-toolchain with: - dfx-version: 'auto' + package-manager: bun - name: Build run: bun run build diff --git a/.gitignore b/.gitignore index 17c7ff5..7c3d8e7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ /.dfx/ +/.icp/cache/ +/.mops/ /node_modules/ /target/ diff --git a/bun.lock b/bun.lock index 5994225..cc17b1d 100644 --- a/bun.lock +++ b/bun.lock @@ -5,6 +5,7 @@ "": { "name": "pic-js", "devDependencies": { + "@icp-sdk/bindgen": "^0.2.1", "@icp-sdk/core": "^5.0.0", "@swc/core": "^1.15.3", "@swc/jest": "^0.2.39", @@ -237,6 +238,8 @@ "@gerrit0/mini-shiki": ["@gerrit0/mini-shiki@3.19.0", "", { "dependencies": { "@shikijs/engine-oniguruma": "^3.19.0", "@shikijs/langs": "^3.19.0", "@shikijs/themes": "^3.19.0", "@shikijs/types": "^3.19.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-ZSlWfLvr8Nl0T4iA3FF/8VH8HivYF82xQts2DY0tJxZd4wtXJ8AA0nmdW9lmO4hlrh3f9xNwEPtOgqETPqKwDA=="], + "@icp-sdk/bindgen": ["@icp-sdk/bindgen@0.2.1", "", { "dependencies": { "commander": "^14.0.2" }, "bin": { "icp-bindgen": "dist/esm/cli/icp-bindgen.js" } }, "sha512-/YXJcYdqb4Qi+c33NVU8BgY4O/ZVqOQy+eYH4fSu5asT5/eAQl5NNgsjMTkhbGknRbxm8N9/ZopzAf2GX0n5lg=="], + "@icp-sdk/core": ["@icp-sdk/core@5.0.0", "", { "dependencies": { "@dfinity/cbor": "^0.2.2", "@noble/curves": "^1.9.2", "@noble/hashes": "^1.8.0", "@scure/bip32": "^1.7.0", "@scure/bip39": "^1.6.0", "asn1js": "^3.0.5" } }, "sha512-t6iRbdylHG57MicWRpR1uMTFXRW7GCzec6KAg55CBwDHbHLQDKikQ252lmlcEa80DrKa3LPvMKYZEUYjEq5XUQ=="], "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], diff --git a/dfx.json b/dfx.json deleted file mode 100644 index 9ca6052..0000000 --- a/dfx.json +++ /dev/null @@ -1,130 +0,0 @@ -{ - "version": 1, - "dfx": "0.30.2", - "output_env_file": ".env", - "networks": { - "local": { - "bind": "127.0.0.1:8080", - "type": "ephemeral" - } - }, - "canisters": { - "test_canister": { - "type": "motoko", - "main": "packages/pic/tests/test-canister/main.mo", - "declarations": { - "bindings": ["js", "ts"], - "output": "packages/pic/tests/test-canister/declarations" - }, - "gzip": true, - "optimize": "cycles" - }, - "clock": { - "type": "motoko", - "main": "examples/clock/src/main.mo", - "declarations": { - "bindings": ["js", "ts"], - "output": "examples/clock/declarations" - }, - "gzip": true, - "optimize": "cycles" - }, - "counter": { - "type": "motoko", - "main": "examples/counter/src/main.mo", - "init_arg": "'(42)'", - "declarations": { - "bindings": ["js", "ts"], - "output": "examples/counter/declarations" - }, - "gzip": true, - "optimize": "cycles" - }, - "google_search": { - "type": "motoko", - "main": "examples/google_search/src/main.mo", - "declarations": { - "bindings": ["js", "ts"], - "output": "examples/google_search/declarations" - }, - "gzip": true, - "optimize": "cycles" - }, - "icp_features": { - "type": "rust", - "candid": "examples/icp_features/icp_features.did", - "package": "icp_features", - "declarations": { - "bindings": ["js", "ts"], - "output": "examples/icp_features/declarations" - }, - "gzip": true, - "optimize": "cycles" - }, - "multicanister": { - "type": "motoko", - "main": "examples/multicanister/src/main.mo", - "dependencies": ["phonebook", "superheroes"], - "declarations": { - "bindings": ["js", "ts"], - "output": "examples/multicanister/declarations/multicanister" - }, - "gzip": true, - "optimize": "cycles" - }, - "nns_proxy": { - "type": "rust", - "candid": "examples/nns_proxy/nns_proxy.did", - "package": "nns_proxy", - "declarations": { - "bindings": ["js", "ts"], - "output": "examples/nns_proxy/declarations" - }, - "gzip": true, - "optimize": "cycles" - }, - "todo": { - "type": "rust", - "candid": "examples/todo/todo.did", - "package": "todo", - "declarations": { - "bindings": ["js", "ts"], - "output": "examples/todo/declarations" - }, - "gzip": true, - "optimize": "cycles" - }, - "phonebook": { - "type": "motoko", - "main": "examples/multicanister/src/phonebook.mo", - "declarations": { - "bindings": ["mo"], - "output": "examples/multicanister/declarations/phonebook" - }, - "gzip": true, - "optimize": "cycles" - }, - "superheroes": { - "type": "motoko", - "main": "examples/multicanister/src/superheroes.mo", - "declarations": { - "bindings": ["mo"], - "output": "examples/multicanister/declarations/superheroes" - }, - "gzip": true, - "optimize": "cycles" - }, - "http": { - "type": "rust", - "candid": "examples/http/http.did", - "package": "http-canister", - "frontend": {}, - "declarations": { - "bindings": ["js", "ts"], - "output": "examples/http/declarations" - }, - "gzip": true, - "optimize": "cycles" - } - } -} diff --git a/examples/README.md b/examples/README.md index 90fdd4b..5a1215c 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,6 +1,6 @@ # Examples -All examples are written in [TypeScript](https://www.typescriptlang.org/) with [Jest](https://jestjs.io/) as the test runner, +All examples are written in [TypeScript](https://www.typescriptlang.org/) with [Jest](https://jestjs.io/) or [Vitest](https://vitest.dev/) as the test runner, but `@dfinity/pic` can be used with JavaScript and any other testing runner, such as [NodeJS](https://nodejs.org/dist/latest-v20.x/docs/api/test.html), [bun](https://bun.sh/docs/cli/test) or [Mocha](https://mochajs.org/). ## Setup @@ -13,6 +13,27 @@ but `@dfinity/pic` can be used with JavaScript and any other testing runner, suc bun i ``` +- Build all examples: + + ```bash + bun build:examples + ``` + +- Test all examples: + + ```bash + bun test:examples + ``` + +- Build or test a single example: + + ```bash + bun build:examples -- counter + bun test:examples -- counter + ``` + +## Examples + - [Counter](./counter/README.md) This example demonstrates how to work with a simple canister as well as init arguments, canister upgrades and WASM reinstallation. - [Clock](./clock/README.md) @@ -21,6 +42,8 @@ but `@dfinity/pic` can be used with JavaScript and any other testing runner, suc This example demonstrates how to work with more complex canisters, identities, canister upgrades, and stable memory management. It also shows how to use "live" mode with agent-js (in contrast to the pic-js actor). - [Multicanister](./multicanister/README.md) This example demonstrates how to work with multiple canisters and multiple subnets. +- [ICP Features](./icp_features/README.md) + This example demonstrates how to enable ICP features when creating a PocketIC instance. - [NNS Proxy](./nns_proxy/README.md) This example demonstrates how to work with an NNS state directory. - [Google Search](./google_search/README.md) diff --git a/examples/clock/README.md b/examples/clock/README.md index 8165d74..d3f5382 100644 --- a/examples/clock/README.md +++ b/examples/clock/README.md @@ -2,14 +2,14 @@ This example demonstrates how to work with the replica's system time, canister timers as well as checking for canister existence and cycle management. -Build the counter canister: +Build the canister: ```shell -bun build:clock +bun build:examples -- clock ``` -Run the counter tests: +Run the tests: ```shell -bun test:clock +bun test:examples -- clock ``` diff --git a/examples/clock/canister.yaml b/examples/clock/canister.yaml new file mode 100644 index 0000000..0fd245d --- /dev/null +++ b/examples/clock/canister.yaml @@ -0,0 +1,7 @@ +name: clock +recipe: + type: '@dfinity/motoko@v4.1.0' + configuration: + main: src/main.mo + candid: clock.did + compress: true diff --git a/examples/clock/clock.did b/examples/clock/clock.did new file mode 100644 index 0000000..a0bdb94 --- /dev/null +++ b/examples/clock/clock.did @@ -0,0 +1,3 @@ +service : { + get : () -> (int) query; +} diff --git a/examples/clock/src/main.mo b/examples/clock/src/main.mo index 76c04cb..4a42cd8 100644 --- a/examples/clock/src/main.mo +++ b/examples/clock/src/main.mo @@ -1,5 +1,5 @@ -import Time "mo:base/Time"; -import { setTimer; recurringTimer } = "mo:base/Timer"; +import Time "mo:core/Time"; +import { setTimer; recurringTimer } = "mo:core/Timer"; persistent actor Clock { private type Time = Time.Time; diff --git a/examples/clock/tests/src/clock.spec.ts b/examples/clock/tests/src/clock.spec.ts index 90188be..66e3f47 100644 --- a/examples/clock/tests/src/clock.spec.ts +++ b/examples/clock/tests/src/clock.spec.ts @@ -11,11 +11,10 @@ const WASM_PATH = resolve( '..', '..', '..', - '.dfx', - 'local', - 'canisters', + '.icp', + 'cache', + 'artifacts', 'clock', - 'clock.wasm.gz', ); describe('Clock', () => { diff --git a/examples/counter/README.md b/examples/counter/README.md index a669c7d..e02bb10 100644 --- a/examples/counter/README.md +++ b/examples/counter/README.md @@ -2,14 +2,14 @@ This example demonstrates how to work with a simple canister as well as init arguments, canister upgrades and WASM reinstallation. -Build the counter canister: +Build the canister: ```shell -bun build:counter +bun build:examples -- counter ``` -Run the counter tests: +Run the tests: ```shell -bun test:counter +bun test:examples -- counter ``` diff --git a/examples/counter/canister.yaml b/examples/counter/canister.yaml new file mode 100644 index 0000000..71ba8c9 --- /dev/null +++ b/examples/counter/canister.yaml @@ -0,0 +1,7 @@ +name: counter +recipe: + type: '@dfinity/motoko@v4.1.0' + configuration: + main: src/main.mo + candid: counter.did + compress: true diff --git a/examples/counter/counter.did b/examples/counter/counter.did new file mode 100644 index 0000000..5080bce --- /dev/null +++ b/examples/counter/counter.did @@ -0,0 +1,6 @@ +service : (nat) -> { + get : () -> (nat) query; + set : (nat) -> (); + inc : () -> (); + dec : () -> (); +} diff --git a/examples/counter/src/main.mo b/examples/counter/src/main.mo index 0fc76c3..fd5f672 100644 --- a/examples/counter/src/main.mo +++ b/examples/counter/src/main.mo @@ -1,4 +1,4 @@ -import Nat "mo:base/Nat"; +import Nat "mo:core/Nat"; persistent actor class Counter(initial_count : Nat) { private var counter = initial_count; diff --git a/examples/counter/tests/src/counter.spec.ts b/examples/counter/tests/src/counter.spec.ts index a90ad4f..83ec0a1 100644 --- a/examples/counter/tests/src/counter.spec.ts +++ b/examples/counter/tests/src/counter.spec.ts @@ -12,11 +12,10 @@ const WASM_PATH = resolve( '..', '..', '..', - '.dfx', - 'local', - 'canisters', + '.icp', + 'cache', + 'artifacts', 'counter', - 'counter.wasm.gz', ); describe('Counter', () => { diff --git a/examples/google_search/README.md b/examples/google_search/README.md index c1c264e..292dce1 100644 --- a/examples/google_search/README.md +++ b/examples/google_search/README.md @@ -1,15 +1,15 @@ -# Multi canister +# Google Search -This example demonstrates how to test HTTPS Outcalls in canisters. +This example demonstrates how to mock HTTPS Outcalls in canisters. -Build the canisters: +Build the canister: ```shell -bun build:google_search +bun build:examples -- google_search ``` Run the tests: ```shell -bun test:google_search +bun test:examples -- google_search ``` diff --git a/examples/google_search/canister.yaml b/examples/google_search/canister.yaml new file mode 100644 index 0000000..f47f9d1 --- /dev/null +++ b/examples/google_search/canister.yaml @@ -0,0 +1,7 @@ +name: google_search +recipe: + type: '@dfinity/motoko@v4.1.0' + configuration: + main: src/main.mo + candid: google_search.did + compress: true diff --git a/examples/google_search/google_search.did b/examples/google_search/google_search.did new file mode 100644 index 0000000..299bd88 --- /dev/null +++ b/examples/google_search/google_search.did @@ -0,0 +1,20 @@ +type HttpHeader = record { + name : text; + value : text; +}; + +type CanisterHttpResponsePayload = record { + status : nat; + headers : vec HttpHeader; + body : vec nat8; +}; + +type TransformArgs = record { + response : CanisterHttpResponsePayload; + context : blob; +}; + +service : { + google_search : () -> (text); + transform : (TransformArgs) -> (CanisterHttpResponsePayload) query; +} diff --git a/examples/google_search/src/main.mo b/examples/google_search/src/main.mo index c4b0a9f..6ca29f7 100644 --- a/examples/google_search/src/main.mo +++ b/examples/google_search/src/main.mo @@ -1,5 +1,5 @@ -import Blob "mo:base/Blob"; -import Text "mo:base/Text"; +import Blob "mo:core/Blob"; +import Text "mo:core/Text"; import Types "types"; persistent actor { diff --git a/examples/google_search/tests/src/google-search.spec.ts b/examples/google_search/tests/src/google-search.spec.ts index f35e117..0cd2fa4 100644 --- a/examples/google_search/tests/src/google-search.spec.ts +++ b/examples/google_search/tests/src/google-search.spec.ts @@ -10,11 +10,10 @@ const WASM_PATH = resolve( '..', '..', '..', - '.dfx', - 'local', - 'canisters', + '.icp', + 'cache', + 'artifacts', 'google_search', - 'google_search.wasm.gz', ); describe('GoogleSearch', () => { diff --git a/examples/http/README.md b/examples/http/README.md index be2a298..3d16158 100644 --- a/examples/http/README.md +++ b/examples/http/README.md @@ -2,14 +2,14 @@ This example demonstrates how to use "live" mode with an HTTP canister. -Build the HTTP canister: +Build the canister: ```shell -bun build:http +bun build:examples -- http ``` -Run the HTTP tests: +Run the tests: ```shell -bun test:http +bun test:examples -- http ``` diff --git a/examples/http/canister.yaml b/examples/http/canister.yaml new file mode 100644 index 0000000..d7c07c4 --- /dev/null +++ b/examples/http/canister.yaml @@ -0,0 +1,7 @@ +name: http +recipe: + type: '@dfinity/rust@v3.2.0' + configuration: + package: http-canister + candid: http.did + compress: true diff --git a/examples/http/tests/src/http.spec.ts b/examples/http/tests/src/http.spec.ts index 2bd9de2..84136c3 100644 --- a/examples/http/tests/src/http.spec.ts +++ b/examples/http/tests/src/http.spec.ts @@ -9,11 +9,10 @@ const WASM_PATH = resolve( '..', '..', '..', - '.dfx', - 'local', - 'canisters', + '.icp', + 'cache', + 'artifacts', 'http', - 'http.wasm.gz', ); describe('HTTP', () => { diff --git a/examples/icp_features/README.md b/examples/icp_features/README.md index b45626d..72358b8 100644 --- a/examples/icp_features/README.md +++ b/examples/icp_features/README.md @@ -1,3 +1,15 @@ # ICP Features This example demonstrates how to enable ICP features when creating a PocketIC instance. + +Build the canister: + +```shell +bun build:examples -- icp_features +``` + +Run the tests: + +```shell +bun test:examples -- icp_features +``` diff --git a/examples/icp_features/canister.yaml b/examples/icp_features/canister.yaml new file mode 100644 index 0000000..5451229 --- /dev/null +++ b/examples/icp_features/canister.yaml @@ -0,0 +1,7 @@ +name: icp_features +recipe: + type: '@dfinity/rust@v3.2.0' + configuration: + package: icp_features + candid: icp_features.did + compress: true diff --git a/examples/icp_features/tests/src/icp-features.spec.ts b/examples/icp_features/tests/src/icp-features.spec.ts index dd70792..1f98de8 100644 --- a/examples/icp_features/tests/src/icp-features.spec.ts +++ b/examples/icp_features/tests/src/icp-features.spec.ts @@ -9,11 +9,10 @@ const WASM_PATH = resolve( '..', '..', '..', - '.dfx', - 'local', - 'canisters', + '.icp', + 'cache', + 'artifacts', 'icp_features', - 'icp_features.wasm.gz', ); const E8S_PER_ICP = 100_000_000; diff --git a/examples/multicanister/README.md b/examples/multicanister/README.md index c9a5bf4..b922b7d 100644 --- a/examples/multicanister/README.md +++ b/examples/multicanister/README.md @@ -1,15 +1,23 @@ -# Multi canister +# Multicanister -This example demonstrates how to work with multiple canisters. It shows how to create and deploy three canisters, two on the same subnet and a third on a different subnet, using init args to inform the main canister of the other canisters' IDs. +This example demonstrates inter-canister calls across multiple subnets. It deploys three canisters across two application subnets: -Build the canisters: +| Canister | Subnet | Description | +| ----------------- | ------ | -------------------------------------------------------- | +| **phonebook** | A | A simple contact storage canister | +| **multicanister** | A | Calls phonebook and superheroes via inter-canister calls | +| **superheroes** | B | A superhero registry canister | + +The multicanister canister receives the other canisters' IDs as init args, demonstrating cross-subnet inter-canister communication. + +Build all three canisters: ```shell -bun build:multicanister +bun build:examples -- phonebook superheroes multicanister ``` Run the tests: ```shell -bun test:multicanister +bun test:examples -- multicanister ``` diff --git a/examples/multicanister/canister.yaml b/examples/multicanister/canister.yaml new file mode 100644 index 0000000..11bdc59 --- /dev/null +++ b/examples/multicanister/canister.yaml @@ -0,0 +1,7 @@ +name: multicanister +recipe: + type: '@dfinity/motoko@v4.1.0' + configuration: + main: src/main.mo + candid: multicanister.did + compress: true diff --git a/examples/multicanister/interfaces/phonebook.mo b/examples/multicanister/interfaces/phonebook.mo new file mode 100644 index 0000000..c92ad90 --- /dev/null +++ b/examples/multicanister/interfaces/phonebook.mo @@ -0,0 +1,13 @@ +module { + public type ContactName = Text; + public type PhoneNumber = Text; + public type PhoneBookEntry = { + phone : PhoneNumber; + description : Text; + }; + + public type Self = actor { + insert : shared (ContactName, PhoneBookEntry) -> async (); + lookup : shared query (ContactName) -> async ?PhoneBookEntry; + }; +} diff --git a/examples/multicanister/interfaces/superheroes.mo b/examples/multicanister/interfaces/superheroes.mo new file mode 100644 index 0000000..ec92c90 --- /dev/null +++ b/examples/multicanister/interfaces/superheroes.mo @@ -0,0 +1,12 @@ +module { + public type SuperHeroId = Nat32; + public type SuperHero = { + name : Text; + superpowers : [Text]; + }; + + public type Self = actor { + insert : shared (SuperHero) -> async SuperHeroId; + lookup : shared query (SuperHeroId) -> async ?SuperHero; + }; +} diff --git a/examples/multicanister/multicanister.did b/examples/multicanister/multicanister.did new file mode 100644 index 0000000..70c6b38 --- /dev/null +++ b/examples/multicanister/multicanister.did @@ -0,0 +1,26 @@ +type PhoneBookEntry = record { + phone : text; + description : text; +}; + +type SuperHero = record { + name : text; + superpowers : vec text; +}; + +type PhoneBookService = service { + insert : (text, PhoneBookEntry) -> (); + lookup : (text) -> (opt PhoneBookEntry) query; +}; + +type SuperHeroesService = service { + insert : (SuperHero) -> (nat32); + lookup : (nat32) -> (opt SuperHero) query; +}; + +service : (PhoneBookService, SuperHeroesService) -> { + insert_phone_book_entry : (text, PhoneBookEntry) -> (); + lookup_phone_book_entry : (text) -> (opt PhoneBookEntry) composite_query; + insert_super_hero : (SuperHero) -> (nat32); + lookup_super_hero : (nat32) -> (opt SuperHero); +} diff --git a/examples/multicanister/phonebook/canister.yaml b/examples/multicanister/phonebook/canister.yaml new file mode 100644 index 0000000..1fc0da9 --- /dev/null +++ b/examples/multicanister/phonebook/canister.yaml @@ -0,0 +1,7 @@ +name: phonebook +recipe: + type: '@dfinity/motoko@v4.1.0' + configuration: + main: phonebook.mo + candid: phonebook.did + compress: true diff --git a/examples/multicanister/phonebook/phonebook.did b/examples/multicanister/phonebook/phonebook.did new file mode 100644 index 0000000..ea659c9 --- /dev/null +++ b/examples/multicanister/phonebook/phonebook.did @@ -0,0 +1,9 @@ +type PhoneBookEntry = record { + phone : text; + description : text; +}; + +service : { + insert : (text, PhoneBookEntry) -> (); + lookup : (text) -> (opt PhoneBookEntry) query; +} diff --git a/examples/multicanister/src/phonebook.mo b/examples/multicanister/phonebook/phonebook.mo similarity index 62% rename from examples/multicanister/src/phonebook.mo rename to examples/multicanister/phonebook/phonebook.mo index 1c3c3ed..7f9f248 100644 --- a/examples/multicanister/src/phonebook.mo +++ b/examples/multicanister/phonebook/phonebook.mo @@ -1,5 +1,5 @@ -import Map "mo:base/HashMap"; -import Text "mo:base/Text"; +import Map "mo:core/Map"; +import Text "mo:core/Text"; persistent actor PhoneBook { public type ContactName = Text; @@ -9,13 +9,13 @@ persistent actor PhoneBook { description : Text; }; - transient let phonebook = Map.HashMap(0, Text.equal, Text.hash); + let phonebook = Map.empty(); public func insert(name : ContactName, entry : PhoneBookEntry) : async () { - phonebook.put(name, entry); + Map.add(phonebook, Text.compare, name, entry); }; public query func lookup(name : ContactName) : async ?PhoneBookEntry { - phonebook.get(name); + Map.get(phonebook, Text.compare, name); }; }; diff --git a/examples/multicanister/src/main.mo b/examples/multicanister/src/main.mo index 89ae481..20e6fff 100644 --- a/examples/multicanister/src/main.mo +++ b/examples/multicanister/src/main.mo @@ -1,5 +1,5 @@ -import PhoneBook "../declarations/phonebook/phonebook"; -import SuperHeroes "../declarations/superheroes/superheroes"; +import PhoneBook "../interfaces/phonebook"; +import SuperHeroes "../interfaces/superheroes"; persistent actor class KeyValue(phonebook : PhoneBook.Self, superheroes : SuperHeroes.Self) { public func insert_phone_book_entry(name : Text, entry : PhoneBook.PhoneBookEntry) : async () { diff --git a/examples/multicanister/src/superheroes.mo b/examples/multicanister/src/superheroes.mo deleted file mode 100644 index 7119c82..0000000 --- a/examples/multicanister/src/superheroes.mo +++ /dev/null @@ -1,36 +0,0 @@ -import List "mo:base/List"; -import Trie "mo:base/Trie"; -import Nat32 "mo:base/Nat32"; - -persistent actor SuperHeroes { - public type SuperHeroId = Nat32; - public type SuperHero = { - name : Text; - superpowers : List.List; - }; - - private var next : SuperHeroId = 0; - private var superheroes : Trie.Trie = Trie.empty(); - - public func insert(superhero : SuperHero) : async SuperHeroId { - let superheroId = next; - next += 1; - - superheroes := Trie.replace( - superheroes, - key(superheroId), - Nat32.equal, - ?superhero, - ).0; - - return superheroId; - }; - - public query func lookup(superheroId : SuperHeroId) : async ?SuperHero { - return Trie.find(superheroes, key(superheroId), Nat32.equal); - }; - - private func key(x : SuperHeroId) : Trie.Key { - return { hash = x; key = x }; - }; -}; diff --git a/examples/multicanister/superheroes/canister.yaml b/examples/multicanister/superheroes/canister.yaml new file mode 100644 index 0000000..f239707 --- /dev/null +++ b/examples/multicanister/superheroes/canister.yaml @@ -0,0 +1,7 @@ +name: superheroes +recipe: + type: '@dfinity/motoko@v4.1.0' + configuration: + main: superheroes.mo + candid: superheroes.did + compress: true diff --git a/examples/multicanister/superheroes/superheroes.did b/examples/multicanister/superheroes/superheroes.did new file mode 100644 index 0000000..1781279 --- /dev/null +++ b/examples/multicanister/superheroes/superheroes.did @@ -0,0 +1,9 @@ +type SuperHero = record { + name : text; + superpowers : vec text; +}; + +service : { + insert : (SuperHero) -> (nat32); + lookup : (nat32) -> (opt SuperHero) query; +} diff --git a/examples/multicanister/superheroes/superheroes.mo b/examples/multicanister/superheroes/superheroes.mo new file mode 100644 index 0000000..773c001 --- /dev/null +++ b/examples/multicanister/superheroes/superheroes.mo @@ -0,0 +1,26 @@ +import Map "mo:core/Map"; +import Nat32 "mo:core/Nat32"; + +persistent actor SuperHeroes { + public type SuperHeroId = Nat32; + public type SuperHero = { + name : Text; + superpowers : [Text]; + }; + + private var next : SuperHeroId = 0; + let superheroes = Map.empty(); + + public func insert(superhero : SuperHero) : async SuperHeroId { + let superheroId = next; + next += 1; + + Map.add(superheroes, Nat32.compare, superheroId, superhero); + + return superheroId; + }; + + public query func lookup(superheroId : SuperHeroId) : async ?SuperHero { + return Map.get(superheroes, Nat32.compare, superheroId); + }; +}; diff --git a/examples/multicanister/tests/src/multicanister.spec.ts b/examples/multicanister/tests/src/multicanister.spec.ts index 6cd28a7..3ba2093 100644 --- a/examples/multicanister/tests/src/multicanister.spec.ts +++ b/examples/multicanister/tests/src/multicanister.spec.ts @@ -8,7 +8,7 @@ import { _SERVICE, idlFactory, init, -} from '../../declarations/multicanister/multicanister.did'; +} from '../../declarations/multicanister.did'; const MAIN_WASM_PATH = resolve( __dirname, @@ -16,11 +16,10 @@ const MAIN_WASM_PATH = resolve( '..', '..', '..', - '.dfx', - 'local', - 'canisters', + '.icp', + 'cache', + 'artifacts', 'multicanister', - 'multicanister.wasm.gz', ); const PHONEBOOK_WASM_PATH = resolve( @@ -29,11 +28,10 @@ const PHONEBOOK_WASM_PATH = resolve( '..', '..', '..', - '.dfx', - 'local', - 'canisters', + '.icp', + 'cache', + 'artifacts', 'phonebook', - 'phonebook.wasm.gz', ); const SUPERHEROES_WASM_PATH = resolve( @@ -42,11 +40,10 @@ const SUPERHEROES_WASM_PATH = resolve( '..', '..', '..', - '.dfx', - 'local', - 'canisters', + '.icp', + 'cache', + 'artifacts', 'superheroes', - 'superheroes.wasm.gz', ); describe('Multicanister', () => { @@ -116,7 +113,7 @@ describe('Multicanister', () => { const name = 'Superman'; const superHero: SuperHero = { name, - superpowers: [['flight', [['super strength', [['heat vision', []]]]]]], + superpowers: ['flight', 'super strength', 'heat vision'], }; const id = await actor.insert_super_hero(superHero); diff --git a/examples/nns_proxy/README.md b/examples/nns_proxy/README.md index 0e99f45..71dc5d3 100644 --- a/examples/nns_proxy/README.md +++ b/examples/nns_proxy/README.md @@ -1,5 +1,17 @@ # NNS Proxy +Build the canister: + +```shell +bun build:examples -- nns_proxy +``` + +Run the tests: + +```shell +bun test:examples -- nns_proxy +``` + ## NNS State Directory This example project leverages an NNS state directory to provide the initial state for the NNS subnet. To learn more about how this state directory was created, check out the guide on [working with the NNS](https://js.icp.build/pic-js/latest/guides/working-with-the-nns). diff --git a/examples/nns_proxy/canister.yaml b/examples/nns_proxy/canister.yaml new file mode 100644 index 0000000..ddedc37 --- /dev/null +++ b/examples/nns_proxy/canister.yaml @@ -0,0 +1,7 @@ +name: nns_proxy +recipe: + type: '@dfinity/rust@v3.2.0' + configuration: + package: nns_proxy + candid: nns_proxy.did + compress: true diff --git a/examples/nns_proxy/tests/src/nns-proxy.spec.ts b/examples/nns_proxy/tests/src/nns-proxy.spec.ts index eb0a91c..0de5afc 100644 --- a/examples/nns_proxy/tests/src/nns-proxy.spec.ts +++ b/examples/nns_proxy/tests/src/nns-proxy.spec.ts @@ -15,11 +15,10 @@ const WASM_PATH = resolve( '..', '..', '..', - '.dfx', - 'local', - 'canisters', + '.icp', + 'cache', + 'artifacts', 'nns_proxy', - 'nns_proxy.wasm.gz', ); const NNS_STATE_PATH = resolve(__dirname, '..', 'state', 'nns_state'); diff --git a/examples/todo/README.md b/examples/todo/README.md index dfacfb3..ba4c541 100644 --- a/examples/todo/README.md +++ b/examples/todo/README.md @@ -2,14 +2,14 @@ This example demonstrates how to work with more complex canisters, identities, canister upgrades, and stable memory management. It also shows how to use "live" mode with agent-js (in contrast to the pic-js actor). -Build the counter canister: +Build the canister: ```shell -bun build:todo +bun build:examples -- todo ``` -Run the counter tests: +Run the tests: ```shell -bun test:todo +bun test:examples -- todo ``` diff --git a/examples/todo/canister.yaml b/examples/todo/canister.yaml new file mode 100644 index 0000000..704d04b --- /dev/null +++ b/examples/todo/canister.yaml @@ -0,0 +1,7 @@ +name: todo +recipe: + type: '@dfinity/rust@v3.2.0' + configuration: + package: todo + candid: todo.did + compress: true diff --git a/examples/todo/tests/src/live-todo.spec.ts b/examples/todo/tests/src/live-todo.spec.ts index 899d2d5..1c730f6 100644 --- a/examples/todo/tests/src/live-todo.spec.ts +++ b/examples/todo/tests/src/live-todo.spec.ts @@ -9,11 +9,10 @@ const WASM_PATH = resolve( '..', '..', '..', - '.dfx', - 'local', - 'canisters', + '.icp', + 'cache', + 'artifacts', 'todo', - 'todo.wasm.gz', ); describe('Live Todo', () => { diff --git a/examples/todo/tests/src/todo.spec.ts b/examples/todo/tests/src/todo.spec.ts index e979cbb..622c37e 100644 --- a/examples/todo/tests/src/todo.spec.ts +++ b/examples/todo/tests/src/todo.spec.ts @@ -10,11 +10,10 @@ const WASM_PATH = resolve( '..', '..', '..', - '.dfx', - 'local', - 'canisters', + '.icp', + 'cache', + 'artifacts', 'todo', - 'todo.wasm.gz', ); describe('Todo', () => { diff --git a/icp.yaml b/icp.yaml new file mode 100644 index 0000000..6b46f66 --- /dev/null +++ b/icp.yaml @@ -0,0 +1,6 @@ +# yaml-language-server: $schema=https://github.com/dfinity/icp-cli/raw/refs/tags/v0.1.0/docs/schemas/icp-yaml-schema.json + +canisters: + - packages/pic/tests/test-canister + - examples/* + - examples/multicanister/* diff --git a/mops.toml b/mops.toml new file mode 100644 index 0000000..3df1706 --- /dev/null +++ b/mops.toml @@ -0,0 +1,5 @@ +[dependencies] +core = "2.0.0" + +[toolchain] +moc = "1.2.0" diff --git a/package.json b/package.json index 4e11533..a6ce038 100644 --- a/package.json +++ b/package.json @@ -27,28 +27,14 @@ "build": "run-p build:pic", "build:pic": "tsc -p ./packages/pic/tsconfig.json", "test:pic": "jest -c ./packages/pic/jest.config.ts", - "build:test-canister": "dfx generate test_canister && dfx build test_canister --check && mv .dfx/local/canisters/test_canister/test_canister.wasm.gz packages/pic/tests/test-canister", - "build:examples": "dfx generate phonebook && dfx generate superheroes && dfx generate && dfx build --all --check", - "test:examples": "run-p test:clock test:counter test:google-search test:icp-features test:multicanister test:nns-proxy test:todo test:http", - "build:clock": "dfx generate clock && dfx build clock --check", - "test:clock": "jest -c ./examples/clock/tests/jest.config.ts", - "build:counter": "dfx generate counter && dfx build counter --check", - "test:counter": "vitest run -c ./examples/counter/tests/vitest.config.ts", - "build:google-search": "dfx generate google_search && dfx build google_search --check", - "test:google-search": "jest -c ./examples/google_search/tests/jest.config.ts", - "build:icp-features": "dfx generate icp_features && dfx build icp_features --check", - "test:icp-features": "jest -c ./examples/icp_features/tests/jest.config.ts", - "build:multicanister": "dfx generate multicanister && dfx build multicanister --check", - "test:multicanister": "jest -c ./examples/multicanister/tests/jest.config.ts", - "build:nns-proxy": "dfx generate nns_proxy && dfx build nns_proxy --check", - "test:nns-proxy": "jest -c ./examples/nns_proxy/tests/jest.config.ts", - "build:todo": "dfx generate todo && dfx build todo --check", - "test:todo": "jest -c ./examples/todo/tests/jest.config.ts", - "build:http": "dfx generate http && dfx build http --check", - "test:http": "vitest run -c ./examples/http/tests/vitest.config.ts", + "build:test-canister": "icp build test_canister && cp .icp/cache/artifacts/test_canister packages/pic/tests/test-canister/test_canister.wasm.gz && pnpm run generate:test-canister", + "generate:test-canister": "icp-bindgen --did-file packages/pic/tests/test-canister/test_canister.did --out-dir packages/pic/tests/test-canister --actor-disabled --force", + "build:examples": "./scripts/build-examples.sh", + "test:examples": "./scripts/test-examples.sh", "postinstall": "tar -xvf examples/nns_proxy/tests/state/nns_state.tar.xz -C examples/nns_proxy/tests/state" }, "devDependencies": { + "@icp-sdk/bindgen": "^0.2.1", "@icp-sdk/core": "^5.0.0", "@swc/core": "^1.15.3", "@swc/jest": "^0.2.39", diff --git a/packages/pic/tests/test-canister/canister.yaml b/packages/pic/tests/test-canister/canister.yaml new file mode 100644 index 0000000..830fd17 --- /dev/null +++ b/packages/pic/tests/test-canister/canister.yaml @@ -0,0 +1,7 @@ +name: test_canister +recipe: + type: '@dfinity/motoko@v4.1.0' + configuration: + main: main.mo + candid: test_canister.did + compress: true diff --git a/packages/pic/tests/test-canister/declarations/index.d.ts b/packages/pic/tests/test-canister/declarations/index.d.ts deleted file mode 100644 index fd1b65a..0000000 --- a/packages/pic/tests/test-canister/declarations/index.d.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { - ActorSubclass, - HttpAgentOptions, - ActorConfig, - Agent, -} from "@dfinity/agent"; -import type { Principal } from "@dfinity/principal"; -import type { IDL } from "@dfinity/candid"; - -import { _SERVICE } from './test_canister.did'; - -export declare const idlFactory: IDL.InterfaceFactory; -export declare const canisterId: string; - -export declare interface CreateActorOptions { - /** - * @see {@link Agent} - */ - agent?: Agent; - /** - * @see {@link HttpAgentOptions} - */ - agentOptions?: HttpAgentOptions; - /** - * @see {@link ActorConfig} - */ - actorOptions?: ActorConfig; -} - -/** - * Intializes an {@link ActorSubclass}, configured with the provided SERVICE interface of a canister. - * @constructs {@link ActorSubClass} - * @param {string | Principal} canisterId - ID of the canister the {@link Actor} will talk to - * @param {CreateActorOptions} options - see {@link CreateActorOptions} - * @param {CreateActorOptions["agent"]} options.agent - a pre-configured agent you'd like to use. Supercedes agentOptions - * @param {CreateActorOptions["agentOptions"]} options.agentOptions - options to set up a new agent - * @see {@link HttpAgentOptions} - * @param {CreateActorOptions["actorOptions"]} options.actorOptions - options for the Actor - * @see {@link ActorConfig} - */ -export declare const createActor: ( - canisterId: string | Principal, - options?: CreateActorOptions -) => ActorSubclass<_SERVICE>; - -/** - * Intialized Actor using default settings, ready to talk to a canister using its candid interface - * @constructs {@link ActorSubClass} - */ -export declare const test_canister: ActorSubclass<_SERVICE>; diff --git a/packages/pic/tests/test-canister/declarations/index.js b/packages/pic/tests/test-canister/declarations/index.js deleted file mode 100644 index beab293..0000000 --- a/packages/pic/tests/test-canister/declarations/index.js +++ /dev/null @@ -1,42 +0,0 @@ -import { Actor, HttpAgent } from "@dfinity/agent"; - -// Imports and re-exports candid interface -import { idlFactory } from "./test_canister.did.js"; -export { idlFactory } from "./test_canister.did.js"; - -/* CANISTER_ID is replaced by webpack based on node environment - * Note: canister environment variable will be standardized as - * process.env.CANISTER_ID_ - * beginning in dfx 0.15.0 - */ -export const canisterId = - process.env.CANISTER_ID_TEST_CANISTER; - -export const createActor = (canisterId, options = {}) => { - const agent = options.agent || new HttpAgent({ ...options.agentOptions }); - - if (options.agent && options.agentOptions) { - console.warn( - "Detected both agent and agentOptions passed to createActor. Ignoring agentOptions and proceeding with the provided agent." - ); - } - - // Fetch root key for certificate validation during development - if (process.env.DFX_NETWORK !== "ic") { - agent.fetchRootKey().catch((err) => { - console.warn( - "Unable to fetch root key. Check to ensure that your local replica is running" - ); - console.error(err); - }); - } - - // Creates an actor with using the candid interface and the HttpAgent - return Actor.createActor(idlFactory, { - agent, - canisterId, - ...options.actorOptions, - }); -}; - -export const test_canister = canisterId ? createActor(canisterId) : undefined; diff --git a/packages/pic/tests/test-canister/declarations/test_canister.did.d.ts b/packages/pic/tests/test-canister/declarations/test_canister.did.d.ts index 2097688..ed3d861 100644 --- a/packages/pic/tests/test-canister/declarations/test_canister.did.d.ts +++ b/packages/pic/tests/test-canister/declarations/test_canister.did.d.ts @@ -1,8 +1,16 @@ -import type { Principal } from '@dfinity/principal'; -import type { ActorMethod } from '@dfinity/agent'; -import type { IDL } from '@dfinity/candid'; +/* eslint-disable */ + +// @ts-nocheck + +// This file was automatically generated by @icp-sdk/bindgen@0.2.1. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import type { ActorMethod } from '@icp-sdk/core/agent'; +import type { IDL } from '@icp-sdk/core/candid'; +import type { Principal } from '@icp-sdk/core/principal'; export type Time = bigint; export interface _SERVICE { 'get_time' : ActorMethod<[], Time> } export declare const idlFactory: IDL.InterfaceFactory; -export declare const init: (args: { IDL: typeof IDL }) => IDL.Type[]; +export declare const init: (args: { IDL: typeof IDL }) => IDL.Type[]; \ No newline at end of file diff --git a/packages/pic/tests/test-canister/declarations/test_canister.did.js b/packages/pic/tests/test-canister/declarations/test_canister.did.js index 11d120e..08229ee 100644 --- a/packages/pic/tests/test-canister/declarations/test_canister.did.js +++ b/packages/pic/tests/test-canister/declarations/test_canister.did.js @@ -1,5 +1,17 @@ +/* eslint-disable */ + +// @ts-nocheck + +// This file was automatically generated by @icp-sdk/bindgen@0.2.1. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import { IDL } from '@icp-sdk/core/candid'; + export const idlFactory = ({ IDL }) => { const Time = IDL.Int; + return IDL.Service({ 'get_time' : IDL.Func([], [Time], ['query']) }); }; -export const init = ({ IDL }) => { return []; }; + +export const init = ({ IDL }) => { return []; }; \ No newline at end of file diff --git a/packages/pic/tests/test-canister/main.mo b/packages/pic/tests/test-canister/main.mo index d081914..5fa458e 100644 --- a/packages/pic/tests/test-canister/main.mo +++ b/packages/pic/tests/test-canister/main.mo @@ -1,4 +1,4 @@ -import Time "mo:base/Time"; +import Time "mo:core/Time"; persistent actor TestCanister { public query func get_time() : async Time.Time { diff --git a/packages/pic/tests/test-canister/test_canister.did b/packages/pic/tests/test-canister/test_canister.did new file mode 100644 index 0000000..6cab63b --- /dev/null +++ b/packages/pic/tests/test-canister/test_canister.did @@ -0,0 +1,5 @@ +type Time = int; + +service : { + get_time : () -> (Time) query; +} diff --git a/packages/pic/tests/test-canister/test_canister.wasm.gz b/packages/pic/tests/test-canister/test_canister.wasm.gz index 0d397bd..a8fc2e6 100644 Binary files a/packages/pic/tests/test-canister/test_canister.wasm.gz and b/packages/pic/tests/test-canister/test_canister.wasm.gz differ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 74029e3..12fdf9b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,6 +13,9 @@ importers: .: devDependencies: + '@icp-sdk/bindgen': + specifier: ^0.2.1 + version: 0.2.1 '@icp-sdk/core': specifier: ^5.0.0 version: 5.0.0 @@ -488,6 +491,10 @@ packages: '@gerrit0/mini-shiki@3.12.2': resolution: {integrity: sha512-HKZPmO8OSSAAo20H2B3xgJdxZaLTwtlMwxg0967scnrDlPwe6j5+ULGHyIqwgTbFCn9yv/ff8CmfWZLE9YKBzA==} + '@icp-sdk/bindgen@0.2.1': + resolution: {integrity: sha512-/YXJcYdqb4Qi+c33NVU8BgY4O/ZVqOQy+eYH4fSu5asT5/eAQl5NNgsjMTkhbGknRbxm8N9/ZopzAf2GX0n5lg==} + hasBin: true + '@icp-sdk/core@5.0.0': resolution: {integrity: sha512-t6iRbdylHG57MicWRpR1uMTFXRW7GCzec6KAg55CBwDHbHLQDKikQ252lmlcEa80DrKa3LPvMKYZEUYjEq5XUQ==} @@ -1307,6 +1314,10 @@ packages: resolution: {integrity: sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A==} engines: {node: '>=20'} + commander@14.0.3: + resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} + engines: {node: '>=20'} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} @@ -1555,11 +1566,12 @@ packages: glob@10.5.0: resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me globalthis@1.0.4: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} @@ -3021,6 +3033,10 @@ snapshots: '@shikijs/types': 3.12.2 '@shikijs/vscode-textmate': 10.0.2 + '@icp-sdk/bindgen@0.2.1': + dependencies: + commander: 14.0.3 + '@icp-sdk/core@5.0.0': dependencies: '@dfinity/cbor': 0.2.2 @@ -3870,6 +3886,8 @@ snapshots: commander@14.0.1: {} + commander@14.0.3: {} + concat-map@0.0.1: {} convert-source-map@2.0.0: {} diff --git a/scripts/build-examples.sh b/scripts/build-examples.sh new file mode 100755 index 0000000..56ed642 --- /dev/null +++ b/scripts/build-examples.sh @@ -0,0 +1,32 @@ +#!/bin/bash +# Build canisters and generate TypeScript bindings for examples. +# Usage: ./scripts/build-examples.sh [name ...] +# If no names are provided, builds all canisters and generates all bindings. + +set -euo pipefail + +# Filter out "--" passed by pnpm when forwarding arguments +args=() +for arg in "$@"; do + [ "$arg" != "--" ] && args+=("$arg") +done + +ALL_EXAMPLES=(clock counter google_search http icp_features multicanister nns_proxy todo) + +if [ ${#args[@]} -eq 0 ]; then + icp build + examples=("${ALL_EXAMPLES[@]}") +else + icp build "${args[@]}" + examples=("${args[@]}") +fi + +for name in "${examples[@]}"; do + icp-bindgen \ + --did-file "examples/$name/$name.did" \ + --out-dir "examples/$name" \ + --actor-disabled \ + --force & +done + +wait diff --git a/scripts/test-examples.sh b/scripts/test-examples.sh new file mode 100755 index 0000000..b539ff8 --- /dev/null +++ b/scripts/test-examples.sh @@ -0,0 +1,32 @@ +#!/bin/bash +# Run tests for examples. +# Usage: ./scripts/test-examples.sh [name ...] +# If no names are provided, runs tests for all examples. + +set -euo pipefail + +# Filter out "--" passed by pnpm when forwarding arguments +args=() +for arg in "$@"; do + [ "$arg" != "--" ] && args+=("$arg") +done + +ALL_EXAMPLES=(clock counter google_search http icp_features multicanister nns_proxy todo) + +if [ ${#args[@]} -eq 0 ]; then + examples=("${ALL_EXAMPLES[@]}") +else + examples=("${args[@]}") +fi + +for name in "${examples[@]}"; do + dir="examples/$name/tests" + if [ -f "$dir/vitest.config.ts" ]; then + vitest run -c "./$dir/vitest.config.ts" + elif [ -f "$dir/jest.config.ts" ]; then + jest -c "./$dir/jest.config.ts" + else + echo "No test config found for $name" >&2 + exit 1 + fi +done