Adds a folder picker (webkitdirectory) and drag-and-drop directory
support (File System Entries API), preserving relative paths via
a new optional relative_path field on the upload endpoint.
- Default CORS_ORIGINS to http://localhost:5173 instead of "*" (still overridable)
- Reject ".." and leading "/" in document keys/paths across get/save/delete/upload,
mapped to HTTP 400 via new InvalidPathError
- Add a delete button to DocumentEditor wired to deleteDocument + onDeleted,
giving the existing DELETE API an actual UI entry point
- Share a single lru_cache'd Meilisearch (and Minio) SDK client instance instead
of constructing duplicates in dependencies.py
- Add a startup check that creates the MinIO bucket if missing, tolerating
MinIO being unreachable at boot without crashing the app
- client.test.ts: use globalThis.fetch instead of global.fetch and drop the
unused describe import, fixing the broken `npm run build`
- DocumentEditor: separate load-error (replaces view) from save-error (shown
inline, editor and unsaved content stay mounted so a failed save no longer
destroys in-progress edits); expose dirty state via onDirtyChange
- App: prompt via window.confirm before switching documents while dirty;
increment a refreshKey on successful upload so FileExplorer re-fetches the
tree; track isSearching so the "no results" overlay doesn't flash during
the search debounce window
- FileExplorer: accept a refreshKey prop to force a root-listing re-fetch
- SearchBar: convert to a controlled component (value prop) so App can clear
the input after jumping to a search result, fixing input/state desync
- UploadButton: surface upload failures inline instead of swallowing the
rejected promise, and keep the modal open for retry