Commit graph

59 commits

Author SHA1 Message Date
6667f320c5 feat: wire AMPP folder placer into server — add /api/ampp/place endpoint 2026-04-30 17:17:39 -04:00
77a64455ae feat: add AMPP folder placer — Node.js port of folder-organizer-v3.5 2026-04-30 17:13:04 -04:00
a07d2c0ae4 Add public/index.html
Speed display was wildly inaccurate during parallel multipart uploads. Fixed with monotonic byte tracking, 15s smoothing window, and cached speed values.
2026-04-12 13:44:54 -04:00
02f5583e96 chore: delete accidental hindex.html (filename typo during edit) 2026-04-12 13:39:20 -04:00
2e3ac69f97 fix: SpeedTracker uses monotonic bytes + 15s smoothing for accurate speed display
Speed display was wildly inaccurate during parallel multipart uploads because:
1. Parallel chunk progress events caused non-monotonic byte counts
2. The 5-second smoothing window was too short for bursty uploads
3. Speed dropped to near-zero between chunk boundaries

Fixes:
- Enforce monotonic byte tracking via _peak guard
- Extend sliding window from 5s to 15s
- Cache last good speed value for display continuity
- Require >= 1s of data before calculating (was 0.5s)
2026-04-12 13:34:03 -04:00
5113adb635 feat: add real-time upload speed monitor with ETA
Shows "XX% · Y.Y MB/s · ~Zm Zs" during uploads. Speed is smoothed
over a 5-second rolling window. Works for both small (single PUT)
and large (multipart chunked) uploads.
2026-04-09 22:08:33 -04:00
009530416f perf: reduce chunk size from 32MB to 8MB for better parallelism
A 46MB file now splits into 6 chunks (all 6 streams active) instead
of 2 chunks (4 streams idle). Better saturation of available bandwidth
on high-latency or constrained links.
2026-04-09 22:07:09 -04:00
f7d8ba14cf feat: presigned multipart upload for large files (browser-direct)
Large files (>32MB) now use presigned S3 multipart URLs via
/api/desktop/multipart/init, letting the browser PUT 32MB chunks
directly to S3 in 6 parallel streams. No data passes through Node.
Small files still use single presigned PUT. Updated HTTP mode
description to "HTTP multi-part upload".
2026-04-09 21:43:22 -04:00
6947e25230 fix: restore uploader + add chunked multipart for large files
Reverts accidental landing page overwrite. Files >32MB now use S3
multipart upload with 32MB chunks and 6 parallel streams per file.
Files <=32MB still use fast direct presigned PUT.
2026-04-09 21:32:06 -04:00
d06f96f208 fix: restore correct uploader with chunked multipart upload support 2026-04-09 21:29:31 -04:00
13349ce32e fix: restore correct uploader with chunked multipart upload support 2026-04-09 21:26:39 -04:00
97c4a4c779 fix: restore correct uploader with chunked multipart upload support 2026-04-09 21:26:12 -04:00
837d848c2e feat: chunked parallel multipart upload for large files
Files >32MB now use S3 multipart upload with 32MB chunks and 6 parallel
streams per file. Files <=32MB still use fast direct presigned PUT.
Fixes slow upload speeds for large files.
2026-04-09 21:22:23 -04:00
14aea6961e feat: chunked parallel multipart upload for large files
Files >32MB now use S3 multipart upload with 32MB chunks and 6 parallel
streams per file. Files <=32MB still use fast direct presigned PUT.
Fixes slow upload speeds for large files.
2026-04-09 21:21:22 -04:00
Zac
02b67f2b6a feat: enable Electron App download button with Windows/macOS links, remove "processed 6 at a time" text 2026-04-08 22:59:09 -04:00
Zac
340837fa72 fix: close desktop/multipart/abort route missing res.json and closing brace 2026-04-08 22:16:48 -04:00
Zac
c4158f0cfd merge: keep desktop multipart API routes alongside parallel chunk upload routes 2026-04-08 22:09:25 -04:00
Zac
675ff9985f feat: add desktop multipart API endpoints for Dragon Wind Desktop app 2026-04-08 22:05:53 -04:00
84cf9cccbe Fix folder sorting, default selection, subfolder S3 keys, and HTTP mode description
Addresses feedback from Gavin (VPM):
- Sort folders alphabetically in both upload tree and admin tree views
- Auto-select VPM as default folder on login instead of Root
- Fix S3 key construction for nested folders: convert "/" to "--" so FLX
  correctly maps subfolders (e.g. Content/TEST - AMPP Demo now produces
  Content--TEST - AMPP Demo--file.ext instead of Content/TEST - AMPP Demo--file.ext)
