From 8b9e3a0fc379d84910e576578c6e4f5b4dfeb4f1 Mon Sep 17 00:00:00 2001 From: martmull Date: Mon, 22 Jun 2026 12:33:38 +0200 Subject: [PATCH] Add self-hosting on internal ci apps (#21940) Add self-hosting to internal apps CI: remove from CI_EXCLUDED_APPLICATIONS and unify config with twenty-discord/twenty-slack. Review in cubic --- .github/workflows/ci-internal-apps.yaml | 2 +- .../internal/self-hosting/.oxlintrc.json | 44 ++++- .../internal/self-hosting/package.json | 16 +- .../__tests__/app-install.integration-test.ts | 72 ------- .../src/__tests__/global-setup.ts | 87 +++++++++ .../self-hosting.integration-test.ts | 25 +++ .../self-hosting/src/__tests__/setup-test.ts | 53 ------ .../telemetryWebhook.function.ts | 6 +- .../is-test-or-example-email.test.ts | 17 ++ .../utils/is-test-or-example-email.ts | 7 + .../self-host-user-navigation-menu-item.ts | 6 +- .../internal/self-hosting/tsconfig.json | 4 +- .../internal/self-hosting/vitest.config.ts | 19 +- .../self-hosting/vitest.unit.config.ts | 14 ++ .../internal/self-hosting/yarn.lock | 176 +++++++++++++++--- 15 files changed, 373 insertions(+), 175 deletions(-) delete mode 100644 packages/twenty-apps/internal/self-hosting/src/__tests__/app-install.integration-test.ts create mode 100644 packages/twenty-apps/internal/self-hosting/src/__tests__/global-setup.ts create mode 100644 packages/twenty-apps/internal/self-hosting/src/__tests__/self-hosting.integration-test.ts delete mode 100644 packages/twenty-apps/internal/self-hosting/src/__tests__/setup-test.ts create mode 100644 packages/twenty-apps/internal/self-hosting/src/logic-functions/utils/__tests__/is-test-or-example-email.test.ts create mode 100644 packages/twenty-apps/internal/self-hosting/src/logic-functions/utils/is-test-or-example-email.ts create mode 100644 packages/twenty-apps/internal/self-hosting/vitest.unit.config.ts diff --git a/.github/workflows/ci-internal-apps.yaml b/.github/workflows/ci-internal-apps.yaml index f1f51d8292..c30bf0f5aa 100644 --- a/.github/workflows/ci-internal-apps.yaml +++ b/.github/workflows/ci-internal-apps.yaml @@ -66,7 +66,7 @@ jobs: // keep this PR small while the remaining apps are made CI-ready. Remove an // app from this list once its checks pass, and delete the list entirely // once every application is covered. - const CI_EXCLUDED_APPLICATIONS = ['call-recording', 'people-data-labs', 'self-hosting', 'twenty-for-twenty', 'twenty-linear', 'twenty-meeting-bot', 'twenty-partners']; + const CI_EXCLUDED_APPLICATIONS = ['call-recording', 'people-data-labs', 'twenty-for-twenty', 'twenty-linear', 'twenty-meeting-bot', 'twenty-partners']; const eventName = process.env.EVENT_NAME; const changedFiles = JSON.parse(process.env.CHANGED_FILES || '[]'); const changedApps = new Set(); diff --git a/packages/twenty-apps/internal/self-hosting/.oxlintrc.json b/packages/twenty-apps/internal/self-hosting/.oxlintrc.json index 34c54bff59..2c2035b0fe 100644 --- a/packages/twenty-apps/internal/self-hosting/.oxlintrc.json +++ b/packages/twenty-apps/internal/self-hosting/.oxlintrc.json @@ -1,20 +1,58 @@ { "$schema": "./node_modules/oxlint/configuration_schema.json", "extends": ["../../.oxlintrc.base.json"], - "plugins": ["typescript"], + "plugins": ["react", "typescript", "import", "unicorn"], "categories": { "correctness": "off" }, "ignorePatterns": ["node_modules", "dist"], "rules": { + "func-style": ["error", "declaration", { "allowArrowFunctions": true }], + "no-console": "off", + "no-control-regex": "off", + "no-debugger": "error", + "no-duplicate-imports": "error", + "no-undef": "off", "no-unused-vars": "off", - + "no-redeclare": "off", + "import/no-duplicates": "error", + "typescript/no-redeclare": "error", + "typescript/ban-ts-comment": "error", + "typescript/consistent-type-imports": [ + "error", + { + "prefer": "type-imports", + "fixStyle": "inline-type-imports" + } + ], + "typescript/explicit-function-return-type": "off", + "typescript/explicit-module-boundary-types": "off", + "typescript/no-empty-object-type": [ + "error", + { + "allowInterfaces": "with-single-extends" + } + ], + "typescript/no-empty-function": "off", + "typescript/no-explicit-any": "off", "typescript/no-unused-vars": [ "warn", { + "vars": "all", + "varsIgnorePattern": "^_", + "args": "after-used", "argsIgnorePattern": "^_" } ], - "typescript/no-explicit-any": "off" + "react/no-unescaped-entities": "off", + "react/prop-types": "off", + "react/jsx-key": "off", + "react/display-name": "off", + "react/jsx-uses-react": "off", + "react/react-in-jsx-scope": "off", + "react/jsx-no-useless-fragment": "off", + "react/jsx-props-no-spreading": ["error", { "explicitSpread": "ignore" }], + "react-hooks/rules-of-hooks": "error", + "react-hooks/exhaustive-deps": "warn" } } diff --git a/packages/twenty-apps/internal/self-hosting/package.json b/packages/twenty-apps/internal/self-hosting/package.json index fd3d775d42..1395a52301 100644 --- a/packages/twenty-apps/internal/self-hosting/package.json +++ b/packages/twenty-apps/internal/self-hosting/package.json @@ -7,13 +7,18 @@ "npm": "please-use-yarn", "yarn": ">=4.0.2" }, + "keywords": [ + "twenty-app" + ], "packageManager": "yarn@4.13.0", "scripts": { "twenty": "twenty", "lint": "oxlint -c .oxlintrc.json .", "lint:fix": "oxlint --fix -c .oxlintrc.json .", + "typecheck": "tsgo --noEmit -p tsconfig.spec.json", "test": "vitest run", - "test:watch": "vitest" + "test:watch": "vitest", + "test:unit": "vitest run --config vitest.unit.config.ts" }, "dependencies": { "twenty-client-sdk": "2.13.0", @@ -21,10 +26,13 @@ }, "devDependencies": { "@types/node": "^24.7.2", - "@types/react": "^19.0.0", + "@types/react": "^18.2.0", + "@typescript/native-preview": "^7.0.0-dev.20260116.1", "oxlint": "^0.16.0", - "react": "^19.0.0", - "react-dom": "^19.0.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "twenty-client-sdk": "^2.14.0", + "twenty-sdk": "^2.14.0", "typescript": "^5.9.3", "vite-tsconfig-paths": "^4.2.1", "vitest": "^4.0.0" diff --git a/packages/twenty-apps/internal/self-hosting/src/__tests__/app-install.integration-test.ts b/packages/twenty-apps/internal/self-hosting/src/__tests__/app-install.integration-test.ts deleted file mode 100644 index bdc379a1d3..0000000000 --- a/packages/twenty-apps/internal/self-hosting/src/__tests__/app-install.integration-test.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { appBuild, appDeploy, appInstall, appUninstall } from 'twenty-sdk/cli'; -import { MetadataApiClient } from 'twenty-client-sdk/metadata'; -import { afterAll, beforeAll, describe, expect, it } from 'vitest'; -import { APPLICATION_UNIVERSAL_IDENTIFIER } from 'src/application.config'; - -const APP_PATH = process.cwd(); - -describe('App installation', () => { - beforeAll(async () => { - const buildResult = await appBuild({ - appPath: APP_PATH, - tarball: true, - onProgress: (message: string) => console.log(`[build] ${message}`), - }); - - if (!buildResult.success) { - throw new Error( - `Build failed: ${buildResult.error?.message ?? 'Unknown error'}`, - ); - } - - const deployResult = await appDeploy({ - tarballPath: buildResult.data.tarballPath!, - onProgress: (message: string) => console.log(`[deploy] ${message}`), - }); - - if (!deployResult.success) { - throw new Error( - `Deploy failed: ${deployResult.error?.message ?? 'Unknown error'}`, - ); - } - - const installResult = await appInstall({ appPath: APP_PATH }); - - if (!installResult.success) { - throw new Error( - `Install failed: ${installResult.error?.message ?? 'Unknown error'}`, - ); - } - }); - - afterAll(async () => { - const uninstallResult = await appUninstall({ appPath: APP_PATH }); - - if (!uninstallResult.success) { - console.warn( - `App uninstall failed: ${ - uninstallResult.error?.message ?? 'Unknown error' - }`, - ); - } - }); - - it('should find the installed app in the applications list', async () => { - const metadataClient = new MetadataApiClient(); - - const result = await metadataClient.query({ - findManyApplications: { - id: true, - name: true, - universalIdentifier: true, - }, - }); - - const installedApp = result.findManyApplications.find( - (application: { universalIdentifier: string }) => - application.universalIdentifier === APPLICATION_UNIVERSAL_IDENTIFIER, - ); - - expect(installedApp).toBeDefined(); - }); -}); diff --git a/packages/twenty-apps/internal/self-hosting/src/__tests__/global-setup.ts b/packages/twenty-apps/internal/self-hosting/src/__tests__/global-setup.ts new file mode 100644 index 0000000000..e0f8c23b05 --- /dev/null +++ b/packages/twenty-apps/internal/self-hosting/src/__tests__/global-setup.ts @@ -0,0 +1,87 @@ +import * as fs from 'fs'; +import * as os from 'os'; +import * as path from 'path'; + +import { appDevOnce, appUninstall } from 'twenty-sdk/cli'; + +const APP_PATH = process.cwd(); +const CONFIG_DIR = path.join(os.homedir(), '.twenty'); + +function validateEnv(): { apiUrl: string; apiKey: string } { + const apiUrl = process.env.TWENTY_API_URL; + const apiKey = process.env.TWENTY_API_KEY; + + if (!apiUrl || !apiKey) { + throw new Error( + 'TWENTY_API_URL and TWENTY_API_KEY must be set.\n' + + 'Start a local server: yarn twenty docker:start\n' + + 'Or set them in vitest env config.', + ); + } + + return { apiUrl, apiKey }; +} + +async function checkServer(apiUrl: string) { + let response: Response; + + try { + response = await fetch(`${apiUrl}/healthz`); + } catch { + throw new Error( + `Twenty server is not reachable at ${apiUrl}. ` + + 'Make sure the server is running before executing integration tests.', + ); + } + + if (!response.ok) { + throw new Error(`Server at ${apiUrl} returned ${response.status}`); + } +} + +function writeConfig(apiUrl: string, apiKey: string) { + const payload = JSON.stringify( + { + remotes: { + local: { apiUrl, apiKey, accessToken: apiKey }, + }, + defaultRemote: 'local', + }, + null, + 2, + ); + + fs.mkdirSync(CONFIG_DIR, { recursive: true }); + fs.writeFileSync(path.join(CONFIG_DIR, 'config.test.json'), payload); +} + +export async function setup() { + const { apiUrl, apiKey } = validateEnv(); + + await checkServer(apiUrl); + + writeConfig(apiUrl, apiKey); + + await appUninstall({ appPath: APP_PATH }).catch(() => {}); + + const result = await appDevOnce({ + appPath: APP_PATH, + onProgress: (message: string) => console.log(`[dev] ${message}`), + }); + + if (!result.success) { + throw new Error( + `Dev sync failed: ${result.error?.message ?? 'Unknown error'}`, + ); + } +} + +export async function teardown() { + const uninstallResult = await appUninstall({ appPath: APP_PATH }); + + if (!uninstallResult.success) { + console.warn( + `App uninstall failed: ${uninstallResult.error?.message ?? 'Unknown error'}`, + ); + } +} diff --git a/packages/twenty-apps/internal/self-hosting/src/__tests__/self-hosting.integration-test.ts b/packages/twenty-apps/internal/self-hosting/src/__tests__/self-hosting.integration-test.ts new file mode 100644 index 0000000000..e4ce17b307 --- /dev/null +++ b/packages/twenty-apps/internal/self-hosting/src/__tests__/self-hosting.integration-test.ts @@ -0,0 +1,25 @@ +import { MetadataApiClient } from 'twenty-client-sdk/metadata'; +import { describe, expect, it } from 'vitest'; + +import { APPLICATION_UNIVERSAL_IDENTIFIER } from 'src/application.config'; + +describe('App installation', () => { + it('should find the installed Self Hosting app in the applications list', async () => { + const client = new MetadataApiClient(); + + const result = await client.query({ + findManyApplications: { + id: true, + name: true, + universalIdentifier: true, + }, + }); + + const matchingApplication = result.findManyApplications.find( + (application: { universalIdentifier: string }) => + application.universalIdentifier === APPLICATION_UNIVERSAL_IDENTIFIER, + ); + + expect(matchingApplication).toBeDefined(); + }); +}); diff --git a/packages/twenty-apps/internal/self-hosting/src/__tests__/setup-test.ts b/packages/twenty-apps/internal/self-hosting/src/__tests__/setup-test.ts deleted file mode 100644 index bfc05cb800..0000000000 --- a/packages/twenty-apps/internal/self-hosting/src/__tests__/setup-test.ts +++ /dev/null @@ -1,53 +0,0 @@ -import * as fs from 'fs'; -import * as os from 'os'; -import * as path from 'path'; -import { beforeAll } from 'vitest'; - -const CONFIG_DIR = path.join(os.homedir(), '.twenty'); -const CONFIG_PATH = path.join(CONFIG_DIR, 'config.test.json'); - -beforeAll(async () => { - const apiUrl = process.env.TWENTY_API_URL!; - const token = process.env.TWENTY_API_KEY!; - - if (!apiUrl || !token) { - throw new Error( - 'TWENTY_API_URL and TWENTY_API_KEY must be set.\n' + - 'Start a local server: yarn twenty docker:start\n' + - 'Or set them in vitest env config.', - ); - } - - let response: Response; - - try { - response = await fetch(`${apiUrl}/healthz`); - } catch { - throw new Error( - `Twenty server is not reachable at ${apiUrl}. ` + - 'Make sure the server is running before executing integration tests.', - ); - } - - if (!response.ok) { - throw new Error(`Server at ${apiUrl} returned ${response.status}`); - } - - fs.mkdirSync(CONFIG_DIR, { recursive: true }); - - fs.writeFileSync( - CONFIG_PATH, - JSON.stringify( - { - remotes: { - local: { apiUrl, apiKey: token }, - }, - defaultRemote: 'local', - }, - null, - 2, - ), - ); - - process.env.TWENTY_APP_ACCESS_TOKEN ??= token; -}); diff --git a/packages/twenty-apps/internal/self-hosting/src/logic-functions/telemetryWebhook.function.ts b/packages/twenty-apps/internal/self-hosting/src/logic-functions/telemetryWebhook.function.ts index 2df303be07..7b5c840208 100644 --- a/packages/twenty-apps/internal/self-hosting/src/logic-functions/telemetryWebhook.function.ts +++ b/packages/twenty-apps/internal/self-hosting/src/logic-functions/telemetryWebhook.function.ts @@ -2,6 +2,7 @@ import { defineLogicFunction } from 'twenty-sdk/define'; import { type RoutePayload } from 'twenty-sdk/logic-function'; import { CoreApiClient } from 'twenty-client-sdk/core'; import { type TelemetryEvent } from 'src/logic-functions/types/telemetry-event.type'; +import { isTestOrExampleEmail } from 'src/logic-functions/utils/is-test-or-example-email'; export const main = async ( params: RoutePayload, @@ -38,10 +39,7 @@ export const main = async ( }; } - if ( - userEmail.toLowerCase().includes('example') || - userEmail.toLowerCase().includes('test') - ) { + if (isTestOrExampleEmail(userEmail)) { return { success: true, message: `Email '${userEmail}' ignored (contains test/example data)`, diff --git a/packages/twenty-apps/internal/self-hosting/src/logic-functions/utils/__tests__/is-test-or-example-email.test.ts b/packages/twenty-apps/internal/self-hosting/src/logic-functions/utils/__tests__/is-test-or-example-email.test.ts new file mode 100644 index 0000000000..39169db8db --- /dev/null +++ b/packages/twenty-apps/internal/self-hosting/src/logic-functions/utils/__tests__/is-test-or-example-email.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, it } from 'vitest'; + +import { isTestOrExampleEmail } from 'src/logic-functions/utils/is-test-or-example-email'; + +describe('isTestOrExampleEmail', () => { + it('should return true when the email contains "example"', () => { + expect(isTestOrExampleEmail('jane@example.com')).toBe(true); + }); + + it('should return true when the email contains "test" regardless of case', () => { + expect(isTestOrExampleEmail('John.TEST@company.com')).toBe(true); + }); + + it('should return false for a regular email address', () => { + expect(isTestOrExampleEmail('jane@twenty.com')).toBe(false); + }); +}); diff --git a/packages/twenty-apps/internal/self-hosting/src/logic-functions/utils/is-test-or-example-email.ts b/packages/twenty-apps/internal/self-hosting/src/logic-functions/utils/is-test-or-example-email.ts new file mode 100644 index 0000000000..7b9c4d31a6 --- /dev/null +++ b/packages/twenty-apps/internal/self-hosting/src/logic-functions/utils/is-test-or-example-email.ts @@ -0,0 +1,7 @@ +export const isTestOrExampleEmail = (email: string): boolean => { + const normalizedEmail = email.toLowerCase(); + + return ( + normalizedEmail.includes('example') || normalizedEmail.includes('test') + ); +}; diff --git a/packages/twenty-apps/internal/self-hosting/src/navigation-menu-items/self-host-user-navigation-menu-item.ts b/packages/twenty-apps/internal/self-hosting/src/navigation-menu-items/self-host-user-navigation-menu-item.ts index 18a4f1097f..75d2e5ab42 100644 --- a/packages/twenty-apps/internal/self-hosting/src/navigation-menu-items/self-host-user-navigation-menu-item.ts +++ b/packages/twenty-apps/internal/self-hosting/src/navigation-menu-items/self-host-user-navigation-menu-item.ts @@ -1,5 +1,7 @@ -import { defineNavigationMenuItem } from 'twenty-sdk/define'; -import { NavigationMenuItemType } from 'twenty-shared/types'; +import { + NavigationMenuItemType, + defineNavigationMenuItem, +} from 'twenty-sdk/define'; import { UNIVERSAL_IDENTIFIERS } from 'src/constants/universal-identifiers.constant'; export default defineNavigationMenuItem({ diff --git a/packages/twenty-apps/internal/self-hosting/tsconfig.json b/packages/twenty-apps/internal/self-hosting/tsconfig.json index d574c8c810..abacf4dcf6 100644 --- a/packages/twenty-apps/internal/self-hosting/tsconfig.json +++ b/packages/twenty-apps/internal/self-hosting/tsconfig.json @@ -6,7 +6,7 @@ "outDir": "./dist", "rootDir": ".", "jsx": "react-jsx", - "moduleResolution": "node", + "moduleResolution": "bundler", "allowSyntheticDefaultImports": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, @@ -16,7 +16,7 @@ "alwaysStrict": true, "noImplicitAny": true, "strictBindCallApply": false, - "target": "es2018", + "target": "es2020", "module": "esnext", "lib": ["es2020", "dom"], "skipLibCheck": true, diff --git a/packages/twenty-apps/internal/self-hosting/vitest.config.ts b/packages/twenty-apps/internal/self-hosting/vitest.config.ts index 9c698b8340..055af77dbe 100644 --- a/packages/twenty-apps/internal/self-hosting/vitest.config.ts +++ b/packages/twenty-apps/internal/self-hosting/vitest.config.ts @@ -1,6 +1,15 @@ import tsconfigPaths from 'vite-tsconfig-paths'; import { defineConfig } from 'vitest/config'; +const TWENTY_API_URL = process.env.TWENTY_API_URL ?? 'http://localhost:2020'; +const TWENTY_API_KEY = + process.env.TWENTY_API_KEY ?? + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC0xYzI1LTRkMDItYmYyNS02YWVjY2Y3ZWE0MTkiLCJ0eXBlIjoiQVBJX0tFWSIsIndvcmtzcGFjZUlkIjoiMjAyMDIwMjAtMWMyNS00ZDAyLWJmMjUtNmFlY2NmN2VhNDE5IiwiaWF0IjoxNzM1Njg5NjAwLCJleHAiOjQ4OTE0NDk2MDAsImp0aSI6IjIwMjAyMDIwLWY0MDEtNGQ4YS1hNzMxLTY0ZDAwN2MyN2JhZCJ9.bfQjfyN0NEtTCLE_xPyNcwonDzlSXFoP8kdCQTdnuDc'; + +// Make env vars available to globalSetup (test.env only applies to workers) +process.env.TWENTY_API_URL = TWENTY_API_URL; +process.env.TWENTY_API_KEY = TWENTY_API_KEY; + export default defineConfig({ plugins: [ tsconfigPaths({ @@ -11,14 +20,12 @@ export default defineConfig({ test: { testTimeout: 120_000, hookTimeout: 120_000, + fileParallelism: false, include: ['src/**/*.integration-test.ts'], - setupFiles: ['src/__tests__/setup-test.ts'], + globalSetup: ['src/__tests__/global-setup.ts'], env: { - TWENTY_API_URL: process.env.TWENTY_API_URL ?? 'http://localhost:2020', - TWENTY_API_KEY: - process.env.TWENTY_API_KEY ?? - // Tim Apple (admin) access token for twenty-app-dev - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC05ZTNiLTQ2ZDQtYTU1Ni04OGI5ZGRjMmIwMzQiLCJ1c2VySWQiOiIyMDIwMjAyMC05ZTNiLTQ2ZDQtYTU1Ni04OGI5ZGRjMmIwMzQiLCJ3b3Jrc3BhY2VJZCI6IjIwMjAyMDIwLTFjMjUtNGQwMi1iZjI1LTZhZWNjZjdlYTQxOSIsIndvcmtzcGFjZU1lbWJlcklkIjoiMjAyMDIwMjAtMDY4Ny00YzQxLWI3MDctZWQxYmZjYTk3MmE3IiwidXNlcldvcmtzcGFjZUlkIjoiMjAyMDIwMjAtOWUzYi00NmQ0LWE1NTYtODhiOWRkYzJiMDM1IiwidHlwZSI6IkFDQ0VTUyIsImF1dGhQcm92aWRlciI6InBhc3N3b3JkIiwiaWF0IjoxNzUxMjgxNzA0LCJleHAiOjQ5MDQ4ODE3MDR9.9S4wc0MOr5iczsomlFxZdOHD1IRDS4dnRSwNVNpctF4', + TWENTY_API_URL, + TWENTY_API_KEY, }, }, }); diff --git a/packages/twenty-apps/internal/self-hosting/vitest.unit.config.ts b/packages/twenty-apps/internal/self-hosting/vitest.unit.config.ts new file mode 100644 index 0000000000..e0d140015b --- /dev/null +++ b/packages/twenty-apps/internal/self-hosting/vitest.unit.config.ts @@ -0,0 +1,14 @@ +import tsconfigPaths from 'vite-tsconfig-paths'; +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + plugins: [ + tsconfigPaths({ + projects: ['tsconfig.spec.json'], + ignoreConfigErrors: true, + }), + ], + test: { + include: ['src/**/*.test.ts'], + }, +}); diff --git a/packages/twenty-apps/internal/self-hosting/yarn.lock b/packages/twenty-apps/internal/self-hosting/yarn.lock index 671218b018..bb56d898c1 100644 --- a/packages/twenty-apps/internal/self-hosting/yarn.lock +++ b/packages/twenty-apps/internal/self-hosting/yarn.lock @@ -794,6 +794,13 @@ __metadata: languageName: node linkType: hard +"@types/prop-types@npm:*": + version: 15.7.15 + resolution: "@types/prop-types@npm:15.7.15" + checksum: 10c0/b59aad1ad19bf1733cf524fd4e618196c6c7690f48ee70a327eb450a42aab8e8a063fbe59ca0a5701aebe2d92d582292c0fb845ea57474f6a15f6994b0e260b2 + languageName: node + linkType: hard + "@types/qs@npm:^6.9.0": version: 6.15.0 resolution: "@types/qs@npm:6.15.0" @@ -801,12 +808,13 @@ __metadata: languageName: node linkType: hard -"@types/react@npm:^19.0.0": - version: 19.2.14 - resolution: "@types/react@npm:19.2.14" +"@types/react@npm:^18.2.0": + version: 18.3.31 + resolution: "@types/react@npm:18.3.31" dependencies: + "@types/prop-types": "npm:*" csstype: "npm:^3.2.2" - checksum: 10c0/7d25bf41b57719452d86d2ac0570b659210402707313a36ee612666bf11275a1c69824f8c3ee1fdca077ccfe15452f6da8f1224529b917050eb2d861e52b59b7 + checksum: 10c0/44180549dd045f536ececd39e39aacdf828e76adc1c4a90b132f453e23cc370c4648d9102ae401172ebd8fd8b1977a901a39e214e53ec77171b27514b588c179 languageName: node linkType: hard @@ -819,6 +827,87 @@ __metadata: languageName: node linkType: hard +"@typescript/native-preview-darwin-arm64@npm:7.0.0-dev.20260619.1": + version: 7.0.0-dev.20260619.1 + resolution: "@typescript/native-preview-darwin-arm64@npm:7.0.0-dev.20260619.1" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@typescript/native-preview-darwin-x64@npm:7.0.0-dev.20260619.1": + version: 7.0.0-dev.20260619.1 + resolution: "@typescript/native-preview-darwin-x64@npm:7.0.0-dev.20260619.1" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@typescript/native-preview-linux-arm64@npm:7.0.0-dev.20260619.1": + version: 7.0.0-dev.20260619.1 + resolution: "@typescript/native-preview-linux-arm64@npm:7.0.0-dev.20260619.1" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@typescript/native-preview-linux-arm@npm:7.0.0-dev.20260619.1": + version: 7.0.0-dev.20260619.1 + resolution: "@typescript/native-preview-linux-arm@npm:7.0.0-dev.20260619.1" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@typescript/native-preview-linux-x64@npm:7.0.0-dev.20260619.1": + version: 7.0.0-dev.20260619.1 + resolution: "@typescript/native-preview-linux-x64@npm:7.0.0-dev.20260619.1" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@typescript/native-preview-win32-arm64@npm:7.0.0-dev.20260619.1": + version: 7.0.0-dev.20260619.1 + resolution: "@typescript/native-preview-win32-arm64@npm:7.0.0-dev.20260619.1" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@typescript/native-preview-win32-x64@npm:7.0.0-dev.20260619.1": + version: 7.0.0-dev.20260619.1 + resolution: "@typescript/native-preview-win32-x64@npm:7.0.0-dev.20260619.1" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@typescript/native-preview@npm:^7.0.0-dev.20260116.1": + version: 7.0.0-dev.20260619.1 + resolution: "@typescript/native-preview@npm:7.0.0-dev.20260619.1" + dependencies: + "@typescript/native-preview-darwin-arm64": "npm:7.0.0-dev.20260619.1" + "@typescript/native-preview-darwin-x64": "npm:7.0.0-dev.20260619.1" + "@typescript/native-preview-linux-arm": "npm:7.0.0-dev.20260619.1" + "@typescript/native-preview-linux-arm64": "npm:7.0.0-dev.20260619.1" + "@typescript/native-preview-linux-x64": "npm:7.0.0-dev.20260619.1" + "@typescript/native-preview-win32-arm64": "npm:7.0.0-dev.20260619.1" + "@typescript/native-preview-win32-x64": "npm:7.0.0-dev.20260619.1" + dependenciesMeta: + "@typescript/native-preview-darwin-arm64": + optional: true + "@typescript/native-preview-darwin-x64": + optional: true + "@typescript/native-preview-linux-arm": + optional: true + "@typescript/native-preview-linux-arm64": + optional: true + "@typescript/native-preview-linux-x64": + optional: true + "@typescript/native-preview-win32-arm64": + optional: true + "@typescript/native-preview-win32-x64": + optional: true + bin: + tsgo: bin/tsgo.js + checksum: 10c0/e8bc6cf171ee29131934f662c9b3577374d7e872247831da36a5723abe175998f1318a134ed8eb0ee5213887dbb1f1209fac5555cdf5b6b19d0d7da044d0cdc9 + languageName: node + linkType: hard + "@vitest/expect@npm:4.1.8": version: 4.1.8 resolution: "@vitest/expect@npm:4.1.8" @@ -1798,6 +1887,13 @@ __metadata: languageName: node linkType: hard +"js-tokens@npm:^3.0.0 || ^4.0.0": + version: 4.0.0 + resolution: "js-tokens@npm:4.0.0" + checksum: 10c0/e248708d377aa058eacf2037b07ded847790e6de892bbad3dac0abba2e759cb9f121b00099a65195616badcb6eca8d14d975cb3e89eb1cfda644756402c8aeed + languageName: node + linkType: hard + "jsonc-parser@npm:^3.2.0": version: 3.3.1 resolution: "jsonc-parser@npm:3.3.1" @@ -1932,6 +2028,17 @@ __metadata: languageName: node linkType: hard +"loose-envify@npm:^1.1.0": + version: 1.4.0 + resolution: "loose-envify@npm:1.4.0" + dependencies: + js-tokens: "npm:^3.0.0 || ^4.0.0" + bin: + loose-envify: cli.js + checksum: 10c0/655d110220983c1a4b9c0c679a2e8016d4b67f6e9c7b5435ff5979ecdb20d0813f4dec0a08674fcbdd4846a3f07edbb50a36811fd37930b94aaa0d9daceb017e + languageName: node + linkType: hard + "lru-cache@npm:^11.0.0, lru-cache@npm:^11.1.0, lru-cache@npm:^11.2.1": version: 11.3.5 resolution: "lru-cache@npm:11.3.5" @@ -2296,14 +2403,15 @@ __metadata: languageName: node linkType: hard -"react-dom@npm:^19.0.0": - version: 19.2.5 - resolution: "react-dom@npm:19.2.5" +"react-dom@npm:^18.2.0": + version: 18.3.1 + resolution: "react-dom@npm:18.3.1" dependencies: - scheduler: "npm:^0.27.0" + loose-envify: "npm:^1.1.0" + scheduler: "npm:^0.23.2" peerDependencies: - react: ^19.2.5 - checksum: 10c0/8067606e9f58e4c2e8cb5f09570217dbc71c4843ebcaa20ae2085912d3e3a351f17d8f7c1713313cdda7f272840c8c34ff6c860fcb840862071bceea218e0c63 + react: ^18.3.1 + checksum: 10c0/a752496c1941f958f2e8ac56239172296fcddce1365ce45222d04a1947e0cc5547df3e8447f855a81d6d39f008d7c32eab43db3712077f09e3f67c4874973e85 languageName: node linkType: hard @@ -2329,10 +2437,12 @@ __metadata: languageName: node linkType: hard -"react@npm:^19.0.0": - version: 19.2.5 - resolution: "react@npm:19.2.5" - checksum: 10c0/4b5f231dbef92886f602533c9ce3bde04d99f0e71dfb5d794c43e02726efaad0421c08688f75fc98a6d6e1dc017372e1af7abbfecdc86a79968f461675931a7a +"react@npm:^18.2.0": + version: 18.3.1 + resolution: "react@npm:18.3.1" + dependencies: + loose-envify: "npm:^1.1.0" + checksum: 10c0/283e8c5efcf37802c9d1ce767f302dd569dd97a70d9bb8c7be79a789b9902451e0d16334b05d73299b20f048cbc3c7d288bbbde10b701fa194e2089c237dbea3 languageName: node linkType: hard @@ -2432,6 +2542,15 @@ __metadata: languageName: node linkType: hard +"scheduler@npm:^0.23.2": + version: 0.23.2 + resolution: "scheduler@npm:0.23.2" + dependencies: + loose-envify: "npm:^1.1.0" + checksum: 10c0/26383305e249651d4c58e6705d5f8425f153211aef95f15161c151f7b8de885f24751b377e4a0b3dd42cce09aad3f87a61dab7636859c0d89b7daf1a1e2a5c78 + languageName: node + linkType: hard + "scheduler@npm:^0.27.0": version: 0.27.0 resolution: "scheduler@npm:0.27.0" @@ -2444,12 +2563,13 @@ __metadata: resolution: "self-hosting@workspace:." dependencies: "@types/node": "npm:^24.7.2" - "@types/react": "npm:^19.0.0" + "@types/react": "npm:^18.2.0" + "@typescript/native-preview": "npm:^7.0.0-dev.20260116.1" oxlint: "npm:^0.16.0" - react: "npm:^19.0.0" - react-dom: "npm:^19.0.0" - twenty-client-sdk: "npm:2.13.0" - twenty-sdk: "npm:2.13.0" + react: "npm:^18.2.0" + react-dom: "npm:^18.2.0" + twenty-client-sdk: "npm:^2.14.0" + twenty-sdk: "npm:^2.14.0" typescript: "npm:^5.9.3" vite-tsconfig-paths: "npm:^4.2.1" vitest: "npm:^4.0.0" @@ -2718,22 +2838,22 @@ __metadata: languageName: node linkType: hard -"twenty-client-sdk@npm:2.13.0": - version: 2.13.0 - resolution: "twenty-client-sdk@npm:2.13.0" +"twenty-client-sdk@npm:2.14.0, twenty-client-sdk@npm:^2.14.0": + version: 2.14.0 + resolution: "twenty-client-sdk@npm:2.14.0" dependencies: "@genql/runtime": "npm:^2.10.0" esbuild: "npm:^0.28.1" graphql: "npm:^16.8.1" lodash: "npm:^4.17.21" prettier: "npm:^3.8.3" - checksum: 10c0/740464acec94c1d4cc5fa50ed6b190a7f1d1681963f61437a6c704835c05ffe0f5a13e254e57601a99b07bbe0f68483dee19211731853aafbcc15ec79f8039ce + checksum: 10c0/eb222a726e21fc98f3a624f9acac7d47f0c769b989911889036665dac7c7c88698ec99beb844bf51a42e1696ea0a067bae8cf47fd751965af52a3720835242f0 languageName: node linkType: hard -"twenty-sdk@npm:2.13.0": - version: 2.13.0 - resolution: "twenty-sdk@npm:2.13.0" +"twenty-sdk@npm:^2.14.0": + version: 2.14.0 + resolution: "twenty-sdk@npm:2.14.0" dependencies: "@sniptt/guards": "npm:^0.2.0" axios: "npm:^1.16.0" @@ -2750,12 +2870,12 @@ __metadata: react: "npm:^19.2.0" react-dom: "npm:^19.2.0" tinyglobby: "npm:^0.2.15" - twenty-client-sdk: "npm:2.13.0" + twenty-client-sdk: "npm:2.14.0" typescript: "npm:^5.9.3" uuid: "npm:^13.0.2" bin: twenty: dist/cli.cjs - checksum: 10c0/51c350abe5d344fcad3c961a77632fd3cb2d91e357d0562b3eb02f05f66dbc41221c5463d0f91c022316a16af03a05ad43f038d9534c0ae31c060008d0e48672 + checksum: 10c0/c4211772f8dd2ba81074a74be5f616c4c264d6bf8a174c5724be6d1c9a8cb3ca68a2674653bb58c059dae4bf1b0f43f91991e73d6a01395807206f0ac44afb08 languageName: node linkType: hard