Fase 5: serve and accept assets over HTTP on the daemon
Closes the gap the plan flagged as blocking the sync deletion: a web/mobile client had no way to read or write asset bytes at all (only db-sync's now end-of-life handlers touched platform/asset-*). Adds GET/PUT /v1/assets/:repo/:name on db_worker_node.cljs, backed by three new thread-api ops (asset-read-bytes/write-bytes/stat) that just call the existing Node platform.cljs asset-*-bytes! functions -- reusing the same JSON+transit /v1/invoke path already proven for export-db-binary, so no new binary RPC mechanism was needed. GET responses carry a real Content-Type (guessed from extension), a sha1 ETag, and immutable Cache-Control -- assets are content-addressed by filename, so this is safe to cache forever once fetched. Auth accepts ?token= as a fallback for a direct <img src>/browser navigation, same rationale as the SSE interim token, but as a genuine fallback alongside the Authorization header rather than replacing it (an early version of this made query-token exclusive with header auth, which 401'd every JS-driven fetch -- caught before committing, real end-to-end curl testing against a live daemon also caught a 500-instead-of-404 on missing assets and a never-firing 304 from a hyphenated JS property access that needed `aget` instead of `.-`). Client side: frontend.handler.assets/resolve-asset-real-path-url and <make-asset-url now resolve to the daemon's asset URL (with the server token) instead of an unreachable file:// path when a web/mobile client has a server configured (frontend.config/get-server-base-url) -- covers viewing existing assets. frontend.fs/write-asset-file! gets the matching upload path via a new frontend.persist-db.remote/upload-asset!, so pasting an asset from a web/mobile client no longer silently lands in frontend.fs.memory-fs and vanishes on reload. Server-side routes and round-trip verified end-to-end against a real daemon (curl) and with new automated tests (byte equality, content-type, etag/304, 404, repo-mismatch, auth-required). The client-side URL resolution changes could not be visually verified -- no browser in this environment -- only reviewed and compiled clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -23,6 +23,14 @@
|
||||
"/v1/import-db-binary?repo="
|
||||
(js/encodeURIComponent repo)))
|
||||
|
||||
(defn- asset-url
|
||||
[base-url repo file-name]
|
||||
(str (normalize-base-url base-url)
|
||||
"/v1/assets/"
|
||||
(js/encodeURIComponent repo)
|
||||
"/"
|
||||
(js/encodeURIComponent file-name)))
|
||||
|
||||
(defn- events-url
|
||||
"EventSource has no header API, so the bearer token travels as a query
|
||||
param here instead of the `Authorization` header every other request
|
||||
@@ -102,6 +110,26 @@
|
||||
:code (normalize-code (:code error))}
|
||||
error (assoc :error error))))))))
|
||||
|
||||
(defn upload-asset!
|
||||
"PUTs raw asset bytes to a db-worker-node daemon's /v1/assets/:repo/:name
|
||||
(see Fase 5 in docs/agent-guide). Used by frontend.fs/write-asset-file! for
|
||||
a web/mobile client, which has no local filesystem to write assets to --
|
||||
Electron keeps writing straight to disk via its own IPC instead."
|
||||
[{:keys [base-url auth-token fetch-fn]} repo file-name data]
|
||||
(p/let [{:keys [status body]} ((or fetch-fn default-fetch-json!)
|
||||
{:method "PUT"
|
||||
:url (asset-url base-url repo file-name)
|
||||
:headers (binary-headers auth-token)
|
||||
:body data})]
|
||||
(if (<= 200 status 299)
|
||||
true
|
||||
(let [parsed (parse-response-body body)
|
||||
error (:error parsed)]
|
||||
(throw (ex-info (or (:message error) "asset upload failed")
|
||||
(cond-> {:status status
|
||||
:code (normalize-code (:code error))}
|
||||
error (assoc :error error))))))))
|
||||
|
||||
(defn- decode-event
|
||||
[{:keys [type payload]}]
|
||||
(let [decoded (when (some? payload)
|
||||
|
||||
Reference in New Issue
Block a user