appliku 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.
Files changed (53) hide show
  1. appliku-0.1.0/.gitignore +36 -0
  2. appliku-0.1.0/CLAUDE.md +117 -0
  3. appliku-0.1.0/LICENSE +21 -0
  4. appliku-0.1.0/PKG-INFO +277 -0
  5. appliku-0.1.0/README.md +241 -0
  6. appliku-0.1.0/pyproject.toml +64 -0
  7. appliku-0.1.0/spec.md +11 -0
  8. appliku-0.1.0/src/appliku/__init__.py +108 -0
  9. appliku-0.1.0/src/appliku/_auth.py +167 -0
  10. appliku-0.1.0/src/appliku/_client.py +142 -0
  11. appliku-0.1.0/src/appliku/_exceptions.py +84 -0
  12. appliku-0.1.0/src/appliku/_main.py +122 -0
  13. appliku-0.1.0/src/appliku/_models.py +356 -0
  14. appliku-0.1.0/src/appliku/cli/__init__.py +93 -0
  15. appliku-0.1.0/src/appliku/cli/apps.py +217 -0
  16. appliku-0.1.0/src/appliku/cli/auth.py +126 -0
  17. appliku-0.1.0/src/appliku/cli/clusters.py +89 -0
  18. appliku-0.1.0/src/appliku/cli/cron_jobs.py +90 -0
  19. appliku-0.1.0/src/appliku/cli/datastores.py +117 -0
  20. appliku-0.1.0/src/appliku/cli/deployments.py +83 -0
  21. appliku-0.1.0/src/appliku/cli/domains.py +53 -0
  22. appliku-0.1.0/src/appliku/cli/invites.py +85 -0
  23. appliku-0.1.0/src/appliku/cli/migrations.py +52 -0
  24. appliku-0.1.0/src/appliku/cli/servers.py +182 -0
  25. appliku-0.1.0/src/appliku/cli/teams.py +78 -0
  26. appliku-0.1.0/src/appliku/cli/volumes.py +82 -0
  27. appliku-0.1.0/src/appliku/resources/__init__.py +0 -0
  28. appliku-0.1.0/src/appliku/resources/apps.py +166 -0
  29. appliku-0.1.0/src/appliku/resources/clusters.py +56 -0
  30. appliku-0.1.0/src/appliku/resources/cron_jobs.py +51 -0
  31. appliku-0.1.0/src/appliku/resources/datastores.py +62 -0
  32. appliku-0.1.0/src/appliku/resources/deployments.py +84 -0
  33. appliku-0.1.0/src/appliku/resources/domains.py +42 -0
  34. appliku-0.1.0/src/appliku/resources/invites.py +46 -0
  35. appliku-0.1.0/src/appliku/resources/migrations.py +45 -0
  36. appliku-0.1.0/src/appliku/resources/servers.py +59 -0
  37. appliku-0.1.0/src/appliku/resources/teams.py +41 -0
  38. appliku-0.1.0/src/appliku/resources/volumes.py +53 -0
  39. appliku-0.1.0/tests/conftest.py +45 -0
  40. appliku-0.1.0/tests/test_apps.py +197 -0
  41. appliku-0.1.0/tests/test_auth.py +76 -0
  42. appliku-0.1.0/tests/test_client.py +169 -0
  43. appliku-0.1.0/tests/test_clusters.py +74 -0
  44. appliku-0.1.0/tests/test_cron_jobs.py +67 -0
  45. appliku-0.1.0/tests/test_datastores.py +99 -0
  46. appliku-0.1.0/tests/test_deployments.py +106 -0
  47. appliku-0.1.0/tests/test_domains.py +45 -0
  48. appliku-0.1.0/tests/test_invites.py +64 -0
  49. appliku-0.1.0/tests/test_migrations.py +70 -0
  50. appliku-0.1.0/tests/test_servers.py +76 -0
  51. appliku-0.1.0/tests/test_teams.py +71 -0
  52. appliku-0.1.0/tests/test_volumes.py +59 -0
  53. appliku-0.1.0/uv.lock +657 -0
