1cdede89deaeee16b708bcd79f2e28e5fd02e4b0
366 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
965a2753d1 |
chore: bump version to 2.17.0 (#22088)
## Summary - Moves current version to previous versions array - Sets TWENTY_CURRENT_VERSION to the new version - Updates TWENTY_NEXT_VERSIONS with the next minor version - Bumps twenty-client-sdk, twenty-sdk, and create-twenty-app to the same version ## Checklist - [ ] Verify version constants are correct - [ ] Verify npm package versions match <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22088?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> Co-authored-by: Github Action Deploy <github-action-deploy@twenty.com> |
||
|
|
b5a1aed24b |
feat(server): run server-exposed logic functions in the owner workspace (#22002)
## Summary Implements the server-level logic-function tier in the simplest shape: a logic function is "server-exposed" iff its manifest entry carries `serverWebhookTriggerSettings`. Execution delegates to the owner-workspace copy of that function — billing, throttling, env vars, and the existing executor all apply uniformly against that workspace. Supersedes #21971 with the simplified design from that discussion (no `applicationRegistrationLogicFunction` registry, no dedicated manifest type, no separate SDK helper, no special throttling). ## Design - **Manifest**: `LogicFunctionManifest` gains `serverWebhookTriggerSettings?`. The declarative `workspaceIdResolver` shape is dropped. - **Materialization**: those settings become two new jsonb columns on `LogicFunctionEntity`. The manifest → flat converter and the create-from-source DTO/util forward them; the property-config map and editable-properties list are extended. - **Lookup**: a single QB query joins `logicFunction → application → applicationRegistration` and filters on `lf.workspaceId = reg.workspaceId` to get only the owner workspace's copy. - **Webhook**: `POST /webhooks/server/:logicFunctionUniversalIdentifier` → `ServerWebhookTriggerService.handle` → join lookup → `LogicFunctionTriggerService.run`. No registry table, no `:applicationRegistrationUniversalIdentifier` segment, no resolver. - **Gate**: `IS_SERVER_LOGIC_FUNCTION_ENABLED` config var (disabled by default). ## Test plan - [x] `npx jest server-webhook-trigger` — 9 unit tests across the webhook service. - [x] `npx jest logic-function` — 88 existing tests stay green. - [x] `npx nx typecheck twenty-server`. - [x] `npx nx lint:diff-with-main twenty-server`. - [x] Reset DB → init → run `database:migrate:prod` → run `database:migrate:generate --name pending-migration-check` → no drift. - [ ] Manual: hit `/webhooks/server/<uid>` end-to-end against a manifest carrying `serverWebhookTriggerSettings`. https://claude.ai/code/session_01GgsnCGmYJ26xRirx8va1Yh --- _Generated by [Claude Code](https://claude.ai/code/session_01GgsnCGmYJ26xRirx8va1Yh)_ <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22002?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
293ff4c462 |
Auto-generate app cover images from the app logo (#22011)
<img width="1388" height="858" alt="image" src="https://github.com/user-attachments/assets/59f16bf7-5908-4624-b3af-51416bbebba3" /> ## What When an app is built (`twenty build` / `twenty publish`), the SDK now generates a marketplace cover image and sets it as the app's screenshot, but only when the app declares a `logoUrl` and has no `screenshots`. The cover composites the app's logo and the Twenty logo over the branded halftone backdrop, matching the design reference. ## Why Most apps ship a logo but no screenshots, so their marketplace detail page had no hero visual. This gives them a polished cover for free, with no per-app design work. ## Notes for reviewers - Generation lives in the build path (`operations/build.ts`), not `buildManifest`, so `twenty dev` and the shared manifest builder are untouched. It is best-effort: on failure it logs a warning and the build continues. - The cover is written to `.twenty/output` and registered as a public asset + screenshot, so the existing copy/checksum/serve pipeline handles it unchanged. No app source files are modified. - Adds `sharp` as a runtime dependency of `twenty-sdk` (a build-time tool, like `esbuild`); it is not bundled into built apps. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22011?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
c52c983b90 |
Source app About description from README and improve internal app READMEs (#22012)
## What - The SDK manifest build now sources an app's `aboutDescription` (the long-form "About" tab content) from its `README.md`. An explicit `aboutDescription` in the config still wins, matching the existing marketplace CDN fallback. - Removed the now-duplicated `aboutDescription` from internal app configs and deleted the standalone `ABOUT_DESCRIPTION` constant files. - Rewrote internal app READMEs to read as user-facing About content: stripped developer/build/source-path noise, and expanded the thin ones. `call-recording` and `self-hosting` (one-liners over substantial apps) and `people-data-labs` were rewritten from a close reading of the code; `twenty-exa` was verified for accuracy. - Added a unit test (and a fixture README) covering README → `aboutDescription` in the build. ## Why The README and the About description were maintained separately and drifted. Making the README the single source keeps the About tab accurate and removes duplicated copy. ## Notes for reviewers - Internal apps depend on the published `twenty-sdk`, so the build change takes effect for them after an SDK release + dependency bump. Until then, published apps still get README → `aboutDescription` via the marketplace CDN sync. - Standard/Custom app descriptions are unchanged (they are resolved in the frontend, not via the manifest). <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22012?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
e59e102448 |
chore: bump version to 2.16.0 (#21973)
## Summary - Moves current version to previous versions array - Sets TWENTY_CURRENT_VERSION to the new version - Updates TWENTY_NEXT_VERSIONS with the next minor version - Bumps twenty-client-sdk, twenty-sdk, and create-twenty-app to the same version ## Checklist - [ ] Verify version constants are correct - [ ] Verify npm package versions match <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21973?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> Co-authored-by: Github Action Deploy <github-action-deploy@twenty.com> |
||
|
|
a682c8fa62 |
feat(sdk): declare row-level permission predicates in the role manifest (#21919)
## Why Apps can declare object and field permissions on a role via `defineRole`, but **not row-level security**. The RLS engine and the metadata-sync machinery already support predicates fully — they're first-class universal flat entities, the `FlatRole` already carries `rowLevelPermissionPredicateUniversalIdentifiers`, and the workspace-migration layer has builders/validators/handlers for them. The only gap was the **manifest layer**: `RoleManifest` had no field for predicates, so the sync converter always left them empty. As a result, the only way to ship RLS with an app was a post-install script that pushed predicates through the `upsertRowLevelPermissionPredicates` mutation. That mutation assigns predicates to the workspace's **generic custom application**, not the app that owns the role — so a single role's definition ends up split across two applications and drifts on every upgrade (you have to remember to re-run the script). The Partner app does exactly this today via `configure-partner-rls.ts`. ## What Adds `rowLevelPermissionPredicates` and `rowLevelPermissionPredicateGroups` to `RoleManifest` / `RoleConfig`, mirroring how `objectPermissions` / `fieldPermissions` already flow end-to-end: - **twenty-shared** — predicate + predicate-group manifest types on `RoleManifest` (referencing objects/fields by `universalIdentifier`, operand/logical-operator from the existing GraphQL enums). - **twenty-sdk** — `defineRole` accepts and validates them; the build derives deterministic predicate `universalIdentifier`s (groups keep an explicit one so predicates can reference them). - **twenty-server** — two converters turn manifest predicates/groups into universal flat entities during application-manifest sync, so they are created/updated/deleted together with the role and **owned by the app that ships it**. ### Bug fix found along the way The migration build order ran the `rowLevelPermissionPredicate(Group)` builders **before** the `role` builder, so a predicate declared alongside a brand-new role failed validation with `ROLE_NOT_FOUND`. They now run **after** the role builder, exactly like object/field permissions. ## Partner app (second commit) Converts `partner.role.ts` to declare its five predicates inline and **deletes `configure-partner-rls.ts`** + the `rls:configure` scripts — the workaround this PR is meant to retire. The predicates are byte-for-byte the same semantics as the script produced. > Live-deployment note: the existing script-created predicates are owned by the *custom* application, so the Partner app sync won't touch them. Clear them once (e.g. an empty upsert on the Partner role) around deploy to avoid duplicates. Kept as a **separate commit** so it can be split out if reviewers prefer. ## Testing - **Integration (full app):** new `successful-manifest-sync-row-level-permission-predicate.integration-spec.ts` — installs an app whose role declares a predicate and asserts the predicate row is created (and **owned by the app**, not the custom app), updated in place on re-sync, removed when dropped from the manifest, and removed on uninstall. Ran locally against a seeded test DB ✅. - Re-ran the existing cross-app permission + view-field manifest suites to confirm the build-order change doesn't regress object/field-permission sync (13/13 ✅). - **Unit (utils only):** `defineRole` validation and `fromRoleConfigToRoleManifest` deterministic-id derivation. - Docs: new "Row-level security" section in `apps/config/roles.mdx`. ## Scope notes / possible follow-ups - Surfacing RLS in the app-install permission summary UI was intentionally left out (predicates *restrict* rather than grant, and typically live on a non-default role) — easy follow-up if wanted. - The `upsertRowLevelPermissionPredicates` mutation still homes out-of-band predicates on the custom app for app-owned roles; making that consistent (or rejecting it, like field permissions already do) is a sensible follow-up. https://claude.ai/code/session_01MipAis9z9okd4oCm9HCKEf --- _Generated by [Claude Code](https://claude.ai/code/session_01MipAis9z9okd4oCm9HCKEf)_ <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21919?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
a870e034a6 |
Add twenty slack to internal application ci (#21849)
- adds `twenty-slack` to internal application ci - unify config with twenty-last-contact app - add base oxlint config to show error twenty-shared is used in internal app <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21849?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
3675f264f1 |
Infer record pickers for record-typed logic function workflow inputs (#21494)
## Context Logic functions can declare workflow inputs typed as records or arrays of records (e.g. the People Data Labs enrichment functions), but the workflow builder rendered those as a plain text input with a variable picker, which is not usable. ## What this does - Adds an `objectUniversalIdentifier` link on input schema properties, so a record-typed input is tied to a workspace object. - The SDK build infers it from a `TwentyRecord<'objectUniversalIdentifier'>` marker type in the handler signature, reading the object's universal identifier straight from the source; explicit input schemas can still set the field directly. - The workflow builder renders these inputs as a single record picker or a record multi-select with the variable picker on the right. Selected records are stored as record ids; `TwentyRecord<UID>` is a branded `string`, so the handler signature reflects that it receives ids (a bound variable resolves to whatever the referenced step produced). - The multi-select collapses overflowing chips into a `+N` badge (reusing `ExpandableList`) and its variable picker offers both record objects and fields. - Updates the People Data Labs enrichment inputs as the reference implementation. <img width="802" height="824" alt="CleanShot 2026-06-12 at 16 54 10@2x" src="https://github.com/user-attachments/assets/a0896d74-0aab-49bd-a173-14c578a2e533" /> <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21494?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
8034c7725f |
Reorganize twenty-ui into best-practice component domains and per-component folders (#21745)
Reorganizes `twenty-ui`'s component organization to follow how the best
UI libraries (MUI, Mantine, Base UI, Polaris) structure their source,
now that the package has stabilized.
**Taxonomy** — dissolves the meaningless `components/` junk-drawer and
the 107-file `display/` mega-category. New domains/subpaths:
`data-display`, `typography`, `icon`, `surfaces`; `feedback` and
`layout` absorb the rest (banners/callout/info + placeholders →
feedback; modal/card → surfaces; motion + separators → layout).
**Per-component layout** — every component is now
`<domain>/<ComponentName>/<ComponentName>.tsx` with colocated
styles/stories/types, `internal/` for private helpers and `parts/` for
re-exported compound sub-parts. The redundant inner `/components/` is
gone. `icon` and `json-visualizer` are kept as cohesive subsystems.
**Also:** adds a tree-shakeable root barrel (`import { Button } from
'twenty-ui'`), the generator now owns `individual-entry.ts`, and a real
barrel-leak bug is fixed (private `internals/` parts were leaking into
the public API).
Consumer imports (~1.2k files) and the `twenty-sdk` UI aggregator were
updated by codemod. The change is **export-neutral** except 16
intentionally-removed private internals symbols (all verified
unconsumed). Gates green: typecheck, lint, build, size-limit, storybook.
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21745?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
|
||
|
|
9c9c34fccf |
Remove twenty-ui-deprecated and migrate frontend to twenty-ui (#21596)
Migrates `twenty-front`, `twenty-sdk`, and `twenty-front-component-renderer` from `twenty-ui-deprecated` to `twenty-ui` (mechanical import swap — the packages have API parity) and deletes the deprecated package along with its workspace/CI/config wiring. Also adds `@linaria/react`/`@linaria/core` as direct deps of `twenty-front` (it used them transitively via the deprecated package). Note: move the required status check from `ci-ui-status-check` to `ci-new-ui-status-check`. Argos: the Storybook box-model/button-reset baseline shift (the bulk of the visual diffs) is isolated in #21665 — Storybook now loads twenty-ui's global `reset.scss`, which the production app already ships. Once #21665 merges and this branch is rebased, the remaining Argos diffs are component-level visual-parity items only. |
||
|
|
257f130fff |
feat(sdk): let docker:start choose the server version (#21690)
## What Makes `yarn twenty docker:start` version-selectable. Same core feature as #21686 — but here scaffolded apps default to `latest` (pinning is **opt-in**) rather than being pinned to the scaffolder's version. > Alternative to #21686. Pick one; the difference is only the scaffolded default. Two layers of resolution: 1. **Explicit flag** — `yarn twenty docker:start [version]`, mirroring the existing `docker:upgrade [version]`. 2. **App-pinned default** — when no version is passed, `docker:start` reads `twenty.serverVersion` from the app's `package.json`, falling back to `latest`. Generated apps ship `twenty.serverVersion: "latest"`, so default behavior is unchanged. To make the local server reproducible as code, set a version: ```json filename="package.json" { "twenty": { "serverVersion": "2.2.0" } } ``` ## Changes - `twenty-sdk`: new `getAppServerVersion()` util reads `twenty.serverVersion` from the cwd's `package.json`; `serverStart` gains a `version` option and resolves `option → app pin → latest`, building the image via `getImageForVersion()`; `docker:start [version]` (and the deprecated `server start [version]` alias) wired up. - `create-twenty-app`: template `package.json` ships `twenty.serverVersion: "latest"`. (`create-app` and the scaffolder are otherwise untouched.) - Docs: `local-server.mdx` documents version selection and the opt-in pin. ## Behavior notes - Default with no pin and no flag is `latest` — same as today. - Version only matters when **creating** a fresh container — an existing container keeps its image until `docker:upgrade` / `docker:reset`. ## Testing - New unit tests for `getAppServerVersion` (5 cases). - Extended the `app-template` scaffolding test to assert the `latest` default. - `twenty-sdk` cli vitest suite (273) and `create-twenty-app` jest suite (9) pass; oxlint + oxfmt clean on changed files. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21690?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
9001078cb2 |
fix(cli): detect expired token on deploy and offer interactive re-auth (#21335)
## I have read the CONTRIBUTING.md file. YES ## What kind of change does this PR introduce? Fix (CLI) — `twenty deploy` now detects an expired/invalid API key on the active remote and offers an interactive re-auth flow (TTY only). In non-TTY contexts the behavior is unchanged: a clear error and a non-zero exit. Fixes #20197 ## What is the current behavior? After a workspace DB reset, key revocation, or workspace deletion, both `twenty deploy` and (effectively) `twenty dev` fail with: ``` Upload failed: Token has expired. ``` The message is technically correct but gives the user no way forward. They have to know to mint a new key from **Settings → Developers** and re-run `twenty remote add --local --api-key <NEW_KEY>`. This came up while testing PR #20181 and is the same friction on any DB reset, key revocation, or workspace deletion. ## What is the new behavior? Two changes, layered: ### (1) Better error message + remediation hint When the upload returns a 401 or its message matches a token-expired pattern (`/token has expired|unauthori[sz]ed|invalid api key/i`), `appDeploy` now prints: ``` Your API key for remote "local" is no longer valid (the workspace may have been reset, or the key was revoked). Re-authenticate with: twenty remote:add --as local --api-key <NEW_KEY> Generate a new key at: <SERVER_URL>/settings/developers ``` ### (2) Interactive re-auth prompt (TTY only) If the process is attached to a TTY, after the hint is printed the user is prompted: ``` Re-authenticate now? (Y/n) ``` - **Yes** → re-validate the token (it may have been refreshed externally), and if still invalid, instruct the user to re-run `remote:add`. The original `appDeploy` is then retried once. - **No** → the original `DEPLOY_FAILED` error is surfaced (same code, better message). - **Non-TTY (CI, scripts, redirects)** → the prompt is suppressed entirely. The user gets the hint and a non-zero exit, preserving scriptable behavior. **No change** to existing CI scripts. ## Acceptance criteria | Scenario | Before | After | |---|---|---| | Happy path deploy | ✅ works | ✅ works (no change) | | Deploy with expired key (TTY) | generic error, exit 1 | hint + prompt, retry on Y, error on N | | Deploy with expired key (CI / no-TTY) | generic error, exit 1 | hint + exit 1 (no prompt, scriptable) | | Deploy with unrelated error (e.g. 500) | generic error, exit 1 | unchanged (no false positive on the matcher) | ## Reproduction 1. Spin up Twenty, mint an API key, run `twenty deploy` — confirm the happy path. 2. Reset the DB (`core.appToken` cleared) and re-run `twenty deploy` — confirm the new hint + prompt fire and the retry succeeds. 3. Repeat step 2 in a non-TTY context (e.g. `twenty deploy < /dev/null` or via `script -qc ''`) — confirm the prompt is suppressed and the scriptable exit-1 behavior is preserved. ## Implementation notes - **`FileApi.uploadAppTarball`** now tags 401 responses with an `isAuthError: true` flag on the failing `ApiResponse`. The existing `error` string is still populated so callers that don't check the flag continue to work — **additive, no breaking change**. - **`FailingApiResponse<TError>`** gained an optional `isAuthError?: boolean` field. The other `ApiResponse` call sites in the SDK don't need to set it. - **`@/cli/utilities/auth/reauth-helper.ts`** is new. It owns: - `isTokenExpiredMessage(...)` — pure matcher, easy to unit-test, used as a backstop if a non-401 message still says "expired" (GraphQL returns 200 with errors in some cases). - `promptForReauthentication(remoteName)` — TTY-gated `inquirer.confirm` prompt that re-validates the token and either returns `'reauthenticated'`, `'declined'`, or `'non-interactive'`. - **`@/cli/operations/deploy.ts`** is the single call site that wires the helper. The helper is structured so it can be reused from the dev orchestrator's upload step (a follow-up) without changes. - **New unit test** at `__tests__/reauth-helper.test.ts` covers the matcher: positive cases, negative cases, case-insensitivity, and nullish input. ## Out of scope (per the issue) - Long-lived dev tokens for `--local` remotes. - Web-based OAuth login flow for the CLI (the existing `authenticate(...)` flow in `remote.ts` is fine; the prompt here just tells the user to re-run it). ## Files changed ``` packages/twenty-sdk/src/cli/operations/deploy.ts | 33 ++++++++ packages/twenty-sdk/src/cli/utilities/api/api-response-type.ts | 1 + packages/twenty-sdk/src/cli/utilities/api/file-api.ts | 8 +++ packages/twenty-sdk/src/cli/utilities/auth/__tests__/reauth-helper.test.ts | 34 ++++++++++ packages/twenty-sdk/src/cli/utilities/auth/reauth-helper.ts | 61 ++++++++++++++++++ 5 files changed, 137 insertions(+) ``` Happy to address feedback and split this into two PRs (hint-only first, prompt-on-top) if the maintainers prefer a smaller first cut. --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: martmull <martmull@hotmail.fr> |
||
|
|
206120677b |
chore: bump version to 2.15.0 (#21624)
## Summary - Moves current version to previous versions array - Sets TWENTY_CURRENT_VERSION to the new version - Updates TWENTY_NEXT_VERSIONS with the next minor version - Bumps twenty-client-sdk, twenty-sdk, and create-twenty-app to the same version ## Checklist - [ ] Verify version constants are correct - [ ] Verify npm package versions match <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21624?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> Co-authored-by: Github Action Deploy <github-action-deploy@twenty.com> |
||
|
|
fdab89ae02 |
Move twenty-client-sdk to dev dep (#21611)
# Introduction The `twenty-client-sdk` is always provided and injected at runtime by the twenty-server instance Which mean that even if in your app locally you're using twenty-client-sdk `1.0` installing this app on twenty instance `2.0` will result in injecting another `twenty-client-sdk` That's the expected behavior and tradeof The twenty-app devdep should only be used to guide local devxp following typesafety and so on A user can still locally generated its own twenty-client-sdk and publish it if necessary <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21611?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
5207493cda |
Add useColorScheme hook to twenty-sdk (#21595)
Ability to update front compoonent design according to the dark or white theme of the UI <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21595?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
5f59ae20bf |
chore: bump version to 2.14.0 (#21593)
## Summary - Moves current version to previous versions array - Sets TWENTY_CURRENT_VERSION to the new version - Updates TWENTY_NEXT_VERSIONS with the next minor version - Bumps twenty-client-sdk, twenty-sdk, and create-twenty-app to the same version ## Checklist - [ ] Verify version constants are correct - [ ] Verify npm package versions match <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21593?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> Co-authored-by: Github Action Deploy <github-action-deploy@twenty.com> |
||
|
|
7c0136b97b |
feat(deps): migrate frontend to React 19 (#21531)
## What Migrates the frontend stack from **React 18.3 → 19.2**. The website, sdk, companion and emails packages were already on React 19; this brings the remaining holdouts (`twenty-front`, `twenty-ui`, `twenty-ui-deprecated`, `twenty-front-component-renderer`) and `twenty-server`'s email rendering onto 19, and pins a single React version repo-wide. ## Why React 18.x is now the legacy line. Staying current keeps us on the patched/maintained branch and unblocks downstream library majors (react-router 7, mantine 9, etc.) that require React 19 peers. ## Dependency bumps (required by React 19 peers / removed APIs) | Package | From | To | Reason | |---|---|---|---| | react / react-dom | 18.3.1 | 19.2.3 | core | | @hello-pangea/dnd | 16 | 18 | peer `^18 \|\| ^19` | | react-datepicker | 6 | 9 | v<7 used removed `findDOMNode`; drops `@types/react-datepicker` | | react-data-grid | beta.13 | beta.59 | peer `^19.2`; new render API | | graphiql (+ @graphiql/react, plugin-explorer) | 3 / 0.23 / 1 | 5 / 0.37 / 5.1 | peer `^18 \|\| ^19` | | react-helmet-async | 1.3 | **@dr.pogodin/react-helmet** 3.2 | upstream caps peer at `^18`; drop-in React 19 fork | A `resolutions` pin enforces a single React (19.2.3) + `@types/react` (19.2.14) across the monorepo to avoid duplicate copies / type-identity splits. Versions are the aged lockfile patches (clears the `npmMinimalAgeGate`). ## Code changes - **Global `JSX` shim** (`react-jsx-global.d.ts` per package): React 19 moved the `JSX` namespace under `React.JSX`; several deps' published types (notably `@linaria/react`'s `styled.d.ts`, which types every `styled.x` via `keyof JSX.IntrinsicElements`) still reference the global namespace. Without the shim, every styled component degrades to `any` props. - **Ref nullability**: `useRef<T>(null)` now returns `RefObject<T | null>`; widened consumer prop/hook ref types accordingly (incl. the shared `useListenClickOutside`). - **react-datepicker v9**: `onChange`/`onSelect` accept `Date | null`, `calendarStartDay` typing, `ReactDatePickerProps`→`DatePickerProps`, relaxed the dynamic `selectsMultiple` discriminated union. - **react-data-grid beta.59**: `formatter`→`renderCell`, `editor`→`renderEditCell`, `headerRenderer`→`renderHeaderCell`, `components`→`renderers`, `onRowClick`→`onCellClick`, object-shaped `useRowSelection`, Set-based selection. - **dnd style cast**: `@radix-ui/react-popper` augments `CSSProperties` with a `--radix-*` index signature that dnd's closed `DraggingStyle` doesn't satisfy → cast at the spread. ## Status / testing - ✅ `typecheck` green: twenty-front, twenty-ui, twenty-ui-deprecated, twenty-front-component-renderer, twenty-server - ⏳ build / lint / unit tests / storybook+argos / runtime smoke-test in progress Draft until local + CI verification completes. Notable behavior to QA manually: spreadsheet import (data-grid), date pickers, drag-and-drop boards/lists, GraphQL playground, page titles/favicon. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21531?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
869680a5a1 |
fix(deps): esbuild ^0.28.1 floors + vite 7→8 (rolldown) upgrade (#21517)
## What this does Resolves the remaining esbuild security alerts on packages we own, and upgrades the repo to **Vite 8** (which drops esbuild entirely in favour of rolldown/oxc). ### 1. esbuild → `^0.28.1` (security) - Raised the declared `esbuild` floor in `twenty-sdk` and the logic-function common-layer (both were `^0.25.0`, which can only resolve to a vulnerable version). These are our packages, so this is just declaring the patched version — clears Dependabot **#1467** and **#1468**. ### 2. Vite 7 → 8 - Bumped `vite` to `^8` in the 5 packages that declare it, and `@vitejs/plugin-react-swc` to `^4.3.1` (the only plugin that needed a bump for Vite 8; everything else already supports it). - `twenty-front` keeps esbuild minification, so esbuild is now an explicit (patched) devDependency there — Vite 8 no longer ships it. ### Two Vite-8 fallout fixes (bundler internals changed) - **Storybook tests:** added React to `optimizeDeps.include` so Vite's dep optimizer doesn't re-bundle React mid-run and break in-flight imports in browser-mode tests. - **`hex-rgb`:** it's ESM-only and broke rolldown's CJS interop (a default import resolved to the wrong thing under jest). Replaced its one use with a tiny inline hex→rgb parse and dropped the dependency. ## Verified Vite resolves to a single `8.0.16` with no esbuild in its tree. Builds pass on Vite 8/rolldown: `twenty-front` production build, the SDKs, and Storybook; the previously-failing front and storybook test jobs now pass; `yarn install --immutable` is clean. ## Note This doesn't close root alert **#1469** — esbuild is still pulled by other third-party tools (storybook, tsx, lingui, zapier, etc.) that haven't shipped a patched release. The vulnerable code path (esbuild's dev server) isn't used here, so that one is best dismissed as not-affected. |
||
|
|
e293c33311 |
Normalize defaultValue properly (#21511)
<img width="1506" height="338" alt="image" src="https://github.com/user-attachments/assets/3ee0d5c9-af32-4ef3-83c9-2f4671219126" /> |
||
|
|
adb60a3867 |
fix(sdk): avoid shell command injection in CLI exec calls (#21508)
## What Fixes the 5 open [CodeQL code-scanning alerts](https://github.com/twentyhq/twenty/security/code-scanning) of type `js/shell-command-constructed-from-input` (medium severity) in the `twenty-sdk` CLI. All flagged call sites built a shell command string by interpolating library inputs (`containerName`, `image`, `npmTag`) and ran it via `execSync`, which executes through a shell. A value containing shell metacharacters could break out of the intended command. ## Changes - `packages/twenty-sdk/src/cli/utilities/server/docker-container.ts` — every `docker` call switched from `execSync` with a template string to `execFileSync('docker', [...args])`. Arguments are passed as an array, so the binary runs directly without a shell and inputs are never reparsed. The single quotes that were shell-quoting the `-f` format strings are removed since there is no shell. - `packages/twenty-sdk/src/cli/operations/publish.ts` — `npm publish` switched to `execFileSync` with `--tag`/value as separate array elements. On Windows the binary resolves to `npm.cmd` (no shell to do the lookup). ## Verification - `npx nx typecheck twenty-sdk` passed - `npx nx lint twenty-sdk` passed <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21508?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
49026a7368 |
chore: bump version to 2.13.0 (#21492)
## Summary - Moves current version to previous versions array - Sets TWENTY_CURRENT_VERSION to the new version - Updates TWENTY_NEXT_VERSIONS with the next minor version - Bumps twenty-client-sdk, twenty-sdk, and create-twenty-app to the same version ## Checklist - [ ] Verify version constants are correct - [ ] Verify npm package versions match <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21492?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> Co-authored-by: Github Action Deploy <github-action-deploy@twenty.com> |
||
|
|
fa9aeea408 |
Add dev:generate-client command to sdk (#21489)
## after `yarn twenty dev:generate-client` <img width="1149" height="246" alt="image" src="https://github.com/user-attachments/assets/1edcba03-2647-4bc8-8188-7ad69362ac52" /> <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21489?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> |
||
|
|
deb956f4fe |
security: bump wait-on 7.2.0 -> 9.0.10 to drop vulnerable joi (Dependabot alert 1437) (#21457)
## Context Two open Dependabot alerts; this PR fixes one with a parent bump (no resolutions), the other is dismissed with analysis (see below). ## joi RangeError DoS (alert 1437, fixed in joi 18.2.1) `joi@17.13.3`'s only parent is `wait-on@7.2.0` (twenty-sdk devDependency, used purely as a CLI: `yarn start`'s `wait-on tcp:3000` and CI's `wait-on http://localhost:3000/healthz --timeout --interval`). Bumping **wait-on 7.2.0 → 9.0.10** (which depends on `joi ^18.2.1`) evicts joi 17 from the lockfile entirely — no forced ranges. Verified: twenty-sdk builds; wait-on 9 smoke-tested with both invocation shapes used in the repo (`tcp:PORT`, `http://… --timeout --interval`). ## @cyntler/react-doc-viewer TXTRenderer "XSS" (alert 1436) — dismissed as inaccurate CVE-2026-30691 claims arbitrary JS execution via a crafted .txt because TXTRenderer "casts raw data as a ReactNode". Verified against the installed 1.17.1 dist: the renderer is `children: currentDocument?.fileData` where the txt fileLoader produces `fileData` via `FileReader.readAsText` — i.e. **always a string rendered as a React child, which React HTML-escapes**. There is no `dangerouslySetInnerHTML`/eval in the path (the only `dangerouslySetInnerHTML` occurrence in the bundle is styled-components' prop whitelist regex). String children cannot execute script in React; the advisory's premise is wrong, and consistently upstream has published no fix. Alert dismissed as *inaccurate* with this analysis. Longer-term, `@cyntler/react-doc-viewer` remains a liability (stale since 2025-09, already needs an ajv resolution) — replacing it with first-party preview renderers is tracked separately. |
||
|
|
a825dcf2cc |
security: clear 8 Dependabot alerts via transitive/parent bumps (no resolutions) (#21409)
Clears 8 Dependabot alerts via in-range transitive/parent bumps and one dead-dependency removal. **No `resolutions` overrides** were used — every fix is a real version bump within existing semver ranges or a parent upgrade. ### Root `yarn.lock` - **react-router** 6.30.3 → 6.30.4 (open redirect via protocol-relative URL) — pulled through react-router-dom, ranges unchanged — alert #1382 - **yaml** 2.8.1 → 2.9.0 (stack overflow on deeply nested collections) — alert #734 - **uuid** `^13.0.0` → 13.0.2 in twenty-sdk + create-twenty-app (buffer bounds check) — alert #1164 - **ip-address** `^9.0.5` dropped by bumping **socks** 2.8.3 → 2.8.9 (now depends on `ip-address ^10.1.1`, which is unaffected) — alert #1171 ### `seed-dependencies` lockfile - **uuid** `^10.0.0` → `^11.1.1` (direct dep; removed now-redundant `@types/uuid` since uuid v11 ships its own types) — alert #1287 - **ip-address** `^9.0.5` dropped via the same socks bump — alert #1170 ### `twenty-for-twenty` lockfile - **resend** bumped to 6.12.4 (`^6.12.0` range kept), which drops its `svix@1.90.0 → uuid@^10` transitive chain — alert #1278 ### `twenty-companion` - Removed the unused **simplemde** dependency. The note editor loads SimpleMDE from a CDN `<script>` tag and never imports the npm package; `easymde` (its maintained fork) is already a dependency — alert #690 ### Not addressed here The remaining alerts can't be closed without `resolutions` overrides (deliberately avoided in this PR) or a larger migration: - **qs** (#1305, #1304), **lodash** (#824 high / #823 / #385), **ws** (#1238), **postcss** (#1061) — vulnerable copies are pinned exact / bundled by parents (express, body-parser, @nestjs/*, next, styled-components, zapier) with no in-range patch. - **webpack-dev-server** (#1237/#692/#691) — pinned by `@electron-forge/plugin-webpack` (still on v4); dev-tooling only. - **uuid <11.1.1** (#1289) — spread across `^3`/`^8`/`^9` transitive ranges; reaching v11 is a breaking jump. - **apollo-server-core** (#735/#736) — requires an Apollo Server 3 → 4 migration. |
||
|
|
6525af5ba4 |
Improve log visibility in dev mode (#21393)
Small PR to improve logging in twenty sdk dev mode ## After <img width="1406" height="580" alt="image" src="https://github.com/user-attachments/assets/a14edc2d-2194-420a-8b0b-b3ca35c31ccd" /> |
||
|
|
c5e95c6649 |
Enrich app:add field relation and morph relations (#21368)
# Before <img width="833" height="358" alt="image" src="https://github.com/user-attachments/assets/e006bc5b-79e8-449f-beba-eb75393a9c60" /> # After <img width="1015" height="383" alt="image" src="https://github.com/user-attachments/assets/586f19df-e43b-45bc-9b26-16573108e750" /> <img width="1061" height="413" alt="image" src="https://github.com/user-attachments/assets/962635fa-6cdf-4aef-a1ea-cd129c5ff656" /> |
||
|
|
beaa4e636c |
Remove default command (#21357)
fix conflict with not existing commands |
||
|
|
ed7ff4a84b |
chore: bump version to 2.12.0 (#21358)
## Summary - Moves current version to previous versions array - Sets TWENTY_CURRENT_VERSION to the new version - Updates TWENTY_NEXT_VERSIONS with the next minor version - Bumps twenty-client-sdk, twenty-sdk, and create-twenty-app to the same version ## Checklist - [ ] Verify version constants are correct - [ ] Verify npm package versions match Co-authored-by: Github Action Deploy <github-action-deploy@twenty.com> |
||
|
|
1d81bdbb22 |
Fix breaking change with dry run input (#21356)
- fix dry-run input parameter breaking change - remove duplicated log |
||
|
|
37b986aa4b |
security: vendor @genql/cli codegen to drop undici/native-fetch (#21339)
## What Vendors a narrowed copy of [`@genql/cli@3.0.5`](https://github.com/remorses/genql) (MIT) into `packages/twenty-client-sdk/src/generate/genql/` and repoints the two client generators at it, then removes `@genql/cli` from `twenty-client-sdk`, `twenty-sdk` and `create-twenty-app`. ## Why `@genql/cli` was used **only** to generate the typed GraphQL client from an SDL string. It is unmaintained and pulls in vulnerable/abandoned transitives — `undici@5` (**30 Dependabot alerts**), `native-fetch`, `listr`, `yargs`, etc. None of these were ever executed by Twenty: the sole consumer of `undici`/`native-fetch` is `@genql/cli`'s live-endpoint schema-introspection path, and Twenty always passes a schema string, never an endpoint. Removing the package eliminates the dependency at the source — for Twenty and for scaffolded end-user apps. ## What changed vs upstream The vendored copy (`genql/README.md` + `genql/LICENSE`) keeps the `render/` and `runtime/` trees verbatim and narrows the orchestration: - **Dropped the endpoint/introspection path** (`schema/fetchSchema.ts`) — the only `undici`/`native-fetch`/`qs` consumer. - **Dropped `listr`** — generation tasks run as plain sequential `async` functions (file contents unchanged). - **Replaced `fs-extra`/`mkdirp`/`rimraf`** with `node:fs`. - **Runtime templates are imported as `?raw`** and bundled, instead of read from `node_modules` at generation time. - **Kept `prettier@^2.8` and `@graphql-tools/*`** so the generated output is byte-for-byte identical. ## Verification - **Byte-identical output**: regenerating the metadata client from its committed schema produces a recursive-diff-clean result vs the previous `@genql/cli` output (including the copied `runtime/` folder). The core client generates and esbuild-bundles cleanly. - The public `twenty-client-sdk/generate` barrel API is unchanged (twenty-server / twenty-sdk consumers unaffected). - `undici@^5`, `native-fetch`, `@genql/cli`, `listr`, `yargs@^15` and `subscriptions-transport-ws@0.9` are gone from `yarn.lock` (net −364 lines). - `twenty-client-sdk` and `twenty-sdk` typecheck, lint and build; `twenty-client-sdk` tests pass (9/9). ## Notes - The vendored folder is excluded from `oxlint`/`oxfmt` (it is third-party code, with `@ts-nocheck` on the verbatim renderers, mirroring the generated output). - Stacks conceptually on #21334 (drops `@genql/runtime`); the two are independent and only overlap trivially in `yarn.lock`. `@genql/runtime` is intentionally left for that PR. |
||
|
|
a0fb157899 |
fix(sdk): bump inquirer ^10 -> ^14 to drop external-editor/tmp from apps (#21340)
The **central fix** for the `tmp` Dependabot alerts in `packages/twenty-apps/*` — so apps don't each need a per-app `resolutions` entry. ### Root cause Every app depends on `twenty-sdk`, whose inquirer chain pulls the vulnerable `tmp`: ``` twenty-sdk → inquirer ^10 → @inquirer/prompts 7.x → @inquirer/editor 4.x → external-editor → tmp@0.0.33 ``` `@inquirer/editor 5.x` dropped `external-editor` (and thus old `tmp`), and it's only reached via `@inquirer/prompts 8.x`, which requires **inquirer ≥ 13.4.3**. So `^12` isn't enough — bump to **`^14`** (latest): ``` inquirer 14 → @inquirer/prompts 8.5.2 → @inquirer/editor 5.2.2 (no external-editor) ``` ### Verified - The SDK uses the classic `inquirer.prompt([...])` API (uninstall / add / remote commands) — **typechecks cleanly under inquirer 14**. - After the bump, the SDK's subtree resolves `@inquirer/editor@5.2.2` (the lingering `external-editor` in this repo's lockfile is from *other* consumers — `nx`/`zapier` — handled separately). ### Propagation Fixes it **once** for every app using the SDK, with no per-app `package.json` additions. Existing `twenty-apps/*` clear their `tmp` alert once a new `twenty-sdk` is published and they bump to it; newly-scaffolded apps are clean immediately. (The root-workspace `tmp` from `nx`/`zapier` is handled by twenty#21338.) |
||
|
|
356cec5f24 |
security: drop unused @genql/runtime dependency (#21334)
## What Removes the `@genql/runtime` dependency from `twenty-client-sdk` and `twenty-sdk`. It was declared but **never imported** in source. ## Why The genql codegen (`@genql/cli` `generate()`) inlines a **fully self-contained runtime** into every generated client — see the committed `twenty-client-sdk/src/metadata/generated/runtime/` (all relative imports) and the generated `index.ts` which imports from `./runtime`, not `@genql/runtime`. So the `@genql/runtime` package was dead weight in the dep graph. Dropping it prunes its abandoned, vulnerable transitive deps **at the source**: - `ws@^6` (old) - `subscriptions-transport-ws@0.9.x` - `isomorphic-unfetch` - `zen-observable-ts` - `graphql-query-batcher` - `lodash` None are used by Twenty — the generated client makes plain `fetch` GraphQL requests and has no `ws`-based subscriptions. ## Verification - `@genql/runtime` is gone from `node_modules` and `yarn.lock` (103 lockfile lines removed); the remaining `subscriptions-transport-ws@0.11.0` is a different, maintained version pulled by an unrelated package. - `twenty-client-sdk` and `twenty-sdk` typecheck. - `twenty-client-sdk` unit tests pass (9/9). - With `@genql/runtime` physically removed from `node_modules`, `generate()` still emits a complete, self-contained client (`index.ts` imports `./runtime`). ## Scope `@genql/cli` (the codegen, which pulls `undici`) is intentionally **not** touched here — it is still required for client generation and will be addressed separately. |
||
|
|
c596a5e342 |
Rename twenty-ui to twenty-ui-deprecated and twenty-new-ui to twenty-ui to prepare package release (#21315)
## Description Promotes the next-gen UI library (formerly `twenty-new-ui`) to the name **`twenty-ui`** (v0.1.0, publishable) and renames the old package to **`twenty-ui-deprecated`**. Rewrites ~1,730 `twenty-ui` imports → `twenty-ui-deprecated`, updates all configs/CI/Docker/deps, and migrates twenty-front's `Toggle` to the new package (first consumer) as a drop-in. ## Next steps - Wire the `ui/v*` publish dispatch (`cd-deploy-tag.yaml` + `.yarnrc.yml`), then tag `ui/v0.1.0` to publish. - Continue migrating components from `twenty-ui-deprecated` → `twenty-ui`. |
||
|
|
77d1e8ced6 |
feat(app-dev): sync error hints, flatEntity labels, dev-mode summary UI, and docs (#21252)
Split out of #21240 — all remaining app-dev improvements. Stacked on #21251 (review/merge that first). - Actionable recovery hints on failed syncs; unified diff renderer; `--dry-run` guard. - Return `flatEntity` on update/delete sync actions and unify the diff label. - Summarize the dev-mode entity list unless `--verbose`. - Docs: syncing & recovery guide + dry-run + open-an-issue prompt. - Live execution mode for synced logic functions; clearer manifest warnings. <img width="1018" height="700" alt="image" src="https://github.com/user-attachments/assets/5e9ce19e-0f1d-4f99-8524-4e118bde932b" /> |
||
|
|
d2e7dc0e74 |
security: bump vulnerable direct dependencies (axios, next, vitest, qs, dompurify, …) (#21309)
## What Within-major version bumps of **direct** dependencies to clear a large batch of Dependabot alerts that are breaching (or near) their SLA. No major-version changes — all stay within the current major, so risk is low. | Package | From → To | Clears | |---|---|---| | `axios` | ^1.13.5 → ^1.16.0 | ReDoS, Proxy-Auth leak, proto-pollution gadgets, NO_PROXY bypass, resource DoS (56 alerts) | | `next` | 16.1.7 → ^16.2.6 | DoS, middleware/proxy bypass, SSRF, cache poisoning, XSS (32 alerts) | | `vitest` | 4.0.18 → ^4.1.0 | **CRITICAL** — UI server arbitrary file read/exec (#1421) | | `qs` | ^6.11.2 → ^6.15.2 | `qs.stringify` DoS | | `dompurify` | 3.3.3 → ^3.4.0 | proto-pollution XSS + FORBID_TAGS / SAFE_FOR_TEMPLATES bypasses | | `@nestjs/core` | 11.1.16 → ^11.1.18 | improper output neutralization / injection | | `nodemailer` | 8.0.4 → 8.0.10 | SMTP command injection via CRLF (bumped via root `resolutions`) | | `path-to-regexp` | ^8.2.0 → ^8.4.0 | ReDoS via multiple wildcards | | `file-type` | ^21.3.1 → ^21.3.2 | ZIP decompression-bomb DoS | | `@opentelemetry/exporter-prometheus` | ^0.211.0 → ^0.217.0 | exporter process crash via malformed HTTP request (#1183/#1184) | ## Notes - Added a `next` root **resolution** so the dev-only `@react-email/preview-server` copy (hard-pinned at `16.0.10`) is also pulled up to the patched `16.2.x` line — otherwise that copy keeps the Next.js alerts open. - `@opentelemetry/exporter-prometheus` 0.217 pulled `@opentelemetry/sdk-metrics` to 2.7.1 (compatible); `@opentelemetry/api` stays pinned at 1.9.1. - **Transitive-only** vulnerable packages (undici, tmp, ws, brace-expansion, …) are handled in a **separate PR** per the split-by-group plan. - Breaking major bumps (electron, uuid, serialize-javascript) and migrations (Apollo Server 3→4, simplemde) are intentionally **out of scope** here. |
||
|
|
6c65d26ced |
feat(app-dev): add dry-run preview to dev sync (#21251)
Split out of #21240. Stacked on #21250 (review/merge that first). `yarn twenty dev --once --dry-run` computes the migration plan and prints the diff **without applying anything** (no migration, no app-record update, no SDK generation). Also renders the diff on a normal `dev --once` sync. <img width="646" height="179" alt="image" src="https://github.com/user-attachments/assets/59f3ddcd-2a5b-4b8a-b21a-c659abe16af0" /> |
||
|
|
2dbdd72e65 |
chore: bump version to 2.11.0 (#21259)
## Summary - Moves current version to previous versions array - Sets TWENTY_CURRENT_VERSION to the new version - Updates TWENTY_NEXT_VERSIONS with the next minor version - Bumps twenty-client-sdk, twenty-sdk, and create-twenty-app to the same version ## Checklist - [ ] Verify version constants are correct - [ ] Verify npm package versions match Co-authored-by: Github Action Deploy <github-action-deploy@twenty.com> |
||
|
|
f20d04eb6e |
feat(app-dev): surface metadata diff in dev sync and name failing migration actions (#21249)
Split out of #21240. - Render the applied metadata changes (created/updated/deleted + identifiers) in the dev sync output instead of a bare `✓ Synced`. - Include the failing entity's `universalIdentifier` in `WorkspaceMigrationRunnerException` messages so conflicts are diagnosable. <img width="637" height="114" alt="image" src="https://github.com/user-attachments/assets/61422a16-370c-4e9b-a2f6-c29ce17f3b1b" /> <img width="497" height="104" alt="image" src="https://github.com/user-attachments/assets/d493c398-da29-49c9-ac5e-aa0f26cd7389" /> <img width="593" height="127" alt="image" src="https://github.com/user-attachments/assets/15e26edc-c0e4-4427-bd34-909040e970c9" /> --------- Co-authored-by: Charles Bochet <charles@twenty.com> |
||
|
|
128d2d394d |
feat: allow apps to add view fields to existing views (defineViewField) (#21160)
## Summary
Lets a Twenty application add **view fields (columns) to an existing
view it does not own** — including standard views like the People index
view — without redeclaring/owning that view. This mirrors the existing,
working pattern by which an app adds a custom field to a standard object
via `defineField` + `objectUniversalIdentifier`.
The asymmetry being removed was purely in the manifest schema:
`ViewFieldManifest` only existed *nested* inside
`ViewManifest.fields[]`, so adding a view field forced declaring a
`ViewManifest` — which the sync treats as a view the app creates and
owns, and rejects when the UID is a standard view's. Validation,
persistence, the FK aggregator machinery, and uninstall cleanup were
already generic and cross-app-safe, so no engine changes were needed.
### Changes
- **twenty-shared:** new top-level `StandaloneViewFieldManifest`
(`ViewFieldManifest & { viewUniversalIdentifier }`),
`Manifest.viewFields`, and a `SyncableEntity.ViewField` member.
- **twenty-sdk:** `defineViewField` (validates `universalIdentifier` +
`viewUniversalIdentifier` + `fieldMetadataUniversalIdentifier`), CLI
manifest assembly of a top-level `viewFields` list, and `dev:add
viewField` scaffolding.
- **twenty-server:** one top-level loop over `manifest.viewFields` that
reuses the existing `fromViewFieldManifestToUniversalFlatViewField`
converter (already parameterized by `viewUniversalIdentifier`). No
validator/persistence/aggregator changes.
### Notes for maintainers
- Confirm the `Manifest.viewFields` optionality convention — implemented
as a **required** array to mirror `fields`/`views`.
- Two different apps adding a column for the same field to the same view
conflicts on the existing unique `(fieldMetadataId, viewId)` partial
index; the existing `flat-view-field-validator` duplicate check surfaces
this as a structured validation error.
- `dev:add viewField` scaffolding is included (was optional in the
plan).
## Test Plan
- [x] `twenty-shared` typecheck
- [x] `twenty-sdk` 364 unit tests + `buildManifest` assembly test
(rich-app fixture) + typecheck + prettier
- [x] `twenty-server` typecheck + `lint:diff-with-main`
- [x] **Server integration suite**
`successful-manifest-update-view-field.integration-spec.ts` (4/4):
- standalone view field attaches to the standard `allPeople` view
without recreating it (sync succeeds, no
`INVALID_VIEW_DATA`/`ENTITY_ALREADY_EXISTS`)
- uninstall removes the contributed column while the standard view + its
columns remain intact
- duplicate `(view, field)` rejected with `METADATA_VALIDATION_FAILED`
- unknown target view rejected
- [x] Sibling `successful-manifest-update-field.integration-spec.ts`
still green (no harness regression)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
||
|
|
c2ca90c255 |
feat(sdk): add runAgent() to run app agents from logic functions (#21157)
<img width="948" height="593" alt="image" src="https://github.com/user-attachments/assets/d990fa98-3cfd-469d-ab7f-0b2d4ccf3afc" /> <img width="1361" height="802" alt="image" src="https://github.com/user-attachments/assets/1091f598-49f3-4c16-92ea-1e1c200181e2" /> ## Add `runAgent()` to the Logic Function SDK Lets an app's logic function run one of its own AI agents server-side and get the result back synchronously — reusing the existing agent executor instead of a new bespoke transport. ### Backend - New **`runAgent` GraphQL mutation** (metadata schema) in `ai-agent-execution`, wrapping the existing `AgentAsyncExecutorService.executeAgent`. Scopes the agent lookup to the calling application and runs it under an application auth context. - New `@AuthApplication()` param decorator (mirrors `@AuthWorkspace()`) — first GraphQL resolver authenticated by an **application access token**. - Guarded by `WorkspaceAuthGuard` + `SettingsPermissionGuard(PermissionFlagType.AI)`: the app's role must grant the `AI` permission flag. ### SDK - `runAgent({ agentUniversalIdentifier, prompt })` posts the mutation to `/metadata` with the app token via a new runtime GraphQL transport. Returns `{ result, hasNoMoreAvailableCredits }`. - Refactored the connections helpers onto a shared `postAppEndpoint` util (removes duplicated transport logic). ### Frontend - App install permission modal now shows an explicit consent line — _"Run AI agents and bill AI credits to your workspace"_ — when the app's role requests the `AI` flag. ### Docs - Documented `runAgent` and its `AI` permission-flag requirement in _Skills & Agents_. - Fixed outdated role-permission examples in _Roles & Permissions_ (`permissionFlags` → `permissionFlagUniversalIdentifiers`, `PermissionFlag` → `SystemPermissionFlag`). ### Test plan - [x] SDK unit tests (`run-agent.spec.ts`) — request shape, GraphQL/HTTP error handling, missing env vars - [x] `twenty-server`, `twenty-front`, `twenty-shared` typecheck + lint - [ ] Manual: install an app granting the `AI` flag, call `runAgent()` from a logic function, confirm the agent runs and credits are billed --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> |
||
|
|
e0d42323af |
Add more control on http trigger (#21216)
add "new Response" utils to define response code or content type of http route triggered logic function responses follow up of https://github.com/twentyhq/twenty/pull/21214 --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
6a2c948e84 |
chore: bump version to 2.10.0 (#21218)
## Summary - Moves current version to previous versions array - Sets TWENTY_CURRENT_VERSION to the new version - Updates TWENTY_NEXT_VERSIONS with the next minor version - Bumps twenty-client-sdk, twenty-sdk, and create-twenty-app to the same version ## Checklist - [ ] Verify version constants are correct - [ ] Verify npm package versions match Co-authored-by: Github Action Deploy <github-action-deploy@twenty.com> |
||
|
|
0671ff3de5 |
Fix lambda error (#21179)
- move twenty-sdk from dependencies to devDependencies - add documentation about breaking - add warning about moving the package to dev dependencies |
||
|
|
b330105470 |
Fix Unzipped size must be smaller than 250Mb error (#21172)
move dev dependencies into devDependencies |
||
|
|
b2539f5b6a |
Prevent conditional availability variables from being used at runtime (#21110)
Fixes https://github.com/twentyhq/twenty/issues/21094 Conditional availability variables (`objectMetadataItem`, `numberOfSelectedRecords`, `objectPermissions`, operators like `everyEquals`/`none`, etc.) are compile-time-only constructs used in `conditionalAvailabilityExpression`. They were previously exported from `twenty-sdk/front-component`, which let developers mistakenly import them into runtime component code where they have no value. - Move conditional availability variables from `twenty-sdk/front-component` to `twenty-sdk/define`. - Add a build-time manifest validation (validate-conditional-availability-usage) that fails the build if these variables are imported/used outside of `conditionalAvailabilityExpression`. - Update the github-connector example app to register commands via dedicated *.command-menu-item.ts files instead of inline command config in front components. - Update docs (all locales) and test mocks to reflect the new import paths. |
||
|
|
26906951b3 |
fix(twenty-sdk): minify front-component bundles & set NODE_ENV=production in deploy build (#20937)
## Summary
`twenty deploy` (and `twenty build`) currently ship front-component
`.mjs` bundles **unminified**, with `process.env.NODE_ENV` undefined at
build time. Two missing options in
`get-base-front-component-build-options.ts` — fix is two lines.
## Why this matters
Each front-component bundle includes React + ReactDOM + the design
system AOT (only `twenty-client-sdk/{core,metadata}` are listed in
`FRONT_COMPONENT_EXTERNAL_MODULES`). A trivial widget measures **~2 MB**
unminified. Because every widget mount spawns a fresh Web Worker that
re-fetches and re-parses the bundle (`FrontComponentWorkerEffect.tsx`),
that 2× size translates directly into 2× cold-start latency on **every
record-page navigation and every browser refresh**. On a CRM with even a
handful of custom widgets this dominates perceived UI latency.
## Why it bites every app, not one user
Reference apps in this repo
(`packages/twenty-apps/fixtures/{minimal,rich}-app`,
`community/github-connector`, `internal/twenty-for-twenty`) ship the
same way — verified by inspecting the released `twenty-sdk@2.5.0`
bundle. There's no CLI flag, env var, or config option to opt into a
production build. A search of issues/PRs for "minify", "bundle size",
"production build" surfaces nothing tracking this.
## Fix
Enable `minify: true` and `define: { 'process.env.NODE_ENV':
'"production"' }` in the base front-component build options. These flow
through `build-application.ts` (the orchestrator for `twenty deploy` and
`twenty build`).
**Watch mode (`twenty dev`) is intentionally untouched.**
`esbuild-watcher.ts` has its own configuration path that doesn't consume
`getBaseFrontComponentBuildOptions()`; it stays unminified so local
rebuilds remain fast and stack traces remain readable during
development.
## Measured impact
Two production extension apps using `twenty-sdk@2.5.0`:
| File | Before | After | Δ |
|---|---:|---:|---:|
| `oapps-deal-items` (single widget) | 2,114,953 B | 863,444 B |
**−59%** |
| `oapps-document-hub/documents-panel` | 2,120,341 B | 872,478 B |
**−59%** |
| `oapps-document-hub/hub-document-record` | 2,077,013 B | 852,544 B |
**−59%** |
| `oapps-document-hub/field-mapping-editor` | 1,168,941 B | 255,787 B |
**−78%** |
End-user effect: opening an Opportunity record with two custom-widget
tabs went from ~3-4s widget paint to under 1s on the same machine, same
browser, same record.
## Risk / scope
- **No behavior change.** Minification is a transparent transform;
`NODE_ENV=production` is the standard signal libraries already gate on.
No app code changes needed.
- **No effect on `twenty dev`** — separate code path.
- **No effect on logic functions** — they use their own build-options
object.
- One file touched.
## Test plan
- [ ] `yarn twenty deploy` on
`packages/twenty-apps/fixtures/minimal-app` → output `.mjs` is mangled
and `process.env.NODE_ENV` no longer appears literally inside the
bundle.
- [ ] `yarn twenty dev` on the same app → output `.mjs` remains
readable.
- [ ] Existing CI green.
Happy to add a feature-flag (`TWENTY_BUILD_MODE` env var or `twenty
deploy --no-minify` escape hatch) if maintainers prefer that over
unconditional minification.
---------
Co-authored-by: 8Maverik8 <8maverik8@users.noreply.github.com>
Co-authored-by: martmull <martmull@hotmail.fr>
|
||
|
|
4e5d47168c |
2439 improve command menu item display in right panel (#21020)
## Before <img width="1512" height="389" alt="image" src="https://github.com/user-attachments/assets/33274356-fb99-4a02-baa7-c324e6d151c6" /> ## After <img width="1512" height="357" alt="image" src="https://github.com/user-attachments/assets/c0affb71-e920-4d64-b2f0-1bed53209ea5" /> |
||
|
|
6d550611d2 |
chore(deps): bump typescript from 5.9.2 to 5.9.3 (#20991)
Bumps [typescript](https://github.com/microsoft/TypeScript) from 5.9.2 to 5.9.3. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/microsoft/TypeScript/releases">typescript's releases</a>.</em></p> <blockquote> <h2>TypeScript 5.9.3</h2> <p>Note: this tag was recreated to point at the correct commit. The npm package contained the correct content.</p> <p>For release notes, check out the <a href="https://devblogs.microsoft.com/typescript/announcing-typescript-5-9/">release announcement</a></p> <ul> <li><a href="https://github.com/Microsoft/TypeScript/issues?utf8=%E2%9C%93&q=milestone%3A%22TypeScript+5.9.0%22+is%3Aclosed+">fixed issues query for Typescript 5.9.0 (Beta)</a>.</li> <li><a href="https://github.com/Microsoft/TypeScript/issues?utf8=%E2%9C%93&q=milestone%3A%22TypeScript+5.9.1%22+is%3Aclosed+">fixed issues query for Typescript 5.9.1 (RC)</a>.</li> <li><em>No specific changes for TypeScript 5.9.2 (Stable)</em></li> <li><a href="https://github.com/Microsoft/TypeScript/issues?utf8=%E2%9C%93&q=milestone%3A%22TypeScript+5.9.3%22+is%3Aclosed+">fixed issues query for Typescript 5.9.3 (Stable)</a>.</li> </ul> <p>Downloads are available on:</p> <ul> <li><a href="https://www.npmjs.com/package/typescript">npm</a></li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/microsoft/TypeScript/commit/c63de15a992d37f0d6cec03ac7631872838602cb"><code>c63de15</code></a> Bump version to 5.9.3 and LKG</li> <li><a href="https://github.com/microsoft/TypeScript/commit/8428ca4cc8a7ecc9ac18dd0258016228814f5eaf"><code>8428ca4</code></a> 🤖 Pick PR <a href="https://redirect.github.com/microsoft/TypeScript/issues/62438">#62438</a> (Fix incorrectly ignored dts file fr...) into release-5.9 (#...</li> <li><a href="https://github.com/microsoft/TypeScript/commit/a131cac6831aa6532ea963d0cb3131b957cad980"><code>a131cac</code></a> 🤖 Pick PR <a href="https://redirect.github.com/microsoft/TypeScript/issues/62351">#62351</a> (Add missing Float16Array constructo...) into release-5.9 (#...</li> <li><a href="https://github.com/microsoft/TypeScript/commit/04243333584a5bfaeb3434c0982c6280fe87b8d5"><code>0424333</code></a> 🤖 Pick PR <a href="https://redirect.github.com/microsoft/TypeScript/issues/62423">#62423</a> (Revert PR 61928) into release-5.9 (<a href="https://redirect.github.com/microsoft/TypeScript/issues/62425">#62425</a>)</li> <li><a href="https://github.com/microsoft/TypeScript/commit/bdb641a4347af822916fb8cdb9894c9c2d2421dd"><code>bdb641a</code></a> 🤖 Pick PR <a href="https://redirect.github.com/microsoft/TypeScript/issues/62311">#62311</a> (Fix parenthesizer rules for manuall...) into release-5.9 (#...</li> <li><a href="https://github.com/microsoft/TypeScript/commit/0d9b9b92e2aca2f75c979a801abbc21bff473748"><code>0d9b9b9</code></a> 🤖 Pick PR <a href="https://redirect.github.com/microsoft/TypeScript/issues/61978">#61978</a> (Restructure CI to prepare for requi...) into release-5.9 (#...</li> <li><a href="https://github.com/microsoft/TypeScript/commit/2dce0c58af51cf9a9068365dc2f756c61b82b597"><code>2dce0c5</code></a> Intentionally regress one buggy declaration output to an older version (<a href="https://redirect.github.com/microsoft/TypeScript/issues/62163">#62163</a>)</li> <li>See full diff in <a href="https://github.com/microsoft/TypeScript/compare/v5.9.2...v5.9.3">compare view</a></li> </ul> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Félix Malfait <felix.malfait@gmail.com> Co-authored-by: Weiko <corentin@twenty.com> Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Félix Malfait <FelixMalfait@users.noreply.github.com> |
||
|
|
6fb6ef4e7a |
Add darkmode for oAuth screen (#21005)
## after <img width="1512" height="828" alt="image" src="https://github.com/user-attachments/assets/71664eab-c921-45da-ac67-7a660c976d5c" /> |
||
|
|
e6221c5f0e |
Fix twenty sdk billing exports (#21016)
Fix two omissions from #19973 that prevented `twenty-sdk/billing` from being a fully exported subpath: - `package.json`: add `billing` to `typesVersions` (every other subpath was listed; billing was the only one missing, breaking type resolution for consumers using classic TS moduleResolution). - `project.json`: add the billing vite build and `dist/billing` output to the `build:sdk` target |