vlrdevapi 2.4.1__tar.gz → 3.1.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 (254) hide show
  1. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/.github/workflows/docs-check.yml +14 -25
  2. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/.github/workflows/publish.yml +2 -2
  3. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/.github/workflows/test.yml +6 -2
  4. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/.gitignore +3 -1
  5. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/CHANGELOG.md +171 -0
  6. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/CODE_OF_CONDUCT.md +2 -1
  7. vlrdevapi-3.1.0/PKG-INFO +495 -0
  8. vlrdevapi-3.1.0/README.md +424 -0
  9. vlrdevapi-3.1.0/SECURITY.md +11 -0
  10. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/SUPPORT.md +2 -2
  11. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/pyproject.toml +47 -3
  12. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/scripts/check_mdx_examples.py +1 -0
  13. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/scripts/download_fixtures.py +137 -4
  14. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/__init__.py +1 -1
  15. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/__init__.pyi +13 -1
  16. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_base.py +64 -22
  17. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_client.py +4 -4
  18. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/info/models.py +23 -1
  19. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/info/namespace.pyi +6 -1
  20. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/info/parser.py +8 -8
  21. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/list/models.py +32 -2
  22. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/list/namespace.pyi +6 -1
  23. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/matches/models.py +39 -1
  24. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/matches/namespace.py +1 -1
  25. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/matches/namespace.pyi +5 -1
  26. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/matches/parser.py +22 -6
  27. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/namespace.pyi +5 -2
  28. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/stages/models.py +17 -1
  29. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/stages/namespace.pyi +6 -1
  30. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/stages/parser.py +1 -1
  31. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/standings/models.py +27 -1
  32. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/standings/namespace.pyi +6 -1
  33. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/standings/parser.py +4 -3
  34. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/teams/models.py +43 -1
  35. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/teams/namespace.pyi +6 -1
  36. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_matches/common.py +6 -45
  37. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_matches/completed/models.py +45 -1
  38. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_matches/completed/namespace.pyi +6 -1
  39. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_matches/completed/parser.py +1 -1
  40. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_matches/live/models.py +38 -1
  41. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_matches/live/namespace.pyi +6 -1
  42. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_matches/namespace.pyi +6 -2
  43. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_matches/upcoming/models.py +42 -1
  44. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_matches/upcoming/namespace.pyi +6 -1
  45. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_matches/upcoming/parser.py +1 -1
  46. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_news/article/models.py +24 -2
  47. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_news/article/parser.py +3 -3
  48. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_news/list/models.py +25 -1
  49. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_news/namespace.py +10 -0
  50. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/__init__.py +1 -1
  51. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/_common_parsing.py +28 -10
  52. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/agents/models.py +47 -1
  53. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/agents/namespace.pyi +5 -1
  54. vlrdevapi-3.1.0/src/vlrdevapi/_player/info/models.py +62 -0
  55. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/info/namespace.py +2 -2
  56. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/info/namespace.pyi +6 -1
  57. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/info/parser.py +3 -0
  58. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/matches/models.py +32 -1
  59. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/matches/namespace.pyi +7 -2
  60. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/matches/parser.py +2 -13
  61. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/namespace.py +46 -5
  62. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/namespace.pyi +13 -2
  63. vlrdevapi-3.1.0/src/vlrdevapi/_player/placements/__init__.py +11 -0
  64. vlrdevapi-3.1.0/src/vlrdevapi/_player/placements/models.py +70 -0
  65. vlrdevapi-3.1.0/src/vlrdevapi/_player/placements/namespace.py +63 -0
  66. vlrdevapi-3.1.0/src/vlrdevapi/_player/placements/namespace.pyi +21 -0
  67. vlrdevapi-3.1.0/src/vlrdevapi/_player/placements/parser.py +147 -0
  68. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/profile/models.py +27 -2
  69. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/profile/namespace.pyi +6 -1
  70. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/teams/models.py +31 -1
  71. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/teams/namespace.pyi +6 -1
  72. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/__init__.py +3 -1
  73. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/economy/__init__.py +6 -0
  74. vlrdevapi-3.1.0/src/vlrdevapi/_series/economy/models.py +288 -0
  75. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/economy/namespace.py +12 -6
  76. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/economy/namespace.pyi +4 -2
  77. vlrdevapi-3.1.0/src/vlrdevapi/_series/economy/parser.py +405 -0
  78. vlrdevapi-3.1.0/src/vlrdevapi/_series/info/__init__.py +17 -0
  79. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/info/models.py +102 -1
  80. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/info/namespace.pyi +6 -1
  81. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/info/parser.py +121 -10
  82. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/match_namespace.py +42 -1
  83. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/match_namespace.pyi +16 -6
  84. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/namespace.py +22 -2
  85. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/namespace.pyi +10 -1
  86. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/performance/models.py +64 -1
  87. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/performance/namespace.pyi +6 -1
  88. vlrdevapi-3.1.0/src/vlrdevapi/_series/players/models.py +280 -0
  89. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/players/namespace.py +2 -0
  90. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/players/namespace.pyi +6 -1
  91. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/players/parser.py +63 -35
  92. vlrdevapi-3.1.0/src/vlrdevapi/_series/replay/__init__.py +25 -0
  93. vlrdevapi-3.1.0/src/vlrdevapi/_series/replay/models.py +411 -0
  94. vlrdevapi-3.1.0/src/vlrdevapi/_series/replay/namespace.py +214 -0
  95. vlrdevapi-3.1.0/src/vlrdevapi/_series/replay/namespace.pyi +18 -0
  96. vlrdevapi-3.1.0/src/vlrdevapi/_series/replay/parser.py +431 -0
  97. vlrdevapi-3.1.0/src/vlrdevapi/_series/rounds/models.py +144 -0
  98. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/rounds/namespace.py +84 -9
  99. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/rounds/namespace.pyi +3 -1
  100. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/rounds/parser.py +18 -9
  101. vlrdevapi-3.1.0/src/vlrdevapi/_series/vods/__init__.py +8 -0
  102. vlrdevapi-3.1.0/src/vlrdevapi/_series/vods/models.py +99 -0
  103. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/vods/namespace.py +10 -10
  104. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/vods/namespace.pyi +6 -1
  105. vlrdevapi-3.1.0/src/vlrdevapi/_series/vods/parser.py +135 -0
  106. vlrdevapi-3.1.0/src/vlrdevapi/_team/completed_matches/models.py +88 -0
  107. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/completed_matches/namespace.py +46 -7
  108. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/completed_matches/namespace.pyi +12 -3
  109. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/completed_matches/parser.py +21 -8
  110. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/info/models.py +24 -1
  111. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/info/namespace.py +2 -9
  112. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/info/namespace.pyi +6 -1
  113. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/namespace.py +16 -3
  114. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/namespace.pyi +11 -5
  115. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/placements/models.py +36 -1
  116. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/placements/namespace.pyi +6 -1
  117. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/placements/parser.py +2 -2
  118. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/roster/models.py +25 -1
  119. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/roster/namespace.pyi +6 -1
  120. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/roster/parser.py +5 -4
  121. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/stats/models.py +27 -2
  122. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/stats/namespace.py +1 -1
  123. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/stats/namespace.pyi +5 -2
  124. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/transactions/models.py +23 -1
  125. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/transactions/namespace.pyi +6 -1
  126. vlrdevapi-3.1.0/src/vlrdevapi/_team/upcoming_matches/models.py +78 -0
  127. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/upcoming_matches/namespace.pyi +6 -1
  128. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/upcoming_matches/parser.py +25 -10
  129. vlrdevapi-3.1.0/src/vlrdevapi/_utils/pagination.py +78 -0
  130. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_utils/team_enrichment.py +5 -4
  131. vlrdevapi-3.1.0/src/vlrdevapi/_utils/text.py +50 -0
  132. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/commons/__init__.py +2 -0
  133. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/commons/datetime.py +1 -3
  134. vlrdevapi-3.1.0/src/vlrdevapi/commons/export.py +306 -0
  135. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/exceptions.py +11 -0
  136. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/fetcher.py +18 -1
  137. vlrdevapi-3.1.0/src/vlrdevapi/mcp/__init__.py +5 -0
  138. vlrdevapi-3.1.0/src/vlrdevapi/mcp/_common.py +69 -0
  139. vlrdevapi-3.1.0/src/vlrdevapi/mcp/server.py +33 -0
  140. vlrdevapi-3.1.0/src/vlrdevapi/mcp/tools/__init__.py +35 -0
  141. vlrdevapi-3.1.0/src/vlrdevapi/mcp/tools/composite.py +179 -0
  142. vlrdevapi-3.1.0/src/vlrdevapi/mcp/tools/events.py +88 -0
  143. vlrdevapi-3.1.0/src/vlrdevapi/mcp/tools/matches.py +40 -0
  144. vlrdevapi-3.1.0/src/vlrdevapi/mcp/tools/news.py +30 -0
  145. vlrdevapi-3.1.0/src/vlrdevapi/mcp/tools/players.py +74 -0
  146. vlrdevapi-3.1.0/src/vlrdevapi/mcp/tools/series.py +105 -0
  147. vlrdevapi-3.1.0/src/vlrdevapi/mcp/tools/teams.py +91 -0
  148. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/validators.py +21 -11
  149. vlrdevapi-3.1.0/uv.lock +2111 -0
  150. vlrdevapi-2.4.1/PKG-INFO +0 -226
  151. vlrdevapi-2.4.1/README.md +0 -178
  152. vlrdevapi-2.4.1/SECURITY.md +0 -9
  153. vlrdevapi-2.4.1/src/vlrdevapi/_player/info/models.py +0 -33
  154. vlrdevapi-2.4.1/src/vlrdevapi/_series/economy/models.py +0 -85
  155. vlrdevapi-2.4.1/src/vlrdevapi/_series/economy/parser.py +0 -169
  156. vlrdevapi-2.4.1/src/vlrdevapi/_series/info/__init__.py +0 -4
  157. vlrdevapi-2.4.1/src/vlrdevapi/_series/players/models.py +0 -84
  158. vlrdevapi-2.4.1/src/vlrdevapi/_series/rounds/models.py +0 -71
  159. vlrdevapi-2.4.1/src/vlrdevapi/_series/vods/__init__.py +0 -4
  160. vlrdevapi-2.4.1/src/vlrdevapi/_series/vods/models.py +0 -28
  161. vlrdevapi-2.4.1/src/vlrdevapi/_series/vods/parser.py +0 -50
  162. vlrdevapi-2.4.1/src/vlrdevapi/_team/completed_matches/models.py +0 -43
  163. vlrdevapi-2.4.1/src/vlrdevapi/_team/upcoming_matches/models.py +0 -40
  164. vlrdevapi-2.4.1/src/vlrdevapi/_utils/pagination.py +0 -37
  165. vlrdevapi-2.4.1/uv.lock +0 -1165
  166. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/.gitattributes +0 -0
  167. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  168. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  169. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/.github/workflows/cleanup-caches.yml +0 -0
  170. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/.nvmrc +0 -0
  171. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/.python-version +0 -0
  172. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/.readthedocs.yaml +0 -0
  173. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/CONTRIBUTING.md +0 -0
  174. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/LICENCE +0 -0
  175. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_cache.py +0 -0
  176. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/__init__.py +0 -0
  177. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/_common.py +0 -0
  178. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/info/__init__.py +0 -0
  179. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/info/namespace.py +0 -0
  180. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/list/__init__.py +0 -0
  181. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/list/namespace.py +0 -0
  182. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/list/parser.py +1 -1
  183. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/matches/__init__.py +0 -0
  184. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/namespace.py +0 -0
  185. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/stages/__init__.py +0 -0
  186. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/stages/namespace.py +0 -0
  187. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/standings/__init__.py +0 -0
  188. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/standings/namespace.py +0 -0
  189. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/teams/__init__.py +1 -1
  190. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/teams/namespace.py +0 -0
  191. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_event/teams/parser.py +0 -0
  192. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_matches/__init__.py +0 -0
  193. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_matches/completed/__init__.py +0 -0
  194. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_matches/completed/namespace.py +0 -0
  195. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_matches/live/__init__.py +0 -0
  196. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_matches/live/namespace.py +0 -0
  197. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_matches/live/parser.py +0 -0
  198. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_matches/namespace.py +0 -0
  199. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_matches/upcoming/__init__.py +0 -0
  200. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_matches/upcoming/namespace.py +0 -0
  201. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_news/__init__.py +0 -0
  202. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_news/article/__init__.py +0 -0
  203. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_news/article/namespace.py +0 -0
  204. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_news/article/namespace.pyi +0 -0
  205. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_news/common.py +0 -0
  206. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_news/list/__init__.py +0 -0
  207. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_news/list/namespace.py +0 -0
  208. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_news/list/namespace.pyi +0 -0
  209. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_news/list/parser.py +0 -0
  210. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_news/namespace.pyi +0 -0
  211. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/agents/__init__.py +0 -0
  212. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/agents/namespace.py +0 -0
  213. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/agents/parser.py +0 -0
  214. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/info/__init__.py +0 -0
  215. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/matches/__init__.py +0 -0
  216. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/matches/namespace.py +0 -0
  217. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/profile/__init__.py +0 -0
  218. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/profile/namespace.py +0 -0
  219. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/profile/parser.py +0 -0
  220. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/teams/__init__.py +0 -0
  221. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/teams/namespace.py +0 -0
  222. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_player/teams/parser.py +0 -0
  223. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/_utils.py +0 -0
  224. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/info/namespace.py +0 -0
  225. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/performance/__init__.py +0 -0
  226. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/performance/namespace.py +0 -0
  227. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/performance/parser.py +0 -0
  228. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/players/__init__.py +0 -0
  229. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_series/rounds/__init__.py +0 -0
  230. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/__init__.py +0 -0
  231. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/completed_matches/__init__.py +0 -0
  232. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/info/__init__.py +0 -0
  233. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/info/parser.py +0 -0
  234. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/placements/__init__.py +0 -0
  235. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/placements/namespace.py +0 -0
  236. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/roster/__init__.py +0 -0
  237. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/roster/namespace.py +0 -0
  238. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/stats/__init__.py +0 -0
  239. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/stats/parser.py +0 -0
  240. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/transactions/__init__.py +0 -0
  241. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/transactions/namespace.py +0 -0
  242. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/transactions/parser.py +0 -0
  243. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/upcoming_matches/__init__.py +0 -0
  244. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_team/upcoming_matches/namespace.py +0 -0
  245. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_utils/__init__.py +0 -0
  246. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_utils/paths.py +0 -0
  247. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/_utils/team_parsing.py +0 -0
  248. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/commons/countries.py +0 -0
  249. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/commons/mappings.py +0 -0
  250. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/commons/prizes.py +0 -0
  251. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/commons/regions.py +0 -0
  252. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/commons/timezone.py +0 -0
  253. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/src/vlrdevapi/py.typed +0 -0
  254. {vlrdevapi-2.4.1 → vlrdevapi-3.1.0}/wrangler.jsonc +0 -0
