quicknode-sdk 0.3.0__tar.gz → 0.5.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.
Files changed (49) hide show
  1. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/Cargo.lock +36 -25
  2. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/Cargo.toml +4 -1
  3. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/PKG-INFO +45 -6
  4. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/Cargo.toml +1 -1
  5. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/README.md +47 -5
  6. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/examples/admin_e2e.rs +7 -7
  7. quicknode_sdk-0.5.0/crates/core/examples/sql.rs +70 -0
  8. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/src/admin/endpoint_security.rs +5 -10
  9. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/src/admin/mod.rs +3 -1
  10. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/src/config.rs +25 -1
  11. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/src/kvstore/mod.rs +1 -0
  12. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/src/lib.rs +20 -2
  13. quicknode_sdk-0.5.0/crates/core/src/sql/mod.rs +466 -0
  14. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/src/streams/mod.rs +1 -0
  15. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/src/webhooks/mod.rs +1 -0
  16. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/python/Cargo.toml +1 -0
  17. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/python/src/lib.rs +73 -10
  18. quicknode_sdk-0.5.0/crates/python/src/sql.rs +59 -0
  19. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/pyproject.toml +1 -1
  20. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/python/README.md +44 -5
  21. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/python/quicknode_sdk/__init__.py +16 -0
  22. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/python/quicknode_sdk/__init__.pyi +16 -0
  23. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/python/quicknode_sdk/_core/__init__.pyi +260 -15
  24. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/python/quicknode_sdk/init_manual_override.pyi +16 -0
  25. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/LICENSE +0 -0
  26. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/LICENSE +0 -0
  27. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/examples/admin.rs +0 -0
  28. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/examples/kvstore_e2e.rs +0 -0
  29. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/examples/streams.rs +0 -0
  30. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/examples/streams_e2e.rs +0 -0
  31. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/examples/webhooks_e2e.rs +0 -0
  32. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/src/admin/billing.rs +0 -0
  33. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/src/admin/bulk.rs +0 -0
  34. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/src/admin/chains.rs +0 -0
  35. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/src/admin/endpoint_metrics.rs +0 -0
  36. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/src/admin/endpoint_rate_limits.rs +0 -0
  37. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/src/admin/endpoint_urls.rs +0 -0
  38. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/src/admin/endpoints.rs +0 -0
  39. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/src/admin/logs.rs +0 -0
  40. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/src/admin/tags.rs +0 -0
  41. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/src/admin/teams.rs +0 -0
  42. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/src/admin/usage.rs +0 -0
  43. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/src/errors.rs +0 -0
  44. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/src/streams/stream.rs +0 -0
  45. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/core/src/webhooks/webhook.rs +0 -0
  46. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/python/src/errors.rs +0 -0
  47. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/python/src/streams_destination.rs +0 -0
  48. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/crates/python/src/webhooks_template.rs +0 -0
  49. {quicknode_sdk-0.3.0 → quicknode_sdk-0.5.0}/python/quicknode_sdk/py.typed +0 -0
