diff --git a/.llms-snapshots/llms-full.txt b/.llms-snapshots/llms-full.txt index b06a4431..ba7dd15f 100644 --- a/.llms-snapshots/llms-full.txt +++ b/.llms-snapshots/llms-full.txt @@ -3077,6 +3077,170 @@ The following functions from `@junobuild/core` are used in this example: | `uploadFile` | Upload a file to storage | [`src/components/Modal.vue`](https://github.com/junobuild/create-juno/blob/main/templates/vue-example/src/components/Modal.vue) | [Upload file](/docs/build/storage/development.md#upload-file) | | `deleteAsset` | Delete a file from storage | [`src/components/Delete.vue`](https://github.com/junobuild/create-juno/blob/main/templates/vue-example/src/components/Delete.vue) | [Delete asset](/docs/build/storage/development.md#delete-asset) | +# Rust Assertions Example + +This example demonstrates how to write a **custom assertion** in **Rust** for a Juno **serverless function**. It shows how to intercept and validate data operations—such as rejecting specific content—before it's written to the datastore. + +The project includes a minimal frontend to help trigger and test the logic, but the primary focus is the backend assertion. + +You can browse the source code here: [github.com/junobuild/examples/tree/main/rust/assertions](https://github.com/junobuild/examples/tree/main/rust/assertions) + +--- + +## Folder Structure + +``` +rust/assertions/├── src/│ ├── satellite/ # Rust Satellite serverless function│ │ ├── src/│ │ │ └── lib.rs # Main Rust logic for Satellite│ │ ├── satellite.did # Candid interface definition│ │ └── Cargo.toml # Rust package config├── src/components/ # Minimal frontend React components├── juno.config.ts # Juno Satellite configuration├── package.json # Frontend dependencies└── ... +``` + +--- + +## Key Features + +* **Custom Assertions in Rust**: Demonstrates how to reject or validate data before it's saved, using Rust serverless functions. +* **Serverless Integration**: Runs as a Satellite function and integrates with Juno's datastore and authentication system. +* **Minimal UI for Testing**: A simple frontend is included to test and demonstrate the assertion logic in action. + +--- + +## Main Backend Components + +* **src/satellite/src/lib.rs**: The core Rust logic for the Satellite serverless function. Implements the custom assertions (e.g., only allow certain valid inputs, etc.). +* **src/satellite/Cargo.toml**: Rust package configuration for the Satellite function. + +--- + +## Example: Custom Assertion in Rust + +Here’s the actual Rust logic from `lib.rs`: + +``` +// This example defines a custom assertion in a Juno Satellite using Rust.// It checks if a document being saved to the "notes" collection contains the word "hello".// If it does, the assertion rejects the operation and logs a message.use ic_cdk::print;use junobuild_macros::assert_set_doc;use junobuild_satellite::{include_satellite, AssertSetDocContext};use junobuild_utils::decode_doc_data;use serde::{Deserialize, Serialize};#[derive(Serialize, Deserialize)]struct Note { text: String, url: Option,}#[assert_set_doc(collections = ["notes"])]fn assert_set_doc(context: AssertSetDocContext) -> Result<(), String> { let note = decode_doc_data::(&context.data.data.proposed.data)?; if note.text.to_lowercase().contains("hello") { print(format!("❌ Rejected note containing 'hello': {}", note.text)); return Err("The note should not contain the keyword 'hello'.".to_string()); } print(format!("✅ Note accepted: {}", note.text)); Ok(())}include_satellite!(); +``` + +**Explanation:** + +* Defines a `Note` struct with `text` and optional `url` fields. Similar as the fields used in the frontend. +* Uses the `#[assert_set_doc]` macro to create a custom assertion for the `notes` collection. +* When a note is created or updated, the assertion checks if the note's text contains the word "hello" (case-insensitive). +* If it does, the note is rejected and an error message is returned; otherwise, the note is accepted. +* Prints a message to the log for both accepted and rejected notes. +* `include_satellite!();` brings in the necessary boilerplate for the Juno Satellite runtime. + +--- + +## How to Run + +1. **Clone the repo**: + +``` +git clone https://github.com/junobuild/examplescd rust/assertions +``` + +2. **Install dependencies**: + +``` +npm install +``` + +3. **Start Juno local emulator**: + +**Important:** + +Requires the Juno CLI to be available `npm i -g @junobuild/cli` + +``` +juno dev start +``` + +4. **Create a Satellite** for local dev: + +* Visit [http://localhost:5866](http://localhost:5866) and follow the instructions. +* Update `juno.config.ts` with your Satellite ID. + +5. **Create required collections**: + +* `notes` in Datastore: [http://localhost:5866/datastore](http://localhost:5866/datastore) +* `images` in Storage: [http://localhost:5866/storage](http://localhost:5866/storage) + +6. **Start the frontend dev server** (in a separate terminal): + +``` +npm run dev +``` + +6. **Build the serverless functions** (in a separate terminal): + +``` +juno functions build +``` + +The emulator will automatically upgrade your Satellite and live reload the changes. + +--- + +## Juno-Specific Configuration + +* **juno.config.ts**: Defines Satellite IDs for development/production, build source, and predeploy steps. See the [Configuration reference](/docs/reference/configuration.md) for details. +* **vite.config.ts**: Registers the `juno` plugin to inject environment variables automatically. See the [Vite Plugin reference](/docs/reference/plugins.md#vite-plugin) for more information. + +--- + +## Production Deployment + +* Create a Satellite on the [Juno Console](https://console.juno.build) for mainnet. +* Update `juno.config.ts` with the production Satellite ID. +* Build and deploy the frontend: + +``` +npm run buildjuno deploy +``` + +* Build and upgrade the serverless functions: + +``` +juno functions buildjuno functions upgrade +``` + +--- + +## Notes + +* This example focuses on the Rust serverless function; the frontend is intentionally minimal and only included for demonstration purposes. +* Use this project as a starting point for writing custom assertions and backend logic in Rust with Juno. + +--- + +## Real-World Example + +Want to see how assertions and serverless logic are used in a live project? + +Check out [proposals.network](https://proposals.network), an open-source app built with Juno: + +* GitHub: [github.com/peterpeterparker/proposals.network](https://github.com/peterpeterparker/proposals.network) +* Example logic: [src/satellite/src/lib.rs](https://github.com/peterpeterparker/proposals.network/blob/main/src/satellite/src/lib.rs) + +This app uses: + +* `#[on_delete_doc]` and `#[assert_delete_doc]` to validate and clean up related documents and assets +* Shared helper modules like `assert`, `delete`, and `types` to keep logic organized +* A real-world pattern of chaining asset/document deletions with assertions + +It’s a great reference for more advanced setups and multi-collection coordination. + +--- + +## References + +* [Serverless Functions Guide](/docs/guides/rust.md) +* [Rust Functions Development](/docs/build/functions.md) +* [Rust SDK Reference](/docs/reference/functions/rust/sdk.md) +* [Rust Utils Reference](/docs/reference/functions/rust/utils.md) +* [Run Local Development](/docs/guides/local-development.md) +* [CLI Reference](/docs/reference/cli.md) +* [Configuration Reference](/docs/reference/configuration.md) +* [Datastore Collections](/docs/build/datastore/collections.md) + # Using Juno with AI If you're using AI to build with Juno, you can use our `llms.txt` files to help AI tools better understand the platform. diff --git a/.llms-snapshots/llms.txt b/.llms-snapshots/llms.txt index 03f9604e..a6077d17 100644 --- a/.llms-snapshots/llms.txt +++ b/.llms-snapshots/llms.txt @@ -56,6 +56,10 @@ Juno is your self-contained serverless platform for building full-stack web apps - [Vanilla JavaScript Example](https://juno.build/docs/examples/frontend/vanilla-javascript.md): A fullstack note-taking app built with vanilla JavaScript, and Tailwind CSS using Juno for authentication, data, and file storage. - [Vue Example](https://juno.build/docs/examples/frontend/vue.md): A fullstack note-taking app built with Vue, and Tailwind CSS using Juno for authentication, data, and file storage. +## Examples - Functions - Rust + +- [Rust Assertions Example](https://juno.build/docs/examples/functions/rust/assertions.md): An example demonstrating how to write custom assertions in Rust for Juno serverless functions. + ## Guides - [AI](https://juno.build/docs/guides/ai.md): Learn how to use Juno's llms.txt files to provide AI tools with better context for building serverless functions, deploying satellites, and integrating the SDK. diff --git a/docs/examples/functions/rust/assertions.mdx b/docs/examples/functions/rust/assertions.mdx new file mode 100644 index 00000000..9b5602b4 --- /dev/null +++ b/docs/examples/functions/rust/assertions.mdx @@ -0,0 +1,215 @@ +--- +title: Rust Assertions Example +description: An example demonstrating how to write custom assertions in Rust for Juno serverless functions. +keywords: [rust, assertion, serverless, juno, satellite, example] +sidebar_label: Assertions +--- + +# Rust Assertions Example + +This example demonstrates how to write a **custom assertion** in **Rust** for a Juno **serverless function**. It shows how to intercept and validate data operations—such as rejecting specific content—before it's written to the datastore. + +The project includes a minimal frontend to help trigger and test the logic, but the primary focus is the backend assertion. + +You can browse the source code here: [github.com/junobuild/examples/tree/main/rust/assertions](https://github.com/junobuild/examples/tree/main/rust/assertions) + +--- + +## Folder Structure + +``` +rust/assertions/ +├── src/ +│ ├── satellite/ # Rust Satellite serverless function +│ │ ├── src/ +│ │ │ └── lib.rs # Main Rust logic for Satellite +│ │ ├── satellite.did # Candid interface definition +│ │ └── Cargo.toml # Rust package config +├── src/components/ # Minimal frontend React components +├── juno.config.ts # Juno Satellite configuration +├── package.json # Frontend dependencies +└── ... +``` + +--- + +## Key Features + +- **Custom Assertions in Rust**: Demonstrates how to reject or validate data before it's saved, using Rust serverless functions. +- **Serverless Integration**: Runs as a Satellite function and integrates with Juno's datastore and authentication system. +- **Minimal UI for Testing**: A simple frontend is included to test and demonstrate the assertion logic in action. + +--- + +## Main Backend Components + +- **src/satellite/src/lib.rs**: The core Rust logic for the Satellite serverless function. Implements the custom assertions (e.g., only allow certain valid inputs, etc.). +- **src/satellite/Cargo.toml**: Rust package configuration for the Satellite function. + +--- + +## Example: Custom Assertion in Rust + +Here’s the actual Rust logic from `lib.rs`: + +```rust +// This example defines a custom assertion in a Juno Satellite using Rust. +// It checks if a document being saved to the "notes" collection contains the word "hello". +// If it does, the assertion rejects the operation and logs a message. + +use ic_cdk::print; +use junobuild_macros::assert_set_doc; +use junobuild_satellite::{include_satellite, AssertSetDocContext}; +use junobuild_utils::decode_doc_data; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize)] +struct Note { + text: String, + url: Option, +} + +#[assert_set_doc(collections = ["notes"])] +fn assert_set_doc(context: AssertSetDocContext) -> Result<(), String> { + let note = decode_doc_data::(&context.data.data.proposed.data)?; + + if note.text.to_lowercase().contains("hello") { + print(format!("❌ Rejected note containing 'hello': {}", note.text)); + return Err("The note should not contain the keyword 'hello'.".to_string()); + } + + print(format!("✅ Note accepted: {}", note.text)); + + Ok(()) +} + +include_satellite!(); +``` + +**Explanation:** + +- Defines a `Note` struct with `text` and optional `url` fields. Similar as the fields used in the frontend. +- Uses the `#[assert_set_doc]` macro to create a custom assertion for the `notes` collection. +- When a note is created or updated, the assertion checks if the note's text contains the word "hello" (case-insensitive). +- If it does, the note is rejected and an error message is returned; otherwise, the note is accepted. +- Prints a message to the log for both accepted and rejected notes. +- `include_satellite!();` brings in the necessary boilerplate for the Juno Satellite runtime. + +--- + +## How to Run + +1. **Clone the repo**: + +```bash +git clone https://github.com/junobuild/examples +cd rust/assertions +``` + +2. **Install dependencies**: + +```bash +npm install +``` + +3. **Start Juno local emulator**: + +:::important + +Requires the Juno CLI to be available `npm i -g @junobuild/cli` + +::: + +```bash +juno dev start +``` + +4. **Create a Satellite** for local dev: + +- Visit [http://localhost:5866](http://localhost:5866) and follow the instructions. +- Update `juno.config.ts` with your Satellite ID. + +5. **Create required collections**: + +- `notes` in Datastore: [http://localhost:5866/datastore](http://localhost:5866/datastore) +- `images` in Storage: [http://localhost:5866/storage](http://localhost:5866/storage) + +6. **Start the frontend dev server** (in a separate terminal): + +```bash +npm run dev +``` + +6. **Build the serverless functions** (in a separate terminal): + +```bash +juno functions build +``` + +The emulator will automatically upgrade your Satellite and live reload the changes. + +--- + +## Juno-Specific Configuration + +- **juno.config.ts**: Defines Satellite IDs for development/production, build source, and predeploy steps. See the [Configuration reference](../../../reference/configuration.mdx) for details. +- **vite.config.ts**: Registers the `juno` plugin to inject environment variables automatically. See the [Vite Plugin reference](../../../reference/plugins.mdx#vite-plugin) for more information. + +--- + +## Production Deployment + +- Create a Satellite on the [Juno Console](https://console.juno.build) for mainnet. +- Update `juno.config.ts` with the production Satellite ID. +- Build and deploy the frontend: + +```bash +npm run build +juno deploy +``` + +- Build and upgrade the serverless functions: + +```bash +juno functions build +juno functions upgrade +``` + +--- + +## Notes + +- This example focuses on the Rust serverless function; the frontend is intentionally minimal and only included for demonstration purposes. +- Use this project as a starting point for writing custom assertions and backend logic in Rust with Juno. + +--- + +## Real-World Example + +Want to see how assertions and serverless logic are used in a live project? + +Check out [proposals.network](https://proposals.network), an open-source app built with Juno: + +- GitHub: [github.com/peterpeterparker/proposals.network](https://github.com/peterpeterparker/proposals.network) +- Example logic: [src/satellite/src/lib.rs](https://github.com/peterpeterparker/proposals.network/blob/main/src/satellite/src/lib.rs) + +This app uses: + +- `#[on_delete_doc]` and `#[assert_delete_doc]` to validate and clean up related documents and assets +- Shared helper modules like `assert`, `delete`, and `types` to keep logic organized +- A real-world pattern of chaining asset/document deletions with assertions + +It’s a great reference for more advanced setups and multi-collection coordination. + +--- + +## References + +- [Serverless Functions Guide](../../../guides/rust.mdx) +- [Rust Functions Development](../../../build/functions/index.md) +- [Rust SDK Reference](../../../reference/functions/rust/sdk.mdx) +- [Rust Utils Reference](../../../reference/functions/rust/utils.mdx) +- [Run Local Development](../../../guides/local-development.mdx) +- [CLI Reference](../../../reference/cli) +- [Configuration Reference](../../../reference/configuration.mdx) +- [Datastore Collections](../../../build/datastore/collections.md) diff --git a/sidebars.ts b/sidebars.ts index 68870cae..a02ef2b0 100644 --- a/sidebars.ts +++ b/sidebars.ts @@ -110,7 +110,18 @@ const sidebars: SidebarsConfig = { description: "Write serverless backend logic for your app using TypeScript or Rust. These examples show how to use hooks, assertions, and common function patterns on Juno." }, - items: [] + items: [ + { + type: "category", + label: "Rust", + link: { + type: "generated-index", + description: + "Examples of writing serverless functions in Rust for Juno. Includes patterns like custom assertions, data manipulation and calls." + }, + items: ["examples/functions/rust/assertions"] + } + ] } ] },