diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..33928abb3 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,30 @@ +{ + "name": "ICP Examples (Motoko + Rust)", + "image": "ghcr.io/dfinity/icp-dev-env-all:0.1.0", + "forwardPorts": [8000, 5173], + "portsAttributes": { + "8000": { + "label": "ICP", + "onAutoForward": "ignore" + }, + "5173": { + "label": "Vite", + "onAutoForward": "openBrowser" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "dfinity-foundation.vscode-motoko", + "rust-lang.rust-analyzer" + ], + "settings": { + "git.openRepositoryInParentFolders": "always", + "workbench.startupEditor": "none", + "workbench.editorAssociations": { + "*.md": "vscode.markdown.preview.editor" + } + } + } + } +} diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index ed0a23cf4..96cf519ac 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,7 +1,5 @@ # Contributing -> For ICP Ninja: check [NINJA_CONTRIBUTING.md](./../NINJA_CONTRIBUTING.md) for how to contribute a project to ICP Ninja. - Thank you for your interest in contributing to example apps for the Internet Computer. By participating in this project, you agree to abide by our [Code of Conduct](./CODE_OF_CONDUCT.md). @@ -116,4 +114,4 @@ To open a new issue: ### Submitting your own example -We're not accepting community examples at this time -- we have something better planned. +See [ADDING_AN_EXAMPLE.md](./../ADDING_AN_EXAMPLE.md) for guidelines on how to structure and submit a new example. diff --git a/.github/workflow-template.yml b/.github/workflow-template.yml new file mode 100644 index 000000000..e7b244c20 --- /dev/null +++ b/.github/workflow-template.yml @@ -0,0 +1,35 @@ +# Workflow template for ICP examples. +# Copy this file to .github/workflows/.yml and replace the placeholders. +# +# PLACEHOLDERS: +# e.g. hello_world +# motoko | rust +# ghcr.io/dfinity/icp-dev-env-motoko | ghcr.io/dfinity/icp-dev-env-rust + +name: + +on: + push: + branches: + - master + pull_request: + paths: + - //** + - .github/workflows/.yml + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + -: + runs-on: ubuntu-24.04 + container: + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - name: Deploy and test + working-directory: / + run: | + icp network start -d + icp deploy + make test diff --git a/.github/workflows/hello_world.yml b/.github/workflows/hello_world.yml new file mode 100644 index 000000000..b2988c222 --- /dev/null +++ b/.github/workflows/hello_world.yml @@ -0,0 +1,40 @@ +name: hello_world + +on: + push: + branches: + - master + pull_request: + paths: + - motoko/hello_world/** + - rust/hello_world/** + - .github/workflows/hello_world.yml + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + motoko-hello_world: + runs-on: ubuntu-24.04 + container: ghcr.io/dfinity/icp-dev-env-motoko:0.1.0 + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - name: Deploy and test + working-directory: motoko/hello_world + run: | + icp network start -d + icp deploy + make test + + rust-hello_world: + runs-on: ubuntu-24.04 + container: ghcr.io/dfinity/icp-dev-env-rust:0.1.0 + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - name: Deploy and test + working-directory: rust/hello_world + run: | + icp network start -d + icp deploy + make test diff --git a/.github/workflows/ninja_pr_checks.yml b/.github/workflows/ninja_pr_checks.yml index a5a39e7f7..b4bc032a7 100644 --- a/.github/workflows/ninja_pr_checks.yml +++ b/.github/workflows/ninja_pr_checks.yml @@ -4,6 +4,50 @@ on: pull_request: branches: - master + paths: + - 'hosting/**' + - 'motoko/backend_only/**' + - 'motoko/canister_logs/**' + - 'motoko/classes/**' + - 'motoko/basic_bitcoin/**' + - 'motoko/daily_planner/**' + - 'motoko/evm_block_explorer/**' + - 'motoko/filevault/**' + - 'motoko/flying_ninja/**' + - 'motoko/llm_chatbot/**' + - 'motoko/query_stats/**' + - 'motoko/send_http_get/**' + - 'motoko/send_http_post/**' + - 'motoko/superheroes/**' + - 'motoko/threshold-ecdsa/**' + - 'motoko/threshold-schnorr/**' + - 'rust/backend_only/**' + - 'rust/backend_wasm64/**' + - 'rust/basic_bitcoin/**' + - 'rust/canister-info/**' + - 'rust/canister_logs/**' + - 'rust/basic_ethereum/**' + - 'rust/candid_type_generation/**' + - 'rust/daily_planner/**' + - 'rust/evm_block_explorer/**' + - 'rust/flying_ninja/**' + - 'rust/guards/**' + - 'rust/llm_chatbot/**' + - 'rust/performance_counters/**' + - 'rust/periodic_tasks/**' + - 'rust/qrcode/**' + - 'rust/query_stats/**' + - 'rust/send_http_get/**' + - 'rust/send_http_post/**' + - 'rust/simd/**' + - 'rust/threshold-ecdsa/**' + - 'rust/unit_testable_rust_canister/**' + - 'rust/photo_gallery/**' + - 'rust/inter-canister-calls/**' + - 'rust/x509/**' + - 'rust/receiving-icp/**' + - 'rust/exchange-rates/**' + - '.github/workflows/ninja_pr_checks.yml' concurrency: group: ninja-pr-checks-${{ github.workflow }}-${{ github.ref }} @@ -41,7 +85,6 @@ jobs: ["EVM Block Explorer (Motoko)"]="motoko/evm_block_explorer" ["FileVault (Motoko)"]="motoko/filevault" ["Flying Ninja (Motoko)"]="motoko/flying_ninja" - ["Hello World (Motoko)"]="motoko/hello_world" ["LLM Chatbot (Motoko)"]="motoko/llm_chatbot" ["Query Stats (Motoko)"]="motoko/query_stats" ["Send HTTP Get (Motoko)"]="motoko/send_http_get" @@ -49,7 +92,6 @@ jobs: ["Superheroes (Motoko)"]="motoko/superheroes" ["Threshold ECDSA (Motoko)"]="motoko/threshold-ecdsa" ["Threshold Schnorr (Motoko)"]="motoko/threshold-schnorr" - ["Who Am I (Motoko)"]="motoko/who_am_i" ["Rust backend (Rust)"]="rust/backend_only" ["Rust backend Wasm64 (Rust)"]="rust/backend_wasm64" ["Basic Bitcoin (Rust)"]="rust/basic_bitcoin" @@ -61,7 +103,6 @@ jobs: ["EVM Block Explorer (Rust)"]="rust/evm_block_explorer" ["Flying Ninja (Rust)"]="rust/flying_ninja" ["Guards (Rust)"]="rust/guards" - ["Hello World (Rust)"]="rust/hello_world" ["LLM Chatbot (Rust)"]="rust/llm_chatbot" ["Performance Counters (Rust)"]="rust/performance_counters" ["Periodic Tasks (Rust)"]="rust/periodic_tasks" @@ -72,7 +113,6 @@ jobs: ["SIMD (Rust)"]="rust/simd" ["Threshold ECDSA (Rust)"]="rust/threshold-ecdsa" ["Unit Testable Canister (Rust)"]="rust/unit_testable_rust_canister" - ["Who Am I (Rust)"]="rust/who_am_i" ["Photo Gallery (Rust)"]="rust/photo_gallery" ["Inter-canister calls (Rust)"]="rust/inter-canister-calls" ["X.509 (Rust)"]="rust/x509" diff --git a/.github/workflows/who_am_i.yml b/.github/workflows/who_am_i.yml new file mode 100644 index 000000000..fbcfffe2e --- /dev/null +++ b/.github/workflows/who_am_i.yml @@ -0,0 +1,40 @@ +name: who_am_i + +on: + push: + branches: + - master + pull_request: + paths: + - motoko/who_am_i/** + - rust/who_am_i/** + - .github/workflows/who_am_i.yml + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + motoko-who_am_i: + runs-on: ubuntu-24.04 + container: ghcr.io/dfinity/icp-dev-env-motoko:0.1.0 + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - name: Deploy and test + working-directory: motoko/who_am_i + run: | + icp network start -d + icp deploy + make test + + rust-who_am_i: + runs-on: ubuntu-24.04 + container: ghcr.io/dfinity/icp-dev-env-rust:0.1.0 + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - name: Deploy and test + working-directory: rust/who_am_i + run: | + icp network start -d + icp deploy + make test diff --git a/ADDING_AN_EXAMPLE.md b/ADDING_AN_EXAMPLE.md index 2aa0a0529..34197c362 100644 --- a/ADDING_AN_EXAMPLE.md +++ b/ADDING_AN_EXAMPLE.md @@ -1,40 +1,49 @@ # How to add a new example -> For ICP Ninja: check [NINJA_CONTRIBUTING.md](./NINJA_CONTRIBUTING.md) for how to contribute a project to ICP Ninja. +## Purpose and acceptance criteria + +Examples in this repository have an **educational focus**. Each example is intended to demonstrate a specific ICP capability or pattern, and should be suitable for reference from the [ICP developer documentation](https://docs.internetcomputer.org). + +**We do not accept general-purpose or arbitrary examples.** Before opening a PR, confirm that: + +- The example demonstrates a distinct ICP concept not already covered by an existing example. +- There is a clear home for it in the developer documentation (an existing or planned guide, tutorial, or reference page). +- The DFINITY DX team has agreed to maintain it long-term. + +If you are unsure whether your example fits, open an issue first to discuss it with the maintainers before investing time in an implementation. + +--- Each example should be available in both Rust and Motoko variations, implementing the same Candid interface (and, ideally, semantics). -To illustrate the pattern, this repo now contains one such example, project `hello_world`: +To illustrate the pattern, this repo contains one such example, project `hello_world`: -`motoko/hello_world` -`rust/hello_world` +``` +motoko/hello_world +rust/hello_world +``` -When adding a new `dfx` generated project, make sure to delete its GitHub metadata files (`.gitignore`, `.git` etc). +When adding a new project, make sure to delete any generated GitHub metadata files (`.gitignore`, `.git` etc). Each project should include a language-specific README.md that also links to the corresponding README.md of its counterpart in another language, making it easy for language-curious readers to explore both implementations. ## CI -Apart from the standard `dfx` material, each project should provide a `Makefile` used by GitHub Actions CI to run (very) basic tests. +Each project should provide a `Makefile` with a `test` target that runs basic canister tests using `icp canister call`. Each example also needs a GitHub Actions workflow file at `.github/workflows/.yml`. -For each example, there is a single CI file with four build actions to produce Darwin and Linux builds and tests of the Motoko/Rust, projects, such as: +Use the workflow template as a starting point: ``` -.github/workflows/hello_world.yml +.github/workflow-template.yml ``` -Implementing the GitHub action will ensure it runs in CI and helps keep examples in sync with releases of `dfx`. - -## Documentation +Copy it, replace the placeholders, and add the appropriate container image: -For your new example to be included in the ICP developer documentation, make sure you update the `samples` submodule in the portal repository to point to the latest commit in this examples repository using the following command: - -```bash -git submodule update --remote submodules/samples -``` +- Motoko: `ghcr.io/dfinity/icp-dev-env-motoko` +- Rust: `ghcr.io/dfinity/icp-dev-env-rust` -After you run this command, commit the changes to a new PR to have them merged into the portal repo. +See `hello_world` and `who_am_i` for reference implementations. Workflows run on Linux only using container images — no provision scripts needed. -## Issues +## Notes -While this structure leads to some duplication (especially shared components like frontend code) it ensures that Motoko users can focus solely on Motoko-specific content, and likewise for Rust users. It also enables easily finding language-specific examples when a given use case is not easily supported in the other language. +While this structure leads to some duplication (especially shared frontend code) it ensures that Motoko users can focus solely on Motoko-specific content, and likewise for Rust users. It also enables easily finding language-specific examples when a given use case is not easily supported in the other language. diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..f3c8281e5 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,358 @@ +# Agent Instructions + +Guidelines for AI agents (Claude, Codex, Cursor, Copilot, etc.) working in this repository. + +## Skills — fetch before working + +ICP skills are live reference documents maintained by DFINITY. Always fetch the relevant skills **before** making changes — do not rely on cached or training-data versions. + +**Index:** `https://skills.internetcomputer.org/.well-known/skills/index.json` + +Fetch the skill content at its `url` field. Skills relevant to this repo: + +| Task | Skill to fetch | +|------|---------------| +| Any ICP project work, `icp.yaml`, canister lifecycle | `icp-cli` | +| Migrating an example from dfx to icp-cli | `icp-cli` + its `references/dfx-migration.md` file | +| Motoko canister code | `motoko` | +| `mops.toml`, toolchain pinning, moc flags | `mops-cli` | +| Internet Identity integration | `internet-identity` | +| Frontend asset canister | `asset-canister` | + +Skills take precedence over general knowledge when both cover the same topic. + +--- + +## Repository overview + +This repo contains canonical ICP examples, each available in both Motoko and Rust. Every example lives under two sibling directories: + +``` +motoko// +rust// +``` + +Both implement the same Candid interface so readers can compare language implementations side by side. + +Reference examples to study first: +- `hello_world` — canonical full-stack example (Motoko backend + Vite frontend); use as the structural template for new examples +- `who_am_i` — Internet Identity integration; reference for II-authenticated examples + +--- + +## Toolchain + +- **Always use `icp-cli`** for all ICP operations. Never use `dfx`. +- CLI docs: https://cli.internetcomputer.org +- ICP developer docs: https://docs.internetcomputer.org + +--- + +## Canonical example structure + +Follow the `hello_world` layout. New examples and migrations should use this pattern: + +``` +// +├── icp.yaml # canister definitions (icp-cli project file) +├── Makefile # must contain a `test` target +├── README.md +├── package.json # npm workspaces root pointing to frontend/ +├── mops.toml # Motoko only +├── Cargo.toml # Rust only (workspace) +├── rust-toolchain.toml # Rust only +├── backend/ +│ ├── app.mo or lib.rs # canister entry point +│ └── backend.did # Candid interface (source of truth) +└── frontend/ + ├── index.html + ├── package.json + ├── vite.config.js + ├── src/ + │ ├── actor.js # icp-sdk actor wiring + │ ├── App.jsx + │ └── main.jsx + └── dist/ # build output (gitignored, rebuilt by icp deploy) +``` + +> **Note:** `who_am_i` uses `src/backend/` and `src/frontend/` for historical reasons. +> New examples and migrations should use the flat `backend/` / `frontend/` layout above. + +### What NOT to include + +- `dfx.json` — dfx project file, not used with icp-cli +- `BUILD.md` — ICP Ninja artifact +- `.dfx/` — dfx state directory +- `src/bindings/` — auto-generated by the bindgen Vite plugin, must be gitignored +- Committed `dist/` output — built by `icp deploy`; never commit pre-built assets + +--- + +## icp.yaml + +### Motoko + +```yaml +networks: # omit if no Internet Identity needed + - name: local + mode: managed + ii: true + +canisters: + - name: backend + recipe: + type: https://raw.githubusercontent.com/dfinity/icp-cli-recipes/bc9581d9258d2d7feb15ab4ae8d04baf923b985f/recipes/motoko/recipe.hbs + # TODO: replace with @dfinity/motoko@vX.Y.Z once https://github.com/dfinity/icp-cli-recipes/pull/26 merges + configuration: + name: backend # must match [canisters.backend] key in mops.toml + + - name: frontend + recipe: + type: "@dfinity/asset-canister@v2.1.0" + configuration: + dir: frontend/dist + build: + - npm install --prefix frontend + - npm run build --prefix frontend +``` + +### Rust + +```yaml +canisters: + - name: backend + recipe: + type: "@dfinity/rust@v3.2.0" + configuration: + package: backend + candid: backend/backend.did + + - name: frontend + recipe: + type: "@dfinity/asset-canister@v2.1.0" + configuration: + dir: frontend/dist + build: + - npm install --prefix frontend + - npm run build --prefix frontend +``` + +**Canister names are always `backend` and `frontend`.** Never use names like `_backend`, `internet_identity_app_backend`, etc. + +--- + +## mops.toml (Motoko) + +```toml +[toolchain] +moc = "1.8.2" + +[dependencies] +core = "2.5.0" + +[moc] +# M0236: use context dot notation +# M0237: redundant explicit implicit arguments +# M0223: redundant type instantiation +args = ["--default-persistent-actors", "-W=M0236,M0237,M0223"] + +[canisters.backend] +main = "backend/app.mo" +candid = "backend/backend.did" +``` + +`[canisters.]` replaces the `main`, `candid`, and `args` fields that were previously in `icp.yaml`. The `name` key must match the `name` in the recipe configuration. `--default-persistent-actors` makes all actors persistent by default, so the `persistent` keyword is not needed in source files. + +--- + +## Cargo.toml (Rust) + +Root workspace: +```toml +[workspace] +members = ["backend"] +resolver = "2" +``` + +`backend/Cargo.toml`: +```toml +[package] +name = "backend" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +candid = "0.10" +ic-cdk = "0.20" +``` + +--- + +## Makefile + +Every example must have a `Makefile` with a `test` target that exercises the deployed canister via `icp canister call`: + +```makefile +.PHONY: test + +test: + @echo "--- Testing ---" + @result=$$(icp canister call backend '') && \ + echo "$$result" && \ + echo "$$result" | grep -q '' && \ + echo "PASS" || (echo "FAIL" && exit 1) +``` + +- Tests must call the `backend` canister by that name. +- Use `grep -q` to assert on output content. +- Each assertion is a separate echo block for clarity. + +--- + +## Devcontainer config + +A single root devcontainer at `.devcontainer/devcontainer.json` covers local VS Code usage across all examples. It uses `ghcr.io/dfinity/icp-dev-env-all:` (Motoko + Rust) with `workspaceFolder` set to `/workspaces/examples`. No per-example devcontainer configs exist — do not add them. + +--- + +## CI workflow + +Copy `.github/workflow-template.yml` to `.github/workflows/.yml` and fill in the placeholders. A single workflow file covers both language variants: + +```yaml +name: + +on: + push: + branches: [master] + pull_request: + paths: + - motoko//** + - rust//** + - .github/workflows/.yml + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + motoko-: + runs-on: ubuntu-24.04 + container: ghcr.io/dfinity/icp-dev-env-motoko: + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - name: Deploy and test + working-directory: motoko/ + run: | + icp network start -d + icp deploy + make test + + rust-: + runs-on: ubuntu-24.04 + container: ghcr.io/dfinity/icp-dev-env-rust: + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - name: Deploy and test + working-directory: rust/ + run: | + icp network start -d + icp deploy + make test +``` + +- Linux only, no macOS runners. +- No provision scripts — toolchain comes from the container image. +- Always include the `concurrency` block to cancel superseded runs. +- Pin the `actions/checkout` SHA and annotate it with the version tag. + +--- + +## README structure + +Each example's README should follow this structure: + +```markdown +# + +[View this sample's code on GitHub]() + +## Overview +<2-3 sentences describing what the example demonstrates> + +## Build and deploy from the command line + +### Prerequisites +- [ ] Install Node.js +- [ ] Install icp-cli: `npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm` + +### Install + + +### Deploy + +If the example has a frontend with a Vite dev server: `npm run dev` (hot reload during frontend development) +When done: `icp network stop` + +## Updating the Candid interface + +Motoko: `$(mops toolchain bin moc) --idl -o backend/backend.did backend/app.mo` +Rust: `icp build backend && candid-extractor target/wasm32-unknown-unknown/release/backend.wasm > backend/backend.did` + +## Security considerations and best practices + +``` + +- Security best practices URL: `https://docs.internetcomputer.org/guides/security/overview` +- Each README links to its counterpart in the other language. + +--- + +## Pending items (do not resolve prematurely) + +### Container images +Images are published at `ghcr.io/dfinity/icp-dev-env-{motoko,rust,all}`. All devcontainer configs and CI workflows reference the pinned tag (e.g. `0.1.0`). When a new release is cut, update the tag in: +- `.devcontainer/devcontainer.json` +- `.github/workflows/*.yml` + +Source: https://github.com/dfinity/icp-dev-env + +### Motoko recipe version +Both `motoko/who_am_i/icp.yaml` and `motoko/hello_world/icp.yaml` pin a specific commit SHA of the Motoko recipe to pick up `[moc] args` support from `mops.toml` before it ships in a stable release: + +```yaml +type: https://raw.githubusercontent.com/dfinity/icp-cli-recipes/bc9581d9258d2d7feb15ab4ae8d04baf923b985f/recipes/motoko/recipe.hbs +``` + +Tracked in: https://github.com/dfinity/icp-cli-recipes/pull/26 + +Once that PR merges and a new `@dfinity/motoko` version is released, replace the raw URL in both files with the versioned tag (e.g. `@dfinity/motoko@vX.Y.Z`). + +--- + +## dfx → icp-cli migration checklist + +When migrating an existing example: + +- [ ] Replace `dfx.json` with `icp.yaml` using the canonical structure above +- [ ] Rename canisters to `backend` and `frontend` +- [ ] Rename `src//` to `backend/` (or `src/backend/` if keeping the `src/` layout) +- [ ] Rename `src//` to `frontend/` (or `src/frontend/`) +- [ ] Rename `.did` file to `backend.did` +- [ ] Update `Cargo.toml` package name to `backend` (Rust) +- [ ] Update `Cargo.lock` package name entry (Rust) +- [ ] Update workspace member path in root `Cargo.toml` (Rust) +- [ ] Update `vite.config.js`: canister name, `didFile` path, env var names, remove dfx fallback +- [ ] Update `actor.js`: import path, `PUBLIC_CANISTER_ID:backend`, `CANISTER_ID_BACKEND` +- [ ] Update root `package.json` workspace path to `frontend/` +- [ ] Update `.gitignore` bindings path to `frontend/src/bindings/` +- [ ] Update `mops.toml` to current toolchain versions (Motoko) +- [ ] Delete `dfx.json`, `BUILD.md`, `.dfx/`, `.env` (dfx-generated) +- [ ] Delete `.devcontainer/` inside the example folder if one exists (only the repo-root devcontainer is kept) +- [ ] Add `Makefile` with `test` target +- [ ] Add CI workflow under `.github/workflows/.yml` +- [ ] Update README deploy instructions to use `icp-cli` +- [ ] Update README Candid regeneration command to use `icp-cli` / `mops` toolchain diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..bdc9873c0 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,3 @@ +# Claude Code Instructions + +Read and follow all guidelines in [AGENTS.md](AGENTS.md) before making any changes to this repository. diff --git a/NINJA_CONTRIBUTING.md b/NINJA_CONTRIBUTING.md deleted file mode 100644 index 8c7a6e393..000000000 --- a/NINJA_CONTRIBUTING.md +++ /dev/null @@ -1,151 +0,0 @@ -# Contributing a project to ICP Ninja - -We recommend to build your example directly within ICP Ninja, such that it starts out with the correct tooling, structure and configs. -If you do that, your project will naturally be in the correct format and can be easily added to ICP Ninja. -Once the example is done, you can download the source files from ICP Ninja. -Alternatively, you can start with an existing Ninja project from this repo (see CODEOWNERS file for Ninja examples, e.g. `motoko/hello_world` or `rust/hello_world`) and modify it. - -Ideally, your project should have a frontend and backend. - -### Where to place your example -* `/motoko` for a Motoko project -* `/rust` for a Rust project -* `/hosting` for a frontend-only project - -### Compilation requirements -* Make sure the project compiles and runs with `dfx deploy` inside the `ghcr.io/dfinity/icp-dev-env-slim:22` container. -* Make sure there are no custom scripts for building or running the project, as ICP Ninja has no terminal! -* Make sure `npm run dev` works and the canister can be called through the browser (if applicable, this is if users download the project and run it locally). -* Make sure II login works (if applicable). -* If you use Rust, make sure the project has `ic_cdk::export_candid!();` in the `lib.rs` file, such that the Candid interface can be auto derived. -* If you use Motoko, use Mops as the package manager. - -## Preparing the PR -1. Add your project in the `CODEOWNERS` file, with your team as codeowner. -2. Add your project to the matrix in `.github/workflows/ninja_pr_checks.yml` to run PR tests. -3. Add a `README.md` file, copy the `BUILD.md` and `devcontainer.json` files. -4. Request review from the `@dfinity/ninja-devs` team if it is not added automatically. - -## Submit a PR to the ICP Ninja repo -1. Add your newly added project to `frontend/public/projects.json` -2. Bump the commit hash in `submodules/examples` to a commit hash after your PR has been merged into the examples repo. -3. Ask the Ninja team or AI to give you a beautiful image for your project - -## Templates - -### Recommended `dfx.json` for a Rust canister: - -```json -{ - "canisters": { - "backend": { - "candid": "backend/backend.did", - "type": "custom", - "shrink": true, - "gzip": true, - "wasm": "target/wasm32-unknown-unknown/release/backend.wasm", - "build": [ - "cargo build --target wasm32-unknown-unknown --release -p backend", - "candid-extractor target/wasm32-unknown-unknown/release/backend.wasm > backend/backend.did" - ], - "metadata": [ - { - "name": "candid:service" - } - ] - } - }, - "output_env_file": ".env" -} -``` - -### Recommended `dfx.json` for a Motoko canister: - -```json -{ - "canisters": { - "backend": { - "main": "backend/app.mo", - "type": "motoko", - "args": "--enhanced-orthogonal-persistence" - }, - }, - "output_env_file": ".env", - "defaults": { - "build": { - "packtool": "mops sources" - } - } -} - -``` - -### Recommended `dfx.json` for a frontend/asset canister: - -```json -{ - "canisters": { - "frontend": { - "dependencies": ["backend"], - "frontend": { - "entrypoint": "frontend/index.html" - }, - "source": ["frontend/dist"], - "type": "assets" - } - }, - "output_env_file": ".env" -} -``` - -### Recommended `package.json` -Make sure to install all packages necessary in the prebuild step of your `package.json`, e.g., with - -```js -"scripts": { - "prebuild": "npm i --include=dev && ...", - ... - }, -``` - -### Recommended `vite.config.js` - -```js -import react from '@vitejs/plugin-react'; -import { defineConfig } from 'vite'; -import { fileURLToPath, URL } from 'url'; -import environment from 'vite-plugin-environment'; - -export default defineConfig({ - base: './', - plugins: [react(), environment('all', { prefix: 'CANISTER_' }), environment('all', { prefix: 'DFX_' })], - envDir: '../', - define: { - 'process.env': process.env - }, - optimizeDeps: { - esbuildOptions: { - define: { - global: 'globalThis' - } - } - }, - resolve: { - alias: [ - { - find: 'declarations', - replacement: fileURLToPath(new URL('../src/declarations', import.meta.url)) - } - ] - }, - server: { - proxy: { - '/api': { - target: 'http://127.0.0.1:4943', - changeOrigin: true - } - }, - host: '127.0.0.1' - } -}); -``` diff --git a/README.md b/README.md index 191a5d00b..d81d34746 100644 --- a/README.md +++ b/README.md @@ -1,66 +1,64 @@ -# Internet Computer sample applications +# Internet Computer sample applications Get started building on ICP with the sample applications in this repository. From this repository, you can deploy, download, clone, fork, or share sample projects. +> Looking to start a new project from scratch? Use [icp-cli-templates](https://github.com/dfinity/icp-cli-templates) to scaffold a project with `icp new`. + The projects in this repository are not intended to be used as commercial applications and do not provide any explicit or implied support or warranty of any kind. You can also contribute your own project or suggest updates to published projects using the standard GitHub workflow. ## Sample applications -Code samples are organized by programming language: - -- [Motoko](https://github.com/dfinity/examples/tree/master/motoko) -- [Rust](https://github.com/dfinity/examples/tree/master/rust) -- [C](https://github.com/dfinity/examples/tree/master/c) - -Some examples include frontends written in a variety of frameworks, such as React, JavaScript, etc. - -Additional frontend samples can be found in the following folders: - -- [Svelte](https://github.com/dfinity/examples/tree/master/svelte) -- [HTML](https://github.com/dfinity/examples/tree/master/hosting) -- [Unity](https://github.com/dfinity/examples/tree/master/native-apps) +**New here?** Start with [hello_world](motoko/hello_world/) (Motoko) or [hello_world](rust/hello_world/) (Rust) — a simple full-stack canister with a frontend. For user authentication with Internet Identity, see [who_am_i](motoko/who_am_i/) or [who_am_i](rust/who_am_i/). -## Deploying samples +Canister examples are organized by language: -### ICP Ninja +- [motoko/](motoko/) +- [rust/](rust/) -You can open and deploy examples with [ICP Ninja](https://icp.ninja/), a web-based tool that allows you to create and manage Internet Computer projects without downloading any tools or setting up a local environment. +Frontend-only and native app examples: -To contribute an example that will be featured on ICP Ninja, check out the [NINJA_CONTRIBUTING.md](./NINJA_CONTRIBUTING.md) file. +- [hosting/](hosting/) — frontend examples (React, static sites, etc.) +- [native-apps/](native-apps/) — Unity and other native app integrations -### GitHub Codespaces or Gitpod +## Local development -This repo can be opened in a web-based developer environment such as [GitHub Codespaces](https://github.com/codespaces) or [Gitpod](https://www.gitpod.io/), allowing you to edit and deploy the sample projects without downloading any tools or setting up a local environment. +### Command line -[Get started with GitHub codespaces](https://internetcomputer.org/docs/current/developer-docs/developer-tools/ide/codespaces). +Install the prerequisites and then follow the example's README to deploy. -[Get started with Gitpod](https://internetcomputer.org/docs/current/developer-docs/developer-tools/ide/gitpod). +**Prerequisites:** +- [Node.js](https://nodejs.org/en/download/) (LTS) +- [icp-cli](https://cli.internetcomputer.org): `npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm` +- **Motoko examples:** [mops](https://mops.one/docs/install): `npm install -g ic-mops` +- **Rust examples:** [Rust](https://rustup.rs/) + `rustup target add wasm32-unknown-unknown` -### dfx +See the [full installation guide](https://cli.internetcomputer.org/0.2/guides/installation.md) for platform-specific instructions. -dfx is a command-line tool used to create, deploy. and manage projects on ICP. To download and use dfx with this examples repo, run the following commands locally (macOS/Linux systems): - -``` +```bash git clone https://github.com/dfinity/examples.git -cd examples -sh -ci "$(curl -fsSL https://internetcomputer.org/install.sh)" +cd examples// ``` -Then, navigate into the folder of the sample that you want to use and follow the project's README instructions to setup and deploy the sample code. +### Dev Containers +Open the repo root in [VS Code](https://code.visualstudio.com/) with the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) to get a pre-configured environment with the full ICP toolchain for both Motoko and Rust. VS Code will prompt you to reopen in the container automatically. -## Resources +```bash +git clone https://github.com/dfinity/examples.git +``` -- [ICP Developer Docs](https://internetcomputer.org/docs/current/home) +Then navigate into an example and follow its README to deploy. -- [Overview of ICP](https://internetcomputer.org/docs/current/developer-docs/getting-started/overview-of-icp) +> **Note:** Open the repo root in the container — not an individual example subfolder. -- [Installing dfx](https://internetcomputer.org/docs/current/developer-docs/getting-started/install/) +## Resources -- [Developer tools](https://internetcomputer.org/docs/current/developer-docs/developer-tools/dev-tools-overview) +- [Quickstart](https://docs.internetcomputer.org/getting-started/quickstart) +- [Developer tools](https://docs.internetcomputer.org/developer-tools) +- [icp-cli](https://cli.internetcomputer.org) ## Security considerations and best practices -If you base your application on one of these examples, we recommend you familiarize yourself with and adhere to the [security best practices](https://internetcomputer.org/docs/current/references/security/) for developing on the Internet Computer. The examples provided here may not implement all the best practices. +If you base your application on one of these examples, we recommend you familiarize yourself with and adhere to the [security best practices](https://docs.internetcomputer.org/guides/security/overview) for developing on the Internet Computer. The examples provided here may not implement all the best practices. diff --git a/motoko/hello_world/.devcontainer/devcontainer.json b/motoko/hello_world/.devcontainer/devcontainer.json deleted file mode 100644 index ebb0b8bcc..000000000 --- a/motoko/hello_world/.devcontainer/devcontainer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "ICP Dev Environment", - "image": "ghcr.io/dfinity/icp-dev-env-slim:22", - "forwardPorts": [4943, 5173], - "portsAttributes": { - "4943": { - "label": "dfx", - "onAutoForward": "ignore" - }, - "5173": { - "label": "vite", - "onAutoForward": "openBrowser" - } - }, - "customizations": { - "vscode": { - "extensions": ["dfinity-foundation.vscode-motoko"] - } - } -} diff --git a/motoko/hello_world/BUILD.md b/motoko/hello_world/BUILD.md deleted file mode 100644 index 8877d3ed2..000000000 --- a/motoko/hello_world/BUILD.md +++ /dev/null @@ -1,26 +0,0 @@ -# Continue building locally - -Projects deployed through ICP Ninja are temporary; they will only be live for 30 minutes before they are removed. To continue building locally, follow these steps. - -### 1. Install developer tools - -Install [Node.js](https://nodejs.org/en/download/) and [icp-cli](https://cli.internetcomputer.org): - -```bash -npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm -``` - -Then navigate into your project's directory that you downloaded from ICP Ninja. - -### 2. Deploy locally - -Start the local network and deploy the project: - -```bash -icp network start -d -icp deploy -``` - -## Additional examples - -Additional code examples and sample applications can be found in the [DFINITY examples repo](https://github.com/dfinity/examples). diff --git a/motoko/hello_world/Makefile b/motoko/hello_world/Makefile new file mode 100644 index 000000000..7f538e890 --- /dev/null +++ b/motoko/hello_world/Makefile @@ -0,0 +1,15 @@ +.PHONY: test + +test: + @echo "--- Testing default greeting ---" + @result=$$(icp canister call backend greet '("World")') && \ + echo "$$result" && \ + echo "$$result" | grep -q 'Hello, World!' && \ + echo "PASS" || (echo "FAIL" && exit 1) + + @echo "--- Testing setGreeting ---" + @icp canister call backend setGreeting '("Hi, ")' + @result=$$(icp canister call backend greet '("Alice")') && \ + echo "$$result" && \ + echo "$$result" | grep -q 'Hi, Alice!' && \ + echo "PASS" || (echo "FAIL" && exit 1) diff --git a/motoko/hello_world/README.md b/motoko/hello_world/README.md index 4afb8738b..ed45d809b 100644 --- a/motoko/hello_world/README.md +++ b/motoko/hello_world/README.md @@ -21,20 +21,12 @@ The `/backend` folder contains the Motoko canister, `app.mo`. The `/frontend` fo Edit the `mops.toml` file to add [Motoko dependencies](https://mops.one/) to the project. -## Deploying from ICP Ninja - -This example can be deployed directly from [ICP Ninja](https://icp.ninja), a browser-based IDE for ICP. To continue developing locally after deploying from ICP Ninja, see [BUILD.md](BUILD.md). - -[![Open in ICP Ninja](https://icp.ninja/assets/open.svg)](https://icp.ninja/i?g=https://github.com/dfinity/examples/motoko/hello_world) - -> **Note:** ICP Ninja currently uses `dfx` under the hood, which is why this example includes a `dfx.json` configuration file. `dfx` is the legacy CLI, being superseded by [icp-cli](https://cli.internetcomputer.org), which is what developers should use for local development. - ## Build and deploy from the command line ### Prerequisites -- [x] Install [Node.js](https://nodejs.org/en/download/) -- [x] Install [icp-cli](https://cli.internetcomputer.org): `npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm` +- Install [Node.js](https://nodejs.org/en/download/) +- Install [icp-cli](https://cli.internetcomputer.org): `npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm` ### Install @@ -47,19 +39,20 @@ cd examples/motoko/hello_world ### Deployment -Start the local network: +Start the local network and deploy: ```bash icp network start -d +icp deploy ``` -Deploy the canisters: +The frontend is served by the asset canister. To run the Vite dev server with hot reload during frontend development: ```bash -icp deploy +npm run dev ``` -Stop the local network when done: +When done, stop the local network to free the port and clear state: ```bash icp network stop @@ -77,4 +70,4 @@ $(mops toolchain bin moc) --idl -o backend/backend.did backend/app.mo ## Security considerations and best practices -If you base your application on this example, it is recommended that you familiarize yourself with and adhere to the [security best practices](https://docs.internetcomputer.org/building-apps/security/overview) for developing on ICP. This example may not implement all the best practices. +If you base your application on this example, it is recommended that you familiarize yourself with and adhere to the [security best practices](https://docs.internetcomputer.org/guides/security/overview) for developing on ICP. This example may not implement all the best practices. diff --git a/motoko/hello_world/backend/app.mo b/motoko/hello_world/backend/app.mo index 7bbd4f6f3..6e434246b 100644 --- a/motoko/hello_world/backend/app.mo +++ b/motoko/hello_world/backend/app.mo @@ -1,4 +1,4 @@ -persistent actor HelloWorld { +actor HelloWorld { // We store the greeting in a stable variable such that it gets persisted over canister upgrades. var greeting : Text = "Hello, "; diff --git a/motoko/hello_world/dfx.json b/motoko/hello_world/dfx.json deleted file mode 100644 index d073ee09f..000000000 --- a/motoko/hello_world/dfx.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "canisters": { - "backend": { - "main": "backend/app.mo", - "type": "motoko", - "args": "--enhanced-orthogonal-persistence" - }, - "frontend": { - "dependencies": ["backend"], - "frontend": { - "entrypoint": "frontend/index.html" - }, - "source": ["frontend/dist"], - "type": "assets" - } - }, - "output_env_file": ".env", - "defaults": { - "build": { - "packtool": "mops sources" - } - } -} diff --git a/motoko/hello_world/icp.yaml b/motoko/hello_world/icp.yaml index a4edd3a0e..3c1670447 100644 --- a/motoko/hello_world/icp.yaml +++ b/motoko/hello_world/icp.yaml @@ -1,10 +1,9 @@ canisters: - name: backend recipe: - type: "@dfinity/motoko@v4.1.0" + type: https://raw.githubusercontent.com/dfinity/icp-cli-recipes/bc9581d9258d2d7feb15ab4ae8d04baf923b985f/recipes/motoko/recipe.hbs configuration: - main: backend/app.mo - candid: backend/backend.did + name: backend - name: frontend recipe: diff --git a/motoko/hello_world/mops.toml b/motoko/hello_world/mops.toml index dc89d0891..49573d4b5 100644 --- a/motoko/hello_world/mops.toml +++ b/motoko/hello_world/mops.toml @@ -1,11 +1,15 @@ [toolchain] -moc = "1.5.1" +moc = "1.8.2" [dependencies] -core = "2.4.0" +core = "2.5.0" [moc] # M0236: use context dot notation (e.g. x.toText() instead of Nat.toText(x)) # M0237: redundant explicit implicit arguments (e.g. Nat.compare is inferred automatically) # M0223: redundant type instantiation (e.g. Array.tabulate instead of Array.tabulate) -args = ["-W=M0236,M0237,M0223"] +args = ["--default-persistent-actors", "-W=M0236,M0237,M0223"] + +[canisters.backend] +main = "backend/app.mo" +candid = "backend/backend.did" diff --git a/motoko/who_am_i/.devcontainer/devcontainer.json b/motoko/who_am_i/.devcontainer/devcontainer.json deleted file mode 100644 index ebb0b8bcc..000000000 --- a/motoko/who_am_i/.devcontainer/devcontainer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "ICP Dev Environment", - "image": "ghcr.io/dfinity/icp-dev-env-slim:22", - "forwardPorts": [4943, 5173], - "portsAttributes": { - "4943": { - "label": "dfx", - "onAutoForward": "ignore" - }, - "5173": { - "label": "vite", - "onAutoForward": "openBrowser" - } - }, - "customizations": { - "vscode": { - "extensions": ["dfinity-foundation.vscode-motoko"] - } - } -} diff --git a/motoko/who_am_i/.gitignore b/motoko/who_am_i/.gitignore index 2a822d5c2..fcacb2b70 100644 --- a/motoko/who_am_i/.gitignore +++ b/motoko/who_am_i/.gitignore @@ -1 +1 @@ -src/internet_identity_app_frontend/src/bindings/ +src/frontend/src/bindings/ diff --git a/motoko/who_am_i/BUILD.md b/motoko/who_am_i/BUILD.md deleted file mode 100644 index 8877d3ed2..000000000 --- a/motoko/who_am_i/BUILD.md +++ /dev/null @@ -1,26 +0,0 @@ -# Continue building locally - -Projects deployed through ICP Ninja are temporary; they will only be live for 30 minutes before they are removed. To continue building locally, follow these steps. - -### 1. Install developer tools - -Install [Node.js](https://nodejs.org/en/download/) and [icp-cli](https://cli.internetcomputer.org): - -```bash -npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm -``` - -Then navigate into your project's directory that you downloaded from ICP Ninja. - -### 2. Deploy locally - -Start the local network and deploy the project: - -```bash -icp network start -d -icp deploy -``` - -## Additional examples - -Additional code examples and sample applications can be found in the [DFINITY examples repo](https://github.com/dfinity/examples). diff --git a/motoko/who_am_i/Makefile b/motoko/who_am_i/Makefile new file mode 100644 index 000000000..e5eba77f5 --- /dev/null +++ b/motoko/who_am_i/Makefile @@ -0,0 +1,14 @@ +.PHONY: test + +test: + @echo "--- Testing whoami returns a principal ---" + @result=$$(icp canister call backend whoami '()') && \ + echo "$$result" && \ + echo "$$result" | grep -q 'principal' && \ + echo "PASS" || (echo "FAIL" && exit 1) + + @echo "--- Testing whoami is deterministic ---" + @result1=$$(icp canister call backend whoami '()') && \ + result2=$$(icp canister call backend whoami '()') && \ + [ "$$result1" = "$$result2" ] && \ + echo "PASS: $$result1" || (echo "FAIL: $$result1 != $$result2" && exit 1) diff --git a/motoko/who_am_i/README.md b/motoko/who_am_i/README.md index f64514f10..8ed3fc2a0 100644 --- a/motoko/who_am_i/README.md +++ b/motoko/who_am_i/README.md @@ -6,20 +6,12 @@ Who am I? demonstrates how entities on the Internet Computer are identified. Every entity, such as a user or canister smart contract, has a principal identifier. Principals can be used for identification and authentication. Who am I? uses Internet Identity (II) for user authentication, then displays the principal identifier associated with that Internet Identity on the user interface. -## Deploying from ICP Ninja - -This example can be deployed directly from [ICP Ninja](https://icp.ninja), a browser-based IDE for ICP. To continue developing locally after deploying from ICP Ninja, see [BUILD.md](BUILD.md). - -[![Open in ICP Ninja](https://icp.ninja/assets/open.svg)](https://icp.ninja/i?g=https://github.com/dfinity/examples/motoko/who_am_i) - -> **Note:** ICP Ninja currently uses `dfx` under the hood, which is why this example includes a `dfx.json` configuration file. `dfx` is the legacy CLI, being superseded by [icp-cli](https://cli.internetcomputer.org), which is what developers should use for local development. - ## Build and deploy from the command line ### Prerequisites -- [x] Install [Node.js](https://nodejs.org/en/download/) -- [x] Install [icp-cli](https://cli.internetcomputer.org): `npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm` +- Install [Node.js](https://nodejs.org/en/download/) +- Install [icp-cli](https://cli.internetcomputer.org): `npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm` ### Install @@ -30,36 +22,41 @@ git clone https://github.com/dfinity/examples cd examples/motoko/who_am_i ``` -### Deployment +### Deploy -Start the local network: +Start the local network and deploy: ```bash icp network start -d +icp deploy ``` -Deploy the canisters: +The frontend is served by the asset canister. To run the Vite dev server with hot reload during frontend development: ```bash -icp deploy +npm run dev ``` -Stop the local network when done: +When done, stop the local network to free the port and clear state: ```bash icp network stop ``` +## Ready to deploy on mainnet? + +When you're ready for mainnet, [install icp-cli locally](https://cli.internetcomputer.org) and follow the [mainnet deployment guide](https://cli.internetcomputer.org/0.2/guides/deploying-to-mainnet.md). Mainnet requires ICP tokens and cycles — managing identities securely is much better from your own machine. + ## Updating the Candid interface -The `src/internet_identity_app_backend/internet_identity_app_backend.did` file defines the backend canister's public interface. The frontend TypeScript bindings are auto-generated from this file during the frontend build. +The `src/backend/backend.did` file defines the backend canister's public interface. The frontend TypeScript bindings are auto-generated from this file during the frontend build. -If you modify the backend's public API, regenerate the `.did` file: +If you modify the backend's public API, regenerate the `.did` file using the Motoko compiler: ```bash -$(mops toolchain bin moc) --idl $(mops sources) -o src/internet_identity_app_backend/internet_identity_app_backend.did src/internet_identity_app_backend/main.mo +$(mops toolchain bin moc) --idl -o src/backend/backend.did src/backend/main.mo ``` ## Security considerations and best practices -If you base your application on this example, it is recommended that you familiarize yourself with and adhere to the [security best practices](https://docs.internetcomputer.org/building-apps/security/overview) for developing on ICP. This example may not implement all the best practices. +If you base your application on this example, it is recommended that you familiarize yourself with and adhere to the [security best practices](https://docs.internetcomputer.org/guides/security/overview) for developing on ICP. This example may not implement all the best practices. diff --git a/motoko/who_am_i/dfx.json b/motoko/who_am_i/dfx.json deleted file mode 100644 index e7ba2df8b..000000000 --- a/motoko/who_am_i/dfx.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "canisters": { - "internet_identity_app_backend": { - "main": "src/internet_identity_app_backend/main.mo", - "type": "motoko" - }, - "internet_identity_app_frontend": { - "dependencies": ["internet_identity_app_backend"], - "internet_identity_app_frontend": { - "entrypoint": "src/internet_identity_app_frontend/index.html" - }, - "source": ["src/internet_identity_app_frontend/dist"], - "type": "assets" - }, - "internet_identity": { - "candid": "https://github.com/dfinity/internet-identity/releases/latest/download/internet_identity.did", - "type": "custom", - "specified_id": "rdmx6-jaaaa-aaaaa-aaadq-cai", - "remote": { - "id": { - "ic": "rdmx6-jaaaa-aaaaa-aaadq-cai" - } - }, - "wasm": "https://github.com/dfinity/internet-identity/releases/latest/download/internet_identity_production.wasm.gz" - }, - "internet_identity_frontend": { - "candid": "https://raw.githubusercontent.com/dfinity/internet-identity/refs/heads/main/src/internet_identity_frontend/internet_identity_frontend.did", - "type": "custom", - "specified_id": "uqzsh-gqaaa-aaaaq-qaada-cai", - "remote": { - "id": { - "ic": "uqzsh-gqaaa-aaaaq-qaada-cai" - } - }, - "wasm": "https://github.com/dfinity/internet-identity/releases/latest/download/internet_identity_frontend.wasm.gz", - "init_arg": "(record { fetch_root_key = opt true; dev_csp = opt true; backend_canister_id = principal \"rdmx6-jaaaa-aaaaa-aaadq-cai\"; analytics_config = null; related_origins = opt vec { \"http://uqzsh-gqaaa-aaaaq-qaada-cai.localhost:4943\" }; backend_origin = \"http://rdmx6-jaaaa-aaaaa-aaadq-cai.localhost:4943\"; captcha_config = opt record { max_unsolved_captchas = 50 : nat64; captcha_trigger = variant { Static = variant { CaptchaDisabled } } }})" - } - }, - "output_env_file": ".env", - "defaults": { - "build": { - "packtool": "mops sources" - } - } -} diff --git a/motoko/who_am_i/icp.yaml b/motoko/who_am_i/icp.yaml index 6cf444682..4cd8aef9c 100644 --- a/motoko/who_am_i/icp.yaml +++ b/motoko/who_am_i/icp.yaml @@ -4,18 +4,17 @@ networks: ii: true canisters: - - name: internet_identity_app_backend + - name: backend recipe: - type: "@dfinity/motoko@v4.1.0" + type: https://raw.githubusercontent.com/dfinity/icp-cli-recipes/bc9581d9258d2d7feb15ab4ae8d04baf923b985f/recipes/motoko/recipe.hbs configuration: - main: src/internet_identity_app_backend/main.mo - candid: src/internet_identity_app_backend/internet_identity_app_backend.did + name: backend - - name: internet_identity_app_frontend + - name: frontend recipe: type: "@dfinity/asset-canister@v2.1.0" configuration: - dir: src/internet_identity_app_frontend/dist + dir: src/frontend/dist build: - - npm install --prefix src/internet_identity_app_frontend - - npm run build --prefix src/internet_identity_app_frontend + - npm install --prefix src/frontend + - npm run build --prefix src/frontend diff --git a/motoko/who_am_i/mops.toml b/motoko/who_am_i/mops.toml index dc89d0891..85ea333c4 100644 --- a/motoko/who_am_i/mops.toml +++ b/motoko/who_am_i/mops.toml @@ -1,11 +1,15 @@ [toolchain] -moc = "1.5.1" +moc = "1.8.2" [dependencies] -core = "2.4.0" +core = "2.5.0" [moc] # M0236: use context dot notation (e.g. x.toText() instead of Nat.toText(x)) # M0237: redundant explicit implicit arguments (e.g. Nat.compare is inferred automatically) # M0223: redundant type instantiation (e.g. Array.tabulate instead of Array.tabulate) -args = ["-W=M0236,M0237,M0223"] +args = ["--default-persistent-actors", "-W=M0236,M0237,M0223"] + +[canisters.backend] +main = "src/backend/main.mo" +candid = "src/backend/backend.did" diff --git a/motoko/who_am_i/package.json b/motoko/who_am_i/package.json index 7684efc81..969610713 100644 --- a/motoko/who_am_i/package.json +++ b/motoko/who_am_i/package.json @@ -7,6 +7,6 @@ }, "type": "module", "workspaces": [ - "src/internet_identity_app_frontend" + "src/frontend" ] } diff --git a/motoko/who_am_i/src/internet_identity_app_backend/internet_identity_app_backend.did b/motoko/who_am_i/src/backend/backend.did similarity index 100% rename from motoko/who_am_i/src/internet_identity_app_backend/internet_identity_app_backend.did rename to motoko/who_am_i/src/backend/backend.did diff --git a/motoko/who_am_i/src/internet_identity_app_backend/main.mo b/motoko/who_am_i/src/backend/main.mo similarity index 82% rename from motoko/who_am_i/src/internet_identity_app_backend/main.mo rename to motoko/who_am_i/src/backend/main.mo index f011aecd3..70015e177 100644 --- a/motoko/who_am_i/src/internet_identity_app_backend/main.mo +++ b/motoko/who_am_i/src/backend/main.mo @@ -1,6 +1,6 @@ import Principal "mo:core/Principal"; -persistent actor Whoami { +actor Whoami { public query (message) func whoami() : async Principal { message.caller; }; diff --git a/motoko/who_am_i/src/internet_identity_app_frontend/index.css b/motoko/who_am_i/src/frontend/index.css similarity index 100% rename from motoko/who_am_i/src/internet_identity_app_frontend/index.css rename to motoko/who_am_i/src/frontend/index.css diff --git a/motoko/who_am_i/src/internet_identity_app_frontend/index.html b/motoko/who_am_i/src/frontend/index.html similarity index 100% rename from motoko/who_am_i/src/internet_identity_app_frontend/index.html rename to motoko/who_am_i/src/frontend/index.html diff --git a/rust/who_am_i/src/internet_identity_app_frontend/package.json b/motoko/who_am_i/src/frontend/package.json similarity index 91% rename from rust/who_am_i/src/internet_identity_app_frontend/package.json rename to motoko/who_am_i/src/frontend/package.json index 49a3f1ace..412b87e6d 100644 --- a/rust/who_am_i/src/internet_identity_app_frontend/package.json +++ b/motoko/who_am_i/src/frontend/package.json @@ -1,5 +1,5 @@ { - "name": "internet_identity_app_frontend", + "name": "frontend", "private": true, "type": "module", "scripts": { diff --git a/motoko/who_am_i/src/internet_identity_app_frontend/public/favicon.ico b/motoko/who_am_i/src/frontend/public/favicon.ico similarity index 100% rename from motoko/who_am_i/src/internet_identity_app_frontend/public/favicon.ico rename to motoko/who_am_i/src/frontend/public/favicon.ico diff --git a/motoko/who_am_i/src/internet_identity_app_frontend/src/App.jsx b/motoko/who_am_i/src/frontend/src/App.jsx similarity index 100% rename from motoko/who_am_i/src/internet_identity_app_frontend/src/App.jsx rename to motoko/who_am_i/src/frontend/src/App.jsx diff --git a/rust/who_am_i/src/internet_identity_app_frontend/src/actor.js b/motoko/who_am_i/src/frontend/src/actor.js similarity index 77% rename from rust/who_am_i/src/internet_identity_app_frontend/src/actor.js rename to motoko/who_am_i/src/frontend/src/actor.js index becf24513..1e4ac04ad 100644 --- a/rust/who_am_i/src/internet_identity_app_frontend/src/actor.js +++ b/motoko/who_am_i/src/frontend/src/actor.js @@ -1,15 +1,15 @@ import { safeGetCanisterEnv } from "@icp-sdk/core/agent/canister-env"; -import { createActor } from "./bindings/internet_identity_app_backend"; +import { createActor } from "./bindings/backend"; const canisterEnv = safeGetCanisterEnv(); const canisterId = - canisterEnv?.["PUBLIC_CANISTER_ID:internet_identity_app_backend"] ?? - process.env.CANISTER_ID_INTERNET_IDENTITY_APP_BACKEND; + canisterEnv?.["PUBLIC_CANISTER_ID:backend"] ?? + process.env.CANISTER_ID_BACKEND; if (!canisterId) { throw new Error( - "Canister ID for 'internet_identity_app_backend' not found. Run 'icp deploy' or 'dfx deploy' first." + "Canister ID for 'backend' not found. Run 'icp deploy' first." ); } diff --git a/motoko/who_am_i/src/internet_identity_app_frontend/src/main.jsx b/motoko/who_am_i/src/frontend/src/main.jsx similarity index 100% rename from motoko/who_am_i/src/internet_identity_app_frontend/src/main.jsx rename to motoko/who_am_i/src/frontend/src/main.jsx diff --git a/rust/who_am_i/src/internet_identity_app_frontend/vite.config.js b/motoko/who_am_i/src/frontend/vite.config.js similarity index 50% rename from rust/who_am_i/src/internet_identity_app_frontend/vite.config.js rename to motoko/who_am_i/src/frontend/vite.config.js index 41d03427c..8bb840ac3 100644 --- a/rust/who_am_i/src/internet_identity_app_frontend/vite.config.js +++ b/motoko/who_am_i/src/frontend/vite.config.js @@ -4,9 +4,8 @@ import react from "@vitejs/plugin-react"; import { icpBindgen } from "@icp-sdk/bindgen/plugins/vite"; function getDevServerConfig() { - // Try icp-cli first try { - const canisterId = execSync("icp canister status internet_identity_app_backend -e local -i", { + const canisterId = execSync("icp canister status backend -e local -i", { encoding: "utf-8", stdio: "pipe", }).trim(); @@ -20,7 +19,7 @@ function getDevServerConfig() { replicaPort: "8000", headers: { "Set-Cookie": `ic_env=${encodeURIComponent( - `ic_root_key=${networkStatus.root_key}&PUBLIC_CANISTER_ID:internet_identity_app_backend=${canisterId}` + `ic_root_key=${networkStatus.root_key}&PUBLIC_CANISTER_ID:backend=${canisterId}` )}; SameSite=Lax;`, }, proxy: { @@ -29,46 +28,12 @@ function getDevServerConfig() { }; } catch {} - // Try dfx - try { - const pingResult = JSON.parse( - execSync("dfx ping", { encoding: "utf-8", stdio: "pipe" }) - ); - const rootKeyHex = Buffer.from(pingResult.root_key).toString("hex"); - const canisterId = execSync( - "dfx canister id internet_identity_app_backend", - { - encoding: "utf-8", - stdio: "pipe", - } - ).trim(); - return { - replicaPort: "4943", - headers: { - "Set-Cookie": `ic_env=${encodeURIComponent( - `ic_root_key=${rootKeyHex}&PUBLIC_CANISTER_ID:internet_identity_app_backend=${canisterId}` - )}; SameSite=Lax;`, - }, - proxy: { - "/api": { - target: "http://127.0.0.1:4943", - changeOrigin: true, - }, - }, - host: "127.0.0.1", - }; - } catch {} - throw new Error( - "No local network running. Start with:\n icp network start -d && icp deploy\nor:\n dfx start --background && dfx deploy" + "No local network running. Start with:\n icp network start -d && icp deploy" ); } export default defineConfig(({ command, mode }) => { - // dfx generates ../../.env with CANISTER_ID_* vars on deploy. Bake them into - // the bundle so actor.js can fall back to them when the ic_env cookie does not - // contain canister IDs (dfx does not inject PUBLIC_CANISTER_ID:* env vars - // into the asset canister, unlike icp-cli). const env = loadEnv(mode, "../..", ["CANISTER_"]); const devConfig = command === "serve" ? getDevServerConfig() : undefined; @@ -77,14 +42,13 @@ export default defineConfig(({ command, mode }) => { plugins: [ react(), icpBindgen({ - didFile: - "../internet_identity_app_backend/internet_identity_app_backend.did", + didFile: "../backend/backend.did", outDir: "./src/bindings", }), ], define: { - "process.env.CANISTER_ID_INTERNET_IDENTITY_APP_BACKEND": JSON.stringify( - env.CANISTER_ID_INTERNET_IDENTITY_APP_BACKEND + "process.env.CANISTER_ID_BACKEND": JSON.stringify( + env.CANISTER_ID_BACKEND ), "process.env.REPLICA_PORT": JSON.stringify(devConfig?.replicaPort ?? ""), }, diff --git a/rust/hello_world/.devcontainer/devcontainer.json b/rust/hello_world/.devcontainer/devcontainer.json deleted file mode 100644 index ebb0b8bcc..000000000 --- a/rust/hello_world/.devcontainer/devcontainer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "ICP Dev Environment", - "image": "ghcr.io/dfinity/icp-dev-env-slim:22", - "forwardPorts": [4943, 5173], - "portsAttributes": { - "4943": { - "label": "dfx", - "onAutoForward": "ignore" - }, - "5173": { - "label": "vite", - "onAutoForward": "openBrowser" - } - }, - "customizations": { - "vscode": { - "extensions": ["dfinity-foundation.vscode-motoko"] - } - } -} diff --git a/rust/hello_world/BUILD.md b/rust/hello_world/BUILD.md deleted file mode 100644 index ffb6557ec..000000000 --- a/rust/hello_world/BUILD.md +++ /dev/null @@ -1,26 +0,0 @@ -# Continue building locally - -Projects deployed through ICP Ninja are temporary; they will only be live for 30 minutes before they are removed. To continue building locally, follow these steps. - -### 1. Install developer tools - -Install [Node.js](https://nodejs.org/en/download/) and [icp-cli](https://cli.icp.build): - -```bash -npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm -``` - -Then navigate into your project's directory that you downloaded from ICP Ninja. - -### 2. Deploy locally - -Start the local network and deploy the project: - -```bash -icp network start -d -icp deploy -``` - -## Additional examples - -Additional code examples and sample applications can be found in the [DFINITY examples repo](https://github.com/dfinity/examples). diff --git a/rust/hello_world/Makefile b/rust/hello_world/Makefile new file mode 100644 index 000000000..269592eca --- /dev/null +++ b/rust/hello_world/Makefile @@ -0,0 +1,15 @@ +.PHONY: test + +test: + @echo "--- Testing default greeting ---" + @result=$$(icp canister call backend greet '("World")') && \ + echo "$$result" && \ + echo "$$result" | grep -q 'Hello, World!' && \ + echo "PASS" || (echo "FAIL" && exit 1) + + @echo "--- Testing set_greeting ---" + @icp canister call backend set_greeting '("Hi, ")' + @result=$$(icp canister call backend greet '("Alice")') && \ + echo "$$result" && \ + echo "$$result" | grep -q 'Hi, Alice!' && \ + echo "PASS" || (echo "FAIL" && exit 1) diff --git a/rust/hello_world/README.md b/rust/hello_world/README.md index 468adb75d..8c97cee04 100644 --- a/rust/hello_world/README.md +++ b/rust/hello_world/README.md @@ -17,20 +17,12 @@ The frontend provides a simple form where users can enter their name and receive The `/backend` folder contains the Rust canister source code. The `/frontend` folder contains web assets for the application's user interface. The user interface is written with plain JavaScript, but any frontend framework can be used. -## Deploying from ICP Ninja - -This example can be deployed directly from [ICP Ninja](https://icp.ninja), a browser-based IDE for ICP. To continue developing locally after deploying from ICP Ninja, see [BUILD.md](BUILD.md). - -[![Open in ICP Ninja](https://icp.ninja/assets/open.svg)](https://icp.ninja/i?g=https://github.com/dfinity/examples/rust/hello_world) - -> **Note:** ICP Ninja currently uses `dfx` under the hood, which is why this example includes a `dfx.json` configuration file. `dfx` is the legacy CLI, being superseded by [icp-cli](https://cli.icp.build), which is what developers should use for local development. - ## Build and deploy from the command line ### Prerequisites -- [x] Install [Node.js](https://nodejs.org/en/download/) -- [x] Install [icp-cli](https://cli.icp.build): `npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm` +- Install [Node.js](https://nodejs.org/en/download/) +- Install [icp-cli](https://cli.internetcomputer.org): `npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm` ### Install @@ -43,19 +35,20 @@ cd examples/rust/hello_world ### Deployment -Start the local network: +Start the local network and deploy: ```bash icp network start -d +icp deploy ``` -Deploy the canisters: +The frontend is served by the asset canister. To run the Vite dev server with hot reload during frontend development: ```bash -icp deploy +npm run dev ``` -Stop the local network when done: +When done, stop the local network to free the port and clear state: ```bash icp network stop @@ -74,4 +67,4 @@ candid-extractor target/wasm32-unknown-unknown/release/backend.wasm > backend/ba ## Security considerations and best practices -If you base your application on this example, it is recommended that you familiarize yourself with and adhere to the [security best practices](https://docs.internetcomputer.org/building-apps/security/overview) for developing on ICP. This example may not implement all the best practices. +If you base your application on this example, it is recommended that you familiarize yourself with and adhere to the [security best practices](https://docs.internetcomputer.org/guides/security/overview) for developing on ICP. This example may not implement all the best practices. diff --git a/rust/hello_world/dfx.json b/rust/hello_world/dfx.json deleted file mode 100644 index 6ed5a89e5..000000000 --- a/rust/hello_world/dfx.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "canisters": { - "backend": { - "candid": "backend/backend.did", - "type": "custom", - "shrink": true, - "gzip": true, - "wasm": "target/wasm32-unknown-unknown/release/backend.wasm", - "build": [ - "cargo build --target wasm32-unknown-unknown --release -p backend", - "candid-extractor target/wasm32-unknown-unknown/release/backend.wasm > backend/backend.did" - ], - "metadata": [ - { - "name": "candid:service" - } - ] - }, - "frontend": { - "dependencies": ["backend"], - "frontend": { - "entrypoint": "frontend/index.html" - }, - "source": ["frontend/dist"], - "type": "assets" - } - }, - "output_env_file": ".env" -} diff --git a/rust/who_am_i/.devcontainer/devcontainer.json b/rust/who_am_i/.devcontainer/devcontainer.json deleted file mode 100644 index ebb0b8bcc..000000000 --- a/rust/who_am_i/.devcontainer/devcontainer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "ICP Dev Environment", - "image": "ghcr.io/dfinity/icp-dev-env-slim:22", - "forwardPorts": [4943, 5173], - "portsAttributes": { - "4943": { - "label": "dfx", - "onAutoForward": "ignore" - }, - "5173": { - "label": "vite", - "onAutoForward": "openBrowser" - } - }, - "customizations": { - "vscode": { - "extensions": ["dfinity-foundation.vscode-motoko"] - } - } -} diff --git a/rust/who_am_i/.gitignore b/rust/who_am_i/.gitignore index 2a822d5c2..fcacb2b70 100644 --- a/rust/who_am_i/.gitignore +++ b/rust/who_am_i/.gitignore @@ -1 +1 @@ -src/internet_identity_app_frontend/src/bindings/ +src/frontend/src/bindings/ diff --git a/rust/who_am_i/BUILD.md b/rust/who_am_i/BUILD.md deleted file mode 100644 index 8877d3ed2..000000000 --- a/rust/who_am_i/BUILD.md +++ /dev/null @@ -1,26 +0,0 @@ -# Continue building locally - -Projects deployed through ICP Ninja are temporary; they will only be live for 30 minutes before they are removed. To continue building locally, follow these steps. - -### 1. Install developer tools - -Install [Node.js](https://nodejs.org/en/download/) and [icp-cli](https://cli.internetcomputer.org): - -```bash -npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm -``` - -Then navigate into your project's directory that you downloaded from ICP Ninja. - -### 2. Deploy locally - -Start the local network and deploy the project: - -```bash -icp network start -d -icp deploy -``` - -## Additional examples - -Additional code examples and sample applications can be found in the [DFINITY examples repo](https://github.com/dfinity/examples). diff --git a/rust/who_am_i/Cargo.lock b/rust/who_am_i/Cargo.lock index b830c16d5..bc1209943 100644 --- a/rust/who_am_i/Cargo.lock +++ b/rust/who_am_i/Cargo.lock @@ -298,7 +298,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] -name = "internet_identity_app_backend" +name = "backend" version = "0.1.0" dependencies = [ "candid", diff --git a/rust/who_am_i/Cargo.toml b/rust/who_am_i/Cargo.toml index b72184e38..4c16df46e 100644 --- a/rust/who_am_i/Cargo.toml +++ b/rust/who_am_i/Cargo.toml @@ -1,3 +1,3 @@ [workspace] -members = ["src/internet_identity_app_backend"] +members = ["src/backend"] resolver = "2" diff --git a/rust/who_am_i/Makefile b/rust/who_am_i/Makefile new file mode 100644 index 000000000..e5eba77f5 --- /dev/null +++ b/rust/who_am_i/Makefile @@ -0,0 +1,14 @@ +.PHONY: test + +test: + @echo "--- Testing whoami returns a principal ---" + @result=$$(icp canister call backend whoami '()') && \ + echo "$$result" && \ + echo "$$result" | grep -q 'principal' && \ + echo "PASS" || (echo "FAIL" && exit 1) + + @echo "--- Testing whoami is deterministic ---" + @result1=$$(icp canister call backend whoami '()') && \ + result2=$$(icp canister call backend whoami '()') && \ + [ "$$result1" = "$$result2" ] && \ + echo "PASS: $$result1" || (echo "FAIL: $$result1 != $$result2" && exit 1) diff --git a/rust/who_am_i/README.md b/rust/who_am_i/README.md index 236aa318e..4adf10069 100644 --- a/rust/who_am_i/README.md +++ b/rust/who_am_i/README.md @@ -6,20 +6,12 @@ Who am I? demonstrates how entities on the Internet Computer are identified. Every entity, such as a user or canister smart contract, has a principal identifier. Principals can be used for identification and authentication. Who am I? uses Internet Identity (II) for user authentication, then displays the principal identifier associated with that Internet Identity on the user interface. -## Deploying from ICP Ninja - -This example can be deployed directly from [ICP Ninja](https://icp.ninja), a browser-based IDE for ICP. To continue developing locally after deploying from ICP Ninja, see [BUILD.md](BUILD.md). - -[![Open in ICP Ninja](https://icp.ninja/assets/open.svg)](https://icp.ninja/i?g=https://github.com/dfinity/examples/rust/who_am_i) - -> **Note:** ICP Ninja currently uses `dfx` under the hood, which is why this example includes a `dfx.json` configuration file. `dfx` is the legacy CLI, being superseded by [icp-cli](https://cli.internetcomputer.org), which is what developers should use for local development. - ## Build and deploy from the command line ### Prerequisites -- [x] Install [Node.js](https://nodejs.org/en/download/) -- [x] Install [icp-cli](https://cli.internetcomputer.org): `npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm` +- Install [Node.js](https://nodejs.org/en/download/) +- Install [icp-cli](https://cli.internetcomputer.org): `npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm` ### Install @@ -30,37 +22,42 @@ git clone https://github.com/dfinity/examples cd examples/rust/who_am_i ``` -### Deployment +### Deploy -Start the local network: +Start the local network and deploy: ```bash icp network start -d +icp deploy ``` -Deploy the canisters: +The frontend is served by the asset canister. To run the Vite dev server with hot reload during frontend development: ```bash -icp deploy +npm run dev ``` -Stop the local network when done: +When done, stop the local network to free the port and clear state: ```bash icp network stop ``` +## Ready to deploy on mainnet? + +When you're ready for mainnet, [install icp-cli locally](https://cli.internetcomputer.org) and follow the [mainnet deployment guide](https://cli.internetcomputer.org/0.2/guides/deploying-to-mainnet.md). Mainnet requires ICP tokens and cycles — managing identities securely is much better from your own machine. + ## Updating the Candid interface -The `src/internet_identity_app_backend/internet_identity_app_backend.did` file defines the backend canister's public interface. The frontend TypeScript bindings are auto-generated from this file during the frontend build. +The `src/backend/backend.did` file defines the backend canister's public interface. The frontend TypeScript bindings are auto-generated from this file during the frontend build. If you modify the backend's public API, rebuild the canister and regenerate the `.did` file: ```bash -icp build internet_identity_app_backend -candid-extractor target/wasm32-unknown-unknown/release/internet_identity_app_backend.wasm > src/internet_identity_app_backend/internet_identity_app_backend.did +icp build backend +candid-extractor target/wasm32-unknown-unknown/release/backend.wasm > src/backend/backend.did ``` ## Security considerations and best practices -If you base your application on this example, it is recommended that you familiarize yourself with and adhere to the [security best practices](https://docs.internetcomputer.org/building-apps/security/overview) for developing on ICP. This example may not implement all the best practices. +If you base your application on this example, it is recommended that you familiarize yourself with and adhere to the [security best practices](https://docs.internetcomputer.org/guides/security/overview) for developing on ICP. This example may not implement all the best practices. diff --git a/rust/who_am_i/dfx.json b/rust/who_am_i/dfx.json deleted file mode 100644 index a4c690961..000000000 --- a/rust/who_am_i/dfx.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "canisters": { - "internet_identity_app_backend": { - "candid": "src/internet_identity_app_backend/internet_identity_app_backend.did", - "package": "internet_identity_app_backend", - "type": "rust" - }, - "internet_identity_app_frontend": { - "dependencies": ["internet_identity_app_backend"], - "internet_identity_app_frontend": { - "entrypoint": "src/internet_identity_app_frontend/index.html" - }, - "source": ["src/internet_identity_app_frontend/dist"], - "type": "assets" - }, - "internet_identity": { - "candid": "https://github.com/dfinity/internet-identity/releases/latest/download/internet_identity.did", - "type": "custom", - "specified_id": "rdmx6-jaaaa-aaaaa-aaadq-cai", - "remote": { - "id": { - "ic": "rdmx6-jaaaa-aaaaa-aaadq-cai" - } - }, - "wasm": "https://github.com/dfinity/internet-identity/releases/latest/download/internet_identity_production.wasm.gz" - }, - "internet_identity_frontend": { - "candid": "https://raw.githubusercontent.com/dfinity/internet-identity/refs/heads/main/src/internet_identity_frontend/internet_identity_frontend.did", - "type": "custom", - "specified_id": "uqzsh-gqaaa-aaaaq-qaada-cai", - "remote": { - "id": { - "ic": "uqzsh-gqaaa-aaaaq-qaada-cai" - } - }, - "wasm": "https://github.com/dfinity/internet-identity/releases/latest/download/internet_identity_frontend.wasm.gz", - "init_arg": "(record { fetch_root_key = opt true; dev_csp = opt true; backend_canister_id = principal \"rdmx6-jaaaa-aaaaa-aaadq-cai\"; analytics_config = null; related_origins = opt vec { \"http://uqzsh-gqaaa-aaaaq-qaada-cai.localhost:4943\" }; backend_origin = \"http://rdmx6-jaaaa-aaaaa-aaadq-cai.localhost:4943\"; captcha_config = opt record { max_unsolved_captchas = 50 : nat64; captcha_trigger = variant { Static = variant { CaptchaDisabled } } }})" - } - }, - "output_env_file": ".env" -} \ No newline at end of file diff --git a/rust/who_am_i/icp.yaml b/rust/who_am_i/icp.yaml index e354013ab..bae2f48bc 100644 --- a/rust/who_am_i/icp.yaml +++ b/rust/who_am_i/icp.yaml @@ -4,18 +4,18 @@ networks: ii: true canisters: - - name: internet_identity_app_backend + - name: backend recipe: type: "@dfinity/rust@v3.2.0" configuration: - package: internet_identity_app_backend - candid: src/internet_identity_app_backend/internet_identity_app_backend.did + package: backend + candid: src/backend/backend.did - - name: internet_identity_app_frontend + - name: frontend recipe: type: "@dfinity/asset-canister@v2.1.0" configuration: - dir: src/internet_identity_app_frontend/dist + dir: src/frontend/dist build: - - npm install --prefix src/internet_identity_app_frontend - - npm run build --prefix src/internet_identity_app_frontend + - npm install --prefix src/frontend + - npm run build --prefix src/frontend diff --git a/rust/who_am_i/package.json b/rust/who_am_i/package.json index 3544e9035..2d7d15ddb 100644 --- a/rust/who_am_i/package.json +++ b/rust/who_am_i/package.json @@ -3,7 +3,7 @@ "node": ">=16.0.0", "npm": ">=7.0.0" }, - "name": "internet_identity_app", + "name": "who-am-i", "scripts": { "build": "npm run build --workspaces --if-present", "prebuild": "npm run prebuild --workspaces --if-present", @@ -13,6 +13,6 @@ }, "type": "module", "workspaces": [ - "src/internet_identity_app_frontend" + "src/frontend" ] } diff --git a/rust/who_am_i/src/internet_identity_app_backend/Cargo.toml b/rust/who_am_i/src/backend/Cargo.toml similarity index 85% rename from rust/who_am_i/src/internet_identity_app_backend/Cargo.toml rename to rust/who_am_i/src/backend/Cargo.toml index ceda7f950..734a31d6b 100644 --- a/rust/who_am_i/src/internet_identity_app_backend/Cargo.toml +++ b/rust/who_am_i/src/backend/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "internet_identity_app_backend" +name = "backend" version = "0.1.0" edition = "2021" diff --git a/rust/who_am_i/src/internet_identity_app_backend/internet_identity_app_backend.did b/rust/who_am_i/src/backend/backend.did similarity index 100% rename from rust/who_am_i/src/internet_identity_app_backend/internet_identity_app_backend.did rename to rust/who_am_i/src/backend/backend.did diff --git a/rust/who_am_i/src/internet_identity_app_backend/src/lib.rs b/rust/who_am_i/src/backend/src/lib.rs similarity index 100% rename from rust/who_am_i/src/internet_identity_app_backend/src/lib.rs rename to rust/who_am_i/src/backend/src/lib.rs diff --git a/rust/who_am_i/src/internet_identity_app_frontend/index.css b/rust/who_am_i/src/frontend/index.css similarity index 100% rename from rust/who_am_i/src/internet_identity_app_frontend/index.css rename to rust/who_am_i/src/frontend/index.css diff --git a/rust/who_am_i/src/internet_identity_app_frontend/index.html b/rust/who_am_i/src/frontend/index.html similarity index 100% rename from rust/who_am_i/src/internet_identity_app_frontend/index.html rename to rust/who_am_i/src/frontend/index.html diff --git a/motoko/who_am_i/src/internet_identity_app_frontend/package.json b/rust/who_am_i/src/frontend/package.json similarity index 91% rename from motoko/who_am_i/src/internet_identity_app_frontend/package.json rename to rust/who_am_i/src/frontend/package.json index 49a3f1ace..412b87e6d 100644 --- a/motoko/who_am_i/src/internet_identity_app_frontend/package.json +++ b/rust/who_am_i/src/frontend/package.json @@ -1,5 +1,5 @@ { - "name": "internet_identity_app_frontend", + "name": "frontend", "private": true, "type": "module", "scripts": { diff --git a/rust/who_am_i/src/internet_identity_app_frontend/public/favicon.ico b/rust/who_am_i/src/frontend/public/favicon.ico similarity index 100% rename from rust/who_am_i/src/internet_identity_app_frontend/public/favicon.ico rename to rust/who_am_i/src/frontend/public/favicon.ico diff --git a/rust/who_am_i/src/internet_identity_app_frontend/src/App.jsx b/rust/who_am_i/src/frontend/src/App.jsx similarity index 100% rename from rust/who_am_i/src/internet_identity_app_frontend/src/App.jsx rename to rust/who_am_i/src/frontend/src/App.jsx diff --git a/motoko/who_am_i/src/internet_identity_app_frontend/src/actor.js b/rust/who_am_i/src/frontend/src/actor.js similarity index 77% rename from motoko/who_am_i/src/internet_identity_app_frontend/src/actor.js rename to rust/who_am_i/src/frontend/src/actor.js index becf24513..1e4ac04ad 100644 --- a/motoko/who_am_i/src/internet_identity_app_frontend/src/actor.js +++ b/rust/who_am_i/src/frontend/src/actor.js @@ -1,15 +1,15 @@ import { safeGetCanisterEnv } from "@icp-sdk/core/agent/canister-env"; -import { createActor } from "./bindings/internet_identity_app_backend"; +import { createActor } from "./bindings/backend"; const canisterEnv = safeGetCanisterEnv(); const canisterId = - canisterEnv?.["PUBLIC_CANISTER_ID:internet_identity_app_backend"] ?? - process.env.CANISTER_ID_INTERNET_IDENTITY_APP_BACKEND; + canisterEnv?.["PUBLIC_CANISTER_ID:backend"] ?? + process.env.CANISTER_ID_BACKEND; if (!canisterId) { throw new Error( - "Canister ID for 'internet_identity_app_backend' not found. Run 'icp deploy' or 'dfx deploy' first." + "Canister ID for 'backend' not found. Run 'icp deploy' first." ); } diff --git a/rust/who_am_i/src/internet_identity_app_frontend/src/main.jsx b/rust/who_am_i/src/frontend/src/main.jsx similarity index 100% rename from rust/who_am_i/src/internet_identity_app_frontend/src/main.jsx rename to rust/who_am_i/src/frontend/src/main.jsx diff --git a/rust/who_am_i/src/internet_identity_app_frontend/tsconfig.json b/rust/who_am_i/src/frontend/tsconfig.json similarity index 100% rename from rust/who_am_i/src/internet_identity_app_frontend/tsconfig.json rename to rust/who_am_i/src/frontend/tsconfig.json diff --git a/motoko/who_am_i/src/internet_identity_app_frontend/vite.config.js b/rust/who_am_i/src/frontend/vite.config.js similarity index 50% rename from motoko/who_am_i/src/internet_identity_app_frontend/vite.config.js rename to rust/who_am_i/src/frontend/vite.config.js index 41d03427c..8bb840ac3 100644 --- a/motoko/who_am_i/src/internet_identity_app_frontend/vite.config.js +++ b/rust/who_am_i/src/frontend/vite.config.js @@ -4,9 +4,8 @@ import react from "@vitejs/plugin-react"; import { icpBindgen } from "@icp-sdk/bindgen/plugins/vite"; function getDevServerConfig() { - // Try icp-cli first try { - const canisterId = execSync("icp canister status internet_identity_app_backend -e local -i", { + const canisterId = execSync("icp canister status backend -e local -i", { encoding: "utf-8", stdio: "pipe", }).trim(); @@ -20,7 +19,7 @@ function getDevServerConfig() { replicaPort: "8000", headers: { "Set-Cookie": `ic_env=${encodeURIComponent( - `ic_root_key=${networkStatus.root_key}&PUBLIC_CANISTER_ID:internet_identity_app_backend=${canisterId}` + `ic_root_key=${networkStatus.root_key}&PUBLIC_CANISTER_ID:backend=${canisterId}` )}; SameSite=Lax;`, }, proxy: { @@ -29,46 +28,12 @@ function getDevServerConfig() { }; } catch {} - // Try dfx - try { - const pingResult = JSON.parse( - execSync("dfx ping", { encoding: "utf-8", stdio: "pipe" }) - ); - const rootKeyHex = Buffer.from(pingResult.root_key).toString("hex"); - const canisterId = execSync( - "dfx canister id internet_identity_app_backend", - { - encoding: "utf-8", - stdio: "pipe", - } - ).trim(); - return { - replicaPort: "4943", - headers: { - "Set-Cookie": `ic_env=${encodeURIComponent( - `ic_root_key=${rootKeyHex}&PUBLIC_CANISTER_ID:internet_identity_app_backend=${canisterId}` - )}; SameSite=Lax;`, - }, - proxy: { - "/api": { - target: "http://127.0.0.1:4943", - changeOrigin: true, - }, - }, - host: "127.0.0.1", - }; - } catch {} - throw new Error( - "No local network running. Start with:\n icp network start -d && icp deploy\nor:\n dfx start --background && dfx deploy" + "No local network running. Start with:\n icp network start -d && icp deploy" ); } export default defineConfig(({ command, mode }) => { - // dfx generates ../../.env with CANISTER_ID_* vars on deploy. Bake them into - // the bundle so actor.js can fall back to them when the ic_env cookie does not - // contain canister IDs (dfx does not inject PUBLIC_CANISTER_ID:* env vars - // into the asset canister, unlike icp-cli). const env = loadEnv(mode, "../..", ["CANISTER_"]); const devConfig = command === "serve" ? getDevServerConfig() : undefined; @@ -77,14 +42,13 @@ export default defineConfig(({ command, mode }) => { plugins: [ react(), icpBindgen({ - didFile: - "../internet_identity_app_backend/internet_identity_app_backend.did", + didFile: "../backend/backend.did", outDir: "./src/bindings", }), ], define: { - "process.env.CANISTER_ID_INTERNET_IDENTITY_APP_BACKEND": JSON.stringify( - env.CANISTER_ID_INTERNET_IDENTITY_APP_BACKEND + "process.env.CANISTER_ID_BACKEND": JSON.stringify( + env.CANISTER_ID_BACKEND ), "process.env.REPLICA_PORT": JSON.stringify(devConfig?.replicaPort ?? ""), },