@@ -1085,9 +1085,9 @@ dependencies = [
1085
1085
 
1086
1086
  [[package]]
1087
1087
  name = "js-sys"
1088
- version = "0.3.102"
1088
+ version = "0.3.103"
1089
1089
  source = "registry+https://github.com/rust-lang/crates.io-index"
1090
- checksum = "03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31"
1090
+ checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102"
1091
1091
  dependencies = [
1092
1092
  "cfg-if",
1093
1093
  "futures-util",
@@ -1234,9 +1234,9 @@ dependencies = [
1234
1234
 
1235
1235
  [[package]]
1236
1236
  name = "napi"
1237
- version = "3.9.3"
1237
+ version = "3.9.4"
1238
1238
  source = "registry+https://github.com/rust-lang/crates.io-index"
1239
- checksum = "fbd9f9295f3ff5921e78a71222c3361a8216f7760b1a99a6ad4e8441de18bbb9"
1239
+ checksum = "b41bda2ac390efb5e8d22025d925ccc3f3807d8c1bea6d19b36127247c4b8f83"
1240
1240
  dependencies = [
1241
1241
  "bitflags",
1242
1242
  "ctor",
@@ -1258,9 +1258,9 @@ checksum = "c9c366d2c8c60b86fa632df75f745509b52f9128f91a6bad4c796e44abb505e1"
1258
1258
 
1259
1259
  [[package]]
1260
1260
  name = "napi-derive"
1261
- version = "3.5.6"
1261
+ version = "3.5.7"
1262
1262
  source = "registry+https://github.com/rust-lang/crates.io-index"
1263
- checksum = "89b3f766e04667e6da0e181e2da4f85475d5a6513b7cf6a80bea184e224a5b42"
1263
+ checksum = "61d66f70256ad5aef58659966064471d0ad90e2897bc36a5a5e0389c85aabc1e"
1264
1264
  dependencies = [
1265
1265
  "convert_case 0.11.0",
1266
1266
  "ctor",
@@ -1272,9 +1272,9 @@ dependencies = [
1272
1272
 
1273
1273
  [[package]]
1274
1274
  name = "napi-derive-backend"
1275
- version = "5.0.4"
1275
+ version = "5.0.5"
1276
1276
  source = "registry+https://github.com/rust-lang/crates.io-index"
1277
- checksum = "0d5af30503edf933ce7377cf6d4c877a62b0f1107ea05585f1b5e430e88d5baf"
1277
+ checksum = "81b4b08f15eed7a2a20c3f4c6314013fc3ac890a3afa9892b594485299ebdb2d"
1278
1278
  dependencies = [
1279
1279
  "convert_case 0.11.0",
1280
1280
  "proc-macro2",
@@ -1694,9 +1694,19 @@ dependencies = [
1694
1694
  "syn",
1695
1695
  ]
1696
1696
 
1697
+ [[package]]
1698
+ name = "pythonize"
1699
+ version = "0.27.0"
1700
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1701
+ checksum = "a3a8f29db331e28c332c63496cfcbb822aca3d7320bc08b655d7fd0c29c50ede"
1702
+ dependencies = [
1703
+ "pyo3",
1704
+ "serde",
1705
+ ]
1706
+
1697
1707
  [[package]]
1698
1708
  name = "quicknode-sdk"
1699
- version = "0.3.0"
1709
+ version = "0.5.0"
1700
1710
  dependencies = [
1701
1711
  "bon",
1702
1712
  "config",
@@ -2173,7 +2183,7 @@ dependencies = [
2173
2183
 
2174
2184
  [[package]]
2175
2185
  name = "sdk-node"
2176
- version = "0.3.0"
2186
+ version = "0.5.0"
2177
2187
  dependencies = [
2178
2188
  "napi",
2179
2189
  "napi-build",
@@ -2185,18 +2195,19 @@ dependencies = [
2185
2195
 
2186
2196
  [[package]]
2187
2197
  name = "sdk-python"
2188
- version = "0.3.0"
2198
+ version = "0.5.0"
2189
2199
  dependencies = [
2190
2200
  "pyo3",
2191
2201
  "pyo3-async-runtimes",
2192
2202
  "pyo3-stub-gen",
2203
+ "pythonize",
2193
2204
  "quicknode-sdk",
2194
2205
  "serde_json",
2195
2206
  ]
2196
2207
 
2197
2208
  [[package]]
2198
2209
  name = "sdk-python-stubs"
2199
- version = "0.3.0"
2210
+ version = "0.5.0"
2200
2211
  dependencies = [
2201
2212
  "pyo3-stub-gen",
2202
2213
  "sdk-python",
@@ -2204,7 +2215,7 @@ dependencies = [
2204
2215
 
2205
2216
  [[package]]
2206
2217
  name = "sdk-ruby"
2207
- version = "0.3.0"
2218
+ version = "0.5.0"
2208
2219
  dependencies = [
2209
2220
  "magnus",
2210
2221
  "quicknode-sdk",
@@ -2919,9 +2930,9 @@ dependencies = [
2919
2930
 
2920
2931
  [[package]]
2921
2932
  name = "wasm-bindgen"
2922
- version = "0.2.125"
2933
+ version = "0.2.126"
2923
2934
  source = "registry+https://github.com/rust-lang/crates.io-index"
2924
- checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a"
2935
+ checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4"
2925
2936
  dependencies = [
2926
2937
  "cfg-if",
2927
2938
  "once_cell",
@@ -2932,9 +2943,9 @@ dependencies = [
2932
2943
 
2933
2944
  [[package]]
2934
2945
  name = "wasm-bindgen-futures"
2935
- version = "0.4.75"
2946
+ version = "0.4.76"
2936
2947
  source = "registry+https://github.com/rust-lang/crates.io-index"
2937
- checksum = "503b14d284f2c8dac03b819967e155ea753f573586193b2b2c95990cb5d69280"
2948
+ checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d"
2938
2949
  dependencies = [
2939
2950
  "js-sys",
2940
2951
  "wasm-bindgen",
@@ -2942,9 +2953,9 @@ dependencies = [
2942
2953
 
2943
2954
  [[package]]
2944
2955
  name = "wasm-bindgen-macro"
2945
- version = "0.2.125"
2956
+ version = "0.2.126"
2946
2957
  source = "registry+https://github.com/rust-lang/crates.io-index"
2947
- checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d"
2958
+ checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1"
2948
2959
  dependencies = [
2949
2960
  "quote",
2950
2961
  "wasm-bindgen-macro-support",
@@ -2952,9 +2963,9 @@ dependencies = [
2952
2963
 
2953
2964
  [[package]]
2954
2965
  name = "wasm-bindgen-macro-support"
2955
- version = "0.2.125"
2966
+ version = "0.2.126"
2956
2967
  source = "registry+https://github.com/rust-lang/crates.io-index"
2957
- checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd"
2968
+ checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e"
2958
2969
  dependencies = [
2959
2970
  "bumpalo",
2960
2971
  "proc-macro2",
@@ -2965,18 +2976,18 @@ dependencies = [
2965
2976
 
2966
2977
  [[package]]
2967
2978
  name = "wasm-bindgen-shared"
2968
- version = "0.2.125"
2979
+ version = "0.2.126"
2969
2980
  source = "registry+https://github.com/rust-lang/crates.io-index"
2970
- checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f"
2981
+ checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24"
2971
2982
  dependencies = [
2972
2983
  "unicode-ident",
2973
2984
  ]
2974
2985
 
2975
2986
  [[package]]
2976
2987
  name = "web-sys"
2977
- version = "0.3.102"
2988
+ version = "0.3.103"
2978
2989
  source = "registry+https://github.com/rust-lang/crates.io-index"
2979
- checksum = "a6430a72df5eb332242960fe84b3002a241163998241eb596d4f739b9757061d"
2990
+ checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141"
2980
2991
  dependencies = [
2981
2992
  "js-sys",
2982
2993
  "wasm-bindgen",
@@ -3,7 +3,7 @@ resolver = "2"
3
3
  members = ["crates/core", "crates/python"]
4
4
 
5
5
  [workspace.package]
6
- version = "0.3.0"
6
+ version = "0.5.0"
7
7
  edition = "2021"
8
8
  license = "MIT"
9
9
 
@@ -20,6 +20,9 @@ needless_pass_by_value = "warn"
20
20
  [workspace.dependencies]
21
21
  pyo3 = { version = "0.27", features = ["experimental-async"] }
22
22
  pyo3-async-runtimes = { version = "0.27", features = ["tokio-runtime"] }
23
+ # Tracks pyo3 versions in lockstep; converts dynamic SQL result rows
24
+ # (serde_json::Value) to native Python objects.
25
+ pythonize = { version = "0.27" }
23
26
  napi = { version = "3", features = ["async", "tokio_rt", "compat-mode"] }
24
27
  napi-derive = { version = "3", features = ["compat-mode"] }
25
28
  pyo3-stub-gen = { version = "0.19.0" }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quicknode-sdk
3
- Version: 0.3.0
3
+ Version: 0.5.0
4
4
  Classifier: Intended Audience :: Developers
5
5
  Classifier: License :: OSI Approved :: MIT License
6
6
  Classifier: Operating System :: POSIX :: Linux
@@ -70,6 +70,7 @@ This is one of four language bindings published from the same Rust core. See the
70
70
  - [KV Store Client](#kv-store-client)
71
71
  - [Sets](#sets)
72
72
  - [Lists](#lists)
73
+ - [SQL Client](#sql-client)
73
74
  - [Error Handling](#error-handling)
74
75
  - [License](#license)
75
76
 
@@ -79,7 +80,7 @@ This is one of four language bindings published from the same Rust core. See the
79
80
 
80
81
  ## Quick Start
81
82
 
82
- Construct the SDK once, then reach into the four sub-clients (`admin`, `streams`, `webhooks`, `kvstore`). Subsequent API Reference snippets assume you have a `qn` handle from one of these blocks.
83
+ Construct the SDK once, then reach into the five sub-clients (`admin`, `streams`, `webhooks`, `kvstore`, `sql`). Subsequent API Reference snippets assume you have a `qn` handle from one of these blocks.
83
84
 
84
85
  ```python
85
86
  # Python
@@ -124,6 +125,7 @@ Environment variables (prefix `QN_SDK__`, separator `__`):
124
125
  | `QN_SDK__STREAMS__BASE_URL` | no | `https://api.quicknode.com/streams/rest/v1/` | Override streams base URL |
125
126
  | `QN_SDK__WEBHOOKS__BASE_URL` | no | `https://api.quicknode.com/webhooks/rest/v1/` | Override webhooks base URL |
126
127
  | `QN_SDK__KVSTORE__BASE_URL` | no | `https://api.quicknode.com/kv/rest/v1/` | Override KV store base URL |
128
+ | `QN_SDK__SQL__BASE_URL` | no | `https://api.quicknode.com/sql/rest/v1/` | Override SQL Explorer base URL |
127
129
  | `QN_SDK__HTTP__HEADERS__<NAME>` | no | — | Custom HTTP header sent on every request. Overrides SDK-managed headers (see below). |
128
130
 
129
131
  ### Custom headers and `User-Agent`
@@ -580,7 +582,7 @@ await qn.admin.delete_token("ep-123", "tok-1")
580
582
 
581
583
  Whitelists a referrer URL or domain on an endpoint.
582
584
 
583
- **Parameters**: `id` (endpoint id, required); body: `referrer` (string, optional).
585
+ **Parameters**: `id` (endpoint id, required); body: `referrer` (string, required).
584
586
 
585
587
  **Returns**: nothing.
586
588
 
@@ -608,7 +610,7 @@ await qn.admin.delete_referrer("ep-123", "ref-1")
608
610
 
609
611
  Whitelists an IP address on an endpoint.
610
612
 
611
- **Parameters**: `id` (endpoint id, required); body: `ip` (string, optional).
613
+ **Parameters**: `id` (endpoint id, required); body: `ip` (string, required).
612
614
 
613
615
  **Returns**: nothing.
614
616
 
@@ -664,7 +666,7 @@ await qn.admin.delete_domain_mask("ep-123", "dm-1")
664
666
 
665
667
  Configures JWT validation on an endpoint.
666
668
 
667
- **Parameters**: `id` (endpoint id, required); body: `public_key` (string, optional), `kid` (string, required), `name` (string, optional).
669
+ **Parameters**: `id` (endpoint id, required); body: `public_key` (string, required), `kid` (string, required), `name` (string, required).
668
670
 
669
671
  **Returns**: nothing.
670
672
 
@@ -697,7 +699,7 @@ Whitelist specific RPC methods on an endpoint. Requests for methods not on the l
697
699
 
698
700
  ##### `create_request_filter` / `createRequestFilter`
699
701
 
700
- **Parameters**: `id` (endpoint id, required); body: `method` (string[], optional). Ruby's Hash key is `methods` (plural).
702
+ **Parameters**: `id` (endpoint id, required); body: `method` (string[], required). Ruby's Hash key is `methods` (plural).
701
703
 
702
704
  **Returns**: `CreateRequestFilterResponse` with `data.id`.
703
705
 
@@ -1630,6 +1632,43 @@ Deletes a list and all of its items.
1630
1632
  await qn.kvstore.delete_list("my-list")
1631
1633
  ```
1632
1634
 
1635
+ ---
1636
+
1637
+ ### SQL Client
1638
+
1639
+ Accessed as `qn.sql`. Runs SQL queries against indexed blockchain data and fetches the database schema. Backed by `https://api.quicknode.com/sql/rest/v1/`.
1640
+
1641
+ ##### `query`
1642
+
1643
+ Executes a SQL query against a cluster and returns the result set. Paginate by writing `LIMIT`/`OFFSET` into the SQL.
1644
+
1645
+ **Parameters**: `query` (str, required), `cluster_id` (str, required).
1646
+
1647
+ **Returns**: `QueryResponse` — `meta` (list of `ColumnMeta`, each with `name` and `column_type`), `data` (`list[dict]`, rows keyed by column name), `rows`, `rows_before_limit_at_least`, `statistics` (`QueryStatistics` with `elapsed`, `rows_read`, `bytes_read`), and `credits`.
1648
+
1649
+ ```python
1650
+ # Python
1651
+ resp = await qn.sql.query(
1652
+ query="SELECT action_type, user FROM hyperliquid_system_actions ORDER BY block_time DESC LIMIT 100",
1653
+ cluster_id="hyperliquid-core-mainnet",
1654
+ )
1655
+ print(resp.rows, resp.data[0])
1656
+ ```
1657
+
1658
+ ##### `get_schema`
1659
+
1660
+ Fetches the database schema for a cluster: table names, columns, types, sort keys, and partition strategies.
1661
+
1662
+ **Parameters**: `cluster_id` (str, required).
1663
+
1664
+ **Returns**: `ChainSchema` — `chain`, `cluster_id`, and `tables` (list of `TableSchema`, each with `name`, `engine`, `total_rows`, `partition_key`, `sorting_key`, and `columns` of `ColumnSchema` with `name` and `column_type`).
1665
+
1666
+ ```python
1667
+ # Python
1668
+ schema = await qn.sql.get_schema("hyperliquid-core-mainnet")
1669
+ print(len(schema.tables))
1670
+ ```
1671
+
1633
1672
  ## Error Handling
1634
1673
 
1635
1674
  Every binding exposes a typed exception hierarchy derived from the core `SdkError`
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "quicknode-sdk"
3
- version = "0.3.0"
3
+ version = "0.5.0"
4
4
  edition.workspace = true
5
5
  license.workspace = true
6
6
  description = "Core library for quicknode sdk"
@@ -46,6 +46,7 @@ This is one of four language bindings published from the same Rust core. See the
46
46
  - [KV Store Client](#kv-store-client)
47
47
  - [Sets](#sets)
48
48
  - [Lists](#lists)
49
+ - [SQL Client](#sql-client)
49
50
  - [Error Handling](#error-handling)
50
51
  - [License](#license)
51
52
 
@@ -55,7 +56,7 @@ This is one of four language bindings published from the same Rust core. See the
55
56
 
56
57
  ## Quick Start
57
58
 
58
- Construct the SDK once, then reach into the four sub-clients (`admin`, `streams`, `webhooks`, `kvstore`). Subsequent API Reference snippets assume you have a `qn` handle from one of these blocks.
59
+ Construct the SDK once, then reach into the five sub-clients (`admin`, `streams`, `webhooks`, `kvstore`, `sql`). Subsequent API Reference snippets assume you have a `qn` handle from one of these blocks.
59
60
 
60
61
  ```rust
61
62
  // Rust
@@ -99,6 +100,7 @@ Environment variables (prefix `QN_SDK__`, separator `__`):
99
100
  | `QN_SDK__STREAMS__BASE_URL` | no | `https://api.quicknode.com/streams/rest/v1/` | Override streams base URL |
100
101
  | `QN_SDK__WEBHOOKS__BASE_URL` | no | `https://api.quicknode.com/webhooks/rest/v1/` | Override webhooks base URL |
101
102
  | `QN_SDK__KVSTORE__BASE_URL` | no | `https://api.quicknode.com/kv/rest/v1/` | Override KV store base URL |
103
+ | `QN_SDK__SQL__BASE_URL` | no | `https://api.quicknode.com/sql/rest/v1/` | Override SQL Explorer base URL |
102
104
  | `QN_SDK__HTTP__HEADERS__<NAME>` | no | — | Custom HTTP header sent on every request. Overrides SDK-managed headers (see below). |
103
105
 
104
106
  ### Custom headers and `User-Agent`
@@ -570,7 +572,7 @@ qn.admin.delete_token("ep-123", "tok-1").await?;
570
572
 
571
573
  Whitelists a referrer URL or domain on an endpoint.
572
574
 
573
- **Parameters**: `id` (endpoint id, required); body: `referrer` (string, optional).
575
+ **Parameters**: `id` (endpoint id, required); body: `referrer` (string, required).
574
576
 
575
577
  **Returns**: nothing.
576
578
 
@@ -599,7 +601,7 @@ qn.admin.delete_referrer("ep-123", "ref-1").await?;
599
601
 
600
602
  Whitelists an IP address on an endpoint.
601
603
 
602
- **Parameters**: `id` (endpoint id, required); body: `ip` (string, optional).
604
+ **Parameters**: `id` (endpoint id, required); body: `ip` (string, required).
603
605
 
604
606
  **Returns**: nothing.
605
607
 
@@ -659,7 +661,7 @@ qn.admin.delete_domain_mask("ep-123", "dm-1").await?;
659
661
 
660
662
  Configures JWT validation on an endpoint.
661
663
 
662
- **Parameters**: `id` (endpoint id, required); body: `public_key` (string, optional), `kid` (string, required), `name` (string, optional).
664
+ **Parameters**: `id` (endpoint id, required); body: `public_key` (string, required), `kid` (string, required), `name` (string, required).
663
665
 
664
666
  **Returns**: nothing.
665
667
 
@@ -692,7 +694,7 @@ Whitelist specific RPC methods on an endpoint. Requests for methods not on the l
692
694
 
693
695
  ##### `create_request_filter` / `createRequestFilter`
694
696
 
695
- **Parameters**: `id` (endpoint id, required); body: `method` (string[], optional). Ruby's Hash key is `methods` (plural).
697
+ **Parameters**: `id` (endpoint id, required); body: `method` (string[], required). Ruby's Hash key is `methods` (plural).
696
698
 
697
699
  **Returns**: `CreateRequestFilterResponse` with `data.id`.
698
700
 
@@ -1689,6 +1691,46 @@ Deletes a list and all of its items.
1689
1691
  qn.kvstore.delete_list("my-list").await?;
1690
1692
  ```
1691
1693
 
1694
+ ---
1695
+
1696
+ ### SQL Client
1697
+
1698
+ Accessed as `qn.sql`. Runs SQL queries against indexed blockchain data and fetches the database schema. Backed by `https://api.quicknode.com/sql/rest/v1/`.
1699
+
1700
+ ##### `query`
1701
+
1702
+ Executes a SQL query against a cluster and returns the result set. Paginate by writing `LIMIT`/`OFFSET` into the SQL.
1703
+
1704
+ **Parameters**: `QueryParams` with `query` (String, required) and `cluster_id` (String, required).
1705
+
1706
+ **Returns**: `QueryResponse` — `meta` (`Vec<ColumnMeta>`, each with `name` and `column_type`), `data` (`Vec<serde_json::Value>`, rows as JSON objects keyed by column name), `rows`, `rows_before_limit_at_least`, `statistics` (`QueryStatistics` with `elapsed`, `rows_read`, `bytes_read`), and `credits`.
1707
+
1708
+ ```rust
1709
+ // Rust
1710
+ let resp = qn
1711
+ .sql
1712
+ .query(&QueryParams {
1713
+ query: "SELECT action_type, user FROM hyperliquid_system_actions ORDER BY block_time DESC LIMIT 100".to_string(),
1714
+ cluster_id: "hyperliquid-core-mainnet".to_string(),
1715
+ })
1716
+ .await?;
1717
+ println!("{} rows, {:?}", resp.rows, resp.data.first());
1718
+ ```
1719
+
1720
+ ##### `get_schema`
1721
+
1722
+ Fetches the database schema for a cluster: table names, columns, types, sort keys, and partition strategies.
1723
+
1724
+ **Parameters**: `cluster_id` (`&str`, required).
1725
+
1726
+ **Returns**: `ChainSchema` — `chain`, `cluster_id`, and `tables` (`Vec<TableSchema>`, each with `name`, `engine`, `total_rows`, `partition_key`, `sorting_key`, and `columns` of `ColumnSchema { name, column_type }`).
1727
+
1728
+ ```rust
1729
+ // Rust
1730
+ let schema = qn.sql.get_schema("hyperliquid-core-mainnet").await?;
1731
+ println!("{} tables", schema.tables.len());
1732
+ ```
1733
+
1692
1734
  ## Error Handling
1693
1735
 
1694
1736
  Every binding exposes a typed exception hierarchy derived from the core `SdkError`
@@ -341,7 +341,7 @@ async fn main() {
341
341
  .create_referrer(
342
342
  &endpoint_id,
343
343
  &CreateReferrerRequest {
344
- referrer: Some("https://example.com".to_string()),
344
+ referrer: "https://example.com".to_string(),
345
345
  },
346
346
  )
347
347
  .await
@@ -378,7 +378,7 @@ async fn main() {
378
378
  .create_ip(
379
379
  &endpoint_id,
380
380
  &CreateIpRequest {
381
- ip: Some("192.0.2.1".to_string()),
381
+ ip: "192.0.2.1".to_string(),
382
382
  },
383
383
  )
384
384
  .await
@@ -452,11 +452,10 @@ async fn main() {
452
452
  .create_jwt(
453
453
  &endpoint_id,
454
454
  &CreateJwtRequest {
455
- public_key: Some(
456
- "-----BEGIN PUBLIC KEY-----\nPLACEHOLDER\n-----END PUBLIC KEY-----".to_string(),
457
- ),
455
+ public_key: "-----BEGIN PUBLIC KEY-----\nPLACEHOLDER\n-----END PUBLIC KEY-----"
456
+ .to_string(),
458
457
  kid: "kid1".to_string(),
459
- name: Some("example-jwt".to_string()),
458
+ name: "example-jwt".to_string(),
460
459
  },
461
460
  )
462
461
  .await
@@ -492,7 +491,7 @@ async fn main() {
492
491
  .create_request_filter(
493
492
  &endpoint_id,
494
493
  &CreateRequestFilterRequest {
495
- method: Some(vec!["eth_getBalance".to_string()]),
494
+ method: vec!["eth_getBalance".to_string()],
496
495
  },
497
496
  )
498
497
  .await
@@ -874,6 +873,7 @@ async fn main() {
874
873
  streams: None,
875
874
  webhooks: None,
876
875
  kvstore: None,
876
+ sql: None,
877
877
  };
878
878
  let headered = QuicknodeSdk::new(&with_headers).expect("build sdk with custom headers");
879
879
  match headered
@@ -0,0 +1,70 @@
1
+ use quicknode_sdk::{errors::SdkError, sql::QueryParams, QuicknodeSdk, SdkFullConfig};
2
+
3
+ const CLUSTER_ID: &str = "hyperliquid-core-mainnet";
4
+
5
+ #[tokio::main]
6
+ #[allow(clippy::unwrap_used, clippy::expect_used)]
7
+ async fn main() {
8
+ let config = SdkFullConfig::from_env().expect("Config from env failed");
9
+ let qn = QuicknodeSdk::new(&config).expect("sdk failed to initialize");
10
+
11
+ // ── Query ─────────────────────────────────────────────────────────────────
12
+
13
+ let params = QueryParams {
14
+ query: "SELECT toDateTime(block_time) AS time, action_type, user \
15
+ FROM hyperliquid_system_actions \
16
+ ORDER BY block_time DESC LIMIT 3"
17
+ .to_string(),
18
+ cluster_id: CLUSTER_ID.to_string(),
19
+ };
20
+
21
+ match qn.sql.query(&params).await {
22
+ Ok(resp) => {
23
+ println!(
24
+ "query: {} rows ({} before limit), {} credits, {:.4}s",
25
+ resp.rows, resp.rows_before_limit_at_least, resp.credits, resp.statistics.elapsed
26
+ );
27
+ println!(
28
+ "columns: {:?}",
29
+ resp.meta.iter().map(|c| &c.name).collect::<Vec<_>>()
30
+ );
31
+ // Read a value out of a dynamic row to confirm the conversion works.
32
+ if let Some(row) = resp.data.first() {
33
+ println!("first row action_type: {}", row["action_type"]);
34
+ }
35
+ }
36
+ Err(e) => eprintln!("query error: {e}"),
37
+ }
38
+
39
+ // ── Schema ──────────────────────────────────────────────────────────────
40
+
41
+ match qn.sql.get_schema(CLUSTER_ID).await {
42
+ Ok(schema) => {
43
+ println!("schema: {} ({} tables)", schema.chain, schema.tables.len());
44
+ if let Some(table) = schema.tables.first() {
45
+ println!(
46
+ "first table: {} ({} columns, {} rows)",
47
+ table.name,
48
+ table.columns.len(),
49
+ table.total_rows
50
+ );
51
+ }
52
+ }
53
+ Err(e) => eprintln!("get_schema error: {e}"),
54
+ }
55
+
56
+ // ── Error handling ────────────────────────────────────────────────────────
57
+
58
+ // An empty query is rejected with a 403 and a JSON body carrying the error
59
+ // message.
60
+ let bad = QueryParams {
61
+ query: String::new(),
62
+ cluster_id: CLUSTER_ID.to_string(),
63
+ };
64
+ match qn.sql.query(&bad).await {
65
+ Err(SdkError::Api { status, body }) => {
66
+ println!("api error {status}: {}", &body[..body.len().min(120)]);
67
+ }
68
+ other => eprintln!("expected Api error, got {other:?}"),
69
+ }
70
+ }
@@ -104,8 +104,7 @@ pub struct UpdateSecurityOptionsResponse {
104
104
  #[derive(Debug, Clone, Default, Serialize)]
105
105
  pub struct CreateReferrerRequest {
106
106
  /// Allowed referrer URL or domain.
107
- #[serde(skip_serializing_if = "Option::is_none")]
108
- pub referrer: Option<String>,
107
+ pub referrer: String,
109
108
  }
110
109
 
111
110
  /// Parameters for `create_ip`.
@@ -116,8 +115,7 @@ pub struct CreateReferrerRequest {
116
115
  #[derive(Debug, Clone, Default, Serialize)]
117
116
  pub struct CreateIpRequest {
118
117
  /// IP address to whitelist.
119
- #[serde(skip_serializing_if = "Option::is_none")]
120
- pub ip: Option<String>,
118
+ pub ip: String,
121
119
  }
122
120
 
123
121
  /// Parameters for `create_domain_mask`.
@@ -140,13 +138,11 @@ pub struct CreateDomainMaskRequest {
140
138
  #[derive(Debug, Clone, Default, Serialize)]
141
139
  pub struct CreateJwtRequest {
142
140
  /// Public key used to verify signed JWTs.
143
- #[serde(skip_serializing_if = "Option::is_none")]
144
- pub public_key: Option<String>,
141
+ pub public_key: String,
145
142
  /// Key identifier (`kid`) embedded in JWT headers.
146
143
  pub kid: String,
147
144
  /// Human-readable name for the JWT configuration.
148
- #[serde(skip_serializing_if = "Option::is_none")]
149
- pub name: Option<String>,
145
+ pub name: String,
150
146
  }
151
147
 
152
148
  /// Parameters for `create_request_filter`.
@@ -157,8 +153,7 @@ pub struct CreateJwtRequest {
157
153
  #[derive(Debug, Clone, Default, Serialize)]
158
154
  pub struct CreateRequestFilterRequest {
159
155
  /// Whitelisted RPC methods; other methods will be blocked.
160
- #[serde(skip_serializing_if = "Option::is_none")]
161
- pub method: Option<Vec<String>>,
156
+ pub method: Vec<String>,
162
157
  }
163
158
 
164
159
  /// Response from `create_request_filter`.
@@ -1903,6 +1903,7 @@ mod tests {
1903
1903
  streams: None,
1904
1904
  webhooks: None,
1905
1905
  kvstore: None,
1906
+ sql: None,
1906
1907
  })
1907
1908
  .unwrap()
1908
1909
  }
@@ -2548,7 +2549,7 @@ mod tests {
2548
2549
  .create_referrer(
2549
2550
  "ep123",
2550
2551
  &CreateReferrerRequest {
2551
- referrer: Some("example.com".to_string()),
2552
+ referrer: "example.com".to_string(),
2552
2553
  },
2553
2554
  )
2554
2555
  .await
@@ -3673,6 +3674,7 @@ mod tests {
3673
3674
  streams: None,
3674
3675
  webhooks: None,
3675
3676
  kvstore: None,
3677
+ sql: None,
3676
3678
  });
3677
3679
  assert!(matches!(result, Err(crate::errors::SdkError::Config(_))));
3678
3680
  }
@@ -140,6 +140,26 @@ impl KvStoreConfig {
140
140
  }
141
141
  }
142
142
 
143
+ #[cfg_attr(feature = "python", gen_stub_pyclass)]
144
+ #[cfg_attr(feature = "python", pyclass(get_all, set_all))]
145
+ #[cfg_attr(feature = "node", napi(object))]
146
+ #[cfg_attr(feature = "rust", derive(Builder))]
147
+ #[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
148
+ pub struct SqlConfig {
149
+ pub base_url: Option<String>,
150
+ }
151
+
152
+ #[cfg(feature = "python")]
153
+ #[gen_stub_pymethods]
154
+ #[pymethods]
155
+ impl SqlConfig {
156
+ #[new]
157
+ #[pyo3(signature = (base_url=None))]
158
+ pub fn new(base_url: Option<String>) -> Self {
159
+ SqlConfig { base_url }
160
+ }
161
+ }
162
+
143
163
  #[cfg_attr(feature = "python", gen_stub_pyclass)]
144
164
  #[cfg_attr(feature = "python", pyclass(get_all, set_all))]
145
165
  #[cfg_attr(feature = "node", napi(object))]
@@ -152,6 +172,7 @@ pub struct SdkFullConfig {
152
172
  pub streams: Option<StreamsConfig>,
153
173
  pub webhooks: Option<WebhooksConfig>,
154
174
  pub kvstore: Option<KvStoreConfig>,
175
+ pub sql: Option<SqlConfig>,
155
176
  }
156
177
 
157
178
  impl SdkFullConfig {
@@ -163,6 +184,7 @@ impl SdkFullConfig {
163
184
  streams: None,
164
185
  webhooks: None,
165
186
  kvstore: None,
187
+ sql: None,
166
188
  }
167
189
  }
168
190
 
@@ -189,7 +211,7 @@ impl SdkFullConfig {
189
211
  #[pymethods]
190
212
  impl SdkFullConfig {
191
213
  #[new]
192
- #[pyo3(signature = (api_key, http=None, admin=None, streams=None, webhooks=None, kvstore=None))]
214
+ #[pyo3(signature = (api_key, http=None, admin=None, streams=None, webhooks=None, kvstore=None, sql=None))]
193
215
  pub fn new(
194
216
  api_key: String,
195
217
  http: Option<HttpConfig>,
@@ -197,6 +219,7 @@ impl SdkFullConfig {
197
219
  streams: Option<StreamsConfig>,
198
220
  webhooks: Option<WebhooksConfig>,
199
221
  kvstore: Option<KvStoreConfig>,
222
+ sql: Option<SqlConfig>,
200
223
  ) -> Self {
201
224
  SdkFullConfig {
202
225
  api_key,
@@ -205,6 +228,7 @@ impl SdkFullConfig {
205
228
  streams,
206
229
  webhooks,
207
230
  kvstore,
231
+ sql,
208
232
  }
209
233
  }
210
234
  }