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.
- noxaeapi_sdk-0.4.0/LICENSE +21 -0
- noxaeapi_sdk-0.4.0/PKG-INFO +176 -0
- noxaeapi_sdk-0.4.0/README.md +143 -0
- noxaeapi_sdk-0.4.0/pyproject.toml +57 -0
- noxaeapi_sdk-0.4.0/src/noxaeapi_sdk/__init__.py +41 -0
- noxaeapi_sdk-0.4.0/src/noxaeapi_sdk/client.py +170 -0
- noxaeapi_sdk-0.4.0/src/noxaeapi_sdk/errors.py +132 -0
- noxaeapi_sdk-0.4.0/src/noxaeapi_sdk/http_engine.py +259 -0
- noxaeapi_sdk-0.4.0/src/noxaeapi_sdk/modules/__init__.py +0 -0
- noxaeapi_sdk-0.4.0/src/noxaeapi_sdk/modules/economy.py +75 -0
- noxaeapi_sdk-0.4.0/src/noxaeapi_sdk/modules/leaderboard.py +39 -0
- noxaeapi_sdk-0.4.0/src/noxaeapi_sdk/modules/luckperms.py +87 -0
- noxaeapi_sdk-0.4.0/src/noxaeapi_sdk/modules/misc.py +29 -0
- noxaeapi_sdk-0.4.0/src/noxaeapi_sdk/modules/network.py +91 -0
- noxaeapi_sdk-0.4.0/src/noxaeapi_sdk/modules/network_hub.py +100 -0
- noxaeapi_sdk-0.4.0/src/noxaeapi_sdk/modules/noxauth.py +35 -0
- noxaeapi_sdk-0.4.0/src/noxaeapi_sdk/modules/players.py +63 -0
- noxaeapi_sdk-0.4.0/src/noxaeapi_sdk/modules/plugins.py +37 -0
- noxaeapi_sdk-0.4.0/src/noxaeapi_sdk/modules/server.py +126 -0
- noxaeapi_sdk-0.4.0/src/noxaeapi_sdk/modules/skills.py +35 -0
- noxaeapi_sdk-0.4.0/src/noxaeapi_sdk/modules/worlds.py +57 -0
- noxaeapi_sdk-0.4.0/src/noxaeapi_sdk/py.typed +0 -0
- noxaeapi_sdk-0.4.0/src/noxaeapi_sdk/socket.py +167 -0
- noxaeapi_sdk-0.4.0/src/noxaeapi_sdk/types.py +305 -0
|
@@ -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)
|