noxaeapi-sdk 0.4.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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 WumX Labs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,176 @@
1
+ Metadata-Version: 2.5
2
+ Name: noxaeapi-sdk
3
+ Version: 0.4.0
4
+ Summary: Typed Python SDK for the NoxAeApi REST + WebSocket API (Fabric, Bukkit/Spigot/Paper) and the NoxAeApi-Velocity network hub
5
+ Project-URL: Homepage, https://github.com/WumXPro/noxaeapi-sdk
6
+ Project-URL: Documentation, https://noxapi.noxlydev.xyz
7
+ Project-URL: Repository, https://github.com/WumXPro/noxaeapi-sdk
8
+ Project-URL: Issues, https://github.com/WumXPro/noxaeapi-sdk/issues
9
+ Author: WumX Labs
10
+ License: MIT
11
+ License-File: LICENSE
12
+ Keywords: bukkit,fabric,minecraft,noxaeapi,noxlydev,paper,rest-client,sdk,spigot,velocity,wumx
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Games/Entertainment
24
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
+ Classifier: Typing :: Typed
26
+ Requires-Python: >=3.8
27
+ Provides-Extra: dev
28
+ Requires-Dist: mypy>=1.0; extra == 'dev'
29
+ Requires-Dist: pytest>=7.0; extra == 'dev'
30
+ Provides-Extra: ws
31
+ Requires-Dist: websocket-client>=1.6; extra == 'ws'
32
+ Description-Content-Type: text/markdown
33
+
34
+ # noxaeapi-sdk
35
+
36
+ Typed Python SDK for [NoxAeApi](https://github.com/WumXPro/noxaeapi-sdk), a REST + WebSocket API plugin/mod for Minecraft servers — ships for both Fabric and Bukkit/Spigot/PaperMC. The REST surface is identical across platforms, so this SDK works against either without any platform-specific configuration.
37
+
38
+ Zero required runtime dependencies — uses only the Python standard library (`urllib`) for HTTP. The realtime socket needs one optional extra.
39
+
40
+ 📖 **Docs:** [noxapi.noxlydev.xyz](https://noxapi.noxlydev.xyz)
41
+
42
+ ## Install
43
+
44
+ ```bash
45
+ pip install noxaeapi-sdk
46
+
47
+ # with realtime console/event socket support:
48
+ pip install "noxaeapi-sdk[ws]"
49
+ ```
50
+
51
+ ## Usage
52
+
53
+ ```python
54
+ from noxaeapi_sdk import NoxAeApiClient
55
+
56
+ client = NoxAeApiClient(base_url="http://localhost:8080", api_key="your-api-key")
57
+
58
+ players = client.players.list()
59
+ balance = client.economy.get_balance(players[0]["uuid"])
60
+ client.server.broadcast("Hello from the SDK!")
61
+
62
+ # Multi-currency (ExcellentEconomy), leaderboards, and network aggregator:
63
+ coins = client.economy.get_currency_balance("coins", players[0]["uuid"])
64
+ top = client.leaderboards.get_top("mcmmo-power", limit=10)
65
+ network = client.network.status_all()
66
+ ```
67
+
68
+ ### From environment variables
69
+
70
+ ```python
71
+ # Reads NOXAEAPI_BASE_URL and NOXAEAPI_KEY from os.environ.
72
+ # If you keep those in a .env file, load it yourself first (e.g. with
73
+ # python-dotenv) — the SDK never reads .env files or os.environ implicitly
74
+ # outside this method.
75
+ client = NoxAeApiClient.from_env()
76
+ ```
77
+
78
+ ### Realtime (console tail / events)
79
+
80
+ Requires the `ws` extra (`pip install "noxaeapi-sdk[ws]"`).
81
+
82
+ ```python
83
+ ws = client.connect(route="console")
84
+ ws.on("console", lambda line: print(line))
85
+ ws.on("close", lambda _: print("disconnected"))
86
+ ```
87
+
88
+ The socket runs on a background thread and auto-reconnects with exponential backoff on unexpected disconnects.
89
+
90
+ ## Error handling
91
+
92
+ All non-2xx responses raise a subclass of `NoxAeApiError`:
93
+
94
+ - `NoxAeApiUnauthorizedError` — 401, missing/invalid API key
95
+ - `NoxAeApiForbiddenError` — 403, key valid but not permitted for this endpoint
96
+ - `NoxAeApiNotFoundError` — 404
97
+ - `NoxAeApiRateLimitError` — 429 (SDK auto-retries these by default; raised only once retries are exhausted)
98
+ - `NoxAeApiServerError` — 5xx (also auto-retried by default)
99
+ - `NoxAeApiNetworkError` — request never completed (timeout, DNS, connection refused)
100
+
101
+ ```python
102
+ from noxaeapi_sdk import NoxAeApiForbiddenError
103
+
104
+ try:
105
+ client.server.restart()
106
+ except NoxAeApiForbiddenError:
107
+ print("This API key isn't allowed to restart the server.")
108
+ ```
109
+
110
+ ## Request encoding
111
+
112
+ The server is a Javalin app, and most endpoints read their body with `ctx.formParam(...)` — i.e. `application/x-www-form-urlencoded` — rather than JSON. The SDK follows the same split:
113
+
114
+ - **Form-urlencoded**: everything in `economy` (including the `economy.get_currency_balance`/`.pay_currency`/etc ExcellentEconomy methods), `players`, `server` (except `luckperms`/`noxauth`), `worlds`, `plugins`, `placeholders`, and `network.broadcast`.
115
+ - **JSON**: `client.luckperms.*` and `client.noxauth.check_password` only — these are read server-side with `ctx.bodyAsClass(...)`.
116
+ - **N/A (GET only)**: `client.leaderboards.*` and most of `client.network.*` are read-only.
117
+
118
+ If you're extending the SDK, check which encoding the corresponding Javalin handler uses before wiring up a new method, and pass `form=True` to `http.request(...)` if it's form-urlencoded (this is also the more common case). Getting this wrong won't raise a type error — the request just silently sends the wrong content type and the server won't see the field.
119
+
120
+ ## Optional modules
121
+
122
+ Some modules only work depending on the target server's setup:
123
+
124
+ - `client.luckperms.*` — requires the LuckPerms mod to be loaded on the server
125
+ - `client.noxauth.*` — requires `noxauth.enabled: true` in the server's `noxaeapi-config.yml`
126
+ - `client.economy.get_currency_balance()`/`.pay_currency()`/`.debit_currency()`/`.set_currency_balance()`/`.get_currency_top()`/`.list_currencies()` — requires ExcellentEconomy (raises a 424 error if it isn't installed)
127
+ - `client.network.*` — requires `network.enabled: true` with at least one backend server configured in the server's config
128
+
129
+ Calling these against a server without the corresponding feature enabled will fail (typically 404).
130
+
131
+ ## NoxAeApi-Velocity network hub
132
+
133
+ If your network runs the **NoxAeApi-Velocity** proxy plugin, use `NoxAeApiNetworkHubClient` instead of (or alongside) `NoxAeApiClient` — point it at the hub's own REST port, not a backend server's port. Backend servers push register/heartbeat updates to the hub over WebSocket, so hub calls answer from its in-memory registry rather than fanning out live requests the way `client.network.*` above does — and the response shapes differ accordingly (e.g. `players()` is one flat proxy-wide list, not a per-backend breakdown, and there's no hub equivalent of `network/health` — see each node's `health` field in `status_all()`/`status_by_id()` instead).
134
+
135
+ ```python
136
+ from noxaeapi_sdk import NoxAeApiNetworkHubClient
137
+
138
+ hub = NoxAeApiNetworkHubClient(base_url="http://localhost:9090", api_key="your-hub-key") # the hub's api-port, not a backend's port
139
+
140
+ status = hub.network.status_all()
141
+ players = hub.network.players()
142
+ found = hub.network.find_player(players["players"][0]["uuid"]) if players["players"] else None
143
+ hub.network.broadcast("Hello from the hub!")
144
+
145
+ # Reach a specific backend's own REST routes through the hub:
146
+ hub.network.forward("survival", "POST", "server/exec", body={"command": "say hi"}, form=True)
147
+ ```
148
+
149
+ Or from environment variables (`NOXAEAPI_HUB_BASE_URL` / `NOXAEAPI_HUB_KEY`, kept separate from `NoxAeApiClient.from_env()`'s `NOXAEAPI_*` vars so a process can hold both clients at once):
150
+
151
+ ```python
152
+ hub = NoxAeApiNetworkHubClient.from_env()
153
+ ```
154
+
155
+ ## Configuration
156
+
157
+ ```python
158
+ from noxaeapi_sdk import NoxAeApiClient, RetryOptions
159
+
160
+ client = NoxAeApiClient(
161
+ base_url="https://mc.example.com",
162
+ api_key="...",
163
+ timeout=10.0, # per-request timeout in seconds, default 10
164
+ retry=RetryOptions(
165
+ attempts=3, # total attempts including the first, default 3
166
+ base_delay_ms=300,
167
+ max_delay_ms=5000,
168
+ ),
169
+ # retry=False, # disable retries entirely
170
+ headers={"X-Extra": "..."},
171
+ )
172
+ ```
173
+
174
+ ## License
175
+
176
+ MIT
@@ -0,0 +1,143 @@
1
+ # noxaeapi-sdk
2
+
3
+ Typed Python SDK for [NoxAeApi](https://github.com/WumXPro/noxaeapi-sdk), a REST + WebSocket API plugin/mod for Minecraft servers — ships for both Fabric and Bukkit/Spigot/PaperMC. The REST surface is identical across platforms, so this SDK works against either without any platform-specific configuration.
4
+
5
+ Zero required runtime dependencies — uses only the Python standard library (`urllib`) for HTTP. The realtime socket needs one optional extra.
6
+
7
+ 📖 **Docs:** [noxapi.noxlydev.xyz](https://noxapi.noxlydev.xyz)
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ pip install noxaeapi-sdk
13
+
14
+ # with realtime console/event socket support:
15
+ pip install "noxaeapi-sdk[ws]"
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```python
21
+ from noxaeapi_sdk import NoxAeApiClient
22
+
23
+ client = NoxAeApiClient(base_url="http://localhost:8080", api_key="your-api-key")
24
+
25
+ players = client.players.list()
26
+ balance = client.economy.get_balance(players[0]["uuid"])
27
+ client.server.broadcast("Hello from the SDK!")
28
+
29
+ # Multi-currency (ExcellentEconomy), leaderboards, and network aggregator:
30
+ coins = client.economy.get_currency_balance("coins", players[0]["uuid"])
31
+ top = client.leaderboards.get_top("mcmmo-power", limit=10)
32
+ network = client.network.status_all()
33
+ ```
34
+
35
+ ### From environment variables
36
+
37
+ ```python
38
+ # Reads NOXAEAPI_BASE_URL and NOXAEAPI_KEY from os.environ.
39
+ # If you keep those in a .env file, load it yourself first (e.g. with
40
+ # python-dotenv) — the SDK never reads .env files or os.environ implicitly
41
+ # outside this method.
42
+ client = NoxAeApiClient.from_env()
43
+ ```
44
+
45
+ ### Realtime (console tail / events)
46
+
47
+ Requires the `ws` extra (`pip install "noxaeapi-sdk[ws]"`).
48
+
49
+ ```python
50
+ ws = client.connect(route="console")
51
+ ws.on("console", lambda line: print(line))
52
+ ws.on("close", lambda _: print("disconnected"))
53
+ ```
54
+
55
+ The socket runs on a background thread and auto-reconnects with exponential backoff on unexpected disconnects.
56
+
57
+ ## Error handling
58
+
59
+ All non-2xx responses raise a subclass of `NoxAeApiError`:
60
+
61
+ - `NoxAeApiUnauthorizedError` — 401, missing/invalid API key
62
+ - `NoxAeApiForbiddenError` — 403, key valid but not permitted for this endpoint
63
+ - `NoxAeApiNotFoundError` — 404
64
+ - `NoxAeApiRateLimitError` — 429 (SDK auto-retries these by default; raised only once retries are exhausted)
65
+ - `NoxAeApiServerError` — 5xx (also auto-retried by default)
66
+ - `NoxAeApiNetworkError` — request never completed (timeout, DNS, connection refused)
67
+
68
+ ```python
69
+ from noxaeapi_sdk import NoxAeApiForbiddenError
70
+
71
+ try:
72
+ client.server.restart()
73
+ except NoxAeApiForbiddenError:
74
+ print("This API key isn't allowed to restart the server.")
75
+ ```
76
+
77
+ ## Request encoding
78
+
79
+ The server is a Javalin app, and most endpoints read their body with `ctx.formParam(...)` — i.e. `application/x-www-form-urlencoded` — rather than JSON. The SDK follows the same split:
80
+
81
+ - **Form-urlencoded**: everything in `economy` (including the `economy.get_currency_balance`/`.pay_currency`/etc ExcellentEconomy methods), `players`, `server` (except `luckperms`/`noxauth`), `worlds`, `plugins`, `placeholders`, and `network.broadcast`.
82
+ - **JSON**: `client.luckperms.*` and `client.noxauth.check_password` only — these are read server-side with `ctx.bodyAsClass(...)`.
83
+ - **N/A (GET only)**: `client.leaderboards.*` and most of `client.network.*` are read-only.
84
+
85
+ If you're extending the SDK, check which encoding the corresponding Javalin handler uses before wiring up a new method, and pass `form=True` to `http.request(...)` if it's form-urlencoded (this is also the more common case). Getting this wrong won't raise a type error — the request just silently sends the wrong content type and the server won't see the field.
86
+
87
+ ## Optional modules
88
+
89
+ Some modules only work depending on the target server's setup:
90
+
91
+ - `client.luckperms.*` — requires the LuckPerms mod to be loaded on the server
92
+ - `client.noxauth.*` — requires `noxauth.enabled: true` in the server's `noxaeapi-config.yml`
93
+ - `client.economy.get_currency_balance()`/`.pay_currency()`/`.debit_currency()`/`.set_currency_balance()`/`.get_currency_top()`/`.list_currencies()` — requires ExcellentEconomy (raises a 424 error if it isn't installed)
94
+ - `client.network.*` — requires `network.enabled: true` with at least one backend server configured in the server's config
95
+
96
+ Calling these against a server without the corresponding feature enabled will fail (typically 404).
97
+
98
+ ## NoxAeApi-Velocity network hub
99
+
100
+ If your network runs the **NoxAeApi-Velocity** proxy plugin, use `NoxAeApiNetworkHubClient` instead of (or alongside) `NoxAeApiClient` — point it at the hub's own REST port, not a backend server's port. Backend servers push register/heartbeat updates to the hub over WebSocket, so hub calls answer from its in-memory registry rather than fanning out live requests the way `client.network.*` above does — and the response shapes differ accordingly (e.g. `players()` is one flat proxy-wide list, not a per-backend breakdown, and there's no hub equivalent of `network/health` — see each node's `health` field in `status_all()`/`status_by_id()` instead).
101
+
102
+ ```python
103
+ from noxaeapi_sdk import NoxAeApiNetworkHubClient
104
+
105
+ hub = NoxAeApiNetworkHubClient(base_url="http://localhost:9090", api_key="your-hub-key") # the hub's api-port, not a backend's port
106
+
107
+ status = hub.network.status_all()
108
+ players = hub.network.players()
109
+ found = hub.network.find_player(players["players"][0]["uuid"]) if players["players"] else None
110
+ hub.network.broadcast("Hello from the hub!")
111
+
112
+ # Reach a specific backend's own REST routes through the hub:
113
+ hub.network.forward("survival", "POST", "server/exec", body={"command": "say hi"}, form=True)
114
+ ```
115
+
116
+ Or from environment variables (`NOXAEAPI_HUB_BASE_URL` / `NOXAEAPI_HUB_KEY`, kept separate from `NoxAeApiClient.from_env()`'s `NOXAEAPI_*` vars so a process can hold both clients at once):
117
+
118
+ ```python
119
+ hub = NoxAeApiNetworkHubClient.from_env()
120
+ ```
121
+
122
+ ## Configuration
123
+
124
+ ```python
125
+ from noxaeapi_sdk import NoxAeApiClient, RetryOptions
126
+
127
+ client = NoxAeApiClient(
128
+ base_url="https://mc.example.com",
129
+ api_key="...",
130
+ timeout=10.0, # per-request timeout in seconds, default 10
131
+ retry=RetryOptions(
132
+ attempts=3, # total attempts including the first, default 3
133
+ base_delay_ms=300,
134
+ max_delay_ms=5000,
135
+ ),
136
+ # retry=False, # disable retries entirely
137
+ headers={"X-Extra": "..."},
138
+ )
139
+ ```
140
+
141
+ ## License
142
+
143
+ MIT
@@ -0,0 +1,57 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "noxaeapi-sdk"
7
+ version = "0.4.0"
8
+ description = "Typed Python SDK for the NoxAeApi REST + WebSocket API (Fabric, Bukkit/Spigot/Paper) and the NoxAeApi-Velocity network hub"
9
+ readme = "README.md"
10
+ license = { text = "MIT" }
11
+ authors = [{ name = "WumX Labs" }]
12
+ requires-python = ">=3.8"
13
+ keywords = [
14
+ "minecraft",
15
+ "fabric",
16
+ "bukkit",
17
+ "spigot",
18
+ "paper",
19
+ "velocity",
20
+ "noxaeapi",
21
+ "noxlydev",
22
+ "wumx",
23
+ "rest-client",
24
+ "sdk",
25
+ ]
26
+ classifiers = [
27
+ "Development Status :: 4 - Beta",
28
+ "Intended Audience :: Developers",
29
+ "License :: OSI Approved :: MIT License",
30
+ "Programming Language :: Python :: 3",
31
+ "Programming Language :: Python :: 3.8",
32
+ "Programming Language :: Python :: 3.9",
33
+ "Programming Language :: Python :: 3.10",
34
+ "Programming Language :: Python :: 3.11",
35
+ "Programming Language :: Python :: 3.12",
36
+ "Programming Language :: Python :: 3.13",
37
+ "Topic :: Games/Entertainment",
38
+ "Topic :: Software Development :: Libraries :: Python Modules",
39
+ "Typing :: Typed",
40
+ ]
41
+ dependencies = []
42
+
43
+ [project.optional-dependencies]
44
+ ws = ["websocket-client>=1.6"]
45
+ dev = ["pytest>=7.0", "mypy>=1.0"]
46
+
47
+ [project.urls]
48
+ Homepage = "https://github.com/WumXPro/noxaeapi-sdk"
49
+ Documentation = "https://noxapi.noxlydev.xyz"
50
+ Repository = "https://github.com/WumXPro/noxaeapi-sdk"
51
+ Issues = "https://github.com/WumXPro/noxaeapi-sdk/issues"
52
+
53
+ [tool.hatch.build.targets.wheel]
54
+ packages = ["src/noxaeapi_sdk"]
55
+
56
+ [tool.hatch.build.targets.sdist]
57
+ include = ["src", "README.md", "LICENSE"]
@@ -0,0 +1,41 @@
1
+ """Typed Python SDK for the NoxAeApi REST + WebSocket API.
2
+
3
+ (Fabric, Bukkit/Spigot/Paper) and the NoxAeApi-Velocity network hub.
4
+
5
+ Example::
6
+
7
+ from noxaeapi_sdk import NoxAeApiClient
8
+
9
+ client = NoxAeApiClient(base_url="http://localhost:8080", api_key="your-api-key")
10
+ players = client.players.list()
11
+ balance = client.economy.get_balance(players[0]["uuid"])
12
+ client.server.broadcast("Hello from the SDK!")
13
+ """
14
+
15
+ from .client import NoxAeApiClient, NoxAeApiNetworkHubClient
16
+ from .errors import (
17
+ NoxAeApiError,
18
+ NoxAeApiForbiddenError,
19
+ NoxAeApiNetworkError,
20
+ NoxAeApiNotFoundError,
21
+ NoxAeApiRateLimitError,
22
+ NoxAeApiServerError,
23
+ NoxAeApiUnauthorizedError,
24
+ )
25
+ from .http_engine import NoxAeApiClientOptions, RetryOptions
26
+
27
+ __version__ = "0.4.0"
28
+
29
+ __all__ = [
30
+ "NoxAeApiClient",
31
+ "NoxAeApiNetworkHubClient",
32
+ "NoxAeApiClientOptions",
33
+ "RetryOptions",
34
+ "NoxAeApiError",
35
+ "NoxAeApiUnauthorizedError",
36
+ "NoxAeApiForbiddenError",
37
+ "NoxAeApiNotFoundError",
38
+ "NoxAeApiRateLimitError",
39
+ "NoxAeApiServerError",
40
+ "NoxAeApiNetworkError",
41
+ ]
@@ -0,0 +1,170 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from typing import Any, Optional
5
+
6
+ from .http_engine import HttpEngine, NoxAeApiClientOptions
7
+ from .modules.economy import EconomyModule
8
+ from .modules.leaderboard import LeaderboardModule
9
+ from .modules.luckperms import LuckPermsModule
10
+ from .modules.misc import AdvancementsModule, PlaceholdersModule
11
+ from .modules.network import NetworkModule
12
+ from .modules.network_hub import NetworkHubModule
13
+ from .modules.noxauth import NoxAuthModule
14
+ from .modules.players import PlayersModule
15
+ from .modules.plugins import PluginsModule
16
+ from .modules.server import ServerModule
17
+ from .modules.skills import SkillsModule
18
+ from .modules.worlds import WorldsModule
19
+
20
+
21
+ class NoxAeApiClient:
22
+ """Client for a NoxAeApi server (Fabric mod or Bukkit/Spigot/Paper plugin).
23
+
24
+ Example::
25
+
26
+ client = NoxAeApiClient(base_url="http://localhost:8080", api_key="your-api-key")
27
+ players = client.players.list()
28
+ balance = client.economy.get_balance(players[0]["uuid"])
29
+ client.server.broadcast("Hello from the SDK!")
30
+ """
31
+
32
+ def __init__(
33
+ self,
34
+ base_url: Optional[str] = None,
35
+ api_key: Optional[str] = None,
36
+ *,
37
+ options: Optional[NoxAeApiClientOptions] = None,
38
+ **kwargs: Any,
39
+ ) -> None:
40
+ """Create a client.
41
+
42
+ Either pass ``base_url`` (and optionally ``api_key``,
43
+ ``timeout``, ``retry``, ``headers``, ...) directly, or build a
44
+ :class:`~noxaeapi_sdk.http_engine.NoxAeApiClientOptions` yourself
45
+ and pass it as ``options=``.
46
+ """
47
+ if options is None:
48
+ if not base_url:
49
+ raise ValueError("NoxAeApiClient requires base_url (or options=NoxAeApiClientOptions(...))")
50
+ options = NoxAeApiClientOptions(base_url=base_url, api_key=api_key, **kwargs)
51
+
52
+ self._options = options
53
+ self._http = HttpEngine(options)
54
+
55
+ self.players = PlayersModule(self._http)
56
+ self.economy = EconomyModule(self._http)
57
+ self.server = ServerModule(self._http)
58
+ self.worlds = WorldsModule(self._http)
59
+ self.plugins = PluginsModule(self._http)
60
+ self.advancements = AdvancementsModule(self._http)
61
+ self.placeholders = PlaceholdersModule(self._http)
62
+ self.luckperms = LuckPermsModule(self._http)
63
+ """Only works if LuckPerms is loaded on the target server."""
64
+ self.noxauth = NoxAuthModule(self._http)
65
+ """Only works if ``noxauth.enabled: true`` is set in the server config."""
66
+ self.skills = SkillsModule(self._http)
67
+ """Requires mcMMO and/or AuraSkills to be loaded on the target server."""
68
+ self.leaderboards = LeaderboardModule(self._http)
69
+ """Generic ranked leaderboards (economy currencies, mcMMO, AuraSkills, ...)."""
70
+ self.network = NetworkModule(self._http)
71
+ """Only works if ``network.enabled: true`` is set in the server config.
72
+
73
+ This is NoxAeApi-main's built-in polling aggregator — it lives on
74
+ the *same* backend server you're already connected to and fans
75
+ requests out to the other backends listed in that server's own
76
+ config. If the network is running NoxAeApi-Velocity instead, use
77
+ :class:`NoxAeApiNetworkHubClient` (pointed at the proxy's hub
78
+ port) rather than this module — the hub replaces this aggregator
79
+ with a push model and its response shapes differ.
80
+ """
81
+
82
+ @classmethod
83
+ def from_env(cls, **overrides: Any) -> "NoxAeApiClient":
84
+ """Build a client from environment variables: ``NOXAEAPI_BASE_URL`` and ``NOXAEAPI_KEY``.
85
+
86
+ Convenience for scripts. The SDK never reads ``.env`` files or
87
+ ``os.environ`` implicitly outside of this method — use a library
88
+ like ``python-dotenv`` in your own app if you want that, then
89
+ call ``NoxAeApiClient.from_env()`` after it's loaded.
90
+ """
91
+ base_url = overrides.pop("base_url", None) or os.environ.get("NOXAEAPI_BASE_URL")
92
+ api_key = overrides.pop("api_key", None) or os.environ.get("NOXAEAPI_KEY")
93
+
94
+ if not base_url:
95
+ raise ValueError(
96
+ "NoxAeApiClient.from_env(): NOXAEAPI_BASE_URL is not set and no base_url override was given."
97
+ )
98
+
99
+ return cls(base_url=base_url, api_key=api_key, **overrides)
100
+
101
+ def connect(self, route: str = "events", **kwargs: Any) -> Any:
102
+ """Open a WebSocket connection to the server (console tail or event stream).
103
+
104
+ Requires the optional ``websocket-client`` package
105
+ (``pip install noxaeapi-sdk[ws]``).
106
+ """
107
+ from .socket import NoxAeApiSocket, NoxAeApiWsOptions
108
+
109
+ return NoxAeApiSocket(
110
+ NoxAeApiWsOptions(
111
+ base_url=self._options.base_url,
112
+ api_key=self._options.api_key,
113
+ route=route,
114
+ **kwargs,
115
+ )
116
+ )
117
+
118
+
119
+ class NoxAeApiNetworkHubClient:
120
+ """Client for the **NoxAeApi-Velocity** network hub.
121
+
122
+ This is a separate plugin that runs on the Velocity proxy, not on any
123
+ individual backend server. Point ``base_url`` at the hub's own REST
124
+ port (``NetworkHubConfig``'s ``api-port``), not a backend's port, and
125
+ use ``NOXAEAPI_HUB_*`` env vars (via :meth:`from_env`) if you keep
126
+ that separate from a regular backend's ``NOXAEAPI_*`` vars.
127
+
128
+ Only exposes ``.network`` — the hub doesn't run any of the other REST
129
+ modules (players, economy, worlds, ...) that a backend
130
+ :class:`NoxAeApiClient` does. To reach a specific backend's own
131
+ routes through the hub, use ``hub.network.forward(id, ...)``.
132
+ """
133
+
134
+ def __init__(
135
+ self,
136
+ base_url: Optional[str] = None,
137
+ api_key: Optional[str] = None,
138
+ *,
139
+ options: Optional[NoxAeApiClientOptions] = None,
140
+ **kwargs: Any,
141
+ ) -> None:
142
+ if options is None:
143
+ if not base_url:
144
+ raise ValueError(
145
+ "NoxAeApiNetworkHubClient requires base_url (or options=NoxAeApiClientOptions(...))"
146
+ )
147
+ options = NoxAeApiClientOptions(base_url=base_url, api_key=api_key, **kwargs)
148
+
149
+ http = HttpEngine(options)
150
+ self.network = NetworkHubModule(http)
151
+ """The network hub's aggregated view of every registered backend node."""
152
+
153
+ @classmethod
154
+ def from_env(cls, **overrides: Any) -> "NoxAeApiNetworkHubClient":
155
+ """Build a hub client from environment variables: ``NOXAEAPI_HUB_BASE_URL`` / ``NOXAEAPI_HUB_KEY``.
156
+
157
+ Same convenience as ``NoxAeApiClient.from_env()``, under separate
158
+ env var names so a process can hold both a backend client and a
159
+ hub client at once without the two colliding.
160
+ """
161
+ base_url = overrides.pop("base_url", None) or os.environ.get("NOXAEAPI_HUB_BASE_URL")
162
+ api_key = overrides.pop("api_key", None) or os.environ.get("NOXAEAPI_HUB_KEY")
163
+
164
+ if not base_url:
165
+ raise ValueError(
166
+ "NoxAeApiNetworkHubClient.from_env(): NOXAEAPI_HUB_BASE_URL is not set "
167
+ "and no base_url override was given."
168
+ )
169
+
170
+ return cls(base_url=base_url, api_key=api_key, **overrides)