85406a58fb05d64e6c36f2183dfbdd74b0775da9
277 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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. --> |
||
|
|
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. |
||
|
|
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. |
||
|
|
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> |
||
|
|
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. |
||
|
|
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. |
||
|
|
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. |
||
|
|
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. --> |
||
|
|
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. --> |
||
|
|
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. --> |
||
|
|
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. --> |
||
|
|
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. --> |
||
|
|
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 |
||
|
|
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
|
||
|
|
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) |
||
|
|
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.** |
||
|
|
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. |
||
|
|
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** ✓. |
||
|
|
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`). |
||
|
|
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. |
||
|
|
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
|
||
|
|
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 |
||
|
|
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. |
||
|
|
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 |
||
|
|
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. |
||
|
|
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. |
||
|
|
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`. |
||
|
|
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. |
||
|
|
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> |
||
|
|
1642be86f5 |
Bonapara/twenty codex plugin (#20857)
@martmull v2.0 ;) --------- Co-authored-by: martmull <martmull@hotmail.fr> Co-authored-by: bosiraphael <raphael.bosi@gmail.com> |
||
|
|
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&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&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&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 /> [](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> |
||
|
|
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> |
||
|
|
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 |
||
|
|
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. |
||
|
|
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 |
||
|
|
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 |
||
|
|
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 |
||
|
|
59107b5b23 | Remove twenty-website package. (#20270) | ||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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>> 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>> 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 "10.3.2" to "10.3.3" [skip ci]</li> <li><a href="https://github.com/storybookjs/storybook/commit/308656fe0f4c6d783b72e24390d6b26ce23e8a91"><code>308656f</code></a> Bump version from "10.3.1" to "10.3.2" [skip ci]</li> <li><a href="https://github.com/storybookjs/storybook/commit/24c2c2c3f2221844406694acc2241e6cdaeb51ac"><code>24c2c2c</code></a> Bump version from "10.3.0" to "10.3.1" [skip ci]</li> <li><a href="https://github.com/storybookjs/storybook/commit/06cb6a6874742c8815f29f650b4b8d0a5273b46e"><code>06cb6a6</code></a> Bump version from "10.3.0-beta.3" to "10.3.0" [skip ci]</li> <li><a href="https://github.com/storybookjs/storybook/commit/94b94304e47ed422010a061beb9f31c12c07d242"><code>94b9430</code></a> Bump version from "10.3.0-beta.2" to "10.3.0-beta.3" [skip ci]</li> <li><a href="https://github.com/storybookjs/storybook/commit/af5b7de899701eb55e511197dbb0420850156125"><code>af5b7de</code></a> Bump version from "10.3.0-beta.1" to "10.3.0-beta.2" [skip ci]</li> <li><a href="https://github.com/storybookjs/storybook/commit/a571619e5c16b91c3d9f7b52c74955804ef6287c"><code>a571619</code></a> Bump version from "10.3.0-beta.0" to "10.3.0-beta.1" [skip ci]</li> <li><a href="https://github.com/storybookjs/storybook/commit/546aece1ec7381700b603eece590c0048d16205d"><code>546aece</code></a> Bump version from "10.3.0-alpha.17" to "10.3.0-beta.0" [skip ci]</li> <li><a href="https://github.com/storybookjs/storybook/commit/ceda0b4de602b3cc5675684bcfbad66fab3601dc"><code>ceda0b4</code></a> Bump version from "10.3.0-alpha.16" to "10.3.0-alpha.17" [skip ci]</li> <li><a href="https://github.com/storybookjs/storybook/commit/1ed871cb53eff30e332b080c3d73ba0cd50acff3"><code>1ed871c</code></a> Bump version from "10.3.0-alpha.15" to "10.3.0-alpha.16" [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 /> [](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> |
||
|
|
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> |
||
|
|
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) |
||
|
|
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). |
||
|
|
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
|
||
|
|
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 |
||
|
|
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>
|
||
|
|
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> |
||
|
|
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. |