e6cc783a23fdedf8d7cfbbdf24cce99d30e96d74
222
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
0cc2194399 |
Simplify create-twenty-app command (#20512)
## Simplify `create-twenty-app` for zero-interaction use Makes `npx create-twenty-app@latest my-app` a fully non-interactive, single-command experience suitable for automated environments (Codex, Claude plugins). ### Changes - **Remove all interactive prompts** — app name, display name, description, and scaffold confirmation are now derived from CLI args with sensible defaults. `inquirer` dependency removed entirely. - **Replace OAuth with API key auth** — use the seeded dev API key (`DEV_API_KEY`) to authenticate against the Docker instance as `tim@apple.dev`, eliminating the browser-based OAuth flow. - **Docker-first with early validation** — check Docker is installed before scaffolding; if missing, print the install URL and exit. Detect alternative runtimes (Podman, nerdctl). - **Parallel image pull** — `docker pull` runs in the background during scaffold + dependency install, saving 10-30s on typical runs. - **Always pull latest image** — ensures the dev server is up-to-date on every run. - **Stop detecting port 3000** — only check port 2020 (Docker instance). - **Update CLI flags** — remove `--skip-local-instance` and `--yes`; add `--skip-docker`. - **Update CI workflows and docs** — align e2e workflows, package README, and template README/cd.yml with the new flow. |
||
|
|
4da8878697 |
feat: add email forwarding message channel (#19535)
## Summary - Add email forwarding as a new message channel type, allowing users to forward emails from addresses like `support@mycompany.com` into Twenty - Inbound emails arrive via S3 (SES → S3 bucket), are polled by a cron job, parsed, routed to the correct workspace/channel, and persisted as messages - Dedicated settings page at `/settings/accounts/new-email-forwarding` where users provide their source email handle and receive a unique forwarding address - Forwarding channels bypass the IMAP/mailbox sync state machine — they skip cron-driven sync, relaunch, and message-list-fetch lifecycle stages - Forwarding address section shown at the top of the Emails settings page so users can find/copy their addresses after initial setup - Tab names for forwarding channels display the user-provided handle (e.g. `support@mycompany.com`) instead of the internal routing address - Shared utilities extracted from IMAP driver: `extractThreadId`, `extractParticipants`, `extractAddresses` to avoid code duplication - Uses the existing S3 bucket (STORAGE_S3_*) with `inbound-email/` prefix — no separate bucket needed - Feature gated behind `isEmailForwardingEnabled` client config (requires `INBOUND_EMAIL_DOMAIN` + S3 storage) ## New backend modules - `InboundEmailS3ClientProvider` — lazy-initialized S3 client using existing storage config - `InboundEmailStorageService` — S3 operations (get, move to processed/unmatched/failed) - `InboundEmailParserService` — RFC 822 parsing via `postal-mime`, builds `MessageWithParticipants` - `InboundEmailImportService` — orchestrates download → parse → route → persist → archive - `MessagingInboundEmailPollCronJob` — polls S3 `incoming/` prefix, enqueues import jobs - `CreateEmailForwardingChannelInput` DTO — accepts user-provided `handle` ## New frontend components - `SettingsAccountsNewEmailForwardingChannel` — dedicated page with handle input form + forwarding address result - `SettingsAccountsEmailForwardingSection` — forwarding address list on the Emails settings page - `useConnectedAccountHandleMap` — shared hook for account ID → handle lookup - `useCreateEmailForwardingChannel` — mutation hook accepting handle parameter ## Test plan - [x] 17 unit tests for inbound email import service (all outcomes: imported, unmatched, loop_dropped, unconfigured, parse_failed, persist_failed) - [x] 16 tests for `computeSyncStatus` including EMAIL_FORWARDING cases - [x] 11 tests for `extractEnvelopeRecipient` utility - [x] TypeScript typechecks pass for both twenty-server and twenty-front - [x] Lint passes for both packages - [ ] Manual: create forwarding channel, verify forwarding address generated - [ ] Manual: send email to forwarding address, verify it appears in Twenty https://claude.ai/code/session_01KpyF6p4cUEnuaT4h8DP5Pm --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: neo773 <62795688+neo773@users.noreply.github.com> Co-authored-by: neo773 <neo773@protonmail.com> |
||
|
|
91124a3cb8 |
AI - Add azure foundry provider (#20170)
[Merge this before](https://github.com/twentyhq/twenty-infra/pull/655) Co-authored-by: Félix Malfait <felix.malfait@gmail.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> |
||
|
|
ff22988caf |
revert: Sentry #20064 + @sentry 10.27 (prod bisect) (#20221)
## Summary Reverts **#20064** (`feat(sentry): propagate workspace context to all spans`) and downgrades **@sentry** packages from **10.51** back to **10.27** (reversing **#20149**), to validate in production whether recent Sentry/instrumentation changes correlate with OTLP/metrics issues. ## Changes 1. **Revert #20064** — removes `beforeSendSpan` from `instrument.ts`, restores `WorkspaceAuthContextMiddleware` / `BullMQDriver` behavior, and deletes the three `apply-workspace-sentry-*` utils added in that PR. 2. **Sentry versions** — `packages/twenty-server` (`@sentry/nestjs`, `@sentry/node`, `@sentry/profiling-node`) and `packages/twenty-front` (`@sentry/react`) set to `^10.27.0`; `yarn.lock` regenerated via `yarn install`. --------- 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> |
||
|
|
83db37d33f |
chore(deps): bump @sentry/profiling-node from 10.27.0 to 10.51.0 (#20149)
Bumps [@sentry/profiling-node](https://github.com/getsentry/sentry-javascript) from 10.27.0 to 10.51.0. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/getsentry/sentry-javascript/releases"><code>@sentry/profiling-node</code>'s releases</a>.</em></p> <blockquote> <h2>10.51.0</h2> <h3>Important Changes</h3> <ul> <li> <p><strong>feat(cloudflare): Add trace propagation for RPC method calls (<a href="https://redirect.github.com/getsentry/sentry-javascript/pull/20343">#20343</a>)</strong></p> <p>Trace context is now propagated across Cloudflare Workers RPC calls, connecting traces between Workers and Durable Objects. This feature is opt-in and requires setting <code>enableRpcTracePropagation: true</code> in your SDK configuration:</p> <pre lang="ts"><code>// Worker export default Sentry.withSentry( env => ({ dsn: env.SENTRY_DSN, enableRpcTracePropagation: true, }), handler, ); <p>// Durable Object<br /> export const MyDurableObject = Sentry.instrumentDurableObjectWithSentry(<br /> env => ({<br /> dsn: env.SENTRY_DSN,<br /> enableRpcTracePropagation: true,<br /> }),<br /> MyDurableObjectBase,<br /> );<br /> </code></pre></p> </li> <li> <p><strong>feat(hono)!: Change setup for <code>@sentry/hono/node</code> (<code>init</code> in external file) (<a href="https://redirect.github.com/getsentry/sentry-javascript/pull/20497">#20497</a>)</strong></p> <p>To improve Node.js instrumentation, the <code>sentry()</code> middleware exported from <code>@sentry/hono/node</code> no longer accepts configuration options. Instead, you must configure the SDK by calling <code>Sentry.init()</code> in a dedicated instrumentation file that runs before your application code (read more in the <a href="https://github.com/getsentry/sentry-javascript/blob/develop/packages/hono/README.md">Hono SDK readme</a>:</p> <pre lang="ts"><code>// instrument.mjs (or instrument.ts) import * as Sentry from '@sentry/hono/node'; <p>Sentry.init({<br /> dsn: '<strong>DSN</strong>',<br /> tracesSampleRate: 1.0,<br /> });<br /> </code></pre></p> </li> <li> <p><strong>feat(nitro): Add <code>@sentry/nitro</code> SDK (<a href="https://redirect.github.com/getsentry/sentry-javascript/pull/19224">#19224</a>)</strong></p> <p>A new <code>@sentry/nitro</code> package provides first-class Sentry support for <a href="https://nitro.build/">Nitro</a> applications, with HTTP handler and error instrumentation, middleware tracing, request isolation, and build-time source map uploading via <code>withSentryConfig</code>. Read more in the <a href="https://docs.sentry.io/platforms/javascript/guides/nitro/">Nitro SDK docs</a> and the <a href="https://github.com/getsentry/sentry-javascript/blob/develop/packages/nitro/README.md">Nitro SDK readme</a>.</p> </li> </ul> <h3>Other Changes</h3> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/getsentry/sentry-javascript/blob/develop/CHANGELOG.md"><code>@sentry/profiling-node</code>'s changelog</a>.</em></p> <blockquote> <h2>10.51.0</h2> <h3>Important Changes</h3> <ul> <li> <p><strong>feat(cloudflare): Add trace propagation for RPC method calls (<a href="https://redirect.github.com/getsentry/sentry-javascript/pull/20343">#20343</a>)</strong></p> <p>Trace context is now propagated across Cloudflare Workers RPC calls, connecting traces between Workers and Durable Objects. This feature is opt-in and requires setting <code>enableRpcTracePropagation: true</code> in your SDK configuration:</p> <pre lang="ts"><code>// Worker export default Sentry.withSentry( env => ({ dsn: env.SENTRY_DSN, enableRpcTracePropagation: true, }), handler, ); <p>// Durable Object<br /> export const MyDurableObject = Sentry.instrumentDurableObjectWithSentry(<br /> env => ({<br /> dsn: env.SENTRY_DSN,<br /> enableRpcTracePropagation: true,<br /> }),<br /> MyDurableObjectBase,<br /> );<br /> </code></pre></p> </li> <li> <p><strong>feat(hono)!: Change setup for <code>@sentry/hono/node</code> (<code>init</code> in external file) (<a href="https://redirect.github.com/getsentry/sentry-javascript/pull/20497">#20497</a>)</strong></p> <p>To improve Node.js instrumentation, the <code>sentry()</code> middleware exported from <code>@sentry/hono/node</code> no longer accepts configuration options. Instead, you must configure the SDK by calling <code>Sentry.init()</code> in a dedicated instrumentation file that runs before your application code (read more in the <a href="https://github.com/getsentry/sentry-javascript/blob/develop/packages/hono/README.md">Hono SDK readme</a>:</p> <pre lang="ts"><code>// instrument.mjs (or instrument.ts) import * as Sentry from '@sentry/hono/node'; <p>Sentry.init({<br /> dsn: '<strong>DSN</strong>',<br /> tracesSampleRate: 1.0,<br /> });<br /> </code></pre></p> </li> <li> <p><strong>feat(nitro): Add <code>@sentry/nitro</code> SDK (<a href="https://redirect.github.com/getsentry/sentry-javascript/pull/19224">#19224</a>)</strong></p> <p>A new <code>@sentry/nitro</code> package provides first-class Sentry support for <a href="https://nitro.build/">Nitro</a> applications, with HTTP handler and error instrumentation, middleware tracing, request isolation, and build-time source map uploading via <code>withSentryConfig</code>. Read more in the <a href="https://docs.sentry.io/platforms/javascript/guides/nitro/">Nitro SDK docs</a> and the <a href="https://github.com/getsentry/sentry-javascript/blob/develop/packages/nitro/README.md">Nitro SDK readme</a>.</p> </li> </ul> <h3>Other Changes</h3> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/getsentry/sentry-javascript/commit/dc0b839ff4896cf90a02f5c1a6de54a31302dcf3"><code>dc0b839</code></a> release: 10.51.0</li> <li><a href="https://github.com/getsentry/sentry-javascript/commit/b3cabee9a9348b9e67332262d44d3d1900424199"><code>b3cabee</code></a> Merge pull request <a href="https://redirect.github.com/getsentry/sentry-javascript/issues/20599">#20599</a> from getsentry/prepare-release/10.51.0</li> <li><a href="https://github.com/getsentry/sentry-javascript/commit/3be99a9afa77e49578e6839e4b32f97fb04fb0f8"><code>3be99a9</code></a> meta(changelog): Update changelog for 10.51.0</li> <li><a href="https://github.com/getsentry/sentry-javascript/commit/bea1aad42277db894d5a299bfec3cdd633d6baf0"><code>bea1aad</code></a> test(browser): Unflake some more tests (<a href="https://redirect.github.com/getsentry/sentry-javascript/issues/20591">#20591</a>)</li> <li><a href="https://github.com/getsentry/sentry-javascript/commit/50aa0859b3a188d34d0317dab3ad57f2140f02fe"><code>50aa085</code></a> test(node): Unflake postgres tests (<a href="https://redirect.github.com/getsentry/sentry-javascript/issues/20593">#20593</a>)</li> <li><a href="https://github.com/getsentry/sentry-javascript/commit/1166839112c4766f210124dc0486ebbfd6db104b"><code>1166839</code></a> fix(hono): Distinguish <code>.use()</code> middleware in sub-apps from <code>.all()</code> handlers...</li> <li><a href="https://github.com/getsentry/sentry-javascript/commit/217ad4a69554281806eccbfeac1b27c4f43f6ffa"><code>217ad4a</code></a> test(node): Fix flaky ANR test (<a href="https://redirect.github.com/getsentry/sentry-javascript/issues/20592">#20592</a>)</li> <li><a href="https://github.com/getsentry/sentry-javascript/commit/91ffb3fac90835ab160f8152527a54a5d64f3250"><code>91ffb3f</code></a> test(node): Fix flaky worker thread integration test (<a href="https://redirect.github.com/getsentry/sentry-javascript/issues/20588">#20588</a>)</li> <li><a href="https://github.com/getsentry/sentry-javascript/commit/c4e3902c9297147158e730f017aba96e83ef619e"><code>c4e3902</code></a> chore(ci): Do not report flaky test issues if we cannot find a test name (<a href="https://redirect.github.com/getsentry/sentry-javascript/issues/20">#20</a>...</li> <li><a href="https://github.com/getsentry/sentry-javascript/commit/c0005cd387f3a7ea6fbb2e85041562c7f32e0484"><code>c0005cd</code></a> test(node): Update timeout for cron integration tests (<a href="https://redirect.github.com/getsentry/sentry-javascript/issues/20586">#20586</a>)</li> <li>Additional commits viewable in <a href="https://github.com/getsentry/sentry-javascript/compare/10.27.0...10.51.0">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: Charles Bochet <charles@twenty.com> |
||
|
|
a713f8d87f |
CalDAV: support Digest auth (#20135)
Adds digest auth support for CalDAV, mostly used by legacy servers /closes https://github.com/twentyhq/twenty/issues/19922 |
||
|
|
fd6d5f895d |
Ai Chat - Caching optim (#20126)
EDIT :
- solving auto-caching from Anthropic by updating ai-sdk/anthropic +
adding providerOption at stream level
- concerning Bedrock, it needs breakpoint
**1. Breakpoints were only on the system prompt**
The code already placed a cache marker on the system prompt (~10K
tokens). But the conversation history — which can grow to hundreds of
thousands of tokens — had no marker, so Anthropic re-read it at full
price on every turn.
The fix adds a prepareStep hook inside streamText that stamps the last
message with a cache breakpoint before every LLM call. Anthropic then
caches the entire conversation prefix, and subsequent turns read it at
$0.30/M instead of $3/M.
prepareStep is used rather than a one-shot pre-processing step because
an agentic turn makes multiple internal LLM calls as tool results
accumulate — the hook refreshes the breakpoint before each one.
**2. Bedrock was using the wrong field**
The system prompt marker for Bedrock was set as cacheControl: { type:
'ephemeral' } — which is the Anthropic wire format. The Bedrock Converse
API expects cachePoint: { type: 'default' }. The system prompt was
silently not being cached on Bedrock at all.
Both the system prompt and the new prepareStep now go through a shared
getCacheProviderOptions helper that returns the correct field per
provider.
**3. Persisted cached token usage to monitor cache strat. efficiency**
|
||
|
|
abfa6200dd |
ssrf hardening (#19963)
Hardened CalDav with new approach of wrapping axios ssrf http agent to fetch via `@lifeomic/axios-fetch` because `tsdav` only accept `fetch` override. Also Hardened test endpoint |
||
|
|
80e8f6d516 |
chore(deps): bump @blocknote/server-util from 0.47.1 to 0.47.3 (#19997)
Bumps [@blocknote/server-util](https://github.com/TypeCellOS/BlockNote/tree/HEAD/packages/server-util) from 0.47.1 to 0.47.3. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/TypeCellOS/BlockNote/releases"><code>@blocknote/server-util</code>'s releases</a>.</em></p> <blockquote> <h2>v0.47.3</h2> <h2>0.47.3 (2026-03-25)</h2> <h3>🩹 Fixes</h3> <ul> <li><strong>core:</strong> preserve whitespace edge cases but collapse html formatting newlines (BLO-1065) (<a href="https://redirect.github.com/TypeCellOS/BlockNote/pull/2551">#2551</a>, <a href="https://redirect.github.com/TypeCellOS/BlockNote/issues/2230">#2230</a>)</li> </ul> <h3>❤️ Thank You</h3> <ul> <li>Yousef</li> </ul> <h2>v0.47.2</h2> <h2>0.47.2 (2026-03-20)</h2> <h3>🩹 Fixes</h3> <ul> <li>use <code><details></code> & <code><summary></code> for toggle block HTML export (<a href="https://redirect.github.com/TypeCellOS/BlockNote/pull/2524">#2524</a>)</li> <li>remove <code>@hocuspocus/provider</code> peer dependency by inlining tiptap comment types BLO-1064 (<a href="https://redirect.github.com/TypeCellOS/BlockNote/pull/2564">#2564</a>)</li> <li><strong>core:</strong> slash menu fails in custom blocks after space BLO-1036 (<a href="https://redirect.github.com/TypeCellOS/BlockNote/pull/2553">#2553</a>)</li> <li><strong>i18n:</strong> fix typo in russian translation (<a href="https://redirect.github.com/TypeCellOS/BlockNote/pull/2560">#2560</a>)</li> </ul> <h3>❤️ Thank You</h3> <ul> <li>Drone</li> <li>Yousef</li> </ul> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/TypeCellOS/BlockNote/blob/main/CHANGELOG.md"><code>@blocknote/server-util</code>'s changelog</a>.</em></p> <blockquote> <h2>0.47.3 (2026-03-25)</h2> <h3>🩹 Fixes</h3> <ul> <li><strong>core:</strong> preserve whitespace edge cases but collapse html formatting newlines (BLO-1065) (<a href="https://redirect.github.com/TypeCellOS/BlockNote/pull/2551">#2551</a>, <a href="https://redirect.github.com/TypeCellOS/BlockNote/issues/2230">#2230</a>)</li> </ul> <h3>❤️ Thank You</h3> <ul> <li>Yousef</li> </ul> <h2>0.47.2 (2026-03-20)</h2> <h3>🩹 Fixes</h3> <ul> <li>use <!-- raw HTML omitted -->/<!-- raw HTML omitted --> for toggle block HTML export (<a href="https://redirect.github.com/TypeCellOS/BlockNote/pull/2524">#2524</a>)</li> <li>remove <code>@hocuspocus/provider</code> peer dependency by inlining tiptap comment types BLO-1064 (<a href="https://redirect.github.com/TypeCellOS/BlockNote/pull/2564">#2564</a>)</li> <li><strong>core:</strong> slash menu fails in custom blocks after space BLO-1036 (<a href="https://redirect.github.com/TypeCellOS/BlockNote/pull/2553">#2553</a>)</li> <li><strong>i18n:</strong> fix typo in russian translation (<a href="https://redirect.github.com/TypeCellOS/BlockNote/pull/2560">#2560</a>)</li> </ul> <h3>❤️ Thank You</h3> <ul> <li>Claude Opus 4.6</li> <li>Drone</li> <li>Yousef</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/TypeCellOS/BlockNote/commit/cd92dc21be49397b658fef4e308e01ce8f5c04ad"><code>cd92dc2</code></a> chore(release): publish 0.47.3</li> <li><a href="https://github.com/TypeCellOS/BlockNote/commit/b63b4096daa575f821980ef897fd90f4c76d9e42"><code>b63b409</code></a> chore(release): publish 0.47.2</li> <li><a href="https://github.com/TypeCellOS/BlockNote/commit/d76fd68e016da698f3896f9d349a935a26a52d5f"><code>d76fd68</code></a> test: get snapshots working again (<a href="https://github.com/TypeCellOS/BlockNote/tree/HEAD/packages/server-util/issues/2554">#2554</a>)</li> <li>See full diff in <a href="https://github.com/TypeCellOS/BlockNote/commits/v0.47.3/packages/server-util">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> |
||
|
|
9a403b84f3 |
database:init:prod triggers instance slow command too (#19555)
When creating a db from scrath we still need to run the slow instance command so the associated queries are still applied to the empty db Please note that by default if there's no workspace the instance slow runner will skip the runDataMigration part |
||
|
|
8a84e32cf6 |
fix(ai): use @ai-sdk/openai-compatible for third-party providers (#19438)
## Summary: I found a bug: 404 call when I use third-party providers (I used deepseek). I found the final request url is: `https://api.deepseek.com/v1/responses' `if we use createOpenAI. But the correct one should be `https://api.provider.com/v1/chat/completions` for the thirty provider. So I replace createOpenAI with createOpenAICompatible in the openai-compatible provider path. **Reproduction**: Add DeepSeek as a new AI provider (deepseek-chat, deepseek-reasoner) Also check the source code in Open Code project, they also use createOpenAICompatible for the @ai-sdk/openai-compatible scenario <img width="703" height="369" alt="image" src="https://github.com/user-attachments/assets/90c4f924-6f1a-4fe7-821b-f13ee86a7a39" /> official docs: https://ai-sdk.dev/providers/openai-compatible-providers https://ai-sdk.dev/providers/ai-sdk-providers/openai <img width="860" height="293" alt="image" src="https://github.com/user-attachments/assets/283b9b91-f1d6-4b1c-bb91-16ddccdff8b4" /> ## Before <img width="473" height="750" alt="deepseek before" src="https://github.com/user-attachments/assets/f6b89294-1fa7-4ddc-a6a8-d396070caaca" /> ## After <img width="468" height="753" alt="deepseek after" src="https://github.com/user-attachments/assets/0d170b70-e829-4a4c-abad-38879427c2df" /> ## Backend error log ```json [1] [Nest] 50907 - 07/04/2026, 23:48:57 LOG [ChatExecutionService] Starting chat execution with model deepseek/deepseek-chat, 4 active tools [1] APICallError [AI_APICallError]: Not Found [1] at /Users/abel/Documents/Code/twenty/node_modules/@ai-sdk/provider-utils/dist/index.js:2512:14 [1] at process.processTicksAndRejections (node:internal/process/task_queues:105:5) [1] at async postToApi (/Users/abel/Documents/Code/twenty/node_modules/@ai-sdk/provider-utils/dist/index.js:2373:28) [1] at async OpenAIResponsesLanguageModel.doStream (/Users/abel/Documents/Code/twenty/node_modules/@ai-sdk/openai/dist/index.js:4925:50) [1] at async fn (/Users/abel/Documents/Code/twenty/node_modules/ai/dist/index.js:7106:27) [1] at async /Users/abel/Documents/Code/twenty/node_modules/ai/dist/index.js:2340:24 [1] at async _retryWithExponentialBackoff (/Users/abel/Documents/Code/twenty/node_modules/ai/dist/index.js:2599:12) [1] at async streamStep (/Users/abel/Documents/Code/twenty/node_modules/ai/dist/index.js:7063:17) [1] at async fn (/Users/abel/Documents/Code/twenty/node_modules/ai/dist/index.js:7455:9) [1] at async /Users/abel/Documents/Code/twenty/node_modules/ai/dist/index.js:2340:24 { [1] cause: undefined, [1] url: 'https://api.deepseek.com/v1/responses', [1] requestBodyValues: { [1] model: 'deepseek-chat', [1] input: [ [Object], [Object] ], [1] temperature: undefined, [1] top_p: undefined, [1] max_output_tokens: undefined, [1] conversation: undefined, [1] max_tool_calls: undefined, [1] metadata: undefined, [1] parallel_tool_calls: undefined, [1] previous_response_id: undefined, [1] store: undefined, [1] user: undefined, [1] instructions: undefined, [1] service_tier: undefined, [1] include: undefined, [1] prompt_cache_key: undefined, [1] prompt_cache_retention: undefined, [1] safety_identifier: undefined, [1] top_logprobs: undefined, [1] truncation: undefined, [1] tools: [ [Object], [Object], [Object], [Object] ], [1] tool_choice: 'auto', [1] stream: true [1] }, [1] statusCode: 404, [1] responseHeaders: { [1] 'access-control-allow-credentials': 'true', [1] connection: 'keep-alive', [1] 'content-length': '0', [1] date: 'Tue, 07 Apr 2026 22:48:57 GMT', [1] server: 'elb', [1] 'strict-transport-security': 'max-age=31536000; includeSubDomains; preload', [1] vary: 'origin, access-control-request-method, access-control-request-headers', [1] via: '1.1 83867089cd39052cd05f9e04909bedde.cloudfront.net (CloudFront)', [1] 'x-amz-cf-id': 'O4b0VTi9Q1VVmTmq6czGlEWst7IPnAQl544hB7uIvfnSphBvUKbZTw==', [1] 'x-amz-cf-pop': 'DUB56-P3', [1] 'x-cache': 'Error from cloudfront', [1] 'x-content-type-options': 'nosniff', [1] 'x-ds-trace-id': 'a90e91809d285170338ef077f67ae2be' [1] }, [1] responseBody: '', [1] isRetryable: false, [1] data: undefined, [1] Symbol(vercel.ai.error): true, [1] Symbol(vercel.ai.error.AI_APICallError): true [1] } [1] Exception Captured [1] undefined [1] [ [1] NoOutputGeneratedError [AI_NoOutputGeneratedError]: No output generated. Check the stream for errors. [1] at Object.flush (/Users/abel/Documents/Code/twenty/node_modules/ai/dist/index.js:6656:103) [1] at invokePromiseCallback (node:internal/webstreams/util:172:10) [1] at Object.<anonymous> (node:internal/webstreams/util:177:23) [1] at transformStreamDefaultSinkCloseAlgorithm (node:internal/webstreams/transformstream:621:43) [1] at node:internal/webstreams/transformstream:379:11 [1] at writableStreamDefaultControllerProcessClose (node:internal/webstreams/writablestream:1162:28) [1] at writableStreamDefaultControllerAdvanceQueueIfNeeded (node:internal/webstreams/writablestream:1253:5) [1] at writableStreamDefaultControllerClose (node:internal/webstreams/writablestream:1220:3) [1] at writableStreamClose (node:internal/webstreams/writablestream:722:3) [1] at writableStreamDefaultWriterClose (node:internal/webstreams/writablestream:1091:10) { [1] cause: undefined, [1] Symbol(vercel.ai.error): true, [1] Symbol(vercel.ai.error.AI_NoOutputGeneratedError): true [1] } [1] ] [1] [Nest] 50907 - 07/04/2026, 23:48:59 LOG [BullMQDriver] Job 24 with name StreamAgentChatJob processed on queue ai-stream-queue in 2756.63ms |
||
|
|
1b14e7e1f1 |
Fix - Update package.json (#19390)
https://github.com/twentyhq/twenty/pull/19383#discussion_r3044330450 |
||
|
|
23874848a4 |
Instance commands and upgrade_migrations table (#19356)
# Introduction Now only using typeorm to generate migrations up and down statement We handle and maintain our own migration table history ## What's new Now all the instance commands will live within the same module and folder than the upgrade commands Sequentiality comes from the timestamp located in the filename Same sequentiality also applies to the workspace commands in the future, for the moment still expected a as code explicit declaration ( below screen is an example see below section ) <img width="1382" height="634" alt="image" src="https://github.com/user-attachments/assets/5610a246-4eae-485e-99f4-98fb89ad5ac8" /> ## Existing 1.21 migrations We won't start following this pattern in 1.21 yet at least not with the migration that has already been released as typeorm migrations in cloud production as they would rerun ## Small duplication Duplicating the legacy typeorm and instance commands run in the `run-instance-commands` to avoid any merge of interest for the moment ## Concurrency Not handling any run in parrallel of the upgrade for the moment |
||
|
|
ea572975d8 |
feat: generic web search driver abstraction with Exa support and billing (#19341)
## Summary - Introduces a pluggable `WebSearchDriver` abstraction (interface, factory, service, module) so web search is no longer tied to native provider tools (Anthropic/OpenAI) - **Exa** is the first driver implementation with support for category-filtered search (company, people, news, research paper, etc.) — particularly useful for CRM workflows - Per-query billing for both Exa ($0.007/query) and native provider surcharges ($0.01/query for Anthropic/OpenAI) via the existing `USAGE_RECORDED` pipeline - New config variables: `WEB_SEARCH_DRIVER` (EXA/DISABLED), `EXA_API_KEY`, `WEB_SEARCH_PREFER_NATIVE` (default false — prefers Exa over native when both available) - `WEB_SEARCH` operation type added for usage tracking and Stripe metering ### Architecture ``` WebSearchDriver (interface) ├── ExaDriver — Exa neural search with category support └── DisabledDriver — throws when search is disabled WebSearchDriverFactory (extends DriverFactoryBase) └── creates driver based on WEB_SEARCH_DRIVER config WebSearchService (facade) ├── search(query, options?, billingContext?) ├── isEnabled() └── emits USAGE_RECORDED events per query WebSearchTool (Tool implementation) └── registered in ActionToolProvider, available via tool catalog ``` ### Native search billing gap fixed Anthropic and OpenAI both charge $0.01/search on top of token costs. The token costs were already billed, but the per-call surcharge was not. Added `countNativeWebSearchCallsFromSteps` utility + `billNativeWebSearchUsage` to `AiBillingService`, wired into both chat and workflow agent paths. ## Test plan - [ ] Set `WEB_SEARCH_DRIVER=EXA` + `EXA_API_KEY=...` and verify AI chat can search the web - [ ] Verify category parameter works (ask about a specific company/person) - [ ] Set `WEB_SEARCH_DRIVER=DISABLED` and verify search tool is not exposed - [ ] Set `WEB_SEARCH_PREFER_NATIVE=true` with Anthropic model and verify native search is used - [ ] Verify usage events are emitted in ClickHouse for both Exa and native search paths - [ ] Verify existing billing tests pass (`npx jest ai-billing.service.spec.ts`) Made with [Cursor](https://cursor.com) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> |
||
|
|
e062343802 |
Refactor typeorm migration lifecycle and generation (#19275)
# Introduction Typeorm migration are now associated to a given twenty-version from the `UPGRADE_COMMAND_SUPPORTED_VERSIONS` that the current twenty core engine handles This way when we upgrade we retrieve the migrations that need to be run, this will be useful for the cross-version incremental upgrade so we preserve sequentiality ## What's new To generate ```sh npx nx database:migrate:generate twenty-server -- --name add-index-to-users ``` To apply all ```sh npx nx database:migrate twenty-server ``` ## Next Introduce slow and fast typeorm migration in order to get rid of the save point pattern in our code base Create a clean and dedicated `InstanceUpgradeService` abstraction |
||
|
|
fd7387928c |
feat: queue messages + replace AI SDK with GraphQL SSE subscription (#19203)
## Summary - **Queue messages while streaming**: Messages sent during active AI streaming are queued server-side and auto-flushed when the current stream completes. Frontend renders queued messages optimistically in a dedicated queue UI. - **Drop `@ai-sdk/react` + `resumable-stream`**: Replace the dual HTTP SSE + AI SDK client architecture with a single GraphQL SSE subscription per thread. All events (token chunks, message persistence, queue updates, errors) flow through Redis PubSub → GraphQL subscription. - **Server-driven architecture**: The server decides whether to queue or stream (via `POST /:threadId/message`). The frontend mirrors this decision for optimistic rendering but defers to the server response. - **Reuse AI SDK accumulation logic**: `readUIMessageStream` from the `ai` package handles chunk-to-message accumulation on the frontend, avoiding a custom 780-line accumulator. ## Key files **Backend:** - `agent-chat-event-publisher.service.ts` — publishes events to Redis PubSub - `agent-chat-subscription.resolver.ts` — GraphQL subscription resolver - `stream-agent-chat.job.ts` — publishes chunks via PubSub instead of resumable-stream - `agent-chat.controller.ts` — unified `POST /:threadId/message` endpoint **Frontend:** - `useAgentChatSubscription.ts` — subscribes to `onAgentChatEvent`, bridges to `readUIMessageStream` - `useAgentChat.ts` — send/stop/optimistic rendering (no more AI SDK) - `AgentChatStreamSubscriptionEffect.tsx` — replaces `AgentChatAiSdkStreamEffect.tsx` ## Test plan - [ ] Send message on new thread → optimistic render, streaming response appears - [ ] Send message while streaming → queued instantly (no flash in main thread) - [ ] Queued message auto-flushes after current stream completes - [ ] Remove queued message via queue UI - [ ] Stop streaming mid-response - [ ] Leave chat idle for several minutes → streaming still works after (SSE client recycling) - [ ] Token refresh during session → requests succeed (authenticated fetch) - [ ] Switch threads while streaming → clean subscription handoff Made with [Cursor](https://cursor.com) --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.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> |
||
|
|
8fa3962e1c |
feat: add resumable stream support for agent chat (#19107)
## Overview Add resumable stream support for agent chat to allow clients to reconnect and resume streaming responses if the connection is interrupted (e.g., during page refresh). ## Changes ### Backend (Twenty Server) - Add `activeStreamId` column to `AgentChatThreadEntity` to track ongoing streams - Create `AgentChatResumableStreamService` to manage Redis-backed resumable streams using the `resumable-stream` library with ioredis - Extend `AgentChatController` with: - `GET /:threadId/stream` endpoint to resume an existing stream - `DELETE /:threadId/stream` endpoint to stop an active stream - Update `AgentChatStreamingService` to store streams in Redis and track active stream IDs - Add `resumable-stream@^2.2.12` dependency to package.json ### Frontend (Twenty Front) - Update `useAgentChat` hook to: - Use a persistent transport with `prepareReconnectToStreamRequest` for resumable streams - Export `resumeStream` function from useChat - Add `handleStop` callback to clear active stream on DELETE endpoint - Use thread ID as stable message ID instead of including message count - Add stream resumption logic in `AgentChatAiSdkStreamEffect` component to automatically call `resumeStream()` when switching threads ## Database Migration New migration `1774003611071-add-active-stream-id-to-agent-chat-thread` adds the `activeStreamId` column to store the current resumable stream identifier. --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
281bb6d783 |
Guard yarn database:migrate:prod (#19008)
## Motivations A lot of self hosters hands up using the `yarn database:migrated:prod` either manually or through AI assisted debug while they try to upgrade an instance while their workspace is still blocked in a previous one Leading to their whole database permanent corruption ## What happened Replaced the direct call the the typeorm cli to a command calling it programmatically, adding a layer of security in case a workspace seems to be blocked in a previous version than the one just before the one being installed ( e.g 1.0 when you try to upgrade from 1.1 to 1.2 ) For our cloud we still need a way to bypass this security explaining the -f flag ## Remark Centralized this logic and refactored creating new services `WorkspaceVersionService` and `CoreEngineVersionService` that will become useful for the upcoming upgrade refactor Related to https://github.com/twentyhq/twenty-infra/pull/529 |
||
|
|
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>
|
||
|
|
908aefe7c1 |
feat: replace hardcoded AI model constants with JSON seed catalog (#18818)
## Summary - Replaces per-provider TypeScript constant files (`openai-models.const.ts`, `anthropic-models.const.ts`, etc.) with a single `ai-providers.json` catalog as the source of truth - Adds runtime model discovery via AI SDK for self-hosted providers, with `models.dev` enrichment for pricing/capabilities - Introduces composite model IDs (`provider/modelId`) for canonical, conflict-free identification - Simplifies provider configuration: API keys are injected from environment variables (e.g., `OPENAI_API_KEY`) - Adds admin panel UI for provider management (add/remove/test), model discovery, recommended model configuration, and default fast/smart model selection per workspace - Removes deprecated config variables (`AI_DISABLED_MODEL_IDS`, `AUTO_ENABLE_NEW_AI_MODELS`, etc.) - Adds database migration for composite model ID format ## Test plan - [ ] Server typecheck passes - [ ] Frontend typecheck passes - [ ] Server unit tests pass - [ ] Frontend unit tests pass - [ ] CI pipeline green - [ ] Admin panel AI tab loads correctly - [ ] Provider discovery works for configured providers - [ ] Model recommendation toggles persist - [ ] Default fast/smart model selection works Made with [Cursor](https://cursor.com) |
||
|
|
6e36ad9fa2 |
fix: mailparser vulnerable to cross-site scripting (#18664)
Resolves [Dependabot Alert 595](https://github.com/twentyhq/twenty/security/dependabot/595) and [Dependabot Alert 596](https://github.com/twentyhq/twenty/security/dependabot/596). |
||
|
|
2c2f66b584 |
fix: DOMPurify contains a cross-site scripting vulnerability (#18665)
Resolves [Dependabot Alert 597](https://github.com/twentyhq/twenty/security/dependabot/597), [Dependabot Alert 598](https://github.com/twentyhq/twenty/security/dependabot/598), [Dependabot Alert 599](https://github.com/twentyhq/twenty/security/dependabot/599) and [Dependabot Alert 600](https://github.com/twentyhq/twenty/security/dependabot/600). |
||
|
|
87c519b72f |
fix: multer vulnerable to denial of service via uncontrolled recursion (#18659)
Resolves [Dependabot Alert 608](https://github.com/twentyhq/twenty/security/dependabot/608). |
||
|
|
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. |
||
|
|
b21fb4aa6f |
Fix PDF Upload edge case (#18533)
we were using an older version of `file-type` which has limited support for PDF as it's a complex spec Updated to latest version which includes support for plugins and added `@file-type/pdf` which has extensive spec compliant detection approach fixes TWENTY-SERVER-FAN |
||
|
|
d9b3507866 |
Run vulnerable operation in isolated environment (#18523)
When driver = LAMBDA: - run esbuild ts transpilation on dedicated lambda - run yarn install on app dependencies on a dedicated lambda |
||
|
|
2de022afcf |
Add standard command menu items (#18527)
## Add standard command menu items
### Summary
This PR introduces standard command menu items, migrating hardcoded
command menu actions to the backend command menu item architecture
powered by front components. It adds a new `twenty-standard-application`
package that defines, builds, and registers front components as standard
command menu items, gated behind the `IS_COMMAND_MENU_ITEM_ENABLED`
feature flag.
### Description
- **New `twenty-standard-application` package**: Contains front
component definitions with an esbuild-based build pipeline that
generates minified `.mjs` bundles and a manifest with checksums.
- **Server-side registration**: New constants register all items with
metadata (labels, icons, positions, availability types, conditional
expressions). A `StandardFrontComponentUploadService` uploads built
components to file storage.
- **`FALLBACK` availability type**: New enum value for command menu
items that appear as fallback options (e.g., "Search Records" fallback).
- **`CommandMenuContextApi` refactor**
- **Conditional availability enhancements**: New array-based helper
functions for evaluating multi-record conditions.
- **Frontend wiring** (twenty-front):
`useCommandMenuItemFrontComponentCommands`
## Next steps
Only simple commands have been implemented for now:
- **Navigation (9)** -- `CommandLink`: go-to-companies,
go-to-dashboards, go-to-notes, go-to-opportunities, go-to-people,
go-to-runs, go-to-settings, go-to-tasks, go-to-workflows
- **Side panel (4)** -- `CommandOpenSidePanelPage`: ask-ai,
search-records, search-records-fallback, view-previous-ai-chats
We still have to implement front components for all the following
commands:
All have placeholder `execute` logic (`async () => {}`) with a `// TODO:
implement execute logic` comment:
**Record (22)**
- `add-to-favorites`, `remove-from-favorites`
- `create-new-record`, `create-new-view`
- `delete-single-record`, `delete-multiple-records`
- `destroy-single-record`, `destroy-multiple-records`
- `restore-single-record`, `restore-multiple-records`
- `export-from-record-index`, `export-from-record-show`,
`export-multiple-records`, `export-note-to-pdf`, `export-view`
- `hide-deleted-records`, `see-deleted-records`
- `import-records`, `merge-multiple-records`, `update-multiple-records`
- `navigate-to-next-record`, `navigate-to-previous-record`
**Page layout (3)** -- `cancel-record-page-layout`,
`edit-record-page-layout`, `save-record-page-layout`
**Dashboard (4)** -- `cancel-dashboard-layout`, `duplicate-dashboard`,
`edit-dashboard-layout`, `save-dashboard-layout`
**Workflow (10)** -- `activate-workflow`, `add-node-workflow`,
`deactivate-workflow`, `discard-draft-workflow`, `duplicate-workflow`,
`see-active-version-workflow`, `see-runs-workflow`,
`see-versions-workflow`, `test-workflow`, `tidy-up-workflow`
**Workflow version (4)** -- `see-runs-workflow-version`,
`see-versions-workflow-version`, `see-workflow-workflow-version`,
`use-as-draft-workflow-version`
**Workflow run (3)** -- `see-version-workflow-run`,
`see-workflow-workflow-run`, `stop-workflow-run`
|
||
|
|
d825ac06dd |
fix server production build (#18458)
## Context
- fuse.js was imported in navigate-app-tool.ts but only declared in the
root package.json (has been like this for months but for the first time
being used in the server)
- This works locally due to yarn hoisting, but breaks in Docker
production builds
```bash
Error: Cannot find module 'fuse.js'
Require stack:
- /app/packages/twenty-server/dist/engine/core-modules/tool/tools/navigate-tool/navigate-app-tool.js
- /app/packages/twenty-server/dist/engine/core-modules/tool-provider/providers/action-tool.provider.js
- /app/packages/twenty-server/dist/engine/core-modules/tool-provider/tool-provider.module.js
- /app/packages/twenty-server/dist/engine/metadata-modules/ai/ai-agent-execution/ai-agent-execution.module.js
- /app/packages/twenty-server/dist/engine/metadata-modules/ai/ai-agent-monitor/ai-agent-monitor.module.js
- /app/packages/twenty-server/dist/engine/metadata-modules/metadata-engine.module.js
- /app/packages/twenty-server/dist/engine/api/graphql/core-graphql-api.module.js
- /app/packages/twenty-server/dist/app.module.js
- /app/packages/twenty-server/dist/main.js
at Module._resolveFilename (node:internal/modules/cjs/loader:1456:15)
at defaultResolveImpl (node:internal/modules/cjs/loader:1066:19)
at resolveForCJSWithHooks (node:internal/modules/cjs/loader:1071:22)
at Module._load (node:internal/modules/cjs/loader:1242:25)
at wrapModuleLoad (node:internal/modules/cjs/loader:255:19)
at Module.require (node:internal/modules/cjs/loader:1556:12)
at require (node:internal/modules/helpers:152:16)
at Object.<anonymous> (/app/packages/twenty-server/dist/engine/core-modules/tool/tools/navigate-tool/navigate-app-tool.js:13:54)
at Module._compile (node:internal/modules/cjs/loader:1812:14)
at Object..js (node:internal/modules/cjs/loader:1943:10) {
code: 'MODULE_NOT_FOUND',
```
Fix: Adding the dependency in twenty-server package.json to make it available in production builds
|
||
|
|
9d57bc39e5 |
Migrate from ESLint to OxLint (#18443)
## Summary Fully replaces ESLint with OxLint across the entire monorepo: - **Replaced all ESLint configs** (`eslint.config.mjs`) with OxLint configs (`.oxlintrc.json`) for every package: `twenty-front`, `twenty-server`, `twenty-emails`, `twenty-ui`, `twenty-shared`, `twenty-sdk`, `twenty-zapier`, `twenty-docs`, `twenty-website`, `twenty-apps/*`, `create-twenty-app` - **Migrated custom lint rules** from ESLint plugin format to OxLint JS plugin system (`@oxlint/plugins`), including `styled-components-prefixed-with-styled`, `no-hardcoded-colors`, `sort-css-properties-alphabetically`, `graphql-resolvers-should-be-guarded`, `rest-api-methods-should-be-guarded`, `max-consts-per-file`, and Jotai-related rules - **Migrated custom rule tests** from ESLint `RuleTester` + Jest to `oxlint/plugins-dev` `RuleTester` + Vitest - **Removed all ESLint dependencies** from `package.json` files and regenerated lockfiles - **Updated Nx targets** (`lint`, `lint:diff-with-main`, `fmt`) in `nx.json` and per-project `project.json` to use `oxlint` commands with proper `dependsOn` for plugin builds - **Updated CI workflows** (`.github/workflows/ci-*.yaml`) — no more ESLint executor - **Updated IDE setup**: replaced `dbaeumer.vscode-eslint` with `oxc.oxc-vscode` extension, configured `source.fixAll.oxc` and format-on-save with Prettier - **Replaced all `eslint-disable` comments** with `oxlint-disable` equivalents across the codebase - **Updated docs** (`twenty-docs`) to reference OxLint instead of ESLint - **Renamed** `twenty-eslint-rules` package to `twenty-oxlint-rules` ### Temporarily disabled rules (tracked in `OXLINT_MIGRATION_TODO.md`) | Rule | Package | Violations | Auto-fixable | |------|---------|-----------|-------------| | `twenty/sort-css-properties-alphabetically` | twenty-front | 578 | Yes | | `typescript/consistent-type-imports` | twenty-server | 3814 | Yes | | `twenty/max-consts-per-file` | twenty-server | 94 | No | ### Dropped plugins (no OxLint equivalent) `eslint-plugin-project-structure`, `lingui/*`, `@stylistic/*`, `import/order`, `prefer-arrow/prefer-arrow-functions`, `eslint-plugin-mdx`, `@next/eslint-plugin-next`, `eslint-plugin-storybook`, `eslint-plugin-react-refresh`. Partial coverage for `jsx-a11y` and `unused-imports`. ### Additional fixes (pre-existing issues exposed by merge) - Fixed `EmailThreadPreview.tsx` broken import from main rename (`useOpenEmailThreadInSidePanel`) - Restored truthiness guard in `getActivityTargetObjectRecords.ts` - Fixed `AgentTurnResolver` return types to match entity (virtual `fileMediaType`/`fileUrl` are resolved via `@ResolveField()`) ## Test plan - [x] `npx nx lint twenty-front` passes - [x] `npx nx lint twenty-server` passes - [x] `npx nx lint twenty-docs` passes - [x] Custom oxlint rules validated with Vitest: `npx nx test twenty-oxlint-rules` - [x] `npx nx typecheck twenty-front` passes - [x] `npx nx typecheck twenty-server` passes - [x] CI workflows trigger correctly with `dependsOn: ["twenty-oxlint-rules:build"]` - [x] IDE linting works with `oxc.oxc-vscode` extension |
||
|
|
57d8954973 |
[SDK] Pure ESM (#18427)
# Introduction While testing the sdk and overall apps in https://github.com/prastoin/twenty-app-hello-world Faced a lot of pure `CJS` external dependencies import issue Replaced all the cjs deps to either esm equivalent or node native replacement |
||
|
|
0e89c96170 |
feat: add npm and tarball app distribution with upgrade mechanism (#18358)
## Summary - **npm + tarball app distribution**: Apps can be installed from the npm registry (public or private) or uploaded as `.tar.gz` tarballs, with `AppRegistrationSourceType` tracking the origin - **Upgrade mechanism**: `AppUpgradeService` checks for newer versions, supports rollback for npm-sourced apps, and a cron job runs every 6 hours to update `latestAvailableVersion` on registrations - **Security hardening**: Tarball extraction uses path traversal protection, and `enableScripts: false` in `.yarnrc.yml` disables all lifecycle scripts during `yarn install` to prevent RCE - **Frontend**: "Install from npm" and "Upload tarball" modals, upgrade button on app detail page, blue "Update" badge on installed apps table when a newer version is available - **Marketplace catalog sync**: Hourly cron job syncs a hardcoded catalog index into `ApplicationRegistration` entities - **Integration tests**: Coverage for install, upgrade, tarball upload, and catalog sync flows ## Backend changes | Area | Files | |------|-------| | Entity & migration | `ApplicationRegistrationEntity` (sourceType, sourcePackage, latestAvailableVersion), `ApplicationEntity` (applicationRegistrationId), migration | | Services | `AppPackageResolverService`, `ApplicationInstallService`, `AppUpgradeService`, `MarketplaceCatalogSyncService` | | Cron jobs | `MarketplaceCatalogSyncCronJob` (hourly), `AppVersionCheckCronJob` (every 6h) | | REST endpoint | `AppRegistrationUploadController` — tarball upload with secure extraction | | Resolver | `MarketplaceResolver` — simplified `installMarketplaceApp` (removed redundant `sourcePackage` arg) | | Security | `.yarnrc.yml` — `enableScripts: false` to block postinstall RCE | ## Frontend changes | Area | Files | |------|-------| | Modals | `SettingsInstallNpmAppModal`, `SettingsUploadTarballModal`, `SettingsAppModalLayout` | | Hooks | `useUploadAppTarball`, `useInstallMarketplaceApp` (cleaned up) | | Upgrade UI | `SettingsApplicationVersionContainer`, `SettingsApplicationDetailAboutTab` | | Badge | `SettingsApplicationTableRow` — blue "Update" tag, `SettingsApplicationsInstalledTab` — fetches registrations for version comparison | | Styling | Migrated to Linaria (matching main) | ## Test plan - [ ] Install an app from npm via the "Install from npm" modal - [ ] Upload a `.tar.gz` tarball via the "Upload tarball" modal - [ ] Verify upgrade badge appears when `latestAvailableVersion > version` - [ ] Verify upgrade flow from app detail page - [ ] Run integration tests: `app-distribution.integration-spec.ts`, `marketplace-catalog-sync.integration-spec.ts` - [ ] Verify `enableScripts: false` blocks postinstall scripts during yarn install Made with [Cursor](https://cursor.com) |
||
|
|
bfa50f566e |
Bump @clickhouse/client from 1.11.0 to 1.18.1 (#18410)
Bumps [@clickhouse/client](https://github.com/ClickHouse/clickhouse-js) from 1.11.0 to 1.18.1. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/ClickHouse/clickhouse-js/releases"><code>@clickhouse/client</code>'s releases</a>.</em></p> <blockquote> <h2>1.18.1</h2> <h2>Improvements</h2> <ul> <li>Setting <code>log.level</code> default value to <code>ClickHouseLogLevel.WARN</code> instead of <code>ClickHouseLogLevel.OFF</code> to provide better visibility into potential issues without overwhelming users with too much information by default.</li> </ul> <pre lang="ts"><code>const client = createClient({ // ... log: { level: ClickHouseLogLevel.WARN, // default is now ClickHouseLogLevel.WARN instead of ClickHouseLogLevel.OFF }, }) </code></pre> <ul> <li>Logging is now lazy, which means that the log messages will only be constructed if the log level is appropriate for the message. This can improve performance in cases where constructing the log message is expensive, and the log level is set to ignore such messages. See <code>ClickHouseLogLevel</code> enum for the complete list of log levels. (<a href="https://redirect.github.com/ClickHouse/clickhouse-js/issues/520">#520</a>)</li> </ul> <pre lang="ts"><code>const client = createClient({ // ... log: { level: ClickHouseLogLevel.TRACE, // to log everything available down to the network level events }, }) </code></pre> <ul> <li>Enhanced the logging of the HTTP request / socket lifecycle with additional trace messages and context such as Connection ID (UUID) and Request ID and Socket ID that embed the connection ID for ease of tracing the logs of a particular request across the connection lifecycle. To enable such logs, set the <code>log.level</code> config option to <code>ClickHouseLogLevel.TRACE</code>. (<a href="https://redirect.github.com/ClickHouse/clickhouse-js/issues/567">#567</a>)</li> </ul> <pre lang="console"><code>[2026-02-25T09:19:13.511Z][TRACE][@clickhouse/client][Connection] Insert: received 'close' event, 'free' listener removed Arguments: { operation: 'Insert', connection_id: 'da3c9796-5dc5-46ef-83b0-ed1f4422094c', query_id: '9dfda627-39a2-41a6-9fc9-8f8716574826', request_id: 'da3c9796-5dc5-46ef-83b0-ed1f4422094c:3', socket_id: 'da3c9796-5dc5-46ef-83b0-ed1f4422094c:2', event: 'close' } [2026-02-25T09:19:13.502Z][TRACE][@clickhouse/client][Connection] Query: reusing socket Arguments: { operation: 'Query', connection_id: 'da3c9796-5dc5-46ef-83b0-ed1f4422094c', query_id: 'ad0127e8-b1c7-4ed6-9681-c0162f7a0ea9', request_id: 'da3c9796-5dc5-46ef-83b0-ed1f4422094c:4', socket_id: 'da3c9796-5dc5-46ef-83b0-ed1f4422094c:2', usage_count: 1 } </code></pre> <ul> <li>A step towards structured logging: the client now passes rich context to the logger <code>args</code> parameter (e.g. <code>connection_id</code>, <code>query_id</code>, <code>request_id</code>, <code>socket_id</code>). (<a href="https://redirect.github.com/ClickHouse/clickhouse-js/issues/576">#576</a>)</li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/ClickHouse/clickhouse-js/blob/main/CHANGELOG.md"><code>@clickhouse/client</code>'s changelog</a>.</em></p> <blockquote> <h1>1.18.1</h1> <h2>Improvements</h2> <ul> <li>Setting <code>log.level</code> default value to <code>ClickHouseLogLevel.WARN</code> instead of <code>ClickHouseLogLevel.OFF</code> to provide better visibility into potential issues without overwhelming users with too much information by default.</li> </ul> <pre lang="ts"><code>const client = createClient({ // ... log: { level: ClickHouseLogLevel.WARN, // default is now ClickHouseLogLevel.WARN instead of ClickHouseLogLevel.OFF }, }) </code></pre> <ul> <li>Logging is now lazy, which means that the log messages will only be constructed if the log level is appropriate for the message. This can improve performance in cases where constructing the log message is expensive, and the log level is set to ignore such messages. See <code>ClickHouseLogLevel</code> enum for the complete list of log levels. (<a href="https://redirect.github.com/ClickHouse/clickhouse-js/issues/520">#520</a>)</li> </ul> <pre lang="ts"><code>const client = createClient({ // ... log: { level: ClickHouseLogLevel.TRACE, // to log everything available down to the network level events }, }) </code></pre> <ul> <li>Enhanced the logging of the HTTP request / socket lifecycle with additional trace messages and context such as Connection ID (UUID) and Request ID and Socket ID that embed the connection ID for ease of tracing the logs of a particular request across the connection lifecycle. To enable such logs, set the <code>log.level</code> config option to <code>ClickHouseLogLevel.TRACE</code>. (<a href="https://redirect.github.com/ClickHouse/clickhouse-js/issues/567">#567</a>)</li> </ul> <pre lang="console"><code>[2026-02-25T09:19:13.511Z][TRACE][@clickhouse/client][Connection] Insert: received 'close' event, 'free' listener removed Arguments: { operation: 'Insert', connection_id: 'da3c9796-5dc5-46ef-83b0-ed1f4422094c', query_id: '9dfda627-39a2-41a6-9fc9-8f8716574826', request_id: 'da3c9796-5dc5-46ef-83b0-ed1f4422094c:3', socket_id: 'da3c9796-5dc5-46ef-83b0-ed1f4422094c:2', event: 'close' } [2026-02-25T09:19:13.502Z][TRACE][@clickhouse/client][Connection] Query: reusing socket Arguments: { operation: 'Query', connection_id: 'da3c9796-5dc5-46ef-83b0-ed1f4422094c', query_id: 'ad0127e8-b1c7-4ed6-9681-c0162f7a0ea9', request_id: 'da3c9796-5dc5-46ef-83b0-ed1f4422094c:4', socket_id: 'da3c9796-5dc5-46ef-83b0-ed1f4422094c:2', usage_count: 1 } </code></pre> <ul> <li>A step towards structured logging: the client now passes rich context to the logger <code>args</code> parameter (e.g. <code>connection_id</code>, <code>query_id</code>, <code>request_id</code>, <code>socket_id</code>). (<a href="https://redirect.github.com/ClickHouse/clickhouse-js/issues/576">#576</a>)</li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/ClickHouse/clickhouse-js/commit/cbdd7bf20904626956e0ff7808d17015813400c1"><code>cbdd7bf</code></a> Release 1.18.1 (<a href="https://redirect.github.com/ClickHouse/clickhouse-js/issues/590">#590</a>)</li> <li><a href="https://github.com/ClickHouse/clickhouse-js/commit/c9f61ebb3a2ec6201f87417e30c4fc4271451ae8"><code>c9f61eb</code></a> Beta 1.18.0 (<a href="https://redirect.github.com/ClickHouse/clickhouse-js/issues/588">#588</a>)</li> <li><a href="https://github.com/ClickHouse/clickhouse-js/commit/d0f67b71ef896d47fc3d8d0942612ced22aa79dc"><code>d0f67b7</code></a> Split public and internal <code>drainStream</code> and cover with tests (<a href="https://redirect.github.com/ClickHouse/clickhouse-js/issues/578">#578</a>)</li> <li><a href="https://github.com/ClickHouse/clickhouse-js/commit/535e9b726e328ce8468c159f935c27910731f4bb"><code>535e9b7</code></a> Remove <code>unsafeLogUnredactedQueries</code> for now (<a href="https://redirect.github.com/ClickHouse/clickhouse-js/issues/580">#580</a>)</li> <li><a href="https://github.com/ClickHouse/clickhouse-js/commit/44e73c73019a3956c1fac67ce0f4f170b3a4f19a"><code>44e73c7</code></a> Default log level to <code>WARN</code> (<a href="https://redirect.github.com/ClickHouse/clickhouse-js/issues/581">#581</a>)</li> <li><a href="https://github.com/ClickHouse/clickhouse-js/commit/5146fbc13e5c23d08e2cc5773bea0adf58d83a5c"><code>5146fbc</code></a> Focus AI on security and API stability (<a href="https://redirect.github.com/ClickHouse/clickhouse-js/issues/579">#579</a>)</li> <li><a href="https://github.com/ClickHouse/clickhouse-js/commit/b7b1d8d7ffe9b6786c9e883379d3edc5a5ed5c58"><code>b7b1d8d</code></a> Trivial E2E test against <code>beta</code> (<a href="https://redirect.github.com/ClickHouse/clickhouse-js/issues/577">#577</a>)</li> <li><a href="https://github.com/ClickHouse/clickhouse-js/commit/761e29ebb5d1bd7a107d2535b385b6565b7120f5"><code>761e29e</code></a> Structured logs, part 1 (<a href="https://redirect.github.com/ClickHouse/clickhouse-js/issues/576">#576</a>)</li> <li><a href="https://github.com/ClickHouse/clickhouse-js/commit/fd23dd7fc9e91ff810a7bb45984a24682ba25482"><code>fd23dd7</code></a> Provide more context in logs for connection and request handling (<a href="https://redirect.github.com/ClickHouse/clickhouse-js/issues/567">#567</a>)</li> <li><a href="https://github.com/ClickHouse/clickhouse-js/commit/a7866e72e356244cae9d20d9fef38a6aafe68ba8"><code>a7866e7</code></a> Adjusting CI DevX (<a href="https://redirect.github.com/ClickHouse/clickhouse-js/issues/574">#574</a>)</li> <li>Additional commits viewable in <a href="https://github.com/ClickHouse/clickhouse-js/compare/1.11.0...1.18.1">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/~4b819b88c84b">4b819b88c84b</a>, a new releaser for <code>@clickhouse/client</code> 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> Co-authored-by: Abdullah <125115953+mabdullahabaid@users.noreply.github.com> |
||
|
|
6a2e0182ab |
Bump @blocknote/server-util from 0.47.0 to 0.47.1 (#18408)
Bumps [@blocknote/server-util](https://github.com/TypeCellOS/BlockNote/tree/HEAD/packages/server-util) from 0.47.0 to 0.47.1. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/TypeCellOS/BlockNote/releases"><code>@blocknote/server-util</code>'s releases</a>.</em></p> <blockquote> <h2>v0.47.1</h2> <h2>0.47.1 (2026-03-02)</h2> <h3>🩹 Fixes</h3> <ul> <li>typeerror cannot read properties of undefined (<a href="https://redirect.github.com/TypeCellOS/BlockNote/pull/2522">#2522</a>)</li> <li>handle more delete key cases (<a href="https://redirect.github.com/TypeCellOS/BlockNote/pull/2126">#2126</a>)</li> <li>add delay for <code>data-active</code> in collab cursors (<a href="https://redirect.github.com/TypeCellOS/BlockNote/pull/2383">#2383</a>)</li> <li>disable slash menu in table content <a href="https://github.com/TypeCellOS/BlockNote/tree/HEAD/packages/server-util/issues/2408">#2408</a> (<a href="https://redirect.github.com/TypeCellOS/BlockNote/pull/2504">#2504</a>, <a href="https://redirect.github.com/TypeCellOS/BlockNote/issues/2408">#2408</a>)</li> <li><strong>ai:</strong> selections broken due to floating-ui focus manager (<a href="https://redirect.github.com/TypeCellOS/BlockNote/pull/2527">#2527</a>)</li> </ul> <h3>❤️ Thank You</h3> <ul> <li>Matthew Lipski <a href="https://github.com/matthewlipski"><code>@matthewlipski</code></a></li> <li>Nick Perez</li> <li>Yousef</li> </ul> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/TypeCellOS/BlockNote/blob/main/CHANGELOG.md"><code>@blocknote/server-util</code>'s changelog</a>.</em></p> <blockquote> <h2>0.47.1 (2026-03-02)</h2> <h3>🩹 Fixes</h3> <ul> <li>typeerror cannot read properties of undefined (<a href="https://redirect.github.com/TypeCellOS/BlockNote/pull/2522">#2522</a>)</li> <li>handle more delete key cases (<a href="https://redirect.github.com/TypeCellOS/BlockNote/pull/2126">#2126</a>)</li> <li>add delay for <code>data-active</code> in collab cursors (<a href="https://redirect.github.com/TypeCellOS/BlockNote/pull/2383">#2383</a>)</li> <li>disable slash menu in table content <a href="https://github.com/TypeCellOS/BlockNote/tree/HEAD/packages/server-util/issues/2408">#2408</a> (<a href="https://redirect.github.com/TypeCellOS/BlockNote/pull/2504">#2504</a>, <a href="https://redirect.github.com/TypeCellOS/BlockNote/issues/2408">#2408</a>)</li> <li><strong>ai:</strong> selections broken due to floating-ui focus manager (<a href="https://redirect.github.com/TypeCellOS/BlockNote/pull/2527">#2527</a>)</li> </ul> <h3>❤️ Thank You</h3> <ul> <li>Matthew Lipski <a href="https://github.com/matthewlipski"><code>@matthewlipski</code></a></li> <li>Nick Perez</li> <li>Yousef</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/TypeCellOS/BlockNote/commit/d5d056fe3d5362e73fb72e3e3bf1f839aee3e875"><code>d5d056f</code></a> chore(release): publish 0.47.1</li> <li>See full diff in <a href="https://github.com/TypeCellOS/BlockNote/commits/v0.47.1/packages/server-util">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> |
||
|
|
72086fe111 |
Bump @dagrejs/dagre from 1.1.3 to 1.1.8 (#18409)
Bumps [@dagrejs/dagre](https://github.com/dagrejs/dagre) from 1.1.3 to 1.1.8. <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/dagrejs/dagre/commit/7e4d15f191678f7f05f3c86d9071a193230e7e00"><code>7e4d15f</code></a> Building for release</li> <li><a href="https://github.com/dagrejs/dagre/commit/d3908e2c13148c9143db585accc10ae0b6634657"><code>d3908e2</code></a> Bumping version</li> <li><a href="https://github.com/dagrejs/dagre/commit/ce295f8e073c4fe96c9e36ecf08ae2940e5e6a10"><code>ce295f8</code></a> Build for release</li> <li><a href="https://github.com/dagrejs/dagre/commit/b64b9057726eee17f24f73579ba0668527276448"><code>b64b905</code></a> Bumping the version</li> <li><a href="https://github.com/dagrejs/dagre/commit/de169d24c13d06c1e9c560f4f4f8f98650109b94"><code>de169d2</code></a> Merge pull request <a href="https://redirect.github.com/dagrejs/dagre/issues/481">#481</a> from Nathan-Fenner/nf/improve-network-simplex-perform...</li> <li><a href="https://github.com/dagrejs/dagre/commit/065e0d8374f4c1c35a7cb4b84df37aaa31598d86"><code>065e0d8</code></a> improve performance of graph node ranking</li> <li><a href="https://github.com/dagrejs/dagre/commit/00d3178d671e49de9c032e3abd281dc9f2739e73"><code>00d3178</code></a> Typo</li> <li><a href="https://github.com/dagrejs/dagre/commit/3982a69d2b323b06aa969a4ec09829d37fe6e7bd"><code>3982a69</code></a> Bump version and set as pre-release</li> <li><a href="https://github.com/dagrejs/dagre/commit/1339f5516508dba0cbcc4ef1c0587e7384bec23d"><code>1339f55</code></a> Building for release</li> <li><a href="https://github.com/dagrejs/dagre/commit/9459f01bc815f16b87db727821d8401acbad2cd3"><code>9459f01</code></a> Bumping the version</li> <li>Additional commits viewable in <a href="https://github.com/dagrejs/dagre/compare/v1.1.3...v1.1.8">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> |
||
|
|
4c001778c2 |
fix google signup edge case (#18365)
Fixes an edge case when a user signs up with Google and the profile avatar network request times out, we crash instead of creating the user without an avatar. Added `axios-retry` to retry max 2 times and if it still fails we gracefully skip avatar image instead of crashing Fixes Sentry TWENTY-SERVER-FDQ Sonarly https://sonarly.com/issue/6564 --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: Charles Bochet <charles@twenty.com> Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> |
||
|
|
225f185278 |
fix: fast-xml-parser has stack overflow in XMLBuilder with preserve order (#18375)
Resolves [Dependabot Alert 551](https://github.com/twentyhq/twenty/security/dependabot/551). |
||
|
|
2f9c94d9a0 |
fix: upgrade nestjs dependencies to upgrade multer transitive import (#18374)
Resolves [Dependabot Alert 549](https://github.com/twentyhq/twenty/security/dependabot/549) and [Dependabot Alert 550](https://github.com/twentyhq/twenty/security/dependabot/550). |
||
|
|
4ed09a3feb |
Upgrade blocknote dependencies from 0.31.1 to 0.47.0. (#18207)
This PR pgrades all BlockNote packages (@blocknote/core, @blocknote/react, @blocknote/mantine, @blocknote/server-util, @blocknote/xl-docx-exporter, @blocknote/xl-pdf-exporter) to 0.47.0 and adapts the codebase to the new API. ### Changes - Dependency upgrades: Bumped all BlockNote packages to 0.47.0, added required Mantine v8 peer dependencies, removed unnecessary prosemirror resolutions - Formatting toolbar: Replaced the manual reimplementation of FormattingToolbarController (which handled visibility, positioning, portal rendering, text-alignment-based placement, and a dangerouslySetInnerHTML transition trick) with BlockNote's built-in FormattingToolbarController. The toolbar buttons themselves are unchanged. - Side menu: Replaced manual drag handle menu positioning and rendering (DashboardBlockDragHandleMenu, DashboardBlockColorPicker, and their floating configs) with BlockNote's built-in SideMenuController, DragHandleButton, and DragHandleMenu components. Deleted 4 files that became dead code. - Extension API migration: Replaced deprecated editor.suggestionMenus and editor.formattingToolbar APIs with the new extension system (SuggestionMenu, useExtensionState, editor.getExtension()) - Slash menu fixes: Filtered out BlockNote's new default "File" item (added in 0.47) to avoid duplicates with our custom one; added icon mappings for new block types (Toggle List, Divider, Toggle Headings, Headings 4-6) - Server-side: Switched @blocknote/server-util to dynamic import() to handle ESM-only transitive dependencies in CJS context |
||
|
|
cbb0f212cf |
fix: fast-xml-parser related dependabot alerts (#18241)
Resolves [Dependabot Alert 459](https://github.com/twentyhq/twenty/security/dependabot/459) and [Dependabot Alert 483](https://github.com/twentyhq/twenty/security/dependabot/483). Upgraded AWS SDKs pulling in fast-xml-parser as transitive dependency. |
||
|
|
9107f5bbc7 |
feat: upgrade ai package to version six and the corresponding @ai-sdk/* packages to compatible versions (#18172)
Used the migration guide to carry out this upgrade: https://ai-sdk.dev/docs/migration-guides/migration-guide-6-0 I have not been able to test locally due to credits. <img width="220" height="450" alt="image" src="https://github.com/user-attachments/assets/050b34b9-3239-4010-8c47-b43d44571994" /> --------- Co-authored-by: Félix Malfait <felix.malfait@gmail.com> |
||
|
|
41f09c5a4c |
Add AI model pricing, Bedrock provider, and InferenceProvider/ModelFamily split (#18155)
## Summary - **Model pricing overhaul**: All model constants updated with accurate pricing in dollars per 1M tokens, including cached input rates, cache creation rates, and tiered >200k context pricing - **New providers**: Added Google (Gemini 3.x), Mistral, and AWS Bedrock as inference providers. Bedrock serves Claude Opus 4.6 and Sonnet 4.6 via AWS, with proper credential handling following the existing S3/SES pattern - **InferenceProvider/ModelFamily split**: Refactored `ModelProvider` into two orthogonal enums — `InferenceProvider` (who serves the model: auth, SDK, metadata format) and `ModelFamily` (who created it: token counting semantics). This eliminates growing `||` chains for token normalization checks like `excludesCachedTokens` - **Billing improvements**: Reasoning tokens charged at output rate, cache token discounts applied accurately, real errors thrown to Sentry on billing failures ## Test plan - [x] All existing unit tests updated and passing (23 tests across 3 test files) - [x] Lint passes for both twenty-server and twenty-front - [ ] CI checks pass Made with [Cursor](https://cursor.com) --------- Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
d0c1841f0f |
File - Migrate avatarUrl > avatarFile on person (data migration + logic) + Attachment data migration (#17752)
- Migration command
- Check IS_FILES_FIELD_MIGRATED:false
- Check or create avatarFile field
- Fetch all people with avatarUrl
- Move (Copy/move) file in storage
- Create core.file record
- Update person record
- bonus : attachment migration : fullPath > file (same logic)
- BE logic
- Add avatarFile field on person
- FE logic
- Adapt logic to upload on/display avatarFile data
The whole imageIdentifier logic will be done later
|
||
|
|
a40612ef9e |
fix: axios related dependabot alerts (#17821)
Resolves [Dependabot Alert 436](https://github.com/twentyhq/twenty/security/dependabot/436), [Dependabot Alert 437](https://github.com/twentyhq/twenty/security/dependabot/437) and [Dependabot Alert 438](https://github.com/twentyhq/twenty/security/dependabot/438). |
||
|
|
3216b634a3 |
feat: improve AI chat - system prompt, tool output, context window display (#17769)
⚠️ **AI-generated PR — not ready for review** ⚠️ cc @FelixMalfait --- ## Changes ### System prompt improvements - Explicit skill-before-tools workflow to prevent the model from calling tools without loading the matching skill first - Data efficiency guidance (default small limits, use filters) - Pluralized `load_skill` → `load_skills` for consistency with `load_tools` ### Token usage reduction - Output serialization layer: strips null/undefined/empty values from tool results - Lowered default `find_*` limit from 100 → 10, max from 1000 → 100 ### System object tool generation - System objects (calendar events, messages, etc.) now generate AI tools - Only workflow-related and favorite-related objects are excluded ### Context window display fix - **Bug**: UI compared cumulative tokens (sum of all turns) against single-request context window → showed 100% after a few turns - **Fix**: Track `conversationSize` (last step's `inputTokens`) which represents the actual conversation history size sent to the model - New `conversationSize` column on thread entity with migration ### Workspace AI instructions - Support for custom workspace-level AI instructions --------- Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> |
||
|
|
6c7c389785 |
fix: webpack related dependabot alerts (#17792)
Resolves [Dependabot Alert 422](https://github.com/twentyhq/twenty/security/dependabot/422) and [Dependabot Alert 423](https://github.com/twentyhq/twenty/security/dependabot/423). |
||
|
|
7402edb887 |
Remove unused GraphQL throttler plugin and graphql-rate-limit dependency (#17785)
## Summary - Deletes `use-throttler.ts` — an envelop plugin that was never registered in the GraphQL config plugin chain (dead code since introduction) - Removes the `graphql-rate-limit` dependency from `package.json` (only consumer was the deleted file) API rate limiting continues to work via `ThrottlerService` in the query runner layer (for API key auth). Global coverage should be handled at the infrastructure level (Cloudflare). ## Test plan - [x] Confirmed no imports of `useThrottler`, `ThrottlerPluginOptions`, or `UnauthenticatedError` from this file exist anywhere in the codebase - [x] `graphql-rate-limit` has no other consumers Made with [Cursor](https://cursor.com) Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
60f2a74bf0 |
fix: fast-xml-parser has rangeerror dos numeric entities bug (#17732)
Resolves [Dependabot Alert 412](https://github.com/twentyhq/twenty/security/dependabot/412). AWS SDK minor-releases are backward compatible. |