diff --git a/packages/twenty-front/src/modules/object-record/cache/utils/getRecordNodeFromRecord.ts b/packages/twenty-front/src/modules/object-record/cache/utils/getRecordNodeFromRecord.ts index 00d590ddc4..f47b89373a 100644 --- a/packages/twenty-front/src/modules/object-record/cache/utils/getRecordNodeFromRecord.ts +++ b/packages/twenty-front/src/modules/object-record/cache/utils/getRecordNodeFromRecord.ts @@ -10,9 +10,8 @@ import { getRecordConnectionFromRecords } from '@/object-record/cache/utils/getR import { getRefName } from '@/object-record/cache/utils/getRefName'; import { type RecordGqlNode } from '@/object-record/graphql/types/RecordGqlNode'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; -import { isDefined } from 'twenty-shared/utils'; +import { isDefined, pascalCase } from 'twenty-shared/utils'; import { FieldMetadataType, RelationType } from '~/generated-metadata/graphql'; -import { pascalCase } from '~/utils/string/pascalCase'; export const getRecordNodeFromRecord = ({ objectMetadataItems, diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/preview/hooks/usePreviewRecord.ts b/packages/twenty-front/src/modules/settings/data-model/fields/preview/hooks/usePreviewRecord.ts index ada010016f..e107ad5927 100644 --- a/packages/twenty-front/src/modules/settings/data-model/fields/preview/hooks/usePreviewRecord.ts +++ b/packages/twenty-front/src/modules/settings/data-model/fields/preview/hooks/usePreviewRecord.ts @@ -4,8 +4,7 @@ import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords'; import { isFieldValueEmpty } from '@/object-record/record-field/ui/utils/isFieldValueEmpty'; import { type ObjectRecord } from '@/object-record/types/ObjectRecord'; import { getFieldPreviewValue } from '@/settings/data-model/fields/preview/utils/getFieldPreviewValue'; -import { isDefined } from 'twenty-shared/utils'; -import { pascalCase } from '~/utils/string/pascalCase'; +import { isDefined, pascalCase } from 'twenty-shared/utils'; type UsePreviewRecordParams = { objectNameSingular: string; diff --git a/packages/twenty-sdk/eslint.config.mjs b/packages/twenty-sdk/eslint.config.mjs index 3617ba404b..237549301d 100644 --- a/packages/twenty-sdk/eslint.config.mjs +++ b/packages/twenty-sdk/eslint.config.mjs @@ -5,6 +5,12 @@ export default [ { ignores: ['**/dist/**'], }, + { + files: ['**/*.{js,jsx,ts,tsx}'], + rules: { + 'prettier/prettier': 'error', + }, + }, { rules: { 'no-console': 'off', diff --git a/packages/twenty-sdk/src/application/__tests__/define-app.spec.ts b/packages/twenty-sdk/src/application/__tests__/define-app.spec.ts index 784aa74c0a..e542a31fda 100644 --- a/packages/twenty-sdk/src/application/__tests__/define-app.spec.ts +++ b/packages/twenty-sdk/src/application/__tests__/define-app.spec.ts @@ -1,4 +1,4 @@ -import { defineApp } from '../define-app'; +import { defineApp } from '@/application'; describe('defineApp', () => { it('should return the config when valid', () => { diff --git a/packages/twenty-sdk/src/application/__tests__/define-front-component.spec.ts b/packages/twenty-sdk/src/application/__tests__/define-front-component.spec.ts index a869eff263..7b2480b37c 100644 --- a/packages/twenty-sdk/src/application/__tests__/define-front-component.spec.ts +++ b/packages/twenty-sdk/src/application/__tests__/define-front-component.spec.ts @@ -1,4 +1,4 @@ -import { defineFrontComponent } from '../front-components/define-front-component'; +import { defineFrontComponent } from '@/application'; // Mock component for testing const MockComponent = () => null; diff --git a/packages/twenty-sdk/src/application/__tests__/define-function.spec.ts b/packages/twenty-sdk/src/application/__tests__/define-function.spec.ts index 1122d00791..c7c5e6dcaa 100644 --- a/packages/twenty-sdk/src/application/__tests__/define-function.spec.ts +++ b/packages/twenty-sdk/src/application/__tests__/define-function.spec.ts @@ -1,4 +1,4 @@ -import { defineFunction } from '../functions/define-function'; +import { defineFunction } from '@/application'; // Mock handler for testing const mockHandler = async () => ({ success: true }); diff --git a/packages/twenty-sdk/src/application/__tests__/define-object.spec.ts b/packages/twenty-sdk/src/application/__tests__/define-object.spec.ts index 044bdf3253..db4773eb7e 100644 --- a/packages/twenty-sdk/src/application/__tests__/define-object.spec.ts +++ b/packages/twenty-sdk/src/application/__tests__/define-object.spec.ts @@ -1,4 +1,4 @@ -import { defineObject } from '../objects/define-object'; +import { defineObject } from '@/application'; import { FieldMetadataType } from 'twenty-shared/types'; import { type ObjectManifest } from 'twenty-shared/application'; diff --git a/packages/twenty-sdk/src/application/__tests__/define-role.spec.ts b/packages/twenty-sdk/src/application/__tests__/define-role.spec.ts index e9f27f03b2..0c1a61f9fc 100644 --- a/packages/twenty-sdk/src/application/__tests__/define-role.spec.ts +++ b/packages/twenty-sdk/src/application/__tests__/define-role.spec.ts @@ -1,4 +1,4 @@ -import { defineRole } from '../roles/define-role'; +import { defineRole } from '@/application'; describe('defineRole', () => { const validConfig = { diff --git a/packages/twenty-sdk/src/application/fields/composite-fields.ts b/packages/twenty-sdk/src/application/fields/composite-fields.ts index 06695ba2ab..603efa53c5 100644 --- a/packages/twenty-sdk/src/application/fields/composite-fields.ts +++ b/packages/twenty-sdk/src/application/fields/composite-fields.ts @@ -6,6 +6,5 @@ export type { FullNameMetadata as FullNameField, LinksMetadata as LinksField, PhonesMetadata as PhonesField, - RichTextV2Metadata as RichTextField + RichTextV2Metadata as RichTextField, } from 'twenty-shared/types'; - diff --git a/packages/twenty-sdk/src/application/front-components/define-front-component.ts b/packages/twenty-sdk/src/application/front-components/define-front-component.ts index ed78a74c48..d82bd73699 100644 --- a/packages/twenty-sdk/src/application/front-components/define-front-component.ts +++ b/packages/twenty-sdk/src/application/front-components/define-front-component.ts @@ -1,4 +1,4 @@ -import { type FrontComponentConfig } from './front-component-config'; +import { type FrontComponentConfig } from '@/application/front-components/front-component-config'; /** * Define a front component configuration with validation. diff --git a/packages/twenty-sdk/src/application/front-components/front-component-config.ts b/packages/twenty-sdk/src/application/front-components/front-component-config.ts index 98c83290b5..62ff75eb8b 100644 --- a/packages/twenty-sdk/src/application/front-components/front-component-config.ts +++ b/packages/twenty-sdk/src/application/front-components/front-component-config.ts @@ -4,7 +4,10 @@ export type FrontComponentType = React.ComponentType; export type FrontComponentConfig = Omit< FrontComponentManifest, - 'sourceComponentPath' | 'builtComponentPath' | 'builtComponentChecksum' | 'componentName' + | 'sourceComponentPath' + | 'builtComponentPath' + | 'builtComponentChecksum' + | 'componentName' > & { name?: string; description?: string; diff --git a/packages/twenty-sdk/src/application/functions/define-function.ts b/packages/twenty-sdk/src/application/functions/define-function.ts index 5a275824db..828e8c8c68 100644 --- a/packages/twenty-sdk/src/application/functions/define-function.ts +++ b/packages/twenty-sdk/src/application/functions/define-function.ts @@ -1,4 +1,4 @@ -import { type FunctionConfig } from './function-config'; +import { type FunctionConfig } from '@/application/functions/function-config'; /** * Define a serverless function configuration with validation. @@ -68,7 +68,9 @@ export const defineFunction = (config: T): T => { break; default: - throw new Error(`Unknown trigger type: ${(trigger as { type: string }).type}`); + throw new Error( + `Unknown trigger type: ${(trigger as { type: string }).type}`, + ); } } diff --git a/packages/twenty-sdk/src/application/functions/function-config.ts b/packages/twenty-sdk/src/application/functions/function-config.ts index 6e518ddfcc..42b64a3fa1 100644 --- a/packages/twenty-sdk/src/application/functions/function-config.ts +++ b/packages/twenty-sdk/src/application/functions/function-config.ts @@ -7,7 +7,10 @@ export type FunctionHandler = (...args: any[]) => any | Promise; export type FunctionConfig = Omit< ServerlessFunctionManifest, - 'sourceHandlerPath' | 'builtHandlerPath' | 'builtHandlerChecksum' | 'handlerName' + | 'sourceHandlerPath' + | 'builtHandlerPath' + | 'builtHandlerChecksum' + | 'handlerName' > & { name?: string; description?: string; diff --git a/packages/twenty-sdk/src/application/roles/define-role.ts b/packages/twenty-sdk/src/application/roles/define-role.ts index 4b5a01c84a..430b486a2a 100644 --- a/packages/twenty-sdk/src/application/roles/define-role.ts +++ b/packages/twenty-sdk/src/application/roles/define-role.ts @@ -1,4 +1,4 @@ -import { type RoleConfig } from '../role-config'; +import { type RoleConfig } from '@/application/role-config'; /** * Define a role configuration with validation. @@ -36,7 +36,10 @@ export const defineRole = (config: T): T => { // Validate object permissions if provided if (config.objectPermissions) { for (const permission of config.objectPermissions) { - if (!permission.objectNameSingular && !permission.objectUniversalIdentifier) { + if ( + !permission.objectNameSingular && + !permission.objectUniversalIdentifier + ) { throw new Error( 'Object permission must have either objectNameSingular or objectUniversalIdentifier', ); @@ -47,7 +50,10 @@ export const defineRole = (config: T): T => { // Validate field permissions if provided if (config.fieldPermissions) { for (const permission of config.fieldPermissions) { - if (!permission.objectNameSingular && !permission.objectUniversalIdentifier) { + if ( + !permission.objectNameSingular && + !permission.objectUniversalIdentifier + ) { throw new Error( 'Field permission must have either objectNameSingular or objectUniversalIdentifier', ); diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-build/app-build.integration.spec.ts b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-build/app-build.integration.spec.ts index e426c1069d..d6bcdc5436 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-build/app-build.integration.spec.ts +++ b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-build/app-build.integration.spec.ts @@ -1,11 +1,11 @@ -import { runAppBuild } from '@/cli/__tests__/integration/utils/run-app-build.util'; -import { type RunCliCommandResult } from '@/cli/__tests__/integration/utils/run-cli-command.util'; import { join } from 'path'; +import { runAppBuild } from '@/cli/__tests__/integration/utils/run-app-build.util'; +import { type RunCliCommandResult } from '@/cli/__tests__/integration/utils/run-cli-command.util'; +import { defineConsoleOutputTests } from './tests/console-output.tests'; +import { defineManifestTests } from '../app-dev/tests/manifest.tests'; import { defineFrontComponentsTests } from '../app-dev/tests/front-components.tests'; import { defineFunctionsTests } from '../app-dev/tests/functions.tests'; -import { defineManifestTests } from '../app-dev/tests/manifest.tests'; -import { defineConsoleOutputTests } from './tests/console-output.tests'; const APP_PATH = join(__dirname, '../..'); diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-build/tests/console-output.tests.ts b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-build/tests/console-output.tests.ts index 4fbc139e92..6040e8f4e7 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-build/tests/console-output.tests.ts +++ b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-build/tests/console-output.tests.ts @@ -33,7 +33,10 @@ export const defineConsoleOutputTests = ( }); it('should contain front-components-watch messages', () => { - const output = getOutputByPrefix(getResult().output, 'front-components-watch'); + const output = getOutputByPrefix( + getResult().output, + 'front-components-watch', + ); expect(output).toContain('[front-components-watch] 🎨 Building...'); expect(output).toContain('[front-components-watch] ✓ Built'); diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-dev/app-dev.integration.spec.ts b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-dev/app-dev.integration.spec.ts index aa5a3f33b7..ed07d94a3c 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-dev/app-dev.integration.spec.ts +++ b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-dev/app-dev.integration.spec.ts @@ -3,9 +3,9 @@ import { type RunCliCommandResult } from '@/cli/__tests__/integration/utils/run- import { join } from 'path'; import { defineConsoleOutputTests } from './tests/console-output.tests'; -import { defineFrontComponentsTests } from './tests/front-components.tests'; -import { defineFunctionsTests } from './tests/functions.tests'; -import { defineManifestTests } from './tests/manifest.tests'; +import { defineManifestTests } from '../app-dev/tests/manifest.tests'; +import { defineFrontComponentsTests } from '../app-dev/tests/front-components.tests'; +import { defineFunctionsTests } from '../app-dev/tests/functions.tests'; const APP_PATH = join(__dirname, '../..'); diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-dev/expected-manifest.ts b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-dev/expected-manifest.ts new file mode 100644 index 0000000000..b2cda45074 --- /dev/null +++ b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-dev/expected-manifest.ts @@ -0,0 +1,376 @@ +import { FieldType } from '@/application'; +import type { ApplicationManifest } from 'twenty-shared/application'; +import { PermissionFlagType } from 'twenty-shared/constants'; + +export const EXPECTED_MANIFEST: ApplicationManifest = { + sources: {}, + application: { + applicationVariables: { + DEFAULT_RECIPIENT_NAME: { + description: 'Default recipient name for postcards', + isSecret: false, + universalIdentifier: '19e94e59-d4fe-4251-8981-b96d0a9f74de', + value: 'Alex Karp', + }, + }, + description: 'A simple hello world app', + displayName: 'Hello World', + functionRoleUniversalIdentifier: 'b648f87b-1d26-4961-b974-0908fd991061', + icon: 'IconWorld', + universalIdentifier: '4ec0391d-18d5-411c-b2f3-266ddc1c3ef7', + }, + frontComponents: [ + { + builtComponentPath: 'front-components/src/root.front-component.mjs', + builtComponentChecksum: '[checksum]', + componentName: 'RootComponent', + description: 'A root-level front component', + name: 'root-component', + sourceComponentPath: 'src/root.front-component.tsx', + universalIdentifier: 'a0a1a2a3-a4a5-4000-8000-000000000001', + }, + { + builtComponentPath: + 'front-components/src/components/card.front-component.mjs', + builtComponentChecksum: '[checksum]', + componentName: 'CardDisplay', + description: 'A component using an external component file', + name: 'card-component', + sourceComponentPath: 'src/components/card.front-component.tsx', + universalIdentifier: 'i0i1i2i3-i4i5-4000-8000-000000000001', + }, + { + builtComponentPath: + 'front-components/src/components/greeting.front-component.mjs', + builtComponentChecksum: '[checksum]', + componentName: 'GreetingComponent', + description: 'A component that uses greeting utility', + name: 'greeting-component', + sourceComponentPath: 'src/components/greeting.front-component.tsx', + universalIdentifier: 'h0h1h2h3-h4h5-4000-8000-000000000001', + }, + { + builtComponentPath: + 'front-components/src/components/test.front-component.mjs', + builtComponentChecksum: '[checksum]', + componentName: 'TestComponent', + description: 'A test front component', + name: 'test-component', + sourceComponentPath: 'src/components/test.front-component.tsx', + universalIdentifier: 'f1234567-abcd-4000-8000-000000000001', + }, + ], + objectExtensions: [ + { + fields: [ + { + description: 'Priority level for the post card (1-10)', + label: 'Priority', + name: 'priority', + type: FieldType.NUMBER, + universalIdentifier: '7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d', + }, + { + description: 'Post card category', + label: 'Category', + name: 'category', + options: [ + { + color: 'blue', + label: 'Personal', + position: 0, + value: 'PERSONAL', + }, + { + color: 'green', + label: 'Business', + position: 1, + value: 'BUSINESS', + }, + { + color: 'orange', + label: 'Promotional', + position: 2, + value: 'PROMOTIONAL', + }, + ], + type: FieldType.SELECT, + universalIdentifier: '8b9c0d1e-2f3a-4b5c-6d7e-8f9a0b1c2d3e', + }, + ], + targetObject: { + nameSingular: 'postCard', + }, + }, + ], + objects: [ + { + description: 'A simple root-level object', + fields: [ + { + label: 'Title', + name: 'title', + type: FieldType.TEXT, + universalIdentifier: 'b0b1b2b3-b4b5-4000-8000-000000000002', + }, + { + label: 'Body', + name: 'body', + type: FieldType.TEXT, + universalIdentifier: 'b0b1b2b3-b4b5-4000-8000-000000000003', + }, + ], + icon: 'IconNote', + labelPlural: 'Root notes', + labelSingular: 'Root note', + namePlural: 'rootNotes', + nameSingular: 'rootNote', + universalIdentifier: 'b0b1b2b3-b4b5-4000-8000-000000000001', + }, + { + description: 'A post card object', + fields: [ + { + description: "Postcard's content", + icon: 'IconAbc', + label: 'Content', + name: 'content', + type: FieldType.TEXT, + universalIdentifier: '58a0a314-d7ea-4865-9850-7fb84e72f30b', + }, + { + icon: 'IconUser', + label: 'Recipient name', + name: 'recipientName', + type: FieldType.FULL_NAME, + universalIdentifier: 'c6aa31f3-da76-4ac6-889f-475e226009ac', + }, + { + icon: 'IconHome', + label: 'Recipient address', + name: 'recipientAddress', + type: FieldType.ADDRESS, + universalIdentifier: '95045777-a0ad-49ec-98f9-22f9fc0c8266', + }, + { + defaultValue: "'DRAFT'", + icon: 'IconSend', + label: 'Status', + name: 'status', + options: [ + { + color: 'gray', + label: 'Draft', + position: 0, + value: 'DRAFT', + }, + { + color: 'orange', + label: 'Sent', + position: 1, + value: 'SENT', + }, + { + color: 'green', + label: 'Delivered', + position: 2, + value: 'DELIVERED', + }, + { + color: 'orange', + label: 'Returned', + position: 3, + value: 'RETURNED', + }, + ], + type: FieldType.SELECT, + universalIdentifier: '87b675b8-dd8c-4448-b4ca-20e5a2234a1e', + }, + { + defaultValue: null, + icon: 'IconCheck', + isNullable: true, + label: 'Delivered at', + name: 'deliveredAt', + type: FieldType.DATE_TIME, + universalIdentifier: 'e06abe72-5b44-4e7f-93be-afc185a3c433', + }, + ], + icon: 'IconMail', + labelPlural: 'Post cards', + labelSingular: 'Post card', + namePlural: 'postCards', + nameSingular: 'postCard', + universalIdentifier: '54b589ca-eeed-4950-a176-358418b85c05', + }, + ], + packageJson: { + name: 'rich-app', + version: '0.1.0', + license: 'MIT', + engines: { + node: '^24.5.0', + npm: 'please-use-yarn', + yarn: '>=4.0.2', + }, + packageManager: 'yarn@4.9.2', + scripts: { + 'auth:login': 'twenty auth:login', + 'auth:logout': 'twenty auth:logout', + 'auth:status': 'twenty auth:status', + 'auth:switch': 'twenty auth:switch', + 'auth:list': 'twenty auth:list', + 'app:dev': 'twenty app:dev', + 'app:build': 'twenty app:build', + 'app:sync': 'twenty app:sync', + 'entity:add': 'twenty entity:add', + 'app:generate': 'twenty app:generate', + 'function:logs': 'twenty function:logs', + 'function:execute': 'twenty function:execute', + 'app:uninstall': 'twenty app:uninstall', + help: 'twenty help', + lint: 'eslint', + 'lint:fix': 'eslint --fix', + }, + dependencies: { + 'twenty-sdk': 'latest', + }, + devDependencies: { + typescript: '^5.9.3', + '@types/node': '^24.7.2', + '@types/react': '^19.0.2', + react: '^19.0.2', + eslint: '^9.32.0', + 'typescript-eslint': '^8.50.0', + }, + }, + roles: [ + { + canBeAssignedToAgents: false, + canBeAssignedToApiKeys: false, + canBeAssignedToUsers: true, + canDestroyAllObjectRecords: false, + canReadAllObjectRecords: true, + canSoftDeleteAllObjectRecords: false, + canUpdateAllObjectRecords: false, + canUpdateAllSettings: false, + description: 'A simple root-level role', + label: 'Root role', + universalIdentifier: 'c0c1c2c3-c4c5-4000-8000-000000000001', + }, + { + canBeAssignedToAgents: false, + canBeAssignedToApiKeys: false, + canBeAssignedToUsers: false, + canDestroyAllObjectRecords: false, + canReadAllObjectRecords: false, + canSoftDeleteAllObjectRecords: false, + canUpdateAllObjectRecords: false, + canUpdateAllSettings: false, + description: 'Default role for function Twenty client', + fieldPermissions: [ + { + canReadFieldValue: false, + canUpdateFieldValue: false, + fieldName: 'content', + objectNameSingular: 'postCard', + }, + ], + label: 'Default function role', + objectPermissions: [ + { + canDestroyObjectRecords: false, + canReadObjectRecords: true, + canSoftDeleteObjectRecords: false, + canUpdateObjectRecords: true, + objectNameSingular: 'postCard', + }, + ], + permissionFlags: [PermissionFlagType.APPLICATIONS], + universalIdentifier: 'b648f87b-1d26-4961-b974-0908fd991061', + }, + ], + functions: [ + { + builtHandlerChecksum: '[checksum]', + builtHandlerPath: 'functions/src/root.function.mjs', + handlerName: 'rootHandler', + name: 'root-function', + sourceHandlerPath: 'src/root.function.ts', + timeoutSeconds: 5, + triggers: [ + { + httpMethod: 'GET', + isAuthRequired: false, + path: '/root', + type: 'route', + universalIdentifier: 'f0f1f2f3-f4f5-4000-8000-000000000002', + }, + ], + universalIdentifier: 'f0f1f2f3-f4f5-4000-8000-000000000001', + }, + { + builtHandlerChecksum: '[checksum]', + builtHandlerPath: 'functions/src/functions/greeting.function.mjs', + handlerName: 'greetingHandler', + name: 'greeting-function', + sourceHandlerPath: 'src/functions/greeting.function.ts', + timeoutSeconds: 5, + triggers: [ + { + httpMethod: 'GET', + isAuthRequired: false, + path: '/greet', + type: 'route', + universalIdentifier: 'g0g1g2g3-g4g5-4000-8000-000000000002', + }, + ], + universalIdentifier: 'g0g1g2g3-g4g5-4000-8000-000000000001', + }, + { + builtHandlerChecksum: '[checksum]', + builtHandlerPath: 'functions/src/functions/test-function-2.function.mjs', + handlerName: 'testFunction2', + name: 'test-function-2', + sourceHandlerPath: 'src/utils/test-function-2.util.ts', + timeoutSeconds: 2, + triggers: [ + { + pattern: '0 0 1 1 *', + type: 'cron', + universalIdentifier: '9fd0dda9-4664-4fbc-9656-509f4477b9ff', + }, + ], + universalIdentifier: 'eb3ffc98-88ec-45d4-9b4a-56833b219ccb', + }, + { + builtHandlerChecksum: '[checksum]', + builtHandlerPath: 'functions/src/functions/test-function.function.mjs', + handlerName: 'handler', + name: 'test-function', + sourceHandlerPath: 'src/functions/test-function.function.ts', + timeoutSeconds: 2, + triggers: [ + { + forwardedRequestHeaders: ['signature'], + httpMethod: 'GET', + isAuthRequired: false, + path: '/post-card/create', + type: 'route', + universalIdentifier: 'c9f84c8d-b26d-40d1-95dd-4f834ae5a2c6', + }, + { + pattern: '0 0 1 1 *', + type: 'cron', + universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2', + }, + { + eventName: 'person.created', + type: 'databaseEvent', + universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156', + }, + ], + universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf', + }, + ], +}; diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-dev/tests/console-output.tests.ts b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-dev/tests/console-output.tests.ts index efb4773ac7..36ab0d70db 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-dev/tests/console-output.tests.ts +++ b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-dev/tests/console-output.tests.ts @@ -8,7 +8,9 @@ export const defineConsoleOutputTests = ( it('should contain init messages', () => { const output = getOutputByPrefix(getResult().output, 'init'); - expect(output).toContain('[init] 🚀 Starting Twenty Application Development Mode'); + expect(output).toContain( + '[init] 🚀 Starting Twenty Application Development Mode', + ); expect(output).toContain('[init] 📁 App Path:'); }); @@ -33,7 +35,10 @@ export const defineConsoleOutputTests = ( }); it('should contain front-components-watch messages', () => { - const output = getOutputByPrefix(getResult().output, 'front-components-watch'); + const output = getOutputByPrefix( + getResult().output, + 'front-components-watch', + ); expect(output).toContain('[front-components-watch] 🎨 Building...'); expect(output).toContain('[front-components-watch] ✓ Built'); diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-dev/tests/front-components.tests.ts b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-dev/tests/front-components.tests.ts index 8e5510c5d5..368362be8c 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-dev/tests/front-components.tests.ts +++ b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-dev/tests/front-components.tests.ts @@ -4,7 +4,10 @@ import { join } from 'path'; export const defineFrontComponentsTests = (appPath: string): void => { describe('front-components', () => { it('should have built front components preserving source path structure', async () => { - const frontComponentsDir = join(appPath, '.twenty/output/front-components'); + const frontComponentsDir = join( + appPath, + '.twenty/output/front-components', + ); const files = await fs.readdir(frontComponentsDir, { recursive: true }); const sortedFiles = files.map((f) => f.toString()).sort(); diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-dev/tests/manifest.tests.ts b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-dev/tests/manifest.tests.ts index e8e19bf91d..f6b63cb5e0 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-dev/tests/manifest.tests.ts +++ b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__integration__/app-dev/tests/manifest.tests.ts @@ -2,7 +2,7 @@ import * as fs from 'fs-extra'; import { join } from 'path'; import { normalizeManifestForComparison } from '@/cli/__tests__/integration/utils/normalize-manifest.util'; -import expectedManifest from '../manifest.expected.json'; +import { EXPECTED_MANIFEST } from '../expected-manifest'; export const defineManifestTests = (appPath: string): void => { const manifestOutputPath = join(appPath, '.twenty/output/manifest.json'); @@ -16,7 +16,7 @@ export const defineManifestTests = (appPath: string): void => { const { sources: _sources, ...sanitizedManifest } = manifest; expect(normalizeManifestForComparison(sanitizedManifest)).toEqual( - normalizeManifestForComparison(expectedManifest), + normalizeManifestForComparison(EXPECTED_MANIFEST), ); for (const fn of manifest.functions) { @@ -36,7 +36,9 @@ export const defineManifestTests = (appPath: string): void => { const manifest = await fs.readJson(manifestOutputPath); expect(manifest?.application.displayName).toBe('Hello World'); - expect(manifest?.application.description).toBe('A simple hello world app'); + expect(manifest?.application.description).toBe( + 'A simple hello world app', + ); }); it('should load all entity types', async () => { diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-build/app-build.integration.spec.ts b/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-build/app-build.integration.spec.ts index 0038af8289..3de298b438 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-build/app-build.integration.spec.ts +++ b/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-build/app-build.integration.spec.ts @@ -1,7 +1,7 @@ import { join } from 'path'; -import { runAppBuild } from '../../../../integration/utils/run-app-build.util'; -import { type RunCliCommandResult } from '../../../../integration/utils/run-cli-command.util'; +import { runAppBuild } from '@/cli/__tests__/integration/utils/run-app-build.util'; +import { type RunCliCommandResult } from '@/cli/__tests__/integration/utils/run-cli-command.util'; import { defineConsoleOutputTests } from './tests/console-output.tests'; import { defineFrontComponentsTests } from '../app-dev/tests/front-components.tests'; import { defineFunctionsTests } from '../app-dev/tests/functions.tests'; diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-build/tests/console-output.tests.ts b/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-build/tests/console-output.tests.ts index ff437d8099..823fb7aa05 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-build/tests/console-output.tests.ts +++ b/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-build/tests/console-output.tests.ts @@ -33,7 +33,10 @@ export const defineConsoleOutputTests = ( }); it('should contain front-components-watch messages', () => { - const output = getOutputByPrefix(getResult().output, 'front-components-watch'); + const output = getOutputByPrefix( + getResult().output, + 'front-components-watch', + ); expect(output).toContain('[front-components-watch] 🎨 Building...'); expect(output).toContain('[front-components-watch] ✓ Built'); diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-dev/app-dev.integration.spec.ts b/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-dev/app-dev.integration.spec.ts index afcd75fec7..214b974278 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-dev/app-dev.integration.spec.ts +++ b/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-dev/app-dev.integration.spec.ts @@ -1,7 +1,7 @@ import { join } from 'path'; -import { runAppDev } from '../../../../integration/utils/run-app-dev.util'; -import { type RunCliCommandResult } from '../../../../integration/utils/run-cli-command.util'; +import { runAppDev } from '@/cli/__tests__/integration/utils/run-app-dev.util'; +import { type RunCliCommandResult } from '@/cli/__tests__/integration/utils/run-cli-command.util'; import { defineConsoleOutputTests } from './tests/console-output.tests'; import { defineFrontComponentsTests } from './tests/front-components.tests'; import { defineFunctionsTests } from './tests/functions.tests'; diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-dev/tests/console-output.tests.ts b/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-dev/tests/console-output.tests.ts index f77c91d22d..7412699d79 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-dev/tests/console-output.tests.ts +++ b/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-dev/tests/console-output.tests.ts @@ -8,7 +8,9 @@ export const defineConsoleOutputTests = ( it('should contain init messages', () => { const output = getOutputByPrefix(getResult().output, 'init'); - expect(output).toContain('[init] 🚀 Starting Twenty Application Development Mode'); + expect(output).toContain( + '[init] 🚀 Starting Twenty Application Development Mode', + ); expect(output).toContain('[init] 📁 App Path:'); }); @@ -33,7 +35,10 @@ export const defineConsoleOutputTests = ( }); it('should contain front-components-watch messages', () => { - const output = getOutputByPrefix(getResult().output, 'front-components-watch'); + const output = getOutputByPrefix( + getResult().output, + 'front-components-watch', + ); expect(output).toContain('[front-components-watch] 🎨 Building...'); expect(output).toContain('[front-components-watch] ✓ Built'); diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-dev/tests/front-components.tests.ts b/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-dev/tests/front-components.tests.ts index 87ad0038c8..3ccf4c2a0b 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-dev/tests/front-components.tests.ts +++ b/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-dev/tests/front-components.tests.ts @@ -4,7 +4,10 @@ import { join } from 'path'; export const defineFrontComponentsTests = (appPath: string): void => { describe('front-components', () => { it('should have built front components at root level', async () => { - const frontComponentsDir = join(appPath, '.twenty/output/front-components'); + const frontComponentsDir = join( + appPath, + '.twenty/output/front-components', + ); const files = await fs.readdir(frontComponentsDir, { recursive: true }); const sortedFiles = files.map((f) => f.toString()).sort(); diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-dev/tests/functions.tests.ts b/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-dev/tests/functions.tests.ts index 55ae97d9ae..acb83a859d 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-dev/tests/functions.tests.ts +++ b/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-dev/tests/functions.tests.ts @@ -8,10 +8,7 @@ export const defineFunctionsTests = (appPath: string): void => { const files = await fs.readdir(functionsDir, { recursive: true }); const sortedFiles = files.map((f) => f.toString()).sort(); - expect(sortedFiles).toEqual([ - 'my.function.mjs', - 'my.function.mjs.map', - ]); + expect(sortedFiles).toEqual(['my.function.mjs', 'my.function.mjs.map']); }); }); }; diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-dev/tests/manifest.tests.ts b/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-dev/tests/manifest.tests.ts index 5ca1f51b7b..7a05d61d02 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-dev/tests/manifest.tests.ts +++ b/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-dev/tests/manifest.tests.ts @@ -16,14 +16,21 @@ export const defineManifestTests = (appPath: string): void => { it('should have correct manifest content', async () => { const manifestPath = join(appPath, '.twenty/output/manifest.json'); const manifest: ApplicationManifest = await fs.readJSON(manifestPath); - const expectedPath = join(appPath, '__integration__/app-dev/manifest.expected.json'); + const expectedPath = join( + appPath, + '__integration__/app-dev/manifest.expected.json', + ); const expected: ApplicationManifest = await fs.readJSON(expectedPath); expect(manifest.application).toEqual(expected.application); expect(manifest.objects).toEqual(expected.objects); - expect(normalizeManifestForComparison({ functions: manifest.functions }).functions).toEqual( - normalizeManifestForComparison({ functions: expected.functions }).functions, + expect( + normalizeManifestForComparison({ functions: manifest.functions }) + .functions, + ).toEqual( + normalizeManifestForComparison({ functions: expected.functions }) + .functions, ); for (const fn of manifest.functions) { @@ -33,9 +40,13 @@ export const defineManifestTests = (appPath: string): void => { } expect( - normalizeManifestForComparison({ frontComponents: manifest.frontComponents }).frontComponents, + normalizeManifestForComparison({ + frontComponents: manifest.frontComponents, + }).frontComponents, ).toEqual( - normalizeManifestForComparison({ frontComponents: expected.frontComponents }).frontComponents, + normalizeManifestForComparison({ + frontComponents: expected.frontComponents, + }).frontComponents, ); for (const component of manifest.frontComponents ?? []) { diff --git a/packages/twenty-sdk/src/cli/__tests__/e2e/constants/testConfig.ts b/packages/twenty-sdk/src/cli/__tests__/e2e/constants/testConfig.ts index 477aa4d627..4f4b9786ac 100644 --- a/packages/twenty-sdk/src/cli/__tests__/e2e/constants/testConfig.ts +++ b/packages/twenty-sdk/src/cli/__tests__/e2e/constants/testConfig.ts @@ -1,4 +1,4 @@ -import { type TwentyConfig } from '@/cli/utilities/config/services/config.service'; +import { type TwentyConfig } from '@/cli/utilities/config/config-service'; export const testConfig: TwentyConfig = { apiUrl: 'http://localhost:3000', diff --git a/packages/twenty-sdk/src/cli/__tests__/e2e/setupTest.ts b/packages/twenty-sdk/src/cli/__tests__/e2e/setupTest.ts index 788a6336e4..00a8a872f0 100644 --- a/packages/twenty-sdk/src/cli/__tests__/e2e/setupTest.ts +++ b/packages/twenty-sdk/src/cli/__tests__/e2e/setupTest.ts @@ -1,4 +1,4 @@ -import { ConfigService } from '@/cli/utilities/config/services/config.service'; +import { ConfigService } from '@/cli/utilities/config/config-service'; import { testConfig } from '@/cli/__tests__/e2e/constants/testConfig'; import { vi, beforeAll, afterAll } from 'vitest'; diff --git a/packages/twenty-sdk/src/cli/__tests__/integration/utils/get-output-by-prefix.util.ts b/packages/twenty-sdk/src/cli/__tests__/integration/utils/get-output-by-prefix.util.ts index fbfefeb5d6..e37e93043e 100644 --- a/packages/twenty-sdk/src/cli/__tests__/integration/utils/get-output-by-prefix.util.ts +++ b/packages/twenty-sdk/src/cli/__tests__/integration/utils/get-output-by-prefix.util.ts @@ -1,6 +1,13 @@ -export type LogPrefix = 'init' | 'manifest-watch' | 'functions-watch' | 'front-components-watch'; +export type LogPrefix = + | 'init' + | 'manifest-watch' + | 'functions-watch' + | 'front-components-watch'; -export const getOutputByPrefix = (output: string, prefix: LogPrefix): string => { +export const getOutputByPrefix = ( + output: string, + prefix: LogPrefix, +): string => { const prefixPattern = `[${prefix}]`; const lines = output.split('\n'); diff --git a/packages/twenty-sdk/src/cli/__tests__/integration/utils/normalize-manifest.util.ts b/packages/twenty-sdk/src/cli/__tests__/integration/utils/normalize-manifest.util.ts index d40e07fe6d..e463ec8b89 100644 --- a/packages/twenty-sdk/src/cli/__tests__/integration/utils/normalize-manifest.util.ts +++ b/packages/twenty-sdk/src/cli/__tests__/integration/utils/normalize-manifest.util.ts @@ -1,7 +1,13 @@ // Loose type for JSON manifest imports where enum values are inferred as strings type JsonManifestInput = { - functions?: Array<{ builtHandlerChecksum?: string | null; [key: string]: unknown }>; - frontComponents?: Array<{ builtComponentChecksum?: string | null; [key: string]: unknown }>; + functions?: Array<{ + builtHandlerChecksum?: string | null; + [key: string]: unknown; + }>; + frontComponents?: Array<{ + builtComponentChecksum?: string | null; + [key: string]: unknown; + }>; [key: string]: unknown; }; @@ -20,4 +26,5 @@ export const normalizeManifestForComparison = ( ? '[checksum]' : null, })), + sources: {}, // removing sources for now, waiting compressed file implementation }); diff --git a/packages/twenty-sdk/src/cli/__tests__/integration/utils/run-app-build.util.ts b/packages/twenty-sdk/src/cli/__tests__/integration/utils/run-app-build.util.ts index ca8b2afee7..ae59fa449d 100644 --- a/packages/twenty-sdk/src/cli/__tests__/integration/utils/run-app-build.util.ts +++ b/packages/twenty-sdk/src/cli/__tests__/integration/utils/run-app-build.util.ts @@ -1,11 +1,16 @@ -import { runCliCommand, type RunCliCommandResult } from './run-cli-command.util'; +import { + runCliCommand, + type RunCliCommandResult, +} from './run-cli-command.util'; export type RunAppBuildOptions = { appPath: string; timeout?: number; }; -export const runAppBuild = (options: RunAppBuildOptions): Promise => { +export const runAppBuild = ( + options: RunAppBuildOptions, +): Promise => { const { appPath, timeout = 30000 } = options; // app:build runs once and exits, so we don't wait for specific output diff --git a/packages/twenty-sdk/src/cli/__tests__/integration/utils/run-app-dev.util.ts b/packages/twenty-sdk/src/cli/__tests__/integration/utils/run-app-dev.util.ts index 40ed5cb693..d319a35ebb 100644 --- a/packages/twenty-sdk/src/cli/__tests__/integration/utils/run-app-dev.util.ts +++ b/packages/twenty-sdk/src/cli/__tests__/integration/utils/run-app-dev.util.ts @@ -1,14 +1,18 @@ -import { runCliCommand, type RunCliCommandResult } from './run-cli-command.util'; +import { + runCliCommand, + type RunCliCommandResult, +} from './run-cli-command.util'; export type RunAppDevOptions = { appPath: string; timeout?: number; }; -export const runAppDev = (options: RunAppDevOptions): Promise => { +export const runAppDev = ( + options: RunAppDevOptions, +): Promise => { const { appPath, timeout = 30000 } = options; - return runCliCommand({ command: 'app:dev', args: [appPath], diff --git a/packages/twenty-sdk/src/cli/__tests__/integration/utils/run-cli-command.util.ts b/packages/twenty-sdk/src/cli/__tests__/integration/utils/run-cli-command.util.ts index 7c85bb2b78..e88bb8d588 100644 --- a/packages/twenty-sdk/src/cli/__tests__/integration/utils/run-cli-command.util.ts +++ b/packages/twenty-sdk/src/cli/__tests__/integration/utils/run-cli-command.util.ts @@ -23,12 +23,7 @@ export type RunCliCommandResult = { export const runCliCommand = ( options: RunCliCommandOptions, ): Promise => { - const { - command, - args = [], - waitForOutput, - timeout = 30000, - } = options; + const { command, args = [], waitForOutput, timeout = 30000 } = options; return new Promise((resolve) => { // Run from CLI directory to use twenty-sdk's tsconfig paths @@ -68,7 +63,7 @@ export const runCliCommand = ( setTimeout(() => { child.kill(); resolve({ success: true, output }); - }, 500); + }, 1500); } }); diff --git a/packages/twenty-sdk/src/cli/__tests__/integration/utils/sanitize-output.util.ts b/packages/twenty-sdk/src/cli/__tests__/integration/utils/sanitize-output.util.ts index 4fa4c0c8a9..9d44acc36d 100644 --- a/packages/twenty-sdk/src/cli/__tests__/integration/utils/sanitize-output.util.ts +++ b/packages/twenty-sdk/src/cli/__tests__/integration/utils/sanitize-output.util.ts @@ -1,16 +1,18 @@ export const sanitizeOutput = (output: string): string => { - return output - // Remove ANSI color codes - .replace(/\x1B\[[0-9;]*[a-zA-Z]/g, '') - // Normalize file paths (replace any absolute path to a test app) - .replace(/\/[^\s]+\/__tests__\/apps\/[^/]+/g, '') - // Normalize timestamps - .replace(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/g, '') - // Normalize durations - .replace(/\d+ms/g, '') - // Trim trailing whitespace from each line - .split('\n') - .map((line) => line.trimEnd()) - .join('\n') - .trim(); + return ( + output + // Remove ANSI color codes + .replace(/\x1B\[[0-9;]*[a-zA-Z]/g, '') + // Normalize file paths (replace any absolute path to a test app) + .replace(/\/[^\s]+\/__tests__\/apps\/[^/]+/g, '') + // Normalize timestamps + .replace(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/g, '') + // Normalize durations + .replace(/\d+ms/g, '') + // Trim trailing whitespace from each line + .split('\n') + .map((line) => line.trimEnd()) + .join('\n') + .trim() + ); }; diff --git a/packages/twenty-sdk/src/cli/cli.ts b/packages/twenty-sdk/src/cli/cli.ts index 825ecd2864..689ff61d7f 100644 --- a/packages/twenty-sdk/src/cli/cli.ts +++ b/packages/twenty-sdk/src/cli/cli.ts @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { registerCommands } from '@/cli/commands/app.command'; -import { ConfigService } from '@/cli/utilities/config/services/config.service'; +import { registerCommands } from '@/cli/commands/app-command'; +import { ConfigService } from '@/cli/utilities/config/config-service'; import chalk from 'chalk'; import { Command, CommanderError } from 'commander'; import { inspect } from 'util'; diff --git a/packages/twenty-sdk/src/cli/commands/app.command.ts b/packages/twenty-sdk/src/cli/commands/app-command.ts similarity index 97% rename from packages/twenty-sdk/src/cli/commands/app.command.ts rename to packages/twenty-sdk/src/cli/commands/app-command.ts index 695b1abdc7..d389481c9d 100644 --- a/packages/twenty-sdk/src/cli/commands/app.command.ts +++ b/packages/twenty-sdk/src/cli/commands/app-command.ts @@ -1,4 +1,4 @@ -import { formatPath } from '@/cli/utilities/file/utils/file-path'; +import { formatPath } from '@/cli/utilities/file/file-path'; import chalk from 'chalk'; import type { Command } from 'commander'; import { AppBuildCommand } from './app/app-build'; @@ -106,9 +106,7 @@ export const registerCommands = (program: Command): void => { .action(async (appPath?: string) => { try { const result = await syncCommand.execute(formatPath(appPath)); - if (!result.success) { - process.exit(1); - } + process.exit(result.success ? 0 : 1); } catch { process.exit(1); } @@ -123,9 +121,7 @@ export const registerCommands = (program: Command): void => { appPath: formatPath(appPath), askForConfirmation: true, }); - if (!result.success) { - process.exit(1); - } + process.exit(result.success ? 0 : 1); } catch { process.exit(1); } diff --git a/packages/twenty-sdk/src/cli/commands/app/app-build.ts b/packages/twenty-sdk/src/cli/commands/app/app-build.ts index 6163668d10..e16d870ab1 100644 --- a/packages/twenty-sdk/src/cli/commands/app/app-build.ts +++ b/packages/twenty-sdk/src/cli/commands/app/app-build.ts @@ -1,15 +1,15 @@ -import { type ApiResponse } from '@/cli/utilities/api/types/api-response.types'; +import { type ApiResponse } from '@/cli/utilities/api/api-response-type'; import { createLogger } from '@/cli/utilities/build/common/logger'; import { FrontComponentsWatcher } from '@/cli/utilities/build/front-components/front-component-watcher'; import { FunctionsWatcher } from '@/cli/utilities/build/functions/function-watcher'; import { + type ManifestBuildResult, runManifestBuild, updateManifestChecksum, - type ManifestBuildResult, } from '@/cli/utilities/build/manifest/manifest-build'; import { manifestExtractFromFileServer } from '@/cli/utilities/build/manifest/manifest-extract-from-file-server'; import { writeManifestToOutput } from '@/cli/utilities/build/manifest/manifest-writer'; -import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/utilities/config/constants/current-execution-directory'; +import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/utilities/config/current-execution-directory'; const initLogger = createLogger('init'); @@ -23,7 +23,9 @@ export class AppBuildCommand { private appPath: string = ''; - async execute(options: AppBuildOptions): Promise> { + async execute( + options: AppBuildOptions, + ): Promise> { this.appPath = options.appPath ?? CURRENT_EXECUTION_DIRECTORY; initLogger.log('🚀 Building Twenty Application'); @@ -38,7 +40,7 @@ export class AppBuildCommand { initLogger.success('✅ Build completed successfully'); - return { success: true, data: null }; + return { success: true, data: buildResult }; } private async runBuild(): Promise { @@ -56,7 +58,9 @@ export class AppBuildCommand { return buildResult; } - private async buildFunctions(buildResult: ManifestBuildResult): Promise { + private async buildFunctions( + buildResult: ManifestBuildResult, + ): Promise { this.functionsBuilder = new FunctionsWatcher({ appPath: this.appPath, sourcePaths: buildResult.filePaths.functions, @@ -69,6 +73,7 @@ export class AppBuildCommand { builtPath, checksum, }); + if (updatedManifest) { buildResult.manifest = updatedManifest; } @@ -79,7 +84,9 @@ export class AppBuildCommand { await this.functionsBuilder.start(); } - private async buildFrontComponents(buildResult: ManifestBuildResult): Promise { + private async buildFrontComponents( + buildResult: ManifestBuildResult, + ): Promise { this.frontComponentsBuilder = new FrontComponentsWatcher({ appPath: this.appPath, sourcePaths: buildResult.filePaths.frontComponents, diff --git a/packages/twenty-sdk/src/cli/commands/app/app-dev.ts b/packages/twenty-sdk/src/cli/commands/app/app-dev.ts index ff02e05e35..2c8b0361e3 100644 --- a/packages/twenty-sdk/src/cli/commands/app/app-dev.ts +++ b/packages/twenty-sdk/src/cli/commands/app/app-dev.ts @@ -1,10 +1,13 @@ import { createLogger } from '@/cli/utilities/build/common/logger'; import { FrontComponentsWatcher } from '@/cli/utilities/build/front-components/front-component-watcher'; import { FunctionsWatcher } from '@/cli/utilities/build/functions/function-watcher'; -import { runManifestBuild, updateManifestChecksum } from '@/cli/utilities/build/manifest/manifest-build'; +import { + runManifestBuild, + updateManifestChecksum, +} from '@/cli/utilities/build/manifest/manifest-build'; import { ManifestWatcher } from '@/cli/utilities/build/manifest/manifest-watcher'; import { writeManifestToOutput } from '@/cli/utilities/build/manifest/manifest-writer'; -import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/utilities/config/constants/current-execution-directory'; +import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/utilities/config/current-execution-directory'; import { type ApplicationManifest } from 'twenty-shared/application'; const initLogger = createLogger('init'); @@ -69,10 +72,14 @@ export class AppDevCommand { await this.startManifestWatcher(); await this.startFunctionsWatcher(buildResult.filePaths.functions); - await this.startFrontComponentsWatcher(buildResult.filePaths.frontComponents); + await this.startFrontComponentsWatcher( + buildResult.filePaths.frontComponents, + ); } - private initializeFunctionsFileUploadStatus(manifest: ApplicationManifest): void { + private initializeFunctionsFileUploadStatus( + manifest: ApplicationManifest, + ): void { this.state.fileStatusMaps.functions.clear(); for (const fn of manifest.functions ?? []) { @@ -85,16 +92,21 @@ export class AppDevCommand { } } - private initializeFrontComponentsFileUploadStatus(manifest: ApplicationManifest): void { + private initializeFrontComponentsFileUploadStatus( + manifest: ApplicationManifest, + ): void { this.state.fileStatusMaps.frontComponents.clear(); for (const component of manifest.frontComponents ?? []) { - this.state.fileStatusMaps.frontComponents.set(component.universalIdentifier, { - sourcePath: component.sourceComponentPath, - builtPath: component.builtComponentPath, - checksum: null, - isUploaded: false, - }); + this.state.fileStatusMaps.frontComponents.set( + component.universalIdentifier, + { + sourcePath: component.sourceComponentPath, + builtPath: component.builtComponentPath, + checksum: null, + isUploaded: false, + }, + ); } } @@ -106,7 +118,8 @@ export class AppDevCommand { this.state.manifest = result.manifest; const functionSourcePaths = result.filePaths.functions; - const shouldRestartFunctions = this.functionsWatcher?.shouldRestart(functionSourcePaths); + const shouldRestartFunctions = + this.functionsWatcher?.shouldRestart(functionSourcePaths); if (shouldRestartFunctions) { if (result.manifest) { this.initializeFunctionsFileUploadStatus(result.manifest); @@ -115,7 +128,8 @@ export class AppDevCommand { } const componentSourcePaths = result.filePaths.frontComponents; - const shouldRestartFrontComponents = this.frontComponentsWatcher?.shouldRestart(componentSourcePaths); + const shouldRestartFrontComponents = + this.frontComponentsWatcher?.shouldRestart(componentSourcePaths); if (shouldRestartFrontComponents) { if (result.manifest) { this.initializeFrontComponentsFileUploadStatus(result.manifest); @@ -133,34 +147,37 @@ export class AppDevCommand { this.functionsWatcher = new FunctionsWatcher({ appPath: this.appPath, sourcePaths, - onFileBuilt: (builtPath, checksum) => { - this.updateFileStatus('function', builtPath, checksum); + onFileBuilt: async (builtPath, checksum) => { + await this.updateFileStatus('function', builtPath, checksum); }, }); await this.functionsWatcher.start(); } - private async startFrontComponentsWatcher(sourcePaths: string[]): Promise { + private async startFrontComponentsWatcher( + sourcePaths: string[], + ): Promise { this.frontComponentsWatcher = new FrontComponentsWatcher({ appPath: this.appPath, sourcePaths, - onFileBuilt: (builtPath, checksum) => { - this.updateFileStatus('frontComponent', builtPath, checksum); + onFileBuilt: async (builtPath, checksum) => { + await this.updateFileStatus('frontComponent', builtPath, checksum); }, }); await this.frontComponentsWatcher.start(); } - private updateFileStatus( + private async updateFileStatus( entityType: 'function' | 'frontComponent', builtPath: string, checksum: string, - ): void { - const statusMap = entityType === 'function' - ? this.state.fileStatusMaps.functions - : this.state.fileStatusMaps.frontComponents; + ): Promise { + const statusMap = + entityType === 'function' + ? this.state.fileStatusMaps.functions + : this.state.fileStatusMaps.frontComponents; for (const [_id, status] of statusMap) { if (status.builtPath === builtPath) { @@ -172,10 +189,33 @@ export class AppDevCommand { const manifest = this.state.manifest; if (manifest) { - const updatedManifest = updateManifestChecksum({ manifest, entityType, builtPath, checksum }); + const updatedManifest = updateManifestChecksum({ + manifest, + entityType, + builtPath, + checksum, + }); if (updatedManifest) { this.state.manifest = updatedManifest; - writeManifestToOutput(this.appPath, updatedManifest); + await writeManifestToOutput(this.appPath, updatedManifest); + } + } + } + + private markFileAsUploaded( + entityType: 'function' | 'frontComponent', + builtPath: string, + success: boolean, + ): void { + const statusMap = + entityType === 'function' + ? this.state.fileStatusMaps.functions + : this.state.fileStatusMaps.frontComponents; + + for (const [_id, status] of statusMap) { + if (status.builtPath === builtPath) { + status.isUploaded = success; + break; } } } diff --git a/packages/twenty-sdk/src/cli/commands/app/app-generate.ts b/packages/twenty-sdk/src/cli/commands/app/app-generate.ts index dd7e092b7d..963ed2ad0f 100644 --- a/packages/twenty-sdk/src/cli/commands/app/app-generate.ts +++ b/packages/twenty-sdk/src/cli/commands/app/app-generate.ts @@ -1,13 +1,13 @@ import chalk from 'chalk'; -import { GenerateService } from '@/cli/utilities/generate/services/generate.service'; -import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/utilities/config/constants/current-execution-directory'; +import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/utilities/config/current-execution-directory'; +import { ClientService } from '@/cli/utilities/client/client-service'; export class AppGenerateCommand { - private generateService = new GenerateService(); + private clientService = new ClientService(); async execute(appPath: string = CURRENT_EXECUTION_DIRECTORY) { try { - await this.generateService.generateClient(appPath); + await this.clientService.generate(appPath); } catch (error) { console.error( chalk.red('Generate Twenty client failed:'), diff --git a/packages/twenty-sdk/src/cli/commands/app/app-sync.ts b/packages/twenty-sdk/src/cli/commands/app/app-sync.ts index 5a3c422c52..b05ee2a0c8 100644 --- a/packages/twenty-sdk/src/cli/commands/app/app-sync.ts +++ b/packages/twenty-sdk/src/cli/commands/app/app-sync.ts @@ -1,27 +1,43 @@ -import { ApiService } from '@/cli/utilities/api/services/api.service'; -import { type ApiResponse } from '@/cli/utilities/api/types/api-response.types'; -import { runManifestBuild } from '@/cli/utilities/build/manifest/manifest-build'; -import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/utilities/config/constants/current-execution-directory'; +import { type ApiResponse } from '@/cli/utilities/api/api-response-type'; +import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/utilities/config/current-execution-directory'; import chalk from 'chalk'; import * as fs from 'fs-extra'; import path from 'path'; +import { AppBuildCommand } from '@/cli/commands/app/app-build'; +import { FileUploader } from '@/cli/utilities/file/file-uploader'; +import { ApiService } from '@/cli/utilities/api/api-service'; export class AppSyncCommand { private apiService = new ApiService(); + private buildCommand = new AppBuildCommand(); async execute( appPath: string = CURRENT_EXECUTION_DIRECTORY, ): Promise> { console.log(chalk.blue('🚀 Syncing Twenty Application')); - console.log(chalk.gray(`📁 App Path: ${appPath}`)); console.log(''); - const { manifest } = await runManifestBuild(appPath, { writeOutput: false }); + const result = await this.buildCommand.execute({ + appPath, + }); + + if (!result.success) { + return result; + } + + const manifest = result.data.manifest; if (!manifest) { - return { success: false, error: 'Build failed' }; + return { success: false, error: 'No manifest found. Build failed?' }; } + const uploadService = new FileUploader({ + applicationUniversalIdentifier: manifest.application.universalIdentifier, + appPath, + }); + + await uploadService.uploadManifestBuiltFiles(manifest); + const yarnLockPath = path.join(appPath, 'yarn.lock'); let yarnLock = ''; @@ -29,20 +45,17 @@ export class AppSyncCommand { yarnLock = await fs.readFile(yarnLockPath, 'utf8'); } - const serverlessSyncResult = await this.apiService.syncApplication({ + const syncResult = await this.apiService.syncApplication({ manifest, yarnLock, }); - if (serverlessSyncResult.success === false) { - console.error( - chalk.red('❌ Application Sync failed:'), - serverlessSyncResult.error, - ); + if (!syncResult.success) { + console.error(chalk.red('❌ Application Sync failed:'), syncResult.error); } else { console.log(chalk.green('✅ Application synced successfully')); } - return serverlessSyncResult; + return syncResult; } } diff --git a/packages/twenty-sdk/src/cli/commands/app/app-uninstall.ts b/packages/twenty-sdk/src/cli/commands/app/app-uninstall.ts index 668b9b5c0e..e5a2562a21 100644 --- a/packages/twenty-sdk/src/cli/commands/app/app-uninstall.ts +++ b/packages/twenty-sdk/src/cli/commands/app/app-uninstall.ts @@ -1,7 +1,7 @@ -import { ApiService } from '@/cli/utilities/api/services/api.service'; -import { type ApiResponse } from '@/cli/utilities/api/types/api-response.types'; +import { ApiService } from '@/cli/utilities/api/api-service'; +import { type ApiResponse } from '@/cli/utilities/api/api-response-type'; import { runManifestBuild } from '@/cli/utilities/build/manifest/manifest-build'; -import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/utilities/config/constants/current-execution-directory'; +import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/utilities/config/current-execution-directory'; import chalk from 'chalk'; import inquirer from 'inquirer'; @@ -25,7 +25,10 @@ export class AppUninstallCommand { process.exit(1); } - const { manifest } = await runManifestBuild(appPath, { display: false, writeOutput: false }); + const { manifest } = await runManifestBuild(appPath, { + display: false, + writeOutput: false, + }); if (!manifest) { return { success: false, error: 'Build failed' }; diff --git a/packages/twenty-sdk/src/cli/commands/auth/auth-list.ts b/packages/twenty-sdk/src/cli/commands/auth/auth-list.ts index 708675f415..16ad716fc3 100644 --- a/packages/twenty-sdk/src/cli/commands/auth/auth-list.ts +++ b/packages/twenty-sdk/src/cli/commands/auth/auth-list.ts @@ -1,5 +1,5 @@ import chalk from 'chalk'; -import { ConfigService } from '@/cli/utilities/config/services/config.service'; +import { ConfigService } from '@/cli/utilities/config/config-service'; export class AuthListCommand { private configService = new ConfigService(); @@ -22,7 +22,8 @@ export class AuthListCommand { console.log(chalk.blue('Available workspaces:\n')); for (const workspace of availableWorkspaces) { - const config = await this.configService.getConfigForWorkspace(workspace); + const config = + await this.configService.getConfigForWorkspace(workspace); const hasCredentials = !!config.apiKey; const isDefault = workspace === currentDefault; diff --git a/packages/twenty-sdk/src/cli/commands/auth/auth-login.ts b/packages/twenty-sdk/src/cli/commands/auth/auth-login.ts index 70c70760fc..c3921bf335 100644 --- a/packages/twenty-sdk/src/cli/commands/auth/auth-login.ts +++ b/packages/twenty-sdk/src/cli/commands/auth/auth-login.ts @@ -1,16 +1,13 @@ import chalk from 'chalk'; import inquirer from 'inquirer'; -import { ApiService } from '@/cli/utilities/api/services/api.service'; -import { ConfigService } from '@/cli/utilities/config/services/config.service'; +import { ApiService } from '@/cli/utilities/api/api-service'; +import { ConfigService } from '@/cli/utilities/config/config-service'; export class AuthLoginCommand { private configService = new ConfigService(); private apiService = new ApiService(); - async execute(options: { - apiKey?: string; - apiUrl?: string; - }): Promise { + async execute(options: { apiKey?: string; apiUrl?: string }): Promise { try { let { apiKey, apiUrl } = options; diff --git a/packages/twenty-sdk/src/cli/commands/auth/auth-logout.ts b/packages/twenty-sdk/src/cli/commands/auth/auth-logout.ts index b2c83901d0..e597538898 100644 --- a/packages/twenty-sdk/src/cli/commands/auth/auth-logout.ts +++ b/packages/twenty-sdk/src/cli/commands/auth/auth-logout.ts @@ -1,5 +1,5 @@ import chalk from 'chalk'; -import { ConfigService } from '@/cli/utilities/config/services/config.service'; +import { ConfigService } from '@/cli/utilities/config/config-service'; export class AuthLogoutCommand { private configService = new ConfigService(); diff --git a/packages/twenty-sdk/src/cli/commands/auth/auth-status.ts b/packages/twenty-sdk/src/cli/commands/auth/auth-status.ts index 2ac6f5a49f..a52d690c24 100644 --- a/packages/twenty-sdk/src/cli/commands/auth/auth-status.ts +++ b/packages/twenty-sdk/src/cli/commands/auth/auth-status.ts @@ -1,6 +1,6 @@ import chalk from 'chalk'; -import { ApiService } from '@/cli/utilities/api/services/api.service'; -import { ConfigService } from '@/cli/utilities/config/services/config.service'; +import { ApiService } from '@/cli/utilities/api/api-service'; +import { ConfigService } from '@/cli/utilities/config/config-service'; export class AuthStatusCommand { private configService = new ConfigService(); diff --git a/packages/twenty-sdk/src/cli/commands/auth/auth-switch.ts b/packages/twenty-sdk/src/cli/commands/auth/auth-switch.ts index a5d3c8badd..11bc85168b 100644 --- a/packages/twenty-sdk/src/cli/commands/auth/auth-switch.ts +++ b/packages/twenty-sdk/src/cli/commands/auth/auth-switch.ts @@ -1,7 +1,7 @@ import chalk from 'chalk'; import inquirer from 'inquirer'; -import { ApiService } from '@/cli/utilities/api/services/api.service'; -import { ConfigService } from '@/cli/utilities/config/services/config.service'; +import { ApiService } from '@/cli/utilities/api/api-service'; +import { ConfigService } from '@/cli/utilities/config/config-service'; export class AuthSwitchCommand { private configService = new ConfigService(); diff --git a/packages/twenty-sdk/src/cli/commands/entity/entity-add.ts b/packages/twenty-sdk/src/cli/commands/entity/entity-add.ts index 8717d27001..6156bcdc75 100644 --- a/packages/twenty-sdk/src/cli/commands/entity/entity-add.ts +++ b/packages/twenty-sdk/src/cli/commands/entity/entity-add.ts @@ -1,9 +1,9 @@ -import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/utilities/config/constants/current-execution-directory'; -import { getFrontComponentBaseFile } from '@/cli/utilities/entity/utils/entity-front-component-template'; -import { getFunctionBaseFile } from '@/cli/utilities/entity/utils/entity-function-template'; -import { convertToLabel } from '@/cli/utilities/entity/utils/entity-label'; -import { getNewObjectFileContent } from '@/cli/utilities/entity/utils/entity-object-template'; -import { getRoleBaseFile } from '@/cli/utilities/entity/utils/entity-role-template'; +import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/utilities/config/current-execution-directory'; +import { getFrontComponentBaseFile } from '@/cli/utilities/entity/entity-front-component-template'; +import { getFunctionBaseFile } from '@/cli/utilities/entity/entity-function-template'; +import { convertToLabel } from '@/cli/utilities/entity/entity-label'; +import { getNewObjectFileContent } from '@/cli/utilities/entity/entity-object-template'; +import { getRoleBaseFile } from '@/cli/utilities/entity/entity-role-template'; import chalk from 'chalk'; import * as fs from 'fs-extra'; import inquirer from 'inquirer'; diff --git a/packages/twenty-sdk/src/cli/commands/function/function-execute.ts b/packages/twenty-sdk/src/cli/commands/function/function-execute.ts index c36425df2e..66c4226dfc 100644 --- a/packages/twenty-sdk/src/cli/commands/function/function-execute.ts +++ b/packages/twenty-sdk/src/cli/commands/function/function-execute.ts @@ -1,6 +1,6 @@ -import { ApiService } from '@/cli/utilities/api/services/api.service'; +import { ApiService } from '@/cli/utilities/api/api-service'; import { runManifestBuild } from '@/cli/utilities/build/manifest/manifest-build'; -import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/utilities/config/constants/current-execution-directory'; +import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/utilities/config/current-execution-directory'; import chalk from 'chalk'; import { type ApplicationManifest } from 'twenty-shared/application'; import { isDefined } from 'twenty-shared/utils'; diff --git a/packages/twenty-sdk/src/cli/commands/function/function-logs.ts b/packages/twenty-sdk/src/cli/commands/function/function-logs.ts index 41db599172..1452cce725 100644 --- a/packages/twenty-sdk/src/cli/commands/function/function-logs.ts +++ b/packages/twenty-sdk/src/cli/commands/function/function-logs.ts @@ -1,6 +1,6 @@ -import { ApiService } from '@/cli/utilities/api/services/api.service'; +import { ApiService } from '@/cli/utilities/api/api-service'; import { runManifestBuild } from '@/cli/utilities/build/manifest/manifest-build'; -import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/utilities/config/constants/current-execution-directory'; +import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/utilities/config/current-execution-directory'; import chalk from 'chalk'; export class FunctionLogsCommand { @@ -16,7 +16,10 @@ export class FunctionLogsCommand { functionName?: string; }): Promise { try { - const { manifest } = await runManifestBuild(appPath, { display: false, writeOutput: false }); + const { manifest } = await runManifestBuild(appPath, { + display: false, + writeOutput: false, + }); if (!manifest) { process.exit(1); diff --git a/packages/twenty-sdk/src/cli/commands/sdk/sdk-generate.ts b/packages/twenty-sdk/src/cli/commands/sdk/sdk-generate.ts deleted file mode 100644 index 20ca9bc860..0000000000 --- a/packages/twenty-sdk/src/cli/commands/sdk/sdk-generate.ts +++ /dev/null @@ -1,8 +0,0 @@ -// Placeholder for sdk generate command -// TODO: Implement SDK generation functionality - -export class SdkGenerateCommand { - async execute(): Promise { - throw new Error('Not implemented'); - } -} diff --git a/packages/twenty-sdk/src/cli/constants/assets-dir.ts b/packages/twenty-sdk/src/cli/constants/assets-dir.ts deleted file mode 100644 index 1d7ac30a8f..0000000000 --- a/packages/twenty-sdk/src/cli/constants/assets-dir.ts +++ /dev/null @@ -1,5 +0,0 @@ -/** - * Directory name for static assets in Twenty applications. - * Assets are copied from this folder at the root of the app to the build output. - */ -export const ASSETS_DIR = 'assets'; diff --git a/packages/twenty-sdk/src/cli/utilities/api/types/api-response.types.ts b/packages/twenty-sdk/src/cli/utilities/api/api-response-type.ts similarity index 100% rename from packages/twenty-sdk/src/cli/utilities/api/types/api-response.types.ts rename to packages/twenty-sdk/src/cli/utilities/api/api-response-type.ts diff --git a/packages/twenty-sdk/src/cli/utilities/api/services/api.service.ts b/packages/twenty-sdk/src/cli/utilities/api/api-service.ts similarity index 96% rename from packages/twenty-sdk/src/cli/utilities/api/services/api.service.ts rename to packages/twenty-sdk/src/cli/utilities/api/api-service.ts index ec82e0961e..dbcffb9987 100644 --- a/packages/twenty-sdk/src/cli/utilities/api/services/api.service.ts +++ b/packages/twenty-sdk/src/cli/utilities/api/api-service.ts @@ -1,4 +1,4 @@ -import { ConfigService } from '@/cli/utilities/config/services/config.service'; +import { ConfigService } from '@/cli/utilities/config/config-service'; import axios, { type AxiosInstance, type AxiosResponse } from 'axios'; import chalk from 'chalk'; import * as fs from 'fs'; @@ -11,7 +11,8 @@ import { import * as path from 'path'; import { type ApplicationManifest } from 'twenty-shared/application'; import { type FileFolder } from 'twenty-shared/types'; -import { type ApiResponse } from '../types/api-response.types'; +import { type ApiResponse } from '@/cli/utilities/api/api-response-type'; +import { pascalCase } from 'twenty-shared/utils'; export class ApiService { private client: AxiosInstance; @@ -271,7 +272,8 @@ export class ApiService { if (response.data.errors) { return { success: false, - error: response.data.errors[0]?.message || 'Failed to fetch functions', + error: + response.data.errors[0]?.message || 'Failed to fetch functions', }; } @@ -415,10 +417,12 @@ export class ApiService { async uploadFile({ filePath, + builtHandlerPath, fileFolder, applicationUniversalIdentifier, }: { filePath: string; + builtHandlerPath: string; fileFolder: FileFolder; applicationUniversalIdentifier: string; }): Promise> { @@ -443,13 +447,15 @@ export class ApiService { } `; + const graphqlEnumFileFolder = pascalCase(fileFolder); + const operations = JSON.stringify({ query: mutation, variables: { file: null, applicationUniversalIdentifier, - filePath, - fileFolder, + filePath: builtHandlerPath, + fileFolder: graphqlEnumFileFolder, }, }); diff --git a/packages/twenty-sdk/src/cli/utilities/build/common/esbuild-result-processor.ts b/packages/twenty-sdk/src/cli/utilities/build/common/esbuild-result-processor.ts index 03cf30a2af..040849717c 100644 --- a/packages/twenty-sdk/src/cli/utilities/build/common/esbuild-result-processor.ts +++ b/packages/twenty-sdk/src/cli/utilities/build/common/esbuild-result-processor.ts @@ -2,7 +2,7 @@ import crypto from 'crypto'; import type * as esbuild from 'esbuild'; import * as fs from 'fs-extra'; import path from 'path'; -import { type OnFileBuiltCallback } from './restartable-watcher.interface'; +import { type OnFileBuiltCallback } from '@/cli/utilities/build/common/restartable-watcher-interface'; export type ProcessEsbuildResultParams = { result: esbuild.BuildResult; @@ -25,8 +25,9 @@ export const processEsbuildResult = async ({ onFileBuilt, onSuccess, }: ProcessEsbuildResultParams): Promise => { - const outputFiles = Object.keys(result.metafile?.outputs ?? {}) - .filter((file) => file.endsWith('.mjs')); + const outputFiles = Object.keys(result.metafile?.outputs ?? {}).filter( + (file) => file.endsWith('.mjs'), + ); let hasChanges = false; @@ -50,7 +51,7 @@ export const processEsbuildResult = async ({ onSuccess(relativePath); if (onFileBuilt) { - onFileBuilt(builtPath, checksum); + await onFileBuilt(builtPath, checksum); } } diff --git a/packages/twenty-sdk/src/cli/utilities/build/common/logger.ts b/packages/twenty-sdk/src/cli/utilities/build/common/logger.ts index 01cdba40d3..34c487d122 100644 --- a/packages/twenty-sdk/src/cli/utilities/build/common/logger.ts +++ b/packages/twenty-sdk/src/cli/utilities/build/common/logger.ts @@ -4,7 +4,8 @@ export type LoggerContext = | 'init' | 'manifest-watch' | 'functions-watch' - | 'front-components-watch'; + | 'front-components-watch' + | 'file-upload'; type LoggerConfig = { prefix: string; @@ -28,6 +29,10 @@ const LOGGER_CONFIGS: Record = { prefix: '[front-components-watch]', color: chalk.green, }, + 'file-upload': { + prefix: '[file-upload]', + color: chalk.blue, + }, }; export type Logger = { @@ -43,8 +48,11 @@ export const createLogger = (context: LoggerContext): Logger => { return { log: (message: string) => console.log(`${prefix} ${message}`), - success: (message: string) => console.log(`${prefix} ${chalk.green(message)}`), - error: (message: string) => console.error(`${prefix} ${chalk.red(message)}`), - warn: (message: string) => console.log(`${prefix} ${chalk.yellow(message)}`), + success: (message: string) => + console.log(`${prefix} ${chalk.green(message)}`), + error: (message: string) => + console.error(`${prefix} ${chalk.red(message)}`), + warn: (message: string) => + console.log(`${prefix} ${chalk.yellow(message)}`), }; }; diff --git a/packages/twenty-sdk/src/cli/utilities/build/common/restartable-watcher.interface.ts b/packages/twenty-sdk/src/cli/utilities/build/common/restartable-watcher-interface.ts similarity index 76% rename from packages/twenty-sdk/src/cli/utilities/build/common/restartable-watcher.interface.ts rename to packages/twenty-sdk/src/cli/utilities/build/common/restartable-watcher-interface.ts index fe0d5f1a77..7dbea25cc3 100644 --- a/packages/twenty-sdk/src/cli/utilities/build/common/restartable-watcher.interface.ts +++ b/packages/twenty-sdk/src/cli/utilities/build/common/restartable-watcher-interface.ts @@ -5,7 +5,10 @@ export interface RestartableWatcher { shouldRestart(sourcePaths: string[]): boolean; } -export type OnFileBuiltCallback = (builtPath: string, checksum: string) => void; +export type OnFileBuiltCallback = ( + builtPath: string, + checksum: string, +) => void | Promise; export type RestartableWatcherOptions = { appPath: string; diff --git a/packages/twenty-sdk/src/cli/utilities/build/front-components/front-component-watcher.ts b/packages/twenty-sdk/src/cli/utilities/build/front-components/front-component-watcher.ts index d23bb6df4f..4753877c5c 100644 --- a/packages/twenty-sdk/src/cli/utilities/build/front-components/front-component-watcher.ts +++ b/packages/twenty-sdk/src/cli/utilities/build/front-components/front-component-watcher.ts @@ -1,16 +1,16 @@ import * as esbuild from 'esbuild'; import * as fs from 'fs-extra'; import path from 'path'; -import { cleanupRemovedFiles } from '../common/cleanup-removed-files'; -import { OUTPUT_DIR } from '../common/constants'; -import { createLogger } from '../common/logger'; -import { processEsbuildResult } from '../common/esbuild-result-processor'; +import { cleanupRemovedFiles } from '@/cli/utilities/build/common/cleanup-removed-files'; +import { OUTPUT_DIR } from '@/cli/utilities/build/common/constants'; +import { processEsbuildResult } from '@/cli/utilities/build/common/esbuild-result-processor'; +import { createLogger } from '@/cli/utilities/build/common/logger'; import { type OnFileBuiltCallback, type RestartableWatcher, type RestartableWatcherOptions, -} from '../common/restartable-watcher.interface'; -import { FRONT_COMPONENTS_DIR } from './constants'; +} from '@/cli/utilities/build/common/restartable-watcher-interface'; +import { FRONT_COMPONENTS_DIR } from '@/cli/utilities/build/front-components/constants'; const logger = createLogger('front-components-watch'); @@ -78,7 +78,11 @@ export class FrontComponentsWatcher implements RestartableWatcher { logger.warn('🔄 Restarting...'); await this.close(); - const outputDir = path.join(this.appPath, OUTPUT_DIR, FRONT_COMPONENTS_DIR); + const outputDir = path.join( + this.appPath, + OUTPUT_DIR, + FRONT_COMPONENTS_DIR, + ); await cleanupRemovedFiles(outputDir, this.componentPaths, sourcePaths); this.componentPaths = sourcePaths; this.lastChecksums.clear(); @@ -142,7 +146,8 @@ export class FrontComponentsWatcher implements RestartableWatcher { builtDir: FRONT_COMPONENTS_DIR, lastChecksums: watcher.lastChecksums, onFileBuilt: watcher.onFileBuilt, - onSuccess: (relativePath) => logger.success(`✓ Built ${relativePath}`), + onSuccess: (relativePath) => + logger.success(`✓ Built ${relativePath}`), }); if (hasChanges && watchMode) { diff --git a/packages/twenty-sdk/src/cli/utilities/build/functions/function-watcher.ts b/packages/twenty-sdk/src/cli/utilities/build/functions/function-watcher.ts index 211f3a6b9e..0d42ac1ba2 100644 --- a/packages/twenty-sdk/src/cli/utilities/build/functions/function-watcher.ts +++ b/packages/twenty-sdk/src/cli/utilities/build/functions/function-watcher.ts @@ -1,16 +1,16 @@ import * as esbuild from 'esbuild'; import * as fs from 'fs-extra'; import path from 'path'; -import { cleanupRemovedFiles } from '../common/cleanup-removed-files'; -import { OUTPUT_DIR } from '../common/constants'; -import { createLogger } from '../common/logger'; -import { processEsbuildResult } from '../common/esbuild-result-processor'; +import { cleanupRemovedFiles } from '@/cli/utilities/build/common/cleanup-removed-files'; +import { OUTPUT_DIR } from '@/cli/utilities/build/common/constants'; +import { processEsbuildResult } from '@/cli/utilities/build/common/esbuild-result-processor'; +import { createLogger } from '@/cli/utilities/build/common/logger'; import { type OnFileBuiltCallback, type RestartableWatcher, type RestartableWatcherOptions, -} from '../common/restartable-watcher.interface'; -import { FUNCTIONS_DIR } from './constants'; +} from '@/cli/utilities/build/common/restartable-watcher-interface'; +import { FUNCTIONS_DIR } from '@/cli/utilities/build/functions/constants'; const logger = createLogger('functions-watch'); @@ -140,10 +140,13 @@ export class FunctionsWatcher implements RestartableWatcher { { name: 'external-patterns', setup: (build) => { - build.onResolve({ filter: /(?:^|\/)generated(?:\/|$)/ }, (args) => ({ - path: args.path, - external: true, - })); + build.onResolve( + { filter: /(?:^|\/)generated(?:\/|$)/ }, + (args) => ({ + path: args.path, + external: true, + }), + ); }, }, { @@ -165,7 +168,8 @@ export class FunctionsWatcher implements RestartableWatcher { builtDir: FUNCTIONS_DIR, lastChecksums: watcher.lastChecksums, onFileBuilt: watcher.onFileBuilt, - onSuccess: (relativePath) => logger.success(`✓ Built ${relativePath}`), + onSuccess: (relativePath) => + logger.success(`✓ Built ${relativePath}`), }); if (hasChanges && watchMode) { diff --git a/packages/twenty-sdk/src/cli/utilities/build/manifest/__tests__/validate-manifest.spec.ts b/packages/twenty-sdk/src/cli/utilities/build/manifest/__tests__/validate-manifest.spec.ts index 48fb14bbb9..417b14f7b8 100644 --- a/packages/twenty-sdk/src/cli/utilities/build/manifest/__tests__/validate-manifest.spec.ts +++ b/packages/twenty-sdk/src/cli/utilities/build/manifest/__tests__/validate-manifest.spec.ts @@ -31,6 +31,7 @@ describe('validateManifest - objectExtensions', () => { const result = validateManifest({ application: validApplication, objects: [], + frontComponents: [], objectExtensions: [validObjectExtension], functions: [], roles: [], @@ -60,6 +61,7 @@ describe('validateManifest - objectExtensions', () => { objects: [], objectExtensions: [extensionByUuid], functions: [], + frontComponents: [], roles: [], }); @@ -87,6 +89,7 @@ describe('validateManifest - objectExtensions', () => { objects: [], objectExtensions: [validObjectExtension, anotherExtension], functions: [], + frontComponents: [], roles: [], }); @@ -123,6 +126,7 @@ describe('validateManifest - objectExtensions', () => { objects: [], objectExtensions: [extensionWithSelect], functions: [], + frontComponents: [], roles: [], }); @@ -142,6 +146,7 @@ describe('validateManifest - objectExtensions', () => { objects: [], objectExtensions: [invalidExtension], functions: [], + frontComponents: [], roles: [], }); @@ -164,6 +169,7 @@ describe('validateManifest - objectExtensions', () => { objects: [], objectExtensions: [invalidExtension], functions: [], + frontComponents: [], roles: [], }); @@ -190,6 +196,7 @@ describe('validateManifest - objectExtensions', () => { objects: [], objectExtensions: [invalidExtension], functions: [], + frontComponents: [], roles: [], }); @@ -217,6 +224,7 @@ describe('validateManifest - objectExtensions', () => { objects: [], objectExtensions: [invalidExtension], functions: [], + frontComponents: [], roles: [], }); @@ -247,6 +255,7 @@ describe('validateManifest - objectExtensions', () => { objects: [], objectExtensions: [invalidExtension], functions: [], + frontComponents: [], roles: [], }); @@ -277,6 +286,7 @@ describe('validateManifest - objectExtensions', () => { objects: [], objectExtensions: [invalidExtension], functions: [], + frontComponents: [], roles: [], }); @@ -307,6 +317,7 @@ describe('validateManifest - objectExtensions', () => { objects: [], objectExtensions: [invalidExtension], functions: [], + frontComponents: [], roles: [], }); @@ -338,6 +349,7 @@ describe('validateManifest - objectExtensions', () => { objects: [], objectExtensions: [invalidExtension], functions: [], + frontComponents: [], roles: [], }); @@ -370,6 +382,7 @@ describe('validateManifest - objectExtensions', () => { objects: [], objectExtensions: [invalidExtension], functions: [], + frontComponents: [], roles: [], }); @@ -411,6 +424,7 @@ describe('validateManifest - objectExtensions', () => { objects: [], objectExtensions: [extensionWithDuplicates], functions: [], + frontComponents: [], roles: [], }); @@ -458,6 +472,7 @@ describe('validateManifest - objectExtensions', () => { }, ], functions: [], + frontComponents: [], roles: [], }); diff --git a/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/application.ts b/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/application.ts index 3822b5649d..742404f339 100644 --- a/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/application.ts +++ b/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/application.ts @@ -6,13 +6,13 @@ import { } from 'twenty-shared/application'; import { createLogger } from '../../common/logger'; import { manifestExtractFromFileServer } from '../manifest-extract-from-file-server'; -import { type ValidationError } from '../manifest.types'; import { type EntityBuildResult, type EntityIdWithLocation, type ManifestEntityBuilder, type ManifestWithoutSources, -} from './entity.interface'; +} from '@/cli/utilities/build/manifest/entities/entity-interface'; +import { type ValidationError } from '@/cli/utilities/build/manifest/manifest-types'; const logger = createLogger('manifest-watch'); diff --git a/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/entity.interface.ts b/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/entity-interface.ts similarity index 88% rename from packages/twenty-sdk/src/cli/utilities/build/manifest/entities/entity.interface.ts rename to packages/twenty-sdk/src/cli/utilities/build/manifest/entities/entity-interface.ts index 1620b87d95..84aae13fdd 100644 --- a/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/entity.interface.ts +++ b/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/entity-interface.ts @@ -1,5 +1,5 @@ import { type ApplicationManifest } from 'twenty-shared/application'; -import { type ValidationError } from '../manifest.types'; +import { type ValidationError } from '@/cli/utilities/build/manifest/manifest-types'; export type EntityIdWithLocation = { id: string; diff --git a/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/front-component.ts b/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/front-component.ts index deee9d88fe..705341e9f5 100644 --- a/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/front-component.ts +++ b/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/front-component.ts @@ -1,21 +1,25 @@ import { glob } from 'fast-glob'; import { type FrontComponentManifest } from 'twenty-shared/application'; -import { createLogger } from '../../common/logger'; -import { FRONT_COMPONENTS_DIR } from '../../front-components/constants'; -import { manifestExtractFromFileServer } from '../manifest-extract-from-file-server'; -import { type ValidationError } from '../manifest.types'; +import { createLogger } from '@/cli/utilities/build/common/logger'; + +import { manifestExtractFromFileServer } from '@/cli/utilities/build/manifest/manifest-extract-from-file-server'; +import { type ValidationError } from '@/cli/utilities/build/manifest/manifest-types'; import { type EntityBuildResult, type EntityIdWithLocation, type ManifestEntityBuilder, type ManifestWithoutSources, -} from './entity.interface'; +} from '@/cli/utilities/build/manifest/entities/entity-interface'; +import { FRONT_COMPONENTS_DIR } from '@/cli/utilities/build/front-components/constants'; const logger = createLogger('manifest-watch'); type FrontComponentConfig = Omit< FrontComponentManifest, - 'sourceComponentPath' | 'builtComponentPath' | 'builtComponentChecksum' | 'componentName' + | 'sourceComponentPath' + | 'builtComponentPath' + | 'builtComponentChecksum' + | 'componentName' > & { component: { name: string }; }; @@ -23,10 +27,17 @@ type FrontComponentConfig = Omit< export class FrontComponentEntityBuilder implements ManifestEntityBuilder { - async build(appPath: string): Promise> { + async build( + appPath: string, + ): Promise> { const componentFiles = await glob(['**/*.front-component.tsx'], { cwd: appPath, - ignore: ['**/node_modules/**', '**/*.d.ts', '**/dist/**', '**/.twenty/**'], + ignore: [ + '**/node_modules/**', + '**/*.d.ts', + '**/dist/**', + '**/.twenty/**', + ], }); const manifests: FrontComponentManifest[] = []; diff --git a/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/function.ts b/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/function.ts index 959210b3cd..bb256307f4 100644 --- a/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/function.ts +++ b/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/function.ts @@ -1,15 +1,16 @@ import { glob } from 'fast-glob'; import { type ServerlessFunctionManifest } from 'twenty-shared/application'; -import { createLogger } from '../../common/logger'; -import { FUNCTIONS_DIR } from '../../functions/constants'; -import { manifestExtractFromFileServer } from '../manifest-extract-from-file-server'; -import { type ValidationError } from '../manifest.types'; +import { createLogger } from '@/cli/utilities/build/common/logger'; + +import { manifestExtractFromFileServer } from '@/cli/utilities/build/manifest/manifest-extract-from-file-server'; +import { type ValidationError } from '@/cli/utilities/build/manifest/manifest-types'; import { type EntityBuildResult, type EntityIdWithLocation, type ManifestEntityBuilder, type ManifestWithoutSources, -} from './entity.interface'; +} from '@/cli/utilities/build/manifest/entities/entity-interface'; +import { FUNCTIONS_DIR } from '@/cli/utilities/build/functions/constants'; const logger = createLogger('manifest-watch'); @@ -23,10 +24,17 @@ type ExtractedFunctionManifest = Omit< export class FunctionEntityBuilder implements ManifestEntityBuilder { - async build(appPath: string): Promise> { + async build( + appPath: string, + ): Promise> { const functionFiles = await glob(['**/*.function.ts'], { cwd: appPath, - ignore: ['**/node_modules/**', '**/*.d.ts', '**/dist/**', '**/.twenty/**'], + ignore: [ + '**/node_modules/**', + '**/*.d.ts', + '**/dist/**', + '**/.twenty/**', + ], }); const manifests: ServerlessFunctionManifest[] = []; diff --git a/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/object-extension.ts b/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/object-extension.ts index 521d817cb2..aeecd811fe 100644 --- a/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/object-extension.ts +++ b/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/object-extension.ts @@ -2,22 +2,29 @@ import { glob } from 'fast-glob'; import { type ObjectExtensionManifest } from 'twenty-shared/application'; import { FieldMetadataType } from 'twenty-shared/types'; import { isNonEmptyArray } from 'twenty-shared/utils'; -import { manifestExtractFromFileServer } from '../manifest-extract-from-file-server'; -import { type ValidationError } from '../manifest.types'; +import { manifestExtractFromFileServer } from '@/cli/utilities/build/manifest/manifest-extract-from-file-server'; +import { type ValidationError } from '@/cli/utilities/build/manifest/manifest-types'; import { type EntityBuildResult, type EntityIdWithLocation, type ManifestEntityBuilder, type ManifestWithoutSources, -} from './entity.interface'; +} from '@/cli/utilities/build/manifest/entities/entity-interface'; export class ObjectExtensionEntityBuilder implements ManifestEntityBuilder { - async build(appPath: string): Promise> { + async build( + appPath: string, + ): Promise> { const extensionFiles = await glob(['**/*.object-extension.ts'], { cwd: appPath, - ignore: ['**/node_modules/**', '**/*.d.ts', '**/dist/**', '**/.twenty/**'], + ignore: [ + '**/node_modules/**', + '**/*.d.ts', + '**/dist/**', + '**/.twenty/**', + ], }); const manifests: ObjectExtensionManifest[] = []; diff --git a/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/object.ts b/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/object.ts index 04829fa678..62bdfbd8d5 100644 --- a/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/object.ts +++ b/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/object.ts @@ -2,15 +2,15 @@ import { glob } from 'fast-glob'; import { type ObjectManifest } from 'twenty-shared/application'; import { FieldMetadataType } from 'twenty-shared/types'; import { isNonEmptyArray } from 'twenty-shared/utils'; -import { createLogger } from '../../common/logger'; -import { manifestExtractFromFileServer } from '../manifest-extract-from-file-server'; -import { type ValidationError } from '../manifest.types'; +import { createLogger } from '@/cli/utilities/build/common/logger'; +import { manifestExtractFromFileServer } from '@/cli/utilities/build/manifest/manifest-extract-from-file-server'; +import { type ValidationError } from '@/cli/utilities/build/manifest/manifest-types'; import { type EntityBuildResult, type EntityIdWithLocation, type ManifestEntityBuilder, type ManifestWithoutSources, -} from './entity.interface'; +} from '@/cli/utilities/build/manifest/entities/entity-interface'; const logger = createLogger('manifest-watch'); @@ -20,7 +20,12 @@ export class ObjectEntityBuilder async build(appPath: string): Promise> { const objectFiles = await glob(['**/*.object.ts'], { cwd: appPath, - ignore: ['**/node_modules/**', '**/*.d.ts', '**/dist/**', '**/.twenty/**'], + ignore: [ + '**/node_modules/**', + '**/*.d.ts', + '**/dist/**', + '**/.twenty/**', + ], }); const manifests: ObjectManifest[] = []; @@ -30,7 +35,9 @@ export class ObjectEntityBuilder const absolutePath = `${appPath}/${filePath}`; manifests.push( - await manifestExtractFromFileServer.extractManifestFromFile(absolutePath), + await manifestExtractFromFileServer.extractManifestFromFile( + absolutePath, + ), ); } catch (error) { throw new Error( diff --git a/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/role.ts b/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/role.ts index 0e368b057a..8050a7f75c 100644 --- a/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/role.ts +++ b/packages/twenty-sdk/src/cli/utilities/build/manifest/entities/role.ts @@ -1,14 +1,14 @@ import { glob } from 'fast-glob'; import { type RoleManifest } from 'twenty-shared/application'; -import { createLogger } from '../../common/logger'; -import { manifestExtractFromFileServer } from '../manifest-extract-from-file-server'; -import { type ValidationError } from '../manifest.types'; +import { manifestExtractFromFileServer } from '@/cli/utilities/build/manifest/manifest-extract-from-file-server'; +import { type ValidationError } from '@/cli/utilities/build/manifest/manifest-types'; import { type EntityBuildResult, type EntityIdWithLocation, type ManifestEntityBuilder, type ManifestWithoutSources, -} from './entity.interface'; +} from '@/cli/utilities/build/manifest/entities/entity-interface'; +import { createLogger } from '@/cli/utilities/build/common/logger'; const logger = createLogger('manifest-watch'); @@ -16,7 +16,12 @@ export class RoleEntityBuilder implements ManifestEntityBuilder { async build(appPath: string): Promise> { const roleFiles = await glob(['**/*.role.ts'], { cwd: appPath, - ignore: ['**/node_modules/**', '**/*.d.ts', '**/dist/**', '**/.twenty/**'], + ignore: [ + '**/node_modules/**', + '**/*.d.ts', + '**/dist/**', + '**/.twenty/**', + ], }); const manifests: RoleManifest[] = []; @@ -26,7 +31,9 @@ export class RoleEntityBuilder implements ManifestEntityBuilder { const absolutePath = `${appPath}/${filePath}`; manifests.push( - await manifestExtractFromFileServer.extractManifestFromFile(absolutePath), + await manifestExtractFromFileServer.extractManifestFromFile( + absolutePath, + ), ); } catch (error) { throw new Error( diff --git a/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-build.ts b/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-build.ts index 3c196ac9b9..a842970e82 100644 --- a/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-build.ts +++ b/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-build.ts @@ -1,22 +1,26 @@ -import { findPathFile } from '@/cli/utilities/file/utils/file-find'; -import { parseJsoncFile } from '@/cli/utilities/file/utils/file-jsonc'; +import { findPathFile } from '@/cli/utilities/file/file-find'; +import { parseJsoncFile } from '@/cli/utilities/file/file-jsonc'; import { glob } from 'fast-glob'; import * as fs from 'fs-extra'; import { relative, sep } from 'path'; import { type ApplicationManifest } from 'twenty-shared/application'; import { type Sources } from 'twenty-shared/types'; -import { createLogger } from '../common/logger'; -import { applicationEntityBuilder } from './entities/application'; -import { frontComponentEntityBuilder } from './entities/front-component'; -import { functionEntityBuilder } from './entities/function'; -import { objectEntityBuilder } from './entities/object'; -import { objectExtensionEntityBuilder } from './entities/object-extension'; -import { roleEntityBuilder } from './entities/role'; -import { displayEntitySummary, displayErrors, displayWarnings } from './manifest-display'; +import { applicationEntityBuilder } from '@/cli/utilities/build/manifest/entities/application'; +import { frontComponentEntityBuilder } from '@/cli/utilities/build/manifest/entities/front-component'; +import { functionEntityBuilder } from '@/cli/utilities/build/manifest/entities/function'; +import { objectEntityBuilder } from '@/cli/utilities/build/manifest/entities/object'; +import { objectExtensionEntityBuilder } from '@/cli/utilities/build/manifest/entities/object-extension'; +import { roleEntityBuilder } from '@/cli/utilities/build/manifest/entities/role'; +import { + displayEntitySummary, + displayErrors, + displayWarnings, +} from '@/cli/utilities/build/manifest/manifest-display'; import { manifestExtractFromFileServer } from './manifest-extract-from-file-server'; -import { validateManifest } from './manifest-validate'; -import { writeManifestToOutput } from './manifest-writer'; -import { ManifestValidationError } from './manifest.types'; +import { writeManifestToOutput } from '@/cli/utilities/build/manifest/manifest-writer'; +import { ManifestValidationError } from '@/cli/utilities/build/manifest/manifest-types'; +import { createLogger } from '@/cli/utilities/build/common/logger'; +import { validateManifest } from '@/cli/utilities/build/manifest/manifest-validate'; const logger = createLogger('manifest-watch'); @@ -93,7 +97,9 @@ export const updateManifestChecksum = ({ checksum, }: UpdateManifestChecksumParams): ApplicationManifest | null => { if (entityType === 'function') { - const fnIndex = manifest.functions.findIndex((f) => f.builtHandlerPath === builtPath); + const fnIndex = manifest.functions.findIndex( + (f) => f.builtHandlerPath === builtPath, + ); if (fnIndex === -1) { return null; } @@ -105,16 +111,19 @@ export const updateManifestChecksum = ({ }; } - const componentIndex = manifest.frontComponents?.findIndex( - (c) => c.builtComponentPath === builtPath, - ) ?? -1; + const componentIndex = + manifest.frontComponents.findIndex( + (c) => c.builtComponentPath === builtPath, + ) ?? -1; if (componentIndex === -1) { return null; } return { ...manifest, - frontComponents: manifest.frontComponents?.map((component, index) => - index === componentIndex ? { ...component, builtComponentChecksum: checksum } : component, + frontComponents: manifest.frontComponents.map((component, index) => + index === componentIndex + ? { ...component, builtComponentChecksum: checksum } + : component, ), }; }; @@ -173,11 +182,9 @@ export const runManifestBuild = async ( const manifest: ApplicationManifest = { application, objects: objectManifests, - objectExtensions: - objectExtensionManifests.length > 0 ? objectExtensionManifests : undefined, + objectExtensions: objectExtensionManifests, functions: functionManifests, - frontComponents: - frontComponentManifests.length > 0 ? frontComponentManifests : undefined, + frontComponents: frontComponentManifests, roles: roleManifests, sources, packageJson, diff --git a/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-display.ts b/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-display.ts index d43608b728..f6f20e3ca2 100644 --- a/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-display.ts +++ b/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-display.ts @@ -1,11 +1,14 @@ import { type ApplicationManifest } from 'twenty-shared/application'; import { createLogger } from '../common/logger'; -import { applicationEntityBuilder } from './entities/application'; -import { frontComponentEntityBuilder } from './entities/front-component'; -import { functionEntityBuilder } from './entities/function'; -import { objectEntityBuilder } from './entities/object'; -import { roleEntityBuilder } from './entities/role'; -import { type ManifestValidationError, type ValidationWarning } from './manifest.types'; +import { frontComponentEntityBuilder } from '@/cli/utilities/build/manifest/entities/front-component'; +import { functionEntityBuilder } from '@/cli/utilities/build/manifest/entities/function'; +import { objectEntityBuilder } from '@/cli/utilities/build/manifest/entities/object'; +import { roleEntityBuilder } from '@/cli/utilities/build/manifest/entities/role'; +import { + type ManifestValidationError, + type ValidationWarning, +} from '@/cli/utilities/build/manifest/manifest-types'; +import { applicationEntityBuilder } from '@/cli/utilities/build/manifest/entities/application'; const logger = createLogger('manifest-watch'); diff --git a/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-extract-from-file-server.ts b/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-extract-from-file-server.ts index 4db0f3af3f..0d0c6aa851 100644 --- a/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-extract-from-file-server.ts +++ b/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-extract-from-file-server.ts @@ -24,14 +24,22 @@ export class ManifestExtractFromFileServer { options: ExtractManifestOptions = {}, ): Promise { if (!this.appPath) { - throw new Error('ManifestExtractFromFileServer not initialized. Call init(appPath) first.'); + throw new Error( + 'ManifestExtractFromFileServer not initialized. Call init(appPath) first.', + ); } const { entryProperty } = options; const server = await this.getServer(); - const module = (await server.ssrLoadModule(filepath)) as Record; + const module = (await server.ssrLoadModule(filepath)) as Record< + string, + unknown + >; - const config = this.extractConfigFromModule>(module, entryProperty); + const config = this.extractConfigFromModule>( + module, + entryProperty, + ); if (!config) { const expectedExport = entryProperty @@ -48,11 +56,14 @@ export class ManifestExtractFromFileServer { const entryName = entryFunction.name; if (!entryName) { - throw new Error(`${entryProperty} function in ${filepath} must be a named function`); + throw new Error( + `${entryProperty} function in ${filepath} must be a named function`, + ); } const importSource = await this.resolveEntryPath(filepath, entryName); - const entryPath = importSource ?? path.relative(this.appPath, filepath).replace(/\\/g, '/'); + const entryPath = + importSource ?? path.relative(this.appPath, filepath).replace(/\\/g, '/'); const { [entryProperty]: _, ...configWithoutEntry } = config; @@ -72,7 +83,9 @@ export class ManifestExtractFromFileServer { private async getServer(): Promise { if (!this.appPath) { - throw new Error('ManifestExtractFromFileServer not initialized. Call init(appPath) first.'); + throw new Error( + 'ManifestExtractFromFileServer not initialized. Call init(appPath) first.', + ); } if (this.server) { @@ -100,7 +113,10 @@ export class ManifestExtractFromFileServer { isPlainObject(value) && typeof (value as Record)[entryProperty!] === 'function'; - if (isDefined(module.default) && (!entryProperty || hasValidEntry(module.default))) { + if ( + isDefined(module.default) && + (!entryProperty || hasValidEntry(module.default)) + ) { return module.default as T; } @@ -124,7 +140,9 @@ export class ManifestExtractFromFileServer { const source = await fs.readFile(filepath, 'utf8'); const patterns = [ - new RegExp(`import\\s*\\{[^}]*\\b${entryName}\\b[^}]*\\}\\s*from\\s*['"]([^'"]+)['"]`), + new RegExp( + `import\\s*\\{[^}]*\\b${entryName}\\b[^}]*\\}\\s*from\\s*['"]([^'"]+)['"]`, + ), new RegExp(`import\\s+${entryName}\\s+from\\s*['"]([^'"]+)['"]`), ]; @@ -142,19 +160,28 @@ export class ManifestExtractFromFileServer { } const server = await this.getServer(); - const resolved = await server.pluginContainer.resolveId(importSpecifier, filepath); + const resolved = await server.pluginContainer.resolveId( + importSpecifier, + filepath, + ); if (resolved?.id) { return path.relative(this.appPath, resolved.id).replace(/\\/g, '/'); } if (importSpecifier.startsWith('.')) { - const absolutePath = path.resolve(path.dirname(filepath), importSpecifier); + const absolutePath = path.resolve( + path.dirname(filepath), + importSpecifier, + ); const relativePath = path.relative(this.appPath, absolutePath); - return (relativePath.endsWith('.ts') ? relativePath : `${relativePath}.ts`).replace(/\\/g, '/'); + return ( + relativePath.endsWith('.ts') ? relativePath : `${relativePath}.ts` + ).replace(/\\/g, '/'); } return null; } } -export const manifestExtractFromFileServer = new ManifestExtractFromFileServer(); +export const manifestExtractFromFileServer = + new ManifestExtractFromFileServer(); diff --git a/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest.types.ts b/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-types.ts similarity index 100% rename from packages/twenty-sdk/src/cli/utilities/build/manifest/manifest.types.ts rename to packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-types.ts diff --git a/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-validate.ts b/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-validate.ts index 7646b59299..7be25123c4 100644 --- a/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-validate.ts +++ b/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-validate.ts @@ -3,7 +3,7 @@ import { applicationEntityBuilder } from './entities/application'; import { type EntityIdWithLocation, type ManifestWithoutSources, -} from './entities/entity.interface'; +} from '@/cli/utilities/build/manifest/entities/entity-interface'; import { frontComponentEntityBuilder } from './entities/front-component'; import { functionEntityBuilder } from './entities/function'; import { objectEntityBuilder } from './entities/object'; @@ -13,7 +13,7 @@ import { type ValidationError, type ValidationResult, type ValidationWarning, -} from './manifest.types'; +} from '@/cli/utilities/build/manifest/manifest-types'; const collectAllDuplicates = ( manifest: ManifestWithoutSources, @@ -39,7 +39,10 @@ export const validateManifest = ( errors, ); objectEntityBuilder.validate(manifest.objects ?? [], errors); - objectExtensionEntityBuilder.validate(manifest.objectExtensions ?? [], errors); + objectExtensionEntityBuilder.validate( + manifest.objectExtensions ?? [], + errors, + ); functionEntityBuilder.validate(manifest.functions ?? [], errors); roleEntityBuilder.validate(manifest.roles ?? [], errors); frontComponentEntityBuilder.validate(manifest.frontComponents ?? [], errors); diff --git a/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-watcher.ts b/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-watcher.ts index 3f58073e98..c7de5d7de0 100644 --- a/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-watcher.ts +++ b/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-watcher.ts @@ -1,7 +1,10 @@ import chokidar, { type FSWatcher } from 'chokidar'; import path from 'path'; -import { createLogger } from '../common/logger'; -import { runManifestBuild, type ManifestBuildResult } from './manifest-build'; +import { createLogger } from '@/cli/utilities/build/common/logger'; +import { + type ManifestBuildResult, + runManifestBuild, +} from '@/cli/utilities/build/manifest/manifest-build'; const logger = createLogger('manifest-watch'); @@ -30,7 +33,8 @@ export class ManifestWatcher { '**/node_modules/**', '**/.twenty/**', '**/dist/**', - (filePath: string) => filePath.includes('/.twenty/') || filePath.includes('\\.twenty\\'), + (filePath: string) => + filePath.includes('/.twenty/') || filePath.includes('\\.twenty\\'), ], ignoreInitial: true, awaitWriteFinish: { diff --git a/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-writer.ts b/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-writer.ts index bdfac2c23e..50ccfa32a0 100644 --- a/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-writer.ts +++ b/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-writer.ts @@ -1,8 +1,7 @@ import * as fs from 'fs-extra'; import path from 'path'; import { type ApplicationManifest } from 'twenty-shared/application'; - -import { OUTPUT_DIR } from '../common/constants'; +import { OUTPUT_DIR } from '@/cli/utilities/build/common/constants'; export const writeManifestToOutput = async ( appPath: string, diff --git a/packages/twenty-sdk/src/cli/utilities/generate/services/generate.service.ts b/packages/twenty-sdk/src/cli/utilities/client/client-service.ts similarity index 94% rename from packages/twenty-sdk/src/cli/utilities/generate/services/generate.service.ts rename to packages/twenty-sdk/src/cli/utilities/client/client-service.ts index be46d7ba38..1316f2ae2f 100644 --- a/packages/twenty-sdk/src/cli/utilities/generate/services/generate.service.ts +++ b/packages/twenty-sdk/src/cli/utilities/client/client-service.ts @@ -1,5 +1,5 @@ -import { ApiService } from '@/cli/utilities/api/services/api.service'; -import { ConfigService } from '@/cli/utilities/config/services/config.service'; +import { ApiService } from '@/cli/utilities/api/api-service'; +import { ConfigService } from '@/cli/utilities/config/config-service'; import { generate } from '@genql/cli'; import chalk from 'chalk'; import * as fs from 'fs-extra'; @@ -11,7 +11,7 @@ import { export const GENERATED_FOLDER_NAME = 'generated'; -export class GenerateService { +export class ClientService { private configService: ConfigService; private apiService: ApiService; @@ -20,7 +20,7 @@ export class GenerateService { this.apiService = new ApiService(); } - async generateClient(appPath: string): Promise { + async generate(appPath: string): Promise { const outputPath = join(appPath, GENERATED_FOLDER_NAME); console.log(chalk.blue('📦 Generating Twenty client...')); diff --git a/packages/twenty-sdk/src/cli/utilities/config/services/config.service.ts b/packages/twenty-sdk/src/cli/utilities/config/config-service.ts similarity index 100% rename from packages/twenty-sdk/src/cli/utilities/config/services/config.service.ts rename to packages/twenty-sdk/src/cli/utilities/config/config-service.ts diff --git a/packages/twenty-sdk/src/cli/utilities/config/constants/current-execution-directory.ts b/packages/twenty-sdk/src/cli/utilities/config/current-execution-directory.ts similarity index 100% rename from packages/twenty-sdk/src/cli/utilities/config/constants/current-execution-directory.ts rename to packages/twenty-sdk/src/cli/utilities/config/current-execution-directory.ts diff --git a/packages/twenty-sdk/src/cli/utilities/entity/utils/__tests__/convert-to-label.spec.ts b/packages/twenty-sdk/src/cli/utilities/entity/__tests__/convert-to-label.spec.ts similarity index 81% rename from packages/twenty-sdk/src/cli/utilities/entity/utils/__tests__/convert-to-label.spec.ts rename to packages/twenty-sdk/src/cli/utilities/entity/__tests__/convert-to-label.spec.ts index 9cca183267..b676439fb1 100644 --- a/packages/twenty-sdk/src/cli/utilities/entity/utils/__tests__/convert-to-label.spec.ts +++ b/packages/twenty-sdk/src/cli/utilities/entity/__tests__/convert-to-label.spec.ts @@ -1,4 +1,4 @@ -import { convertToLabel } from '@/cli/utilities/entity/utils/entity-label'; +import { convertToLabel } from '@/cli/utilities/entity/entity-label'; describe('convertToLabel', () => { it('should convert to label', () => { diff --git a/packages/twenty-sdk/src/cli/utilities/entity/utils/__tests__/get-front-component-base-file.spec.ts b/packages/twenty-sdk/src/cli/utilities/entity/__tests__/get-front-component-base-file.spec.ts similarity index 97% rename from packages/twenty-sdk/src/cli/utilities/entity/utils/__tests__/get-front-component-base-file.spec.ts rename to packages/twenty-sdk/src/cli/utilities/entity/__tests__/get-front-component-base-file.spec.ts index aca1faa8a8..9fdaff6bf7 100644 --- a/packages/twenty-sdk/src/cli/utilities/entity/utils/__tests__/get-front-component-base-file.spec.ts +++ b/packages/twenty-sdk/src/cli/utilities/entity/__tests__/get-front-component-base-file.spec.ts @@ -1,4 +1,4 @@ -import { getFrontComponentBaseFile } from '@/cli/utilities/entity/utils/entity-front-component-template'; +import { getFrontComponentBaseFile } from '@/cli/utilities/entity/entity-front-component-template'; describe('getFrontComponentBaseFile', () => { it('should render proper file using defineFrontComponent', () => { diff --git a/packages/twenty-sdk/src/cli/utilities/entity/utils/__tests__/get-function-base-file.spec.ts b/packages/twenty-sdk/src/cli/utilities/entity/__tests__/get-function-base-file.spec.ts similarity index 95% rename from packages/twenty-sdk/src/cli/utilities/entity/utils/__tests__/get-function-base-file.spec.ts rename to packages/twenty-sdk/src/cli/utilities/entity/__tests__/get-function-base-file.spec.ts index c901d7790f..e5413efa7e 100644 --- a/packages/twenty-sdk/src/cli/utilities/entity/utils/__tests__/get-function-base-file.spec.ts +++ b/packages/twenty-sdk/src/cli/utilities/entity/__tests__/get-function-base-file.spec.ts @@ -1,4 +1,4 @@ -import { getFunctionBaseFile } from '@/cli/utilities/entity/utils/entity-function-template'; +import { getFunctionBaseFile } from '@/cli/utilities/entity/entity-function-template'; describe('getFunctionBaseFile', () => { it('should render proper file using defineFunction', () => { diff --git a/packages/twenty-sdk/src/cli/utilities/entity/utils/__tests__/get-new-object-file-content.spec.ts b/packages/twenty-sdk/src/cli/utilities/entity/__tests__/get-new-object-file-content.spec.ts similarity index 98% rename from packages/twenty-sdk/src/cli/utilities/entity/utils/__tests__/get-new-object-file-content.spec.ts rename to packages/twenty-sdk/src/cli/utilities/entity/__tests__/get-new-object-file-content.spec.ts index 99c01dd6b2..1ac7ebf4c7 100644 --- a/packages/twenty-sdk/src/cli/utilities/entity/utils/__tests__/get-new-object-file-content.spec.ts +++ b/packages/twenty-sdk/src/cli/utilities/entity/__tests__/get-new-object-file-content.spec.ts @@ -1,4 +1,4 @@ -import { getNewObjectFileContent } from '@/cli/utilities/entity/utils/entity-object-template'; +import { getNewObjectFileContent } from '@/cli/utilities/entity/entity-object-template'; describe('getNewObjectFileContent', () => { it('should return proper object file using defineObject', () => { diff --git a/packages/twenty-sdk/src/cli/utilities/entity/utils/__tests__/get-role-base-file.spec.ts b/packages/twenty-sdk/src/cli/utilities/entity/__tests__/get-role-base-file.spec.ts similarity index 86% rename from packages/twenty-sdk/src/cli/utilities/entity/utils/__tests__/get-role-base-file.spec.ts rename to packages/twenty-sdk/src/cli/utilities/entity/__tests__/get-role-base-file.spec.ts index f5ae797ab5..1377c271d7 100644 --- a/packages/twenty-sdk/src/cli/utilities/entity/utils/__tests__/get-role-base-file.spec.ts +++ b/packages/twenty-sdk/src/cli/utilities/entity/__tests__/get-role-base-file.spec.ts @@ -1,4 +1,4 @@ -import { getRoleBaseFile } from '@/cli/utilities/entity/utils/entity-role-template'; +import { getRoleBaseFile } from '@/cli/utilities/entity/entity-role-template'; describe('getRoleBaseFile', () => { it('should render proper file using defineRole', () => { @@ -11,11 +11,9 @@ describe('getRoleBaseFile', () => { expect(result).toContain('export default defineRole({'); expect(result).toContain( - "universalIdentifier: MY_ROLE_ROLE_UNIVERSAL_IDENTIFIER", - ); - expect(result).toContain( - "'71e45a58-41da-4ae4-8b73-a543c0a9d3d4'", + 'universalIdentifier: MY_ROLE_ROLE_UNIVERSAL_IDENTIFIER', ); + expect(result).toContain("'71e45a58-41da-4ae4-8b73-a543c0a9d3d4'"); expect(result).toContain("label: 'my-role'"); expect(result).toContain("description: 'Add a description for your role'"); @@ -48,7 +46,9 @@ describe('getRoleBaseFile', () => { name: 'admin-access', }); - expect(result).toContain('export const ADMIN_ACCESS_ROLE_UNIVERSAL_IDENTIFIER'); + expect(result).toContain( + 'export const ADMIN_ACCESS_ROLE_UNIVERSAL_IDENTIFIER', + ); expect(result).toContain( 'universalIdentifier: ADMIN_ACCESS_ROLE_UNIVERSAL_IDENTIFIER', ); diff --git a/packages/twenty-sdk/src/cli/utilities/entity/utils/entity-front-component-template.ts b/packages/twenty-sdk/src/cli/utilities/entity/entity-front-component-template.ts similarity index 100% rename from packages/twenty-sdk/src/cli/utilities/entity/utils/entity-front-component-template.ts rename to packages/twenty-sdk/src/cli/utilities/entity/entity-front-component-template.ts diff --git a/packages/twenty-sdk/src/cli/utilities/entity/utils/entity-function-template.ts b/packages/twenty-sdk/src/cli/utilities/entity/entity-function-template.ts similarity index 100% rename from packages/twenty-sdk/src/cli/utilities/entity/utils/entity-function-template.ts rename to packages/twenty-sdk/src/cli/utilities/entity/entity-function-template.ts diff --git a/packages/twenty-sdk/src/cli/utilities/entity/utils/entity-label.ts b/packages/twenty-sdk/src/cli/utilities/entity/entity-label.ts similarity index 100% rename from packages/twenty-sdk/src/cli/utilities/entity/utils/entity-label.ts rename to packages/twenty-sdk/src/cli/utilities/entity/entity-label.ts diff --git a/packages/twenty-sdk/src/cli/utilities/entity/utils/entity-object-template.ts b/packages/twenty-sdk/src/cli/utilities/entity/entity-object-template.ts similarity index 100% rename from packages/twenty-sdk/src/cli/utilities/entity/utils/entity-object-template.ts rename to packages/twenty-sdk/src/cli/utilities/entity/entity-object-template.ts diff --git a/packages/twenty-sdk/src/cli/utilities/entity/utils/entity-role-template.ts b/packages/twenty-sdk/src/cli/utilities/entity/entity-role-template.ts similarity index 100% rename from packages/twenty-sdk/src/cli/utilities/entity/utils/entity-role-template.ts rename to packages/twenty-sdk/src/cli/utilities/entity/entity-role-template.ts diff --git a/packages/twenty-sdk/src/cli/utilities/file/utils/file-find.ts b/packages/twenty-sdk/src/cli/utilities/file/file-find.ts similarity index 100% rename from packages/twenty-sdk/src/cli/utilities/file/utils/file-find.ts rename to packages/twenty-sdk/src/cli/utilities/file/file-find.ts diff --git a/packages/twenty-sdk/src/cli/utilities/file/utils/file-jsonc.ts b/packages/twenty-sdk/src/cli/utilities/file/file-jsonc.ts similarity index 81% rename from packages/twenty-sdk/src/cli/utilities/file/utils/file-jsonc.ts rename to packages/twenty-sdk/src/cli/utilities/file/file-jsonc.ts index 1b3407e76f..41e170271d 100644 --- a/packages/twenty-sdk/src/cli/utilities/file/utils/file-jsonc.ts +++ b/packages/twenty-sdk/src/cli/utilities/file/file-jsonc.ts @@ -43,10 +43,6 @@ export const parseJsoncString = ( return result; }; -export const parseTextFile = async (filePath: string) => { - return await fs.readFile(filePath, 'utf8'); -}; - export const parseJsoncFile = async ( filePath: string, options: JsoncParseOptions = {}, @@ -61,12 +57,3 @@ export const parseJsoncFile = async ( throw new Error(`Failed to read file ${filePath}: ${error}`); } }; - -export const writeJsoncFile = async ( - filePath: string, - data: any, - options: { spaces?: number } = {}, -): Promise => { - const content = JSON.stringify(data, null, options.spaces ?? 2); - await fs.writeFile(filePath, content, 'utf8'); -}; diff --git a/packages/twenty-sdk/src/cli/utilities/file/file-path.ts b/packages/twenty-sdk/src/cli/utilities/file/file-path.ts new file mode 100644 index 0000000000..44d28e2534 --- /dev/null +++ b/packages/twenty-sdk/src/cli/utilities/file/file-path.ts @@ -0,0 +1,8 @@ +import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/utilities/config/current-execution-directory'; +import { join } from 'path'; + +export const formatPath = (appPath?: string) => { + return appPath && !appPath?.startsWith('/') + ? join(CURRENT_EXECUTION_DIRECTORY, appPath) + : appPath; +}; diff --git a/packages/twenty-sdk/src/cli/utilities/file/utils/file-tarball.ts b/packages/twenty-sdk/src/cli/utilities/file/file-tarball.ts similarity index 100% rename from packages/twenty-sdk/src/cli/utilities/file/utils/file-tarball.ts rename to packages/twenty-sdk/src/cli/utilities/file/file-tarball.ts diff --git a/packages/twenty-sdk/src/cli/utilities/file/file-uploader.ts b/packages/twenty-sdk/src/cli/utilities/file/file-uploader.ts new file mode 100644 index 0000000000..ea31b860b4 --- /dev/null +++ b/packages/twenty-sdk/src/cli/utilities/file/file-uploader.ts @@ -0,0 +1,64 @@ +import { ApiService } from '@/cli/utilities/api/api-service'; +import path from 'path'; +import { OUTPUT_DIR } from '@/cli/utilities/build/common/constants'; +import { FileFolder } from 'twenty-shared/types'; +import { createLogger } from '@/cli/utilities/build/common/logger'; +import { type ApplicationManifest } from 'twenty-shared/application'; + +export class FileUploader { + private apiService = new ApiService(); + private applicationUniversalIdentifier: string; + private appPath: string; + private logger = createLogger('file-upload'); + + constructor(options: { + applicationUniversalIdentifier: string; + appPath: string; + }) { + this.applicationUniversalIdentifier = + options.applicationUniversalIdentifier; + this.appPath = options.appPath; + } + + async uploadFile({ + builtPath, + fileFolder, + }: { + builtPath: string; + fileFolder: FileFolder; + }) { + const uploadResult = await this.apiService.uploadFile({ + filePath: path.join(this.appPath, OUTPUT_DIR, builtPath), + builtHandlerPath: builtPath, + fileFolder, + applicationUniversalIdentifier: this.applicationUniversalIdentifier, + }); + + if (uploadResult.success) { + this.logger.success(`☁️ Uploaded ${builtPath}`); + } else { + this.logger.error( + `Failed to upload ${builtPath} -- ${uploadResult.error}`, + ); + } + } + + async uploadManifestBuiltFiles(manifest: ApplicationManifest) { + const uploadPromises = [ + ...manifest.functions.map((builtFile) => + this.uploadFile({ + builtPath: builtFile.builtHandlerPath, + fileFolder: FileFolder.BuiltFunction, + }), + ), + ...manifest.frontComponents.map((builtFile) => + this.uploadFile({ + builtPath: builtFile.builtComponentPath, + fileFolder: FileFolder.BuiltFrontComponent, + }), + ), + ]; + + await Promise.all(uploadPromises); + } +} diff --git a/packages/twenty-sdk/src/cli/utilities/file/utils/file-env.ts b/packages/twenty-sdk/src/cli/utilities/file/utils/file-env.ts deleted file mode 100644 index a2b02d9b84..0000000000 --- a/packages/twenty-sdk/src/cli/utilities/file/utils/file-env.ts +++ /dev/null @@ -1,17 +0,0 @@ -import * as fs from 'fs-extra'; -import dotenv from 'dotenv'; -import { findPathFile } from './file-find'; - -export const loadEnvVariables = async (appPath: string) => { - let envFile = ''; - - try { - const envFilePath = await findPathFile(appPath, '.env'); - - envFile = await fs.readFile(envFilePath, 'utf8'); - } catch { - // Allow missing .env - } - - return dotenv.parse(envFile); -}; diff --git a/packages/twenty-sdk/src/cli/utilities/file/utils/file-path.ts b/packages/twenty-sdk/src/cli/utilities/file/utils/file-path.ts deleted file mode 100644 index 2f45c53f87..0000000000 --- a/packages/twenty-sdk/src/cli/utilities/file/utils/file-path.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { CURRENT_EXECUTION_DIRECTORY } from '@/cli/utilities/config/constants/current-execution-directory'; -import { join, posix, relative, sep } from 'path'; - -export const formatPath = (appPath?: string) => { - return appPath && !appPath?.startsWith('/') - ? join(CURRENT_EXECUTION_DIRECTORY, appPath) - : appPath; -}; - -export const toPosixRelative = (filepath: string, basePath: string): string => { - const rel = relative(basePath, filepath); - return rel.split(sep).join(posix.sep); -}; diff --git a/packages/twenty-sdk/src/cli/utilities/typescript/utils/typescript-diagnostics.ts b/packages/twenty-sdk/src/cli/utilities/typescript/typescript-diagnostics.ts similarity index 86% rename from packages/twenty-sdk/src/cli/utilities/typescript/utils/typescript-diagnostics.ts rename to packages/twenty-sdk/src/cli/utilities/typescript/typescript-diagnostics.ts index a0ca520457..303116eb17 100644 --- a/packages/twenty-sdk/src/cli/utilities/typescript/utils/typescript-diagnostics.ts +++ b/packages/twenty-sdk/src/cli/utilities/typescript/typescript-diagnostics.ts @@ -1,7 +1,7 @@ import { - type Diagnostic, - formatDiagnosticsWithColorAndContext, - sys, + type Diagnostic, + formatDiagnosticsWithColorAndContext, + sys, } from 'typescript'; export const formatAndWarnTsDiagnostics = ({ diff --git a/packages/twenty-sdk/src/cli/utilities/typescript/utils/typescript-program.ts b/packages/twenty-sdk/src/cli/utilities/typescript/typescript-program.ts similarity index 100% rename from packages/twenty-sdk/src/cli/utilities/typescript/utils/typescript-program.ts rename to packages/twenty-sdk/src/cli/utilities/typescript/typescript-program.ts diff --git a/packages/twenty-sdk/vitest.integration.config.ts b/packages/twenty-sdk/vitest.integration.config.ts index 455faf2752..624085a617 100644 --- a/packages/twenty-sdk/vitest.integration.config.ts +++ b/packages/twenty-sdk/vitest.integration.config.ts @@ -17,5 +17,6 @@ export default defineConfig({ diff: { truncateThreshold: 0, }, + fileParallelism: false, }, }); diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/enum-types/composite-field-metadata-gql-enum-type.generator.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/enum-types/composite-field-metadata-gql-enum-type.generator.ts index 15b89cb7e4..5a22adc467 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/enum-types/composite-field-metadata-gql-enum-type.generator.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/enum-types/composite-field-metadata-gql-enum-type.generator.ts @@ -6,6 +6,7 @@ import { type CompositeProperty, type CompositeType, } from 'twenty-shared/types'; +import { pascalCase } from 'twenty-shared/utils'; import { GqlTypesStorage } from 'src/engine/api/graphql/workspace-schema-builder/storages/gql-types.storage'; import { computeCompositeFieldEnumTypeKey } from 'src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-composite-field-enum-type-key.util'; @@ -14,7 +15,6 @@ import { type FieldMetadataDefaultOption, } from 'src/engine/metadata-modules/field-metadata/dtos/options.input'; import { isEnumFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-enum-field-metadata-type.util'; -import { pascalCase } from 'src/utils/pascal-case'; @Injectable() export class CompositeFieldMetadataGqlEnumTypeGenerator { diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/enum-types/enum-field-metadata-gql-enum-type.generator.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/enum-types/enum-field-metadata-gql-enum-type.generator.ts index 70ca1bc31e..09da5a293b 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/enum-types/enum-field-metadata-gql-enum-type.generator.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/enum-types/enum-field-metadata-gql-enum-type.generator.ts @@ -1,7 +1,7 @@ import { Injectable, Logger } from '@nestjs/common'; import { GraphQLEnumType } from 'graphql'; -import { isDefined } from 'twenty-shared/utils'; +import { isDefined, pascalCase } from 'twenty-shared/utils'; import { GqlTypesStorage } from 'src/engine/api/graphql/workspace-schema-builder/storages/gql-types.storage'; import { computeEnumFieldGqlTypeKey } from 'src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-enum-field-gql-type-key.util'; @@ -13,7 +13,6 @@ import { isEnumFieldMetadataType } from 'src/engine/metadata-modules/field-metad import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; import { transformEnumValue } from 'src/engine/utils/transform-enum-value'; -import { pascalCase } from 'src/utils/pascal-case'; @Injectable() export class EnumFieldMetadataGqlEnumTypeGenerator { diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/create-input/composite-field-metadata-create-gql-input-type.generator.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/create-input/composite-field-metadata-create-gql-input-type.generator.ts index f2fa527dec..537ec686cc 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/create-input/composite-field-metadata-create-gql-input-type.generator.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/create-input/composite-field-metadata-create-gql-input-type.generator.ts @@ -6,7 +6,7 @@ import { isObjectType, } from 'graphql'; import { CompositeType } from 'twenty-shared/types'; -import { isDefined } from 'twenty-shared/utils'; +import { isDefined, pascalCase } from 'twenty-shared/utils'; import { GqlInputTypeDefinitionKind } from 'src/engine/api/graphql/workspace-schema-builder/enums/gql-input-type-definition-kind.enum'; import { TypeMapperService } from 'src/engine/api/graphql/workspace-schema-builder/services/type-mapper.service'; @@ -16,7 +16,6 @@ import { computeCompositeFieldEnumTypeKey } from 'src/engine/api/graphql/workspa import { computeCompositeFieldInputTypeKey } from 'src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-composite-field-input-type-key.util'; import { isEnumFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-enum-field-metadata-type.util'; import { isMorphOrRelationFieldMetadataType } from 'src/engine/utils/is-morph-or-relation-field-metadata-type.util'; -import { pascalCase } from 'src/utils/pascal-case'; @Injectable() export class CompositeFieldMetadataCreateGqlInputTypeGenerator { diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/create-input/object-metadata-create-gql-input-type.generator.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/create-input/object-metadata-create-gql-input-type.generator.ts index 23f755aa7c..3a2a9d4f8f 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/create-input/object-metadata-create-gql-input-type.generator.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/create-input/object-metadata-create-gql-input-type.generator.ts @@ -7,7 +7,7 @@ import { isInputObjectType, isObjectType, } from 'graphql'; -import { isDefined } from 'twenty-shared/utils'; +import { isDefined, pascalCase } from 'twenty-shared/utils'; import { GqlInputTypeDefinitionKind } from 'src/engine/api/graphql/workspace-schema-builder/enums/gql-input-type-definition-kind.enum'; import { RelationFieldMetadataGqlInputTypeGenerator } from 'src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/relation-field-metadata-gql-type.generator'; @@ -26,7 +26,6 @@ import { isEnumFieldMetadataType } from 'src/engine/metadata-modules/field-metad import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util'; import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; -import { pascalCase } from 'src/utils/pascal-case'; @Injectable() export class ObjectMetadataCreateGqlInputTypeGenerator { diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/filter-input/composite-field-metadata-filter-gql-input-types.generator.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/filter-input/composite-field-metadata-filter-gql-input-types.generator.ts index 421fddbae5..6c8735eb21 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/filter-input/composite-field-metadata-filter-gql-input-types.generator.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/filter-input/composite-field-metadata-filter-gql-input-types.generator.ts @@ -7,7 +7,7 @@ import { isEnumType, isObjectType, } from 'graphql'; -import { isDefined } from 'twenty-shared/utils'; +import { isDefined, pascalCase } from 'twenty-shared/utils'; import { CompositeType } from 'twenty-shared/types'; import { GqlInputTypeDefinitionKind } from 'src/engine/api/graphql/workspace-schema-builder/enums/gql-input-type-definition-kind.enum'; @@ -19,7 +19,6 @@ import { computeCompositeFieldInputTypeKey } from 'src/engine/api/graphql/worksp import { createGqlEnumFilterType } from 'src/engine/api/graphql/workspace-schema-builder/utils/create-gql-enum-filter-type.util'; import { isEnumFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-enum-field-metadata-type.util'; import { isMorphOrRelationFieldMetadataType } from 'src/engine/utils/is-morph-or-relation-field-metadata-type.util'; -import { pascalCase } from 'src/utils/pascal-case'; @Injectable() export class CompositeFieldMetadataFilterGqlInputTypeGenerator { diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/filter-input/object-metadata-filter-gql-input-type.generator.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/filter-input/object-metadata-filter-gql-input-type.generator.ts index 65248d0580..f418ccf0de 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/filter-input/object-metadata-filter-gql-input-type.generator.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/filter-input/object-metadata-filter-gql-input-type.generator.ts @@ -7,7 +7,7 @@ import { isInputObjectType, isObjectType, } from 'graphql'; -import { isDefined } from 'twenty-shared/utils'; +import { isDefined, pascalCase } from 'twenty-shared/utils'; import { GqlInputTypeDefinitionKind } from 'src/engine/api/graphql/workspace-schema-builder/enums/gql-input-type-definition-kind.enum'; import { RelationFieldMetadataGqlInputTypeGenerator } from 'src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/relation-field-metadata-gql-type.generator'; @@ -26,7 +26,6 @@ import { isEnumFieldMetadataType } from 'src/engine/metadata-modules/field-metad import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util'; import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; -import { pascalCase } from 'src/utils/pascal-case'; @Injectable() export class ObjectMetadataFilterGqlInputTypeGenerator { diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/group-by-input/composite-field-metadata-group-by-gql-input-type.generator.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/group-by-input/composite-field-metadata-group-by-gql-input-type.generator.ts index 4671e1cd7c..2c15d65993 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/group-by-input/composite-field-metadata-group-by-gql-input-type.generator.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/group-by-input/composite-field-metadata-group-by-gql-input-type.generator.ts @@ -6,13 +6,13 @@ import { GraphQLInputObjectType, } from 'graphql'; import { CompositeType } from 'twenty-shared/types'; +import { pascalCase } from 'twenty-shared/utils'; import { GqlInputTypeDefinitionKind } from 'src/engine/api/graphql/workspace-schema-builder/enums/gql-input-type-definition-kind.enum'; import { TypeMapperService } from 'src/engine/api/graphql/workspace-schema-builder/services/type-mapper.service'; import { GqlTypesStorage } from 'src/engine/api/graphql/workspace-schema-builder/storages/gql-types.storage'; import { computeCompositeFieldInputTypeKey } from 'src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-composite-field-input-type-key.util'; import { isMorphOrRelationFieldMetadataType } from 'src/engine/utils/is-morph-or-relation-field-metadata-type.util'; -import { pascalCase } from 'src/utils/pascal-case'; @Injectable() export class CompositeFieldMetadataGroupByGqlInputTypeGenerator { diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/group-by-input/object-metadata-group-by-gql-input-type.generator.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/group-by-input/object-metadata-group-by-gql-input-type.generator.ts index c4171ed49a..c5d1559afd 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/group-by-input/object-metadata-group-by-gql-input-type.generator.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/group-by-input/object-metadata-group-by-gql-input-type.generator.ts @@ -9,7 +9,7 @@ import { isInputObjectType, } from 'graphql'; import { FieldMetadataType } from 'twenty-shared/types'; -import { isDefined } from 'twenty-shared/utils'; +import { isDefined, pascalCase } from 'twenty-shared/utils'; import { GqlInputTypeDefinitionKind } from 'src/engine/api/graphql/workspace-schema-builder/enums/gql-input-type-definition-kind.enum'; import { GROUP_BY_DATE_GRANULARITY_INPUT_KEY } from 'src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/group-by-input/group-by-date-granularity-gql-input-type.generator'; @@ -23,7 +23,6 @@ import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field- import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util'; import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; -import { pascalCase } from 'src/utils/pascal-case'; @Injectable() export class ObjectMetadataGroupByGqlInputTypeGenerator { diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/order-by-input/composite-field-metadata-order-by-gql-input-type.generator.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/order-by-input/composite-field-metadata-order-by-gql-input-type.generator.ts index 601e154143..26167312ee 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/order-by-input/composite-field-metadata-order-by-gql-input-type.generator.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/order-by-input/composite-field-metadata-order-by-gql-input-type.generator.ts @@ -5,7 +5,7 @@ import { GraphQLInputObjectType, isObjectType, } from 'graphql'; -import { isDefined } from 'twenty-shared/utils'; +import { isDefined, pascalCase } from 'twenty-shared/utils'; import { CompositeType } from 'twenty-shared/types'; import { GqlInputTypeDefinitionKind } from 'src/engine/api/graphql/workspace-schema-builder/enums/gql-input-type-definition-kind.enum'; @@ -14,7 +14,6 @@ import { GqlTypesStorage } from 'src/engine/api/graphql/workspace-schema-builder import { computeCompositeFieldTypeOptions } from 'src/engine/api/graphql/workspace-schema-builder/utils/compute-composite-field-type-options.util'; import { computeCompositeFieldInputTypeKey } from 'src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-composite-field-input-type-key.util'; import { isMorphOrRelationFieldMetadataType } from 'src/engine/utils/is-morph-or-relation-field-metadata-type.util'; -import { pascalCase } from 'src/utils/pascal-case'; @Injectable() export class CompositeFieldMetadataOrderByGqlInputTypeGenerator { diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/order-by-input/object-metadata-order-by-gql-input-type.generator.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/order-by-input/object-metadata-order-by-gql-input-type.generator.ts index e2582860c6..8d1933b97f 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/order-by-input/object-metadata-order-by-gql-input-type.generator.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/order-by-input/object-metadata-order-by-gql-input-type.generator.ts @@ -1,6 +1,7 @@ import { Injectable, Logger } from '@nestjs/common'; import { GraphQLInputObjectType } from 'graphql'; +import { pascalCase } from 'twenty-shared/utils'; import { GqlInputTypeDefinitionKind } from 'src/engine/api/graphql/workspace-schema-builder/enums/gql-input-type-definition-kind.enum'; import { ObjectMetadataOrderByBaseGenerator } from 'src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/order-by-input/object-metadata-order-by-base.generator'; @@ -9,7 +10,6 @@ import { type SchemaGenerationContext } from 'src/engine/api/graphql/workspace-s import { computeObjectMetadataInputTypeKey } from 'src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-object-metadata-input-type.util'; import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; -import { pascalCase } from 'src/utils/pascal-case'; @Injectable() export class ObjectMetadataOrderByGqlInputTypeGenerator { diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/order-by-input/object-metadata-order-by-with-group-by-gql-input-type.generator.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/order-by-input/object-metadata-order-by-with-group-by-gql-input-type.generator.ts index 54515a1c5e..31329a20a5 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/order-by-input/object-metadata-order-by-with-group-by-gql-input-type.generator.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/order-by-input/object-metadata-order-by-with-group-by-gql-input-type.generator.ts @@ -5,7 +5,7 @@ import { GraphQLInputObjectType, isInputObjectType, } from 'graphql'; -import { isDefined } from 'twenty-shared/utils'; +import { isDefined, pascalCase } from 'twenty-shared/utils'; import { GqlInputTypeDefinitionKind } from 'src/engine/api/graphql/workspace-schema-builder/enums/gql-input-type-definition-kind.enum'; import { ObjectMetadataOrderByBaseGenerator } from 'src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/order-by-input/object-metadata-order-by-base.generator'; @@ -24,7 +24,6 @@ import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field- import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util'; import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; -import { pascalCase } from 'src/utils/pascal-case'; @Injectable() export class ObjectMetadataOrderByWithGroupByGqlInputTypeGenerator { diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/relation-connect-gql-input-type.generator.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/relation-connect-gql-input-type.generator.ts index 7fed0223ff..46fb87b641 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/relation-connect-gql-input-type.generator.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/relation-connect-gql-input-type.generator.ts @@ -9,7 +9,11 @@ import { } from 'graphql'; import { RELATION_NESTED_QUERY_KEYWORDS } from 'twenty-shared/constants'; import { compositeTypeDefinitions } from 'twenty-shared/types'; -import { getUniqueConstraintsFields, isDefined } from 'twenty-shared/utils'; +import { + getUniqueConstraintsFields, + isDefined, + pascalCase, +} from 'twenty-shared/utils'; import { TypeMapperService } from 'src/engine/api/graphql/workspace-schema-builder/services/type-mapper.service'; import { GqlTypesStorage } from 'src/engine/api/graphql/workspace-schema-builder/storages/gql-types.storage'; @@ -18,7 +22,6 @@ import { computeRelationConnectInputTypeKey } from 'src/engine/api/graphql/works import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util'; import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; -import { pascalCase } from 'src/utils/pascal-case'; @Injectable() export class RelationConnectGqlInputTypeGenerator { diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/update-input/composite-field-metadata-update-gql-input-type.generator.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/update-input/composite-field-metadata-update-gql-input-type.generator.ts index 2ddea5c472..1ee4128a04 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/update-input/composite-field-metadata-update-gql-input-type.generator.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/update-input/composite-field-metadata-update-gql-input-type.generator.ts @@ -6,7 +6,7 @@ import { isObjectType, } from 'graphql'; import { CompositeType } from 'twenty-shared/types'; -import { isDefined } from 'twenty-shared/utils'; +import { isDefined, pascalCase } from 'twenty-shared/utils'; import { GqlInputTypeDefinitionKind } from 'src/engine/api/graphql/workspace-schema-builder/enums/gql-input-type-definition-kind.enum'; import { TypeMapperService } from 'src/engine/api/graphql/workspace-schema-builder/services/type-mapper.service'; @@ -16,7 +16,6 @@ import { computeCompositeFieldEnumTypeKey } from 'src/engine/api/graphql/workspa import { computeCompositeFieldInputTypeKey } from 'src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-composite-field-input-type-key.util'; import { isEnumFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-enum-field-metadata-type.util'; import { isMorphOrRelationFieldMetadataType } from 'src/engine/utils/is-morph-or-relation-field-metadata-type.util'; -import { pascalCase } from 'src/utils/pascal-case'; @Injectable() export class CompositeFieldMetadataUpdateGqlInputTypeGenerator { diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/update-input/object-metadata-update-gql-input-type.generator.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/update-input/object-metadata-update-gql-input-type.generator.ts index f5ee682d22..3ee9ecd67c 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/update-input/object-metadata-update-gql-input-type.generator.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/update-input/object-metadata-update-gql-input-type.generator.ts @@ -11,7 +11,7 @@ import { isObjectType, type GraphQLInputType, } from 'graphql'; -import { isDefined } from 'twenty-shared/utils'; +import { isDefined, pascalCase } from 'twenty-shared/utils'; import { GqlInputTypeDefinitionKind } from 'src/engine/api/graphql/workspace-schema-builder/enums/gql-input-type-definition-kind.enum'; import { RelationFieldMetadataGqlInputTypeGenerator } from 'src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/input-types/relation-field-metadata-gql-type.generator'; @@ -27,7 +27,6 @@ import { isEnumFieldMetadataType } from 'src/engine/metadata-modules/field-metad import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util'; import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; -import { pascalCase } from 'src/utils/pascal-case'; @Injectable() export class ObjectMetadataUpdateGqlInputTypeGenerator { diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/object-types/composite-field-metadata-gql-object-type.generator.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/object-types/composite-field-metadata-gql-object-type.generator.ts index f1ad5622c6..a1c5cf6d95 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/object-types/composite-field-metadata-gql-object-type.generator.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/object-types/composite-field-metadata-gql-object-type.generator.ts @@ -2,7 +2,7 @@ import { Injectable, Logger } from '@nestjs/common'; import { GraphQLObjectType, isInputObjectType } from 'graphql'; import { FieldMetadataType, type CompositeType } from 'twenty-shared/types'; -import { isDefined } from 'twenty-shared/utils'; +import { isDefined, pascalCase } from 'twenty-shared/utils'; import { ObjectTypeDefinitionKind } from 'src/engine/api/graphql/workspace-schema-builder/enums/object-type-definition-kind.enum'; import { TypeMapperService } from 'src/engine/api/graphql/workspace-schema-builder/services/type-mapper.service'; @@ -12,7 +12,6 @@ import { computeCompositeFieldEnumTypeKey } from 'src/engine/api/graphql/workspa import { computeCompositeFieldObjectTypeKey } from 'src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-composite-field-object-type-key.util'; import { isEnumFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-enum-field-metadata-type.util'; import { isMorphOrRelationFieldMetadataType } from 'src/engine/utils/is-morph-or-relation-field-metadata-type.util'; -import { pascalCase } from 'src/utils/pascal-case'; @Injectable() export class CompositeFieldMetadataGqlObjectTypeGenerator { diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/object-types/connection-gql-object-type.generator.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/object-types/connection-gql-object-type.generator.ts index bf6cd3fdc1..d6e96d1a01 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/object-types/connection-gql-object-type.generator.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/object-types/connection-gql-object-type.generator.ts @@ -1,7 +1,7 @@ import { Injectable, Logger } from '@nestjs/common'; import { GraphQLObjectType, isInputObjectType } from 'graphql'; -import { isDefined } from 'twenty-shared/utils'; +import { isDefined, pascalCase } from 'twenty-shared/utils'; import { ObjectTypeDefinitionKind } from 'src/engine/api/graphql/workspace-schema-builder/enums/object-type-definition-kind.enum'; import { AggregationObjectTypeGenerator } from 'src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/object-types/aggregation-type.generator'; @@ -12,7 +12,6 @@ import { GraphQLOutputTypeFieldConfigMap } from 'src/engine/api/graphql/workspac import { computeObjectMetadataObjectTypeKey } from 'src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-object-metadata-object-type-key.util'; import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; -import { pascalCase } from 'src/utils/pascal-case'; @Injectable() export class ConnectionGqlObjectTypeGenerator { diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/object-types/edge-gql-object-type.generator.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/object-types/edge-gql-object-type.generator.ts index 9392adde92..f0b67736d1 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/object-types/edge-gql-object-type.generator.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/object-types/edge-gql-object-type.generator.ts @@ -1,7 +1,7 @@ import { Injectable, Logger } from '@nestjs/common'; import { GraphQLObjectType, isInputObjectType } from 'graphql'; -import { isDefined } from 'twenty-shared/utils'; +import { isDefined, pascalCase } from 'twenty-shared/utils'; import { ObjectTypeDefinitionKind } from 'src/engine/api/graphql/workspace-schema-builder/enums/object-type-definition-kind.enum'; import { CursorScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; @@ -10,7 +10,6 @@ import { GqlTypesStorage } from 'src/engine/api/graphql/workspace-schema-builder import { GraphQLOutputTypeFieldConfigMap } from 'src/engine/api/graphql/workspace-schema-builder/types/graphql-field-config-map.types'; import { computeObjectMetadataObjectTypeKey } from 'src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-object-metadata-object-type-key.util'; import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; -import { pascalCase } from 'src/utils/pascal-case'; @Injectable() export class EdgeGqlObjectTypeGenerator { diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/object-types/group-by-connection-gql-object-type.generator.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/object-types/group-by-connection-gql-object-type.generator.ts index f70315776c..94bf258569 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/object-types/group-by-connection-gql-object-type.generator.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/object-types/group-by-connection-gql-object-type.generator.ts @@ -2,7 +2,7 @@ import { Injectable, Logger } from '@nestjs/common'; import { GraphQLObjectType, isObjectType } from 'graphql'; import GraphQLJSON from 'graphql-type-json'; -import { isDefined } from 'twenty-shared/utils'; +import { isDefined, pascalCase } from 'twenty-shared/utils'; import { ObjectTypeDefinitionKind } from 'src/engine/api/graphql/workspace-schema-builder/enums/object-type-definition-kind.enum'; import { TypeMapperService } from 'src/engine/api/graphql/workspace-schema-builder/services/type-mapper.service'; @@ -10,7 +10,6 @@ import { GqlTypesStorage } from 'src/engine/api/graphql/workspace-schema-builder import { GraphQLOutputTypeFieldConfigMap } from 'src/engine/api/graphql/workspace-schema-builder/types/graphql-field-config-map.types'; import { computeObjectMetadataObjectTypeKey } from 'src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-object-metadata-object-type-key.util'; import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; -import { pascalCase } from 'src/utils/pascal-case'; @Injectable() export class GroupByConnectionGqlObjectTypeGenerator { diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/object-types/object-metadata-gql-object-type.generator.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/object-types/object-metadata-gql-object-type.generator.ts index 597046e2a7..d32981f872 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/object-types/object-metadata-gql-object-type.generator.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/object-types/object-metadata-gql-object-type.generator.ts @@ -6,7 +6,7 @@ import { isInputObjectType, } from 'graphql'; import { FieldMetadataType } from 'twenty-shared/types'; -import { isDefined } from 'twenty-shared/utils'; +import { isDefined, pascalCase } from 'twenty-shared/utils'; import { ObjectTypeDefinitionKind } from 'src/engine/api/graphql/workspace-schema-builder/enums/object-type-definition-kind.enum'; import { RelationFieldMetadataGqlObjectTypeGenerator } from 'src/engine/api/graphql/workspace-schema-builder/graphql-type-generators/object-types/relation-field-metadata-gql-object-type.generator'; @@ -21,7 +21,6 @@ import { isEnumFieldMetadataType } from 'src/engine/metadata-modules/field-metad import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/utils/is-morph-or-relation-flat-field-metadata.util'; import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; -import { pascalCase } from 'src/utils/pascal-case'; @Injectable() export class ObjectMetadataGqlObjectTypeGenerator { diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-composite-field-enum-type-key.util.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-composite-field-enum-type-key.util.ts index 331aee24f7..54acea5c49 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-composite-field-enum-type-key.util.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-composite-field-enum-type-key.util.ts @@ -1,4 +1,4 @@ -import { pascalCase } from 'src/utils/pascal-case'; +import { pascalCase } from 'twenty-shared/utils'; export const computeCompositeFieldEnumTypeKey = ( fieldMetadataType: string, diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-composite-field-input-type-key.util.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-composite-field-input-type-key.util.ts index 0a0d963a8a..208a04a9ac 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-composite-field-input-type-key.util.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-composite-field-input-type-key.util.ts @@ -1,7 +1,7 @@ import { type FieldMetadataType } from 'twenty-shared/types'; +import { pascalCase } from 'twenty-shared/utils'; import { type GqlInputTypeDefinitionKind } from 'src/engine/api/graphql/workspace-schema-builder/enums/gql-input-type-definition-kind.enum'; -import { pascalCase } from 'src/utils/pascal-case'; export const computeCompositeFieldInputTypeKey = ( fieldType: FieldMetadataType, diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-composite-field-object-type-key.util.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-composite-field-object-type-key.util.ts index 0bf6f35772..b548379a01 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-composite-field-object-type-key.util.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-composite-field-object-type-key.util.ts @@ -1,7 +1,7 @@ import { type FieldMetadataType } from 'twenty-shared/types'; +import { pascalCase } from 'twenty-shared/utils'; import { ObjectTypeDefinitionKind } from 'src/engine/api/graphql/workspace-schema-builder/enums/object-type-definition-kind.enum'; -import { pascalCase } from 'src/utils/pascal-case'; export const computeCompositeFieldObjectTypeKey = ( compositeFieldMetadataType: FieldMetadataType, diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-enum-field-gql-type-key.util.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-enum-field-gql-type-key.util.ts index 68f21ea430..42edc33cbc 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-enum-field-gql-type-key.util.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-enum-field-gql-type-key.util.ts @@ -1,4 +1,4 @@ -import { pascalCase } from 'src/utils/pascal-case'; +import { pascalCase } from 'twenty-shared/utils'; export const computeEnumFieldGqlTypeKey = ( objectMetadataName: string, diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-object-metadata-input-type.util.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-object-metadata-input-type.util.ts index 90068581f2..a70a4f334c 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-object-metadata-input-type.util.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-object-metadata-input-type.util.ts @@ -1,5 +1,6 @@ +import { pascalCase } from 'twenty-shared/utils'; + import { type GqlInputTypeDefinitionKind } from 'src/engine/api/graphql/workspace-schema-builder/enums/gql-input-type-definition-kind.enum'; -import { pascalCase } from 'src/utils/pascal-case'; export const computeObjectMetadataInputTypeKey = ( objectMetadataNameSingular: string, diff --git a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-object-metadata-object-type-key.util.ts b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-object-metadata-object-type-key.util.ts index 502a9d83f6..daf0d9098c 100644 --- a/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-object-metadata-object-type-key.util.ts +++ b/packages/twenty-server/src/engine/api/graphql/workspace-schema-builder/utils/compute-stored-gql-type-key-utils/compute-object-metadata-object-type-key.util.ts @@ -1,5 +1,6 @@ +import { pascalCase } from 'twenty-shared/utils'; + import { type ObjectTypeDefinitionKind } from 'src/engine/api/graphql/workspace-schema-builder/enums/object-type-definition-kind.enum'; -import { pascalCase } from 'src/utils/pascal-case'; export const computeObjectMetadataObjectTypeKey = ( objectMetadataNameSingular: string, diff --git a/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/compute-column-name.util.ts b/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/compute-column-name.util.ts index b8a107f94b..babb088ac2 100644 --- a/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/compute-column-name.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/field-metadata/utils/compute-column-name.util.ts @@ -2,13 +2,13 @@ import { type FieldMetadataType, type CompositeProperty, } from 'twenty-shared/types'; +import { pascalCase } from 'twenty-shared/utils'; import { FieldMetadataException, FieldMetadataExceptionCode, } from 'src/engine/metadata-modules/field-metadata/field-metadata.exception'; import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util'; -import { pascalCase } from 'src/utils/pascal-case'; type ComputeColumnNameOptions = { isForeignKey?: boolean }; diff --git a/packages/twenty-server/src/engine/utils/get-resolver-name.util.ts b/packages/twenty-server/src/engine/utils/get-resolver-name.util.ts index a4df3965c2..7e6bead21e 100644 --- a/packages/twenty-server/src/engine/utils/get-resolver-name.util.ts +++ b/packages/twenty-server/src/engine/utils/get-resolver-name.util.ts @@ -1,8 +1,9 @@ +import { pascalCase } from 'twenty-shared/utils'; + import { type WorkspaceResolverBuilderMethodNames } from 'src/engine/api/graphql/workspace-resolver-builder/interfaces/workspace-resolvers-builder.interface'; import { type ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { camelCase } from 'src/utils/camel-case'; -import { pascalCase } from 'src/utils/pascal-case'; export const getResolverName = ( objectMetadata: Pick, diff --git a/packages/twenty-server/src/utils/pascal-case.ts b/packages/twenty-server/src/utils/pascal-case.ts index 6a5b98ce99..37c2647f60 100644 --- a/packages/twenty-server/src/utils/pascal-case.ts +++ b/packages/twenty-server/src/utils/pascal-case.ts @@ -1,10 +1,6 @@ import isObject from 'lodash.isobject'; -import lodashCamelCase from 'lodash.camelcase'; -import upperFirst from 'lodash.upperfirst'; -import { type PascalCase, type PascalCasedPropertiesDeep } from 'type-fest'; - -export const pascalCase = (text: T) => - upperFirst(lodashCamelCase(text as unknown as string)) as PascalCase; +import { type PascalCasedPropertiesDeep } from 'type-fest'; +import { pascalCase } from 'twenty-shared/utils'; export const pascalCaseDeep = (value: T): PascalCasedPropertiesDeep => { // Check if it's an array diff --git a/packages/twenty-server/test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-success.util.ts b/packages/twenty-server/test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-success.util.ts index e2acce5813..08453966bf 100644 --- a/packages/twenty-server/test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-success.util.ts +++ b/packages/twenty-server/test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-gql-create-input-validation-success.util.ts @@ -1,8 +1,7 @@ import { TEST_OBJECT_GQL_FIELDS } from 'test/integration/graphql/suites/inputs-validation/constants/test-object-gql-fields.constant'; import { createOneOperationFactory } from 'test/integration/graphql/utils/create-one-operation-factory.util'; import { makeGraphqlAPIRequestWithApiKey } from 'test/integration/graphql/utils/make-graphql-api-request-with-api-key.util'; - -import { pascalCase } from 'src/utils/pascal-case'; +import { pascalCase } from 'twenty-shared/utils'; export const expectGqlCreateInputValidationSuccess = async ( objectMetadataSingularName: string, diff --git a/packages/twenty-server/test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-success.util.ts b/packages/twenty-server/test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-success.util.ts index f8df006ae1..bfddf9eef9 100644 --- a/packages/twenty-server/test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-success.util.ts +++ b/packages/twenty-server/test/integration/graphql/suites/inputs-validation/create-validation/utils/expect-rest-create-input-validation-success.util.ts @@ -1,6 +1,5 @@ import { makeRestAPIRequest } from 'test/integration/rest/utils/make-rest-api-request.util'; - -import { pascalCase } from 'src/utils/pascal-case'; +import { pascalCase } from 'twenty-shared/utils'; export const expectRestCreateInputValidationSuccess = async ( objectMetadataPluralName: string, diff --git a/packages/twenty-shared/src/application/applicationManifestType.ts b/packages/twenty-shared/src/application/applicationManifestType.ts index adf238aaa5..43d15c2137 100644 --- a/packages/twenty-shared/src/application/applicationManifestType.ts +++ b/packages/twenty-shared/src/application/applicationManifestType.ts @@ -1,5 +1,5 @@ import { - PackageJson, + type PackageJson, type Application, type ObjectManifest, type ServerlessFunctionManifest, @@ -14,7 +14,7 @@ export type ApplicationManifest = { objects: ObjectManifest[]; objectExtensions?: ObjectExtensionManifest[]; functions: ServerlessFunctionManifest[]; - frontComponents?: FrontComponentManifest[]; + frontComponents: FrontComponentManifest[]; roles?: RoleManifest[]; sources: Sources; packageJson: PackageJson; diff --git a/packages/twenty-shared/src/application/packageJsonType.ts b/packages/twenty-shared/src/application/packageJsonType.ts index a646a472d1..bf84ff19e0 100644 --- a/packages/twenty-shared/src/application/packageJsonType.ts +++ b/packages/twenty-shared/src/application/packageJsonType.ts @@ -10,4 +10,5 @@ export type PackageJson = { version: string; dependencies?: object; devDependencies?: object; + scripts?: Record; }; diff --git a/packages/twenty-shared/src/utils/index.ts b/packages/twenty-shared/src/utils/index.ts index 3b88d5ed91..3278672d78 100644 --- a/packages/twenty-shared/src/utils/index.ts +++ b/packages/twenty-shared/src/utils/index.ts @@ -145,6 +145,7 @@ export { getGenericOperationName } from './sentry/getGenericOperationName'; export { getHumanReadableNameFromCode } from './sentry/getHumanReadableNameFromCode'; export { appendCopySuffix } from './strings/appendCopySuffix'; export { capitalize } from './strings/capitalize'; +export { pascalCase } from './strings/pascalCase'; export { uncapitalize } from './strings/uncapitalize'; export type { TipTapMarkType, diff --git a/packages/twenty-front/src/utils/string/__tests__/pascalCase.test.ts b/packages/twenty-shared/src/utils/strings/__tests__/pascalCase.test.ts similarity index 95% rename from packages/twenty-front/src/utils/string/__tests__/pascalCase.test.ts rename to packages/twenty-shared/src/utils/strings/__tests__/pascalCase.test.ts index 4fe787e9ea..9ddc249da2 100644 --- a/packages/twenty-front/src/utils/string/__tests__/pascalCase.test.ts +++ b/packages/twenty-shared/src/utils/strings/__tests__/pascalCase.test.ts @@ -1,4 +1,4 @@ -import { pascalCase } from '~/utils/string/pascalCase'; +import { pascalCase } from '@/utils/strings/pascalCase'; describe('pascalCase', () => { it('converts a string to pascal case', () => { diff --git a/packages/twenty-shared/src/utils/strings/index.ts b/packages/twenty-shared/src/utils/strings/index.ts index 41aa8035d5..618c37627f 100644 --- a/packages/twenty-shared/src/utils/strings/index.ts +++ b/packages/twenty-shared/src/utils/strings/index.ts @@ -1,2 +1,3 @@ export * from './appendCopySuffix'; export * from './capitalize'; +export * from './pascalCase'; diff --git a/packages/twenty-front/src/utils/string/pascalCase.ts b/packages/twenty-shared/src/utils/strings/pascalCase.ts similarity index 69% rename from packages/twenty-front/src/utils/string/pascalCase.ts rename to packages/twenty-shared/src/utils/strings/pascalCase.ts index b65da3cb4f..bcb51b6828 100644 --- a/packages/twenty-front/src/utils/string/pascalCase.ts +++ b/packages/twenty-shared/src/utils/strings/pascalCase.ts @@ -1,4 +1,4 @@ import camelCase from 'lodash.camelcase'; -import { capitalize } from 'twenty-shared/utils'; +import { capitalize } from '@/utils'; export const pascalCase = (str: string) => capitalize(camelCase(str));