From 936ec06fe8b99140854fa9a6bdd02d8335a32af4 Mon Sep 17 00:00:00 2001 From: martmull Date: Sat, 10 Jan 2026 15:52:28 +0100 Subject: [PATCH] Improve application ast 3 (#17061) - fix should generate - fix errors not displayed properly --- packages/create-twenty-app/package.json | 2 +- .../src/utils/__tests__/app-template.spec.ts | 2 +- .../create-twenty-app/src/utils/app-template.ts | 2 +- .../developers/extend/capabilities/apps.mdx | 4 ++++ .../tabs/SettingsServerlessFunctionTriggersTab.tsx | 5 ++++- packages/twenty-sdk/package.json | 2 +- .../test-app/src/utils/test-function-2.util.ts | 8 +++++++- packages/twenty-sdk/src/cli/commands/app.command.ts | 3 +++ .../src/cli/utils/__tests__/load-manifest.spec.ts | 2 +- packages/twenty-sdk/src/cli/utils/load-manifest.ts | 13 +++++++++---- 10 files changed, 32 insertions(+), 11 deletions(-) diff --git a/packages/create-twenty-app/package.json b/packages/create-twenty-app/package.json index da09b7532d..89fa5f0e61 100644 --- a/packages/create-twenty-app/package.json +++ b/packages/create-twenty-app/package.json @@ -1,6 +1,6 @@ { "name": "create-twenty-app", - "version": "0.3.0", + "version": "0.3.1", "description": "Command-line interface to create Twenty application", "main": "dist/cli.cjs", "bin": "dist/cli.cjs", diff --git a/packages/create-twenty-app/src/utils/__tests__/app-template.spec.ts b/packages/create-twenty-app/src/utils/__tests__/app-template.spec.ts index ba5d08fa8c..7eee983d67 100644 --- a/packages/create-twenty-app/src/utils/__tests__/app-template.spec.ts +++ b/packages/create-twenty-app/src/utils/__tests__/app-template.spec.ts @@ -67,7 +67,7 @@ describe('copyBaseApplicationProject', () => { const packageJson = await fs.readJson(packageJsonPath); expect(packageJson.name).toBe('my-test-app'); expect(packageJson.version).toBe('0.1.0'); - expect(packageJson.dependencies['twenty-sdk']).toBe('0.3.0'); + expect(packageJson.dependencies['twenty-sdk']).toBe('0.3.1'); expect(packageJson.scripts.sync).toBe('twenty app sync'); expect(packageJson.scripts.dev).toBe('twenty app dev'); }); diff --git a/packages/create-twenty-app/src/utils/app-template.ts b/packages/create-twenty-app/src/utils/app-template.ts index b0700c4730..9e6c1a8add 100644 --- a/packages/create-twenty-app/src/utils/app-template.ts +++ b/packages/create-twenty-app/src/utils/app-template.ts @@ -168,7 +168,7 @@ const createPackageJson = async ({ 'lint-fix': 'eslint --fix', }, dependencies: { - 'twenty-sdk': '0.3.0', + 'twenty-sdk': '0.3.1', }, devDependencies: { typescript: '^5.9.3', diff --git a/packages/twenty-docs/developers/extend/capabilities/apps.mdx b/packages/twenty-docs/developers/extend/capabilities/apps.mdx index 4aabf645fd..66cbc8767c 100644 --- a/packages/twenty-docs/developers/extend/capabilities/apps.mdx +++ b/packages/twenty-docs/developers/extend/capabilities/apps.mdx @@ -280,6 +280,10 @@ Key points: - The `fields` array is optional — you can define objects without custom fields. - You can scaffold new objects using `yarn create-entity`, which guides you through naming, fields, and relationships. + +**Base fields are created automatically.** When you define a custom object, Twenty automatically adds standard fields such as `name`, `createdAt`, `updatedAt`, `createdBy`, `position`, and `deletedAt`. You don't need to define these in your `fields` array — only add your custom fields. + + You can also define objects using TypeScript decorators. This approach uses class-based syntax with `@Object`, `@Field`, and `@Relation` decorators: diff --git a/packages/twenty-front/src/modules/settings/serverless-functions/components/tabs/SettingsServerlessFunctionTriggersTab.tsx b/packages/twenty-front/src/modules/settings/serverless-functions/components/tabs/SettingsServerlessFunctionTriggersTab.tsx index 8724a25386..ef59fa31b0 100644 --- a/packages/twenty-front/src/modules/settings/serverless-functions/components/tabs/SettingsServerlessFunctionTriggersTab.tsx +++ b/packages/twenty-front/src/modules/settings/serverless-functions/components/tabs/SettingsServerlessFunctionTriggersTab.tsx @@ -2,6 +2,7 @@ import { H2Title, OverflowingTextWithTooltip } from 'twenty-ui/display'; import { Section } from 'twenty-ui/layout'; import { type ServerlessFunction } from '~/generated/graphql'; import { useLingui } from '@lingui/react/macro'; +import { REACT_APP_SERVER_BASE_URL } from '~/config'; import { SettingsDatabaseEventsForm } from '@/settings/components/SettingsDatabaseEventsForm'; import { FormTextFieldInput } from '@/object-record/record-field/ui/form-types/components/FormTextFieldInput'; import { Table } from '@/ui/layout/table/components/Table'; @@ -122,7 +123,9 @@ export const SettingsServerlessFunctionTriggersTab = ({ {routeTriggers.map((routeTrigger, index) => ( - + {routeTrigger.httpMethod} diff --git a/packages/twenty-sdk/package.json b/packages/twenty-sdk/package.json index 481fd21f17..52cf85a1c8 100644 --- a/packages/twenty-sdk/package.json +++ b/packages/twenty-sdk/package.json @@ -1,6 +1,6 @@ { "name": "twenty-sdk", - "version": "0.3.0", + "version": "0.3.1", "main": "dist/index.cjs", "module": "dist/index.mjs", "types": "dist/index.d.ts", diff --git a/packages/twenty-sdk/src/cli/__tests__/test-app/src/utils/test-function-2.util.ts b/packages/twenty-sdk/src/cli/__tests__/test-app/src/utils/test-function-2.util.ts index 3d30602cb8..8849aafbd6 100644 --- a/packages/twenty-sdk/src/cli/__tests__/test-app/src/utils/test-function-2.util.ts +++ b/packages/twenty-sdk/src/cli/__tests__/test-app/src/utils/test-function-2.util.ts @@ -1 +1,7 @@ -export const testFunction2 = () => 'testFunction2'; +export const testFunction2 = () => { + const Twenty = require('../../generated').default; + + const client = new Twenty(); + + return client.query('testQuery'); +}; diff --git a/packages/twenty-sdk/src/cli/commands/app.command.ts b/packages/twenty-sdk/src/cli/commands/app.command.ts index d357a10ff6..dc809eba4e 100644 --- a/packages/twenty-sdk/src/cli/commands/app.command.ts +++ b/packages/twenty-sdk/src/cli/commands/app.command.ts @@ -1,3 +1,4 @@ +import { inspect } from 'util'; import chalk from 'chalk'; import { Command } from 'commander'; import { @@ -12,6 +13,8 @@ import { formatPath } from '@/cli/utils/format-path'; import { AppGenerateCommand } from '@/cli/commands/app-generate.command'; import { AppLogsCommand } from '@/cli/commands/app-logs.command'; +inspect.defaultOptions.depth = 10; + export class AppCommand { private devCommand = new AppDevCommand(); private syncCommand = new AppSyncCommand(); diff --git a/packages/twenty-sdk/src/cli/utils/__tests__/load-manifest.spec.ts b/packages/twenty-sdk/src/cli/utils/__tests__/load-manifest.spec.ts index 0d0698ec57..1a3f9f626e 100644 --- a/packages/twenty-sdk/src/cli/utils/__tests__/load-manifest.spec.ts +++ b/packages/twenty-sdk/src/cli/utils/__tests__/load-manifest.spec.ts @@ -154,7 +154,7 @@ describe('loadManifest with test-app', () => { expect(appSources['test-function.function.ts']).toContain('defineFunction'); expect(appSources['default-function.role.ts']).toContain('defineRole'); - expect(shouldGenerate).toBe(false); + expect(shouldGenerate).toBe(true); const expectedRoleId = DEFAULT_FUNCTION_ROLE_UNIVERSAL_IDENTIFIER; diff --git a/packages/twenty-sdk/src/cli/utils/load-manifest.ts b/packages/twenty-sdk/src/cli/utils/load-manifest.ts index 302780af21..683759de8a 100644 --- a/packages/twenty-sdk/src/cli/utils/load-manifest.ts +++ b/packages/twenty-sdk/src/cli/utils/load-manifest.ts @@ -181,19 +181,24 @@ const loadSources = async (appPath: string): Promise => { /** * Check if the app imports from the generated folder. - * Detects any `import ... from '...generated'` or `import ... from '...generated/...'` pattern. + * Detects ESM imports: `import ... from '...generated'` or `import ... from '...generated/...'` + * Detects CommonJS requires: `require('...generated')` or `require('...generated/...')` */ const checkShouldGenerate = async (appPath: string): Promise => { const tsFiles = await loadFiles(['src/**/*.ts'], appPath); - // Matches: import ... from 'generated' or from '.../generated' or from '.../generated/...' - const generatedImportPattern = + // Matches ESM: import ... from 'generated' or from '.../generated' or from '.../generated/...' + const esmImportPattern = /from\s+['"][^'"]*\/generated(?:\/[^'"]*)?['"]|from\s+['"]generated['"]/; + // Matches CommonJS: require('generated') or require('.../generated') or require('.../generated/...') + const commonJsRequirePattern = + /require\s*\(\s*['"][^'"]*\/generated(?:\/[^'"]*)?['"]\s*\)|require\s*\(\s*['"]generated['"]\s*\)/; + for (const filepath of tsFiles) { const content = await fs.readFile(filepath, 'utf8'); - if (generatedImportPattern.test(content)) { + if (esmImportPattern.test(content) || commonJsRequirePattern.test(content)) { return true; } }