Implement penpot_import_library (multipart upload plus SSE result) #203
Labels
No labels
bug
chore
documentation
enhancement
feature
ready
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
david/pi-extensions-and-skills#203
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Implement
penpot_import_library: upload a committed.penpotlibrary artifact into a nominated project as a new file, using a multipart request with kebab-case field names and reading the created file ids from the SSEendframe. This is how the design system's component library gets into a project without hand-authoring components over the API.Background
Depends on: #202
Component authoring over the API (
add-componentwith a main-instance marking) is the riskiest part of the API surface, and it is deliberately out of scope. Instead the component library is authored once in the Penpot UI, exported, and committed to the repo as an artifact — the extension imports it per project, repeatedly and reproducibly.Confirmed contract on Penpot 2.17:
import-binfileis a multipart request. Field names are kebab-case:name,project-id,version,file(the upload itself). An optionalfile-idparameter also exists on 2.17.versiondefaults to3.event: progressframes and terminates withevent: endwhosedata:is a Transit vector of the created file ids (["~u<uuid>"]).Two safety properties matter here:
registerCreatedFile(fileId, projectId)) — a file the extension created in a nominated project is exactly the case the guard is designed to permit writes to.Documentation Required
A separate process downloads these into the listed folders before this issue is implemented. Check the folders for the actual reference material before starting.
docs/reference/penpot-api/<PENPOT_URL>/api/main/doc/openapi.json—import-binfile's exact parameters (including whetherfile-idexists on this instance) and its declared response type..penpotimport flow from the user's perspective: what the file contains and what appears after import.docs/reference/transit-format/endpayload's Transit vector and UUID tags are encoded (implemented in the previous step).docs/reference/nodejs/.penpotartifact.docs/reference/pi-coding-agent/anddocs/reference/typebox/details.Implementation Details
Create
extensions/penpot/src/tools/importLibrary.ts(reusingsrc/binfile.tsandsrc/media.ts-style multipart construction) and register the tool.Parameters:
project_id(string, required) — the project to import into.path(string, required) — path to the.penpotartifact (default it to the repo artifact underskills/penpot/assets/, but allow an explicit path).name(string, optional) — the imported file's name; default the artifact's basename.file_id(string, optional) — only pass through if the instance's spec lists it; omit otherwise.Behaviour:
name,project-id,version,file), no JSONContent-Typeheader.endframe via the Transit decoder.endpayload to a list of created file ids. If it decodes to something unexpected, fail loudly with the raw payload (do not guess).createdFilesinproject_id.detailsplus a text summary; when more than one file is created, say so explicitly rather than assuming one.decodeTransitError.Acceptance Criteria
name,project-id,version,file) and sends no JSONContent-Typeheader.endframe's Transit payload is decoded into the created file id(s) and returned indetails.endpayload fails loudly with the raw payload attached.endframe fails with the accumulated raw frames attached.penpot_committo it is permitted without a separate authorisation call.end-payload normalisation, the guard refusal path and the permission error mapping, with a stubbed client.Test Plan
Live validation (requires
PENPOT_URL/PENPOT_TOKEN, scratch project):.penpotartifact (or any known-good.penpotexport) into it.penpot_commitagainst the newly created file after staging a colour, and confirm the guard permits it because the file was registered as created.pi-loop opened and merged a pull request for this issue: #236