@@ -22,38 +22,28 @@ jobs:
22
22
  python-version: '3.12'
23
23
 
24
24
  - name: Install package
25
- run: uv sync --group dev
25
+ run: uv sync --group dev --all-extras
26
26
 
27
- # main always validates live against fresh vlr.gg data; never uses the
28
- # cache. Branch/PR runs reuse fixtures cached by earlier runs in the
29
- # same PR (within a 2h TTL), falling back to live fetches for anything
30
- # missing, so the check is correct even with a partially-stale cache.
31
- - name: Run MDX examples check (main, live)
32
- if: github.ref_name == 'main'
33
- run: uv run scripts/check_mdx_examples.py --live
34
-
35
- # actions/cache v6.1.0, pinned to a reviewed commit SHA.
36
- - name: Restore fixture cache (branch)
27
+ # Restore fixture cache scoped to the current ref (branch or main) and version prefix (v3).
28
+ # This ensures caches are never shared across unrelated branches or older versions.
29
+ - name: Restore fixture cache
37
30
  id: mdx-fixtures
38
- if: github.ref_name != 'main'
39
31
  uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9
40
32
  with:
41
33
  path: fixtures.tar.gz
42
- key: mdx-fixtures-${{ github.ref_name }}-run-${{ github.run_id }}
34
+ key: mdx-fixtures-v3-${{ github.ref_name }}-run-${{ github.run_id }}
43
35
  restore-keys: |
