No description
Find a file
despiegk 54262dd649 docs: remove hardcoded dependency references from README examples
Replace specific git URLs with comments directing users to use
configuration management for dependency references.
2026-06-06 21:30:04 +02:00
crates chore: align deps to development branch 2026-06-06 08:52:25 +02:00
.gitignore Vendor frozen herolib stack (derive, oschema, openrpc, core) from hero_lib@9657556a; repo now fully self-contained 2026-06-05 20:02:31 +00:00
Cargo.lock chore: update cargo dependencies 2026-06-06 08:17:09 +02:00
Cargo.toml Re-cut old stack from pre-bridge d31c7b6 (self-contained hero_rpc2); rename frozen herolib_derive->hero_derive; drop unneeded vendored runtime crates 2026-06-05 22:04:15 +00:00
README.md docs: remove hardcoded dependency references from README examples 2026-06-06 21:30:04 +02:00

hero_macros_previous

Frozen, known-good ("previous") snapshot of the macro + OpenRPC client stack that main across the hero repositories already builds against.

Why this repo exists

The active refactor moved the macro stack onto a fast-moving new home (hero_lib for the new derive macros, hero_blueprint for the scaffolder). Every service repo was therefore forced to pin a moving target — typically hero_blueprint (or the older hero_rpc) on branch = development — which breaks main whenever that branch advances.

This repo freezes the previous, stable macros in one place so that:

  1. main pins this repo and stops tracking hero_blueprint / hero_lib.
  2. main becomes buildable and stable on its own again, with no hero_blueprint dependency.
  3. main can then be folded back into development (development becomes a superset of main).
  4. Each service repo migrates onto the new hero_lib library one at a time, on its own schedule, without breaking main in the meantime.

The newer, evolving macros stay in hero_lib / hero_blueprint. "New" in the task ("use these new macros") means the macros now living in this new repo, not a newer version.

What's here

Two frozen macro stacks live side by side: the old hero_rpc stack (lifted verbatim from hero_blueprint@f6509f9, the pre-teardown main/integration tip) and the frozen new-gen derive macro (cut from hero_lib@9657556a). Workspace version 0.6.0, Rust 1.96:

