c59df4cddde8ff595b1d1b07cbef47e9ea3eac65
18 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
0dbae2eda3 |
Address #22827 review comments and converge application file endpoints (#22868)
Follow-up to #22827, addressing the review comments left around merge time and applying the endpoint convergence discussed afterwards. ## Review comments from #22827 - **Swallowed error in dev sync asset read** ([comment](https://github.com/twentyhq/twenty/pull/22827#discussion_r3571513265)): the swallow is intentional (a missing public asset must not fail the whole dev sync) but it now logs a warning with the asset path and error, and the registration keeps its previously stored file for that path instead of losing it. - **`isAbsoluteUrl` location** ([comment](https://github.com/twentyhq/twenty/pull/22827#discussion_r3571524234)): moved to `twenty-shared/utils/url`. The server, and now also `twenty-sdk`'s `normalize-application-assets`, use the shared util. - **Soft delete vs file cleanup** ([comment](https://github.com/twentyhq/twenty/pull/22827#discussion_r3571589558)): per review, deleting a registration is now a hard delete. Stored assets (bytes + rows) are deleted with it, dependent rows are removed by their existing FK cascades, and installed applications keep working with their registration link nulled. No soft-delete/cron mechanism. - **Asset cap too generous** ([comment](https://github.com/twentyhq/twenty/pull/22827#discussion_r3571595745)): lowered to 10MB per review and documented in the publishing and public-assets docs pages. - **One missing image retriggers a full asset sync** ([comment](https://github.com/twentyhq/twenty/pull/22827#discussion_r3571646243)): `storeRegistrationAssets` now takes `skipAlreadyStoredPaths`; the catalog sync passes it when the package version is unchanged, so only assets missing a stored file are fetched instead of re-downloading everything. - **`existing.logo` already contains the new logo** ([comment](https://github.com/twentyhq/twenty/pull/22827#discussion_r3571667847)): correct, `updateFromManifest` runs first, so the previous "keep fileId when the path did not change" guard compared the new logo against itself. The fileId preservation is now keyed on the stored server file for the exact path (files are unique per `(applicationRegistrationId, path)`): a changed logo path no longer inherits the old file's id, and a transient download failure on an unchanged path still keeps the working file. This also removed the fileId-preservation bookkeeping from `storeRegistrationAssets`. ## Endpoint convergence - **Path-addressed public route for registration assets**: `GET /file/server/application-registration/:fileId` is replaced by `GET /files/application-registrations/:registrationId/*path`, mirroring the manifest's public-folder paths and leaving room for a future `:version` segment. Assets stay addressable by stable ids server-side; the fileId now only marks a path as stored. No URL is ever persisted (all are built at query time), and the old route never shipped in a release, so there is nothing to migrate. - **`Application.logoUrl` resolved server-side**: new `ResolveField` on the `Application` type builds the `/public-assets/...` display URL (or passes absolute URLs through). `useApplicationChipData` now reads it from `currentWorkspace.installedApplications`, and the frontend `buildApplicationLogoUrl` util is deleted, so clients no longer construct file URLs themselves. ## Validation - Unit: `file.controller.spec` (route renamed, traversal case added), `server-file-storage.service.spec` (`findServerFile`, `deleteByApplicationRegistrationId`), `application-registration-asset-url.service.spec` (new URL shape, url-encoding), new `isAbsoluteUrl` test; all application/file suites pass. - Live against a local server: new route serves tarball and rehosted npm assets with `public, max-age=3600` (nested paths included), 404s on missing files, unknown registrations, traversal attempts, and the removed old route; `findManyApplicationRegistrations` returns path-addressed URLs for stored assets, CDN fallback for npm, absolute passthrough; `installedApplications.logoUrl` resolves the public-assets URL and stays null for logo-less apps. Registration hard delete verified against the DB: file rows cascade, application rows keep a nulled registration link. - Typecheck + lint on twenty-server, twenty-front, twenty-shared, twenty-sdk; metadata codegen and client-sdk regenerated. |
||
|
|
8da69e0f77 |
Fix stored XSS via unsafe URL protocols in href attributes (#19282)
## Summary
- Fixes **GHSA-7w89-7q26-gj7q**: stored XSS via `javascript:` URIs in
BlockNote `FileBlock` `props.url`, rendered as a clickable `<a href>`.
- Audited the full codebase and hardened **all** surfaces where
user-controlled URLs are rendered as `href` or passed to `window.open`.
- Applies defense-in-depth: server-side input validation + client-side
render-time checks + lint rules to prevent regressions.
### Changes
**New utility** — `isSafeUrl` (`~/utils/isSafeUrl.ts`):
Allowlists `http:`, `https:`, `mailto:`, `tel:` protocols and relative
paths (`/`). Returns `false` for `javascript:`, `data:`, `vbscript:`,
etc.
**Server-side** — `validateBlocknoteFieldOrThrow`:
- Recursively walks all blocks and validates `props.url` and inline link
`href` values
- Rejects payloads with unsafe URL protocols at save time (before data
is stored)
**Client-side** — 8 components hardened:
| Component | Fix |
|-----------|-----|
| `FileBlock` (reported vuln) | `isSafeUrl` gate, fixed
`target="__blank"` → `_blank`, added `rel="noopener noreferrer"` |
| `LazyMarkdownRenderer` | `isSafeUrl` gate on markdown `<a href>`,
added `target`/`rel` |
| `EditLinkPopover` (TipTap) | Validates + auto-prefixes `https://`,
rejects unsafe URLs |
| `LinkBubbleMenu` (TipTap) | `isSafeUrl` gate on `window.open`, added
`noopener,noreferrer` |
| `AttachmentRow` | `isSafeUrl` gate on file attachment `href` |
| `URLDisplay` / `LinkDisplay` | `isSafeUrl` as second check after
`startsWith('http')` |
| `IframeWidget` | `isSafeUrl` gate on `src`, shows error state for
unsafe URLs |
| `InformationBannerMaintenance` | `isSafeUrl` gate on `window.open` |
**Lint rules** — `.oxlintrc.json`:
- `no-script-url: error` — catches `javascript:` string literals
- `react/jsx-no-script-url: error` — catches `javascript:` in JSX href
attributes
## Test plan
- [ ] Create a note via GraphQL mutation with `"url":
"javascript:void(alert(1))"` in a file block — should be rejected by
server validation
- [ ] Verify existing file attachments in notes still render and are
clickable
- [ ] Verify TipTap link insertion works for normal `https://` URLs
- [ ] Verify TipTap link insertion rejects `javascript:` URIs
- [ ] Verify markdown links in AI chat render correctly for safe URLs
- [ ] Verify URL/Link field displays still work for normal URLs
- [ ] Verify iframe widget rejects non-http(s) URLs
Made with [Cursor](https://cursor.com)
---------
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
|
||
|
|
42269cc45b |
fix(links): preserve percent-encoded URLs during normalization (#18792)
## Summary This preserves percent-encoded payloads when normalizing links fields. `lowercaseUrlOriginAndRemoveTrailingSlash` was decoding the path and query string while lowercasing the URL origin. That changes URLs where encoded payloads are semantically significant, such as Google Maps links containing `%2F` segments. Closes #18698. ## Changes - stop decoding the path/query payload in `lowercaseUrlOriginAndRemoveTrailingSlash` - preserve the raw path, query, and hash while still lowercasing the origin and trimming a trailing slash - update shared URL normalization tests to assert encoded payloads stay encoded - add a server-side regression test covering imported links field normalization ## Validation - `corepack yarn jest --config packages/twenty-shared/jest.config.mjs packages/twenty-shared/src/utils/url/__tests__/lowercaseUrlOriginAndRemoveTrailingSlash.test.ts --runInBand` - `corepack yarn jest --config packages/twenty-server/jest.config.mjs packages/twenty-server/src/engine/core-modules/record-transformer/utils/__tests__/transform-links-value.util.spec.ts --runInBand` - `corepack yarn nx test twenty-server --runInBand --testFile=src/engine/core-modules/record-transformer/utils/__tests__/transform-links-value.util.spec.ts` --------- Co-authored-by: Charles Bochet <charles@twenty.com> |
||
|
|
da064d5e88 |
Support define is tool logic function (#17926)
- supports isTool and timeout settings in defineLogicFunction in apps and in setting tabs definition - compute for all toolInputSchema for logic funciton, in settings and in code steps <img width="991" height="802" alt="image" src="https://github.com/user-attachments/assets/05dc1221-cac9-45a3-87b0-3b13161446fd" /> |
||
|
|
0b5be7caa3 |
Refactored Date to Temporal in critical date zones (#16544)
Fixes https://github.com/twentyhq/twenty/issues/16110 This PR implements Temporal to replace the legacy Date object, in all features that are time zone sensitive. (around 80% of the app) Here we define a few utils to handle Temporal primitives and obtain an easier DX for timezone manipulation, front end and back end. This PR deactivates the usage of timezone from the graph configuration, because for now it's always UTC and is not really relevant, let's handle that later. Workflows code and backend only code that don't take user input are using UTC time zone, the affected utils have not been refactored yet because this PR is big enough. # New way of filtering on date intervals As we'll progressively rollup Temporal everywhere in the codebase and remove `Date` JS object everywhere possible, we'll use the way to filter that is recommended by Temporal. This way of filtering on date intervals involves half-open intervals, and is the preferred way to avoid edge-cases with DST and smallest time increment edge-case. ## Filtering endOfX with DST edge-cases Some day-light save time shifts involve having no existing hour, or even day on certain days, for example Samoa Islands have no 30th of December 2011 : https://www.timeanddate.com/news/time/samoa-dateline.html, it jumps from 29th to 31st, so filtering on `< next period start` makes it easier to let the date library handle the strict inferior comparison, than filtering on `≤ end of period` and trying to compute manually the end of the period. For example for Samoa Islands, is end of day `2011-12-29T23:59:59.999` or is it `2011-12-30T23:59:59.999` ? If you say I don't need to know and compute it, because I want everything strictly before `2011-12-29T00:00:00 + start of next day (according to the library which knows those edge-cases)`, then you have a 100% deterministic way of computing date intervals in any timezone, for any day of any year. Of course the Samoa example is an extreme one, but more common ones involve DST shifts of 1 hour, which are still problematic on certain days of the year. ## Computing the exact _end of period_ Having an open interval filtering, with `[included - included]` instead of half-open `[included - excluded)`, forces to compute the open end of an interval, which often involves taking an arbitrary unit like minute, second, microsecond or nanosecond, which will lead to edge-case of unhandled values. For example, let's say my code computes endOfDay by setting the time to `23:59:59.999`, if another library, API, or anything else, ends up giving me a date-time with another time precision `23:59:59.999999999` (down to the nanosecond), then this date-time will be filtered out, while it should not. The good deterministic way to avoid 100% of those complex bugs is to create a half-open filter : `≥ start of period` to `< start of next period` For example : `≥ 2025-01-01T00:00:00` to `< 2025-01-02T00:00:00` instead of `≥ 2025-01-01T00:00:00` to `≤ 2025-01-01T23:59:59.999` Because, `2025-01-01T00:00:00` = `2025-01-01T00:00:00.000` = `2025-01-01T00:00:00.000000` = `2025-01-01T00:00:00.000000000` => no risk of error in computing start of period But `2025-01-01T23:59:59` ≠ `2025-01-01T23:59:59.999` ≠ `2025-01-01T23:59:59.999999` ≠ `2025-01-01T23:59:59.999999999` => existing risk of error in computing end of period This is why an half-open interval has no risk of error in computing a date-time interval filter. Here is a link to this debate : https://github.com/tc39/proposal-temporal/issues/2568 > For this reason, we recommend not calculating the exact nanosecond at the end of the day if it's not absolutely necessary. For example, if it's needed for <= comparisons, we recommend just changing the comparison code. So instead of <= zdtEndOfDay your code could be < zdtStartOfNextDay which is easier to calculate and not subject to the issue of not knowing which unit is the right one. > > [Justin Grant](https://github.com/justingrant), top contributor of Temporal ## Application to our codebase Applying this half-open filtering paradigm to our codebase means we would have to rename `IS_AFTER` to `IS_AFTER_OR_EQUAL` and to keep `IS_BEFORE` (or even `IS_STRICTLY_BEFORE`) to make this half-open interval self-explanatory everywhere in the codebase, this will avoid any confusion. See the relevant issue : https://github.com/twentyhq/core-team-issues/issues/2010 In the mean time, we'll keep this operand and add this semantic in the naming everywhere possible. ## Example with a different user timezone Example on a graph grouped by week in timezone Pacific/Samoa, on a computer running on Europe/Paris : <img width="342" height="511" alt="image" src="https://github.com/user-attachments/assets/9e7d5121-ecc4-4233-835b-f59293fbd8c8" /> Then the associated data in the table view, with our **half-open date-time filter** : <img width="804" height="262" alt="image" src="https://github.com/user-attachments/assets/28efe1d7-d2fc-4aec-b521-bada7f980447" /> And the associated SQL query result to see how DATE_TRUNC in Postgres applies its internal start of week logic : <img width="709" height="220" alt="image" src="https://github.com/user-attachments/assets/4d0542e1-eaae-4b4b-afa9-5005f48ffdca" /> The associated SQL query without parameters to test in your SQL client : ```SQL SELECT "opportunity"."closeDate" as "close_date", TO_CHAR(DATE_TRUNC('week', "opportunity"."closeDate", 'Pacific/Samoa') AT TIME ZONE 'Pacific/Samoa', 'YYYY-MM-DD') AS "DATE_TRUNC by week start in timezone Pacific/Samoa", "opportunity"."name" FROM "workspace_1wgvd1injqtife6y4rvfbu3h5"."opportunity" "opportunity" ORDER BY "opportunity"."closeDate" ASC NULLS LAST ``` # Date picker simplification (not in this PR) Our DatePicker component, which is wrapping `react-datepicker` library component, is now exposing plain dates as string instead of Date object. The Date object is still used internally to manage the library component, but since the date picker calendar is only manipulating plain dates, there is no need to add timezone management to it, and no need to expose a handleChange with Date object. The timezone management relies on date time inputs now. The modification has been made in a previous PR : https://github.com/twentyhq/twenty/issues/15377 but it's good to reference it here. # Calendar feature refactor Calendar feature has been refactored to rely on Temporal.PlainDate as much as possible, while leaving some date-fns utils to avoid re-coding them. Since the trick is to use utils to convert back and from Date object in exec env reliably, we can do it everywhere we need to interface legacy Date object utils and Temporal related code. ## TimeZone is now shown on Calendar : <img width="894" height="958" alt="image" src="https://github.com/user-attachments/assets/231f8107-fad6-4786-b532-456692c20f1d" /> ## Month picker has been refactored <img width="503" height="266" alt="image" src="https://github.com/user-attachments/assets/cb90bc34-6c4d-436d-93bc-4b6fb00de7f5" /> Since the days weren't useful, the picker has been refactored to remove the days. # Miscellaneous - Fixed a bug with drag and drop edge-case with 2 items in a list. # Improvements ## Lots of chained operations It would be nice to create small utils to avoid repeated chained operations, but that is how Temporal is designed, a very small set of primitive operations that allow to compose everything needed. Maybe we'll have wrappers on top of Temporal in the coming years. ## Creation of Temporal objects is throwing errors If the input is badly formatted Temporal will throw, we might want to adopt a global strategy to avoid that. Example : ```ts const newPlainDate = Temporal.PlainDate.from('bad-string'); // Will throw ``` |
||
|
|
2eb8006a30 | Fix tests | ||
|
|
1119e3d77e |
fix(twenty-shared): preserve special characters in URLs (#16312)
# Fix: URL Encoding Bug & Code Refactor
## Issue
**Bug**: URLs with encoded characters (e.g., `%20` for spaces) were
being double-encoded or incorrectly processed in
[lowercaseUrlOriginAndRemoveTrailingSlash](cci:1://file:///Users/apple/WebstormProjects/twenty/packages/twenty-shared/src/utils/url/lowercaseUrlOriginAndRemoveTrailingSlash.ts:4:0-16:2),
causing URL mismatches and potential data integrity issues.
**Build Error**: `TS2307: Cannot find module
'src/modules/messaging/message-import-manager/drivers/imap/utils/safe-decode-uri-component.util'`
## Root Cause Analysis
### 1. Missing URL Decoding
The
[lowercaseUrlOriginAndRemoveTrailingSlash](cci:1://file:///Users/apple/WebstormProjects/twenty/packages/twenty-shared/src/utils/url/lowercaseUrlOriginAndRemoveTrailingSlash.ts:4:0-16:2)
function was processing URLs without properly decoding URI components.
When URLs contained encoded characters like `%20`, `%2F`, etc., they
weren't being normalized correctly.
### 2. Invalid Cross-Package Import
The fix attempted to import
[safeDecodeURIComponent](cci:1://file:///Users/apple/WebstormProjects/twenty/packages/twenty-shared/src/utils/url/safeDecodeURIComponent.ts:0:0-6:2)
from `twenty-server`:
```typescript
import { safeDecodeURIComponent } from 'src/modules/messaging/message-import-manager/drivers/imap/utils/safe-decode-uri-component.util';
```
This failed because:
- The file resides in `twenty-shared`, a separate package
- TypeScript cannot resolve internal paths from another package
- The monorepo uses package exports (`twenty-shared/utils`) for
cross-package imports, not direct file paths
## Solution
### 1. Bug Fix: Added Safe URI Decoding
Updated
[lowercaseUrlOriginAndRemoveTrailingSlash.ts](cci:7://file:///Users/apple/WebstormProjects/twenty/packages/twenty-shared/src/utils/url/lowercaseUrlOriginAndRemoveTrailingSlash.ts:0:0-0:0)
to properly decode URL components:
```typescript
export const lowercaseUrlOriginAndRemoveTrailingSlash = (rawUrl: string) => {
const url = getURLSafely(rawUrl);
if (!isDefined(url)) {
return rawUrl;
}
const lowercaseOrigin = url.origin.toLowerCase();
const path =
safeDecodeURIComponent(url.pathname) +
safeDecodeURIComponent(url.search) +
url.hash;
return (lowercaseOrigin + path).replace(/\/$/, '');
};
```
The
[safeDecodeURIComponent](cci:1://file:///Users/apple/WebstormProjects/twenty/packages/twenty-shared/src/utils/url/safeDecodeURIComponent.ts:0:0-6:2)
wrapper handles malformed URI sequences gracefully by returning the
original string if decoding fails, preventing runtime crashes.
### 2. Refactor: Consolidated Shared Utility
**Before**: Duplicate utility existed in `twenty-server`
```
twenty-server/src/modules/messaging/.../utils/safe-decode-uri-component.util.ts
```
**After**: Single source of truth in `twenty-shared`
```
twenty-shared/src/utils/url/safeDecodeURIComponent.ts
```
This follows the established pattern in the codebase where shared
utilities live in `twenty-shared` and are imported via subpath exports:
```typescript
// In twenty-server
import { safeDecodeURIComponent } from 'twenty-shared/utils';
// In twenty-shared (local import)
import { safeDecodeURIComponent } from './safeDecodeURIComponent';
```
## Files Changed
| File | Action | Description |
|------|--------|-------------|
|
[twenty-shared/src/utils/url/safeDecodeURIComponent.ts](cci:7://file:///Users/apple/WebstormProjects/twenty/packages/twenty-shared/src/utils/url/safeDecodeURIComponent.ts:0:0-0:0)
| **Created** | New shared utility (moved from twenty-server) |
|
[twenty-shared/src/utils/url/index.ts](cci:7://file:///Users/apple/WebstormProjects/twenty/packages/twenty-shared/src/utils/url/index.ts:0:0-0:0)
| **Modified** | Added export for
[safeDecodeURIComponent](cci:1://file:///Users/apple/WebstormProjects/twenty/packages/twenty-shared/src/utils/url/safeDecodeURIComponent.ts:0:0-6:2)
|
|
[twenty-shared/src/utils/url/lowercaseUrlOriginAndRemoveTrailingSlash.ts](cci:7://file:///Users/apple/WebstormProjects/twenty/packages/twenty-shared/src/utils/url/lowercaseUrlOriginAndRemoveTrailingSlash.ts:0:0-0:0)
| **Modified** | Fixed import path, now uses local relative import |
| `twenty-server/.../imap-message-text-extractor.service.ts` |
**Modified** | Updated import to use `twenty-shared/utils` |
| `twenty-server/.../safe-decode-uri-component.util.ts` | **Deleted** |
Removed duplicate utility |
## The Utility
```typescript
// safeDecodeURIComponent.ts
export const safeDecodeURIComponent = (text: string): string => {
try {
return decodeURIComponent(text);
} catch {
return text;
}
};
```
This wrapper is necessary because `decodeURIComponent()` throws a
`URIError` on malformed sequences (e.g., `%E0%A4%A`). The safe version
returns the original string instead of crashing.
## Testing
- **342 tests passed** in `twenty-shared`
- `lowercaseUrlOriginAndRemoveTrailingSlash.test.ts` validates URL
normalization behavior
- No regressions in existing functionality
## Impact
- **Bug Fixed**: URLs with encoded characters are now properly
normalized
- **Code Quality**: Eliminated code duplication between packages
- **Maintainability**: Single source of truth for URI decoding utility
- **Build**: Resolved TS2307 compilation error
---------
Co-authored-by: Joker <apple@Apples-MacBook-Pro.local>
|
||
|
|
f60817a1e1 |
Morph many to one picker (#14155)
This PR follows the multiSelect PR merged previously. It will enable morph relation Many to One to be handled from the table, using a singleSelect picker Main point : I decided to change the singleSelect API to take an array of **objectMetadataName** instead of only one to deal with both our usecases. --------- Co-authored-by: Charles Bochet <charles@twenty.com> |
||
|
|
3cada58908 |
Migrate from Zod v3 to v4 (#14639)
Closes [#1526](https://github.com/twentyhq/core-team-issues/issues/1526) --------- Co-authored-by: Félix Malfait <felix@twenty.com> Co-authored-by: Félix Malfait <felix.malfait@gmail.com> |
||
|
|
b44b46109c |
Update try/catch syntax (#13732)
Update try/catch syntax to prepare for eslint migration |
||
|
|
d916ec0af9 |
Fix link formatting (#13210)
closes https://github.com/twentyhq/twenty/issues/13207 --------- Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com> |
||
|
|
b80762b3e1 |
fix IndexFieldMetadata availability in IndexMetadata/ObjectMetadata in front (#12886)
Context : - IndexFieldMetadata was no longer available on 'objects' gql query ([since this PR](https://github.com/twentyhq/twenty/pull/12785)). Then, unicity checks on import do not work anymore. Fix : - Add a dataloader logic in indexFieldMetadata - Add extra check in unicity hook on import |
||
|
|
1cee587709 |
Removing trailing slashes (#12658)
Fix inconsistent domain URL formats : removing the last / that was caused by URL method Standardize URL formatting to ensure consistent links storage and retrieval of domain URLs across the application. Will improve the dedpulicates in the links Note: there is another temporary issue from google that was solved on the 13th of june https://groups.google.com/g/adwords-api/c/tRSQMRZrJYM but we consider this out of this scope Fixes #12621 |
||
|
|
3d57c90e04 |
refactor: Webhooks (#12487)
Closes #12303 ### What’s Changed - Replace auto‐save with explicit Save / Cancel Webhook forms now use manual “Save” and “Cancel” buttons instead of the old debounced auto‐save/update. - Separate “New” and “Detail” routes Two dedicated paths `/settings/webhooks/new` for creation and /`settings/webhooks/:webhookId` for editing, making the UX clearer. - URL hint & normalization If a user omits the http(s):// scheme, we display a “Will be saved as https://…” hint and automatically default to HTTPS. - Centralized validation with Zod Introduced a `webhookFormSchema` for client‐side URL, operations, and secret validation. - Storybook coverage Added stories for both “New Webhook” and “Webhook Detail” - Unit tests Added tests for the new `useWebhookForm` hook |
||
|
|
aa58259019 |
11744 emails broken image in emails (#12265)
- refactor file tokens - update file token management - generate one token per file per workspaceId - move token from query params to url path |
||
|
|
ec9d8e4e95 |
Discard empty and null links in Links fields (#12188)
This PR has several objectives: - Ignore invalid and empty links in the frontend - Ignore empty links when creating or updating a link field in the backend - Throw an error when trying to create or update a link field with an invalid link The logic is mostly the same in the frontend and the backend: we take the initial primaryLink and the secondaryLinks, we discard all the empty links (with `url === '' || url === null`), and the primaryLink becomes the first remaining link. ## Frontend There are three parts in the frontend where we have to remove the empty links: - LinksDisplay - LinksFieldInput - isFieldValueEmpty; used in RecordInlineCell ## Backend I put the logic in `packages/twenty-server/src/engine/core-modules/record-transformer/services/record-input-transformer.service.ts` as it's used by the REST API, the GraphQL API, and by Create Record and Update Record actions in the workflows. |
||
|
|
9ad8287dbc |
[REFACTOR] twenty-shared multi barrel and CJS/ESM build with preconstruct (#11083)
# Introduction In this PR we've migrated `twenty-shared` from a `vite` app [libary-mode](https://vite.dev/guide/build#library-mode) to a [preconstruct](https://preconstruct.tools/) "atomic" application ( in the future would like to introduce preconstruct to handle of all our atomic dependencies such as `twenty-emails` `twenty-ui` etc it will be integrated at the monorepo's root directly, would be to invasive in the first, starting incremental via `twenty-shared`) For more information regarding the motivations please refer to nor: - https://github.com/twentyhq/core-team-issues/issues/587 - https://github.com/twentyhq/core-team-issues/issues/281#issuecomment-2630949682 close https://github.com/twentyhq/core-team-issues/issues/589 close https://github.com/twentyhq/core-team-issues/issues/590 ## How to test In order to ease the review this PR will ship all the codegen at the very end, the actual meaning full diff is `+2,411 −114` In order to migrate existing dependent packages to `twenty-shared` multi barrel new arch you need to run in local: ```sh yarn tsx packages/twenty-shared/scripts/migrateFromSingleToMultiBarrelImport.ts && \ npx nx run-many -t lint --fix -p twenty-front twenty-ui twenty-server twenty-emails twenty-shared twenty-zapier ``` Note that `migrateFromSingleToMultiBarrelImport` is idempotent, it's atm included in the PR but should not be merged. ( such as codegen will be added before merging this script will be removed ) ## Misc - related opened issue preconstruct https://github.com/preconstruct/preconstruct/issues/617 ## Closed related PR - https://github.com/twentyhq/twenty/pull/11028 - https://github.com/twentyhq/twenty/pull/10993 - https://github.com/twentyhq/twenty/pull/10960 ## Upcoming enhancement: ( in others dedicated PRs ) - 1/ refactor generate barrel to export atomic module instead of `*` - 2/ generate barrel own package with several files and tests - 3/ Migration twenty-ui the same way - 4/ Use `preconstruct` at monorepo global level ## Conclusion As always any suggestions are welcomed ! |
||
|
|
9046a9ac16 |
Migrate url tooling to twenty-shared (#10440)
Migrate and unify URL tooling in twenty-shared. We now have: - isValidHostname which follows our own business rules - a zod schema that can be re-used in different context and leverages is isValidHostname - isValidUrl on top of the zod schema - a getAbsoluteURl and getHostname on top of the zod schema I have added a LOT of tests to cover all the cases I've found Also fixes: https://github.com/twentyhq/twenty/issues/10147 |