Sync foss-main with upstream Penpot 2.15.3#25
Merged
Conversation
In `preview-next-point`, `st/get-path` was called without extra keys, which returns the full Shape record. That value was then passed directly to `path/next-node` as its `content` argument. `path/next-node` delegates to `impl/path-data`, which only accepts a `PathData` instance, `nil`, or a sequential collection of segments. A Shape record matches none of those cases, so `path-data` threw "unexpected data" every time the user moved the mouse while drawing a path. The fix is to call `(st/get-path state :content)` so that only the `:content` field (a `PathData` instance) is extracted and forwarded to `path/next-node`.
…ssue 🐛 Fix path drawing preview passing shape instead of content to next-node
* 🐛 Add webp export format to plugin types Align plugin API typings with runtime export support by including 'webp' in 'Export.type' and updating the exported formats documentation. Signed-off-by: Marek Hrabe <marekhrabe@me.com> * 📚 Add plugin-types changelog entry for missing webp export format Signed-off-by: Marek Hrabe <marekhrabe@me.com> --------- Signed-off-by: Marek Hrabe <marekhrabe@me.com> Co-authored-by: Andrey Antukh <niwi@niwi.nz>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
…enpot#8929) The backtrace-tokens-tree function used a namespaced keyword :temp/id which clj->js converted to the JS property "temp/id". The sd-token-uuid function then tried to access .id on the sd-token top-level object, which was undefined, causing "Cannot read properties of undefined (reading uuid)". Fix by using the existing token :id instead of generating a temporary one, and read it from sd-token.original (matching sd-token-name pattern).
Add normalize-coord helper function that clamps coordinate values to max-safe-int and min-safe-int bounds when reading segments from PathData binary buffer. Applies normalization to read-segment, impl-walk, impl-reduce, and impl-lookup functions to ensure coordinates remain within safe bounds. Add corresponding test to verify out-of-bounds coordinates are properly clamped when reading PathData. Signed-off-by: Andrey Antukh <niwi@niwi.nz>
The CLJS implementation of PathData's -nth protocol method had swapped arguments in the 3-arity version (with default value). The call (d/in-range? i size) should be (d/in-range? size i) to match the CLJ implementation. With swapped args, valid indices always returned the default value, and invalid indices attempted out-of-bounds buffer reads.
The metadata key was misspelled as :cosnt instead of :const, preventing the compiler from recognizing the Var as a compile-time constant.
- Fix 'conten' typo to 'content' in path.cljc docstring
- Fix 'curvle' typo to 'curve' in shape_to_path.cljc docstring
- Replace confusing XOR-style filter with readable
(contains? #{:line-to :curve-to} ...) in bool.cljc
- Align handler-indices and opposite-index docstrings with
matching API in path.cljc
…enpot#8937) Co-authored-by: Andrey Antukh <niwi@niwi.nz>
Fixes three concrete builder issues in common/files/builder:\n- Use bool type from shape when selecting style source for difference bools\n- Persist :strokes correctly (fix typo :stroks)\n- Validate add-file-media params after assigning default id\n\nAlso adds regression tests in common-tests.files-builder-test and registers them in runner. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: raguirref <ricardoaguirredelafuente@gmail.com>
Remove unrelated local pid file that was accidentally included in previous commit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: raguirref <ricardoaguirredelafuente@gmail.com>
…-media-validation 🐛 Fix builder bool styles and media validation
Refactor use-portal-container to allocate one persistent <div> per logical category (:modal, :popup, :tooltip, :default) instead of creating a new div for every component instance. This keeps the DOM clean with at most four fixed portal containers and eliminates the arbitrary growth of empty <div> elements on document.body while preserving the removeChild race condition fix.
lambdaisland/uri's query-string->map uses :multikeys :duplicates by default: a key that appears once yields a plain string, but the same key repeated yields a vector. cljs.core/parse-long only accepts strings and therefore threw "Expected string, got: object" whenever a URL contained a duplicate 'index' parameter. Add rt/get-query-param to app.main.router. The helper returns the scalar value of a query param key, taking the last element when the value is a sequential (i.e. the key was repeated). Use it at every call site that feeds a query-param value into parse-long, in both app.main.ui (page*) and app.main.data.viewer.
…selected The 'Move to' menu in the dashboard file context menu only filtered out the first selected file's project from the available target list. When multiple files from different projects were selected, the other files' projects still appeared as valid targets, causing a 400 'cant-move-to-same-project' backend error. Now all selected files' project IDs are collected and excluded from the available target projects.
The key :podition was used instead of :position when updating the id-from cell in swap-shapes, silently discarding the position value and leaving the cell's :position as nil after every swap. Signed-off-by: Andrey Antukh <niwi@niwi.nz>
… stops When no gradient stop satisfies (<= offset (:offset %)), d/index-of-pred returns nil. The previous code called (dec nil) in the start binding before the nil check, throwing a NullPointerException/ClassCastException. Guard the start binding with a cond that handles nil before attempting dec. Signed-off-by: Andrey Antukh <niwi@niwi.nz>
get-children-rec passed the original children vector to each recursive call instead of the updated one that already includes the current shape. This caused descendant results to be accumulated from the wrong starting point, losing intermediate shapes. Pass children' (which includes the current shape) into every recursive call. Signed-off-by: Andrey Antukh <niwi@niwi.nz>
font-weight-keys was listed twice in the set/union call for typography-keys, a copy-paste error. The duplicate entry has no functional effect (sets deduplicate), but it is misleading and suggests a missing key such as font-style-keys in its place. Signed-off-by: Andrey Antukh <niwi@niwi.nz>
\`(get "type" shadow)\` always returns nil because the map and key arguments were swapped. The correct call is \`(get shadow "type")\`, which allows the legacy innerShadow detection to work correctly. Update the test expectation accordingly. Signed-off-by: Andrey Antukh <niwi@niwi.nz>
`(mapcat collect-main-shapes children objects)` passes `objects` as a second parallel collection instead of threading it as the second argument to `collect-main-shapes` for each child. Fix by using an anonymous fn: `(mapcat #(collect-main-shapes % objects) children)`. Signed-off-by: Andrey Antukh <niwi@niwi.nz>
* ✨ Add additional logging and validation for image upload
* 🎉 Add chunked upload support for font variants
Extend the font variant upload flow across frontend, backend, and common
to support the standardized chunked upload protocol.
**Backend:**
- Add \`:font-max-file-size\` config default (30 MiB) and schema entry
- Add \`validate-font-size!\` in \`media.clj\` (mirrors
\`validate-media-size!\`, raises \`:font-max-file-size-reached\`)
- Extend \`schema:create-font-variant\` to accept either \`:data\`
(legacy bytes or chunk-vector) or \`:uploads\` (new chunked session
map), with a validator requiring exactly one
- Add \`prepare-font-data-from-uploads\`: assembles each chunked
session via \`cmedia/assemble-chunks\`, validates type+size
- Add \`prepare-font-data-from-legacy\`: normalises legacy byte/chunk
entries, writing to a tempfile (joining via SequenceInputStream),
validates type+size
- Add structured logging ("init"/"end") with \`:size\`, \`:mtypes\`,
and \`:elapsed\` in \`create-font-variant\`
**Frontend:**
- \`upload-blob-chunked\` accepts a per-caller \`:chunk-size\` option
- Add \`font-upload-chunk-size\` (10 MiB) and \`upload-font-variant\`
fn that uploads each mtype as a separate chunked session
- \`on-upload*\` in dashboard fonts now calls \`upload-font-variant\`
instead of issuing \`create-font-variant\` RPC directly
- \`process-upload\` stores raw ArrayBuffer instead of chunking
client-side
**Common:**
- Replace \`"font/opentype"\` with \`"font/woff2"\` in \`font-types\`
**Tests:**
- 25 tests / 224 assertions covering all three upload paths (direct
bytes, legacy chunk-vector, new chunked sessions), size validation,
and media type validation
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
* 📎 Add a script for check the commit format locally
---------
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
* ⬆️ Update dependencies * 📎 Fix playwright dep
* ✨ Remove usage of RELEASE placeholder on deps.edn * 🔧 Add Maven cache to CI --------- Co-authored-by: Yamila Moreno <yamila.moreno@kaleidos.net>
Add escape-html function that escapes HTML special characters and apply it in the comment editor at four dom/set-html! call sites where user-provided text is inserted as innerHTML, preventing stored XSS. Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Add a shared `schema:font-family` whitelist validator in app.common.types.font that only allows letters, digits, spaces, hyphens, underscores, and dots in font family names. Apply the schema to create-font-variant and update-font RPC endpoints on the backend, and add client-side validation in the dashboard fonts UI. Include unit tests for the schema and integration tests for the RPC handlers. Signed-off-by: Andrey Antukh <niwi@niwi.nz>
# Conflicts: # backend/test/backend_tests/rpc_profile_test.clj
Author
|
Local build verified ✅
Test plan progress:
|
On macOS Docker Desktop, Node's fs.cpSync writes files in the bind mount with a com.docker.grpcfuse.ownership xattr declaring mode 200 even when the host inode is 644. The subsequent `cp -a` (and the original `rsync -avr`) then chmod the destination to 200, which lands on the real host inode and renders the bundle unreadable to anything outside the build container (Linux containers via gRPC-FUSE included). chmod-ing packages/server/dist before the copy rewrites the xattr to 644 while the host mode is still 644, so cp -a propagates the correct mode and the bundle is readable downstream. Behaviour on Linux hosts is unchanged: gRPC-FUSE only runs on macOS Docker Desktop; chmod -R is a no-op when modes are already correct. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…attr fix(mcp-build): normalize dist modes before cp -a (macOS gRPC-FUSE)
UsamaSadiq
approved these changes
May 20, 2026
aznszn
approved these changes
May 20, 2026
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.
Summary
2.15.3intofoss-main— first sync since2.14.2.Conflict resolution
Only one file had a real conflict:
backend/test/backend_tests/rpc_profile_test.clj.email-change-requesttest toemail-change-request-is-disabledand rewrote its body to assert:email-managed-by-external-idprejection (matchesrpc/commands/profile.clj).email-change-request-is-disabledtest + docstring + assertions.Pressingly customizations verified post-merge
docker/images/files/nginx-entrypoint.sh—update_mpass_signout_url+MPASS_SIGNOUT_URLwiring intact.backend/src/app/rpc/commands/profile.clj—:email-managed-by-external-idprejection intact.backend/src/app/rpc/commands/verify_token.clj—:email-managed-by-external-idpbelt-and-suspenders intact.backend/src/app/http/auth_request.clj— X-Auth-Request session re-keying, auto-register, askii.ai default-email-domain all intact.Scope
442 files changed, +19076 / −6315 lines (upstream's diff between 2.14.2 and 2.15.3, plus the conflict resolution).
Test plan
make dev.build.penpot.frontend(kicked off locally; will update if it fails)https://design.foss.local.devreachable through mPass SSO after rebuild2.15.3-22-g5633682a2make dev.build.penpot.backend(slower; do separately)