3152 Commits

Author SHA1 Message Date
Andrés Moya
06c9a18ab0
🔧 Revert migration for tokens with clashing names (#9950)
* Revert "🐛 Detect duplicated token names in the whole library (#9034)"

This reverts commit 61cd7573553b1c5e9fc2d7300cf9b2c36b4dcbb6.

* 🔧 Preserve some enhancements and fixes that are still valid

* 🔧 Fix broken integration tests
2026-06-02 09:09:58 +02:00
Andrey Antukh
4a8fb5af53 Merge remote-tracking branch 'origin/staging' into develop 2026-06-01 13:15:57 +02:00
Andrey Antukh
c5de4c27b0 Merge remote-tracking branch 'origin/main' into staging 2026-06-01 12:57:39 +02:00
Alejandro Alonso
88f2366c6f
🎉 Enable render switch and wasm info by default and simplify feature helpers to use pre-computed features set (#9942)
The setup-wasm-features function is the single source of truth for
    resolving the renderer choice (URL param > profile preference > team
    flags), storing the result in state[:features]. Several helpers were
    re-deriving the same priority chain independently, duplicating logic:

    - wasm-enabled?, wasm-url-override, wasm-url-override-ref
    - enabled-by-flags?, enabled-without-migration?

    This change removes all duplicated helpers and simplifies the
    remaining functions to rely exclusively on the pre-computed
    :features set:

    - active-feature? — now just checks (contains? (:features state)
      feature) without special-casing render-wasm/v1
    - use-feature — uses the reactive features-ref for all features
    - initialize/recompute-features effects — use the local features
      binding directly

    Since :features is rebuilt by setup-wasm-features on every
    initialization and recompute, this preserves correctness while
    eliminating ~50 lines of duplicated code.
2026-06-01 12:52:34 +02:00
John Eismeier
c156559f2c
📚 Fix several typos on code comments and messages (#9946)
Signed-off-by: John E <jeis4wpi@outlook.com>
2026-06-01 09:43:07 +02:00
Luis de Dios
0b56fd2f77
🐛 Fix locked flex and grid elements cannot be selected in viewer role (#9865)
* 🐛 Fix locked flex and grid elements cannot be selected in viewer role

*  Add playwright test
2026-06-01 08:30:27 +02:00
Andrés Moya
7e6884e330
🐛 Fix error when copy & paste a swapped copy (#9934) 2026-05-29 13:36:17 +02:00
Jeff
bec21e69e6
🐛 Preserve explicit hide-in-viewer when adding prototype interactions (#9695)
`cls/show-in-viewer` unconditionally dissoc'ed `:hide-in-viewer` on the
interaction destination, so every `add-interaction`, `add-new-interaction`,
and `update-interaction` call silently re-enabled the destination's
view-mode visibility — even when the user had just deliberately hidden
that frame. Reporter (#9049) hid a board, dragged a prototype arrow at
it, and watched the board reappear in View Mode.

Make `show-in-viewer` a no-op when the destination already has
`:hide-in-viewer true`. The auto-unhide still fires on destinations with
no explicit hide flag (the original ergonomic — new prototype targets
default to visible), but explicit user intent is now preserved across
interaction-add / interaction-update.

Behaviour change: dropping the auto-unhide on explicitly-hidden
destinations matches the reporter's expectation ("nothing would show up
in View Mode unless explicitly marked as such") and the surrounding
`:hide-in-viewer`-aware UI in `measures.cljs`, which already lets users
toggle the same property directly.

Closes #9049.

Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-05-29 11:31:59 +02:00
Yamila Moreno
ddba2ffa75
📎 Update Kaleidos Copyright (#9929) 2026-05-29 11:24:58 +02:00
Chan
ac3950e36c
🐛 Fix CORS middleware reflecting arbitrary origins (#9675)
*  Align profile and dashboard files with penpot develop

* 🐛 Fix CORS origin allowlist for issue #9659

---------

Signed-off-by: Chan <101856681+enjoyandlove@users.noreply.github.com>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-05-29 11:23:16 +02:00
Pablo Alba
aa996c5118
🐛 Fix nested components becomes flat after reset (#9841) 2026-05-28 15:57:35 +02:00
Andrés Moya
1f35f57258
🐛 Fix DTCG token import discriminator and group-level $type inheritance (#9912)
* 🐛 Fix DTCG token import discriminator and group-level $type inheritance

Closes #8342.

The DTCG Community Group Final Report (W3C, 2025-10-28) specifies:

  "The presence of a $value property definitively identifies an object
   as a token."

  "A token's type can be specified by the optional $type property [...]
   Furthermore, the $type property on a group applies to all tokens
   nested within that group."

Two bugs in `common/src/app/common/types/tokens_lib.cljc` violate the
spec and silently break import of any third-party DTCG file that uses
group-level type inheritance:

1. `flatten-nested-tokens-json` used `(not (contains? v "$type"))` as
   the group-vs-token discriminator. A group node carrying only a
   `$type` (to set a default for child tokens) was misidentified as a
   token, then immediately discarded because it had no `$value`.

2. `schema:dtcg-node` declared both `$type` and `$value` as required,
   so even after the discriminator was fixed any leaf token that
   relied on group-level type inheritance failed `dtcg-node?`
   validation and never reached the parser.

The combined effect: importing a spec-compliant DTCG file that
expressed types at the group level produced a TokensLib with no
tokens at all, because every leaf was discarded as "unknown type".

Penpot-exported files were unaffected because Penpot always emits
both `$type` and `$value` on every token and never attaches `$type`
to a group, so the existing tests covered only the inline-type
shape.

- `schema:dtcg-node`: mark `$type` optional.
- `flatten-nested-tokens-json`: use `$value` as the discriminator
  (anything without `$value` is a group), accept an optional
  `inherited-type` accumulator that carries the nearest enclosing
  group `$type` down through recursion, and resolve a token's type
  from its own `$type` first, falling back to the inherited type.
  A token's own `$type` always wins over the inherited one (per
  spec).

Added `parse-dtcg-group-type-inheritance` covering both cases:
- group `$type` is inherited by tokens that don't declare their own
  (`colors.red`, `colors.blue`, `space.small`)
- token `$type` overrides the inherited group `$type`
  (`colors.danger`, `space.large`)

Existing DTCG round-trip tests continue to pass because they all
declare `$type` at the token level, which the new code still honours.

CHANGES.md entry added under the 2.17.0 Bugs-fixed section.

* 📚 Do not update CHANGES.md

We are changing the procedures to not update the changelog on each PR. Instead, we use github tracking to check what issues come in a release, and update the changelog automatically in a batch.

Signed-off-by: Andrés Moya <hirunatan@hammo.org>

---------

Signed-off-by: Andrés Moya <hirunatan@hammo.org>
Co-authored-by: MilosM348 <milos.milic001@outlook.com>
2026-05-28 11:01:11 +02:00
Belén Albeza
0dd40776f8
🐛 Fix default path stroke thickness 2026-05-27 14:47:11 +02:00
Andrey Antukh
3858993a57 Merge remote-tracking branch 'origin/staging' into develop 2026-05-27 13:37:02 +02:00
Andrey Antukh
40ce360c99
Improve performance and fix orphan detection in validate-file (#9789)
*  Improve performance and fix orphan detection in validate-file

- Add `*ref-shape-cache*` dynamic var to memoize `find-ref-shape`
  lookups per page, avoiding repeated O(depth) ancestor walks.
- Add `*children-sets*` pre-computed maps for O(1) parent-child
  containment checks, replacing linear `some` scans.
- Short-circuit `inside-component-main?` when the shape context
  already implies a main component.
- Use single-pass reduce with early exit for duplicate detection
  (children, swap slots) instead of count/distinct or frequencies.
- Guard `check-missing-slot` to skip expensive `find-near-match`
  when the shape already has a swap slot.
- Refactor variant-set validation to use `run!` with direct `get`.
- Refactor `check-ref-cycles` to use a single `reduce-kv` pass.
- Fix `get-orphan-shapes`: the original `map` pipeline produced
  nils so orphan shapes were never validated; rewrite with
  `reduce-kv` for correct results.
- Add `validate-file-affected!` for change-scoped validation,
  replacing full file validation in `process-changes-and-validate`
  to only validate pages and components touched by the changes.

Signed-off-by: Andrey Antukh <niwi@niwi.nz>

*  Improved validation

---------

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Co-authored-by: alonso.torres <alonso.torres@kaleidos.net>
2026-05-27 12:36:21 +02:00
Pablo Alba
3cecc29276 🐛 Fix update library dialog when a component position changes
Do not show the library sync popup when the only differences are global x/y changes on library components. We now generate the actual sync changes and only notify if there are real redo-changes to apply.
Run cll/generate-sync-file-changes for candidate libraries and filter out those with empty :redo-changes. The expensive check is deferred via rx/timer 0 so it runs asynchronously and does not block the UI.
Why: Position-only changes are normalized during sync (via reposition-shape) and never propagate to copies; showing the popup in that case was a false positive.
Performance: The check is deferred to the next tick to avoid UI stutter on large files with many libraries.
2026-05-27 11:22:57 +02:00
Belén Albeza
34f30e38aa
🐛 Fix migrations throwing exception on corrupted file (#9868) 2026-05-26 12:07:22 +02:00
María Valderrama
87384aaccd 🐛 Fix nitrate delete and leave org flow 2026-05-25 14:39:03 +02:00
Pablo Alba
dac98c0625 Add nitrate add team members permission 2026-05-23 17:18:27 +02:00
Alonso Torres
a7b17f54f1
🐛 Fix problem of path position on variant change (#9801) 2026-05-21 16:39:26 +02:00
Michael Panchenko
cec90416c2 Improve common JS test runner
Add focused common JavaScript test execution with log-level control and a quiet test wrapper matching the frontend workflow.

Update developer docs and testing memories to reflect the common/frontend test split, and document why runner helper extraction is deferred.

Signed-off-by: Codex <codex@openai.com>
2026-05-21 14:20:10 +02:00
Dominik Jain
63e7df5fda Add structured memories for agents
Memories use a system of progressive disclosure:
Starting from a root memory, memories reference other memories using explicit
references.

The new system of hierarchical memories replaces AGENTS.md files.

GitHub #9215

Co-authored-by: Michael Panchenko <michael.panchenko@oraios-ai.de>
Co-authored-by: Codex <codex@openai.com>
2026-05-21 14:20:10 +02:00
Eva Marco
2c453e4a00
🎉 Add dash and gap inputs for dashed strokes (#9765)
*  Add dash and gap customization for dashed strokes

Signed-off-by: eureka0928 <meobius123@gmail.com>

* ♻️ Change old numeric-inputs for new components

---------

Signed-off-by: eureka0928 <meobius123@gmail.com>
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Co-authored-by: eureka0928 <meobius123@gmail.com>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
Co-authored-by: Alejandro Alonso <alejandro.alonso@kaleidos.net>
2026-05-21 13:52:01 +02:00
Belén Albeza
3512a57df7
🐛 Fix referential integrity data in old files (#9771) 2026-05-21 11:18:13 +02:00
María Valderrama
a157ecdc5b
Add nitrate advanced permissions for invite to teams
*  Add nitrate advanced permissions for invite to teams

* 📎 Code review
2026-05-20 16:02:37 +02:00
Andrey Antukh
d0cc859bc2
Migrate svg-attrs, optimize set-shape-svg-attrs, filter invalid URLs (#9118)
*  Add svg-attrs casing fix migration

*  Optimize set-shape-svg-attrs by removing redundant operations

- Remove backward compatibility for kebab-case SVG attribute keys
  (fill-rule, stroke-linecap, stroke-linejoin) since svg-attrs are
  already normalized to camelCase by the attrs->props migration.
- Remove unnecessary select-keys filtering and intermediate map
  construction (dissoc :style + merge style).
- Directly extract values from style and attrs using or, avoiding
  any intermediate map allocation.

Signed-off-by: Andrey Antukh <niwi@niwi.nz>

* 🐛 Filter non-http(s) URLs in upload-images to prevent invalid calls

Skip upload for image items that are not data URIs and do not have
an http:// or https:// URL, avoiding unnecessary RPC calls with
invalid URLs to create-file-media-object-from-url.

Signed-off-by: Andrey Antukh <niwi@niwi.nz>

---------

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-05-19 17:41:41 +02:00
Dexterity
bcc0b0d313
Validate shape on add-object to catch malformed inputs early (#9291)
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-05-19 17:37:48 +02:00
Andrey Antukh
6f41a2b729 Merge remote-tracking branch 'origin/staging' into develop 2026-05-18 15:24:02 +02:00
Pablo Alba
ddfe2f7406 Remove nitrate teams with expired license from the teams list 2026-05-18 14:37:38 +02:00
Andrés Moya
82169bc0a3
🐛 Fix loss of swap slot in some cases of variant switch (#9147)
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-05-18 14:25:32 +02:00
María Valderrama
637ff3005a Add nitrate advanced permissions for move teams 2026-05-18 13:40:30 +02:00
Andrés Moya
25ee8dee78
🐛 Fix editing a text element detaches applied tokens (#9525) 2026-05-18 12:28:48 +02:00
Andrey Antukh
d620c86053 Merge remote-tracking branch 'origin/staging' into develop 2026-05-15 11:58:06 +02:00
María Valderrama
e3df1d6f1f Restrict team delete to owners, prep org-owner flow 2026-05-14 19:30:03 +02:00
Andrey Antukh
9021544c05 Merge remote-tracking branch 'origin/main' into staging 2026-05-14 15:24:29 +02:00
Andrey Antukh
67d9567971
🐛 Prevent CSS injection vulnerability in font family names
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>
2026-05-14 13:46:02 +02:00
Andrey Antukh
52588412c7 Merge remote-tracking branch 'origin/staging' into develop 2026-05-14 11:12:01 +02:00
Andrey Antukh
d78074307f Merge remote-tracking branch 'origin/main' into staging 2026-05-14 11:07:42 +02:00
Andrey Antukh
55dd6d2b00 🔧 Add cache to github tests CI worflow. (#9621)
*  Remove usage of RELEASE placeholder on deps.edn

* 🔧 Add Maven cache to CI

---------

Co-authored-by: Yamila Moreno <yamila.moreno@kaleidos.net>
2026-05-14 10:54:22 +02:00
Andrey Antukh
e9bec0a13b
🔧 Add cache to github tests CI worflow. (#9621)
*  Remove usage of RELEASE placeholder on deps.edn

* 🔧 Add Maven cache to CI

---------

Co-authored-by: Yamila Moreno <yamila.moreno@kaleidos.net>
2026-05-14 10:53:05 +02:00
Andrey Antukh
da85e02a6f
⬆️ Update dependencies (#9597)
* ⬆️ Update dependencies

* 📎 Fix playwright dep
2026-05-13 14:14:10 +02:00
Andrey Antukh
947f6d392d
🎉 Add chunked upload support for font variants (#9551)
*  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>
2026-05-12 18:30:19 +02:00
Michael Panchenko
7fb19fc1a2
🐛 Fix float comparison #14070 (#9434)
* 📎 Add test that surfaces the bug described in #14070

The bug: alt-drag-duplicating a variant master into the variant container
auto-creates a new variant component cloned from the source
via duplicate-component, which preserves :touched on every cloned shape.
The resulting copy's children inherit those :geometry-group touched flags
through add-touched-from-ref-chain on switch.

variants-switch -> component-swap (keep-touched? true) -> generate-keep-touched
then runs update-attrs-on-switch for each touched child. The new shape's
:y is correctly skipped by the per-attr "different masters" guard, but
:selrect/:points fall through to a width/height-based safety check that
uses exact equality. In practice, the alt-drag modifier path leaves a
sub-pixel drift in :width on the copy, so equal-geometry? returns false,
the safety check is bypassed, and the :else branch copies the source
variant's :selrect verbatim onto the freshly instantiated target shape.
The shape ends up with :y from the target master but :selrect.y from the
source — the renderer reads :selrect, so the child appears at the source
position inside a parent that has resized to the target's dimensions:
the visible "button cut off" symptom.

The new test sets up a variant container whose children are themselves
component copies (matching production: variant masters' children carry
:touched), introduces the same kind of width drift on the copy that the
alt-drag path produces, and runs the swap directly via the existing
test harness. It asserts (a) :y matches the target, (b) :selrect.y
matches the target, and (c) :y and :selrect.y agree. With the current
code (a) passes and (b)/(c) fail — capturing both the wrong value and
the internal inconsistency that causes the visible regression.

* 🐛 Fix #14070 by no longer comparing floats for exact equality in equal-geometry?
2026-05-11 15:17:48 +02:00
Dexterity
e30e5906c8
♻️ Remove unreachable try/catch in hex->hsl (#9245) 2026-05-10 19:28:12 +02:00
Andrey Antukh
60c718eba1 Merge remote-tracking branch 'origin/staging' into develop 2026-05-10 09:20:27 +02:00
Andrey Antukh
10a23a6869 Merge remote-tracking branch 'origin/main' into staging 2026-05-10 09:16:41 +02:00
Pablo Alba
f3c2c0bee2 Change team organization structure on state 2026-05-08 11:18:26 +02:00
Eva Marco
cccd7bc6de
🐛 Fix pixel grid color row (#9360) 2026-05-08 11:06:56 +02:00
Andrey Antukh
279231240d
🐛 Harden outbound HTTP requests against SSRF and restrict assets handlers (#9390)
* ⬆️ Update root deps

* 🐛 Harden outbound HTTP requests against SSRF and restrict unauthenticated asset access

- Add app.util.ssrf URL/host validator that resolves hostnames and blocks
  loopback, link-local, site-local, cloud metadata, and operator-supplied CIDRs
- Add app.media.sanitize image EOF truncator that strips trailing data after
  PNG IEND, JPEG EOI, GIF trailer, and WebP RIFF markers
- Disable HTTP client auto-redirect; add req-with-redirects! helper that
  revalidates every redirect hop against the SSRF blocklist
- Wire SSRF validation and EOF sanitization into media/download-image
- Validate webhook URLs and OIDC profile picture URLs against SSRF
- Restrict /assets/by-id to require authentication for non-public buckets
  (profile) while keeping public access for file-media-object,
  file-object-thumbnail, team-font-variant, and file-data-fragment
- Add config knobs: ssrf-protection-enabled, ssrf-allowed-hosts,
  ssrf-extra-blocked-cidrs

Signed-off-by: Andrey Antukh <niwi@niwi.nz>

---------

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-05-08 09:18:22 +02:00
Andrés Moya
61cd757355
🐛 Detect duplicated token names in the whole library (#9034)
* 🐛 Detect duplicated token names in the whole library

* 🔧 Review comments

* 🐛 Prevent and repair token themes with inexistent sets

* 🔧 Convert tokens lib migration into file migration
2026-05-08 08:26:15 +02:00