Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
aacf845
ruby: add serde_magnus dep and to_ruby helper
johnpmitsch Apr 27, 2026
7aa72b2
ruby: return native Hash/Array via serde_magnus instead of JSON strings
johnpmitsch Apr 27, 2026
97a0dd0
ruby: move native binding classes under QuicknodeSdk::Native
johnpmitsch Apr 27, 2026
9b6e64a
ruby: add hashie runtime dep and broaden gemspec file glob
johnpmitsch Apr 27, 2026
0d5e4d1
ruby: wrap native bindings with Hashie::Mash delegators
johnpmitsch Apr 27, 2026
215e958
ruby: update admin.rb example to dot-notation responses
johnpmitsch Apr 27, 2026
2cec85e
ruby: update admin_e2e.rb example to dot-notation responses
johnpmitsch Apr 27, 2026
13ed76d
ruby: update streams.rb example to dot-notation responses
johnpmitsch Apr 27, 2026
9b55ec8
ruby: update streams_e2e.rb example to dot-notation responses
johnpmitsch Apr 27, 2026
dc09b55
ruby: update webhooks_e2e.rb example to dot-notation responses
johnpmitsch Apr 27, 2026
819a43c
ruby: update kvstore_e2e.rb example to dot-notation responses
johnpmitsch Apr 27, 2026
ddb3915
docs: update README Ruby snippets to dot-notation responses
johnpmitsch Apr 27, 2026
87d5577
docs: update CLAUDE.md Ruby binding section for Hashie::Mash returns
johnpmitsch Apr 27, 2026
3c5ccc3
ruby: update inline comment to reflect Hashie::Mash return path
johnpmitsch Apr 27, 2026
9bb933a
ruby: switch from Hashie::Mash to IndifferentHash to avoid method col…
johnpmitsch Apr 27, 2026
69e3446
ruby: fix stale Hashie::Mash reference in inline comment
johnpmitsch Apr 27, 2026
652a6f5
RBS
johnpmitsch Apr 27, 2026
920623a
Refactor
johnpmitsch Apr 27, 2026
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
7 changes: 5 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,15 @@ When adding a new `SdkError` variant:
`crates/node/src/lib.rs` uses `#[napi(constructor)]` and `#[napi(getter)]` macros. napi handles async conversion automatically.

### Ruby Binding Pattern
`crates/ruby/src/lib.rs` uses the `magnus` crate. All async SDK calls are wrapped via a single shared `tokio::runtime` (static `OnceLock`) using `.block_on()` to produce a synchronous Ruby API. Methods returning data return **JSON strings** — callers must parse with `JSON.parse()`. All parameters are passed as a single Ruby Hash with symbol keys (e.g. `get_endpoints(limit: 20)`). Required keys throw `ArgumentError` if missing; unknown keys also throw `ArgumentError` (validated via `validate_keys`). The magnus arity limit of 15 is why this pattern is used uniformly — all methods are registered with arity `1` (or `0` for zero-param methods). Classes are exposed under the `QuicknodeSdk` module and registered via `#[magnus::init(name = "quicknode_sdk")]`.
`crates/ruby/src/lib.rs` uses the `magnus` crate. All async SDK calls are wrapped via a single shared `tokio::runtime` (static `OnceLock`) using `.block_on()` to produce a synchronous Ruby API. Methods returning data return native Ruby `Hash`/`Array` (via `serde_magnus`); a per-client Ruby delegator in `ruby/lib/quicknode_sdk/clients/` wraps responses in `QuicknodeSdk::IndifferentHash` (a `Hash` subclass with `Hashie::Extensions::IndifferentAccess`) so callers can use either symbol or string keys. All parameters are passed as a single Ruby Hash with symbol keys (e.g. `get_endpoints(limit: 20)`). Required keys throw `ArgumentError` if missing; unknown keys also throw `ArgumentError` (validated via `validate_keys`). The magnus arity limit of 15 is why this pattern is used uniformly — all methods are registered with arity `1` (or `0` for zero-param methods). The native binding classes are registered under `QuicknodeSdk::Native::*` (via `#[magnus::init(name = "quicknode_sdk")]`); user-facing `QuicknodeSdk::SDK`/`Admin`/`Streams`/`Webhooks`/`KvStore` are pure-Ruby wrapper classes defined in `ruby/lib/quicknode_sdk/`.

When adding a new Ruby method:
1. Accept `opts: RHash` as the single parameter
2. Call `validate_keys(&opts, &["key1", "key2", ...])?;` as the first line
3. Use `hash_require_string/i64/i32/bool/vec_string` for required fields and `hash_get_*` for optional fields
4. Register with `method!(ClassName::method_name, 1)` in the `init` function
4. Register with `method!(ClassName::method_name, 1)` in the `init` function on the `QuicknodeSdk::Native::*` class (the user-facing Ruby wrapper in `ruby/lib/quicknode_sdk/clients/` picks up new methods automatically via `method_missing`)
5. For methods returning data, the return type is `Result<magnus::Value, Error>` and the call ends with `.and_then(to_ruby)`. The Ruby delegator wraps the result in `QuicknodeSdk::IndifferentHash` automatically — no per-method code is needed on the Ruby side.
6. Add a corresponding RBS signature to `ruby/sig/quicknode_sdk.rbs` under the matching client class. Method name must match step 4; keyword args must match the `validate_keys` list from step 2 with types derived from the `hash_require_*` / `hash_get_*` accessors (`hash_require_string` → `String`, `hash_get_string` → optional `?key: String`, `hash_*_i32`/`i64` → `Integer`, `hash_*_bool` → `bool`, `hash_*_vec_string` → `Array[String]`, `hash_get_map_string_string` → `Hash[String, String]`). Use `untyped` as the return type for methods that return `Result<magnus::Value, Error>` (response is wrapped as a `Hashie::Mash` at the Ruby boundary) and `void` for methods returning `Result<(), Error>`. If a new exception class is added, also add it to the error hierarchy section at the top of the same file.

### Testing
Core clients are tested using mocked API calls with wiremock. All functions making external http calls should be tested this way and test the happy path, errors, with params, and with bad params. Keep testing focused and flexible, avoid overtesting
Expand All @@ -163,6 +165,7 @@ Core clients are tested using mocked API calls with wiremock. All functions maki
- When updating `sdk.js` wrapper methods, verify the argument types match the underlying napi-rs constructor/method signature (object vs primitive)
- When adding a new export to `sdk.js`, also add it to the named exports in `npm/sdk.mjs` — ESM named exports cannot be spread dynamically and must be listed explicitly
- `python/sdk/__init__.pyi` is overwritten by `just python-build` — edit `init_manual_override.pyi` instead
- `ruby/sig/quicknode_sdk.rbs` is **manually maintained** — it is NOT auto-generated. It provides RBS type signatures so editor LSPs (VSCode Ruby LSP, Solargraph, RubyMine, Steep) autocomplete method names and keyword argument keys for `QuicknodeSdk::Admin/Streams/Webhooks/KvStore/DestinationAttributes` and the exception classes. Every change to method registration in `crates/ruby/src/lib.rs` (new method, renamed key, new arg, removed arg, type change) must be mirrored here in the same PR. Responses are typed as `untyped` because they're wrapped in `Hashie::Mash` at the Ruby boundary — that's intentional, do not try to type response shapes.
- Always update examples alongside the code changes

### Security
Expand Down
Loading
Loading