Skip to content
Open
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
5 changes: 4 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,7 @@ jobs:
run: cargo test --workspace --all-targets

- name: Check feature compilation
run: cargo check --workspace --all-targets --features "fastly cloudflare"
run: cargo check --workspace --all-targets --features "fastly cloudflare spin"

- name: Check Spin wasm32 compilation
run: cargo check -p edgezero-adapter-spin --target wasm32-wasip1 --features spin
26 changes: 17 additions & 9 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
## Project Overview

EdgeZero is a portable HTTP workload toolkit in Rust. Write once, deploy to
Fastly Compute, Cloudflare Workers, or native Axum servers. The codebase is a
Cargo workspace with 7 crates under `crates/`, an example app under
`examples/app-demo/`, a VitePress documentation site under `docs/`, and CI
workflows under `.github/workflows/`.
Fastly Compute, Cloudflare Workers, Fermyon Spin, or native Axum servers. The
codebase is a Cargo workspace with 8 crates under `crates/`, an example app
under `examples/app-demo/`, a VitePress documentation site under `docs/`, and
CI workflows under `.github/workflows/`.

## Workspace Layout

Expand All @@ -17,6 +17,7 @@ crates/
edgezero-adapter/ # Adapter registry and traits
edgezero-adapter-fastly/ # Fastly Compute bridge (wasm32-wasip1)
edgezero-adapter-cloudflare/# Cloudflare Workers bridge (wasm32-unknown-unknown)
edgezero-adapter-spin/ # Fermyon Spin bridge (wasm32-wasip1)
edgezero-adapter-axum/ # Axum/Tokio bridge (native, dev server)
edgezero-cli/ # CLI: new, build, deploy, dev, serve
examples/app-demo/ # Reference app with all 3 adapters (excluded from workspace)
Expand Down Expand Up @@ -49,7 +50,10 @@ cargo fmt --all -- --check
cargo clippy --workspace --all-targets --all-features -- -D warnings

# Feature compilation check
cargo check --workspace --all-targets --features "fastly cloudflare"
cargo check --workspace --all-targets --features "fastly cloudflare spin"

# Spin wasm32 compilation check
cargo check -p edgezero-adapter-spin --target wasm32-wasip1 --features spin

# Run the demo dev server
cargo run -p edgezero-cli --features dev-example -- dev
Expand All @@ -67,6 +71,7 @@ faster iteration on a single crate.
| ---------- | ------------------------ | ---------------------------------- |
| Fastly | `wasm32-wasip1` | Requires Viceroy for local testing |
| Cloudflare | `wasm32-unknown-unknown` | Requires `wrangler` for dev/deploy |
| Spin | `wasm32-wasip1` | Requires `spin` CLI for dev/deploy |
| Axum | Native (host triple) | Standard Tokio runtime |

## Coding Conventions
Expand Down Expand Up @@ -132,12 +137,14 @@ impl Middleware for MyMiddleware {
### Proxy

Use `ProxyService` with adapter-specific clients (`FastlyProxyClient`,
`CloudflareProxyClient`). Keep proxy logic provider-agnostic in core.
`CloudflareProxyClient`, `SpinProxyClient`). Keep proxy logic provider-agnostic
in core.

### Logging

- Adapter-specific init: `edgezero_adapter_fastly::init_logger()`,
`edgezero_adapter_cloudflare::init_logger()`.
`edgezero_adapter_cloudflare::init_logger()`,
`edgezero_adapter_spin::init_logger()`.
- Use `simple_logger` for local/Axum builds.
- Use the `log` / `tracing` facade, not direct dependencies.