44
- mdx-fixtures-${{ github.ref_name }}-
36
+ mdx-fixtures-v3-${{ github.ref_name }}-
45
37
 
46
- - name: Unpack fixtures (branch)
47
- if: github.ref_name != 'main'
38
+ - name: Unpack fixtures
48
39
  run: |
49
40
  if [ -f fixtures.tar.gz ]; then
50
41
  mkdir -p .cache
51
42
  tar -C .cache -xzf fixtures.tar.gz
52
43
  fi
53
44
 
54
- - name: Check fixture cache age (branch, 2h TTL)
45
+ - name: Check fixture cache age (2h TTL)
55
46
  id: cache-age
56
- if: github.ref_name != 'main'
57
47
  run: |
58
48
  matched="${{ steps.mdx-fixtures.outputs.cache-matched-key }}"
59
49
  now=$(date +%s)
@@ -73,8 +63,7 @@ jobs:
73
63
  fi
74
64
  echo "now=$now" >> "$GITHUB_OUTPUT"
75
65
 
76
- - name: Run MDX examples check (branch)
77
- if: github.ref_name != 'main'
66
+ - name: Run MDX examples check
78
67
  run: |
79
68
  if [ "${{ steps.cache-age.outputs.fresh }}" == "true" ]; then
80
69
  uv run scripts/check_mdx_examples.py --skip-warm