crate (path) package stack purpose
crates/derive hero_rpc_derive old openrpc_client!, openrpc_proxy!, rhai_openrpc! proc macros (emit ::hero_rpc2:: transport)
crates/hero_rpc2 hero_rpc2 old JSON-RPC 2.0 runtime over UDS; owns the OpenRPC transport (folds in the retired hero_rpc_openrpc per hero_rpc#146)
crates/openrpc hero_rpc_openrpc old Deprecated re-export shim; kept so older consumers still resolve
crates/openrpc_http_client_lib hero_rpc_client old Cross-platform OpenRPC HTTP client (native + wasm)
crates/hero_derive hero_derive new-gen Frozen herolib_derive (renamed); openrpc_client! here emits ::herolib_openrpc:: transport. New-stack repos alias herolib_derive = { package = "hero_derive", … }
crates/herolib_oschema herolib_oschema new-gen Host-time OSIS schema dep of hero_derive (vendored, was an external hero_lib dep)

The scaffolder crates (generator, blueprinter, osis) are intentionally not included — they are the "too new" parts being decoupled from.

Both openrpc_client! macros (old hero_rpc_derive and new-gen hero_derive) carry the same socket-placeholder fix — see Socket placeholder in servers[].url below.

Dependencies — what this repo pulls, and for what

No external git dependencies. Every crate builds against only crates.io packages plus the workspace-internal path crates below — nothing points at a still-moving hero_lib / hero_blueprint, so this repo cannot break when those advance. Cargo.lock is committed for reproducible, frozen builds.

Internal (path) crates — all path = "crates/…", re-exported via [workspace.dependencies]: hero_rpc_derive, hero_rpc2, hero_rpc_openrpc, hero_rpc_client, hero_derive, and herolib_oschema (the OSIS schema lib, vendored here — formerly an external hero_lib dep).

External (crates.io) deps, by crate and purpose:

crate external deps for what
hero_rpc_derive proc-macro2, quote, syn, serde, serde_json, prettyplease proc-macro plumbing, OpenRPC-spec parsing, pretty-printing the generated client
hero_rpc2 jsonrpsee, tokio, serde(_json), thiserror, tracing, futures; optional schemars, hyper, hyper-util, http-body-util, reqwest, futures-util, syn, prettyplease JSON-RPC 2.0 runtime over UDS; OpenRPC transport/codegen gated behind features
hero_rpc_openrpc serde_json deprecated shim re-exporting hero_rpc2
hero_rpc_client serde(_json); wasm: gloo-net, wasm-bindgen, web-sys, js-sys cross-platform OpenRPC HTTP client (native uses internal hero_rpc2)
hero_derive proc-macro2, quote, syn, serde(_json), toml, prettyplease new-gen derive macros (ToSchema / Otoml / …)
herolib_oschema serde(_json), toml, thiserror, regex; native: fs2 OSIS types, OTOML serialization, OsisObject, filesystem collection storage

The one soft coupling: herolib_core (consumer-side only)

herolib_core is not a build dependency of any crate here. The openrpc_client! macros only emit a call to ::herolib_core::base::resolve_socket_path_with_override(...) inside the generated connect() (see the socket-placeholder section above). The consuming repo must therefore have herolib_core on its dependency path — but this snapshot itself never compiles against it, keeping the freeze intact.

How consumers use it

Repoint the old dependency, e.g.:

# before — moving target on hero_blueprint / hero_rpc
hero_rpc_derive = { git = "https://forge.ourworld.tf/lhumina_code/hero_blueprint.git", branch = "development" }
hero_rpc2       = { git = "https://forge.ourworld.tf/lhumina_code/hero_blueprint.git", branch = "development", features = ["client", "uds-http", "openrpc-transport"] }

# after — frozen, stable
# [dependency references removed - stable references should be updated via configuration management]

The macro and its runtime are a matched pair — take BOTH from here

openrpc_client! / openrpc_proxy! do not contain a transport; they emit code that calls into a runtime crate. The two must come from the same frozen snapshot, or the generated code won't compile / will drift:

You use this macro… …it emits calls into take the runtime from
hero_rpc_derive (old stack) ::hero_rpc2:: hero_rpc2 here
hero_derive (new-gen, aliased as herolib_derive) ::herolib_openrpc:: see note below

⚠️ Do NOT pull the OpenRPC runtime from hero_lib (herolib_openrpc on branch = "development"). That crate moves independently of this frozen macro, so pairing a frozen macro with a live herolib_openrpc reintroduces exactly the drift this repo exists to stop. The old stack avoids the problem entirely: hero_rpc_derive emits ::hero_rpc2::, and hero_rpc2 is fully self-contained and lives here — no herolib_openrpc anywhere.

Recommended for client repos: the old stack. Alias it so existing herolib_macros::openrpc_client! / openrpc_proxy! call sites need no change, and add the matching runtime:

# proc-macro — aliased onto the existing `herolib_macros` name
# herolib_macros dependency reference removed - use configuration management instead
# runtime the macro emits into — MUST also come from here, NOT hero_lib
# hero_rpc2 dependency reference removed - use configuration management instead

Then drop any herolib_openrpc = { … hero_lib … } dependency and re-export the error type from the new runtime instead:

// before
pub use herolib_openrpc::OpenRpcError as MyApiError;
// after
pub use hero_rpc2::OpenRpcError as MyApiError;

hero_rpc2 provides the same surface the generated client needs — OpenRpcError, RpcError, OpenRpcTransport (::unix_socket), and SseEvent (with .json()).

The hero_derive (new-gen) path still emits ::herolib_openrpc::, but this repo does not vendor a herolib_openrpc crate — so that path currently has no frozen runtime here. Prefer the old stack above until a frozen herolib_openrpc is vendored.

Socket placeholder in servers[].url (must read before migrating)

openrpc_client! generates a default connect() from the spec's servers[0].url. When that URL embeds a socket-dir env-var placeholder, the macro strips unix://, takes the relative tail (<svc>/rpc.sock), and resolves the real path at runtime via herolib_core::base::resolve_socket_path_with_override, which applies the canonical cascade HERO_SOCKET_DIR → PATH_VAR → PATH_ROOT/var/sockets.

The frozen snapshot originally only recognised the old placeholder name ${HERO_SOCKET_DIR}. The current Hero stack renamed it to ${PATH_SOCKET} (and some specs use other ${...} names). With the old check, any spec using the new name fell through to the literal-URL branch and emitted a broken connect() containing the unexpanded placeholder — e.g. "unix://${PATH_SOCKET}/<svc>/rpc.sock" — so every connect() failed at runtime with "socket not found at '${PATH_SOCKET}/...'".

Fix applied here (both hero_rpc_derive and hero_derive): the macro now accepts any ${...} placeholder as the socket-dir segment and always routes through resolve_socket_path_with_override, regardless of the literal name. So ${HERO_SOCKET_DIR}, ${PATH_SOCKET}, etc. all resolve correctly — this keeps the backwards-compat macros in line with current sockets.

Migration checklist when repointing a repo at this snapshot:

  • No spec change is required — your servers[].url may use either ${HERO_SOCKET_DIR} or ${PATH_SOCKET}; both now work.
  • The consuming crate must depend on herolib_core (the macro emits a call into herolib_core::base::resolve_socket_path_with_override).
  • If connect() still can't find the socket, check that the server actually binds under the resolved dir — set HERO_SOCKET_DIR/PATH_SOCKET/PATH_ROOT consistently for both server and client, or pass an override_env = "..." to openrpc_client! and export that var.

Build / test

cargo build --workspace
cargo test  --workspace --all-features

Both are green. One carried-over SSE test is quarantined — see crates/derive/tests/README.md.