7ca2efeb96f73a7a3e200d61adcf8bb84cd5b5cf
12204
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
7ca2efeb96 |
i18n - translations (#20796)
Created by Github action --------- Co-authored-by: github-actions <github-actions@twenty.com> |
||
|
|
224376233b |
fix(front): focus new Field widget and open side panel on add (#20777)
## Context In the record-page edit mode, the "Add widget" section has three menu items: `Fields group`, `Field`, and `More widgets`. `Fields group` creates the widget, focuses it, and opens its settings side panel. `Field` only added the widget to the draft — no focus, no panel — which left the user without visible confirmation or a way to immediately edit the new widget. ## Change Updated `useCreateRecordPageFieldWidget` to mirror `useCreateRecordPageFieldsWidget`: After appending the new widget to the draft, it now sets `pageLayoutEditingWidgetIdComponentState` to the new widget's id and navigates the side panel to `SidePanelPages.RecordPageFieldSettings` (with `focusTitleInput: true`, `resetNavigationStack: true`). This matches the behavior of clicking an existing field widget in `useOpenWidgetSettingsInSidePanel` (`WidgetType.FIELD` branch). |
||
|
|
a3c92311e3 |
Application file storage service (#20793)
# Introduction Fix unsafe resource path join with expected prefix at file storage directly Add early paths transversal detections in metadata validators |
||
|
|
1ed347bc17 |
chore: sync AI model catalog from models.dev (#20791)
Automated daily sync of `ai-providers.json` from [models.dev](https://models.dev). This PR updates pricing, context windows, and model availability based on the latest data. New models meeting inclusion criteria (tool calling, pricing data, context limits) are added automatically. Deprecated models are detected based on cost-efficiency within the same model family. **Please review before merging** — verify no critical models were incorrectly deprecated. Co-authored-by: FelixMalfait <6399865+FelixMalfait@users.noreply.github.com> |
||
|
|
b792f7654b |
chore(deps): bump tinyglobby from 0.2.15 to 0.2.16 (#20788)
Bumps [tinyglobby](https://github.com/SuperchupuDev/tinyglobby) from 0.2.15 to 0.2.16. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/SuperchupuDev/tinyglobby/releases">tinyglobby's releases</a>.</em></p> <blockquote> <h2>0.2.16</h2> <h2>Fixed</h2> <ul> <li>Upgraded <code>picomatch</code> to 4.0.4, mitigating any potential exposure to <a href="https://github.com/micromatch/picomatch/security/advisories/GHSA-c2c7-rcm5-vvqj">CVE-2026-33671</a> and <a href="https://github.com/micromatch/picomatch/security/advisories/GHSA-3v7f-55p6-f55p">CVE-2026-33672</a></li> </ul> <h2>Changed</h2> <ul> <li>Overhauled and optimized most internals by <a href="https://github.com/Torathion"><code>@Torathion</code></a></li> <li>Ignore patterns are no longer compiled twice by <a href="https://github.com/webpro"><code>@webpro</code></a></li> </ul> <p>Consider <a href="https://github.com/sponsors/SuperchupuDev">sponsoring</a> if you'd like to support the development of this project and the goal of reaching a lighter and faster ecosystem</p> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/SuperchupuDev/tinyglobby/blob/main/CHANGELOG.md">tinyglobby's changelog</a>.</em></p> <blockquote> <h3><a href="https://github.com/SuperchupuDev/tinyglobby/compare/0.2.15...0.2.16">0.2.16</a></h3> <h4>Fixed</h4> <ul> <li>Upgraded <code>picomatch</code> to 4.0.4, mitigating any potential exposure to <a href="https://github.com/micromatch/picomatch/security/advisories/GHSA-c2c7-rcm5-vvqj">CVE-2026-33671</a> and <a href="https://github.com/micromatch/picomatch/security/advisories/GHSA-3v7f-55p6-f55p">CVE-2026-33672</a></li> </ul> <h4>Changed</h4> <ul> <li>Overhauled and optimized most internals by <a href="https://github.com/Torathion">Torathion</a></li> <li>Ignore patterns are no longer compiled twice by <a href="https://github.com/webpro">webpro</a></li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/SuperchupuDev/tinyglobby/commit/577920259c91f5603fab3dbfa599a83bbb14a27a"><code>5779202</code></a> release 0.2.16</li> <li><a href="https://github.com/SuperchupuDev/tinyglobby/commit/071954f97f4d2b573ecd92aecb48220867b3c776"><code>071954f</code></a> bump deps once more</li> <li><a href="https://github.com/SuperchupuDev/tinyglobby/commit/e541dde000158e69b44e8b5a03789d136d88ae0d"><code>e541dde</code></a> do not import the whole <code>fs</code> module</li> <li><a href="https://github.com/SuperchupuDev/tinyglobby/commit/2381b766d3447e078b3112e533ada07621f60526"><code>2381b76</code></a> fix root being too broad</li> <li><a href="https://github.com/SuperchupuDev/tinyglobby/commit/0addeb9a78cab5fd93ac6dad217f75930cfbfda2"><code>0addeb9</code></a> chore(deps): update all non-major dependencies (<a href="https://redirect.github.com/SuperchupuDev/tinyglobby/issues/191">#191</a>)</li> <li><a href="https://github.com/SuperchupuDev/tinyglobby/commit/91ac26cc3bda60378d188565ce4f05e884aa4f31"><code>91ac26c</code></a> chore(deps): update pnpm/action-setup action to v5 (<a href="https://redirect.github.com/SuperchupuDev/tinyglobby/issues/192">#192</a>)</li> <li><a href="https://github.com/SuperchupuDev/tinyglobby/commit/c50558e944bf71dbfeb392f8693fada87f520a70"><code>c50558e</code></a> upgrade picomatch (and everything else)</li> <li><a href="https://github.com/SuperchupuDev/tinyglobby/commit/618517544e95f8167f1722902558dd78dcd34fe6"><code>6185175</code></a> chore(deps): update dependency picomatch to v4.0.4 [security] (<a href="https://redirect.github.com/SuperchupuDev/tinyglobby/issues/193">#193</a>)</li> <li><a href="https://github.com/SuperchupuDev/tinyglobby/commit/49c2b9356c4977f1f531de651f90b420a06c64f6"><code>49c2b93</code></a> enable pnpm <code>trustPolicy</code></li> <li><a href="https://github.com/SuperchupuDev/tinyglobby/commit/bc825c476a5a429e58e06d11364cd68707b4cdd1"><code>bc825c4</code></a> chore(deps): update all non-major dependencies (<a href="https://redirect.github.com/SuperchupuDev/tinyglobby/issues/181">#181</a>)</li> <li>Additional commits viewable in <a href="https://github.com/SuperchupuDev/tinyglobby/compare/0.2.15...0.2.16">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> |
||
|
|
42ad3cbd1a |
chore(deps): bump linkify-react from 4.3.2 to 4.3.3 (#20789)
Bumps [linkify-react](https://github.com/nfrasser/linkifyjs/tree/HEAD/packages/linkify-react) from 4.3.2 to 4.3.3. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/nfrasser/linkifyjs/releases">linkify-react's releases</a>.</em></p> <blockquote> <h2>v4.3.3</h2> <h2>What's Changed</h2> <ul> <li>Fix parsing bugs with some special encoded URLs</li> <li>Parsed emails should not include port numbers</li> <li>Exact version requirement for interfaces and plugins to avoid incompatibility issues with older versions of linkify core</li> <li>Support for jQuery 4</li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/nfrasser/linkifyjs/compare/v4.3.2...v4.3.3">https://github.com/nfrasser/linkifyjs/compare/v4.3.2...v4.3.3</a></p> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/nfrasser/linkifyjs/blob/main/CHANGELOG.md">linkify-react's changelog</a>.</em></p> <blockquote> <h2>v4.3.3</h2> <ul> <li>Fix parsing bugs with some special encoded URLs</li> <li>Parsed emails should not include port numbers</li> <li>Exact version requirement for interfaces and plugins to avoid incompatibility issues with older versions of linkify core</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/nfrasser/linkifyjs/commit/7fffcc6b48f7dbf8e98fca493e1c997a659fe651"><code>7fffcc6</code></a> v4.3.3</li> <li><a href="https://github.com/nfrasser/linkifyjs/commit/2cb8352d78c7449cd8c7ee489a647d3422640a25"><code>2cb8352</code></a> Update dependencies (<a href="https://github.com/nfrasser/linkifyjs/tree/HEAD/packages/linkify-react/issues/529">#529</a>)</li> <li>See full diff in <a href="https://github.com/nfrasser/linkifyjs/commits/v4.3.3/packages/linkify-react">compare view</a></li> </ul> </details> <details> <summary>Maintainer changes</summary> <p>This version was pushed to npm by <a href="https://www.npmjs.com/~GitHub%20Actions">GitHub Actions</a>, a new releaser for linkify-react since your current version.</p> </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> |
||
|
|
e1378dd4cf |
chore(deps): bump @azure/msal-node from 3.8.4 to 3.8.10 (#20787)
Bumps [@azure/msal-node](https://github.com/AzureAD/microsoft-authentication-library-for-js) from 3.8.4 to 3.8.10. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/AzureAD/microsoft-authentication-library-for-js/releases">@azure/msal-node's releases</a>.</em></p> <blockquote> <h2><code>@azure/msal-node</code> v3.8.10</h2> <h2>3.8.10</h2> <p>Wed, 18 Mar 2026 20:48:29 GMT</p> <h3>Patches</h3> <ul> <li>Bump <code>@azure/msal-common</code> to v15.17.0 (beachball)</li> <li>Bump eslint-config-msal to v0.0.0 (beachball)</li> <li>Bump rollup-msal to v0.0.0 (beachball)</li> </ul> <h2><code>@azure/msal-node</code> v3.8.9</h2> <h2>3.8.9</h2> <p>Fri, 13 Mar 2026 04:32:07 GMT</p> <h3>Patches</h3> <ul> <li>Bump <code>@azure/msal-common</code> to v15.16.1 (beachball)</li> <li>Bump eslint-config-msal to v0.0.0 (beachball)</li> <li>Bump rollup-msal to v0.0.0 (beachball)</li> </ul> <h2><code>@azure/msal-node</code> v3.8.8</h2> <h2>3.8.8</h2> <p>Mon, 23 Feb 2026 16:28:24 GMT</p> <h3>Patches</h3> <ul> <li>Bump <code>@azure/msal-common</code> to v15.15.0 (beachball)</li> <li>Bump eslint-config-msal to v0.0.0 (beachball)</li> <li>Bump rollup-msal to v0.0.0 (beachball)</li> </ul> <h2><code>@azure/msal-node</code> v3.8.7</h2> <h2>3.8.7</h2> <p>Tue, 10 Feb 2026 22:19:29 GMT</p> <h3>Patches</h3> <ul> <li>Bump <code>@azure/msal-common</code> to v15.14.2 (beachball)</li> <li>Bump eslint-config-msal to v0.0.0 (beachball)</li> <li>Bump rollup-msal to v0.0.0 (beachball)</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/AzureAD/microsoft-authentication-library-for-js/commit/74c792ec34cd83a3470c4d878b403af0fa2884f0"><code>74c792e</code></a> [v4] Add missing client capabilities in platform broker flows (<a href="https://redirect.github.com/AzureAD/microsoft-authentication-library-for-js/issues/8429">#8429</a>)</li> <li><a href="https://github.com/AzureAD/microsoft-authentication-library-for-js/commit/e096fc85e22fcb941646b3f5d9f264b90dffd0ad"><code>e096fc8</code></a> [v4] Post-release PR (<a href="https://redirect.github.com/AzureAD/microsoft-authentication-library-for-js/issues/8425">#8425</a>)</li> <li><a href="https://github.com/AzureAD/microsoft-authentication-library-for-js/commit/23cd31c1fbcfa569dd9135830f5168ec71678a19"><code>23cd31c</code></a> [v4] Add support for client data telemetry with CLI_DATA parameter (<a href="https://redirect.github.com/AzureAD/microsoft-authentication-library-for-js/issues/8378">#8378</a>)</li> <li><a href="https://github.com/AzureAD/microsoft-authentication-library-for-js/commit/eb893e565a4f7de5b9c957b37bb4f975302f1713"><code>eb893e5</code></a> Track online/offline status change (<a href="https://redirect.github.com/AzureAD/microsoft-authentication-library-for-js/issues/8410">#8410</a>)</li> <li><a href="https://github.com/AzureAD/microsoft-authentication-library-for-js/commit/d221f4e6dbc439e771a90f1648c8f5db09b4d88b"><code>d221f4e</code></a> [v4] Respect claims of the brokered application (<a href="https://redirect.github.com/AzureAD/microsoft-authentication-library-for-js/issues/8409">#8409</a>)</li> <li><a href="https://github.com/AzureAD/microsoft-authentication-library-for-js/commit/73df97e5c505010f6b9681749df28a328e4e3894"><code>73df97e</code></a> Common partial release resolution (<a href="https://redirect.github.com/AzureAD/microsoft-authentication-library-for-js/issues/8397">#8397</a>)</li> <li><a href="https://github.com/AzureAD/microsoft-authentication-library-for-js/commit/ee5e7abd5d9a6cfb6ada9b3ac36e15a81f7ba3a8"><code>ee5e7ab</code></a> monitor_window_timeout telemetry (<a href="https://redirect.github.com/AzureAD/microsoft-authentication-library-for-js/issues/8380">#8380</a>)</li> <li><a href="https://github.com/AzureAD/microsoft-authentication-library-for-js/commit/2be7888051cc12e7447487e84c826159dad3ed42"><code>2be7888</code></a> Rename dev to v4-lts changes (<a href="https://redirect.github.com/AzureAD/microsoft-authentication-library-for-js/issues/8364">#8364</a>)</li> <li><a href="https://github.com/AzureAD/microsoft-authentication-library-for-js/commit/4486b7e4bfedc414f7f5f1a7786be30484318206"><code>4486b7e</code></a> Fix JSON object conversion in PlatformDOMRequest v4 (<a href="https://redirect.github.com/AzureAD/microsoft-authentication-library-for-js/issues/8350">#8350</a>)</li> <li><a href="https://github.com/AzureAD/microsoft-authentication-library-for-js/commit/3e5d58b71e232b5978edcf0bd4c05f5948b8a747"><code>3e5d58b</code></a> Post-release PR (<a href="https://redirect.github.com/AzureAD/microsoft-authentication-library-for-js/issues/8354">#8354</a>)</li> <li>Additional commits viewable in <a href="https://github.com/AzureAD/microsoft-authentication-library-for-js/compare/msal-node-v3.8.4...msal-node-v3.8.10">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> |
||
|
|
5e1b23a28b |
chore(deps): bump @recallai/desktop-sdk from 2.0.8 to 2.0.15 (#20785)
Bumps @recallai/desktop-sdk from 2.0.8 to 2.0.15. [](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> |
||
|
|
7aef406696 |
i18n - translations (#20782)
Created by Github action --------- Co-authored-by: github-actions <github-actions@twenty.com> |
||
|
|
923c3beead |
fix(auth): clarify error when joining a non-active workspace (#20769)
## Summary When an existing user accepts an invite into a workspace whose `activationStatus` is not `ACTIVE` (e.g. `SUSPENDED`, `INACTIVE`, `PENDING_CREATION`), the throw in `throwIfWorkspaceIsNotReadyForSignInUp` returns: > User is not part of the workspace The message describes the symptom (they aren't a member yet) instead of the cause (the workspace can't accept new members), which makes invitees assume their invite is broken when the real issue is the target workspace's state. The sibling branch a few lines above — for brand-new users hitting the same non-ACTIVE workspace — already returns `"Workspace is not ready to welcome new members"`. This PR reuses the same message in the existing-user branch so both paths give a consistent, accurate explanation. Single file, two string literals. ## Test plan - [ ] Sign in via Google with an existing Twenty account, accepting an invite to a `SUSPENDED` workspace → confirm the new message is shown instead of "User is not part of the workspace". - [ ] Confirm the happy path (sign-in to an `ACTIVE` workspace via invite) is unchanged — early-return on `ACTIVE` is untouched. --------- Co-authored-by: Charles Bochet <charles@twenty.com> |
||
|
|
31842f7714 |
Ci server custom jest reporter (#20765)
# Introduction Only display failing unit tests trace in the ci-server server-test jobs So it's possible to identify what unit test are failing without having to re run them locally |
||
|
|
9988f98577 |
feat(server): idempotent CLI to rotate ENCRYPTION_KEY across enc:v2 rows (#20613)
## Summary
Adds the \`secret-encryption:rotate\` CLI command, which re-encrypts
every at-rest secret stored in an \`enc:v2:\` envelope under the current
\`ENCRYPTION_KEY\`. The command is **online** and **resumable**: a SQL
filter skips rows already on the current keyId, so interrupting it
(Ctrl-C, container restart, …) and re-running picks up where it left off
without re-rotating earlier rows.
### Sites covered (one handler each)
| Site | Table.column | Scope |
| --- | --- | --- |
| \`connected-account-tokens\` | \`connectedAccount.{accessToken,
refreshToken}\` | workspace |
| \`application-variable\` | \`applicationVariable.value\` (isSecret
only) | workspace |
| \`application-registration-variable\` |
\`applicationRegistrationVariable.encryptedValue\` | instance |
| \`signing-key-private-keys\` | \`signingKey.privateKey\` | instance |
| \`sensitive-config-storage\` | \`keyValuePair.value\` (isSensitive +
STRING configs) | instance |
| \`totp-secrets\` | \`twoFactorAuthenticationMethod.secret\` |
workspace |
Each handler:
- Filters at SQL level on \`value LIKE 'enc:v2:%' AND value NOT LIKE
'enc:v2:<primaryKeyId>:%'\` to enforce idempotency without re-decrypting
already-rotated rows.
- Uses cursor-based batching (default **200**, capped **5000**).
- Threads \`workspaceId\` into HKDF for workspace-scoped sites; runs
instance-scoped for the rest.
### CLI flags
| Flag | Description |
| --- | --- |
| \`-s, --site <site>\` | Limit to a single site. |
| \`-b, --batch-size <n>\` | Override per-batch row count. |
| \`-d, --dry-run\` | Decrypt + re-encrypt in memory, skip the
\`UPDATE\`. |
The runner logs progress via Nest \`Logger\` (per-site start,
completion, final summary) and exits non-zero when any site reports
\`errors > 0\`. \`FALLBACK_ENCRYPTION_KEY\` must be set to the previous
\`ENCRYPTION_KEY\` during rotation; the runner warns when it is unset.
Operator documentation lives in #20611 (docs PR).
|
||
|
|
3c458ce4ca |
i18n - docs translations (#20778)
Created by Github action Co-authored-by: github-actions <github-actions@twenty.com> |
||
|
|
b869107a22 |
fix(messaging): preserve all gmail to/cc/bcc recipients as participants (#20491)
As title but I also refactored it a little to match our current file and code conventions since the code was very old Reported by a cloud customer --------- Co-authored-by: martmull <martmull@hotmail.fr> |
||
|
|
4c4dc4cb21 | fix(ai-chat)-preference models import (#20776) | ||
|
|
237a943947 |
Update twenty sdk commands (#20735)
Performs twenty-sdk cli command migration: Summary ``` ┌─────┬──────────────────────────┬────────────────────────────┬───────────────────────┐ │ # │ Old command │ New command │ Status │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 1 │ twenty dev [appPath] │ twenty dev [appPath] │ Unchanged (now also │ │ │ │ │ DEFAULT) │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 2 │ twenty dev --once │ twenty dev --once │ Unchanged │ │ │ [appPath] │ [appPath] │ │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 3 │ twenty dev --watch │ twenty dev [appPath] │ --watch flag removed │ │ │ [appPath] │ │ (was default) │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 4 │ twenty dev --verbose │ twenty dev --verbose │ Unchanged │ │ │ [appPath] │ [appPath] │ │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 5 │ twenty dev --debug │ twenty dev --debug │ Unchanged │ │ │ [appPath] │ [appPath] │ │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 6 │ twenty dev --debounceMs │ twenty dev --debounceMs │ Unchanged │ │ │ <ms> [appPath] │ <ms> [appPath] │ │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 7 │ twenty build [appPath] │ twenty dev:build [appPath] │ Deprecated → colon │ │ │ │ │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 8 │ twenty build --tarball │ twenty dev:build --tarball │ Deprecated → colon │ │ │ [appPath] │ [appPath] │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 9 │ twenty typecheck │ twenty dev:typecheck │ Deprecated → colon │ │ │ [appPath] │ [appPath] │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 10 │ twenty logs [appPath] │ twenty dev:fn-logs │ Deprecated → colon │ │ │ │ [appPath] │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 11 │ twenty logs -n <name> │ twenty dev:fn-logs -n │ Deprecated → colon │ │ │ [appPath] │ <name> [appPath] │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 12 │ twenty logs -u <id> │ twenty dev:fn-logs -u <id> │ Deprecated → colon │ │ │ [appPath] │ [appPath] │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 13 │ twenty exec [appPath] │ twenty dev:fn-exec │ Deprecated → colon │ │ │ │ [appPath] │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 14 │ twenty exec -n <name> │ twenty dev:fn-exec -n │ Deprecated → colon │ │ │ [appPath] │ <name> [appPath] │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 15 │ twenty exec -u <id> │ twenty dev:fn-exec -u <id> │ Deprecated → colon │ │ │ [appPath] │ [appPath] │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 16 │ twenty exec -p <json> │ twenty dev:fn-exec -p │ Deprecated → colon │ │ │ [appPath] │ <json> [appPath] │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 17 │ twenty exec │ twenty dev:fn-exec │ Deprecated → colon │ │ │ --postInstall [appPath] │ --postInstall [appPath] │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 18 │ twenty exec --preInstall │ twenty dev:fn-exec │ Deprecated → colon │ │ │ [appPath] │ --preInstall [appPath] │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 19 │ twenty add [entityType] │ twenty dev:add │ Deprecated → colon │ │ │ │ [entityType] │ command │ ├─────┼──────────────────────────┼────────────────────────────┼───────────────────────┤ │ 20 │ twenty add --path <path> │ twenty dev:add --path │ Deprecated → colon │ │ │ [entityType] │ <path> [entityType] │ command │ └─────┴──────────────────────────┴────────────────────────────┴───────────────────────┘ App lifecycle commands ┌─────┬────────────────────────┬────────────────────────────┬─────────────────────────┐ │ # │ Old command │ New command │ Status │ ├─────┼────────────────────────┼────────────────────────────┼─────────────────────────┤ │ 21 │ twenty publish │ twenty app:publish │ Deprecated → colon │ │ │ [appPath] │ [appPath] │ command │ ├─────┼────────────────────────┼────────────────────────────┼─────────────────────────┤ │ 22 │ twenty publish --tag │ twenty app:publish --tag │ Deprecated → colon │ │ │ <tag> [appPath] │ <tag> [appPath] │ command │ ├─────┼────────────────────────┼────────────────────────────┼─────────────────────────┤ │ 23 │ twenty deploy │ twenty app:publish │ Deprecated → colon │ │ │ [appPath] │ --private [appPath] │ command + --private │ ├─────┼────────────────────────┼────────────────────────────┼─────────────────────────┤ │ 24 │ twenty install │ twenty app:install │ Deprecated → colon │ │ │ [appPath] │ [appPath] │ command │ ├─────┼────────────────────────┼────────────────────────────┼─────────────────────────┤ │ 25 │ twenty uninstall │ twenty app:uninstall │ Deprecated → colon │ │ │ [appPath] │ [appPath] │ command │ ├─────┼────────────────────────┼────────────────────────────┼─────────────────────────┤ │ 26 │ twenty uninstall -y │ twenty app:uninstall -y │ Deprecated → colon │ │ │ [appPath] │ [appPath] │ command │ └─────┴────────────────────────┴────────────────────────────┴─────────────────────────┘ Server commands ┌─────┬─────────────────────────┬─────────────────────────────┬──────────────────────┐ │ # │ Old command │ New command │ Status │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 27 │ twenty server start │ twenty docker:start │ Deprecated → colon │ │ │ │ │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 28 │ twenty server start -p │ twenty docker:start -p │ Deprecated → colon │ │ │ <port> │ <port> │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 29 │ twenty server start │ twenty docker:start --test │ Deprecated → colon │ │ │ --test │ │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 30 │ twenty server stop │ twenty docker:stop │ Deprecated → colon │ │ │ │ │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 31 │ twenty server stop │ twenty docker:stop --test │ Deprecated → colon │ │ │ --test │ │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 32 │ twenty server status │ twenty docker:status │ Deprecated → colon │ │ │ │ │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 33 │ twenty server status │ twenty docker:status --test │ Deprecated → colon │ │ │ --test │ │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 34 │ twenty server logs │ twenty docker:logs │ Deprecated → colon │ │ │ │ │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 35 │ twenty server logs -n │ twenty docker:logs -n │ Deprecated → colon │ │ │ <lines> │ <lines> │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 36 │ twenty server logs │ twenty docker:logs --test │ Deprecated → colon │ │ │ --test │ │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 37 │ twenty server reset │ twenty docker:reset │ Deprecated → colon │ │ │ │ │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 38 │ twenty server reset │ twenty docker:reset --test │ Deprecated → colon │ │ │ --test │ │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 39 │ twenty server upgrade │ twenty docker:upgrade │ Deprecated → colon │ │ │ [version] │ [version] │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 40 │ twenty server upgrade │ twenty docker:upgrade │ Deprecated → colon │ │ │ --test [version] │ --test [version] │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 41 │ twenty server │ twenty app:catalog-sync │ Deprecated → colon │ │ │ catalog-sync │ │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 42 │ twenty server │ twenty app:catalog-sync │ Deprecated → colon │ │ │ catalog-sync -r <name> │ -r <name> │ syntax │ ├─────┼─────────────────────────┼─────────────────────────────┼──────────────────────┤ │ 43 │ twenty catalog-sync │ (removed) │ Removed (was already │ │ │ │ │ deprecated) │ └─────┴─────────────────────────┴─────────────────────────────┴──────────────────────┘ Remote commands ┌─────┬────────────────────────┬──────────────────────────┬──────────────────────────┐ │ # │ Old command │ New command │ Status │ ├─────┼────────────────────────┼──────────────────────────┼──────────────────────────┤ │ 44 │ twenty remote add │ twenty remote:add │ Deprecated → colon │ │ │ │ │ syntax │ ├─────┼────────────────────────┼──────────────────────────┼──────────────────────────┤ │ 45 │ twenty remote add --as │ twenty remote:add --as │ Deprecated → colon │ │ │ <name> │ <name> │ syntax │ ├─────┼────────────────────────┼──────────────────────────┼──────────────────────────┤ │ 46 │ twenty remote add │ twenty remote:add │ Deprecated → colon │ │ │ --api-key <key> │ --api-key <key> │ syntax │ ├─────┼────────────────────────┼──────────────────────────┼──────────────────────────┤ │ 47 │ twenty remote add │ twenty remote:add │ Deprecated → colon │ │ │ --api-url <url> │ --api-url <url> │ syntax │ ├─────┼────────────────────────┼──────────────────────────┼──────────────────────────┤ │ 48 │ twenty remote add │ twenty remote:add │ Deprecated → colon │ │ │ --local │ --local │ syntax │ ├─────┼────────────────────────┼──────────────────────────┼──────────────────────────┤ │ 49 │ twenty remote add │ twenty remote:add --test │ Deprecated → colon │ │ │ --test │ │ syntax │ ├─────┼────────────────────────┼──────────────────────────┼──────────────────────────┤ │ 50 │ twenty remote list │ twenty remote:list │ Deprecated → colon │ │ │ │ │ syntax │ ├─────┼────────────────────────┼──────────────────────────┼──────────────────────────┤ │ 51 │ twenty remote switch │ twenty remote:use [name] │ Deprecated → colon │ │ │ [name] │ │ syntax + renamed │ ├─────┼────────────────────────┼──────────────────────────┼──────────────────────────┤ │ 52 │ twenty remote status │ twenty remote:status │ Deprecated → colon │ │ │ │ │ syntax │ ├─────┼────────────────────────┼──────────────────────────┼──────────────────────────┤ │ 53 │ twenty remote remove │ twenty remote:remove │ Deprecated → colon │ │ │ <name> │ <name> │ syntax │ └─────┴────────────────────────┴──────────────────────────┴──────────────────────────┘ ``` --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> |
||
|
|
6e5e7963b5 |
fix(server): map PermissionsException to proper HTTP status on REST API (#20739)
## Summary `PermissionsException` thrown by `SettingsPermissionGuard` (and other permission code paths) was bubbling up through every typed REST exception filter and landing in the global `UnhandledExceptionFilter`, which falls back to **500** for anything that isn't an `HttpException`. So a forbidden user (e.g. an API key whose role doesn't have `DATA_MODEL`) calling `GET /rest/metadata/objects` got: ``` HTTP/1.1 500 Internal Server Error "Entity performing the request does not have permission" ``` GraphQL already had the right plumbing via `permissionGraphqlApiExceptionHandler` (`ForbiddenError` → 403, `UserInputError` → 400, `NotFoundError` → 404). This PR mirrors it on the REST side. ## What - New util `permissionRestApiExceptionCodeToHttpStatus` mapping every `PermissionsExceptionCode` → HTTP status, with `assertUnreachable` to force explicit handling of future codes. - New filter `PermissionsRestApiExceptionFilter` (`@Catch(PermissionsException)`) that delegates to `HttpExceptionHandlerService.handleError(...)` with the resolved status. - Wired `PermissionsRestApiExceptionFilter` (placed first, so the typed filter wins over any sibling catch-all) into `@UseFilters(...)` of every REST controller that uses `SettingsPermissionGuard` or whose service can throw `PermissionsException`: - `object-metadata`, `field-metadata`, `webhook`, `api-key` - `view`, `view-sort`, `view-group`, `view-filter`, `view-filter-group`, `view-field` - `page-layout`, `page-layout-widget`, `page-layout-tab` - `front-component`, `ai-generate-text` - Unit tests covering 403 / 400 / 404 / 500 mappings. ## Mapping | Code | Status | |------|--------| | `PERMISSION_DENIED`, `NO_AUTHENTICATION_CONTEXT`, `ROLE_LABEL_ALREADY_EXISTS`, `CANNOT_UNASSIGN_LAST_ADMIN`, `CANNOT_UPDATE_SELF_ROLE`, `CANNOT_DELETE_LAST_ADMIN_USER`, `ROLE_NOT_EDITABLE`, `CANNOT_ADD_OBJECT_PERMISSION_ON_SYSTEM_OBJECT`, `CANNOT_ADD_FIELD_PERMISSION_ON_SYSTEM_OBJECT` | **403** | | `INVALID_ARG`, `INVALID_SETTING`, `CANNOT_GIVE_WRITING_PERMISSION_ON_NON_READABLE_OBJECT`, `CANNOT_GIVE_WRITING_PERMISSION_WITHOUT_READING_PERMISSION`, `ONLY_FIELD_RESTRICTION_ALLOWED`, `FIELD_RESTRICTION_ONLY_ALLOWED_ON_READABLE_OBJECT`, `FIELD_RESTRICTION_ON_UPDATE_ONLY_ALLOWED_ON_UPDATABLE_OBJECT`, `EMPTY_FIELD_PERMISSION_NOT_ALLOWED`, `ROLE_MUST_HAVE_AT_LEAST_ONE_TARGET`, `ROLE_CANNOT_BE_ASSIGNED_TO_USERS` | **400** | | `ROLE_NOT_FOUND`, `OBJECT_METADATA_NOT_FOUND`, `FIELD_METADATA_NOT_FOUND`, `FIELD_PERMISSION_NOT_FOUND`, `PERMISSION_NOT_FOUND` | **404** | | All remaining "internal" codes (rethrown as-is in GraphQL) | **500** | ## Before <img width="507" height="216" alt="Screenshot 2026-05-19 at 19 26 07" src="https://github.com/user-attachments/assets/21d633aa-7ee8-4923-94e4-7ad57258a29e" /> ## After <img width="610" height="385" alt="Screenshot 2026-05-19 at 19 26 01" src="https://github.com/user-attachments/assets/0103b7ee-7df7-4aef-999a-73c22901afd2" /> |
||
|
|
a2acf88a57 |
feat(website): per-PR preview deploys via Worker versions (#20762)
## Summary Adds review apps for the marketing site. Every PR that touches `packages/twenty-website/**` or `packages/twenty-shared/**` gets a per-version Worker preview URL, sticky-commented on the PR, auto-cleaned up when the PR closes. Same Cloudflare machinery skew protection rides on, just used for previews — no extra plan, no extra services. Cleaner than the GitHub-Actions-runner + Cloudflare-tunnel pattern: previews persist for the life of the version, accessible from anywhere, no warm-up. ## Files - **`.github/workflows/website-pr-preview.yaml`** — on PR open/sync/reopen: builds the Worker with a per-PR `DEPLOYMENT_ID`, runs `wrangler versions upload --tag pr-<N>` (no production traffic), sticky-comments the preview URL. Skipped on fork PRs because GitHub doesn't pass secrets to forks anyway. - **`.github/workflows/website-pr-preview-cleanup.yaml`** — on PR close: walks the Worker version list via the CF API, deletes anything tagged `pr-<N>` (with message-based fallback if the annotation key changes), updates the sticky comment. - **`open-next.config.ts`** — `maxNumberOfVersions: 10 → 50` to leave room for PR previews on top of skew protection's prod-version retention. ## How it looks on a PR The bot leaves a sticky comment like: > 🔍 **Website preview** is up at **https://abc12345-twenty-website-dev.twentyhq.workers.dev** > > | | | > |---|---| > | Version | `abc12345-...` | > | Commit | `<sha>` | > | Bindings | shared with the `dev` Worker (R2 cache + secrets) | > > Updates on every push. Auto-deleted when the PR closes. On close it becomes: > 🧹 Website preview for this PR was cleaned up after close. ## Twenty repo credentials already provisioned - `secret CLOUDFLARE_API_TOKEN` — same scoped token the `twenty-infra` workflow uses - `var CLOUDFLARE_ACCOUNT_ID` = `67b2bbe4381006564d2b0aa6ce6177be` - `var CF_PREVIEW_DOMAIN` = `twentyhq` (no `.workers.dev` suffix — OpenNext appends it; [opennextjs-cloudflare#811](https://github.com/opennextjs/opennextjs-cloudflare/issues/811)) ## Known limitations - **Shared dev bindings**: PR previews use the dev Worker's R2 bucket + secrets (Stripe test key, JWT private key). Fine for a read-mostly marketing site; if two simultaneous PRs ever fight over ISR cache state we can prefix R2 keys per-PR later. - **Fork PRs don't get previews**. GitHub Actions doesn't pass `secrets.*` to fork-PR runs (security), and the wrangler upload requires the CF token. To enable forks, would need to switch to `pull_request_target` and gate on a maintainer label — not done here because the security tradeoff isn't worth it for a marketing-site preview. - **Version cap**: 50 versions is the new ceiling, and `maxVersionAgeDays: 14` auto-prunes anything older. Cleanup-on-close should keep us well under in steady state. ## Test plan - [ ] CI on this PR triggers the preview workflow itself; check that the sticky comment appears with a working URL - [ ] Hit the URL, click around — should look like a fresh marketing-site build with this PR's changes - [ ] Close (don't merge) → cleanup workflow should run; sticky comment switches to the "cleaned up" message; the version is gone from `wrangler versions list --name twenty-website-dev` |
||
|
|
c002bc52bd |
fix(ci): repair preview-environment dispatch (use PAT, not GITHUB_TOKEN) (#20773)
## What One-line token swap on the same-repo dispatch step in [`preview-env-dispatch.yaml`](.github/workflows/preview-env-dispatch.yaml#L40): `secrets.GITHUB_TOKEN` → `secrets.CI_PRIVILEGED_DISPATCH_TOKEN`. ## Why Regression from [#20476](https://github.com/twentyhq/twenty/pull/20476) ("security: harden CI against supply-chain attacks"), merged 2026-05-12. That PR replaced ```yaml uses: peter-evans/repository-dispatch@v2 with: token: ${{ secrets.GITHUB_TOKEN }} ... ``` with a raw `gh api` call but kept `GITHUB_TOKEN`: ```yaml env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | gh api repos/"$REPOSITORY"/dispatches -f event_type=preview-environment ... ``` The auto-provisioned `GITHUB_TOKEN` can't fire `repository_dispatch` via `gh api` even when the workflow declares `permissions: contents: write`. The action used a different code path that worked; the CLI requires a token with `repo` scope. So every dispatch from this workflow has returned `403 Resource not accessible by integration` since that PR merged — except for runs the `author_association` / `preview-app` label gate skips entirely (which then show "success" because no jobs ran). Recent failed example: https://github.com/twentyhq/twenty/actions/runs/26162974597/job/76959379235?pr=20769 ## The fix `secrets.CI_PRIVILEGED_DISPATCH_TOKEN` already exists in repo secrets and is **already used** by the immediately-following cross-repo dispatch step in the same file. Using it for the same-repo dispatch too matches the surrounding code and is consistent with the original hardening intent (use a scoped PAT, not the auto-provisioned token). ## Test plan - [ ] Merge this PR - [ ] Next PR open / sync / reopen on a member's branch → check that `Preview Environment Dispatch` succeeds (no 403) - [ ] Confirm `Preview Environment Keep Alive` workflow gets triggered (the downstream effect of the dispatch) - [ ] Confirm the tunnel URL sticky comment lands on the PR Discovered while testing an unrelated PR ([#20762](https://github.com/twentyhq/twenty/pull/20762)). Independent fix. |
||
|
|
127fb2a470 |
Increase size of tarball upload (#20767)
- check size while reading stream instead of checking after reading all stream - move MAX_TARBALL_UPLOAD_SIZE_BYTES to config variables - increase MAX_TARBALL_UPLOAD_SIZE_BYTES default from 50Mb to 100Mb |
||
|
|
3d49c17e34 |
[CONNECTED_ACCOUNT_BREAKING_CHANGE] Unify connected account permissions (#20732)
# Introduction This PR is a followup of https://github.com/twentyhq/twenty/pull/20673 It aims to unify the authentication/permissions layer with all the connectedAccount interactions across the application ## Deprecate - findAll - findById ## Email sync An user can only sync the message of his own connected account ## Workflow email - Related https://github.com/twentyhq/private-issues/issues/478 - Only reauthorize owned account |
||
|
|
b454ad2aea |
fix(workflow): restore initial input fields on code step creation (#20756)
## Summary - Fixes a regression from #20208 where creating a new CODE workflow step shows no input fields - The split-triggers PR removed `SEED_LOGIC_FUNCTION_INPUT_SCHEMA` and replaced `toolInputSchema` with `workflowActionTriggerSettings`, but `CodeStepBuildService.createCodeStepLogicFunction` was not updated to pass the seed schema — causing `logicFunctionInput` to default to `{}` and no fields to render - Adds `SEED_WORKFLOW_ACTION_TRIGGER_SETTINGS` constant (matching the seed template's `{ a: string, b: number }` params) and passes it when creating the seed logic function ## Test plan - [x] Unit test updated to assert `logicFunctionInput` contains `{ a: null, b: null }` on code step creation - [x] Create a new CODE step in the workflow builder and verify input fields `a` and `b` appear immediately Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
fb47e4497a |
i18n - docs translations (#20764)
Created by Github action Co-authored-by: github-actions <github-actions@twenty.com> |
||
|
|
00fad657f4 |
feat(website): enable OpenNext skew protection + tune CF cache (#20760)
## Summary
The original goal of this whole migration: **cross-deployment skew is
now handled by OpenNext's per-version routing instead of by users having
to refresh.**
A client holding a stale tab from deployment X requests assets with
`?dpl=X` — the Worker compares X to the current `DEPLOYMENT_ID`, looks
it up in `CF_DEPLOYMENT_MAPPING`, and routes to the matching old Worker
version via its per-version preview URL
(`<old-version>-twenty-website-<env>.twentyhq.workers.dev`). The old
version serves the old assets / RSC payloads / Server Actions
consistently.
**Verified end-to-end on dev**:
| | Marker in HTML |
|---|---|
| Current Worker (`twenty-main.com/`) | `9npeiytir8EPOtW71cqDZ` |
| Stale request (`twenty-main.com/?dpl=<previous-deploy-id>`) |
`B9OC_TNl1vaGcJ5oUUty6` |
| Direct hit on old preview URL | `B9OC_TNl1vaGcJ5oUUty6` ← matches the
skew-routed response |
## Changes
**`open-next.config.ts`** — enable skew protection
```ts
const baseConfig = defineCloudflareConfig({ incrementalCache: r2IncrementalCache });
export default {
...baseConfig,
cloudflare: {
...baseConfig.cloudflare,
skewProtection: {
enabled: true,
maxNumberOfVersions: 10,
maxVersionAgeDays: 14,
},
},
};
```
(`defineCloudflareConfig` doesn't accept `skewProtection` directly — has
to be merged in)
**`next.config.ts`** — `deploymentId: process.env.DEPLOYMENT_ID`. CI
sets `DEPLOYMENT_ID` per-build; Next bakes it into prerendered HTML,
`?dpl=…` on asset URLs, Server Actions, and RSC fetch headers.
**`wrangler.jsonc`**:
- `compatibility_date: 2026-04-15` (was `2025-01-15`; build was warning)
- `assets.run_worker_first: true` — Worker must intercept asset requests
so the skew handler can route stale `/_next/static/*` to the old
version. CF edge cache absorbs hot paths so this isn't a 5×
billable-invocation tax
- `preview_urls: true` — required; skew routes via the per-version
preview URL which only exists when previews are enabled
- Per-env `services: [{ binding: WORKER_SELF_REFERENCE, service:
twenty-website-<env> }]` — OpenNext's recommended setup for
fire-and-forget ISR revalidation
- Per-env `vars`: `CF_WORKER_NAME` + `CF_PREVIEW_DOMAIN` (bare
`twentyhq`, *not* `twentyhq.workers.dev` — OpenNext appends
`.workers.dev` itself, see
[opennextjs-cloudflare#811](https://github.com/opennextjs/opennextjs-cloudflare/issues/811))
- Kept `global_fetch_strictly_public` in compat flags — without it, CF's
optimised intra-account routing self-loops the cross-version fetch and
522s out. With it, the fetch takes the public-Internet path which routes
correctly.
**`public/_headers`** — deleted (with `run_worker_first: true` the
assets pipeline doesn't process it; Next sets the same `Cache-Control:
immutable` on `/_next/static/*` anyway).
## Companion infra PR
https://github.com/twentyhq/twenty-infra/pull/__ — wires the four CF env
vars (`DEPLOYMENT_ID`, `CF_WORKER_NAME`, `CF_PREVIEW_DOMAIN`,
`CF_ACCOUNT_ID`, `CF_WORKERS_SCRIPTS_API_TOKEN`) into the deploy
workflow.
## Known limitation
Skew routing only works for Worker versions deployed AFTER this PR
(older versions don't have `preview_urls: true` and don't have
`DEPLOYMENT_ID` bindings OpenNext can read). Users on tabs older than
the first post-merge deploy still fall through to the current Worker
(same behaviour as today).
OpenNext marks `skewProtection` as **experimental** in their type docs
("might break on minor releases") — worth keeping an eye on.
|
||
|
|
c800eccc65 |
Slack workflow connector (#20427)
https://github.com/user-attachments/assets/5a746414-988b-473c-9401-b8863a3e1c15 https://github.com/user-attachments/assets/0cdebdb1-f7c8-43cb-beef-f279387b6ce9 https://github.com/user-attachments/assets/df31c631-0781-42d8-8e6e-e5a16573ee3b https://github.com/user-attachments/assets/6adaeae4-f3c9-4a5f-b0df-50c1f9a78428 --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: martmull <martmull@hotmail.fr> |
||
|
|
a26fe3bb65 |
docs(sdk): document DatabaseEventPayload and simplify its type (#20754)
closes https://discord.com/channels/1130383047699738754/1505967920163983502 Update logic-function docs to match the real `DatabaseEventPayload` shape. The docs now show database event payloads as record-level events with `recordId` and `properties.before/after/diff/updatedFields`, including compact examples for created, updated, and destroyed events. Route payload type imports now use the preferred `twenty-sdk/logic-function` surface. Also clean up the shared payload type wrapper so it models event metadata without over-promising actor fields; `userId`, `userWorkspaceId`, and `workspaceMemberId` remain optional through the underlying event type. |
||
|
|
8d81496625 |
fix(ai-chat) - fixes on cost display (#20750)
- total cost conversion - update metrics at message end |
||
|
|
f1b7c21b6c |
Update create twenty app scaffolded front component (#20733)
- Replace inline SVG icons with proper Avatar and icon components (IconBox, IconHierarchy, IconLayout, IconSettingsAutomation) from twenty-sdk/ui in the scaffolded front component template - Strip trailing slashes from workspace/API URLs in both create-twenty-app CLI and twenty-sdk remote commands to prevent malformed requests - Fix the application settings link to navigate to #installed anchor - Bump twenty-sdk, twenty-client-sdk, and create-twenty-app versions to 2.6.0 <img width="1512" height="824" alt="image" src="https://github.com/user-attachments/assets/8561d7bb-3458-46c4-b01e-664321634b4c" /> |
||
|
|
f630ce34fe |
feat(website): mirror prod hostname pattern on dev (apex + www) (#20753)
## Summary Drops the `website.` subdomain on dev entirely and serves the marketing site from the bare zone + `www`, mirroring how prod is served at `twenty.com` + `www.twenty.com`. Also fixes a latent root-path substitution bug in the existing www→apex redirect that was masked on prod by a CF-level redirect. ## What changes - `wrangler.jsonc` env.dev routes: `twenty-main.com` (apex) + `www.twenty-main.com` (was `website.twenty-main.com`) - `next.config.ts`: extends host-based www→apex redirect to also cover `www.twenty-main.com`, and adds explicit `source: '/'` rules for both prod + dev before the catch-all `source: '/:path*'` (the `:path*` parameter doesn't substitute properly when it matches the empty root path against an absolute destination URL — Next.js leaves the literal `:path*` in the `Location` header) ## Live verification (after redeploy) | URL | Status | Notes | |---|---|---| | `https://twenty-main.com/` | 200 | `x-opennext: 1`, `x-nextjs-cache: HIT` | | `https://twenty-main.com/pricing` | 200 | Worker SSR | | `https://www.twenty-main.com/` | 308 → `https://twenty-main.com/` | Root-redirect fix applied | | `https://www.twenty-main.com/pricing` | 308 → `https://twenty-main.com/pricing` | Path preserved | | `https://twenty.com/` | 200 | Unchanged | | `https://www.twenty.com/` | 301 → `https://twenty.com/` | Still routed via CF-level redirect, now also covered by the new explicit Next rule as a defense-in-depth | | `https://website.twenty-main.com/` | 503 | DNS record removed by wrangler when route was deleted; hostname effectively retired | ## Companion infra PR https://github.com/twentyhq/twenty-infra/pull/__ — `cloudflare/website/dev.env` + `docs/4-environments.md` updated to the new URL; also bundles the CI fix that should have landed in #683 (was pushed too late). |
||
|
|
7ebcbe8801 |
Unify oAuth success and failure screen with autorize page (#20746)
Goal, matching authorize page design <img width="2062" height="1376" alt="image" src="https://github.com/user-attachments/assets/93d0f77a-c769-4a32-b41b-16459378314f" /> ## Before <img width="1540" height="942" alt="image" src="https://github.com/user-attachments/assets/4de64f37-8519-4fdc-9388-70d98a69663e" /> ## After <img width="962" height="657" alt="image" src="https://github.com/user-attachments/assets/c4fd19aa-13e3-452e-b6b7-c10202cb1edf" /> <img width="705" height="437" alt="image" src="https://github.com/user-attachments/assets/e1f743f1-a862-4629-a3d0-c8e62e429e04" /> |
||
|
|
b821061526 |
fix(create-twenty-app): preserve .yarnrc.yml in template (#20623)
**Source:** https://sonarly.com/issue/37981?type=bug ## Summary New apps created with `create-twenty-app@2.5.0` can fail at `yarn twenty dev` with `Could not resolve "twenty-sdk/define"`, blocking onboarding for app developers. ## Root cause Proximate cause: manifest module loading in the SDK fails to resolve `twenty-sdk/define` when the generated app uses Yarn PnP (no `node_modules` tree), and esbuild is invoked with normal Node-style resolution. - The failing path is `extractManifestFromFile()` → `loadModule()` in `packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-extract-config-from-file.ts`, which calls `esbuild.build({ bundle: true, ... })` and does not stub/mock `twenty-sdk/define` [ref: read `manifest-extract-config-from-file.ts`]. - The scaffolded template imports `twenty-sdk/define` in `src/application-config.ts` and `src/default-role.ts` [ref: grep in `packages/create-twenty-app/src/constants/template/src/*`]. - If esbuild cannot resolve that import from the app environment, the exact error matches the issue: `src/application-config.ts:1:34: ERROR: Could not resolve "twenty-sdk/define"`. Triggering cause (why now): `create-twenty-app@2.5.0` (the current npm `latest`) ships a template tarball without `.yarnrc.yml`, so new projects silently default to Yarn PnP instead of `node-modules`. Evidence: - Source template contains `.yarnrc.yml` with `nodeLinker: node-modules` [ref: read `packages/create-twenty-app/src/constants/template/.yarnrc.yml`]. - Published npm tarball for `create-twenty-app-2.5.0.tgz` does **not** contain `template/.yarnrc.yml` (but does contain renamed `gitignore`/`github`) [ref: tarball listing command output: `hasYarnrc: false`]. - Dotfile-preservation logic in `copyBaseApplicationProject()` only renames `gitignore` and `github`; it does not preserve `.yarnrc.yml` [ref: read `packages/create-twenty-app/src/utils/app-template.ts`]. - `npm dist-tags` shows `latest: 2.5.0`, so users following docs with `@latest` receive this broken scaffold path now [ref: npm registry query]. Why this is attributable to a specific change: - Commit `15eb3e7edccdf4e9770a00a07bfbd026420f7c3b` introduced dotfile-preservation mechanics for template publish (`gitignore`/`github`) but left out `.yarnrc.yml`, creating the regression window for newly scaffolded apps [ref: `git show --stat 15eb3e7...`, `git blame` on `renameDotfiles()`]. ## Fix Implemented a targeted fix in `create-twenty-app` so `.yarnrc.yml` is preserved through npm packaging the same way `.gitignore` and `.github` are handled. What changed: 1) Template dotfile preservation - Removed `packages/create-twenty-app/src/constants/template/.yarnrc.yml` - Added `packages/create-twenty-app/src/constants/template/yarnrc.yml` with identical content: - `nodeLinker: node-modules` This avoids npm stripping the file from the published tarball. 2) Scaffold rename logic - Updated `packages/create-twenty-app/src/utils/app-template.ts`: - Added `{ from: 'yarnrc.yml', to: '.yarnrc.yml' }` in `renameDotfiles()` - Updated progress text and inline comment to include `.yarnrc.yml` So generated apps reliably restore `.yarnrc.yml` after template copy. 3) Regression test - Updated `packages/create-twenty-app/src/utils/__tests__/app-template.spec.ts`: - Added a test asserting `yarnrc.yml` is renamed to `.yarnrc.yml` - Added a small constant for the test path This locks the behavior and prevents reintroducing the publish omission regression. Validation notes: - Attempted to run the focused Jest test, but execution failed due missing workspace dependency state (`@nx/jest/preset` / node_modules state not installed in this environment). ## Original request fix(create-twenty-app): preserve .yarnrc.yml in template _Created by Sonarly by autonomous analysis (run 43375)._ --------- Co-authored-by: sonarly-bot <sonarly@sonarly.com> Co-authored-by: martmull <martmull@hotmail.fr> |
||
|
|
f3aadbbb66 |
chore(server): drop leftover favorite and favoriteFolder workspace objects (#20744)
## Summary - Adds a 2.7.0 workspace upgrade command `upgrade:2-7:drop-favorite-objects` that removes the legacy `favorite` and `favoriteFolder` object metadata (and their workspace tables) from every active or suspended workspace. - The records were migrated to `navigationMenuItem` in the 1.17/1.18 upgrades and the entity code was deleted in #19536, but the per-workspace metadata rows were never cleaned up — so they still surface in the "Existing objects" settings list and expose stale CRUD tools to the AI/MCP layer (e.g. the model can hallucinate `create_favorite_folder` against a real-looking schema). ## Implementation notes - Modeled on [`upgrade:2-3:drop-message-direction-field`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/database/commands/upgrade-version-command/2-3/2-3-workspace-command-1777400000000-drop-message-direction-field.command.ts), but at object granularity. - Uses `ObjectMetadataService.deleteOneObject({ isSystemBuild: true })` so all cascading is handled by the existing pipeline: field metadata, indexes, relation fields on other workspace entities, command menu items, and the workspace data tables. Views and orphaned `navigationMenuItem` rows pointing at favorite views are removed by the existing `onDelete: 'CASCADE'` FKs. - Deletion order: `favorite` first (holds a relation to `favoriteFolder`), then `favoriteFolder`. - Both objects are flagged `isSystem: true`, hence `isSystemBuild: true` on the call. - Idempotent: workspaces where the object is already absent are logged and skipped. - Honors `--dry-run`. - Universal identifiers are hard-coded because the matching `STANDARD_OBJECTS` entries were deleted in #19536. ## Test plan - [ ] Run on a workspace that still has `favorite` / `favoriteFolder` in `core.objectMetadata` (verify in prod-like DB beforehand) and confirm both objects, their fields, indexes, relation fields on linked objects, views, and the workspace data tables are gone after running. - [ ] Re-run on the same workspace — confirm it logs "already absent" and exits clean (idempotency). - [ ] Run on a workspace where the objects don't exist (e.g. fresh local) — confirm clean no-op. - [ ] Run with \`--dry-run\` first — confirm log output and no DB mutations. - [ ] Confirm the "Existing objects" settings page no longer lists Favorites / Favorite Folders after the migration. ## Safety check before rollout Before running in prod, verify no workspace has live (non-soft-deleted) favorite data that didn't make it to \`navigationMenuItem\`: \`\`\`sql -- Per workspace SELECT count(*) FROM workspace_xxx.favorite WHERE "deletedAt" IS NULL; \`\`\` Should be ~0 in workspaces that ran the 1.17 / 1.18 migrations. --------- Co-authored-by: prastoin <paul@twenty.com> |
||
|
|
e494bc7006 |
chore: sync AI model catalog from models.dev (#20751)
Automated daily sync of `ai-providers.json` from [models.dev](https://models.dev). This PR updates pricing, context windows, and model availability based on the latest data. New models meeting inclusion criteria (tool calling, pricing data, context limits) are added automatically. Deprecated models are detected based on cost-efficiency within the same model family. **Please review before merging** — verify no critical models were incorrectly deprecated. Co-authored-by: FelixMalfait <6399865+FelixMalfait@users.noreply.github.com> |
||
|
|
91e0e07af4 |
fix: render PAGE_LAYOUT nav items with standard icon tile and compute… (#20743)
## Before <img width="434" height="583" alt="image" src="https://github.com/user-attachments/assets/a336620f-3f85-4d20-ba58-b20d779ba3b9" /> ## after <img width="539" height="600" alt="image" src="https://github.com/user-attachments/assets/f88e4793-e1a1-4215-baf1-289c413d9dac" /> |
||
|
|
7ab6f5719f |
Update default widget gridPosition (#20740)
move DEFAULT_WIDGET_SIZE to twenty-shared and use it in sync application manifest |
||
|
|
d17393e91d |
feat(website): migrate dev hostname website-new.twenty-main.com → website.twenty-main.com (#20747)
## Summary Last "-new" trace in the source repo, follow-up to the rename in #20745. The dev Worker custom domain swaps from `website-new.twenty-main.com` to `website.twenty-main.com`, matching the prod pattern (no "-new" anywhere). ## Live operations already performed - Deleted the legacy CNAME at `website.twenty-main.com` that pointed at the dev EKS NLB (record id `52b4a4174dfd382ecf38111b7f08e642`, was the Docusaurus dev deploy that had been 503'ing) - Redeployed `twenty-website-dev` Worker — Wrangler provisioned the new custom domain via the CF API - Verified `https://website.twenty-main.com/` returns 200 with `x-opennext: 1` and `x-nextjs-cache: HIT` The old hostname `website-new.twenty-main.com` is now unbound; Wrangler removed its DNS record when the route disappeared from this file. Visitors get 522, which is the desired state for a retired hostname. ## Companion infra PR https://github.com/twentyhq/twenty-infra/pull/683 — removes `charts/dev/apps/website` Helm chart (the legacy Docusaurus deploy) + ArgoCD app, updates `cloudflare/website/dev.env` and `docs/4-environments.md`. ## Out of scope - Legacy `website.twenty-staging.com` and `website.twenty.com` are still alive serving Docusaurus content. Decommissioning those is a separate decision (those URLs may still be linked externally). |
||
|
|
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 |
||
|
|
24a836cc7d |
feat(website-new): add Cloudflare Workers deployment via OpenNext (#20741)
## Summary - Adds `@opennextjs/cloudflare` adapter so `packages/twenty-website-new` can deploy to Cloudflare Workers - Two environments (`dev` / `prod`) wired via `wrangler.jsonc` env blocks - Existing Docker / EKS build path is untouched in this PR — the cutover happens in the paired infra PR Pairs with: https://github.com/twentyhq/twenty-infra/pull/__ (to be opened, will swap CI + decommission Helm/ArgoCD) ## Files added - `packages/twenty-website-new/wrangler.jsonc` — Worker config, `nodejs_compat` flag, R2 incremental cache, Cloudflare `IMAGES` binding, env-specific routes (`website-new.twenty-main.com` for dev; `twenty.com` + `www.twenty.com` for prod) - `packages/twenty-website-new/open-next.config.ts` — minimal config using `r2IncrementalCache` - `packages/twenty-website-new/.dev.vars.example` — local secrets template (`STRIPE_SECRET_KEY`, `ENTERPRISE_JWT_PRIVATE_KEY`) - `packages/twenty-website-new/public/_headers` — immutable cache headers for `/_next/static/*` ## Files modified - `packages/twenty-website-new/package.json` — adds `@opennextjs/cloudflare`, `wrangler` to devDeps; adds `preview`, `deploy:dev`, `deploy:prod`, `cf-typegen` scripts - `packages/twenty-website-new/next.config.ts` — calls `initOpenNextCloudflareForDev()` (no-op outside `next dev`); preserves Linaria CommonJS export - `packages/twenty-website-new/.gitignore` — ignores `.open-next/`, `.wrangler/`, `.dev.vars`, generated `cloudflare-env.d.ts` ## Compatibility notes - `enterprise-jwt.ts` uses Node `crypto` + `Buffer` — works on Workers with the `nodejs_compat` flag (compat date 2025-01-15, well past the 2024-09-23 minimum) - `sharp` stays as a build-time dep (Next/Image asset processing); runtime image optimization routes through the Cloudflare `IMAGES` binding - Linaria runs at build time, unaffected - Stripe SDK is HTTP-based, fine on Workers ## One-time CF setup required before this PR is useful The infra PR adds GitHub Actions wiring, but the Cloudflare account itself needs: - R2 buckets: `twenty-website-cache-dev`, `twenty-website-cache-prod` - Worker secrets per env (via `wrangler secret put --env <dev|prod>`): `STRIPE_SECRET_KEY`, `ENTERPRISE_JWT_PRIVATE_KEY` - An API token with `Workers Scripts:Edit`, `Workers R2 Storage:Edit`, `Zone DNS:Edit` on the `twenty.com` zone — stored as `CLOUDFLARE_API_TOKEN` + `CLOUDFLARE_ACCOUNT_ID` in the infra repo's GitHub secrets - The Cloudflare Images subscription enabled on the account (binding is configured; \$5/mo + per-transformation pricing) ## Follow-up (out of scope) - Rename `packages/twenty-website-new` → `packages/twenty-website` and delete the legacy `packages/twenty-website` (mechanical, separate PR to keep this diff reviewable) - Remove `packages/twenty-docker/twenty-website-new/` once the EKS deploy is fully retired ## Test plan - [ ] `yarn install` resolves new devDeps cleanly - [ ] `cd packages/twenty-website-new && npx next build` still succeeds (Linaria path untouched) - [ ] `yarn preview` builds the Worker locally and serves on http://localhost:8788 - [ ] Smoke: `/`, `/pricing`, an enterprise-key-signing flow (needs `.dev.vars` populated) - [ ] After CF resources are provisioned: `yarn deploy:dev` succeeds and `website-new.twenty-main.com` serves the new Worker |
||
|
|
1a9f786e42 |
refactor(filters): pass fieldMetadataItems array to dispatcher (#20737)
## Summary Alternative to #20717. Same goal (clean up the filter dispatcher API after #20670) but smaller and follows the codebase's "pass data, not behavior" style. The dispatcher takes a `fieldMetadataItems: FieldShared[]` array directly instead of a `findFieldMetadataItemById: (id) => FieldShared | undefined` callback. The util builds the id lookup internally — once per call, used for both source-field and relation-target-field lookups. No new types, no separate hydration step. ## What changes **`twenty-shared`** - `computeRecordGqlOperationFilter` / `turnRecordFilterIntoRecordGqlOperationFilter` / `turnRecordFilterGroupsIntoGqlOperationFilter`: replace `findFieldMetadataItemById` param with `fieldMetadataItems` / `fieldMetadataItemById` (internal Map). - Remove the exported `FindFieldMetadataItemById` type. - `turnAnyFieldFilterIntoRecordGqlFilter`: rename its internal `fieldById` Map for consistency. - Tests updated to pass arrays. **Frontend (15 call sites)** - Switch from `fieldMetadataItemByIdMapSelector` to `flattenedFieldMetadataItemsSelector`. - Pass `fieldMetadataItems: flattenedFieldMetadataItems` to the dispatcher. - `useFindManyRecordsSelectedInContextStore` keeps the Map selector because it still does a per-filter lookup for the soft-delete check. **Server (5 call sites)** - Pass `Object.values(flatFieldMetadataMaps.byUniversalIdentifier).filter(isDefined)`. ## Why this over #20717 #20717 moves resolution into a separate hydration step + introduces a `HydratedRecordFilter` type. The bug that #20717 originally surfaced was Sentry catching 4 critical runtime errors during review (`fieldMetadataItemByIdMap` declared but not passed). The added type and the explicit hydration boundary are extra surface area for not much benefit — the existing API was a callback wrapping a Map at every call site, and the natural simplification is to just pass the Map (or its array) directly. Net diff: **196 insertions, 203 deletions** (~7 lines net removed). 32 files. ## Test plan - [x] Shared filter unit tests pass (461 tests) - [x] Frontend filter/context-store tests pass (13 tests) - [x] Frontend typecheck passes - [x] Server typecheck passes - [x] Lint passes (frontend + server) - [ ] Integration tests on #20670 still pass — workflow find-records + chart-data with relation-traversal filter still work end-to-end through the new array param |
||
|
|
265d2edc83 |
Fix QueryRunnerAlreadyReleasedError in sign-in-up service (#20734)
## Context
When signing up on a new workspace,
`SignInUpService.signUpOnNewWorkspace`
manually drove a transaction with `createQueryRunner` /
`startTransaction` /
`commitTransaction` / `rollbackTransaction` / `release`.
If the underlying Postgres connection dropped mid-transaction
(`idle_in_transaction_session_timeout`, server-side termination), the
`pg`
client's `'error'` event fires. TypeORM's connect-time listener responds
by
calling `release()` on the `QueryRunner`, which sets `isReleased = true`
but
deliberately does **not** touch `isTransactionActive`.
The `catch` branch then hit:
```ts
if (queryRunner.isTransactionActive) {
await queryRunner.rollbackTransaction(); // throws QueryRunnerAlreadyReleasedError
}
throw error;
```
Error from Sentry
```typescript
QueryRunnerAlreadyReleasedError: Query runner already released. Cannot run queries anymore.
at PostgresQueryRunner.query (.../PostgresQueryRunner.js:177)
at PostgresQueryRunner.rollbackTransaction (.../PostgresQueryRunner.js:167)
at SignInUpService.signUpOnNewWorkspace (.../sign-in-up.service.js:370)
```
## Changes
Replaced the hand-rolled transaction with
this.dataSource.transaction(...).
TypeORM's built-in wrapper already does what we need:
- starts/commits/rolls back the transaction
- wraps rollback in try { ... } catch { /* ignore */ }, so a connection
drop no longer masks the real error
- releases the QueryRunner unconditionally
## Note
Other fix would have been to do this
```typescript
if (queryRunner.isTransactionActive && **!queryRunner.isReleased**) {
try {
await queryRunner.rollbackTransaction();
} catch {
```
|
||
|
|
d345a6b2d6 |
Twenty fireflies integration (#20618)
Co-authored-by: martmull <martmull@hotmail.fr> |
||
|
|
f8605763dd |
i18n - docs translations (#20736)
Created by Github action Co-authored-by: github-actions <github-actions@twenty.com> |
||
|
|
ac432d3195 |
Add @WasRemovedInUpgrade decorator (#20729)
## Summary
Adds the symmetric counterpart to `@WasIntroducedInUpgrade` for the
upgrade-aware ORM. Today the framework can describe "this column will
exist once upgrade X applies" but not "this
column will stop existing once upgrade X applies". Plain field deletion
only works when nothing writes to the table during the mid-state window
between the binary booting and the drop
migration completing for a given workspace — fine for sparse tables
(`DropWorkspaceVersionColumn`, `DropPostgresCredentialsTable`), risky
for hot-write tables.
This PR ships the primitive on its own so the upcoming
`rolePermissionFlag.flag` drop has the framework support it needs. No
in-tree consumer yet — coverage is via unit tests against
synthetic entities.
### What's in it
- **New `@WasRemovedInUpgrade({ upgradeCommandName })` decorator**
(class- or property-scope) — mirrors `@WasIntroducedInUpgrade`, uses the
shared
`defineUpgradeMetadataOnClassOrProperty` helper, exposes class +
property getters.
- **`resolveEntityShapeAtUpgradeCursor`** now folds applied-removals
into the existing `hiddenPropertyNames` set. Intro-pending and
removal-applied share one hide bucket — both ask
TypeORM for the same thing.
- **`UpgradeAwareEntityMetadataAdapter`** now disables `isSelect`,
`isInsert`, **and** `isUpdate` for any hidden column, restoring
canonical values when the column comes back.
Previously only `isSelect` was flipped, which left an
INSERT-into-nonexistent-column hole the intro path was tacitly relying
on application code to avoid; this PR closes that hole for
both directions.
- **`validateUpgradeAwareEntityDecorators`** validates
`@WasRemovedInUpgrade` `upgradeCommandName` references, and surfaces a
new `removal-before-introduction` problem when a property
has both decorators with the removal step preceding the introduction
step.
|
||
|
|
e463a09e17 |
chore(server): remove unused CommandLogger from command module (#20638)
## Summary
This PR removes the unused `CommandLogger` implementation located at:
```
/commands/command-logger.ts
```
The Command application context is bootstrapped using `LoggerService`
from:
```ts
import { LoggerService } from 'src/engine/core-modules/logger/logger.service';
...
const loggerService = app.get(LoggerService);
...
// Inject our logger
app.useLogger(loggerService);
...
```
So `CommandLogger` is not imported, injected, or referenced anywhere in
the Command execution flow and is safe to remove.
## Note
There is another `CommandLogger` class at:
```
/database/commands/logger.ts
```
This one is only used within `database-command` module and is unrelated
to the Command module logger being removed in this PR.
Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
|
||
|
|
83b10ad698 |
fix(server): sync command menu item availability expressions on existing workspaces (#20719)
Two fixes via one workspace command: 1. Gates 5 standard command menu items behind `pageType == "INDEX_PAGE"` -- `importRecords`, `exportView`, `seeDeletedRecords`, `createNewView`, `hideDeletedRecords`. They currently appear (and crash or do nothing) on RECORD_PAGE. 2. Fixes Edit Layout missing from older workspaces -- root cause is `conditionalAvailabilityExpression` drift between source-of-truth constants and the workspace DB (e.g. #20556 removed a feature flag from the expression without syncing existing workspaces). The 2-6 workspace command iterates all `STANDARD_COMMAND_MENU_ITEMS` and reconciles any `conditionalAvailabilityExpression` that differs from the constant. Idempotent -- already-correct rows are skipped. Deferred: `deleteRecords` doesn't refetch the current record after deletion on RECORD_PAGE (mutation fires but UI shows stale state until refresh) -- different fix shape (frontend handler), separate PR. |
||
|
|
08e7e4819b |
use declared outputSchema for logic-function steps (#20679)
When a logic function declares `workflowActionTriggerSettings.outputSchema`, use it as the step's initial output schema so downstream steps can pick variables without first running the Test tab. A successful test run still overrides the schema with the inferred shape, preserving "test wins" behavior. Falls back to the existing "Generate Function Output" LINK placeholder when no schema is declared (custom code steps, older functions). https://github.com/user-attachments/assets/af9c45ed-d623-4234-be9f-46812fd06e2e |
||
|
|
827f24df2b |
fix(ai) - add ai model preferences fallback (#20704)
**Problem** AI_MODEL_PREFERENCES, JSON env var is not supported + IS_CONFIG_VARIABLES_IN_DB_ENABLED=false in twenty cloud server -> No option to set AI_MODEL_PREFERENCES **Solution** AI_MODEL_PREFERENCES supports three override sources beyond the hardcoded code defaults, in priority order: - DB (IS_CONFIG_VARIABLES_IN_DB_ENABLED=true), the only writable source; admin-panel mutations persist here - ENV not usable in Twenty Cloud, which does not handle JSON-format env vars - **Introduced in this PR** --> File (AI_MODEL_PREFERENCES_STORAGE_PATH), a read-only startup fallback, the only viable override in Cloud/self-managed deployments where DB config is disabled and JSON env vars are unsupported. |
||
|
|
d5ff9eb515 |
Create twenty app improvements (#20688)
create-twenty-app updates: - remove --example option - sync --once when scaffolding an applicaiton - rename --api-url option to --workspace-url - create a standalone page when scaffolding an app <img width="1494" height="765" alt="image" src="https://github.com/user-attachments/assets/0e35ed0c-b0aa-466c-9f56-7939294fd2cf" /> --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> |
||
|
|
71a7a3c42d |
i18n - website translations (#20724)
Created by Github action Co-authored-by: github-actions <github-actions@twenty.com> |
||
|
|
cbac2ba0bf |
i18n - translations (#20725)
Created by Github action --------- Co-authored-by: github-actions <github-actions@twenty.com> |