onemax 0.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.
@@ -0,0 +1,29 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ concurrency:
9
+ group: ${{ github.workflow }}-${{ github.ref }}
10
+ cancel-in-progress: true
11
+
12
+ jobs:
13
+ test:
14
+ runs-on: ubuntu-latest
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ python: ["3.10", "3.11", "3.12", "3.13"]
19
+ steps:
20
+ - uses: actions/checkout@v5
21
+ - uses: astral-sh/setup-uv@v7
22
+ with:
23
+ enable-cache: true
24
+ python-version: ${{ matrix.python }}
25
+ - run: uv sync
26
+ - run: uv run ruff format --check .
27
+ - run: uv run ruff check .
28
+ - run: uv run mypy src
29
+ - run: uv run pytest --cov --cov-report=term-missing
@@ -0,0 +1,58 @@
1
+ name: Publish
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+
7
+ jobs:
8
+ verify:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v5
12
+ - uses: astral-sh/setup-uv@v7
13
+ with:
14
+ python-version: "3.12"
15
+ - name: Check the tag matches the package version
16
+ run: |
17
+ tag="${GITHUB_REF_NAME#v}"
18
+ declared="$(uv run python -c 'from importlib.metadata import version; print(version("onemax"))')"
19
+ imported="$(uv run python -c 'import onemax; print(onemax.__version__)')"
20
+ echo "tag $tag, pyproject $declared, module $imported"
21
+ test "$tag" = "$declared"
22
+ test "$tag" = "$imported"
23
+ - run: uv run ruff check .
24
+ - run: uv run mypy src
25
+ - run: uv run pytest
26
+
27
+ publish:
28
+ needs: verify
29
+ runs-on: ubuntu-latest
30
+ environment: pypi
31
+ permissions:
32
+ id-token: write
33
+ steps:
34
+ - uses: actions/checkout@v5
35
+ - uses: astral-sh/setup-uv@v7
36
+ - run: uv build
37
+ - uses: pypa/gh-action-pypi-publish@release/v1
38
+ with:
39
+ password: ${{ secrets.PYPI_API_TOKEN }}
40
+
41
+ release:
42
+ needs: publish
43
+ runs-on: ubuntu-latest
44
+ permissions:
45
+ contents: write
46
+ steps:
47
+ - uses: actions/checkout@v5
48
+ - name: Take the notes from the changelog
49
+ run: |
50
+ awk -v version="${GITHUB_REF_NAME#v}" '
51
+ /^## / { found = ($2 == version); next }
52
+ found { print }
53
+ ' CHANGELOG.md > notes.md
54
+ test -s notes.md
55
+ - name: Publish the GitHub release
56
+ env:
57
+ GH_TOKEN: ${{ github.token }}
58
+ run: gh release create "$GITHUB_REF_NAME" --title "$GITHUB_REF_NAME" --notes-file notes.md
@@ -0,0 +1,11 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.py[cod]
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ .mypy_cache/
7
+ .coverage
8
+ dist/
9
+ build/
10
+ *.egg-info/
11
+ .env
@@ -0,0 +1,13 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0
4
+
5
+ First release.
6
+
7
+ - Check a member by the code on their card and record the usage: `verify_code`, `confirm_usage`,
8
+ `void_usage`, `usage`.
9
+ - Account linking with PKCE: `generate_pkce`, `authorize_url`, `exchange_code`, `link_status`,
10
+ `verify_link`, `revoke_link`.
11
+ - `context` to check a key and list the venue's offers.
12
+ - Sync `OneMaxClient` and async `AsyncOneMaxClient` with the same methods.
13
+ - Typed results and one error class per kind of failure.
onemax-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 OneMax
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.
onemax-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,225 @@
1
+ Metadata-Version: 2.5
2
+ Name: onemax
3
+ Version: 0.1.0
4
+ Summary: Python client for the OneMax partner API
5
+ Project-URL: Homepage, https://onemax.az
6
+ Project-URL: Repository, https://github.com/onemax-az/onemax-python
7
+ Project-URL: Changelog, https://github.com/onemax-az/onemax-python/blob/main/CHANGELOG.md
8
+ Author: OneMax
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: api,azerbaijan,membership,onemax,partner
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Typing :: Typed
20
+ Requires-Python: >=3.10
21
+ Requires-Dist: httpx>=0.27
22
+ Description-Content-Type: text/markdown
23
+
24
+ # onemax
25
+
26
+ Python client for the [OneMax](https://onemax.az) partner API.
27
+
28
+ OneMax is a 1+1 membership club in Baku. Members pay for a plan and show a code at the counter to
29
+ use a partner's offer. This library lets a partner's own system do what the counter does: check
30
+ that someone is a member and record that they used the offer.
31
+
32
+ Sync and async, fully typed, one dependency.
33
+
34
+ ```bash
35
+ pip install onemax
36
+ ```
37
+
38
+ ## Getting a key
39
+
40
+ 1. OneMax switches API access on for your business.
41
+ 2. The owner opens the partner panel, goes to API and creates a key.
42
+ 3. The key is shown once. It belongs to one venue and acts there like a cashier.
43
+
44
+ Keep the key on your server. It must never reach a browser or a mobile app.
45
+
46
+ ## Quick start: a member's code
47
+
48
+ A member opens their OneMax card and reads you the six digit code.
49
+
50
+ ```python
51
+ from onemax import OneMaxClient
52
+
53
+ client = OneMaxClient("omx_live_...")
54
+
55
+ check = client.verify_code("482915")
56
+ if not check.usable:
57
+ print("No discount:", check.reason)
58
+ else:
59
+ order = place_order(discounted=True)
60
+ client.confirm_usage(check.usage_id, reference=order.id)
61
+ ```
62
+
63
+ `verify_code` only answers the question. Nothing counts against the member until you call
64
+ `confirm_usage`. If the order falls through, call `void_usage(check.usage_id)` instead.
65
+
66
+ Pass your own order id as `reference`. Confirming again with the same reference returns the same
67
+ usage, so a retried request is safe.
68
+
69
+ ## Account linking
70
+
71
+ A member links their OneMax account to your app once. After that you check them without a code.
72
+ Linking is the OAuth 2.0 authorization code flow with PKCE, so the same steps work for a website
73
+ and a mobile app.
74
+
75
+ Register the addresses your app may return to in the partner panel, under API, Account linking.
76
+ Your client id is shown there.
77
+
78
+ **1. Send the member to the permission page.**
79
+
80
+ ```python
81
+ from onemax import generate_pkce
82
+
83
+ pkce = generate_pkce()
84
+ session["onemax_verifier"] = pkce.verifier
85
+
86
+ url = client.authorize_url(
87
+ client_id="omx_client_...",
88
+ redirect_uri="https://example.az/onemax/return",
89
+ code_challenge=pkce.challenge,
90
+ state=session_id,
91
+ )
92
+ ```
93
+
94
+ In a mobile app, open `url` in the system browser and use your app link as the `redirect_uri`,
95
+ for example `taksi://onemax/return`.
96
+
97
+ **2. The member returns to your address** with `code` and `state`, or with `error=access_denied`
98
+ if they declined. Check that `state` is the one you sent.
99
+
100
+ **3. Exchange the code on your server and store the token.**
101
+
102
+ ```python
103
+ link = client.exchange_code(
104
+ code,
105
+ code_verifier=session["onemax_verifier"],
106
+ redirect_uri="https://example.az/onemax/return",
107
+ )
108
+ save(user_id, link.link_token)
109
+ ```
110
+
111
+ The code works once and for five minutes.
112
+
113
+ **4. Check the member whenever you need to.**
114
+
115
+ ```python
116
+ status = client.link_status(link_token)
117
+ if not status.linked:
118
+ forget(user_id)
119
+
120
+ check = client.verify_link(link_token)
121
+ if check.usable:
122
+ client.confirm_usage(check.usage_id, reference=order.id)
123
+ ```
124
+
125
+ A member can unlink at any time in their OneMax profile. From then on `link_status` answers
126
+ `linked=False` and `verify_link` answers `reason="not_linked"`. Neither raises.
127
+
128
+ You learn only whether the subscription is active. The member's name, email, phone and photo are
129
+ never shared.
130
+
131
+ ## Async
132
+
133
+ `AsyncOneMaxClient` has the same methods, awaited:
134
+
135
+ ```python
136
+ from onemax import AsyncOneMaxClient
137
+
138
+ async with AsyncOneMaxClient("omx_live_...") as client:
139
+ check = await client.verify_code("482915")
140
+ ```
141
+
142
+ ## Results
143
+
144
+ `verify_code` and `verify_link` return a `Verification`:
145
+
146
+ | Field | Meaning |
147
+ | --- | --- |
148
+ | `active` | The member has a subscription that works today |
149
+ | `usable` | They may use the offer right now |
150
+ | `reason` | Why, as a `Reason` |
151
+ | `usage_id` | Set when `usable` is true. Confirm it or void it |
152
+ | `daily_limit` | How many times a day a member may use this venue |
153
+
154
+ | `Reason` | Meaning |
155
+ | --- | --- |
156
+ | `OK` | Go ahead |
157
+ | `NOT_SUBSCRIBED` | No subscription, or it has ended |
158
+ | `LIMIT_REACHED` | The member already used today's allowance at this venue |
159
+ | `OFFER_UNAVAILABLE` | The venue or the offer is not open right now |
160
+ | `INVALID_CODE` | The code is wrong, expired or already used |
161
+ | `NOT_LINKED` | The link token no longer works |
162
+
163
+ `Reason` and `UsageStatus` are string enums, so `check.reason == "ok"` works as well. A value this
164
+ version does not know is returned as a plain string.
165
+
166
+ If a venue has several offers open, pass `offer_id`. `client.context()` lists them.
167
+
168
+ ## Errors
169
+
170
+ Everything the library raises is a `OneMaxError`.
171
+
172
+ | Class | When |
173
+ | --- | --- |
174
+ | `TransportError` | No usable answer: a connection failure, a timeout, or a body that is not JSON |
175
+ | `ApiError` | The API answered with an error. Has `status`, `code`, `message`, `details`, `request_id` |
176
+ | `AuthenticationError` | 401. The key is missing, wrong or switched off |
177
+ | `AccessDisabledError` | 403. API access is switched off for the partner |
178
+ | `NotFoundError` | 404. No such usage for this key |
179
+ | `ConflictError` | 409. For example `usage_limit_reached`, `already_applied`, `reference_used` |
180
+ | `InvalidRequestError` | 400 or 422. For example `offer_required`, `link_code_invalid` |
181
+ | `RateLimitError` | 429. Has `retry_after` in seconds |
182
+ | `ServerError` | 500 and above |
183
+
184
+ ```python
185
+ from onemax import ConflictError, OneMaxError
186
+
187
+ try:
188
+ client.confirm_usage(usage_id, reference=order.id)
189
+ except ConflictError as error:
190
+ if error.code == "usage_limit_reached":
191
+ charge_full_price(order)
192
+ else:
193
+ raise
194
+ except OneMaxError:
195
+ retry_later(order)
196
+ ```
197
+
198
+ `message` is in Azerbaijani and meant for your logs. Decide on `code`.
199
+
200
+ ## Limits
201
+
202
+ - The member's daily limit applies exactly as it does at a counter.
203
+ - 120 requests a minute per key.
204
+ - The library never retries by itself. `confirm_usage` with a `reference` is safe to retry.
205
+
206
+ ## Development
207
+
208
+ ```bash
209
+ uv sync
210
+ uv run ruff format --check .
211
+ uv run ruff check .
212
+ uv run mypy src
213
+ uv run pytest
214
+ ```
215
+
216
+ ## Releasing
217
+
218
+ Set the version in `src/onemax/_version.py`, add a `## x.y.z` section to `CHANGELOG.md`, commit, then push a tag
219
+ `vx.y.z`. The `Publish` workflow checks that the tag equals the package version, runs the checks,
220
+ publishes to PyPI and creates the GitHub release from the changelog section. A tag that does not match the
221
+ version publishes nothing.
222
+
223
+ ## License
224
+
225
+ MIT
onemax-0.1.0/README.md ADDED
@@ -0,0 +1,202 @@
1
+ # onemax
2
+
3
+ Python client for the [OneMax](https://onemax.az) partner API.
4
+
5
+ OneMax is a 1+1 membership club in Baku. Members pay for a plan and show a code at the counter to
6
+ use a partner's offer. This library lets a partner's own system do what the counter does: check
7
+ that someone is a member and record that they used the offer.
8
+
9
+ Sync and async, fully typed, one dependency.
10
+
11
+ ```bash
12
+ pip install onemax
13
+ ```
14
+
15
+ ## Getting a key
16
+
17
+ 1. OneMax switches API access on for your business.
18
+ 2. The owner opens the partner panel, goes to API and creates a key.
19
+ 3. The key is shown once. It belongs to one venue and acts there like a cashier.
20
+
21
+ Keep the key on your server. It must never reach a browser or a mobile app.
22
+
23
+ ## Quick start: a member's code
24
+
25
+ A member opens their OneMax card and reads you the six digit code.
26
+
27
+ ```python
28
+ from onemax import OneMaxClient
29
+
30
+ client = OneMaxClient("omx_live_...")
31
+
32
+ check = client.verify_code("482915")
33
+ if not check.usable:
34
+ print("No discount:", check.reason)
35
+ else:
36
+ order = place_order(discounted=True)
37
+ client.confirm_usage(check.usage_id, reference=order.id)
38
+ ```
39
+
40
+ `verify_code` only answers the question. Nothing counts against the member until you call
41
+ `confirm_usage`. If the order falls through, call `void_usage(check.usage_id)` instead.
42
+
43
+ Pass your own order id as `reference`. Confirming again with the same reference returns the same
44
+ usage, so a retried request is safe.
45
+
46
+ ## Account linking
47
+
48
+ A member links their OneMax account to your app once. After that you check them without a code.
49
+ Linking is the OAuth 2.0 authorization code flow with PKCE, so the same steps work for a website
50
+ and a mobile app.
51
+
52
+ Register the addresses your app may return to in the partner panel, under API, Account linking.
53
+ Your client id is shown there.
54
+
55
+ **1. Send the member to the permission page.**
56
+
57
+ ```python
58
+ from onemax import generate_pkce
59
+
60
+ pkce = generate_pkce()
61
+ session["onemax_verifier"] = pkce.verifier
62
+
63
+ url = client.authorize_url(
64
+ client_id="omx_client_...",
65
+ redirect_uri="https://example.az/onemax/return",
66
+ code_challenge=pkce.challenge,
67
+ state=session_id,
68
+ )
69
+ ```
70
+
71
+ In a mobile app, open `url` in the system browser and use your app link as the `redirect_uri`,
72
+ for example `taksi://onemax/return`.
73
+
74
+ **2. The member returns to your address** with `code` and `state`, or with `error=access_denied`
75
+ if they declined. Check that `state` is the one you sent.
76
+
77
+ **3. Exchange the code on your server and store the token.**
78
+
79
+ ```python
80
+ link = client.exchange_code(
81
+ code,
82
+ code_verifier=session["onemax_verifier"],
83
+ redirect_uri="https://example.az/onemax/return",
84
+ )
85
+ save(user_id, link.link_token)
86
+ ```
87
+
88
+ The code works once and for five minutes.
89
+
90
+ **4. Check the member whenever you need to.**
91
+
92
+ ```python
93
+ status = client.link_status(link_token)
94
+ if not status.linked:
95
+ forget(user_id)
96
+
97
+ check = client.verify_link(link_token)
98
+ if check.usable:
99
+ client.confirm_usage(check.usage_id, reference=order.id)
100
+ ```
101
+
102
+ A member can unlink at any time in their OneMax profile. From then on `link_status` answers
103
+ `linked=False` and `verify_link` answers `reason="not_linked"`. Neither raises.
104
+
105
+ You learn only whether the subscription is active. The member's name, email, phone and photo are
106
+ never shared.
107
+
108
+ ## Async
109
+
110
+ `AsyncOneMaxClient` has the same methods, awaited:
111
+
112
+ ```python
113
+ from onemax import AsyncOneMaxClient
114
+
115
+ async with AsyncOneMaxClient("omx_live_...") as client:
116
+ check = await client.verify_code("482915")
117
+ ```
118
+
119
+ ## Results
120
+
121
+ `verify_code` and `verify_link` return a `Verification`:
122
+
123
+ | Field | Meaning |
124
+ | --- | --- |
125
+ | `active` | The member has a subscription that works today |
126
+ | `usable` | They may use the offer right now |
127
+ | `reason` | Why, as a `Reason` |
128
+ | `usage_id` | Set when `usable` is true. Confirm it or void it |
129
+ | `daily_limit` | How many times a day a member may use this venue |
130
+
131
+ | `Reason` | Meaning |
132
+ | --- | --- |
133
+ | `OK` | Go ahead |
134
+ | `NOT_SUBSCRIBED` | No subscription, or it has ended |
135
+ | `LIMIT_REACHED` | The member already used today's allowance at this venue |
136
+ | `OFFER_UNAVAILABLE` | The venue or the offer is not open right now |
137
+ | `INVALID_CODE` | The code is wrong, expired or already used |
138
+ | `NOT_LINKED` | The link token no longer works |
139
+
140
+ `Reason` and `UsageStatus` are string enums, so `check.reason == "ok"` works as well. A value this
141
+ version does not know is returned as a plain string.
142
+
143
+ If a venue has several offers open, pass `offer_id`. `client.context()` lists them.
144
+
145
+ ## Errors
146
+
147
+ Everything the library raises is a `OneMaxError`.
148
+
149
+ | Class | When |
150
+ | --- | --- |
151
+ | `TransportError` | No usable answer: a connection failure, a timeout, or a body that is not JSON |
152
+ | `ApiError` | The API answered with an error. Has `status`, `code`, `message`, `details`, `request_id` |
153
+ | `AuthenticationError` | 401. The key is missing, wrong or switched off |
154
+ | `AccessDisabledError` | 403. API access is switched off for the partner |
155
+ | `NotFoundError` | 404. No such usage for this key |
156
+ | `ConflictError` | 409. For example `usage_limit_reached`, `already_applied`, `reference_used` |
157
+ | `InvalidRequestError` | 400 or 422. For example `offer_required`, `link_code_invalid` |
158
+ | `RateLimitError` | 429. Has `retry_after` in seconds |
159
+ | `ServerError` | 500 and above |
160
+
161
+ ```python
162
+ from onemax import ConflictError, OneMaxError
163
+
164
+ try:
165
+ client.confirm_usage(usage_id, reference=order.id)
166
+ except ConflictError as error:
167
+ if error.code == "usage_limit_reached":
168
+ charge_full_price(order)
169
+ else:
170
+ raise
171
+ except OneMaxError:
172
+ retry_later(order)
173
+ ```
174
+
175
+ `message` is in Azerbaijani and meant for your logs. Decide on `code`.
176
+
177
+ ## Limits
178
+
179
+ - The member's daily limit applies exactly as it does at a counter.
180
+ - 120 requests a minute per key.
181
+ - The library never retries by itself. `confirm_usage` with a `reference` is safe to retry.
182
+
183
+ ## Development
184
+
185
+ ```bash
186
+ uv sync
187
+ uv run ruff format --check .
188
+ uv run ruff check .
189
+ uv run mypy src
190
+ uv run pytest
191
+ ```
192
+
193
+ ## Releasing
194
+
195
+ Set the version in `src/onemax/_version.py`, add a `## x.y.z` section to `CHANGELOG.md`, commit, then push a tag
196
+ `vx.y.z`. The `Publish` workflow checks that the tag equals the package version, runs the checks,
197
+ publishes to PyPI and creates the GitHub release from the changelog section. A tag that does not match the
198
+ version publishes nothing.
199
+
200
+ ## License
201
+
202
+ MIT
@@ -0,0 +1,61 @@
1
+ [project]
2
+ name = "onemax"
3
+ dynamic = ["version"]
4
+ description = "Python client for the OneMax partner API"
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ license = "MIT"
8
+ authors = [{ name = "OneMax" }]
9
+ keywords = ["onemax", "membership", "partner", "api", "azerbaijan"]
10
+ classifiers = [
11
+ "Development Status :: 4 - Beta",
12
+ "Intended Audience :: Developers",
13
+ "License :: OSI Approved :: MIT License",
14
+ "Programming Language :: Python :: 3.10",
15
+ "Programming Language :: Python :: 3.11",
16
+ "Programming Language :: Python :: 3.12",
17
+ "Programming Language :: Python :: 3.13",
18
+ "Typing :: Typed",
19
+ ]
20
+ dependencies = ["httpx>=0.27"]
21
+
22
+ [project.urls]
23
+ Homepage = "https://onemax.az"
24
+ Repository = "https://github.com/onemax-az/onemax-python"
25
+ Changelog = "https://github.com/onemax-az/onemax-python/blob/main/CHANGELOG.md"
26
+
27
+ [dependency-groups]
28
+ dev = [
29
+ "pytest>=8.4.2",
30
+ "pytest-asyncio>=1.0",
31
+ "pytest-cov>=7.0.0",
32
+ "ruff>=0.15.0",
33
+ "mypy>=1.19.0",
34
+ ]
35
+
36
+ [build-system]
37
+ requires = ["hatchling"]
38
+ build-backend = "hatchling.build"
39
+
40
+ [tool.hatch.version]
41
+ path = "src/onemax/_version.py"
42
+
43
+ [tool.hatch.build.targets.wheel]
44
+ packages = ["src/onemax"]
45
+
46
+ [tool.ruff]
47
+ line-length = 100
48
+ target-version = "py310"
49
+ src = ["src", "tests"]
50
+
51
+ [tool.ruff.lint]
52
+ select = ["E", "W", "F", "I", "N", "UP", "B", "A", "C4", "SIM", "RUF", "PT", "TID"]
53
+
54
+ [tool.mypy]
55
+ python_version = "3.10"
56
+ strict = true
57
+ files = ["src"]
58
+
59
+ [tool.pytest.ini_options]
60
+ testpaths = ["tests"]
61
+ asyncio_mode = "auto"
@@ -0,0 +1,44 @@
1
+ from ._version import __version__
2
+ from .aio import AsyncOneMaxClient
3
+ from .client import OneMaxClient
4
+ from .errors import (
5
+ AccessDisabledError,
6
+ ApiError,
7
+ AuthenticationError,
8
+ ConflictError,
9
+ InvalidRequestError,
10
+ NotFoundError,
11
+ OneMaxError,
12
+ RateLimitError,
13
+ ServerError,
14
+ TransportError,
15
+ )
16
+ from .models import Context, LinkStatus, LinkToken, Offer, Reason, Usage, UsageStatus, Verification
17
+ from .pkce import Pkce, challenge_for, generate_pkce
18
+
19
+ __all__ = [
20
+ "AccessDisabledError",
21
+ "ApiError",
22
+ "AsyncOneMaxClient",
23
+ "AuthenticationError",
24
+ "ConflictError",
25
+ "Context",
26
+ "InvalidRequestError",
27
+ "LinkStatus",
28
+ "LinkToken",
29
+ "NotFoundError",
30
+ "Offer",
31
+ "OneMaxClient",
32
+ "OneMaxError",
33
+ "Pkce",
34
+ "RateLimitError",
35
+ "Reason",
36
+ "ServerError",
37
+ "TransportError",
38
+ "Usage",
39
+ "UsageStatus",
40
+ "Verification",
41
+ "__version__",
42
+ "challenge_for",
43
+ "generate_pkce",
44
+ ]