@@ -84,8 +73,8 @@ jobs:
84
73
 
85
74
  # always(): a run that fails validation still saved its warm fixtures,
86
75
  # so the next fix commit restores and validates fast instead of warming.
87
- - name: Package fixtures (branch)
88
- if: always() && github.ref_name != 'main' && steps.cache-age.outputs.fresh == 'false'
76
+ - name: Package fixtures
77
+ if: always() && steps.cache-age.outputs.fresh == 'false'
89
78
  run: |
90
79
  mkdir -p .cache/mdx-html
91
80
  if [ -n "$(ls -A .cache/mdx-html)" ]; then
@@ -94,9 +83,9 @@ jobs:
94
83
  rm -f fixtures.tar.gz
95
84
  fi
96
85
 
97
- - name: Save fixture cache (branch)
98
- if: always() && github.ref_name != 'main' && steps.cache-age.outputs.fresh == 'false'
86
+ - name: Save fixture cache
87
+ if: always() && steps.cache-age.outputs.fresh == 'false'
99
88
  uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9
100
89
  with:
101
90
  path: fixtures.tar.gz
102
- key: mdx-fixtures-${{ github.ref_name }}-${{ steps.cache-age.outputs.now }}
91
+ key: mdx-fixtures-v3-${{ github.ref_name }}-${{ steps.cache-age.outputs.now }}
@@ -13,7 +13,7 @@ jobs:
13
13
  runs-on: ubuntu-latest