- Clarify HTTP mode note: "Files are processed 6 at a time" instead of
  "up to 6 concurrent files" which implied a total file limit

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 21:40:44 -04:00
Zac
5b0a3ef2cc Add server-side AMPP job debug logging to identify field names
Logs the first job's keys and data (truncated to 1000 chars) on each
/api/ampp/jobs request to help identify which field contains the asset name.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 09:16:24 -04:00
Zac
ecdfe0f7cd Presigned direct-to-S3 uploads — bypass Node server entirely
Browser now uploads files directly to RustFS/S3 via presigned PUT URLs.
The Node server only generates signed URLs and tracks quota — file data
never touches the server. 6 concurrent file uploads.

Falls back to server-proxied PutObjectCommand upload if presigned fails.

Server changes:
- /api/presigned now checks folder permissions, quota, and blocked files
- /api/presigned/complete endpoint for post-upload quota tracking

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 01:08:55 -04:00
Zac
0f81cac6ec QOL improvements: folder search, user audit, admin folders fix, AMPP debug
- Add search/filter input to destination folder browser with 320px
  scrollable container
- Add User Audit button showing each user's visible pages, role,
  quota, and folder access permissions
- Fix admin Folders tab delete buttons (were broken due to
  JSON.stringify quote conflicts in innerHTML onclick handlers)
- Add more AMPP job name field fallbacks and debug logging to
  diagnose asset name display issue

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 01:03:28 -04:00
Zac
ad5f9a4186 Update HTTP mode description to reflect actual upload method
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 00:56:04 -04:00
Zac
44c22bd95e Replace Upload class with PutObjectCommand for RustFS compatibility
The @aws-sdk/lib-storage Upload class internally uses
CreateMultipartUploadCommand for files over the part size threshold,
which returns non-standard XML from RustFS causing UnknownError.
PutObjectCommand does a simple single PUT request that RustFS handles
correctly. Fixed in both /api/upload and /api/link/:id/upload endpoints.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 00:52:54 -04:00
Zac
d5192e8847 Replace chunked multipart upload with simple Upload class
The manual CreateMultipartUploadCommand/UploadPartCommand/CompleteMultipartUploadCommand
flow fails with RustFS due to non-standard XML responses (same issue as HeadBucketCommand).
Switch front-end to use /api/upload endpoint which uses @aws-sdk/lib-storage Upload class —
the same method that worked reliably in VPM-Uploader with RustFS.

Uses XMLHttpRequest for upload progress tracking.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 00:49:13 -04:00
Zac
43aa18f963 Use ListObjectsV2Command for S3 test instead of raw HTTP signing 2026-04-07 00:42:52 -04:00
Zac
1bc30010a4 Replace AWS SDK test with raw S3v4 signed HTTP request for RustFS/MinIO compat 2026-04-07 00:38:44 -04:00
Zac
4b0f56ac2a Add full S3 error dump for debugging 2026-04-07 00:34:46 -04:00
Zac
89291a4baf Fix S3 test: always merge with saved config, add debug logging 2026-04-07 00:32:59 -04:00
Zac
ae4360e85a Fix S3 test (use HeadBucket like VPM-Uploader), replace UDP button with grayed Electron App 2026-04-07 00:30:28 -04:00
Zac
db25255472 Fix S3 save, remove UDP relay entirely, remove Extension tab 2026-04-07 00:26:43 -04:00
Zac
f3aa44104c Remove Extension tab, fix S3 save, update footer, add Electron uploader coming soon to UDP Relay 2026-04-07 00:21:31 -04:00
2b713fd169 fix: remove duplicate require causing SyntaxError on startup
CreateMultipartUploadCommand etc. were already declared at top of file.
Appended block re-declared them causing 'Identifier already declared' crash.
2026-04-06 23:32:08 -04:00
172250b279 fix: AMPP Monitor field mapping for Grassvalley API colon-namespaced keys
AMPP API returns keys like 'state:jobState', 'name:text', 'type:jobType',
'creator:id', 'created:dateTime', 'job:id' — not plain 'status', 'name',
etc. Frontend was falling back to 'Job' / 'Unknown' for every entry.

