feat: implement Layer 2 per-file transit, RAM session, mock buffer, and tests (v0.2.0)

This commit is contained in:
“Naeel”
2026-09-06 12:01:56 +03:00
parent 0ea7ba058c
commit 112c84f11a
34 changed files with 2200 additions and 162 deletions
+26 -39
View File
@@ -1,44 +1,31 @@
# Upload module
# Upload module (v0.2.0)
Для встраивания скопируйте один готовый bundle из `dist/`:
Переиспользуемый модуль загрузки, состоящий из двух независимых слоёв:
- IIFE: `FilePicker.initFilePicker(config)`;
- ESM: `import { initFilePicker } from './file-picker.esm.js'`.
1. **Слой 1 (`upload/frontend/`)**File Picker:
- IIFE: `FilePicker.initFilePicker(config)`;
- ESM: `import { initFilePicker } from './file-picker.esm.js'` (или из `upload/frontend/index.js`).
- Получение выбранных файлов: `picker.getFiles()` возвращает плоский массив `{ path, name, size, file }`.
- Поддерживает выбор файлов, папок, клиентскую распаковку ZIP (fflate) и проверку лимитов.
`config` должен содержать `mount` как DOM-элемент или CSS-селектор. Основные
параметры: `allowedExt`, `labels`, `layout`, `limits`, `onChange(files)` и
`onError(error, file)`. `onError` вызывается для ошибок разбора ZIP; обычные
файлы с неподдерживаемым расширением просто пропускаются.
2. **Слой 2 (`upload/frontend/upload/` + `upload/backend/`)** — Пофайловый транзит в RAM сессии:
- Фронтенд: `uploadViaVM(files, options)` или `FilePicker.uploadViaVM(files, options)`:
- Пофайловый стриминг: для каждого файла выполняется `PUT` в буфер на ВМ, немедленный `POST /api/upload_refs` в бэкенд, и после подтверждения приёма буфер на ВМ очищается.
- Поддержка `AbortSignal` для отмены загрузки на любом этапе.
- Бэкенд: `create_upload_refs_blueprint(cfg)`:
- Приём ссылок через исходящий потоковый `GET` в память RAM.
- SSRF-валидация префикса буфера (`vmUploadPrefix`).
- Защита от path traversal (`safe_name`).
- Хранилище сессий в оперативной памяти (`upload/backend/session`).
- Никакой записи на диск.
Публичный API picker-а:
## Интеграция в сторонний проект
- `pickFiles()` и `pickFolder()` — открыть системный выбор;
- `getFiles()` — получить leaf-файлы с `path`, `name`, `size` и `file`;
- `addFiles(files)` — добавить файлы программно;
- `remove(id)` и `clear()` — удалить узел или очистить дерево;
- `render()` и `destroy()` — перерисовать или удалить экземпляр.
Picker поддерживает разрешённые документы, папки и вложенные ZIP, хранит
исходные browser `File` objects и выполняет дедупликацию по пути и размеру.
Загрузка на VM, backend sessions и upload API не используются. ZIP обрабатывается
локально через встроенный в bundle `fflate`; отдельный vendor script не требуется.
## Legacy
Старые `uploadViaVM`, VM-буфер, backend sessions и upload API относятся к
предыдущей архитектуре и в текущем модуле отсутствуют. Упоминания этих названий
в `HISTORY/` являются историческими и не должны использоваться как инструкция.
Подробная таблица функций, входов, выходов и побочных эффектов находится в
[`../docs/CODE-REFERENCE.md`](../docs/CODE-REFERENCE.md).
## Сборка из исходников
Исходники находятся в `frontend/`. В корне проекта:
```bash
npm install
npm run build
```
Результат сборки: `dist/file-picker.esm.js` и `dist/file-picker.iife.js`.
1. Скопировать каталог `upload/` в проект.
2. Во Flask подключить Blueprint:
```python
from upload.backend.upload_refs import create_upload_refs_blueprint
app.register_blueprint(create_upload_refs_blueprint({"vmUploadPrefix": "..."}))
```
3. На фронтенде подключить `file-picker.iife.js` или импортировать ESM.
4. Вызвать `initFilePicker`, а при отправке вызвать `uploadViaVM(picker.getFiles(), options)`.