14
14
  strategy:
15
15
  matrix:
16
- python-version: ['3.11', '3.12', '3.13', '3.14']
16
+ python-version: ['3.11', '3.12', '3.13', '3.14', '3.15']
17
17
 
18
18
  steps:
19
19
  - uses: actions/checkout@v7
@@ -23,7 +23,7 @@ jobs:
23
23
  python-version: ${{ matrix.python-version }}
24
24
 
25
25
  - name: Install dependencies
26
- run: uv sync --group dev
26
+ run: uv sync --group dev --all-extras
27
27
 
28
28
  - name: Download fixtures
29
29
  run: uv run python scripts/download_fixtures.py
@@ -5,6 +5,8 @@ on:
5
5
  paths:
6
6
  - 'src/**'
7
7
  - 'tests/**'
8
+ - 'pyproject.toml'
9
+ - 'uv.lock'
8
10
  - 'scripts/download_fixtures.py'
9
11
  - '.github/workflows/test.yml'
10
12
  push:
@@ -12,6 +14,8 @@ on:
12
14
  paths:
13
15
  - 'src/**'
14
16
  - 'tests/**'
17
+ - 'pyproject.toml'
18
+ - 'uv.lock'
15
19
  - 'scripts/download_fixtures.py'
16
20
  - '.github/workflows/test.yml'
17
21
 
@@ -20,7 +24,7 @@ jobs:
20
24
  runs-on: ubuntu-latest
21
25
  strategy:
22
26
  matrix:
23
- python-version: ['3.11', '3.12', '3.13', '3.14']
27
+ python-version: ['3.11', '3.12', '3.13', '3.14', '3.15']
24
28
 
25
29
  steps:
26
30
  - uses: actions/checkout@v7
@@ -30,7 +34,7 @@ jobs:
30
34
  python-version: ${{ matrix.python-version }}
31
35
 
32
36
  - name: Install dependencies
33
- run: uv sync --group dev
37
+ run: uv sync --group dev --all-extras
34
38
 
35
39
  - name: Download fixtures
36
40
  run: uv run python scripts/download_fixtures.py
@@ -30,4 +30,6 @@ main.py
30
30
  official-docs/node_modules/
31
31
 
32
32
  # Zensical cache
33
- docs-py/.cache/
33
+ docs-py/.cache/
34
+
35
+ temp/
@@ -5,6 +5,175 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/).
7
7
 
