adapt-server 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.
- adapt_server-0.1.0/LICENSE +21 -0
- adapt_server-0.1.0/PKG-INFO +576 -0
- adapt_server-0.1.0/README.md +534 -0
- adapt_server-0.1.0/adapt/__init__.py +3 -0
- adapt_server-0.1.0/adapt/__main__.py +5 -0
- adapt_server-0.1.0/adapt/admin/__init__.py +10 -0
- adapt_server-0.1.0/adapt/admin/api_keys.py +123 -0
- adapt_server-0.1.0/adapt/admin/audit_logs.py +66 -0
- adapt_server-0.1.0/adapt/admin/cache.py +78 -0
- adapt_server-0.1.0/adapt/admin/groups.py +170 -0
- adapt_server-0.1.0/adapt/admin/locks.py +82 -0
- adapt_server-0.1.0/adapt/admin/models.py +37 -0
- adapt_server-0.1.0/adapt/admin/permissions.py +169 -0
- adapt_server-0.1.0/adapt/admin/resources.py +25 -0
- adapt_server-0.1.0/adapt/admin/ui.py +32 -0
- adapt_server-0.1.0/adapt/admin/users.py +114 -0
- adapt_server-0.1.0/adapt/api_keys.py +82 -0
- adapt_server-0.1.0/adapt/app.py +256 -0
- adapt_server-0.1.0/adapt/audit.py +49 -0
- adapt_server-0.1.0/adapt/auth/__init__.py +15 -0
- adapt_server-0.1.0/adapt/auth/dependencies.py +109 -0
- adapt_server-0.1.0/adapt/auth/password.py +24 -0
- adapt_server-0.1.0/adapt/auth/routes.py +198 -0
- adapt_server-0.1.0/adapt/auth/session.py +53 -0
- adapt_server-0.1.0/adapt/cache.py +152 -0
- adapt_server-0.1.0/adapt/cli.py +124 -0
- adapt_server-0.1.0/adapt/commands/__init__.py +1 -0
- adapt_server-0.1.0/adapt/commands/addsuperuser.py +46 -0
- adapt_server-0.1.0/adapt/commands/admin/__init__.py +73 -0
- adapt_server-0.1.0/adapt/commands/admin/add_to_group.py +42 -0
- adapt_server-0.1.0/adapt/commands/admin/create_group.py +29 -0
- adapt_server-0.1.0/adapt/commands/admin/create_permissions.py +167 -0
- adapt_server-0.1.0/adapt/commands/admin/create_user.py +40 -0
- adapt_server-0.1.0/adapt/commands/admin/delete_group.py +28 -0
- adapt_server-0.1.0/adapt/commands/admin/delete_user.py +28 -0
- adapt_server-0.1.0/adapt/commands/admin/list_groups.py +57 -0
- adapt_server-0.1.0/adapt/commands/admin/list_resources.py +20 -0
- adapt_server-0.1.0/adapt/commands/admin/list_users.py +32 -0
- adapt_server-0.1.0/adapt/commands/admin/remove_from_group.py +42 -0
- adapt_server-0.1.0/adapt/commands/check.py +41 -0
- adapt_server-0.1.0/adapt/commands/list_endpoints.py +37 -0
- adapt_server-0.1.0/adapt/commands/serve.py +78 -0
- adapt_server-0.1.0/adapt/config.py +230 -0
- adapt_server-0.1.0/adapt/discovery.py +117 -0
- adapt_server-0.1.0/adapt/locks.py +140 -0
- adapt_server-0.1.0/adapt/models.py +15 -0
- adapt_server-0.1.0/adapt/permissions.py +57 -0
- adapt_server-0.1.0/adapt/plugins/__init__.py +22 -0
- adapt_server-0.1.0/adapt/plugins/base.py +137 -0
- adapt_server-0.1.0/adapt/plugins/csv_plugin.py +67 -0
- adapt_server-0.1.0/adapt/plugins/dataset_plugin.py +390 -0
- adapt_server-0.1.0/adapt/plugins/excel_plugin.py +130 -0
- adapt_server-0.1.0/adapt/plugins/html_plugin.py +104 -0
- adapt_server-0.1.0/adapt/plugins/markdown_plugin.py +113 -0
- adapt_server-0.1.0/adapt/plugins/media_plugin.py +202 -0
- adapt_server-0.1.0/adapt/plugins/parquet_plugin.py +156 -0
- adapt_server-0.1.0/adapt/plugins/python_plugin.py +92 -0
- adapt_server-0.1.0/adapt/routes.py +68 -0
- adapt_server-0.1.0/adapt/static/admin/app.js +672 -0
- adapt_server-0.1.0/adapt/static/admin/style.css +299 -0
- adapt_server-0.1.0/adapt/storage.py +138 -0
- adapt_server-0.1.0/adapt/templates/admin/index.html +452 -0
- adapt_server-0.1.0/adapt/templates/admin_base.html +78 -0
- adapt_server-0.1.0/adapt/templates/base.html +81 -0
- adapt_server-0.1.0/adapt/templates/datatable.html +234 -0
- adapt_server-0.1.0/adapt/templates/landing.html +56 -0
- adapt_server-0.1.0/adapt/templates/login.html +128 -0
- adapt_server-0.1.0/adapt/templates/media_gallery.html +51 -0
- adapt_server-0.1.0/adapt/templates/media_player.html +23 -0
- adapt_server-0.1.0/adapt/templates/profile.html +169 -0
- adapt_server-0.1.0/adapt/utils/__init__.py +82 -0
- adapt_server-0.1.0/adapt/utils/query.py +91 -0
- adapt_server-0.1.0/adapt_server.egg-info/PKG-INFO +576 -0
- adapt_server-0.1.0/adapt_server.egg-info/SOURCES.txt +94 -0
- adapt_server-0.1.0/adapt_server.egg-info/dependency_links.txt +1 -0
- adapt_server-0.1.0/adapt_server.egg-info/entry_points.txt +2 -0
- adapt_server-0.1.0/adapt_server.egg-info/requires.txt +19 -0
- adapt_server-0.1.0/adapt_server.egg-info/top_level.txt +1 -0
- adapt_server-0.1.0/pyproject.toml +66 -0
- adapt_server-0.1.0/setup.cfg +4 -0
- adapt_server-0.1.0/tests/test_admin.py +488 -0
- adapt_server-0.1.0/tests/test_auth.py +342 -0
- adapt_server-0.1.0/tests/test_config.py +186 -0
- adapt_server-0.1.0/tests/test_constraints.py +57 -0
- adapt_server-0.1.0/tests/test_csv_plugin.py +284 -0
- adapt_server-0.1.0/tests/test_dataset_plugin.py +127 -0
- adapt_server-0.1.0/tests/test_discovery.py +79 -0
- adapt_server-0.1.0/tests/test_html_plugin.py +72 -0
- adapt_server-0.1.0/tests/test_integration.py +270 -0
- adapt_server-0.1.0/tests/test_locks.py +165 -0
- adapt_server-0.1.0/tests/test_markdown_plugin.py +72 -0
- adapt_server-0.1.0/tests/test_on_delete.py +95 -0
- adapt_server-0.1.0/tests/test_parquet_plugin.py +50 -0
- adapt_server-0.1.0/tests/test_phase3.py +140 -0
- adapt_server-0.1.0/tests/test_plugin_interface.py +69 -0
- adapt_server-0.1.0/tests/test_readonly.py +70 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 notesofcliff
|
|
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.
|
|
@@ -0,0 +1,576 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: adapt-server
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Adaptive file-backed FastAPI server that turns datasets into CRUD APIs and UIs.
|
|
5
|
+
Author-email: notesofcliff <notesofcliff@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/notesofcliff/adapt
|
|
8
|
+
Project-URL: Repository, https://github.com/notesofcliff/adapt
|
|
9
|
+
Project-URL: Issues, https://github.com/notesofcliff/adapt/issues
|
|
10
|
+
Keywords: fastapi,api,csv,excel,parquet,markdown,media
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Framework :: FastAPI
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: fastapi
|
|
24
|
+
Requires-Dist: uvicorn
|
|
25
|
+
Requires-Dist: sqlmodel
|
|
26
|
+
Requires-Dist: pendulum
|
|
27
|
+
Requires-Dist: watchfiles
|
|
28
|
+
Requires-Dist: jinja2
|
|
29
|
+
Requires-Dist: openpyxl
|
|
30
|
+
Requires-Dist: markdown
|
|
31
|
+
Requires-Dist: python-multipart
|
|
32
|
+
Requires-Dist: mutagen
|
|
33
|
+
Requires-Dist: moviepy
|
|
34
|
+
Requires-Dist: pillow
|
|
35
|
+
Requires-Dist: python-json-logger
|
|
36
|
+
Provides-Extra: dev
|
|
37
|
+
Requires-Dist: pytest; extra == "dev"
|
|
38
|
+
Requires-Dist: httpx; extra == "dev"
|
|
39
|
+
Requires-Dist: build; extra == "dev"
|
|
40
|
+
Requires-Dist: twine; extra == "dev"
|
|
41
|
+
Dynamic: license-file
|
|
42
|
+
|
|
43
|
+
# Adapt — The Adaptive File-Backed Web Server
|
|
44
|
+
|
|
45
|
+
Adapt is a lightweight, FastAPI-powered adaptive server that automatically turns files and Python modules into fully functional REST APIs.
|
|
46
|
+
|
|
47
|
+
Note: README vs Implementation
|
|
48
|
+
----------------------------------
|
|
49
|
+
The `README.md` outlines the intended design and functionality. Some features are partially implemented, still in the roadmap, or only scaffolded in the repository. For a detailed list of known differences between README/spec and the current implementation, see `IMPLEMENTATION_NOTES.md` at the project root.
|
|
50
|
+
---
|
|
51
|
+
Drop a CSV, Excel file, Markdown document, HTML page, Parquet-style dataset, audio/video file, or Python handler into a directory and Adapt instantly generates:
|
|
52
|
+
|
|
53
|
+
* CRUD API endpoints
|
|
54
|
+
* HTML DataTables UI (sortable, searchable)
|
|
55
|
+
* Inline editing with PATCH support
|
|
56
|
+
* HTTP streaming for audio/video files
|
|
57
|
+
* Media gallery UI with searchable cards
|
|
58
|
+
* Automatic schema inspection
|
|
59
|
+
* Safe writes via file locking
|
|
60
|
+
* Plugin-driven handlers
|
|
61
|
+
* Authentication, users, groups, and permissions
|
|
62
|
+
* API Keys for programmatic access
|
|
63
|
+
* Audit logging for security and compliance
|
|
64
|
+
* Health check endpoint for monitoring
|
|
65
|
+
* Row-Level Security (RLS) for granular data access
|
|
66
|
+
* Admin dashboard for managing users, groups, locks, caches, and keys
|
|
67
|
+
|
|
68
|
+
A backend that lives in a folder.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Features
|
|
73
|
+
|
|
74
|
+
### Adaptive File Discovery
|
|
75
|
+
|
|
76
|
+
On startup, Adapt:
|
|
77
|
+
|
|
78
|
+
* Scans the document root
|
|
79
|
+
* Detects supported files & handlers
|
|
80
|
+
* Builds REST routes
|
|
81
|
+
* Generates HTML table UIs for CSV/XLSX
|
|
82
|
+
* Generates media players and galleries for audio/video files
|
|
83
|
+
* Loads schema overrides and custom renderers
|
|
84
|
+
* Registers Python handlers automatically
|
|
85
|
+
* Serves all resources at extensionless URLs for cleaner access (e.g., `data.csv` → `/data`)
|
|
86
|
+
* Creates companion files in a hidden `.adapt` directory to avoid cluttering the docroot
|
|
87
|
+
|
|
88
|
+
No configuration required.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Landing Page
|
|
93
|
+
|
|
94
|
+
Adapt provides a user-friendly landing page at the root URL (`/`) that serves as the entry point for authenticated users:
|
|
95
|
+
|
|
96
|
+
* **Welcome Message** - Introduction to Adapt and its capabilities
|
|
97
|
+
* **Quick Start Guide** - Step-by-step instructions for getting started
|
|
98
|
+
* **Accessible Resources** - Dynamic list of datasets, HTML pages, and Markdown documents the user can access based on their permissions
|
|
99
|
+
* **Media Gallery** - Browse and stream audio/video files
|
|
100
|
+
* **Admin Access** - Direct link to the admin dashboard for superusers
|
|
101
|
+
|
|
102
|
+
The landing page adapts to the user's authentication status and permissions, showing only resources they are authorized to view. For unauthenticated users, it displays public HTML and Markdown content.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Automatic CRUD API
|
|
107
|
+
|
|
108
|
+
For CSV, Excel sheets, and Parquet datasets, Adapt exposes:
|
|
109
|
+
|
|
110
|
+
* `GET` — read items
|
|
111
|
+
* `POST` — create/append items
|
|
112
|
+
* `PATCH` — modify items
|
|
113
|
+
* `DELETE` — remove items
|
|
114
|
+
* `/schema` — JSON schema
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
### Request Format for Dataset Endpoints
|
|
118
|
+
|
|
119
|
+
**Note:** For dataset resources (CSV, Excel, Parquet), API requests must use an envelope format specifying the action and data. This is required for all POST, PATCH, and DELETE requests.
|
|
120
|
+
|
|
121
|
+
**Envelope format:**
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"action": "create|update|delete",
|
|
126
|
+
"data": [ ... ] // for create, or { ... } for update/delete
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**Examples:**
|
|
131
|
+
|
|
132
|
+
*Create rows (POST):*
|
|
133
|
+
```json
|
|
134
|
+
{
|
|
135
|
+
"action": "create",
|
|
136
|
+
"data": [
|
|
137
|
+
{"id": "899", "name": "Unknown"},
|
|
138
|
+
{"id": "900", "name": "Alice"}
|
|
139
|
+
]
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
*Update a row (PATCH):*
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"action": "update",
|
|
147
|
+
"data": {"_row_id": 1, "name": "Updated Name"}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
*Delete a row (DELETE):*
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"action": "delete",
|
|
155
|
+
"data": {"_row_id": 2}
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
This format is required for all dataset plugin endpoints. Future versions may support simpler payloads, but for now, always wrap your data in this envelope.
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
Each Excel **sheet** and Parquet file receives its own resource, enabling full CRUD operations per dataset. Parquet support is now robust and consistent with other dataset plugins, including atomic writes, schema inference, and safe concurrent editing.
|
|
163
|
+
|
|
164
|
+
For audio and video files, Adapt provides HTTP streaming endpoints using open standards for efficient playback, along with individual player pages and a searchable media gallery.
|
|
165
|
+
|
|
166
|
+
The plugin system is extensible, allowing any plugin to create sub-resources by setting a "sub_namespace" in the resource metadata, enabling hierarchical API routes for complex file formats.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Caching System
|
|
171
|
+
|
|
172
|
+
Adapt now includes a robust, SQLite-backed caching system:
|
|
173
|
+
|
|
174
|
+
* GET responses for datasets, media metadata, and rendered content are cached for performance.
|
|
175
|
+
* Cache is stored in `DOCROOT/.adapt/adapt.db` and managed per resource.
|
|
176
|
+
* Plugins control what is cached and for how long (TTL).
|
|
177
|
+
* Cache is automatically invalidated on resource mutation (POST/PATCH/DELETE).
|
|
178
|
+
* Admin UI supports cache inspection and manual invalidation.
|
|
179
|
+
|
|
180
|
+
All major plugins (CSV, Excel, Parquet, HTML, Markdown, Media, Python handler) now support caching where appropriate. Parquet, CSV, Excel plugins use cache for reads and schema inference. Media plugin caches metadata. Python handler plugin does not cache routers (for safety).
|
|
181
|
+
|
|
182
|
+
Cache storage is configured at application startup, so plugin cache operations and Admin cache views use the same database path.
|
|
183
|
+
|
|
184
|
+
All cache expiry logic uses timezone-aware UTC datetimes.
|
|
185
|
+
|
|
186
|
+
Comprehensive test suite covers all cache logic and plugin integration.
|
|
187
|
+
|
|
188
|
+
## Built-In HTML UIs (DataTables)
|
|
189
|
+
|
|
190
|
+
CSV and Excel datasets automatically generate a full-featured HTML UI:
|
|
191
|
+
|
|
192
|
+
* Sortable columns
|
|
193
|
+
* Search box
|
|
194
|
+
* Pagination
|
|
195
|
+
* Column hiding
|
|
196
|
+
* Responsive layout
|
|
197
|
+
* Automatic schema-based type formatting
|
|
198
|
+
* Inline editing (PATCH)
|
|
199
|
+
* Form-based row addition (POST)
|
|
200
|
+
* Row deletion (DELETE)
|
|
201
|
+
* **Common navigation bar** with links to API docs, admin dashboard (for superusers), dropdown of all discovered datasets, and logout
|
|
202
|
+
|
|
203
|
+
This UI is powered by DataTables and delivered via Jinja2 templates that extend a base template for consistent navigation. Companion files (`.adapt/*.index.html`) are generated during startup and can be customized by users to add features like charts, custom styling, or additional JavaScript. Rendering happens during requests to ensure dynamic data is always current.
|
|
204
|
+
|
|
205
|
+
Perfect for:
|
|
206
|
+
|
|
207
|
+
* Internal dashboards
|
|
208
|
+
* Quick data exploration
|
|
209
|
+
* Lightweight admin interfaces
|
|
210
|
+
* Local-first tools
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Media Gallery
|
|
215
|
+
|
|
216
|
+
Audio and video files automatically generate a Netflix/YouTube-style gallery UI:
|
|
217
|
+
|
|
218
|
+
* Card-based layout with file information, metadata, and video thumbnails
|
|
219
|
+
* Searchable by filename
|
|
220
|
+
* Direct streaming playback
|
|
221
|
+
* Responsive design
|
|
222
|
+
* Integrated with common navigation bar
|
|
223
|
+
|
|
224
|
+
Individual media files also have dedicated player pages with HTML5 video/audio elements for focused viewing. Streaming uses HTTP range requests for open-standard, efficient delivery. Metadata such as duration, bitrate, artist, and title are extracted and displayed where available.
|
|
225
|
+
|
|
226
|
+
Perfect for:
|
|
227
|
+
|
|
228
|
+
* Media libraries
|
|
229
|
+
* Content management
|
|
230
|
+
* Personal streaming servers
|
|
231
|
+
* Educational resources
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## Python Handler Plugins (`*.py`)
|
|
236
|
+
|
|
237
|
+
Drop Python files into your doc root to auto-register custom FastAPI routes.
|
|
238
|
+
|
|
239
|
+
If the file defines an `APIRouter` named `router`:
|
|
240
|
+
|
|
241
|
+
```python
|
|
242
|
+
from fastapi import APIRouter
|
|
243
|
+
|
|
244
|
+
router = APIRouter()
|
|
245
|
+
|
|
246
|
+
@router.get("/hello")
|
|
247
|
+
def hello():
|
|
248
|
+
return {"message": "Hello from a file handler!"}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Adapt mounts it under:
|
|
252
|
+
|
|
253
|
+
```
|
|
254
|
+
/api/<filename>/*
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
This enables:
|
|
258
|
+
|
|
259
|
+
* Custom business logic
|
|
260
|
+
* Aggregation endpoints
|
|
261
|
+
* Integrations with external APIs
|
|
262
|
+
* Data transformations
|
|
263
|
+
* Secured/role-based logic layers
|
|
264
|
+
|
|
265
|
+
Without editing the core server.
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## Safe Write Operations
|
|
270
|
+
|
|
271
|
+
Writes to CSV, Excel, and Parquet files follow a strict, atomic workflow:
|
|
272
|
+
|
|
273
|
+
1. Permission check
|
|
274
|
+
2. Acquire a file lock (with unique constraint to prevent race conditions)
|
|
275
|
+
3. Write to a temporary file
|
|
276
|
+
4. Atomic rename/move
|
|
277
|
+
5. Release lock
|
|
278
|
+
|
|
279
|
+
**Lock Safety Features:**
|
|
280
|
+
* Database-level unique constraint prevents concurrent lock acquisition
|
|
281
|
+
* Automatic retry with exponential backoff (starting at 0.1s, doubling each attempt, capped at 1.0s, 30-second timeout)
|
|
282
|
+
* Stale lock cleanup on server startup (5-minute threshold)
|
|
283
|
+
* Lock expiration (5-minute TTL by default)
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
Parquet plugin now uses the same atomic write logic as CSV and Excel plugins, writing to a temporary file and atomically replacing the original, ensuring data integrity and safe concurrent access.
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## Authentication & Authorization
|
|
291
|
+
|
|
292
|
+
Adapt includes a complete security layer for multi-user deployments:
|
|
293
|
+
|
|
294
|
+
### Session-Based Authentication
|
|
295
|
+
|
|
296
|
+
* Cookie-based login system (HttpOnly, Secure, SameSite flags for comprehensive protection)
|
|
297
|
+
* PBKDF2 password hashing with per-user salts (100,000 iterations)
|
|
298
|
+
* 7-day session expiration with **active enforcement** and automatic cleanup
|
|
299
|
+
* Sliding session renewal - active sessions stay valid
|
|
300
|
+
* Background task removes expired sessions (runs daily)
|
|
301
|
+
* Timing attack mitigation with constant-time operations
|
|
302
|
+
* Automatic redirect to login for unauthenticated browser requests, followed by redirect to landing page after successful authentication
|
|
303
|
+
* JSON error responses for API clients
|
|
304
|
+
|
|
305
|
+
### User Management
|
|
306
|
+
|
|
307
|
+
* Create and manage users via Admin UI or CLI
|
|
308
|
+
* Superuser role for administrative access
|
|
309
|
+
* Active/inactive user status
|
|
310
|
+
* Secure password storage (never plaintext)
|
|
311
|
+
|
|
312
|
+
### Group-Based Permissions
|
|
313
|
+
|
|
314
|
+
* Organize users into groups (teams, departments, roles)
|
|
315
|
+
* Assign permissions to groups, not individual users
|
|
316
|
+
* Users inherit permissions from all their groups
|
|
317
|
+
* Supports complex organizational hierarchies
|
|
318
|
+
|
|
319
|
+
### Resource-Level Permissions
|
|
320
|
+
|
|
321
|
+
* Granular control over dataset access
|
|
322
|
+
* Two permission types: `read` and `write`
|
|
323
|
+
* Permissions map to resource namespaces (e.g., `data`, `workbook/People`)
|
|
324
|
+
* Automatic enforcement on all dynamically generated routes
|
|
325
|
+
* Superusers bypass all permission checks
|
|
326
|
+
|
|
327
|
+
### Permission Enforcement
|
|
328
|
+
|
|
329
|
+
All dataset routes (`/api/*`, `/ui/*`, `/schema/*`) are automatically protected:
|
|
330
|
+
|
|
331
|
+
1. User must be authenticated (valid session cookie)
|
|
332
|
+
2. User must have appropriate permission for the resource
|
|
333
|
+
3. GET requests require `read` permission
|
|
334
|
+
4. POST/PUT/PATCH/DELETE require `write` permission
|
|
335
|
+
5. 403 Forbidden if permission denied
|
|
336
|
+
|
|
337
|
+
### API Keys
|
|
338
|
+
|
|
339
|
+
* Programmatic access for scripts and external tools
|
|
340
|
+
* Generate keys via Admin UI or user Profile page with optional expiration (max 1 year)
|
|
341
|
+
* Authenticate via `X-API-Key` header
|
|
342
|
+
* Secure storage (SHA-256 hashed)
|
|
343
|
+
* Users can self-issue API keys for their own account
|
|
344
|
+
|
|
345
|
+
### Audit Logging
|
|
346
|
+
|
|
347
|
+
* Records critical system actions for security and compliance
|
|
348
|
+
* Logs: Login/Logout, User/Group changes, Permission changes, API Key management
|
|
349
|
+
* Viewable and filterable via Admin UI
|
|
350
|
+
|
|
351
|
+
### Row-Level Security (RLS)
|
|
352
|
+
|
|
353
|
+
* Plugins can enforce granular access control based on the authenticated user
|
|
354
|
+
* `filter_for_user` hook allows plugins to restrict data visibility
|
|
355
|
+
* Applied automatically during data retrieval
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
## Admin UI
|
|
360
|
+
|
|
361
|
+
Adapt ships with a built-in admin interface at `/admin/` to manage the entire security layer:
|
|
362
|
+
|
|
363
|
+
### Users Tab
|
|
364
|
+
|
|
365
|
+
* Create new users with username and password
|
|
366
|
+
* Set superuser status
|
|
367
|
+
* Delete users
|
|
368
|
+
* View all registered users
|
|
369
|
+
|
|
370
|
+
### Groups Tab
|
|
371
|
+
|
|
372
|
+
* Create groups with names and descriptions
|
|
373
|
+
* Manage group membership (add/remove users)
|
|
374
|
+
* Assign permissions to groups
|
|
375
|
+
* Delete groups
|
|
376
|
+
|
|
377
|
+
### Permissions Tab
|
|
378
|
+
|
|
379
|
+
* Define new permissions (resource + action pairs)
|
|
380
|
+
* View all available permissions
|
|
381
|
+
* Delete unused permissions
|
|
382
|
+
* Assign permissions to groups
|
|
383
|
+
|
|
384
|
+
### Locks Tab
|
|
385
|
+
|
|
386
|
+
* View current file locks
|
|
387
|
+
* Release stale locks
|
|
388
|
+
* Monitor concurrent access
|
|
389
|
+
|
|
390
|
+
### API Keys Tab
|
|
391
|
+
|
|
392
|
+
* Generate new API keys for users (admin only)
|
|
393
|
+
* Users can self-manage their API keys via Profile page
|
|
394
|
+
* Revoke existing keys
|
|
395
|
+
* Set expiration dates (max 1 year)
|
|
396
|
+
|
|
397
|
+
### Audit Logs Tab
|
|
398
|
+
|
|
399
|
+
* View chronological history of system actions
|
|
400
|
+
* Filter by user, action, or resource
|
|
401
|
+
* Inspect action details
|
|
402
|
+
|
|
403
|
+
### Cache Tab
|
|
404
|
+
|
|
405
|
+
* View all cached entries with key, resource, expiration, and user
|
|
406
|
+
* Delete individual cache entries
|
|
407
|
+
* Clear all cache entries
|
|
408
|
+
* Monitor cache usage and performance
|
|
409
|
+
|
|
410
|
+
The Admin UI uses vanilla HTML/CSS/JavaScript for portability and simplicity—no build step required.
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
## Custom Overrides
|
|
415
|
+
|
|
416
|
+
Optional companion files customize behavior:
|
|
417
|
+
|
|
418
|
+
| File | Purpose |
|
|
419
|
+
| ----------------------------------- | --------------------------- |
|
|
420
|
+
| `.adapt/dataset.schema.json` | Override inferred schema |
|
|
421
|
+
| `.adapt/dataset.index.html` | Custom Jinja2 HTML template |
|
|
422
|
+
| `.adapt/dataset.<sheet>.html` | Sheet-level HTML override |
|
|
423
|
+
| `.adapt/dataset.<sheet>.schema.json`| Sheet-level schema override |
|
|
424
|
+
|
|
425
|
+
---
|
|
426
|
+
|
|
427
|
+
## Configuration
|
|
428
|
+
|
|
429
|
+
Adapt supports configuration via a `conf.json` file in `DOCROOT/.adapt/`. If the file doesn't exist, it's created with default values on first run.
|
|
430
|
+
|
|
431
|
+
The configuration allows customizing:
|
|
432
|
+
|
|
433
|
+
- `plugin_registry`: Map file extensions to plugin classes (e.g., add custom handlers).
|
|
434
|
+
- `host`: Bind host for `adapt serve`.
|
|
435
|
+
- `port`: Bind port for `adapt serve`.
|
|
436
|
+
- `tls_cert`: Path to TLS certificate file.
|
|
437
|
+
- `tls_key`: Path to TLS key file.
|
|
438
|
+
- `secure_cookies`: Whether to set secure flags on cookies.
|
|
439
|
+
- `readonly`: Enable read-only mode.
|
|
440
|
+
- `debug`: Enable debug logging.
|
|
441
|
+
- `logging`: Logging configuration dictionary for Python's dictConfig.
|
|
442
|
+
|
|
443
|
+
Precedence: explicit CLI flags > environment variables > `conf.json` > defaults.
|
|
444
|
+
|
|
445
|
+
Example `conf.json`:
|
|
446
|
+
|
|
447
|
+
```json
|
|
448
|
+
{
|
|
449
|
+
"plugin_registry": {
|
|
450
|
+
".custom": "my_plugin.CustomPlugin"
|
|
451
|
+
},
|
|
452
|
+
"host": "127.0.0.1",
|
|
453
|
+
"port": 8000,
|
|
454
|
+
"tls_cert": "/path/to/cert.pem",
|
|
455
|
+
"tls_key": "/path/to/key.pem",
|
|
456
|
+
"secure_cookies": true,
|
|
457
|
+
"readonly": false,
|
|
458
|
+
"debug": false,
|
|
459
|
+
"logging": {
|
|
460
|
+
"root": {
|
|
461
|
+
"level": "DEBUG"
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
To reset, delete `conf.json` and restart the server.
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
## Plugin Registry & Companion Files
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
`AdaptConfig` embeds a `plugin_registry` that maps file extensions to dotted paths for the classes that own those datasets. The default registry wires `.csv`, `.xlsx`, and `.parquet` files to the built-in dataset plugins, all of which now use a consistent interface for schema inference, atomic writes, and safe editing. Parquet support is fully integrated and tested. Each plugin is responsible for producing the inferred JSON schema that becomes the companion `.adapt/*.schema.json`. Those companion files are generated once on server startup and never exposed directly over HTTP—they exist purely to inform the API responses, HTML UI rendering, and validation layers.
|
|
475
|
+
|
|
476
|
+
HTML companion files (`.adapt/*.index.html`) are generated as Jinja2 templates with pre-computed schema data (e.g., column headers) baked in, allowing for efficient rendering while supporting full customization. If a companion HTML file exists, it overrides the default UI template for that resource.
|
|
477
|
+
|
|
478
|
+
Plugins now have full control over route generation via the `get_route_configs` method. This allows plugins to define their own API, Schema, and UI endpoints, including injecting necessary context (like `api_url`) into UI templates. This architecture supports complex multi-resource files (like Excel workbooks) by allowing plugins to generate hierarchical routes using "sub_namespace" metadata.
|
|
479
|
+
|
|
480
|
+
### Stability & Testing
|
|
481
|
+
|
|
482
|
+
The plugin system is backed by a strict interface contract (`adapt.plugins.base.Plugin`) and a comprehensive test suite. This ensures that custom plugins—whether for new file types or complex logic—integrate seamlessly with the core discovery and routing engines. The `ResourceDescriptor` acts as the immutable boundary between the file system and your code.
|
|
483
|
+
|
|
484
|
+
## CLI Commands
|
|
485
|
+
|
|
486
|
+
The `adapt` CLI includes a few core commands:
|
|
487
|
+
|
|
488
|
+
* `adapt serve <root>` — serve the given document root (supports `--host`, `--port`, `--tls-cert`, `--tls-key`, `--reload`, `--readonly`, `--debug`).
|
|
489
|
+
* `adapt check <root>` — sanity-check the configuration, initialize `.adapt.db`, and print the discovered datasets.
|
|
490
|
+
* `adapt addsuperuser <root> --username <name>` — create a local superuser backed by `.adapt.db`.
|
|
491
|
+
* `adapt list-endpoints <root>` — show the automatically generated `/api/*`, `/ui/*`, and `/schema/*` paths for every resource.
|
|
492
|
+
|
|
493
|
+
### Admin Commands
|
|
494
|
+
|
|
495
|
+
Adapt includes administrative commands for managing users, groups, and permissions:
|
|
496
|
+
|
|
497
|
+
* `adapt admin list-resources <root>` — list all discovered resources in the document root, including sub-namespaces for multi-resource files (e.g., Excel sheets).
|
|
498
|
+
* `adapt admin create-permissions <root> <resources>...` — create permissions and groups for specified resources (use `__all__` for all resources, including sub-namespaces).
|
|
499
|
+
* `adapt admin list-groups <root>` — display all groups with their associated permissions and assigned users.
|
|
500
|
+
* `adapt admin list-users <root>` — list local users.
|
|
501
|
+
* `adapt admin create-user <root> --username <name> [--password <pw>] [--superuser]` — create a user.
|
|
502
|
+
* `adapt admin delete-user <root> --username <name>` — delete a user.
|
|
503
|
+
* `adapt admin create-group <root> --name <group> [--description <text>]` — create a group.
|
|
504
|
+
* `adapt admin delete-group <root> --name <group>` — delete a group.
|
|
505
|
+
* `adapt admin add-to-group <root> --username <name> --group <group>` — add a user to a group.
|
|
506
|
+
* `adapt admin remove-from-group <root> --username <name> --group <group>` — remove a user from a group.
|
|
507
|
+
|
|
508
|
+
## Installation
|
|
509
|
+
|
|
510
|
+
```
|
|
511
|
+
pip install adapt-server
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
Serve your directory:
|
|
515
|
+
|
|
516
|
+
```
|
|
517
|
+
adapt serve ./data
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
Runs on Uvicorn with TLS, RBAC, caching, locking, and adaptive routing.
|
|
521
|
+
|
|
522
|
+
---
|
|
523
|
+
|
|
524
|
+
## Example Directory Layout
|
|
525
|
+
|
|
526
|
+
```
|
|
527
|
+
data/
|
|
528
|
+
employees.csv
|
|
529
|
+
employees.schema.json
|
|
530
|
+
sales.xlsx
|
|
531
|
+
sales.q1.html
|
|
532
|
+
video.mp4
|
|
533
|
+
audio.mp3
|
|
534
|
+
stats.py
|
|
535
|
+
readme.md
|
|
536
|
+
index.html
|
|
537
|
+
docs/
|
|
538
|
+
guide.md
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
Adapt exposes:
|
|
542
|
+
|
|
543
|
+
* `/` — landing page with resource overview
|
|
544
|
+
* `/ui/employees` — DataTables UI
|
|
545
|
+
* `/api/employees` — CRUD API
|
|
546
|
+
* `/api/sales` — sheet listing
|
|
547
|
+
* `/api/sales/<sheet>` — CRUD API for each sheet
|
|
548
|
+
* `/media/video.mp4` — streaming endpoint
|
|
549
|
+
* `/ui/video.mp4` — media player page
|
|
550
|
+
* `/ui/media` — media gallery
|
|
551
|
+
* `/api/stats/*` — handler routes
|
|
552
|
+
* `/readme` — rendered Markdown content
|
|
553
|
+
* `/index` — HTML page content
|
|
554
|
+
* `/docs/guide` — rendered Markdown content
|
|
555
|
+
* `/admin/*` — admin UI
|
|
556
|
+
|
|
557
|
+
---
|
|
558
|
+
|
|
559
|
+
## Roadmap
|
|
560
|
+
|
|
561
|
+
* File watchers (hot-reload route generation)
|
|
562
|
+
* GraphQL auto-introspection
|
|
563
|
+
* Audit log browser in Admin UI (Completed)
|
|
564
|
+
* Plugin marketplace
|
|
565
|
+
|
|
566
|
+
---
|
|
567
|
+
|
|
568
|
+
## License
|
|
569
|
+
|
|
570
|
+
MIT License. See `LICENSE` file for details.
|
|
571
|
+
|
|
572
|
+
---
|
|
573
|
+
|
|
574
|
+
# Adapt
|
|
575
|
+
|
|
576
|
+
Your filesystem is now an API platform.
|