e515f174a437cfdca47d9bf561fbcce361ce0366
12770 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e515f174a4 |
Load twenty-ui global styles in twenty-front Storybook (#21665)
Loads `twenty-ui/style.css` in twenty-front's Storybook preview,
matching the real app — `src/index.tsx` already imports it, but
`.storybook/preview.tsx` only loaded the deprecated stylesheet, so
Storybook rendered without twenty-ui's global `reset.scss`
(`*{box-sizing:border-box}` + a native `button` reset) that the
production app has.
This isolates the resulting box-model/button-reset baseline shift ahead
of the `twenty-ui-deprecated` removal PR. The Argos diff here is exactly
that global shift (Storybook catching up to how the app already renders)
and is expected — bulk-approve. Once this lands, the removal PR's Argos
will show only genuine deprecated→twenty-ui component diffs instead of
being buried under ~240 reset-driven diffs.
Only the reset applies in this PR: twenty-ui's component CSS targets
hashed module classes that don't exist in the deprecated-rendered
Storybook, and `reset.scss` is the only global selector twenty-ui emits.
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21665?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. -->
|
||
|
|
a67fdf2dac |
Clean up MCP Monaco editor (#21643)
Rebuild the MCP setup block on the shared Monaco editor with theme-driven colors, padding, and auto-height; add the settings description line-height token; revert the clipboard util to the shared navigator.clipboard implementation; and consolidate the code editor's auto-height to a single disposed, reactive effect. |
||
|
|
ce92a1f1e1 |
Update GitHub banners and remove unused assets (#21655)
saves 24mb duly checked |
||
|
|
b7c68e082e |
Enable inline field editing in calendar event details (#21666)
before - https://github.com/user-attachments/assets/b6645bb5-0ffc-4281-b054-2035c865ba77 after - https://github.com/user-attachments/assets/a62a1134-c959-4281-aefe-b04e310b4926 <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21666?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. --> |
||
|
|
b327999b04 |
fix(server): run 2-14 standard relation label/icon heal as a system build (#21667)
## Problem The `2-14:fix-standard-relation-field-labels-icons` workspace upgrade command aborts the upgrade, failing for every workspace that has drift to heal with: ``` FIELD_MUTATION_NOT_ALLOWED: System fields only allow updating: universalSettings, isActive. Forbidden properties: icon ``` The default relation fields it heals (note/task/attachment/timeline) on standard objects are **system-owned**. The flat-field-metadata validator forbids mutating any property other than `universalSettings`/`isActive` on a system field **unless the migration runs as a system build** (`buildOptions.isSystemBuild`). The command omitted `isSystemBuild`, so it defaulted to `false` and the heal was rejected. ## Fix Pass `isSystemBuild: true` when building the heal migration — consistent with every other standard-metadata upgrade command (2-3, 2-5, 2-7, 2-8, 2-9, 2-10, 2-13, other 2-14 commands). ## Notes - Follow-up to #21658, which added the error-surfacing diagnostics that revealed this root cause but did not include this fix. - `label` and `icon` are both in `FLAT_FIELD_METADATA_RELATION_PROPERTIES_TO_COMPARE`, so the relation-field validator (not gated on `isSystemBuild`) already permits them — the system-build flag was the only blocker. - Dry-run returns before the build step, so this only manifests on real runs. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21667?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. --> |
||
|
|
8205c97b5b |
fix(route-trigger): return 422 instead of 500 for logic function execution errors (#21656)
## What Return HTTP 422 instead of 500 for `LOGIC_FUNCTION_EXECUTION_ERROR` in the route trigger exception filter. ## Why When a logic function's user code fails (e.g. an HTTP call inside the function returns a 502 from an upstream service), the exception was mapped to HTTP 500. This caused two problems: - **Sentry noise**: `shouldCaptureException` captures all 5xx responses, so every user-code failure was reported as a platform error. This generated ~56k Sentry events over 2 months for a single workspace's logic function hitting a transient upstream 502. - **Webhook retry loops**: Webhook senders like GitHub auto-retry on 5xx responses, amplifying the event count. `LOGIC_FUNCTION_EXECUTION_ERROR` is a user-code error, not a platform error. A 422 (Unprocessable Entity) correctly signals that the request could not be processed due to the logic function's own failure, without triggering Sentry capture or webhook retries. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21656?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. --> |
||
|
|
5cb8a091fc |
Add Recall webhook status handler to the meeting bot app (#21659)
Adds a `recall-webhook` logic function (`POST /webhook/recall`, unauthenticated) to the `twenty-meeting-bot` app. It verifies the Recall/Svix `whsec_` signature over the raw body, parses bot lifecycle events, matches the corresponding `CallRecording` (by `twentyCallRecordingId` metadata, falling back to `externalBotId`), and updates lifecycle fields — `status`, `externalBotId`, `externalRecordingId`, and `startedAt`/`endedAt` (only when unset) — guarded against stale out-of-order events that would move the status backwards. Adds the required `RECALL_WEBHOOK_SECRET` server variable. This opens the real provider test path: install the app → schedule a bot through the existing calendar-event flow → point a Recall webhook endpoint at Twenty → bot lifecycle events update the matching `CallRecording`. Unit tests cover signature verification, status mapping, the downgrade guard, metadata/bot-id matching, and timestamp fill. Deferred to later PRs: - transcript/media ingestion, file uploads, and the completion charge (so `COMPLETED` is never set here) - repair/reconcile cron jobs Also flips `DEFAULT_RECALL_REGION` to `eu-central-1` (separate commit) to match the Recall account region. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21659?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. --> |
||
|
|
ee6c9db33a |
fix(server): surface validation errors in 2-14 fix-standard-relation-field-labels-icons upgrade command (#21658)
## Problem
The \`2-14:fix-standard-relation-field-labels-icons\` workspace upgrade
command threw a generic error on migration build failure:
\`\`\`ts
if (result.status === 'fail') {
throw new Error(\`Migration failed for workspace \${workspaceId} while
healing standard relation field labels/icons\`);
}
\`\`\`
This discarded \`result.report\` entirely — the structured per-field
validation failures (\`code\`, \`message\`, \`value\`, offending field)
— making real-world upgrade failures impossible to diagnose from logs.
On a recent staging/app-main upgrade, 13 workspaces failed here with no
actionable detail.
## Change
Flatten \`result.report\` into both the logged error and the thrown
message, so failures now print the actual validation errors per field,
e.g.:
\`\`\`
[fieldMetadata] <universalIdentifier> -> SOME_VALIDATION_CODE: <real
reason>
\`\`\`
No behavior change beyond logging/error content — the command still
aborts on failure as before.
## Notes
- Dry-run still returns before the build step, so this only surfaces on
real runs (unchanged).
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21658?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. -->
|
||
|
|
c3835a839f |
fix(ui): default Monaco CodeEditor to scrollBeyondLastLine: false (#21657)
## Problem In the AI chat "Python Code Execution" panel (`CodeExecutionDisplay`), scrolling the code goes far past the last line, leaving a large empty area below the code. The root cause is in the shared `CodeEditor`: Monaco's `scrollBeyondLastLine` option **defaults to `true`**, which lets the viewport scroll roughly a full editor height past the last line. The shared component never set this option, so the Monaco default leaked through to every consumer. This affected every read-only viewer built on `CodeEditor` — the code interpreter, `WorkflowReadonlyActionCode`, `WorkflowStepExecutionResult`, and `SettingsLogicFunctionTriggerPayloadFormat` — and each one had to remember to disable it (only `WorkflowEditActionCode` did). ## Change Set `scrollBeyondLastLine: false` in the shared `CodeEditor` defaults, in both the active `twenty-ui-deprecated` copy and the `twenty-ui` copy (kept in sync). Since `options` is spread last, any editor that genuinely wants scroll-past-end can still opt back in with `scrollBeyondLastLine: true`. ## Impact - **Auto-fixed** the read-only viewers that showed dead scroll space (code interpreter, workflow readonly action, step execution result, trigger payload sample). - The editable editors that previously inherited Monaco's default (`SettingsLogicFunctionCodeEditor`, `RawJsonFieldInput`, `SettingsLogicFunctionTestTab`, `ConfigVariableDatabaseInput`) now also stop at the last line — consistent with `WorkflowEditActionCode`, which already opted out. Any of these can re-enable scroll-past-end via `options` if desired. ## Testing Behavior verified by inspection against Monaco's option semantics and existing usages. Note: dependencies were not installed in the authoring environment, so `lint`/`typecheck` were not run locally — `scrollBeyondLastLine: false` is a standard, type-safe Monaco option already used with this component elsewhere. Worth a CI check. https://claude.ai/code/session_01CWzyw1spKF8Dog9E5tcdj4 --- _Generated by [Claude Code](https://claude.ai/code/session_01CWzyw1spKF8Dog9E5tcdj4)_ <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21657?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: Claude <noreply@anthropic.com> |
||
|
|
d4b597e14e |
fix(docker): run twenty-server in production mode (NODE_ENV=production) (#21635)
## What
Set `ENV NODE_ENV=production` in the `twenty-server` Docker stage
(inherited by `twenty-server-aws` and `twenty`).
## Why — root cause of the empty verification emails
Verification emails have been delivered with an **empty body** in
deployed environments — the subject renders ("Bienvenue chez Twenty :
Veuillez confirmer votre email") but the HTML is `<!DOCTYPE
…><!--$!--><template></template><!--/$-->`, an **errored React Suspense
boundary**. Prod logs showed:
```
TypeError: dispatcher.getOwner is not a function
```
Chain:
1. The prod server stages never set `NODE_ENV`, so at runtime it's
**unset** → React loads its **development** builds.
2. Since the **React 18→19 upgrade** (#21531), React 19's dev JSX
runtime calls `dispatcher.getOwner()` (React 18's did not — which is why
this is a recent regression).
3. That call throws in the server runtime → the email React tree throws
during SSR → `@react-email/render` (which streams without an `onError`)
swallows it into an errored `<Suspense>` boundary → the body ships
empty. The subject is unaffected because it's built without React.
Production React never tracks owner, so `jsx()` never calls `getOwner` —
setting `NODE_ENV=production` removes the failing code path entirely.
It's also simply the correct prod configuration (dev React builds are
slower and emit dev-only behavior).
## Scope / safety
- Only the prod runtime stages are affected. The dev image
(`twenty-app-dev`) keeps its own `NODE_ENV=development`.
- Verified the deployed image currently bakes `NODE_ENV=[]` (unset) and
has a single, matched `react`/`react-dom` 19.2.7 — so this is a mode
issue, not a duplicate-React issue.
## Related
- Mitigation already in place: twentyhq/twenty-infra#729 disables email
verification on prod-eu meanwhile (revert once this ships).
- Diagnostic logging: #21628 (can be reverted after this lands).
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21635?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. -->
|
||
|
|
14d8105f22 |
fix(front): remove runtime default-view creation fallback (#21652)
## Problem `useCreateDefaultViewForObject` was a temporary runtime fallback that created a view + one view field per field (each with a fresh `v4()` id) whenever `RecordIndexLoadBaseOnContextStoreEffect` found no view for the current view id. Because the created view got a fresh id that never matched the requested `contextStoreCurrentViewId`, the next load missed again and re-created another duplicate — leaking `core.view` / `core.viewField` rows without bound (notably during the 2.13.0 cache-first bootstrap window). #21592 made the fallback idempotent as a stop-gap, but the mechanism is no longer needed at all: standard/index views are created server-side at object creation and during standard app installation, so the client never needs to mint them. ## Change Remove the fallback entirely: - Delete `useCreateDefaultViewForObject`. - In `RecordIndexLoadBaseOnContextStoreEffect`, when no view resolves for the current id, do nothing and let the loaded views settle (the effect re-runs once the view is present and loads it). ## Note This removes the leak at the source for any client running the new bundle. Clients still on old cached JS will keep creating duplicates until they reload; the already-leaked rows are being cleaned up separately via SQL. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21652?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. --> |
||
|
|
e83fa2108d |
Add single-record People Data Labs enrich functions (company & person) (#21650)
Adds two single-record enrichment logic functions to the People Data
Labs app — `enrich-company` and `enrich-person` — that call PDL's
single-record Enrichment endpoints (`/company/enrich`,
`/person/enrich`). Each function declares both a workflow-action trigger
and an AI-tool trigger, so the same function is usable as a workflow
step and as an AI tool. They take a single `{ recordId,
overrideExistingValues? }` and return a single `EnrichResult`.
The new functions replace the previous `enrich-company-tool` /
`enrich-person-tool` AI-tool functions (which delegated to the bulk
endpoints), avoiding duplicate near-identical tools for the LLM. The
bulk `enrich-companies` / `enrich-people` workflow actions are
unchanged.
Implementation reuses the existing enrichment machinery: the
single-record adapters spread the existing company/person adapters and
only override `enrichBatch`, so identifier extraction, TTL guard, field
mapping (fill-only-if-empty), billing, and error backoff all carry over.
A new `post-pdl-single-enrich` util posts params directly and classifies
the response via the existing `parsePdlItem`.
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21650?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. -->
|
||
|
|
ceb7698689 |
fix(ai) - workflow tool outputs optim + display fix (#21500)
<!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21500?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. --> |
||
|
|
12b1dba986 |
Add call recording scheduling backend (#21629)
This PR adds the backend scheduling slice for call recording. It wires the `twenty-meeting-bot` internal app to reconcile calendar events, calendar-channel associations, and workspace member auto-record preference changes, then schedule, cancel, or reschedule Recall bots based on the resulting policy. It also adds the needed calendar-channel owner lookup support, generated metadata updates, app config/default role updates, unit tests, and CI for the internal app. Coming next: - Recall webhook handling and signature validation - Stale-state convergence for failed Recall cleanup/recreate cases - Media, transcript, audio, and video ingestion - Billing charge flow - Frontend/settings UI for recording controls <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21629?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. --> |
||
|
|
065b6efe11 |
fix(twenty-partners): reuse existing company by domain in partner-application handler (#21615)
## Problem
Partner applications **502** for any applicant whose company is already
in the CRM.
The `submit-partner-application` logic function dedupes applicants
**only by person email**. When no person matches that email, it takes
the create path and calls `createCompany` unconditionally. But
`Company.domainName` has a **UNIQUE index**, so whenever a company with
the applicant's domain already exists — which is common, since the **TFT
import seeds companies** — the mutation throws `"duplicate entry"`. The
handler's `catch` returns `{ ok: false }`, and the website
`/api/partner-application` route surfaces it as a **502**. The applicant
can never be submitted.
Real case that surfaced this: an applicant whose company (`BKG
Integration UG`, domain `bkg-integration.de`) was already present from
the TFT import with no Partner/Person attached.
## Fix
Extract `findOrCreateCompanyId`:
- Look the company up by **exact domain** (`domainName.primaryLinkUrl
eq`) and **reuse** it when found.
- Only `createCompany` when no domain matches.
- The matched company is **never renamed** — the existing CRM name wins
over the applicant's free-text `companyName`.
Person-email dedup is unchanged (already handled upstream in the
handler).
### Known limitation
Matches **active** rows only. A *soft-deleted* company still holds the
unique index and would re-collide; clear those with `yarn purge:prod`.
Noted inline.
## Tests
Adds an integration test: pre-seed a company by domain → submit an
application with the same domain → assert the partner reuses the same
company id and the company name is untouched.
## Version
`twenty-partners` 0.5.1 → **0.5.2** (patch: bug fix, no schema change).
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21615?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. -->
|
||
|
|
504eaa5600 |
Fix relation-traversal filters showing no options on select fields (#21616)
Relation-traversal filters (e.g. *Company → Industry*) on `SELECT`/`MULTI_SELECT` fields rendered an empty option picker, so the filter couldn't be configured. The value inputs resolved the select options from the **source relation field** (which has no options) instead of the **relation target field**. Fixed in both filter UIs: - Dashboard chart filters and workflow "Find Records" (`AdvancedFilterSidePanelValueFormInput`) - Record-index simple & advanced filters and the role-permission filter builder (`ObjectFilterDropdownOptionSelect`) Both now resolve the value-input field and its options from `relationTargetFieldMetadataId` when a filter traverses a relation, falling back to the source field otherwise. ## Before <img width="802" height="702" alt="CleanShot 2026-06-15 at 17 27 35@2x" src="https://github.com/user-attachments/assets/032b0875-8a5a-4e09-a2ad-4c4a8a319f49" /> ## After <img width="804" height="796" alt="CleanShot 2026-06-15 at 17 27 05@2x" src="https://github.com/user-attachments/assets/88248409-5781-49c7-aa9e-3502ff8c68e4" /> <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21616?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. --> |
||
|
|
f77d8da8a7 |
i18n - docs translations (#21633)
Created by Github action Co-authored-by: github-actions <github-actions@twenty.com> |
||
|
|
f0c3883fd1 |
fix(command-menu-item): persist overrides after save and add reset-to-default (#21623)
## Context Command menu items are an overridable entity (like page-layout / FIELDS widgets), but the override flow in layout-customization mode was broken: - **Move / pin-unpin / hide-label didn't persist.** `useSaveCommandMenuItemsDraft` fired the `updateCommandMenuItem` mutations (backend persisted correctly) but never wrote the result back into `metadataStoreState`, the source the live menu and edit panel read from. So the UI reverted on exit and changes only showed after a hard reload. - **No true "reset to default".** Existing reset controls only reverted the draft to the last-saved values (which still contained overrides). there was no way to clear overrides back to the original values after a save. Notes - removed the footer "Reset to default" button. This is not clear to me how we want to build, let's re-implement better in the next version - reset are done on click and not delayed on the save. This is similar to other reset to default on page layouts where we actually usually reload the component and this is because the FE has no idea what's original VS override from the response itself <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21623?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. --> |
||
|
|
9dd097e11e |
fix(front): set up Monaco workers for GraphQL playground (#21620)
## Problem The GraphQL API playground (`/settings/playground/graphql/core`) crashes with: ``` Uncaught Error: Cannot read properties of undefined (reading 'toUrl') at FileAccessImpl.toUri (monaco-editor) at WorkerManager.getLanguageServiceWorker (graphqlMode) at DiagnosticsAdapter._doValidate (graphqlMode) ``` ## Root cause GraphiQL 5 (adopted in the React 19 migration, #21531) renders its editors with **Monaco** instead of CodeMirror. Monaco spawns web workers for GraphQL validation/autocomplete and needs a `globalThis.MonacoEnvironment.getWorker` factory. None was ever configured, so Monaco fell back to a main-thread worker whose URL resolves to `undefined` → the `toUrl` crash. ## Why not the official helper GraphiQL ships `@graphiql/react/setup-workers/vite`, but its bundled `?worker` imports are incompatible with our rolldown-based Vite setup: - **pre-bundled** (in `optimizeDeps`): esbuild's optimizer can't process `?worker` → the dep 504s and the page fails to load the chunk. - **excluded** from `optimizeDeps`: rolldown tries to load `editor.worker.js?worker` as a literal path → `UNLOADABLE_DEPENDENCY`, crashing the dev server. ## Fix - Register `MonacoEnvironment.getWorker` in **app source** (`setupGraphiqlMonacoWorkers.ts`), where Vite's worker plugin handles `?worker` reliably, and side-effect import it from `GraphQLPlayground.tsx` before GraphiQL mounts. - Align `monaco-editor` to `0.52.2` and add `monaco-graphql@1.8.0` as direct deps so the workers run on the **same deduped Monaco instance** GraphiQL uses on the main thread (a version mismatch would break the worker protocol). ## Verification Ran the playground locally against the dev server: - Editor renders, syntax highlighting works, operation name parses (GraphQL language service alive). - All three worker files (`editor`, `json`, `graphql`) load `200` and instantiate as module workers. - Console is free of `toUrl` / `Cannot read` errors and the "must define MonacoEnvironment.getWorker" warning. - `oxlint`, `oxfmt`, and `nx typecheck twenty-front` pass. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21620?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. --> |
||
|
|
2de60d7ea1 |
chore(server): temporary diagnostic logging for empty verification email body (#21628)
## What Adds **temporary** diagnostic logging to `EmailVerificationService.sendVerificationEmail` so we can capture the real error behind the empty verification email body in deployed environments. ## Why Verification emails are delivered with an **empty body** (subject is fine). The body is `<!DOCTYPE html …><!--$!--><template></template><!--/$-->` — an **errored React Suspense boundary**. `@react-email/render`'s `render()` wraps the email in `<Suspense>` and streams via `renderToReadableStream` **without an `onError` handler**, so any throw during SSR is swallowed into the errored boundary and the body ships empty. In production React also strips the error text from the markup, so the cause is invisible. This could **not** be reproduced locally on `main` (renders fine in dev, in the production-focused `yarn workspaces focus --production` install layout, and on the React 18 + react-email 6 dep set), so we need the error from a deployed environment. ## What it logs When the rendered html is empty or contains `<!--$!-->`, it logs (prefix `EMAIL_VERIFICATION_RENDER_DEBUG`): - locale, trigger, html length, and the first 400 chars of the html; - the **real error + stack**, obtained by re-rendering synchronously with `renderToStaticMarkup` (which re-throws instead of swallowing). No behavior change on the happy path — the block only runs when rendering already failed. ## How to use Deploy, trigger a verification email (sign up / resend), then: ``` grep -i "EMAIL_VERIFICATION_RENDER_DEBUG" <twenty-server logs> ``` ## Revert Remove this block once the root cause is identified. |
||
|
|
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. --> |
||
|
|
09694b2f3b |
feat(partners): add twenty-partner-match skill (#21601)
## Summary - Adds `twenty-partner-match` — a Claude Code skill that closes the partner pipeline loop: query validated partners from the API, score and explain candidates against a lead's match criteria, pause for human validation, then generate and open all intro emails in Gmail (1 client notification + 2N partner emails for N confirmed partners) - Updates `twenty-partner-design-doc` to distinguish **default zero-inference mode** (strict, 1-page brief) from `--full` inference mode, and adds **Step 8** which always produces `partner-match-criteria.md` alongside the brief - Updates `design-doc-doctrine.md` with the full zero-inference / full-mode doctrine so the Claude Code skill and a future in-product `defineSkill` stay in sync ## Skill chain ``` /twenty-lead-intro-call-summary → /twenty-partner-design-doc → /twenty-partner-match ``` `/twenty-partner-match` chains back into the earlier skills if `partner-match-criteria.md` is missing, and applies critical review if the brief is thin before querying the API. ## Credentials The skill reads `~/.twenty/credentials.env` for API keys (never committed). See `SKILL.md` for setup instructions. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21601?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. --> |
||
|
|
03f9ace0bc |
Make flaky Storybook stories deterministic for Argos (animations + lazy-load) (#21609)
Follow-up to #21594. A set of stories were still flagged flaky by Argos after the data/image/date fixes. The remaining causes are **animation** and **lazy-load timing**, not data. Argos's screenshot stabilization waits for fonts and images and disables CSS animations at capture, but it does **not** stop JS-driven animations (react-spring) or wait for `React.lazy` chunks to load. Two global, test-only changes in the Storybook Vitest setup, plus an `optimizeDeps` entry: **1. Disable JS animations (charts).** GraphWidgetLineChart (incl. `--catalog`) and the pie chart draw via `@react-spring/web` (`useAnimatedPath`/`useArcsTransition`, used by nivo), so they get captured mid-draw. - `Globals.assign({ skipAnimation: true })` from `@react-spring/web` (single hoisted instance → covers nivo), mirroring the existing `MotionGlobalConfig.skipAnimations`. - A global CSS rule zeroing animation/transition durations (belt-and-suspenders for the pre-capture window). - `@react-spring/web` added to `optimizeDeps.include` (next to `@nivo/*`) so importing it in the setup file doesn't trigger a mid-run Vite re-optimization. **2. Pre-warm lazy chunks.** RichTextFieldInput (BlockNote editor), AiChatMessage (`react-markdown`/`remark-gfm`), and AppNavigationDrawer (favorites/workspace section dispatchers) lazy-load behind `Suspense`; the snapshot could capture the skeleton fallback instead of the loaded content. Pre-warming the chunks at setup time (same pattern already used for the workflow-step mock) caches them before stories render. The settings object-about form was already covered by the framer-motion/CSS animation disable. |
||
|
|
87c878b101 |
fix(twenty-front): stop unbounded default-view creation on record-index load (#21592)
## Problem Since the 2.13.0 deploy, `core.viewField` and `core.view` rows are being created without bound. From Sentry (`twenty-server`, prod), comparing equal 24h windows before/after the deploy: | INSERT (per day) | Before (Jun 11→12) | After (Jun 14→15) | |---|---|---| | `core.viewField` | 1,885 | 193,719 (**103×**) | | `core.view` | 161 | 12,130 (**75×**) | All under `POST /metadata`, via the `CreateManyViewFields` operation (with frequent "Could not find view for given viewId" races). The accumulating rows then feed a quadratic flat-map rebuild, ramping `POST /metadata` tail latency (p99 0.67s → 7s → 11s and climbing) and server CPU. ## Root cause `useCreateDefaultViewForObject` is a temporary fallback that creates a view + a view field per field, each with a fresh `v4()` id. [`RecordIndexLoadBaseOnContextStoreEffect`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-front/src/modules/object-record/record-index/components/RecordIndexLoadBaseOnContextStoreEffect.tsx) calls it whenever the current view id has no match in the loaded views: ```ts if (isDefined(view)) { loadRecordIndexStates(...) } else { createDefaultViewForObject(objectMetadataItem); } // fires when the lookup misses ``` This is **non-convergent**: the created view gets a *fresh* id, never equal to the requested `contextStoreCurrentViewId`, so the next load misses again and creates another duplicate — every record-index load mints a view + ~17 view fields forever. **Why it started at 2.13.0:** the lookup now misses during normal loads because of the cache-first bootstrap experiment (#21532, which is the `v2.13.0` tag commit). It opens the app gate from cache before the network revalidation, so the record-index effect runs while `contextStoreCurrentViewId` is set but the views aren't settled — the exact window that trips the fallback. ## Fix Make the fallback idempotent: never auto-create a default view for an object that already has one. During the cache-first load window the object's views are present (just not the specifically-requested id), so the guard short-circuits; and once any view exists, it can never re-create. The legitimate case (an object genuinely without views) still creates exactly one. ## Scope / follow-ups - This is the **root-cause** fix for the leak. - The quadratic amplification is mitigated separately by the O(N²)→O(N) change in the flat-map builder (#21585). - The cache-first experiment (#21532) should be reviewed — it's marked "[Experiment] — not for merge as-is" yet shipped; reverting/gating it is the fastest standalone stop-gap, and confirms the trigger if `viewField` inserts drop. - The already-leaked duplicate `core.view` / `core.viewField` rows need a cleanup pass. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21592?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. --> |
||
|
|
97871131a1 |
fix(server): mitigate integration-test OOM flakiness (#21588)
## Problem `server-integration-test` shards have been failing intermittently across unrelated PRs with a distinctive signature: the shard exits code 1 with **no jest assertion failure, no `Test Suites:` summary, and no V8 `JavaScript heap out of memory` error** — the process just dies mid-run. Failures hit random shards and clear on re-run (e.g. an unrelated branch failed shard 6 once, then passed 3× on identical code), while the `merge_group` gate stays green. ### Root cause Each shard runs a **single in-band jest process** that boots one shared NestJS app (`globalSetup` → `app.listen`) and holds it for the entire shard, driving heavy metadata migrations + cache rebuilds in that one process. `NODE_OPTIONS=--max-old-space-size=12288` let V8 grow to 12 GB — *above* the `ubuntu-latest` runner's available RAM (16 GB, shared with Postgres/Redis/ClickHouse). V8 therefore deferred aggressive GC and grew past physical memory, so the **OS OOM-killer killed the process before V8 hit its own ceiling** — which is why there's no heap error and no jest summary, just a silent exit. ## Changes (CI/test-only — prod runtime untouched) - **Lower the integration jest heap cap `12288` → `6144`** so V8 self-limits below physical headroom instead of being OS-killed. Counterintuitively safer: a real leak now surfaces as a *visible* heap error naming the test, rather than a silent death. (`database:reset` keeps 12288 — it runs alone, before jest.) - **Add `--logHeapUsage`** to the integration jest runs to expose the per-file heap trend for confirming/pinpointing the growth. - **Split integration tests across 16 shards (was 10)** to lower the peak working set per shard. - **Make perf logging a first-class `LoggerService` tool** (per @prastoin's review): add `LoggerService.perf()` and unify the existing `time()`/`timeEnd()` helpers into `perfTime()`/`perfTimeEnd()` (now routed through the driver), all gated by a new `PERF_LOG_ENABLED` config var. It **defaults on** so real environments keep emitting the install-perf logs, and `.env.test` sets it `false` to mute the per-action flood in integration tests. The `application-manifest` and `validate-build` services were moved from the built-in `Logger` to `LoggerService` to use it. ## Notes - `--max-old-space-size` lives only in the `test:integration` nx target; it is **not** the prod server heap setting, so prod is unaffected. - This is mitigation. If `--logHeapUsage` shows monotonic growth across files, there's a real accumulation in the long-lived app (retained flat-maps / metadata cache) worth a follow-up heap-snapshot fix. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21588?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. --> |
||
|
|
88b9294afd |
feat(front): persist metadata store cache in IndexedDB instead of localStorage (#21586)
## Problem The metadata store cache (object/field metadata, views, page layouts, command menu items, …) is persisted client-side to power **cache-first boot**: the app renders instantly from the cache, then `MinimalMetadataLoadEffect` revalidates per-collection hashes and only refetches what's stale. It was persisted to **localStorage**, which Safari/WebKit caps at **~5 MB per origin, counted in UTF-16 (2 bytes/char)** → an effective ceiling of ~2.5 M characters. Measured on the seeded demo workspace (33 objects, 612 fields): | Bucket | Safari quota (UTF-16) | |---|---| | `metadataStoreState__*` (26 keys) | **1.9 MB — 37%** | | Whole origin | **2.47 MB — 48%** | A workspace ~2.5× the demo's schema blows past 5 MB, and there is **no `QuotaExceededError` handling** — `setItem` throws and breaks the app. This is what large-workspace users on Safari have been hitting. ## Fix Move **only the metadata store** to **IndexedDB** (multi-GB, disk-based quota), keeping a **fully synchronous read path** so the ~24 consumers that read these atoms with `useAtomValue` never suspend. The auth/UI atoms (incl. the synchronously-read `tokenPair`) stay on localStorage — intentionally scoped. - **`createIndexedDbBackedJotaiStorage.ts`** — a synchronous Jotai storage facade backed by an in-memory map, hydrated once from IndexedDB at boot and written through on every set. IndexedDB access uses the **`idb-keyval`** library (by the IndexedDB spec co-author, ~0.6 KB) rather than a hand-rolled wrapper. Each cache gets its own database + BroadcastChannel (`twenty-front-<cacheName>`), so it's safely reusable. Swallowed errors are surfaced via `logError`. When IndexedDB is unavailable the cache stays in memory only (re-fetched each boot). - **`createAtomFamilyState`** — gains an optional `storage` param; `metadataStoreState` uses the IndexedDB-backed storage. - **`index.tsx`** — awaits hydration before mounting so atoms (`getOnInit: true`) read the persisted snapshot synchronously → cache-first boot preserved. - **No migration**: the facade does not touch localStorage at all. Pre-existing localStorage snapshots are ignored — on first boot of the new code the IndexedDB cache is empty and atoms re-fetch from the network (a one-time reconnect). Old `metadataStoreState__*` localStorage keys are left in place (cleared by the existing logout/reset cleanup); new writes only ever go to IndexedDB. - **Cross-tab sync**: the old localStorage atoms synced across tabs for free via `storage` events; the IndexedDB facade had no equivalent, so a schema change in one tab left others stale until reload. Restored by implementing the Jotai storage `subscribe` contract over a **`BroadcastChannel`** — writes broadcast to other tabs, which update their in-memory map and notify `atomWithStorage` subscribers so mounted atoms re-render live. (BroadcastChannel doesn't echo to the sender, so no feedback loop; guarded for environments without it.) ## Why a synchronous facade (not async `atomWithStorage`) Consumers use `useAtomValue` directly; an async storage would make the atoms resolve to Promises and **suspend** every reader. The in-memory facade keeps reads synchronous (zero ripple on consumers) and confines the async part to a single bulk read at boot, which the existing `MinimalMetadataGater` loader already covers. ## Tests ### Automated - Unit test (10 cases) for the storage facade: synchronous read/write, IndexedDB write-through, hydration from IndexedDB, `removeItem`/`clear`, per-cache DB namespacing, persist-failure logging, in-memory-only behaviour when IndexedDB is unavailable, distinguishing a stored `undefined` from a missing key, and cross-tab subscriber registration. - Existing metadata-store tests (`useIsLayoutCustomizationDirty`, `useDefaultHomePagePath`) still pass. - `nx typecheck twenty-front` and `nx lint:diff-with-main twenty-front` clean. ### Manual (local seeded workspace, two tabs, Playwright) Storage: - After login the metadata cache lives in **IndexedDB (24 keys, ~945 KB)** and **localStorage drops 48% → 11%** of the Safari quota (the remainder is `currentUserState` + auth, out of scope). - Reload boots from the cache (no heavy refetch). Scenarios: | Scenario | Result | |---|---| | **Sign out** | auth cleared, redirect to sign-in, no leftover localStorage, no errors | | **Sign back in** | metadata `up-to-date`, company table renders, token restored | | **Add object** (`Gadget`) | write-through to IndexedDB; survives reload via cache-first hydration | | **Add view** (`QA Cross Tab View`, TABLE) | persisted to the `views` collection (`up-to-date`) | | **Two tabs open** | second tab boots cleanly from the shared IndexedDB — no lock/crash under concurrent access | | **Cross-tab live sync** | creating an object in tab A makes it appear in tab B's open settings object list **without a reload** | Verified by design (no regression): - Runtime sign-out (`clearSession`) clears session keys and does a full `window.location.assign` reload; the metadata-clearing path (`resetJotaiStore`) is test-only, so there's no async-`clear()`-vs-sign-in race. Metadata persisting across sign-out is unchanged from the old localStorage behavior (it's schema, revalidated by hash on next login). ## Notes / follow-ups (not in this PR) - **IndexedDB query capabilities** are not used yet: the cache stores one blob per collection (as it did in localStorage), so this is still a pure key-value use (`idb-keyval`). If we later want to query individual metadata records — e.g. fields by `objectMetadataId` via an index/cursor, or partial hydration — that means record-level storage and a richer wrapper (`idb` for a thin near-native layer, or **Dexie** for a full query API + reactive `liveQuery` that could also replace the BroadcastChannel sync). - IndexedDB still has a (large) quota and Safari ITP eviction applies to both stores — the cache-first design already tolerates eviction by revalidating. - Complementary "load less" wins remain: the denormalized per-field `relation` block (~700 chars/field of pure duplication) and persisting `currentUser.workspaceMembers` (the ~0.5 MB still in localStorage). <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21586?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. --> |
||
|
|
018af36cfc |
Hide logic functions that are not exposed as tools (#21598)
each time we create a workflow node that is a logic function, it creates a logic function that is then exposed in the options for future nodes. Let's hide them by only showing here functions that were added by applications that are not the workspace application. If a logic function was meant to be exposed as a tool by an application, it will still show. Decided to go with this as I see no case where we create a logic function from the main app that we want exposed as a tool. <img width="614" height="927" alt="image" src="https://github.com/user-attachments/assets/e51d38a6-234f-4eee-a993-32d02ce6ad1e" /> <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21598?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. --> |
||
|
|
2f6a267b68 |
chore(server): remove stray comment in flat-entity-maps spec (#21599)
Follow-up to #21585: removes an explanatory comment in the test that slipped through before merge. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21599?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. --> |
||
|
|
8a866dba54 |
Add call recording schema and meeting bot scaffold (#21584)
## Summary - add 2.13 upgrade commands for call recording request status and dropping CalendarEvent recordingPreference - remove the recording preference from the core CalendarEvent standard object - add a scaffold-generated twenty-meeting-bot app with logo and the CalendarEvent meetingBotPreference field ## Tests - yarn install - yarn lint - yarn twenty dev:typecheck - git diff --check <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21584?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. --> |
||
|
|
d1ba63d4a4 |
Postcard app e2e front component rendering test (#21600)
# Introduction Creating a playwright test, quite granular and verbose that will verify that the post card preview front component is rendered as expected on the tested twenty instance This covers everything e2e from twenty front, front comp renderer, assets cdn rendered redirection etc Style bridge etc ## Note The playwright test setup assumes the application has already been installed once, it's mainly used by the merge queue as a high level front component and logic function ( will be in the same ci ) regression bottleneck The goal isn't for this test to be run locally |
||
|
|
4be76e3fd1 |
Support morph relations in workflow record nodes (#21403)
## Support morph (polymorphic) relations in workflow record nodes
Morph relations (e.g. a polymorphic `Owner` on `Pet` targeting `Person`
or `Company`) were not selectable in the workflow **Create / Update /
Upsert Record** nodes. This PR adds full support for setting them.
### What changed
**Frontend**
- `shouldDisplayFormField`: allow `MORPH_RELATION` (many-to-one) so
morph fields appear in record forms.
- New `FormMorphRelationToOneFieldInput`: a polymorphic record picker
across the morph's target objects, storing a self-describing value `{
targetObjectMetadataId, id }`.
- Wired the morph branch into `FormFieldInput`.
**Backend**
- New `formatWorkflowRecordMorphRelationFields` util: resolves the form
value (stored under the base field name, e.g. `owner`) into the correct
per-target join column (`ownerCompanyId`), nulling siblings to keep
exactly one target referenced.
- Wired into the create / update / upsert workflow actions (update also
expands `fieldsToUpdate` to the concrete join columns).
### Permissions handling
- The picker's search is scoped to only the morph targets the user can
read (`canReadObjectRecords`), so it no longer breaks when a target
object is inaccessible.
- If an existing value points to an object the user can't read, the
field shows the reused **"Not shared"** lock display instead of an empty
field, while remaining editable when other targets are readable.
### Notes
- No data schema / migration changes — reuses the existing per-target
morph columns and stores the selection in the existing workflow step
JSON settings.
<img width="607" height="717" alt="Screenshot 2026-06-10 at 14 57 40"
src="https://github.com/user-attachments/assets/496442a1-04a5-40f8-8b56-b28e38b00d5a"
/>
Also handles the case where the selected record is not readable
<img width="596" height="737" alt="image"
src="https://github.com/user-attachments/assets/c5ffb94e-3838-4db5-853e-f8e490331f23"
/>
|
||
|
|
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. --> |
||
|
|
02d6e2d76f |
perf(server): avoid O(n²) when building flat entity maps (#21585)
## Problem
After 2.13, server CPU stepped up and stayed up. Sentry profiling of
`POST /metadata` pins it on
`addFlatEntityToFlatEntityMapsThroughMutationOrThrow` — ~26% self-time
plus a long tail, turning metadata-write requests into multi-second
(~18s observed) operations.
The hot stack is:
```
WorkspaceMigrationValidateBuildAndRunService.computeAllRelatedFlatEntityMaps
└ getSubFlatEntityMapsByApplicationIdsOrThrow
└ addFlatEntityToFlatEntityMapsThroughMutationOrThrow
```
Every metadata migration rebuilds the twenty-standard application's flat
sub-maps — thousands of entities, across every involved metadata type —
through this util.
## Root cause
`addFlatEntityToFlatEntityMapsThroughMutationOrThrow` maintains
`universalIdentifiersByApplicationId` and deduped each insert with
`Array.includes`:
```ts
if (!existingUniversalIdentifiers.includes(flatEntity.universalIdentifier)) {
existingUniversalIdentifiers.push(flatEntity.universalIdentifier);
}
```
That scan is O(n) per insert, so building a map for an application with
`n` entities is **O(n²)**. The twenty-standard application groups
thousands of standard entities under one `applicationId`, so its sub-map
rebuild dominates.
The dedup is also redundant: the function throws `ENTITY_ALREADY_EXISTS`
at the top if the `universalIdentifier` is already in
`byUniversalIdentifier`, and every id pushed to the per-application list
is also written there. So reaching the push guarantees the id is new —
the `.includes()` is always `false`.
## Fix
Drop the scan and push directly → map building is **O(n)**. Behavior is
unchanged (the early throw already enforces uniqueness).
## Test
Adds a unit spec covering indexing, the no-`applicationId` case, the
duplicate throw, and a 20k-entity build that completes instantly (guards
against re-introducing the quadratic).
## Follow-up (separate PR)
This is the bleed-stopper. The deeper issue is that
`computeAllInvolvedApplicationIds` pulls the **entire** twenty-standard
application into the dependency set of every migration and rebuilds
those sub-maps per request instead of caching them. Worth scoping the
dependency set to referenced entities (or caching the standard-app
sub-maps), which I'll raise separately.
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21585?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. -->
|
||
|
|
0a99f784eb |
fix(front): dedupe morph relation fields in view field pickers (#21580)
## Issue Reported in quality-feedbacks: **"Issues with morph relation view field"** — a morph relation column added to a view **disappears after refresh** (and can be added several times). ## Root cause — the SSE metadata sync A morph relation is stored as **one `fieldMetadata` row per target object**, all sharing a `morphId`. Collapsing those rows into the single field that represents the relation is a **read-time projection** in the server's `objects.fieldsList` resolver — it is *not* a storage invariant, and the rows are never merged. The frontend metadata store is kept in sync with the raw rows **one row at a time over SSE** (`MetadataStoreSSEEffect`): every metadata change broadcasts a single created/updated record that's pushed straight into the store. Creating a morph relation creates N rows (one per target), so **N `create` events arrive and N raw sub-fields land in the store — bypassing the `fieldsList` projection entirely.** The view-field pickers read straight from that store, so they saw the morph relation **once per target**. Each could be added as a column referencing a different sub-field id; after a refresh the view reloads from the projected (deduped) data, the non-survivor columns no longer resolve, and they disappear. ## Fix & architecture note Because the store deliberately mirrors raw rows (that's what the SSE sync maintains), the fix applies the **same read-time projection on the client** — deduping morph rows by `morphId` in `useActiveFieldMetadataItems` — rather than filtering rows at each insert path (SSE, optimistic create, …). This matches how the backend already models morph fields and is robust regardless of which path delivered the rows. The survivor-selection rule (which sub-field id represents the relation) now lives in `twenty-shared` (`pickMorphGroupSurvivor`) so client and server can't drift. |
||
|
|
ecc7b38b75 |
Remove randomness from flaky twenty-front Storybook stories (#21594)
Several twenty-front Storybook stories were flagged flaky by Argos because they render different pixels across runs. This removes the non-determinism behind them. **What changed** - **Images** — replaced random `picsum.photos` URLs in the Logo and TabList stories with the existing `AVATAR_URL_MOCK`, and added global MSW handlers in `.storybook/preview.tsx` that serve a deterministic image for every remote host (picsum, twenty-icons.com, twentyhq.github.io, etc.) so no story depends on a network image load. - **Numbers** — the line-chart story built its data with `Math.random()`; now uses a deterministic formula. - **Dates** — the terminal "long output" story stamped its lines with `new Date()`; now uses a fixed base timestamp. The calendar-channel date/time format previews and example event used render-time `Date.now()`/`new Date()` in shared components; they now use a fixed reference date (`DateTimeSettingsPreviewDate`). - **Lazy-load timing** — the date-picker story now waits for the lazily-loaded calendar before the snapshot. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21594?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. --> |
||
|
|
c848ac34fd |
Fix default view widget visibility (#21590)
Tim logged on the left, Phil on the right, Tim created view widget ## Before <img width="1512" height="938" alt="image" src="https://github.com/user-attachments/assets/7f993f41-a244-42db-b56a-b17c15fb3409" /> ## After Fix Tim created a second view widget, Phil can see it <img width="1512" height="982" alt="image" src="https://github.com/user-attachments/assets/3908a70d-538b-4adf-95df-7373a2f6e269" /> ## After slow migration Phil can see first widget <img width="1512" height="982" alt="image" src="https://github.com/user-attachments/assets/6b30429e-1acf-4119-ba32-26db3155975e" /> <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21590?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: Weiko <corentin@twenty.com> |
||
|
|
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> |
||
|
|
04a304aa99 |
Ignore generated Storybook/Argos screenshot output (#21589)
## Context `packages/twenty-front/screenshots/` (and the equivalent under other Storybook packages) holds Argos visual-regression baselines that are generated on demand and not meant to be committed. The existing rules in `.gitignore` were: ``` screenshots/ !**/screenshots/ ``` The `!**/screenshots/` negation was added so app images committed under `public/screenshots/` (github-connector) and `assets/screenshots/` (codex-plugin) stay tracked — but it is too broad: it also re-includes the generated output, so a `git add -A` can accidentally commit hundreds of baseline PNGs. ## What this does Narrows the negation to the two locations where screenshots are intentionally committed: ``` screenshots/ !**/public/screenshots/ !**/assets/screenshots/ ``` Generated `screenshots/` directories at package roots (twenty-front, twenty-ui, twenty-ui-deprecated, twenty-front-component-renderer) are now ignored again, while committed app images remain tracked. Verified with `git check-ignore`. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21589?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. --> |
||
|
|
ebababcda1 |
chore(deps): bump @ai-sdk/amazon-bedrock from 4.0.97 to 4.0.117 (#21569)
Bumps [@ai-sdk/amazon-bedrock](https://github.com/vercel/ai/tree/HEAD/packages/amazon-bedrock) from 4.0.97 to 4.0.117. <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/vercel/ai/blob/@ai-sdk/amazon-bedrock@4.0.117/packages/amazon-bedrock/CHANGELOG.md">@ai-sdk/amazon-bedrock's changelog</a>.</em></p> <blockquote> <h2>4.0.117</h2> <h3>Patch Changes</h3> <ul> <li>Updated dependencies [bfa5864]</li> <li>Updated dependencies [f42aa79] <ul> <li><code>@ai-sdk/provider-utils</code><a href="https://github.com/4"><code>@4</code></a>.0.29</li> <li><code>@ai-sdk/anthropic</code><a href="https://github.com/3"><code>@3</code></a>.0.84</li> <li><code>@ai-sdk/openai</code><a href="https://github.com/3"><code>@3</code></a>.0.71</li> </ul> </li> </ul> <h2>4.0.116</h2> <h3>Patch Changes</h3> <ul> <li>f0b5c16: fix(provider/amazon-bedrock): detect Cohere embedding models behind cross-region inference profile ids</li> <li>Updated dependencies [942f2f8] <ul> <li><code>@ai-sdk/provider-utils</code><a href="https://github.com/4"><code>@4</code></a>.0.28</li> <li><code>@ai-sdk/anthropic</code><a href="https://github.com/3"><code>@3</code></a>.0.83</li> <li><code>@ai-sdk/openai</code><a href="https://github.com/3"><code>@3</code></a>.0.70</li> </ul> </li> </ul> <h2>4.0.115</h2> <h3>Patch Changes</h3> <ul> <li>c97ede5: fix(provider/amazon-bedrock): extract Cohere embedding token usage from response header</li> </ul> <h2>4.0.114</h2> <h3>Patch Changes</h3> <ul> <li>2a91a17: feat(provider/anthropic): add support for <code>claude-fable-5</code> and the <code>fallbacks</code> API parameter</li> <li>Updated dependencies [9a55f6d]</li> <li>Updated dependencies [2a91a17] <ul> <li><code>@ai-sdk/openai</code><a href="https://github.com/3"><code>@3</code></a>.0.69</li> <li><code>@ai-sdk/anthropic</code><a href="https://github.com/3"><code>@3</code></a>.0.82</li> </ul> </li> </ul> <h2>4.0.113</h2> <h3>Patch Changes</h3> <ul> <li>Updated dependencies [c65c952] <ul> <li><code>@ai-sdk/openai</code><a href="https://github.com/3"><code>@3</code></a>.0.68</li> </ul> </li> </ul> <h2>4.0.112</h2> <h3>Patch Changes</h3> <ul> <li>53b002d: added bedrock mantle provider</li> </ul> <h2>4.0.111</h2> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/vercel/ai/commit/bae9babb22e195e74a9a0c0e26a5e52c8ba8e7f2"><code>bae9bab</code></a> Version Packages (<a href="https://github.com/vercel/ai/tree/HEAD/packages/amazon-bedrock/issues/16026">#16026</a>)</li> <li><a href="https://github.com/vercel/ai/commit/9ef2c3cfadfc4a469e9eec6a6e8a0ac0fc80a1e5"><code>9ef2c3c</code></a> Version Packages (<a href="https://github.com/vercel/ai/tree/HEAD/packages/amazon-bedrock/issues/15998">#15998</a>)</li> <li><a href="https://github.com/vercel/ai/commit/f0b5c16ce5f17a7c9cc91ce0ae8f292920594e91"><code>f0b5c16</code></a> Backport: fix(provider/amazon-bedrock): detect Cohere embedding models behind...</li> <li><a href="https://github.com/vercel/ai/commit/dca8c38b09acba1a5eebf354b532833ab055413a"><code>dca8c38</code></a> Version Packages (<a href="https://github.com/vercel/ai/tree/HEAD/packages/amazon-bedrock/issues/15992">#15992</a>)</li> <li><a href="https://github.com/vercel/ai/commit/c97ede5cbbbc0aaca0137ed41c7fd6f5fedd23b6"><code>c97ede5</code></a> Backport: fix(provider/amazon-bedrock): extract Cohere embedding token usage ...</li> <li><a href="https://github.com/vercel/ai/commit/f6e588173713842794c619f9554a4b341c6e97f5"><code>f6e5881</code></a> Version Packages (<a href="https://github.com/vercel/ai/tree/HEAD/packages/amazon-bedrock/issues/15902">#15902</a>)</li> <li><a href="https://github.com/vercel/ai/commit/2a91a17e0b885968814110fe3581d1ea0fd589ae"><code>2a91a17</code></a> backport: feat(provider/anthropic): add support for <code>claude-fable-5</code> and the ...</li> <li><a href="https://github.com/vercel/ai/commit/de852ab79aac88345c8a9ae54003fb206e1a64b4"><code>de852ab</code></a> Version Packages (<a href="https://github.com/vercel/ai/tree/HEAD/packages/amazon-bedrock/issues/15821">#15821</a>)</li> <li><a href="https://github.com/vercel/ai/commit/879395199bac3796e6c34b43f6aa43ca5d682940"><code>8793951</code></a> Version Packages (<a href="https://github.com/vercel/ai/tree/HEAD/packages/amazon-bedrock/issues/15755">#15755</a>)</li> <li><a href="https://github.com/vercel/ai/commit/53b002d2d0701235026b41e0fa11aa1a41c90b8b"><code>53b002d</code></a> Backport: feat (provider/amazon-bedrock): add bedrock mantle provider (<a href="https://github.com/vercel/ai/tree/HEAD/packages/amazon-bedrock/issues/14246">#14246</a>...</li> <li>Additional commits viewable in <a href="https://github.com/vercel/ai/commits/@ai-sdk/amazon-bedrock@4.0.117/packages/amazon-bedrock">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> <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21569?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: Charles Bochet <charles@twenty.com> |
||
|
|
fb4608e437 |
chore(deps): upgrade Tier-1 deps (googleapis 173, gaxios 7, express 5, jsdom 29, date-fns 4, stripe 20) (#21570)
## What Security-driven upgrade of the biggest-drift Tier-1 dependencies (staying on latest = staying patched). Bundled because they share the lockfile and the googleapis/gaxios pair must move together. | Package | From | To | Gap | |---|---|---|---| | googleapis | 105.0.0 | **173.0.0** | 68 majors | | gaxios | 5.1.3 | **7.1.5** | 2 majors | | express | 4.22.2 | **5.2.1** | 1 major | | jsdom | 26.1.0 | **29.1.1** | 3 majors | | date-fns | 2.30.0 | **4.4.0** | 2 majors | | date-fns-tz | 2.0.0 | **3.2.0** | 1 major | | stripe | 19.3.1 | **20.4.1** | 1 major | `yarn npm audit` reports **0 high/critical** advisories before and after. ## Code changes - **gaxios v7** — `GaxiosError.code` is now `string | number` (guard the calendar network-error check by `typeof`); `GaxiosError` config/response use `URL` + `Headers`; and crucially the v7 constructor drops `response.data` unless `bodyUsed` is set — updated the synthetic gmail error mocks accordingly (production gaxios sets it, so real error parsing is unaffected). - **google-auth-library / gaxios dedup** — `googleapis-common@8.0.2` exact-pins `google-auth-library@10.5.0` + `gaxios@7.1.3` while `googleapis` pulls `^10.2.0`; the two copies made `OAuth2Client`/`GaxiosError` type-identities diverge across every gmail/calendar service. Added two singleton `resolutions` (documented inline in root `package.json`). - **express 5** — no source changes. `@nestjs/platform-express@11.1.24` already resolves `express@5.2.1` internally; the old `4.22.2` pin was the override. - **jsdom 29** — no source changes, but it now pulls ESM-only transitive deps (`@csstools/*` `.mjs`, `parse5`, `entities`, `tough-cookie`, `@exodus/bytes`). Extended the server jest `transformIgnorePatterns` allowlist and added `.mjs` to the transform/extensions so jest can load jsdom. - **stripe 20** — `Subscription` gained a required `customer_account` field; added to mocks. No runtime changes. - **date-fns v4** — `Locale` is no longer ambient (import explicitly in 5 files); per-locale entrypoints dropped the typed `default` export (the locale loader now reads the single named export); fixed the default locale import in `formatTimeZoneLabel`. ## Tests - Full suites green locally: **twenty-server 5709 passed**, **twenty-front 4937 passed**, twenty-ui / twenty-ui-deprecated green; typecheck + builds (swc + vite) + lint all pass. - Added regression tests for the two runtime behaviors these upgrades touch and that had no coverage: - `getDateFnsLocale` — named-export locale resolution (date-fns v4). - `sanitizeFile` — jsdom 29 + DOMPurify still strips `<script>`/event handlers from uploaded SVGs (security guard). ## Deliberately deferred (not in this PR) - **stripe → 21/22**: stripe **21** bundles a runtime `Decimal` type for money fields **and** jumps the pinned API version to `2026-03-25.dahlia` (changes webhook/billing payload behavior) — too risky to fold into a deps bump on billing code. stripe **22** additionally drops the node10-resolvable `types` entry, which would force a repo-wide `moduleResolution` change. Capped at the latest clean **20.x**. - **openid-client → 6**: v6 is a full functional rewrite and its passport strategy manages the OAuth `state` internally, but our SSO flow uses `state` to carry `identityProviderId` across the shared `/auth/oidc/callback`. That needs an auth-flow redesign (session-carried provider id) on Enterprise SSO code with no integration harness — it deserves its own focused PR rather than riding along here. ## Tier-1 source Originated from a dependency-drift audit; remaining Tier-1 items (date-fns done here) plus Tier-2/3 follow-ups tracked separately. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21570?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. --> |
||
|
|
d7d4b36d5e |
fix(front): keep the filename when a file has no extension (#21576)
Closes #21575. ## Summary `getFileNameAndExtension` split filenames with `lastIndexOf('.')`. For an extensionless name (`README`, `Makefile`), `lastIndexOf` returns `-1` and `substring`'s negative-index clamping returned `{ name: '', extension: 'README' }` — losing the whole name into the extension. In the attachments UI this rendered an empty rename field and corrupted the name on edit. ## Changes - Early return `{ name, extension: '' }` when there is no dot - Correct the existing test that asserted the buggy output; add no-dot + trailing-dot cases ## Testing Pure, dependency-free function — verified deterministically (17/17 assertions, red-green proven: reverting the fix fails the corrected `README` assertion). Note: twenty's full nx lint/test wasn't run locally (repo wants Node ^24.5.0; this box is on Node 26), so CI is the authoritative check for lint/format. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21576?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. --> |
||
|
|
e70776f705 |
chore(deps): bump prettier from 3.8.3 to 3.8.4 (#21568)
Bumps [prettier](https://github.com/prettier/prettier) from 3.8.3 to 3.8.4. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/prettier/prettier/releases">prettier's releases</a>.</em></p> <blockquote> <h2>3.8.4</h2> <ul> <li>Markdown: Fix blank lines between list items and nested sub-lists being removed in Markdown/MDX (<a href="https://redirect.github.com/prettier/prettier/pull/17746">prettier/prettier#17746</a> by <a href="https://github.com/byplayer"><code>@byplayer</code></a>)</li> </ul> <p>🔗 <a href="https://github.com/prettier/prettier/blob/3.8.4/CHANGELOG.md#384">Changelog</a></p> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md">prettier's changelog</a>.</em></p> <blockquote> <h1>3.8.4</h1> <p><a href="https://github.com/prettier/prettier/compare/3.8.3...3.8.4">diff</a></p> <h4>Markdown: Fix blank lines between list items and nested sub-lists being removed in Markdown/MDX (<a href="https://redirect.github.com/prettier/prettier/pull/17746">#17746</a> by <a href="https://github.com/byplayer"><code>@byplayer</code></a>)</h4> <p>Prettier was removing blank lines between list items and their nested sub-lists, converting loose lists into tight lists and changing their semantic meaning.</p> <!-- raw HTML omitted --> <pre lang="markdown"><code><!-- Input --> - a <ul> <li> <p>b</p> </li> <li> <p>c</p> <ul> <li>d</li> </ul> </li> </ul> <p><!-- Prettier 3.8.3 --></p> <ul> <li>a <ul> <li>b</li> </ul> </li> <li>c <ul> <li>d</li> </ul> </li> </ul> <p><!-- Prettier 3.8.4 --></p> <ul> <li> <p>a</p> <ul> <li>b</li> </ul> </li> <li> <p>c</p> <ul> <li>d<br /> </code></pre></li> </ul> </li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/prettier/prettier/commit/1c6ba5539141552e0e8e22d401ea620d8fdff468"><code>1c6ba55</code></a> Release 3.8.4</li> <li><a href="https://github.com/prettier/prettier/commit/4a673dc9b59ddf7296bbab9822093d2971da84a8"><code>4a673dc</code></a> Fix blank lines between list items and nested sub-lists being removed in Mark...</li> <li><a href="https://github.com/prettier/prettier/commit/074aaedbb052a288e89d15eb0a4214de37a08866"><code>074aaed</code></a> Replace <code>main</code> branch in changelog link with tags (<a href="https://redirect.github.com/prettier/prettier/issues/19054">#19054</a>)</li> <li><a href="https://github.com/prettier/prettier/commit/c22a003ae97917c5043e8685b4fdff0f93e978f9"><code>c22a003</code></a> Bump Prettier dependency to 3.8.3</li> <li><a href="https://github.com/prettier/prettier/commit/07bad1f04536e9799927007baf466e67151576f0"><code>07bad1f</code></a> Clean changelog_unreleased</li> <li>See full diff in <a href="https://github.com/prettier/prettier/compare/3.8.3...3.8.4">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> <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21568?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. --> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
1f30d4df97 |
chore(deps): bump @ai-sdk/azure from 3.0.55 to 3.0.74 (#21566)
Bumps [@ai-sdk/azure](https://github.com/vercel/ai/tree/HEAD/packages/azure) from 3.0.55 to 3.0.74. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/vercel/ai/releases">@ai-sdk/azure's releases</a>.</em></p> <blockquote> <h2><code>@ai-sdk/openai</code><a href="https://github.com/3"><code>@3</code></a>.0.71</h2> <h3>Patch Changes</h3> <ul> <li>Updated dependencies [bfa5864]</li> <li>Updated dependencies [f42aa79] <ul> <li><code>@ai-sdk/provider-utils</code><a href="https://github.com/4"><code>@4</code></a>.0.29</li> </ul> </li> </ul> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/vercel/ai/blob/@ai-sdk/azure@3.0.74/packages/azure/CHANGELOG.md">@ai-sdk/azure's changelog</a>.</em></p> <blockquote> <h2>3.0.74</h2> <h3>Patch Changes</h3> <ul> <li>Updated dependencies [bfa5864]</li> <li>Updated dependencies [f42aa79] <ul> <li><code>@ai-sdk/provider-utils</code><a href="https://github.com/4"><code>@4</code></a>.0.29</li> <li><code>@ai-sdk/deepseek</code><a href="https://github.com/2"><code>@2</code></a>.0.38</li> <li><code>@ai-sdk/openai</code><a href="https://github.com/3"><code>@3</code></a>.0.71</li> </ul> </li> </ul> <h2>3.0.73</h2> <h3>Patch Changes</h3> <ul> <li>Updated dependencies [942f2f8] <ul> <li><code>@ai-sdk/provider-utils</code><a href="https://github.com/4"><code>@4</code></a>.0.28</li> <li><code>@ai-sdk/deepseek</code><a href="https://github.com/2"><code>@2</code></a>.0.37</li> <li><code>@ai-sdk/openai</code><a href="https://github.com/3"><code>@3</code></a>.0.70</li> </ul> </li> </ul> <h2>3.0.72</h2> <h3>Patch Changes</h3> <ul> <li>79f0ae6: feat(azure): add deepseek model support to azure</li> <li>Updated dependencies [79f0ae6] <ul> <li><code>@ai-sdk/deepseek</code><a href="https://github.com/2"><code>@2</code></a>.0.36</li> </ul> </li> </ul> <h2>3.0.71</h2> <h3>Patch Changes</h3> <ul> <li>Updated dependencies [9a55f6d] <ul> <li><code>@ai-sdk/openai</code><a href="https://github.com/3"><code>@3</code></a>.0.69</li> </ul> </li> </ul> <h2>3.0.70</h2> <h3>Patch Changes</h3> <ul> <li>Updated dependencies [c65c952] <ul> <li><code>@ai-sdk/openai</code><a href="https://github.com/3"><code>@3</code></a>.0.68</li> </ul> </li> </ul> <h2>3.0.69</h2> <h3>Patch Changes</h3> <ul> <li>cbc161a: Add Microsoft Entra ID token provider authentication for Azure OpenAI.</li> </ul> <h2>3.0.68</h2> <h3>Patch Changes</h3> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/vercel/ai/commit/bae9babb22e195e74a9a0c0e26a5e52c8ba8e7f2"><code>bae9bab</code></a> Version Packages (<a href="https://github.com/vercel/ai/tree/HEAD/packages/azure/issues/16026">#16026</a>)</li> <li><a href="https://github.com/vercel/ai/commit/9ef2c3cfadfc4a469e9eec6a6e8a0ac0fc80a1e5"><code>9ef2c3c</code></a> Version Packages (<a href="https://github.com/vercel/ai/tree/HEAD/packages/azure/issues/15998">#15998</a>)</li> <li><a href="https://github.com/vercel/ai/commit/174255acffab2833236b94fd49af3497ff9ff618"><code>174255a</code></a> Version Packages (<a href="https://github.com/vercel/ai/tree/HEAD/packages/azure/issues/15955">#15955</a>)</li> <li><a href="https://github.com/vercel/ai/commit/79f0ae6c23aee02f816fa3123c8d589a27e61bb9"><code>79f0ae6</code></a> feat(azure): add deepseek model support to azure (<a href="https://github.com/vercel/ai/tree/HEAD/packages/azure/issues/15945">#15945</a>)</li> <li><a href="https://github.com/vercel/ai/commit/f6e588173713842794c619f9554a4b341c6e97f5"><code>f6e5881</code></a> Version Packages (<a href="https://github.com/vercel/ai/tree/HEAD/packages/azure/issues/15902">#15902</a>)</li> <li><a href="https://github.com/vercel/ai/commit/de852ab79aac88345c8a9ae54003fb206e1a64b4"><code>de852ab</code></a> Version Packages (<a href="https://github.com/vercel/ai/tree/HEAD/packages/azure/issues/15821">#15821</a>)</li> <li><a href="https://github.com/vercel/ai/commit/7aca1fc2004800171233ae16c2456ef297552441"><code>7aca1fc</code></a> backport: chore: update TypeScript references and fix `pnpm update-references...</li> <li><a href="https://github.com/vercel/ai/commit/7e449f2b40d21aeec94dd9f41ebc5581e7971d94"><code>7e449f2</code></a> Version Packages (<a href="https://github.com/vercel/ai/tree/HEAD/packages/azure/issues/15766">#15766</a>)</li> <li><a href="https://github.com/vercel/ai/commit/cbc161ae49b8a6708f1a6cf271081d8ba54ffe4e"><code>cbc161a</code></a> Backport: feat(azure): support Microsoft Entra ID auth (<a href="https://github.com/vercel/ai/tree/HEAD/packages/azure/issues/15740">#15740</a>) (<a href="https://github.com/vercel/ai/tree/HEAD/packages/azure/issues/15764">#15764</a>)</li> <li><a href="https://github.com/vercel/ai/commit/d4893c4421aeaea6dc8db407c35cdeae71a65aaa"><code>d4893c4</code></a> Version Packages (<a href="https://github.com/vercel/ai/tree/HEAD/packages/azure/issues/15700">#15700</a>)</li> <li>Additional commits viewable in <a href="https://github.com/vercel/ai/commits/@ai-sdk/azure@3.0.74/packages/azure">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> <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21566?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. --> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
b81641808a |
chore(deps): bump @graphiql/plugin-explorer from 5.1.2 to 5.1.3 (#21565)
Bumps [@graphiql/plugin-explorer](https://github.com/graphql/graphiql/tree/HEAD/packages/graphiql-plugin-explorer) from 5.1.2 to 5.1.3. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/graphql/graphiql/releases">@graphiql/plugin-explorer's releases</a>.</em></p> <blockquote> <h2><code>@graphiql/plugin-explorer</code><a href="https://github.com/5"><code>@5</code></a>.1.3</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/graphql/graphiql/pull/4346">#4346</a> <a href="https://github.com/graphql/graphiql/commit/0f5a2a0b250a568ca618e934a5ad119a869bb973"><code>0f5a2a0</code></a> Thanks <a href="https://github.com/trevor-scheer"><code>@trevor-scheer</code></a>! - Release a patch version of the packages served from esm.sh in the <a href="https://github.com/graphql/graphiql/tree/HEAD/packages/graphiql-plugin-explorer/blob/HEAD/examples/graphiql-cdn/index.html">GraphiQL CDN example</a> to trigger a rebuild on esm.sh now that a longstanding esm.sh issue has been fixed.</li> </ul> <h2><code>@graphiql/plugin-explorer</code><a href="https://github.com/5"><code>@5</code></a>.1.3-alpha.0</h2> <h3>Patch Changes</h3> <ul> <li>Updated dependencies [<a href="https://github.com/graphql/graphiql/commit/5f44a27ae0ff370b4f9eaffe8f92975091bfeb89"><code>5f44a27</code></a>]: <ul> <li><code>@graphiql/react</code><a href="https://github.com/0"><code>@0</code></a>.37.6-alpha.0</li> </ul> </li> </ul> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/graphql/graphiql/blob/main/packages/graphiql-plugin-explorer/CHANGELOG.md">@graphiql/plugin-explorer's changelog</a>.</em></p> <blockquote> <h2>5.1.3</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/graphql/graphiql/pull/4346">#4346</a> <a href="https://github.com/graphql/graphiql/commit/0f5a2a0b250a568ca618e934a5ad119a869bb973"><code>0f5a2a0</code></a> Thanks <a href="https://github.com/trevor-scheer"><code>@trevor-scheer</code></a>! - Release a patch version of the packages served from esm.sh in the <a href="https://github.com/graphql/graphiql/blob/main/packages/graphiql-plugin-explorer/examples/graphiql-cdn/index.html">GraphiQL CDN example</a> to trigger a rebuild on esm.sh now that a longstanding esm.sh issue has been fixed.</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/graphql/graphiql/commit/987eb5c51fa29d0a9babf86aa54764acc9a17f2c"><code>987eb5c</code></a> Version Packages (<a href="https://github.com/graphql/graphiql/tree/HEAD/packages/graphiql-plugin-explorer/issues/4343">#4343</a>)</li> <li><a href="https://github.com/graphql/graphiql/commit/d23f3b1a0b67cd3ae82d43b049b2651ef946c95e"><code>d23f3b1</code></a> Cut over from tsc to tsgo (<a href="https://github.com/graphql/graphiql/tree/HEAD/packages/graphiql-plugin-explorer/issues/4274">#4274</a>)</li> <li>See full diff in <a href="https://github.com/graphql/graphiql/commits/@graphiql/plugin-explorer@5.1.3/packages/graphiql-plugin-explorer">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> <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21565?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. --> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
9d5561c96c |
chore(deps): bump @xyflow/react from 12.10.0 to 12.11.0 (#21561)
Bumps [@xyflow/react](https://github.com/xyflow/xyflow/tree/HEAD/packages/react) from 12.10.0 to 12.11.0. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/xyflow/xyflow/releases">@xyflow/react's releases</a>.</em></p> <blockquote> <h2><code>@xyflow/react</code><a href="https://github.com/12"><code>@12</code></a>.11.0</h2> <h2>12.11.0</h2> <h3>Minor Changes</h3> <ul> <li><a href="https://redirect.github.com/xyflow/xyflow/pull/5677">#5677</a> <a href="https://github.com/xyflow/xyflow/commit/e6661de531212f9a209dba17dd63fbbd4ee16f62"><code>e6661de</code></a> - Add <code>autoPanOnSelection</code> to auto-pan when user drags a selection close to the edge of the viewport.</li> </ul> <h3>Patch Changes</h3> <ul> <li> <p><a href="https://redirect.github.com/xyflow/xyflow/pull/5791">#5791</a> <a href="https://github.com/xyflow/xyflow/commit/732c8eb8d5ff86ab1c057588724221e9b3b8553c"><code>732c8eb</code></a> - Adds a type error when <code>handleId</code> is used without <code>handleType</code> in <code>useNodeConnections</code></p> </li> <li> <p><a href="https://redirect.github.com/xyflow/xyflow/pull/5793">#5793</a> <a href="https://github.com/xyflow/xyflow/commit/c5c853d4a2f537caaea725ab9e7bd480e24b86fb"><code>c5c853d</code></a> - Dev Warnings now use library-specific messaging with the correct documentation links.</p> </li> <li> <p><a href="https://redirect.github.com/xyflow/xyflow/pull/5776">#5776</a> <a href="https://github.com/xyflow/xyflow/commit/0441e9f9471380b5ba057fc0a6a8cbdc6ff5ed7b"><code>0441e9f</code></a> - Export <code>NodeHandle</code> type</p> </li> <li> <p><a href="https://redirect.github.com/xyflow/xyflow/pull/5755">#5755</a> <a href="https://github.com/xyflow/xyflow/commit/88737f9713f3a6f99c6448e02b6518c7aeedae28"><code>88737f9</code></a> - Add <code>@types/react</code> and <code>@types/react-dom</code> as optional peer dependencies to prevent issues with pnpm strict mode (<code>hoist: false</code>)</p> </li> <li> <p><a href="https://redirect.github.com/xyflow/xyflow/pull/5105">#5105</a> <a href="https://github.com/xyflow/xyflow/commit/076ad3893725f654641f7b8c39e7a4e7935eb702"><code>076ad38</code></a> - Fix type for event passed to onNodeDrag</p> </li> <li> <p><a href="https://redirect.github.com/xyflow/xyflow/pull/5784">#5784</a> <a href="https://github.com/xyflow/xyflow/commit/7055140e66e4aebb08ce512bdff34add7e115472"><code>7055140</code></a> - Fix node resizing possible beyond absolute extents</p> </li> <li> <p><a href="https://redirect.github.com/xyflow/xyflow/pull/5769">#5769</a> <a href="https://github.com/xyflow/xyflow/commit/ad4d547724a1c2debf8eb7c6e117aabbfd601934"><code>ad4d547</code></a> - Use <code>useEffect</code> for StoreUpdater to restore previous behaviour</p> </li> <li> <p>Updated dependencies [<a href="https://github.com/xyflow/xyflow/commit/732c8eb8d5ff86ab1c057588724221e9b3b8553c"><code>732c8eb</code></a>, <a href="https://github.com/xyflow/xyflow/commit/c5c853d4a2f537caaea725ab9e7bd480e24b86fb"><code>c5c853d</code></a>, <a href="https://github.com/xyflow/xyflow/commit/e6661de531212f9a209dba17dd63fbbd4ee16f62"><code>e6661de</code></a>, <a href="https://github.com/xyflow/xyflow/commit/737194d571894dd84ce7cbab02f2a4d0b779d018"><code>737194d</code></a>, <a href="https://github.com/xyflow/xyflow/commit/40660cdb054fb1a110799a3ad7cecbf51371727f"><code>40660cd</code></a>, <a href="https://github.com/xyflow/xyflow/commit/4806e7cde6d69cd7570098ecca86523666b80175"><code>4806e7c</code></a>, <a href="https://github.com/xyflow/xyflow/commit/7055140e66e4aebb08ce512bdff34add7e115472"><code>7055140</code></a>]:</p> <ul> <li><code>@xyflow/system</code><a href="https://github.com/0"><code>@0</code></a>.0.77</li> </ul> </li> </ul> <h2><code>@xyflow/react</code><a href="https://github.com/12"><code>@12</code></a>.10.2</h2> <h3>Patch Changes</h3> <ul> <li> <p><a href="https://redirect.github.com/xyflow/xyflow/pull/5735">#5735</a> <a href="https://github.com/xyflow/xyflow/commit/a6c938fb2e5ed030512ef75d665ac80dc3a66bc6"><code>a6c938fb2</code></a> Thanks <a href="https://github.com/nvie"><code>@nvie</code></a>! - Allow <code>type</code> field to be missing in <code>BuiltInNode</code> (no <code>type</code> field is the same as <code>type: "default"</code>)</p> </li> <li> <p><a href="https://redirect.github.com/xyflow/xyflow/pull/5722">#5722</a> <a href="https://github.com/xyflow/xyflow/commit/8c9b7e726e0bb79871c85017dace0f1ccf1b478c"><code>8c9b7e726</code></a> Thanks <a href="https://github.com/dfblhmm"><code>@dfblhmm</code></a>! - Add <code>snapGrid</code> to <code>screenToFlowPosition</code> options</p> </li> <li> <p><a href="https://redirect.github.com/xyflow/xyflow/pull/5723">#5723</a> <a href="https://github.com/xyflow/xyflow/commit/82249517a3338d7bd0d6d499abecfaa6bca8c339"><code>82249517a</code></a> Thanks <a href="https://github.com/moklick"><code>@moklick</code></a>! - Pass options to useReactFlow/useSvelteFlow viewport helper functions correctly</p> </li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/xyflow/xyflow/blob/main/packages/react/CHANGELOG.md">@xyflow/react's changelog</a>.</em></p> <blockquote> <h2>12.11.0</h2> <h3>Minor Changes</h3> <ul> <li><a href="https://redirect.github.com/xyflow/xyflow/pull/5677">#5677</a> <a href="https://github.com/xyflow/xyflow/commit/e6661de531212f9a209dba17dd63fbbd4ee16f62"><code>e6661de</code></a> - Add <code>autoPanOnSelection</code> to auto-pan when user drags a selection close to the edge of the viewport.</li> </ul> <h3>Patch Changes</h3> <ul> <li> <p><a href="https://redirect.github.com/xyflow/xyflow/pull/5791">#5791</a> <a href="https://github.com/xyflow/xyflow/commit/732c8eb8d5ff86ab1c057588724221e9b3b8553c"><code>732c8eb</code></a> - Adds a type error when <code>handleId</code> is used without <code>handleType</code> in <code>useNodeConnections</code></p> </li> <li> <p><a href="https://redirect.github.com/xyflow/xyflow/pull/5793">#5793</a> <a href="https://github.com/xyflow/xyflow/commit/c5c853d4a2f537caaea725ab9e7bd480e24b86fb"><code>c5c853d</code></a> - Dev Warnings now use library-specific messaging with the correct documentation links.</p> </li> <li> <p><a href="https://redirect.github.com/xyflow/xyflow/pull/5776">#5776</a> <a href="https://github.com/xyflow/xyflow/commit/0441e9f9471380b5ba057fc0a6a8cbdc6ff5ed7b"><code>0441e9f</code></a> - Export <code>NodeHandle</code> type</p> </li> <li> <p><a href="https://redirect.github.com/xyflow/xyflow/pull/5755">#5755</a> <a href="https://github.com/xyflow/xyflow/commit/88737f9713f3a6f99c6448e02b6518c7aeedae28"><code>88737f9</code></a> - Add <code>@types/react</code> and <code>@types/react-dom</code> as optional peer dependencies to prevent issues with pnpm strict mode (<code>hoist: false</code>)</p> </li> <li> <p><a href="https://redirect.github.com/xyflow/xyflow/pull/5105">#5105</a> <a href="https://github.com/xyflow/xyflow/commit/076ad3893725f654641f7b8c39e7a4e7935eb702"><code>076ad38</code></a> - Fix type for event passed to onNodeDrag</p> </li> <li> <p><a href="https://redirect.github.com/xyflow/xyflow/pull/5784">#5784</a> <a href="https://github.com/xyflow/xyflow/commit/7055140e66e4aebb08ce512bdff34add7e115472"><code>7055140</code></a> - Fix node resizing possible beyond absolute extents</p> </li> <li> <p><a href="https://redirect.github.com/xyflow/xyflow/pull/5769">#5769</a> <a href="https://github.com/xyflow/xyflow/commit/ad4d547724a1c2debf8eb7c6e117aabbfd601934"><code>ad4d547</code></a> - Use <code>useEffect</code> for StoreUpdater to restore previous behaviour</p> </li> <li> <p>Updated dependencies [<a href="https://github.com/xyflow/xyflow/commit/732c8eb8d5ff86ab1c057588724221e9b3b8553c"><code>732c8eb</code></a>, <a href="https://github.com/xyflow/xyflow/commit/c5c853d4a2f537caaea725ab9e7bd480e24b86fb"><code>c5c853d</code></a>, <a href="https://github.com/xyflow/xyflow/commit/e6661de531212f9a209dba17dd63fbbd4ee16f62"><code>e6661de</code></a>, <a href="https://github.com/xyflow/xyflow/commit/737194d571894dd84ce7cbab02f2a4d0b779d018"><code>737194d</code></a>, <a href="https://github.com/xyflow/xyflow/commit/40660cdb054fb1a110799a3ad7cecbf51371727f"><code>40660cd</code></a>, <a href="https://github.com/xyflow/xyflow/commit/4806e7cde6d69cd7570098ecca86523666b80175"><code>4806e7c</code></a>, <a href="https://github.com/xyflow/xyflow/commit/7055140e66e4aebb08ce512bdff34add7e115472"><code>7055140</code></a>]:</p> <ul> <li><code>@xyflow/system</code><a href="https://github.com/0"><code>@0</code></a>.0.77</li> </ul> </li> </ul> <h2>12.10.2</h2> <h3>Patch Changes</h3> <ul> <li> <p><a href="https://redirect.github.com/xyflow/xyflow/pull/5735">#5735</a> <a href="https://github.com/xyflow/xyflow/commit/a6c938fb2e5ed030512ef75d665ac80dc3a66bc6"><code>a6c938fb2</code></a> Thanks <a href="https://github.com/nvie"><code>@nvie</code></a>! - Allow <code>type</code> field to be missing in <code>BuiltInNode</code> (no <code>type</code> field is the same as <code>type: "default"</code>)</p> </li> <li> <p><a href="https://redirect.github.com/xyflow/xyflow/pull/5722">#5722</a> <a href="https://github.com/xyflow/xyflow/commit/8c9b7e726e0bb79871c85017dace0f1ccf1b478c"><code>8c9b7e726</code></a> Thanks <a href="https://github.com/dfblhmm"><code>@dfblhmm</code></a>! - Add <code>snapGrid</code> to <code>screenToFlowPosition</code> options</p> </li> <li> <p><a href="https://redirect.github.com/xyflow/xyflow/pull/5723">#5723</a> <a href="https://github.com/xyflow/xyflow/commit/82249517a3338d7bd0d6d499abecfaa6bca8c339"><code>82249517a</code></a> Thanks <a href="https://github.com/moklick"><code>@moklick</code></a>! - Pass options to useReactFlow/useSvelteFlow viewport helper functions correctly</p> </li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/xyflow/xyflow/commit/6970ded32ff745e8fb6ecc97eb6b78956d7cc016"><code>6970ded</code></a> chore(packages): bump</li> <li><a href="https://github.com/xyflow/xyflow/commit/c9db70d050830fa1b06703ef775b12120a0662e2"><code>c9db70d</code></a> Merge branch 'main' of <a href="https://github.com/xyflow/xyflow">https://github.com/xyflow/xyflow</a> into 5780-svelte-flow...</li> <li><a href="https://github.com/xyflow/xyflow/commit/af23aef9de095f68fc893b8d18296398c54329bf"><code>af23aef</code></a> chore: cleanup error messages</li> <li><a href="https://github.com/xyflow/xyflow/commit/9d58ab9d2ff1bbf1dc79bb556cc9eed725d116d6"><code>9d58ab9</code></a> fix: make error messages framework-specific</li> <li><a href="https://github.com/xyflow/xyflow/commit/e52bb557888fbae0237432300142180aaca1774f"><code>e52bb55</code></a> Merge pull request <a href="https://github.com/xyflow/xyflow/tree/HEAD/packages/react/issues/5105">#5105</a> from thedanchez/xydrag-type-generics</li> <li><a href="https://github.com/xyflow/xyflow/commit/03e3dc0ae6ac64d77ab9281a3dbf629ee8b75d4e"><code>03e3dc0</code></a> Merge pull request <a href="https://github.com/xyflow/xyflow/tree/HEAD/packages/react/issues/5755">#5755</a> from nielskaspers/fix/issue-5738-react-types-peer-dep</li> <li><a href="https://github.com/xyflow/xyflow/commit/caebfd681b997020fe20444c181113d161ff7aa0"><code>caebfd6</code></a> Merge pull request <a href="https://github.com/xyflow/xyflow/tree/HEAD/packages/react/issues/5784">#5784</a> from xyflow/fix-node-resizer-again</li> <li><a href="https://github.com/xyflow/xyflow/commit/9dc7ec938bed30b59417bade64473cb8f795e039"><code>9dc7ec9</code></a> chore(react): fix util function</li> <li><a href="https://github.com/xyflow/xyflow/commit/c4e783308c2adb022a431a4eb0fb8e46706e27c7"><code>c4e7833</code></a> Merge pull request <a href="https://github.com/xyflow/xyflow/tree/HEAD/packages/react/issues/5785">#5785</a> from xyflow/fix-useless-promises</li> <li><a href="https://github.com/xyflow/xyflow/commit/01fb1f1524d6b514145c1c906e1e5b2b8bb359bb"><code>01fb1f1</code></a> chore(system): add UseNodeConnectionsParams type</li> <li>Additional commits viewable in <a href="https://github.com/xyflow/xyflow/commits/@xyflow/react@12.11.0/packages/react">compare view</a></li> </ul> </details> <details> <summary>Maintainer changes</summary> <p>This version was pushed to npm by <a href="https://www.npmjs.com/~GitHub%20Actions">GitHub Actions</a>, a new releaser for <code>@xyflow/react</code> since your current version.</p> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21561?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. --> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Charles Bochet <charles@twenty.com> |
||
|
|
a84a4c1ab7 |
fix(server): load integration jest config transpile-only; drop tsx pin (#21563)
## Context Follow-up to [#21559](https://github.com/twentyhq/twenty/pull/21559) (the esbuild 0.28.1 security bump). That PR had to pin `tsx` to `4.21.0` to avoid a CI-only `server-integration-test` failure. This removes the need for that pin by fixing the root cause. ## Root cause The integration-test command boots jest with `NODE_OPTIONS="--import tsx/esm"`, while jest *also* compiles `jest-integration.config.ts` with **ts-node, type-checking on**. Two TypeScript transformers run over the same file: - tsx's loader transpiles `node-environment.interface.ts` via esbuild, downleveling the enum to `var NodeEnvironment = (…)(NodeEnvironment || {})`. - jest's ts-node then *type-checks that downleveled output* and rejects it with `TS7022: 'NodeEnvironment' … referenced directly or indirectly in its own initializer`. It's not a real type error and not esbuild's fault — esbuild's output is valid JS, just not valid TS to re-type-check. It only surfaced once `tsx` resolved to `4.22.x` (whose loader feeds that output into ts-node), which is why #21559 pinned tsx to 4.21.0. Verified in isolation: ts-node type-checking esbuild's downleveled enum → `TS7022`; the same under `transpileOnly`/`TS_NODE_TRANSPILE_ONLY=true` → clean. ## Fix Run the integration jest config **transpile-only** (`TS_NODE_TRANSPILE_ONLY=true` on the `test:integration` target, base + `with-db-reset`). The config file doesn't need type-checking at boot, and jest's ts-node now emits JS without re-type-checking esbuild's output — eliminating the whole class of tsx/esbuild-downleveling sensitivity. With the collision gone, drop the workaround from the root `package.json`: - removed the `tsx: 4.21.0` resolution - removed the `tsx/esbuild: 0.28.1` resolution `tsx`'s `^4.x` ranges now resolve to **4.22.4**, which pins esbuild `~0.28.0` → **0.28.1** on its own, so esbuild stays 0.28.1 across the lockfile with no resolution. The `//resolutions` doc block is updated accordingly. ## Verification - `yarn install` clean; lockfile has only esbuild 0.28.1; tsx resolves to 4.22.4. - `jest --config ./jest-integration.config.ts --listTests` with tsx 4.22.4 + `TS_NODE_TRANSPILE_ONLY=true` loads the config and lists all 420 suites. - CI `server-integration-test` is the real validator (the failure was CI-only). <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21563?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. --> |
||
|
|
6a6fe81d3a |
chore(deps): ignore chokidar in dependabot (#21564)
## Context Dependabot keeps proposing a chokidar v3 to v4 bump (e.g. #21555), but chokidar is intentionally pinned to v3 via a `resolutions` entry in the root `package.json`. chokidar v4 removed the native macOS FSEvents backend and falls back to `node:fs.watch`, which hits `EMFILE` on a repo this size. That was diagnosed and fixed in #20316. The bump can't even be satisfied while the resolution is in place, so the lockfile and `package.json` end up inconsistent and CI goes red. ## Change Add `chokidar` to the dependabot ignore list so it stops re-proposing the bump every cycle. The pin stays until upstream restores a native watcher backend. Closes out #21555. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21564?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. --> |
||
|
|
c5c8cf1379 |
fix(setup-script): add database schema initialization to setup script (#20063)
fixes #20062 ### Changes Made packages/twenty-utils/setup-dev-env.sh: - Added step 4 to header comment (line 11) - Added schema_exists() helper function (lines 83-91) — checks if core schema exists in default database - Added schema initialization step (lines 255-270) — runs npx nx database:reset twenty-server when schema doesn't exist - Fixed conflicting error message (line 267) CLAUDE.md: - Updated line 210 to document that the script now initializes database schema --------- Co-authored-by: Charles Bochet <charles@twenty.com> |
||
|
|
fa80eb68b3 |
fix(deps): upgrade esbuild to 0.28.1 (GHSA-gv7w-rqvm-qjhr) (#21559)
## Context Clears [Dependabot alert #1469](https://github.com/twentyhq/twenty/security/dependabot/1469) — esbuild Deno-module binary-integrity RCE (`GHSA-gv7w-rqvm-qjhr`, vulnerable `>=0.17.0 <0.28.1`, fixed in `0.28.1`). The advisory's range is much wider than the previous esbuild one (`>=0.27.3`), so it re-exposed several older transitive esbuild copies in the tree. ## Approach Prefer upgrading the parent over adding a resolution; resolutions only where the latest upstream release still pins a vulnerable esbuild **outside** the `0.28.1` range (so an upgrade can't help). **Upgraded parent (no resolution needed):** - `tsx` → `^4.22.4` across all workspaces (its `~0.28.0` esbuild now resolves to 0.28.1) - `size-limit` / `@size-limit/preset-small-lib` → `^12.1.0` in `twenty-ui` (v12 pins esbuild `^0.28.0`) **Resolutions added** (verified against npm — latest still pins vulnerable esbuild): - `@opennextjs/aws` (exact-pins 0.25.4, still 0.25.4 in latest 4.0.3) - `@lingui/cli` (`^0.25.1`, caps `<0.26`, unchanged in latest 6.3.0) - `storybook` (range tops at `^0.27.0`, caps `<0.28`, unchanged in latest 10.4.4) - `zapier-platform-cli` (exact-pins 0.25.8, latest) The three existing esbuild resolutions (`wrangler`, `@react-email/ui`, `react-email`) remain. The `//resolutions` doc in `package.json` and the `.yarnrc.yml` age-gate comment were updated to cover both advisories. ## Result Every esbuild copy in `yarn.lock` now resolves to a single `0.28.1` entry — no version `<0.28.1` remains. Lockfile change is a net reduction (dropped duplicate esbuild trees + their `@esbuild/*` platform binaries); no unrelated deps bumped. `yarn install` passes with constraint checks enabled. <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21559?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. --> |