quicknode-sdk 0.6.0__tar.gz → 0.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/Cargo.lock +17 -17
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/Cargo.toml +1 -1
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/PKG-INFO +52 -2
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/Cargo.toml +9 -1
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/README.md +63 -1
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/examples/admin_e2e.rs +3 -0
- quicknode_sdk-0.7.0/crates/core/examples/rpc.rs +83 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/src/admin/mod.rs +4 -0
- quicknode_sdk-0.7.0/crates/core/src/admin/tooling_access.rs +386 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/src/config.rs +102 -1
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/src/errors.rs +3 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/src/kvstore/mod.rs +1 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/src/lib.rs +62 -21
- quicknode_sdk-0.7.0/crates/core/src/rpc/mod.rs +766 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/src/sql/mod.rs +1 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/src/streams/mod.rs +1 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/src/webhooks/mod.rs +1 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/python/Cargo.toml +2 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/python/src/errors.rs +20 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/python/src/lib.rs +151 -1
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/pyproject.toml +1 -1
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/python/README.md +51 -1
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/python/quicknode_sdk/__init__.py +10 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/python/quicknode_sdk/__init__.pyi +10 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/python/quicknode_sdk/_core/__init__.pyi +200 -1
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/python/quicknode_sdk/init_manual_override.pyi +10 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/LICENSE +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/LICENSE +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/examples/admin.rs +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/examples/kvstore_e2e.rs +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/examples/sql.rs +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/examples/streams.rs +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/examples/streams_e2e.rs +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/examples/webhooks_e2e.rs +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/src/admin/account.rs +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/src/admin/api_credits.rs +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/src/admin/billing.rs +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/src/admin/bulk.rs +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/src/admin/chains.rs +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/src/admin/endpoint_metrics.rs +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/src/admin/endpoint_rate_limits.rs +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/src/admin/endpoint_security.rs +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/src/admin/endpoint_urls.rs +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/src/admin/endpoints.rs +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/src/admin/logs.rs +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/src/admin/tags.rs +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/src/admin/teams.rs +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/src/admin/usage.rs +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/src/streams/stream.rs +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/core/src/webhooks/webhook.rs +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/python/src/sql.rs +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/python/src/streams_destination.rs +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/crates/python/src/webhooks_template.rs +0 -0
- {quicknode_sdk-0.6.0 → quicknode_sdk-0.7.0}/python/quicknode_sdk/py.typed +0 -0
|
@@ -154,9 +154,9 @@ checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
|
|
|
154
154
|
|
|
155
155
|
[[package]]
|
|
156
156
|
name = "bytes"
|
|
157
|
-
version = "1.12.
|
|
157
|
+
version = "1.12.1"
|
|
158
158
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
159
|
-
checksum = "
|
|
159
|
+
checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"
|
|
160
160
|
|
|
161
161
|
[[package]]
|
|
162
162
|
name = "cc"
|
|
@@ -1175,9 +1175,9 @@ dependencies = [
|
|
|
1175
1175
|
|
|
1176
1176
|
[[package]]
|
|
1177
1177
|
name = "memchr"
|
|
1178
|
-
version = "2.8.
|
|
1178
|
+
version = "2.8.3"
|
|
1179
1179
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1180
|
-
checksum = "
|
|
1180
|
+
checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98"
|
|
1181
1181
|
|
|
1182
1182
|
[[package]]
|
|
1183
1183
|
name = "memoffset"
|
|
@@ -1684,7 +1684,7 @@ dependencies = [
|
|
|
1684
1684
|
|
|
1685
1685
|
[[package]]
|
|
1686
1686
|
name = "quicknode-sdk"
|
|
1687
|
-
version = "0.
|
|
1687
|
+
version = "0.7.0"
|
|
1688
1688
|
dependencies = [
|
|
1689
1689
|
"bon",
|
|
1690
1690
|
"config",
|
|
@@ -1870,9 +1870,9 @@ checksum = "cca7ad6a7e21e72151d56fe2495a259b5670e204c3adac41ee7ef676ea08117a"
|
|
|
1870
1870
|
|
|
1871
1871
|
[[package]]
|
|
1872
1872
|
name = "regex"
|
|
1873
|
-
version = "1.
|
|
1873
|
+
version = "1.13.0"
|
|
1874
1874
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1875
|
-
checksum = "
|
|
1875
|
+
checksum = "2a0e75113e14dc5acb068cd0786884f214f1312650a3d36d269f5c4f3cdee8a2"
|
|
1876
1876
|
dependencies = [
|
|
1877
1877
|
"aho-corasick",
|
|
1878
1878
|
"memchr",
|
|
@@ -1882,9 +1882,9 @@ dependencies = [
|
|
|
1882
1882
|
|
|
1883
1883
|
[[package]]
|
|
1884
1884
|
name = "regex-automata"
|
|
1885
|
-
version = "0.4.
|
|
1885
|
+
version = "0.4.15"
|
|
1886
1886
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1887
|
-
checksum = "
|
|
1887
|
+
checksum = "1f388202e4b80542a0921078cc23b6333bcf1409c1e3f86404cae4766a6131db"
|
|
1888
1888
|
dependencies = [
|
|
1889
1889
|
"aho-corasick",
|
|
1890
1890
|
"memchr",
|
|
@@ -2159,7 +2159,7 @@ dependencies = [
|
|
|
2159
2159
|
|
|
2160
2160
|
[[package]]
|
|
2161
2161
|
name = "sdk-node"
|
|
2162
|
-
version = "0.
|
|
2162
|
+
version = "0.7.0"
|
|
2163
2163
|
dependencies = [
|
|
2164
2164
|
"napi",
|
|
2165
2165
|
"napi-build",
|
|
@@ -2171,7 +2171,7 @@ dependencies = [
|
|
|
2171
2171
|
|
|
2172
2172
|
[[package]]
|
|
2173
2173
|
name = "sdk-python"
|
|
2174
|
-
version = "0.
|
|
2174
|
+
version = "0.7.0"
|
|
2175
2175
|
dependencies = [
|
|
2176
2176
|
"pyo3",
|
|
2177
2177
|
"pyo3-async-runtimes",
|
|
@@ -2183,7 +2183,7 @@ dependencies = [
|
|
|
2183
2183
|
|
|
2184
2184
|
[[package]]
|
|
2185
2185
|
name = "sdk-python-stubs"
|
|
2186
|
-
version = "0.
|
|
2186
|
+
version = "0.7.0"
|
|
2187
2187
|
dependencies = [
|
|
2188
2188
|
"pyo3-stub-gen",
|
|
2189
2189
|
"sdk-python",
|
|
@@ -2191,7 +2191,7 @@ dependencies = [
|
|
|
2191
2191
|
|
|
2192
2192
|
[[package]]
|
|
2193
2193
|
name = "sdk-ruby"
|
|
2194
|
-
version = "0.
|
|
2194
|
+
version = "0.7.0"
|
|
2195
2195
|
dependencies = [
|
|
2196
2196
|
"magnus",
|
|
2197
2197
|
"quicknode-sdk",
|
|
@@ -3180,18 +3180,18 @@ dependencies = [
|
|
|
3180
3180
|
|
|
3181
3181
|
[[package]]
|
|
3182
3182
|
name = "zerocopy"
|
|
3183
|
-
version = "0.8.
|
|
3183
|
+
version = "0.8.54"
|
|
3184
3184
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3185
|
-
checksum = "
|
|
3185
|
+
checksum = "b7cbbc0a705a0fd05cc3676525980d2bf5a9bc4adac6d6475209a7887cf59d19"
|
|
3186
3186
|
dependencies = [
|
|
3187
3187
|
"zerocopy-derive",
|
|
3188
3188
|
]
|
|
3189
3189
|
|
|
3190
3190
|
[[package]]
|
|
3191
3191
|
name = "zerocopy-derive"
|
|
3192
|
-
version = "0.8.
|
|
3192
|
+
version = "0.8.54"
|
|
3193
3193
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
3194
|
-
checksum = "
|
|
3194
|
+
checksum = "e2e817b7b52d0c7358d3246da9d69935ebb18116b2b102b4230dac079b4862f5"
|
|
3195
3195
|
dependencies = [
|
|
3196
3196
|
"proc-macro2",
|
|
3197
3197
|
"quote",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: quicknode-sdk
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Classifier: Intended Audience :: Developers
|
|
5
5
|
Classifier: License :: OSI Approved :: MIT License
|
|
6
6
|
Classifier: Operating System :: POSIX :: Linux
|
|
@@ -1698,6 +1698,55 @@ schema = await qn.sql.get_schema("hyperliquid-core-mainnet")
|
|
|
1698
1698
|
print(len(schema.tables))
|
|
1699
1699
|
```
|
|
1700
1700
|
|
|
1701
|
+
---
|
|
1702
|
+
|
|
1703
|
+
### RPC & Tooling Access
|
|
1704
|
+
|
|
1705
|
+
Tooling Access provisions a single multichain, read-only endpoint per account and
|
|
1706
|
+
mints short-lived session JWTs. `qn.rpc` makes JSON-RPC calls directly against that
|
|
1707
|
+
endpoint, minting and refreshing the JWT automatically — no endpoint URL or token to
|
|
1708
|
+
manage.
|
|
1709
|
+
|
|
1710
|
+
Tooling Access must be enabled once (admin role + eligible plan). The control-plane
|
|
1711
|
+
methods live on `qn.admin`:
|
|
1712
|
+
|
|
1713
|
+
```python
|
|
1714
|
+
# Python
|
|
1715
|
+
status = await qn.admin.tooling_access_status()
|
|
1716
|
+
if not status.enabled:
|
|
1717
|
+
await qn.admin.enable_tooling_access() # idempotent; admin role required
|
|
1718
|
+
|
|
1719
|
+
# Make on-chain calls. params defaults to []; pass a list (positional) or dict.
|
|
1720
|
+
block_number = await qn.rpc.call("eth_blockNumber")
|
|
1721
|
+
balance = await qn.rpc.call("eth_getBalance", ["0xabc...", "latest"])
|
|
1722
|
+
|
|
1723
|
+
# Multichain: select a network by its multichain_urls key. Seed the map first
|
|
1724
|
+
# (from admin.get_endpoint_urls), then pass network=.
|
|
1725
|
+
urls = await qn.admin.get_endpoint_urls(endpoint_id)
|
|
1726
|
+
mc = urls.data.multichain_urls if urls.data else {}
|
|
1727
|
+
qn.rpc.set_networks({k: v.http_url for k, v in (mc or {}).items()})
|
|
1728
|
+
slot = await qn.rpc.call("getSlot", network="solana-mainnet")
|
|
1729
|
+
|
|
1730
|
+
# Custom endpoint URL: send to a fully-formed HTTP URL, bypassing Tooling Access
|
|
1731
|
+
# and the JWT (no Authorization header). Per-call via endpoint_url=, or
|
|
1732
|
+
# client-wide via RpcConfig(endpoint_url=...). endpoint_url and network are
|
|
1733
|
+
# mutually exclusive (a custom URL is not multichain-routed).
|
|
1734
|
+
block = await qn.rpc.call("eth_blockNumber", endpoint_url="https://my-endpoint.example/rpc")
|
|
1735
|
+
|
|
1736
|
+
# A JSON-RPC error member is raised as RpcError (with .code and .message).
|
|
1737
|
+
from quicknode_sdk import RpcError
|
|
1738
|
+
try:
|
|
1739
|
+
await qn.rpc.call("eth_getBalance", ["bad"])
|
|
1740
|
+
except RpcError as e:
|
|
1741
|
+
print(e.code, e.message)
|
|
1742
|
+
```
|
|
1743
|
+
|
|
1744
|
+
A host that persists across processes can snapshot the cached token with
|
|
1745
|
+
`qn.rpc.current_token()` and re-seed it via `RpcConfig(seed=...)` on the next
|
|
1746
|
+
construction; `refresh_margin_secs` (default 60) tunes how early the token is
|
|
1747
|
+
refreshed. Set `RpcConfig(endpoint_url=...)` to route every call to a custom
|
|
1748
|
+
HTTP URL by default (no JWT minted); a per-call `endpoint_url` overrides it.
|
|
1749
|
+
|
|
1701
1750
|
## Error Handling
|
|
1702
1751
|
|
|
1703
1752
|
Every binding exposes a typed exception hierarchy derived from the core `SdkError`
|
|
@@ -1713,8 +1762,9 @@ subclass to branch on transport vs. API semantics.
|
|
|
1713
1762
|
| `ConnectionError` | connection refused / DNS / TLS (subclass of `HttpError`) | — |
|
|
1714
1763
|
| `ApiError` | non-2xx HTTP response | `status`, `body` |
|
|
1715
1764
|
| `DecodeError` | 2xx response but JSON parse failed | `body` |
|
|
1765
|
+
| `RpcError` | JSON-RPC call returned an `error` member | `code`, `message` |
|
|
1716
1766
|
|
|
1717
|
-
Class names: Importable from `quicknode_sdk`: `QuicknodeError`, `ConfigError`, `HttpError`, `TimeoutError`, `ConnectionError`, `ApiError`, `DecodeError`.
|
|
1767
|
+
Class names: Importable from `quicknode_sdk`: `QuicknodeError`, `ConfigError`, `HttpError`, `TimeoutError`, `ConnectionError`, `ApiError`, `DecodeError`, `RpcError`.
|
|
1718
1768
|
|
|
1719
1769
|
```python
|
|
1720
1770
|
# Python
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "quicknode-sdk"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.7.0"
|
|
4
4
|
edition.workspace = true
|
|
5
5
|
license.workspace = true
|
|
6
6
|
description = "Core library for quicknode sdk"
|
|
@@ -34,6 +34,10 @@ bon = { version = "3.9", optional = true }
|
|
|
34
34
|
config = "0.15"
|
|
35
35
|
url = "2.5.8"
|
|
36
36
|
secrecy = "0.8"
|
|
37
|
+
# sync-only: provides tokio::sync::Mutex for single-flight JWT refresh in the
|
|
38
|
+
# rpc client without pulling in the tokio runtime. The async runtime itself is
|
|
39
|
+
# supplied by the caller (bindings or the user's own runtime).
|
|
40
|
+
tokio = { version = "1", default-features = false, features = ["sync"] }
|
|
37
41
|
|
|
38
42
|
[[example]]
|
|
39
43
|
name = "admin"
|
|
@@ -55,6 +59,10 @@ required-features = ["rust"]
|
|
|
55
59
|
name = "webhooks_e2e"
|
|
56
60
|
required-features = ["rust"]
|
|
57
61
|
|
|
62
|
+
[[example]]
|
|
63
|
+
name = "rpc"
|
|
64
|
+
required-features = ["rust"]
|
|
65
|
+
|
|
58
66
|
[dev-dependencies]
|
|
59
67
|
tokio = { version = "1.0", features = ["rt-multi-thread", "macros"] }
|
|
60
68
|
wiremock = "0.6"
|
|
@@ -1760,6 +1760,67 @@ let schema = qn.sql.get_schema("hyperliquid-core-mainnet").await?;
|
|
|
1760
1760
|
println!("{} tables", schema.tables.len());
|
|
1761
1761
|
```
|
|
1762
1762
|
|
|
1763
|
+
---
|
|
1764
|
+
|
|
1765
|
+
### RPC & Tooling Access
|
|
1766
|
+
|
|
1767
|
+
Tooling Access provisions a single multichain, read-only endpoint per account and
|
|
1768
|
+
mints short-lived session JWTs. `qn.rpc` makes JSON-RPC calls directly against that
|
|
1769
|
+
endpoint, minting and refreshing the JWT automatically — no endpoint URL or token to
|
|
1770
|
+
manage.
|
|
1771
|
+
|
|
1772
|
+
Tooling Access must be enabled once (admin role + eligible plan). The control-plane
|
|
1773
|
+
methods live on `qn.admin`:
|
|
1774
|
+
|
|
1775
|
+
```rust
|
|
1776
|
+
// Rust
|
|
1777
|
+
let status = qn.admin.tooling_access_status().await?;
|
|
1778
|
+
if !status.enabled {
|
|
1779
|
+
qn.admin.enable_tooling_access().await?; // idempotent; admin role required
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
// call(method, params, network, endpoint_url). params is Option<serde_json::Value>;
|
|
1783
|
+
// None defaults to []. Both trailing args are Option and independently omittable.
|
|
1784
|
+
let block_number = qn.rpc.call("eth_blockNumber", None, None, None).await?;
|
|
1785
|
+
let balance = qn
|
|
1786
|
+
.rpc
|
|
1787
|
+
.call(
|
|
1788
|
+
"eth_getBalance",
|
|
1789
|
+
Some(serde_json::json!(["0xabc...", "latest"])),
|
|
1790
|
+
None,
|
|
1791
|
+
None,
|
|
1792
|
+
)
|
|
1793
|
+
.await?;
|
|
1794
|
+
|
|
1795
|
+
// Multichain: seed the per-network URL map (from get_endpoint_urls), then pass
|
|
1796
|
+
// the network key as the third arg.
|
|
1797
|
+
let urls = qn.admin.get_endpoint_urls(endpoint_id).await?;
|
|
1798
|
+
if let Some(data) = urls.data {
|
|
1799
|
+
if let Some(mc) = data.multichain_urls {
|
|
1800
|
+
qn.rpc
|
|
1801
|
+
.set_networks(mc.into_iter().map(|(k, v)| (k, v.http_url)).collect());
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
let slot = qn.rpc.call("getSlot", None, Some("solana-mainnet".into()), None).await?;
|
|
1805
|
+
|
|
1806
|
+
// Custom endpoint URL: send to a fully-formed HTTP URL, bypassing Tooling Access
|
|
1807
|
+
// and the JWT (no Authorization header). Per-call via the 4th arg, or client-wide
|
|
1808
|
+
// via RpcConfig { endpoint_url, .. }. endpoint_url and network are mutually
|
|
1809
|
+
// exclusive (a custom URL is not multichain-routed).
|
|
1810
|
+
let block = qn
|
|
1811
|
+
.rpc
|
|
1812
|
+
.call("eth_blockNumber", None, None, Some("https://my-endpoint.example/rpc".into()))
|
|
1813
|
+
.await?;
|
|
1814
|
+
|
|
1815
|
+
// A JSON-RPC error member is returned as SdkError::Rpc { code, message }.
|
|
1816
|
+
```
|
|
1817
|
+
|
|
1818
|
+
A host that persists across processes can snapshot the cached token with
|
|
1819
|
+
`qn.rpc.current_token()` and re-seed it via `RpcConfig { seed, .. }`;
|
|
1820
|
+
`refresh_margin_secs` (default 60) tunes how early the token is refreshed. Set
|
|
1821
|
+
`RpcConfig { endpoint_url, .. }` to route every call to a custom HTTP URL by
|
|
1822
|
+
default (no JWT minted); a per-call `endpoint_url` overrides it.
|
|
1823
|
+
|
|
1763
1824
|
## Error Handling
|
|
1764
1825
|
|
|
1765
1826
|
Every binding exposes a typed exception hierarchy derived from the core `SdkError`
|
|
@@ -1775,8 +1836,9 @@ subclass to branch on transport vs. API semantics.
|
|
|
1775
1836
|
| `ConnectionError` | connection refused / DNS / TLS (subclass of `HttpError`) | — |
|
|
1776
1837
|
| `ApiError` | non-2xx HTTP response | `status`, `body` |
|
|
1777
1838
|
| `DecodeError` | 2xx response but JSON parse failed | `body` |
|
|
1839
|
+
| `RpcError` | JSON-RPC call returned an `error` member | `code`, `message` |
|
|
1778
1840
|
|
|
1779
|
-
Variants: pattern-match on `SdkError { Http, Api, Decode, UrlParse, Config }`; use `err.http_kind()` to classify `Http` into `Timeout`, `Connect`, or `Other`.
|
|
1841
|
+
Variants: pattern-match on `SdkError { Http, Api, Decode, UrlParse, Config, Rpc }`; use `err.http_kind()` to classify `Http` into `Timeout`, `Connect`, or `Other`.
|
|
1780
1842
|
|
|
1781
1843
|
```rust
|
|
1782
1844
|
// Rust
|
|
@@ -874,6 +874,7 @@ async fn main() {
|
|
|
874
874
|
webhooks: None,
|
|
875
875
|
kvstore: None,
|
|
876
876
|
sql: None,
|
|
877
|
+
rpc: None,
|
|
877
878
|
};
|
|
878
879
|
let headered = QuicknodeSdk::new(&with_headers).expect("build sdk with custom headers");
|
|
879
880
|
match headered
|
|
@@ -900,6 +901,8 @@ async fn main() {
|
|
|
900
901
|
streams: None,
|
|
901
902
|
webhooks: None,
|
|
902
903
|
kvstore: None,
|
|
904
|
+
sql: None,
|
|
905
|
+
rpc: None,
|
|
903
906
|
};
|
|
904
907
|
let tiny = QuicknodeSdk::new(&blackhole).expect("build tiny sdk");
|
|
905
908
|
match tiny
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
use quicknode_sdk::{errors::SdkError, QuicknodeSdk, SdkFullConfig};
|
|
2
|
+
|
|
3
|
+
#[tokio::main]
|
|
4
|
+
#[allow(clippy::unwrap_used, clippy::expect_used)]
|
|
5
|
+
async fn main() {
|
|
6
|
+
let config = SdkFullConfig::from_env().expect("Config from env failed");
|
|
7
|
+
let qn = QuicknodeSdk::new(&config).expect("sdk failed to initialize");
|
|
8
|
+
|
|
9
|
+
// Ensure Tooling Access is provisioned (idempotent; requires admin role).
|
|
10
|
+
let status = qn
|
|
11
|
+
.admin
|
|
12
|
+
.tooling_access_status()
|
|
13
|
+
.await
|
|
14
|
+
.expect("tooling_access_status failed");
|
|
15
|
+
println!("tooling access enabled: {}", status.enabled);
|
|
16
|
+
if !status.enabled {
|
|
17
|
+
match qn.admin.enable_tooling_access().await {
|
|
18
|
+
Ok(s) => println!("enabled tooling access: {}", s.enabled),
|
|
19
|
+
Err(e) => {
|
|
20
|
+
eprintln!("could not enable tooling access: {e}");
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Make a JSON-RPC call. The SDK mints and refreshes the session JWT.
|
|
27
|
+
match qn.rpc.call("eth_blockNumber", None, None, None).await {
|
|
28
|
+
Ok(result) => println!("eth_blockNumber => {result}"),
|
|
29
|
+
Err(e) => eprintln!("rpc call error: {e}"),
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Multichain: seed the per-network URL map from the endpoint id (returned by
|
|
33
|
+
// status), then route a call to a specific network by its key.
|
|
34
|
+
if let Some(id) = &status.endpoint_id {
|
|
35
|
+
if let Ok(urls) = qn.admin.get_endpoint_urls(id).await {
|
|
36
|
+
if let Some(mc) = urls.data.and_then(|d| d.multichain_urls) {
|
|
37
|
+
qn.rpc
|
|
38
|
+
.set_networks(mc.into_iter().map(|(k, v)| (k, v.http_url)).collect());
|
|
39
|
+
match qn
|
|
40
|
+
.rpc
|
|
41
|
+
.call("getSlot", None, Some("solana-mainnet".to_string()), None)
|
|
42
|
+
.await
|
|
43
|
+
{
|
|
44
|
+
Ok(result) => println!("solana getSlot => {result}"),
|
|
45
|
+
Err(e) => eprintln!("solana rpc error: {e}"),
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Demonstrate the typed JSON-RPC error path.
|
|
52
|
+
match qn
|
|
53
|
+
.rpc
|
|
54
|
+
.call(
|
|
55
|
+
"eth_getBalance",
|
|
56
|
+
Some(serde_json::json!(["not-an-address"])),
|
|
57
|
+
None,
|
|
58
|
+
None,
|
|
59
|
+
)
|
|
60
|
+
.await
|
|
61
|
+
{
|
|
62
|
+
Ok(result) => println!("unexpected ok: {result}"),
|
|
63
|
+
Err(SdkError::Rpc { code, message }) => {
|
|
64
|
+
println!("got expected RpcError: code={code} message={message}");
|
|
65
|
+
}
|
|
66
|
+
Err(e) => eprintln!("other error: {e}"),
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Custom endpoint URL: send a call to a fully-formed HTTP URL, bypassing the
|
|
70
|
+
// Tooling Access endpoint and the session JWT entirely. Useful for a
|
|
71
|
+
// provisioned `.quiknode.pro` URL or a self-hosted node. Set it per-call
|
|
72
|
+
// here, or client-wide via `RpcConfig::endpoint_url`.
|
|
73
|
+
if let Ok(custom_url) = std::env::var("QN_RPC_ENDPOINT_URL") {
|
|
74
|
+
match qn
|
|
75
|
+
.rpc
|
|
76
|
+
.call("eth_blockNumber", None, None, Some(custom_url))
|
|
77
|
+
.await
|
|
78
|
+
{
|
|
79
|
+
Ok(result) => println!("custom endpoint eth_blockNumber => {result}"),
|
|
80
|
+
Err(e) => eprintln!("custom endpoint rpc error: {e}"),
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -11,6 +11,7 @@ pub mod endpoints;
|
|
|
11
11
|
pub mod logs;
|
|
12
12
|
pub mod tags;
|
|
13
13
|
pub mod teams;
|
|
14
|
+
pub mod tooling_access;
|
|
14
15
|
pub mod usage;
|
|
15
16
|
|
|
16
17
|
pub use account::{AccountInfo, AccountInfoResponse, AccountSubscription};
|
|
@@ -66,6 +67,7 @@ pub use teams::{
|
|
|
66
67
|
TeamDetail, TeamEndpoint, TeamMessageData, TeamSummary, TeamUser, UpdateTeamEndpointsData,
|
|
67
68
|
UpdateTeamEndpointsRequest, UpdateTeamEndpointsResponse,
|
|
68
69
|
};
|
|
70
|
+
pub use tooling_access::ToolingAccessStatus;
|
|
69
71
|
|
|
70
72
|
pub use usage::{
|
|
71
73
|
ChainUsage, EndpointUsage, GetUsageByChainResponse, GetUsageByEndpointResponse,
|
|
@@ -1957,6 +1959,7 @@ mod tests {
|
|
|
1957
1959
|
webhooks: None,
|
|
1958
1960
|
kvstore: None,
|
|
1959
1961
|
sql: None,
|
|
1962
|
+
rpc: None,
|
|
1960
1963
|
})
|
|
1961
1964
|
.unwrap()
|
|
1962
1965
|
}
|
|
@@ -3847,6 +3850,7 @@ mod tests {
|
|
|
3847
3850
|
webhooks: None,
|
|
3848
3851
|
kvstore: None,
|
|
3849
3852
|
sql: None,
|
|
3853
|
+
rpc: None,
|
|
3850
3854
|
});
|
|
3851
3855
|
assert!(matches!(result, Err(crate::errors::SdkError::Config(_))));
|
|
3852
3856
|
}
|