Commit Graph
62 Commits
Author SHA1 Message Date
Raphaël BosiandGitHub a88d1f4442 Introduce standalone page (#19675)
Add support for standalone pages: a new `PageLayout` type
(`STANDALONE_PAGE`) that can be rendered independently at
`/page/:pageLayoutId`, not tied to any record or object context.

- New `STANDALONE_PAGE` page layout type
- New `PAGE_LAYOUT` navigation menu item type: adds a `pageLayoutId`
foreign key to `NavigationMenuItemEntity`, allowing sidebar items to
link directly to standalone pages
- New `GLOBAL_OBJECT_CONTEXT` command menu availability type: separates
object-context-dependent commands (Create Record, Import, Export, See
Deleted, Create View, Hide Deleted) from truly global ones, so
standalone pages only show relevant commands
- Frontend routing & rendering: adds a `/page/:pageLayoutId` route with
its own page component, header, and command menu
- Widget rendering refactor
- Instance commands: two fast 1.22 migrations: `pageLayoutId` column +
`STANDALONE_PAGE` enum, and `GLOBAL_OBJECT_CONTEXT` availability type
enum
- Workspace command: backfills existing command menu items from `GLOBAL`
to `GLOBAL_OBJECT_CONTEXT` where appropriate
- Dev seeds: adds a sample "Star History" standalone page with an iframe
widget for local development
2026-04-14 15:52:45 +00:00
Charles BochetandGitHub ad1a4ecca0 Add isUnique support for application-defined fields (#19609)
## Summary

- Adds `isUnique?: boolean` to `RegularFieldManifest` in
`twenty-shared`, allowing SDK applications to declare unique constraints
on fields
- Updates the manifest-to-flat-field converter to read `isUnique` from
the manifest instead of hardcoding `false`
- Generates corresponding unique index metadata in
`computeApplicationManifestAllUniversalFlatEntityMaps` when a field has
`isUnique: true`, matching the behavior of the `CreateFieldInput` path
- Adds SDK-side validation rejecting `isUnique` on RELATION,
MORPH_RELATION, and FILES field types
- Adds integration test verifying manifest sync creates a unique index
for `isUnique` fields
- Adds SDK unit tests for `isUnique` validation on unsupported field
types

## Test plan

- [x] SDK unit tests: `defineField` accepts `isUnique: true` on TEXT,
rejects on RELATION and FILES
- [ ] Integration test: manifest sync with `isUnique: true` creates the
unique index in DB
- [ ] Verify `isUnique` defaults to `false` when not specified (backward
compatible)
- [ ] Verify standalone manifest fields (not nested in objects) also
generate unique indexes correctly
2026-04-12 17:03:09 +02:00
d2f51cc939 Fix pre post logic function not executed (#19462)
- removes pre-install function 
- execute **asyncrhonously** post-install function at application
installation
- add optional `shouldRunOnVersionUpgrade` boolean value on post-install
function definition default false
- update PostInstallPayload to 
```
export type PostInstallPayload = {
  previousVersion?: string;
  newVersion: string;
};
```

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-04-09 20:22:41 +00:00
martmullandGitHub 5eaabe95e7 Fix role synchronisation (#19469)
As title
solves
https://discord.com/channels/1130383047699738754/1491167098398052503
2026-04-09 09:36:16 +00:00
MarieandGitHub 2d6c8be7df [Apps] Fix - app-synced object should be searchable (#19206)
## Summary

- **Make app-synced objects searchable**: `isSearchable` was hardcoded
to `false` and the `searchVector` field was missing the `GENERATED
ALWAYS AS (...)` expression, causing all records to have a `NULL` search
vector and be excluded from search results. Fixed by defaulting
`isSearchable` to `true` (configurable via the object manifest),
computing the `asExpression` from the label identifier field, and
allowing the update-field-action-handler to handle the `null` → defined
`asExpression` transition.
- **Make `isSearchable` updatable on an object**: The property had
`toCompare: false` in the entity properties configuration, so updates
via the API were silently ignored and never persisted. Fixed by setting
`toCompare: true`.
2026-04-02 17:14:37 +00:00
martmullandGitHub fe1377f18b Provide applicatiion assets (#18973)
- improve backend
- improve frontend

<img width="1293" height="824" alt="image"
src="https://github.com/user-attachments/assets/7a4633f1-85cd-4126-b058-dbeae6ba2218"
/>
2026-03-30 10:53:31 +02:00
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>
2026-03-24 18:10:25 +00:00
Raphaël BosiandGitHub dedcf4e9b9 Support template variables in command menu item labels (#18707)
- Adds template variable interpolation (`${...}`) to command menu item
labels and short labels, enabling dynamic text like `Create new
${capitalize(objectMetadataItem.labelSingular)}` instead of static
`Create new record`.
- Supports `capitalize` and `lowercase` transform functions within
template expressions.
2026-03-18 10:26:58 +00:00
Charles BochetandGitHub a121d00ddd feat: add color property to ObjectMetadata for object icon customization (#18672)
## Summary

- Adds a `color` column to `ObjectMetadataEntity` with full GraphQL
support so object icon colors are persisted at the metadata level
- Adds a `type` column to `NavigationMenuItemEntity` (enum: `OBJECT`,
`VIEW`, `FOLDER`, `LINK`, `RECORD`) replacing field-based type inference
- Updates frontend to read object colors from `objectMetadata.color`
(falling back to standard defaults) in the sidebar nav, record index
header, and record show breadcrumb
- Simplifies `NavigationMenuItemIcon` color resolution via
`getEffectiveNavigationMenuItemColor` util

## Color rules

| Item type | Color source | Editable in sidebar? |
|-----------|-------------|---------------------|
| **Object** | `objectMetadata.color` | Yes — persisted to
`objectMetadata.color` on Save |
| **Folder** | `navigationMenuItem.color` | Yes |
| **Link** | Fixed default (`DEFAULT_NAVIGATION_MENU_ITEM_COLOR_LINK`) |
No |
| **View** | `objectMetadata.color` (from the parent object) | No |
| **Record** | None | No |

- **Object** items represent the whole object (e.g. "Companies") and
point to the INDEX view. Changing their color updates
`objectMetadata.color` via `useSaveObjectMetadataColorsFromDraft`.
- **View** items represent specific non-INDEX views. Their color comes
from the parent object's metadata (read-only).
- Only **folders** store their color on `navigationMenuItem.color` —
enforced by `hasNavigationMenuItemOwnColor` util.
- `getEffectiveNavigationMenuItemColor` returns `objectColor` for both
OBJECT and VIEW items, folder's own color for folders, and the fixed
default for links.

## NavigationMenuItemType enum

- Shared enum created in `twenty-shared` with values: `OBJECT`, `VIEW`,
`FOLDER`, `LINK`, `RECORD`
- Registered as a GraphQL enum on the backend
- Replaces string literals across entity, DTOs, input, converters, and
frontend hooks
- Migration backfills existing rows: INDEX views → `OBJECT`, non-INDEX
views → `VIEW`, based on join with the view table

## Design decisions

- **OBJECT vs VIEW distinction**: Items pointing to INDEX views are
typed as `OBJECT` (represent the whole object, color editable). Items
pointing to non-INDEX views are typed as `VIEW` (specific view, color
read-only from parent object).
- **Dual color storage**: `navigationMenuItem.color` is preserved for
folders only. Objects use `objectMetadata.color` as their source of
truth.
- **Type discriminator**: The `type` column replaces field-based
inference (checking `viewId`, `link`, `targetRecordId` presence) with an
explicit enum, simplifying `isNavigationMenuItemLink` /
`isNavigationMenuItemFolder` to simple `item.type ===` checks.
- **No settings page color picker**: Object color editing is done from
the sidebar edit panel, not the data model settings page.

## Test plan

- [ ] Verify objects display their default standard colors in the
sidebar
- [ ] Verify object color editing works in the sidebar edit panel
(persists to objectMetadata.color)
- [ ] Verify folder color editing works in the sidebar edit panel
- [ ] Verify views, links, and records do NOT show a color picker in the
sidebar edit panel
- [ ] Run `npx nx typecheck twenty-front` and `npx nx typecheck
twenty-server`
- [ ] Verify the database migrations add `color` to `objectMetadata` and
`type` to `navigationMenuItem`


Made with [Cursor](https://cursor.com)
2026-03-16 23:54:56 +01:00
Raphaël BosiandGitHub 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`
2026-03-10 17:36:41 +00:00
Paul RastoinandGitHub 06bdb5ad6a [SDK] Agent in manifest (#18431)
# Introduction
Adding agent in the manifest, required for twenty standard app
extraction out of twenty-server
2026-03-09 11:10:14 +00:00
martmullandGitHub 403db7ad3f Add default viewField when creating object (#18441)
as title
2026-03-06 14:59:31 +01:00
Raphaël BosiandGitHub abd9709291 Update Command Menu Item entity (#18391)
Closes https://github.com/twentyhq/core-team-issues/issues/2256
2026-03-05 11:21:56 +01:00
Charles BochetandGitHub eda905f271 [DevXP] Improve Linaria pre-build speed (#18382)
## Summary

This PR improves Linaria/WYW pre-build speed and continues the migration
of `twenty-ui` components away from runtime `ThemeContext` reads toward
static CSS variables and theme constants.

### Linaria/WYW profiling plugin improvements (`twenty-shared`)

- **Babel JIT warmup**: added a `buildStart` warmup step that triggers
WYW's Babel JIT compilation before the real build starts, so the first
real file doesn't pay the cold-start penalty
- **`configResolved` hook**: detects dev vs prod mode and resolves the
correct warmup file path relative to `config.root`
- **Dev-only per-file logging**: slow file warnings are now gated behind
`isDevMode`, keeping production/CI build output clean
- **`closeBundle` summary**: moved the final top-slow-files report to
`closeBundle` for accurate end-of-build reporting
- **Removed noisy progress interval logging** in favor of the warmup log
+ final summary

### Migration from `ThemeContext` to static CSS variables / constants

Across `twenty-ui`, replaced runtime `useTheme()` reads with:
- `themeCssVariables` CSS custom properties (colors, spacing)
- Hard-coded design-system constants (`ICON.size.md` → `16`,
`ICON.stroke.sm` → `1.6`) so components no longer need a React context
at render time — enabling Linaria static extraction

**Components migrated:**
- `Button`, `AnimatedButton`, `LightButton`, `LightIconButton`,
`AnimatedLightIconButton`, `ButtonIcon`, `ButtonSoon`
- `ProgressBar` (Framer Motion width animation → CSS `transition`)
- `Info`, `HorizontalSeparator`, `LinkChip`
- `MenuPicker`, `MenuItemLeftContent`, `MenuItemIconWithGripSwap`,
`NavigationBarItem`
- `JsonArrow`, `JsonNestedNode`
- `ModalHeader`

### Other
- Added `aria-valuenow` to `ProgressBar` for accessibility
- `VisibilityHidden` component updated to inline accessibility styles
2026-03-04 17:04:16 +01:00
Raphaël BosiandGitHub b11f77df2a [FRONT COMPONENTS] Introduce conditionalAvailabilityExpression to command menu items (#18319)
## PR Description

- Uses `expr-eval` to enable front components (SDK plugins) to define
conditional availability as declarative expressions.
- Moves shared types and constants to `twenty-shared`
- Introduces a `conditionalAvailabilityExpression` field on
`CommandMenuItemEntity`, allowing command menu items to store an
`expr-eval` compatible expression string that is evaluated against a
CommandMenuContext to determine if the item should be shown.
- Creates an esbuild transform plugin
`conditional-availability-transform-plugin` in `twenty-sdk` that
converts TypeScript conditional availability expressions into
`expr-eval` compatible syntax at build time, so SDK developers can write
natural TS expressions that get transformed to evaluable strings.
- Removes deprecated `forceRegisteredActionsByKey` state and its usage.
- Creates `useCommandMenuContext` hook that builds the full
`CommandMenuContext` object from React state, which is then passed to
`useCommandMenuItemFrontComponentActions` for evaluating conditional
availability expressions.
2026-03-04 16:33:58 +01:00
Paul RastoinGitHubThomas TrompettebosiraphaelWeikogithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>github-actionsCharles Bochet
845a1934d3 Tt call recording app (#18281)
Co-authored-by: Thomas Trompette <thomas.trompette@sfr.fr>
Co-authored-by: bosiraphael <raphael.bosi@gmail.com>
Co-authored-by: Weiko <corentin@twenty.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@twenty.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
2026-03-04 14:11:57 +00:00
Félix MalfaitGitHubclaude[bot] <41898282+claude[bot]@users.noreply.github.com>
012d819557 OAuth Client — Unified ApplicationRegistration, OAuth server, and frontend (#18267)
## Summary

Consolidates three separate PRs (#18260, #18261, #18262) into a single
unified branch with all review feedback addressed:

### New features
- **ApplicationRegistration entity** — server-level registration for
OAuth apps with encrypted server variables
- **OAuth 2.0 server** — authorization code, client credentials, refresh
token grants with PKCE support
- **OAuth discovery endpoint** —
`.well-known/oauth-authorization-server` metadata
- **Frontend UI** — app registration details page with credential
management, redirect URI editing, and server variable configuration
- **CLI integration** — `twenty dev` auto-registers apps and stores
OAuth credentials locally
- **Authorize consent screen** — OAuth consent page at `/authorize`
showing requested scopes

### Review feedback addressed

**Renames (PR #18260):**
- `appRegistration` → `applicationRegistration` (entity, tables, files,
imports, GraphQL types)
- `appRegistrationVariable` → `applicationRegistrationVariable`
- `clientId` → `oAuthClientId`, `clientSecretHash` →
`oAuthClientSecretHash`, `redirectUris` → `oAuthRedirectUris`, `scopes`
→ `oAuthScopes`

**Security fixes (PR #18261):**
- Fixed redirect URI validation bypass when `oAuthRedirectUris` is an
empty array
- Fixed workspace isolation in `clientCredentialsGrant` — now uses
`find()` with explicit handling for multiple installations
- Added error logging in refresh token `catch` block instead of silently
swallowing

**Code quality (PR #18262):**
- Split `VersionDistributionEntry` into its own file (one export per
file)
- Split GraphQL queries and mutations into individual files with a
shared fragment
- Removed unused `OAuth` entry from `AuthProviderEnum`
- Added loading state to `handleRotateSecret`
- Removed 27 narration-style comments from test files
- Added proper guards (`PublicEndpointGuard`, `NoPermissionGuard`) to
controllers and resolvers

## Test plan

- [ ] Verify `twenty dev` registers an app and stores OAuth credentials
- [ ] Test OAuth authorization code flow end-to-end (authorize → token →
API call)
- [ ] Test client credentials grant
- [ ] Verify redirect URI validation rejects requests when no URIs are
registered
- [ ] Verify app registration detail page renders correctly
- [ ] Test secret rotation with loading state
- [ ] Verify server variable editing and saving
- [ ] Run `npx nx database:reset twenty-server` to validate migration

Closes #18260, #18261, #18262


Made with [Cursor](https://cursor.com)

---------

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
2026-02-28 14:07:49 +01:00
Abdul RahmanGitHubCopilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>DevessierCharles Bochet
9fe2a07c55 Navbar customization v2 (#18026)
Adds color support for navigation menu items.

---------

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Co-authored-by: Devessier <baptiste@devessier.fr>
Co-authored-by: Charles Bochet <charles@twenty.com>
2026-02-28 11:48:28 +01:00
WeikoandGitHub 3bbaff801a Add Twenty app settings custom app (#18273)
## Context
This PR adds the ability to define a front-component as a custom tab for
the application settings, allowing app creators to inject some
logic/rendering the their app settings.


## Example
```typescript
// packages/twenty-apps/my-test-app/src/front-components/settings-custom-tab.tsx
import { defineFrontComponent } from 'twenty-sdk';

export const SETTINGS_CUSTOM_TAB_UNIVERSAL_IDENTIFIER =
  'a42a88a8-21ce-4d22-bc44-d5146da64726';

export const SettingsCustomTab = () => {
  return (
    <div style={{ padding: '20px', fontFamily: 'sans-serif' }}>
      <h2>My Test App Settings</h2>
      <p>This is a custom settings tab provided by My Test App.</p>
      <p>Application creators can customize this component freely.</p>
    </div>
  );
};

export default defineFrontComponent({
  universalIdentifier: SETTINGS_CUSTOM_TAB_UNIVERSAL_IDENTIFIER,
  name: 'settings-custom-tab',
  description: 'Custom settings tab for the application',
  component: SettingsCustomTab,
});
```

```typescript
// packages/twenty-apps/my-test-app/src/application-config.ts
export default defineApplication({
  universalIdentifier: '52870ce6-e584-4bd4-bc1a-6c63c508982e',
  displayName: 'My test app',
  description: '',
  defaultRoleUniversalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
  settingsCustomTabFrontComponentUniversalIdentifier:
    SETTINGS_CUSTOM_TAB_UNIVERSAL_IDENTIFIER,
});
```
<img width="786" height="757" alt="Screenshot 2026-02-26 at 14 54 09"
src="https://github.com/user-attachments/assets/fcba70db-35da-48f1-bd65-359e894a691d"
/>
2026-02-26 16:26:49 +01:00
martmullandGitHub 120096346a Add define post isntall logic function (#18248)
As title
2026-02-26 11:09:21 +01:00
nitinandGitHub 887371054a Host-remote refresh token implementation (#18044) 2026-02-24 19:37:29 +01:00
Raphaël BosiandGitHub 7da8450075 [FRONT COMPONENTS] Headless components (#18096)
## Description

- Add `isHeadless` field to `FrontComponent` entity so front components
can run without rendering UI in the command menu
- Introduce headless front component mounting logic:
`HeadlessFrontComponentMountRoot` at the application root,
`useMountHeadlessFrontComponent`, and `useUnmountHeadlessFrontComponent`
hooks to mount/unmount headless components
- Expand the SDK with new action components (`Action`, `ActionLink`,
`ActionOpenSidePanelPage`) and host communication functions
(`openSidePanelPage`, `unmountFrontComponent`)
- Move `CommandMenuPages` type to twenty-shared so the SDK can reference
it for side panel navigation

## Video QA



https://github.com/user-attachments/assets/4f9e3bb1-fcd1-42be-b3f4-a97e80c2add2
2026-02-20 14:14:42 +00:00
3bc887e12e Add default relation to standard object on custom object in manifest (#18033)
add default relation fields when creating an object from an application

---------

Co-authored-by: prastoin <paul@twenty.com>
2026-02-20 11:49:06 +01:00
Paul RastoinandGitHub 175df59c21 Support Skill in manifest (#18092)
# Introduction
Support skill in manifest, pre-requisite for the twenty standard app
migration
2026-02-20 11:45:42 +01:00
Raphaël BosiandGitHub bd03073b6d [FRONT COMPONENTS] Declare command menu items in front components (#18047)
## Description

- Adds support for declaring command menu items directly within
`defineFrontComponent` via an optional command config property
- Introduces a new `CommandMenuItemManifest` type in twenty-shared and
wires it through the manifest build pipeline

## Example Of usage

```tsx
import { defineFrontComponent } from "twenty-sdk";

const TestAction = () => {
  return <div>Test Action</div>;
};

export default defineFrontComponent({
  universalIdentifier: "6c289461-0007-4a62-a99f-69e5c11a4ce7",
  name: "test-action",
  description: "Test Action",
  component: TestAction,
  command: {
    universalIdentifier: "c07df864-495f-46f3-9f5b-9d3ce2589e9b",
    label: "Run My Action",
    icon: "IconBolt",
    isPinned: false,
  },
});

```

## Video QA


https://github.com/user-attachments/assets/f910fc6a-44a9-45d1-87c5-f0ce64bb3878
2026-02-19 15:23:46 +01:00
Charles BochetandGitHub ce1ffa8550 Refactor page layout types (#18042)
## Refactor page layout widget types into shared package and expose from
SDK

### Why

Widget configuration types were defined only on the server, forcing SDK
consumer apps to import from deep internal `twenty-shared/dist` paths —
fragile and breaks on structural changes. Server DTOs also had no
compile-time guarantee they matched the canonical types.

### What changed

- **`twenty-shared`**: Migrated `ChartFilter`, `GridPosition`,
`RatioAggregateConfig` and all 20 widget configuration variants into
`twenty-shared/types`. `PageLayoutWidgetConfiguration` (base, with
`SerializedRelation`) and `PageLayoutWidgetUniversalConfiguration`
(derived via `FormatRecordSerializedRelationProperties`) are now the
single source of truth.
- **`twenty-sdk`**: Re-exported `AggregateOperations`,
`ObjectRecordGroupByDateGranularity`, `PageLayoutTabLayoutMode`, and
`PageLayoutWidgetUniversalConfiguration` so consumer apps import from
`twenty-sdk` directly.
- **`twenty-server`**: All widget DTOs now `implements` their shared
type for compile-time enforcement. Added helpers to convert nested
`fieldMetadataId` ↔ `fieldMetadataUniversalIdentifier` inside chart
filters. Removed redundant local type re-exports.
2026-02-18 20:17:40 +01:00
martmullandGitHub 2cc3c75c7e Add example in create-twenty-app (#18043)
- add interactive mode to create-twenty-app
- by default create an example for each entities

<img width="1181" height="168" alt="image"
src="https://github.com/user-attachments/assets/a2490d8f-66a1-4cd5-bf41-57166cc20a1e"
/>
2026-02-18 18:04:19 +00:00
Charles BochetandGitHub c3781e87cc Sync page Layout (#18034)
## Sync page layouts, tabs, and widgets

Adds the ability for SDK applications to synchronize `pageLayout`,
`pageLayoutTab`, and `pageLayoutWidget` entities, following the same
pattern established in #18003 for views and navigation menu items.

### Changes

**`twenty-shared`**
- New `PageLayoutManifest`, `PageLayoutTabManifest`, and
`PageLayoutWidgetManifest` types with a hierarchical structure (page
layout → tabs → widgets)
- Added `pageLayouts: PageLayoutManifest[]` to the `Manifest` type

**`twenty-sdk`**
- New `definePageLayout()` SDK function with validation for
universalIdentifier, name, and nested tabs/widgets
- Wired into the manifest extraction and build pipeline
(`DefinePageLayout` target function, `PageLayouts` entity key)
- Exported from the SDK entry point

**`twenty-server`**
- Added `pageLayout`, `pageLayoutTab`, `pageLayoutWidget` to
`APPLICATION_MANIFEST_METADATA_NAMES`
- New conversion utilities: manifest → universal flat entity for all
three entity types
- Updated `computeApplicationManifestAllUniversalFlatEntity
2026-02-18 17:55:04 +01:00
martmullandGitHub 53c314d0fa 2094 extensibility define postinstall orand preinstall function to run in application (#18037)
- add a new optional key `postInstallLogicFunctionUniversalIdentifier`
in applicationConfig
- seed postInstall function in create-twenty-app
- update execute:function options
- update doc
2026-02-18 15:38:22 +00:00
Charles BochetandGitHub 7332379d26 Improve API Client usage and add Typescript check (#18023)
## Summary


https://github.com/user-attachments/assets/1e75cc9d-d9d2-4ef2-99f9-34450f5d8de7



Add background incremental type checking (`tsc --watch`) to the SDK dev
mode, so type regressions are caught when the generated API client
changes — without requiring a full rebuild of source files.

Previously, removing a field from the data model would regenerate the
API client, but existing front components/logic functions referencing
the removed field wouldn't surface type errors (since their source
didn't change, esbuild wouldn't rebuild them).

## What changed

- **Background `tsc --watch`**: a long-lived TypeScript watcher runs
alongside esbuild watchers, incrementally re-checking all files when the
generated client changes. Only logs on state transitions (errors appear
/ errors clear) to stay quiet.
- **Atomic client generation**: API client is now generated into a temp
directory and swapped in atomically, avoiding a race condition where
`tsc --watch` could see an empty `generated/` directory
mid-regeneration.
- **Step decoupling**: orchestrator steps no longer receive
`uploadFilesStep` directly. Instead, they use callbacks (`onFileBuilt`,
`onApiClientGenerated`), and each step manages its own `builtFileInfos`
state.
- **`apiClientChecksum` omitted from `ApplicationConfig`**: it's a
build-time computed value, same as `packageJsonChecksum`.
<img width="327" height="177" alt="image"
src="https://github.com/user-attachments/assets/02bd25bb-fa41-42b0-8d96-01c51bd4580c"
/>

<img width="529" height="452" alt="image"
src="https://github.com/user-attachments/assets/61f6e968-365b-4a5b-8f2b-a8419d6b1bd3"
/>
2026-02-18 13:26:30 +01:00
Abdul RahmanGitHubCopilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>DevessierFélix Malfait
015ccbf0a7 Navbar customization improvements (#17863)
- Add folder icon editing support
- And other navbar customization fixes/improvements.

---------

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Co-authored-by: Devessier <baptiste@devessier.fr>
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
2026-02-17 19:53:52 +00:00
Thomas TrompetteandGitHub b4e924b671 Sync views and navigation items (#18003)
Both objects are necessary to fully enjoy objects within applications

<img width="770" height="311" alt="Capture d’écran 2026-02-17 à 15 19
43"
src="https://github.com/user-attachments/assets/48c51fa4-63f4-45b2-a40a-df73f3aa79be"
/>
2026-02-17 16:32:41 +01:00
Paul RastoinandGitHub 2b7b05de2e [OBJECT_MANIFEST_BREAKING_CHANGE] Sync returns workspace migration (#17918)
# Introduction
In this PR we start returning a workspace migration post sync so it can
committed and provided within the tarball

## Universal aggregators utils
Created two utils
### deleteUniversalFlatEntityForeignKeyAggregators
Used when building a universal create action, a newly created actions
should not contain any aggregated foreign key so they won't be codegen
in the workspace migration but also they are overriden at uninversal to
flat transpilation anw

### resetUniversalFlatEntityForeignKeyAggregators
Used before validating a new flat entity creation, some validator will
consume the fk aggregator in order to validate integrity, but of
optimstically provided it can result to errors. To avoid caller
responsability we override them here

## create-field-action refactor
Refactored the universal and flat field create action to be following
the base actions in order to ease typing
Also it was tailored to handle unlimited amount of flat field metadata
in the same actions whereas in the reality we were always only sending
at max 2 ( for relation fields )

Note: relation field has to be provided at the same as if not optimistic
would fail to retrieve circular universal identifiers

## ObjectManifest
Now always expect a `labelIdentifierFieldMetadataUniversalIdentifier`

## Integration test
Created an integration test that creates an app, sync a first manifest
and a second implying update workspace migration action generation
2026-02-16 15:00:24 +01:00
martmullandGitHub 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"
/>
2026-02-16 10:43:29 +01:00
martmullandGitHub a4ed043d43 Logic function refactorization (#17861)
As title
2026-02-12 11:40:49 +01:00
Paul RastoinandGitHub b2f7c745f8 Solo transaction application synchronization service refactor (#17864)
# Introduction
Refactoring the application sync service to be making a single validate
build and run transaction instead of calling all the services n times
thanks to the universal workspace migration refactor that allow doing so

## What's next
Migrating all below entities to by syncableEntities so they can be
universalised too ( right now they're still calling the services n times
and won't be returned in the workspace migration )
-
[objectPermission](https://github.com/twentyhq/core-team-issues/issues/2223)
-
[fieldPermission](https://github.com/twentyhq/core-team-issues/issues/2224)
-
[permissionFlag](https://github.com/twentyhq/core-team-issues/issues/2225)
2026-02-11 16:30:01 +00:00
martmullandGitHub 9162685b2e Reorganize logic function files (#17766)
reorganize according to

<img width="1243" height="725" alt="Pasted Graphic"
src="https://github.com/user-attachments/assets/ba65dd10-8eec-4b13-ad49-9726edd3b79c"
/>

Not working yet
2026-02-09 12:36:39 +01:00
WeikoandGitHub 9aa63f7ddc Add sync front component (#17748)
## Context
Allow twenty apps to sync front components
2026-02-08 23:00:23 +00:00
martmullandGitHub 65678ed99f Upload files instead ofsources (#17608) 2026-02-03 12:11:10 +01:00
Raphaël BosiandGitHub f0bc9fcb43 [FRONT COMPONENTS] Move to twenty-sdk (#17587)
Move front components from twenty-shared to twenty-sdk
2026-02-02 12:21:53 +00:00
MarieandGitHub 0001c2e7d0 [Apps] Apps marketplace (first draft) (#17562)
https://github.com/user-attachments/assets/c4e63edb-6e98-44bc-841f-ee110ae712d4

How it works
- `manifest.json` files are now committed when apps are published to our
repo
- to display available apps, from the server, we read into our github
repo, using a pod-scoped cache
- feature flagged
- app installation will be behind permission gate MARKETPLACE_APPS

Limitations and what is yet to develop
- content and settings tabs
- installed apps tab
- app installation
- test and potentially fix reading from .manifest.json once [Reshape
manifest
structure](https://github.com/twentyhq/core-team-issues/issues/2183) is
done. additional work is expected on assets notably. (couldnt properly
do it here as manifest.json will only be committed after this pr)
- we only read in community/ folder for now - we may want tochange that
- the cache is rather artisanal for now and scoped by pod - we may want
to change that
2026-01-30 17:32:32 +00:00
martmullandGitHub f46da3eefd Update manifest structure (#17547)
Move all sync entities in an `entities` key. Rename functions to
logicFunctions

```json
{
  application: {
    ...
  },
  entities: {
    objects: [],
    logicFunctions: [],
    ...
  }
}
```
2026-01-30 16:26:45 +01:00
martmullandGitHub 3412992e99 2162 Add asset watcher in twenty-sdk dev mode (#17513)
- assets are pushed in .twenty/output
- assets are uploaded in FileFolder.Assets
- not handled yet by the sync-manifest endpoint
2026-01-29 09:08:44 +00:00
Charles BochetandGitHub 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
martmullandGitHub f4ca69a474 Implement dev mode nice UI (#17471)
Implement a nice terminal UI for dev mode using INK

<img width="1512" height="721" alt="image"
src="https://github.com/user-attachments/assets/79a71f37-1b31-4761-9e8d-718ef029ceb8"
/>
2026-01-27 15:34:28 +00:00
martmullandGitHub 41d470e687 Implement sync in dev mode (#17405)
implement orchestrator to sync application in dev mode

Log example when starting dev mode, delete and add back functions

```bash
👩‍💻 Workspace - default
[init] 🚀 Starting Twenty Application Development Mode
[init] 📁 App Path: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto

[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/.gitignore
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/.nvmrc
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/.yarnrc.yml
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/README.md
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/eslint.config.mjs
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/package.json
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/tsconfig.json
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/yarn.lock
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/.yarn/install-state.gz
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/ooo.front-component.tsx
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/tata.object.ts
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/application.config.ts
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/default-function.role.ts
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world-2.function.ts
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world-3.function.ts
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world.front-component.tsx
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world.function.ts
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/myObject.object.ts
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/utils/toto.ts
[dev-mode] Building manifest...
[dev-mode] Successfully built manifest
[dev-mode] Syncing...
[dev-mode] ✓ Successfully built src/ooo.front-component.tsx
[dev-mode] Uploading .twenty/output/src/ooo.front-component.mjs...
[dev-mode] ✓ Successfully built src/app/hello-world-2.function.ts
[dev-mode] Uploading .twenty/output/src/app/hello-world-2.function.mjs...
[dev-mode] ✓ Successfully built src/app/hello-world.front-component.tsx
[dev-mode] Uploading .twenty/output/src/app/hello-world.front-component.mjs...
[dev-mode] ✓ Successfully built src/app/hello-world-3.function.ts
[dev-mode] Uploading .twenty/output/src/app/hello-world-3.function.mjs...
[dev-mode] ✓ Successfully built src/app/hello-world.function.ts
[dev-mode] Uploading .twenty/output/src/app/hello-world.function.mjs...
[dev-mode] Successfully uploaded .twenty/output/src/ooo.front-component.mjs
[dev-mode] Successfully uploaded .twenty/output/src/app/hello-world-3.function.mjs
[dev-mode] Successfully uploaded .twenty/output/src/app/hello-world.front-component.mjs
[dev-mode] Successfully uploaded .twenty/output/src/app/hello-world.function.mjs
[dev-mode] Successfully uploaded .twenty/output/src/app/hello-world-2.function.mjs
[dev-mode] ✓ Synced

[dev-mode] ✓ Successfully built src/app/hello-world-2.function.ts
[dev-mode] Uploading .twenty/output/src/app/hello-world-2.function.mjs...
[dev-mode] Successfully uploaded .twenty/output/src/app/hello-world-2.function.mjs
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world-2.function.ts
[dev-mode] Building manifest...
[dev-mode] Successfully built manifest
[dev-mode] Syncing...
[dev-mode] ✓ Synced
[dev-mode] Build failed:
[dev-mode]   Could not resolve "/Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world.function.ts"
[dev-mode]   Could not resolve "/Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world-3.function.ts"
[dev-mode]   Could not resolve "/Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world-2.function.ts"
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world.function.ts
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world-2.function.ts
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world-3.function.ts
[dev-mode] Building manifest...
[dev-mode] ⚠ No functions defined
[dev-mode] Successfully built manifest
[dev-mode] Syncing...
  🗑️  Removed src/app/hello-world-2.function.mjs
  🗑️  Removed src/app/hello-world-3.function.mjs
  🗑️  Removed src/app/hello-world.function.mjs
[dev-mode] ✓ Synced
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world-2.function.ts
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world-3.function.ts
[dev-mode] File changed: /Users/martinmuller/Desktop/twenty/packages/twenty-apps/toto/src/app/hello-world.function.ts
[dev-mode] Building manifest...
[dev-mode] Successfully built manifest
[dev-mode] Syncing...
[dev-mode] ✓ Successfully built src/app/hello-world-2.function.ts
[dev-mode] Uploading .twenty/output/src/app/hello-world-2.function.mjs...
[dev-mode] ✓ Successfully built src/app/hello-world-3.function.ts
[dev-mode] Uploading .twenty/output/src/app/hello-world-3.function.mjs...
[dev-mode] ✓ Successfully built src/app/hello-world.function.ts
[dev-mode] Uploading .twenty/output/src/app/hello-world.function.mjs...
[dev-mode] Successfully uploaded .twenty/output/src/app/hello-world.function.mjs
[dev-mode] Successfully uploaded .twenty/output/src/app/hello-world-2.function.mjs
[dev-mode] Successfully uploaded .twenty/output/src/app/hello-world-3.function.mjs
[dev-mode] ✓ Synced
```
2026-01-26 19:32:13 +00:00
0091ef5f6c Sync built files (#17379)
as title, upload built files to local storage

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-01-23 13:43:53 +01:00
Charles BochetandGitHub 210c66b5dd Add checksum to manifest (#17368)
## Refactor app-dev state management and build utilities

- Store only `manifest` in `AppDevState` instead of full
`ManifestBuildResult`; add `sourcePath` to `FileStatus`
- Pass `sourcePaths` directly to watchers instead of
`ManifestBuildResult`
- Only reset `fileUploadStatus` for functions/components when their
source paths change
- Add pure `updateManifestChecksum` utility that returns a new manifest
without side effects
- Extract `processEsbuildResult` to deduplicate build result processing
between watchers
- Rename `serverlessFunctions` → `functions` in SDK code (API unchanged)
- Extract `writeManifestToOutput` to shared `manifest-writer.ts`
2026-01-22 18:16:55 +01:00
Charles BochetandGitHub d537d941a7 Add sdk build (#17335)
## Summary

Adds `app:build` command as a one-shot version of `app:dev` - builds
manifest, functions, and front components once then exits (no watching).

**Changes:**
- Added `watch` option to `FunctionsWatcher` and
`FrontComponentsWatcher` to support both watch and one-shot modes
- Created `AppBuildCommand` reusing the same build logic as `app:dev`
with `watch: false`
- Added integration tests for `app:build` on both `rich-app` and
`root-app`
- Updated manifest types: `handlerPath` → `sourceHandlerPath` +
`builtHandlerPath`, `componentPath` → `sourceComponentPath` +
`builtComponentPath`
- Updated test app `package.json` scripts to match `create-twenty-app`
template
2026-01-22 14:36:40 +01:00
martmullandGitHub 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