@@ -0,0 +1,36 @@
1
+ # Byte-compiled / optimized
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Distribution / packaging
7
+ dist/
8
+ build/
9
+ *.egg-info/
10
+
11
+ # Virtual environments
12
+ .venv/
13
+ venv/
14
+
15
+ # Environment variables
16
+ .env
17
+ .env.*
18
+
19
+ # IDE
20
+ .idea/
21
+ .vscode/
22
+ *.swp
23
+ *.swo
24
+
25
+ # OS
26
+ .DS_Store
27
+ Thumbs.db
28
+
29
+ # Test artifacts
30
+ .pytest_cache/
31
+ htmlcov/
32
+ .coverage
33
+ coverage.xml
34
+
35
+ # Type checking
36
+ .mypy_cache/
@@ -0,0 +1,117 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ `appliku-cli` is a Python CLI and SDK for the [Appliku](https://api.appliku.com) platform. It wraps the Appliku OpenAPI spec (`https://api.appliku.com/api/schema/`) and is published to PyPI. The project uses **UV** for all Python environment and dependency management.
8
+
9
+ ## Environment & Tooling
10
+
11
+ - **Python package manager**: UV exclusively. Never use `pip install` directly. Use `uv add` for dependencies, `uv run` to execute commands within the project environment.
12
+ - **Project config**: `pyproject.toml` is the single source of truth for metadata, dependencies, scripts, and tool configuration.
13
+ - **Build backend**: `hatchling` as specified in `pyproject.toml`.
14
+
15
+ ## Common Commands
16
+
17
+ ```bash
18
+ # Create/sync the environment
19
+ uv sync
20
+
21
+ # Run the CLI
22
+ uv run appliku --help
23
+
24
+ # Run tests
25
+ uv run pytest
26
+
27
+ # Run a single test file or test by keyword
28
+ uv run pytest tests/test_apps.py
29
+ uv run pytest -k "test_create_app"
30
+
31
+ # Lint and format (assuming ruff is configured)
32
+ uv run ruff check .
33
+ uv run ruff format .
34
+
35
+ # Type check (if mypy is configured)
36
+ uv run mypy src/
37
+
38
+ # Build the package for PyPI
39
+ uv build
40
+
41
+ # Publish to PyPI (dry run first)
42
+ uv publish --dry-run
43
+ uv publish
44
+ ```
45
+
46
+ ## Architecture & Code Organization
47
+
48
+ The project follows a **src layout**:
49
+
50
+ ```
51
+ src/appliku/
52
+ ├── __init__.py # Public SDK exports (Appliku class + all models + exceptions)
53
+ ├── _main.py # Appliku class — SDK entry point with lazy resource properties
54
+ ├── _client.py # AplikuClient — HTTP client with retry, pagination, error handling
55
+ ├── _auth.py # Token resolution (env/config/param) + login flow + config persistence
56
+ ├── _exceptions.py # Exception hierarchy: AplikuError → typed subclasses
57
+ ├── _models.py # All Pydantic v2 models (PaginatedResponse, Team, App, Deployment, etc.)
58
+ ├── resources/ # Resource classes — one per API domain
59
+ │ ├── teams.py # TeamsResource: list, get, create, update, delete
60
+ │ ├── apps.py # AppsResource: list, get, create, update, delete, deploy, config vars
61
+ │ ├── deployments.py # DeploymentsResource: list, get, latest, logs, stream_logs
62
+ │ ├── datastores.py # DatastoresResource: list, get, create, delete, start, stop, restart
63
+ │ ├── domains.py # DomainsResource: list, get, create, delete
64
+ │ ├── volumes.py # VolumesResource: list, get, create, update, delete
65
+ │ ├── cron_jobs.py # CronJobsResource: list, get, create, update, delete
66
+ │ ├── clusters.py # ClustersResource: list, get, create, delete
67
+ │ ├── servers.py # ServersResource: list, get, create_digitalocean, create_ec2, create_custom
68
+ │ ├── invites.py # InvitesResource: list, create, delete, accept, decline
69
+ │ └── migrations.py # MigrationsResource: list, get, run, logs
70
+ └── cli/ # Typer CLI layer
71
+ ├── __init__.py # Root Typer app + shared helpers (get_client, render_output, render_table)
72
+ ├── auth.py # Root commands: login, logout, whoami
73
+ ├── teams.py # teams sub-app
74
+ ├── apps.py # apps sub-app (list, get, create, update, delete, deploy, config, set-config)
75
+ ├── deployments.py # deployments sub-app (list, latest, logs --stream)
76
+ ├── datastores.py # datastores sub-app (list, create, delete, start, stop, restart)
77
+ ├── domains.py # domains sub-app (list, create, delete)
78
+ ├── volumes.py # volumes sub-app (list, create, update, delete)
79
+ ├── cron_jobs.py # crons sub-app (list, create, update, delete)
80
+ ├── clusters.py # clusters sub-app (list, create, delete)
81
+ ├── servers.py # servers sub-app (list, create-do, create-ec2, create-custom)
82
+ ├── invites.py # invites sub-app (list, create, delete, accept, decline)
83
+ └── migrations.py # migrations sub-app (list, run, logs)
84
+ ```
85
+
86
+ ### Key Architectural Decisions
87
+
88
+ 1. **API surface is driven by the OpenAPI spec at `https://api.appliku.com/api/schema/`**. The resource model maps to:
89
+ - **Auth**: Token + JWT authentication, API key management
90
+ - **Teams**: Team CRUD, member invitations, cloud credential storage (AWS, DigitalOcean)
91
+ - **Apps**: Application lifecycle — deploy, scale processes, manage domains/SSL, config vars
92
+ - **Infrastructure**: Clusters, build servers, EC2/DigitalOcean instance provisioning
93
+ - **Data Services**: Datastores (databases), backups, volumes, replica promotion
94
+ - **Monitoring**: Logs (app, nginx, deployment, DB migration), stats/metrics
95
+ - **Integrations**: GitHub/GitLab repos, cron jobs, webhooks, one-off commands
96
+
97
+ 2. **CLI commands mirror SDK client methods.** Each top-level resource maps to a Typer sub-app. The SDK client is usable independently of the CLI.
98
+
99
+ 3. **Authentication flow**: Token resolution priority: explicit param → `APPLIKU_TOKEN` env → `~/.config/appliku/config.toml`. Login does a two-step flow: POST `/api/sign_up/` for JWT, then POST `/api/obtain_user_api_key/` for persistent API key.
100
+
101
+ 4. **Output formatting**: CLI commands default to Rich tables. All list commands support `--output json` for scripting.
102
+
103
+ 5. **Error handling**: Typed exception hierarchy with auto-retry on 429 (respect Retry-After) and 5xx (exponential backoff, up to 3 attempts).
104
+
105
+ 6. **Pagination**: `AplikuClient.paginate()` for single page, `paginate_all()` for auto-following next links.
106
+
107
+ ## OpenAPI Schema
108
+
109
+ The canonical schema is at `https://api.appliku.com/api/schema/`. When adding new endpoints or updating models, fetch the latest schema to verify field names and types.
110
+
111
+ ## Testing
112
+
113
+ - Tests live in `tests/` and use **pytest**.
114
+ - `conftest.py` provides `mock_client` fixture using `httpx.MockTransport` — no network calls.
115
+ - Push `httpx.Response` objects onto the responses list to define mock behavior.
116
+ - `paginated_response` fixture factory wraps results in standard pagination envelope.
117
+ - Integration/e2e tests (if any) should be gated behind `@pytest.mark.integration`.
appliku-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Appliku
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.
appliku-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,277 @@
1
+ Metadata-Version: 2.4
2
+ Name: appliku
3
+ Version: 0.1.0
4
+ Summary: Python CLI and SDK for Appliku
5
+ Project-URL: Homepage, https://github.com/appliku/appliku-cli
6
+ Project-URL: Documentation, https://github.com/appliku/appliku-cli#readme
7
+ Project-URL: Issues, https://github.com/appliku/appliku-cli/issues
8
+ Author-email: Appliku <dev@appliku.com>
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: appliku,cli,deployment,paas,sdk
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Internet
22
+ Requires-Python: >=3.10
23
+ Requires-Dist: httpx>=0.27.0
24
+ Requires-Dist: pydantic>=2.6.0
25
+ Requires-Dist: rich>=13.7.0
26
+ Requires-Dist: tomli-w>=1.0.0
27
+ Requires-Dist: tomli>=2.0.0; python_version < '3.11'
28
+ Requires-Dist: typer>=0.12.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: httpx>=0.27.0; extra == 'dev'
31
+ Requires-Dist: mypy>=1.8.0; extra == 'dev'
32
+ Requires-Dist: pytest-httpx>=0.30.0; extra == 'dev'
33
+ Requires-Dist: pytest>=8.0.0; extra == 'dev'
34
+ Requires-Dist: ruff>=0.3.0; extra == 'dev'
35
+ Description-Content-Type: text/markdown
36
+
37
+ # appliku
38
+
39
+ [![PyPI version](https://badge.fury.io/py/appliku.svg)](https://pypi.org/project/appliku/)
40
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
41
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/downloads/)
42
+
43
+ Python CLI and SDK for the [Appliku](https://appliku.com) cloud deployment platform.
44
+
45
+ Appliku is a PaaS that lets you deploy applications, manage infrastructure, and scale services — all from a single unified interface. This package provides both a programmatic Python SDK and a fully-featured command-line interface.
46
+
47
+ ## Installation
48
+
49
+ ```bash
50
+ pip install appliku
51
+ ```
52
+
53
+ UV users:
54
+
55
+ ```bash
56
+ uv add appliku
57
+ ```
58
+
59
+ ## Quick Start (SDK)
60
+
61
+ ```python
62
+ from appliku import Appliku
63
+
64
+ client = Appliku(token="your-api-token")
65
+
66
+ # List apps in a team
67
+ apps = client.apps.list("my-team")
68
+ for app in apps.results:
69
+ print(f"{app.name} — {app.status}")
70
+
71
+ # Trigger a deployment
72
+ deployment = client.apps.deploy("my-team", app_id=42)
73
+ print(f"Deployment {deployment.id} is {deployment.status}")
74
+ ```
75
+
76
+ ## Authentication
77
+
78
+ There are three ways to authenticate:
79
+
80
+ 1. **Constructor parameter**: `Appliku(token="tok_...")`
81
+ 2. **Environment variable**: `export APPLIKU_TOKEN=tok_...`
82
+ 3. **CLI login** (saves token to `~/.config/appliku/config.toml`):
83
+ ```bash
84
+ appliku login --email you@example.com --password secret
85
+ ```
86
+
87
+ The SDK checks these sources in order: explicit token → `APPLIKU_TOKEN` env var → config file.
88
+
89
+ ## SDK Usage
90
+
91
+ ### Teams
92
+
93
+ ```python
94
+ # List teams
95
+ teams = client.teams.list()
96
+
97
+ # Create a team
98
+ team = client.teams.create("my-team-slug", "My Team")
99
+
100
+ # Update and delete
101
+ client.teams.update("my-team-slug", name="Renamed Team")
102
+ client.teams.delete("my-team-slug")
103
+ ```
104
+
105
+ ### Apps
106
+
107
+ ```python
108
+ # List apps
109
+ apps = client.apps.list("my-team")
110
+
111
+ # Create an app
112
+ app = client.apps.create(
113
+ "my-team",
114
+ name="web-app",
115
+ branch="main",
116
+ git_url="https://github.com/user/repo.git",
117
+ build_pack="dockerfile",
118
+ )
119
+
120
+ # Deploy
121
+ deployment = client.apps.deploy("my-team", app.id)
122
+
123
+ # Config vars
124
+ vars = client.apps.get_config_vars("my-team", app.id)
125
+ client.apps.set_config_vars("my-team", app.id, {"DATABASE_URL": "postgres://...", "DEBUG": "false"})
126
+ ```
127
+
128
+ ### Deployments
129
+
130
+ ```python
131
+ # List deployments
132
+ deployments = client.deployments.list("my-team", app_id=42)
133
+
134
+ # Get latest
135
+ latest = client.deployments.latest("my-team", app_id=42)
136
+
137
+ # Stream logs in real-time
138
+ for log in client.deployments.stream_logs("my-team", app_id=42, deployment_id=latest.id):
139
+ print(f"[{log.timestamp}] {log.message}")
140
+ ```
141
+
142
+ ### Datastores
143
+
144
+ ```python
145
+ # Create a database
146
+ db = client.datastores.create("my-team", app_id=42, name="primary-db", engine="postgres", version="15")
147
+
148
+ # Lifecycle management
149
+ client.datastores.stop("my-team", 42, db.id)
150
+ client.datastores.start("my-team", 42, db.id)
151
+ client.datastores.restart("my-team", 42, db.id)
152
+ ```
153
+
154
+ ### Domains & Volumes
155
+
156
+ ```python
157
+ # Domains
158
+ domain = client.domains.create("my-team", app_id=42, domain="app.example.com")
159
+ client.domains.delete("my-team", 42, domain.id)
160
+
161
+ # Volumes
162
+ vol = client.volumes.create("my-team", app_id=42, name="data", container_path="/data")
163
+ client.volumes.update("my-team", 42, vol.id, name="user-data")
164
+ ```
165
+
166
+ ### Cron Jobs
167
+
168
+ ```python
169
+ cron = client.cron_jobs.create(
170
+ "my-team", app_id=42,
171
+ name="cleanup", schedule="0 2 * * *", command="python manage.py cleanup"
172
+ )
173
+ client.cron_jobs.update("my-team", 42, cron.id, is_disabled=True)
174
+ ```
175
+
176
+ ### Clusters & Servers
177
+
178
+ ```python
179
+ # Create a cluster
180
+ cluster = client.clusters.create("my-team", name="production")
181
+
182
+ # Provision servers
183
+ do_server = client.servers.create_digitalocean("my-team", name="web-1", region="nyc1", size="s-2vcpu-2gb")
184
+ ec2_server = client.servers.create_ec2("my-team", name="worker-1", region="us-east-1", instance_type="t3.large")
185
+ custom_server = client.servers.create_custom("my-team", name="bare-metal", host="203.0.113.1")
186
+ ```
187
+
188
+ ## CLI Usage
189
+
190
+ ### Authentication
191
+
192
+ ```bash
193
+ appliku login --email you@example.com --password secret
194
+ appliku whoami
195
+ appliku logout
196
+ ```
197
+
198
+ ### Apps
199
+
200
+ ```bash
201
+ appliku apps list --team my-team
202
+ appliku apps create --team my-team --name web-app --branch main --git-url https://github.com/user/repo.git
203
+ appliku apps deploy --team my-team --app 42
204
+ appliku apps config --team my-team --app 42
205
+ appliku apps set-config --team my-team --app 42 --var FOO=bar --var BAZ=qux
206
+ ```
207
+
208
+ ### Deployments
209
+
210
+ ```bash
211
+ appliku deployments list --team my-team --app 42
212
+ appliku deployments latest --team my-team --app 42
213
+ appliku deployments logs --team my-team --app 42 --deployment 7 --stream
214
+ ```
215
+
216
+ ### Datastores
217
+
218
+ ```bash
219
+ appliku datastores create --team my-team --app 42 --name primary-db --engine postgres --version 15
220
+ appliku datastores start --team my-team --app 42 1
221
+ appliku datastores stop --team my-team --app 42 1
222
+ ```
223
+
224
+ ### All commands support `--output json` for scripting:
225
+
226
+ ```bash
227
+ appliku apps list --team my-team --output json
228
+ ```
229
+
230
+ ## CLI Reference
231
+
232
+ | Command Group | Subcommands |
233
+ |-----------------|--------------------------------------------------|
234
+ | *(root)* | `login`, `logout`, `whoami` |
235
+ | `teams` | `list`, `get`, `create`, `update`, `delete` |
236
+ | `apps` | `list`, `get`, `create`, `update`, `delete`, `deploy`, `config`, `set-config` |
237
+ | `deployments` | `list`, `latest`, `logs` |
238
+ | `datastores` | `list`, `create`, `delete`, `start`, `stop`, `restart` |
239
+ | `domains` | `list`, `create`, `delete` |
240
+ | `volumes` | `list`, `create`, `update`, `delete` |
241
+ | `crons` | `list`, `create`, `update`, `delete` |
242
+ | `clusters` | `list`, `create`, `delete` |
243
+ | `servers` | `list`, `create-do`, `create-ec2`, `create-custom` |
244
+ | `invites` | `list`, `create`, `delete`, `accept`, `decline` |
245
+ | `migrations` | `list`, `run`, `logs` |
246
+
247
+ ## Error Handling
248
+
249
+ The SDK raises typed exceptions so you can handle specific failure modes:
250
+
251
+ ```python
252
+ from appliku import Appliku, NotFoundError, AuthenticationError, RateLimitError
253
+
254
+ client = Appliku()
255
+
256
+ try:
257
+ app = client.apps.get("my-team", app_id=999)
258
+ except NotFoundError as e:
259
+ print(f"App not found: {e}")
260
+ except AuthenticationError:
261
+ print("Invalid or expired token")
262
+ except RateLimitError:
263
+ print("Too many requests — retried automatically")
264
+ ```
265
+
266
+ Exception hierarchy:
267
+ - `AplikuError` (base)
268
+ - `AuthenticationError` — 401
269
+ - `AuthorizationError` — 403
270
+ - `NotFoundError` — 404
271
+ - `ValidationError` — 400 (field-level errors)
272
+ - `RateLimitError` — 429 (auto-retried)
273
+ - `ServerError` — 5xx (auto-retried with backoff)
274
+
275
+ ## License
276
+
277
+ MIT
@@ -0,0 +1,241 @@
1
+ # appliku
2
+
3
+ [![PyPI version](https://badge.fury.io/py/appliku.svg)](https://pypi.org/project/appliku/)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/downloads/)
6
+
7
+ Python CLI and SDK for the [Appliku](https://appliku.com) cloud deployment platform.
8
+
9
+ Appliku is a PaaS that lets you deploy applications, manage infrastructure, and scale services — all from a single unified interface. This package provides both a programmatic Python SDK and a fully-featured command-line interface.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ pip install appliku
15
+ ```
16
+
17
+ UV users:
18
+
19
+ ```bash
20
+ uv add appliku
21
+ ```
22
+
23
+ ## Quick Start (SDK)
24
+
25
+ ```python
26
+ from appliku import Appliku
27
+
28
+ client = Appliku(token="your-api-token")
29
+
30
+ # List apps in a team
31
+ apps = client.apps.list("my-team")
32
+ for app in apps.results:
33
+ print(f"{app.name} — {app.status}")
34
+
35
+ # Trigger a deployment
36
+ deployment = client.apps.deploy("my-team", app_id=42)
37
+ print(f"Deployment {deployment.id} is {deployment.status}")
38
+ ```
39
+
40
+ ## Authentication
41
+
42
+ There are three ways to authenticate:
43
+
44
+ 1. **Constructor parameter**: `Appliku(token="tok_...")`
45
+ 2. **Environment variable**: `export APPLIKU_TOKEN=tok_...`
46
+ 3. **CLI login** (saves token to `~/.config/appliku/config.toml`):
47
+ ```bash
48
+ appliku login --email you@example.com --password secret
49
+ ```
50
+
51
+ The SDK checks these sources in order: explicit token → `APPLIKU_TOKEN` env var → config file.
52
+
53
+ ## SDK Usage
54
+
55
+ ### Teams
56
+
57
+ ```python
58
+ # List teams
59
+ teams = client.teams.list()
60
+
61
+ # Create a team
62
+ team = client.teams.create("my-team-slug", "My Team")
63
+
64
+ # Update and delete
65
+ client.teams.update("my-team-slug", name="Renamed Team")
66
+ client.teams.delete("my-team-slug")
67
+ ```
68
+
69
+ ### Apps
70
+
71
+ ```python
72
+ # List apps
73
+ apps = client.apps.list("my-team")
74
+
75
+ # Create an app
76
+ app = client.apps.create(
77
+ "my-team",
78
+ name="web-app",
79
+ branch="main",
80
+ git_url="https://github.com/user/repo.git",
81
+ build_pack="dockerfile",
82
+ )
83
+
84
+ # Deploy
85
+ deployment = client.apps.deploy("my-team", app.id)
86
+
87
+ # Config vars
88
+ vars = client.apps.get_config_vars("my-team", app.id)
89
+ client.apps.set_config_vars("my-team", app.id, {"DATABASE_URL": "postgres://...", "DEBUG": "false"})
90
+ ```
91
+
92
+ ### Deployments
93
+
94
+ ```python
95
+ # List deployments
96
+ deployments = client.deployments.list("my-team", app_id=42)
97
+
98
+ # Get latest
99
+ latest = client.deployments.latest("my-team", app_id=42)
100
+
101
+ # Stream logs in real-time
102
+ for log in client.deployments.stream_logs("my-team", app_id=42, deployment_id=latest.id):
103
+ print(f"[{log.timestamp}] {log.message}")
104
+ ```
105
+
106
+ ### Datastores
107
+
108
+ ```python
109
+ # Create a database
110
+ db = client.datastores.create("my-team", app_id=42, name="primary-db", engine="postgres", version="15")
111
+
112
+ # Lifecycle management
113
+ client.datastores.stop("my-team", 42, db.id)
114
+ client.datastores.start("my-team", 42, db.id)
115
+ client.datastores.restart("my-team", 42, db.id)
116
+ ```
117
+
118
+ ### Domains & Volumes
119
+
120
+ ```python
121
+ # Domains
122
+ domain = client.domains.create("my-team", app_id=42, domain="app.example.com")
123
+ client.domains.delete("my-team", 42, domain.id)
124
+
125
+ # Volumes
126
+ vol = client.volumes.create("my-team", app_id=42, name="data", container_path="/data")
127
+ client.volumes.update("my-team", 42, vol.id, name="user-data")
128
+ ```
129
+
130
+ ### Cron Jobs
131
+
132
+ ```python
133
+ cron = client.cron_jobs.create(
134
+ "my-team", app_id=42,
135
+ name="cleanup", schedule="0 2 * * *", command="python manage.py cleanup"
136
+ )
137
+ client.cron_jobs.update("my-team", 42, cron.id, is_disabled=True)
138
+ ```
139
+
140
+ ### Clusters & Servers
141
+
142
+ ```python
143
+ # Create a cluster
144
+ cluster = client.clusters.create("my-team", name="production")
145
+
146
+ # Provision servers
147
+ do_server = client.servers.create_digitalocean("my-team", name="web-1", region="nyc1", size="s-2vcpu-2gb")
148
+ ec2_server = client.servers.create_ec2("my-team", name="worker-1", region="us-east-1", instance_type="t3.large")
149
+ custom_server = client.servers.create_custom("my-team", name="bare-metal", host="203.0.113.1")
150
+ ```
151
+
152
+ ## CLI Usage
153
+
154
+ ### Authentication
155
+
156
+ ```bash
157
+ appliku login --email you@example.com --password secret
158
+ appliku whoami
159
+ appliku logout
160
+ ```
161
+
162
+ ### Apps
163
+
164
+ ```bash
165
+ appliku apps list --team my-team
166
+ appliku apps create --team my-team --name web-app --branch main --git-url https://github.com/user/repo.git
167
+ appliku apps deploy --team my-team --app 42
168
+ appliku apps config --team my-team --app 42
169
+ appliku apps set-config --team my-team --app 42 --var FOO=bar --var BAZ=qux
170
+ ```
171
+
172
+ ### Deployments
173
+
174
+ ```bash
175
+ appliku deployments list --team my-team --app 42
176
+ appliku deployments latest --team my-team --app 42
177
+ appliku deployments logs --team my-team --app 42 --deployment 7 --stream
178
+ ```
179
+
180
+ ### Datastores
181
+
182
+ ```bash
183
+ appliku datastores create --team my-team --app 42 --name primary-db --engine postgres --version 15
184
+ appliku datastores start --team my-team --app 42 1
185
+ appliku datastores stop --team my-team --app 42 1
186
+ ```
187
+
188
+ ### All commands support `--output json` for scripting:
189
+
190
+ ```bash
191
+ appliku apps list --team my-team --output json
192
+ ```
193
+
194
+ ## CLI Reference
195
+
196
+ | Command Group | Subcommands |
197
+ |-----------------|--------------------------------------------------|
198
+ | *(root)* | `login`, `logout`, `whoami` |
199
+ | `teams` | `list`, `get`, `create`, `update`, `delete` |
200
+ | `apps` | `list`, `get`, `create`, `update`, `delete`, `deploy`, `config`, `set-config` |
201
+ | `deployments` | `list`, `latest`, `logs` |
202
+ | `datastores` | `list`, `create`, `delete`, `start`, `stop`, `restart` |
203
+ | `domains` | `list`, `create`, `delete` |
204
+ | `volumes` | `list`, `create`, `update`, `delete` |
205
+ | `crons` | `list`, `create`, `update`, `delete` |
206
+ | `clusters` | `list`, `create`, `delete` |
207
+ | `servers` | `list`, `create-do`, `create-ec2`, `create-custom` |
208
+ | `invites` | `list`, `create`, `delete`, `accept`, `decline` |
209
+ | `migrations` | `list`, `run`, `logs` |
210
+
211
+ ## Error Handling
212
+
213
+ The SDK raises typed exceptions so you can handle specific failure modes:
214
+
215
+ ```python
216
+ from appliku import Appliku, NotFoundError, AuthenticationError, RateLimitError
217
+
218
+ client = Appliku()
219
+
220
+ try:
221
+ app = client.apps.get("my-team", app_id=999)
222
+ except NotFoundError as e:
223
+ print(f"App not found: {e}")
224
+ except AuthenticationError:
225
+ print("Invalid or expired token")
226
+ except RateLimitError:
227
+ print("Too many requests — retried automatically")
228
+ ```
229
+
230
+ Exception hierarchy:
231
+ - `AplikuError` (base)
232
+ - `AuthenticationError` — 401
233
+ - `AuthorizationError` — 403
234
+ - `NotFoundError` — 404
235
+ - `ValidationError` — 400 (field-level errors)
236
+ - `RateLimitError` — 429 (auto-retried)
237
+ - `ServerError` — 5xx (auto-retried with backoff)
238
+
239
+ ## License
240
+
241
+ MIT