Expand All @@ -151,7 +158,7 @@ Use `ProxyService` with adapter-specific clients (`FastlyProxyClient`,
- **Minimal changes**: every change should impact as little code as possible.
Avoid unnecessary refactoring, docstrings on untouched code, or premature abstractions.
- **Feature gates**: platform-specific code goes behind `fastly`, `cloudflare`,
or `axum` features. Core stays `default-features = false` for WASM targets.
`spin`, or `axum` features. Core stays `default-features = false` for WASM targets.
- **No direct `http` crate imports** in application code — use `edgezero_core` re-exports.

## Adapter Pattern
Expand Down Expand Up @@ -179,7 +186,8 @@ Every PR must pass:
1. `cargo fmt --all -- --check`
2. `cargo clippy --workspace --all-targets --all-features -- -D warnings`
3. `cargo test --workspace --all-targets`
4. `cargo check --workspace --all-targets --features "fastly cloudflare"`
4. `cargo check --workspace --all-targets --features "fastly cloudflare spin"`
5. `cargo check -p edgezero-adapter-spin --target wasm32-wasip1 --features spin`

Docs CI additionally runs ESLint + Prettier on the `docs/` directory.

Expand Down
123 changes: 121 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ members = [
"crates/edgezero-adapter-axum",
"crates/edgezero-adapter-cloudflare",
"crates/edgezero-adapter-fastly",
"crates/edgezero-adapter-spin",
"crates/edgezero-adapter",
"crates/edgezero-cli",
"crates/edgezero-core",
Expand Down Expand Up @@ -35,6 +36,7 @@ edgezero-adapter = { path = "crates/edgezero-adapter" }
edgezero-adapter-axum = { path = "crates/edgezero-adapter-axum", default-features = false }
edgezero-adapter-cloudflare = { path = "crates/edgezero-adapter-cloudflare", default-features = false }
edgezero-adapter-fastly = { path = "crates/edgezero-adapter-fastly", default-features = false }
edgezero-adapter-spin = { path = "crates/edgezero-adapter-spin", default-features = false }
edgezero-core = { path = "crates/edgezero-core", default-features = false }
fastly = "0.11"
fern = "0.7"
Expand All @@ -53,6 +55,7 @@ serde = { version = "1", features = ["derive"] }
serde_json = "1"
serde_urlencoded = "0.7"
simple_logger = "5"
spin-sdk = { version = "5.2", default-features = false }
tempfile = "3"
thiserror = "2"
tokio = { version = "1", features = ["macros", "rt-multi-thread", "signal"] }
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# EdgeZero

Production-ready toolkit for portable edge HTTP workloads. Write once, deploy to Fastly Compute, Cloudflare Workers, or native Axum servers.
Production-ready toolkit for portable edge HTTP workloads. Write once, deploy to Fastly Compute, Cloudflare Workers, Fermyon Spin, or native Axum servers.

## Quick Start

Expand Down Expand Up @@ -34,6 +34,7 @@ Full documentation is available at **[stackpop.github.io/edgezero](https://stack
| ------------------ | ------------------------ | ------ |
| Fastly Compute | `wasm32-wasip1` | Stable |
| Cloudflare Workers | `wasm32-unknown-unknown` | Stable |
| Fermyon Spin | `wasm32-wasip1` | Stable |
| Axum (Native) | Host | Stable |

## License
Expand Down
4 changes: 2 additions & 2 deletions crates/edgezero-adapter-cloudflare/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub fn build() -> Result<PathBuf, String> {
let pkg_dir = workspace_root.join("pkg");
fs::create_dir_all(&pkg_dir)
.map_err(|e| format!("failed to create {}: {e}", pkg_dir.display()))?;
let dest = pkg_dir.join(format!("{crate_name}.wasm"));
let dest = pkg_dir.join(format!("{}.wasm", crate_name.replace('-', "_")));
fs::copy(&artifact, &dest)
.map_err(|e| format!("failed to copy artifact to {}: {e}", dest.display()))?;

Expand Down Expand Up @@ -284,7 +284,7 @@ fn locate_artifact(
manifest_dir: &Path,
crate_name: &str,
) -> Result<PathBuf, String> {
let release_name = format!("{crate_name}.wasm");
let release_name = format!("{}.wasm", crate_name.replace('-', "_"));

if let Some(custom) = std::env::var_os("CARGO_TARGET_DIR") {
let candidate = PathBuf::from(custom)
Expand Down
4 changes: 2 additions & 2 deletions crates/edgezero-adapter-fastly/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ pub fn build(extra_args: &[String]) -> Result<PathBuf, String> {
let pkg_dir = workspace_root.join("pkg");
fs::create_dir_all(&pkg_dir)
.map_err(|e| format!("failed to create {}: {e}", pkg_dir.display()))?;
let dest = pkg_dir.join(format!("{crate_name}.wasm"));
let dest = pkg_dir.join(format!("{}.wasm", crate_name.replace('-', "_")));
fs::copy(&artifact, &dest)
.map_err(|e| format!("failed to copy artifact to {}: {e}", dest.display()))?;

Expand Down Expand Up @@ -269,7 +269,7 @@ fn locate_artifact(
crate_name: &str,
) -> Result<PathBuf, String> {
let target_triple = "wasm32-wasip1";
let release_name = format!("{crate_name}.wasm");
let release_name = format!("{}.wasm", crate_name.replace('-', "_"));

if let Some(custom) = std::env::var_os("CARGO_TARGET_DIR") {
let candidate = PathBuf::from(custom)
Expand Down
27 changes: 27 additions & 0 deletions crates/edgezero-adapter-spin/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[package]
name = "edgezero-adapter-spin"
edition = { workspace = true }
version = { workspace = true }
authors = { workspace = true }
license = { workspace = true }

[features]
default = []
spin = ["dep:spin-sdk"]
cli = ["dep:edgezero-adapter", "edgezero-adapter/cli", "dep:ctor", "dep:walkdir"]

[dependencies]
edgezero-core = { path = "../edgezero-core" }
edgezero-adapter = { path = "../edgezero-adapter", optional = true, features = ["cli"] }
anyhow = { workspace = true }
async-trait = { workspace = true }
bytes = { workspace = true }
futures = { workspace = true }
futures-util = { workspace = true }
log = { workspace = true }
spin-sdk = { workspace = true, optional = true }
ctor = { workspace = true, optional = true }
walkdir = { workspace = true, optional = true }

[dev-dependencies]
tempfile = { workspace = true }
Loading
Loading