You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* docs: asset generation example
Signed-off-by: David Dal Busco <david.dalbusco@outlook.com>
* fix: build
Signed-off-by: David Dal Busco <david.dalbusco@outlook.com>
* 📄 Update LLMs.txt snapshot for PR review
---------
Signed-off-by: David Dal Busco <david.dalbusco@outlook.com>
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
@@ -3286,6 +3286,169 @@ These crates are used to build and extend serverless functions in Rust with Juno
3286
3286
* [junobuild-satellite](https://docs.rs/junobuild-satellite): Core features and runtime for building a Satellite in Rust, including hooks, assertions, and datastore integration.
3287
3287
* [junobuild-macros](https://docs.rs/junobuild-macros): Procedural macros for declaratively attaching hooks and assertions.
3288
3288
* [junobuild-utils](https://docs.rs/junobuild-utils): Utility helpers for working with documents, including data encoding, decoding, and assertion context handling.
3289
+
* [junobuild-shared](https://docs.rs/junobuild-shared): Shared types and helpers for Juno projects. Used by all containers including the Console.
3290
+
* [junobuild-storage](https://docs.rs/junobuild-storage): Storage helpers for working with assets and HTTP headers in Juno.
3291
+
3292
+
# Generating Assets with Rust Serverless Functions
3293
+
3294
+
This example demonstrates how to use **Rust serverless functions** to dynamically generate and store assets in **Juno Storage** from a **Satellite**. In this example, the generated assets are JSON files.
3295
+
3296
+
Each time a note is added through the frontend, the Satellite saves the note as an individual JSON file and updates a list of all notes as another JSON file. This pattern is useful for exposing structured, queryable data as static assets — consumable by your frontend or external services.
3297
+
3298
+
You can browse the source code here: [github.com/junobuild/examples/tree/main/rust/json](https://github.com/junobuild/examples/tree/main/rust/json)
* **Serverless JSON Generation**: Demonstrates how to generate and store JSON files in Storage from Rust serverless functions.
3313
+
* **Automatic List Updates**: Each note addition updates both the individual note JSON and a list of all notes as JSON.
3314
+
* **Integration with Juno Storage**: Uses Juno's Storage API to expose JSON assets on the web.
3315
+
* **Minimal SvelteKit UI**: A simple SvelteKit frontend is included to test and demonstrate the logic.
3316
+
3317
+
---
3318
+
3319
+
## Main Backend Components
3320
+
3321
+
* **src/satellite/src/lib.rs**: The entry point for the Satellite serverless function. Triggers JSON generation and list update on document set.
3322
+
* **src/satellite/src/generators.rs**: Helper logic for encoding notes and lists as JSON and storing them as assets.
3323
+
* **src/satellite/Cargo.toml**: Rust package configuration for the Satellite function.
3324
+
3325
+
---
3326
+
3327
+
## Example: Generating and Storing JSON
3328
+
3329
+
Here’s the actual Rust logic from `lib.rs` and `generators.rs`:
3330
+
3331
+
```
3332
+
// src/satellite/src/lib.rsmod generators;use crate::generators::{generate_list_of_notes, generate_note};use junobuild_macros::on_set_doc;use junobuild_satellite::{include_satellite, OnSetDocContext};/// Hook triggered whenever a document is set (e.g., added or updated)./// This example:/// - Stores the updated document as an individual JSON file in Storage/// - Updates a list of all note filenames as a separate JSON file#[on_set_doc]async fn on_set_doc(context: OnSetDocContext) -> Result<(), String> { ic_cdk::print("Let's go!"); // Save the current note as a JSON asset generate_note(&context.data.key, &context.data.data.after)?; // Regenerate the list of notes as a JSON array generate_list_of_notes()?; Ok(())}// Boilerplate macro to include the all Satellite runtimeinclude_satellite!();
3333
+
```
3334
+
3335
+
```
3336
+
// src/satellite/src/generators.rsuse junobuild_satellite::{list_assets_store, set_asset_handler, Doc};use junobuild_shared::types::core::Key;use junobuild_shared::types::list::ListParams;use junobuild_storage::http::types::HeaderField;use junobuild_storage::types::store::AssetKey;use junobuild_utils::{decode_doc_data, encode_doc_data_to_string};use serde::{Deserialize, Serialize};/// Represents the expected shape of a note stored in the Datastore#[derive(Serialize, Deserialize)]struct Note { text: String, url: Option<String>,}/// Encodes a note document as JSON and stores it as a `.json` file in Storagepub fn generate_note(key: &Key, doc: &Doc) -> Result<(), String> { let note: Note = decode_doc_data(&doc.data)?; let json = encode_doc_data_to_string(¬e)?; let name = format!("{}.json", key); insert_asset(&name, &json)}const STORAGE_COLLECTION: &str = "json";/// Lists all assets in the `json` collection and stores their filenames/// in a `notes.json` file — a JSON array of all note filenamespub fn generate_list_of_notes() -> Result<(), String> { let params: ListParams = ListParams { matcher: None, paginate: None, order: None, owner: None, }; let result = list_assets_store(ic_cdk::id(), STORAGE_COLLECTION, ¶ms)?; // Extract the full paths of all assets in the collection let list_of_keys: Vec<String> = result .items .iter() .map(|(_, asset)| asset.key.full_path.clone()) .collect(); let json = encode_doc_data_to_string(&list_of_keys)?; let name = "notes.json".to_string(); insert_asset(&name, &json)?; Ok(())}/// Stores a given string as an asset in the `json` collectionfn insert_asset(name: &String, json: &String) -> Result<(), String> { ic_cdk::print(format!("Json: {} {}", name, json)); let full_path = format!("/{}/{}", STORAGE_COLLECTION, name); let key: AssetKey = AssetKey { name: name.clone(), full_path: full_path.clone(), token: None, collection: STORAGE_COLLECTION.to_string(), owner: ic_cdk::id(), description: None, }; // Set appropriate headers for serving JSON let headers = vec![HeaderField( "content-type".to_string(), "application/json".to_string(), )]; // Upload asset to Juno Storage set_asset_handler(&key, &json.as_bytes().to_vec(), &headers)?; ic_cdk::print(format!( "Asset saved in Storage: http://{}.localhost:5987{}", ic_cdk::id(), full_path )); Ok(())}
3337
+
```
3338
+
3339
+
**Explanation:**
3340
+
3341
+
* When a note is added or updated, the `on_set_doc` hook is triggered.
3342
+
* The note is encoded as JSON and stored as an asset in the `json` collection.
3343
+
* A list of all note asset paths is also generated and stored as `notes.json`.
3344
+
* These JSON assets are accessible via the Storage API and can be fetched by the frontend or other clients.
Requires the Juno CLI to be available `npm i -g @junobuild/cli`
3367
+
3368
+
```
3369
+
juno dev start
3370
+
```
3371
+
3372
+
4. **Create a Satellite** for local dev:
3373
+
3374
+
* Visit [http://localhost:5866](http://localhost:5866) and follow the instructions.
3375
+
* Update `juno.config.ts` with your Satellite ID.
3376
+
3377
+
5. **Create required collections**:
3378
+
3379
+
* `demo` in Datastore: [http://localhost:5866/datastore](http://localhost:5866/datastore)
3380
+
* `json` in Storage: [http://localhost:5866/storage](http://localhost:5866/storage)
3381
+
3382
+
6. **Start the frontend dev server** (in a separate terminal):
3383
+
3384
+
```
3385
+
npm run dev
3386
+
```
3387
+
3388
+
7. **Build the serverless functions** (in a separate terminal):
3389
+
3390
+
```
3391
+
juno functions build
3392
+
```
3393
+
3394
+
The emulator will automatically upgrade your Satellite and live reload the changes.
3395
+
3396
+
---
3397
+
3398
+
## Juno-Specific Configuration
3399
+
3400
+
* **juno.config.ts**: Defines Satellite IDs for development/production, build source, and predeploy steps. See the [Configuration reference](/docs/reference/configuration.md) for details.
3401
+
* **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.
3402
+
3403
+
---
3404
+
3405
+
## Production Deployment
3406
+
3407
+
* Create a Satellite on the [Juno Console](https://console.juno.build) for mainnet.
3408
+
* Update `juno.config.ts` with the production Satellite ID.
3409
+
* Build and deploy the frontend:
3410
+
3411
+
```
3412
+
npm run buildjuno deploy
3413
+
```
3414
+
3415
+
* Build and upgrade the serverless functions:
3416
+
3417
+
```
3418
+
juno functions buildjuno functions upgrade
3419
+
```
3420
+
3421
+
---
3422
+
3423
+
## Notes
3424
+
3425
+
* This example focuses on the Rust serverless function. The frontend is intentionally minimal and included only for demonstration.
3426
+
* Use this project as a starting point for generate dynamic assets using Juno and Rust.
These crates are used to build and extend serverless functions in Rust with Juno:
3446
+
3447
+
* [junobuild-satellite](https://docs.rs/junobuild-satellite): Core features and runtime for building a Satellite in Rust, including hooks, assertions, and datastore integration.
3448
+
* [junobuild-macros](https://docs.rs/junobuild-macros): Procedural macros for declaratively attaching hooks and assertions.
3449
+
* [junobuild-utils](https://docs.rs/junobuild-utils): Utility helpers for working with documents, including data encoding, decoding, and assertion context handling.
3450
+
* [junobuild-shared](https://docs.rs/junobuild-shared): Shared types and helpers for Juno projects. Used by all containers including the Console.
3451
+
* [junobuild-storage](https://docs.rs/junobuild-storage): Storage helpers for working with assets and HTTP headers in Juno.
3289
3452
3290
3453
# Mutating Documents with Rust Hooks
3291
3454
@@ -3458,6 +3621,8 @@ These crates are used to build and extend serverless functions in Rust with Juno
3458
3621
* [junobuild-satellite](https://docs.rs/junobuild-satellite): Core features and runtime for building a Satellite in Rust, including hooks, assertions, and datastore integration.
3459
3622
* [junobuild-macros](https://docs.rs/junobuild-macros): Procedural macros for declaratively attaching hooks and assertions.
3460
3623
* [junobuild-utils](https://docs.rs/junobuild-utils): Utility helpers for working with documents, including data encoding, decoding, and assertion context handling.
3624
+
* [junobuild-shared](https://docs.rs/junobuild-shared): Shared types and helpers for Juno projects. Used by all containers including the Console.
3625
+
* [junobuild-storage](https://docs.rs/junobuild-storage): Storage helpers for working with assets and HTTP headers in Juno.
This action will build and publish your serverless function bundle.
5383
5548
5384
-
If your access key has a **write** role, the changes will be automatically deployed to your Satellite's CDN.
5549
+
If your access key is an **editor**, the changes will be automatically deployed to your Satellite's CDN.
5385
5550
5386
-
If your key only has a **submit** role, the release will be submitted as a pending change for manual approval. To avoid errors in submit-only workflows, you can explicitly use the `--no-apply` flag to skip auto-application.
5551
+
If your key is only a **submitter**, the release will be proposed as a pending change for manual approval. To avoid errors in submit-only workflows, you can explicitly use the `--no-apply` flag to skip auto-application.
Copy file name to clipboardExpand all lines: .llms-snapshots/llms.txt
+1Lines changed: 1 addition & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -59,6 +59,7 @@ Juno is your self-contained serverless platform for building full-stack web apps
59
59
## Examples - Functions - Rust
60
60
61
61
- [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.
62
+
- [Generating Assets with Rust Serverless Functions](https://juno.build/docs/examples/functions/rust/generating-assets-with-hooks.md): An example showing how to dynamically generate and store assets (like JSON) in Storage using Rust in Juno Satellites.
62
63
- [Mutating Documents with Rust Hooks](https://juno.build/docs/examples/functions/rust/mutating-docs-with-hooks.md): An example demonstrating how to modify and re-save documents in Juno Satellites using Rust hooks.
Copy file name to clipboardExpand all lines: docs/examples/functions/rust/components/references.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -18,3 +18,5 @@ These crates are used to build and extend serverless functions in Rust with Juno
18
18
-[junobuild-satellite](https://docs.rs/junobuild-satellite): Core features and runtime for building a Satellite in Rust, including hooks, assertions, and datastore integration.
19
19
-[junobuild-macros](https://docs.rs/junobuild-macros): Procedural macros for declaratively attaching hooks and assertions.
20
20
-[junobuild-utils](https://docs.rs/junobuild-utils): Utility helpers for working with documents, including data encoding, decoding, and assertion context handling.
21
+
-[junobuild-shared](https://docs.rs/junobuild-shared): Shared types and helpers for Juno projects. Used by all containers including the Console.
22
+
-[junobuild-storage](https://docs.rs/junobuild-storage): Storage helpers for working with assets and HTTP headers in Juno.
0 commit comments