Commit Graph

1174 Commits

Author SHA1 Message Date
Thomas Trompette 3ad7a9ac94 App logic function as step (#17525)
- Add logic function as step
- Rename previous one as Code

<img width="494" height="573" alt="Capture d’écran 2026-01-28 à 16 15
29"
src="https://github.com/user-attachments/assets/82f7e720-20da-4926-b5bc-94a33cd1f53a"
/>
<img width="494" height="264" alt="Capture d’écran 2026-01-28 à 16 15
39"
src="https://github.com/user-attachments/assets/a0444ae9-8c50-418d-8c5f-68c4da08fce7"
/>
<img width="494" height="264" alt="Capture d’écran 2026-01-28 à 16 15
58"
src="https://github.com/user-attachments/assets/3025db09-4e59-421e-8dc5-f3a7a7326554"
/>

---------

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-01-29 11:59:24 +01:00
Weiko fc908e9d87 Refactor WorkspaceAuthContext to use discriminated union types (#17491)
## Context
The previous WorkspaceAuthContext was a single interface with many
optional fields, making it unclear which fields are available in
different authentication scenarios. This made the code harder to reason
about and required runtime checks scattered throughout the codebase.

## Changes
- Introduced a discriminated union type for WorkspaceAuthContext with
four specific variants:
-> UserWorkspaceAuthContext - for authenticated users
-> ApiKeyWorkspaceAuthContext - for API key authentication
-> ApplicationWorkspaceAuthContext - for application-based auth
-> SystemWorkspaceAuthContext - for system/internal operations
- Added type guard functions (isUserAuthContext, isApiKeyAuthContext,
etc.) for safe type narrowing
- Added builder utilities (buildUserAuthContext, buildApiKeyAuthContext,
etc.) to construct each context variant with proper type safety
- Refactored WorkspaceAuthContextMiddleware to use the new builders
instead of constructing a loosely-typed object
- Moved the type definition from twenty-orm/interfaces/ to
core-modules/auth/types/ for better organization
- Updated all consumers across query runners, tool providers, and
modules to use the new type location


## Notes
- I had to query User and WorkspaceMember in some parts of tool module
that were expecting userWorkspaceId but not the rest of
UserWorkspaceAuthContext (that should be required with the new proper
type otherwise it would break a lot of logic and mostly permissions with
the newly added RLS -> This is what we expect from
UserWorkspaceAuthContext and how it's done in the "normal" path in HTTP
middleware)
- WorkspaceMember is in the cache already but ideally we should move
User (And Workspace?) in the cache as well to avoid querying the DB
after each request (this is also valid for HTTP middleware when we
hydrate the Request object btw)
2026-01-28 17:50:42 +00:00
Paul Rastoin fe9d6f34ff [REQUIRES_FULL_CACHE_FLUSH_WHEN_RELEASED] Refactor FlatEntity to be UniversalFlatEntity superset (#17452)
# Introduction
In this PR we're refactoring the `FlatEntity` type to become a superset
of the `UniversalFlatEntity`.
Right now we're storing all the extra properties in `__universal`
property, at some point it might just be sibling to other entity and we
might rely on the `propertiesToCompare` constants and TypeScript
allowing passing a superset type into a smaller subset type

## FromTo utils
The entity to flat entity method now computes the universal information,
standardized a typing and pattern to do

## Example
Also strictly type
```ts
    "bbb019ea-6205-498c-aea5-67bc53bce8a9": {
      "workspaceId": "20202020-1c25-4d02-bf25-6aeccf7ea419",
      "universalIdentifier": "20202020-d111-4d11-8d11-da5ab0a11002",
      "applicationId": "d01b010d-b984-465b-b40b-370e954e5188",
      "id": "bbb019ea-6205-498c-aea5-67bc53bce8a9",
      "pageLayoutTabId": "791a512f-169f-4209-b731-aa86716668c6",
      "title": "Deals by Company",
      "type": "GRAPH",
      "objectMetadataId": "9e14efea-df5b-4c0e-aba9-cfe455f32397",
      "gridPosition": { "row": 0, "column": 6, "rowSpan": 6, "columnSpan": 6 },
      "configuration": {
        "color": "orange",
        "orderBy": "FIELD_ASC",
        "timezone": "UTC",
        "displayLegend": true,
        "displayDataLabel": false,
        "showCenterMetric": true,
        "configurationType": "PIE_CHART",
        "firstDayOfTheWeek": 0,
        "aggregateOperation": "COUNT",
        "groupBySubFieldName": "name",
        "groupByFieldMetadataId": "6673ff18-63d2-47a1-8f85-2b9b09ca27a5",
        "aggregateFieldMetadataId": "8d64ee41-5dd4-4de6-945a-7c0c18399715"
      },
      "createdAt": "2026-01-28T14:08:52.140Z",
      "updatedAt": "2026-01-28T14:08:52.140Z",
      "deletedAt": null,
      "__universal": {
        "universalIdentifier": "20202020-d111-4d11-8d11-da5ab0a11002",
        "applicationUniversalIdentifier": "20202020-64aa-4b6f-b003-9c74b97cee20",
        "pageLayoutTabUniversalIdentifier": "20202020-d011-4d11-8d11-da5ab0a01001",
        "objectMetadataUniversalIdentifier": "20202020-9549-49dd-b2b2-883999db8938",
        "gridPosition": {
          "row": 0,
          "column": 6,
          "rowSpan": 6,
          "columnSpan": 6
        },
        "configuration": {
          "color": "orange",
          "orderBy": "FIELD_ASC",
          "timezone": "UTC",
          "displayLegend": true,
          "displayDataLabel": false,
          "showCenterMetric": true,
          "configurationType": "PIE_CHART",
          "firstDayOfTheWeek": 0,
          "aggregateOperation": "COUNT",
          "groupBySubFieldName": "name",
          "aggregateFieldMetadataUniversalIdentifier": "20202020-d01a-4131-8a31-f123456789ab",
          "groupByFieldMetadataUniversalIdentifier": "20202020-cbac-457e-b565-adece5fc815f"
        }
      }
    },
```
2026-01-28 16:46:34 +00:00
neo773 7d64ee85ac Clean up and enhance logging for messaging and calendar (#17498)
This PR reduces noise to signal ratio for messaging and calendar logging
in production
Impact would be faster queries and debugging
2026-01-28 01:46:25 +01:00
Charles Bochet da6f1bbef3 Rename serverlessFunction to logicFunction (#17494)
## Summary

Rename "Serverless Function" to "Logic Function" across the codebase for
clearer naming.

### Environment Variable Changes

| Old | New |
|-----|-----|
| `SERVERLESS_TYPE` | `LOGIC_FUNCTION_TYPE` |
| `SERVERLESS_LAMBDA_REGION` | `LOGIC_FUNCTION_LAMBDA_REGION` |
| `SERVERLESS_LAMBDA_ROLE` | `LOGIC_FUNCTION_LAMBDA_ROLE` |
| `SERVERLESS_LAMBDA_SUBHOSTING_URL` |
`LOGIC_FUNCTION_LAMBDA_SUBHOSTING_URL` |
| `SERVERLESS_LAMBDA_ACCESS_KEY_ID` |
`LOGIC_FUNCTION_LAMBDA_ACCESS_KEY_ID` |
| `SERVERLESS_LAMBDA_SECRET_ACCESS_KEY` |
`LOGIC_FUNCTION_LAMBDA_SECRET_ACCESS_KEY` |

### Breaking Changes

- Environment variables must be updated in production deployments
- Database migration renames `serverlessFunction` → `logicFunction`
tables
2026-01-28 01:42:19 +01:00
neo773 8fb8b5d2f1 fix message channels stuck in ONGOING (#17492)
`markAsMessagesListFetchOngoing()` was missing `syncStageStartedAt`
causing stuck channels to be never recovered.

Regression was caused by commit
[68a9ef57f0](https://github.com/twentyhq/twenty/commit/68a9ef57f0)
2026-01-27 20:23:29 +00:00
Charles Bochet a4499d21bb Migrate cron, databaseEventTrigger, httpRoute triggers to serverless functions (#17488)
## Summary

Migrates trigger entities (`CronTriggerEntity`,
`DatabaseEventTriggerEntity`, `RouteTriggerEntity`) into
`ServerlessFunctionEntity` by storing trigger settings as JSONB columns
directly on the serverless function. This simplifies the architecture
since these relationships were effectively one-to-one.

## Changes

### Schema Changes
- Added three new nullable JSONB columns to `ServerlessFunctionEntity`:
  - `cronTriggerSettings` - stores cron pattern
- `databaseEventTriggerSettings` - stores event name and updated fields
filter
- `httpRouteTriggerSettings` - stores path, HTTP method, auth
requirements, and forwarded headers

### Core Logic Updates
- `CronTriggerCronJob` - now queries `ServerlessFunctionEntity` directly
instead of `CronTriggerEntity`
- `CallDatabaseEventTriggerJobsJob` - now queries
`ServerlessFunctionEntity` directly
- `RouteTriggerService` - now queries `ServerlessFunctionEntity`
directly
- `ApplicationSyncService` - extracts trigger settings from manifest and
writes to serverless function
2026-01-27 20:54:09 +01:00
Weiko 2daebc6d0f Add WorkspaceAuthContextMiddleware (#17487)
## Context
Introduces a middleware that automatically sets the workspace auth
context in AsyncLocalStorage for HTTP requests, making it available
throughout the request lifecycle without explicit parameter passing.

The motivation behind this change is to reduce boilerplate and simplify
the developer experience when working with workspace data in HTTP
request handlers.

The Problem (Before)
Every HTTP request handler that needed to access workspace data had to:
- Extract auth-related info from decorators (@AuthWorkspace(),
@AuthUserWorkspaceId(), etc.) in controller/resolver and pass down to
services
- Build or pass the authContext explicitly (sometimes with type
assertion which was flaky)
Then call executeInWorkspaceContext(authContext, async () => { ... })

## Changes
- Add WorkspaceAuthContextMiddleware that extracts auth context from the
request and stores it in AsyncLocalStorage
- Register middleware for GraphQL, metadata, and REST routes (runs after
hydration middlewares)
- Simplify executeInWorkspaceContext signature: fn is now the first
parameter, authContext is optional second
- If authContext is not provided, it's automatically retrieved from the
storage (set by middleware)
- Update all callers (~120 files) to use the new parameter order


- Fixes a bug in search where system auth context was used, bypassing
RLS feature.
2026-01-27 17:24:51 +00:00
neo773 ae1151cf5d IMAP fix edge case of nested folder filtering of unwanted folders (#17428)
Fixes this edge case I saw on a customer's account, where INBOX was the
parent folder of standard folders

<img width="580" height="634" alt="edge case folders"
src="https://github.com/user-attachments/assets/c715e5c6-8d37-45a8-a962-16da2bf38ced"
/>
2026-01-26 17:14:26 +00:00
Paul Rastoin d0bc9a94c0 [OBJECT_CACHE_FLUSH_REQUIRED_WHEN_RELEASED] Remove FlatObjectMetadata custom fieldMetadataIds fk aggregator property (#17438)
# Introduction
Currently refactoring `flatEntity` typing, encountering some tsc errors
due to this fk aggregator custom override
It shall now follow generic pattern leading to be named `fieldIds`

Needs to flush object cache when released
2026-01-26 13:33:07 +00:00
Abdullah. fa0615d41e Migrate attachments to morph relations + fix morph join column filtering (#17381)
Closes [1744](https://github.com/twentyhq/core-team-issues/issues/1744).

This PR migrates attachments to morph relations behind a feature flag,
following the TimelineActivity pattern. it introduces the
`IS_ATTACHMENT_MIGRATED` flag, updates standard field metadata and
indexes to use morph relations, adds a workspace migration that renames
`attachment.*Id` columns to `target*Id` and converts the corresponding
field metadata to `MORPH_RELATION` with a shared `morphId`. On the
frontend, attachment read/write paths now switch to `target*Id` when the
flag is enabled.

It also fixes optimistic filtering for morph join columns. The metadata
API deduplicates morph fields, so attachments now expose a single target
field of type `MORPH_RELATION` plus a `morphRelations` array listing
each target object. Because only one `settings.joinColumnName` is
returned (e.g. `targetRocketId`), filters like `targetCompanyId` don’t
map to any field and the optimistic cache code throws.
`doesMorphRelationJoinColumnMatch` resolves this by computing all valid
join column names from `morphRelations` using
`computeMorphRelationFieldName` and comparing them to the filter key.
That makes filters like `targetCompanyId` resolvable even with a single
target field, so attachment uploads and list matching no longer crash.

<img width="477" height="474" alt="image"
src="https://github.com/user-attachments/assets/50e19418-3438-4d1e-9f1f-1bc1a03174a9"
/>

<br />
<br />

Today the metadata API returns one morph field called `target` and a
list of possible targets (`morphRelations`), but it does not tell us the
join column for each target. That’s why the Frontend had to compute join
column names.

If we want to fix this at the API level, there are two options:

- Add join column names to each target in `morphRelations` (e.g. company
→ `targetCompanyId`). This is additive and low‑risk.
- Return each target as its own field (`targetCompany`, `targetPerson`,
etc.) instead of a single target. This is a larger change because it
changes the shape of metadata and would require more UI updates.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Introduces morph relations for attachments behind
`IS_ATTACHMENT_MIGRATED`, aligning server schema/metadata and frontend
behavior.
> 
> - Adds `IS_ATTACHMENT_MIGRATED` flag (frontend/server) and
seeds/defaults; updates generated GraphQL enums
> - New workspace upgrade `1.17` command migrates data: renames
`attachment.*Id` → `target*Id` and converts related fields to
`MORPH_RELATION` with shared `morphId`
> - Updates standard field metadata and indexes to `target*` (attachment
+ related objects), dev seeds, snapshots, and workspace entity types
> - Frontend: switches attachment read/write filters via
`getActivityTargetObjectFieldIdName` using the feature flag; updates
hooks/components (`useAttachments`, `useUploadAttachmentFile`, editors);
expands `Attachment` type
> - Fixes optimistic cache filtering to recognize morph join columns in
`isRecordMatchingFilter` by computing valid join-column keys from
`morphRelations`
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
f208fa23b1135af114f484f6d65041a816d6e718. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
2026-01-24 21:17:24 +00:00
Lucas Bordeau 9ecab8fb82 Fix event logic for soft-delete and restore (#17393)
This PR changes the shape and logic of SSE events `DELETE` and
`RESTORE`, because they behave like `UPDATE` events in practice, they
should share the same logic.

Before this PR, it was impossible for the frontend to obtain the
`deletedAt` value, and the logic to handle soft-delete and restore would
have been flawed.

Because there is a typing confusion in the parameters of
`formatTwentyOrmEventToDatabaseBatchEvent`, due to TypeORM, we also
update this util to only accept an array of records, instead of `T |
T[]`. We should improve our TypeORM layer in the future.

Also the naming was not clear, so we clearly use `recordsAfter` and
`recordsBefore` as much as possible, because that is what we have at the
end in events.

Events are sent from their respective query builders, so these last ones
have been updated also.

Because TypeORM `soft-remove` operation only returns record ids, we add
`.getMany()` to fetch all fields for soft-removed records, so that our
event can have before and after.
2026-01-23 17:55:07 +00:00
neo773 843fda7564 CalDav throw error If a user tries to connect an unsupported server. (#17363)
Legacy CalDav servers don't support `syncCollection` which is required
to store a `syncCursor` this PR updates the code to let user know we
don't support their server.

Source:
https://github.com/natelindev/tsdav/blob/main/src/collection.ts#L193-L194
2026-01-22 18:12:00 +01:00
Thomas Trompette c008e874e5 Allow variables with dots and keys (#17361)
Fixes
https://github.com/twentyhq/private-issues/issues/410#issuecomment-3781085655

Currently, JSON keys with spaces like { "toto toto": 123 } are rejected
with "JSON keys cannot contain spaces" error. This is problematic for
HTTP requests and webhook triggers where users cannot control the
response structure.

We use Handlebars to eval variables, segment-literal bracket notation to
escape keys with special characters:
Normal: {{step.normalKey}}
With spaces: `{{step.[key with space]}}`

So we simply need to wrap segments with spaces with brackets.

This PR: 
- Create shared path utilities to wrap the variable segments when needed
- Use it in all variable generation places
- Remove the restrictions

This body is now supported:
<img width="609" height="457" alt="Capture d’écran 2026-01-22 à 16 10
13"
src="https://github.com/user-attachments/assets/e7653c0a-df1e-49af-9c9a-4b7d59a99726"
/>
2026-01-22 16:06:53 +00:00
martmull a68e05682b Serverless built updates (#17351)
follow up of https://github.com/twentyhq/twenty/pull/17317
2026-01-22 15:04:29 +00:00
Abdul Rahman 4ccdbf1150 fix: remove empty else-if branches and add numbering (#17315) 2026-01-22 14:30:11 +00:00
Félix Malfait 8dec37b826 feat: migrate typecheck to tsgo for faster type checking (#17331)
## Summary
- Switch `twenty-server` and `fireflies` typecheck from tsc to tsgo
(~75x faster)
- Enable tsgo in VSCode via `typescript.experimental.useTsgo` setting
- Add `@ts-nocheck` to `remove-step.spec.ts` to work around tsgo
performance issue with deep spread operations

## Performance
| Package | Before (tsc) | After (tsgo) |
|---------|-------------|--------------|
| `twenty-server` | ~150s | ~2s |
| `twenty-front` | ~40s | ~2s |

## Related
- Workaround for: https://github.com/microsoft/typescript-go/issues/2551

## Test plan
- [x] `npx nx typecheck twenty-server` passes
- [x] `npx nx typecheck twenty-front` passes  
- [x] `npx nx run-many --target=typecheck --exclude=fireflies` passes
(fireflies has pre-existing type errors)
2026-01-22 13:39:07 +01:00
martmull f92c8a98a4 2114 extensibility manage serverless execution from built code (#17317)
Summary

- Serverless functions are now built when created/updated instead of at
execution time
  - Added builtHandlerPath field to track pre-built function artifacts
- Renamed base-typescript-project to seed-project with pre-built ESM
output included
- Renamed file folder enums for consistency (Functions → BuiltFunction,
SourceCode → Source)
  - supports backwards compatibility with existing serverless functions

Tested with all combinations
- storage : local driver and S3 driver
- serverless : local driver and lambda driver
2026-01-22 12:56:44 +01:00
neo773 1ffd23764c Fix Gmail sync edge case with multi-label emails (#17318)
Gmail emails often have multiple labels - an email in "XYZ" label
typically also has "INBOX". The previous negative filter approach
(-label:inbox -label:sent...) excluded these emails entirely, even when
they had a selected label.

Switched to positive OR filtering: (label:cyz OR label:xyz-visible)
-label:spam... which correctly fetches emails with any of the selected
labels regardless of other labels they have.

This edge case wasn't caught earlier because manual testing with INBOX
selected worked fine - it only surfaced when selecting custom labels
without INBOX.
2026-01-22 12:00:45 +01:00
Thomas Trompette 2920dec6ba Add logs to debug workflow crons (#17302)
We have 3 crons that get a lot of timeout in sentry. 
Adding logs to help debugging.
2026-01-21 15:49:45 +00:00
nitin 26a70c23e9 [Dashboards] fix line chart duplicate widget bleed by hashing series IDs (#17303)
closes last issue in the bug bucket -
https://github.com/twentyhq/core-team-issues/issues/2109

<img width="695" height="41" alt="CleanShot 2026-01-21 at 19 40 38"
src="https://github.com/user-attachments/assets/c6872e11-1e36-4b4e-ab06-9943c22cfab2"
/>


 ### Root cause - 
line chart series have stable IDs, so Apollo normalizes them across
duplicated widgets and X‑axis edits leak
 
 ### Fix - 
prefix series IDs with a deterministic hash of objectMetadataId +
configuration
 
 before - 
 


https://github.com/user-attachments/assets/538eded8-7036-415a-b707-a10007c3aa11


 


after - 


https://github.com/user-attachments/assets/cf9ca89a-e7c9-4106-b6cd-fbc072d9a233
2026-01-21 15:39:29 +00:00
neo773 2ecc1ba897 fix gmail message import policy (#17272)
Gmail sync was importing messages from folders users had explicitly
disabled because the folder filtering logic lived in the parent service
but the Gmail driver wasn't aware of the import policy when building its
API queries.
Moved messageFolderImportPolicy down to the driver level so Gmail can
- Build proper -label: exclusions during initial sync
- Added `buildGmailLabelSearchName` as our syntax for nested folders was
wrong
- Filter out messages from disabled folders during incremental sync via
history API
2026-01-21 12:49:58 +00:00
Paul Rastoin 596b7cc62d Deprecate nullable syncableEntity (#17279)
# Introduction
As we've been identifying both standard and custom entities for all the
metadata that had standard
We now still need to identify all custom entities enforcing them to have
an `applicationId` and `universalIdentifier`

In this PR we've removed the `SyncableEntityRequired` in favor requiring
props directly in the `SyncableEntity`
Which means that all metadata in db will now expect non nullable
applicationId and universalIdentifier across the whole application

Will add some type cleanup later in
https://github.com/twentyhq/twenty/pull/17277
2026-01-21 10:23:55 +00:00
Paul Rastoin e35b4b86cb Migrate serverless function service to v2 (#17285)
# Introduction

In this PR we're migrating the serverless function service that was
using the SF repo directly to the v2 build and runner.
The whole serverless engine now deals with flat entities only

## Resolvers
Refactored the resolvers ( serverlessFunction, route, database and cron
trigger) :
- return types to `dto`
- Standardized the flat to dto transpilation within the resolvers
- Find and findMany passing by the cached data

## Services
Refactored the services ( serverlessFunction, route, database and cron
trigger) :
- return type to be `flat`
- always calling v2 and computing cache

## New additional caches
- application variables ( cf
https://github.com/twentyhq/core-team-issues/issues/2116 )
- serverless function layer

## What to test:
- CRUD ( database trigger  , route trigger, cron trigger, serverless
function through workflows  )
- Duplicating a workflow with a serverless function code node  

## Concerns
We need to implement the cron that will hard delete soft deleted s3
serverless functions, not in this PR though ( cf
https://github.com/twentyhq/twenty/pull/17285#discussion_r2709168570 and
https://github.com/twentyhq/core-team-issues/issues/2118 )
2026-01-20 18:32:22 +00:00
Thomas Trompette 799b08e1f2 Stop workflow in any status (#17271)
Workflows can now be cancelled when not started or enqueued.
Also displaying the stop option when selecting all.

We got the case of a client that did an infinite loop. So he had a lot
of workflows to stop. Supporting select all would have avoid him to wait
for 4 hours so we process the runs throttled. This is not something that
is supposed to happen often so I did not see the point of refactoring
the endpoint. But I wanted the users to have this option just in case
2026-01-20 16:38:39 +00:00
nitin a004662221 [Dashboards] align cumulative range filtering with raw-value filters (#17265)
closes https://github.com/twentyhq/core-team-issues/issues/2097

- Align cumulative range filtering with non‑cumulative behavior by
applying rangeMin/rangeMax to raw values before cumulative totals are
computed.
- Remove cumulative‑value filtering to prevent hidden points from
influencing visible totals.
2026-01-20 12:15:24 +00:00
neo773 527c00d326 refresh oAuth tokens when sending email (#17250)
calls `connectedAccountRefreshTokensService` in `SendEmailTool`
resolving error `Lifetime validation failed, the token is expired.`
2026-01-19 17:54:07 +00:00
Raphaël Bosi d0bc8b9ffe [DASHBOARDS] Move all the graph computing logic to the backend (#17189)
- Create resolvers for each type of charts which needs data
transformation after the group by operation: Bar Chart, Line Chart and
Pie Chart
- Move all the utils to the backend and refactored some into services

This allows all the computation to be done in the backend, improving
performances in the frontend.
2026-01-19 17:25:45 +00:00
Weiko 1f1ccb281e Cache WorkspaceMember (#17247)
## Context
Due to RLS feature, workspaceMember entity and its properties is
becoming necessary in different places of the backend. To avoid querying
many times, this PR adds a map of workspace members per workspaceId,
leveraging WorkspaceCache pattern for WorkspaceEntity (in opposition
with CoreEntity)

Due to its content (mostly PII), I prefer to cache it locally only (node
process VS Redis) using localDataOnly.

TODO: invalidation logic when the workspaceMember object is updated
(more precisely, when its field map is updated). There is no easy way
today to update that list so it can be done in another PR imho
2026-01-19 17:13:10 +00:00
Félix Malfait dc93cf4c59 feat: add TypeScript Go (tsgo) for faster type checking (#17211)
## Summary

- Add `@typescript/native-preview` (tsgo) for dramatically faster type
checking on frontend projects
- Configure tsgo as default for frontend projects (twenty-front,
twenty-ui, twenty-shared, etc.)
- Keep tsc for twenty-server (faster for NestJS decorator-heavy code)
- Fix type imports for tsgo compatibility (DOMPurify, AxiosInstance)
- Remove deprecated `baseUrl` from tsconfigs where safe

## Performance Results

| Project | tsgo | tsc -b | Speedup |
|---------|------|--------|---------|
| **twenty-front** | 1.4s | 60.7s | **43x faster** |
| **twenty-server** | 2m42s | 1m10s | tsc is faster (decorators) |

tsgo excels at modern React/JSX codebases but struggles with
decorator-heavy NestJS backends, so we use the optimal checker for each.

## Usage

```bash
# Default (tsgo for frontend, tsc for backend)
nx typecheck twenty-front
nx typecheck twenty-server

# Force tsc fallback if needed
nx typecheck twenty-front --configuration=tsc

# Force tsgo on backend (slower, not recommended)
nx typecheck twenty-server --configuration=tsgo
```

## Test plan

- [x] `nx typecheck twenty-front` passes with tsgo
- [x] `nx typecheck twenty-server` passes with tsc
- [x] `nx run-many -t typecheck --exclude=fireflies` passes
- [ ] CI tests pass
2026-01-19 12:46:34 +01:00
Félix Malfait c737028dd6 Move tools/eslint-rules to packages/twenty-eslint-rules (#17203)
## Summary

Moves the custom ESLint rules from `tools/eslint-rules` to
`packages/twenty-eslint-rules` for better organization within the
monorepo packages structure.

## Changes

- Move `eslint-rules` from `tools/` to `packages/twenty-eslint-rules`
- Use `loadWorkspaceRules` from `@nx/eslint-plugin` to load custom rules
- Update all ESLint configs to use the `twenty/` rule prefix instead of
`@nx/workspace-`
- Update `project.json`, `jest.config.mjs` with new paths
- Update `package.json` workspaces and `nx.json` cache inputs
- Update Dockerfile reference

## Technical Details

The custom ESLint rules are now loaded using Nx's `loadWorkspaceRules`
utility which:
- Handles TypeScript transpilation automatically
- Allows loading workspace rules from any directory
- Provides a cleaner approach than the previous `@nx/workspace-`
convention

## Testing

- Verified all 17 custom ESLint rules load correctly from the new
location
- Verified linting works on dependent packages (twenty-front,
twenty-server, etc.)
2026-01-17 07:37:17 +01:00
Abdul Rahman 5a617e4718 Add command menu item entity (#17181) 2026-01-16 19:02:07 +00:00
nitin 9620961f16 [Dashboards] [ai] expand widget schemas with subfield grouping, color, and styling options (#17185)
Got rid of filters for now -- filters would need extra tailoring since
they depend on field names/types and the RecordGqlOperationFilter DSL
(nested AND/OR and composite subfields), which the AI can’t reliably
construct without additional metadata and skills

created a followup to tackle the same
https://github.com/twentyhq/core-team-issues/issues/2108
2026-01-16 13:22:34 +00:00
nitin 8908e0785f [Dashboards] [ai] update dashboard tools schema and skill with correct config field names (#17180)
<img width="2560" height="1353" alt="CleanShot 2026-01-16 at 00 55 56"
src="https://github.com/user-attachments/assets/c242071c-13d3-494d-bcce-9d45f36fcd77"
/>
2026-01-15 20:55:47 +00:00
Thomas Trompette 0fa8098c50 Add get current workflow version tool (#17177)
This is required so an agent can easily understand what version should
be updated from the workflow show page.
2026-01-15 16:59:11 +00:00
Thomas Trompette 6e53f5ab92 Throw 400 for webhook triggering deleted workspaces + enqueue workflows by batches (#17154)
Fixes https://github.com/twentyhq/twenty/issues/17027

Fixes https://github.com/twentyhq/twenty/issues/16824
2026-01-14 17:35:05 +00:00
Thomas Trompette 79e0207efa Filter valid fields in record steps (#17145)
Fixes https://github.com/twentyhq/twenty/issues/16775

When a field is deleted from the model, the workflow action step still
stores the deleted field name in `step.settings.input.objectRecord`.

We need to filter out the fields that are not valid anymore. This logic
existed before but had been removed with the migration to tool services.
2026-01-14 14:43:35 +00:00
neo773 0412ce2cda IMAP Error handling enhancement and fix revoked authentication edge case (#17133)
## Changes

- Removed complex retry logic in `ImapClientProvider` by delegating to
root orchestrator
- Added `parseImapAuthenticationError` for handling revoked
authentication credentials previously the code existed in
`parse-imap-error.util` but it didn't belong there and nor was not used
in `ImapClientProvider` causing revoked channels to be stuck in limbo
- Removed `parseImapError` from `*-error-handler.service.ts `
- Created `isImapNetworkError`  for consistency with Gmail and Microsoft
- `isImapNetworkError` is called at utility level for consistency
2026-01-14 13:00:43 +00:00
neo773 b79056b3a2 refactor google refresh token service error handling (#17127)
Refactors to be consistent with Microsoft service
Handles scenarios like temporary error which was not handled before
Moved `IsGmailNetworkError` from root orchestrator to driver level
2026-01-13 18:24:53 +00:00
Raphaël Bosi f793faae2b 17042 followups (#17122)
Followups after @Weiko review on
https://github.com/twentyhq/twenty/pull/17042
2026-01-13 16:25:30 +00:00
Abdullah. 2c8d3f02e1 feat: upgrade to Storybook version 10 (#17110)
Upgraded to Storybook 10. We still use `@storybook/test-runner` for
testing since it appears it'd require more work to move from Jest to
Vitest than I initially anticipated, but I completed this PR to fix
`storybook:serve:dev` - it takes time to load, but it works the way it
used to with Storybook 8.


https://github.com/user-attachments/assets/7afc32c6-4bcf-4b37-b83b-8d00d28dda15
2026-01-13 08:18:07 +00:00
Raphaël Bosi 655f1eef5f [DASHBOARDS] Allow dashboards to be restored (#17042)
This PR introduces a few changes:
- Add three actions: see deleted dashboards, destroy dashboard and
restore dashboard
- Remove the soft delete and restore on all the page layout entities
- Cascade the destruction of a dashboard to a page layout

Video QA:


https://github.com/user-attachments/assets/ab993b11-dd9c-4e88-880c-92691a521cc2
2026-01-12 12:59:17 +00:00
nitin 46e5420d20 dashboard workspace standard seeds (#16962)
# Introduction

In this pull request we're introducing new standard page layout, tabs
and widget ( 1 page layout, 1 tab and 8 widgets ) and also a new
opportunity field

Also now prefilling new records, 6 opportunities and a dashboard.

## Standard declaration
### New workspace creation
Relies on existing standard declaration builder

### Backfill command
We've been hacking through the standard builder in order to extract only
the standard page layout entities, updated their entity dependencies to
match the workspace ids so the validation passes


## Remark
- Refactored the `PageLayoutWidget` configuration type to be dynamically
typed through a generic discriminated union

---------

Co-authored-by: prastoin <paul@twenty.com>
2026-01-12 09:34:15 +00:00
neo773 87fb25c703 IMAP edge cases (#17065)
Fixes IMAP edge case. We had a maximum call stack reached crash if the
array was very large for some folders. Plus some minor perf improvement.


https://twenty-v7.sentry.io/issues/6997180505/events/652c69da1be944aab1c87ac2e6a06c30/
2026-01-10 14:26:07 +00:00
Abdul Rahman 151731c05d If else node followup changes (#16974)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-01-09 17:20:58 +00:00
neo773 a0b2aa207f Fix messaging 404 handling (#17041)
`MessageImportExceptionHandlerService.handleSyncCursorErrorException()`
was calling `messageChannelSyncStatusService.markAsFailed()`
instead of

`messageChannelSyncStatusService.resetAndMarkAsMessagesListFetchPending()`

Also adds a new command `MessagingTriggerMessageListFetchCommand` for
faster local development speed
2026-01-09 16:35:12 +00:00
neo773 a5eae50c66 Migrate MicrosoftAPIRefreshAccessTokenService to @azure/msal-node (#16954) 2026-01-08 17:18:35 +00:00
Paul Rastoin 942d2fef83 Remove sync-metadata and IS_WORKSPACE_CREATION_V2_ENABLED feature flag (#16997)
# Introduction
Followup of
https://github.com/twentyhq/twenty/pull/17001#pullrequestreview-3638508738
close https://github.com/twentyhq/core-team-issues/issues/1910

We've completely decom the `sync-metadata` in production. We're now then
removing its implementation in favor of the v2.

## TODO:
- [x] Remove sync-metadata implem and commands
- [x] Remove workspace decorators 
- [x] Type each deprecated field to deprecated on their workspaceEntity
- [x] Remove the `workspace-sync-metadata` folder entirely
- [x] remove workspace migration
- [x] workspace migration removal migration
- [x] remove the `v2` references from workspace manager file names
- [x] remove the `v2` references from workspace manager modules
- [ ] Double check impact on translation file path updates


## Note
- Removed the gate logic
- Remains some service v2 naming, serverless needs to be migrated on v2
fully
- Removed workspaceMigration service app health consumption, making it
always returning up ( no more down ) cc @FelixMalfait ( quite obsolete
health check now, will require complete refactor once we introduce inter
app dependency etc )
2026-01-08 15:45:12 +00:00
Raphaël Bosi 2e0eeda52e [DASHBOARDS] Fix dashboard duplication createdBy (#16999)
Fixes https://github.com/twentyhq/core-team-issues/issues/2032

## Before


https://github.com/user-attachments/assets/5804d3e7-1c03-4eb9-9203-64656438f5d1


## After


https://github.com/user-attachments/assets/9f96458c-d2a5-481a-b6b2-4d88f0daa98a
2026-01-08 09:13:43 +00:00
Raphaël Bosi 7af98a9c15 Update updatedat field on dashboards after edition (#16964)
Closes https://github.com/twentyhq/core-team-issues/issues/1896
2026-01-07 17:14:24 +00:00