feat(packages): implement multipart .xar upload on POST /api/packages/install#49
Open
joewiz wants to merge 2 commits into
Open
feat(packages): implement multipart .xar upload on POST /api/packages/install#49joewiz wants to merge 2 commits into
joewiz wants to merge 2 commits into
Conversation
…/install
The endpoint declared a multipart/form-data body with a binary `file`
field, but packages:install only implemented the JSON registry path
({name,url,version} -> repo:install-and-deploy); a file upload fell
through to {"error":"Missing required fields: name, url"}. So clients
could install from a registry by name but could not upload and install a
locally built .xar -- the headline deploy-a-built-app workflow for
editor clients (Oxygen plugin, eXide, vscode, notebook).
Dispatch on the presence of a `file` part: multipart upload ->
packages:install-from-upload (store bytes to /db/system/repo,
repo:install-and-deploy-from-db, clean up the temp .xar, return
name/version/target from the deployed descriptor); else the existing
JSON registry path (refactored into packages:install-from-registry,
unchanged). repo:install-and-deploy-from-db is idempotent, so
re-uploading a new build of an installed package replaces it without
explicit pre-removal. Malformed uploads return a caught
{success:false, error:{...}} with HTTP 400, not a 500.
Verified: multipart upload of a fixture .xar installs + deploys (appears
in GET /api/packages), re-upload replaces idempotently, temp .xar is
cleaned up, the JSON path is unchanged, and a malformed JSON body still
errors as before.
Cypress: 5 new tests in packages.cy.js. The happy-path upload is driven
via cy.exec + curl rather than cy.request -- Cypress mangles raw binary
request bodies (Buffer<->JSON serialization), so a real multipart file
upload can't go through cy.request reliably; curl sends correct bytes.
Fixture: src/test/cypress/fixtures/test-multipart.xar (566-byte minimal
EXPath package).
Refs oxex multipart-install tasking (2026-06-06).
…pload Align the multipart upload path with how xst, the dashboard, and atom-editor-support install a .xar: - Pass the public registry's /find endpoint to repo:install-and-deploy-from-db so transitive dependencies are resolved from the registry during install (previously the 1-arg form was used, so an upload with unmet dependencies failed instead of resolving them). - Undeploy + remove any previously installed copy of the same package before reinstalling, rather than relying solely on install-and-deploy-from-db idempotency. The package name is read from the upload's expath-pkg.xml via a new packages:xar-package-name helper. Verified on a clean eXist 7.0.0-beta3: fresh install, re-install (pre-removal path), and temp-.xar cleanup all succeed; xar-package-name extracts the package name from the uploaded descriptor. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
[This PR was co-authored with Claude Code. -Joe]
Implement multipart
.xarupload onPOST /api/packages/installFrom the existdb-oxygen-plugin (oxex) Package Manager tasking. The endpoint already declared a
multipart/form-databody with a binaryfilefield, butpackages:installonly implemented the JSON registry path ({name, url, version}→repo:install-and-deploy). A file upload fell straight through to{"error": "Missing required fields: name, url"}— so clients could install from a registry by name but could not upload and install a locally built.xar, the headline deploy-a-built-app workflow for editor clients.Change
Dispatch on the presence of a
filepart:packages:install-from-upload: store the bytes to/db/system/repo,repo:install-and-deploy-from-db, clean up the temp.xar, and returnname/version/targetfrom the deployed descriptor.repo:install-and-deploy-from-dbis idempotent, so re-uploading a new build of an already-installed package replaces it — no explicit pre-removal needed. Malformed uploads return a caught{success: false, error: {...}}with HTTP 400, not a 500.packages:install-from-registry, behavior unchanged).Response shape matches across both paths:
{ success, result: { name, version, target } }.Verification
.xarinstalls + deploys (appears inGET /api/packages); re-upload replaces idempotently; temp.xaris cleaned up; JSON path unchanged; malformed JSON still errors as before. Verified on the integration instance and deployed to the oxex test instance.packages.cy.js. The happy-path upload is driven viacy.exec+ curl rather thancy.request: Cypress mangles raw binary request bodies (Buffer↔JSON serialization), so a real multipart file upload can't go throughcy.requestreliably — curl sends correct bytes. Fixture:src/test/cypress/fixtures/test-multipart.xar(566-byte minimal EXPath package, force-added past the*.xargitignore).api.json already declared the multipart requestBody and the 200/400 responses, so no spec change was needed.
Downstream
Unblocks the oxygen plugin's "Install
.xar…" file-chooser; same local-deploy capability for eXide, vscode-existdb, and the notebook kernel over the shared HTTP contract.