fix: update CI and publish workflows to use consistent action versions and improve error handling in API requests

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
bohd4nx
2026-05-03 19:10:11 +03:00
parent 7923dff8b2
commit d5dfed5f1a
8 changed files with 51 additions and 27 deletions
+4 -4
View File
@@ -14,9 +14,9 @@ jobs:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v6
- uses: actions/setup-python@v6.2.0
- uses: actions/setup-python@v6
with:
python-version: "3.10"
@@ -36,9 +36,9 @@ jobs:
python-version: [ "3.10", "3.11", "3.12" ] # 3.13, 3.14 are not supported by some dependencies yet
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v6
- uses: actions/setup-python@v6.2.0
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
+10 -10
View File
@@ -18,7 +18,7 @@ jobs:
is-new: ${{ steps.tag.outputs.is-new }}
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v6
with:
fetch-depth: 0
@@ -46,17 +46,17 @@ jobs:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v6
- uses: actions/setup-python@v6.2.0
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- uses: astral-sh/setup-uv@v8.0.0
- uses: astral-sh/setup-uv@v8.1.0
- run: uv build
- uses: actions/upload-artifact@v7
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/*
@@ -74,12 +74,12 @@ jobs:
id-token: write
steps:
- uses: actions/download-artifact@v8.0.1
- uses: actions/download-artifact@v4
with:
name: dist
path: dist
- uses: pypa/gh-action-pypi-publish@v1.14.0
- uses: pypa/gh-action-pypi-publish@v1
release:
name: GitHub Release
@@ -91,11 +91,11 @@ jobs:
contents: write
steps:
- uses: actions/checkout@v6.0.2
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/download-artifact@v8.0.1
- uses: actions/download-artifact@v4
with:
name: dist
path: dist
@@ -108,7 +108,7 @@ jobs:
echo "$body" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- uses: softprops/action-gh-release@v3.0.0
- uses: softprops/action-gh-release@v3
with:
tag_name: v${{ needs.version-check.outputs.version }}
name: v${{ needs.version-check.outputs.version }}
+16
View File
@@ -7,6 +7,21 @@ and this project uses [Calendar Versioning](https://calver.org/) (`YYYY.MINOR.MI
---
## [2026.2.1] — 2026-05-03
### Fixed
- Fragment API 429 responses are now retried automatically (up to 3 attempts) with exponential backoff and jitter in `fragment_request`
- Retry delays in TON transaction broadcasting now include jitter to reduce contention under concurrent calls
- Improved handling of non-200 HTTP responses in `get_fragment_hash`
- Removed unnecessary `method` key leaking into certain API request payloads
### Changed
- Type hints refined across the codebase for better clarity and `mypy` strict compliance
---
## [2026.2.0] — 2026-04-14
### Added
@@ -104,6 +119,7 @@ and this project uses [Calendar Versioning](https://calver.org/) (`YYYY.MINOR.MI
- `py.typed` marker — full PEP 561 typing support for type-checkers
- `__repr__` on all result types for readable debug output
[2026.2.1]: https://github.com/bohd4nx/pyfragment/releases/tag/v2026.2.1
[2026.2.0]: https://github.com/bohd4nx/pyfragment/releases/tag/v2026.2.0
[2026.1.0]: https://github.com/bohd4nx/pyfragment/releases/tag/v2026.1.0
[2026.0.2]: https://github.com/bohd4nx/pyfragment/releases/tag/v2026.0.2
+17 -8
View File
@@ -1,5 +1,7 @@
from __future__ import annotations
import asyncio
import random
import re
from typing import Any, cast
@@ -106,14 +108,21 @@ async def fragment_request(
Returns:
Parsed API response as a dict.
"""
resp = await session.post(
f"{FRAGMENT_BASE_URL}/api?hash={fragment_hash}",
headers=headers,
data=data,
)
if resp.status_code != 200:
raise FragmentPageError(FragmentPageError.BAD_STATUS.format(status=resp.status_code, url=f"{FRAGMENT_BASE_URL}/api"))
return parse_json_response(resp, data.get("method", "request"))
for attempt in range(3):
resp = await session.post(
f"{FRAGMENT_BASE_URL}/api?hash={fragment_hash}",
headers=headers,
data=data,
)
if resp.status_code == 429 and attempt < 2:
await asyncio.sleep(1 + attempt + random.uniform(0, 0.5))
continue
if resp.status_code != 200:
raise FragmentPageError(
FragmentPageError.BAD_STATUS.format(status=resp.status_code, url=f"{FRAGMENT_BASE_URL}/api")
)
return parse_json_response(resp, data.get("method", "request"))
raise FragmentPageError(FragmentPageError.BAD_STATUS.format(status=429, url=f"{FRAGMENT_BASE_URL}/api"))
async def execute_transaction_request(
+3 -2
View File
@@ -2,6 +2,7 @@ from __future__ import annotations
import asyncio
import base64
import random
import ssl
from typing import TYPE_CHECKING, Any
@@ -69,12 +70,12 @@ async def process_transaction(client: FragmentClient, transaction_data: dict[str
return str(result.normalized_hash)
except ProviderResponseError as exc:
if exc.code == 429 and attempt == 0:
await asyncio.sleep(1)
await asyncio.sleep(1 + random.uniform(0, 0.5))
continue
if exc.code == 406 and "seqno" in str(exc).lower():
# Previous tx seqno not yet confirmed — wallet will re-fetch seqno on retry
if attempt < 2:
await asyncio.sleep(2)
await asyncio.sleep(2 + random.uniform(0, 1))
continue
raise TransactionError(TransactionError.DUPLICATE_SEQNO) from exc
raise
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project]
name = "pyfragment"
version = "2026.2.0"
version = "2026.2.1"
description = "Async Python client for the Fragment API — a unified toolkit to manage Telegram assets: purchase Stars and Premium, top up TON and Ads balances, run giveaways, manage anonymous numbers, and explore the marketplace for usernames, numbers, and gifts."
readme = "README.md"
license = { text = "MIT" }
-1
View File
@@ -1 +0,0 @@
-e .[dev]
-1
View File
@@ -1 +0,0 @@
-e .