8
+ ## [3.1.0] - 2026-10-25
9
+
10
+ ### Added
11
+
12
+ - **Multi-Format Tabular Export Layer** — All Pydantic models now inherit from `ExportableModel`, enabling seamless tabular serialization into popular data science formats:
13
+ - `.to_records()` — extracts clean, unnested lists of Python dictionaries with semantic flattening across every namespace.
14
+ - `.to_df()` — converts records directly into a `pandas.DataFrame`.
15
+ - `.to_polars()` — converts records directly into a native `polars.DataFrame` with typed nested arrays (`pl.List(pl.String)`).
16
+ - `.to_csv(path=None)` — exports to standard CSV format with semicolon-delimited lists (`"Player;IGL"`) and in-memory string output when `path` is omitted.
17
+ - `.to_parquet(path, index=False)` — writes Apache Parquet files via pandas and pyarrow.
18
+ - `.to_excel(path, sheet_name="Sheet1", index=False)` — exports Excel `.xlsx` spreadsheets via pandas and openpyxl.
19
+ - `.to_json(path=None, indent=2)` — exports clean serialized JSON to string or disk with comprehensive recursive datetime and list handling.
20
+ - `.to_markdown(columns=None)` — generates GitHub-flavored markdown tables with proper column alignments, pipe escaping, and zero dependencies.
21
+ - **Granular Optional Dependency Extras** — Data export dependencies are strictly optional and modular:
22
+ - `vlrdevapi[pandas]`: installs `pandas>=2.0.0`
23
+ - `vlrdevapi[polars]`: installs `polars>=1.0.0`
24
+ - `vlrdevapi[excel]`: installs `openpyxl>=3.1.0` and `pandas>=2.0.0`
25
+ - `vlrdevapi[parquet]`: installs `pyarrow>=14.0.0` and `pandas>=2.0.0`
26
+ - `vlrdevapi[mcp]`: installs `mcp>=1.2.0`
27
+ - `vlrdevapi[all]`: installs all optional tabular, file, and MCP dependencies.
28
+ - Missing dependencies provide actionable, friendly install prompts with exact pip commands instead of generic import errors.
29
+ - **First-Class Model Context Protocol (MCP) Server** — Built-in MCP server for AI agents and LLMs (Claude Desktop, Cursor, Zed, Antigravity):
30
+ - CLI executable `vlrdevapi-mcp` (or `python -m vlrdevapi.mcp.server`, `uvx vlrdevapi-mcp`).
31
+ - Standard `stdio` transport with structured, formatted tool definitions.
32
+ - 40 tools covering all endpoints across Matches, Series, Teams, Players, Events, and News.
33
+ - High-level composite tools for complex agent tasks:
34
+ - `get_match_full_context(series_id)` — aggregates overview, player statistics, and streams/VODs into a single response.
35
+ - `get_team_overview(team_id)` — combines team info, roster, upcoming schedule, and tournament placements.
36
+ - `compare_teams(team_id_1, team_id_2, last_days=60)` — side-by-side comparison of two teams with rosters and recent map statistics/forms.
37
+ - `get_player_career_summary(player_id)` — consolidated dossier with profile, current teams, agent pool ratings, and tournament placements.
38
+ - `get_h2h_matchup(team_id_1, team_id_2)` — head-to-head match history between two organizations.
39
+ - `get_tournament_dossier(event_id)` — tournament overview with participating teams, stages, and standings.
40
+ - `get_live_and_upcoming_schedule(limit)` — live ticker combined with upcoming match schedule.
41
+ - `get_news_digest(limit, include_top_article_body)` — latest esports headlines with optional top article body.
42
+ - `series_map_summary(series_id, game_id)` — targeted map-level overview combining economy, replay timeline, and player stats.
43
+ - **Python 3.15 Ready** — Added Python 3.15 to the CI/CD test and publish workflows, verified across uv python matrix.
44
+ - **Production/Stable Status** — Package status promoted to `Development Status :: 5 - Production/Stable` in package metadata.
45
+
46
+ ### Improved
47
+
48
+ - **Semantic Model Flattening** — Tabular export extractors (`.to_records()`) now generate clean, non-redundant rows:
49
+ - Upcoming/completed matches omit static status columns and resolve unannounced teams as `"TBD"`.
50
+ - Player agent statistics provide unnested, clean numeric columns (`acs`, `kd`, `adr`, `kast`, `kpr`, `apr`).
51
+ - Series player stats properly segregate map rows, labeling the aggregate map view as `"All Maps"`.
52
+ - Team rosters separate `primary_role` and multi-role lists.
53
+ - **Unified Serialization in MCP Tools** — MCP server tools now leverage `ExportableModel.to_dict()` and `ExportableModel.to_json()`, eliminating redundant ad-hoc JSON conversion and drastically speeding up tool invocations.
54
+ - **CSV Multi-Value List Formatting** — Agent lists and team roles are formatted with standard semicolon delimiters (`"neon;raze;jett"`) instead of Python `repr()` strings, ensuring full compatibility with spreadsheet applications and analytical parsers.
55
+ - **Parser Corrections** — Fixed swapped KAST and ADR columns in `player.agents()` table extraction to match VLR.gg's actual table headers.
56
+
57
+ ## [3.0.0] - 2026-10-23
58
+
59
+ ### Breaking
60
+
61
+ - **`BuyType` re-tiered to match vlr.gg** — the economy tab no longer uses
62
+ its old four spend tiers. `SEMI_ECO` and `SEMI_BUY` are removed and the
63
+ remaining tiers follow VLR's current categories based on total team
64
+ spend: `ECO` (under 10k), `HALF_BUY` (10k–18k), and `FULL_BUY` (18k+).
65
+ A new `PISTOL` member marks pistol-round buys (previously reported as
66
+ `ECO`). Code switching on `BuyType.SEMI_ECO` / `BuyType.SEMI_BUY` needs
67
+ updating; string values are `"Pistol"`, `"Eco"`, `"Half-buy"`,
68
+ `"Full-buy"`.
69
+
70
+ ### Added
71
+
72
+ - **Buy-type matrix** — `EconomyData` now carries the economy tab's
73
+ buy-type matrix as `buy_matrix_team1` / `buy_matrix_team2`
74
+ (`TeamBuyMatrix`): the Pistol / Conv. / Bonus summary and the
75
+ `On Eco` / `On Half buy` / `On Full buy` records
76
+ (`BuyTierRecord.vs_eco` / `vs_half` / `vs_full`), each a
77
+ `won`/`total` `EconScore`. Unplayed matchups are `None`.
78
+ `series.economy(game_id="all")` on the parser also now returns the
79
+ all-maps aggregate matrix instead of an empty result.
80
+ - **Convenience accessors** — flat summary shortcuts
81
+ (`pistol_team1` / `converted_team1` / `bonus_team1` and the
82
+ `_team2` counterparts), `full_buy` / `half_buy` / `eco` aliases on
83
+ `TeamBuyMatrix`, and a combined `total` on `BuyTierRecord` for the
84
+ overall won/total on a tier regardless of the opponent's buy type.
85
+ - **Round economy in `series.rounds`** — `RoundData` now carries the
86
+ per-round economy from the economy tab: `bank_team1`/`bank_team2`,
87
+ `spent_team1`/`spent_team2`, `buy_type_team1`/`buy_type_team2`, and
88
+ `is_pistol_round`. `series.rounds` fetches and merges the economy tab
89
+ automatically (economy fields stay `None`/empty when that page is
90
+ unavailable), making it the single round-by-round source alongside
91
+ `win_type` and the winner's `side`.
92
+ - **Series replay (logs tab)** — new `series.replay(series_id, game_id)`
93
+ returning the per-round kill-feed timeline (`ReplayData` /
94
+ `ReplayRound` / `ReplayEvent`): events typed by the `ReplayEventType`
95
+ enum (`KILL`, `PLANT`, `DEFUSE`, plus derived `BOOM` detonation and
96
+ `RESURRECT` events with `derived=True`, since vlr.gg logs neither as
97
+ feed rows), round clocks in both display (`clock`) and numeric
98
+ (`seconds`) form, kill cause (weapon or ability, e.g. `Sheriff`,
99
+ `Overdrive`, `Tour de Force`, `Spike`), killer/victim positions with
100
+ distance in minimap units, spike sites, and per-event alive snapshots
101
+ (name, agent, team, side, minimap coordinates, facing angle). Each
102
+ `ReplayRound` also includes `loadouts` (`list[PlayerRoundLoadout]`)
103
+ and the `loadout_for(player)` helper, capturing every player's
104
+ equipped weapon at round start, armor (supporting `No armor`,
105
+ `Light armor`, `Heavy armor`, and `Regen Shield`), and credits
106
+ left / spent in the buy phase. Real vlr.gg team and player IDs are
107
+ resolved from the game's overview tab
108
+ (one extra request, `team1_id`/`team2_id` and `player_id` fields) and
109
+ matched strictly within each player's team so duplicate names never
110
+ cross teams; unplayed maps or maps without round data return an
111
+ empty timeline gracefully.
112
+ - **Series head-to-head history** — `SeriesInfo.head_to_head` exposes
113
+ previous meetings between the two teams, parsed from the same overview
114
+ page. Each `SeriesHeadToHeadMatch` includes the series ID/URL, event,
115
+ stage, date, both team names/scores, and which side won.
116
+ - **Series streams in `series.vods()`** — `SeriesVods.streams` now contains
117
+ live broadcasts and watch-party streams alongside the existing `vods`
118
+ list. Each `SeriesStream` exposes the platform, channel, URL, stream
119
+ type, and country code. `SeriesVod` also gains `platform`, `map_number`,
120
+ and `start_seconds`.
121
+ - **Player total winnings** — `PlayerInfo.total_winnings` and
122
+ `total_winnings_currency` now expose the total from the player's Event
123
+ Placements card.
124
+ - **New `player.placements()` namespace** — returns `PlayerPlacements` with
125
+ individual `PlayerEventPlacement` rows (event, year, stage, placement,
126
+ prize, team) and the player's total winnings.
127
+ - **New grand-final fixtures** — series 130685 (LOUD vs OpTic, Champions
128
+ 2022 GF) and 754737 (LOUD vs Vitality, Champions 2026 GF) are now
129
+ covered by tests across economy, info/pick-bans, players, rounds, and
130
+ performance parsers.
131
+
132
+ ### Fixed
133
+
134
+ - **`team.upcoming_matches()` no longer returns completed matches** — the
135
+ parser now scopes its search to the heading's section wrapper instead of
136
+ the whole team-summary column, so "Recent Results" is excluded.
137
+ - **`series.info()` on upcoming/live series** — `best_of` is now read from
138
+ whichever match-header note contains the format (vlr.gg renders the
139
+ countdown twice before `BoN`), and `TBD` map tabs are no longer marked
140
+ `played`.
141
+ - **`team.completed_matches()` pagination** — added `limit` (default `50`)
142
+ and `return_all`; extra pages are fetched only when the requested limit
143
+ needs them. `TeamCompletedMatches.has_next_page` reports whether more
144
+ matches exist beyond the returned results.
145
+ - **Team match `stage`/`bracket`** — both fields are now parsed separately
146
+ from the team matches page (e.g. `stage="Playoffs"`, `bracket="LBF"`),
147
+ and enrichment no longer concatenates them into `"Playoffs - LBF"`.
148
+ - **Parser whitespace** — shared `normalize_whitespace()` collapses raw tabs,
149
+ newlines, and repeated spaces in parsed event/stage/bracket/role values
150
+ instead of leaving values such as `"Playoffs ⋅\n\t\t\tLBF"`.
151
+ - **`events.matches()` team countries** — `MatchTeam` now exposes
152
+ `country_name`, parsed from the team flag on the event matches page.
153
+ - **Thread-local HTTP client lifecycle** — parallel requests now reuse
154
+ thread-local clients and close every client after fetching or enrichment,
155
+ reducing client-creation overhead and preventing resource leaks.
156
+
157
+ ### Changed
158
+
159
+ - **`RoundData.win_type` is now a `RoundWinType` enum** instead of a
160
+ human-readable string. Use `round.win_type.full_name` for display text and
161
+ `round.win_type.value` (`"elimination"`, `"defuse"`, `"spike_detonation"`,
162
+ `"time_expired"`) for the raw value.
163
+
164
+ ### Documentation
165
+
166
+ - Series economy reference updated for the new `BuyType` values,
167
+ buy-matrix fields, and nested models; series rounds reference updated
168
+ for the merged per-round economy fields; new series replay reference
169
+ page for the kill-feed timeline module.
170
+ - Updated the `team.completed_matches`, `team.upcoming_matches`,
171
+ `events.matches`, and `series.rounds` references for `bracket`,
172
+ `country_name`, and the `RoundWinType` enum.
173
+ - Updated `series.info`, `series.vods`, and `player.info`, and added a
174
+ `player.placements` reference for head-to-head history, streams, VOD
175
+ metadata, and event placements.
176
+
8
177
  ## [2.4.1] - 2026-10-17
