avios-cli 0.4.2__tar.gz → 0.5.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 (58) hide show
  1. {avios_cli-0.4.2 → avios_cli-0.5.0}/CHANGELOG.md +63 -1
  2. {avios_cli-0.4.2 → avios_cli-0.5.0}/PKG-INFO +34 -28
  3. {avios_cli-0.4.2 → avios_cli-0.5.0}/README.md +30 -24
  4. avios_cli-0.5.0/docs/dashboard.svg +216 -0
  5. {avios_cli-0.4.2 → avios_cli-0.5.0}/docs/reward-flights.svg +107 -106
  6. {avios_cli-0.4.2 → avios_cli-0.5.0}/pyproject.toml +8 -6
  7. {avios_cli-0.4.2 → avios_cli-0.5.0}/scripts/screenshot.py +9 -3
  8. {avios_cli-0.4.2 → avios_cli-0.5.0}/src/avios/__init__.py +1 -1
  9. {avios_cli-0.4.2 → avios_cli-0.5.0}/src/avios/auth.py +45 -19
  10. {avios_cli-0.4.2 → avios_cli-0.5.0}/src/avios/cli.py +72 -23
  11. {avios_cli-0.4.2 → avios_cli-0.5.0}/src/avios/client.py +27 -4
  12. {avios_cli-0.4.2 → avios_cli-0.5.0}/src/avios/config.py +3 -1
  13. avios_cli-0.5.0/src/avios/rewards.py +1396 -0
  14. {avios_cli-0.4.2 → avios_cli-0.5.0}/src/avios/session.py +19 -0
  15. {avios_cli-0.4.2 → avios_cli-0.5.0}/src/avios/tui/rewards.py +46 -22
  16. {avios_cli-0.4.2 → avios_cli-0.5.0}/tests/conftest.py +3 -0
  17. avios_cli-0.5.0/tests/fixtures/reward_search.rsc +6 -0
  18. {avios_cli-0.4.2 → avios_cli-0.5.0}/tests/test_auth.py +41 -1
  19. {avios_cli-0.4.2 → avios_cli-0.5.0}/tests/test_cli.py +160 -69
  20. avios_cli-0.5.0/tests/test_rewards.py +711 -0
  21. {avios_cli-0.4.2 → avios_cli-0.5.0}/tests/test_tui.py +80 -21
  22. {avios_cli-0.4.2 → avios_cli-0.5.0}/uv.lock +4 -8
  23. avios_cli-0.4.2/docs/dashboard.svg +0 -216
  24. avios_cli-0.4.2/src/avios/rewards.py +0 -530
  25. avios_cli-0.4.2/tests/fixtures/reward_search.rsc +0 -3
  26. avios_cli-0.4.2/tests/test_rewards.py +0 -324
  27. {avios_cli-0.4.2 → avios_cli-0.5.0}/.editorconfig +0 -0
  28. {avios_cli-0.4.2 → avios_cli-0.5.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  29. {avios_cli-0.4.2 → avios_cli-0.5.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  30. {avios_cli-0.4.2 → avios_cli-0.5.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  31. {avios_cli-0.4.2 → avios_cli-0.5.0}/.github/dependabot.yml +0 -0
  32. {avios_cli-0.4.2 → avios_cli-0.5.0}/.github/workflows/ci.yml +0 -0
  33. {avios_cli-0.4.2 → avios_cli-0.5.0}/.github/workflows/publish.yml +0 -0
  34. {avios_cli-0.4.2 → avios_cli-0.5.0}/.gitignore +0 -0
  35. {avios_cli-0.4.2 → avios_cli-0.5.0}/.pre-commit-config.yaml +0 -0
  36. {avios_cli-0.4.2 → avios_cli-0.5.0}/.python-version +0 -0
  37. {avios_cli-0.4.2 → avios_cli-0.5.0}/CONTRIBUTING.md +0 -0
  38. {avios_cli-0.4.2 → avios_cli-0.5.0}/LICENSE +0 -0
  39. {avios_cli-0.4.2 → avios_cli-0.5.0}/SECURITY.md +0 -0
  40. {avios_cli-0.4.2 → avios_cli-0.5.0}/src/avios/accounts.py +0 -0
  41. {avios_cli-0.4.2 → avios_cli-0.5.0}/src/avios/aggregate.py +0 -0
  42. {avios_cli-0.4.2 → avios_cli-0.5.0}/src/avios/endpoints.py +0 -0
  43. {avios_cli-0.4.2 → avios_cli-0.5.0}/src/avios/finnair.py +0 -0
  44. {avios_cli-0.4.2 → avios_cli-0.5.0}/src/avios/models.py +0 -0
  45. {avios_cli-0.4.2 → avios_cli-0.5.0}/src/avios/programmes.py +0 -0
  46. {avios_cli-0.4.2 → avios_cli-0.5.0}/src/avios/tui/__init__.py +0 -0
  47. {avios_cli-0.4.2 → avios_cli-0.5.0}/src/avios/tui/app.py +0 -0
  48. {avios_cli-0.4.2 → avios_cli-0.5.0}/src/avios/tui/art.py +0 -0
  49. {avios_cli-0.4.2 → avios_cli-0.5.0}/src/avios/tui/styles.tcss +0 -0
  50. {avios_cli-0.4.2 → avios_cli-0.5.0}/src/avios/tui/widgets.py +0 -0
  51. {avios_cli-0.4.2 → avios_cli-0.5.0}/tests/fixtures/balance.json +0 -0
  52. {avios_cli-0.4.2 → avios_cli-0.5.0}/tests/fixtures/transactions.json +0 -0
  53. {avios_cli-0.4.2 → avios_cli-0.5.0}/tests/test_accounts.py +0 -0
  54. {avios_cli-0.4.2 → avios_cli-0.5.0}/tests/test_aggregate.py +0 -0
  55. {avios_cli-0.4.2 → avios_cli-0.5.0}/tests/test_client.py +0 -0
  56. {avios_cli-0.4.2 → avios_cli-0.5.0}/tests/test_finnair.py +0 -0
  57. {avios_cli-0.4.2 → avios_cli-0.5.0}/tests/test_models.py +0 -0
  58. {avios_cli-0.4.2 → avios_cli-0.5.0}/tests/test_session.py +0 -0
@@ -6,6 +6,67 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.5.0] - 2026-08-11
10
+
11
+ ### Fixed
12
+ - **BA reward-flight search returned nothing after British Airways rebuilt the
13
+ flight finder.** The new Next.js app moved each day's flights one level deeper
14
+ (`departureJourneys.<date>.journeys[].flights[]` instead of
15
+ `departureJourneys.<date>.flights[]`), so every day parsed as empty. Availability
16
+ parsing now follows the new shape, and the old flat shape still parses if BA
17
+ rolls back.
18
+ - **Business-class seats were always reported as zero.** BA's availability rows use
19
+ cabin code `J`; the client only looked for `C`. Both are now recognised, matching
20
+ the site's own `cabinClassCodeMap`.
21
+ - The request contract was re-derived from a live capture and is now reproduced
22
+ byte for byte — query parameters, both `next-router-state-tree` variants, `rsc`,
23
+ `next-url`, `accept`, and the full browser header set. A user-agent that
24
+ disagreed with the `sec-ch-ua` client hints (Chrome 126 vs 148) is fixed, since
25
+ the mismatch is itself a bot signal.
26
+
27
+ ### Added
28
+ - **Avios prices.** Searching an exact `--date` now calls the finder's
29
+ `fetchPricingAction` server action and shows the Avios cost per cabin for your
30
+ party, in both the CLI table and the TUI. Calendar (month) searches stay
31
+ seats-only so they remain one request per leg.
32
+ - Exact-date searches also re-read that date through
33
+ `getFlightResultsForSingleJourneyAction`, exactly as the website does when you
34
+ click a day, so seat counts are fresh rather than served from the month cache.
35
+ - Seats that only sell against a BA companion voucher (Business `rbd: I`) are
36
+ marked `†` instead of being counted as general availability.
37
+ - `AviosClient.search_reward_legs()` searches every leg of a trip over **one**
38
+ browser session, and reports failures per leg so one bad leg does not lose the
39
+ other. The CLI and TUI both use it.
40
+ - Akamai denials are now distinguished from an expired session: a bot-manager 403
41
+ or a 429 raises `RewardSearchBlockedError` telling you to wait and switch
42
+ network, rather than sending you to log in again.
43
+
44
+ ### Changed
45
+ - **Reward searches make far fewer requests.** Previously each leg launched its own
46
+ Chrome, navigated to the finder, and drove the search form. A search now warms
47
+ one browser navigation and issues in-page `fetch()` calls for everything after
48
+ it — a return trip costs one navigation and two fetches — with pacing between
49
+ requests. British Airways blocks by IP address, and page loads were what
50
+ triggered it.
51
+ - One availability request now returns the whole 13-month booking window, so an
52
+ out-of-range month reports the window BA actually offers.
53
+ - Dates beyond BA's rolling booking horizon are recognised (`availabilityLevel: 3`)
54
+ and no longer render as "no reward seats".
55
+ - `flights --json` reports days as `journeys[].flights[]`, following the upstream
56
+ shape, and includes the `price` attached to each cabin.
57
+
58
+ ## [0.4.3] - 2026-07-27
59
+
60
+ ### Changed
61
+ - **`uvx avios-cli login` now works with no extra flags.** Browser-assisted login
62
+ (Playwright + browser-cookie3) moved from the optional `[login]` extra into the
63
+ base package, so `uvx avios-cli login iberia` just works — no more
64
+ `uvx --from 'avios-cli[login]' …`. The `login` extra is kept as a no-op alias
65
+ for backward compatibility.
66
+ - If you have no system Chrome, `avios login` now **downloads Playwright's Chromium
67
+ automatically** on first use (~150 MB, one-time) instead of failing with an
68
+ install hint.
69
+
9
70
  ## [0.4.2] - 2026-07-27
10
71
 
11
72
  ### Fixed
@@ -198,7 +259,8 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
198
259
  - Reward-flight **availability** search is not yet implemented (needs a British
199
260
  Airways capture).
200
261
 
201
- [Unreleased]: https://github.com/alexechoi/avios-cli/compare/v0.4.2...HEAD
262
+ [Unreleased]: https://github.com/alexechoi/avios-cli/compare/v0.4.3...HEAD
263
+ [0.4.3]: https://github.com/alexechoi/avios-cli/compare/v0.4.2...v0.4.3
202
264
  [0.4.2]: https://github.com/alexechoi/avios-cli/compare/v0.4.1...v0.4.2
203
265
  [0.4.1]: https://github.com/alexechoi/avios-cli/compare/v0.4.0...v0.4.1
204
266
  [0.4.0]: https://github.com/alexechoi/avios-cli/compare/v0.3.0...v0.4.0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: avios-cli
3
- Version: 0.4.2
3
+ Version: 0.5.0
4
4
  Summary: A CLI and TUI for Avios balances, transactions, and BA reward-flight availability.
5
5
  Project-URL: Homepage, https://github.com/alexechoi/avios-cli
6
6
  Project-URL: Repository, https://github.com/alexechoi/avios-cli
@@ -21,7 +21,9 @@ Classifier: Programming Language :: Python :: 3.12
21
21
  Classifier: Programming Language :: Python :: 3.13
22
22
  Classifier: Topic :: Utilities
23
23
  Requires-Python: >=3.10
24
+ Requires-Dist: browser-cookie3>=0.19
24
25
  Requires-Dist: httpx>=0.27
26
+ Requires-Dist: playwright>=1.44
25
27
  Requires-Dist: pydantic-settings>=2.3
26
28
  Requires-Dist: pydantic>=2.7
27
29
  Requires-Dist: pyyaml>=6.0
@@ -29,8 +31,6 @@ Requires-Dist: rich>=13.7
29
31
  Requires-Dist: textual>=0.80
30
32
  Requires-Dist: typer>=0.12
31
33
  Provides-Extra: login
32
- Requires-Dist: browser-cookie3>=0.19; extra == 'login'
33
- Requires-Dist: playwright>=1.44; extra == 'login'
34
34
  Description-Content-Type: text/markdown
35
35
 
36
36
  # avios-cli
@@ -86,22 +86,26 @@ uv run avios --help
86
86
  avios.com has no credential API — login is Auth0 Universal Login behind hCaptcha and
87
87
  SMS/passkey MFA — so `avios login` opens a real browser, **waits while you finish
88
88
  logging in** (password, captcha, SMS code), and captures the session once you land
89
- on the dashboard. It needs the **`login` extra**:
89
+ on the dashboard:
90
90
 
91
91
  ```bash
92
- uvx --from 'avios-cli[login]' avios login
93
- uvx --from 'avios-cli[login]' avios login finnair
92
+ uvx avios-cli login
93
+ uvx avios-cli login iberia
94
+ uvx avios-cli login finnair
94
95
  ```
95
96
 
96
- It launches your installed **Google Chrome** (no extra download). If you don't have
97
- Chrome, install Playwright's browser once with
98
- `uvx --from playwright playwright install chromium`.
97
+ It launches your installed **Google Chrome** (no download). If you don't have
98
+ Chrome, it fetches Playwright's Chromium automatically on first login (~150 MB,
99
+ one-time). No extra flags — browser support ships in the package.
100
+
101
+ > Tip: if you'll use it often, `uv tool install avios-cli` once, then just run
102
+ > `avios login`, `avios balance`, etc. directly.
99
103
 
100
104
  Prefer not to open a browser? Import the cookie from a Chrome you're already logged
101
105
  into avios.com with:
102
106
 
103
107
  ```bash
104
- uvx --from 'avios-cli[login]' avios login --from-browser
108
+ uvx avios-cli login --from-browser
105
109
  ```
106
110
 
107
111
  This scans **all your Chrome profiles** and uses whichever one is actually logged
@@ -109,16 +113,12 @@ into avios.com (it tells you which). If you have several profiles, you can targe
109
113
  one directly:
110
114
 
111
115
  ```bash
112
- uvx --from 'avios-cli[login]' avios login --from-browser --profile "Profile 1"
116
+ uvx avios-cli login --from-browser --profile "Profile 1"
113
117
  ```
114
118
 
115
- Plain `uvx avios-cli login` won't work — the isolated environment doesn't include
116
- the `login` extra.
117
-
118
119
  **Stuck in an endless captcha loop?** That's bot detection on the automated
119
120
  browser. Use `--from-browser` instead: log into avios.com in your normal Chrome
120
- (you'll get one normal captcha), then run
121
- `uvx --from 'avios-cli[login]' avios login --from-browser`.
121
+ (you'll get one normal captcha), then run `uvx avios-cli login --from-browser`.
122
122
 
123
123
  Finnair uses a different CAS/OAuth flow. `avios login finnair` opens the Finnair Plus
124
124
  balance page, lets you complete password and MFA in the real browser, and captures the
@@ -130,10 +130,12 @@ Each programme session is stored at `~/.config/avios/accounts/<programme>.json`
130
130
  `avios logout <programme>` for one account or `avios logout` for all accounts.
131
131
  For BA, browser-assisted login also opens the separate reward-flight application.
132
132
  British Airways may show a second login prompt; keep the browser open until the
133
- CLI confirms success. Reward searches drive the site's own form in a background
134
- Chrome window because the flight-search route rejects plain HTTP and automated
135
- headless requests, so the `login` extra remains required when running
136
- `avios flights` or the Reward Flights TUI tab.
133
+ CLI confirms success. Reward searches run inside a background Chrome window: the
134
+ flight finder is behind Akamai Bot Manager, which rejects plain HTTP clients and
135
+ **blocks by IP address** — a handful of ordinary page loads from a shared office
136
+ network is enough to earn a site-wide 403. Every leg of a search is therefore
137
+ batched through a single browser navigation, paced, and served by in-page
138
+ `fetch()` calls. If you do get blocked, wait a few minutes and switch network.
137
139
 
138
140
  ## Usage
139
141
 
@@ -150,9 +152,9 @@ avios overview # dashboard summary
150
152
  avios whoami # name, tier, membership, email
151
153
  avios raw /shell/api/users/current/accounts # hit any endpoint directly
152
154
 
153
- # Direct British Airways reward-seat availability:
154
- avios flights LON ABZ --date 2026-11-05
155
- avios flights LON ABZ --date 2026-11-05 --return-date 2026-11-12
155
+ # Direct British Airways reward-seat availability (--date also prices in Avios):
156
+ avios flights LON HKG --date 2027-01-05
157
+ avios flights LON HKG --date 2027-01-05 --return-date 2027-01-12
156
158
  avios flights LON ABZ --month 2026-11 --cabin economy --cabin business
157
159
  avios flights LON ABZ --month 2026-11 --return-month 2026-12 --json
158
160
  ```
@@ -176,10 +178,13 @@ A tabbed full-screen application:
176
178
  Press `r` to refresh the dashboard and `q` to quit. Reward searches run only when
177
179
  you press Search or Enter.
178
180
 
179
- Reward search is an unofficial, availability-only view. It currently supports
180
- direct BA flights, three-letter airport/city codes, and seat counts by cabin. It
181
- does not price, book, or show taxes/fees or connecting flights. Return journeys
182
- are two independent one-way searches.
181
+ Reward search is an unofficial view of BA's own flight finder. It supports direct
182
+ BA flights, three-letter airport/city codes, and seat counts by cabin. Searching
183
+ an exact `--date` also fetches the Avios price per cabin for your party; calendar
184
+ (month) searches show seats only, which keeps them to one request per leg. Seats
185
+ that need a BA companion voucher are marked `†`. It does not book, and it does
186
+ not show taxes/fees or connecting flights. Return journeys are two reverse-route
187
+ one-way searches sharing one browser session.
183
188
 
184
189
  ## Roadmap
185
190
 
@@ -191,6 +196,7 @@ are two independent one-way searches.
191
196
  - [x] Textual TUI dashboard
192
197
  - [x] Multiple accounts (BA, Iberia, Aer Lingus, Finnair) with combined views
193
198
  - [x] British Airways reward-flight **availability** search (CLI + TUI)
199
+ - [x] Avios pricing per cabin for an exact date
194
200
 
195
201
  ## Development
196
202
 
@@ -51,22 +51,26 @@ uv run avios --help
51
51
  avios.com has no credential API — login is Auth0 Universal Login behind hCaptcha and
52
52
  SMS/passkey MFA — so `avios login` opens a real browser, **waits while you finish
53
53
  logging in** (password, captcha, SMS code), and captures the session once you land
54
- on the dashboard. It needs the **`login` extra**:
54
+ on the dashboard:
55
55
 
56
56
  ```bash
57
- uvx --from 'avios-cli[login]' avios login
58
- uvx --from 'avios-cli[login]' avios login finnair
57
+ uvx avios-cli login
58
+ uvx avios-cli login iberia
59
+ uvx avios-cli login finnair
59
60
  ```
60
61
 
61
- It launches your installed **Google Chrome** (no extra download). If you don't have
62
- Chrome, install Playwright's browser once with
63
- `uvx --from playwright playwright install chromium`.
62
+ It launches your installed **Google Chrome** (no download). If you don't have
63
+ Chrome, it fetches Playwright's Chromium automatically on first login (~150 MB,
64
+ one-time). No extra flags — browser support ships in the package.
65
+
66
+ > Tip: if you'll use it often, `uv tool install avios-cli` once, then just run
67
+ > `avios login`, `avios balance`, etc. directly.
64
68
 
65
69
  Prefer not to open a browser? Import the cookie from a Chrome you're already logged
66
70
  into avios.com with:
67
71
 
68
72
  ```bash
69
- uvx --from 'avios-cli[login]' avios login --from-browser
73
+ uvx avios-cli login --from-browser
70
74
  ```
71
75
 
72
76
  This scans **all your Chrome profiles** and uses whichever one is actually logged
@@ -74,16 +78,12 @@ into avios.com (it tells you which). If you have several profiles, you can targe
74
78
  one directly:
75
79
 
76
80
  ```bash
77
- uvx --from 'avios-cli[login]' avios login --from-browser --profile "Profile 1"
81
+ uvx avios-cli login --from-browser --profile "Profile 1"
78
82
  ```
79
83
 
80
- Plain `uvx avios-cli login` won't work — the isolated environment doesn't include
81
- the `login` extra.
82
-
83
84
  **Stuck in an endless captcha loop?** That's bot detection on the automated
84
85
  browser. Use `--from-browser` instead: log into avios.com in your normal Chrome
85
- (you'll get one normal captcha), then run
86
- `uvx --from 'avios-cli[login]' avios login --from-browser`.
86
+ (you'll get one normal captcha), then run `uvx avios-cli login --from-browser`.
87
87
 
88
88
  Finnair uses a different CAS/OAuth flow. `avios login finnair` opens the Finnair Plus
89
89
  balance page, lets you complete password and MFA in the real browser, and captures the
@@ -95,10 +95,12 @@ Each programme session is stored at `~/.config/avios/accounts/<programme>.json`
95
95
  `avios logout <programme>` for one account or `avios logout` for all accounts.
96
96
  For BA, browser-assisted login also opens the separate reward-flight application.
97
97
  British Airways may show a second login prompt; keep the browser open until the
98
- CLI confirms success. Reward searches drive the site's own form in a background
99
- Chrome window because the flight-search route rejects plain HTTP and automated
100
- headless requests, so the `login` extra remains required when running
101
- `avios flights` or the Reward Flights TUI tab.
98
+ CLI confirms success. Reward searches run inside a background Chrome window: the
99
+ flight finder is behind Akamai Bot Manager, which rejects plain HTTP clients and
100
+ **blocks by IP address** — a handful of ordinary page loads from a shared office
101
+ network is enough to earn a site-wide 403. Every leg of a search is therefore
102
+ batched through a single browser navigation, paced, and served by in-page
103
+ `fetch()` calls. If you do get blocked, wait a few minutes and switch network.
102
104
 
103
105
  ## Usage
104
106
 
@@ -115,9 +117,9 @@ avios overview # dashboard summary
115
117
  avios whoami # name, tier, membership, email
116
118
  avios raw /shell/api/users/current/accounts # hit any endpoint directly
117
119
 
118
- # Direct British Airways reward-seat availability:
119
- avios flights LON ABZ --date 2026-11-05
120
- avios flights LON ABZ --date 2026-11-05 --return-date 2026-11-12
120
+ # Direct British Airways reward-seat availability (--date also prices in Avios):
121
+ avios flights LON HKG --date 2027-01-05
122
+ avios flights LON HKG --date 2027-01-05 --return-date 2027-01-12
121
123
  avios flights LON ABZ --month 2026-11 --cabin economy --cabin business
122
124
  avios flights LON ABZ --month 2026-11 --return-month 2026-12 --json
123
125
  ```
@@ -141,10 +143,13 @@ A tabbed full-screen application:
141
143
  Press `r` to refresh the dashboard and `q` to quit. Reward searches run only when
142
144
  you press Search or Enter.
143
145
 
144
- Reward search is an unofficial, availability-only view. It currently supports
145
- direct BA flights, three-letter airport/city codes, and seat counts by cabin. It
146
- does not price, book, or show taxes/fees or connecting flights. Return journeys
147
- are two independent one-way searches.
146
+ Reward search is an unofficial view of BA's own flight finder. It supports direct
147
+ BA flights, three-letter airport/city codes, and seat counts by cabin. Searching
148
+ an exact `--date` also fetches the Avios price per cabin for your party; calendar
149
+ (month) searches show seats only, which keeps them to one request per leg. Seats
150
+ that need a BA companion voucher are marked `†`. It does not book, and it does
151
+ not show taxes/fees or connecting flights. Return journeys are two reverse-route
152
+ one-way searches sharing one browser session.
148
153
 
149
154
  ## Roadmap
150
155
 
@@ -156,6 +161,7 @@ are two independent one-way searches.
156
161
  - [x] Textual TUI dashboard
157
162
  - [x] Multiple accounts (BA, Iberia, Aer Lingus, Finnair) with combined views
158
163
  - [x] British Airways reward-flight **availability** search (CLI + TUI)
164
+ - [x] Avios pricing per cabin for an exact date
159
165
 
160
166
  ## Development
161
167