Updated field lookups to read colon-namespaced keys first, with fallbacks
for compatibility. Also added 'aborted' to the failed status detection.
2026-04-06 23:30:00 -04:00
8ec43c299e Add parallel chunked HTTP upload (Option 4 — Aspera-class speed)
Split files into 32 MB chunks, POST 6 concurrently to /api/upload/chunk,
server proxies each chunk as an S3 multipart part. Up to 4 files upload
in parallel simultaneously. Achieves Aspera-class throughput over plain
HTTP with no UDP port forwarding or custom protocols required.

Same approach used by MASV under the hood.

- server.js: Add /api/upload/initiate, /chunk, /complete, /abort endpoints
- public/index.html: Replace single-PUT uploadHTTP() with parallel chunked version
2026-04-06 23:22:51 -04:00
a3d1446060 fix: add missing UDP Relay admin tab button and HTTP/UDP mode toggle buttons on upload page 2026-04-06 22:46:52 -04:00
efdaa48cb6 fix: UDP upload was completely broken — relay never received sessions or chunks
Root cause: three critical bugs in the UDP upload flow:

1. Main server never registered sessions on the relay — it stored them
   in its own memory but never called POST /session on the relay, so
   the relay had no idea about any upload sessions.

2. Relay had no HTTP chunk endpoint — the Chrome extension sends chunks
   via HTTP POST to /session/:id/chunk/:index, but the relay only had
   a binary UDP listener. Added the HTTP fallback endpoint.

3. Relay had no CORS headers — browser requests from chrome-extension://
   origins were blocked. Added CORS middleware.

The flow now works:
  Browser → POST /api/udp/session (main server)
  Main server → POST /session (relay, with s3Config)
  Browser → POST /session/:id/chunk/:n (relay, via public URL)
  Relay → S3 multipart upload
  Browser → POST /api/udp/session/:id/complete (main server)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 22:12:22 -04:00
