noxaeapi-sdk 0.4.0__tar.gz → 0.4.1__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 (25) hide show
  1. {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/PKG-INFO +1 -1
  2. {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/pyproject.toml +1 -1
  3. noxaeapi_sdk-0.4.1/src/noxaeapi_sdk/modules/leaderboard.py +89 -0
  4. {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/modules/players.py +19 -1
  5. {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/types.py +73 -0
  6. noxaeapi_sdk-0.4.0/src/noxaeapi_sdk/modules/leaderboard.py +0 -39
  7. {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/LICENSE +0 -0
  8. {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/README.md +0 -0
  9. {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/__init__.py +0 -0
  10. {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/client.py +0 -0
  11. {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/errors.py +0 -0
  12. {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/http_engine.py +0 -0
  13. {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/modules/__init__.py +0 -0
  14. {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/modules/economy.py +0 -0
  15. {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/modules/luckperms.py +0 -0
  16. {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/modules/misc.py +0 -0
  17. {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/modules/network.py +0 -0
  18. {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/modules/network_hub.py +0 -0
  19. {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/modules/noxauth.py +0 -0
  20. {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/modules/plugins.py +0 -0
  21. {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/modules/server.py +0 -0
  22. {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/modules/skills.py +0 -0
  23. {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/modules/worlds.py +0 -0
  24. {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/py.typed +0 -0
  25. {noxaeapi_sdk-0.4.0 → noxaeapi_sdk-0.4.1}/src/noxaeapi_sdk/socket.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: noxaeapi-sdk
3
- Version: 0.4.0
3
+ Version: 0.4.1
4
4
  Summary: Typed Python SDK for the NoxAeApi REST + WebSocket API (Fabric, Bukkit/Spigot/Paper) and the NoxAeApi-Velocity network hub
5
5
  Project-URL: Homepage, https://github.com/WumXPro/noxaeapi-sdk
6
6
  Project-URL: Documentation, https://noxapi.noxlydev.xyz
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "noxaeapi-sdk"
7
- version = "0.4.0"
7
+ version = "0.4.1"
8
8
  description = "Typed Python SDK for the NoxAeApi REST + WebSocket API (Fabric, Bukkit/Spigot/Paper) and the NoxAeApi-Velocity network hub"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -0,0 +1,89 @@
1
+ from __future__ import annotations
2
+
3
+ import urllib.parse
4
+ from typing import List, Optional, Sequence
5
+
6
+ from ..http_engine import HttpEngine
7
+ from ..types import (
8
+ LeaderboardEntry,
9
+ LeaderboardSourceInfo,
10
+ PlayerProfile,
11
+ PlayerProfilesResponse,
12
+ )
13
+
14
+
15
+ def _q(value: str) -> str:
16
+ return urllib.parse.quote(value, safe="")
17
+
18
+
19
+ class LeaderboardModule:
20
+ """Wraps the generic, pluggable ``/v1/leaderboards/*`` routes.
21
+
22
+ This is a unified view over every ranking source registered on the
23
+ server — economy currencies, mcMMO power level, AuraSkills power
24
+ level, etc — so you don't need to know ahead of time which plugins
25
+ are installed.
26
+
27
+ Use :meth:`list` to discover available source IDs, then pass one to
28
+ :meth:`get_top`. Sources that are registered but currently
29
+ unavailable (e.g. the backing plugin isn't loaded) raise
30
+ ``NoxAeApiError`` with the source's own unavailable status (424 for
31
+ economy currencies, 503 for mcMMO/AuraSkills) when you call
32
+ :meth:`get_top`.
33
+
34
+ This module also wraps the player-profile routes
35
+ (``/v1/players/{uuid}/profile`` and ``/v1/players/profiles``), which live
36
+ server-side alongside the leaderboard sources since they're built on top
37
+ of them.
38
+ """
39
+
40
+ def __init__(self, http: HttpEngine) -> None:
41
+ self._http = http
42
+
43
+ def list(self) -> List[LeaderboardSourceInfo]:
44
+ """List every registered leaderboard source and its availability."""
45
+ return self._http.request("GET", "leaderboards")
46
+
47
+ def get_top(self, id: str, limit: Optional[int] = None) -> List[LeaderboardEntry]:
48
+ """Get ranked entries for one leaderboard source (see :meth:`list` for valid IDs)."""
49
+ return self._http.request("GET", f"leaderboards/{_q(id)}/top", query={"limit": limit})
50
+
51
+ def get_player_profile(self, uuid: str) -> PlayerProfile:
52
+ """One-call player profile: identity, whitelist/ban status, Vault balance,
53
+ and this player's entry in every registered leaderboard source. Built so
54
+ clients never have to know how many leaderboard sources exist or scan
55
+ top-N lists themselves.
56
+
57
+ Raises ``NoxAeApiNotFoundError`` if no known player with that UUID has
58
+ ever joined.
59
+ """
60
+ return self._http.request("GET", f"players/{_q(uuid)}/profile")
61
+
62
+ def get_player_profiles(
63
+ self,
64
+ *,
65
+ uuids: Optional[Sequence[str]] = None,
66
+ page: Optional[int] = None,
67
+ limit: Optional[int] = None,
68
+ online_only: Optional[bool] = None,
69
+ ) -> PlayerProfilesResponse:
70
+ """Bulk player profiles — same shape as :meth:`get_player_profile`, for many
71
+ players at once. Computes each leaderboard source's full ranking exactly
72
+ once for the whole batch rather than once per player, so this is far
73
+ cheaper than calling :meth:`get_player_profile` in a loop.
74
+
75
+ Pass ``uuids`` to fetch an exact, specific set of players — unknown UUIDs
76
+ are silently skipped rather than raising. Omit ``uuids`` to page through
77
+ every known player instead, using ``page``/``limit``, optionally narrowed
78
+ to only currently-online players via ``online_only``.
79
+ """
80
+ return self._http.request(
81
+ "GET",
82
+ "players/profiles",
83
+ query={
84
+ "uuids": ",".join(uuids) if uuids else None,
85
+ "page": page,
86
+ "limit": limit,
87
+ "onlineOnly": online_only,
88
+ },
89
+ )
@@ -4,7 +4,14 @@ import urllib.parse
4
4
  from typing import Any, Dict, List, Optional, Union
5
5
 
6
6
  from ..http_engine import HttpEngine
7
- from ..types import Gamemode, InventoryItem, OfflinePlayer, OnlinePlayer, PlayerStats
7
+ from ..types import (
8
+ Gamemode,
9
+ InventoryItem,
10
+ OfflinePlayer,
11
+ OnlinePlayer,
12
+ PlayerResolveResult,
13
+ PlayerStats,
14
+ )
8
15
 
9
16
 
10
17
  def _q(value: str) -> str:
@@ -27,6 +34,17 @@ class PlayersModule:
27
34
  """Get a single player by UUID (works for online or offline players)."""
28
35
  return self._http.request("GET", f"players/{_q(uuid)}")
29
36
 
37
+ def resolve(self, name: str) -> PlayerResolveResult:
38
+ """Resolve a player name to their UUID using the server's own local player cache.
39
+
40
+ Works on both online-mode and offline-mode servers, unlike Mojang's public
41
+ API - the UUID returned matches whatever this server actually uses for that
42
+ player's stats/economy/etc. Checks currently online players first, then
43
+ falls back to the server's offline player cache. Raises
44
+ ``NoxAeApiNotFoundError`` if no known player with that name has ever joined.
45
+ """
46
+ return self._http.request("GET", f"players/resolve/{_q(name)}")
47
+
30
48
  def get_inventory(self, player_uuid: str, world_uuid: str) -> List[InventoryItem]:
31
49
  """Get a player's inventory in a specific world."""
32
50
  return self._http.request("GET", f"players/{_q(player_uuid)}/{_q(world_uuid)}/inventory")
@@ -45,6 +45,13 @@ class OfflinePlayer(TypedDict):
45
45
  lastPlayed: int
46
46
 
47
47
 
48
+ class PlayerResolveResult(TypedDict):
49
+ """Result of resolving a player name to their UUID via ``GET /players/resolve/{name}``."""
50
+
51
+ name: str
52
+ uuid: str
53
+
54
+
48
55
  class ServerHealth(TypedDict):
49
56
  cpus: int
50
57
  uptime: int
@@ -221,6 +228,72 @@ class LeaderboardEntry(TypedDict):
221
228
  value: float
222
229
 
223
230
 
231
+ class PlayerProfileBan(TypedDict, total=False):
232
+ """Ban details for a player, as reported by ``GET /v1/players/{uuid}/profile``'s ``status.ban``."""
233
+
234
+ banned: bool
235
+ reason: str
236
+ """Only present when ``banned`` is true."""
237
+ source: str
238
+ """Only present when ``banned`` is true."""
239
+ created: str
240
+ """Only present when ``banned`` is true. Serialized server-side as a locale-formatted date string, not ISO-8601."""
241
+ expires: Optional[str]
242
+ """Only present when ``banned`` is true. ``None``/absent means a permanent ban. Same date-string format as ``created``."""
243
+
244
+
245
+ class PlayerProfileStatus(TypedDict):
246
+ """Whitelist + ban status for a player, as reported by ``GET /v1/players/{uuid}/profile``'s ``status`` field."""
247
+
248
+ whitelisted: bool
249
+ ban: PlayerProfileBan
250
+
251
+
252
+ class PlayerProfileEconomy(TypedDict, total=False):
253
+ """Vault economy info for a player, as reported by ``GET /v1/players/{uuid}/profile``'s ``economy`` field.
254
+
255
+ Single-currency (Vault), not ExcellentEconomy's multi-currency system - see
256
+ :meth:`EconomyModule.get_currency_balance` for that.
257
+ """
258
+
259
+ available: bool
260
+ balance: float
261
+ """Only present when ``available`` is true."""
262
+
263
+
264
+ class PlayerProfileStatTile(TypedDict, total=False):
265
+ """One leaderboard source's contribution to a player profile's ``stats`` array."""
266
+
267
+ id: str
268
+ label: str
269
+ status: Literal["ranked", "not_ranked", "unavailable"]
270
+ value: float
271
+ """Only present when ``status`` is "ranked"."""
272
+ rank: int
273
+ """Only present when ``status`` is "ranked" and the source reports a positive rank."""
274
+
275
+
276
+ class PlayerProfile(TypedDict):
277
+ """One-call player profile combining identity, whitelist/ban status, Vault balance, and this
278
+ player's entry in every registered leaderboard source. Returned by
279
+ ``GET /v1/players/{uuid}/profile`` and (as the ``players`` array) by ``GET /v1/players/profiles``.
280
+ """
281
+
282
+ name: Optional[str]
283
+ uuid: str
284
+ online: bool
285
+ status: PlayerProfileStatus
286
+ economy: PlayerProfileEconomy
287
+ stats: List[PlayerProfileStatTile]
288
+
289
+
290
+ class PlayerProfilesResponse(TypedDict):
291
+ """Response shape of ``GET /v1/players/profiles`` (bulk player profiles)."""
292
+
293
+ count: int
294
+ players: List[PlayerProfile]
295
+
296
+
224
297
  class NetworkServerStatus(TypedDict):
225
298
  id: str
226
299
  label: str
@@ -1,39 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import urllib.parse
4
- from typing import List, Optional
5
-
6
- from ..http_engine import HttpEngine
7
- from ..types import LeaderboardEntry, LeaderboardSourceInfo
8
-
9
-
10
- def _q(value: str) -> str:
11
- return urllib.parse.quote(value, safe="")
12
-
13
-
14
- class LeaderboardModule:
15
- """Wraps the generic, pluggable ``/v1/leaderboards/*`` routes.
16
-
17
- This is a unified view over every ranking source registered on the
18
- server — economy currencies, mcMMO power level, AuraSkills power
19
- level, etc — so you don't need to know ahead of time which plugins
20
- are installed.
21
-
22
- Use :meth:`list` to discover available source IDs, then pass one to
23
- :meth:`get_top`. Sources that are registered but currently
24
- unavailable (e.g. the backing plugin isn't loaded) raise
25
- ``NoxAeApiError`` with the source's own unavailable status (424 for
26
- economy currencies, 503 for mcMMO/AuraSkills) when you call
27
- :meth:`get_top`.
28
- """
29
-
30
- def __init__(self, http: HttpEngine) -> None:
31
- self._http = http
32
-
33
- def list(self) -> List[LeaderboardSourceInfo]:
34
- """List every registered leaderboard source and its availability."""
35
- return self._http.request("GET", "leaderboards")
36
-
37
- def get_top(self, id: str, limit: Optional[int] = None) -> List[LeaderboardEntry]:
38
- """Get ranked entries for one leaderboard source (see :meth:`list` for valid IDs)."""
39
- return self._http.request("GET", f"leaderboards/{_q(id)}/top", query={"limit": limit})
File without changes
File without changes