9
178
 
10
179
  ### Fixed
@@ -316,6 +485,8 @@ The API surface, module structure, and type system are all new.
316
485
  - `aiohttp` and `asyncio` dependencies.
317
486
  - v1.x match/event/team parsing modules.
318
487
 
488
+ [3.1.0]: https://github.com/Vanshbordia/vlrdevapi/compare/v3.0.0...v3.1.0
489
+ [3.0.0]: https://github.com/Vanshbordia/vlrdevapi/compare/v2.4.1...v3.0.0
319
490
  [2.4.1]: https://github.com/Vanshbordia/vlrdevapi/compare/v2.4.0...v2.4.1
320
491
  [2.4.0]: https://github.com/Vanshbordia/vlrdevapi/compare/v2.3.0...v2.4.0
321
492
  [2.3.0]: https://github.com/Vanshbordia/vlrdevapi/compare/v2.2.0...v2.3.0
@@ -15,5 +15,6 @@ diverse, inclusive, and healthy community.
15
15
  ## Enforcement
16
16
 
17
17
  Instances of abusive, harassing, or otherwise unacceptable behavior may be
18
- reported to the project maintainers at vanshb@riftwatch.org. All complaints
18
+ reported to the project maintainers via the repository at
19
+ https://github.com/vanshbordia/vlrdevapi. All complaints
19
20
  will be reviewed and investigated.