42fead82aa fix: split relay URL into internal + public for browser clients
The relay container is reached internally via docker service name
(http://dragon-wind-relay:3001) but browsers need the public address.
Previously the internal URL was sent to clients causing UDP uploads to fail.

- Add publicRelayUrl field to relay config (server + admin UI)
- /api/udp/session now returns publicRelayUrl to browser clients
- Internal relayUrl still used for server-side health checks
- Falls back to internal URL if public not set

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 22:02:14 -04:00
b3f669afe4 fix: extension defaulting to UDP mode causing upload failures
The extension was saving and restoring UDP mode from storage. If UDP
was previously selected and the relay isn't configured, every upload
immediately fails with "UDP relay not configured".

- Default to HTTP mode on fresh installs (no saved mode)
- Before UDP upload, check /api/health relayConfigured flag and
  auto-fall-back to HTTP with a warning if relay isn't set up

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 22:00:20 -04:00
9e1e25ac97 fix: web GUI upload Content-Type mismatch with presigned URL
Same fix as the Chrome extension — the web GUI's uploadHTTP() was using
item.file.type (browser-determined MIME) instead of presigned.contentType
(server-signed MIME). For broadcast formats like MXF, R3D, BRAW where
the browser returns empty or generic types, this causes an S3 signature
mismatch and the PUT fails.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 21:56:03 -04:00
3b39803b49 fix: extension upload uses server-signed content type + better error logging
The presigned URL is signed with a specific Content-Type (determined by
the server's MIME map). If the browser's file.type doesn't match (common
for broadcast formats like MXF, R3D, BRAW), S3 rejects the PUT with a
signature mismatch. Now the extension uses presigned.contentType from the
server response instead of item.file.type.

Also added console logging for upload requests and detailed error
messages from S3 responses on failure.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 21:54:38 -04:00
8bb9cf7ce9 debug: add console logging and 10s timeout to extension API calls
- apiFetch() now logs method+URL on start and status code on response
- Added 10s AbortController timeout to prevent infinite hangs
- Added try/catch wrapper in saveSettings() around login() call
- This helps diagnose the "stuck on connecting" issue

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 21:50:28 -04:00
7c2aa0d739 fix: extension Save & Connect stuck on connecting state
- Login failures (wrong password) were caught by the 401 handler in
  apiFetch() which threw "Session expired" instead of returning the
  actual error message. Now /api/login 401 responses pass through
  so the real "Invalid credentials" error is shown.
- Settings panel now shows error messages from login() failures
  instead of staying stuck on "Saved — connecting…" forever.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 21:45:08 -04:00
e588a69a78 fix: Chrome extension MV3 CSP violations and missing alarms permission
- Add "alarms" permission to manifest — chrome.alarms.create() was
  throwing "Cannot read properties of undefined" because the permission
  was missing; also removed invalid "sockets" permission (not a valid MV3 perm)
- Remove all inline event handlers from popup.html (onclick, ondragover,
  ondragleave, ondrop, onchange) — MV3 CSP blocks inline JS entirely;
  all handlers moved to popup.js addEventListener() calls
- Replace inline onclick="removeFile(i)" on dynamically generated remove
  buttons with data-idx attribute + delegated click listener on the list
  container — same CSP fix for runtime-generated elements

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 21:38:50 -04:00
fa206ba21a fix: AMPP monitor duplicate ID, not-configured UX, and auto-refresh
- Fix duplicate id="ampp-status" collision between the monitor page and
  admin AMPP panel — admin panel now uses id="ampp-cfg-status" so the
  monitor status messages are no longer silently hijacked
- AMPP monitor now shows a clear "not configured" card with a direct
  button to Admin → AMPP instead of a cryptic error when the API key
  hasn't been entered yet
- Improve job field mapping to handle AMPP response variations
  (jobStatus, displayName, jobType, results array vs items array)
- Add 30-second auto-refresh while on the Monitor tab; timer is cleared
  when navigating away to avoid ghost requests

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 21:32:09 -04:00
978d447b3d fix: add CORS headers for Chrome extension + fix Save & Connect button
- Add CORS middleware to server.js allowing chrome-extension:// origins
  so the popup can make authenticated API requests without browser blocking
- Fix popup.js saveSettings(): require password on save, call login() directly
  instead of tryConnect() to avoid password-not-found loop
- Fix init(): open settings panel automatically if no saved token, so users
  know they need to enter credentials after first install or session expiry
- Don't persist password to chrome.storage (security), use remove('token')
  instead of set({token:null}) to properly clear the old session

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 21:30:17 -04:00
08c138ca46 Fix extension icons and AMPP autofill
- Generate missing chrome-extension/images/ icons (16, 48, 128px)
  that were absent from repo, causing 'Could not load manifest' error
- Fix AMPP API key field: add readonly+onfocus to block Bitwarden/browser autofill

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 21:05:46 -04:00
017d73f48c Fix S3 config form: autofill, region default, secret field
- Add readonly+onfocus trick to prevent browser autofilling secret key with garbage
- Set region value="us-east-1" so it always has a real default, not just placeholder
- loadS3Config always clears secret field and sets contextual placeholder
- Secret hint now clearly shows saved vs not-saved state

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 20:39:22 -04:00
d0525eb718 Fix extension 404, simplify UDP/relay UI
- Add chrome-extension/ to Dockerfile COPY (was missing, caused 404 on download)
- Remove UDP Relay tab from admin panel (relay is server-side, no user config needed)
- Remove upload mode toggle buttons, replace with clean inline status bar
- Extension panel: drop relay port-forwarding note, simplify to 'extension required' message
- UDP hint shown inline only when extension is detected in browser

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 20:32:25 -04:00
b393eca960 Redesign folder UI, VPM branding, and auto theme
- Replace chip-pill folder selector with clean vertical tree list
- VPM text wordmark replaces vpm-logo.png in login + header (no PNG/invert hack)
- Wild Dragon logo/icon retained only on favicon and splash animation
- Auto-detect prefers-color-scheme on first load (no longer defaults to dark)
- System theme changes update UI if user hasn't manually toggled
- Remove dragon icon from login card and app header

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 20:26:51 -04:00