Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 53 additions & 69 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,92 +1,76 @@
Uzumibi
==========
# Uzumibi

![Uzumibi's Logo](./logo.png)

Uzumibi is a lightweight web application framework for embedding MRuby into edge computing platforms like Cloudflare Workers, Fastly Compute@Edge, Spin and so on. It allows developers to write serverless applications using Ruby, leveraging the power of MRuby for efficient execution in constrained environments.
Uzumibi is a Ruby web framework and project generator for WebAssembly-based edge and serverless runtimes. Ruby application code is compiled to mruby bytecode at build time and executed by [mruby/edge](https://github.com/mrubyedge/mrubyedge) inside a platform-specific host.

Uzumibi uses a specialized mruby implementation [mruby/edge](https://github.com/mrubyedge/mrubyedge), which is optimized for edge computing scenarios - WebAssembly environments with limited resources.
The `uzumibi` CLI currently provides templates for:

## 👉 Documentation
- Cloudflare Workers
- Fastly Compute
- Spin
- Google Cloud Run
- Browser Service Workers
- Browser Web Workers

- [Beginning Uzumibi](https://mrubyedge.github.io/beginning-uzumibi/) - An online book to get you up and running with Uzumibi.
- [On GitHub Pages](https://mrubyedge.github.io/uzumibi/) - The official Uzumibi documentation, covering installation, usage, supported platforms, and more.
## Documentation

### tl;dr
- [Beginning Uzumibi](https://mrubyedge.github.io/beginning-uzumibi/)
- [Uzumibi documentation](https://mrubyedge.github.io/uzumibi/)

Ruby code example for Uzumibi:
## Quick start with Cloudflare Workers

```ruby
class App < Uzumibi::Router
get "/" do |req, res|
res.status_code = 200
res.headers = {
"content-type" => "text/plain",
"x-powered-by" => "#{RUBY_ENGINE} #{RUBY_VERSION}"
}
res.body = "It works!\nVisit /greet/to/:name to get greeted.\n"
res
end
Install the CLI and the WebAssembly target:

get "/description" do |req, res|
res.status_code = 200
res.headers = {
"content-type" => "text/plain",
}
res.body =
"\"Uzumibi\" is a Japanese term that refers\n" +
"to live embers buried under a layer of ash\n" +
"to keep the fire from going out.\n"
res
end
~~~bash
cargo install uzumibi-cli
rustup target add wasm32-unknown-unknown
~~~

Create and run a project:

~~~bash
uzumibi new --template cloudflare my-app
cd my-app
pnpm install
pnpm run dev
~~~

Edit `lib/app.rb` to define routes:

get "/greet/to/:name" do |req, res|
res.status_code = 200
res.headers = {
"content-type" => "text/plain",
"x-powered-by" => "#{RUBY_ENGINE} #{RUBY_VERSION}"
}
res.body = "Hello, #{req.params[:name]}!!\n"
res
~~~ruby
class App < Uzumibi::Router
get "/" do |req, res|
res.return(
200,
{ "content-type" => "text/plain" },
"Hello from #{RUBY_ENGINE} #{RUBY_VERSION}\n"
)
end

get "/hello/:name" do |req, res|
res.status_code = 302
res.headers = {
"location" => "/greet/to/#{req.params[:name]}",
"content-type" => "text/plain",
}
res.body = "Moved\n"
res
res.return(
200,
{ "content-type" => "text/plain" },
"Hello, #{req.params[:name]}!\n"
)
end
end

$APP = App.new
```

...that runs on various edge platforms!!

Crates and projects
-----------------

- [**uzumibi-cli**](./uzumibi-cli/) - A command-line interface tool to generate Uzumibi application scaffolds to various edge platforms.
- ![crates.io](https://img.shields.io/crates/v/uzumibi-cli.svg)
- [**uzumibi-gem**](./uzumibi-gem/) - The mruby/edge gem that provides the core Uzumibi framework functionality.
- ![crates.io](https://img.shields.io/crates/v/uzumibi-gem.svg)
- [**uzumibi-art-router**](./uzumibi-art-router/) - A lightweight router library for Uzumibi, providing routing capabilities for handling HTTP requests.
- ![crates.io](https://img.shields.io/crates/v/uzumibi-art-router.svg)

### Spike codes
~~~

- [**uzumibi-on-cloudflare-spike**](./uzumibi-on-cloudflare-spike/) - An Uzumibi application scaffold for Cloudflare Workers (using Wasm with some JavaScript).
- [**uzumibi-on-cloudrun-spike**](./uzumibi-on-cloudrun-spike/) - An Uzumibi application scaffold for Google Cloud Run. Experimental.
- [**uzumibi-on-fastly-spike**](./uzumibi-on-fastly-spike/) - An Uzumibi application scaffold for Fastly Compute@Edge.
- [**uzumibi-on-spin-spike**](./uzumibi-on-spin-spike/) - An Uzumibi application scaffold for Spin using Fermyon Cloud.
For Cloudflare Workers, `pnpm run dev` rebuilds the Wasm module and starts Wrangler. See the [Cloudflare Workers guide](https://mrubyedge.github.io/uzumibi/platforms/cloudflare-workers.html) for request-size configuration, external services, static assets, and Queue consumers.

### ToDos
## Workspace components

- Support of wasmCloud
- [`uzumibi-cli`](./uzumibi-cli/) — generates platform-specific application projects
- [`uzumibi-gem`](./uzumibi-gem/) — defines `Uzumibi::Router`, `Request`, and `Response`
- [`uzumibi-art-router`](./uzumibi-art-router/) — route matching and path-parameter extraction
- [`uzumibi-cloudflare-ext`](./uzumibi-cloudflare-ext/) — Cloudflare host APIs exposed to Ruby
- [`uzumibi-google`](./uzumibi-google/) — Google Cloud integrations used by the Cloud Run template
- `uzumibi-on-*-spike` directories — development and integration examples for individual runtimes

## How to pronounce "Uzumibi"
## How to pronounce Uzumibi

Uzumibi(うずみび) is pronounced as /`oo-zóo-mi-bì`/, which sounds natural when you pronounce in relaxed oo - `ʊ`
Uzumibi (うずみび) is pronounced roughly as oo-zoo-mee-bee.” The Japanese word refers to live embers kept under ash so that the fire does not go out.
5 changes: 5 additions & 0 deletions uzumibi-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,11 @@ fn print_project_next_steps(template: &str, _project_name: &str, features: &[Str
" • After trying to bootstrap, edit \x1b[33mlib/app.rb\x1b[0m and \x1b[33mpublic/index.html\x1b[0m to develop your custom SPA application"
);
}
"cloudflare" | "cloudrun" if has_queue => {
println!(
" • After trying to bootstrap, edit \x1b[33mlib/consumer.rb\x1b[0m to develop your queue consumer"
);
}
_ => {
println!(
" • After trying to bootstrap, edit \x1b[33mlib/app.rb\x1b[0m to develop your custom application"
Expand Down
14 changes: 14 additions & 0 deletions uzumibi-cli/templates/cloudflare/__features__/queue/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,20 @@ export default {
return 0;
},

// Secret.get(key) -> secret value from env bindings
uzumibi_cf_secret_get: (keyPtr, keySize, resultPtr, resultMaxSize) => {
const memory = exports.memory;
const key = decoder.decode(new Uint8Array(memory.buffer, keyPtr, keySize));
const value = env[key];
if (value === undefined || value === null) {
return -1;
}
const valueBytes = encoder.encode(String(value));
const length = Math.min(valueBytes.length, resultMaxSize);
new Uint8Array(memory.buffer, resultPtr, resultMaxSize).set(valueBytes.slice(0, length));
return length;
},

// Queue.send(queue_name, message)
uzumibi_cf_queue_send: async (queueNamePtr, queueNameSize, messagePtr, messageSize) => {
const memory = exports.memory;
Expand Down
12 changes: 11 additions & 1 deletion uzumibi-cli/tests/runn/new_cloudflare_queue.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ steps:
command: cd {{ vars.tmpdir }} && {{ vars.binary }} new -t cloudflare --features queue {{ vars.project_name }}
test: |
current.exit_code == 0 &&
current.stdout contains 'Successfully created project'
current.stdout contains 'Successfully created project' &&
current.stdout contains 'lib/consumer.rb' &&
!(current.stdout contains 'lib/app.rb')

check_queue_files:
desc: Check Queue-specific files and configuration
Expand All @@ -50,6 +52,14 @@ steps:
command: cd {{ vars.tmpdir }}/{{ vars.project_name }} && pnpm run build:wasm:queue
test: current.exit_code == 0

check_queue_wasm_imports:
desc: Check that the Queue Worker provides every WASM host import
exec:
command: >-
cd {{ vars.tmpdir }}/{{ vars.project_name }} &&
node -e 'const fs = require("node:fs"); const p = require("./package.json"); const wasm = fs.readFileSync("src/" + p.name.replaceAll("-", "_") + "_queue.wasm"); const imports = WebAssembly.Module.imports(new WebAssembly.Module(wasm)).filter((item) => item.module === "env"); const source = fs.readFileSync("src/index.js", "utf8"); const missing = imports.map((item) => item.name).filter((name) => !source.includes(name + ":")); if (missing.length) { console.error("Missing WASM host imports: " + missing.join(", ")); process.exit(1); }'
test: current.exit_code == 0

start_server:
desc: Start Queue Worker dev server in background
exec:
Expand Down
10 changes: 4 additions & 6 deletions uzumibi-docs/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,11 @@
- [Platform Comparison](./platforms/platform-comparison.md)
- [Choosing a Platform](./platforms/choosing-a-platform.md)

- [External Service Abstractions](./external-services.md)
- [What are External Service Abstractions?](./external-services/what-are-external-service-abstractions.md)
- [Platform Service APIs](./external-services.md)
- [How Platform Service APIs Work](./external-services/what-are-external-service-abstractions.md)
- [Available Services](./external-services/available-services.md)
- [Platform Support Matrix](./external-services/platform-support-matrix.md)
- [Usage Examples](./external-services/usage-examples.md)
- [Development Roadmap](./external-services/development-roadmap.md)
- [Feature Support Matrix](./external-services/platform-support-matrix.md)
- [Cloudflare Usage Examples](./external-services/usage-examples.md)
- [Contributing](./external-services/contributing.md)

# Reference
Expand All @@ -56,7 +55,6 @@
- [Common Workflows](./cli-reference/common-workflows.md)
- [Troubleshooting](./cli-reference/troubleshooting.md)
- [Environment Variables](./cli-reference/environment-variables.md)
- [Future Commands](./cli-reference/future-commands.md)
- [Updating the CLI](./cli-reference/updating-the-cli.md)
- [Getting Help](./cli-reference/getting-help.md)

Expand Down
1 change: 0 additions & 1 deletion uzumibi-docs/src/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,5 @@ The Uzumibi CLI (`uzumibi`) is a command-line tool for scaffolding new edge appl
- [Common Workflows](./cli-reference/common-workflows.md)
- [Troubleshooting](./cli-reference/troubleshooting.md)
- [Environment Variables](./cli-reference/environment-variables.md)
- [Future Commands](./cli-reference/future-commands.md)
- [Updating the CLI](./cli-reference/updating-the-cli.md)
- [Getting Help](./cli-reference/getting-help.md)
134 changes: 32 additions & 102 deletions uzumibi-docs/src/cli-reference/commands.md
Original file line number Diff line number Diff line change
@@ -1,119 +1,49 @@
# Commands

### `uzumibi new`
The current CLI has one subcommand: `uzumibi new`.

Create a new edge application project from a template.
## `uzumibi new`

#### Synopsis
~~~text
uzumibi new [OPTIONS] --template <TEMPLATE> <PROJECT_NAME>
~~~

```bash
uzumibi new --template <TEMPLATE> <PROJECT_NAME>
```
### Arguments and options

#### Arguments
| Argument or option | Description |
| --- | --- |
| `<PROJECT_NAME>` | Project name used in generated files and, by default, as the destination directory |
| `-t, --template <TEMPLATE>` | Required template name |
| `-d, --dest-dir <DEST_DIR>` | Write to a directory other than `PROJECT_NAME` |
| `--force` | Overwrite existing files without prompting |
| `--features <FEATURES>` | Comma-separated feature overlays |

- `<PROJECT_NAME>`: The name of your project. This will be used as the directory name.
Available templates are `cloudflare`, `cloudrun`, `fastly`, `spin`, `serviceworker`, and `webworker`.

#### Options
Currently defined feature overlays are:

- `-t, --template <TEMPLATE>`: The platform template to use. **Required.**
| Template | Feature | Purpose |
| --- | --- | --- |
| `cloudflare` | `enable-external` | Async Cloudflare host APIs from Ruby |
| `cloudflare` | `queue` | Cloudflare Queues consumer; includes external APIs |
| `cloudrun` | `enable-external` | Google Cloud external-service APIs |
| `cloudrun` | `queue` | Pub/Sub push consumer |

#### Available Templates
### Examples

| Template | Description | Status |
|----------|-------------|--------|
| `cloudflare` | Cloudflare Workers | Stable |
| `fastly` | Fastly Compute@Edge | Stable |
| `spin` | Spin (Fermyon) | Stable |
| `cloudrun` | Google Cloud Run | Experimental |

#### Examples

Create a Cloudflare Workers project:

```bash
~~~bash
uzumibi new --template cloudflare my-worker
```

Create a Fastly Compute project:

```bash
uzumibi new --template fastly my-compute-app
```

Create a Spin project:

```bash
uzumibi new --template spin my-spin-app
```

Create a Cloud Run project:

```bash
uzumibi new --template cloudrun my-cloudrun-app
```

#### What Gets Created

The `uzumibi new` command generates a complete project structure including:
uzumibi new -t cloudflare --features enable-external my-worker
uzumibi new -t cloudflare --features queue queue-consumer
uzumibi new -t cloudflare --dest-dir ./apps/worker my-worker
~~~

- **Cargo.toml**: Rust workspace configuration
- **build.rs**: Build script that compiles Ruby to mruby bytecode
- **lib/app.rb**: Your Ruby application code (main entry point)
- **src/**: Platform-specific Rust/JavaScript code
- Platform-specific configuration files:
- `wrangler.jsonc` (Cloudflare)
- `fastly.toml` (Fastly)
- `spin.toml` (Spin)
- `Dockerfile` (Cloud Run)
When files already exist and `--force` is not supplied, the CLI shows a diff and prompts for each conflicting file.

Example project structure for Cloudflare Workers:
## Help and version

```
my-worker/
├── Cargo.toml
├── package.json
├── pnpm-lock.yaml
├── wrangler.jsonc
├── lib/
│ └── app.rb
├── src/
│ └── index.js
└── wasm-app/
├── Cargo.toml
├── build.rs
└── src/
└── lib.rs
```

### `uzumibi --help`

Display help information:

```bash
~~~bash
uzumibi --help
```

Output:

```
Uzumibi CLI - Create a new edge application project powered by Ruby

Usage: uzumibi <COMMAND>

Commands:
new Create a new edge application project
help Print this message or the help of the given subcommand(s)

Options:
-h, --help Print help
-V, --version Print version
```

### `uzumibi --version`

Display the CLI version:

```bash
uzumibi new --help
uzumibi --version
```
~~~
Loading
Loading