Commit Graph

277 Commits

Author SHA1 Message Date
Charles Bochet a884945aca fix(deps): remediate HIGH image vulns (multer, ws, nodemailer) (#21984)
## What

Clears the HIGH-severity AWS Inspector findings on the `twenty-server`
container image. All three have stable, in-range fixes — no prereleases.

| Package | From → To | CVE | Path |
|---------|-----------|-----|------|
| multer | 2.1.1 → **2.2.0** (resolution) | CVE-2026-5038, CVE-2026-5079
(DoS) | transitive via `@nestjs/platform-express` |
| ws | 8.20.1 → **8.21.0** (resolution) | CVE-2026-48779 | pinned by
`@nestjs/graphql` (8.21.0 already in tree) |
| nodemailer | 8.0.10 → **9.0.1** | GHSA-p6gq-j5cr-w38f | nested in
`imapflow`; bumped `imapflow` 1.3.6 → 1.4.2 which depends on nodemailer
9.0.1 |

## Notes

- **multer 2.2.0 is the stable fix.** The advisories
([CVE-2026-5038](https://advisories.gitlab.com/npm/multer/CVE-2026-5038/),
[CVE-2026-5079](https://advisories.gitlab.com/npm/multer/CVE-2026-5079/))
list both `2.2.0` and `3.0.0-alpha.2` as fixed; Inspector reported only
the `3.0.0-alpha.2` prerelease, but we stay on the stable 2.x line.
- **nodemailer:** the top-level dep was already `^9.0.1`; only
`imapflow`'s nested copy was stale. imapflow 1.4.0 still ships
nodemailer 8.0.10 and 1.4.1 ships 9.0.0 (< the 9.0.1 fix), so **1.4.2 is
the minimum** that pulls the patched nodemailer.
- Lockfile-only resolution for multer/ws (they're transitive); imapflow
is a direct dep bump. yarn.lock net-shrinks from deduping.

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21984?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
2026-06-23 00:54:46 +02:00
Abdullah. 6ae2170744 chore(deps): bump wrangler to 4.102.0 and drop the wrangler/esbuild resolution (#21930)
## chore(deps): bump wrangler to 4.102.0 and drop the `wrangler/esbuild`
resolution

Removes a now-redundant `resolutions` override (resolution **cleanup**,
identified by the resolutions audit). It does not close a Dependabot
alert — esbuild stays at `0.28.1` either way — but reduces the standing
override count by one, per the `//resolutions` policy of dropping each
entry once its parent ships a fixed range.

### What

The `wrangler/esbuild: 0.28.1` resolution existed because `wrangler`
exact-pinned a vulnerable esbuild (`0.27.3`). **wrangler 4.102.0 now
ships esbuild `0.28.1` natively**, and our workspaces declare `wrangler
^4.0.0`, so it resolves to the safe version on its own.

### How — parent-bump, then drop the override

- Bumped `wrangler` within `^4.0.0` to `4.102.0` (lockfile-only).
- Removed the `wrangler/esbuild` entry from `resolutions`.
- Updated the `//resolutions` doc: moved wrangler to the "fixed by
parent-bump" list and decremented the esbuild counts (seven → six
resolutions; six → five exact-pin parents).

### Verification

- No `esbuild 0.27.3` regression (wrangler 4.102.0 pins `0.28.1`); the
remaining six esbuild resolutions are unchanged.
- `//resolutions` doc is consistent with the `resolutions` object.
- Lockfile + package.json only; `yarn install --immutable` passes.
2026-06-22 10:26:15 +02:00
Abdullah. 569d887d1e [Website] Cut over to the rebuilt site (#21825)
Renaming the package so any further PRs directed to the website are
targeted to the reworked code instead of diverging. Once merged, I will
start preparing this for deployment to dev to test before releasing to
prod. Any improvements will also be applied to this package.

I avoided making significant changes to API routes so nothing breaks,
but will test it thoroughly today to confirm. That said, everything is
ported - double checked.

Big diff PR, impossible to review, but last one! No more rebuilds.
2026-06-19 10:22:46 +02:00
Abdullah. ba7b435885 fix(security): bump webpack-dev-server resolution to 5.2.5 (HMR WS interception) (#21818)
## fix(security): bump webpack-dev-server resolution to 5.2.5 (HMR WS
interception)

Resolves [Dependabot Alert
#1514](https://github.com/twentyhq/twenty/security/dependabot/1514).

### What

`webpack-dev-server` `< 5.2.5` is affected by
[GHSA-mx8g-39q3-5c79](https://github.com/advisories/GHSA-mx8g-39q3-5c79)
(**Moderate**) — HMR WebSocket interception via permissive user proxies.
Patched in `5.2.5`.

### How

`webpack-dev-server` is already force-resolved via a scoped
`resolutions` entry: its sole consumer `@electron-forge/plugin-webpack`
(latest 7.11.2 / 8.x alphas) still declares `webpack-dev-server ^4`, so
the resolution evicts the vulnerable 4.x line up to 5.x. The
newly-disclosed CVE affects the pinned `5.2.4`, so this **bumps the
existing scoped resolution `5.2.4 -> 5.2.5`** and updates its
`//resolutions` doc line — extending an already-documented, load-bearing
entry rather than adding a new one.

**Still-required check:** `@electron-forge/plugin-webpack` still
declares `^4`, so the resolution remains necessary (removing it would
regress to vulnerable 4.x).

### Verification

- `webpack-dev-server` resolves to a single `5.2.5` bucket; no `< 5.2.5`
remains.
- Not imported in our source (electron-forge build tooling only).
- `yarn install --immutable` passes.

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-06-19 07:17:23 +00:00
Abdullah. bebe03e453 fix(security): bump tar to 7.5.16 across lockfiles (PAX file smuggling) (#21813)
## fix(security): bump tar to 7.5.16 across lockfiles (PAX file
smuggling)

Resolves [#1472 1474 1476 1479 1481 1483 1485 1487 1489 1491 1493 1496
1498 1505](https://github.com/twentyhq/twenty/security/dependabot/1472
1474 1476 1479 1481 1483 1485 1487 1489 1491 1493 1496 1498 1505).

### What

`tar` (`node-tar`) `<= 7.5.15` applies a PAX size override to
intermediary GNU long-name/long-link headers, causing a tar-parser
interpretation differential (file smuggling). Patched in `7.5.16`.

### Why these alerts

The advisory is scanned across many independent Yarn projects, so it
surfaced as one alert per lockfile: the root `yarn.lock` plus 13
`packages/twenty-apps/**` lockfiles (each pulls `tar` transitively).

### How

- Refreshed `tar` to `7.5.16` in the root and all 13 app lockfiles —
they hold `tar` via `^7.5.x` ranges that already permit it, so this is
an in-range lockfile refresh (no override) via `yarn up -R tar`.
- The root additionally had `tar@7.5.15` exact-pinned by
`@mintlify/previewing`, which has **no upstream fix** (latest `4.0.1163`
still pins `7.5.15`). Added a scoped resolution
`@mintlify/previewing/tar -> ^7.5.16`, **extending the existing scoped
tar resolutions** already used for `@electron/rebuild` and
`@electron/node-gyp`.

### Not included

`seed-dependencies/yarn.lock` (alert #1500) is intentionally excluded:
that lockfile and its checksum constants are already modified by the
open form-data PR, so its `tar` bump will follow separately to avoid a
conflict.

### Verification

- No `tar <= 7.5.15` remains across the root or any app lockfile.
- `yarn install --immutable` passes.
2026-06-19 08:49:07 +02:00
Abdullah. 465eb05aaf Reworked website. (#21763)
twenty-website had accumulated structural problems that were cheaper to
fix by rebuilding than to refactor in place:
  
- Drift had no guardrails. Values were matched at call sites instead of
single-sourced, so things silently diverged — e.g. the radius token base
was wrong for days (every radius() consumer rendered double) because
nothing measured it against the old site's CSS variables.
- A whole tree escaped quality checks. src/lib/ (~9.8k lines) was never
format-checked, because oxfmt silently ignores directories named lib/.
- Inconsistent rhythm. Hero spacing varied 24–88px between pages
(CEO-flagged), because section spacing wasn't a token.
- Over-extraction. -config.ts sprawl pulled single-component
configuration out into the wrong place.
  
The goal: a ground-up rebuild where drift is structurally impossible,
held to a Linear / Railway / Notion / Attio quality bar. The old site is
treated as source of intent only — nothing is blindly ported; every
piece is re-decided and A/B-verified.

**Rebuild**
  
A full rebuild on Next 16 + Turbopack + Linaria (zero-runtime CSS),
~1,100 files. Marketing pages (home, product, pricing, partners +
marketplace, customers/case-studies, why-twenty, releases, legal), the
interactive AppPreview product mockup, the platform/visuals WebGL system
(engine + rigs, three code-split off every initial chunk), and the
standalone /halftone studio (the dev tool that generates the site's
halftone art — engine, exporters, and full UI ported as an isolated
island).
  
**Architecture & guarantees**
  
- Parity by construction. src/tokens/definitions.ts is the only file
with raw values; the :root CSS-variable block is generated from it at
build time and accessors derive var names through the same helpers —
derived alpha tokens appear in served CSS without ever being
hand-written.
- Mobile-first by API shape. mediaUp() is the only media helper (no
max-width helper exists, on purpose).
- Section rhythm is a token (RHYTHM.section) — the hero-spacing
inconsistency class is fixed by construction.
- Fluid type ramps interpolate font-size and line-height between
designed endpoints [390px → md]; TYPE_SCALE is the single source.
- three.js never enters an initial chunk — confined to platform/visuals
heavy zones, reached only via dynamic(ssr:false), enforced by
check-visual-bundle.
2026-06-18 11:55:24 +02:00
Raphaël Bosi 9c9c34fccf Remove twenty-ui-deprecated and migrate frontend to twenty-ui (#21596)
Migrates `twenty-front`, `twenty-sdk`, and
`twenty-front-component-renderer` from `twenty-ui-deprecated` to
`twenty-ui` (mechanical import swap — the packages have API parity) and
deletes the deprecated package along with its workspace/CI/config
wiring.

Also adds `@linaria/react`/`@linaria/core` as direct deps of
`twenty-front` (it used them transitively via the deprecated package).

Note: move the required status check from `ci-ui-status-check` to
`ci-new-ui-status-check`.

Argos: the Storybook box-model/button-reset baseline shift (the bulk of
the visual diffs) is isolated in #21665 — Storybook now loads
twenty-ui's global `reset.scss`, which the production app already ships.
Once #21665 merges and this branch is rebased, the remaining Argos diffs
are component-level visual-parity items only.
2026-06-17 09:41:11 +00:00
Charles Bochet fb4608e437 chore(deps): upgrade Tier-1 deps (googleapis 173, gaxios 7, express 5, jsdom 29, date-fns 4, stripe 20) (#21570)
## What

Security-driven upgrade of the biggest-drift Tier-1 dependencies
(staying on latest = staying patched). Bundled because they share the
lockfile and the googleapis/gaxios pair must move together.

| Package | From | To | Gap |
|---|---|---|---|
| googleapis | 105.0.0 | **173.0.0** | 68 majors |
| gaxios | 5.1.3 | **7.1.5** | 2 majors |
| express | 4.22.2 | **5.2.1** | 1 major |
| jsdom | 26.1.0 | **29.1.1** | 3 majors |
| date-fns | 2.30.0 | **4.4.0** | 2 majors |
| date-fns-tz | 2.0.0 | **3.2.0** | 1 major |
| stripe | 19.3.1 | **20.4.1** | 1 major |

`yarn npm audit` reports **0 high/critical** advisories before and
after.

## Code changes

- **gaxios v7** — `GaxiosError.code` is now `string | number` (guard the
calendar network-error check by `typeof`); `GaxiosError` config/response
use `URL` + `Headers`; and crucially the v7 constructor drops
`response.data` unless `bodyUsed` is set — updated the synthetic gmail
error mocks accordingly (production gaxios sets it, so real error
parsing is unaffected).
- **google-auth-library / gaxios dedup** — `googleapis-common@8.0.2`
exact-pins `google-auth-library@10.5.0` + `gaxios@7.1.3` while
`googleapis` pulls `^10.2.0`; the two copies made
`OAuth2Client`/`GaxiosError` type-identities diverge across every
gmail/calendar service. Added two singleton `resolutions` (documented
inline in root `package.json`).
- **express 5** — no source changes. `@nestjs/platform-express@11.1.24`
already resolves `express@5.2.1` internally; the old `4.22.2` pin was
the override.
- **jsdom 29** — no source changes, but it now pulls ESM-only transitive
deps (`@csstools/*` `.mjs`, `parse5`, `entities`, `tough-cookie`,
`@exodus/bytes`). Extended the server jest `transformIgnorePatterns`
allowlist and added `.mjs` to the transform/extensions so jest can load
jsdom.
- **stripe 20** — `Subscription` gained a required `customer_account`
field; added to mocks. No runtime changes.
- **date-fns v4** — `Locale` is no longer ambient (import explicitly in
5 files); per-locale entrypoints dropped the typed `default` export (the
locale loader now reads the single named export); fixed the default
locale import in `formatTimeZoneLabel`.

## Tests

- Full suites green locally: **twenty-server 5709 passed**,
**twenty-front 4937 passed**, twenty-ui / twenty-ui-deprecated green;
typecheck + builds (swc + vite) + lint all pass.
- Added regression tests for the two runtime behaviors these upgrades
touch and that had no coverage:
  - `getDateFnsLocale` — named-export locale resolution (date-fns v4).
- `sanitizeFile` — jsdom 29 + DOMPurify still strips `<script>`/event
handlers from uploaded SVGs (security guard).

## Deliberately deferred (not in this PR)

- **stripe → 21/22**: stripe **21** bundles a runtime `Decimal` type for
money fields **and** jumps the pinned API version to `2026-03-25.dahlia`
(changes webhook/billing payload behavior) — too risky to fold into a
deps bump on billing code. stripe **22** additionally drops the
node10-resolvable `types` entry, which would force a repo-wide
`moduleResolution` change. Capped at the latest clean **20.x**.
- **openid-client → 6**: v6 is a full functional rewrite and its
passport strategy manages the OAuth `state` internally, but our SSO flow
uses `state` to carry `identityProviderId` across the shared
`/auth/oidc/callback`. That needs an auth-flow redesign (session-carried
provider id) on Enterprise SSO code with no integration harness — it
deserves its own focused PR rather than riding along here.

## Tier-1 source

Originated from a dependency-drift audit; remaining Tier-1 items
(date-fns done here) plus Tier-2/3 follow-ups tracked separately.


<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21570?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
2026-06-15 10:23:42 +02:00
Charles Bochet a84a4c1ab7 fix(server): load integration jest config transpile-only; drop tsx pin (#21563)
## Context

Follow-up to [#21559](https://github.com/twentyhq/twenty/pull/21559)
(the esbuild 0.28.1 security bump). That PR had to pin `tsx` to `4.21.0`
to avoid a CI-only `server-integration-test` failure. This removes the
need for that pin by fixing the root cause.

## Root cause

The integration-test command boots jest with `NODE_OPTIONS="--import
tsx/esm"`, while jest *also* compiles `jest-integration.config.ts` with
**ts-node, type-checking on**. Two TypeScript transformers run over the
same file:

- tsx's loader transpiles `node-environment.interface.ts` via esbuild,
downleveling the enum to `var NodeEnvironment = (…)(NodeEnvironment ||
{})`.
- jest's ts-node then *type-checks that downleveled output* and rejects
it with `TS7022: 'NodeEnvironment' … referenced directly or indirectly
in its own initializer`.

It's not a real type error and not esbuild's fault — esbuild's output is
valid JS, just not valid TS to re-type-check. It only surfaced once
`tsx` resolved to `4.22.x` (whose loader feeds that output into
ts-node), which is why #21559 pinned tsx to 4.21.0.

Verified in isolation: ts-node type-checking esbuild's downleveled enum
→ `TS7022`; the same under `transpileOnly`/`TS_NODE_TRANSPILE_ONLY=true`
→ clean.

## Fix

Run the integration jest config **transpile-only**
(`TS_NODE_TRANSPILE_ONLY=true` on the `test:integration` target, base +
`with-db-reset`). The config file doesn't need type-checking at boot,
and jest's ts-node now emits JS without re-type-checking esbuild's
output — eliminating the whole class of tsx/esbuild-downleveling
sensitivity.

With the collision gone, drop the workaround from the root
`package.json`:
- removed the `tsx: 4.21.0` resolution
- removed the `tsx/esbuild: 0.28.1` resolution

`tsx`'s `^4.x` ranges now resolve to **4.22.4**, which pins esbuild
`~0.28.0` → **0.28.1** on its own, so esbuild stays 0.28.1 across the
lockfile with no resolution. The `//resolutions` doc block is updated
accordingly.

## Verification

- `yarn install` clean; lockfile has only esbuild 0.28.1; tsx resolves
to 4.22.4.
- `jest --config ./jest-integration.config.ts --listTests` with tsx
4.22.4 + `TS_NODE_TRANSPILE_ONLY=true` loads the config and lists all
420 suites.
- CI `server-integration-test` is the real validator (the failure was
CI-only).

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21563?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
2026-06-14 23:34:21 +02:00
Charles Bochet fa80eb68b3 fix(deps): upgrade esbuild to 0.28.1 (GHSA-gv7w-rqvm-qjhr) (#21559)
## Context

Clears [Dependabot alert
#1469](https://github.com/twentyhq/twenty/security/dependabot/1469) —
esbuild Deno-module binary-integrity RCE (`GHSA-gv7w-rqvm-qjhr`,
vulnerable `>=0.17.0 <0.28.1`, fixed in `0.28.1`).

The advisory's range is much wider than the previous esbuild one
(`>=0.27.3`), so it re-exposed several older transitive esbuild copies
in the tree.

## Approach

Prefer upgrading the parent over adding a resolution; resolutions only
where the latest upstream release still pins a vulnerable esbuild
**outside** the `0.28.1` range (so an upgrade can't help).

**Upgraded parent (no resolution needed):**
- `tsx` → `^4.22.4` across all workspaces (its `~0.28.0` esbuild now
resolves to 0.28.1)
- `size-limit` / `@size-limit/preset-small-lib` → `^12.1.0` in
`twenty-ui` (v12 pins esbuild `^0.28.0`)

**Resolutions added** (verified against npm — latest still pins
vulnerable esbuild):
- `@opennextjs/aws` (exact-pins 0.25.4, still 0.25.4 in latest 4.0.3)
- `@lingui/cli` (`^0.25.1`, caps `<0.26`, unchanged in latest 6.3.0)
- `storybook` (range tops at `^0.27.0`, caps `<0.28`, unchanged in
latest 10.4.4)
- `zapier-platform-cli` (exact-pins 0.25.8, latest)

The three existing esbuild resolutions (`wrangler`, `@react-email/ui`,
`react-email`) remain. The `//resolutions` doc in `package.json` and the
`.yarnrc.yml` age-gate comment were updated to cover both advisories.

## Result

Every esbuild copy in `yarn.lock` now resolves to a single `0.28.1`
entry — no version `<0.28.1` remains. Lockfile change is a net reduction
(dropped duplicate esbuild trees + their `@esbuild/*` platform
binaries); no unrelated deps bumped. `yarn install` passes with
constraint checks enabled.

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21559?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
2026-06-14 22:29:11 +02:00
Charles Bochet 7c0136b97b feat(deps): migrate frontend to React 19 (#21531)
## What

Migrates the frontend stack from **React 18.3 → 19.2**. The website,
sdk, companion and emails packages were already on React 19; this brings
the remaining holdouts (`twenty-front`, `twenty-ui`,
`twenty-ui-deprecated`, `twenty-front-component-renderer`) and
`twenty-server`'s email rendering onto 19, and pins a single React
version repo-wide.

## Why

React 18.x is now the legacy line. Staying current keeps us on the
patched/maintained branch and unblocks downstream library majors
(react-router 7, mantine 9, etc.) that require React 19 peers.

## Dependency bumps (required by React 19 peers / removed APIs)

| Package | From | To | Reason |
|---|---|---|---|
| react / react-dom | 18.3.1 | 19.2.3 | core |
| @hello-pangea/dnd | 16 | 18 | peer `^18 \|\| ^19` |
| react-datepicker | 6 | 9 | v<7 used removed `findDOMNode`; drops
`@types/react-datepicker` |
| react-data-grid | beta.13 | beta.59 | peer `^19.2`; new render API |
| graphiql (+ @graphiql/react, plugin-explorer) | 3 / 0.23 / 1 | 5 /
0.37 / 5.1 | peer `^18 \|\| ^19` |
| react-helmet-async | 1.3 | **@dr.pogodin/react-helmet** 3.2 | upstream
caps peer at `^18`; drop-in React 19 fork |

A `resolutions` pin enforces a single React (19.2.3) + `@types/react`
(19.2.14) across the monorepo to avoid duplicate copies / type-identity
splits. Versions are the aged lockfile patches (clears the
`npmMinimalAgeGate`).

## Code changes

- **Global `JSX` shim** (`react-jsx-global.d.ts` per package): React 19
moved the `JSX` namespace under `React.JSX`; several deps' published
types (notably `@linaria/react`'s `styled.d.ts`, which types every
`styled.x` via `keyof JSX.IntrinsicElements`) still reference the global
namespace. Without the shim, every styled component degrades to `any`
props.
- **Ref nullability**: `useRef<T>(null)` now returns `RefObject<T |
null>`; widened consumer prop/hook ref types accordingly (incl. the
shared `useListenClickOutside`).
- **react-datepicker v9**: `onChange`/`onSelect` accept `Date | null`,
`calendarStartDay` typing, `ReactDatePickerProps`→`DatePickerProps`,
relaxed the dynamic `selectsMultiple` discriminated union.
- **react-data-grid beta.59**: `formatter`→`renderCell`,
`editor`→`renderEditCell`, `headerRenderer`→`renderHeaderCell`,
`components`→`renderers`, `onRowClick`→`onCellClick`, object-shaped
`useRowSelection`, Set-based selection.
- **dnd style cast**: `@radix-ui/react-popper` augments `CSSProperties`
with a `--radix-*` index signature that dnd's closed `DraggingStyle`
doesn't satisfy → cast at the spread.

## Status / testing

-  `typecheck` green: twenty-front, twenty-ui, twenty-ui-deprecated,
twenty-front-component-renderer, twenty-server
-  build / lint / unit tests / storybook+argos / runtime smoke-test in
progress

Draft until local + CI verification completes. Notable behavior to QA
manually: spreadsheet import (data-grid), date pickers, drag-and-drop
boards/lists, GraphQL playground, page titles/favicon.

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21531?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
2026-06-14 15:42:22 +02:00
Charles Bochet 4614fe963c fix(deps): bump esbuild to 0.28.1 to fix GHSA-g7r4-m6w7-qqqr (#21515)
## Summary

Fixes Dependabot alert
[#1438](https://github.com/twentyhq/twenty/security/dependabot/1438) —
**esbuild dev-server path traversal**
([GHSA-g7r4-m6w7-qqqr](https://github.com/advisories/GHSA-g7r4-m6w7-qqqr),
CWE-22, low severity, Windows-only). Vulnerable range `>= 0.27.3, <
0.28.1`; patched in `0.28.1`.

Two vulnerable transitive `esbuild` copies were present in the lockfile:

| Version | Parent | Notes |
|---|---|---|
| `0.27.3` | `wrangler@4.98.0` (twenty-website) | exact-pinned;
**latest** wrangler `4.100.0` *still* pins `0.27.3` |
| `0.28.0` | `@react-email/ui@6.5.0`, `react-email@6.5.0`,
`twenty-client-sdk` (twenty-emails / our SDK) | `@react-email/ui`
exact-pins it; **latest** `6.6.0` still does |

Because no fixed upstream release exists for these parents, bumping them
can't reach `0.28.1`.

## Changes

- **`package.json`** — scoped `resolutions` forcing `esbuild` to
`0.28.1` for `wrangler`, `@react-email/ui`, and `react-email`.
Documented in the existing `//resolutions` ledger.
- **`packages/twenty-client-sdk/package.json`** — raised the `esbuild`
floor `^0.28.0` → `^0.28.1` at the source. `esbuild` is a runtime
`dependency` of the SDK, so fixing it here (rather than via a root
resolution) also protects consumers of the published package.
- **`.yarnrc.yml`** — `0.28.1` was published 2026-06-11, inside the
`npmMinimalAgeGate: 3d` window, so it's quarantined. Preapproved
`esbuild@0.28.1` + `@esbuild/*@0.28.1` (scoped to this exact version) so
the security fix can land now instead of waiting out the gate. Safe to
remove once `0.28.1` ages past the gate.
- **`yarn.lock`** — regenerated.

## Verification

- No vulnerable esbuild left in the lockfile — remaining versions are
`0.25.4`, `0.25.8`, `0.25.12`, `0.27.2`, `0.28.1`, all outside `>=
0.27.3, < 0.28.1`.
- `yarn install --immutable` passes (no quarantine errors, clean link
step).

## Follow-up

The scoped resolutions are load-bearing only until upstreams ship an
esbuild `>= 0.28.1` pin; the `react-email` one can also drop once
`0.28.1` clears the age gate. All noted in the `//resolutions` ledger.

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21515?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
2026-06-12 23:26:22 +02:00
Charles Bochet 503c689f37 security: upgrade typeorm to 0.3.26 (CVE-2025-60542) (#21456)
## Context

Retry of the typeorm upgrade that was pulled out of #21448 after CI
showed "intermittently lossy metadata sync". **The investigation
exonerated typeorm**: the postcard/seed failures were a pre-existing bug
in `@ptc-org/nestjs-query-typeorm`'s batched relation paging (global
LIMIT across parents) that scan-order luck had been hiding — reproduced
byte-for-byte on typeorm **0.3.20** against a frozen repro DB. That bug
is fixed in #21455, which this PR is stacked on (base branch =
`charles/fix-nestjs-query-batch-relation-paging`; will retarget to main
when it merges).

## Changes

- typeorm `0.3.20` → `0.3.26`
([CVE-2025-60542](https://github.com/advisories/GHSA-q2pj-6v73-8rgj),
MEDIUM). The CVE lives in TypeORM's MySQL path
(`sqlstring`/`stringifyObjects`); Postgres-only Twenty never exercises
it — this is scanner hygiene + staying current.
- The local yarn patch (`PickKeysByType` + `DeleteResult.generatedMaps`)
applies **verbatim** to 0.3.26 (verified against the pristine tarball) —
renamed to `typeorm+0.3.26.patch`.
- `WorkspaceRepository.query` restricted override adapted to the generic
`query<T = any>()` base signature introduced in 0.3.24 (one-line change,
still throws `RAW_SQL_NOT_ALLOWED`).
- 0.3.26 ships `uuid ^11` natively → the scoped `typeorm/uuid`
resolution from #21441 and its `//resolutions` comment clause (including
the now-disproven "lossy sync" warning) are removed.

## Why we're confident this time

The original failure signature was fully understood, not just retried:
- On a frozen failing DB, **all fieldMetadata rows + workspace columns
were intact** — only the batched metadata API read was truncated (`LIMIT
501` over 558 rows, no ORDER BY).
- Same DB, typeorm 0.3.20: identical truncation, identical SQL → not a
typeorm regression.
- With #21455 applied: postcard install/uninstall stress loop **12/12
green on typeorm 0.3.26** (previously failed within 1–2 iterations), API
returns 558/558 fields.

## Verification

- `npx nx typecheck twenty-server` — clean
- Full `twenty-server` unit suite — green (5651 passed)
- `group-by-resolver` integration suite — 19/19 on a fresh 0.3.26-seeded
test DB
- Postcard app-sync stress loop — 12/12 on this exact stack
- Lockfile: typeorm 0.3.26 + new `sql-highlight` dep, `esbuild`/uuid
entries untouched
2026-06-11 16:41:22 +02:00
Charles Bochet 184c4948d6 security: strip Node dev headers from images + lingui 5.9.5 (drops vulnerable esbuild) (#21448)
## Context

AWS Inspector flags the `prod-twenty` image (built from current main)
with 16 findings, and Dependabot alert 174 flags esbuild. This PR fixes
the OpenSSL scanner findings and the esbuild CVE. The typeorm bump
(CVE-2025-60542) was **pulled out of this PR** — see "typeorm status"
below.

## Changes

### Strip `/usr/local/include/node` from runtime stages
(`twenty-server`, `twenty-app-dev`)
15 OpenSSL CVEs (June 9 advisory, incl. CRITICAL CVE-2026-34182) are all
detected via **Node's bundled OpenSSL dev headers**: 3 GENERIC
`openssl/openssl` 3.5.6 detections per CVE at
`/usr/local/include/node/openssl/archs/linux-x86_64/{asm,asm_avx2,no-asm}/include/openssl/opensslv.h`.
The headers are only needed by node-gyp and native addons are compiled
in the build stages — nothing compiles at runtime. Dropping them clears
all 45 detection instances and permanently ends this class of finding
(third occurrence: 3.5.5 → 3.5.6 → 3.5.7). None of these CVEs are
reachable through Node (no CMS/PKCS#7 API, `pfx` is operator-supplied,
Node's QUIC uses ngtcp2, ASN.1 issues need ~2GB inputs).

**Follow-up (~June 17, 2026):** the `node` binary itself still
statically links OpenSSL 3.5.6 — invisible to the scanner after this PR
and unreachable in practice, but the real fix is bumping the pinned
`node:24-alpine` digest once the [announced June 17 Node.js security
releases](https://nodejs.org/en/blog/vulnerability/june-2026-security-releases)
ship a 24.x linking OpenSSL ≥ 3.5.7 (verify via
`deps/openssl/openssl/VERSION.dat` on the release tag — 24.16.0 is still
on 3.5.6). A dated TODO sits next to the cleanup in the Dockerfile.

### esbuild dev-server CORS CVE (Dependabot alert 174,
GHSA-67mh-4wv8-2f99)
`@lingui/cli@5.1.2` (pins `esbuild ^0.21.5`) was the last parent
resolving a vulnerable esbuild (≤ 0.24.2 lets any website send requests
to the dev server and read responses). Instead of a resolution override,
this bumps the lockstepped **lingui suite 5.1.2 → 5.9.5** (within-major;
lingui adopted `esbuild ^0.25.1` in 5.4.1), which:

- removes `esbuild@0.21.5` and all its platform packages from the
lockfile with no forced ranges;
- drops the `@lingui/core` lockstep resolution (its comment marked it
droppable on the next coordinated lingui bump — the tree now resolves a
single `@lingui/core@5.9.5`);
- `@lingui/swc-plugin` stays at `^5.11.0` (peers on `@lingui/core: 5`;
its 6.x line targets lingui 6).

**lingui 5.9.5 behavioral fallout handled here:**
- Translation functions now **throw without an active locale** (5.1.2
fell back silently). The global `i18n` singleton that backs server-side
`` t`…` `` calls only had a messages compiler set, never an activated
locale → activate the source locale in `I18nService.loadTranslations()`,
mirrored in the server jest setup (unit tests bypass Nest bootstrap).
- `msg`/`t` placeholders are now strictly typed (reject
`null`/`undefined`/`unknown`) → one server call site and 16 twenty-front
files adapted with minimal nullish-coalescing fixes that preserve
rendering.
- `.po`/compiled-catalog churn from the new extractor/compiler
(reference reordering, sorted keys — verified content-identical on
unchanged `.po` inputs) is intentionally not committed: the scheduled
i18n workflows regenerate those.

## typeorm status (pulled out)

typeorm 0.3.20 → 0.3.26 was originally in this PR but **made workspace
metadata sync intermittently lossy**: `example-app-postcard` failed
twice with a *different* field missing from the synced PostCard object
each run, and one integration shard's `DataSeedWorkspaceCommand` died
with "Could not find flat entity with universal identifier …" — versus
zero such failures on recent main. Local runs (db reset + seed, group-by
integration suite 19/19) pass, so it is a nondeterministic
CI-load-sensitive regression that needs dedicated debugging (typeorm
changed LIMIT/OFFSET 0 semantics, lazy count for `getManyAndCount`,
upsert WHERE construction, and topological-sort internals in that
range). The resolutions comment documents this as the blocker;
CVE-2025-60542 is MySQL-driver-only (`sqlstring`), so Postgres-only
Twenty is not exposed in the meantime.

## Verification

- `npx nx typecheck twenty-server` / `twenty-front` — clean (no cache)
- `npx nx test twenty-server` — full suite green
- `lingui:extract` + `lingui:compile` — clean for twenty-server /
twenty-emails / twenty-front
- `oxfmt --check` — clean for both packages
- Lockfile diff: lingui 5.9.5 entries, `esbuild@0.21.5` +
`@esbuild/*@0.21.5` platform packages removed, no typeorm changes
2026-06-11 15:11:29 +02:00
Charles Bochet 166f7ee0d2 chore(deps): prune yarn resolutions down to load-bearing entries (#21446)
## Context

Audit of all 28 `resolutions` entries in the root package.json against
yarn.lock dependency graphs and the npm registry, to remove every entry
that is no longer forcing anything a normal resolution wouldn't do —
resolutions are hard to maintain and silently freeze versions.

Net result: **28 → 22 entries**, two small dependency bumps replace
pins, and every remaining entry now has its blocker + removal condition
documented in `//resolutions`.

## Removed — dead weight (re-resolution lands on the same safe versions)

| Entry | Why it was dead |
|---|---|
| `type-fest: 4.10.1` | Stale 2024 dedup pin that semver-overrode ~16 of
19 declared ranges (forced `^0.13`/`^0.20`/`^0.21` consumers up four
majors, `^5.x` consumers down one). Types-only; each parent now resolves
its own compatible copy. |
| `typescript: 5.9.3` | No-op: every range (`^5.9.3`, `5.9.3`, `~5.9.2`)
resolves to 5.9.3 naturally. Only the electron-forge scaffolding
template regains its own nested `~5.4.5` (never builds this repo). |
| `node-gyp: ^12.4.0` | All requesters are Yarn-injected `node-gyp:
latest` = 12.4.0 today. The tar-6-era node-gyp versions it evicted have
no requesting parent left. |
| `cacache: ^20.0.0` | All four parents (arborist, metavuln-calculator,
make-fetch-happen 15, pacote 21) already declare `^20`. Guarded by the
kept `make-fetch-happen: ^15` resolution. |
| `pacote/tar: ^7.5.16` | The original target (pacote 11/15 via zapier)
is gone; the only pacote left is 21.5.0 which declares `tar ^7.4.3`
natively. |

## Removed — replaced by a parent upgrade

- **`nodemailer: 8.0.10`** → `imapflow` 1.2.1 → **1.3.6** (ships patched
nodemailer 8.0.10 exact; 1.4.0 is blocked by the 3-day npm age gate).
twenty-server's own `^8.0.5` range was already safe.
- **`node-ical/uuid: 11.1.1`** → `node-ical` ^0.20.1 → **^0.21.0**,
which drops uuid (and axios) entirely. The uuid removal happened at
0.21.0 — not in the 0.26 rrule-temporal type overhaul that #21441
flagged as the blocker.

## Narrowed — `qs: 6.15.2` global → two scoped entries

Only three lockfile entries actually request vulnerable qs ranges:
`express@4.22.0` (pinned by `@mintlify/previewing`), `express@4.22.1` +
`@cypress/request@3.0.10` (pinned by verdaccio 6.7.2, latest). Replaced
the global pin with `express/qs` + `@cypress/request/qs`, so the 12+
healthy parents (express 4.22.2/5.x, body-parser, stripe, …) are no
longer frozen and will pick up future qs releases naturally.

## Re-pinned — `graphql-redis-subscriptions/ioredis`

Changed `^5.6.0` → exact `5.10.1` and documented why: this must equal
the exact ioredis version pinned by twenty-server and bullmq. Without
it, graphql-redis-subscriptions' `^5.3.2` resolves to a second ioredis
copy and `RedisPubSub`'s publisher/subscriber types reject the server's
client (caught by twenty-server typecheck during this work — bump it in
lockstep with the ioredis pin).

## Kept (all load-bearing, now documented inline)

graphql (singleton below msw's `^16.12.0`), @lingui/core (suite
lockstep), @types/qs (6.9.17 typing-break holdback), @opentelemetry/api
(NoopMeterProvider singleton, #20231), chokidar v3 (NestJS CLI fsevents,
#20316), tmp (zapier-platform-cli pins 0.2.5), make-fetch-happen + the
two @electron tar entries (blocked on electron-forge adopting
@electron/rebuild 4), @angular-devkit/core (blocked on a fixed
@nestjs/cli > 11.0.23), yeoman-environment, webpack-dev-server,
next/postcss (fix only in next 16.3.0 canaries), the remaining uuid
pins, and react-doc-viewer/ajv.

## Follow-ups (separate PRs)

- `typeorm` 0.3.20 → 0.3.30: re-roll the 46-line patch; clears the
`typeorm/uuid` resolution **and** the open high-severity
GHSA-q2pj-6v73-8rgj (SQL injection in `repository.save/update`, fixed in
0.3.26).
- googleapis 105 → ≥152 migration clears `googleapis-common/uuid`.

## Verification

- `yarn install` clean; lockfile contains **no** vulnerable qs
(≤6.15.1)/tar 6/uuid <11/nodemailer <8.0.4/postcss 8.4.31/tmp <0.2.6
entries
- `npx nx typecheck twenty-server` ✓ and `npx nx typecheck twenty-front`
✓
- CalDAV + IMAP unit tests (node-ical/imapflow consumers): 9 suites, 121
tests ✓
- `yarn npm audit --all`: only pre-existing typeorm finding remains (see
follow-up)
2026-06-11 13:41:03 +02:00
Charles Bochet 1ccede2309 security: scoped ajv 8.20.0 resolution for react-doc-viewer (Dependabot alert 481) (#21445)
Closes the **final** open Dependabot alert — ajv
[481](https://github.com/twentyhq/twenty/security/dependabot/481) — with
a scoped resolution.

### Why a resolution (no parent path)
`ajv >= 7.0.0 < 8.18.0` is pulled **only** by
`@cyntler/react-doc-viewer`, which pins `ajv ^7.2.4`. Its **latest
(1.17.1) still pins `^7`** — there is no react-doc-viewer version on ajv
8 (no 1.18/2.0) — so it can't be closed by upgrading the parent.

### Why it's completely safe
`@cyntler/react-doc-viewer` **never imports ajv** — zero references in
its dist; ajv is a declared-but-unused dependency. So forcing it to ajv
8 has **no functional impact**, and the ajv 7→8 breaking-change concern
is moot. Scoped to `@cyntler/react-doc-viewer/ajv` so it touches nothing
else.

### Verification
- `yarn install --immutable` ✓; every ajv now resolves to **8.18.0 /
8.20.0** (safe) or `6.12.x` (outside the advisory range) — no vulnerable
ajv remains.

Documented in the top-level `//resolutions` note with a removal trigger.
**This was the last open alert.**
2026-06-11 12:37:45 +02:00
Charles Bochet 462dd3b0e9 security: uuid CVE — bump bullmq/msal/blocknote + scoped resolutions for the rest (Dependabot alert 1289) (#21441)
Closes the uuid Dependabot alert —
[1289](https://github.com/twentyhq/twenty/security/dependabot/1289) — by
**upgrading the parents that bump cleanly** and **scope-resolving only
the ones that genuinely can't**.

`uuid < 11.1.1` (buffer-bounds check in v3/v5/v6) is pulled by ~9
transitives.

### Bumped (parent upgrade — drops uuid<11, no behavior change;
typecheck verified)
- **bullmq** 5.40.0 → 5.78.0 — also aligned **ioredis** 5.6.0 → 5.10.1
(bullmq pins it) and fixed the renamed `Job.returnValue→returnvalue` /
`stackTrace→stacktrace` (now `string[]|null`) in
`admin-panel-queue.service.ts`.
- **@azure/msal-node** ^3.8.4 → ^5.2.3 (5.2.4 was age-gate-quarantined).
- **@blocknote/** ×5 ^0.47.3 → ^0.51.4.

### Scope-resolved to uuid 11.1.1 (no clean bump exists)
- **sockjs** (latest; pinned by webpack-dev-server) and
**@ptc-org/nestjs-query-typeorm** (9.4.0 *is* latest, pins `^10`) — no
version drops uuid.
- **typeorm** — a `patch:` dep / ORM core, too risky to bump.
- **node-ical** 0.26 (type-model overhaul → caldav-parser rewrite) and
**googleapis** 173 (Gmail/OAuth, 105→173) — large breaking migrations;
**deferred to dedicated PRs**.
- **@cypress/request** — transitive (cypress isn't a direct dep).

Resolutions are **per-package** and preserve the intentional **uuid
13.x** (twenty-sdk / create-twenty-app).

### Verification
- `twenty-server` typecheck ✓ (0 errors), `twenty-front` typecheck ✓ (0
errors).
- `yarn install --immutable` ✓; every uuid resolves to **11.1.1** or
**13.0.2**.
- bullmq/msal/typeorm runtime exercised by the **server integration
tests**; @blocknote by the **storybook tests** in CI.
2026-06-11 12:26:26 +02:00
Charles Bochet 6af06c1062 security: postcss CVE via styled-components bump + next/postcss resolution (Dependabot alert 1061) (#21438)
Closes the postcss Dependabot alert —
[1061](https://github.com/twentyhq/twenty/security/dependabot/1061) — by
**bumping one parent** and using a **scoped resolution** only where
there's no other path.

postcss `< 8.5.10` (XSS via unescaped `</style>` in stringify output)
was bundled by two parents:

### styled-components → bumped (no resolution)
`styled-components 6.4.2` (in-range for our `^6.1.0`; we were on a stale
6.3.12) **dropped its postcss dependency entirely**, so a plain `yarn
up` removes the 8.4.49 copy — no override. (styled-components is only
used in one component-renderer Storybook showcase; product UI is on
Linaria.) Re-built `twenty-front-component-renderer` to confirm the
bump.

### next → scoped resolution (no parent path)
`next` pins postcss `8.4.31` **exact on every stable release** —
next@latest (16.2.9) still pins it; the fix (8.5.10) exists only in the
**16.3.0 canary** (unreleased). So `next/postcss: 8.5.15` is the only
mechanism, scoped to next and documented in the top-level
`//resolutions` note with a removal trigger.

### Verification
- Every postcss now resolves `>= 8.5.14` (safe); `yarn install
--immutable` ✓.
- postcss is build-time and **CI doesn't build twenty-website on regular
PRs**, so verified locally: **twenty-website** (Next production build) ✓
and **twenty-front-component-renderer** ✓.
2026-06-11 11:19:50 +02:00
Charles Bochet 2da28cb03e security: upgrade express 4.22.2 + qs 6.15.2 resolution for dev-tool holdouts (Dependabot alert 1305) (#21434)
Closes the qs Dependabot alert —
[1305](https://github.com/twentyhq/twenty/security/dependabot/1305) — by
**upgrading express where possible** and using a **documented qs
resolution** only for the irreducible dev-only holdouts.

### What's vulnerable
`qs 6.14.x` (the `qs.stringify` DoS) is pulled by `express 4.22.1` /
`body-parser 1.x`. The fix is `qs 6.15.2`, and there's **no backport to
the 6.14 line**.

### Upgrade what we can (no resolution)
`express 4.22.2` / `body-parser 1.20.5` moved to the patched `qs
~6.15.1`. So this PR bumps the app + in-range tooling to **express
4.22.2**:
- twenty-server's stale direct pin `4.22.1 → 4.22.2` (its runtime HTTP
is already express 5.2.1 via `@nestjs/platform-express`; this just
patches the redundant direct dep — typecheck passes),
- nx / electron-forge / webpack-dev-server / companion follow via `yarn
up -R express body-parser`.

### Resolution only for the two holdouts
Two **dev-only** tools pin express *exactly* with no patched release on
a line we can use, so they still drag in `qs 6.14.2`:
- **verdaccio** `4.22.1` — express 5 only landed in the **v7 beta**
([verdaccio#5680](https://github.com/verdaccio/verdaccio/issues/5680),
[#2479](https://github.com/verdaccio/verdaccio/issues/2479)), **not**
backported to the 6.x line we use.
- **@mintlify/previewing** `4.22.0` — closed-source, latest still pins
4.22.0, no movement.

A `qs: 6.15.2` resolution covers those, documented with a top-level
`//resolutions` note and a removal trigger.

### Verification
- `yarn install --immutable` ✓; every `qs` resolves to `6.15.2`; express
app/tooling on `4.22.2` (only verdaccio/mintlify remain on old express,
neutralized by the resolution).
- `twenty-server` typecheck ✓ (90 files import express types;
4.22.1→4.22.2 is a patch).
- Non-exploitable in prod regardless (express/body-parser use
`qs.parse`, not the vulnerable `stringify`).
2026-06-11 10:46:04 +02:00
Charles Bochet 9100fb1e9f security: scoped resolution for webpack-dev-server 5.2.4 (Dependabot alerts 1237/691/692) (#21420)
Closes 3 webpack-dev-server Dependabot alerts —
[1237](https://github.com/twentyhq/twenty/security/dependabot/1237),
[691](https://github.com/twentyhq/twenty/security/dependabot/691),
[692](https://github.com/twentyhq/twenty/security/dependabot/692) — with
a **scoped** resolution:
`@electron-forge/plugin-webpack/webpack-dev-server: 5.2.4`.

(These numbers are Dependabot **alert** IDs, not issue/PR numbers —
written without `#` to avoid cross-linking unrelated issues, per review
feedback.)

### Why a resolution (the one place it's unavoidable)
webpack-dev-server is pulled **only** by
`@electron-forge/plugin-webpack` (twenty-companion's build tooling), and
**no electron-forge release uses webpack-dev-server 5** — not even
`8.0.0-alpha.9` still pins `^4`. There is no parent-upgrade path, so a
resolution is the only mechanism.

### Scoped, not global
Per review feedback, the resolution targets
`@electron-forge/plugin-webpack/webpack-dev-server` rather than a global
override — it only forces v5 under electron-forge (the sole consumer),
limiting blast radius. Verified the scoped syntax is honored: removing
it reverts the lockfile to `webpack-dev-server@npm:^4.0.0`; with it, the
lock pins `webpack-dev-server@npm:5.2.4` and `yarn install --immutable`
passes.

### Why it's safe (constructor did NOT change v4→v5)
`@electron-forge/plugin-webpack@7` calls `new
WebpackDevServer(this.devServerOptions(), compiler)`.
webpack-dev-server's constructor is `constructor(options, compiler)` in
**both v4 and v5** (verified in `lib/Server.js:331` and
`types/lib/Server.d.ts:1179`). The `(compiler, options)` → `(options,
compiler)` swap happened at **v3 → v4**, not v4 → v5. The plugin passes
only options unchanged in v5 (`hot`, `devMiddleware.writeToDisk`,
`historyApiFallback`, `port`, `setupExitSignals`, `static`, `headers`)
and uses none of the hooks v5 removed.

### Scope / verification
- `yarn install --immutable` ✓; webpack-dev-server resolves to 5.2.4
only (was 4.15.2), no vulnerable copy remains.
- Only exercised by `electron-forge start` (dev HMR); production
`make`/`package` builds don't use it, and **twenty-companion has no CI
workflow**, so this can't affect CI.
- Residual manual check (not CI-covered): `yarn start:electron` in
twenty-companion still boots the dev server.
2026-06-11 09:38:16 +02:00
Charles Bochet 09cc0c6f21 security: clear yeoman-environment High alert via resolution to 6.0.1 (#21400)
## What

Clears the `yeoman-environment` High alert (GHSA-vv9j-gjw2-j8wp —
*arbitrary package install without confirmation*).

`yeoman-environment@4.4.3` is exact-pinned by `zapier-platform-cli`.
**There is no parent-bump fix**: `zapier-platform-cli@19.0.0` is the
latest stable and still pins 4.4.3 — cli 17→3.19.3, 18/19→4.4.3, all in
the vulnerable `< 6.0.1` range.

## Why a resolution (and why it's safe for us)

zapier-cli **lazy-loads** `yeoman-environment` via dynamic `import()`
*only* inside its `init` and `pull` scaffolding command handlers.
twenty-zapier only ever runs `validate` / `versions` / `push` /
`promote` (see `project.json`), so the vulnerable code path is never
imported here.

Since no zapier-cli release carries the fix, the only way to remove the
vulnerable version is a resolution:

```jsonc
"yeoman-environment": "6.0.1"
```

The 4→6 major only affects zapier-cli's `init`/`pull` (which we never
invoke); all our commands are unaffected.

## Verification
- `yeoman-environment` now **6.0.1** (no 4.4.3 in the lockfile)
- `nx build` + `typecheck` twenty-zapier 
- `zapier-platform validate` → **35/35 checks pass** with yeoman 6
forced
- `yarn install --immutable` clean
2026-06-10 13:35:28 +02:00
Charles Bochet e53f877559 security: clear picomatch High alert via @angular-devkit/core resolution (#21398)
## What

Clears the root `picomatch` High alert (GHSA-c2c7-rcm5-vvqj, range
`>=4.0.0 <4.0.4`).

`picomatch@4.0.2` is exact-pinned by `@angular-devkit/core@19.2.x`,
pulled by NestJS's codegen tooling (`@nestjs/schematics` + `@nestjs/cli`
use Angular's schematics engine). angular-devkit/core backported the
picomatch 4.0.4 fix in **19.2.24**.

## Why a resolution here (not a parent bump)

The clean parent-bump — bumping `@nestjs/cli` so it pulls patched
angular-devkit — **breaks `nest build`**. `@nestjs/cli` 11.0.17+ has an
SWC-builder output-path change: it writes compiled files under
`dist/`**`src/`**`…` instead of `dist/…`, breaking every `node
dist/<path>` reference (`main`, `command`, worker,
`database/scripts/*`). This is what failed in the first revision of this
PR (`Cannot find module '…/dist/database/scripts/truncate-db.js'`).

- The cli's angular-devkit pin is **exact**, so there's no clean
refresh.
- Every `@nestjs/cli` ≥11.0.17 (incl. the latest 11.0.23) has the
regression.
- There's no stable NestJS 12/13 to move to (12 is alpha-only).
- `tsconfig` `rootDir` doesn't override the output base.

So a one-patch resolution is genuinely the cleaner, lower-risk fix:

```jsonc
"@angular-devkit/core": "19.2.24"   // patch within the same 19.2 minor
```

`@nestjs/cli` stays 11.0.16 (correct `dist/` layout), and picomatch
resolves to 4.0.4.

## Verification
- picomatch now **4.0.4 + 2.3.2** (both patched); no 4.0.2 in the
lockfile
- `nx build twenty-server` emits `dist/main.js` and
`dist/database/scripts/*.js` at the correct paths (the prior CI failure)
- `yarn install --immutable` clean
2026-06-10 13:22:05 +02:00
Charles Bochet 3ee82c7a3c security: clear koa High alert by bumping nx 22.5.4 → 22.7.5 (#21396)
## What

Clears the High `koa` alert (GHSA-7gcc-r8m5-44qm) — via a parent bump,
**no resolution**.

`koa@3.0.3` was a deep transitive of the module-federation build
tooling:
`koa` ← `@module-federation/dts-plugin@0.21.4` ←
`@module-federation/enhanced@0.21.4`, pulled via **two** paths —
`@nx/module-federation@22.5.4` (directly) and `@module-federation/node`
(pinning the old `enhanced@0.21.x` line).

`@module-federation/dts-plugin` 2.x dropped koa, so the fix moves both
paths onto the 2.x line:

- bump `nx` + `@nx/{jest,js,react,storybook,vite,web}` **22.5.4 →
22.7.5** (minor): `@nx/module-federation@22.7.5` uses
`@module-federation/enhanced@^2.3.3`
- refresh `@module-federation/node` within its existing `^2.7.21` range
→ 2.7.44, which uses `@module-federation/enhanced@2.5.1`

Result: `@module-federation/enhanced` + `dts-plugin` collapse to 2.5.1,
and **koa is gone from the tree entirely** (net −309 lockfile lines
after dedup).

## Verification (nx is the monorepo task runner — verified broadly)
- `nx build` + `typecheck`: twenty-shared, twenty-ui, twenty-front 
- `nx typecheck twenty-server` 
- `nx test twenty-shared` 
- `yarn install --immutable` clean

The only `package.json` change is the nx version bump; everything else
is lockfile.
2026-06-10 11:44:03 +02:00
Charles Bochet 232ca8eec2 security: clear happy-dom High alerts by upgrading wyw-in-js 0.7 → 1.1 (#21394)
## What

Clears the 2 High `happy-dom` alerts (GHSA-w4gp-fjgq-3q4g,
GHSA-6q6h-j7hj-3r64) via a parent bump — **no resolution**.

`happy-dom@15.11.7` came from **`@wyw-in-js/transform@0.7.0`**
(Linaria's CSS transform), pinned by a root resolution + a local `.yarn`
patch and requested by `@wyw-in-js/vite@^0.7.0` in twenty-front +
twenty-ui-deprecated.

- `@wyw-in-js/vite` `^0.7.0` → `^1.1.0` (twenty-front,
twenty-ui-deprecated)
- `@wyw-in-js/babel-preset` `^0.6.0` → `^1.1.0` (twenty-ui-deprecated)
- **drop the `@wyw-in-js/transform` 0.7.0 resolutions + the `.yarn`
patch** — the patch added a `visited` cycle-guard to
`TransformCacheCollection.invalidateIfChanged`, which is **already
upstream** in transform 1.1.0, so it's obsolete.

`@wyw-in-js/transform` now resolves to **1.1.0** (→ happy-dom 20.10.2)
and 0.8.1 (website, unchanged, → happy-dom 20.8.9). The vulnerable
0.7.0/15.11.7 are gone.

## Required config change

wyw-in-js 1.x resolves modules in its CSS pre-build via vite's
`resolve.alias` instead of `vite-tsconfig-paths`. So twenty-front's `@/`
and `~/` tsconfig path aliases are mirrored into `vite.config`
`resolve.alias` — otherwise the CSS evaluator throws `Cannot find module
'@/...'` for aliased imports used inside `styled` definitions.

## Verification
- happy-dom now **20.8.9 + 20.10.2** (both patched); no 15.x left
- `nx build twenty-front` — CSS extraction works (**1018 files
transformed**) + `typecheck`
- `nx build twenty-ui`, `twenty-ui-deprecated` (Linaria CSS extraction)
- website's Linaria transform runs fine (local build only stops on a
missing `TWENTY_PARTNERS_API_URL` env var, unrelated)
- `yarn install --immutable` clean
2026-06-10 11:24:38 +02:00
Charles Bochet 1e309369bc chore(deps): upgrade tar to v7, evict vulnerable tar@6.2.1 (CVE-2026-24842) (#21341)
## Summary

Removes all transitive **`tar@6.2.1`** from the dependency tree,
resolving [Dependabot alert
#400](https://github.com/twentyhq/twenty/security/dependabot/400)
([GHSA-34x7-hfp2-rc4v](https://github.com/isaacs/node-tar/security/advisories/GHSA-34x7-hfp2-rc4v)
/ CVE-2026-24842 — node-tar hardlink path traversal, high/8.2).

The alert had been dismissed as `no_bandwidth`, but `tar@6.2.1` was
still in the lockfile. I confirmed **6.2.1 is genuinely exploitable** by
running the advisory's PoC (the hardlink escaped the extraction dir to a
parent-directory file); `7.5.16` blocks it. There is **no patched 6.x
release** — the fix only exists in `7.5.7+`.

## Approach

Upgrade the build tooling that pulled tar v6 to the majors that depend
on tar v7, rather than forcing tar onto v6-era consumers:

| Package | Change | Mechanism |
|---|---|---|
| `node-gyp` | 10.2.0 / 7.1.2 / 9.4.1 → **12.4.0** | resolution |
| `cacache` | 18 → **20.0.4** | resolution |
| `make-fetch-happen` | → **15.0.6** | resolution |
| `mintlify` (twenty-docs) | `latest` → **^4.2.594**
(`@mintlify/previewing` → tar 7.5.15) | direct dep bump |
| `@electron/rebuild`, `@electron/node-gyp`, `pacote` → `tar` | →
**^7.5.16** | scoped resolution |

The last row covers the two subtrees with **no upstream tar-v7
release**: `@electron/rebuild` (+ electron's `node-gyp` fork) in
`twenty-companion`, and `pacote@11/15` via `zapier-platform-cli` in
`twenty-zapier`.

All `tar` now resolves to **7.5.13 / 7.5.15 / 7.5.16**; `node_modules`
verified free of tar v6.

## Validation done
- `yarn install` completes cleanly (constraints pass, only pre-existing
`enableScripts: false` + peer-dep warnings).
- Installed `node_modules` contains zero tar v6.

## Validation still needed before merge ⚠️
- The scoped overrides force tar v7 onto packages written for the v6
API. Resolution is consistent, but **runtime not exercised**
(`enableScripts: false` skips native builds at install). Please
validate:
  - `twenty-companion` electron `make` / native rebuild
  - `twenty-zapier` build/push
- If either breaks, drop the scoped overrides and accept those two
**dev/build-only** clusters as residual — they extract only trusted
archives at build time, so the CVE (which needs attacker-controlled
input) isn't reachable there.
- `mintlify` is pinned (not `latest`) because `.yarnrc.yml`'s
`npmMinimalAgeGate: 3d` quarantines the true latest. Pinning is arguably
healthier, but it's a deliberate behavior change.

## Note
twenty-server's own runtime tarball extraction
(`extract-tarball-securely.util.ts`) was already on patched tar **and**
rejects all hardlink/symlink entries — so this PR addresses the
remaining build-tooling exposure, not a live runtime hole.

Large `yarn.lock` churn is expected: the node-gyp/cacache major bumps
refresh npm-internals tree-wide.
2026-06-08 20:48:44 +02:00
Charles Bochet 822beb6a86 chore: force tmp >= 0.2.7 for root dev tooling (nx/zapier) (#21338)
Resolves the **root** `tmp` Dependabot alert (`tmp < 0.2.6`, #1308).

In the root workspace, `tmp` is a transitive dep of `nx` (`~0.2.1`) and
`zapier-platform-cli` (exact `0.2.1`) — dev/CLI tooling that
**exact-pins old tmp with no fixed parent to upgrade to** (verified:
even latest `zapier-platform-cli@15.19.0` still pins `0.2.1`). So it's
pinned to the patched **0.2.7** via a root `resolutions` entry — the
correct tool for un-dedupe-able transitive pins. Not in the prod image.

### Why the `twenty-apps/*` alerts are not fixed here
Those come from a different source — `twenty-sdk → inquirer ^10 →
@inquirer/editor 4.x → external-editor → tmp@0.0.33`. Rather than add a
`resolutions` block to every app's `package.json` (which doesn't scale —
every newly-scaffolded app would need it), they'll be fixed
**centrally** by bumping `inquirer` in `twenty-sdk` (`^10 → ^12`, which
reaches `@inquirer/editor 5.x` that dropped external-editor). Separate
PR — apps inherit the fix on the next SDK release with no manual
additions.
2026-06-08 20:11:56 +02:00
Raphaël Bosi c596a5e342 Rename twenty-ui to twenty-ui-deprecated and twenty-new-ui to twenty-ui to prepare package release (#21315)
## Description

Promotes the next-gen UI library (formerly `twenty-new-ui`) to the name
**`twenty-ui`** (v0.1.0, publishable) and renames the old package to
**`twenty-ui-deprecated`**. Rewrites ~1,730 `twenty-ui` imports →
`twenty-ui-deprecated`, updates all configs/CI/Docker/deps, and migrates
twenty-front's `Toggle` to the new package (first consumer) as a
drop-in.

## Next steps
- Wire the `ui/v*` publish dispatch (`cd-deploy-tag.yaml` +
`.yarnrc.yml`), then tag `ui/v0.1.0` to publish.
- Continue migrating components from `twenty-ui-deprecated` →
`twenty-ui`.
2026-06-08 18:12:28 +02:00
Charles Bochet d2e7dc0e74 security: bump vulnerable direct dependencies (axios, next, vitest, qs, dompurify, …) (#21309)
## What

Within-major version bumps of **direct** dependencies to clear a large
batch of Dependabot alerts that are breaching (or near) their SLA. No
major-version changes — all stay within the current major, so risk is
low.

| Package | From → To | Clears |
|---|---|---|
| `axios` | ^1.13.5 → ^1.16.0 | ReDoS, Proxy-Auth leak, proto-pollution
gadgets, NO_PROXY bypass, resource DoS (56 alerts) |
| `next` | 16.1.7 → ^16.2.6 | DoS, middleware/proxy bypass, SSRF, cache
poisoning, XSS (32 alerts) |
| `vitest` | 4.0.18 → ^4.1.0 | **CRITICAL** — UI server arbitrary file
read/exec (#1421) |
| `qs` | ^6.11.2 → ^6.15.2 | `qs.stringify` DoS |
| `dompurify` | 3.3.3 → ^3.4.0 | proto-pollution XSS + FORBID_TAGS /
SAFE_FOR_TEMPLATES bypasses |
| `@nestjs/core` | 11.1.16 → ^11.1.18 | improper output neutralization /
injection |
| `nodemailer` | 8.0.4 → 8.0.10 | SMTP command injection via CRLF
(bumped via root `resolutions`) |
| `path-to-regexp` | ^8.2.0 → ^8.4.0 | ReDoS via multiple wildcards |
| `file-type` | ^21.3.1 → ^21.3.2 | ZIP decompression-bomb DoS |
| `@opentelemetry/exporter-prometheus` | ^0.211.0 → ^0.217.0 | exporter
process crash via malformed HTTP request (#1183/#1184) |

## Notes
- Added a `next` root **resolution** so the dev-only
`@react-email/preview-server` copy (hard-pinned at `16.0.10`) is also
pulled up to the patched `16.2.x` line — otherwise that copy keeps the
Next.js alerts open.
- `@opentelemetry/exporter-prometheus` 0.217 pulled
`@opentelemetry/sdk-metrics` to 2.7.1 (compatible); `@opentelemetry/api`
stays pinned at 1.9.1.
- **Transitive-only** vulnerable packages (undici, tmp, ws,
brace-expansion, …) are handled in a **separate PR** per the
split-by-group plan.
- Breaking major bumps (electron, uuid, serialize-javascript) and
migrations (Apollo Server 3→4, simplemde) are intentionally **out of
scope** here.
2026-06-08 12:49:31 +00:00
Raphaël Bosi 6f9b59b224 Scaffold twenty-new-ui (#21236)
Scaffolds `twenty-new-ui`, the next-gen replacement for `twenty-ui`, on
**SCSS** Modules + **Base UI** (no Linaria).

- **Tooling**: Vite lib build, subpaths mirror twenty-ui, typed SCSS
Modules, Storybook + axe a11y, size-limit, Nx targets.
- **Theme**: single token source → nx generateTheme emits the CSS vars +
accessor; parity test asserts token-for-token match with twenty-ui.

Migrated a first `Toggle` component with its stories to allow
@charlesBochet to wire the new pixel-diff system.

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 10:42:57 +00:00
Thomas des Francs 1642be86f5 Bonapara/twenty codex plugin (#20857)
@martmull v2.0 ;)

---------

Co-authored-by: martmull <martmull@hotmail.fr>
Co-authored-by: bosiraphael <raphael.bosi@gmail.com>
2026-06-02 14:39:14 +00:00
dependabot[bot] 6d550611d2 chore(deps): bump typescript from 5.9.2 to 5.9.3 (#20991)
Bumps [typescript](https://github.com/microsoft/TypeScript) from 5.9.2
to 5.9.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/microsoft/TypeScript/releases">typescript's
releases</a>.</em></p>
<blockquote>
<h2>TypeScript 5.9.3</h2>
<p>Note: this tag was recreated to point at the correct commit. The npm
package contained the correct content.</p>
<p>For release notes, check out the <a
href="https://devblogs.microsoft.com/typescript/announcing-typescript-5-9/">release
announcement</a></p>
<ul>
<li><a
href="https://github.com/Microsoft/TypeScript/issues?utf8=%E2%9C%93&amp;q=milestone%3A%22TypeScript+5.9.0%22+is%3Aclosed+">fixed
issues query for Typescript 5.9.0 (Beta)</a>.</li>
<li><a
href="https://github.com/Microsoft/TypeScript/issues?utf8=%E2%9C%93&amp;q=milestone%3A%22TypeScript+5.9.1%22+is%3Aclosed+">fixed
issues query for Typescript 5.9.1 (RC)</a>.</li>
<li><em>No specific changes for TypeScript 5.9.2 (Stable)</em></li>
<li><a
href="https://github.com/Microsoft/TypeScript/issues?utf8=%E2%9C%93&amp;q=milestone%3A%22TypeScript+5.9.3%22+is%3Aclosed+">fixed
issues query for Typescript 5.9.3 (Stable)</a>.</li>
</ul>
<p>Downloads are available on:</p>
<ul>
<li><a href="https://www.npmjs.com/package/typescript">npm</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/microsoft/TypeScript/commit/c63de15a992d37f0d6cec03ac7631872838602cb"><code>c63de15</code></a>
Bump version to 5.9.3 and LKG</li>
<li><a
href="https://github.com/microsoft/TypeScript/commit/8428ca4cc8a7ecc9ac18dd0258016228814f5eaf"><code>8428ca4</code></a>
🤖 Pick PR <a
href="https://redirect.github.com/microsoft/TypeScript/issues/62438">#62438</a>
(Fix incorrectly ignored dts file fr...) into release-5.9 (#...</li>
<li><a
href="https://github.com/microsoft/TypeScript/commit/a131cac6831aa6532ea963d0cb3131b957cad980"><code>a131cac</code></a>
🤖 Pick PR <a
href="https://redirect.github.com/microsoft/TypeScript/issues/62351">#62351</a>
(Add missing Float16Array constructo...) into release-5.9 (#...</li>
<li><a
href="https://github.com/microsoft/TypeScript/commit/04243333584a5bfaeb3434c0982c6280fe87b8d5"><code>0424333</code></a>
🤖 Pick PR <a
href="https://redirect.github.com/microsoft/TypeScript/issues/62423">#62423</a>
(Revert PR 61928) into release-5.9 (<a
href="https://redirect.github.com/microsoft/TypeScript/issues/62425">#62425</a>)</li>
<li><a
href="https://github.com/microsoft/TypeScript/commit/bdb641a4347af822916fb8cdb9894c9c2d2421dd"><code>bdb641a</code></a>
🤖 Pick PR <a
href="https://redirect.github.com/microsoft/TypeScript/issues/62311">#62311</a>
(Fix parenthesizer rules for manuall...) into release-5.9 (#...</li>
<li><a
href="https://github.com/microsoft/TypeScript/commit/0d9b9b92e2aca2f75c979a801abbc21bff473748"><code>0d9b9b9</code></a>
🤖 Pick PR <a
href="https://redirect.github.com/microsoft/TypeScript/issues/61978">#61978</a>
(Restructure CI to prepare for requi...) into release-5.9 (#...</li>
<li><a
href="https://github.com/microsoft/TypeScript/commit/2dce0c58af51cf9a9068365dc2f756c61b82b597"><code>2dce0c5</code></a>
Intentionally regress one buggy declaration output to an older version
(<a
href="https://redirect.github.com/microsoft/TypeScript/issues/62163">#62163</a>)</li>
<li>See full diff in <a
href="https://github.com/microsoft/TypeScript/compare/v5.9.2...v5.9.3">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=typescript&package-manager=npm_and_yarn&previous-version=5.9.2&new-version=5.9.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Weiko <corentin@twenty.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Félix Malfait <FelixMalfait@users.noreply.github.com>
2026-05-29 08:39:35 +02:00
neo773 323e66433e lint: migrate prettier to oxfmt (#20783)
Most changes are `implements` being unwrapped this is not a oxfmt
regression
Prettier in 3.7 (we're on 3.1) changed this behaviour prettier blog
[post](https://prettier.io/blog/2025/11/27/3.7.0#change-18094)

This unifies our linting tooling

---------

Co-authored-by: github-actions <github-actions@twenty.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
2026-05-22 00:21:33 +02:00
Félix Malfait 658bdf3e57 chore(website): rename twenty-website-new → twenty-website (#20745)
## Summary
Follow-up to the Cloudflare/OpenNext migration (#20741). Now that the
legacy `twenty-website` package was already removed in #20270, the
`-new` suffix on the marketing site package is no longer meaningful.

## What changes
- **Directory rename**: `git mv packages/twenty-website-new
packages/twenty-website` (1213 files moved, no content change)
- **Package + nx config**: `package.json` and `project.json` name fields
updated, `sourceRoot` repointed
- **Source refs**: `load-local-articles.ts` and
`load-local-release-notes.ts` had a hardcoded `'twenty-website-new'`
segment in their monorepo-root fallback path;
`app/[locale]/releases/page.tsx` had display strings showing where to
add content
- **External refs**: root `package.json` workspaces, root `CLAUDE.md` /
`README.md`, `twenty-sdk` + `create-twenty-app` READMEs,
`.vscode/twenty.code-workspace`, `.cursor/rules/changelog-process.mdc`,
Crowdin config + the three `website-i18n-*` CI workflows +
`ci-website.yaml`
- **Docker cleanup**:
`packages/twenty-docker/twenty-website-new/Dockerfile` deleted; the two
Makefile targets (`prod-website-new-build` / `prod-website-new-run`)
that referenced it removed — EKS deploy was retired in the Cloudflare
migration
- **`yarn.lock`** regenerated against the new workspace path

## What's deliberately not in this PR
The dev hostname `website-new.twenty-main.com` in `wrangler.jsonc` stays
for now. Migrating it to `website.twenty-main.com` needs coordinated DNS
deletion (current CNAME points at the legacy Docusaurus NLB and serves
503s) and removal of the matching legacy `website` Helm chart in
`twenty-infra`. Flagged as a separate cleanup.

Companion infra PR: https://github.com/twentyhq/twenty-infra/pull/682
(workflow paths + Terraform ECR + docs)

## Test plan
- [x] `yarn install --immutable` resolves clean against the new path
- [x] `npx nx typecheck twenty-website` passes
- [x] `npx nx lint twenty-website` passes
- [ ] CI on this PR confirms the same on a fresh checkout
- [ ] After merge: trigger `Deploy Website` workflow against
`environment=dev` to confirm the renamed working-directory deploys
correctly
2026-05-19 23:42:09 +02:00
Thomas des Francs 93d83b2e36 [codex] Add Twenty Claude skills package (#20450)
## Summary

Adds a new `twenty-claude-skills` workspace package under `packages/`
for Claude skills related to Twenty.

## Changes

- Registers `packages/twenty-claude-skills` in the root Yarn workspace
list.
- Adds package metadata for `twenty-claude-skills`.
- Adds a README documenting the multi-skill layout.
- Adds the `twenty-record-presentation` skill under
`skills/twenty-record-presentation/SKILL.md`.

## Impact

This gives Claude-specific Twenty skills a dedicated package location
while preserving the skill metadata from the provided skill bundle.

## Validation

- Parsed the root `package.json` and
`packages/twenty-claude-skills/package.json` with Node.
- Compared the imported skill content against the source `.skill`
archive; the only difference is a trailing newline at EOF.
2026-05-11 14:56:45 +00:00
martmull 773245fa65 Isolate twenty apps from nx project (#20406)
- avoids importing twenty-shared or else in twenty-apps applications
- update and add workflow action in twenty linear app
2026-05-08 13:16:25 +00:00
neo773 1faf725498 Fix NestJS CLI pin chokidar to v3 (#20316)
fixes `EMFILE` by downgrading chokidar to v3
root cause is v4 removed kernel level FSEvents on macOS and instead uses
`node:fs.watch` which doesn't scales for a repo of our size

Seems to be working well, even survives multiple hot reloads after
editing files
2026-05-07 09:55:53 +02:00
Paul Rastoin 3b180e7cb5 Fix root monorepo package json focused installation (#20292)
# Introduction
Running `yarn workspace focus twenty`( only installing root package.json
dependencies ) would fail because the yarn constraint expect the yarn
types to be installed
2026-05-05 15:13:31 +00:00
Abdullah. 59107b5b23 Remove twenty-website package. (#20270) 2026-05-05 12:45:02 +02:00
martmull 3ffda0a29e Add twenty version validation (#20227)
as title, server version is checked before app deploy, and app install
commands

### New section in publishing doc
<img width="1344" height="912" alt="image"
src="https://github.com/user-attachments/assets/2a9335e7-0a7a-4973-a2db-f30f03181001"
/>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-04 13:55:31 +00:00
Charles Bochet 3c7c62c79f fix(server): deduplicate @opentelemetry/api to fix NoopMeterProvider (#20231)
## Summary

**All OTel metrics in twenty-server have been silently dropped since
April 30.**

### Root cause

PR #20149 (`bump @sentry/profiling-node 10.27→10.51`) pulled in
`@sentry/node@10.51.0`, which declares `@opentelemetry/api: ^1.9.1` as a
**dependency** (not peer). Yarn installed it as a **nested** copy at
`1.9.1`, while the hoisted copy stayed at `1.9.0`.

At startup in `instrument.ts`:
1. `Sentry.init()` uses the **nested `1.9.1`** to register `trace`,
`propagation`, `context` on the OTel global → global version becomes
**`1.9.1`**
2. `setGlobalMeterProvider()` uses the **hoisted `1.9.0`** →
`registerGlobal` sees version mismatch (`1.9.1` ≠ `1.9.0`) → **silently
returns `false`**
3. Global stays `NoopMeterProvider` → every counter, gauge, and
histogram in the server is a no-op

### What this PR does

1. **Reverts three troubleshooting PRs** that are no longer needed now
that the root cause is identified:
   - #20230 — heartbeat gauge
   - #20228 — OTLP export lifecycle logs
- #20221 — Sentry revert to 10.27 (which never actually downgraded in
`yarn.lock` since `^10.27.0` resolved to `10.51.0`)

2. **Fixes the root cause**:
- Root Yarn resolution pinning `@opentelemetry/api` to `1.9.1` → single
copy in the entire tree, Sentry and Twenty share the same instance
- Named import in `instrument.ts` (`import { metrics as otelMetrics }`
instead of default import) as defense-in-depth against CJS interop
issues

### Verified on dev cluster

Exec'd into the running pod and confirmed:
- `@sentry/node` nests `@opentelemetry/api@1.9.1`, hoisted is `1.9.0`
- `Sentry.init()` → global version `1.9.1` → `setGlobalMeterProvider`
with VERSION `1.9.0` → returns `false` → `NoopMeterProvider`
- Same-version registration returns `true` → `MeterProvider` ✓

## Test plan
- [ ] CI passes (lint, typecheck, build)
- [ ] Deploy to dev cluster and verify metrics flow to collector
- [ ] Confirm `node_modules/@opentelemetry/api/package.json` shows
`1.9.1` with no nested copy under `@sentry/`

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-04 15:15:00 +02:00
Paul Rastoin 8a0225e974 Dispatch root package.json hoisted deps and devDeps (#20140)
# Introduction
Dispatching root package.json devDeps, prod deps
Taking care of keeping non imported module used at build/ci level in the
root package.json

## Motivation
Avoid redundant deps declaration, better scoping allow better workspace
deps granularity installation.

<img width="385" height="247" alt="image"
src="https://github.com/user-attachments/assets/9d7162ec-ba01-4f58-8563-38333733fdf0"
/>

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-04-30 16:50:22 +00:00
dependabot[bot] 2c73d47555 Bump @storybook/react-vite from 10.2.13 to 10.3.3 (#19232)
Bumps
[@storybook/react-vite](https://github.com/storybookjs/storybook/tree/HEAD/code/frameworks/react-vite)
from 10.2.13 to 10.3.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/storybookjs/storybook/releases"><code>@​storybook/react-vite</code>'s
releases</a>.</em></p>
<blockquote>
<h2>v10.3.3</h2>
<h2>10.3.3</h2>
<ul>
<li>Addon-Vitest: Streamline vite(st) config detection across init and
postinstall - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34193">#34193</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
</ul>
<h2>v10.3.2</h2>
<h2>10.3.2</h2>
<ul>
<li>CLI: Shorten CTA link messages - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34236">#34236</a>,
thanks <a
href="https://github.com/shilman"><code>@​shilman</code></a>!</li>
<li>React Native Web: Fix vite8 support by bumping vite-plugin-rnw - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34231">#34231</a>,
thanks <a
href="https://github.com/dannyhw"><code>@​dannyhw</code></a>!</li>
</ul>
<h2>v10.3.1</h2>
<h2>10.3.1</h2>
<ul>
<li>CLI: Use npm info to fetch versions in repro command - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34214">#34214</a>,
thanks <a
href="https://github.com/yannbf"><code>@​yannbf</code></a>!</li>
<li>Core: Prevent story-local viewport from persisting in URL - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34153">#34153</a>,
thanks <a
href="https://github.com/ghengeveld"><code>@​ghengeveld</code></a>!</li>
</ul>
<h2>v10.3.0</h2>
<h2>10.3.0</h2>
<p><em>&gt; Improved developer experience, AI-assisting tools, and
broader ecosystem support</em></p>
<p>Storybook 10.3 contains hundreds of fixes and improvements
including:</p>
<ul>
<li>🤖 Storybook MCP: Agentic component dev, docs, and test (Preview
release for React)</li>
<li> Vite 8 support</li>
<li>▲ Next.js 16.2 support</li>
<li>📝 ESLint 10 support</li>
<li>〰️ Addon Pseudo-States: Tailwind v4 support</li>
<li>🔧 Addon-Vitest: Simplified configuration - no more setup files
required</li>
<li> Numerous accessibility improvements across the UI</li>
</ul>
<!-- raw HTML omitted -->
<ul>
<li>A11y: Add ScrollArea prop focusable for when it has static children
- <a
href="https://redirect.github.com/storybookjs/storybook/pull/33876">#33876</a>,
thanks <a
href="https://github.com/Sidnioulz"><code>@​Sidnioulz</code></a>!</li>
<li>A11y: Ensure popover dialogs have an ARIA label - <a
href="https://redirect.github.com/storybookjs/storybook/pull/33500">#33500</a>,
thanks <a
href="https://github.com/gayanMatch"><code>@​gayanMatch</code></a>!</li>
<li>A11y: Make resize handles for addon panel and sidebar accessible <a
href="https://redirect.github.com/storybookjs/storybook/pull/33980">#33980</a></li>
<li>A11y: Underline MDX links for WCAG SC 1.4.1 compliance - <a
href="https://redirect.github.com/storybookjs/storybook/pull/33139">#33139</a>,
thanks <a
href="https://github.com/NikhilChowdhury27"><code>@​NikhilChowdhury27</code></a>!</li>
<li>Actions: Add expandLevel parameter to configure tree depth - <a
href="https://redirect.github.com/storybookjs/storybook/pull/33977">#33977</a>,
thanks <a
href="https://github.com/mixelburg"><code>@​mixelburg</code></a>!</li>
<li>Actions: Fix HandlerFunction type to support async callback props -
<a
href="https://redirect.github.com/storybookjs/storybook/pull/33864">#33864</a>,
thanks <a
href="https://github.com/mixelburg"><code>@​mixelburg</code></a>!</li>
<li>Addon-Docs: Add React as optimizeDeps entry - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34176">#34176</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
<li>Addon-Docs: Add support for `sourceState: 'none'` to canvas block
parameters - <a
href="https://redirect.github.com/storybookjs/storybook/pull/33627">#33627</a>,
thanks <a
href="https://github.com/quisido"><code>@​quisido</code></a>!</li>
<li>Addon-docs: Restore `docs.components` overrides for doc blocks <a
href="https://redirect.github.com/storybookjs/storybook/pull/34111">#34111</a></li>
<li>Addon-Vitest: Add channel API to programmatically trigger test runs
- <a
href="https://redirect.github.com/storybookjs/storybook/pull/33206">#33206</a>,
thanks <a
href="https://github.com/JReinhold"><code>@​JReinhold</code></a>!</li>
<li>Addon-Vitest: Handle additional vitest config export patterns in
postinstall - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34106">#34106</a>,
thanks <a
href="https://github.com/copilot-swe-agent"><code>@​copilot-swe-agent</code></a>!</li>
<li>Addon-Vitest: Make Playwright `--with-deps` platform-aware to avoid
`sudo` prompt on Linux <a
href="https://redirect.github.com/storybookjs/storybook/pull/34121">#34121</a></li>
<li>Addon-Vitest: Refactor Vitest setup to eliminate the need for a
dedicated setup file - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34025">#34025</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
<li>Addon-Vitest: Support Vitest canaries - <a
href="https://redirect.github.com/storybookjs/storybook/pull/33833">#33833</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
<li>Angular: Add moduleResolution: bundler to tsconfig - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34085">#34085</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/storybookjs/storybook/blob/next/CHANGELOG.md"><code>@​storybook/react-vite</code>'s
changelog</a>.</em></p>
<blockquote>
<h2>10.3.3</h2>
<ul>
<li>Addon-Vitest: Streamline vite(st) config detection across init and
postinstall - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34193">#34193</a>,
thanks <a
href="https://github.com/valentinpalkovic"><code>@​valentinpalkovic</code></a>!</li>
</ul>
<h2>10.3.2</h2>
<ul>
<li>CLI: Shorten CTA link messages - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34236">#34236</a>,
thanks <a
href="https://github.com/shilman"><code>@​shilman</code></a>!</li>
<li>React Native Web: Fix vite8 support by bumping vite-plugin-rnw - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34231">#34231</a>,
thanks <a
href="https://github.com/dannyhw"><code>@​dannyhw</code></a>!</li>
</ul>
<h2>10.3.1</h2>
<ul>
<li>CLI: Use npm info to fetch versions in repro command - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34214">#34214</a>,
thanks <a
href="https://github.com/yannbf"><code>@​yannbf</code></a>!</li>
<li>Core: Prevent story-local viewport from persisting in URL - <a
href="https://redirect.github.com/storybookjs/storybook/pull/34153">#34153</a>,
thanks <a
href="https://github.com/ghengeveld"><code>@​ghengeveld</code></a>!</li>
</ul>
<h2>10.3.0</h2>
<p><em>&gt; Improved developer experience, AI-assisting tools, and
broader ecosystem support</em></p>
<p>Storybook 10.3 contains hundreds of fixes and improvements
including:</p>
<ul>
<li>🤖 Storybook MCP: Agentic component dev, docs, and test (Preview
release for React)</li>
<li> Vite 8 support</li>
<li>▲ Next.js 16.2 support</li>
<li>📝 ESLint 10 support</li>
<li>〰️ Addon Pseudo-States: Tailwind v4 support</li>
<li>🔧 Addon-Vitest: Simplified configuration - no more setup files
required</li>
<li> Numerous accessibility improvements across the UI</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/storybookjs/storybook/commit/b0acfb41eb86f7e167ffba404acade8c397681df"><code>b0acfb4</code></a>
Bump version from &quot;10.3.2&quot; to &quot;10.3.3&quot; [skip
ci]</li>
<li><a
href="https://github.com/storybookjs/storybook/commit/308656fe0f4c6d783b72e24390d6b26ce23e8a91"><code>308656f</code></a>
Bump version from &quot;10.3.1&quot; to &quot;10.3.2&quot; [skip
ci]</li>
<li><a
href="https://github.com/storybookjs/storybook/commit/24c2c2c3f2221844406694acc2241e6cdaeb51ac"><code>24c2c2c</code></a>
Bump version from &quot;10.3.0&quot; to &quot;10.3.1&quot; [skip
ci]</li>
<li><a
href="https://github.com/storybookjs/storybook/commit/06cb6a6874742c8815f29f650b4b8d0a5273b46e"><code>06cb6a6</code></a>
Bump version from &quot;10.3.0-beta.3&quot; to &quot;10.3.0&quot; [skip
ci]</li>
<li><a
href="https://github.com/storybookjs/storybook/commit/94b94304e47ed422010a061beb9f31c12c07d242"><code>94b9430</code></a>
Bump version from &quot;10.3.0-beta.2&quot; to &quot;10.3.0-beta.3&quot;
[skip ci]</li>
<li><a
href="https://github.com/storybookjs/storybook/commit/af5b7de899701eb55e511197dbb0420850156125"><code>af5b7de</code></a>
Bump version from &quot;10.3.0-beta.1&quot; to &quot;10.3.0-beta.2&quot;
[skip ci]</li>
<li><a
href="https://github.com/storybookjs/storybook/commit/a571619e5c16b91c3d9f7b52c74955804ef6287c"><code>a571619</code></a>
Bump version from &quot;10.3.0-beta.0&quot; to &quot;10.3.0-beta.1&quot;
[skip ci]</li>
<li><a
href="https://github.com/storybookjs/storybook/commit/546aece1ec7381700b603eece590c0048d16205d"><code>546aece</code></a>
Bump version from &quot;10.3.0-alpha.17&quot; to
&quot;10.3.0-beta.0&quot; [skip ci]</li>
<li><a
href="https://github.com/storybookjs/storybook/commit/ceda0b4de602b3cc5675684bcfbad66fab3601dc"><code>ceda0b4</code></a>
Bump version from &quot;10.3.0-alpha.16&quot; to
&quot;10.3.0-alpha.17&quot; [skip ci]</li>
<li><a
href="https://github.com/storybookjs/storybook/commit/1ed871cb53eff30e332b080c3d73ba0cd50acff3"><code>1ed871c</code></a>
Bump version from &quot;10.3.0-alpha.15&quot; to
&quot;10.3.0-alpha.16&quot; [skip ci]</li>
<li>Additional commits viewable in <a
href="https://github.com/storybookjs/storybook/commits/v10.3.3/code/frameworks/react-vite">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@storybook/react-vite&package-manager=npm_and_yarn&previous-version=10.2.13&new-version=10.3.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Abdullah <125115953+mabdullahabaid@users.noreply.github.com>
2026-04-02 08:49:11 +00:00
Gabriel 36dece43c7 Fix: Upgrade Nodemailer to address SMTP command injection vulnerability (#19151)
📄 Summary

This PR upgrades the nodemailer dependency to a secure version (≥ 8.0.4)
to fix a known SMTP command injection vulnerability
(GHSA-c7w3-x93f-qmm8).

🚨 Issue

The current version used in twenty-server (^7.0.11, resolved to 7.0.11 /
7.0.13) is vulnerable to SMTP command injection due to improper
sanitization of the envelope.size parameter.
This could allow CRLF injection, potentially enabling attackers to add
unauthorized recipients to outgoing emails.

🔍 Root Cause

The vulnerability originates from insufficient validation of
user-controlled input in the SMTP envelope, specifically the size field,
which can be exploited via crafted input containing CRLF sequences.

 Changes
Upgraded nodemailer to version ^8.0.4
Ensured compatibility with existing email sending logic
Verified that no breaking changes affect current usage

🔐 Security Impact

This update mitigates the risk of:

SMTP command injection
Unauthorized email recipient manipulation
Potential data leakage via crafted email payloads
📎 References
GHSA: GHSA-c7w3-x93f-qmm8
CVE: (see linked report in issue)

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
2026-03-31 19:55:50 +00:00
Paul Rastoin 37908114fc [SDK] Extract twenty-front-component-renderer outside of twenty-sdk ( 2.8MB ) (#19021)
Followup https://github.com/twentyhq/twenty/pull/19010

## Dependency diagram

```
┌─────────────────────┐
│     twenty-front    │
│   (React frontend)  │
└─────────┬───────────┘
          │ imports runtime:
          │   FrontComponentRenderer
          │   FrontComponentRendererWithSdkClient
          │   useFrontComponentExecutionContext
          ▼
┌──────────────────────────────────┐         ┌─────────────────────────┐
│ twenty-front-component-renderer  │────────▶│       twenty-sdk        │
│   (remote-dom host + worker)     │         │  (app developer SDK)    │
│                                  │         │                         │
│  imports from twenty-sdk:        │         │  Public API:            │
│   • types only:                  │         │   defineFrontComponent  │
│     FrontComponentExecutionContext│         │   navigate, closeSide…  │
│     NavigateFunction             │         │   useFrontComponent…    │
│     CloseSidePanelFunction       │         │   Command components    │
│     CommandConfirmation…         │         │   conditional avail.    │
│     OpenCommandConfirmation…     │         │                         │
│     EnqueueSnackbarFunction      │         │  Internal only:         │
│     etc.                         │         │   frontComponentHost…   │
│                                  │         │   front-component-build │
│  owns locally:                   │         │   esbuild plugins       │
│   • ALLOWED_HTML_ELEMENTS        │         │                         │
│   • EVENT_TO_REACT               │         └────────────┬────────────┘
│   • HTML_TAG_TO_CUSTOM_ELEMENT…  │                      │
│   • SerializedEventData          │                      │ types
│   • PropertySchema               │                      ▼
│   • frontComponentHostComm…      │         ┌─────────────────────────┐
│     (local ref to globalThis)    │         │     twenty-shared       │
│   • setFrontComponentExecution…  │         │  (common types/utils)   │
│     (local impl, same keys)      │         │   AppPath, SidePanelP…  │
│                                  │         │   EnqueueSnackbarParams │
└──────────────────────────────────┘         │   isDefined, …          │
          │                                  └─────────────────────────┘
          │ also depends on
          ▼
    twenty-shared (types)
    @remote-dom/* (runtime)
    @quilted/threads (runtime)
    react (runtime)
```

**Key points:**

- **`twenty-front`** depends on the renderer, **not** on `twenty-sdk`
directly (for rendering)
- **`twenty-front-component-renderer`** depends on `twenty-sdk` for
**types only** (function signatures, `FrontComponentExecutionContext`).
The runtime bridge (`frontComponentHostCommunicationApi`) is shared via
`globalThis` keys, not module imports
- **`twenty-sdk`** has no dependency on the renderer — clean one-way
dependency
- The renderer owns all remote-dom infrastructure (element schemas,
event mappings, custom element tags) that was previously leaking through
the SDK's public API
- The SDK's `./build` entry point was removed entirely (unused)
2026-03-30 17:06:06 +00:00
Abdullah. 22c9693ce5 First PR to bring in the new twenty website. (#19035)
This PR contains Menu, Hero, TrustedBy, Problem, ThreeCards and Footer
sections of the new website.

Most components in there match the Figma designs, except for two things.
- Zoom levels on 3D illustrations from Endless Tools.
- Menu needs to have the same color as Hero - it's not happening at the
moment since Menu is in the layout, not nested inside pages or Hero.

Images are placeholders (same as Figma).
2026-03-27 13:48:03 +01:00
Paul Rastoin 052aecccc7 Refactor dependency graph for SDK, client-sdk and create-app (#18963)
## Summary

### Externalize `twenty-client-sdk` from `twenty-sdk`

Previously, `twenty-client-sdk` was listed as a `devDependency` of
`twenty-sdk`, which caused Vite to bundle it inline into the dist
output. This meant end-user apps had two copies of `twenty-client-sdk`:
one hidden inside `twenty-sdk`'s bundle, and one installed explicitly in
their `node_modules`. These copies could drift apart since they weren't
guaranteed to be the same version.

**Change:** Moved `twenty-client-sdk` from `devDependencies` to
`dependencies` in `twenty-sdk/package.json`. Vite's `external` function
now recognizes it and keeps it as an external `require`/`import` in the
dist output. End users get a single deduplicated copy resolved by their
package manager.

### Externalize `twenty-sdk` from `create-twenty-app`

Similarly, `create-twenty-app` had `twenty-sdk` as a `devDependency`
(bundled inline). After refactoring `create-twenty-app` to
programmatically import operations from `twenty-sdk` (instead of
shelling out via `execSync`), it became a proper runtime dependency.

**Change:** Moved `twenty-sdk` from `devDependencies` to `dependencies`
in `create-twenty-app/package.json`.

### Switch E2E CI to `yarn npm publish`

The `workspace:*` protocol in `dependencies` is a Yarn-specific feature.
`npm publish` publishes it as-is (which breaks for consumers), while
`yarn npm publish` automatically replaces `workspace:*` with the
resolved version at publish time (e.g., `workspace:*` becomes `=1.2.3`).

**Change:** Replaced `npm publish` with `yarn npm publish` in
`.github/workflows/ci-create-app-e2e.yaml`.

### Replace `execSync` with programmatic SDK calls in
`create-twenty-app`

`create-twenty-app` was shelling out to `yarn twenty remote add` and
`yarn twenty server start` via `execSync`, which assumed the `twenty`
binary was already installed in the scaffolded app. This was fragile and
created an implicit circular dependency.

**Changes:**
- Replaced `execSync('yarn twenty remote add ...')` with a direct call
to `authLoginOAuth()` from `twenty-sdk/cli`
- Replaced `execSync('yarn twenty server start')` with a direct call to
`serverStart()` from `twenty-sdk/cli`
- Deleted the duplicated `setup-local-instance.ts` from
`create-twenty-app`

### Centralize `serverStart` as a dedicated operation

The Docker server start logic was previously inline in the `server
start` CLI command handler (`server.ts`), and `setup-local-instance.ts`
was shelling out to `yarn twenty server start` to invoke it -- meaning
`twenty-sdk` was calling itself via a child process.

**Changes:**
- Extracted the Docker container management logic into a new
`serverStart` operation (`cli/operations/server-start.ts`)
- Merged the detect-or-start flow from `setup-local-instance.ts` into
`serverStart` (detect across multiple ports, start Docker if needed,
poll for health)
- Deleted `setup-local-instance.ts` from `twenty-sdk`
- Added `onProgress` callback (consistent with other operations like
`appBuild`) instead of direct `console.log` calls
- Both the `server start` CLI command and `create-twenty-app` now call
`serverStart()` programmatically

related to https://github.com/twentyhq/twenty-infra/pull/525
2026-03-26 10:56:52 +00:00
Charles Bochet 790a58945b Migrate twenty-companion from npm to yarn workspaces (#18946)
## Summary
- Migrates twenty-companion from standalone npm to the repo yarn
workspaces
- Removes package-lock.json (resolves Oneleet security finding about npm
lifecycle scripts)
- Converts npm overrides to yarn resolutions
- Updates scripts from npm run to yarn

## Test plan
- [x] Verified yarn install succeeds at root
- [x] Verified yarn start in twenty-companion launches the Electron app
- [ ] Verify Oneleet finding is resolved after merge
2026-03-25 10:45:43 +01:00
Paul Rastoin 4ea2e32366 Refactor twenty client sdk provisioning for logic function and front-component (#18544)
## 1. The `twenty-client-sdk` Package (Source of Truth)

The monorepo package at `packages/twenty-client-sdk` ships with:
- A **pre-built metadata client** (static, generated from a fixed
schema)
- A **stub core client** that throws at runtime (`CoreApiClient was not
generated...`)
- Both ESM (`.mjs`) and CJS (`.cjs`) bundles in `dist/`
- A `package.json` with proper `exports` map for
`twenty-client-sdk/core`, `twenty-client-sdk/metadata`, and
`twenty-client-sdk/generate`

## 2. Generation & Upload (Server-Side, at Migration Time)

**When**: `WorkspaceMigrationRunnerService.run()` executes after a
metadata schema change.

**What happens in `SdkClientGenerationService.generateAndStore()`**:
1. Copies the stub `twenty-client-sdk` package from the server's assets
(resolved via `SDK_CLIENT_PACKAGE_DIRNAME` — from
`dist/assets/twenty-client-sdk/` in production, or from `node_modules`
in dev)
2. Filters out `node_modules/` and `src/` during copy — only
`package.json` + `dist/` are kept (like an npm publish)
3. Calls `replaceCoreClient()` which uses `@genql/cli` to introspect the
**application-scoped** GraphQL schema and generates a real
`CoreApiClient`, then compiles it to ESM+CJS and overwrites
`dist/core.mjs` and `dist/core.cjs`
4. Archives the **entire package** (with `package.json` + `dist/`) into
`twenty-client-sdk.zip`
5. Uploads the single archive to S3 under
`FileFolder.GeneratedSdkClient`
6. Sets `isSdkLayerStale = true` on the `ApplicationEntity` in the
database

## 3. Invalidation Signal

The `isSdkLayerStale` boolean column on `ApplicationEntity` is the
invalidation mechanism:
- **Set to `true`** by `generateAndStore()` after uploading a new client
archive
- **Checked** by both logic function drivers before execution — if
`true`, they rebuild their local layer
- **Set back to `false`** by `markSdkLayerFresh()` after the driver has
successfully consumed the new archive

Default is `false` so existing applications without a generated client
aren't affected.

## 4a. Logic Functions — Local Driver

**`ensureSdkLayer()`** is called before every execution:
1. Checks if the local SDK layer directory exists AND `isSdkLayerStale`
is `false` → early return
2. Otherwise, cleans the local layer directory
3. Calls `downloadAndExtractToPackage()` which streams the zip from S3
directly to disk and extracts the full package into
`<tmpdir>/sdk/<workspaceId>-<appId>/node_modules/twenty-client-sdk/`
4. Calls `markSdkLayerFresh()` to set `isSdkLayerStale = false`

**At execution time**, `assembleNodeModules()` symlinks everything from
the deps layer's `node_modules/` **except** `twenty-client-sdk`, which
is symlinked from the SDK layer instead. This ensures the logic
function's `import ... from 'twenty-client-sdk/core'` resolves to the
generated client.

## 4b. Logic Functions — Lambda Driver

**`ensureSdkLayer()`** is called during `build()`:
1. Checks if `isSdkLayerStale` is `false` and an existing Lambda layer
ARN exists → early return
2. Otherwise, deletes all existing layer versions for this SDK layer
name
3. Calls `downloadArchiveBuffer()` to get the raw zip from S3 (no disk
extraction)
4. Calls `reprefixZipEntries()` which streams the zip entries into a
**new zip** with the path prefix
`nodejs/node_modules/twenty-client-sdk/` — this is the Lambda layer
convention path. All done in memory, no disk round-trip
5. Publishes the re-prefixed zip as a new Lambda layer via
`publishLayer()`
6. Calls `markSdkLayerFresh()`

**At function creation**, the Lambda is created with **two layers**:
`[depsLayerArn, sdkLayerArn]`. The SDK layer is listed last so it
overwrites the stub `twenty-client-sdk` from the deps layer (later
layers take precedence in Lambda's `/opt` merge).

## 5. Front Components

Front components are built by `app:build` with `twenty-client-sdk/core`
and `twenty-client-sdk/metadata` as **esbuild externals**. The stored
`.mjs` in S3 has unresolved bare import specifiers like `import {
CoreApiClient } from 'twenty-client-sdk/core'`.

SDK import resolution is split between the **frontend host** (fetching &
caching SDK modules) and the **Web Worker** (rewriting imports):

**Server endpoints**:
- `GET /rest/front-components/:id` —
`FrontComponentService.getBuiltComponentStream()` returns the **raw
`.mjs`** directly from file storage. No bundling, no SDK injection.
- `GET /rest/sdk-client/:applicationId/:moduleName` —
`SdkClientController` reads a single file (e.g. `dist/core.mjs`) from
the generated SDK archive via
`SdkClientGenerationService.readFileFromArchive()` and serves it as
JavaScript.

**Frontend host** (`FrontComponentRenderer` in `twenty-front`):
1. Queries `FindOneFrontComponent` which returns `applicationId`,
`builtComponentChecksum`, `usesSdkClient`, and `applicationTokenPair`
2. If `usesSdkClient` is `true`, renders
`FrontComponentRendererWithSdkClient` which calls the
`useApplicationSdkClient` hook
3. `useApplicationSdkClient({ applicationId, accessToken })` checks the
Jotai atom family cache for existing blob URLs. On cache miss, fetches
both SDK modules from `GET /rest/sdk-client/:applicationId/core` and
`/metadata`, creates **blob URLs** for each, and stores them in the atom
family
4. Once the blob URLs are cached, passes them as `sdkClientUrls`
(already blob URLs, not server URLs) to `SharedFrontComponentRenderer` →
`FrontComponentWorkerEffect` → worker's `render()` call via
`HostToWorkerRenderContext`

**Worker** (`remote-worker.ts` in `twenty-sdk`):
1. Fetches the raw component `.mjs` source as text
2. If `sdkClientUrls` are provided and the source contains SDK import
specifiers (`twenty-client-sdk/core`, `twenty-client-sdk/metadata`),
**rewrites** the bare specifiers to the blob URLs received from the host
(e.g. `'twenty-client-sdk/core'` → `'blob:...'`)
3. Creates a blob URL for the rewritten source and `import()`s it
4. Revokes only the component blob URL after the module is loaded — the
SDK blob URLs are owned and managed by the host's Jotai cache

This approach eliminates server-side esbuild bundling on every request,
caches SDK modules per application in the frontend, and keeps the
worker's job to a simple string rewrite.

## Summary Diagram

```
app:build (SDK)
  └─ twenty-client-sdk stub (metadata=real, core=stub)
       │
       ▼
WorkspaceMigrationRunnerService.run()
  └─ SdkClientGenerationService.generateAndStore()
       ├─ Copy stub package (package.json + dist/)
       ├─ replaceCoreClient() → regenerate core.mjs/core.cjs
       ├─ Zip entire package → upload to S3
       └─ Set isSdkLayerStale = true
              │
     ┌────────┴────────────────────┐
     ▼                             ▼
Logic Functions               Front Components
     │                             │
     ├─ Local Driver               ├─ GET /rest/sdk-client/:appId/core
     │   └─ downloadAndExtract     │    → core.mjs from archive
     │      → symlink into         │
     │        node_modules         ├─ Host (useApplicationSdkClient)
     │                             │    ├─ Fetch SDK modules
     └─ Lambda Driver              │    ├─ Create blob URLs
         └─ downloadArchiveBuffer  │    └─ Cache in Jotai atom family
            → reprefixZipEntries   │
            → publish as Lambda    ├─ GET /rest/front-components/:id
              layer                │    → raw .mjs (no bundling)
                                   │
                                   └─ Worker (browser)
                                        ├─ Fetch component .mjs
                                        ├─ Rewrite imports → blob URLs
                                        └─ import() rewritten source
```

## Next PR
- Estimate perf improvement by implementing a redis caching for front
component client storage ( we don't even cache front comp initially )
- Implem frontent blob invalidation sse event from server

---------

Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
2026-03-24 18:10:25 +00:00
Félix Malfait b470cb21a1 Upgrade Apollo Client to v4 and refactor error handling (#18584)
## Summary
This PR upgrades Apollo Client from v3.10.0 to v4 and refactors error
handling patterns across the codebase to use a new centralized
`useSnackBarOnQueryError` hook.

## Key Changes

- **Dependency Update**: Upgraded `@apollo/client` from `^3.10.0` to
`^3.11.0` in root package.json
- **New Hook**: Added `useSnackBarOnQueryError` hook for centralized
Apollo query error handling with snack bar notifications
- **Error Handling Refactor**: Updated 100+ files to use the new error
handling pattern:
  - Removed direct `ApolloError` imports where no longer needed
- Replaced manual error handling logic with `useSnackBarOnQueryError`
hook
- Simplified error handling in hooks and components across multiple
modules
- **GraphQL Codegen**: Updated codegen configuration files to work with
Apollo Client v3.11.0
- **Type Definitions**: Added TypeScript declaration file for
`apollo-upload-client` module
- **Test Updates**: Updated test files to reflect new error handling
patterns

## Notable Implementation Details

- The new `useSnackBarOnQueryError` hook provides a consistent way to
handle Apollo query errors with automatic snack bar notifications
- Changes span across multiple feature areas: auth, object records,
settings, workflows, billing, and more
- All changes maintain backward compatibility while improving code
maintainability and reducing duplication
- Jest configuration updated to work with the new Apollo Client version

https://claude.ai/code/session_019WGZ6Rd7sEHuBg9sTrXRqJ

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-13 14:59:46 +01:00
Raphaël Bosi c9deab4373 [COMMAND MENU ITEMS] Remove standard front components (#18581)
All standard command menu items will link to an engine component instead
of standard front components.
2026-03-12 15:18:00 +01:00