diff --git a/.github/workflows/ci-sdk.yaml b/.github/workflows/ci-sdk.yaml index 67f2639778f..0bf71bb9491 100644 --- a/.github/workflows/ci-sdk.yaml +++ b/.github/workflows/ci-sdk.yaml @@ -47,67 +47,68 @@ jobs: with: tag: scope:sdk tasks: ${{ matrix.task }} - # TODO uncomment when syncApplication resolver is fixed - # sdk-e2e-integration-test: - # timeout-minutes: 30 - # runs-on: ubuntu-latest-8-cores - # needs: [changed-files-check, sdk-test] - # strategy: - # matrix: - # task: [test:integration, test:e2e] - # if: needs.changed-files-check.outputs.any_changed == 'true' - # services: - # postgres: - # image: twentycrm/twenty-postgres-spilo - # env: - # PGUSER_SUPERUSER: postgres - # PGPASSWORD_SUPERUSER: postgres - # ALLOW_NOSSL: 'true' - # SPILO_PROVIDER: 'local' - # ports: - # - 5432:5432 - # options: >- - # --health-cmd pg_isready - # --health-interval 10s - # --health-timeout 5s - # --health-retries 5 - # redis: - # image: redis - # ports: - # - 6379:6379 - # env: - # NODE_ENV: test - # steps: - # - name: Fetch custom Github Actions and base branch history - # uses: actions/checkout@v4 - # with: - # fetch-depth: 0 - # - name: Install dependencies - # uses: ./.github/actions/yarn-install - # - name: Server / Append billing config to .env.test - # working-directory: packages/twenty-server - # run: | - # echo "" >> .env.test - # echo "IS_BILLING_ENABLED=true" >> .env.test - # echo "BILLING_STRIPE_API_KEY=test-api-key" >> .env.test - # echo "BILLING_STRIPE_BASE_PLAN_PRODUCT_ID=test-base-plan-product-id" >> .env.test - # echo "BILLING_STRIPE_WEBHOOK_SECRET=test-webhook-secret" >> .env.test - # echo "BILLING_PLAN_REQUIRED_LINK=http://localhost:3001/stripe-redirection" >> .env.test - # - name: Server / Create Test DB - # run: | - # PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "test";' - # - name: SDK / Run ${{ matrix.task }} Tests - # uses: ./.github/actions/nx-affected - # with: - # tag: scope:sdk - # tasks: ${{ matrix.task }} + sdk-e2e-integration-test: + timeout-minutes: 30 + runs-on: ubuntu-latest-8-cores + needs: [changed-files-check, sdk-test] + if: needs.changed-files-check.outputs.any_changed == 'true' + services: + postgres: + image: twentycrm/twenty-postgres-spilo + env: + PGUSER_SUPERUSER: postgres + PGPASSWORD_SUPERUSER: postgres + ALLOW_NOSSL: 'true' + SPILO_PROVIDER: 'local' + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + redis: + image: redis + ports: + - 6379:6379 + env: + NODE_ENV: test + steps: + - name: Fetch custom Github Actions and base branch history + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Install dependencies + uses: ./.github/actions/yarn-install + - name: Build + run: npx nx build twenty-sdk + - name: Server / Append billing config to .env.test + working-directory: packages/twenty-server + run: | + echo "" >> .env.test + echo "IS_BILLING_ENABLED=true" >> .env.test + echo "BILLING_STRIPE_API_KEY=test-api-key" >> .env.test + echo "BILLING_STRIPE_BASE_PLAN_PRODUCT_ID=test-base-plan-product-id" >> .env.test + echo "BILLING_STRIPE_WEBHOOK_SECRET=test-webhook-secret" >> .env.test + echo "BILLING_PLAN_REQUIRED_LINK=http://localhost:3001/stripe-redirection" >> .env.test + - name: Server / Create Test DB + run: | + PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "test";' + - name: SDK / Run integration tests + uses: ./.github/actions/nx-affected + with: + tag: scope:sdk + tasks: test:integration + - name: SDK / Run e2e Tests + uses: ./.github/actions/nx-affected + with: + tag: scope:sdk + tasks: test:e2e ci-sdk-status-check: if: always() && !cancelled() timeout-minutes: 5 runs-on: ubuntu-latest - needs: [changed-files-check, sdk-test] - # TODO uncomment when syncApplication resolver is fixed - # needs: [changed-files-check, sdk-test, sdk-e2e-integration-test] + needs: [changed-files-check, sdk-test, sdk-e2e-integration-test] steps: - name: Fail job if any needs failed if: contains(needs.*.result, 'failure') diff --git a/packages/create-twenty-app/package.json b/packages/create-twenty-app/package.json index 3a2e760f449..2223ffeb728 100644 --- a/packages/create-twenty-app/package.json +++ b/packages/create-twenty-app/package.json @@ -1,6 +1,6 @@ { "name": "create-twenty-app", - "version": "0.4.8", + "version": "0.5.0-alpha", "description": "Command-line interface to create Twenty application", "main": "dist/cli.cjs", "bin": "dist/cli.cjs", diff --git a/packages/create-twenty-app/src/utils/__tests__/app-template.spec.ts b/packages/create-twenty-app/src/utils/__tests__/app-template.spec.ts index 402784128d0..9868b89528b 100644 --- a/packages/create-twenty-app/src/utils/__tests__/app-template.spec.ts +++ b/packages/create-twenty-app/src/utils/__tests__/app-template.spec.ts @@ -70,7 +70,7 @@ describe('copyBaseApplicationProject', () => { const packageJson = await fs.readJson(packageJsonPath); expect(packageJson.name).toBe('my-test-app'); expect(packageJson.version).toBe('0.1.0'); - expect(packageJson.dependencies['twenty-sdk']).toBe('0.4.8'); + expect(packageJson.dependencies['twenty-sdk']).toBe('0.5.0-alpha'); expect(packageJson.scripts['app:dev']).toBe('twenty app:dev'); }); diff --git a/packages/create-twenty-app/src/utils/app-template.ts b/packages/create-twenty-app/src/utils/app-template.ts index f1679f00191..f640ac8332c 100644 --- a/packages/create-twenty-app/src/utils/app-template.ts +++ b/packages/create-twenty-app/src/utils/app-template.ts @@ -189,7 +189,6 @@ const createDefaultFunction = async ({ fileName: string; }) => { const universalIdentifier = v4(); - const triggerUniversalIdentifier = v4(); const content = `import { defineLogicFunction } from 'twenty-sdk'; @@ -204,15 +203,11 @@ export default defineLogicFunction({ description: 'A simple logic function', timeoutSeconds: 5, handler, - triggers: [ - { - universalIdentifier: '${triggerUniversalIdentifier}', - type: 'route', - path: '/hello-world-logic-function', - httpMethod: 'GET', - isAuthRequired: false, - }, - ], + httpRouteTriggerSettings: { + path: '/hello-world-logic-function', + httpMethod: 'GET', + isAuthRequired: false, + }, }); `; @@ -282,7 +277,7 @@ const createPackageJson = async ({ 'lint:fix': 'eslint --fix', }, dependencies: { - 'twenty-sdk': '0.4.8', + 'twenty-sdk': '0.5.0-alpha', }, devDependencies: { typescript: '^5.9.3', diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 9ce0907dd89..b48c8866b2f 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -945,6 +945,14 @@ export type CreateCommandMenuItemInput = { workflowVersionId?: InputMaybe; }; +export type CreateDefaultLogicFunctionInput = { + description?: InputMaybe; + isTool?: InputMaybe; + name: Scalars['String']; + timeoutSeconds?: InputMaybe; + toolInputSchema?: InputMaybe; +}; + export type CreateDraftFromWorkflowVersionInput = { /** Workflow ID */ workflowId: Scalars['UUID']; @@ -984,18 +992,6 @@ export type CreateFrontComponentInput = { sourceComponentPath: Scalars['String']; }; -export type CreateLogicFunctionInput = { - builtHandlerPath?: InputMaybe; - code?: InputMaybe; - description?: InputMaybe; - handlerName?: InputMaybe; - isTool?: InputMaybe; - name: Scalars['String']; - sourceHandlerPath?: InputMaybe; - timeoutSeconds?: InputMaybe; - toolInputSchema?: InputMaybe; -}; - export type CreateNavigationMenuItemInput = { folderId?: InputMaybe; name?: InputMaybe; @@ -1713,11 +1709,6 @@ export type GetAuthorizationUrlForSsoOutput = { type: Scalars['String']; }; -export type GetLogicFunctionSourceCodeInput = { - /** The id of the function. */ - id: Scalars['ID']; -}; - /** Order by options for graph widgets */ export enum GraphOrderBy { FIELD_ASC = 'FIELD_ASC', @@ -2109,6 +2100,7 @@ export type Mutation = { createCoreViewGroup: CoreViewGroup; createCoreViewSort: CoreViewSort; createDatabaseConfigVariable: Scalars['Boolean']; + createDefaultLogicFunction: LogicFunction; createDraftFromWorkflowVersion: WorkflowVersionDto; createEmailingDomain: EmailingDomain; createFile: File; @@ -2122,7 +2114,6 @@ export type Mutation = { createOneAppToken: AppToken; createOneApplication: Application; createOneField: Field; - createOneLogicFunction: LogicFunction; createOneObject: Object; createOneRole: Role; createPageLayout: PageLayout; @@ -2384,6 +2375,11 @@ export type MutationCreateDatabaseConfigVariableArgs = { }; +export type MutationCreateDefaultLogicFunctionArgs = { + input: CreateDefaultLogicFunctionInput; +}; + + export type MutationCreateDraftFromWorkflowVersionArgs = { input: CreateDraftFromWorkflowVersionInput; }; @@ -2453,11 +2449,6 @@ export type MutationCreateOneFieldArgs = { }; -export type MutationCreateOneLogicFunctionArgs = { - input: CreateLogicFunctionInput; -}; - - export type MutationCreateOneObjectArgs = { input: CreateOneObjectInput; }; @@ -3913,7 +3904,7 @@ export type QueryGetIndicatorHealthStatusArgs = { export type QueryGetLogicFunctionSourceCodeArgs = { - input: GetLogicFunctionSourceCodeInput; + input: LogicFunctionIdInput; }; @@ -6015,7 +6006,7 @@ export type UpdateLogicFunctionSourceMutationVariables = Exact<{ export type UpdateLogicFunctionSourceMutation = { __typename?: 'Mutation', updateLogicFunctionSource: boolean }; export type GetLogicFunctionSourceCodeQueryVariables = Exact<{ - input: GetLogicFunctionSourceCodeInput; + input: LogicFunctionIdInput; }>; @@ -6413,12 +6404,12 @@ export type UpdateLabPublicFeatureFlagMutation = { __typename?: 'Mutation', upda export type LogicFunctionFieldsFragment = { __typename?: 'LogicFunction', id: string, name: string, description?: string | null, runtime: string, timeoutSeconds: number, sourceHandlerPath: string, builtHandlerPath: string, handlerName: string, toolInputSchema?: any | null, isTool: boolean, applicationId?: string | null, createdAt: string, updatedAt: string }; -export type CreateOneLogicFunctionItemMutationVariables = Exact<{ - input: CreateLogicFunctionInput; +export type CreateDefaultLogicFunctionItemMutationVariables = Exact<{ + input: CreateDefaultLogicFunctionInput; }>; -export type CreateOneLogicFunctionItemMutation = { __typename?: 'Mutation', createOneLogicFunction: { __typename?: 'LogicFunction', id: string, name: string, description?: string | null, runtime: string, timeoutSeconds: number, sourceHandlerPath: string, builtHandlerPath: string, handlerName: string, toolInputSchema?: any | null, isTool: boolean, applicationId?: string | null, createdAt: string, updatedAt: string } }; +export type CreateDefaultLogicFunctionItemMutation = { __typename?: 'Mutation', createDefaultLogicFunction: { __typename?: 'LogicFunction', id: string, name: string, description?: string | null, runtime: string, timeoutSeconds: number, sourceHandlerPath: string, builtHandlerPath: string, handlerName: string, toolInputSchema?: any | null, isTool: boolean, applicationId?: string | null, createdAt: string, updatedAt: string } }; export type DeleteOneLogicFunctionMutationVariables = Exact<{ input: LogicFunctionIdInput; @@ -10447,7 +10438,7 @@ export type UpdateLogicFunctionSourceMutationHookResult = ReturnType; export type UpdateLogicFunctionSourceMutationOptions = Apollo.BaseMutationOptions; export const GetLogicFunctionSourceCodeDocument = gql` - query GetLogicFunctionSourceCode($input: GetLogicFunctionSourceCodeInput!) { + query GetLogicFunctionSourceCode($input: LogicFunctionIdInput!) { getLogicFunctionSourceCode(input: $input) } `; @@ -12659,39 +12650,39 @@ export function useUpdateLabPublicFeatureFlagMutation(baseOptions?: Apollo.Mutat export type UpdateLabPublicFeatureFlagMutationHookResult = ReturnType; export type UpdateLabPublicFeatureFlagMutationResult = Apollo.MutationResult; export type UpdateLabPublicFeatureFlagMutationOptions = Apollo.BaseMutationOptions; -export const CreateOneLogicFunctionItemDocument = gql` - mutation CreateOneLogicFunctionItem($input: CreateLogicFunctionInput!) { - createOneLogicFunction(input: $input) { +export const CreateDefaultLogicFunctionItemDocument = gql` + mutation CreateDefaultLogicFunctionItem($input: CreateDefaultLogicFunctionInput!) { + createDefaultLogicFunction(input: $input) { ...LogicFunctionFields } } ${LogicFunctionFieldsFragmentDoc}`; -export type CreateOneLogicFunctionItemMutationFn = Apollo.MutationFunction; +export type CreateDefaultLogicFunctionItemMutationFn = Apollo.MutationFunction; /** - * __useCreateOneLogicFunctionItemMutation__ + * __useCreateDefaultLogicFunctionItemMutation__ * - * To run a mutation, you first call `useCreateOneLogicFunctionItemMutation` within a React component and pass it any options that fit your needs. - * When your component renders, `useCreateOneLogicFunctionItemMutation` returns a tuple that includes: + * To run a mutation, you first call `useCreateDefaultLogicFunctionItemMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useCreateDefaultLogicFunctionItemMutation` returns a tuple that includes: * - A mutate function that you can call at any time to execute the mutation * - An object with fields that represent the current status of the mutation's execution * * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; * * @example - * const [createOneLogicFunctionItemMutation, { data, loading, error }] = useCreateOneLogicFunctionItemMutation({ + * const [createDefaultLogicFunctionItemMutation, { data, loading, error }] = useCreateDefaultLogicFunctionItemMutation({ * variables: { * input: // value for 'input' * }, * }); */ -export function useCreateOneLogicFunctionItemMutation(baseOptions?: Apollo.MutationHookOptions) { +export function useCreateDefaultLogicFunctionItemMutation(baseOptions?: Apollo.MutationHookOptions) { const options = {...defaultOptions, ...baseOptions} - return Apollo.useMutation(CreateOneLogicFunctionItemDocument, options); + return Apollo.useMutation(CreateDefaultLogicFunctionItemDocument, options); } -export type CreateOneLogicFunctionItemMutationHookResult = ReturnType; -export type CreateOneLogicFunctionItemMutationResult = Apollo.MutationResult; -export type CreateOneLogicFunctionItemMutationOptions = Apollo.BaseMutationOptions; +export type CreateDefaultLogicFunctionItemMutationHookResult = ReturnType; +export type CreateDefaultLogicFunctionItemMutationResult = Apollo.MutationResult; +export type CreateDefaultLogicFunctionItemMutationOptions = Apollo.BaseMutationOptions; export const DeleteOneLogicFunctionDocument = gql` mutation DeleteOneLogicFunction($input: LogicFunctionIdInput!) { deleteOneLogicFunction(input: $input) { diff --git a/packages/twenty-front/src/generated/graphql.ts b/packages/twenty-front/src/generated/graphql.ts index ede24a0317a..ee8a3d12cc5 100644 --- a/packages/twenty-front/src/generated/graphql.ts +++ b/packages/twenty-front/src/generated/graphql.ts @@ -941,6 +941,14 @@ export type CreateCommandMenuItemInput = { workflowVersionId?: InputMaybe; }; +export type CreateDefaultLogicFunctionInput = { + description?: InputMaybe; + isTool?: InputMaybe; + name: Scalars['String']; + timeoutSeconds?: InputMaybe; + toolInputSchema?: InputMaybe; +}; + export type CreateDraftFromWorkflowVersionInput = { /** Workflow ID */ workflowId: Scalars['UUID']; @@ -980,18 +988,6 @@ export type CreateFrontComponentInput = { sourceComponentPath: Scalars['String']; }; -export type CreateLogicFunctionInput = { - builtHandlerPath?: InputMaybe; - code?: InputMaybe; - description?: InputMaybe; - handlerName?: InputMaybe; - isTool?: InputMaybe; - name: Scalars['String']; - sourceHandlerPath?: InputMaybe; - timeoutSeconds?: InputMaybe; - toolInputSchema?: InputMaybe; -}; - export type CreateObjectInput = { description?: InputMaybe; icon?: InputMaybe; @@ -1685,11 +1681,6 @@ export type GetAuthorizationUrlForSsoOutput = { type: Scalars['String']; }; -export type GetLogicFunctionSourceCodeInput = { - /** The id of the function. */ - id: Scalars['ID']; -}; - /** Order by options for graph widgets */ export enum GraphOrderBy { FIELD_ASC = 'FIELD_ASC', @@ -2079,6 +2070,7 @@ export type Mutation = { createCoreViewGroup: CoreViewGroup; createCoreViewSort: CoreViewSort; createDatabaseConfigVariable: Scalars['Boolean']; + createDefaultLogicFunction: LogicFunction; createDraftFromWorkflowVersion: WorkflowVersionDto; createEmailingDomain: EmailingDomain; createFile: File; @@ -2091,7 +2083,6 @@ export type Mutation = { createOneAppToken: AppToken; createOneApplication: Application; createOneField: Field; - createOneLogicFunction: LogicFunction; createOneObject: Object; createOneRole: Role; createPageLayout: PageLayout; @@ -2340,6 +2331,11 @@ export type MutationCreateDatabaseConfigVariableArgs = { }; +export type MutationCreateDefaultLogicFunctionArgs = { + input: CreateDefaultLogicFunctionInput; +}; + + export type MutationCreateDraftFromWorkflowVersionArgs = { input: CreateDraftFromWorkflowVersionInput; }; @@ -2399,11 +2395,6 @@ export type MutationCreateOneFieldArgs = { }; -export type MutationCreateOneLogicFunctionArgs = { - input: CreateLogicFunctionInput; -}; - - export type MutationCreateOneObjectArgs = { input: CreateOneObjectInput; }; @@ -3784,7 +3775,7 @@ export type QueryGetIndicatorHealthStatusArgs = { export type QueryGetLogicFunctionSourceCodeArgs = { - input: GetLogicFunctionSourceCodeInput; + input: LogicFunctionIdInput; }; diff --git a/packages/twenty-front/src/modules/logic-functions/graphql/queries/getLogicFunctionSourceCode.ts b/packages/twenty-front/src/modules/logic-functions/graphql/queries/getLogicFunctionSourceCode.ts index 85a8a732d71..42b7bd9bb99 100644 --- a/packages/twenty-front/src/modules/logic-functions/graphql/queries/getLogicFunctionSourceCode.ts +++ b/packages/twenty-front/src/modules/logic-functions/graphql/queries/getLogicFunctionSourceCode.ts @@ -1,7 +1,7 @@ import { gql } from '@apollo/client'; export const GET_LOGIC_FUNCTION_SOURCE_CODE = gql` - query GetLogicFunctionSourceCode($input: GetLogicFunctionSourceCodeInput!) { + query GetLogicFunctionSourceCode($input: LogicFunctionIdInput!) { getLogicFunctionSourceCode(input: $input) } `; diff --git a/packages/twenty-front/src/modules/logic-functions/hooks/usePersistLogicFunction.ts b/packages/twenty-front/src/modules/logic-functions/hooks/usePersistLogicFunction.ts index 2b59e06d8ae..9282dc5bae1 100644 --- a/packages/twenty-front/src/modules/logic-functions/hooks/usePersistLogicFunction.ts +++ b/packages/twenty-front/src/modules/logic-functions/hooks/usePersistLogicFunction.ts @@ -5,7 +5,7 @@ import { GET_LOGIC_FUNCTION_SOURCE_CODE } from '@/logic-functions/graphql/querie import { useMetadataErrorHandler } from '@/metadata-error-handler/hooks/useMetadataErrorHandler'; import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient'; import { type MetadataRequestResult } from '@/object-metadata/types/MetadataRequestResult.type'; -import { CREATE_ONE_LOGIC_FUNCTION } from '@/settings/logic-functions/graphql/mutations/createOneLogicFunction'; +import { CREATE_DEFAULT_LOGIC_FUNCTION } from '@/settings/logic-functions/graphql/mutations/createDefaultLogicFunction'; import { DELETE_ONE_LOGIC_FUNCTION } from '@/settings/logic-functions/graphql/mutations/deleteOneLogicFunction'; import { FIND_MANY_LOGIC_FUNCTIONS } from '@/settings/logic-functions/graphql/queries/findManyLogicFunctions'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; @@ -14,8 +14,8 @@ import { getOperationName } from '@apollo/client/utilities'; import { t } from '@lingui/core/macro'; import { type Sources, CrudOperationType } from 'twenty-shared/types'; import { - type CreateOneLogicFunctionItemMutation, - type CreateOneLogicFunctionItemMutationVariables, + type CreateDefaultLogicFunctionItemMutation, + type CreateDefaultLogicFunctionItemMutationVariables, type DeleteOneLogicFunctionMutation, type DeleteOneLogicFunctionMutationVariables, } from '~/generated-metadata/graphql'; @@ -29,10 +29,10 @@ export const usePersistLogicFunction = () => { const { handleMetadataError } = useMetadataErrorHandler(); const { enqueueErrorSnackBar } = useSnackBar(); - const [createLogicFunctionMutation] = useMutation< - CreateOneLogicFunctionItemMutation, - CreateOneLogicFunctionItemMutationVariables - >(CREATE_ONE_LOGIC_FUNCTION, { + const [createDefaultLogicFunctionMutation] = useMutation< + CreateDefaultLogicFunctionItemMutation, + CreateDefaultLogicFunctionItemMutationVariables + >(CREATE_DEFAULT_LOGIC_FUNCTION, { client: apolloMetadataClient, }); @@ -52,14 +52,14 @@ export const usePersistLogicFunction = () => { const createLogicFunction = useCallback( async ( - variables: CreateOneLogicFunctionItemMutationVariables, + variables: CreateDefaultLogicFunctionItemMutationVariables, ): Promise< MetadataRequestResult< - Awaited> + Awaited> > > => { try { - const result = await createLogicFunctionMutation({ + const result = await createDefaultLogicFunctionMutation({ variables, awaitRefetchQueries: true, refetchQueries: [getOperationName(FIND_MANY_LOGIC_FUNCTIONS) ?? ''], @@ -85,7 +85,11 @@ export const usePersistLogicFunction = () => { }; } }, - [createLogicFunctionMutation, handleMetadataError, enqueueErrorSnackBar], + [ + createDefaultLogicFunctionMutation, + handleMetadataError, + enqueueErrorSnackBar, + ], ); const updateLogicFunctionSource = useCallback( @@ -99,9 +103,6 @@ export const usePersistLogicFunction = () => { try { const result = await updateLogicFunctionSourceMutation({ variables, - refetchQueries: [ - getOperationName(GET_LOGIC_FUNCTION_SOURCE_CODE) ?? '', - ], }); return { diff --git a/packages/twenty-front/src/modules/settings/logic-functions/graphql/mutations/createOneLogicFunction.ts b/packages/twenty-front/src/modules/settings/logic-functions/graphql/mutations/createDefaultLogicFunction.ts similarity index 53% rename from packages/twenty-front/src/modules/settings/logic-functions/graphql/mutations/createOneLogicFunction.ts rename to packages/twenty-front/src/modules/settings/logic-functions/graphql/mutations/createDefaultLogicFunction.ts index 3cc17e1ea6f..026952a3b96 100644 --- a/packages/twenty-front/src/modules/settings/logic-functions/graphql/mutations/createOneLogicFunction.ts +++ b/packages/twenty-front/src/modules/settings/logic-functions/graphql/mutations/createDefaultLogicFunction.ts @@ -1,10 +1,12 @@ import { gql } from '@apollo/client'; import { LOGIC_FUNCTION_FRAGMENT } from '@/settings/logic-functions/graphql/fragments/logicFunctionFragment'; -export const CREATE_ONE_LOGIC_FUNCTION = gql` +export const CREATE_DEFAULT_LOGIC_FUNCTION = gql` ${LOGIC_FUNCTION_FRAGMENT} - mutation CreateOneLogicFunctionItem($input: CreateLogicFunctionInput!) { - createOneLogicFunction(input: $input) { + mutation CreateDefaultLogicFunctionItem( + $input: CreateDefaultLogicFunctionInput! + ) { + createDefaultLogicFunction(input: $input) { ...LogicFunctionFields } } diff --git a/packages/twenty-front/src/pages/settings/ai/components/SettingsToolsTable.tsx b/packages/twenty-front/src/pages/settings/ai/components/SettingsToolsTable.tsx index a07b9916d1d..f9682230798 100644 --- a/packages/twenty-front/src/pages/settings/ai/components/SettingsToolsTable.tsx +++ b/packages/twenty-front/src/pages/settings/ai/components/SettingsToolsTable.tsx @@ -131,7 +131,7 @@ export const SettingsToolsTable = () => { }); if (result.status === 'successful' && isDefined(result.response?.data)) { - const newFunction = result.response.data.createOneLogicFunction; + const newFunction = result.response.data.createDefaultLogicFunction; enqueueSuccessSnackBar({ message: t`Tool created` }); // Navigate to the logic function detail page diff --git a/packages/twenty-front/src/pages/settings/logic-functions/SettingsLogicFunctionDetail.tsx b/packages/twenty-front/src/pages/settings/logic-functions/SettingsLogicFunctionDetail.tsx index 774d086728c..94a5115e667 100644 --- a/packages/twenty-front/src/pages/settings/logic-functions/SettingsLogicFunctionDetail.tsx +++ b/packages/twenty-front/src/pages/settings/logic-functions/SettingsLogicFunctionDetail.tsx @@ -46,7 +46,7 @@ export const SettingsLogicFunctionDetail = () => { }); const handleExecute = async () => { - await executeLogicFunction({ forceRebuild: true }); + await executeLogicFunction({ forceRebuild: false }); }; const onChange = (key: string) => { diff --git a/packages/twenty-sdk/package.json b/packages/twenty-sdk/package.json index c5ecd42021b..2c1a8313f29 100644 --- a/packages/twenty-sdk/package.json +++ b/packages/twenty-sdk/package.json @@ -1,6 +1,6 @@ { "name": "twenty-sdk", - "version": "0.4.8", + "version": "0.5.0-alpha", "main": "dist/index.cjs", "module": "dist/index.mjs", "types": "dist/index.d.ts", diff --git a/packages/twenty-sdk/project.json b/packages/twenty-sdk/project.json index 77da008d398..bcde0a5e194 100644 --- a/packages/twenty-sdk/project.json +++ b/packages/twenty-sdk/project.json @@ -64,15 +64,25 @@ "options": { "cwd": "packages/twenty-sdk", "command": "npx wait-on http://localhost:3000/healthz --timeout 600000 --interval 1000 --log && npx vitest run --config vitest.integration.config.ts" - } + }, + "parallel": false, + "dependsOn": [ + "build", + { + "target": "database:reset", + "projects": "twenty-server" + }, + { + "target": "start:ci-if-needed", + "projects": "twenty-server" + } + ] }, "test:e2e": { "executor": "nx:run-commands", "options": { "cwd": "packages/twenty-sdk", - "commands": [ - "npx wait-on http://localhost:3000/healthz --timeout 600000 --interval 1000 --log && NODE_ENV=test npx vitest run --config ./vitest.e2e.config.ts" - ] + "command": "npx wait-on http://localhost:3000/healthz --timeout 600000 --interval 1000 --log && NODE_ENV=test npx vitest run --config ./vitest.e2e.config.ts" }, "parallel": false, "dependsOn": [ diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__e2e__/applications-install-delete-reinstall.e2e-spec.ts b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__e2e__/applications-install-delete-reinstall.e2e-spec.ts index 0f78163a169..33995f9bb80 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__e2e__/applications-install-delete-reinstall.e2e-spec.ts +++ b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__e2e__/applications-install-delete-reinstall.e2e-spec.ts @@ -1,31 +1,29 @@ -import { getTestedApplicationPath } from '@/cli/__tests__/e2e/utils/get-tested-application-path.util'; import { runAppDev } from '@/cli/__tests__/integration/utils/run-app-dev.util'; import { OUTPUT_DIR } from 'twenty-shared/application'; import { AppUninstallCommand } from '@/cli/commands/app/app-uninstall'; import { existsSync } from 'fs'; -import { join } from 'path'; +import { join, resolve } from 'path'; import { inspect } from 'util'; inspect.defaultOptions.depth = 10; -xdescribe('Application: install delete and reinstall rich-app', () => { +describe('Application: install delete and reinstall rich-app', () => { const applicationName = 'rich-app'; const deleteCommand = new AppUninstallCommand(); - const appPath = getTestedApplicationPath(applicationName); + const appPath = resolve(__dirname, '../'); - // TODO @charles: Re-enable e2e tests after fixing authentication issues - // beforeAll(async () => { - // expect(existsSync(appPath)).toBe(true); - // }); + beforeAll(async () => { + expect(existsSync(appPath)).toBe(true); + }); - // afterAll(async () => { - // const result = await deleteCommand.execute({ - // appPath, - // askForConfirmation: false, - // }); + afterAll(async () => { + const result = await deleteCommand.execute({ + appPath, + askForConfirmation: false, + }); - // expect(result.success).toBe(true); - // }); + expect(result.success).toBe(true); + }); it(`should successfully install ${applicationName} application`, async () => { await runAppDev({ appPath }); diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__e2e__/health.e2e-spec.ts b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__e2e__/health.e2e-spec.ts index 12aed653fe5..57807d5dc60 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__e2e__/health.e2e-spec.ts +++ b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/__e2e__/health.e2e-spec.ts @@ -1,5 +1,5 @@ import axios from 'axios'; -import { SERVER_URL } from '@/cli/__tests__/e2e/constants/server-url.constant'; +import { SERVER_URL } from '@/cli/__tests__/constants/server-url.constant'; describe('Twenty Server Health Check (E2E)', () => { const HEALTH_ENDPOINT = `${SERVER_URL}/healthz`; 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 fbc7733ed2a..7812462a40d 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 @@ -14,7 +14,7 @@ describe('rich-app app:dev', () => { beforeAll(async () => { result = await runAppDev({ appPath: APP_PATH }); if (!result.success) { - console.log(result.output); + console.log(result.output.slice(undefined, 20_000)); } expect(result.success).toBe(true); }, 60000); 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 index b876f2b3bc5..9101807f9a6 100644 --- 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 @@ -21,8 +21,8 @@ export const EXPECTED_MANIFEST: Manifest = { value: 'Alex Karp', }, }, - description: 'A simple hello world app', - displayName: 'Hello World', + description: 'A simple rich app', + displayName: 'Rich App', defaultRoleUniversalIdentifier: 'b648f87b-1d26-4961-b974-0908fd991061', icon: 'IconWorld', universalIdentifier: '4ec0391d-18d5-411c-b2f3-266ddc1c3ef7', @@ -46,7 +46,7 @@ export const EXPECTED_MANIFEST: Manifest = { description: 'A component using an external component file', name: 'card-component', sourceComponentPath: 'src/components/card.front-component.tsx', - universalIdentifier: 'i0i1i2i3-i4i5-4000-8000-000000000001', + universalIdentifier: '88c15ae2-5f87-4a6b-b48f-1974bbe62eb7', }, { builtComponentPath: 'src/components/greeting.front-component.mjs', @@ -55,7 +55,7 @@ export const EXPECTED_MANIFEST: Manifest = { description: 'A component that uses greeting utility', name: 'greeting-component', sourceComponentPath: 'src/components/greeting.front-component.tsx', - universalIdentifier: 'h0h1h2h3-h4h5-4000-8000-000000000001', + universalIdentifier: '370ae182-743f-4ecb-b625-7ac48e21f0e5', }, { builtComponentPath: 'src/components/test.front-component.mjs', @@ -257,82 +257,56 @@ export const EXPECTED_MANIFEST: Manifest = { { builtHandlerChecksum: '[checksum]', builtHandlerPath: 'src/root.function.mjs', - handlerName: 'default.handler', + handlerName: 'default.config.handler', 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', - }, - ], + httpRouteTriggerSettings: { + httpMethod: 'GET', + isAuthRequired: false, + path: '/root', + }, universalIdentifier: 'f0f1f2f3-f4f5-4000-8000-000000000001', }, { builtHandlerChecksum: '[checksum]', builtHandlerPath: 'src/logic-functions/greeting.function.mjs', - handlerName: 'default.handler', + handlerName: 'default.config.handler', name: 'greeting-function', sourceHandlerPath: 'src/logic-functions/greeting.function.ts', timeoutSeconds: 5, - triggers: [ - { - httpMethod: 'GET', - isAuthRequired: false, - path: '/greet', - type: 'route', - universalIdentifier: 'f7b12160-3d25-4c92-a13f-a325dd60eb04', - }, - ], + httpRouteTriggerSettings: { + httpMethod: 'GET', + isAuthRequired: false, + path: '/greet', + }, universalIdentifier: '9d412d9e-2caf-487c-8b66-d1585883dd4e', }, { builtHandlerChecksum: '[checksum]', builtHandlerPath: 'src/logic-functions/test-function-2.function.mjs', - handlerName: 'default.handler', + handlerName: 'default.config.handler', name: 'test-function-2', sourceHandlerPath: 'src/logic-functions/test-function-2.function.ts', timeoutSeconds: 2, - triggers: [ - { - pattern: '0 0 1 1 *', - type: 'cron', - universalIdentifier: '9fd0dda9-4664-4fbc-9656-509f4477b9ff', - }, - ], + cronTriggerSettings: { + pattern: '0 0 1 1 *', + }, universalIdentifier: 'eb3ffc98-88ec-45d4-9b4a-56833b219ccb', }, { builtHandlerChecksum: '[checksum]', builtHandlerPath: 'src/logic-functions/test-function.function.mjs', - handlerName: 'default.handler', + handlerName: 'default.config.handler', name: 'test-function', sourceHandlerPath: 'src/logic-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', - }, - ], + httpRouteTriggerSettings: { + forwardedRequestHeaders: ['signature'], + httpMethod: 'GET', + isAuthRequired: false, + path: '/post-card/create', + }, universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf', }, ], 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 da6b23c076e..bb835241307 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 @@ -35,10 +35,8 @@ export const defineManifestTests = (appPath: string): void => { it('should have correct application config', async () => { 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.displayName).toBe('Rich App'); + expect(manifest?.application.description).toBe('A simple rich app'); }); it('should load all entity types', async () => { diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/application.config.ts b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/application.config.ts index 9d328c2327e..faf14ac37b5 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/application.config.ts +++ b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/application.config.ts @@ -3,8 +3,8 @@ import { DEFAULT_ROLE_UNIVERSAL_IDENTIFIER } from './src/roles/default-function. export default defineApplication({ universalIdentifier: '4ec0391d-18d5-411c-b2f3-266ddc1c3ef7', - displayName: 'Hello World', - description: 'A simple hello world app', + displayName: 'Rich App', + description: 'A simple rich app', icon: 'IconWorld', applicationVariables: { DEFAULT_RECIPIENT_NAME: { diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/components/card.front-component.tsx b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/components/card.front-component.tsx index afc292f472e..6e3d8df8668 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/components/card.front-component.tsx +++ b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/components/card.front-component.tsx @@ -2,7 +2,7 @@ import { defineFrontComponent } from '@/sdk'; import { CardDisplay } from '../utils/card-display.component'; export default defineFrontComponent({ - universalIdentifier: 'i0i1i2i3-i4i5-4000-8000-000000000001', + universalIdentifier: '88c15ae2-5f87-4a6b-b48f-1974bbe62eb7', name: 'card-component', description: 'A component using an external component file', component: CardDisplay, diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/components/greeting.front-component.tsx b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/components/greeting.front-component.tsx index ed148e89eef..641485f9601 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/components/greeting.front-component.tsx +++ b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/components/greeting.front-component.tsx @@ -12,7 +12,7 @@ const GreetingComponent = () => { }; export default defineFrontComponent({ - universalIdentifier: 'h0h1h2h3-h4h5-4000-8000-000000000001', + universalIdentifier: '370ae182-743f-4ecb-b625-7ac48e21f0e5', name: 'greeting-component', description: 'A component that uses greeting utility', component: GreetingComponent, diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/fields/postCardCategoryField.ts b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/fields/postCardCategoryField.ts index d96ef0ee80e..5be87474eb3 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/fields/postCardCategoryField.ts +++ b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/fields/postCardCategoryField.ts @@ -1,10 +1,9 @@ import { defineField, FieldType } from '@/sdk'; import { POST_CARD_UNIVERSAL_IDENTIFIER } from '@/cli/__tests__/apps/rich-app/src/objects/postCard.object'; -import { POST_CARD_EXTENSION_CATEGORY_FIELD_ID } from '@/cli/__tests__/apps/rich-app/src/fields/postCardNumber.field'; export default defineField({ objectUniversalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER, - universalIdentifier: POST_CARD_EXTENSION_CATEGORY_FIELD_ID, + universalIdentifier: '8b9c0d1e-2f3a-4b5c-6d7e-8f9a0b1c2d3e', type: FieldType.SELECT, name: 'category', label: 'Category', diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/fields/postCardNumber.field.ts b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/fields/postCardNumber.field.ts index c471a7d175f..f96d4560b21 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/fields/postCardNumber.field.ts +++ b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/fields/postCardNumber.field.ts @@ -1,15 +1,9 @@ import { defineField, FieldType } from '@/sdk'; import { POST_CARD_UNIVERSAL_IDENTIFIER } from '@/cli/__tests__/apps/rich-app/src/objects/postCard.object'; -export const POST_CARD_EXTENSION_PRIORITY_FIELD_ID = - '7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d'; - -export const POST_CARD_EXTENSION_CATEGORY_FIELD_ID = - '8b9c0d1e-2f3a-4b5c-6d7e-8f9a0b1c2d3e'; - export default defineField({ objectUniversalIdentifier: POST_CARD_UNIVERSAL_IDENTIFIER, - universalIdentifier: POST_CARD_EXTENSION_PRIORITY_FIELD_ID, + universalIdentifier: '7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d', type: FieldType.NUMBER, name: 'priority', label: 'Priority', diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/logic-functions/greeting.function.ts b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/logic-functions/greeting.function.ts index 12b4f305634..a02f5193b32 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/logic-functions/greeting.function.ts +++ b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/logic-functions/greeting.function.ts @@ -10,13 +10,9 @@ export default defineLogicFunction({ name: 'greeting-function', timeoutSeconds: 5, handler: greetingHandler, - triggers: [ - { - universalIdentifier: 'f7b12160-3d25-4c92-a13f-a325dd60eb04', - type: 'route', - path: '/greet', - httpMethod: 'GET', - isAuthRequired: false, - }, - ], + httpRouteTriggerSettings: { + path: '/greet', + httpMethod: 'GET', + isAuthRequired: false, + }, }); diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/logic-functions/test-function-2.function.ts b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/logic-functions/test-function-2.function.ts index 7aab36fec1b..f3746c9590c 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/logic-functions/test-function-2.function.ts +++ b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/logic-functions/test-function-2.function.ts @@ -6,11 +6,7 @@ export default defineLogicFunction({ name: 'test-function-2', timeoutSeconds: 2, handler: testFunction2, - triggers: [ - { - universalIdentifier: '9fd0dda9-4664-4fbc-9656-509f4477b9ff', - type: 'cron', - pattern: '0 0 1 1 *', - }, - ], + cronTriggerSettings: { + pattern: '0 0 1 1 *', + }, }); diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/logic-functions/test-function.function.ts b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/logic-functions/test-function.function.ts index 2e8dea036a4..11db08e00f7 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/logic-functions/test-function.function.ts +++ b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/logic-functions/test-function.function.ts @@ -10,24 +10,10 @@ export default defineLogicFunction({ name: 'test-function', timeoutSeconds: 2, handler, - triggers: [ - { - universalIdentifier: 'c9f84c8d-b26d-40d1-95dd-4f834ae5a2c6', - type: 'route', - path: '/post-card/create', - httpMethod: 'GET', - isAuthRequired: false, - forwardedRequestHeaders: ['signature'], - }, - { - universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2', - type: 'cron', - pattern: '0 0 1 1 *', - }, - { - universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156', - type: 'databaseEvent', - eventName: 'person.created', - }, - ], + httpRouteTriggerSettings: { + path: '/post-card/create', + httpMethod: 'GET', + isAuthRequired: false, + forwardedRequestHeaders: ['signature'], + }, }); diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/root.function.ts b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/root.function.ts index 504aad593c6..340fbe10b88 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/root.function.ts +++ b/packages/twenty-sdk/src/cli/__tests__/apps/rich-app/src/root.function.ts @@ -9,13 +9,9 @@ export default defineLogicFunction({ name: 'root-function', timeoutSeconds: 5, handler: rootHandler, - triggers: [ - { - universalIdentifier: 'f0f1f2f3-f4f5-4000-8000-000000000002', - type: 'route', - path: '/root', - httpMethod: 'GET', - isAuthRequired: false, - }, - ], + httpRouteTriggerSettings: { + path: '/root', + httpMethod: 'GET', + isAuthRequired: false, + }, }); 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 212f028a9ba..7de175854cf 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 @@ -15,7 +15,7 @@ describe('root-app app:dev', () => { beforeAll(async () => { result = await runAppDev({ appPath: APP_PATH }); if (!result.success) { - console.log(result.output); + console.log(result.output.slice(undefined, 20_000)); } expect(result.success).toBe(true); }, 60000); diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-dev/expected-manifest.ts b/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-dev/expected-manifest.ts index b48473ee858..5771e8b8cc1 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-dev/expected-manifest.ts +++ b/packages/twenty-sdk/src/cli/__tests__/apps/root-app/__integration__/app-dev/expected-manifest.ts @@ -38,16 +38,12 @@ export const EXPECTED_MANIFEST: Manifest = { universalIdentifier: 'e1e2e3e4-e5e6-4000-8000-000000000010', name: 'my-function', timeoutSeconds: 5, - triggers: [ - { - universalIdentifier: 'e1e2e3e4-e5e6-4000-8000-000000000011', - type: 'route', - path: '/my-function', - httpMethod: 'GET', - isAuthRequired: false, - }, - ], - handlerName: 'default.handler', + httpRouteTriggerSettings: { + path: '/my-function', + httpMethod: 'GET', + isAuthRequired: false, + }, + handlerName: 'default.config.handler', sourceHandlerPath: 'my.function.ts', builtHandlerPath: 'my.function.mjs', builtHandlerChecksum: '[checksum]', diff --git a/packages/twenty-sdk/src/cli/__tests__/apps/root-app/my.function.ts b/packages/twenty-sdk/src/cli/__tests__/apps/root-app/my.function.ts index 974ae0a28e9..824c1eac33f 100644 --- a/packages/twenty-sdk/src/cli/__tests__/apps/root-app/my.function.ts +++ b/packages/twenty-sdk/src/cli/__tests__/apps/root-app/my.function.ts @@ -9,13 +9,9 @@ export default defineLogicFunction({ name: 'my-function', timeoutSeconds: 5, handler: myHandler, - triggers: [ - { - universalIdentifier: 'e1e2e3e4-e5e6-4000-8000-000000000011', - type: 'route', - path: '/my-function', - httpMethod: 'GET', - isAuthRequired: false, - }, - ], + httpRouteTriggerSettings: { + path: '/my-function', + httpMethod: 'GET', + isAuthRequired: false, + }, }); diff --git a/packages/twenty-sdk/src/cli/__tests__/e2e/constants/server-url.constant.ts b/packages/twenty-sdk/src/cli/__tests__/constants/server-url.constant.ts similarity index 100% rename from packages/twenty-sdk/src/cli/__tests__/e2e/constants/server-url.constant.ts rename to packages/twenty-sdk/src/cli/__tests__/constants/server-url.constant.ts diff --git a/packages/twenty-sdk/src/cli/__tests__/e2e/setupTest.ts b/packages/twenty-sdk/src/cli/__tests__/constants/setupTest.ts similarity index 79% rename from packages/twenty-sdk/src/cli/__tests__/e2e/setupTest.ts rename to packages/twenty-sdk/src/cli/__tests__/constants/setupTest.ts index 00a8a872f0c..d2458df652a 100644 --- a/packages/twenty-sdk/src/cli/__tests__/e2e/setupTest.ts +++ b/packages/twenty-sdk/src/cli/__tests__/constants/setupTest.ts @@ -1,5 +1,5 @@ import { ConfigService } from '@/cli/utilities/config/config-service'; -import { testConfig } from '@/cli/__tests__/e2e/constants/testConfig'; +import { testConfig } from '@/cli/__tests__/constants/testConfig'; import { vi, beforeAll, afterAll } from 'vitest'; beforeAll(() => { diff --git a/packages/twenty-sdk/src/cli/__tests__/e2e/teardown.ts b/packages/twenty-sdk/src/cli/__tests__/constants/teardown.ts similarity index 100% rename from packages/twenty-sdk/src/cli/__tests__/e2e/teardown.ts rename to packages/twenty-sdk/src/cli/__tests__/constants/teardown.ts diff --git a/packages/twenty-sdk/src/cli/__tests__/e2e/constants/testConfig.ts b/packages/twenty-sdk/src/cli/__tests__/constants/testConfig.ts similarity index 100% rename from packages/twenty-sdk/src/cli/__tests__/e2e/constants/testConfig.ts rename to packages/twenty-sdk/src/cli/__tests__/constants/testConfig.ts diff --git a/packages/twenty-sdk/src/cli/__tests__/e2e/utils/get-tested-application-path.util.ts b/packages/twenty-sdk/src/cli/__tests__/e2e/utils/get-tested-application-path.util.ts deleted file mode 100644 index 8f9a19f3c9f..00000000000 --- a/packages/twenty-sdk/src/cli/__tests__/e2e/utils/get-tested-application-path.util.ts +++ /dev/null @@ -1,7 +0,0 @@ -import path from 'path'; - -export const getTestedApplicationPath = (appName: string): string => { - const appsPath = path.resolve(__dirname, '../../apps'); - - return path.join(appsPath, appName); -}; 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 82a8a0d9b2c..713f1eaabd5 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 @@ -11,7 +11,7 @@ export type RunAppDevOptions = { export const runAppDev = ( options: RunAppDevOptions, ): Promise => { - const { appPath, timeout = 30000 } = options; + const { appPath, timeout = 60_000 } = options; return runCliCommand({ command: 'app:dev', 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 a4d189a245e..d96236b3fad 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,7 +23,7 @@ export type RunCliCommandResult = { export const runCliCommand = ( options: RunCliCommandOptions, ): Promise => { - const { command, args = [], waitForOutput, timeout = 30000 } = options; + const { command, args = [], waitForOutput, timeout = 60_000 } = options; return new Promise((resolve) => { // Run from CLI directory to use twenty-sdk's tsconfig paths 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 76cd54ea227..d781fd530ed 100644 --- a/packages/twenty-sdk/src/cli/commands/app/app-dev.ts +++ b/packages/twenty-sdk/src/cli/commands/app/app-dev.ts @@ -152,7 +152,7 @@ export class AppDevCommand { private async startDependencyWatcher(): Promise { this.dependencyWatcher = new FileUploadWatcher({ appPath: this.appPath, - fileFolder: FileFolder.Source, + fileFolder: FileFolder.Dependencies, watchPaths: ['package.json', 'yarn.lock'], handleFileBuilt: this.orchestrator!.handleFileBuilt.bind( this.orchestrator, diff --git a/packages/twenty-sdk/src/cli/utilities/api/api-service.ts b/packages/twenty-sdk/src/cli/utilities/api/api-service.ts index 593d5443636..22eb911ffb5 100644 --- a/packages/twenty-sdk/src/cli/utilities/api/api-service.ts +++ b/packages/twenty-sdk/src/cli/utilities/api/api-service.ts @@ -413,7 +413,7 @@ export class ApiService { > { try { const mutation = ` - mutation ExecuteOneLogicFunction($input: ExecuteLogicFunctionInput!) { + mutation ExecuteOneLogicFunction($input: ExecuteOneLogicFunctionInput!) { executeOneLogicFunction(input: $input) { data logs diff --git a/packages/twenty-sdk/src/cli/utilities/build/common/esbuild-watcher.ts b/packages/twenty-sdk/src/cli/utilities/build/common/esbuild-watcher.ts index 9ba7019bf8c..ca5a3a3860f 100644 --- a/packages/twenty-sdk/src/cli/utilities/build/common/esbuild-watcher.ts +++ b/packages/twenty-sdk/src/cli/utilities/build/common/esbuild-watcher.ts @@ -10,7 +10,7 @@ import { } from '@/cli/utilities/build/common/restartable-watcher-interface'; import * as esbuild from 'esbuild'; import path from 'path'; -import { OUTPUT_DIR } from 'twenty-shared/application'; +import { OUTPUT_DIR, NODE_ESM_CJS_BANNER } from 'twenty-shared/application'; import { FileFolder } from 'twenty-shared/types'; export const LOGIC_FUNCTION_EXTERNAL_MODULES: string[] = [ @@ -45,6 +45,7 @@ export type EsbuildWatcherConfig = { jsx?: 'automatic'; extraPlugins?: esbuild.Plugin[]; minify?: boolean; + banner?: esbuild.BuildOptions['banner']; }; export type EsbuildWatcherOptions = RestartableWatcherOptions & { @@ -170,6 +171,7 @@ export class EsbuildWatcher implements RestartableWatcher { metafile: true, logLevel: 'silent', minify: this.config.minify, + banner: this.config.banner, plugins, }); @@ -206,6 +208,7 @@ export const createLogicFunctionsWatcher = ( fileFolder: FileFolder.BuiltLogicFunction, platform: 'node', extraPlugins: [externalPatternsPlugin], + banner: NODE_ESM_CJS_BANNER, }, }); diff --git a/packages/twenty-sdk/src/cli/utilities/build/manifest/__tests__/manifest-validate.spec.ts b/packages/twenty-sdk/src/cli/utilities/build/manifest/__tests__/manifest-validate.spec.ts index d14f82f66fe..d1ec754637a 100644 --- a/packages/twenty-sdk/src/cli/utilities/build/manifest/__tests__/manifest-validate.spec.ts +++ b/packages/twenty-sdk/src/cli/utilities/build/manifest/__tests__/manifest-validate.spec.ts @@ -9,6 +9,7 @@ import { manifestValidate } from '@/cli/utilities/build/manifest/manifest-valida const validApplication: ApplicationManifest = { universalIdentifier: '4ec0391d-18d5-411c-b2f3-266ddc1c3ef7', displayName: 'Test App', + description: 'Test app for Twenty', defaultRoleUniversalIdentifier: '68bb56f3-8300-4cb5-8cc3-8da9ee66f1b2', packageJsonChecksum: '98592af7-4be9-4655-b5c4-9bef307a996c', yarnLockChecksum: '580ee05f-15fe-4146-bac2-6c382483c94e', 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 72e13c1ee4b..01a7e71ae6d 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 @@ -168,10 +168,10 @@ export const buildManifest = async ( const config: LogicFunctionManifest = { ...rest, - handlerName: 'default.handler', + handlerName: 'default.config.handler', sourceHandlerPath: relativeFilePath, builtHandlerPath: relativeFilePath.replace(/\.tsx?$/, '.mjs'), - builtHandlerChecksum: null, + builtHandlerChecksum: '[default-checksum]', }; logicFunctions.push(config); diff --git a/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-update-checksums.ts b/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-update-checksums.ts index 2023f98020c..e9e525dad1a 100644 --- a/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-update-checksums.ts +++ b/packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-update-checksums.ts @@ -78,7 +78,7 @@ export const manifestUpdateChecksums = ({ }; } - if (fileFolder === FileFolder.Source) { + if (fileFolder === FileFolder.Dependencies) { if (rootBuiltPath === 'package.json') { result.application.packageJsonChecksum = checksum; } diff --git a/packages/twenty-sdk/src/cli/utilities/entity/__tests__/get-function-base-file.spec.ts b/packages/twenty-sdk/src/cli/utilities/entity/__tests__/get-function-base-file.spec.ts index f5157f5e86e..49e670dc9dc 100644 --- a/packages/twenty-sdk/src/cli/utilities/entity/__tests__/get-function-base-file.spec.ts +++ b/packages/twenty-sdk/src/cli/utilities/entity/__tests__/get-function-base-file.spec.ts @@ -18,7 +18,7 @@ describe('getFunctionBaseFile', () => { expect(result).toContain("name: 'my-function'"); expect(result).toContain('timeoutSeconds: 5'); expect(result).toContain('handler,'); - expect(result).toContain('triggers: ['); + expect(result).toContain('// httpRouteTriggerSettings: {'); expect(result).toContain('const handler = async'); @@ -51,9 +51,9 @@ describe('getFunctionBaseFile', () => { name: 'example-function', }); - expect(result).toContain("type: 'route'"); - expect(result).toContain("type: 'cron'"); - expect(result).toContain("type: 'databaseEvent'"); + expect(result).toContain('// httpRouteTriggerSettings: {'); + expect(result).toContain('// cronTriggerSettings: {'); + expect(result).toContain('// databaseEventTriggerSettings: {'); expect(result).toContain("httpMethod: 'POST'"); expect(result).toContain("pattern: '0 0 * * *'"); expect(result).toContain("eventName: 'objectName.created'"); diff --git a/packages/twenty-sdk/src/cli/utilities/entity/entity-logic-function-template.ts b/packages/twenty-sdk/src/cli/utilities/entity/entity-logic-function-template.ts index 1a72b9f916c..a67a218e925 100644 --- a/packages/twenty-sdk/src/cli/utilities/entity/entity-logic-function-template.ts +++ b/packages/twenty-sdk/src/cli/utilities/entity/entity-logic-function-template.ts @@ -9,7 +9,6 @@ export const getLogicFunctionBaseFile = ({ universalIdentifier?: string; }) => { const kebabCaseName = kebabCase(name); - const triggerUniversalIdentifier = v4(); return `import { defineLogicFunction } from 'twenty-sdk'; @@ -32,26 +31,19 @@ export default defineLogicFunction({ description: 'Add a description for your logic function', timeoutSeconds: 5, handler, - triggers: [ - // Add your triggers here + // Add your trigger here // Route trigger example: - // { - // universalIdentifier: '${triggerUniversalIdentifier}', - // type: 'route', + // httpRouteTriggerSettings: { // path: '/${kebabCaseName}', // httpMethod: 'POST', // isAuthRequired: true, // }, // Cron trigger example: - // { - // universalIdentifier: '...', - // type: 'cron', + // cronTriggerSettings: { // pattern: '0 0 * * *', // Daily at midnight // }, // Database event trigger example: - // { - // universalIdentifier: '...', - // type: 'databaseEvent', + // databaseEventTriggerSettings: { // eventName: 'objectName.created', // }, ], diff --git a/packages/twenty-sdk/src/sdk/logic-functions/__tests__/define-logic-function.spec.ts b/packages/twenty-sdk/src/sdk/logic-functions/__tests__/define-logic-function.spec.ts index ca7e928894d..4bcc33555a5 100644 --- a/packages/twenty-sdk/src/sdk/logic-functions/__tests__/define-logic-function.spec.ts +++ b/packages/twenty-sdk/src/sdk/logic-functions/__tests__/define-logic-function.spec.ts @@ -7,85 +7,49 @@ describe('defineLogicFunction', () => { universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf', name: 'Send Postcard', handler: mockHandler, - triggers: [ - { - universalIdentifier: 'c9f84c8d-b26d-40d1-95dd-4f834ae5a2c6', - type: 'route' as const, - path: '/postcards/send', - httpMethod: 'POST' as const, - isAuthRequired: true, - }, - ], + httpRouteTriggerSettings: { + universalIdentifier: 'c9f84c8d-b26d-40d1-95dd-4f834ae5a2c6', + type: 'route', + path: '/postcards/send', + httpMethod: 'POST', + isAuthRequired: true, + }, }; it('should return the config when valid with route trigger', () => { - const result = defineLogicFunction(validRouteConfig); + const result = defineLogicFunction(validRouteConfig as any); expect(result.config).toEqual(validRouteConfig); }); - it('should accept cron trigger', () => { + it('should accept cronTriggerSettings', () => { const config = { universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf', name: 'Daily Report', handler: mockHandler, - triggers: [ - { - universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2', - type: 'cron' as const, - pattern: '0 9 * * *', - }, - ], + cronTriggerSettings: { + pattern: '0 9 * * *', + }, }; - const result = defineLogicFunction(config); + const result = defineLogicFunction(config as any); - expect(result.config.triggers[0].type).toBe('cron'); + expect(result.config.cronTriggerSettings.pattern).toBeDefined(); }); - it('should accept databaseEvent trigger', () => { + it('should accept databaseEventTriggerSettings', () => { const config = { universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf', name: 'On Contact Created', handler: mockHandler, - triggers: [ - { - universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156', - type: 'databaseEvent' as const, - eventName: 'contact.created', - }, - ], + databaseEventTriggerSettings: { + eventName: 'contact.created', + }, }; - const result = defineLogicFunction(config); + const result = defineLogicFunction(config as any); - expect(result.config.triggers[0].type).toBe('databaseEvent'); - }); - - it('should accept multiple triggers', () => { - const config = { - universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf', - name: 'Multi-trigger Function', - handler: mockHandler, - triggers: [ - { - universalIdentifier: 'c9f84c8d-b26d-40d1-95dd-4f834ae5a2c6', - type: 'route' as const, - path: '/sync', - httpMethod: 'POST' as const, - isAuthRequired: true, - }, - { - universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2', - type: 'cron' as const, - pattern: '0 * * * *', - }, - ], - }; - - const result = defineLogicFunction(config); - - expect(result.config.triggers).toHaveLength(2); + expect(result.config.databaseEventTriggerSettings.eventName).toBeDefined(); }); it('should pass through optional fields', () => { @@ -95,7 +59,7 @@ describe('defineLogicFunction', () => { timeoutSeconds: 30, }; - const result = defineLogicFunction(config); + const result = defineLogicFunction(config as any); expect(result.config.description).toBe('Send a postcard to a contact'); expect(result.config.timeoutSeconds).toBe(30); @@ -105,7 +69,7 @@ describe('defineLogicFunction', () => { const config = { name: 'Send Postcard', handler: mockHandler, - triggers: validRouteConfig.triggers, + httpRouteTriggerSettings: validRouteConfig.httpRouteTriggerSettings, }; const result = defineLogicFunction(config as any); @@ -119,7 +83,7 @@ describe('defineLogicFunction', () => { const config = { universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf', name: 'Send Postcard', - triggers: validRouteConfig.triggers, + httpRouteTriggerSettings: validRouteConfig.httpRouteTriggerSettings, }; const result = defineLogicFunction(config as any); @@ -133,7 +97,7 @@ describe('defineLogicFunction', () => { universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf', name: 'Send Postcard', handler: 'not-a-function', - triggers: validRouteConfig.triggers, + httpRouteTriggerSettings: validRouteConfig.httpRouteTriggerSettings, }; const result = defineLogicFunction(config as any); @@ -144,20 +108,20 @@ describe('defineLogicFunction', () => { ); }); - it('should accept empty triggers array', () => { + it('should accept empty undefined', () => { const config = { universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf', name: 'Send Postcard', handler: mockHandler, - triggers: [], + httpRouteTriggerSettings: undefined, }; const result = defineLogicFunction(config as any); - expect(result.config.triggers).toEqual([]); + expect(result.config.httpRouteTriggerSettings).toBeUndefined(); }); - it('should accept missing triggers', () => { + it('should accept missing trigger', () => { const config = { universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf', name: 'Send Postcard', @@ -166,50 +130,7 @@ describe('defineLogicFunction', () => { const result = defineLogicFunction(config as any); - expect(result.config.triggers).toBeUndefined(); - }); - - it('should return error when trigger is missing universalIdentifier', () => { - const config = { - universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf', - name: 'Send Postcard', - handler: mockHandler, - triggers: [ - { - type: 'route' as const, - path: '/postcards/send', - httpMethod: 'POST' as const, - isAuthRequired: true, - }, - ], - }; - - const result = defineLogicFunction(config as any); - - expect(result.success).toBe(false); - expect(result.errors).toContain( - 'Each trigger must have a universalIdentifier', - ); - }); - - it('should return error when trigger is missing type', () => { - const config = { - universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf', - name: 'Send Postcard', - handler: mockHandler, - triggers: [ - { - universalIdentifier: 'c9f84c8d-b26d-40d1-95dd-4f834ae5a2c6', - path: '/postcards/send', - httpMethod: 'POST' as const, - }, - ], - }; - - const result = defineLogicFunction(config as any); - - expect(result.success).toBe(false); - expect(result.errors).toContain('Each trigger must have a type'); + expect(result.config.httpRouteTriggerSettings).toBeUndefined(); }); it('should return error when route trigger is missing path', () => { @@ -217,14 +138,11 @@ describe('defineLogicFunction', () => { universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf', name: 'Send Postcard', handler: mockHandler, - triggers: [ - { - universalIdentifier: 'c9f84c8d-b26d-40d1-95dd-4f834ae5a2c6', - type: 'route' as const, - httpMethod: 'POST' as const, - isAuthRequired: true, - }, - ], + httpRouteTriggerSettings: { + type: 'route', + httpMethod: 'POST', + isAuthRequired: true, + }, }; const result = defineLogicFunction(config as any); @@ -238,14 +156,11 @@ describe('defineLogicFunction', () => { universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf', name: 'Send Postcard', handler: mockHandler, - triggers: [ - { - universalIdentifier: 'c9f84c8d-b26d-40d1-95dd-4f834ae5a2c6', - type: 'route' as const, - path: '/postcards/send', - isAuthRequired: true, - }, - ], + httpRouteTriggerSettings: { + type: 'route', + path: '/postcards/send', + isAuthRequired: true, + }, }; const result = defineLogicFunction(config as any); @@ -259,12 +174,7 @@ describe('defineLogicFunction', () => { universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf', name: 'Daily Report', handler: mockHandler, - triggers: [ - { - universalIdentifier: 'dd802808-0695-49e1-98c9-d5c9e2704ce2', - type: 'cron' as const, - }, - ], + cronTriggerSettings: {}, }; const result = defineLogicFunction(config as any); @@ -278,12 +188,7 @@ describe('defineLogicFunction', () => { universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf', name: 'On Contact Created', handler: mockHandler, - triggers: [ - { - universalIdentifier: '203f1df3-4a82-4d06-a001-b8cf22a31156', - type: 'databaseEvent' as const, - }, - ], + databaseEventTriggerSettings: {}, }; const result = defineLogicFunction(config as any); @@ -293,22 +198,4 @@ describe('defineLogicFunction', () => { 'Database event trigger must have an eventName', ); }); - - it('should return error for unknown trigger type', () => { - const config = { - universalIdentifier: 'e56d363b-0bdc-4d8a-a393-6f0d1c75bdcf', - name: 'Unknown Trigger', - handler: mockHandler, - triggers: [ - { - universalIdentifier: 'c9f84c8d-b26d-40d1-95dd-4f834ae5a2c6', - type: 'unknown' as any, - }, - ], - }; - const result = defineLogicFunction(config as any); - - expect(result.success).toBe(false); - expect(result.errors).toContain('Unknown trigger type: unknown'); - }); }); diff --git a/packages/twenty-sdk/src/sdk/logic-functions/define-logic-function.ts b/packages/twenty-sdk/src/sdk/logic-functions/define-logic-function.ts index 18f649ccf42..20080e7c32b 100644 --- a/packages/twenty-sdk/src/sdk/logic-functions/define-logic-function.ts +++ b/packages/twenty-sdk/src/sdk/logic-functions/define-logic-function.ts @@ -19,41 +19,24 @@ export const defineLogicFunction: DefineEntity = ( errors.push('Logic function handler must be a function'); } - for (const trigger of config.triggers ?? []) { - if (!trigger.universalIdentifier) { - errors.push('Each trigger must have a universalIdentifier'); + if (config.httpRouteTriggerSettings) { + if (!config.httpRouteTriggerSettings.path) { + errors.push('Route trigger must have a path'); } - - if (!trigger.type) { - errors.push('Each trigger must have a type'); + if (!config.httpRouteTriggerSettings.httpMethod) { + errors.push('Route trigger must have an httpMethod'); } + } - switch (trigger.type) { - case 'route': - if (!trigger.path) { - errors.push('Route trigger must have a path'); - } - if (!trigger.httpMethod) { - errors.push('Route trigger must have an httpMethod'); - } - break; + if (config.cronTriggerSettings) { + if (!config.cronTriggerSettings.pattern) { + errors.push('Cron trigger must have a pattern'); + } + } - case 'cron': - if (!trigger.pattern) { - errors.push('Cron trigger must have a pattern'); - } - break; - - case 'databaseEvent': - if (!trigger.eventName) { - errors.push('Database event trigger must have an eventName'); - } - break; - - default: - errors.push( - `Unknown trigger type: ${(trigger as { type: string }).type}`, - ); + if (config.databaseEventTriggerSettings) { + if (!config.databaseEventTriggerSettings.eventName) { + errors.push('Database event trigger must have an eventName'); } } diff --git a/packages/twenty-sdk/src/sdk/logic-functions/logic-function-config.ts b/packages/twenty-sdk/src/sdk/logic-functions/logic-function-config.ts index 82686a8122b..cfb0ccaa595 100644 --- a/packages/twenty-sdk/src/sdk/logic-functions/logic-function-config.ts +++ b/packages/twenty-sdk/src/sdk/logic-functions/logic-function-config.ts @@ -1,7 +1,4 @@ -import { - type LogicFunctionManifest, - type LogicFunctionTriggerManifest, -} from 'twenty-shared/application'; +import { type LogicFunctionManifest } from 'twenty-shared/application'; export type LogicFunctionHandler = (...args: any[]) => any | Promise; @@ -13,5 +10,4 @@ export type LogicFunctionConfig = Omit< | 'handlerName' > & { handler: LogicFunctionHandler; - triggers?: LogicFunctionTriggerManifest[]; }; diff --git a/packages/twenty-sdk/vitest.e2e.config.ts b/packages/twenty-sdk/vitest.e2e.config.ts index 062b9f69ffb..27710e628ae 100644 --- a/packages/twenty-sdk/vitest.e2e.config.ts +++ b/packages/twenty-sdk/vitest.e2e.config.ts @@ -13,8 +13,8 @@ export default defineConfig({ environment: 'node', include: ['src/**/*.e2e-spec.ts'], globals: true, - testTimeout: 30000, - hookTimeout: 30000, + testTimeout: 60_000, + hookTimeout: 60_000, pool: 'forks', poolOptions: { forks: { @@ -24,7 +24,7 @@ export default defineConfig({ sequence: { concurrent: false, }, - setupFiles: ['src/cli/__tests__/e2e/setupTest.ts'], + setupFiles: ['src/cli/__tests__/constants/setupTest.ts'], globalSetup: undefined, onConsoleLog: () => true, }, diff --git a/packages/twenty-sdk/vitest.integration.config.ts b/packages/twenty-sdk/vitest.integration.config.ts index 624085a6173..b5dc70c60f1 100644 --- a/packages/twenty-sdk/vitest.integration.config.ts +++ b/packages/twenty-sdk/vitest.integration.config.ts @@ -18,5 +18,6 @@ export default defineConfig({ truncateThreshold: 0, }, fileParallelism: false, + setupFiles: ['src/cli/__tests__/constants/setupTest.ts'], }, }); diff --git a/packages/twenty-server/eslint.config.mjs b/packages/twenty-server/eslint.config.mjs index 2c1a4645be0..0957df89d6d 100644 --- a/packages/twenty-server/eslint.config.mjs +++ b/packages/twenty-server/eslint.config.mjs @@ -16,7 +16,9 @@ import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -const twentyRules = await nxPlugin.loadWorkspaceRules('packages/twenty-eslint-rules'); +const twentyRules = await nxPlugin.loadWorkspaceRules( + 'packages/twenty-eslint-rules', +); export default [ // Base JavaScript configuration @@ -36,8 +38,8 @@ export default [ 'src/engine/workspace-manager/dev-seeder/data/seeds/**', 'src/utils/email-providers.ts', 'src/engine/core-modules/i18n/locales/generated/**', - 'src/engine/core-modules/serverless/drivers/constants/seed-project/src/index.ts', - 'packages/twenty-server/src/engine/core-modules/i18n/locales/**' + 'src/engine/core-modules/logic-function/logic-function-resource/constants/seed-project/src/index.ts', + 'packages/twenty-server/src/engine/core-modules/i18n/locales/**', ], }, @@ -45,22 +47,25 @@ export default [ { files: ['**/*.{js,jsx,ts,tsx}'], plugins: { - 'prettier': prettierPlugin, - 'lingui': linguiPlugin, + prettier: prettierPlugin, + lingui: linguiPlugin, '@nx': nxPlugin, 'prefer-arrow': preferArrowPlugin, - 'import': importPlugin, + import: importPlugin, 'unused-imports': unusedImportsPlugin, - 'unicorn': unicornPlugin, + unicorn: unicornPlugin, '@stylistic': stylisticPlugin, - 'twenty': { rules: twentyRules }, + twenty: { rules: twentyRules }, }, rules: { 'prettier/prettier': 'error', // General rules 'func-style': ['error', 'declaration', { allowArrowFunctions: true }], - 'no-console': ['warn', { allow: ['group', 'groupCollapsed', 'groupEnd'] }], + 'no-console': [ + 'warn', + { allow: ['group', 'groupCollapsed', 'groupEnd'] }, + ], 'no-control-regex': 0, 'no-debugger': 'error', 'no-duplicate-imports': 'error', @@ -142,7 +147,7 @@ export default [ 'error', { prefer: 'type-imports', - fixStyle: 'inline-type-imports' + fixStyle: 'inline-type-imports', }, ], '@typescript-eslint/explicit-function-return-type': 'off', @@ -169,7 +174,8 @@ export default [ }, { group: ['lodash'], - message: "Please use the standalone lodash package (for instance: `import groupBy from 'lodash.groupby'` instead of `import { groupBy } from 'lodash'`)", + message: + "Please use the standalone lodash package (for instance: `import groupBy from 'lodash.groupby'` instead of `import { groupBy } from 'lodash'`)", }, ], }, diff --git a/packages/twenty-server/nest-cli.json b/packages/twenty-server/nest-cli.json index d55c88999a1..e79349e9d72 100644 --- a/packages/twenty-server/nest-cli.json +++ b/packages/twenty-server/nest-cli.json @@ -17,23 +17,15 @@ "watchAssets": true, "assets": [ { - "include": "modules/workflow/workflow-builder/workflow-version-step/code-step/constants/seed-project/**", + "include": "engine/core-modules/logic-function/logic-function-resource/constants/seed-project/**", "outDir": "dist/assets" }, { - "include": "engine/core-modules/logic-function/logic-function-source-builder/constants/seed-project/**", + "include": "engine/core-modules/application-layer/constants/seed-dependencies/**", "outDir": "dist/assets" }, { - "include": "engine/core-modules/logic-function/logic-function-drivers/layers/*/package.json", - "outDir": "dist/assets" - }, - { - "include": "engine/core-modules/logic-function/logic-function-drivers/layers/*/yarn.lock", - "outDir": "dist/assets" - }, - { - "include": "engine/core-modules/logic-function/logic-function-drivers/layers/engine/**", + "include": "engine/core-modules/application-layer/constants/yarn-engine/**", "outDir": "dist/assets" }, { @@ -47,10 +39,6 @@ { "include": "engine/workspace-manager/dev-seeder/data/sample-files/**", "outDir": "dist/assets" - }, - { - "include": "engine/core-modules/application/constants/default-package-files/**", - "outDir": "dist/assets" } ] }, diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-backfill-application-package-files.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-backfill-application-package-files.command.ts index 83fa7cc883b..5d9994a30e3 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-backfill-application-package-files.command.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-backfill-application-package-files.command.ts @@ -10,7 +10,7 @@ import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/ import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; -import { parseAvailablePackagesFromPackageJsonAndYarnLock } from 'src/engine/core-modules/application/utils/parse-available-packages-from-package-json-and-yarn-lock.util'; +import { parseAvailablePackagesFromPackageJsonAndYarnLock } from 'src/engine/core-modules/application-layer/utils/parse-available-packages-from-package-json-and-yarn-lock.util'; import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service'; import { FileSettings } from 'src/engine/core-modules/file/types/file-settings.types'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-migrate-workflow-code-steps.command.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-migrate-workflow-code-steps.command.ts index f80c8a2eb3b..1385695190b 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-migrate-workflow-code-steps.command.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/1-17/1-17-migrate-workflow-code-steps.command.ts @@ -2,20 +2,20 @@ import { Logger } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import * as fs from 'fs/promises'; -import { dirname, join } from 'path'; +import { join } from 'path'; -import { isObject } from '@sniptt/guards'; import { Command } from 'nest-commander'; import { FileFolder, type Sources } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { In, Repository } from 'typeorm'; +import { v4 } from 'uuid'; import { ActiveOrSuspendedWorkspacesMigrationCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner'; import { RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner'; import { + type CodeStepMigrationTarget, collectCodeStepMigrationTargets, migrateWorkflowCodeStepsWithMapping, - type CodeStepMigrationTarget, type ServerlessToLogicFunctionMapping, } from 'src/database/commands/upgrade-version-command/1-17/utils/migrate-workflow-code-step.util'; import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; @@ -23,9 +23,12 @@ import { FileStorageService } from 'src/engine/core-modules/file-storage/file-st import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity'; -import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/services/logic-function.service'; +import { LogicFunctionMetadataService } from 'src/engine/metadata-modules/logic-function/services/logic-function-metadata.service'; import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; import { WorkflowVersionStatus } from 'src/modules/workflow/common/standard-objects/workflow-version.workspace-entity'; +import { LogicFunctionResourceService } from 'src/engine/core-modules/logic-function/logic-function-resource/logic-function-resource.service'; +import { logicFunctionCreateHash } from 'src/engine/metadata-modules/logic-function/utils/logic-function-create-hash.utils'; +import { streamToBuffer } from 'src/utils/stream-to-buffer'; const OLD_BUILT_FOLDER = 'built-function'; const OLD_SOURCE_FOLDER = 'serverless-function'; @@ -48,7 +51,8 @@ export class MigrateWorkflowCodeStepsCommand extends ActiveOrSuspendedWorkspaces protected readonly dataSourceService: DataSourceService, private readonly fileStorageService: FileStorageService, private readonly applicationService: ApplicationService, - private readonly logicFunctionService: LogicFunctionService, + private readonly logicFunctionMetadataService: LogicFunctionMetadataService, + private readonly logicFunctionResourceService: LogicFunctionResourceService, ) { super(workspaceRepository, globalWorkspaceOrmManager, dataSourceService); } @@ -183,30 +187,45 @@ export class MigrateWorkflowCodeStepsCommand extends ActiveOrSuspendedWorkspaces return null; } - const tempRoot = await this.migrateFilesFromOldPathToTemp( + const applicationUniversalIdentifier = + await this.getApplicationUniversalIdentifier( + oldLogicFunction.application.id, + ); + + if (!applicationUniversalIdentifier) { + this.logger.warn( + `Logic function ${serverlessFunctionId} application ${oldLogicFunction.application.id} not found not found in workspace ${workspaceId}, skipping`, + ); + + return null; + } + + const newLogicFunctionId = v4(); + + const { tempRoot, checksum } = await this.migrateFilesFromOldPathToTemp({ workspaceId, + applicationUniversalIdentifier, serverlessFunctionId, version, - ); + }); - const newFlatLogicFunction = await this.logicFunctionService.createOne({ + await this.logicFunctionMetadataService.createOne({ input: { name: oldLogicFunction.name, description: oldLogicFunction.description ?? undefined, timeoutSeconds: oldLogicFunction.timeoutSeconds ?? 300, toolInputSchema: oldLogicFunction.toolInputSchema ?? undefined, isTool: oldLogicFunction.isTool ?? false, + handlerName: 'main', + builtHandlerPath: 'src/index.mjs', + sourceHandlerPath: 'src/index.ts', + checksum, + id: newLogicFunctionId, }, workspaceId, - applicationId: oldLogicFunction.applicationId, + ownerFlatApplication: oldLogicFunction.application, }); - const newLogicFunctionId = newFlatLogicFunction.id; - const applicationUniversalIdentifier = - await this.getApplicationUniversalIdentifier( - newFlatLogicFunction.applicationId, - ); - if (isDefined(applicationUniversalIdentifier)) { await this.uploadTempToNewPath( workspaceId, @@ -225,11 +244,17 @@ export class MigrateWorkflowCodeStepsCommand extends ActiveOrSuspendedWorkspaces return newLogicFunctionId; } - private async migrateFilesFromOldPathToTemp( - workspaceId: string, - serverlessFunctionId: string, - version: string, - ): Promise { + private async migrateFilesFromOldPathToTemp({ + workspaceId, + applicationUniversalIdentifier, + serverlessFunctionId, + version, + }: { + workspaceId: string; + applicationUniversalIdentifier: string; + serverlessFunctionId: string; + version: string; + }): Promise<{ tempRoot: string; checksum: string }> { const workspacePrefix = `workspace-${workspaceId}`; const oldPaths = { built: `${workspacePrefix}/${OLD_BUILT_FOLDER}/${serverlessFunctionId}/${version}`, @@ -249,7 +274,23 @@ export class MigrateWorkflowCodeStepsCommand extends ActiveOrSuspendedWorkspaces oldPaths.built, ); - await this.writeSourcesToLocalFolder(builtSources as Sources, builtTempDir); + const builtContent = ( + await streamToBuffer( + await this.fileStorageService.readFile({ + fileFolder: FileFolder.BuiltLogicFunction, + resourcePath: 'src/index.mjs', + workspaceId, + applicationUniversalIdentifier, + }), + ) + ).toString('utf-8'); + + const checksum = logicFunctionCreateHash(builtContent); + + await this.logicFunctionResourceService.writeSourcesToLocalFolder( + builtSources as Sources, + builtTempDir, + ); const sourceSources = await this.fileStorageService.readFolderLegacy( oldPaths.source, @@ -257,9 +298,12 @@ export class MigrateWorkflowCodeStepsCommand extends ActiveOrSuspendedWorkspaces const flattened = (sourceSources.src as Sources) ?? (sourceSources as Sources); - await this.writeSourcesToLocalFolder(flattened, sourceTempDir); + await this.logicFunctionResourceService.writeSourcesToLocalFolder( + flattened, + sourceTempDir, + ); - return tempRoot; + return { tempRoot, checksum }; } private async uploadTempToNewPath( @@ -288,21 +332,4 @@ export class MigrateWorkflowCodeStepsCommand extends ActiveOrSuspendedWorkspaces localPath: sourceTempDir, }); } - - private async writeSourcesToLocalFolder( - sources: Sources, - localPath: string, - ): Promise { - for (const key of Object.keys(sources)) { - const filePath = join(localPath, key); - const value = sources[key]; - - if (isObject(value)) { - await this.writeSourcesToLocalFolder(value as Sources, filePath); - continue; - } - await fs.mkdir(dirname(filePath), { recursive: true }); - await fs.writeFile(filePath, value); - } - } } diff --git a/packages/twenty-server/src/engine/core-modules/application-layer/application-layer.module.ts b/packages/twenty-server/src/engine/core-modules/application-layer/application-layer.module.ts new file mode 100644 index 00000000000..ba95a036846 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/application-layer/application-layer.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common'; + +import { ApplicationLayerService } from 'src/engine/core-modules/application-layer/application-layer.service'; +import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module'; +import { FileModule } from 'src/engine/core-modules/file/file.module'; + +@Module({ + imports: [WorkspaceCacheModule, FileModule], + providers: [ApplicationLayerService], + exports: [ApplicationLayerService], +}) +export class ApplicationLayerModule {} diff --git a/packages/twenty-server/src/engine/core-modules/application-layer/application-layer.service.ts b/packages/twenty-server/src/engine/core-modules/application-layer/application-layer.service.ts new file mode 100644 index 00000000000..3d045be4fe4 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/application-layer/application-layer.service.ts @@ -0,0 +1,46 @@ +import { Injectable } from '@nestjs/common'; + +import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; +import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service'; + +@Injectable() +export class ApplicationLayerService { + constructor( + private readonly fileStorageService: FileStorageService, + private readonly workspaceCacheService: WorkspaceCacheService, + ) {} + + async getAvailablePackages({ + logicFunctionId, + workspaceId, + }: { + logicFunctionId: string; + workspaceId: string; + }) { + const { flatLogicFunctionMaps, flatApplicationMaps } = + await this.workspaceCacheService.getOrRecompute(workspaceId, [ + 'flatLogicFunctionMaps', + 'flatApplicationMaps', + ]); + + const logicFunctionUniversalIdentifier = + flatLogicFunctionMaps.universalIdentifierById[logicFunctionId]; + + if (!logicFunctionUniversalIdentifier) { + return {}; + } + + const logicFunction = + flatLogicFunctionMaps.byUniversalIdentifier[ + logicFunctionUniversalIdentifier + ]; + + if (!logicFunction) { + return {}; + } + + const application = flatApplicationMaps.byId[logicFunction.applicationId]; + + return application?.availablePackages ?? {}; + } +} diff --git a/packages/twenty-server/src/engine/core-modules/application-layer/constants/seed-dependencies-dirname.ts b/packages/twenty-server/src/engine/core-modules/application-layer/constants/seed-dependencies-dirname.ts new file mode 100644 index 00000000000..29c06e7e14f --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/application-layer/constants/seed-dependencies-dirname.ts @@ -0,0 +1,11 @@ +import path from 'path'; + +import { ASSET_PATH } from 'src/constants/assets-path'; + +export const SEED_DEPENDENCIES_DIRNAME = path.resolve( + __dirname, + path.join( + ASSET_PATH, + 'engine/core-modules/application-layer/constants/seed-dependencies', + ), +); diff --git a/packages/twenty-server/src/engine/core-modules/application/constants/default-package-files/package.json b/packages/twenty-server/src/engine/core-modules/application-layer/constants/seed-dependencies/package.json similarity index 100% rename from packages/twenty-server/src/engine/core-modules/application/constants/default-package-files/package.json rename to packages/twenty-server/src/engine/core-modules/application-layer/constants/seed-dependencies/package.json diff --git a/packages/twenty-server/src/engine/core-modules/application/constants/default-package-files/yarn.lock b/packages/twenty-server/src/engine/core-modules/application-layer/constants/seed-dependencies/yarn.lock similarity index 100% rename from packages/twenty-server/src/engine/core-modules/application/constants/default-package-files/yarn.lock rename to packages/twenty-server/src/engine/core-modules/application-layer/constants/seed-dependencies/yarn.lock diff --git a/packages/twenty-server/src/engine/core-modules/application-layer/constants/yarn-engine-dirname.ts b/packages/twenty-server/src/engine/core-modules/application-layer/constants/yarn-engine-dirname.ts new file mode 100644 index 00000000000..e9676efc450 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/application-layer/constants/yarn-engine-dirname.ts @@ -0,0 +1,11 @@ +import path from 'path'; + +import { ASSET_PATH } from 'src/constants/assets-path'; + +export const YARN_ENGINE_DIRNAME = path.resolve( + __dirname, + path.join( + ASSET_PATH, + 'engine/core-modules/application-layer/constants/yarn-engine', + ), +); diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/layers/engine/.yarn/releases/yarn-4.9.2.cjs b/packages/twenty-server/src/engine/core-modules/application-layer/constants/yarn-engine/.yarn/releases/yarn-4.9.2.cjs similarity index 100% rename from packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/layers/engine/.yarn/releases/yarn-4.9.2.cjs rename to packages/twenty-server/src/engine/core-modules/application-layer/constants/yarn-engine/.yarn/releases/yarn-4.9.2.cjs diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/layers/engine/.yarnrc.yml b/packages/twenty-server/src/engine/core-modules/application-layer/constants/yarn-engine/.yarnrc.yml similarity index 100% rename from packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/layers/engine/.yarnrc.yml rename to packages/twenty-server/src/engine/core-modules/application-layer/constants/yarn-engine/.yarnrc.yml diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/utils/copy-yarn-engine-and-build-dependencies.ts b/packages/twenty-server/src/engine/core-modules/application-layer/utils/copy-yarn-engine-and-build-dependencies.ts similarity index 86% rename from packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/utils/copy-yarn-engine-and-build-dependencies.ts rename to packages/twenty-server/src/engine/core-modules/application-layer/utils/copy-yarn-engine-and-build-dependencies.ts index bfca06d2eed..11a58eea370 100644 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/utils/copy-yarn-engine-and-build-dependencies.ts +++ b/packages/twenty-server/src/engine/core-modules/application-layer/utils/copy-yarn-engine-and-build-dependencies.ts @@ -3,7 +3,7 @@ import { promises as fs, statSync } from 'fs'; import { join } from 'path'; import { promisify } from 'util'; -import { getLayerDependenciesDirName } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/get-layer-dependencies-dir-name'; +import { YARN_ENGINE_DIRNAME } from 'src/engine/core-modules/application-layer/constants/yarn-engine-dirname'; const execFilePromise = promisify(execFile); @@ -14,7 +14,7 @@ export const copyYarnEngineAndBuildDependencies = async ( recursive: true, }); - await fs.cp(getLayerDependenciesDirName('engine'), buildDirectory, { + await fs.cp(YARN_ENGINE_DIRNAME, buildDirectory, { recursive: true, }); diff --git a/packages/twenty-server/src/engine/core-modules/application/utils/get-default-application-package-fields.util.ts b/packages/twenty-server/src/engine/core-modules/application-layer/utils/get-default-application-package-fields.util.ts similarity index 74% rename from packages/twenty-server/src/engine/core-modules/application/utils/get-default-application-package-fields.util.ts rename to packages/twenty-server/src/engine/core-modules/application-layer/utils/get-default-application-package-fields.util.ts index 771e9589925..ad9e1df4d13 100644 --- a/packages/twenty-server/src/engine/core-modules/application/utils/get-default-application-package-fields.util.ts +++ b/packages/twenty-server/src/engine/core-modules/application-layer/utils/get-default-application-package-fields.util.ts @@ -1,13 +1,8 @@ import { readFile } from 'fs/promises'; import path from 'path'; -import { ASSET_PATH } from 'src/constants/assets-path'; -import { parseAvailablePackagesFromPackageJsonAndYarnLock } from 'src/engine/core-modules/application/utils/parse-available-packages-from-package-json-and-yarn-lock.util'; - -const DEFAULT_PACKAGE_FILES_DIR = path.join( - ASSET_PATH, - 'engine/core-modules/application/constants/default-package-files', -); +import { parseAvailablePackagesFromPackageJsonAndYarnLock } from 'src/engine/core-modules/application-layer/utils/parse-available-packages-from-package-json-and-yarn-lock.util'; +import { SEED_DEPENDENCIES_DIRNAME } from 'src/engine/core-modules/application-layer/constants/seed-dependencies-dirname'; // To regenerate: use logicFunctionCreateHash from logic-function-create-hash.utils. // package.json: hash(JSON.stringify(JSON.parse(content))). yarn.lock: hash(content). @@ -26,8 +21,8 @@ export type DefaultApplicationPackageFields = { export const getDefaultApplicationPackageFields = async (): Promise => { const [packageJsonContent, yarnLockContent] = await Promise.all([ - readFile(path.join(DEFAULT_PACKAGE_FILES_DIR, 'package.json'), 'utf8'), - readFile(path.join(DEFAULT_PACKAGE_FILES_DIR, 'yarn.lock'), 'utf8'), + readFile(path.join(SEED_DEPENDENCIES_DIRNAME, 'package.json'), 'utf8'), + readFile(path.join(SEED_DEPENDENCIES_DIRNAME, 'yarn.lock'), 'utf8'), ]); const availablePackages = parseAvailablePackagesFromPackageJsonAndYarnLock( diff --git a/packages/twenty-server/src/engine/core-modules/application/utils/parse-available-packages-from-package-json-and-yarn-lock.util.ts b/packages/twenty-server/src/engine/core-modules/application-layer/utils/parse-available-packages-from-package-json-and-yarn-lock.util.ts similarity index 100% rename from packages/twenty-server/src/engine/core-modules/application/utils/parse-available-packages-from-package-json-and-yarn-lock.util.ts rename to packages/twenty-server/src/engine/core-modules/application-layer/utils/parse-available-packages-from-package-json-and-yarn-lock.util.ts diff --git a/packages/twenty-server/src/engine/core-modules/application/resolvers/application.resolver.ts b/packages/twenty-server/src/engine/core-modules/application/resolvers/application.resolver.ts index 4df4c324983..f2754d723fe 100644 --- a/packages/twenty-server/src/engine/core-modules/application/resolvers/application.resolver.ts +++ b/packages/twenty-server/src/engine/core-modules/application/resolvers/application.resolver.ts @@ -194,6 +194,7 @@ export class ApplicationResolver { FileFolder.BuiltFrontComponent, FileFolder.PublicAsset, FileFolder.Source, + FileFolder.Dependencies, ]; if (!allowedApplicationFileFolders.includes(fileFolder)) { diff --git a/packages/twenty-server/src/engine/core-modules/application/services/application-sync.service.ts b/packages/twenty-server/src/engine/core-modules/application/services/application-sync.service.ts index b1623ba7f66..2cccc787342 100644 --- a/packages/twenty-server/src/engine/core-modules/application/services/application-sync.service.ts +++ b/packages/twenty-server/src/engine/core-modules/application/services/application-sync.service.ts @@ -3,7 +3,10 @@ import { Injectable, Logger } from '@nestjs/common'; import { parse } from 'path'; import { + CronTriggerSettings, + DatabaseEventTriggerSettings, FieldManifest, + HttpRouteTriggerSettings, FrontComponentManifest, LogicFunctionManifest, Manifest, @@ -12,9 +15,10 @@ import { RelationFieldManifest, RoleManifest, } from 'twenty-shared/application'; -import { FieldMetadataType, FileFolder, Sources } from 'twenty-shared/types'; +import { FieldMetadataType, FileFolder } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { PackageJson } from 'type-fest'; +import { v4 } from 'uuid'; import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity'; import { @@ -24,9 +28,10 @@ import { import { ApplicationInput } from 'src/engine/core-modules/application/dtos/application.input'; import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; -import { getDefaultApplicationPackageFields } from 'src/engine/core-modules/application/utils/get-default-application-package-fields.util'; +import { getDefaultApplicationPackageFields } from 'src/engine/core-modules/application-layer/utils/get-default-application-package-fields.util'; import { ApplicationVariableEntityService } from 'src/engine/core-modules/applicationVariable/application-variable.service'; import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service'; +import type { JsonbProperty } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/jsonb-property.type'; import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; import { CreateFieldInput } from 'src/engine/metadata-modules/field-metadata/dtos/create-field.input'; import { FieldMetadataService } from 'src/engine/metadata-modules/field-metadata/services/field-metadata.service'; @@ -37,8 +42,8 @@ import { findFlatEntityByUniversalIdentifier } from 'src/engine/metadata-modules import { FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-metadata/types/flat-field-metadata.type'; import { type FlatFrontComponent } from 'src/engine/metadata-modules/flat-front-component/types/flat-front-component.type'; import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; +import { LogicFunctionMetadataService } from 'src/engine/metadata-modules/logic-function/services/logic-function-metadata.service'; import { FrontComponentService } from 'src/engine/metadata-modules/front-component/front-component.service'; -import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/services/logic-function.service'; import { FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type'; import { ObjectMetadataService } from 'src/engine/metadata-modules/object-metadata/object-metadata.service'; import { FieldPermissionService } from 'src/engine/metadata-modules/object-permission/field-permission/field-permission.service'; @@ -58,7 +63,7 @@ export class ApplicationSyncService { private readonly applicationVariableService: ApplicationVariableEntityService, private readonly objectMetadataService: ObjectMetadataService, private readonly fieldMetadataService: FieldMetadataService, - private readonly logicFunctionService: LogicFunctionService, + private readonly logicFunctionMetadataService: LogicFunctionMetadataService, private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, private readonly dataSourceService: DataSourceService, private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, @@ -106,7 +111,6 @@ export class ApplicationSyncService { if (manifest.logicFunctions.length > 0) { await this.syncLogicFunctions({ logicFunctionsToSync: manifest.logicFunctions, - code: manifest.sources, workspaceId, ownerFlatApplication, }); @@ -142,7 +146,7 @@ export class ApplicationSyncService { await this.fileStorageService.readFile({ applicationUniversalIdentifier: manifest.application.universalIdentifier, - fileFolder: FileFolder.Source, + fileFolder: FileFolder.Dependencies, resourcePath: 'package.json', workspaceId, }), @@ -158,7 +162,7 @@ export class ApplicationSyncService { }); if (!application) { - const created = await this.applicationService.create({ + application = await this.applicationService.create({ universalIdentifier: manifest.application.universalIdentifier, name, description: manifest.application.description, @@ -172,36 +176,6 @@ export class ApplicationSyncService { yarnLockFileId: null, availablePackages: defaultPackageFields.availablePackages, }); - - await this.applicationService.uploadDefaultPackageFilesAndSetFileIds( - created, - ); - - application = created; - } - - if ( - manifest.logicFunctions.length > 0 && - isDefined(manifest.application.packageJsonChecksum) && - isDefined(manifest.application.yarnLockChecksum) - ) { - const yarnLockContent = ( - await streamToBuffer( - await this.fileStorageService.readFile({ - applicationUniversalIdentifier: - manifest.application.universalIdentifier, - fileFolder: FileFolder.Source, - resourcePath: 'yarn.lock', - workspaceId, - }), - ) - ).toString('utf-8'); - - await this.applicationService.uploadPackageFilesFromContent( - application, - JSON.stringify(packageJson, null, 2), - yarnLockContent, - ); } await this.applicationVariableService.upsertManyApplicationVariableEntities( @@ -216,7 +190,9 @@ export class ApplicationSyncService { name, description: manifest.application.description, version: packageJson.version, - defaultRoleId: null, + packageJsonChecksum: manifest.application.packageJsonChecksum, + yarnLockChecksum: manifest.application.yarnLockChecksum, + //availablePackages: manifest.application.availablePackages, // TODO: compute available package in dev-mode-orchestrator }); } @@ -797,11 +773,11 @@ export class ApplicationSyncService { workspaceId: string; ownerFlatApplication: FlatApplication; }) { - const { flatObjectMetadataMaps } = + const { flatObjectMetadataMaps, flatFieldMetadataMaps } = await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps( { workspaceId, - flatMapsKeys: ['flatObjectMetadataMaps'], + flatMapsKeys: ['flatObjectMetadataMaps', 'flatFieldMetadataMaps'], }, ); @@ -818,12 +794,52 @@ export class ApplicationSyncService { ); } - await this.syncObjectFieldsWithoutRelations({ - objectId: targetObjectMetadata.id, - fieldsToSync: [fieldToSync], - workspaceId, - ownerFlatApplication, - }); + if (!this.isFieldTypeRelation(fieldToSync.type)) { + const existingField = findFlatEntityByUniversalIdentifier({ + flatEntityMaps: flatFieldMetadataMaps, + universalIdentifier: fieldToSync.universalIdentifier, + }); + + if (isDefined(existingField)) { + await this.fieldMetadataService.updateOneField({ + updateFieldInput: { + id: existingField.id, + label: fieldToSync.label, + description: fieldToSync.description ?? undefined, + icon: fieldToSync.icon ?? undefined, + defaultValue: fieldToSync.defaultValue ?? undefined, + options: fieldToSync.options ?? undefined, + settings: fieldToSync.settings ?? undefined, + isNullable: fieldToSync.isNullable ?? true, + }, + workspaceId, + ownerFlatApplication, + }); + } else { + const createFieldInput: CreateFieldInput = { + name: computeMetadataNameFromLabelOrThrow(fieldToSync.label), + type: fieldToSync.type, + label: fieldToSync.label, + description: fieldToSync.description ?? undefined, + icon: fieldToSync.icon ?? undefined, + defaultValue: fieldToSync.defaultValue ?? undefined, + options: fieldToSync.options ?? undefined, + settings: fieldToSync.settings ?? undefined, + isNullable: fieldToSync.isNullable ?? true, + objectMetadataId: targetObjectMetadata.id, + universalIdentifier: fieldToSync.universalIdentifier, + applicationId: ownerFlatApplication.id, + isCustom: true, + workspaceId, + }; + + await this.fieldMetadataService.createOneField({ + createFieldInput, + workspaceId, + ownerFlatApplication, + }); + } + } await this.syncObjectFieldsRelationOnly({ objectId: targetObjectMetadata.id, @@ -837,13 +853,11 @@ export class ApplicationSyncService { private async syncLogicFunctions({ logicFunctionsToSync, - code, workspaceId, ownerFlatApplication, }: { logicFunctionsToSync: LogicFunctionManifest[]; workspaceId: string; - code: Sources; ownerFlatApplication: FlatApplication; }) { const { flatLogicFunctionMaps } = @@ -895,7 +909,7 @@ export class ApplicationSyncService { ); for (const logicFunctionToDelete of logicFunctionsToDelete) { - await this.logicFunctionService.destroyOne({ + await this.logicFunctionMetadataService.destroyOne({ id: logicFunctionToDelete.id, workspaceId, isSystemBuild: true, @@ -920,17 +934,28 @@ export class ApplicationSyncService { const name = logicFunctionToSync.name ?? parse(logicFunctionToSync.handlerName).name; - await this.logicFunctionService.updateOne({ + await this.logicFunctionMetadataService.updateOne({ id: logicFunctionToUpdate.id, update: { name, - code, timeoutSeconds: logicFunctionToSync.timeoutSeconds, sourceHandlerPath: logicFunctionToSync.sourceHandlerPath, builtHandlerPath: logicFunctionToSync.builtHandlerPath, handlerName: logicFunctionToSync.handlerName, toolInputSchema: logicFunctionToSync.toolInputSchema, isTool: logicFunctionToSync.isTool, + checksum: logicFunctionToSync.builtHandlerChecksum, + cronTriggerSettings: logicFunctionToSync.cronTriggerSettings as + | JsonbProperty + | undefined, + databaseEventTriggerSettings: + logicFunctionToSync.databaseEventTriggerSettings as + | JsonbProperty + | undefined, + httpRouteTriggerSettings: + logicFunctionToSync.httpRouteTriggerSettings as + | JsonbProperty + | undefined, }, workspaceId, ownerFlatApplication, @@ -942,10 +967,9 @@ export class ApplicationSyncService { logicFunctionToCreate.name ?? parse(logicFunctionToCreate.handlerName).name; - await this.logicFunctionService.createOne({ + await this.logicFunctionMetadataService.createOne({ input: { name, - code, universalIdentifier: logicFunctionToCreate.universalIdentifier, timeoutSeconds: logicFunctionToCreate.timeoutSeconds, sourceHandlerPath: logicFunctionToCreate.sourceHandlerPath, @@ -953,6 +977,19 @@ export class ApplicationSyncService { builtHandlerPath: logicFunctionToCreate.builtHandlerPath, toolInputSchema: logicFunctionToCreate.toolInputSchema, isTool: logicFunctionToCreate.isTool, + checksum: logicFunctionToCreate.builtHandlerChecksum, + id: v4(), + cronTriggerSettings: logicFunctionToCreate.cronTriggerSettings as + | JsonbProperty + | undefined, + databaseEventTriggerSettings: + logicFunctionToCreate.databaseEventTriggerSettings as + | JsonbProperty + | undefined, + httpRouteTriggerSettings: + logicFunctionToCreate.httpRouteTriggerSettings as + | JsonbProperty + | undefined, }, workspaceId, ownerFlatApplication, @@ -1068,6 +1105,9 @@ export class ApplicationSyncService { flatObjectMetadataMaps: existingFlatObjectMetadataMaps, flatIndexMaps: existingFlatIndexMetadataMaps, flatFieldMetadataMaps: existingFlatFieldMetadataMaps, + flatFrontComponentMaps: existingFlatFrontComponentMaps, + flatLogicFunctionMaps: existingFlatLogicFunctionMaps, + flatRoleMaps: existingFlatRoleMaps, } = await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps( { workspaceId, @@ -1075,6 +1115,9 @@ export class ApplicationSyncService { 'flatObjectMetadataMaps', 'flatIndexMaps', 'flatFieldMetadataMaps', + 'flatFrontComponentMaps', + 'flatLogicFunctionMaps', + 'flatRoleMaps', ], }, ); @@ -1115,6 +1158,23 @@ export class ApplicationSyncService { applicationId: application.id, }); + const flatFrontComponentMapsByApplicationId = + findFlatEntitiesByApplicationId({ + flatEntityMaps: existingFlatFrontComponentMaps, + applicationId: application.id, + }); + + const flatLogicFunctionMapsByApplicationId = + findFlatEntitiesByApplicationId({ + flatEntityMaps: existingFlatLogicFunctionMaps, + applicationId: application.id, + }); + + const flatRoleMapsByApplicationId = findFlatEntitiesByApplicationId({ + flatEntityMaps: existingFlatRoleMaps, + applicationId: application.id, + }); + await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration( { allFlatEntityOperationByMetadataName: { @@ -1133,6 +1193,21 @@ export class ApplicationSyncService { flatEntityToDelete: flatFieldMetadataMapsByApplicationId, flatEntityToUpdate: [], }, + frontComponent: { + flatEntityToCreate: [], + flatEntityToDelete: flatFrontComponentMapsByApplicationId, + flatEntityToUpdate: [], + }, + logicFunction: { + flatEntityToCreate: [], + flatEntityToDelete: flatLogicFunctionMapsByApplicationId, + flatEntityToUpdate: [], + }, + role: { + flatEntityToCreate: [], + flatEntityToDelete: flatRoleMapsByApplicationId, + flatEntityToUpdate: [], + }, }, workspaceId, isSystemBuild: true, diff --git a/packages/twenty-server/src/engine/core-modules/application/services/application.service.ts b/packages/twenty-server/src/engine/core-modules/application/services/application.service.ts index 1055b08b763..f6ad4f5fdd2 100644 --- a/packages/twenty-server/src/engine/core-modules/application/services/application.service.ts +++ b/packages/twenty-server/src/engine/core-modules/application/services/application.service.ts @@ -10,8 +10,8 @@ import { ApplicationException, ApplicationExceptionCode, } from 'src/engine/core-modules/application/application.exception'; -import { getDefaultApplicationPackageFields } from 'src/engine/core-modules/application/utils/get-default-application-package-fields.util'; -import { parseAvailablePackagesFromPackageJsonAndYarnLock } from 'src/engine/core-modules/application/utils/parse-available-packages-from-package-json-and-yarn-lock.util'; +import { getDefaultApplicationPackageFields } from 'src/engine/core-modules/application-layer/utils/get-default-application-package-fields.util'; +import { parseAvailablePackagesFromPackageJsonAndYarnLock } from 'src/engine/core-modules/application-layer/utils/parse-available-packages-from-package-json-and-yarn-lock.util'; import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { ALL_FLAT_ENTITY_MAPS_PROPERTIES } from 'src/engine/metadata-modules/flat-entity/constant/all-flat-entity-maps-properties.constant'; @@ -405,51 +405,6 @@ export class ApplicationService { } } - async uploadPackageFilesFromContent( - application: Pick< - ApplicationEntity, - 'id' | 'universalIdentifier' | 'workspaceId' - >, - packageJsonContent: string, - yarnLockContent: string, - ): Promise { - const packageJsonChecksum = logicFunctionCreateHash(packageJsonContent); - const yarnLockChecksum = logicFunctionCreateHash(yarnLockContent); - const availablePackages = parseAvailablePackagesFromPackageJsonAndYarnLock( - packageJsonContent, - yarnLockContent, - ); - - const packageJsonFile = await this.fileStorageService.writeFile({ - sourceFile: packageJsonContent, - mimeType: undefined, - fileFolder: FileFolder.Dependencies, - applicationUniversalIdentifier: application.universalIdentifier, - workspaceId: application.workspaceId, - resourcePath: 'package.json', - settings: { isTemporaryFile: false, toDelete: false }, - }); - - const yarnLockFile = await this.fileStorageService.writeFile({ - sourceFile: yarnLockContent, - mimeType: undefined, - fileFolder: FileFolder.Dependencies, - applicationUniversalIdentifier: application.universalIdentifier, - workspaceId: application.workspaceId, - resourcePath: 'yarn.lock', - settings: { isTemporaryFile: false, toDelete: false }, - }); - - await this.update(application.id, { - packageJsonFileId: packageJsonFile.id, - yarnLockFileId: yarnLockFile.id, - packageJsonChecksum, - yarnLockChecksum, - availablePackages, - workspaceId: application.workspaceId, - }); - } - async create( data: Partial & { workspaceId: string }, queryRunner?: QueryRunner, @@ -502,6 +457,11 @@ export class ApplicationService { throw new Error(`Application does not exist`); } + await this.fileStorageService.deleteApplicationFiles({ + workspaceId, + applicationUniversalIdentifier: universalIdentifier, + }); + await this.applicationRepository.delete({ universalIdentifier, workspaceId, diff --git a/packages/twenty-server/src/engine/core-modules/core-engine.module.ts b/packages/twenty-server/src/engine/core-modules/core-engine.module.ts index 36359cee2f4..58a2278012d 100644 --- a/packages/twenty-server/src/engine/core-modules/core-engine.module.ts +++ b/packages/twenty-server/src/engine/core-modules/core-engine.module.ts @@ -28,7 +28,6 @@ import { ExceptionHandlerModule } from 'src/engine/core-modules/exception-handle import { exceptionHandlerModuleFactory } from 'src/engine/core-modules/exception-handler/exception-handler.module-factory'; import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module'; import { FileStorageModule } from 'src/engine/core-modules/file-storage/file-storage.module'; -import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service'; import { GeoMapModule } from 'src/engine/core-modules/geo-map/geo-map-module'; import { HealthModule } from 'src/engine/core-modules/health/health.module'; import { ImapSmtpCaldavModule } from 'src/engine/core-modules/imap-smtp-caldav-connection/imap-smtp-caldav-connection.module'; @@ -47,7 +46,7 @@ import { PublicDomainModule } from 'src/engine/core-modules/public-domain/public import { RedisClientModule } from 'src/engine/core-modules/redis-client/redis-client.module'; import { RedisClientService } from 'src/engine/core-modules/redis-client/redis-client.service'; import { SearchModule } from 'src/engine/core-modules/search/search.module'; -import { logicFunctionModuleFactory } from 'src/engine/core-modules/logic-function/logic-function-executor/factories/logic-function-module.factory'; +import { logicFunctionModuleFactory } from 'src/engine/core-modules/logic-function/logic-function-drivers/factories/logic-function-module.factory'; import { LogicFunctionModule } from 'src/engine/core-modules/logic-function/logic-function.module'; import { WorkspaceSSOModule } from 'src/engine/core-modules/sso/sso.module'; import { TelemetryModule } from 'src/engine/core-modules/telemetry/telemetry.module'; @@ -69,6 +68,8 @@ import { TrashCleanupModule } from 'src/engine/trash-cleanup/trash-cleanup.modul import { WorkspaceEventEmitterModule } from 'src/engine/workspace-event-emitter/workspace-event-emitter.module'; import { ChannelSyncModule } from 'src/modules/connected-account/channel-sync/channel-sync.module'; import { DashboardModule } from 'src/modules/dashboard/dashboard.module'; +import { ApplicationLayerModule } from 'src/engine/core-modules/application-layer/application-layer.module'; +import { LogicFunctionResourceService } from 'src/engine/core-modules/logic-function/logic-function-resource/logic-function-resource.service'; import { AuditModule } from './audit/audit.module'; import { ClientConfigModule } from './client-config/client-config.module'; @@ -90,6 +91,7 @@ import { FileModule } from './file/file.module'; RowLevelPermissionModule, OpenApiModule, ApplicationModule, + ApplicationLayerModule, ApplicationSyncModule, AppTokenModule, TimelineMessagingModule, @@ -144,7 +146,7 @@ import { FileModule } from './file/file.module'; AiBillingModule, LogicFunctionModule.forRootAsync({ useFactory: logicFunctionModuleFactory, - inject: [TwentyConfigService, FileStorageService], + inject: [TwentyConfigService, LogicFunctionResourceService], }), CodeInterpreterModule.forRootAsync({ useFactory: codeInterpreterModuleFactory, diff --git a/packages/twenty-server/src/engine/core-modules/file-storage/drivers/local.driver.ts b/packages/twenty-server/src/engine/core-modules/file-storage/drivers/local.driver.ts index 4da02794e34..6995fe0ec73 100644 --- a/packages/twenty-server/src/engine/core-modules/file-storage/drivers/local.driver.ts +++ b/packages/twenty-server/src/engine/core-modules/file-storage/drivers/local.driver.ts @@ -160,7 +160,7 @@ export class LocalDriver implements StorageDriver { params.filename || '', ); - await fs.rm(filePath, { recursive: true }); + await fs.rm(filePath, { recursive: true, force: true }); } async move(params: { diff --git a/packages/twenty-server/src/engine/core-modules/file-storage/file-storage.service.ts b/packages/twenty-server/src/engine/core-modules/file-storage/file-storage.service.ts index 7569144499b..35120926486 100644 --- a/packages/twenty-server/src/engine/core-modules/file-storage/file-storage.service.ts +++ b/packages/twenty-server/src/engine/core-modules/file-storage/file-storage.service.ts @@ -37,7 +37,12 @@ export class FileStorageService { fileFolder, resourcePath, }: ResourceIdentifier): string { - return `${workspaceId}/${applicationUniversalIdentifier}/${fileFolder}/${resourcePath}`; + return join( + workspaceId, + applicationUniversalIdentifier, + fileFolder, + resourcePath, + ).replace(/\/+/g, '/'); } writeFileLegacy(params: { @@ -251,11 +256,51 @@ export class FileStorageService { return driver.delete(params); } - delete(params: ResourceIdentifier): Promise { + async deleteApplicationFiles({ + applicationUniversalIdentifier, + workspaceId, + }: { + applicationUniversalIdentifier: string; + workspaceId: string; + }) { + const application = await this.applicationRepository.findOneOrFail({ + where: { + universalIdentifier: applicationUniversalIdentifier, + workspaceId: workspaceId, + }, + }); + + await this.fileRepository.delete({ + applicationId: application.id, + workspaceId, + }); + } + + async delete(params: ResourceIdentifier): Promise { const driver = this.fileStorageDriverFactory.getCurrentDriver(); const onStoragePath = this.buildOnStoragePath(params); - return driver.delete({ folderPath: onStoragePath }); + const deleteResult = driver.delete({ folderPath: onStoragePath }); + + const application = await this.applicationRepository.findOneOrFail({ + where: { + universalIdentifier: params.applicationUniversalIdentifier, + workspaceId: params.workspaceId, + }, + }); + + const basePath = `${join(params.fileFolder, params.resourcePath)}`.replace( + /\/+/g, + '/', + ); + + await this.fileRepository.delete({ + path: Like(`${basePath}%`), + applicationId: application.id, + workspaceId: params.workspaceId, + }); + + return deleteResult; } async deleteByFileId({ diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/constants/executor/index.mjs b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/constants/executor/index.mjs index 29023fe0c4a..b5aa7d43613 100644 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/constants/executor/index.mjs +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/constants/executor/index.mjs @@ -19,7 +19,11 @@ export const handler = async (event) => { const mainFile = await import(mainPath); - return await mainFile[handlerName](params); + const handlerFn = handlerName + .split('.') + .reduce((obj, key) => obj[key], mainFile); + + return await handlerFn(params); } finally { await fs.rm(mainPath, { force: true }); // eslint-disable-next-line no-undef diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/constants/lambda-layer.constant.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/constants/lambda-layer.constant.ts deleted file mode 100644 index 137da95c382..00000000000 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/constants/lambda-layer.constant.ts +++ /dev/null @@ -1 +0,0 @@ -export const NODE_LAYER_SUBFOLDER = 'nodejs'; diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/constants/logic-function-driver.constants.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/constants/logic-function-driver.constants.ts new file mode 100644 index 00000000000..a4c9b02e77d --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/constants/logic-function-driver.constants.ts @@ -0,0 +1 @@ +export const LOGIC_FUNCTION_DRIVER = Symbol('LOGIC_FUNCTION_DRIVER'); diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/drivers/disabled.driver.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/drivers/disabled.driver.ts index 691f80bb24b..586a7b46ea9 100644 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/drivers/disabled.driver.ts +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/drivers/disabled.driver.ts @@ -1,14 +1,14 @@ import { - type LogicFunctionExecutorDriver, + type LogicFunctionDriver, type LogicFunctionExecuteResult, -} from 'src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-executor-driver.interface'; +} from 'src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-driver.interface'; import { LogicFunctionException, LogicFunctionExceptionCode, } from 'src/engine/metadata-modules/logic-function/logic-function.exception'; -export class DisabledDriver implements LogicFunctionExecutorDriver { +export class DisabledDriver implements LogicFunctionDriver { async delete(): Promise { // No-op when disabled } diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/drivers/lambda.driver.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/drivers/lambda.driver.ts index b6f0dbbbbee..49b4aba3b69 100644 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/drivers/lambda.driver.ts +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/drivers/lambda.driver.ts @@ -19,22 +19,18 @@ import { waitUntilFunctionUpdatedV2, } from '@aws-sdk/client-lambda'; import { AssumeRoleCommand, STSClient } from '@aws-sdk/client-sts'; -import { FileFolder } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; import { type LogicFunctionExecuteParams, type LogicFunctionExecuteResult, - type LogicFunctionExecutorDriver, -} from 'src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-executor-driver.interface'; + type LogicFunctionDriver, +} from 'src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-driver.interface'; import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; -import { type FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service'; -import { NODE_LAYER_SUBFOLDER } from 'src/engine/core-modules/logic-function/logic-function-drivers/constants/lambda-layer.constant'; import { copyExecutor } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/copy-executor'; -import { copyYarnEngineAndBuildDependencies } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/copy-yarn-engine-and-build-dependencies'; import { createZipFile } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/create-zip-file'; -import { LambdaBuildDirectoryManager } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/lambda-build-directory-manager'; +import { TemporaryDirManager } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/temporary-dir-manager'; import { LogicFunctionExecutionStatus } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-execution-result.dto'; import { LogicFunctionRuntime } from 'src/engine/metadata-modules/logic-function/logic-function.entity'; import { @@ -42,7 +38,8 @@ import { LogicFunctionExceptionCode, } from 'src/engine/metadata-modules/logic-function/logic-function.exception'; import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type'; -import { streamToBuffer } from 'src/utils/stream-to-buffer'; +import { copyYarnEngineAndBuildDependencies } from 'src/engine/core-modules/application-layer/utils/copy-yarn-engine-and-build-dependencies'; +import { type LogicFunctionResourceService } from 'src/engine/core-modules/logic-function/logic-function-resource/logic-function-resource.service'; const UPDATE_FUNCTION_DURATION_TIMEOUT_IN_SECONDS = 60; const CREDENTIALS_DURATION_IN_SECONDS = 60 * 60; // 1h @@ -55,22 +52,22 @@ type LambdaDriverExecutorPayload = { }; export interface LambdaDriverOptions extends LambdaClientConfig { - fileStorageService: FileStorageService; + logicFunctionResourceService: LogicFunctionResourceService; region: string; lambdaRole: string; subhostingRole?: string; } -export class LambdaDriver implements LogicFunctionExecutorDriver { +export class LambdaDriver implements LogicFunctionDriver { private lambdaClient: Lambda | undefined; private credentialsExpiry: Date | null = null; private readonly options: LambdaDriverOptions; - private readonly fileStorageService: FileStorageService; + private readonly logicFunctionResourceService: LogicFunctionResourceService; constructor(options: LambdaDriverOptions) { this.options = options; this.lambdaClient = undefined; - this.fileStorageService = options.fileStorageService; + this.logicFunctionResourceService = options.logicFunctionResourceService; } private async getLambdaClient() { @@ -140,33 +137,6 @@ export class LambdaDriver implements LogicFunctionExecutorDriver { return flatApplication.yarnLockChecksum ?? 'default'; } - private async copyDependenciesInMemory({ - applicationUniversalIdentifier, - workspaceId, - inMemoryLayerFolderPath, - }: { - applicationUniversalIdentifier: string; - workspaceId: string; - inMemoryLayerFolderPath: string; - }) { - await Promise.all([ - this.fileStorageService.downloadFile({ - workspaceId, - applicationUniversalIdentifier, - fileFolder: FileFolder.Dependencies, - resourcePath: 'package.json', - localPath: join(inMemoryLayerFolderPath, 'package.json'), - }), - this.fileStorageService.downloadFile({ - workspaceId, - applicationUniversalIdentifier, - fileFolder: FileFolder.Dependencies, - resourcePath: 'yarn.lock', - localPath: join(inMemoryLayerFolderPath, 'yarn.lock'), - }), - ]); - } - private async createLayerIfNotExists({ flatApplication, applicationUniversalIdentifier, @@ -191,19 +161,16 @@ export class LambdaDriver implements LogicFunctionExecutorDriver { return listLayerResult.LayerVersions[0].LayerVersionArn; } - const buildTemporaryDirectoryManager = new LambdaBuildDirectoryManager(); + const temporaryDirManager = new TemporaryDirManager(); const { sourceTemporaryDir, lambdaZipPath } = - await buildTemporaryDirectoryManager.init(); + await temporaryDirManager.init(); - const nodeDependenciesFolder = join( - sourceTemporaryDir, - NODE_LAYER_SUBFOLDER, - ); + const nodeDependenciesFolder = join(sourceTemporaryDir, 'nodejs'); - await this.copyDependenciesInMemory({ + await this.logicFunctionResourceService.copyDependenciesInMemory({ applicationUniversalIdentifier, workspaceId: flatApplication.workspaceId, - inMemoryLayerFolderPath: nodeDependenciesFolder, + inMemoryFolderPath: nodeDependenciesFolder, }); await copyYarnEngineAndBuildDependencies(nodeDependenciesFolder); @@ -224,7 +191,7 @@ export class LambdaDriver implements LogicFunctionExecutorDriver { const result = await (await this.getLambdaClient()).send(command); - await buildTemporaryDirectoryManager.clean(); + await temporaryDirManager.clean(); if (!isDefined(result.LayerVersionArn)) { throw new Error('new layer version arn if undefined'); @@ -306,10 +273,10 @@ export class LambdaDriver implements LogicFunctionExecutorDriver { applicationUniversalIdentifier, }); - const buildTemporaryDirectoryManager = new LambdaBuildDirectoryManager(); + const temporaryDirManager = new TemporaryDirManager(); const { sourceTemporaryDir, lambdaZipPath } = - await buildTemporaryDirectoryManager.init(); + await temporaryDirManager.init(); await copyExecutor(sourceTemporaryDir); @@ -331,7 +298,7 @@ export class LambdaDriver implements LogicFunctionExecutorDriver { await (await this.getLambdaClient()).send(command); - await buildTemporaryDirectoryManager.clean(); + await temporaryDirManager.clean(); } private extractLogs(logString: string): string { @@ -366,16 +333,11 @@ export class LambdaDriver implements LogicFunctionExecutorDriver { const startTime = Date.now(); - const compiledCode = ( - await streamToBuffer( - await this.fileStorageService.readFile({ - workspaceId: flatLogicFunction.workspaceId, - applicationUniversalIdentifier, - fileFolder: FileFolder.BuiltLogicFunction, - resourcePath: flatLogicFunction.builtHandlerPath, - }), - ) - ).toString('utf-8'); + const compiledCode = await this.logicFunctionResourceService.getBuiltCode({ + workspaceId: flatLogicFunction.workspaceId, + applicationUniversalIdentifier, + builtHandlerPath: flatLogicFunction.builtHandlerPath, + }); const executorPayload: LambdaDriverExecutorPayload = { params: payload, diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/drivers/local.driver.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/drivers/local.driver.ts index 4de4084c3a7..e588a1064e6 100644 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/drivers/local.driver.ts +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/drivers/local.driver.ts @@ -1,34 +1,30 @@ import { promises as fs } from 'fs'; import { spawn } from 'node:child_process'; import { join } from 'path'; -import { dirname } from 'node:path'; - -import { FileFolder } from 'twenty-shared/types'; import { type LogicFunctionExecuteParams, type LogicFunctionExecuteResult, - type LogicFunctionExecutorDriver, -} from 'src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-executor-driver.interface'; + type LogicFunctionDriver, +} from 'src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-driver.interface'; import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; -import { type FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service'; import { LOGIC_FUNCTION_EXECUTOR_TMPDIR_FOLDER } from 'src/engine/core-modules/logic-function/logic-function-drivers/constants/logic-function-executor-tmpdir-folder'; -import { copyYarnEngineAndBuildDependencies } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/copy-yarn-engine-and-build-dependencies'; import { ConsoleListener } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/intercept-console'; -import { LambdaBuildDirectoryManager } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/lambda-build-directory-manager'; +import { TemporaryDirManager } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/temporary-dir-manager'; import { LogicFunctionExecutionStatus } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-execution-result.dto'; -import { getRelativePathFromBase } from 'src/modules/workflow/workflow-builder/workflow-version-step/code-step/utils/get-code-step-handler-path.util'; +import { copyYarnEngineAndBuildDependencies } from 'src/engine/core-modules/application-layer/utils/copy-yarn-engine-and-build-dependencies'; +import type { LogicFunctionResourceService } from 'src/engine/core-modules/logic-function/logic-function-resource/logic-function-resource.service'; export interface LocalDriverOptions { - fileStorageService: FileStorageService; + logicFunctionResourceService: LogicFunctionResourceService; } -export class LocalDriver implements LogicFunctionExecutorDriver { - private readonly fileStorageService: FileStorageService; +export class LocalDriver implements LogicFunctionDriver { + private readonly logicFunctionResourceService: LogicFunctionResourceService; constructor(options: LocalDriverOptions) { - this.fileStorageService = options.fileStorageService; + this.logicFunctionResourceService = options.logicFunctionResourceService; } private getInMemoryLayerFolderPath = (flatApplication: FlatApplication) => { @@ -37,33 +33,6 @@ export class LocalDriver implements LogicFunctionExecutorDriver { return join(LOGIC_FUNCTION_EXECUTOR_TMPDIR_FOLDER, checksum); }; - private async copyDependenciesInMemory({ - applicationUniversalIdentifier, - workspaceId, - inMemoryLayerFolderPath, - }: { - applicationUniversalIdentifier: string; - workspaceId: string; - inMemoryLayerFolderPath: string; - }) { - await Promise.all([ - this.fileStorageService.downloadFile({ - workspaceId, - applicationUniversalIdentifier, - fileFolder: FileFolder.Dependencies, - resourcePath: 'package.json', - localPath: join(inMemoryLayerFolderPath, 'package.json'), - }), - this.fileStorageService.downloadFile({ - workspaceId, - applicationUniversalIdentifier, - fileFolder: FileFolder.Dependencies, - resourcePath: 'yarn.lock', - localPath: join(inMemoryLayerFolderPath, 'yarn.lock'), - }), - ]); - } - private async createLayerIfNotExists({ flatApplication, applicationUniversalIdentifier, @@ -77,10 +46,10 @@ export class LocalDriver implements LogicFunctionExecutorDriver { try { await fs.access(inMemoryLayerFolderPath); } catch { - await this.copyDependenciesInMemory({ + await this.logicFunctionResourceService.copyDependenciesInMemory({ applicationUniversalIdentifier, workspaceId: flatApplication.workspaceId, - inMemoryLayerFolderPath, + inMemoryFolderPath: inMemoryLayerFolderPath, }); await copyYarnEngineAndBuildDependencies(inMemoryLayerFolderPath); } @@ -115,19 +84,21 @@ export class LocalDriver implements LogicFunctionExecutorDriver { const startTime = Date.now(); - const lambdaBuildDirectoryManager = new LambdaBuildDirectoryManager(); + const temporaryDirManager = new TemporaryDirManager(); try { - const { sourceTemporaryDir } = await lambdaBuildDirectoryManager.init(); + const { sourceTemporaryDir } = await temporaryDirManager.init(); - const baseFolderPath = dirname(flatLogicFunction.builtHandlerPath); + const inMemoryBuiltHandlerPath = join( + sourceTemporaryDir, + flatLogicFunction.builtHandlerPath, + ); - await this.fileStorageService.downloadFolder({ + await this.logicFunctionResourceService.copyBuiltCodeInMemory({ workspaceId: flatLogicFunction.workspaceId, applicationUniversalIdentifier, - fileFolder: FileFolder.BuiltLogicFunction, - resourcePath: baseFolderPath, - localPath: sourceTemporaryDir, + builtHandlerPath: flatLogicFunction.builtHandlerPath, + inMemoryDestinationPath: inMemoryBuiltHandlerPath, }); try { @@ -179,15 +150,9 @@ export class LocalDriver implements LogicFunctionExecutorDriver { }); try { - const relativeBuiltPath = getRelativePathFromBase( - flatLogicFunction.builtHandlerPath, - baseFolderPath, - ); - const builtBundleFilePath = join(sourceTemporaryDir, relativeBuiltPath); - const runnerPath = await this.writeBootstrapRunner({ dir: sourceTemporaryDir, - builtFileAbsPath: builtBundleFilePath, + builtFileAbsPath: inMemoryBuiltHandlerPath, handlerName: flatLogicFunction.handlerName, }); @@ -240,7 +205,7 @@ export class LocalDriver implements LogicFunctionExecutorDriver { consoleListener.release(); } } finally { - await lambdaBuildDirectoryManager.clean(); + await temporaryDirManager.clean(); } } diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/factories/logic-function-module.factory.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/factories/logic-function-module.factory.ts similarity index 66% rename from packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/factories/logic-function-module.factory.ts rename to packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/factories/logic-function-module.factory.ts index aa5d73bb65b..ceb098eaf19 100644 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/factories/logic-function-module.factory.ts +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/factories/logic-function-module.factory.ts @@ -1,33 +1,33 @@ import { fromNodeProviderChain } from '@aws-sdk/credential-providers'; import { - LogicFunctionExecutorDriverType, - type LogicFunctionExecutorModuleOptions, -} from 'src/engine/core-modules/logic-function/logic-function-executor/interfaces/logic-function-executor.interface'; + LogicFunctionDriverType, + type LogicFunctionModuleOptions, +} from 'src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-driver.interface'; -import { type FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service'; import { type TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service'; +import type { LogicFunctionResourceService } from 'src/engine/core-modules/logic-function/logic-function-resource/logic-function-resource.service'; export const logicFunctionModuleFactory = async ( twentyConfigService: TwentyConfigService, - fileStorageService: FileStorageService, -): Promise => { + logicFunctionResourceService: LogicFunctionResourceService, +): Promise => { const driverType = twentyConfigService.get('LOGIC_FUNCTION_TYPE'); - const options = { fileStorageService }; + const options = { logicFunctionResourceService }; switch (driverType) { - case LogicFunctionExecutorDriverType.DISABLED: { + case LogicFunctionDriverType.DISABLED: { return { - type: LogicFunctionExecutorDriverType.DISABLED, + type: LogicFunctionDriverType.DISABLED, }; } - case LogicFunctionExecutorDriverType.LOCAL: { + case LogicFunctionDriverType.LOCAL: { return { - type: LogicFunctionExecutorDriverType.LOCAL, + type: LogicFunctionDriverType.LOCAL, options, }; } - case LogicFunctionExecutorDriverType.LAMBDA: { + case LogicFunctionDriverType.LAMBDA: { const region = twentyConfigService.get('LOGIC_FUNCTION_LAMBDA_REGION'); const accessKeyId = twentyConfigService.get( 'LOGIC_FUNCTION_LAMBDA_ACCESS_KEY_ID', @@ -42,7 +42,7 @@ export const logicFunctionModuleFactory = async ( ); return { - type: LogicFunctionExecutorDriverType.LAMBDA, + type: LogicFunctionDriverType.LAMBDA, options: { ...options, credentials: accessKeyId diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-driver.interface.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-driver.interface.ts new file mode 100644 index 00000000000..285e54521ce --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-driver.interface.ts @@ -0,0 +1,69 @@ +import type { FactoryProvider, ModuleMetadata } from '@nestjs/common'; + +import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; +import { type LogicFunctionExecutionStatus } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-execution-result.dto'; +import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type'; +import type { LocalDriverOptions } from 'src/engine/core-modules/logic-function/logic-function-drivers/drivers/local.driver'; +import type { LambdaDriverOptions } from 'src/engine/core-modules/logic-function/logic-function-drivers/drivers/lambda.driver'; + +export type LogicFunctionExecuteError = { + errorType: string; + errorMessage: string; + stackTrace: string | string[]; +}; + +export type LogicFunctionExecuteResult = { + data: object | null; + duration: number; + logs: string; + status: LogicFunctionExecutionStatus; + error?: LogicFunctionExecuteError; +}; + +export type LogicFunctionExecuteParams = { + flatLogicFunction: FlatLogicFunction; + flatApplication: FlatApplication; + applicationUniversalIdentifier: string; + payload: object; + env?: Record; +}; + +export interface LogicFunctionDriver { + delete(flatLogicFunction: FlatLogicFunction): Promise; + execute( + params: LogicFunctionExecuteParams, + ): Promise; +} + +export enum LogicFunctionDriverType { + DISABLED = 'DISABLED', + LAMBDA = 'LAMBDA', + LOCAL = 'LOCAL', +} + +export interface DisabledDriverFactoryOptions { + type: LogicFunctionDriverType.DISABLED; +} + +export interface LocalDriverFactoryOptions { + type: LogicFunctionDriverType.LOCAL; + options: LocalDriverOptions; +} + +export interface LambdaDriverFactoryOptions { + type: LogicFunctionDriverType.LAMBDA; + options: LambdaDriverOptions; +} + +export type LogicFunctionModuleOptions = + | DisabledDriverFactoryOptions + | LocalDriverFactoryOptions + | LambdaDriverFactoryOptions; + +export type LogicFunctionModuleAsyncOptions = { + useFactory: ( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ...args: any[] + ) => LogicFunctionModuleOptions | Promise; +} & Pick & + Pick; diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-executor-driver.interface.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-executor-driver.interface.ts deleted file mode 100644 index 1f00c526337..00000000000 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-executor-driver.interface.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; -import { type LogicFunctionExecutionStatus } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-execution-result.dto'; -import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type'; - -export type LogicFunctionExecuteError = { - errorType: string; - errorMessage: string; - stackTrace: string | string[]; -}; - -export type LogicFunctionExecuteResult = { - data: object | null; - duration: number; - logs: string; - status: LogicFunctionExecutionStatus; - error?: LogicFunctionExecuteError; -}; - -export type LogicFunctionExecuteParams = { - flatLogicFunction: FlatLogicFunction; - flatApplication: FlatApplication; - applicationUniversalIdentifier: string; - payload: object; - env?: Record; -}; - -export interface LogicFunctionExecutorDriver { - delete(flatLogicFunction: FlatLogicFunction): Promise; - execute( - params: LogicFunctionExecuteParams, - ): Promise; -} diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/layers/1/package.json b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/layers/1/package.json deleted file mode 100644 index 44d30fa7747..00000000000 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/layers/1/package.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "dependencies": { - "@types/bcrypt": "^5.0.2", - "@types/deep-equal": "^1.0.4", - "@types/lodash.camelcase": "^4.3.9", - "@types/lodash.compact": "^3.0.9", - "@types/lodash.groupby": "^4.6.9", - "@types/lodash.identity": "^3.0.9", - "@types/lodash.isempty": "^4.4.9", - "@types/lodash.isequal": "^4.5.8", - "@types/lodash.isobject": "^3.0.9", - "@types/lodash.kebabcase": "^4.1.9", - "@types/lodash.mapvalues": "^4.6.9", - "@types/lodash.omit": "^4.5.9", - "@types/lodash.pickby": "^4.6.9", - "@types/lodash.snakecase": "^4.1.9", - "@types/lodash.upperfirst": "^4.3.9", - "@types/uuid": "^10.0.0", - "archiver": "^7.0.1", - "axios": "^1.12.0", - "bcrypt": "^5.1.1", - "body-parser": "^1.20.4", - "deep-equal": "^2.2.3", - "jsonwebtoken": "^9.0.2", - "lodash.camelcase": "^4.3.0", - "lodash.chunk": "^4.2.0", - "lodash.compact": "^3.0.1", - "lodash.groupby": "^4.6.0", - "lodash.identity": "^3.0.0", - "lodash.isempty": "^4.4.0", - "lodash.isequal": "^4.5.0", - "lodash.isobject": "^3.0.2", - "lodash.kebabcase": "^4.1.1", - "lodash.mapvalues": "^4.6.0", - "lodash.merge": "^4.6.2", - "lodash.omit": "^4.5.0", - "lodash.pickby": "^4.6.0", - "lodash.snakecase": "^4.1.1", - "lodash.upperfirst": "^4.3.1", - "nodemailer": "^7.0.11", - "sharp": "^0.33.5", - "uuid": "^10.0.0", - "winston": "^3.14.2" - } -} diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/layers/1/yarn.lock b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/layers/1/yarn.lock deleted file mode 100644 index 54b343e6b5a..00000000000 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/layers/1/yarn.lock +++ /dev/null @@ -1,3374 +0,0 @@ -# This file is generated by running "yarn install" inside your project. -# Manual changes might be lost - proceed with caution! - -__metadata: - version: 8 - cacheKey: 10c0 - -"@colors/colors@npm:1.6.0, @colors/colors@npm:^1.6.0": - version: 1.6.0 - resolution: "@colors/colors@npm:1.6.0" - checksum: 10c0/9328a0778a5b0db243af54455b79a69e3fb21122d6c15ef9e9fcc94881d8d17352d8b2b2590f9bdd46fac5c2d6c1636dcfc14358a20c70e22daf89e1a759b629 - languageName: node - linkType: hard - -"@dabh/diagnostics@npm:^2.0.2": - version: 2.0.3 - resolution: "@dabh/diagnostics@npm:2.0.3" - dependencies: - colorspace: "npm:1.1.x" - enabled: "npm:2.0.x" - kuler: "npm:^2.0.0" - checksum: 10c0/a5133df8492802465ed01f2f0a5784585241a1030c362d54a602ed1839816d6c93d71dde05cf2ddb4fd0796238c19774406bd62fa2564b637907b495f52425fe - languageName: node - linkType: hard - -"@emnapi/runtime@npm:^1.2.0": - version: 1.2.0 - resolution: "@emnapi/runtime@npm:1.2.0" - dependencies: - tslib: "npm:^2.4.0" - checksum: 10c0/7005ff8b67724c9e61b6cd79a3decbdb2ce25d24abd4d3d187472f200ee6e573329c30264335125fb136bd813aa9cf9f4f7c9391d04b07dd1e63ce0a3427be57 - languageName: node - linkType: hard - -"@img/sharp-darwin-arm64@npm:0.33.5": - version: 0.33.5 - resolution: "@img/sharp-darwin-arm64@npm:0.33.5" - dependencies: - "@img/sharp-libvips-darwin-arm64": "npm:1.0.4" - dependenciesMeta: - "@img/sharp-libvips-darwin-arm64": - optional: true - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - -"@img/sharp-darwin-x64@npm:0.33.5": - version: 0.33.5 - resolution: "@img/sharp-darwin-x64@npm:0.33.5" - dependencies: - "@img/sharp-libvips-darwin-x64": "npm:1.0.4" - dependenciesMeta: - "@img/sharp-libvips-darwin-x64": - optional: true - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"@img/sharp-libvips-darwin-arm64@npm:1.0.4": - version: 1.0.4 - resolution: "@img/sharp-libvips-darwin-arm64@npm:1.0.4" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - -"@img/sharp-libvips-darwin-x64@npm:1.0.4": - version: 1.0.4 - resolution: "@img/sharp-libvips-darwin-x64@npm:1.0.4" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"@img/sharp-libvips-linux-arm64@npm:1.0.4": - version: 1.0.4 - resolution: "@img/sharp-libvips-linux-arm64@npm:1.0.4" - conditions: os=linux & cpu=arm64 & libc=glibc - languageName: node - linkType: hard - -"@img/sharp-libvips-linux-arm@npm:1.0.5": - version: 1.0.5 - resolution: "@img/sharp-libvips-linux-arm@npm:1.0.5" - conditions: os=linux & cpu=arm & libc=glibc - languageName: node - linkType: hard - -"@img/sharp-libvips-linux-s390x@npm:1.0.4": - version: 1.0.4 - resolution: "@img/sharp-libvips-linux-s390x@npm:1.0.4" - conditions: os=linux & cpu=s390x & libc=glibc - languageName: node - linkType: hard - -"@img/sharp-libvips-linux-x64@npm:1.0.4": - version: 1.0.4 - resolution: "@img/sharp-libvips-linux-x64@npm:1.0.4" - conditions: os=linux & cpu=x64 & libc=glibc - languageName: node - linkType: hard - -"@img/sharp-libvips-linuxmusl-arm64@npm:1.0.4": - version: 1.0.4 - resolution: "@img/sharp-libvips-linuxmusl-arm64@npm:1.0.4" - conditions: os=linux & cpu=arm64 & libc=musl - languageName: node - linkType: hard - -"@img/sharp-libvips-linuxmusl-x64@npm:1.0.4": - version: 1.0.4 - resolution: "@img/sharp-libvips-linuxmusl-x64@npm:1.0.4" - conditions: os=linux & cpu=x64 & libc=musl - languageName: node - linkType: hard - -"@img/sharp-linux-arm64@npm:0.33.5": - version: 0.33.5 - resolution: "@img/sharp-linux-arm64@npm:0.33.5" - dependencies: - "@img/sharp-libvips-linux-arm64": "npm:1.0.4" - dependenciesMeta: - "@img/sharp-libvips-linux-arm64": - optional: true - conditions: os=linux & cpu=arm64 & libc=glibc - languageName: node - linkType: hard - -"@img/sharp-linux-arm@npm:0.33.5": - version: 0.33.5 - resolution: "@img/sharp-linux-arm@npm:0.33.5" - dependencies: - "@img/sharp-libvips-linux-arm": "npm:1.0.5" - dependenciesMeta: - "@img/sharp-libvips-linux-arm": - optional: true - conditions: os=linux & cpu=arm & libc=glibc - languageName: node - linkType: hard - -"@img/sharp-linux-s390x@npm:0.33.5": - version: 0.33.5 - resolution: "@img/sharp-linux-s390x@npm:0.33.5" - dependencies: - "@img/sharp-libvips-linux-s390x": "npm:1.0.4" - dependenciesMeta: - "@img/sharp-libvips-linux-s390x": - optional: true - conditions: os=linux & cpu=s390x & libc=glibc - languageName: node - linkType: hard - -"@img/sharp-linux-x64@npm:0.33.5": - version: 0.33.5 - resolution: "@img/sharp-linux-x64@npm:0.33.5" - dependencies: - "@img/sharp-libvips-linux-x64": "npm:1.0.4" - dependenciesMeta: - "@img/sharp-libvips-linux-x64": - optional: true - conditions: os=linux & cpu=x64 & libc=glibc - languageName: node - linkType: hard - -"@img/sharp-linuxmusl-arm64@npm:0.33.5": - version: 0.33.5 - resolution: "@img/sharp-linuxmusl-arm64@npm:0.33.5" - dependencies: - "@img/sharp-libvips-linuxmusl-arm64": "npm:1.0.4" - dependenciesMeta: - "@img/sharp-libvips-linuxmusl-arm64": - optional: true - conditions: os=linux & cpu=arm64 & libc=musl - languageName: node - linkType: hard - -"@img/sharp-linuxmusl-x64@npm:0.33.5": - version: 0.33.5 - resolution: "@img/sharp-linuxmusl-x64@npm:0.33.5" - dependencies: - "@img/sharp-libvips-linuxmusl-x64": "npm:1.0.4" - dependenciesMeta: - "@img/sharp-libvips-linuxmusl-x64": - optional: true - conditions: os=linux & cpu=x64 & libc=musl - languageName: node - linkType: hard - -"@img/sharp-wasm32@npm:0.33.5": - version: 0.33.5 - resolution: "@img/sharp-wasm32@npm:0.33.5" - dependencies: - "@emnapi/runtime": "npm:^1.2.0" - conditions: cpu=wasm32 - languageName: node - linkType: hard - -"@img/sharp-win32-ia32@npm:0.33.5": - version: 0.33.5 - resolution: "@img/sharp-win32-ia32@npm:0.33.5" - conditions: os=win32 & cpu=ia32 - languageName: node - linkType: hard - -"@img/sharp-win32-x64@npm:0.33.5": - version: 0.33.5 - resolution: "@img/sharp-win32-x64@npm:0.33.5" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - -"@isaacs/cliui@npm:^8.0.2": - version: 8.0.2 - resolution: "@isaacs/cliui@npm:8.0.2" - dependencies: - string-width: "npm:^5.1.2" - string-width-cjs: "npm:string-width@^4.2.0" - strip-ansi: "npm:^7.0.1" - strip-ansi-cjs: "npm:strip-ansi@^6.0.1" - wrap-ansi: "npm:^8.1.0" - wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0" - checksum: 10c0/b1bf42535d49f11dc137f18d5e4e63a28c5569de438a221c369483731e9dac9fb797af554e8bf02b6192d1e5eba6e6402cf93900c3d0ac86391d00d04876789e - languageName: node - linkType: hard - -"@mapbox/node-pre-gyp@npm:^1.0.11": - version: 1.0.11 - resolution: "@mapbox/node-pre-gyp@npm:1.0.11" - dependencies: - detect-libc: "npm:^2.0.0" - https-proxy-agent: "npm:^5.0.0" - make-dir: "npm:^3.1.0" - node-fetch: "npm:^2.6.7" - nopt: "npm:^5.0.0" - npmlog: "npm:^5.0.1" - rimraf: "npm:^3.0.2" - semver: "npm:^7.3.5" - tar: "npm:^6.1.11" - bin: - node-pre-gyp: bin/node-pre-gyp - checksum: 10c0/2b24b93c31beca1c91336fa3b3769fda98e202fb7f9771f0f4062588d36dcc30fcf8118c36aa747fa7f7610d8cf601872bdaaf62ce7822bb08b545d1bbe086cc - languageName: node - linkType: hard - -"@npmcli/agent@npm:^2.0.0": - version: 2.2.2 - resolution: "@npmcli/agent@npm:2.2.2" - dependencies: - agent-base: "npm:^7.1.0" - http-proxy-agent: "npm:^7.0.0" - https-proxy-agent: "npm:^7.0.1" - lru-cache: "npm:^10.0.1" - socks-proxy-agent: "npm:^8.0.3" - checksum: 10c0/325e0db7b287d4154ecd164c0815c08007abfb07653cc57bceded17bb7fd240998a3cbdbe87d700e30bef494885eccc725ab73b668020811d56623d145b524ae - languageName: node - linkType: hard - -"@npmcli/fs@npm:^3.1.0": - version: 3.1.1 - resolution: "@npmcli/fs@npm:3.1.1" - dependencies: - semver: "npm:^7.3.5" - checksum: 10c0/c37a5b4842bfdece3d14dfdb054f73fe15ed2d3da61b34ff76629fb5b1731647c49166fd2a8bf8b56fcfa51200382385ea8909a3cbecdad612310c114d3f6c99 - languageName: node - linkType: hard - -"@pkgjs/parseargs@npm:^0.11.0": - version: 0.11.0 - resolution: "@pkgjs/parseargs@npm:0.11.0" - checksum: 10c0/5bd7576bb1b38a47a7fc7b51ac9f38748e772beebc56200450c4a817d712232b8f1d3ef70532c80840243c657d491cf6a6be1e3a214cff907645819fdc34aadd - languageName: node - linkType: hard - -"@types/bcrypt@npm:^5.0.2": - version: 5.0.2 - resolution: "@types/bcrypt@npm:5.0.2" - dependencies: - "@types/node": "npm:*" - checksum: 10c0/dd7f05e183b9b1fc08ec499069febf197ab8e9c720766b5bbb5628395082e248f9a444c60882fe7788361fcadc302e21e055ab9c26a300f100e08791c353e6aa - languageName: node - linkType: hard - -"@types/deep-equal@npm:^1.0.4": - version: 1.0.4 - resolution: "@types/deep-equal@npm:1.0.4" - checksum: 10c0/583d41df5d7655b0bd5fdd4b173b045396108fad2191e1bd3b1bfc188f98d24fafff34a8a09c04f9c650c87d82e9f25a8119d269044522da0770a05075fbf74d - languageName: node - linkType: hard - -"@types/lodash.camelcase@npm:^4.3.9": - version: 4.3.9 - resolution: "@types/lodash.camelcase@npm:4.3.9" - dependencies: - "@types/lodash": "npm:*" - checksum: 10c0/d6c42c800624b75b079ff7862d258d7c8236837f8485a4fe9f92e5e7d3e9ccaef2eb202e24e8f04d209ad5573c85edc7871d0cecc831454a501d594b11f1311b - languageName: node - linkType: hard - -"@types/lodash.compact@npm:^3.0.9": - version: 3.0.9 - resolution: "@types/lodash.compact@npm:3.0.9" - dependencies: - "@types/lodash": "npm:*" - checksum: 10c0/9eff2fecd6773352f5b762a2c58f261e3c83f61d7297efe94b08f9a4b524b24ccc2de5e8d728e2ffd42472fa06973df0856e474eb74b5e614813d26d7436efc6 - languageName: node - linkType: hard - -"@types/lodash.groupby@npm:^4.6.9": - version: 4.6.9 - resolution: "@types/lodash.groupby@npm:4.6.9" - dependencies: - "@types/lodash": "npm:*" - checksum: 10c0/1302531f76da99cc8f1bbd486a8c7048a833352b12c39eb5b2ded01173dd5fff76f2c7ace04f08b51c55840271170f1cfbffe4e454dde8597c3ee996e70d4e11 - languageName: node - linkType: hard - -"@types/lodash.identity@npm:^3.0.9": - version: 3.0.9 - resolution: "@types/lodash.identity@npm:3.0.9" - dependencies: - "@types/lodash": "npm:*" - checksum: 10c0/fac961d04fe704b04bef608e9bffd8c7ea44d1d6f014c01ff520cd63e22fa58aa843d2017c18e31bcf21b35124b9c5c7dbf12b33362020d15f5c0591ff4cbc19 - languageName: node - linkType: hard - -"@types/lodash.isempty@npm:^4.4.9": - version: 4.4.9 - resolution: "@types/lodash.isempty@npm:4.4.9" - dependencies: - "@types/lodash": "npm:*" - checksum: 10c0/581b3b1e896524b00cb32dc08f1aea328cec0ab95720f24e0f6d9e8a2c9be5b65e4ad030ec45f58f656ab8dcf555f039863862e04c91051a24ee27cac8a994ab - languageName: node - linkType: hard - -"@types/lodash.isequal@npm:^4.5.8": - version: 4.5.8 - resolution: "@types/lodash.isequal@npm:4.5.8" - dependencies: - "@types/lodash": "npm:*" - checksum: 10c0/6db28cacf165d55421fbf2970ccfb1682a7b82b743bb7aba4398fa8ab98f1711fca2fe4afa1aa2b7b4afb3eff76c8aca13b22206f5efeb038d99e41300589bca - languageName: node - linkType: hard - -"@types/lodash.isobject@npm:^3.0.9": - version: 3.0.9 - resolution: "@types/lodash.isobject@npm:3.0.9" - dependencies: - "@types/lodash": "npm:*" - checksum: 10c0/ab35ebaf0e53bce9f419194e8857da01a0f4ed668b2a61860f724e6ecedaad72bfe636bd6d98f9969cadf654595e317d19f7ba05cc3dfbea49966feb71ab687a - languageName: node - linkType: hard - -"@types/lodash.kebabcase@npm:^4.1.9": - version: 4.1.9 - resolution: "@types/lodash.kebabcase@npm:4.1.9" - dependencies: - "@types/lodash": "npm:*" - checksum: 10c0/f00fbfb891fd1883e3fab2286fa2b23a013550b3498013c8c8c5e3ed437f52543afe8e8dc899b4f3317bab8db403bb281de863274a6fa12f088667378fd7b475 - languageName: node - linkType: hard - -"@types/lodash.mapvalues@npm:^4.6.9": - version: 4.6.9 - resolution: "@types/lodash.mapvalues@npm:4.6.9" - dependencies: - "@types/lodash": "npm:*" - checksum: 10c0/09216965c2c64854c8c765f38f436333e931b98638a0b9d996bda7b6d538593a4cfe53cad7415d50593be48d76798763b97dc2d7925ab200dce1fa5b630ed3b4 - languageName: node - linkType: hard - -"@types/lodash.omit@npm:^4.5.9": - version: 4.5.9 - resolution: "@types/lodash.omit@npm:4.5.9" - dependencies: - "@types/lodash": "npm:*" - checksum: 10c0/3b60c8ee8e9a691392d9a3ceabb32c85f888784bd3307eac3de01aeb7ff37383dc8899f027fe852641f5e0f56158fb19785cc3d20a4922e85b5810f14cba23f6 - languageName: node - linkType: hard - -"@types/lodash.pickby@npm:^4.6.9": - version: 4.6.9 - resolution: "@types/lodash.pickby@npm:4.6.9" - dependencies: - "@types/lodash": "npm:*" - checksum: 10c0/a572e22a24f73e9041e1beca8bb8125875734471c440f7fe9ff48ced10e6ffe45a2392098940f4c1327252e3455afd0e2ea0cc3908a2e3bd0bafe60335e27e6c - languageName: node - linkType: hard - -"@types/lodash.snakecase@npm:^4.1.9": - version: 4.1.9 - resolution: "@types/lodash.snakecase@npm:4.1.9" - dependencies: - "@types/lodash": "npm:*" - checksum: 10c0/69c565f5d914628314de307ac30bcaf6060d2a1e782e87bc25a9c0d287ad06a29cc9308af285ea49e485dba3d909d4fc3b0a0b279cf7545492b37926f1fb2f8f - languageName: node - linkType: hard - -"@types/lodash.upperfirst@npm:^4.3.9": - version: 4.3.9 - resolution: "@types/lodash.upperfirst@npm:4.3.9" - dependencies: - "@types/lodash": "npm:*" - checksum: 10c0/4f6be2e9d4b03a0739972fce3044c28bdf7fd96d5a3c773464f7b8e035d687e46878ad9b958a2fac448807636c0675962e3fbedf20af4fc74bc91bbaf471114f - languageName: node - linkType: hard - -"@types/lodash@npm:*": - version: 4.17.7 - resolution: "@types/lodash@npm:4.17.7" - checksum: 10c0/40c965b5ffdcf7ff5c9105307ee08b782da228c01b5c0529122c554c64f6b7168fc8f11dc79aa7bae4e67e17efafaba685dc3a47e294dbf52a65ed2b67100561 - languageName: node - linkType: hard - -"@types/node@npm:*": - version: 22.5.1 - resolution: "@types/node@npm:22.5.1" - dependencies: - undici-types: "npm:~6.19.2" - checksum: 10c0/35373176d8a1d4e16004a1ed303e68d39e4c6341024dc056f2577982df98c1a045a6b677f12ed557796f09bbf7d621f428f6874cc37ed28f7b336fa604b5f6a6 - languageName: node - linkType: hard - -"@types/triple-beam@npm:^1.3.2": - version: 1.3.5 - resolution: "@types/triple-beam@npm:1.3.5" - checksum: 10c0/d5d7f25da612f6d79266f4f1bb9c1ef8f1684e9f60abab251e1261170631062b656ba26ff22631f2760caeafd372abc41e64867cde27fba54fafb73a35b9056a - languageName: node - linkType: hard - -"@types/uuid@npm:^10.0.0": - version: 10.0.0 - resolution: "@types/uuid@npm:10.0.0" - checksum: 10c0/9a1404bf287164481cb9b97f6bb638f78f955be57c40c6513b7655160beb29df6f84c915aaf4089a1559c216557dc4d2f79b48d978742d3ae10b937420ddac60 - languageName: node - linkType: hard - -"abbrev@npm:1": - version: 1.1.1 - resolution: "abbrev@npm:1.1.1" - checksum: 10c0/3f762677702acb24f65e813070e306c61fafe25d4b2583f9dfc935131f774863f3addd5741572ed576bd69cabe473c5af18e1e108b829cb7b6b4747884f726e6 - languageName: node - linkType: hard - -"abbrev@npm:^2.0.0": - version: 2.0.0 - resolution: "abbrev@npm:2.0.0" - checksum: 10c0/f742a5a107473946f426c691c08daba61a1d15942616f300b5d32fd735be88fef5cba24201757b6c407fd564555fb48c751cfa33519b2605c8a7aadd22baf372 - languageName: node - linkType: hard - -"abort-controller@npm:^3.0.0": - version: 3.0.0 - resolution: "abort-controller@npm:3.0.0" - dependencies: - event-target-shim: "npm:^5.0.0" - checksum: 10c0/90ccc50f010250152509a344eb2e71977fbf8db0ab8f1061197e3275ddf6c61a41a6edfd7b9409c664513131dd96e962065415325ef23efa5db931b382d24ca5 - languageName: node - linkType: hard - -"agent-base@npm:6": - version: 6.0.2 - resolution: "agent-base@npm:6.0.2" - dependencies: - debug: "npm:4" - checksum: 10c0/dc4f757e40b5f3e3d674bc9beb4f1048f4ee83af189bae39be99f57bf1f48dde166a8b0a5342a84b5944ee8e6ed1e5a9d801858f4ad44764e84957122fe46261 - languageName: node - linkType: hard - -"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0, agent-base@npm:^7.1.1": - version: 7.1.1 - resolution: "agent-base@npm:7.1.1" - dependencies: - debug: "npm:^4.3.4" - checksum: 10c0/e59ce7bed9c63bf071a30cc471f2933862044c97fd9958967bfe22521d7a0f601ce4ed5a8c011799d0c726ca70312142ae193bbebb60f576b52be19d4a363b50 - languageName: node - linkType: hard - -"aggregate-error@npm:^3.0.0": - version: 3.1.0 - resolution: "aggregate-error@npm:3.1.0" - dependencies: - clean-stack: "npm:^2.0.0" - indent-string: "npm:^4.0.0" - checksum: 10c0/a42f67faa79e3e6687a4923050e7c9807db3848a037076f791d10e092677d65c1d2d863b7848560699f40fc0502c19f40963fb1cd1fb3d338a7423df8e45e039 - languageName: node - linkType: hard - -"ansi-regex@npm:^5.0.1": - version: 5.0.1 - resolution: "ansi-regex@npm:5.0.1" - checksum: 10c0/9a64bb8627b434ba9327b60c027742e5d17ac69277960d041898596271d992d4d52ba7267a63ca10232e29f6107fc8a835f6ce8d719b88c5f8493f8254813737 - languageName: node - linkType: hard - -"ansi-regex@npm:^6.0.1": - version: 6.0.1 - resolution: "ansi-regex@npm:6.0.1" - checksum: 10c0/cbe16dbd2c6b2735d1df7976a7070dd277326434f0212f43abf6d87674095d247968209babdaad31bb00882fa68807256ba9be340eec2f1004de14ca75f52a08 - languageName: node - linkType: hard - -"ansi-styles@npm:^4.0.0": - version: 4.3.0 - resolution: "ansi-styles@npm:4.3.0" - dependencies: - color-convert: "npm:^2.0.1" - checksum: 10c0/895a23929da416f2bd3de7e9cb4eabd340949328ab85ddd6e484a637d8f6820d485f53933446f5291c3b760cbc488beb8e88573dd0f9c7daf83dccc8fe81b041 - languageName: node - linkType: hard - -"ansi-styles@npm:^6.1.0": - version: 6.2.1 - resolution: "ansi-styles@npm:6.2.1" - checksum: 10c0/5d1ec38c123984bcedd996eac680d548f31828bd679a66db2bdf11844634dde55fec3efa9c6bb1d89056a5e79c1ac540c4c784d592ea1d25028a92227d2f2d5c - languageName: node - linkType: hard - -"aproba@npm:^1.0.3 || ^2.0.0": - version: 2.0.0 - resolution: "aproba@npm:2.0.0" - checksum: 10c0/d06e26384a8f6245d8c8896e138c0388824e259a329e0c9f196b4fa533c82502a6fd449586e3604950a0c42921832a458bb3aa0aa9f0ba449cfd4f50fd0d09b5 - languageName: node - linkType: hard - -"archiver-utils@npm:^5.0.0, archiver-utils@npm:^5.0.2": - version: 5.0.2 - resolution: "archiver-utils@npm:5.0.2" - dependencies: - glob: "npm:^10.0.0" - graceful-fs: "npm:^4.2.0" - is-stream: "npm:^2.0.1" - lazystream: "npm:^1.0.0" - lodash: "npm:^4.17.15" - normalize-path: "npm:^3.0.0" - readable-stream: "npm:^4.0.0" - checksum: 10c0/3782c5fa9922186aa1a8e41ed0c2867569faa5f15c8e5e6418ea4c1b730b476e21bd68270b3ea457daf459ae23aaea070b2b9f90cf90a59def8dc79b9e4ef538 - languageName: node - linkType: hard - -"archiver@npm:^7.0.1": - version: 7.0.1 - resolution: "archiver@npm:7.0.1" - dependencies: - archiver-utils: "npm:^5.0.2" - async: "npm:^3.2.4" - buffer-crc32: "npm:^1.0.0" - readable-stream: "npm:^4.0.0" - readdir-glob: "npm:^1.1.2" - tar-stream: "npm:^3.0.0" - zip-stream: "npm:^6.0.1" - checksum: 10c0/02afd87ca16f6184f752db8e26884e6eff911c476812a0e7f7b26c4beb09f06119807f388a8e26ed2558aa8ba9db28646ebd147a4f99e46813b8b43158e1438e - languageName: node - linkType: hard - -"are-we-there-yet@npm:^2.0.0": - version: 2.0.0 - resolution: "are-we-there-yet@npm:2.0.0" - dependencies: - delegates: "npm:^1.0.0" - readable-stream: "npm:^3.6.0" - checksum: 10c0/375f753c10329153c8d66dc95e8f8b6c7cc2aa66e05cb0960bd69092b10dae22900cacc7d653ad11d26b3ecbdbfe1e8bfb6ccf0265ba8077a7d979970f16b99c - languageName: node - linkType: hard - -"array-buffer-byte-length@npm:^1.0.0": - version: 1.0.1 - resolution: "array-buffer-byte-length@npm:1.0.1" - dependencies: - call-bind: "npm:^1.0.5" - is-array-buffer: "npm:^3.0.4" - checksum: 10c0/f5cdf54527cd18a3d2852ddf73df79efec03829e7373a8322ef5df2b4ef546fb365c19c71d6b42d641cb6bfe0f1a2f19bc0ece5b533295f86d7c3d522f228917 - languageName: node - linkType: hard - -"async-function@npm:^1.0.0": - version: 1.0.0 - resolution: "async-function@npm:1.0.0" - checksum: 10c0/669a32c2cb7e45091330c680e92eaeb791bc1d4132d827591e499cd1f776ff5a873e77e5f92d0ce795a8d60f10761dec9ddfe7225a5de680f5d357f67b1aac73 - languageName: node - linkType: hard - -"async-generator-function@npm:^1.0.0": - version: 1.0.0 - resolution: "async-generator-function@npm:1.0.0" - checksum: 10c0/2c50ef856c543ad500d8d8777d347e3c1ba623b93e99c9263ecc5f965c1b12d2a140e2ab6e43c3d0b85366110696f28114649411cbcd10b452a92a2318394186 - languageName: node - linkType: hard - -"async@npm:^3.2.3, async@npm:^3.2.4": - version: 3.2.6 - resolution: "async@npm:3.2.6" - checksum: 10c0/36484bb15ceddf07078688d95e27076379cc2f87b10c03b6dd8a83e89475a3c8df5848859dd06a4c95af1e4c16fc973de0171a77f18ea00be899aca2a4f85e70 - languageName: node - linkType: hard - -"asynckit@npm:^0.4.0": - version: 0.4.0 - resolution: "asynckit@npm:0.4.0" - checksum: 10c0/d73e2ddf20c4eb9337e1b3df1a0f6159481050a5de457c55b14ea2e5cb6d90bb69e004c9af54737a5ee0917fcf2c9e25de67777bbe58261847846066ba75bc9d - languageName: node - linkType: hard - -"available-typed-arrays@npm:^1.0.7": - version: 1.0.7 - resolution: "available-typed-arrays@npm:1.0.7" - dependencies: - possible-typed-array-names: "npm:^1.0.0" - checksum: 10c0/d07226ef4f87daa01bd0fe80f8f310982e345f372926da2e5296aecc25c41cab440916bbaa4c5e1034b453af3392f67df5961124e4b586df1e99793a1374bdb2 - languageName: node - linkType: hard - -"axios@npm:^1.12.0": - version: 1.12.2 - resolution: "axios@npm:1.12.2" - dependencies: - follow-redirects: "npm:^1.15.6" - form-data: "npm:^4.0.4" - proxy-from-env: "npm:^1.1.0" - checksum: 10c0/80b063e318cf05cd33a4d991cea0162f3573481946f9129efb7766f38fde4c061c34f41a93a9f9521f02b7c9565ccbc197c099b0186543ac84a24580017adfed - languageName: node - linkType: hard - -"b4a@npm:^1.6.4": - version: 1.6.6 - resolution: "b4a@npm:1.6.6" - checksum: 10c0/56f30277666cb511a15829e38d369b114df7dc8cec4cedc09cc5d685bc0f27cb63c7bcfb58e09a19a1b3c4f2541069ab078b5328542e85d74a39620327709a38 - languageName: node - linkType: hard - -"balanced-match@npm:^1.0.0": - version: 1.0.2 - resolution: "balanced-match@npm:1.0.2" - checksum: 10c0/9308baf0a7e4838a82bbfd11e01b1cb0f0cf2893bc1676c27c2a8c0e70cbae1c59120c3268517a8ae7fb6376b4639ef81ca22582611dbee4ed28df945134aaee - languageName: node - linkType: hard - -"bare-events@npm:^2.2.0": - version: 2.4.2 - resolution: "bare-events@npm:2.4.2" - checksum: 10c0/09fa923061f31f815e83504e2ed4a8ba87732a01db40a7fae703dbb7eef7f05d99264b5e186074cbe9698213990d1af564c62cca07a5ff88baea8099ad9a6303 - languageName: node - linkType: hard - -"base64-js@npm:^1.3.1": - version: 1.5.1 - resolution: "base64-js@npm:1.5.1" - checksum: 10c0/f23823513b63173a001030fae4f2dabe283b99a9d324ade3ad3d148e218134676f1ee8568c877cd79ec1c53158dcf2d2ba527a97c606618928ba99dd930102bf - languageName: node - linkType: hard - -"bcrypt@npm:^5.1.1": - version: 5.1.1 - resolution: "bcrypt@npm:5.1.1" - dependencies: - "@mapbox/node-pre-gyp": "npm:^1.0.11" - node-addon-api: "npm:^5.0.0" - checksum: 10c0/743231158c866bddc46f25eb8e9617fe38bc1a6f5f3052aba35e361d349b7f8fb80e96b45c48a4c23c45c29967ccd11c81cf31166454fc0ab019801c336cab40 - languageName: node - linkType: hard - -"body-parser@npm:^1.20.4": - version: 1.20.4 - resolution: "body-parser@npm:1.20.4" - dependencies: - bytes: "npm:~3.1.2" - content-type: "npm:~1.0.5" - debug: "npm:2.6.9" - depd: "npm:2.0.0" - destroy: "npm:~1.2.0" - http-errors: "npm:~2.0.1" - iconv-lite: "npm:~0.4.24" - on-finished: "npm:~2.4.1" - qs: "npm:~6.14.0" - raw-body: "npm:~2.5.3" - type-is: "npm:~1.6.18" - unpipe: "npm:~1.0.0" - checksum: 10c0/569c1e896297d1fcd8f34026c8d0ab70b90d45343c15c5d8dff5de2bad08125fc1e2f8c2f3f4c1ac6c0caaad115218202594d37dcb8d89d9b5dcae1c2b736aa9 - languageName: node - linkType: hard - -"brace-expansion@npm:^1.1.7": - version: 1.1.12 - resolution: "brace-expansion@npm:1.1.12" - dependencies: - balanced-match: "npm:^1.0.0" - concat-map: "npm:0.0.1" - checksum: 10c0/975fecac2bb7758c062c20d0b3b6288c7cc895219ee25f0a64a9de662dbac981ff0b6e89909c3897c1f84fa353113a721923afdec5f8b2350255b097f12b1f73 - languageName: node - linkType: hard - -"brace-expansion@npm:^2.0.1": - version: 2.0.2 - resolution: "brace-expansion@npm:2.0.2" - dependencies: - balanced-match: "npm:^1.0.0" - checksum: 10c0/6d117a4c793488af86b83172deb6af143e94c17bc53b0b3cec259733923b4ca84679d506ac261f4ba3c7ed37c46018e2ff442f9ce453af8643ecd64f4a54e6cf - languageName: node - linkType: hard - -"buffer-crc32@npm:^1.0.0": - version: 1.0.0 - resolution: "buffer-crc32@npm:1.0.0" - checksum: 10c0/8b86e161cee4bb48d5fa622cbae4c18f25e4857e5203b89e23de59e627ab26beb82d9d7999f2b8de02580165f61f83f997beaf02980cdf06affd175b651921ab - languageName: node - linkType: hard - -"buffer-equal-constant-time@npm:^1.0.1": - version: 1.0.1 - resolution: "buffer-equal-constant-time@npm:1.0.1" - checksum: 10c0/fb2294e64d23c573d0dd1f1e7a466c3e978fe94a4e0f8183937912ca374619773bef8e2aceb854129d2efecbbc515bbd0cc78d2734a3e3031edb0888531bbc8e - languageName: node - linkType: hard - -"buffer@npm:^6.0.3": - version: 6.0.3 - resolution: "buffer@npm:6.0.3" - dependencies: - base64-js: "npm:^1.3.1" - ieee754: "npm:^1.2.1" - checksum: 10c0/2a905fbbcde73cc5d8bd18d1caa23715d5f83a5935867c2329f0ac06104204ba7947be098fe1317fbd8830e26090ff8e764f08cd14fefc977bb248c3487bcbd0 - languageName: node - linkType: hard - -"bytes@npm:~3.1.2": - version: 3.1.2 - resolution: "bytes@npm:3.1.2" - checksum: 10c0/76d1c43cbd602794ad8ad2ae94095cddeb1de78c5dddaa7005c51af10b0176c69971a6d88e805a90c2b6550d76636e43c40d8427a808b8645ede885de4a0358e - languageName: node - linkType: hard - -"cacache@npm:^18.0.0": - version: 18.0.4 - resolution: "cacache@npm:18.0.4" - dependencies: - "@npmcli/fs": "npm:^3.1.0" - fs-minipass: "npm:^3.0.0" - glob: "npm:^10.2.2" - lru-cache: "npm:^10.0.1" - minipass: "npm:^7.0.3" - minipass-collect: "npm:^2.0.1" - minipass-flush: "npm:^1.0.5" - minipass-pipeline: "npm:^1.2.4" - p-map: "npm:^4.0.0" - ssri: "npm:^10.0.0" - tar: "npm:^6.1.11" - unique-filename: "npm:^3.0.0" - checksum: 10c0/6c055bafed9de4f3dcc64ac3dc7dd24e863210902b7c470eb9ce55a806309b3efff78033e3d8b4f7dcc5d467f2db43c6a2857aaaf26f0094b8a351d44c42179f - languageName: node - linkType: hard - -"call-bind-apply-helpers@npm:^1.0.1, call-bind-apply-helpers@npm:^1.0.2": - version: 1.0.2 - resolution: "call-bind-apply-helpers@npm:1.0.2" - dependencies: - es-errors: "npm:^1.3.0" - function-bind: "npm:^1.1.2" - checksum: 10c0/47bd9901d57b857590431243fea704ff18078b16890a6b3e021e12d279bbf211d039155e27d7566b374d49ee1f8189344bac9833dec7a20cdec370506361c938 - languageName: node - linkType: hard - -"call-bind@npm:^1.0.2, call-bind@npm:^1.0.5, call-bind@npm:^1.0.6, call-bind@npm:^1.0.7": - version: 1.0.7 - resolution: "call-bind@npm:1.0.7" - dependencies: - es-define-property: "npm:^1.0.0" - es-errors: "npm:^1.3.0" - function-bind: "npm:^1.1.2" - get-intrinsic: "npm:^1.2.4" - set-function-length: "npm:^1.2.1" - checksum: 10c0/a3ded2e423b8e2a265983dba81c27e125b48eefb2655e7dfab6be597088da3d47c47976c24bc51b8fd9af1061f8f87b4ab78a314f3c77784b2ae2ba535ad8b8d - languageName: node - linkType: hard - -"call-bound@npm:^1.0.2": - version: 1.0.4 - resolution: "call-bound@npm:1.0.4" - dependencies: - call-bind-apply-helpers: "npm:^1.0.2" - get-intrinsic: "npm:^1.3.0" - checksum: 10c0/f4796a6a0941e71c766aea672f63b72bc61234c4f4964dc6d7606e3664c307e7d77845328a8f3359ce39ddb377fed67318f9ee203dea1d47e46165dcf2917644 - languageName: node - linkType: hard - -"chownr@npm:^2.0.0": - version: 2.0.0 - resolution: "chownr@npm:2.0.0" - checksum: 10c0/594754e1303672171cc04e50f6c398ae16128eb134a88f801bf5354fd96f205320f23536a045d9abd8b51024a149696e51231565891d4efdab8846021ecf88e6 - languageName: node - linkType: hard - -"clean-stack@npm:^2.0.0": - version: 2.2.0 - resolution: "clean-stack@npm:2.2.0" - checksum: 10c0/1f90262d5f6230a17e27d0c190b09d47ebe7efdd76a03b5a1127863f7b3c9aec4c3e6c8bb3a7bbf81d553d56a1fd35728f5a8ef4c63f867ac8d690109742a8c1 - languageName: node - linkType: hard - -"color-convert@npm:^1.9.3": - version: 1.9.3 - resolution: "color-convert@npm:1.9.3" - dependencies: - color-name: "npm:1.1.3" - checksum: 10c0/5ad3c534949a8c68fca8fbc6f09068f435f0ad290ab8b2f76841b9e6af7e0bb57b98cb05b0e19fe33f5d91e5a8611ad457e5f69e0a484caad1f7487fd0e8253c - languageName: node - linkType: hard - -"color-convert@npm:^2.0.1": - version: 2.0.1 - resolution: "color-convert@npm:2.0.1" - dependencies: - color-name: "npm:~1.1.4" - checksum: 10c0/37e1150172f2e311fe1b2df62c6293a342ee7380da7b9cfdba67ea539909afbd74da27033208d01d6d5cfc65ee7868a22e18d7e7648e004425441c0f8a15a7d7 - languageName: node - linkType: hard - -"color-name@npm:1.1.3": - version: 1.1.3 - resolution: "color-name@npm:1.1.3" - checksum: 10c0/566a3d42cca25b9b3cd5528cd7754b8e89c0eb646b7f214e8e2eaddb69994ac5f0557d9c175eb5d8f0ad73531140d9c47525085ee752a91a2ab15ab459caf6d6 - languageName: node - linkType: hard - -"color-name@npm:^1.0.0, color-name@npm:~1.1.4": - version: 1.1.4 - resolution: "color-name@npm:1.1.4" - checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95 - languageName: node - linkType: hard - -"color-string@npm:^1.6.0, color-string@npm:^1.9.0": - version: 1.9.1 - resolution: "color-string@npm:1.9.1" - dependencies: - color-name: "npm:^1.0.0" - simple-swizzle: "npm:^0.2.2" - checksum: 10c0/b0bfd74c03b1f837f543898b512f5ea353f71630ccdd0d66f83028d1f0924a7d4272deb278b9aef376cacf1289b522ac3fb175e99895283645a2dc3a33af2404 - languageName: node - linkType: hard - -"color-support@npm:^1.1.2": - version: 1.1.3 - resolution: "color-support@npm:1.1.3" - bin: - color-support: bin.js - checksum: 10c0/8ffeaa270a784dc382f62d9be0a98581db43e11eee301af14734a6d089bd456478b1a8b3e7db7ca7dc5b18a75f828f775c44074020b51c05fc00e6d0992b1cc6 - languageName: node - linkType: hard - -"color@npm:^3.1.3": - version: 3.2.1 - resolution: "color@npm:3.2.1" - dependencies: - color-convert: "npm:^1.9.3" - color-string: "npm:^1.6.0" - checksum: 10c0/39345d55825884c32a88b95127d417a2c24681d8b57069413596d9fcbb721459ef9d9ec24ce3e65527b5373ce171b73e38dbcd9c830a52a6487e7f37bf00e83c - languageName: node - linkType: hard - -"color@npm:^4.2.3": - version: 4.2.3 - resolution: "color@npm:4.2.3" - dependencies: - color-convert: "npm:^2.0.1" - color-string: "npm:^1.9.0" - checksum: 10c0/7fbe7cfb811054c808349de19fb380252e5e34e61d7d168ec3353e9e9aacb1802674bddc657682e4e9730c2786592a4de6f8283e7e0d3870b829bb0b7b2f6118 - languageName: node - linkType: hard - -"colorspace@npm:1.1.x": - version: 1.1.4 - resolution: "colorspace@npm:1.1.4" - dependencies: - color: "npm:^3.1.3" - text-hex: "npm:1.0.x" - checksum: 10c0/af5f91ff7f8e146b96e439ac20ed79b197210193bde721b47380a75b21751d90fa56390c773bb67c0aedd34ff85091883a437ab56861c779bd507d639ba7e123 - languageName: node - linkType: hard - -"combined-stream@npm:^1.0.8": - version: 1.0.8 - resolution: "combined-stream@npm:1.0.8" - dependencies: - delayed-stream: "npm:~1.0.0" - checksum: 10c0/0dbb829577e1b1e839fa82b40c07ffaf7de8a09b935cadd355a73652ae70a88b4320db322f6634a4ad93424292fa80973ac6480986247f1734a1137debf271d5 - languageName: node - linkType: hard - -"compress-commons@npm:^6.0.2": - version: 6.0.2 - resolution: "compress-commons@npm:6.0.2" - dependencies: - crc-32: "npm:^1.2.0" - crc32-stream: "npm:^6.0.0" - is-stream: "npm:^2.0.1" - normalize-path: "npm:^3.0.0" - readable-stream: "npm:^4.0.0" - checksum: 10c0/2347031b7c92c8ed5011b07b93ec53b298fa2cd1800897532ac4d4d1aeae06567883f481b6e35f13b65fc31b190c751df6635434d525562f0203fde76f1f0814 - languageName: node - linkType: hard - -"concat-map@npm:0.0.1": - version: 0.0.1 - resolution: "concat-map@npm:0.0.1" - checksum: 10c0/c996b1cfdf95b6c90fee4dae37e332c8b6eb7d106430c17d538034c0ad9a1630cb194d2ab37293b1bdd4d779494beee7786d586a50bd9376fd6f7bcc2bd4c98f - languageName: node - linkType: hard - -"console-control-strings@npm:^1.0.0, console-control-strings@npm:^1.1.0": - version: 1.1.0 - resolution: "console-control-strings@npm:1.1.0" - checksum: 10c0/7ab51d30b52d461412cd467721bb82afe695da78fff8f29fe6f6b9cbaac9a2328e27a22a966014df9532100f6dd85370460be8130b9c677891ba36d96a343f50 - languageName: node - linkType: hard - -"content-type@npm:~1.0.5": - version: 1.0.5 - resolution: "content-type@npm:1.0.5" - checksum: 10c0/b76ebed15c000aee4678c3707e0860cb6abd4e680a598c0a26e17f0bfae723ec9cc2802f0ff1bc6e4d80603719010431d2231018373d4dde10f9ccff9dadf5af - languageName: node - linkType: hard - -"core-util-is@npm:~1.0.0": - version: 1.0.3 - resolution: "core-util-is@npm:1.0.3" - checksum: 10c0/90a0e40abbddfd7618f8ccd63a74d88deea94e77d0e8dbbea059fa7ebebb8fbb4e2909667fe26f3a467073de1a542ebe6ae4c73a73745ac5833786759cd906c9 - languageName: node - linkType: hard - -"crc-32@npm:^1.2.0": - version: 1.2.2 - resolution: "crc-32@npm:1.2.2" - bin: - crc32: bin/crc32.njs - checksum: 10c0/11dcf4a2e77ee793835d49f2c028838eae58b44f50d1ff08394a610bfd817523f105d6ae4d9b5bef0aad45510f633eb23c903e9902e4409bed1ce70cb82b9bf0 - languageName: node - linkType: hard - -"crc32-stream@npm:^6.0.0": - version: 6.0.0 - resolution: "crc32-stream@npm:6.0.0" - dependencies: - crc-32: "npm:^1.2.0" - readable-stream: "npm:^4.0.0" - checksum: 10c0/bf9c84571ede2d119c2b4f3a9ef5eeb9ff94b588493c0d3862259af86d3679dcce1c8569dd2b0a6eff2f35f5e2081cc1263b846d2538d4054da78cf34f262a3d - languageName: node - linkType: hard - -"cross-spawn@npm:^7.0.0": - version: 7.0.6 - resolution: "cross-spawn@npm:7.0.6" - dependencies: - path-key: "npm:^3.1.0" - shebang-command: "npm:^2.0.0" - which: "npm:^2.0.1" - checksum: 10c0/053ea8b2135caff68a9e81470e845613e374e7309a47731e81639de3eaeb90c3d01af0e0b44d2ab9d50b43467223b88567dfeb3262db942dc063b9976718ffc1 - languageName: node - linkType: hard - -"debug@npm:2.6.9": - version: 2.6.9 - resolution: "debug@npm:2.6.9" - dependencies: - ms: "npm:2.0.0" - checksum: 10c0/121908fb839f7801180b69a7e218a40b5a0b718813b886b7d6bdb82001b931c938e2941d1e4450f33a1b1df1da653f5f7a0440c197f29fbf8a6e9d45ff6ef589 - languageName: node - linkType: hard - -"debug@npm:4, debug@npm:^4.3.4": - version: 4.3.6 - resolution: "debug@npm:4.3.6" - dependencies: - ms: "npm:2.1.2" - peerDependenciesMeta: - supports-color: - optional: true - checksum: 10c0/3293416bff072389c101697d4611c402a6bacd1900ac20c0492f61a9cdd6b3b29750fc7f5e299f8058469ef60ff8fb79b86395a30374fbd2490113c1c7112285 - languageName: node - linkType: hard - -"deep-equal@npm:^2.2.3": - version: 2.2.3 - resolution: "deep-equal@npm:2.2.3" - dependencies: - array-buffer-byte-length: "npm:^1.0.0" - call-bind: "npm:^1.0.5" - es-get-iterator: "npm:^1.1.3" - get-intrinsic: "npm:^1.2.2" - is-arguments: "npm:^1.1.1" - is-array-buffer: "npm:^3.0.2" - is-date-object: "npm:^1.0.5" - is-regex: "npm:^1.1.4" - is-shared-array-buffer: "npm:^1.0.2" - isarray: "npm:^2.0.5" - object-is: "npm:^1.1.5" - object-keys: "npm:^1.1.1" - object.assign: "npm:^4.1.4" - regexp.prototype.flags: "npm:^1.5.1" - side-channel: "npm:^1.0.4" - which-boxed-primitive: "npm:^1.0.2" - which-collection: "npm:^1.0.1" - which-typed-array: "npm:^1.1.13" - checksum: 10c0/a48244f90fa989f63ff5ef0cc6de1e4916b48ea0220a9c89a378561960814794a5800c600254482a2c8fd2e49d6c2e196131dc983976adb024c94a42dfe4949f - languageName: node - linkType: hard - -"define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.4": - version: 1.1.4 - resolution: "define-data-property@npm:1.1.4" - dependencies: - es-define-property: "npm:^1.0.0" - es-errors: "npm:^1.3.0" - gopd: "npm:^1.0.1" - checksum: 10c0/dea0606d1483eb9db8d930d4eac62ca0fa16738b0b3e07046cddfacf7d8c868bbe13fa0cb263eb91c7d0d527960dc3f2f2471a69ed7816210307f6744fe62e37 - languageName: node - linkType: hard - -"define-properties@npm:^1.2.1": - version: 1.2.1 - resolution: "define-properties@npm:1.2.1" - dependencies: - define-data-property: "npm:^1.0.1" - has-property-descriptors: "npm:^1.0.0" - object-keys: "npm:^1.1.1" - checksum: 10c0/88a152319ffe1396ccc6ded510a3896e77efac7a1bfbaa174a7b00414a1747377e0bb525d303794a47cf30e805c2ec84e575758512c6e44a993076d29fd4e6c3 - languageName: node - linkType: hard - -"delayed-stream@npm:~1.0.0": - version: 1.0.0 - resolution: "delayed-stream@npm:1.0.0" - checksum: 10c0/d758899da03392e6712f042bec80aa293bbe9e9ff1b2634baae6a360113e708b91326594c8a486d475c69d6259afb7efacdc3537bfcda1c6c648e390ce601b19 - languageName: node - linkType: hard - -"delegates@npm:^1.0.0": - version: 1.0.0 - resolution: "delegates@npm:1.0.0" - checksum: 10c0/ba05874b91148e1db4bf254750c042bf2215febd23a6d3cda2e64896aef79745fbd4b9996488bd3cafb39ce19dbce0fd6e3b6665275638befffe1c9b312b91b5 - languageName: node - linkType: hard - -"depd@npm:2.0.0, depd@npm:~2.0.0": - version: 2.0.0 - resolution: "depd@npm:2.0.0" - checksum: 10c0/58bd06ec20e19529b06f7ad07ddab60e504d9e0faca4bd23079fac2d279c3594334d736508dc350e06e510aba5e22e4594483b3a6562ce7c17dd797f4cc4ad2c - languageName: node - linkType: hard - -"destroy@npm:~1.2.0": - version: 1.2.0 - resolution: "destroy@npm:1.2.0" - checksum: 10c0/bd7633942f57418f5a3b80d5cb53898127bcf53e24cdf5d5f4396be471417671f0fee48a4ebe9a1e9defbde2a31280011af58a57e090ff822f589b443ed4e643 - languageName: node - linkType: hard - -"detect-libc@npm:^2.0.0, detect-libc@npm:^2.0.3": - version: 2.0.3 - resolution: "detect-libc@npm:2.0.3" - checksum: 10c0/88095bda8f90220c95f162bf92cad70bd0e424913e655c20578600e35b91edc261af27531cf160a331e185c0ced93944bc7e09939143225f56312d7fd800fdb7 - languageName: node - linkType: hard - -"dunder-proto@npm:^1.0.1": - version: 1.0.1 - resolution: "dunder-proto@npm:1.0.1" - dependencies: - call-bind-apply-helpers: "npm:^1.0.1" - es-errors: "npm:^1.3.0" - gopd: "npm:^1.2.0" - checksum: 10c0/199f2a0c1c16593ca0a145dbf76a962f8033ce3129f01284d48c45ed4e14fea9bbacd7b3610b6cdc33486cef20385ac054948fefc6272fcce645c09468f93031 - languageName: node - linkType: hard - -"eastasianwidth@npm:^0.2.0": - version: 0.2.0 - resolution: "eastasianwidth@npm:0.2.0" - checksum: 10c0/26f364ebcdb6395f95124fda411f63137a4bfb5d3a06453f7f23dfe52502905bd84e0488172e0f9ec295fdc45f05c23d5d91baf16bd26f0fe9acd777a188dc39 - languageName: node - linkType: hard - -"ecdsa-sig-formatter@npm:1.0.11": - version: 1.0.11 - resolution: "ecdsa-sig-formatter@npm:1.0.11" - dependencies: - safe-buffer: "npm:^5.0.1" - checksum: 10c0/ebfbf19d4b8be938f4dd4a83b8788385da353d63307ede301a9252f9f7f88672e76f2191618fd8edfc2f24679236064176fab0b78131b161ee73daa37125408c - languageName: node - linkType: hard - -"ee-first@npm:1.1.1": - version: 1.1.1 - resolution: "ee-first@npm:1.1.1" - checksum: 10c0/b5bb125ee93161bc16bfe6e56c6b04de5ad2aa44234d8f644813cc95d861a6910903132b05093706de2b706599367c4130eb6d170f6b46895686b95f87d017b7 - languageName: node - linkType: hard - -"emoji-regex@npm:^8.0.0": - version: 8.0.0 - resolution: "emoji-regex@npm:8.0.0" - checksum: 10c0/b6053ad39951c4cf338f9092d7bfba448cdfd46fe6a2a034700b149ac9ffbc137e361cbd3c442297f86bed2e5f7576c1b54cc0a6bf8ef5106cc62f496af35010 - languageName: node - linkType: hard - -"emoji-regex@npm:^9.2.2": - version: 9.2.2 - resolution: "emoji-regex@npm:9.2.2" - checksum: 10c0/af014e759a72064cf66e6e694a7fc6b0ed3d8db680427b021a89727689671cefe9d04151b2cad51dbaf85d5ba790d061cd167f1cf32eb7b281f6368b3c181639 - languageName: node - linkType: hard - -"enabled@npm:2.0.x": - version: 2.0.0 - resolution: "enabled@npm:2.0.0" - checksum: 10c0/3b2c2af9bc7f8b9e291610f2dde4a75cf6ee52a68f4dd585482fbdf9a55d65388940e024e56d40bb03e05ef6671f5f53021fa8b72a20e954d7066ec28166713f - languageName: node - linkType: hard - -"encoding@npm:^0.1.13": - version: 0.1.13 - resolution: "encoding@npm:0.1.13" - dependencies: - iconv-lite: "npm:^0.6.2" - checksum: 10c0/36d938712ff00fe1f4bac88b43bcffb5930c1efa57bbcdca9d67e1d9d6c57cfb1200fb01efe0f3109b2ce99b231f90779532814a81370a1bd3274a0f58585039 - languageName: node - linkType: hard - -"env-paths@npm:^2.2.0": - version: 2.2.1 - resolution: "env-paths@npm:2.2.1" - checksum: 10c0/285325677bf00e30845e330eec32894f5105529db97496ee3f598478e50f008c5352a41a30e5e72ec9de8a542b5a570b85699cd63bd2bc646dbcb9f311d83bc4 - languageName: node - linkType: hard - -"err-code@npm:^2.0.2": - version: 2.0.3 - resolution: "err-code@npm:2.0.3" - checksum: 10c0/b642f7b4dd4a376e954947550a3065a9ece6733ab8e51ad80db727aaae0817c2e99b02a97a3d6cecc648a97848305e728289cf312d09af395403a90c9d4d8a66 - languageName: node - linkType: hard - -"es-define-property@npm:^1.0.0": - version: 1.0.0 - resolution: "es-define-property@npm:1.0.0" - dependencies: - get-intrinsic: "npm:^1.2.4" - checksum: 10c0/6bf3191feb7ea2ebda48b577f69bdfac7a2b3c9bcf97307f55fd6ef1bbca0b49f0c219a935aca506c993d8c5d8bddd937766cb760cd5e5a1071351f2df9f9aa4 - languageName: node - linkType: hard - -"es-define-property@npm:^1.0.1": - version: 1.0.1 - resolution: "es-define-property@npm:1.0.1" - checksum: 10c0/3f54eb49c16c18707949ff25a1456728c883e81259f045003499efba399c08bad00deebf65cccde8c0e07908c1a225c9d472b7107e558f2a48e28d530e34527c - languageName: node - linkType: hard - -"es-errors@npm:^1.3.0": - version: 1.3.0 - resolution: "es-errors@npm:1.3.0" - checksum: 10c0/0a61325670072f98d8ae3b914edab3559b6caa980f08054a3b872052640d91da01d38df55df797fcc916389d77fc92b8d5906cf028f4db46d7e3003abecbca85 - languageName: node - linkType: hard - -"es-get-iterator@npm:^1.1.3": - version: 1.1.3 - resolution: "es-get-iterator@npm:1.1.3" - dependencies: - call-bind: "npm:^1.0.2" - get-intrinsic: "npm:^1.1.3" - has-symbols: "npm:^1.0.3" - is-arguments: "npm:^1.1.1" - is-map: "npm:^2.0.2" - is-set: "npm:^2.0.2" - is-string: "npm:^1.0.7" - isarray: "npm:^2.0.5" - stop-iteration-iterator: "npm:^1.0.0" - checksum: 10c0/ebd11effa79851ea75d7f079405f9d0dc185559fd65d986c6afea59a0ff2d46c2ed8675f19f03dce7429d7f6c14ff9aede8d121fbab78d75cfda6a263030bac0 - languageName: node - linkType: hard - -"es-object-atoms@npm:^1.0.0, es-object-atoms@npm:^1.1.1": - version: 1.1.1 - resolution: "es-object-atoms@npm:1.1.1" - dependencies: - es-errors: "npm:^1.3.0" - checksum: 10c0/65364812ca4daf48eb76e2a3b7a89b3f6a2e62a1c420766ce9f692665a29d94fe41fe88b65f24106f449859549711e4b40d9fb8002d862dfd7eb1c512d10be0c - languageName: node - linkType: hard - -"es-set-tostringtag@npm:^2.1.0": - version: 2.1.0 - resolution: "es-set-tostringtag@npm:2.1.0" - dependencies: - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.6" - has-tostringtag: "npm:^1.0.2" - hasown: "npm:^2.0.2" - checksum: 10c0/ef2ca9ce49afe3931cb32e35da4dcb6d86ab02592cfc2ce3e49ced199d9d0bb5085fc7e73e06312213765f5efa47cc1df553a6a5154584b21448e9fb8355b1af - languageName: node - linkType: hard - -"event-target-shim@npm:^5.0.0": - version: 5.0.1 - resolution: "event-target-shim@npm:5.0.1" - checksum: 10c0/0255d9f936215fd206156fd4caa9e8d35e62075d720dc7d847e89b417e5e62cf1ce6c9b4e0a1633a9256de0efefaf9f8d26924b1f3c8620cffb9db78e7d3076b - languageName: node - linkType: hard - -"events@npm:^3.3.0": - version: 3.3.0 - resolution: "events@npm:3.3.0" - checksum: 10c0/d6b6f2adbccbcda74ddbab52ed07db727ef52e31a61ed26db9feb7dc62af7fc8e060defa65e5f8af9449b86b52cc1a1f6a79f2eafcf4e62add2b7a1fa4a432f6 - languageName: node - linkType: hard - -"exponential-backoff@npm:^3.1.1": - version: 3.1.1 - resolution: "exponential-backoff@npm:3.1.1" - checksum: 10c0/160456d2d647e6019640bd07111634d8c353038d9fa40176afb7cd49b0548bdae83b56d05e907c2cce2300b81cae35d800ef92fefb9d0208e190fa3b7d6bb579 - languageName: node - linkType: hard - -"fast-fifo@npm:^1.2.0, fast-fifo@npm:^1.3.2": - version: 1.3.2 - resolution: "fast-fifo@npm:1.3.2" - checksum: 10c0/d53f6f786875e8b0529f784b59b4b05d4b5c31c651710496440006a398389a579c8dbcd2081311478b5bf77f4b0b21de69109c5a4eabea9d8e8783d1eb864e4c - languageName: node - linkType: hard - -"fecha@npm:^4.2.0": - version: 4.2.3 - resolution: "fecha@npm:4.2.3" - checksum: 10c0/0e895965959cf6a22bb7b00f0bf546f2783836310f510ddf63f463e1518d4c96dec61ab33fdfd8e79a71b4856a7c865478ce2ee8498d560fe125947703c9b1cf - languageName: node - linkType: hard - -"fn.name@npm:1.x.x": - version: 1.1.0 - resolution: "fn.name@npm:1.1.0" - checksum: 10c0/8ad62aa2d4f0b2a76d09dba36cfec61c540c13a0fd72e5d94164e430f987a7ce6a743112bbeb14877c810ef500d1f73d7f56e76d029d2e3413f20d79e3460a9a - languageName: node - linkType: hard - -"follow-redirects@npm:^1.15.6": - version: 1.15.6 - resolution: "follow-redirects@npm:1.15.6" - peerDependenciesMeta: - debug: - optional: true - checksum: 10c0/9ff767f0d7be6aa6870c82ac79cf0368cd73e01bbc00e9eb1c2a16fbb198ec105e3c9b6628bb98e9f3ac66fe29a957b9645bcb9a490bb7aa0d35f908b6b85071 - languageName: node - linkType: hard - -"for-each@npm:^0.3.3": - version: 0.3.3 - resolution: "for-each@npm:0.3.3" - dependencies: - is-callable: "npm:^1.1.3" - checksum: 10c0/22330d8a2db728dbf003ec9182c2d421fbcd2969b02b4f97ec288721cda63eb28f2c08585ddccd0f77cb2930af8d958005c9e72f47141dc51816127a118f39aa - languageName: node - linkType: hard - -"foreground-child@npm:^3.1.0": - version: 3.3.0 - resolution: "foreground-child@npm:3.3.0" - dependencies: - cross-spawn: "npm:^7.0.0" - signal-exit: "npm:^4.0.1" - checksum: 10c0/028f1d41000553fcfa6c4bb5c372963bf3d9bf0b1f25a87d1a6253014343fb69dfb1b42d9625d7cf44c8ba429940f3d0ff718b62105d4d4a4f6ef8ca0a53faa2 - languageName: node - linkType: hard - -"form-data@npm:^4.0.4": - version: 4.0.4 - resolution: "form-data@npm:4.0.4" - dependencies: - asynckit: "npm:^0.4.0" - combined-stream: "npm:^1.0.8" - es-set-tostringtag: "npm:^2.1.0" - hasown: "npm:^2.0.2" - mime-types: "npm:^2.1.12" - checksum: 10c0/373525a9a034b9d57073e55eab79e501a714ffac02e7a9b01be1c820780652b16e4101819785e1e18f8d98f0aee866cc654d660a435c378e16a72f2e7cac9695 - languageName: node - linkType: hard - -"fs-minipass@npm:^2.0.0": - version: 2.1.0 - resolution: "fs-minipass@npm:2.1.0" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10c0/703d16522b8282d7299337539c3ed6edddd1afe82435e4f5b76e34a79cd74e488a8a0e26a636afc2440e1a23b03878e2122e3a2cfe375a5cf63c37d92b86a004 - languageName: node - linkType: hard - -"fs-minipass@npm:^3.0.0": - version: 3.0.3 - resolution: "fs-minipass@npm:3.0.3" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10c0/63e80da2ff9b621e2cb1596abcb9207f1cf82b968b116ccd7b959e3323144cce7fb141462200971c38bbf2ecca51695069db45265705bed09a7cd93ae5b89f94 - languageName: node - linkType: hard - -"fs.realpath@npm:^1.0.0": - version: 1.0.0 - resolution: "fs.realpath@npm:1.0.0" - checksum: 10c0/444cf1291d997165dfd4c0d58b69f0e4782bfd9149fd72faa4fe299e68e0e93d6db941660b37dd29153bf7186672ececa3b50b7e7249477b03fdf850f287c948 - languageName: node - linkType: hard - -"function-bind@npm:^1.1.2": - version: 1.1.2 - resolution: "function-bind@npm:1.1.2" - checksum: 10c0/d8680ee1e5fcd4c197e4ac33b2b4dce03c71f4d91717292785703db200f5c21f977c568d28061226f9b5900cbcd2c84463646134fd5337e7925e0942bc3f46d5 - languageName: node - linkType: hard - -"functions-have-names@npm:^1.2.3": - version: 1.2.3 - resolution: "functions-have-names@npm:1.2.3" - checksum: 10c0/33e77fd29bddc2d9bb78ab3eb854c165909201f88c75faa8272e35899e2d35a8a642a15e7420ef945e1f64a9670d6aa3ec744106b2aa42be68ca5114025954ca - languageName: node - linkType: hard - -"gauge@npm:^3.0.0": - version: 3.0.2 - resolution: "gauge@npm:3.0.2" - dependencies: - aproba: "npm:^1.0.3 || ^2.0.0" - color-support: "npm:^1.1.2" - console-control-strings: "npm:^1.0.0" - has-unicode: "npm:^2.0.1" - object-assign: "npm:^4.1.1" - signal-exit: "npm:^3.0.0" - string-width: "npm:^4.2.3" - strip-ansi: "npm:^6.0.1" - wide-align: "npm:^1.1.2" - checksum: 10c0/75230ccaf216471e31025c7d5fcea1629596ca20792de50c596eb18ffb14d8404f927cd55535aab2eeecd18d1e11bd6f23ec3c2e9878d2dda1dc74bccc34b913 - languageName: node - linkType: hard - -"generator-function@npm:^2.0.0": - version: 2.0.1 - resolution: "generator-function@npm:2.0.1" - checksum: 10c0/8a9f59df0f01cfefafdb3b451b80555e5cf6d76487095db91ac461a0e682e4ff7a9dbce15f4ecec191e53586d59eece01949e05a4b4492879600bbbe8e28d6b8 - languageName: node - linkType: hard - -"get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.2, get-intrinsic@npm:^1.2.4": - version: 1.2.4 - resolution: "get-intrinsic@npm:1.2.4" - dependencies: - es-errors: "npm:^1.3.0" - function-bind: "npm:^1.1.2" - has-proto: "npm:^1.0.1" - has-symbols: "npm:^1.0.3" - hasown: "npm:^2.0.0" - checksum: 10c0/0a9b82c16696ed6da5e39b1267104475c47e3a9bdbe8b509dfe1710946e38a87be70d759f4bb3cda042d76a41ef47fe769660f3b7c0d1f68750299344ffb15b7 - languageName: node - linkType: hard - -"get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.3.0": - version: 1.3.1 - resolution: "get-intrinsic@npm:1.3.1" - dependencies: - async-function: "npm:^1.0.0" - async-generator-function: "npm:^1.0.0" - call-bind-apply-helpers: "npm:^1.0.2" - es-define-property: "npm:^1.0.1" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.1.1" - function-bind: "npm:^1.1.2" - generator-function: "npm:^2.0.0" - get-proto: "npm:^1.0.1" - gopd: "npm:^1.2.0" - has-symbols: "npm:^1.1.0" - hasown: "npm:^2.0.2" - math-intrinsics: "npm:^1.1.0" - checksum: 10c0/9f4ab0cf7efe0fd2c8185f52e6f637e708f3a112610c88869f8f041bb9ecc2ce44bf285dfdbdc6f4f7c277a5b88d8e94a432374d97cca22f3de7fc63795deb5d - languageName: node - linkType: hard - -"get-proto@npm:^1.0.1": - version: 1.0.1 - resolution: "get-proto@npm:1.0.1" - dependencies: - dunder-proto: "npm:^1.0.1" - es-object-atoms: "npm:^1.0.0" - checksum: 10c0/9224acb44603c5526955e83510b9da41baf6ae73f7398875fba50edc5e944223a89c4a72b070fcd78beb5f7bdda58ecb6294adc28f7acfc0da05f76a2399643c - languageName: node - linkType: hard - -"glob@npm:^10.0.0, glob@npm:^10.2.2, glob@npm:^10.3.10": - version: 10.5.0 - resolution: "glob@npm:10.5.0" - dependencies: - foreground-child: "npm:^3.1.0" - jackspeak: "npm:^3.1.2" - minimatch: "npm:^9.0.4" - minipass: "npm:^7.1.2" - package-json-from-dist: "npm:^1.0.0" - path-scurry: "npm:^1.11.1" - bin: - glob: dist/esm/bin.mjs - checksum: 10c0/100705eddbde6323e7b35e1d1ac28bcb58322095bd8e63a7d0bef1a2cdafe0d0f7922a981b2b48369a4f8c1b077be5c171804534c3509dfe950dde15fbe6d828 - languageName: node - linkType: hard - -"glob@npm:^7.1.3": - version: 7.2.3 - resolution: "glob@npm:7.2.3" - dependencies: - fs.realpath: "npm:^1.0.0" - inflight: "npm:^1.0.4" - inherits: "npm:2" - minimatch: "npm:^3.1.1" - once: "npm:^1.3.0" - path-is-absolute: "npm:^1.0.0" - checksum: 10c0/65676153e2b0c9095100fe7f25a778bf45608eeb32c6048cf307f579649bcc30353277b3b898a3792602c65764e5baa4f643714dfbdfd64ea271d210c7a425fe - languageName: node - linkType: hard - -"gopd@npm:^1.0.1": - version: 1.0.1 - resolution: "gopd@npm:1.0.1" - dependencies: - get-intrinsic: "npm:^1.1.3" - checksum: 10c0/505c05487f7944c552cee72087bf1567debb470d4355b1335f2c262d218ebbff805cd3715448fe29b4b380bae6912561d0467233e4165830efd28da241418c63 - languageName: node - linkType: hard - -"gopd@npm:^1.2.0": - version: 1.2.0 - resolution: "gopd@npm:1.2.0" - checksum: 10c0/50fff1e04ba2b7737c097358534eacadad1e68d24cccee3272e04e007bed008e68d2614f3987788428fd192a5ae3889d08fb2331417e4fc4a9ab366b2043cead - languageName: node - linkType: hard - -"graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.6": - version: 4.2.11 - resolution: "graceful-fs@npm:4.2.11" - checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 - languageName: node - linkType: hard - -"has-bigints@npm:^1.0.1": - version: 1.0.2 - resolution: "has-bigints@npm:1.0.2" - checksum: 10c0/724eb1485bfa3cdff6f18d95130aa190561f00b3fcf9f19dc640baf8176b5917c143b81ec2123f8cddb6c05164a198c94b13e1377c497705ccc8e1a80306e83b - languageName: node - linkType: hard - -"has-property-descriptors@npm:^1.0.0, has-property-descriptors@npm:^1.0.2": - version: 1.0.2 - resolution: "has-property-descriptors@npm:1.0.2" - dependencies: - es-define-property: "npm:^1.0.0" - checksum: 10c0/253c1f59e80bb476cf0dde8ff5284505d90c3bdb762983c3514d36414290475fe3fd6f574929d84de2a8eec00d35cf07cb6776205ff32efd7c50719125f00236 - languageName: node - linkType: hard - -"has-proto@npm:^1.0.1": - version: 1.0.3 - resolution: "has-proto@npm:1.0.3" - checksum: 10c0/35a6989f81e9f8022c2f4027f8b48a552de714938765d019dbea6bb547bd49ce5010a3c7c32ec6ddac6e48fc546166a3583b128f5a7add8b058a6d8b4afec205 - languageName: node - linkType: hard - -"has-symbols@npm:^1.0.2, has-symbols@npm:^1.0.3": - version: 1.0.3 - resolution: "has-symbols@npm:1.0.3" - checksum: 10c0/e6922b4345a3f37069cdfe8600febbca791c94988c01af3394d86ca3360b4b93928bbf395859158f88099cb10b19d98e3bbab7c9ff2c1bd09cf665ee90afa2c3 - languageName: node - linkType: hard - -"has-symbols@npm:^1.1.0": - version: 1.1.0 - resolution: "has-symbols@npm:1.1.0" - checksum: 10c0/dde0a734b17ae51e84b10986e651c664379018d10b91b6b0e9b293eddb32f0f069688c841fb40f19e9611546130153e0a2a48fd7f512891fb000ddfa36f5a20e - languageName: node - linkType: hard - -"has-tostringtag@npm:^1.0.0, has-tostringtag@npm:^1.0.2": - version: 1.0.2 - resolution: "has-tostringtag@npm:1.0.2" - dependencies: - has-symbols: "npm:^1.0.3" - checksum: 10c0/a8b166462192bafe3d9b6e420a1d581d93dd867adb61be223a17a8d6dad147aa77a8be32c961bb2f27b3ef893cae8d36f564ab651f5e9b7938ae86f74027c48c - languageName: node - linkType: hard - -"has-unicode@npm:^2.0.1": - version: 2.0.1 - resolution: "has-unicode@npm:2.0.1" - checksum: 10c0/ebdb2f4895c26bb08a8a100b62d362e49b2190bcfd84b76bc4be1a3bd4d254ec52d0dd9f2fbcc093fc5eb878b20c52146f9dfd33e2686ed28982187be593b47c - languageName: node - linkType: hard - -"hasown@npm:^2.0.0, hasown@npm:^2.0.2": - version: 2.0.2 - resolution: "hasown@npm:2.0.2" - dependencies: - function-bind: "npm:^1.1.2" - checksum: 10c0/3769d434703b8ac66b209a4cca0737519925bbdb61dd887f93a16372b14694c63ff4e797686d87c90f08168e81082248b9b028bad60d4da9e0d1148766f56eb9 - languageName: node - linkType: hard - -"http-cache-semantics@npm:^4.1.1": - version: 4.1.1 - resolution: "http-cache-semantics@npm:4.1.1" - checksum: 10c0/ce1319b8a382eb3cbb4a37c19f6bfe14e5bb5be3d09079e885e8c513ab2d3cd9214902f8a31c9dc4e37022633ceabfc2d697405deeaf1b8f3552bb4ed996fdfc - languageName: node - linkType: hard - -"http-errors@npm:~2.0.1": - version: 2.0.1 - resolution: "http-errors@npm:2.0.1" - dependencies: - depd: "npm:~2.0.0" - inherits: "npm:~2.0.4" - setprototypeof: "npm:~1.2.0" - statuses: "npm:~2.0.2" - toidentifier: "npm:~1.0.1" - checksum: 10c0/fb38906cef4f5c83952d97661fe14dc156cb59fe54812a42cd448fa57b5c5dfcb38a40a916957737bd6b87aab257c0648d63eb5b6a9ca9f548e105b6072712d4 - languageName: node - linkType: hard - -"http-proxy-agent@npm:^7.0.0": - version: 7.0.2 - resolution: "http-proxy-agent@npm:7.0.2" - dependencies: - agent-base: "npm:^7.1.0" - debug: "npm:^4.3.4" - checksum: 10c0/4207b06a4580fb85dd6dff521f0abf6db517489e70863dca1a0291daa7f2d3d2d6015a57bd702af068ea5cf9f1f6ff72314f5f5b4228d299c0904135d2aef921 - languageName: node - linkType: hard - -"https-proxy-agent@npm:^5.0.0": - version: 5.0.1 - resolution: "https-proxy-agent@npm:5.0.1" - dependencies: - agent-base: "npm:6" - debug: "npm:4" - checksum: 10c0/6dd639f03434003577c62b27cafdb864784ef19b2de430d8ae2a1d45e31c4fd60719e5637b44db1a88a046934307da7089e03d6089ec3ddacc1189d8de8897d1 - languageName: node - linkType: hard - -"https-proxy-agent@npm:^7.0.1": - version: 7.0.5 - resolution: "https-proxy-agent@npm:7.0.5" - dependencies: - agent-base: "npm:^7.0.2" - debug: "npm:4" - checksum: 10c0/2490e3acec397abeb88807db52cac59102d5ed758feee6df6112ab3ccd8325e8a1ce8bce6f4b66e5470eca102d31e425ace904242e4fa28dbe0c59c4bafa7b2c - languageName: node - linkType: hard - -"iconv-lite@npm:^0.6.2": - version: 0.6.3 - resolution: "iconv-lite@npm:0.6.3" - dependencies: - safer-buffer: "npm:>= 2.1.2 < 3.0.0" - checksum: 10c0/98102bc66b33fcf5ac044099d1257ba0b7ad5e3ccd3221f34dd508ab4070edff183276221684e1e0555b145fce0850c9f7d2b60a9fcac50fbb4ea0d6e845a3b1 - languageName: node - linkType: hard - -"iconv-lite@npm:~0.4.24": - version: 0.4.24 - resolution: "iconv-lite@npm:0.4.24" - dependencies: - safer-buffer: "npm:>= 2.1.2 < 3" - checksum: 10c0/c6886a24cc00f2a059767440ec1bc00d334a89f250db8e0f7feb4961c8727118457e27c495ba94d082e51d3baca378726cd110aaf7ded8b9bbfd6a44760cf1d4 - languageName: node - linkType: hard - -"ieee754@npm:^1.2.1": - version: 1.2.1 - resolution: "ieee754@npm:1.2.1" - checksum: 10c0/b0782ef5e0935b9f12883a2e2aa37baa75da6e66ce6515c168697b42160807d9330de9a32ec1ed73149aea02e0d822e572bca6f1e22bdcbd2149e13b050b17bb - languageName: node - linkType: hard - -"imurmurhash@npm:^0.1.4": - version: 0.1.4 - resolution: "imurmurhash@npm:0.1.4" - checksum: 10c0/8b51313850dd33605c6c9d3fd9638b714f4c4c40250cff658209f30d40da60f78992fb2df5dabee4acf589a6a82bbc79ad5486550754bd9ec4e3fc0d4a57d6a6 - languageName: node - linkType: hard - -"indent-string@npm:^4.0.0": - version: 4.0.0 - resolution: "indent-string@npm:4.0.0" - checksum: 10c0/1e1904ddb0cb3d6cce7cd09e27a90184908b7a5d5c21b92e232c93579d314f0b83c246ffb035493d0504b1e9147ba2c9b21df0030f48673fba0496ecd698161f - languageName: node - linkType: hard - -"inflight@npm:^1.0.4": - version: 1.0.6 - resolution: "inflight@npm:1.0.6" - dependencies: - once: "npm:^1.3.0" - wrappy: "npm:1" - checksum: 10c0/7faca22584600a9dc5b9fca2cd5feb7135ac8c935449837b315676b4c90aa4f391ec4f42240178244b5a34e8bede1948627fda392ca3191522fc46b34e985ab2 - languageName: node - linkType: hard - -"inherits@npm:2, inherits@npm:^2.0.3, inherits@npm:~2.0.3, inherits@npm:~2.0.4": - version: 2.0.4 - resolution: "inherits@npm:2.0.4" - checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2 - languageName: node - linkType: hard - -"internal-slot@npm:^1.0.4": - version: 1.0.7 - resolution: "internal-slot@npm:1.0.7" - dependencies: - es-errors: "npm:^1.3.0" - hasown: "npm:^2.0.0" - side-channel: "npm:^1.0.4" - checksum: 10c0/f8b294a4e6ea3855fc59551bbf35f2b832cf01fd5e6e2a97f5c201a071cc09b49048f856e484b67a6c721da5e55736c5b6ddafaf19e2dbeb4a3ff1821680de6c - languageName: node - linkType: hard - -"ip-address@npm:^9.0.5": - version: 9.0.5 - resolution: "ip-address@npm:9.0.5" - dependencies: - jsbn: "npm:1.1.0" - sprintf-js: "npm:^1.1.3" - checksum: 10c0/331cd07fafcb3b24100613e4b53e1a2b4feab11e671e655d46dc09ee233da5011284d09ca40c4ecbdfe1d0004f462958675c224a804259f2f78d2465a87824bc - languageName: node - linkType: hard - -"is-arguments@npm:^1.1.1": - version: 1.1.1 - resolution: "is-arguments@npm:1.1.1" - dependencies: - call-bind: "npm:^1.0.2" - has-tostringtag: "npm:^1.0.0" - checksum: 10c0/5ff1f341ee4475350adfc14b2328b38962564b7c2076be2f5bac7bd9b61779efba99b9f844a7b82ba7654adccf8e8eb19d1bb0cc6d1c1a085e498f6793d4328f - languageName: node - linkType: hard - -"is-array-buffer@npm:^3.0.2, is-array-buffer@npm:^3.0.4": - version: 3.0.4 - resolution: "is-array-buffer@npm:3.0.4" - dependencies: - call-bind: "npm:^1.0.2" - get-intrinsic: "npm:^1.2.1" - checksum: 10c0/42a49d006cc6130bc5424eae113e948c146f31f9d24460fc0958f855d9d810e6fd2e4519bf19aab75179af9c298ea6092459d8cafdec523cd19e529b26eab860 - languageName: node - linkType: hard - -"is-arrayish@npm:^0.3.1": - version: 0.3.2 - resolution: "is-arrayish@npm:0.3.2" - checksum: 10c0/f59b43dc1d129edb6f0e282595e56477f98c40278a2acdc8b0a5c57097c9eff8fe55470493df5775478cf32a4dc8eaf6d3a749f07ceee5bc263a78b2434f6a54 - languageName: node - linkType: hard - -"is-bigint@npm:^1.0.1": - version: 1.0.4 - resolution: "is-bigint@npm:1.0.4" - dependencies: - has-bigints: "npm:^1.0.1" - checksum: 10c0/eb9c88e418a0d195ca545aff2b715c9903d9b0a5033bc5922fec600eb0c3d7b1ee7f882dbf2e0d5a6e694e42391be3683e4368737bd3c4a77f8ac293e7773696 - languageName: node - linkType: hard - -"is-boolean-object@npm:^1.1.0": - version: 1.1.2 - resolution: "is-boolean-object@npm:1.1.2" - dependencies: - call-bind: "npm:^1.0.2" - has-tostringtag: "npm:^1.0.0" - checksum: 10c0/6090587f8a8a8534c0f816da868bc94f32810f08807aa72fa7e79f7e11c466d281486ffe7a788178809c2aa71fe3e700b167fe80dd96dad68026bfff8ebf39f7 - languageName: node - linkType: hard - -"is-callable@npm:^1.1.3": - version: 1.2.7 - resolution: "is-callable@npm:1.2.7" - checksum: 10c0/ceebaeb9d92e8adee604076971dd6000d38d6afc40bb843ea8e45c5579b57671c3f3b50d7f04869618242c6cee08d1b67806a8cb8edaaaf7c0748b3720d6066f - languageName: node - linkType: hard - -"is-date-object@npm:^1.0.5": - version: 1.0.5 - resolution: "is-date-object@npm:1.0.5" - dependencies: - has-tostringtag: "npm:^1.0.0" - checksum: 10c0/eed21e5dcc619c48ccef804dfc83a739dbb2abee6ca202838ee1bd5f760fe8d8a93444f0d49012ad19bb7c006186e2884a1b92f6e1c056da7fd23d0a9ad5992e - languageName: node - linkType: hard - -"is-fullwidth-code-point@npm:^3.0.0": - version: 3.0.0 - resolution: "is-fullwidth-code-point@npm:3.0.0" - checksum: 10c0/bb11d825e049f38e04c06373a8d72782eee0205bda9d908cc550ccb3c59b99d750ff9537982e01733c1c94a58e35400661f57042158ff5e8f3e90cf936daf0fc - languageName: node - linkType: hard - -"is-lambda@npm:^1.0.1": - version: 1.0.1 - resolution: "is-lambda@npm:1.0.1" - checksum: 10c0/85fee098ae62ba6f1e24cf22678805473c7afd0fb3978a3aa260e354cb7bcb3a5806cf0a98403188465efedec41ab4348e8e4e79305d409601323855b3839d4d - languageName: node - linkType: hard - -"is-map@npm:^2.0.2, is-map@npm:^2.0.3": - version: 2.0.3 - resolution: "is-map@npm:2.0.3" - checksum: 10c0/2c4d431b74e00fdda7162cd8e4b763d6f6f217edf97d4f8538b94b8702b150610e2c64961340015fe8df5b1fcee33ccd2e9b62619c4a8a3a155f8de6d6d355fc - languageName: node - linkType: hard - -"is-number-object@npm:^1.0.4": - version: 1.0.7 - resolution: "is-number-object@npm:1.0.7" - dependencies: - has-tostringtag: "npm:^1.0.0" - checksum: 10c0/aad266da1e530f1804a2b7bd2e874b4869f71c98590b3964f9d06cc9869b18f8d1f4778f838ecd2a11011bce20aeecb53cb269ba916209b79c24580416b74b1b - languageName: node - linkType: hard - -"is-regex@npm:^1.1.4": - version: 1.1.4 - resolution: "is-regex@npm:1.1.4" - dependencies: - call-bind: "npm:^1.0.2" - has-tostringtag: "npm:^1.0.0" - checksum: 10c0/bb72aae604a69eafd4a82a93002058c416ace8cde95873589a97fc5dac96a6c6c78a9977d487b7b95426a8f5073969124dd228f043f9f604f041f32fcc465fc1 - languageName: node - linkType: hard - -"is-set@npm:^2.0.2, is-set@npm:^2.0.3": - version: 2.0.3 - resolution: "is-set@npm:2.0.3" - checksum: 10c0/f73732e13f099b2dc879c2a12341cfc22ccaca8dd504e6edae26484bd5707a35d503fba5b4daad530a9b088ced1ae6c9d8200fd92e09b428fe14ea79ce8080b7 - languageName: node - linkType: hard - -"is-shared-array-buffer@npm:^1.0.2": - version: 1.0.3 - resolution: "is-shared-array-buffer@npm:1.0.3" - dependencies: - call-bind: "npm:^1.0.7" - checksum: 10c0/adc11ab0acbc934a7b9e5e9d6c588d4ec6682f6fea8cda5180721704fa32927582ede5b123349e32517fdadd07958973d24716c80e7ab198970c47acc09e59c7 - languageName: node - linkType: hard - -"is-stream@npm:^2.0.0, is-stream@npm:^2.0.1": - version: 2.0.1 - resolution: "is-stream@npm:2.0.1" - checksum: 10c0/7c284241313fc6efc329b8d7f08e16c0efeb6baab1b4cd0ba579eb78e5af1aa5da11e68559896a2067cd6c526bd29241dda4eb1225e627d5aa1a89a76d4635a5 - languageName: node - linkType: hard - -"is-string@npm:^1.0.5, is-string@npm:^1.0.7": - version: 1.0.7 - resolution: "is-string@npm:1.0.7" - dependencies: - has-tostringtag: "npm:^1.0.0" - checksum: 10c0/905f805cbc6eedfa678aaa103ab7f626aac9ebbdc8737abb5243acaa61d9820f8edc5819106b8fcd1839e33db21de9f0116ae20de380c8382d16dc2a601921f6 - languageName: node - linkType: hard - -"is-symbol@npm:^1.0.3": - version: 1.0.4 - resolution: "is-symbol@npm:1.0.4" - dependencies: - has-symbols: "npm:^1.0.2" - checksum: 10c0/9381dd015f7c8906154dbcbf93fad769de16b4b961edc94f88d26eb8c555935caa23af88bda0c93a18e65560f6d7cca0fd5a3f8a8e1df6f1abbb9bead4502ef7 - languageName: node - linkType: hard - -"is-weakmap@npm:^2.0.2": - version: 2.0.2 - resolution: "is-weakmap@npm:2.0.2" - checksum: 10c0/443c35bb86d5e6cc5929cd9c75a4024bb0fff9586ed50b092f94e700b89c43a33b186b76dbc6d54f3d3d09ece689ab38dcdc1af6a482cbe79c0f2da0a17f1299 - languageName: node - linkType: hard - -"is-weakset@npm:^2.0.3": - version: 2.0.3 - resolution: "is-weakset@npm:2.0.3" - dependencies: - call-bind: "npm:^1.0.7" - get-intrinsic: "npm:^1.2.4" - checksum: 10c0/8ad6141b6a400e7ce7c7442a13928c676d07b1f315ab77d9912920bf5f4170622f43126f111615788f26c3b1871158a6797c862233124507db0bcc33a9537d1a - languageName: node - linkType: hard - -"isarray@npm:^2.0.5": - version: 2.0.5 - resolution: "isarray@npm:2.0.5" - checksum: 10c0/4199f14a7a13da2177c66c31080008b7124331956f47bca57dd0b6ea9f11687aa25e565a2c7a2b519bc86988d10398e3049a1f5df13c9f6b7664154690ae79fd - languageName: node - linkType: hard - -"isarray@npm:~1.0.0": - version: 1.0.0 - resolution: "isarray@npm:1.0.0" - checksum: 10c0/18b5be6669be53425f0b84098732670ed4e727e3af33bc7f948aac01782110eb9a18b3b329c5323bcdd3acdaae547ee077d3951317e7f133bff7105264b3003d - languageName: node - linkType: hard - -"isexe@npm:^2.0.0": - version: 2.0.0 - resolution: "isexe@npm:2.0.0" - checksum: 10c0/228cfa503fadc2c31596ab06ed6aa82c9976eec2bfd83397e7eaf06d0ccf42cd1dfd6743bf9aeb01aebd4156d009994c5f76ea898d2832c1fe342da923ca457d - languageName: node - linkType: hard - -"isexe@npm:^3.1.1": - version: 3.1.1 - resolution: "isexe@npm:3.1.1" - checksum: 10c0/9ec257654093443eb0a528a9c8cbba9c0ca7616ccb40abd6dde7202734d96bb86e4ac0d764f0f8cd965856aacbff2f4ce23e730dc19dfb41e3b0d865ca6fdcc7 - languageName: node - linkType: hard - -"jackspeak@npm:^3.1.2": - version: 3.4.3 - resolution: "jackspeak@npm:3.4.3" - dependencies: - "@isaacs/cliui": "npm:^8.0.2" - "@pkgjs/parseargs": "npm:^0.11.0" - dependenciesMeta: - "@pkgjs/parseargs": - optional: true - checksum: 10c0/6acc10d139eaefdbe04d2f679e6191b3abf073f111edf10b1de5302c97ec93fffeb2fdd8681ed17f16268aa9dd4f8c588ed9d1d3bffbbfa6e8bf897cbb3149b9 - languageName: node - linkType: hard - -"jsbn@npm:1.1.0": - version: 1.1.0 - resolution: "jsbn@npm:1.1.0" - checksum: 10c0/4f907fb78d7b712e11dea8c165fe0921f81a657d3443dde75359ed52eb2b5d33ce6773d97985a089f09a65edd80b11cb75c767b57ba47391fee4c969f7215c96 - languageName: node - linkType: hard - -"jsonwebtoken@npm:^9.0.2": - version: 9.0.2 - resolution: "jsonwebtoken@npm:9.0.2" - dependencies: - jws: "npm:^3.2.2" - lodash.includes: "npm:^4.3.0" - lodash.isboolean: "npm:^3.0.3" - lodash.isinteger: "npm:^4.0.4" - lodash.isnumber: "npm:^3.0.3" - lodash.isplainobject: "npm:^4.0.6" - lodash.isstring: "npm:^4.0.1" - lodash.once: "npm:^4.0.0" - ms: "npm:^2.1.1" - semver: "npm:^7.5.4" - checksum: 10c0/d287a29814895e866db2e5a0209ce730cbc158441a0e5a70d5e940eb0d28ab7498c6bf45029cc8b479639bca94056e9a7f254e2cdb92a2f5750c7f358657a131 - languageName: node - linkType: hard - -"jwa@npm:^1.4.2": - version: 1.4.2 - resolution: "jwa@npm:1.4.2" - dependencies: - buffer-equal-constant-time: "npm:^1.0.1" - ecdsa-sig-formatter: "npm:1.0.11" - safe-buffer: "npm:^5.0.1" - checksum: 10c0/210a544a42ca22203e8fc538835205155ba3af6a027753109f9258bdead33086bac3c25295af48ac1981f87f9c5f941bc8f70303670f54ea7dcaafb53993d92c - languageName: node - linkType: hard - -"jws@npm:^3.2.2": - version: 3.2.3 - resolution: "jws@npm:3.2.3" - dependencies: - jwa: "npm:^1.4.2" - safe-buffer: "npm:^5.0.1" - checksum: 10c0/9fdf9d6783b1892ef413ef373cd351eacc847ba01deec6fbfea96830e93241863ccbee66f3b749fc2310c59b6db2209d3f4b52931c0c259b52b17de20715917f - languageName: node - linkType: hard - -"kuler@npm:^2.0.0": - version: 2.0.0 - resolution: "kuler@npm:2.0.0" - checksum: 10c0/0a4e99d92ca373f8f74d1dc37931909c4d0d82aebc94cf2ba265771160fc12c8df34eaaac80805efbda367e2795cb1f1dd4c3d404b6b1cf38aec94035b503d2d - languageName: node - linkType: hard - -"lazystream@npm:^1.0.0": - version: 1.0.1 - resolution: "lazystream@npm:1.0.1" - dependencies: - readable-stream: "npm:^2.0.5" - checksum: 10c0/ea4e509a5226ecfcc303ba6782cc269be8867d372b9bcbd625c88955df1987ea1a20da4643bf9270336415a398d33531ebf0d5f0d393b9283dc7c98bfcbd7b69 - languageName: node - linkType: hard - -"lodash.camelcase@npm:^4.3.0": - version: 4.3.0 - resolution: "lodash.camelcase@npm:4.3.0" - checksum: 10c0/fcba15d21a458076dd309fce6b1b4bf611d84a0ec252cb92447c948c533ac250b95d2e00955801ebc367e5af5ed288b996d75d37d2035260a937008e14eaf432 - languageName: node - linkType: hard - -"lodash.chunk@npm:^4.2.0": - version: 4.2.0 - resolution: "lodash.chunk@npm:4.2.0" - checksum: 10c0/f9f99969561ad2f62af1f9a96c5bd0af776f000292b0d8db3126c28eb3b32e210d7c31b49c18d0d7901869bd769057046dc134b60cfa0c2c4ce017823a26bb23 - languageName: node - linkType: hard - -"lodash.compact@npm:^3.0.1": - version: 3.0.1 - resolution: "lodash.compact@npm:3.0.1" - checksum: 10c0/9cc32065f1a9aa90bf3caa987fb7e00f8b90a49209e7f9f37c601e595f396a83ebe8f3328b2ef7f365cf822c9f21697527620c9c9c9734f107453b4c6c4dd810 - languageName: node - linkType: hard - -"lodash.groupby@npm:^4.6.0": - version: 4.6.0 - resolution: "lodash.groupby@npm:4.6.0" - checksum: 10c0/3d136cad438ad6c3a078984ef60e057a3498b1312aa3621b00246ecb99e8f2c4d447e2815460db7a0b661a4fe4e2eeee96c84cb661a824bad04b6cf1f7bc6e9b - languageName: node - linkType: hard - -"lodash.identity@npm:^3.0.0": - version: 3.0.0 - resolution: "lodash.identity@npm:3.0.0" - checksum: 10c0/a09ca0f99ae495c353e4ac6888684397f3b5b0c5f7d13a866a3956b7b2aa779462c78c219a31d4aab255d027ac5e11e8c3d943e70956e2a3d42feea56a8e9c1c - languageName: node - linkType: hard - -"lodash.includes@npm:^4.3.0": - version: 4.3.0 - resolution: "lodash.includes@npm:4.3.0" - checksum: 10c0/7ca498b9b75bf602d04e48c0adb842dfc7d90f77bcb2a91a2b2be34a723ad24bc1c8b3683ec6b2552a90f216c723cdea530ddb11a3320e08fa38265703978f4b - languageName: node - linkType: hard - -"lodash.isboolean@npm:^3.0.3": - version: 3.0.3 - resolution: "lodash.isboolean@npm:3.0.3" - checksum: 10c0/0aac604c1ef7e72f9a6b798e5b676606042401dd58e49f051df3cc1e3adb497b3d7695635a5cbec4ae5f66456b951fdabe7d6b387055f13267cde521f10ec7f7 - languageName: node - linkType: hard - -"lodash.isempty@npm:^4.4.0": - version: 4.4.0 - resolution: "lodash.isempty@npm:4.4.0" - checksum: 10c0/6c7eaa0802398736809b9e8aed8b8ac1abca9be71788fd719ba9d7f5b4c23e8dc63b7f049df4131713dda30a2fdedc2f655268e9deb8cd5a985dfc934afca194 - languageName: node - linkType: hard - -"lodash.isequal@npm:^4.5.0": - version: 4.5.0 - resolution: "lodash.isequal@npm:4.5.0" - checksum: 10c0/dfdb2356db19631a4b445d5f37868a095e2402292d59539a987f134a8778c62a2810c2452d11ae9e6dcac71fc9de40a6fedcb20e2952a15b431ad8b29e50e28f - languageName: node - linkType: hard - -"lodash.isinteger@npm:^4.0.4": - version: 4.0.4 - resolution: "lodash.isinteger@npm:4.0.4" - checksum: 10c0/4c3e023a2373bf65bf366d3b8605b97ec830bca702a926939bcaa53f8e02789b6a176e7f166b082f9365bfec4121bfeb52e86e9040cb8d450e64c858583f61b7 - languageName: node - linkType: hard - -"lodash.isnumber@npm:^3.0.3": - version: 3.0.3 - resolution: "lodash.isnumber@npm:3.0.3" - checksum: 10c0/2d01530513a1ee4f72dd79528444db4e6360588adcb0e2ff663db2b3f642d4bb3d687051ae1115751ca9082db4fdef675160071226ca6bbf5f0c123dbf0aa12d - languageName: node - linkType: hard - -"lodash.isobject@npm:^3.0.2": - version: 3.0.2 - resolution: "lodash.isobject@npm:3.0.2" - checksum: 10c0/da4c8480d98b16835b59380b2fbd43c54081acd9466febb788ba77c434384349e0bec162d1c4e89f613f21687b2b6d8384d8a112b80da00c78d28d9915a5cdde - languageName: node - linkType: hard - -"lodash.isplainobject@npm:^4.0.6": - version: 4.0.6 - resolution: "lodash.isplainobject@npm:4.0.6" - checksum: 10c0/afd70b5c450d1e09f32a737bed06ff85b873ecd3d3d3400458725283e3f2e0bb6bf48e67dbe7a309eb371a822b16a26cca4a63c8c52db3fc7dc9d5f9dd324cbb - languageName: node - linkType: hard - -"lodash.isstring@npm:^4.0.1": - version: 4.0.1 - resolution: "lodash.isstring@npm:4.0.1" - checksum: 10c0/09eaf980a283f9eef58ef95b30ec7fee61df4d6bf4aba3b5f096869cc58f24c9da17900febc8ffd67819b4e29de29793190e88dc96983db92d84c95fa85d1c92 - languageName: node - linkType: hard - -"lodash.kebabcase@npm:^4.1.1": - version: 4.1.1 - resolution: "lodash.kebabcase@npm:4.1.1" - checksum: 10c0/da5d8f41dbb5bc723d4bf9203d5096ca8da804d6aec3d2b56457156ba6c8d999ff448d347ebd97490da853cb36696ea4da09a431499f1ee8deb17b094ecf4e33 - languageName: node - linkType: hard - -"lodash.mapvalues@npm:^4.6.0": - version: 4.6.0 - resolution: "lodash.mapvalues@npm:4.6.0" - checksum: 10c0/a976bfc3923d4d8d2034e049ec4700e3aaf141a6143c973d06be3b2c87697923cd0158ee770484ad1af52dfed93ae90d2b76268413db95a42a2f46d7e1754828 - languageName: node - linkType: hard - -"lodash.merge@npm:^4.6.2": - version: 4.6.2 - resolution: "lodash.merge@npm:4.6.2" - checksum: 10c0/402fa16a1edd7538de5b5903a90228aa48eb5533986ba7fa26606a49db2572bf414ff73a2c9f5d5fd36b31c46a5d5c7e1527749c07cbcf965ccff5fbdf32c506 - languageName: node - linkType: hard - -"lodash.omit@npm:^4.5.0": - version: 4.5.0 - resolution: "lodash.omit@npm:4.5.0" - checksum: 10c0/3808b9b6faae35177174b6ab327f1177e29c91f1e98dcbccf13a72a6767bba337306449d537a4e0d8a33d2673f10d39bc732e30c4b803274ea0c1168ea60e549 - languageName: node - linkType: hard - -"lodash.once@npm:^4.0.0": - version: 4.1.1 - resolution: "lodash.once@npm:4.1.1" - checksum: 10c0/46a9a0a66c45dd812fcc016e46605d85ad599fe87d71a02f6736220554b52ffbe82e79a483ad40f52a8a95755b0d1077fba259da8bfb6694a7abbf4a48f1fc04 - languageName: node - linkType: hard - -"lodash.pickby@npm:^4.6.0": - version: 4.6.0 - resolution: "lodash.pickby@npm:4.6.0" - checksum: 10c0/46befadb64ab0f61159977174b291f87b005cec1c7bd73d1b6949ec4cdff483c1be0e34398df8955b76ce06a3e93a4a5c5a552a4299520390d6993c5420c7ab9 - languageName: node - linkType: hard - -"lodash.snakecase@npm:^4.1.1": - version: 4.1.1 - resolution: "lodash.snakecase@npm:4.1.1" - checksum: 10c0/f0b3f2497eb20eea1a1cfc22d645ecaeb78ac14593eb0a40057977606d2f35f7aaff0913a06553c783b535aafc55b718f523f9eb78f8d5293f492af41002eaf9 - languageName: node - linkType: hard - -"lodash.upperfirst@npm:^4.3.1": - version: 4.3.1 - resolution: "lodash.upperfirst@npm:4.3.1" - checksum: 10c0/435625da4b3ee74e7a1367a780d9107ab0b13ef4359fc074b2a1a40458eb8d91b655af62f6795b7138d493303a98c0285340160341561d6896e4947e077fa975 - languageName: node - linkType: hard - -"lodash@npm:^4.17.15": - version: 4.17.23 - resolution: "lodash@npm:4.17.23" - checksum: 10c0/1264a90469f5bb95d4739c43eb6277d15b6d9e186df4ac68c3620443160fc669e2f14c11e7d8b2ccf078b81d06147c01a8ccced9aab9f9f63d50dcf8cace6bf6 - languageName: node - linkType: hard - -"logform@npm:^2.6.0, logform@npm:^2.6.1": - version: 2.6.1 - resolution: "logform@npm:2.6.1" - dependencies: - "@colors/colors": "npm:1.6.0" - "@types/triple-beam": "npm:^1.3.2" - fecha: "npm:^4.2.0" - ms: "npm:^2.1.1" - safe-stable-stringify: "npm:^2.3.1" - triple-beam: "npm:^1.3.0" - checksum: 10c0/c20019336b1da8c08adea67dd7de2b0effdc6e35289c0156722924b571df94ba9f900ef55620c56bceb07cae7cc46057c9859accdee37a131251ba34d6789bce - languageName: node - linkType: hard - -"lru-cache@npm:^10.0.1, lru-cache@npm:^10.2.0": - version: 10.4.3 - resolution: "lru-cache@npm:10.4.3" - checksum: 10c0/ebd04fbca961e6c1d6c0af3799adcc966a1babe798f685bb84e6599266599cd95d94630b10262f5424539bc4640107e8a33aa28585374abf561d30d16f4b39fb - languageName: node - linkType: hard - -"make-dir@npm:^3.1.0": - version: 3.1.0 - resolution: "make-dir@npm:3.1.0" - dependencies: - semver: "npm:^6.0.0" - checksum: 10c0/56aaafefc49c2dfef02c5c95f9b196c4eb6988040cf2c712185c7fe5c99b4091591a7fc4d4eafaaefa70ff763a26f6ab8c3ff60b9e75ea19876f49b18667ecaa - languageName: node - linkType: hard - -"make-fetch-happen@npm:^13.0.0": - version: 13.0.1 - resolution: "make-fetch-happen@npm:13.0.1" - dependencies: - "@npmcli/agent": "npm:^2.0.0" - cacache: "npm:^18.0.0" - http-cache-semantics: "npm:^4.1.1" - is-lambda: "npm:^1.0.1" - minipass: "npm:^7.0.2" - minipass-fetch: "npm:^3.0.0" - minipass-flush: "npm:^1.0.5" - minipass-pipeline: "npm:^1.2.4" - negotiator: "npm:^0.6.3" - proc-log: "npm:^4.2.0" - promise-retry: "npm:^2.0.1" - ssri: "npm:^10.0.0" - checksum: 10c0/df5f4dbb6d98153b751bccf4dc4cc500de85a96a9331db9805596c46aa9f99d9555983954e6c1266d9f981ae37a9e4647f42b9a4bb5466f867f4012e582c9e7e - languageName: node - linkType: hard - -"math-intrinsics@npm:^1.1.0": - version: 1.1.0 - resolution: "math-intrinsics@npm:1.1.0" - checksum: 10c0/7579ff94e899e2f76ab64491d76cf606274c874d8f2af4a442c016bd85688927fcfca157ba6bf74b08e9439dc010b248ce05b96cc7c126a354c3bae7fcb48b7f - languageName: node - linkType: hard - -"media-typer@npm:0.3.0": - version: 0.3.0 - resolution: "media-typer@npm:0.3.0" - checksum: 10c0/d160f31246907e79fed398470285f21bafb45a62869dc469b1c8877f3f064f5eabc4bcc122f9479b8b605bc5c76187d7871cf84c4ee3ecd3e487da1993279928 - languageName: node - linkType: hard - -"mime-db@npm:1.52.0": - version: 1.52.0 - resolution: "mime-db@npm:1.52.0" - checksum: 10c0/0557a01deebf45ac5f5777fe7740b2a5c309c6d62d40ceab4e23da9f821899ce7a900b7ac8157d4548ddbb7beffe9abc621250e6d182b0397ec7f10c7b91a5aa - languageName: node - linkType: hard - -"mime-types@npm:^2.1.12, mime-types@npm:~2.1.24": - version: 2.1.35 - resolution: "mime-types@npm:2.1.35" - dependencies: - mime-db: "npm:1.52.0" - checksum: 10c0/82fb07ec56d8ff1fc999a84f2f217aa46cb6ed1033fefaabd5785b9a974ed225c90dc72fff460259e66b95b73648596dbcc50d51ed69cdf464af2d237d3149b2 - languageName: node - linkType: hard - -"minimatch@npm:^3.1.1": - version: 3.1.2 - resolution: "minimatch@npm:3.1.2" - dependencies: - brace-expansion: "npm:^1.1.7" - checksum: 10c0/0262810a8fc2e72cca45d6fd86bd349eee435eb95ac6aa45c9ea2180e7ee875ef44c32b55b5973ceabe95ea12682f6e3725cbb63d7a2d1da3ae1163c8b210311 - languageName: node - linkType: hard - -"minimatch@npm:^5.1.0": - version: 5.1.6 - resolution: "minimatch@npm:5.1.6" - dependencies: - brace-expansion: "npm:^2.0.1" - checksum: 10c0/3defdfd230914f22a8da203747c42ee3c405c39d4d37ffda284dac5e45b7e1f6c49aa8be606509002898e73091ff2a3bbfc59c2c6c71d4660609f63aa92f98e3 - languageName: node - linkType: hard - -"minimatch@npm:^9.0.4": - version: 9.0.5 - resolution: "minimatch@npm:9.0.5" - dependencies: - brace-expansion: "npm:^2.0.1" - checksum: 10c0/de96cf5e35bdf0eab3e2c853522f98ffbe9a36c37797778d2665231ec1f20a9447a7e567cb640901f89e4daaa95ae5d70c65a9e8aa2bb0019b6facbc3c0575ed - languageName: node - linkType: hard - -"minipass-collect@npm:^2.0.1": - version: 2.0.1 - resolution: "minipass-collect@npm:2.0.1" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10c0/5167e73f62bb74cc5019594709c77e6a742051a647fe9499abf03c71dca75515b7959d67a764bdc4f8b361cf897fbf25e2d9869ee039203ed45240f48b9aa06e - languageName: node - linkType: hard - -"minipass-fetch@npm:^3.0.0": - version: 3.0.5 - resolution: "minipass-fetch@npm:3.0.5" - dependencies: - encoding: "npm:^0.1.13" - minipass: "npm:^7.0.3" - minipass-sized: "npm:^1.0.3" - minizlib: "npm:^2.1.2" - dependenciesMeta: - encoding: - optional: true - checksum: 10c0/9d702d57f556274286fdd97e406fc38a2f5c8d15e158b498d7393b1105974b21249289ec571fa2b51e038a4872bfc82710111cf75fae98c662f3d6f95e72152b - languageName: node - linkType: hard - -"minipass-flush@npm:^1.0.5": - version: 1.0.5 - resolution: "minipass-flush@npm:1.0.5" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10c0/2a51b63feb799d2bb34669205eee7c0eaf9dce01883261a5b77410c9408aa447e478efd191b4de6fc1101e796ff5892f8443ef20d9544385819093dbb32d36bd - languageName: node - linkType: hard - -"minipass-pipeline@npm:^1.2.4": - version: 1.2.4 - resolution: "minipass-pipeline@npm:1.2.4" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10c0/cbda57cea20b140b797505dc2cac71581a70b3247b84480c1fed5ca5ba46c25ecc25f68bfc9e6dcb1a6e9017dab5c7ada5eab73ad4f0a49d84e35093e0c643f2 - languageName: node - linkType: hard - -"minipass-sized@npm:^1.0.3": - version: 1.0.3 - resolution: "minipass-sized@npm:1.0.3" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10c0/298f124753efdc745cfe0f2bdfdd81ba25b9f4e753ca4a2066eb17c821f25d48acea607dfc997633ee5bf7b6dfffb4eee4f2051eb168663f0b99fad2fa4829cb - languageName: node - linkType: hard - -"minipass@npm:^3.0.0": - version: 3.3.6 - resolution: "minipass@npm:3.3.6" - dependencies: - yallist: "npm:^4.0.0" - checksum: 10c0/a114746943afa1dbbca8249e706d1d38b85ed1298b530f5808ce51f8e9e941962e2a5ad2e00eae7dd21d8a4aae6586a66d4216d1a259385e9d0358f0c1eba16c - languageName: node - linkType: hard - -"minipass@npm:^5.0.0": - version: 5.0.0 - resolution: "minipass@npm:5.0.0" - checksum: 10c0/a91d8043f691796a8ac88df039da19933ef0f633e3d7f0d35dcd5373af49131cf2399bfc355f41515dc495e3990369c3858cd319e5c2722b4753c90bf3152462 - languageName: node - linkType: hard - -"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.1.2": - version: 7.1.2 - resolution: "minipass@npm:7.1.2" - checksum: 10c0/b0fd20bb9fb56e5fa9a8bfac539e8915ae07430a619e4b86ff71f5fc757ef3924b23b2c4230393af1eda647ed3d75739e4e0acb250a6b1eb277cf7f8fe449557 - languageName: node - linkType: hard - -"minizlib@npm:^2.1.1, minizlib@npm:^2.1.2": - version: 2.1.2 - resolution: "minizlib@npm:2.1.2" - dependencies: - minipass: "npm:^3.0.0" - yallist: "npm:^4.0.0" - checksum: 10c0/64fae024e1a7d0346a1102bb670085b17b7f95bf6cfdf5b128772ec8faf9ea211464ea4add406a3a6384a7d87a0cd1a96263692134323477b4fb43659a6cab78 - languageName: node - linkType: hard - -"mkdirp@npm:^1.0.3": - version: 1.0.4 - resolution: "mkdirp@npm:1.0.4" - bin: - mkdirp: bin/cmd.js - checksum: 10c0/46ea0f3ffa8bc6a5bc0c7081ffc3907777f0ed6516888d40a518c5111f8366d97d2678911ad1a6882bf592fa9de6c784fea32e1687bb94e1f4944170af48a5cf - languageName: node - linkType: hard - -"ms@npm:2.0.0": - version: 2.0.0 - resolution: "ms@npm:2.0.0" - checksum: 10c0/f8fda810b39fd7255bbdc451c46286e549794fcc700dc9cd1d25658bbc4dc2563a5de6fe7c60f798a16a60c6ceb53f033cb353f493f0cf63e5199b702943159d - languageName: node - linkType: hard - -"ms@npm:2.1.2": - version: 2.1.2 - resolution: "ms@npm:2.1.2" - checksum: 10c0/a437714e2f90dbf881b5191d35a6db792efbca5badf112f87b9e1c712aace4b4b9b742dd6537f3edf90fd6f684de897cec230abde57e87883766712ddda297cc - languageName: node - linkType: hard - -"ms@npm:^2.1.1": - version: 2.1.3 - resolution: "ms@npm:2.1.3" - checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48 - languageName: node - linkType: hard - -"negotiator@npm:^0.6.3": - version: 0.6.3 - resolution: "negotiator@npm:0.6.3" - checksum: 10c0/3ec9fd413e7bf071c937ae60d572bc67155262068ed522cf4b3be5edbe6ddf67d095ec03a3a14ebf8fc8e95f8e1d61be4869db0dbb0de696f6b837358bd43fc2 - languageName: node - linkType: hard - -"node-addon-api@npm:^5.0.0": - version: 5.1.0 - resolution: "node-addon-api@npm:5.1.0" - dependencies: - node-gyp: "npm:latest" - checksum: 10c0/0eb269786124ba6fad9df8007a149e03c199b3e5a3038125dfb3e747c2d5113d406a4e33f4de1ea600aa2339be1f137d55eba1a73ee34e5fff06c52a5c296d1d - languageName: node - linkType: hard - -"node-fetch@npm:^2.6.7": - version: 2.7.0 - resolution: "node-fetch@npm:2.7.0" - dependencies: - whatwg-url: "npm:^5.0.0" - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - checksum: 10c0/b55786b6028208e6fbe594ccccc213cab67a72899c9234eb59dba51062a299ea853210fcf526998eaa2867b0963ad72338824450905679ff0fa304b8c5093ae8 - languageName: node - linkType: hard - -"node-gyp@npm:latest": - version: 10.2.0 - resolution: "node-gyp@npm:10.2.0" - dependencies: - env-paths: "npm:^2.2.0" - exponential-backoff: "npm:^3.1.1" - glob: "npm:^10.3.10" - graceful-fs: "npm:^4.2.6" - make-fetch-happen: "npm:^13.0.0" - nopt: "npm:^7.0.0" - proc-log: "npm:^4.1.0" - semver: "npm:^7.3.5" - tar: "npm:^6.2.1" - which: "npm:^4.0.0" - bin: - node-gyp: bin/node-gyp.js - checksum: 10c0/00630d67dbd09a45aee0a5d55c05e3916ca9e6d427ee4f7bc392d2d3dc5fad7449b21fc098dd38260a53d9dcc9c879b36704a1994235d4707e7271af7e9a835b - languageName: node - linkType: hard - -"nodemailer@npm:^7.0.11": - version: 7.0.11 - resolution: "nodemailer@npm:7.0.11" - checksum: 10c0/208f108fdb4c5dd0e3a2f013578d53dad505cf1b9c7a084f6d22fc9d6f3912daafb4a23793ca568ff848afc35f15f4eb24382d3f6f9fb8ede4a8410d4ca63618 - languageName: node - linkType: hard - -"nopt@npm:^5.0.0": - version: 5.0.0 - resolution: "nopt@npm:5.0.0" - dependencies: - abbrev: "npm:1" - bin: - nopt: bin/nopt.js - checksum: 10c0/fc5c4f07155cb455bf5fc3dd149fac421c1a40fd83c6bfe83aa82b52f02c17c5e88301321318adaa27611c8a6811423d51d29deaceab5fa158b585a61a551061 - languageName: node - linkType: hard - -"nopt@npm:^7.0.0": - version: 7.2.1 - resolution: "nopt@npm:7.2.1" - dependencies: - abbrev: "npm:^2.0.0" - bin: - nopt: bin/nopt.js - checksum: 10c0/a069c7c736767121242037a22a788863accfa932ab285a1eb569eb8cd534b09d17206f68c37f096ae785647435e0c5a5a0a67b42ec743e481a455e5ae6a6df81 - languageName: node - linkType: hard - -"normalize-path@npm:^3.0.0": - version: 3.0.0 - resolution: "normalize-path@npm:3.0.0" - checksum: 10c0/e008c8142bcc335b5e38cf0d63cfd39d6cf2d97480af9abdbe9a439221fd4d749763bab492a8ee708ce7a194bb00c9da6d0a115018672310850489137b3da046 - languageName: node - linkType: hard - -"npmlog@npm:^5.0.1": - version: 5.0.1 - resolution: "npmlog@npm:5.0.1" - dependencies: - are-we-there-yet: "npm:^2.0.0" - console-control-strings: "npm:^1.1.0" - gauge: "npm:^3.0.0" - set-blocking: "npm:^2.0.0" - checksum: 10c0/489ba519031013001135c463406f55491a17fc7da295c18a04937fe3a4d523fd65e88dd418a28b967ab743d913fdeba1e29838ce0ad8c75557057c481f7d49fa - languageName: node - linkType: hard - -"object-assign@npm:^4.1.1": - version: 4.1.1 - resolution: "object-assign@npm:4.1.1" - checksum: 10c0/1f4df9945120325d041ccf7b86f31e8bcc14e73d29171e37a7903050e96b81323784ec59f93f102ec635bcf6fa8034ba3ea0a8c7e69fa202b87ae3b6cec5a414 - languageName: node - linkType: hard - -"object-inspect@npm:^1.13.1": - version: 1.13.2 - resolution: "object-inspect@npm:1.13.2" - checksum: 10c0/b97835b4c91ec37b5fd71add84f21c3f1047d1d155d00c0fcd6699516c256d4fcc6ff17a1aced873197fe447f91a3964178fd2a67a1ee2120cdaf60e81a050b4 - languageName: node - linkType: hard - -"object-inspect@npm:^1.13.3": - version: 1.13.4 - resolution: "object-inspect@npm:1.13.4" - checksum: 10c0/d7f8711e803b96ea3191c745d6f8056ce1f2496e530e6a19a0e92d89b0fa3c76d910c31f0aa270432db6bd3b2f85500a376a83aaba849a8d518c8845b3211692 - languageName: node - linkType: hard - -"object-is@npm:^1.1.5": - version: 1.1.6 - resolution: "object-is@npm:1.1.6" - dependencies: - call-bind: "npm:^1.0.7" - define-properties: "npm:^1.2.1" - checksum: 10c0/506af444c4dce7f8e31f34fc549e2fb8152d6b9c4a30c6e62852badd7f520b579c679af433e7a072f9d78eb7808d230dc12e1cf58da9154dfbf8813099ea0fe0 - languageName: node - linkType: hard - -"object-keys@npm:^1.1.1": - version: 1.1.1 - resolution: "object-keys@npm:1.1.1" - checksum: 10c0/b11f7ccdbc6d406d1f186cdadb9d54738e347b2692a14439ca5ac70c225fa6db46db809711b78589866d47b25fc3e8dee0b4c722ac751e11180f9380e3d8601d - languageName: node - linkType: hard - -"object.assign@npm:^4.1.4": - version: 4.1.5 - resolution: "object.assign@npm:4.1.5" - dependencies: - call-bind: "npm:^1.0.5" - define-properties: "npm:^1.2.1" - has-symbols: "npm:^1.0.3" - object-keys: "npm:^1.1.1" - checksum: 10c0/60108e1fa2706f22554a4648299b0955236c62b3685c52abf4988d14fffb0e7731e00aa8c6448397e3eb63d087dcc124a9f21e1980f36d0b2667f3c18bacd469 - languageName: node - linkType: hard - -"on-finished@npm:~2.4.1": - version: 2.4.1 - resolution: "on-finished@npm:2.4.1" - dependencies: - ee-first: "npm:1.1.1" - checksum: 10c0/46fb11b9063782f2d9968863d9cbba33d77aa13c17f895f56129c274318b86500b22af3a160fe9995aa41317efcd22941b6eba747f718ced08d9a73afdb087b4 - languageName: node - linkType: hard - -"once@npm:^1.3.0": - version: 1.4.0 - resolution: "once@npm:1.4.0" - dependencies: - wrappy: "npm:1" - checksum: 10c0/5d48aca287dfefabd756621c5dfce5c91a549a93e9fdb7b8246bc4c4790aa2ec17b34a260530474635147aeb631a2dcc8b32c613df0675f96041cbb8244517d0 - languageName: node - linkType: hard - -"one-time@npm:^1.0.0": - version: 1.0.0 - resolution: "one-time@npm:1.0.0" - dependencies: - fn.name: "npm:1.x.x" - checksum: 10c0/6e4887b331edbb954f4e915831cbec0a7b9956c36f4feb5f6de98c448ac02ff881fd8d9b55a6b1b55030af184c6b648f340a76eb211812f4ad8c9b4b8692fdaa - languageName: node - linkType: hard - -"p-map@npm:^4.0.0": - version: 4.0.0 - resolution: "p-map@npm:4.0.0" - dependencies: - aggregate-error: "npm:^3.0.0" - checksum: 10c0/592c05bd6262c466ce269ff172bb8de7c6975afca9b50c975135b974e9bdaafbfe80e61aaaf5be6d1200ba08b30ead04b88cfa7e25ff1e3b93ab28c9f62a2c75 - languageName: node - linkType: hard - -"package-json-from-dist@npm:^1.0.0": - version: 1.0.0 - resolution: "package-json-from-dist@npm:1.0.0" - checksum: 10c0/e3ffaf6ac1040ab6082a658230c041ad14e72fabe99076a2081bb1d5d41210f11872403fc09082daf4387fc0baa6577f96c9c0e94c90c394fd57794b66aa4033 - languageName: node - linkType: hard - -"path-is-absolute@npm:^1.0.0": - version: 1.0.1 - resolution: "path-is-absolute@npm:1.0.1" - checksum: 10c0/127da03c82172a2a50099cddbf02510c1791fc2cc5f7713ddb613a56838db1e8168b121a920079d052e0936c23005562059756d653b7c544c53185efe53be078 - languageName: node - linkType: hard - -"path-key@npm:^3.1.0": - version: 3.1.1 - resolution: "path-key@npm:3.1.1" - checksum: 10c0/748c43efd5a569c039d7a00a03b58eecd1d75f3999f5a28303d75f521288df4823bc057d8784eb72358b2895a05f29a070bc9f1f17d28226cc4e62494cc58c4c - languageName: node - linkType: hard - -"path-scurry@npm:^1.11.1": - version: 1.11.1 - resolution: "path-scurry@npm:1.11.1" - dependencies: - lru-cache: "npm:^10.2.0" - minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" - checksum: 10c0/32a13711a2a505616ae1cc1b5076801e453e7aae6ac40ab55b388bb91b9d0547a52f5aaceff710ea400205f18691120d4431e520afbe4266b836fadede15872d - languageName: node - linkType: hard - -"possible-typed-array-names@npm:^1.0.0": - version: 1.0.0 - resolution: "possible-typed-array-names@npm:1.0.0" - checksum: 10c0/d9aa22d31f4f7680e20269db76791b41c3a32c01a373e25f8a4813b4d45f7456bfc2b6d68f752dc4aab0e0bb0721cb3d76fb678c9101cb7a16316664bc2c73fd - languageName: node - linkType: hard - -"proc-log@npm:^4.1.0, proc-log@npm:^4.2.0": - version: 4.2.0 - resolution: "proc-log@npm:4.2.0" - checksum: 10c0/17db4757c2a5c44c1e545170e6c70a26f7de58feb985091fb1763f5081cab3d01b181fb2dd240c9f4a4255a1d9227d163d5771b7e69c9e49a561692db865efb9 - languageName: node - linkType: hard - -"process-nextick-args@npm:~2.0.0": - version: 2.0.1 - resolution: "process-nextick-args@npm:2.0.1" - checksum: 10c0/bec089239487833d46b59d80327a1605e1c5287eaad770a291add7f45fda1bb5e28b38e0e061add0a1d0ee0984788ce74fa394d345eed1c420cacf392c554367 - languageName: node - linkType: hard - -"process@npm:^0.11.10": - version: 0.11.10 - resolution: "process@npm:0.11.10" - checksum: 10c0/40c3ce4b7e6d4b8c3355479df77aeed46f81b279818ccdc500124e6a5ab882c0cc81ff7ea16384873a95a74c4570b01b120f287abbdd4c877931460eca6084b3 - languageName: node - linkType: hard - -"promise-retry@npm:^2.0.1": - version: 2.0.1 - resolution: "promise-retry@npm:2.0.1" - dependencies: - err-code: "npm:^2.0.2" - retry: "npm:^0.12.0" - checksum: 10c0/9c7045a1a2928094b5b9b15336dcd2a7b1c052f674550df63cc3f36cd44028e5080448175b6f6ca32b642de81150f5e7b1a98b728f15cb069f2dd60ac2616b96 - languageName: node - linkType: hard - -"proxy-from-env@npm:^1.1.0": - version: 1.1.0 - resolution: "proxy-from-env@npm:1.1.0" - checksum: 10c0/fe7dd8b1bdbbbea18d1459107729c3e4a2243ca870d26d34c2c1bcd3e4425b7bcc5112362df2d93cc7fb9746f6142b5e272fd1cc5c86ddf8580175186f6ad42b - languageName: node - linkType: hard - -"qs@npm:~6.14.0": - version: 6.14.1 - resolution: "qs@npm:6.14.1" - dependencies: - side-channel: "npm:^1.1.0" - checksum: 10c0/0e3b22dc451f48ce5940cbbc7c7d9068d895074f8c969c0801ac15c1313d1859c4d738e46dc4da2f498f41a9ffd8c201bd9fb12df67799b827db94cc373d2613 - languageName: node - linkType: hard - -"queue-tick@npm:^1.0.1": - version: 1.0.1 - resolution: "queue-tick@npm:1.0.1" - checksum: 10c0/0db998e2c9b15215317dbcf801e9b23e6bcde4044e115155dae34f8e7454b9a783f737c9a725528d677b7a66c775eb7a955cf144fe0b87f62b575ce5bfd515a9 - languageName: node - linkType: hard - -"raw-body@npm:~2.5.3": - version: 2.5.3 - resolution: "raw-body@npm:2.5.3" - dependencies: - bytes: "npm:~3.1.2" - http-errors: "npm:~2.0.1" - iconv-lite: "npm:~0.4.24" - unpipe: "npm:~1.0.0" - checksum: 10c0/449844344fc90547fb994383a494b83300e4f22199f146a79f68d78a199a8f2a923ea9fd29c3be979bfd50291a3884733619ffc15ba02a32e703b612f8d3f74a - languageName: node - linkType: hard - -"readable-stream@npm:^2.0.5": - version: 2.3.8 - resolution: "readable-stream@npm:2.3.8" - dependencies: - core-util-is: "npm:~1.0.0" - inherits: "npm:~2.0.3" - isarray: "npm:~1.0.0" - process-nextick-args: "npm:~2.0.0" - safe-buffer: "npm:~5.1.1" - string_decoder: "npm:~1.1.1" - util-deprecate: "npm:~1.0.1" - checksum: 10c0/7efdb01f3853bc35ac62ea25493567bf588773213f5f4a79f9c365e1ad13bab845ac0dae7bc946270dc40c3929483228415e92a3fc600cc7e4548992f41ee3fa - languageName: node - linkType: hard - -"readable-stream@npm:^3.4.0, readable-stream@npm:^3.6.0, readable-stream@npm:^3.6.2": - version: 3.6.2 - resolution: "readable-stream@npm:3.6.2" - dependencies: - inherits: "npm:^2.0.3" - string_decoder: "npm:^1.1.1" - util-deprecate: "npm:^1.0.1" - checksum: 10c0/e37be5c79c376fdd088a45fa31ea2e423e5d48854be7a22a58869b4e84d25047b193f6acb54f1012331e1bcd667ffb569c01b99d36b0bd59658fb33f513511b7 - languageName: node - linkType: hard - -"readable-stream@npm:^4.0.0": - version: 4.5.2 - resolution: "readable-stream@npm:4.5.2" - dependencies: - abort-controller: "npm:^3.0.0" - buffer: "npm:^6.0.3" - events: "npm:^3.3.0" - process: "npm:^0.11.10" - string_decoder: "npm:^1.3.0" - checksum: 10c0/a2c80e0e53aabd91d7df0330929e32d0a73219f9477dbbb18472f6fdd6a11a699fc5d172a1beff98d50eae4f1496c950ffa85b7cc2c4c196963f289a5f39275d - languageName: node - linkType: hard - -"readdir-glob@npm:^1.1.2": - version: 1.1.3 - resolution: "readdir-glob@npm:1.1.3" - dependencies: - minimatch: "npm:^5.1.0" - checksum: 10c0/a37e0716726650845d761f1041387acd93aa91b28dd5381950733f994b6c349ddc1e21e266ec7cc1f9b92e205a7a972232f9b89d5424d07361c2c3753d5dbace - languageName: node - linkType: hard - -"regexp.prototype.flags@npm:^1.5.1": - version: 1.5.2 - resolution: "regexp.prototype.flags@npm:1.5.2" - dependencies: - call-bind: "npm:^1.0.6" - define-properties: "npm:^1.2.1" - es-errors: "npm:^1.3.0" - set-function-name: "npm:^2.0.1" - checksum: 10c0/0f3fc4f580d9c349f8b560b012725eb9c002f36daa0041b3fbf6f4238cb05932191a4d7d5db3b5e2caa336d5150ad0402ed2be81f711f9308fe7e1a9bf9bd552 - languageName: node - linkType: hard - -"retry@npm:^0.12.0": - version: 0.12.0 - resolution: "retry@npm:0.12.0" - checksum: 10c0/59933e8501727ba13ad73ef4a04d5280b3717fd650408460c987392efe9d7be2040778ed8ebe933c5cbd63da3dcc37919c141ef8af0a54a6e4fca5a2af177bfe - languageName: node - linkType: hard - -"rimraf@npm:^3.0.2": - version: 3.0.2 - resolution: "rimraf@npm:3.0.2" - dependencies: - glob: "npm:^7.1.3" - bin: - rimraf: bin.js - checksum: 10c0/9cb7757acb489bd83757ba1a274ab545eafd75598a9d817e0c3f8b164238dd90eba50d6b848bd4dcc5f3040912e882dc7ba71653e35af660d77b25c381d402e8 - languageName: node - linkType: hard - -"root-workspace-0b6124@workspace:.": - version: 0.0.0-use.local - resolution: "root-workspace-0b6124@workspace:." - dependencies: - "@types/bcrypt": "npm:^5.0.2" - "@types/deep-equal": "npm:^1.0.4" - "@types/lodash.camelcase": "npm:^4.3.9" - "@types/lodash.compact": "npm:^3.0.9" - "@types/lodash.groupby": "npm:^4.6.9" - "@types/lodash.identity": "npm:^3.0.9" - "@types/lodash.isempty": "npm:^4.4.9" - "@types/lodash.isequal": "npm:^4.5.8" - "@types/lodash.isobject": "npm:^3.0.9" - "@types/lodash.kebabcase": "npm:^4.1.9" - "@types/lodash.mapvalues": "npm:^4.6.9" - "@types/lodash.omit": "npm:^4.5.9" - "@types/lodash.pickby": "npm:^4.6.9" - "@types/lodash.snakecase": "npm:^4.1.9" - "@types/lodash.upperfirst": "npm:^4.3.9" - "@types/uuid": "npm:^10.0.0" - archiver: "npm:^7.0.1" - axios: "npm:^1.12.0" - bcrypt: "npm:^5.1.1" - body-parser: "npm:^1.20.4" - deep-equal: "npm:^2.2.3" - jsonwebtoken: "npm:^9.0.2" - lodash.camelcase: "npm:^4.3.0" - lodash.chunk: "npm:^4.2.0" - lodash.compact: "npm:^3.0.1" - lodash.groupby: "npm:^4.6.0" - lodash.identity: "npm:^3.0.0" - lodash.isempty: "npm:^4.4.0" - lodash.isequal: "npm:^4.5.0" - lodash.isobject: "npm:^3.0.2" - lodash.kebabcase: "npm:^4.1.1" - lodash.mapvalues: "npm:^4.6.0" - lodash.merge: "npm:^4.6.2" - lodash.omit: "npm:^4.5.0" - lodash.pickby: "npm:^4.6.0" - lodash.snakecase: "npm:^4.1.1" - lodash.upperfirst: "npm:^4.3.1" - nodemailer: "npm:^7.0.11" - sharp: "npm:^0.33.5" - uuid: "npm:^10.0.0" - winston: "npm:^3.14.2" - languageName: unknown - linkType: soft - -"safe-buffer@npm:^5.0.1, safe-buffer@npm:~5.2.0": - version: 5.2.1 - resolution: "safe-buffer@npm:5.2.1" - checksum: 10c0/6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3 - languageName: node - linkType: hard - -"safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1": - version: 5.1.2 - resolution: "safe-buffer@npm:5.1.2" - checksum: 10c0/780ba6b5d99cc9a40f7b951d47152297d0e260f0df01472a1b99d4889679a4b94a13d644f7dbc4f022572f09ae9005fa2fbb93bbbd83643316f365a3e9a45b21 - languageName: node - linkType: hard - -"safe-stable-stringify@npm:^2.3.1": - version: 2.5.0 - resolution: "safe-stable-stringify@npm:2.5.0" - checksum: 10c0/baea14971858cadd65df23894a40588ed791769db21bafb7fd7608397dbdce9c5aac60748abae9995e0fc37e15f2061980501e012cd48859740796bea2987f49 - languageName: node - linkType: hard - -"safer-buffer@npm:>= 2.1.2 < 3, safer-buffer@npm:>= 2.1.2 < 3.0.0": - version: 2.1.2 - resolution: "safer-buffer@npm:2.1.2" - checksum: 10c0/7e3c8b2e88a1841c9671094bbaeebd94448111dd90a81a1f606f3f67708a6ec57763b3b47f06da09fc6054193e0e6709e77325415dc8422b04497a8070fa02d4 - languageName: node - linkType: hard - -"semver@npm:^6.0.0": - version: 6.3.1 - resolution: "semver@npm:6.3.1" - bin: - semver: bin/semver.js - checksum: 10c0/e3d79b609071caa78bcb6ce2ad81c7966a46a7431d9d58b8800cfa9cb6a63699b3899a0e4bcce36167a284578212d9ae6942b6929ba4aa5015c079a67751d42d - languageName: node - linkType: hard - -"semver@npm:^7.3.5, semver@npm:^7.5.4, semver@npm:^7.6.3": - version: 7.6.3 - resolution: "semver@npm:7.6.3" - bin: - semver: bin/semver.js - checksum: 10c0/88f33e148b210c153873cb08cfe1e281d518aaa9a666d4d148add6560db5cd3c582f3a08ccb91f38d5f379ead256da9931234ed122057f40bb5766e65e58adaf - languageName: node - linkType: hard - -"set-blocking@npm:^2.0.0": - version: 2.0.0 - resolution: "set-blocking@npm:2.0.0" - checksum: 10c0/9f8c1b2d800800d0b589de1477c753492de5c1548d4ade52f57f1d1f5e04af5481554d75ce5e5c43d4004b80a3eb714398d6907027dc0534177b7539119f4454 - languageName: node - linkType: hard - -"set-function-length@npm:^1.2.1": - version: 1.2.2 - resolution: "set-function-length@npm:1.2.2" - dependencies: - define-data-property: "npm:^1.1.4" - es-errors: "npm:^1.3.0" - function-bind: "npm:^1.1.2" - get-intrinsic: "npm:^1.2.4" - gopd: "npm:^1.0.1" - has-property-descriptors: "npm:^1.0.2" - checksum: 10c0/82850e62f412a258b71e123d4ed3873fa9377c216809551192bb6769329340176f109c2eeae8c22a8d386c76739855f78e8716515c818bcaef384b51110f0f3c - languageName: node - linkType: hard - -"set-function-name@npm:^2.0.1": - version: 2.0.2 - resolution: "set-function-name@npm:2.0.2" - dependencies: - define-data-property: "npm:^1.1.4" - es-errors: "npm:^1.3.0" - functions-have-names: "npm:^1.2.3" - has-property-descriptors: "npm:^1.0.2" - checksum: 10c0/fce59f90696c450a8523e754abb305e2b8c73586452619c2bad5f7bf38c7b6b4651895c9db895679c5bef9554339cf3ef1c329b66ece3eda7255785fbe299316 - languageName: node - linkType: hard - -"setprototypeof@npm:~1.2.0": - version: 1.2.0 - resolution: "setprototypeof@npm:1.2.0" - checksum: 10c0/68733173026766fa0d9ecaeb07f0483f4c2dc70ca376b3b7c40b7cda909f94b0918f6c5ad5ce27a9160bdfb475efaa9d5e705a11d8eaae18f9835d20976028bc - languageName: node - linkType: hard - -"sharp@npm:^0.33.5": - version: 0.33.5 - resolution: "sharp@npm:0.33.5" - dependencies: - "@img/sharp-darwin-arm64": "npm:0.33.5" - "@img/sharp-darwin-x64": "npm:0.33.5" - "@img/sharp-libvips-darwin-arm64": "npm:1.0.4" - "@img/sharp-libvips-darwin-x64": "npm:1.0.4" - "@img/sharp-libvips-linux-arm": "npm:1.0.5" - "@img/sharp-libvips-linux-arm64": "npm:1.0.4" - "@img/sharp-libvips-linux-s390x": "npm:1.0.4" - "@img/sharp-libvips-linux-x64": "npm:1.0.4" - "@img/sharp-libvips-linuxmusl-arm64": "npm:1.0.4" - "@img/sharp-libvips-linuxmusl-x64": "npm:1.0.4" - "@img/sharp-linux-arm": "npm:0.33.5" - "@img/sharp-linux-arm64": "npm:0.33.5" - "@img/sharp-linux-s390x": "npm:0.33.5" - "@img/sharp-linux-x64": "npm:0.33.5" - "@img/sharp-linuxmusl-arm64": "npm:0.33.5" - "@img/sharp-linuxmusl-x64": "npm:0.33.5" - "@img/sharp-wasm32": "npm:0.33.5" - "@img/sharp-win32-ia32": "npm:0.33.5" - "@img/sharp-win32-x64": "npm:0.33.5" - color: "npm:^4.2.3" - detect-libc: "npm:^2.0.3" - semver: "npm:^7.6.3" - dependenciesMeta: - "@img/sharp-darwin-arm64": - optional: true - "@img/sharp-darwin-x64": - optional: true - "@img/sharp-libvips-darwin-arm64": - optional: true - "@img/sharp-libvips-darwin-x64": - optional: true - "@img/sharp-libvips-linux-arm": - optional: true - "@img/sharp-libvips-linux-arm64": - optional: true - "@img/sharp-libvips-linux-s390x": - optional: true - "@img/sharp-libvips-linux-x64": - optional: true - "@img/sharp-libvips-linuxmusl-arm64": - optional: true - "@img/sharp-libvips-linuxmusl-x64": - optional: true - "@img/sharp-linux-arm": - optional: true - "@img/sharp-linux-arm64": - optional: true - "@img/sharp-linux-s390x": - optional: true - "@img/sharp-linux-x64": - optional: true - "@img/sharp-linuxmusl-arm64": - optional: true - "@img/sharp-linuxmusl-x64": - optional: true - "@img/sharp-wasm32": - optional: true - "@img/sharp-win32-ia32": - optional: true - "@img/sharp-win32-x64": - optional: true - checksum: 10c0/6b81421ddfe6ee524d8d77e325c5e147fef22884e1c7b1656dfd89a88d7025894115da02d5f984261bf2e6daa16f98cadd1721c4ba408b4212b1d2a60f233484 - languageName: node - linkType: hard - -"shebang-command@npm:^2.0.0": - version: 2.0.0 - resolution: "shebang-command@npm:2.0.0" - dependencies: - shebang-regex: "npm:^3.0.0" - checksum: 10c0/a41692e7d89a553ef21d324a5cceb5f686d1f3c040759c50aab69688634688c5c327f26f3ecf7001ebfd78c01f3c7c0a11a7c8bfd0a8bc9f6240d4f40b224e4e - languageName: node - linkType: hard - -"shebang-regex@npm:^3.0.0": - version: 3.0.0 - resolution: "shebang-regex@npm:3.0.0" - checksum: 10c0/1dbed0726dd0e1152a92696c76c7f06084eb32a90f0528d11acd764043aacf76994b2fb30aa1291a21bd019d6699164d048286309a278855ee7bec06cf6fb690 - languageName: node - linkType: hard - -"side-channel-list@npm:^1.0.0": - version: 1.0.0 - resolution: "side-channel-list@npm:1.0.0" - dependencies: - es-errors: "npm:^1.3.0" - object-inspect: "npm:^1.13.3" - checksum: 10c0/644f4ac893456c9490ff388bf78aea9d333d5e5bfc64cfb84be8f04bf31ddc111a8d4b83b85d7e7e8a7b845bc185a9ad02c052d20e086983cf59f0be517d9b3d - languageName: node - linkType: hard - -"side-channel-map@npm:^1.0.1": - version: 1.0.1 - resolution: "side-channel-map@npm:1.0.1" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.5" - object-inspect: "npm:^1.13.3" - checksum: 10c0/010584e6444dd8a20b85bc926d934424bd809e1a3af941cace229f7fdcb751aada0fb7164f60c2e22292b7fa3c0ff0bce237081fd4cdbc80de1dc68e95430672 - languageName: node - linkType: hard - -"side-channel-weakmap@npm:^1.0.2": - version: 1.0.2 - resolution: "side-channel-weakmap@npm:1.0.2" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.5" - object-inspect: "npm:^1.13.3" - side-channel-map: "npm:^1.0.1" - checksum: 10c0/71362709ac233e08807ccd980101c3e2d7efe849edc51455030327b059f6c4d292c237f94dc0685031dd11c07dd17a68afde235d6cf2102d949567f98ab58185 - languageName: node - linkType: hard - -"side-channel@npm:^1.0.4": - version: 1.0.6 - resolution: "side-channel@npm:1.0.6" - dependencies: - call-bind: "npm:^1.0.7" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.4" - object-inspect: "npm:^1.13.1" - checksum: 10c0/d2afd163dc733cc0a39aa6f7e39bf0c436293510dbccbff446733daeaf295857dbccf94297092ec8c53e2503acac30f0b78830876f0485991d62a90e9cad305f - languageName: node - linkType: hard - -"side-channel@npm:^1.1.0": - version: 1.1.0 - resolution: "side-channel@npm:1.1.0" - dependencies: - es-errors: "npm:^1.3.0" - object-inspect: "npm:^1.13.3" - side-channel-list: "npm:^1.0.0" - side-channel-map: "npm:^1.0.1" - side-channel-weakmap: "npm:^1.0.2" - checksum: 10c0/cb20dad41eb032e6c24c0982e1e5a24963a28aa6122b4f05b3f3d6bf8ae7fd5474ef382c8f54a6a3ab86e0cac4d41a23bd64ede3970e5bfb50326ba02a7996e6 - languageName: node - linkType: hard - -"signal-exit@npm:^3.0.0": - version: 3.0.7 - resolution: "signal-exit@npm:3.0.7" - checksum: 10c0/25d272fa73e146048565e08f3309d5b942c1979a6f4a58a8c59d5fa299728e9c2fcd1a759ec870863b1fd38653670240cd420dad2ad9330c71f36608a6a1c912 - languageName: node - linkType: hard - -"signal-exit@npm:^4.0.1": - version: 4.1.0 - resolution: "signal-exit@npm:4.1.0" - checksum: 10c0/41602dce540e46d599edba9d9860193398d135f7ff72cab629db5171516cfae628d21e7bfccde1bbfdf11c48726bc2a6d1a8fb8701125852fbfda7cf19c6aa83 - languageName: node - linkType: hard - -"simple-swizzle@npm:^0.2.2": - version: 0.2.2 - resolution: "simple-swizzle@npm:0.2.2" - dependencies: - is-arrayish: "npm:^0.3.1" - checksum: 10c0/df5e4662a8c750bdba69af4e8263c5d96fe4cd0f9fe4bdfa3cbdeb45d2e869dff640beaaeb1ef0e99db4d8d2ec92f85508c269f50c972174851bc1ae5bd64308 - languageName: node - linkType: hard - -"smart-buffer@npm:^4.2.0": - version: 4.2.0 - resolution: "smart-buffer@npm:4.2.0" - checksum: 10c0/a16775323e1404dd43fabafe7460be13a471e021637bc7889468eb45ce6a6b207261f454e4e530a19500cc962c4cc5348583520843b363f4193cee5c00e1e539 - languageName: node - linkType: hard - -"socks-proxy-agent@npm:^8.0.3": - version: 8.0.4 - resolution: "socks-proxy-agent@npm:8.0.4" - dependencies: - agent-base: "npm:^7.1.1" - debug: "npm:^4.3.4" - socks: "npm:^2.8.3" - checksum: 10c0/345593bb21b95b0508e63e703c84da11549f0a2657d6b4e3ee3612c312cb3a907eac10e53b23ede3557c6601d63252103494caa306b66560f43af7b98f53957a - languageName: node - linkType: hard - -"socks@npm:^2.8.3": - version: 2.8.3 - resolution: "socks@npm:2.8.3" - dependencies: - ip-address: "npm:^9.0.5" - smart-buffer: "npm:^4.2.0" - checksum: 10c0/d54a52bf9325165770b674a67241143a3d8b4e4c8884560c4e0e078aace2a728dffc7f70150660f51b85797c4e1a3b82f9b7aa25e0a0ceae1a243365da5c51a7 - languageName: node - linkType: hard - -"sprintf-js@npm:^1.1.3": - version: 1.1.3 - resolution: "sprintf-js@npm:1.1.3" - checksum: 10c0/09270dc4f30d479e666aee820eacd9e464215cdff53848b443964202bf4051490538e5dd1b42e1a65cf7296916ca17640aebf63dae9812749c7542ee5f288dec - languageName: node - linkType: hard - -"ssri@npm:^10.0.0": - version: 10.0.6 - resolution: "ssri@npm:10.0.6" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10c0/e5a1e23a4057a86a97971465418f22ea89bd439ac36ade88812dd920e4e61873e8abd6a9b72a03a67ef50faa00a2daf1ab745c5a15b46d03e0544a0296354227 - languageName: node - linkType: hard - -"stack-trace@npm:0.0.x": - version: 0.0.10 - resolution: "stack-trace@npm:0.0.10" - checksum: 10c0/9ff3dabfad4049b635a85456f927a075c9d0c210e3ea336412d18220b2a86cbb9b13ec46d6c37b70a302a4ea4d49e30e5d4944dd60ae784073f1cde778ac8f4b - languageName: node - linkType: hard - -"statuses@npm:~2.0.2": - version: 2.0.2 - resolution: "statuses@npm:2.0.2" - checksum: 10c0/a9947d98ad60d01f6b26727570f3bcceb6c8fa789da64fe6889908fe2e294d57503b14bf2b5af7605c2d36647259e856635cd4c49eab41667658ec9d0080ec3f - languageName: node - linkType: hard - -"stop-iteration-iterator@npm:^1.0.0": - version: 1.0.0 - resolution: "stop-iteration-iterator@npm:1.0.0" - dependencies: - internal-slot: "npm:^1.0.4" - checksum: 10c0/c4158d6188aac510d9e92925b58709207bd94699e9c31186a040c80932a687f84a51356b5895e6dc72710aad83addb9411c22171832c9ae0e6e11b7d61b0dfb9 - languageName: node - linkType: hard - -"streamx@npm:^2.15.0": - version: 2.19.0 - resolution: "streamx@npm:2.19.0" - dependencies: - bare-events: "npm:^2.2.0" - fast-fifo: "npm:^1.3.2" - queue-tick: "npm:^1.0.1" - text-decoder: "npm:^1.1.0" - dependenciesMeta: - bare-events: - optional: true - checksum: 10c0/5833a2c1226488a015e8efde08c6cd4983d7d20098b2210d09594b23f598a8b028c083d542621e2e91ddcb33a266233c3524c60152203be40f1dd816b9ede9da - languageName: node - linkType: hard - -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.1.0, string-width@npm:^4.2.3": - version: 4.2.3 - resolution: "string-width@npm:4.2.3" - dependencies: - emoji-regex: "npm:^8.0.0" - is-fullwidth-code-point: "npm:^3.0.0" - strip-ansi: "npm:^6.0.1" - checksum: 10c0/1e525e92e5eae0afd7454086eed9c818ee84374bb80328fc41217ae72ff5f065ef1c9d7f72da41de40c75fa8bb3dee63d92373fd492c84260a552c636392a47b - languageName: node - linkType: hard - -"string-width@npm:^5.0.1, string-width@npm:^5.1.2": - version: 5.1.2 - resolution: "string-width@npm:5.1.2" - dependencies: - eastasianwidth: "npm:^0.2.0" - emoji-regex: "npm:^9.2.2" - strip-ansi: "npm:^7.0.1" - checksum: 10c0/ab9c4264443d35b8b923cbdd513a089a60de339216d3b0ed3be3ba57d6880e1a192b70ae17225f764d7adbf5994e9bb8df253a944736c15a0240eff553c678ca - languageName: node - linkType: hard - -"string_decoder@npm:^1.1.1, string_decoder@npm:^1.3.0": - version: 1.3.0 - resolution: "string_decoder@npm:1.3.0" - dependencies: - safe-buffer: "npm:~5.2.0" - checksum: 10c0/810614ddb030e271cd591935dcd5956b2410dd079d64ff92a1844d6b7588bf992b3e1b69b0f4d34a3e06e0bd73046ac646b5264c1987b20d0601f81ef35d731d - languageName: node - linkType: hard - -"string_decoder@npm:~1.1.1": - version: 1.1.1 - resolution: "string_decoder@npm:1.1.1" - dependencies: - safe-buffer: "npm:~5.1.0" - checksum: 10c0/b4f89f3a92fd101b5653ca3c99550e07bdf9e13b35037e9e2a1c7b47cec4e55e06ff3fc468e314a0b5e80bfbaf65c1ca5a84978764884ae9413bec1fc6ca924e - languageName: node - linkType: hard - -"strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": - version: 6.0.1 - resolution: "strip-ansi@npm:6.0.1" - dependencies: - ansi-regex: "npm:^5.0.1" - checksum: 10c0/1ae5f212a126fe5b167707f716942490e3933085a5ff6c008ab97ab2f272c8025d3aa218b7bd6ab25729ca20cc81cddb252102f8751e13482a5199e873680952 - languageName: node - linkType: hard - -"strip-ansi@npm:^7.0.1": - version: 7.1.0 - resolution: "strip-ansi@npm:7.1.0" - dependencies: - ansi-regex: "npm:^6.0.1" - checksum: 10c0/a198c3762e8832505328cbf9e8c8381de14a4fa50a4f9b2160138158ea88c0f5549fb50cb13c651c3088f47e63a108b34622ec18c0499b6c8c3a5ddf6b305ac4 - languageName: node - linkType: hard - -"tar-stream@npm:^3.0.0": - version: 3.1.7 - resolution: "tar-stream@npm:3.1.7" - dependencies: - b4a: "npm:^1.6.4" - fast-fifo: "npm:^1.2.0" - streamx: "npm:^2.15.0" - checksum: 10c0/a09199d21f8714bd729993ac49b6c8efcb808b544b89f23378ad6ffff6d1cb540878614ba9d4cfec11a64ef39e1a6f009a5398371491eb1fda606ffc7f70f718 - languageName: node - linkType: hard - -"tar@npm:^6.1.11, tar@npm:^6.2.1": - version: 6.2.1 - resolution: "tar@npm:6.2.1" - dependencies: - chownr: "npm:^2.0.0" - fs-minipass: "npm:^2.0.0" - minipass: "npm:^5.0.0" - minizlib: "npm:^2.1.1" - mkdirp: "npm:^1.0.3" - yallist: "npm:^4.0.0" - checksum: 10c0/a5eca3eb50bc11552d453488344e6507156b9193efd7635e98e867fab275d527af53d8866e2370cd09dfe74378a18111622ace35af6a608e5223a7d27fe99537 - languageName: node - linkType: hard - -"text-decoder@npm:^1.1.0": - version: 1.1.1 - resolution: "text-decoder@npm:1.1.1" - dependencies: - b4a: "npm:^1.6.4" - checksum: 10c0/e527d05454b59c0fa77456495de68c88e560a122de3dd28b3ebdbf81828aabeaa7e9bb8054b9eb52bc5029ccb5899ad04f466cbba3c53b2685270599d1710cee - languageName: node - linkType: hard - -"text-hex@npm:1.0.x": - version: 1.0.0 - resolution: "text-hex@npm:1.0.0" - checksum: 10c0/57d8d320d92c79d7c03ffb8339b825bb9637c2cbccf14304309f51d8950015c44464b6fd1b6820a3d4821241c68825634f09f5a2d9d501e84f7c6fd14376860d - languageName: node - linkType: hard - -"toidentifier@npm:~1.0.1": - version: 1.0.1 - resolution: "toidentifier@npm:1.0.1" - checksum: 10c0/93937279934bd66cc3270016dd8d0afec14fb7c94a05c72dc57321f8bd1fa97e5bea6d1f7c89e728d077ca31ea125b78320a616a6c6cd0e6b9cb94cb864381c1 - languageName: node - linkType: hard - -"tr46@npm:~0.0.3": - version: 0.0.3 - resolution: "tr46@npm:0.0.3" - checksum: 10c0/047cb209a6b60c742f05c9d3ace8fa510bff609995c129a37ace03476a9b12db4dbf975e74600830ef0796e18882b2381fb5fb1f6b4f96b832c374de3ab91a11 - languageName: node - linkType: hard - -"triple-beam@npm:^1.3.0": - version: 1.4.1 - resolution: "triple-beam@npm:1.4.1" - checksum: 10c0/4bf1db71e14fe3ff1c3adbe3c302f1fdb553b74d7591a37323a7badb32dc8e9c290738996cbb64f8b10dc5a3833645b5d8c26221aaaaa12e50d1251c9aba2fea - languageName: node - linkType: hard - -"tslib@npm:^2.4.0": - version: 2.7.0 - resolution: "tslib@npm:2.7.0" - checksum: 10c0/469e1d5bf1af585742128827000711efa61010b699cb040ab1800bcd3ccdd37f63ec30642c9e07c4439c1db6e46345582614275daca3e0f4abae29b0083f04a6 - languageName: node - linkType: hard - -"type-is@npm:~1.6.18": - version: 1.6.18 - resolution: "type-is@npm:1.6.18" - dependencies: - media-typer: "npm:0.3.0" - mime-types: "npm:~2.1.24" - checksum: 10c0/a23daeb538591b7efbd61ecf06b6feb2501b683ffdc9a19c74ef5baba362b4347e42f1b4ed81f5882a8c96a3bfff7f93ce3ffaf0cbbc879b532b04c97a55db9d - languageName: node - linkType: hard - -"undici-types@npm:~6.19.2": - version: 6.19.8 - resolution: "undici-types@npm:6.19.8" - checksum: 10c0/078afa5990fba110f6824823ace86073b4638f1d5112ee26e790155f481f2a868cc3e0615505b6f4282bdf74a3d8caad715fd809e870c2bb0704e3ea6082f344 - languageName: node - linkType: hard - -"unique-filename@npm:^3.0.0": - version: 3.0.0 - resolution: "unique-filename@npm:3.0.0" - dependencies: - unique-slug: "npm:^4.0.0" - checksum: 10c0/6363e40b2fa758eb5ec5e21b3c7fb83e5da8dcfbd866cc0c199d5534c42f03b9ea9ab069769cc388e1d7ab93b4eeef28ef506ab5f18d910ef29617715101884f - languageName: node - linkType: hard - -"unique-slug@npm:^4.0.0": - version: 4.0.0 - resolution: "unique-slug@npm:4.0.0" - dependencies: - imurmurhash: "npm:^0.1.4" - checksum: 10c0/cb811d9d54eb5821b81b18205750be84cb015c20a4a44280794e915f5a0a70223ce39066781a354e872df3572e8155c228f43ff0cce94c7cbf4da2cc7cbdd635 - languageName: node - linkType: hard - -"unpipe@npm:~1.0.0": - version: 1.0.0 - resolution: "unpipe@npm:1.0.0" - checksum: 10c0/193400255bd48968e5c5383730344fbb4fa114cdedfab26e329e50dd2d81b134244bb8a72c6ac1b10ab0281a58b363d06405632c9d49ca9dfd5e90cbd7d0f32c - languageName: node - linkType: hard - -"util-deprecate@npm:^1.0.1, util-deprecate@npm:~1.0.1": - version: 1.0.2 - resolution: "util-deprecate@npm:1.0.2" - checksum: 10c0/41a5bdd214df2f6c3ecf8622745e4a366c4adced864bc3c833739791aeeeb1838119af7daed4ba36428114b5c67dcda034a79c882e97e43c03e66a4dd7389942 - languageName: node - linkType: hard - -"uuid@npm:^10.0.0": - version: 10.0.0 - resolution: "uuid@npm:10.0.0" - bin: - uuid: dist/bin/uuid - checksum: 10c0/eab18c27fe4ab9fb9709a5d5f40119b45f2ec8314f8d4cf12ce27e4c6f4ffa4a6321dc7db6c515068fa373c075b49691ba969f0010bf37f44c37ca40cd6bf7fe - languageName: node - linkType: hard - -"webidl-conversions@npm:^3.0.0": - version: 3.0.1 - resolution: "webidl-conversions@npm:3.0.1" - checksum: 10c0/5612d5f3e54760a797052eb4927f0ddc01383550f542ccd33d5238cfd65aeed392a45ad38364970d0a0f4fea32e1f4d231b3d8dac4a3bdd385e5cf802ae097db - languageName: node - linkType: hard - -"whatwg-url@npm:^5.0.0": - version: 5.0.0 - resolution: "whatwg-url@npm:5.0.0" - dependencies: - tr46: "npm:~0.0.3" - webidl-conversions: "npm:^3.0.0" - checksum: 10c0/1588bed84d10b72d5eec1d0faa0722ba1962f1821e7539c535558fb5398d223b0c50d8acab950b8c488b4ba69043fd833cc2697056b167d8ad46fac3995a55d5 - languageName: node - linkType: hard - -"which-boxed-primitive@npm:^1.0.2": - version: 1.0.2 - resolution: "which-boxed-primitive@npm:1.0.2" - dependencies: - is-bigint: "npm:^1.0.1" - is-boolean-object: "npm:^1.1.0" - is-number-object: "npm:^1.0.4" - is-string: "npm:^1.0.5" - is-symbol: "npm:^1.0.3" - checksum: 10c0/0a62a03c00c91dd4fb1035b2f0733c341d805753b027eebd3a304b9cb70e8ce33e25317add2fe9b5fea6f53a175c0633ae701ff812e604410ddd049777cd435e - languageName: node - linkType: hard - -"which-collection@npm:^1.0.1": - version: 1.0.2 - resolution: "which-collection@npm:1.0.2" - dependencies: - is-map: "npm:^2.0.3" - is-set: "npm:^2.0.3" - is-weakmap: "npm:^2.0.2" - is-weakset: "npm:^2.0.3" - checksum: 10c0/3345fde20964525a04cdf7c4a96821f85f0cc198f1b2ecb4576e08096746d129eb133571998fe121c77782ac8f21cbd67745a3d35ce100d26d4e684c142ea1f2 - languageName: node - linkType: hard - -"which-typed-array@npm:^1.1.13": - version: 1.1.15 - resolution: "which-typed-array@npm:1.1.15" - dependencies: - available-typed-arrays: "npm:^1.0.7" - call-bind: "npm:^1.0.7" - for-each: "npm:^0.3.3" - gopd: "npm:^1.0.1" - has-tostringtag: "npm:^1.0.2" - checksum: 10c0/4465d5348c044032032251be54d8988270e69c6b7154f8fcb2a47ff706fe36f7624b3a24246b8d9089435a8f4ec48c1c1025c5d6b499456b9e5eff4f48212983 - languageName: node - linkType: hard - -"which@npm:^2.0.1": - version: 2.0.2 - resolution: "which@npm:2.0.2" - dependencies: - isexe: "npm:^2.0.0" - bin: - node-which: ./bin/node-which - checksum: 10c0/66522872a768b60c2a65a57e8ad184e5372f5b6a9ca6d5f033d4b0dc98aff63995655a7503b9c0a2598936f532120e81dd8cc155e2e92ed662a2b9377cc4374f - languageName: node - linkType: hard - -"which@npm:^4.0.0": - version: 4.0.0 - resolution: "which@npm:4.0.0" - dependencies: - isexe: "npm:^3.1.1" - bin: - node-which: bin/which.js - checksum: 10c0/449fa5c44ed120ccecfe18c433296a4978a7583bf2391c50abce13f76878d2476defde04d0f79db8165bdf432853c1f8389d0485ca6e8ebce3bbcded513d5e6a - languageName: node - linkType: hard - -"wide-align@npm:^1.1.2": - version: 1.1.5 - resolution: "wide-align@npm:1.1.5" - dependencies: - string-width: "npm:^1.0.2 || 2 || 3 || 4" - checksum: 10c0/1d9c2a3e36dfb09832f38e2e699c367ef190f96b82c71f809bc0822c306f5379df87bab47bed27ea99106d86447e50eb972d3c516c2f95782807a9d082fbea95 - languageName: node - linkType: hard - -"winston-transport@npm:^4.7.0": - version: 4.7.1 - resolution: "winston-transport@npm:4.7.1" - dependencies: - logform: "npm:^2.6.1" - readable-stream: "npm:^3.6.2" - triple-beam: "npm:^1.3.0" - checksum: 10c0/99b7b55cc2ef7f38988ab1717e7fd946c81b856b42a9530aef8ee725490ef2f2811f9cb06d63aa2f76a85fe99ae15b3bef10a54afde3be8b5059ce325e78481f - languageName: node - linkType: hard - -"winston@npm:^3.14.2": - version: 3.14.2 - resolution: "winston@npm:3.14.2" - dependencies: - "@colors/colors": "npm:^1.6.0" - "@dabh/diagnostics": "npm:^2.0.2" - async: "npm:^3.2.3" - is-stream: "npm:^2.0.0" - logform: "npm:^2.6.0" - one-time: "npm:^1.0.0" - readable-stream: "npm:^3.4.0" - safe-stable-stringify: "npm:^2.3.1" - stack-trace: "npm:0.0.x" - triple-beam: "npm:^1.3.0" - winston-transport: "npm:^4.7.0" - checksum: 10c0/3f8fe505ea18310982e60452f335dd2b22fdbc9b25839b6ad882971b2416d5adc94a1f1a46e24cb37d967ad01dfe5499adaf5e53575626b5ebb2a25ff30f4e1d - languageName: node - linkType: hard - -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version: 7.0.0 - resolution: "wrap-ansi@npm:7.0.0" - dependencies: - ansi-styles: "npm:^4.0.0" - string-width: "npm:^4.1.0" - strip-ansi: "npm:^6.0.0" - checksum: 10c0/d15fc12c11e4cbc4044a552129ebc75ee3f57aa9c1958373a4db0292d72282f54373b536103987a4a7594db1ef6a4f10acf92978f79b98c49306a4b58c77d4da - languageName: node - linkType: hard - -"wrap-ansi@npm:^8.1.0": - version: 8.1.0 - resolution: "wrap-ansi@npm:8.1.0" - dependencies: - ansi-styles: "npm:^6.1.0" - string-width: "npm:^5.0.1" - strip-ansi: "npm:^7.0.1" - checksum: 10c0/138ff58a41d2f877eae87e3282c0630fc2789012fc1af4d6bd626eeb9a2f9a65ca92005e6e69a75c7b85a68479fe7443c7dbe1eb8fbaa681a4491364b7c55c60 - languageName: node - linkType: hard - -"wrappy@npm:1": - version: 1.0.2 - resolution: "wrappy@npm:1.0.2" - checksum: 10c0/56fece1a4018c6a6c8e28fbc88c87e0fbf4ea8fd64fc6c63b18f4acc4bd13e0ad2515189786dd2c30d3eec9663d70f4ecf699330002f8ccb547e4a18231fc9f0 - languageName: node - linkType: hard - -"yallist@npm:^4.0.0": - version: 4.0.0 - resolution: "yallist@npm:4.0.0" - checksum: 10c0/2286b5e8dbfe22204ab66e2ef5cc9bbb1e55dfc873bbe0d568aa943eb255d131890dfd5bf243637273d31119b870f49c18fcde2c6ffbb7a7a092b870dc90625a - languageName: node - linkType: hard - -"zip-stream@npm:^6.0.1": - version: 6.0.1 - resolution: "zip-stream@npm:6.0.1" - dependencies: - archiver-utils: "npm:^5.0.0" - compress-commons: "npm:^6.0.2" - readable-stream: "npm:^4.0.0" - checksum: 10c0/50f2fb30327fb9d09879abf7ae2493705313adf403e794b030151aaae00009162419d60d0519e807673ec04d442e140c8879ca14314df0a0192de3b233e8f28b - languageName: node - linkType: hard diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/layers/last-layer-version.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/layers/last-layer-version.ts deleted file mode 100644 index 4dd6fef1a02..00000000000 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/layers/last-layer-version.ts +++ /dev/null @@ -1 +0,0 @@ -export const LAST_LAYER_VERSION = 1; diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/logic-function-drivers.module.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/logic-function-drivers.module.ts index b2dc7024261..350c49cb0b5 100644 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/logic-function-drivers.module.ts +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/logic-function-drivers.module.ts @@ -1,32 +1,30 @@ import { type DynamicModule, Module } from '@nestjs/common'; import { - LogicFunctionExecutorDriverType, - type LogicFunctionExecutorModuleAsyncOptions, -} from 'src/engine/core-modules/logic-function/logic-function-executor/interfaces/logic-function-executor.interface'; + LogicFunctionDriverType, + LogicFunctionModuleAsyncOptions, +} from 'src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-driver.interface'; import { DisabledDriver } from 'src/engine/core-modules/logic-function/logic-function-drivers/drivers/disabled.driver'; import { LambdaDriver } from 'src/engine/core-modules/logic-function/logic-function-drivers/drivers/lambda.driver'; import { LocalDriver } from 'src/engine/core-modules/logic-function/logic-function-drivers/drivers/local.driver'; -import { LOGIC_FUNCTION_EXECUTOR_DRIVER } from 'src/engine/core-modules/logic-function/logic-function-executor/constants/logic-function-executor.constants'; +import { LOGIC_FUNCTION_DRIVER } from 'src/engine/core-modules/logic-function/logic-function-drivers/constants/logic-function-driver.constants'; @Module({}) export class LogicFunctionDriversModule { - static forRootAsync( - options: LogicFunctionExecutorModuleAsyncOptions, - ): DynamicModule { + static forRootAsync(options: LogicFunctionModuleAsyncOptions): DynamicModule { const provider = { - provide: LOGIC_FUNCTION_EXECUTOR_DRIVER, + provide: LOGIC_FUNCTION_DRIVER, // eslint-disable-next-line @typescript-eslint/no-explicit-any useFactory: async (...args: any[]) => { const config = await options.useFactory(...args); switch (config?.type) { - case LogicFunctionExecutorDriverType.DISABLED: + case LogicFunctionDriverType.DISABLED: return new DisabledDriver(); - case LogicFunctionExecutorDriverType.LOCAL: + case LogicFunctionDriverType.LOCAL: return new LocalDriver(config.options); - case LogicFunctionExecutorDriverType.LAMBDA: + case LogicFunctionDriverType.LAMBDA: return new LambdaDriver(config.options); default: { const unknownConfig = config as { type?: string }; @@ -44,7 +42,7 @@ export class LogicFunctionDriversModule { module: LogicFunctionDriversModule, imports: options.imports || [], providers: [provider], - exports: [LOGIC_FUNCTION_EXECUTOR_DRIVER], + exports: [LOGIC_FUNCTION_DRIVER], }; } } diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/utils/get-last-common-layer-dependencies.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/utils/get-last-common-layer-dependencies.ts deleted file mode 100644 index b65a548cb4d..00000000000 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/utils/get-last-common-layer-dependencies.ts +++ /dev/null @@ -1,22 +0,0 @@ -import fs from 'fs/promises'; -import { join } from 'path'; - -import { getLayerDependenciesDirName } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/get-layer-dependencies-dir-name'; -import { LAST_LAYER_VERSION } from 'src/engine/core-modules/logic-function/logic-function-drivers/layers/last-layer-version'; - -export type LayerDependencies = { - packageJson: string; - yarnLock: string; -}; - -export const getLastCommonLayerDependencies = async ( - layerVersion = LAST_LAYER_VERSION, -): Promise => { - const lastVersionLayerDirName = getLayerDependenciesDirName(layerVersion); - const [packageJson, yarnLock] = await Promise.all([ - fs.readFile(join(lastVersionLayerDirName, 'package.json'), 'utf8'), - fs.readFile(join(lastVersionLayerDirName, 'yarn.lock'), 'utf8'), - ]); - - return { packageJson, yarnLock }; -}; diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/utils/get-layer-dependencies-dir-name.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/utils/get-layer-dependencies-dir-name.ts deleted file mode 100644 index 82eb0c0b0cb..00000000000 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/utils/get-layer-dependencies-dir-name.ts +++ /dev/null @@ -1,14 +0,0 @@ -import path from 'path'; - -import { ASSET_PATH } from 'src/constants/assets-path'; - -export const getLayerDependenciesDirName = ( - version: 'engine' | number, -): string => { - const baseTypescriptProjectPath = path.join( - ASSET_PATH, - `engine/core-modules/logic-function/logic-function-drivers/layers/${version}`, - ); - - return path.resolve(__dirname, baseTypescriptProjectPath); -}; diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/utils/lambda-build-directory-manager.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/utils/temporary-dir-manager.ts similarity index 90% rename from packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/utils/lambda-build-directory-manager.ts rename to packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/utils/temporary-dir-manager.ts index 9f0a60189f2..47eca6dd52e 100644 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/utils/lambda-build-directory-manager.ts +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/utils/temporary-dir-manager.ts @@ -5,12 +5,10 @@ import { v4 } from 'uuid'; import { LOGIC_FUNCTION_EXECUTOR_TMPDIR_FOLDER } from 'src/engine/core-modules/logic-function/logic-function-drivers/constants/logic-function-executor-tmpdir-folder'; -export const NODE_LAYER_SUBFOLDER = 'nodejs'; - const TEMPORARY_LAMBDA_FOLDER = 'lambda-build'; const LAMBDA_ZIP_FILE_NAME = 'lambda.zip'; -export class LambdaBuildDirectoryManager { +export class TemporaryDirManager { private temporaryDir = join( LOGIC_FUNCTION_EXECUTOR_TMPDIR_FOLDER, `${TEMPORARY_LAMBDA_FOLDER}-${v4()}`, diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/commands/add-packages.command.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/commands/add-packages.command.ts deleted file mode 100644 index a6cd9d1227b..00000000000 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/commands/add-packages.command.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { Logger } from '@nestjs/common'; - -import { execFile } from 'child_process'; -import * as fs from 'fs/promises'; -import { resolve } from 'path'; -import { promisify } from 'util'; - -import { Command, CommandRunner, Option } from 'nest-commander'; - -const execFilePromise = promisify(execFile); - -@Command({ - name: 'logic-function-executor:add-packages', - description: - 'Create a new logic function executor layer version and install packages in it', -}) -export class AddPackagesCommand extends CommandRunner { - private readonly logger = new Logger(AddPackagesCommand.name); - - @Option({ - flags: '-p, --packages ', - description: 'comma separated packages (eg: axios,uuid@9.0.1)', - required: true, - }) - parsePackages(val: string): string[] { - return val.split(','); - } - - async run( - _passedParams: string[], - // eslint-disable-next-line @typescript-eslint/no-explicit-any - options: Record, - ): Promise { - this.logger.log('---------------------------------------'); - this.logger.warn('This command should be run locally only'); - this.logger.log(''); - - const layersFolder = this.getAbsoluteFilePath( - `src/engine/core-modules/logic-function/logic-function-drivers/layers`, - ); - - const currentVersion = await this.getLastLayerVersion(); - const newVersion = currentVersion + 1; - - const currentVersionFolder = `${layersFolder}/${currentVersion}`; - const newVersionFolder = `${layersFolder}/${newVersion}`; - - await fs.cp(currentVersionFolder, newVersionFolder, { recursive: true }); - - // Install each package - this.logger.log('Installing packages'); - await this.installPackages(options.packages, newVersionFolder); - - this.logger.log('Cleaning'); - await this.cleanPackageInstallation(newVersionFolder); - - this.logger.log('Updating last layer version'); - await this.updateLastLayerVersion(newVersion); - - this.logger.log('Add changes to git'); - await this.addToGit(layersFolder); - - this.logger.log(''); - this.logger.log( - `New packages '${options.packages.join("', '")}' installed in new layer version '${newVersion}' `, - ); - this.logger.log('Please commit your changes'); - this.logger.log('---------------------------------------'); - } - - private getAbsoluteFilePath(path: string) { - const rootPath = process.cwd(); - - return resolve(rootPath, path); - } - - private async addToGit(folderPath: string) { - await execFilePromise('git', ['add', folderPath]); - } - - private async cleanPackageInstallation(folderPath: string) { - await fs.rm(folderPath + '/node_modules', { - recursive: true, - force: true, - }); - await fs.rm(folderPath + '/.yarn', { - recursive: true, - force: true, - }); - } - - private async installPackages(packages: string[], folderPath: string) { - if (packages?.length) { - for (const packageName of packages) { - this.logger.log(`- adding '${packageName}'...`); - try { - await execFilePromise('yarn', ['add', packageName], { - cwd: folderPath, - }); - } catch (error) { - this.logger.error( - `Failed to install ${packageName}: ${(error as Error).message}`, - ); - } - } - } - } - - private async getLastLayerVersion() { - const filePath = this.getAbsoluteFilePath( - 'src/engine/core-modules/logic-function/logic-function-drivers/layers/last-layer-version.ts', - ); - - const content = await fs.readFile(filePath, 'utf8'); - const match = content.match(/export const LAST_LAYER_VERSION = (\d+);/); - - if (!match) { - throw new Error('LAST_LAYER_VERSION not found'); - } - - return parseInt(match[1], 10); - } - - private async updateLastLayerVersion(newVersion: number) { - const filePath = this.getAbsoluteFilePath( - 'src/engine/core-modules/logic-function/logic-function-drivers/layers/last-layer-version.ts', - ); - - await fs.writeFile( - filePath, - `export const LAST_LAYER_VERSION = ${newVersion};\n`, - 'utf8', - ); - } -} diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/constants/logic-function-executor.constants.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/constants/logic-function-executor.constants.ts deleted file mode 100644 index 74c69ad18f1..00000000000 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/constants/logic-function-executor.constants.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const LOGIC_FUNCTION_EXECUTOR_DRIVER = Symbol( - 'LOGIC_FUNCTION_EXECUTOR_DRIVER', -); diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/interfaces/logic-function-executor.interface.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/interfaces/logic-function-executor.interface.ts deleted file mode 100644 index ecdf3541b04..00000000000 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/interfaces/logic-function-executor.interface.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { type FactoryProvider, type ModuleMetadata } from '@nestjs/common'; - -import { type LambdaDriverOptions } from 'src/engine/core-modules/logic-function/logic-function-drivers/drivers/lambda.driver'; -import { type LocalDriverOptions } from 'src/engine/core-modules/logic-function/logic-function-drivers/drivers/local.driver'; - -export enum LogicFunctionExecutorDriverType { - DISABLED = 'DISABLED', - LAMBDA = 'LAMBDA', - LOCAL = 'LOCAL', -} - -export interface DisabledDriverFactoryOptions { - type: LogicFunctionExecutorDriverType.DISABLED; -} - -export interface LocalDriverFactoryOptions { - type: LogicFunctionExecutorDriverType.LOCAL; - options: LocalDriverOptions; -} - -export interface LambdaDriverFactoryOptions { - type: LogicFunctionExecutorDriverType.LAMBDA; - options: LambdaDriverOptions; -} - -export type LogicFunctionExecutorModuleOptions = - | DisabledDriverFactoryOptions - | LocalDriverFactoryOptions - | LambdaDriverFactoryOptions; - -export type LogicFunctionExecutorModuleAsyncOptions = { - useFactory: ( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - ...args: any[] - ) => - | LogicFunctionExecutorModuleOptions - | Promise; -} & Pick & - Pick; diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.module.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.module.ts index 9aa4dc910e4..130387357e3 100644 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.module.ts +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.module.ts @@ -1,14 +1,10 @@ import { Module } from '@nestjs/common'; -import { TypeOrmModule } from '@nestjs/typeorm'; +import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.service'; +import { ThrottlerModule } from 'src/engine/core-modules/throttler/throttler.module'; import { AuditModule } from 'src/engine/core-modules/audit/audit.module'; import { TokenModule } from 'src/engine/core-modules/auth/token/token.module'; -import { FileModule } from 'src/engine/core-modules/file/file.module'; -import { AddPackagesCommand } from 'src/engine/core-modules/logic-function/logic-function-executor/commands/add-packages.command'; -import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/services/logic-function-executor.service'; import { SecretEncryptionModule } from 'src/engine/core-modules/secret-encryption/secret-encryption.module'; -import { ThrottlerModule } from 'src/engine/core-modules/throttler/throttler.module'; -import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity'; import { SubscriptionsModule } from 'src/engine/subscriptions/subscriptions.module'; import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module'; @@ -20,10 +16,8 @@ import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache SecretEncryptionModule, SubscriptionsModule, WorkspaceCacheModule, - FileModule, - TypeOrmModule.forFeature([LogicFunctionEntity]), ], - providers: [LogicFunctionExecutorService, AddPackagesCommand], + providers: [LogicFunctionExecutorService], exports: [LogicFunctionExecutorService], }) export class LogicFunctionExecutorModule {} diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/services/logic-function-executor.service.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.service.ts similarity index 54% rename from packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/services/logic-function-executor.service.ts rename to packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.service.ts index 073322c823f..cdb0c2283f5 100644 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/services/logic-function-executor.service.ts +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.service.ts @@ -1,37 +1,32 @@ import { Inject, Injectable } from '@nestjs/common'; -import { InjectRepository } from '@nestjs/typeorm'; import { DEFAULT_API_KEY_NAME, DEFAULT_API_URL_NAME, } from 'twenty-shared/application'; -import { FileFolder } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; -import { Repository } from 'typeorm'; import { - LogicFunctionExecutorDriver, - type LogicFunctionExecuteParams, + LogicFunctionDriver, type LogicFunctionExecuteResult, -} from 'src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-executor-driver.interface'; +} from 'src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-driver.interface'; -import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; import { AuditService } from 'src/engine/core-modules/audit/services/audit.service'; import { LOGIC_FUNCTION_EXECUTED_EVENT } from 'src/engine/core-modules/audit/utils/events/workspace-event/logic-function/logic-function-executed'; import { ApplicationTokenService } from 'src/engine/core-modules/auth/token/services/application-token.service'; -import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service'; -import { buildEnvVar } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/build-env-var'; -import { LOGIC_FUNCTION_EXECUTOR_DRIVER } from 'src/engine/core-modules/logic-function/logic-function-executor/constants/logic-function-executor.constants'; +import { buildEnvVar } from 'src/engine/core-modules/logic-function/logic-function-executor/utils/build-env-var'; +import { LOGIC_FUNCTION_DRIVER } from 'src/engine/core-modules/logic-function/logic-function-drivers/constants/logic-function-driver.constants'; import { SecretEncryptionService } from 'src/engine/core-modules/secret-encryption/secret-encryption.service'; import { ThrottlerService } from 'src/engine/core-modules/throttler/throttler.service'; import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service'; import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util'; -import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity'; -import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type'; import { SubscriptionChannel } from 'src/engine/subscriptions/enums/subscription-channel.enum'; import { SubscriptionService } from 'src/engine/subscriptions/subscription.service'; import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; import { cleanServerUrl } from 'src/utils/clean-server-url'; +import type { FlatApplicationVariable } from 'src/engine/core-modules/applicationVariable/types/flat-application-variable.type'; +import { FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type'; +import { FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; const MIN_TOKEN_EXPIRATION_IN_SECONDS = 5; @@ -51,12 +46,10 @@ export enum LogicFunctionExecutionExceptionCode { } @Injectable() -export class LogicFunctionExecutorService - implements LogicFunctionExecutorDriver -{ +export class LogicFunctionExecutorService { constructor( - @Inject(LOGIC_FUNCTION_EXECUTOR_DRIVER) - private driver: LogicFunctionExecutorDriver, + @Inject(LOGIC_FUNCTION_DRIVER) + private driver: LogicFunctionDriver, private readonly throttlerService: ThrottlerService, private readonly twentyConfigService: TwentyConfigService, private readonly workspaceCacheService: WorkspaceCacheService, @@ -64,185 +57,54 @@ export class LogicFunctionExecutorService private readonly secretEncryptionService: SecretEncryptionService, private readonly subscriptionService: SubscriptionService, private readonly auditService: AuditService, - private readonly fileStorageService: FileStorageService, - @InjectRepository(LogicFunctionEntity) - private readonly logicFunctionRepository: Repository, ) {} - async delete(flatLogicFunction: FlatLogicFunction): Promise { - return this.driver.delete(flatLogicFunction); - } - - async execute( - params: LogicFunctionExecuteParams, - ): Promise { - return this.driver.execute(params); - } - - async executeOneLogicFunction({ - id, + async execute({ + logicFunctionId, workspaceId, payload, }: { - id: string; + logicFunctionId: string; workspaceId: string; payload: object; }): Promise { await this.throttleExecution(workspaceId); - const { - flatLogicFunctionMaps, - flatApplicationMaps, - applicationVariableMaps, - } = await this.workspaceCacheService.getOrRecompute(workspaceId, [ - 'flatLogicFunctionMaps', - 'flatApplicationMaps', - 'applicationVariableMaps', - ]); + const { flatApplication, flatLogicFunction, flatApplicationVariables } = + await this.getFlatEntitiesOrThrow({ + workspaceId, + logicFunctionId, + }); - const flatLogicFunction = findFlatEntityByIdInFlatEntityMaps({ - flatEntityId: id, - flatEntityMaps: flatLogicFunctionMaps, + const envVariables = await this.getExecutionEnvVariables({ + workspaceId, + flatApplication, + flatApplicationVariables, + flatLogicFunction, }); - if ( - !isDefined(flatLogicFunction) || - isDefined(flatLogicFunction.deletedAt) - ) { - throw new LogicFunctionExecutionException( - `Logic function with id ${id} not found`, - LogicFunctionExecutionExceptionCode.LOGIC_FUNCTION_NOT_FOUND, - ); - } - - const flatApplication = isDefined(flatLogicFunction.applicationId) - ? flatApplicationMaps.byId[flatLogicFunction.applicationId] - : undefined; - - if (!isDefined(flatApplication)) { - throw new LogicFunctionExecutionException( - `Application not found for logic function ${id}`, - LogicFunctionExecutionExceptionCode.LOGIC_FUNCTION_NOT_FOUND, - ); - } - - const applicationAccessToken = isDefined(flatLogicFunction.applicationId) - ? await this.applicationTokenService.generateApplicationToken({ - workspaceId, - applicationId: flatLogicFunction.applicationId, - expiresInSeconds: Math.max( - flatLogicFunction.timeoutSeconds, - MIN_TOKEN_EXPIRATION_IN_SECONDS, - ), - }) - : undefined; - - const baseUrl = cleanServerUrl(this.twentyConfigService.get('SERVER_URL')); - - const flatApplicationVariables = isDefined(flatLogicFunction.applicationId) - ? (applicationVariableMaps.byApplicationId[ - flatLogicFunction.applicationId - ] ?? []) - : []; - - const envVariables = { - ...(isDefined(baseUrl) - ? { - [DEFAULT_API_URL_NAME]: baseUrl, - } - : {}), - ...(isDefined(applicationAccessToken) - ? { - [DEFAULT_API_KEY_NAME]: applicationAccessToken.token, - } - : {}), - ...buildEnvVar(flatApplicationVariables, this.secretEncryptionService), - }; - - const applicationUniversalIdentifier = isDefined( - flatLogicFunction.applicationId, - ) - ? flatApplicationMaps.byId[flatLogicFunction.applicationId] - ?.universalIdentifier - : undefined; - - if (!isDefined(applicationUniversalIdentifier)) { - throw new LogicFunctionExecutionException( - `Application universal identifier not found for logic function ${flatLogicFunction.id}`, - LogicFunctionExecutionExceptionCode.LOGIC_FUNCTION_NOT_FOUND, - ); - } - - if ( - !(await this.hasLayerDependencies({ - flatApplication, - applicationUniversalIdentifier, - })) - ) { - throw new LogicFunctionExecutionException( - 'Logic function dependencies not found', - LogicFunctionExecutionExceptionCode.LOGIC_FUNCTION_NOT_FOUND, - ); - } - const resultLogicFunction = await this.callWithTimeout({ callback: () => - this.execute({ + this.driver.execute({ flatLogicFunction, flatApplication, - applicationUniversalIdentifier, + applicationUniversalIdentifier: flatApplication.universalIdentifier, payload, env: envVariables, }), timeoutMs: flatLogicFunction.timeoutSeconds * 1000, }); - if (this.twentyConfigService.get('LOGIC_FUNCTION_LOGS_ENABLED')) { - /* eslint-disable no-console */ - console.log(resultLogicFunction.logs); - } - - await this.subscriptionService.publish({ - channel: SubscriptionChannel.LOGIC_FUNCTION_LOGS_CHANNEL, + await this.handleExecutionResult({ + result: resultLogicFunction, + flatApplication, + flatLogicFunction, workspaceId, - payload: { - logicFunctionLogs: { - logs: resultLogicFunction.logs, - id: flatLogicFunction.id, - name: flatLogicFunction.name, - universalIdentifier: flatLogicFunction.universalIdentifier, - applicationId: flatLogicFunction.applicationId, - applicationUniversalIdentifier, - }, - }, }); - this.auditService - .createContext({ - workspaceId, - }) - .insertWorkspaceEvent(LOGIC_FUNCTION_EXECUTED_EVENT, { - duration: resultLogicFunction.duration, - status: resultLogicFunction.status, - ...(resultLogicFunction.error && { - errorType: resultLogicFunction.error.errorType, - }), - functionId: flatLogicFunction.id, - functionName: flatLogicFunction.name, - }); - return resultLogicFunction; } - async getAvailablePackages(logicFunctionId: string) { - const logicFunction = await this.logicFunctionRepository.findOneOrFail({ - where: { id: logicFunctionId }, - relations: ['application'], - }); - - return logicFunction.application.availablePackages ?? {}; - } - private async throttleExecution(workspaceId: string) { try { await this.throttlerService.tokenBucketThrottleOrThrow( @@ -274,26 +136,128 @@ export class LogicFunctionExecutorService ]); } - private async hasLayerDependencies({ - flatApplication, - applicationUniversalIdentifier, + private async getFlatEntitiesOrThrow({ + workspaceId, + logicFunctionId, }: { - flatApplication: FlatApplication; - applicationUniversalIdentifier: string; - }): Promise { - const packageJsonExists = await this.fileStorageService.checkFileExists({ - workspaceId: flatApplication.workspaceId, - applicationUniversalIdentifier, - fileFolder: FileFolder.Dependencies, - resourcePath: 'package.json', - }); - const yarnLockExists = await this.fileStorageService.checkFileExists({ - workspaceId: flatApplication.workspaceId, - applicationUniversalIdentifier, - fileFolder: FileFolder.Dependencies, - resourcePath: 'yarn.lock', + workspaceId: string; + logicFunctionId: string; + }) { + const { + flatLogicFunctionMaps, + flatApplicationMaps, + applicationVariableMaps, + } = await this.workspaceCacheService.getOrRecompute(workspaceId, [ + 'flatLogicFunctionMaps', + 'flatApplicationMaps', + 'applicationVariableMaps', + ]); + + const flatLogicFunction = findFlatEntityByIdInFlatEntityMaps({ + flatEntityId: logicFunctionId, + flatEntityMaps: flatLogicFunctionMaps, }); - return packageJsonExists && yarnLockExists; + if ( + !isDefined(flatLogicFunction) || + isDefined(flatLogicFunction.deletedAt) + ) { + throw new LogicFunctionExecutionException( + `Logic function with id ${logicFunctionId} not found`, + LogicFunctionExecutionExceptionCode.LOGIC_FUNCTION_NOT_FOUND, + ); + } + + const flatApplication = isDefined(flatLogicFunction.applicationId) + ? flatApplicationMaps.byId[flatLogicFunction.applicationId] + : undefined; + + if (!isDefined(flatApplication)) { + throw new LogicFunctionExecutionException( + `Application not found for logic function ${logicFunctionId}`, + LogicFunctionExecutionExceptionCode.LOGIC_FUNCTION_NOT_FOUND, + ); + } + + const flatApplicationVariables = + applicationVariableMaps.byApplicationId[flatApplication.id] ?? []; + + return { flatApplication, flatLogicFunction, flatApplicationVariables }; + } + + private async getExecutionEnvVariables({ + workspaceId, + flatApplication, + flatLogicFunction, + flatApplicationVariables, + }: { + workspaceId: string; + flatApplication: FlatApplication; + flatLogicFunction: FlatLogicFunction; + flatApplicationVariables: FlatApplicationVariable[]; + }) { + const applicationAccessToken = + await this.applicationTokenService.generateApplicationToken({ + workspaceId, + applicationId: flatApplication.id, + expiresInSeconds: Math.max( + flatLogicFunction.timeoutSeconds, + MIN_TOKEN_EXPIRATION_IN_SECONDS, + ), + }); + + const baseUrl = cleanServerUrl(this.twentyConfigService.get('SERVER_URL')); + + return { + [DEFAULT_API_URL_NAME]: baseUrl ?? '', + [DEFAULT_API_KEY_NAME]: applicationAccessToken.token, + ...buildEnvVar(flatApplicationVariables, this.secretEncryptionService), + }; + } + + private async handleExecutionResult({ + result, + flatApplication, + flatLogicFunction, + workspaceId, + }: { + result: LogicFunctionExecuteResult; + workspaceId: string; + flatLogicFunction: FlatLogicFunction; + flatApplication: FlatApplication; + }) { + if (this.twentyConfigService.get('LOGIC_FUNCTION_LOGS_ENABLED')) { + /* eslint-disable no-console */ + console.log(result.logs); + } + + await this.subscriptionService.publish({ + channel: SubscriptionChannel.LOGIC_FUNCTION_LOGS_CHANNEL, + workspaceId, + payload: { + logicFunctionLogs: { + logs: result.logs, + id: flatLogicFunction.id, + name: flatLogicFunction.name, + universalIdentifier: flatLogicFunction.universalIdentifier, + applicationId: flatApplication.id, + applicationUniversalIdentifier: flatApplication.universalIdentifier, + }, + }, + }); + + this.auditService + .createContext({ + workspaceId, + }) + .insertWorkspaceEvent(LOGIC_FUNCTION_EXECUTED_EVENT, { + duration: result.duration, + status: result.status, + ...(result.error && { + errorType: result.error.errorType, + }), + functionId: flatLogicFunction.id, + functionName: flatLogicFunction.name, + }); } } diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/utils/__tests__/build-env-var.spec.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/utils/__tests__/build-env-var.spec.ts similarity index 98% rename from packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/utils/__tests__/build-env-var.spec.ts rename to packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/utils/__tests__/build-env-var.spec.ts index a8c3391491f..6cde020aec4 100644 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/utils/__tests__/build-env-var.spec.ts +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/utils/__tests__/build-env-var.spec.ts @@ -1,6 +1,6 @@ import { type FlatApplicationVariable } from 'src/engine/core-modules/applicationVariable/types/flat-application-variable.type'; import { type SecretEncryptionService } from 'src/engine/core-modules/secret-encryption/secret-encryption.service'; -import { buildEnvVar } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/build-env-var'; +import { buildEnvVar } from 'src/engine/core-modules/logic-function/logic-function-executor/utils/build-env-var'; describe('buildEnvVar', () => { const mockSecretEncryptionService = { diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/utils/build-env-var.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/utils/build-env-var.ts similarity index 100% rename from packages/twenty-server/src/engine/core-modules/logic-function/logic-function-drivers/utils/build-env-var.ts rename to packages/twenty-server/src/engine/core-modules/logic-function/logic-function-executor/utils/build-env-var.ts diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-resource/constants/seed-logic-function-input-schema.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-resource/constants/seed-logic-function-input-schema.ts new file mode 100644 index 00000000000..90905d9ca18 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-resource/constants/seed-logic-function-input-schema.ts @@ -0,0 +1,4 @@ +export const SEED_LOGIC_FUNCTION_INPUT_SCHEMA = { + a: null, + b: null, +}; diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-source-builder/constants/seed-project/src/index.mjs b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-resource/constants/seed-project/src/index.mjs similarity index 100% rename from packages/twenty-server/src/engine/core-modules/logic-function/logic-function-source-builder/constants/seed-project/src/index.mjs rename to packages/twenty-server/src/engine/core-modules/logic-function/logic-function-resource/constants/seed-project/src/index.mjs diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-source-builder/constants/seed-project/src/index.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-resource/constants/seed-project/src/index.ts similarity index 100% rename from packages/twenty-server/src/engine/core-modules/logic-function/logic-function-source-builder/constants/seed-project/src/index.ts rename to packages/twenty-server/src/engine/core-modules/logic-function/logic-function-resource/constants/seed-project/src/index.ts diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-resource/logic-function-resource.module.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-resource/logic-function-resource.module.ts new file mode 100644 index 00000000000..7cb2854d5bc --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-resource/logic-function-resource.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; + +import { LogicFunctionResourceService } from 'src/engine/core-modules/logic-function/logic-function-resource/logic-function-resource.service'; + +@Module({ + providers: [LogicFunctionResourceService], + exports: [LogicFunctionResourceService], +}) +export class LogicFunctionResourceModule {} diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-source-builder/logic-function-source-builder.service.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-resource/logic-function-resource.service.ts similarity index 75% rename from packages/twenty-server/src/engine/core-modules/logic-function/logic-function-source-builder/logic-function-source-builder.service.ts rename to packages/twenty-server/src/engine/core-modules/logic-function/logic-function-resource/logic-function-resource.service.ts index 1d08ab0fc1c..5936a85669c 100644 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-source-builder/logic-function-source-builder.service.ts +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-resource/logic-function-resource.service.ts @@ -8,19 +8,20 @@ import { isObject } from '@sniptt/guards'; import { build } from 'esbuild'; import { FileFolder, Sources } from 'twenty-shared/types'; import { isDefined } from 'twenty-shared/utils'; +import { NODE_ESM_CJS_BANNER } from 'twenty-shared/application'; import { FileStorageExceptionCode } from 'src/engine/core-modules/file-storage/interfaces/file-storage-exception'; import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service'; -import { LambdaBuildDirectoryManager } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/lambda-build-directory-manager'; +import { TemporaryDirManager } from 'src/engine/core-modules/logic-function/logic-function-drivers/utils/temporary-dir-manager'; import { getLogicFunctionBaseFolderPath, getRelativePathFromBase, -} from 'src/engine/core-modules/logic-function/logic-function-source-builder/utils/get-logic-function-handler-path.util'; +} from 'src/engine/core-modules/logic-function/logic-function-resource/utils/get-logic-function-handler-path.util'; import { getLogicFunctionSeedProjectFiles, LogicFunctionSeedProjectFile, -} from 'src/engine/core-modules/logic-function/logic-function-source-builder/utils/get-logic-function-seed-project-files.util'; +} from 'src/engine/core-modules/logic-function/logic-function-resource/utils/get-logic-function-seed-project-files.util'; import { DEFAULT_BUILT_HANDLER_PATH, DEFAULT_SOURCE_HANDLER_PATH, @@ -29,17 +30,18 @@ import { LogicFunctionException, LogicFunctionExceptionCode, } from 'src/engine/metadata-modules/logic-function/logic-function.exception'; +import { streamToBuffer } from 'src/utils/stream-to-buffer'; type SeedSourceFilesParams = { - logicFunctionId: string; workspaceId: string; applicationUniversalIdentifier: string; - code?: Sources; + sourceSubfolder: string; }; type SeedSourceFilesResult = { sourceHandlerPath: string; builtHandlerPath: string; + handlerName: string; checksum: string; }; @@ -63,7 +65,7 @@ type GetSourceCodeParams = { applicationUniversalIdentifier: string; }; -type CopySourceAndBuiltParams = { +type CopySourceParams = { fromSourceHandlerPath: string; fromBuiltHandlerPath: string; toSourceHandlerPath: string; @@ -73,42 +75,17 @@ type CopySourceAndBuiltParams = { }; @Injectable() -export class LogicFunctionSourceBuilderService { +export class LogicFunctionResourceService { constructor(private readonly fileStorageService: FileStorageService) {} async seedSourceFiles({ - logicFunctionId, workspaceId, applicationUniversalIdentifier, - code, + sourceSubfolder, }: SeedSourceFilesParams): Promise { - const sourceHandlerPath = `${logicFunctionId}/${DEFAULT_SOURCE_HANDLER_PATH}`; - const builtHandlerPath = `${logicFunctionId}/${DEFAULT_BUILT_HANDLER_PATH}`; + const sourceHandlerPath = `${sourceSubfolder}/${DEFAULT_SOURCE_HANDLER_PATH}`; + const builtHandlerPath = `${sourceSubfolder}/${DEFAULT_BUILT_HANDLER_PATH}`; - if (isDefined(code)) { - // Use provided code - await this.updateSourceFiles({ - sourceHandlerPath, - workspaceId, - applicationUniversalIdentifier, - code, - }); - - const { checksum } = await this.buildFromSource({ - sourceHandlerPath, - builtHandlerPath, - workspaceId, - applicationUniversalIdentifier, - }); - - return { - sourceHandlerPath, - builtHandlerPath, - checksum, - }; - } - - // Use seed project files const seedProjectFiles = await getLogicFunctionSeedProjectFiles(); const sourceFiles = seedProjectFiles.filter( @@ -160,6 +137,7 @@ export class LogicFunctionSourceBuilderService { .digest('hex'); return { + handlerName: 'main', sourceHandlerPath, builtHandlerPath, checksum, @@ -172,10 +150,10 @@ export class LogicFunctionSourceBuilderService { applicationUniversalIdentifier, code, }: UpdateSourceFilesParams): Promise { - const lambdaBuildDirectoryManager = new LambdaBuildDirectoryManager(); + const temporaryDirManager = new TemporaryDirManager(); try { - const { sourceTemporaryDir } = await lambdaBuildDirectoryManager.init(); + const { sourceTemporaryDir } = await temporaryDirManager.init(); await this.writeSourcesToLocalFolder(code, sourceTemporaryDir); @@ -189,7 +167,7 @@ export class LogicFunctionSourceBuilderService { localPath: sourceTemporaryDir, }); } finally { - await lambdaBuildDirectoryManager.clean(); + await temporaryDirManager.clean(); } } @@ -199,10 +177,10 @@ export class LogicFunctionSourceBuilderService { workspaceId, applicationUniversalIdentifier, }: BuildFromSourceParams): Promise<{ checksum: string }> { - const lambdaBuildDirectoryManager = new LambdaBuildDirectoryManager(); + const temporaryDirManager = new TemporaryDirManager(); try { - const { sourceTemporaryDir } = await lambdaBuildDirectoryManager.init(); + const { sourceTemporaryDir } = await temporaryDirManager.init(); const baseFolderPath = getLogicFunctionBaseFolderPath(sourceHandlerPath); @@ -248,7 +226,7 @@ export class LogicFunctionSourceBuilderService { checksum: crypto.createHash('md5').update(builtFile).digest('hex'), }; } finally { - await lambdaBuildDirectoryManager.clean(); + await temporaryDirManager.clean(); } } @@ -279,14 +257,14 @@ export class LogicFunctionSourceBuilderService { } } - async copySourceAndBuilt({ + async copyResources({ fromSourceHandlerPath, fromBuiltHandlerPath, toSourceHandlerPath, toBuiltHandlerPath, workspaceId, applicationUniversalIdentifier, - }: CopySourceAndBuiltParams): Promise { + }: CopySourceParams): Promise { const fromSourceBaseFolderPath = getLogicFunctionBaseFolderPath( fromSourceHandlerPath, ); @@ -328,7 +306,75 @@ export class LogicFunctionSourceBuilderService { }); } - private async writeSourcesToLocalFolder( + async copyDependenciesInMemory({ + applicationUniversalIdentifier, + workspaceId, + inMemoryFolderPath, + }: { + applicationUniversalIdentifier: string; + workspaceId: string; + inMemoryFolderPath: string; + }) { + await Promise.all([ + this.fileStorageService.downloadFile({ + workspaceId, + applicationUniversalIdentifier, + fileFolder: FileFolder.Dependencies, + resourcePath: 'package.json', + localPath: join(inMemoryFolderPath, 'package.json'), + }), + this.fileStorageService.downloadFile({ + workspaceId, + applicationUniversalIdentifier, + fileFolder: FileFolder.Dependencies, + resourcePath: 'yarn.lock', + localPath: join(inMemoryFolderPath, 'yarn.lock'), + }), + ]); + } + + async getBuiltCode({ + builtHandlerPath, + workspaceId, + applicationUniversalIdentifier, + }: { + builtHandlerPath: string; + workspaceId: string; + applicationUniversalIdentifier: string; + }): Promise { + return ( + await streamToBuffer( + await this.fileStorageService.readFile({ + workspaceId: workspaceId, + applicationUniversalIdentifier, + fileFolder: FileFolder.BuiltLogicFunction, + resourcePath: builtHandlerPath, + }), + ) + ).toString('utf-8'); + } + + async copyBuiltCodeInMemory({ + builtHandlerPath, + workspaceId, + applicationUniversalIdentifier, + inMemoryDestinationPath, + }: { + builtHandlerPath: string; + workspaceId: string; + applicationUniversalIdentifier: string; + inMemoryDestinationPath: string; + }): Promise { + await this.fileStorageService.downloadFile({ + workspaceId, + applicationUniversalIdentifier, + fileFolder: FileFolder.BuiltLogicFunction, + resourcePath: builtHandlerPath, + localPath: inMemoryDestinationPath, + }); + } + + async writeSourcesToLocalFolder( sources: Sources, localPath: string, ): Promise { @@ -368,6 +414,7 @@ export class LogicFunctionSourceBuilderService { bundle: true, sourcemap: true, packages: 'external', + banner: NODE_ESM_CJS_BANNER, }); return builtBundleFilePath; diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-source-builder/utils/get-logic-function-handler-path.util.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-resource/utils/get-logic-function-handler-path.util.ts similarity index 100% rename from packages/twenty-server/src/engine/core-modules/logic-function/logic-function-source-builder/utils/get-logic-function-handler-path.util.ts rename to packages/twenty-server/src/engine/core-modules/logic-function/logic-function-resource/utils/get-logic-function-handler-path.util.ts diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-source-builder/utils/get-logic-function-seed-project-files.util.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-resource/utils/get-logic-function-seed-project-files.util.ts similarity index 91% rename from packages/twenty-server/src/engine/core-modules/logic-function/logic-function-source-builder/utils/get-logic-function-seed-project-files.util.ts rename to packages/twenty-server/src/engine/core-modules/logic-function/logic-function-resource/utils/get-logic-function-seed-project-files.util.ts index 213125efa27..e091a083378 100644 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-source-builder/utils/get-logic-function-seed-project-files.util.ts +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-resource/utils/get-logic-function-seed-project-files.util.ts @@ -38,7 +38,7 @@ export const getLogicFunctionSeedProjectFiles = async (): Promise< > => { const seedProjectPath = path.join( ASSET_PATH, - 'engine/core-modules/logic-function/logic-function-source-builder/constants/seed-project', + 'engine/core-modules/logic-function/logic-function-resource/constants/seed-project', ); return getAllFiles(seedProjectPath); diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-source-builder/logic-function-source-builder.module.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-source-builder/logic-function-source-builder.module.ts deleted file mode 100644 index 8145e779cce..00000000000 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-source-builder/logic-function-source-builder.module.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Module } from '@nestjs/common'; - -import { LogicFunctionSourceBuilderService } from './logic-function-source-builder.service'; - -@Module({ - providers: [LogicFunctionSourceBuilderService], - exports: [LogicFunctionSourceBuilderService], -}) -export class LogicFunctionSourceBuilderModule {} diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-trigger/jobs/logic-function-trigger.job.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-trigger/jobs/logic-function-trigger.job.ts index 4f412385e83..a4d590caa81 100644 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-trigger/jobs/logic-function-trigger.job.ts +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-trigger/jobs/logic-function-trigger.job.ts @@ -3,7 +3,7 @@ import { Scope } from '@nestjs/common'; import { Process } from 'src/engine/core-modules/message-queue/decorators/process.decorator'; import { Processor } from 'src/engine/core-modules/message-queue/decorators/processor.decorator'; import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants'; -import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/services/logic-function-executor.service'; +import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.service'; export type LogicFunctionTriggerJobData = { logicFunctionId: string; @@ -25,8 +25,8 @@ export class LogicFunctionTriggerJob { await Promise.all( logicFunctionPayloads.map( async (logicFunctionPayload) => - await this.logicFunctionExecutorService.executeOneLogicFunction({ - id: logicFunctionPayload.logicFunctionId, + await this.logicFunctionExecutorService.execute({ + logicFunctionId: logicFunctionPayload.logicFunctionId, workspaceId: logicFunctionPayload.workspaceId, payload: logicFunctionPayload.payload ?? {}, }), diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-trigger/triggers/route/route-trigger.service.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-trigger/triggers/route/route-trigger.service.ts index eed78366a6a..a227adada9f 100644 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-trigger/triggers/route/route-trigger.service.ts +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function-trigger/triggers/route/route-trigger.service.ts @@ -9,13 +9,13 @@ import { HTTPMethod } from 'twenty-shared/types'; import { AccessTokenService } from 'src/engine/core-modules/auth/token/services/access-token.service'; import { WorkspaceDomainsService } from 'src/engine/core-modules/domain/workspace-domains/services/workspace-domains.service'; -import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/services/logic-function-executor.service'; import { RouteTriggerException, RouteTriggerExceptionCode, } from 'src/engine/core-modules/logic-function/logic-function-trigger/triggers/route/exceptions/route-trigger.exception'; import { buildLogicFunctionEvent } from 'src/engine/core-modules/logic-function/logic-function-trigger/triggers/route/utils/build-logic-function-event.util'; import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity'; +import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.service'; @Injectable() export class RouteTriggerService { @@ -146,12 +146,11 @@ export class RouteTriggerService { forwardedRequestHeaders: httpRouteSettings?.forwardedRequestHeaders ?? [], }); - const result = - await this.logicFunctionExecutorService.executeOneLogicFunction({ - id: logicFunction.id, - workspaceId: logicFunction.workspaceId, - payload: event, - }); + const result = await this.logicFunctionExecutorService.execute({ + logicFunctionId: logicFunction.id, + workspaceId: logicFunction.workspaceId, + payload: event, + }); if (!isDefined(result)) { return result; diff --git a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function.module.ts b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function.module.ts index 01f5d124053..7f0d1ddcd2d 100644 --- a/packages/twenty-server/src/engine/core-modules/logic-function/logic-function.module.ts +++ b/packages/twenty-server/src/engine/core-modules/logic-function/logic-function.module.ts @@ -1,31 +1,29 @@ import { type DynamicModule, Global, Module } from '@nestjs/common'; -import { type LogicFunctionExecutorModuleAsyncOptions } from 'src/engine/core-modules/logic-function/logic-function-executor/interfaces/logic-function-executor.interface'; +import { LogicFunctionModuleAsyncOptions } from 'src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-driver.interface'; import { LogicFunctionDriversModule } from 'src/engine/core-modules/logic-function/logic-function-drivers/logic-function-drivers.module'; -import { LogicFunctionExecutorModule } from 'src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.module'; -import { LogicFunctionSourceBuilderModule } from 'src/engine/core-modules/logic-function/logic-function-source-builder/logic-function-source-builder.module'; +import { LogicFunctionResourceModule } from 'src/engine/core-modules/logic-function/logic-function-resource/logic-function-resource.module'; import { LogicFunctionTriggerModule } from 'src/engine/core-modules/logic-function/logic-function-trigger/logic-function-trigger.module'; +import { LogicFunctionExecutorModule } from 'src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.module'; @Global() @Module({}) export class LogicFunctionModule { - static forRootAsync( - options: LogicFunctionExecutorModuleAsyncOptions, - ): DynamicModule { + static forRootAsync(options: LogicFunctionModuleAsyncOptions): DynamicModule { return { module: LogicFunctionModule, imports: [ LogicFunctionDriversModule.forRootAsync(options), - LogicFunctionExecutorModule, - LogicFunctionSourceBuilderModule, + LogicFunctionResourceModule, LogicFunctionTriggerModule, + LogicFunctionExecutorModule, ], exports: [ LogicFunctionDriversModule, - LogicFunctionExecutorModule, - LogicFunctionSourceBuilderModule, + LogicFunctionResourceModule, LogicFunctionTriggerModule, + LogicFunctionExecutorModule, ], }; } diff --git a/packages/twenty-server/src/engine/core-modules/tool-provider/providers/logic-function-tool.provider.ts b/packages/twenty-server/src/engine/core-modules/tool-provider/providers/logic-function-tool.provider.ts index 067da7227c2..cf34d173a1f 100644 --- a/packages/twenty-server/src/engine/core-modules/tool-provider/providers/logic-function-tool.provider.ts +++ b/packages/twenty-server/src/engine/core-modules/tool-provider/providers/logic-function-tool.provider.ts @@ -8,11 +8,11 @@ import { type ToolProviderContext, } from 'src/engine/core-modules/tool-provider/interfaces/tool-provider.interface'; -import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/services/logic-function-executor.service'; import { ToolCategory } from 'src/engine/core-modules/tool-provider/enums/tool-category.enum'; import { wrapJsonSchemaForExecution } from 'src/engine/core-modules/tool/utils/wrap-tool-for-execution.util'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type'; +import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.service'; @Injectable() export class LogicFunctionToolProvider implements ToolProvider { @@ -62,12 +62,11 @@ export class LogicFunctionToolProvider implements ToolProvider { execute: async (parameters: Record) => { const { loadingMessage: _, ...actualParams } = parameters; - const result = - await this.logicFunctionExecutorService.executeOneLogicFunction({ - id: logicFunction.id, - workspaceId: context.workspaceId, - payload: actualParams, - }); + const result = await this.logicFunctionExecutorService.execute({ + logicFunctionId: logicFunction.id, + workspaceId: context.workspaceId, + payload: actualParams, + }); if (result.error) { return { diff --git a/packages/twenty-server/src/engine/core-modules/twenty-config/config-variables.ts b/packages/twenty-server/src/engine/core-modules/twenty-config/config-variables.ts index 3f327e83552..06c677bb2f9 100644 --- a/packages/twenty-server/src/engine/core-modules/twenty-config/config-variables.ts +++ b/packages/twenty-server/src/engine/core-modules/twenty-config/config-variables.ts @@ -15,7 +15,7 @@ import { type LoggerOptions } from 'typeorm/logger/LoggerOptions'; import { type AwsRegion } from 'src/engine/core-modules/twenty-config/interfaces/aws-region.interface'; import { NodeEnvironment } from 'src/engine/core-modules/twenty-config/interfaces/node-environment.interface'; import { SupportDriver } from 'src/engine/core-modules/twenty-config/interfaces/support.interface'; -import { LogicFunctionExecutorDriverType } from 'src/engine/core-modules/logic-function/logic-function-executor/interfaces/logic-function-executor.interface'; +import { LogicFunctionDriverType } from 'src/engine/core-modules/logic-function/logic-function-drivers/interfaces/logic-function-driver.interface'; import { CaptchaDriverType } from 'src/engine/core-modules/captcha/interfaces'; import { CodeInterpreterDriverType } from 'src/engine/core-modules/code-interpreter/code-interpreter.interface'; @@ -456,13 +456,12 @@ export class ConfigVariables { group: ConfigVariablesGroup.LOGIC_FUNCTION_CONFIG, description: 'Type of function execution (local or Lambda)', type: ConfigVariableType.ENUM, - options: Object.values(LogicFunctionExecutorDriverType), + options: Object.values(LogicFunctionDriverType), isEnvOnly: true, }) @IsOptional() @CastToUpperSnakeCase() - LOGIC_FUNCTION_TYPE: LogicFunctionExecutorDriverType = - LogicFunctionExecutorDriverType.LOCAL; + LOGIC_FUNCTION_TYPE: LogicFunctionDriverType = LogicFunctionDriverType.LOCAL; @ConfigVariablesMetadata({ group: ConfigVariablesGroup.LOGIC_FUNCTION_CONFIG, @@ -496,7 +495,7 @@ export class ConfigVariables { type: ConfigVariableType.STRING, }) @ValidateIf( - (env) => env.LOGIC_FUNCTION_TYPE === LogicFunctionExecutorDriverType.LAMBDA, + (env) => env.LOGIC_FUNCTION_TYPE === LogicFunctionDriverType.LAMBDA, ) @IsAWSRegion() LOGIC_FUNCTION_LAMBDA_REGION: AwsRegion; @@ -507,7 +506,7 @@ export class ConfigVariables { type: ConfigVariableType.STRING, }) @ValidateIf( - (env) => env.LOGIC_FUNCTION_TYPE === LogicFunctionExecutorDriverType.LAMBDA, + (env) => env.LOGIC_FUNCTION_TYPE === LogicFunctionDriverType.LAMBDA, ) LOGIC_FUNCTION_LAMBDA_ROLE: string; @@ -517,7 +516,7 @@ export class ConfigVariables { type: ConfigVariableType.STRING, }) @ValidateIf( - (env) => env.LOGIC_FUNCTION_TYPE === LogicFunctionExecutorDriverType.LAMBDA, + (env) => env.LOGIC_FUNCTION_TYPE === LogicFunctionDriverType.LAMBDA, ) @IsOptional() LOGIC_FUNCTION_LAMBDA_SUBHOSTING_ROLE?: string; @@ -529,7 +528,7 @@ export class ConfigVariables { type: ConfigVariableType.STRING, }) @ValidateIf( - (env) => env.LOGIC_FUNCTION_TYPE === LogicFunctionExecutorDriverType.LAMBDA, + (env) => env.LOGIC_FUNCTION_TYPE === LogicFunctionDriverType.LAMBDA, ) @IsOptional() LOGIC_FUNCTION_LAMBDA_ACCESS_KEY_ID: string; @@ -541,7 +540,7 @@ export class ConfigVariables { type: ConfigVariableType.STRING, }) @ValidateIf( - (env) => env.LOGIC_FUNCTION_TYPE === LogicFunctionExecutorDriverType.LAMBDA, + (env) => env.LOGIC_FUNCTION_TYPE === LogicFunctionDriverType.LAMBDA, ) @IsOptional() LOGIC_FUNCTION_LAMBDA_SECRET_ACCESS_KEY: string; diff --git a/packages/twenty-server/src/engine/core-modules/workflow/workflow-api.module.ts b/packages/twenty-server/src/engine/core-modules/workflow/workflow-api.module.ts index 420e4e3b31f..1ce80b1da66 100644 --- a/packages/twenty-server/src/engine/core-modules/workflow/workflow-api.module.ts +++ b/packages/twenty-server/src/engine/core-modules/workflow/workflow-api.module.ts @@ -2,7 +2,6 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module'; -import { LogicFunctionExecutorModule } from 'src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.module'; import { ToolModule } from 'src/engine/core-modules/tool/tool.module'; import { WorkflowTriggerController } from 'src/engine/core-modules/workflow/controllers/workflow-trigger.controller'; import { WorkflowBuilderResolver } from 'src/engine/core-modules/workflow/resolvers/workflow-builder.resolver'; @@ -34,7 +33,6 @@ import { WorkflowTriggerModule } from 'src/modules/workflow/workflow-trigger/wor WorkflowRunnerModule, PermissionsModule, ToolModule, - LogicFunctionExecutorModule, LogicFunctionModule, CodeStepBuildModule, WorkspaceManyOrAllFlatEntityMapsCacheModule, diff --git a/packages/twenty-server/src/engine/metadata-modules/flat-entity/constant/all-flat-entity-properties-to-compare-and-stringify.constant.ts b/packages/twenty-server/src/engine/metadata-modules/flat-entity/constant/all-flat-entity-properties-to-compare-and-stringify.constant.ts index 97c1b3529c6..829f6d2db49 100644 --- a/packages/twenty-server/src/engine/metadata-modules/flat-entity/constant/all-flat-entity-properties-to-compare-and-stringify.constant.ts +++ b/packages/twenty-server/src/engine/metadata-modules/flat-entity/constant/all-flat-entity-properties-to-compare-and-stringify.constant.ts @@ -75,9 +75,7 @@ export const ALL_FLAT_ENTITY_PROPERTIES_TO_COMPARE_AND_STRINGIFY = { }, logicFunction: { propertiesToCompare: [ - ...FLAT_LOGIC_FUNCTION_EDITABLE_PROPERTIES.filter( - (property) => property !== 'code', - ), + ...FLAT_LOGIC_FUNCTION_EDITABLE_PROPERTIES, 'deletedAt', ], propertiesToStringify: ['toolInputSchema'], diff --git a/packages/twenty-server/src/engine/metadata-modules/logic-function/constants/default-tool-input-schema.constant.ts b/packages/twenty-server/src/engine/metadata-modules/logic-function/constants/default-tool-input-schema.constant.ts index a494a09c2ac..23f1e5d3d33 100644 --- a/packages/twenty-server/src/engine/metadata-modules/logic-function/constants/default-tool-input-schema.constant.ts +++ b/packages/twenty-server/src/engine/metadata-modules/logic-function/constants/default-tool-input-schema.constant.ts @@ -1,5 +1,3 @@ -// Default tool input schema matching the seed-project template -// Template params: { a: string; b: number; } export const DEFAULT_TOOL_INPUT_SCHEMA = { type: 'object', properties: { diff --git a/packages/twenty-server/src/engine/metadata-modules/logic-function/constants/flat-logic-function-editable-properties.constant.ts b/packages/twenty-server/src/engine/metadata-modules/logic-function/constants/flat-logic-function-editable-properties.constant.ts index 65c75883b75..efc3761bf29 100644 --- a/packages/twenty-server/src/engine/metadata-modules/logic-function/constants/flat-logic-function-editable-properties.constant.ts +++ b/packages/twenty-server/src/engine/metadata-modules/logic-function/constants/flat-logic-function-editable-properties.constant.ts @@ -5,9 +5,11 @@ export const FLAT_LOGIC_FUNCTION_EDITABLE_PROPERTIES = [ 'description', 'timeoutSeconds', 'checksum', - 'code', 'sourceHandlerPath', 'handlerName', 'toolInputSchema', 'isTool', + 'cronTriggerSettings', + 'databaseEventTriggerSettings', + 'httpRouteTriggerSettings', ] as const satisfies (keyof FlatLogicFunction)[]; diff --git a/packages/twenty-server/src/engine/metadata-modules/logic-function/dtos/create-default-logic-function.input.ts b/packages/twenty-server/src/engine/metadata-modules/logic-function/dtos/create-default-logic-function.input.ts new file mode 100644 index 00000000000..c93c9023044 --- /dev/null +++ b/packages/twenty-server/src/engine/metadata-modules/logic-function/dtos/create-default-logic-function.input.ts @@ -0,0 +1,52 @@ +import { Field, HideField, InputType } from '@nestjs/graphql'; + +import { + IsBoolean, + IsNotEmpty, + IsNumber, + IsObject, + IsOptional, + IsString, + Max, + Min, +} from 'class-validator'; +import graphqlTypeJson from 'graphql-type-json'; + +@InputType() +export class CreateDefaultLogicFunctionInput { + @IsString() + @IsNotEmpty() + @Field() + name: string; + + @IsString() + @IsOptional() + @Field({ nullable: true }) + description?: string; + + @IsNumber() + @Field({ nullable: true }) + @Min(1) + @Max(900) + @IsOptional() + timeoutSeconds?: number; + + @HideField() + applicationId?: string; + + @HideField() + universalIdentifier?: string; + + @HideField() + id?: string; + + @Field(() => graphqlTypeJson, { nullable: true }) + @IsObject() + @IsOptional() + toolInputSchema?: object; + + @IsBoolean() + @Field({ nullable: true }) + @IsOptional() + isTool?: boolean; +} diff --git a/packages/twenty-server/src/engine/metadata-modules/logic-function/dtos/create-logic-function.input.ts b/packages/twenty-server/src/engine/metadata-modules/logic-function/dtos/create-logic-function.input.ts index 053db0aabb1..01dd4794abb 100644 --- a/packages/twenty-server/src/engine/metadata-modules/logic-function/dtos/create-logic-function.input.ts +++ b/packages/twenty-server/src/engine/metadata-modules/logic-function/dtos/create-logic-function.input.ts @@ -11,7 +11,13 @@ import { Min, } from 'class-validator'; import graphqlTypeJson from 'graphql-type-json'; -import { Sources } from 'twenty-shared/types'; +import { + CronTriggerSettings, + DatabaseEventTriggerSettings, + HttpRouteTriggerSettings, +} from 'twenty-shared/application'; + +import type { JsonbProperty } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/jsonb-property.type'; @InputType() export class CreateLogicFunctionInput { @@ -33,36 +39,28 @@ export class CreateLogicFunctionInput { timeoutSeconds?: number; @HideField() - applicationId?: string; + applicationId: string; @HideField() universalIdentifier?: string; @HideField() - id?: string; + id: string; @HideField() - checksum?: string; - - @Field(() => graphqlTypeJson, { nullable: true }) - @IsObject() - @IsOptional() - code?: Sources; + checksum: string; @IsString() - @Field({ nullable: true }) - @IsOptional() - handlerName?: string; + @Field({ nullable: false }) + handlerName: string; @IsString() - @Field({ nullable: true }) - @IsOptional() - sourceHandlerPath?: string; + @Field({ nullable: false }) + sourceHandlerPath: string; @IsString() - @Field({ nullable: true }) - @IsOptional() - builtHandlerPath?: string; + @Field({ nullable: false }) + builtHandlerPath: string; @Field(() => graphqlTypeJson, { nullable: true }) @IsObject() @@ -73,4 +71,19 @@ export class CreateLogicFunctionInput { @Field({ nullable: true }) @IsOptional() isTool?: boolean; + + @IsObject() + @Field(() => graphqlTypeJson, { nullable: true }) + @IsOptional() + cronTriggerSettings?: JsonbProperty; + + @IsObject() + @Field(() => graphqlTypeJson, { nullable: true }) + @IsOptional() + databaseEventTriggerSettings?: JsonbProperty; + + @IsObject() + @Field(() => graphqlTypeJson, { nullable: true }) + @IsOptional() + httpRouteTriggerSettings?: JsonbProperty; } diff --git a/packages/twenty-server/src/engine/metadata-modules/logic-function/dtos/get-logic-function-source-code.input.ts b/packages/twenty-server/src/engine/metadata-modules/logic-function/dtos/get-logic-function-source-code.input.ts deleted file mode 100644 index f008c01ecea..00000000000 --- a/packages/twenty-server/src/engine/metadata-modules/logic-function/dtos/get-logic-function-source-code.input.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { ID, InputType } from '@nestjs/graphql'; - -import { IDField } from '@ptc-org/nestjs-query-graphql'; - -@InputType() -export class GetLogicFunctionSourceCodeInput { - @IDField(() => ID, { description: 'The id of the function.' }) - id!: string; -} diff --git a/packages/twenty-server/src/engine/metadata-modules/logic-function/dtos/logic-function.dto.ts b/packages/twenty-server/src/engine/metadata-modules/logic-function/dtos/logic-function.dto.ts index d3a8d65f81d..9ce47ed2904 100644 --- a/packages/twenty-server/src/engine/metadata-modules/logic-function/dtos/logic-function.dto.ts +++ b/packages/twenty-server/src/engine/metadata-modules/logic-function/dtos/logic-function.dto.ts @@ -16,13 +16,13 @@ import { IsUUID, } from 'class-validator'; import graphqlTypeJson from 'graphql-type-json'; - -import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; import { CronTriggerSettings, DatabaseEventTriggerSettings, HttpRouteTriggerSettings, -} from 'src/engine/metadata-modules/logic-function/logic-function.entity'; +} from 'twenty-shared/application'; + +import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; @ObjectType('LogicFunction') @Authorize({ diff --git a/packages/twenty-server/src/engine/metadata-modules/logic-function/dtos/update-logic-function.input.ts b/packages/twenty-server/src/engine/metadata-modules/logic-function/dtos/update-logic-function.input.ts index e56843dd0ea..3786fc1d5cd 100644 --- a/packages/twenty-server/src/engine/metadata-modules/logic-function/dtos/update-logic-function.input.ts +++ b/packages/twenty-server/src/engine/metadata-modules/logic-function/dtos/update-logic-function.input.ts @@ -14,10 +14,14 @@ import { ValidateNested, } from 'class-validator'; import graphqlTypeJson from 'graphql-type-json'; - -import type { Sources } from 'twenty-shared/types'; +import { + CronTriggerSettings, + DatabaseEventTriggerSettings, + HttpRouteTriggerSettings, +} from 'twenty-shared/application'; import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars'; +import type { JsonbProperty } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/jsonb-property.type'; @InputType() class UpdateLogicFunctionInputUpdates { @@ -38,11 +42,6 @@ class UpdateLogicFunctionInputUpdates { @IsOptional() timeoutSeconds?: number; - @Field(() => graphqlTypeJson, { nullable: true }) - @IsObject() - @IsOptional() - code?: Sources; - @IsString() @Field({ nullable: true }) @IsOptional() @@ -67,10 +66,30 @@ class UpdateLogicFunctionInputUpdates { @Field({ nullable: true }) @IsOptional() isTool?: boolean; + + @IsString() + @Field({ nullable: true }) + @IsOptional() + checksum?: string; + + @IsObject() + @Field(() => graphqlTypeJson, { nullable: true }) + @IsOptional() + cronTriggerSettings?: JsonbProperty; + + @IsObject() + @Field(() => graphqlTypeJson, { nullable: true }) + @IsOptional() + databaseEventTriggerSettings?: JsonbProperty; + + @IsObject() + @Field(() => graphqlTypeJson, { nullable: true }) + @IsOptional() + httpRouteTriggerSettings?: JsonbProperty; } @InputType() -export class UpdateLogicFunctionInput { +export class UpdateLogicFunctionSourceInput { @Field(() => UUIDScalarType, { description: 'Id of the logic function to update', }) diff --git a/packages/twenty-server/src/engine/metadata-modules/logic-function/logic-function.entity.ts b/packages/twenty-server/src/engine/metadata-modules/logic-function/logic-function.entity.ts index ecc16587169..182810c5b80 100644 --- a/packages/twenty-server/src/engine/metadata-modules/logic-function/logic-function.entity.ts +++ b/packages/twenty-server/src/engine/metadata-modules/logic-function/logic-function.entity.ts @@ -1,4 +1,3 @@ -import { HTTPMethod } from 'twenty-shared/types'; import { Check, Column, @@ -9,26 +8,15 @@ import { PrimaryGeneratedColumn, UpdateDateColumn, } from 'typeorm'; +import { + CronTriggerSettings, + DatabaseEventTriggerSettings, + HttpRouteTriggerSettings, +} from 'twenty-shared/application'; import { SyncableEntity } from 'src/engine/workspace-manager/types/syncable-entity.interface'; import { type JsonbProperty } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/jsonb-property.type'; -export type CronTriggerSettings = { - pattern: string; -}; - -export type DatabaseEventTriggerSettings = { - eventName: string; - updatedFields?: string[]; -}; - -export type HttpRouteTriggerSettings = { - path: string; - httpMethod: HTTPMethod; - isAuthRequired: boolean; - forwardedRequestHeaders?: string[]; -}; - const DEFAULT_LOGIC_FUNCTION_TIMEOUT_SECONDS = 300; // 5 minutes export enum LogicFunctionRuntime { diff --git a/packages/twenty-server/src/engine/metadata-modules/logic-function/logic-function.module.ts b/packages/twenty-server/src/engine/metadata-modules/logic-function/logic-function.module.ts index 41471fa33fd..db4dd0ff37b 100644 --- a/packages/twenty-server/src/engine/metadata-modules/logic-function/logic-function.module.ts +++ b/packages/twenty-server/src/engine/metadata-modules/logic-function/logic-function.module.ts @@ -10,48 +10,44 @@ import { TokenModule } from 'src/engine/core-modules/auth/token/token.module'; import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module'; import { FileUploadModule } from 'src/engine/core-modules/file/file-upload/file-upload.module'; -import { FileModule } from 'src/engine/core-modules/file/file.module'; -import { LogicFunctionExecutorModule } from 'src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.module'; -import { LogicFunctionSourceBuilderModule } from 'src/engine/core-modules/logic-function/logic-function-source-builder/logic-function-source-builder.module'; +import { LogicFunctionResourceModule } from 'src/engine/core-modules/logic-function/logic-function-resource/logic-function-resource.module'; import { SecretEncryptionModule } from 'src/engine/core-modules/secret-encryption/secret-encryption.module'; import { ThrottlerModule } from 'src/engine/core-modules/throttler/throttler.module'; import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module'; import { LogicFunctionLayerModule } from 'src/engine/metadata-modules/logic-function-layer/logic-function-layer.module'; import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity'; import { LogicFunctionResolver } from 'src/engine/metadata-modules/logic-function/logic-function.resolver'; -import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/services/logic-function.service'; +import { LogicFunctionMetadataService } from 'src/engine/metadata-modules/logic-function/services/logic-function-metadata.service'; import { WorkspaceFlatLogicFunctionMapCacheService } from 'src/engine/metadata-modules/logic-function/services/workspace-flat-logic-function-map-cache.service'; import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module'; import { SubscriptionsModule } from 'src/engine/subscriptions/subscriptions.module'; -import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module'; import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace-migration/workspace-migration.module'; +import { ApplicationLayerModule } from 'src/engine/core-modules/application-layer/application-layer.module'; @Module({ imports: [ FileUploadModule, NestjsQueryTypeOrmModule.forFeature([LogicFunctionEntity]), TypeOrmModule.forFeature([ApplicationEntity, FeatureFlagEntity]), - FileModule, ThrottlerModule, ApplicationModule, + ApplicationLayerModule, AuditModule, FeatureFlagModule, PermissionsModule, WorkspaceManyOrAllFlatEntityMapsCacheModule, WorkspaceMigrationModule, LogicFunctionLayerModule, - LogicFunctionExecutorModule, - LogicFunctionSourceBuilderModule, + LogicFunctionResourceModule, SubscriptionsModule, - WorkspaceCacheModule, TokenModule, SecretEncryptionModule, ], providers: [ - LogicFunctionService, + LogicFunctionMetadataService, LogicFunctionResolver, WorkspaceFlatLogicFunctionMapCacheService, ], - exports: [LogicFunctionService, LogicFunctionExecutorModule], + exports: [LogicFunctionMetadataService], }) export class LogicFunctionModule {} diff --git a/packages/twenty-server/src/engine/metadata-modules/logic-function/logic-function.resolver.ts b/packages/twenty-server/src/engine/metadata-modules/logic-function/logic-function.resolver.ts index 368f32285fd..1f0b2bbfe4e 100644 --- a/packages/twenty-server/src/engine/metadata-modules/logic-function/logic-function.resolver.ts +++ b/packages/twenty-server/src/engine/metadata-modules/logic-function/logic-function.resolver.ts @@ -4,34 +4,35 @@ import { Args, Mutation, Query, Resolver, Subscription } from '@nestjs/graphql'; import graphqlTypeJson from 'graphql-type-json'; import { PermissionFlagType } from 'twenty-shared/constants'; import { isDefined } from 'twenty-shared/utils'; +import { v4 } from 'uuid'; import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter'; import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe'; -import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/services/logic-function-executor.service'; -import { LogicFunctionSourceBuilderService } from 'src/engine/core-modules/logic-function/logic-function-source-builder/logic-function-source-builder.service'; +import { LogicFunctionResourceService } from 'src/engine/core-modules/logic-function/logic-function-resource/logic-function-resource.service'; import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity'; import { AuthWorkspace } from 'src/engine/decorators/auth/auth-workspace.decorator'; import { FeatureFlagGuard } from 'src/engine/guards/feature-flag.guard'; import { SettingsPermissionGuard } from 'src/engine/guards/settings-permission.guard'; import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; -import { CreateLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/create-logic-function.input'; import { ExecuteOneLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/execute-logic-function.input'; -import { GetLogicFunctionSourceCodeInput } from 'src/engine/metadata-modules/logic-function/dtos/get-logic-function-source-code.input'; import { LogicFunctionExecutionResultDTO } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-execution-result.dto'; import { LogicFunctionIdInput } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-id.input'; import { LogicFunctionLogsDTO } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-logs.dto'; import { LogicFunctionLogsInput } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-logs.input'; import { LogicFunctionDTO } from 'src/engine/metadata-modules/logic-function/dtos/logic-function.dto'; import { UpdateLogicFunctionSourceInput } from 'src/engine/metadata-modules/logic-function/dtos/update-logic-function-source.input'; -import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/services/logic-function.service'; +import { LogicFunctionMetadataService } from 'src/engine/metadata-modules/logic-function/services/logic-function-metadata.service'; import { FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type'; import { findFlatLogicFunctionOrThrow } from 'src/engine/metadata-modules/logic-function/utils/find-flat-logic-function-or-throw.util'; import { fromFlatLogicFunctionToLogicFunctionDto } from 'src/engine/metadata-modules/logic-function/utils/from-flat-logic-function-to-logic-function-dto.util'; import { logicFunctionGraphQLApiExceptionHandler } from 'src/engine/metadata-modules/logic-function/utils/logic-function-graphql-api-exception-handler.utils'; import { SubscriptionChannel } from 'src/engine/subscriptions/enums/subscription-channel.enum'; import { SubscriptionService } from 'src/engine/subscriptions/subscription.service'; +import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.service'; +import { ApplicationLayerService } from 'src/engine/core-modules/application-layer/application-layer.service'; +import { CreateDefaultLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/create-default-logic-function.input'; @UseGuards( WorkspaceAuthGuard, @@ -43,44 +44,15 @@ import { SubscriptionService } from 'src/engine/subscriptions/subscription.servi @UseFilters(PreventNestToAutoLogGraphqlErrorsFilter) export class LogicFunctionResolver { constructor( - private readonly logicFunctionService: LogicFunctionService, private readonly logicFunctionExecutorService: LogicFunctionExecutorService, - private readonly logicFunctionSourceBuilderService: LogicFunctionSourceBuilderService, + private readonly logicFunctionMetadataService: LogicFunctionMetadataService, + private readonly logicFunctionResourceService: LogicFunctionResourceService, private readonly applicationService: ApplicationService, + private readonly applicationLayerService: ApplicationLayerService, private readonly subscriptionService: SubscriptionService, private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, ) {} - private async getLogicFunctionContext({ - id, - workspaceId, - }: { - id: string; - workspaceId: string; - }) { - const [{ flatLogicFunctionMaps }, { workspaceCustomFlatApplication }] = - await Promise.all([ - this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps({ - workspaceId, - flatMapsKeys: ['flatLogicFunctionMaps'], - }), - this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( - { workspaceId }, - ), - ]); - - const flatLogicFunction = findFlatLogicFunctionOrThrow({ - id, - flatLogicFunctionMaps, - }); - - return { - flatLogicFunction, - applicationUniversalIdentifier: - workspaceCustomFlatApplication.universalIdentifier, - }; - } - @Query(() => LogicFunctionDTO) async findOneLogicFunction( @Args('input') { id }: LogicFunctionIdInput, @@ -138,9 +110,15 @@ export class LogicFunctionResolver { } @Query(() => graphqlTypeJson) - async getAvailablePackages(@Args('input') { id }: LogicFunctionIdInput) { + async getAvailablePackages( + @Args('input') { id }: LogicFunctionIdInput, + @AuthWorkspace() { id: workspaceId }: WorkspaceEntity, + ) { try { - return await this.logicFunctionExecutorService.getAvailablePackages(id); + return await this.applicationLayerService.getAvailablePackages({ + logicFunctionId: id, + workspaceId, + }); } catch (error) { return logicFunctionGraphQLApiExceptionHandler(error); } @@ -153,10 +131,11 @@ export class LogicFunctionResolver { @AuthWorkspace() { id: workspaceId }: WorkspaceEntity, ): Promise { try { - const flatLogicFunction = await this.logicFunctionService.destroyOne({ - id: input.id, - workspaceId, - }); + const flatLogicFunction = + await this.logicFunctionMetadataService.destroyOne({ + id: input.id, + workspaceId, + }); return fromFlatLogicFunctionToLogicFunctionDto({ flatLogicFunction, @@ -168,16 +147,42 @@ export class LogicFunctionResolver { @Mutation(() => LogicFunctionDTO) @UseGuards(SettingsPermissionGuard(PermissionFlagType.WORKFLOWS)) - async createOneLogicFunction( + async createDefaultLogicFunction( @Args('input') - input: CreateLogicFunctionInput, + input: CreateDefaultLogicFunctionInput, @AuthWorkspace() { id: workspaceId }: WorkspaceEntity, ): Promise { try { - const flatLogicFunction = await this.logicFunctionService.createOne({ - input, - workspaceId, - }); + const { workspaceCustomFlatApplication } = + await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( + { + workspaceId, + }, + ); + + const logicFunctionId = input.id ?? v4(); + + const { sourceHandlerPath, builtHandlerPath, handlerName, checksum } = + await this.logicFunctionResourceService.seedSourceFiles({ + sourceSubfolder: logicFunctionId, + workspaceId, + applicationUniversalIdentifier: + workspaceCustomFlatApplication.universalIdentifier, + }); + + const flatLogicFunction = + await this.logicFunctionMetadataService.createOne({ + input: { + ...input, + id: logicFunctionId, + sourceHandlerPath, + builtHandlerPath, + handlerName, + checksum, + }, + workspaceId, + ownerFlatApplication: workspaceCustomFlatApplication, + }); return fromFlatLogicFunctionToLogicFunctionDto({ flatLogicFunction, @@ -193,32 +198,32 @@ export class LogicFunctionResolver { @Args('input') { id, payload, forceRebuild }: ExecuteOneLogicFunctionInput, @AuthWorkspace() { id: workspaceId }: WorkspaceEntity, ): Promise { + // TODO: remove forceRebuild parameter and add a column called shouldRebuild or isBuiltUpToDate try { if (forceRebuild) { const { flatLogicFunction, applicationUniversalIdentifier } = await this.getLogicFunctionContext({ id, workspaceId }); const { checksum } = - await this.logicFunctionSourceBuilderService.buildFromSource({ + await this.logicFunctionResourceService.buildFromSource({ workspaceId, applicationUniversalIdentifier, sourceHandlerPath: flatLogicFunction.sourceHandlerPath, builtHandlerPath: flatLogicFunction.builtHandlerPath, }); - await this.logicFunctionService.updateChecksum({ + await this.logicFunctionMetadataService.updateChecksum({ id, checksum, workspaceId, }); } - const result = - await this.logicFunctionExecutorService.executeOneLogicFunction({ - id, - workspaceId, - payload, - }); + const result = await this.logicFunctionExecutorService.execute({ + logicFunctionId: id, + workspaceId, + payload, + }); return { data: result.data as LogicFunctionExecutionResultDTO['data'], @@ -242,14 +247,14 @@ export class LogicFunctionResolver { @Query(() => graphqlTypeJson, { nullable: true }) async getLogicFunctionSourceCode( - @Args('input') { id }: GetLogicFunctionSourceCodeInput, + @Args('input') { id }: LogicFunctionIdInput, @AuthWorkspace() { id: workspaceId }: WorkspaceEntity, ) { try { const { flatLogicFunction, applicationUniversalIdentifier } = await this.getLogicFunctionContext({ id, workspaceId }); - return this.logicFunctionSourceBuilderService.getSourceCode({ + return this.logicFunctionResourceService.getSourceCode({ workspaceId, applicationUniversalIdentifier, sourceHandlerPath: flatLogicFunction.sourceHandlerPath, @@ -269,7 +274,7 @@ export class LogicFunctionResolver { const { flatLogicFunction, applicationUniversalIdentifier } = await this.getLogicFunctionContext({ id, workspaceId }); - await this.logicFunctionSourceBuilderService.updateSourceFiles({ + await this.logicFunctionResourceService.updateSourceFiles({ workspaceId, applicationUniversalIdentifier, sourceHandlerPath: flatLogicFunction.sourceHandlerPath, @@ -325,4 +330,34 @@ export class LogicFunctionResolver { workspaceId: workspace.id, }); } + + private async getLogicFunctionContext({ + id, + workspaceId, + }: { + id: string; + workspaceId: string; + }) { + const [{ flatLogicFunctionMaps }, { workspaceCustomFlatApplication }] = + await Promise.all([ + this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps({ + workspaceId, + flatMapsKeys: ['flatLogicFunctionMaps'], + }), + this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( + { workspaceId }, + ), + ]); + + const flatLogicFunction = findFlatLogicFunctionOrThrow({ + id, + flatLogicFunctionMaps, + }); + + return { + flatLogicFunction, + applicationUniversalIdentifier: + workspaceCustomFlatApplication.universalIdentifier, + }; + } } diff --git a/packages/twenty-server/src/engine/metadata-modules/logic-function/services/logic-function.service.ts b/packages/twenty-server/src/engine/metadata-modules/logic-function/services/logic-function-metadata.service.ts similarity index 86% rename from packages/twenty-server/src/engine/metadata-modules/logic-function/services/logic-function.service.ts rename to packages/twenty-server/src/engine/metadata-modules/logic-function/services/logic-function-metadata.service.ts index add6886a715..925c9cd7125 100644 --- a/packages/twenty-server/src/engine/metadata-modules/logic-function/services/logic-function.service.ts +++ b/packages/twenty-server/src/engine/metadata-modules/logic-function/services/logic-function-metadata.service.ts @@ -4,13 +4,11 @@ import { isDefined } from 'twenty-shared/utils'; import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; -import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service'; -import { LogicFunctionSourceBuilderService } from 'src/engine/core-modules/logic-function/logic-function-source-builder/logic-function-source-builder.service'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util'; import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util'; import type { CreateLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/create-logic-function.input'; -import type { UpdateLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/update-logic-function.input'; +import type { UpdateLogicFunctionSourceInput } from 'src/engine/metadata-modules/logic-function/dtos/update-logic-function.input'; import { LogicFunctionException, LogicFunctionExceptionCode, @@ -19,19 +17,15 @@ import { FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/ty import { findFlatLogicFunctionOrThrow } from 'src/engine/metadata-modules/logic-function/utils/find-flat-logic-function-or-throw.util'; import { fromCreateLogicFunctionInputToFlatLogicFunction } from 'src/engine/metadata-modules/logic-function/utils/from-create-logic-function-input-to-flat-logic-function.util'; import { fromUpdateLogicFunctionInputToFlatLogicFunctionToUpdateOrThrow } from 'src/engine/metadata-modules/logic-function/utils/from-update-logic-function-input-to-flat-logic-function-to-update-or-throw.util'; -import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager/workspace-migration/exceptions/workspace-migration-builder-exception'; import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service'; @Injectable() -export class LogicFunctionService { +export class LogicFunctionMetadataService { constructor( private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService, private readonly applicationService: ApplicationService, - private readonly workspaceCacheService: WorkspaceCacheService, - private readonly fileStorageService: FileStorageService, - private readonly logicFunctionSourceBuilderService: LogicFunctionSourceBuilderService, ) {} async createOne({ @@ -40,9 +34,8 @@ export class LogicFunctionService { ownerFlatApplication, }: { input: Omit; - ownerFlatApplication?: FlatApplication; + ownerFlatApplication: FlatApplication; workspaceId: string; - applicationId?: string; }) { const resolvedOwnerFlatApplication = ownerFlatApplication ?? @@ -52,7 +45,6 @@ export class LogicFunctionService { ) ).workspaceCustomFlatApplication; - // Generate flat logic function to get the ID const flatLogicFunctionToCreate = fromCreateLogicFunctionInputToFlatLogicFunction({ createLogicFunctionInput: input, @@ -60,21 +52,6 @@ export class LogicFunctionService { ownerFlatApplication: resolvedOwnerFlatApplication, }); - // Seed the source files (uses provided code or default seed project) - const { sourceHandlerPath, builtHandlerPath, checksum } = - await this.logicFunctionSourceBuilderService.seedSourceFiles({ - logicFunctionId: flatLogicFunctionToCreate.id, - workspaceId, - applicationUniversalIdentifier: - resolvedOwnerFlatApplication.universalIdentifier, - code: input.code, - }); - - // Update paths and checksum with actual values from seeding - flatLogicFunctionToCreate.sourceHandlerPath = sourceHandlerPath; - flatLogicFunctionToCreate.builtHandlerPath = builtHandlerPath; - flatLogicFunctionToCreate.checksum = checksum; - const validateAndBuildResult = await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration( { @@ -109,7 +86,7 @@ export class LogicFunctionService { ownerFlatApplication, }: { id: string; - update: UpdateLogicFunctionInput['update']; + update: UpdateLogicFunctionSourceInput['update']; workspaceId: string; ownerFlatApplication?: FlatApplication; }) { diff --git a/packages/twenty-server/src/engine/metadata-modules/logic-function/utils/from-create-logic-function-input-to-flat-logic-function.util.ts b/packages/twenty-server/src/engine/metadata-modules/logic-function/utils/from-create-logic-function-input-to-flat-logic-function.util.ts index 1fb3d50afad..2ee67631476 100644 --- a/packages/twenty-server/src/engine/metadata-modules/logic-function/utils/from-create-logic-function-input-to-flat-logic-function.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/logic-function/utils/from-create-logic-function-input-to-flat-logic-function.util.ts @@ -1,22 +1,15 @@ -import { isDefined } from 'twenty-shared/utils'; import { v4 } from 'uuid'; import { type FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type'; -import { DEFAULT_TOOL_INPUT_SCHEMA } from 'src/engine/metadata-modules/logic-function/constants/default-tool-input-schema.constant'; import { type CreateLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/create-logic-function.input'; import { - DEFAULT_BUILT_HANDLER_PATH, DEFAULT_HANDLER_NAME, - DEFAULT_SOURCE_HANDLER_PATH, LogicFunctionRuntime, } from 'src/engine/metadata-modules/logic-function/logic-function.entity'; import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type'; -import { logicFunctionCreateHash } from 'src/engine/metadata-modules/logic-function/utils/logic-function-create-hash.utils'; - -const WORKFLOW_BASE_FOLDER_PREFIX = 'workflow'; export type FromCreateLogicFunctionInputToFlatLogicFunctionArgs = { - createLogicFunctionInput: CreateLogicFunctionInput; + createLogicFunctionInput: Omit; workspaceId: string; ownerFlatApplication: FlatApplication; }; @@ -26,34 +19,25 @@ export const fromCreateLogicFunctionInputToFlatLogicFunction = ({ workspaceId, ownerFlatApplication, }: FromCreateLogicFunctionInputToFlatLogicFunctionArgs): FlatLogicFunction => { - const id = rawCreateLogicFunctionInput.id ?? v4(); + const id = rawCreateLogicFunctionInput.id; const currentDate = new Date(); - // Build full paths including the base folder - const baseFolder = `${WORKFLOW_BASE_FOLDER_PREFIX}/${id}`; - const sourceHandlerPath = - rawCreateLogicFunctionInput.sourceHandlerPath ?? - `${baseFolder}/${DEFAULT_SOURCE_HANDLER_PATH}`; - const builtHandlerPath = - rawCreateLogicFunctionInput.builtHandlerPath ?? - `${baseFolder}/${DEFAULT_BUILT_HANDLER_PATH}`; + const sourceHandlerPath = rawCreateLogicFunctionInput.sourceHandlerPath; + const builtHandlerPath = rawCreateLogicFunctionInput.builtHandlerPath; const universalIdentifier = rawCreateLogicFunctionInput.universalIdentifier ?? v4(); - const checksum = isDefined(rawCreateLogicFunctionInput.checksum) - ? rawCreateLogicFunctionInput.checksum - : rawCreateLogicFunctionInput?.code - ? logicFunctionCreateHash( - JSON.stringify(rawCreateLogicFunctionInput.code), - ) - : null; + const checksum = rawCreateLogicFunctionInput.checksum; return { id, - cronTriggerSettings: null, - databaseEventTriggerSettings: null, - httpRouteTriggerSettings: null, + cronTriggerSettings: + rawCreateLogicFunctionInput.cronTriggerSettings ?? null, + databaseEventTriggerSettings: + rawCreateLogicFunctionInput.databaseEventTriggerSettings ?? null, + httpRouteTriggerSettings: + rawCreateLogicFunctionInput.httpRouteTriggerSettings ?? null, name: rawCreateLogicFunctionInput.name, description: rawCreateLogicFunctionInput.description ?? null, sourceHandlerPath, @@ -68,15 +52,8 @@ export const fromCreateLogicFunctionInputToFlatLogicFunction = ({ runtime: LogicFunctionRuntime.NODE22, timeoutSeconds: rawCreateLogicFunctionInput.timeoutSeconds ?? 300, workspaceId, - code: rawCreateLogicFunctionInput?.code, checksum, - // If no schema provided and no code provided, use default schema - // (because the default template will be used) - toolInputSchema: isDefined(rawCreateLogicFunctionInput?.toolInputSchema) - ? rawCreateLogicFunctionInput.toolInputSchema - : !isDefined(rawCreateLogicFunctionInput?.code) - ? DEFAULT_TOOL_INPUT_SCHEMA - : null, + toolInputSchema: rawCreateLogicFunctionInput.toolInputSchema ?? null, isTool: rawCreateLogicFunctionInput?.isTool ?? false, applicationUniversalIdentifier: ownerFlatApplication.universalIdentifier, }; diff --git a/packages/twenty-server/src/engine/metadata-modules/logic-function/utils/from-update-logic-function-input-to-flat-logic-function-to-update-or-throw.util.ts b/packages/twenty-server/src/engine/metadata-modules/logic-function/utils/from-update-logic-function-input-to-flat-logic-function-to-update-or-throw.util.ts index 155afda5100..02f942292d2 100644 --- a/packages/twenty-server/src/engine/metadata-modules/logic-function/utils/from-update-logic-function-input-to-flat-logic-function-to-update-or-throw.util.ts +++ b/packages/twenty-server/src/engine/metadata-modules/logic-function/utils/from-update-logic-function-input-to-flat-logic-function-to-update-or-throw.util.ts @@ -1,22 +1,17 @@ -import { - extractAndSanitizeObjectStringFields, - isDefined, - trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties, -} from 'twenty-shared/utils'; +import { trimAndRemoveDuplicatedWhitespacesFromObjectStringProperties } from 'twenty-shared/utils'; import { type MetadataFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity-maps.type'; import { FLAT_LOGIC_FUNCTION_EDITABLE_PROPERTIES } from 'src/engine/metadata-modules/logic-function/constants/flat-logic-function-editable-properties.constant'; -import { type UpdateLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/update-logic-function.input'; +import { type UpdateLogicFunctionSourceInput } from 'src/engine/metadata-modules/logic-function/dtos/update-logic-function.input'; import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type'; import { findFlatLogicFunctionOrThrow } from 'src/engine/metadata-modules/logic-function/utils/find-flat-logic-function-or-throw.util'; -import { logicFunctionCreateHash } from 'src/engine/metadata-modules/logic-function/utils/logic-function-create-hash.utils'; import { mergeUpdateInExistingRecord } from 'src/utils/merge-update-in-existing-record.util'; export const fromUpdateLogicFunctionInputToFlatLogicFunctionToUpdateOrThrow = ({ updateLogicFunctionInput: rawUpdateLogicFunctionInput, flatLogicFunctionMaps, }: { - updateLogicFunctionInput: UpdateLogicFunctionInput; + updateLogicFunctionInput: UpdateLogicFunctionSourceInput; flatLogicFunctionMaps: MetadataFlatEntityMaps<'logicFunction'>; }): FlatLogicFunction => { const { id: logicFunctionToUpdateId } = @@ -30,23 +25,9 @@ export const fromUpdateLogicFunctionInputToFlatLogicFunctionToUpdateOrThrow = ({ flatLogicFunctionMaps, }); - const update = rawUpdateLogicFunctionInput.update; - const updatedEditableFieldProperties = { - ...extractAndSanitizeObjectStringFields( - { - ...update, - ...(isDefined(update.code) && { - checksum: logicFunctionCreateHash(JSON.stringify(update.code)), - }), - }, - FLAT_LOGIC_FUNCTION_EDITABLE_PROPERTIES, - ), - ...(isDefined(update.code) && { code: update.code }), - }; - return mergeUpdateInExistingRecord({ existing: existingFlatLogicFunctionToUpdate, properties: FLAT_LOGIC_FUNCTION_EDITABLE_PROPERTIES, - update: updatedEditableFieldProperties, + update: rawUpdateLogicFunctionInput.update, }); }; diff --git a/packages/twenty-server/src/engine/metadata-modules/logic-function/utils/logic-function-create-hash.utils.ts b/packages/twenty-server/src/engine/metadata-modules/logic-function/utils/logic-function-create-hash.utils.ts index 05e4530ffbd..2eef74566df 100644 --- a/packages/twenty-server/src/engine/metadata-modules/logic-function/utils/logic-function-create-hash.utils.ts +++ b/packages/twenty-server/src/engine/metadata-modules/logic-function/utils/logic-function-create-hash.utils.ts @@ -1,5 +1,6 @@ import { createHash } from 'crypto'; +// TODO: migrate to twenty-shared and spread everywhere export const logicFunctionCreateHash = (fileContent: string) => { return createHash('sha512') .update(fileContent) diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/logic-function/services/create-logic-function-action-handler.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/logic-function/services/create-logic-function-action-handler.service.ts index 7786f73a044..c33ab43e157 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/logic-function/services/create-logic-function-action-handler.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/logic-function/services/create-logic-function-action-handler.service.ts @@ -39,24 +39,16 @@ export class CreateLogicFunctionActionHandlerService extends WorkspaceMigrationR const applicationUniversalIdentifier = flatApplication.universalIdentifier; - const [sourceExists, builtExists] = await Promise.all([ - this.fileStorageService.checkFileExists({ - workspaceId, - applicationUniversalIdentifier, - fileFolder: FileFolder.Source, - resourcePath: logicFunction.sourceHandlerPath, - }), - this.fileStorageService.checkFileExists({ - workspaceId, - applicationUniversalIdentifier, - fileFolder: FileFolder.BuiltLogicFunction, - resourcePath: logicFunction.builtHandlerPath, - }), - ]); + const builtExists = await this.fileStorageService.checkFileExists({ + workspaceId, + applicationUniversalIdentifier, + fileFolder: FileFolder.BuiltLogicFunction, + resourcePath: logicFunction.builtHandlerPath, + }); - if (!sourceExists || !builtExists) { + if (!builtExists) { throw new LogicFunctionException( - `Logic function source or built file missing before create (source: ${sourceExists}, built: ${builtExists})`, + 'Logic function built file missing before create', LogicFunctionExceptionCode.LOGIC_FUNCTION_CREATE_FAILED, ); } diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/logic-function/services/update-logic-function-action-handler.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/logic-function/services/update-logic-function-action-handler.service.ts index d57751718e2..4d4dd815103 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/logic-function/services/update-logic-function-action-handler.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/logic-function/services/update-logic-function-action-handler.service.ts @@ -5,7 +5,6 @@ import { FileFolder } from 'twenty-shared/types'; import { WorkspaceMigrationRunnerActionHandler } from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/interfaces/workspace-migration-runner-action-handler-service.interface'; import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service'; -import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/services/logic-function-executor.service'; import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util'; import { LogicFunctionEntity } from 'src/engine/metadata-modules/logic-function/logic-function.entity'; import { @@ -24,10 +23,7 @@ export class UpdateLogicFunctionActionHandlerService extends WorkspaceMigrationR 'update', 'logicFunction', ) { - constructor( - private readonly logicFunctionExecutorService: LogicFunctionExecutorService, - private readonly fileStorageService: FileStorageService, - ) { + constructor(private readonly fileStorageService: FileStorageService) { super(); } @@ -72,24 +68,16 @@ export class UpdateLogicFunctionActionHandlerService extends WorkspaceMigrationR flatLogicFunction: FlatLogicFunction; applicationUniversalIdentifier: string; }): Promise { - const [sourceExists, builtExists] = await Promise.all([ - this.fileStorageService.checkFileExists({ - workspaceId: flatLogicFunction.workspaceId, - applicationUniversalIdentifier, - fileFolder: FileFolder.Source, - resourcePath: flatLogicFunction.sourceHandlerPath, - }), - this.fileStorageService.checkFileExists({ - workspaceId: flatLogicFunction.workspaceId, - applicationUniversalIdentifier, - fileFolder: FileFolder.BuiltLogicFunction, - resourcePath: flatLogicFunction.builtHandlerPath, - }), - ]); + const builtExists = await this.fileStorageService.checkFileExists({ + workspaceId: flatLogicFunction.workspaceId, + applicationUniversalIdentifier, + fileFolder: FileFolder.BuiltLogicFunction, + resourcePath: flatLogicFunction.builtHandlerPath, + }); - if (!sourceExists || !builtExists) { + if (!builtExists) { throw new LogicFunctionException( - `Logic function source or built file missing before update (source: ${sourceExists}, built: ${builtExists})`, + 'Logic function source or built file missing before update', LogicFunctionExceptionCode.LOGIC_FUNCTION_NOT_READY, ); } diff --git a/packages/twenty-server/src/modules/workflow/common/workspace-services/workflow-common.workspace-service.ts b/packages/twenty-server/src/modules/workflow/common/workspace-services/workflow-common.workspace-service.ts index 33e4d620458..7d3d635aa1f 100644 --- a/packages/twenty-server/src/modules/workflow/common/workspace-services/workflow-common.workspace-service.ts +++ b/packages/twenty-server/src/modules/workflow/common/workspace-services/workflow-common.workspace-service.ts @@ -8,7 +8,7 @@ import { type FlatFieldMetadata } from 'src/engine/metadata-modules/flat-field-m import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type'; import { buildObjectIdByNameMaps } from 'src/engine/metadata-modules/flat-object-metadata/utils/build-object-id-by-name-maps.util'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; -import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/services/logic-function.service'; +import { LogicFunctionMetadataService } from 'src/engine/metadata-modules/logic-function/services/logic-function-metadata.service'; import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; import { type WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository'; import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util'; @@ -42,7 +42,7 @@ export type ObjectMetadataInfo = { export class WorkflowCommonWorkspaceService { constructor( private readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager, - private readonly logicFunctionService: LogicFunctionService, + private readonly logicFunctionMetadataService: LogicFunctionMetadataService, private readonly workspaceManyOrAllFlatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, ) {} @@ -322,7 +322,7 @@ export class WorkflowCommonWorkspaceService { for (const workflowVersion of workflowVersions) { for (const step of workflowVersion.steps ?? []) { if (step.type === WorkflowActionType.CODE) { - await this.logicFunctionService.destroyOne({ + await this.logicFunctionMetadataService.destroyOne({ id: step.settings.input.logicFunctionId, workspaceId, }); diff --git a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/__tests__/workflow-version-step-operations.workspace-service.spec.ts b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/__tests__/workflow-version-step-operations.workspace-service.spec.ts index 8bf0aa5e9e7..8c8c6b7115d 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/__tests__/workflow-version-step-operations.workspace-service.spec.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/__tests__/workflow-version-step-operations.workspace-service.spec.ts @@ -1,13 +1,12 @@ import { Test, type TestingModule } from '@nestjs/testing'; import { getRepositoryToken } from '@nestjs/typeorm'; -import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; import { AiAgentRoleService } from 'src/engine/metadata-modules/ai/ai-agent-role/ai-agent-role.service'; import { AgentEntity } from 'src/engine/metadata-modules/ai/ai-agent/entities/agent.entity'; import { createEmptyAllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/constant/create-empty-all-flat-entity-maps.constant'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; import { LogicFunctionRuntime } from 'src/engine/metadata-modules/logic-function/logic-function.entity'; -import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/services/logic-function.service'; +import { LogicFunctionMetadataService } from 'src/engine/metadata-modules/logic-function/services/logic-function-metadata.service'; import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity'; @@ -27,8 +26,7 @@ const mockWorkspaceId = 'workspace-id'; describe('WorkflowVersionStepOperationsWorkspaceService', () => { let service: WorkflowVersionStepOperationsWorkspaceService; let globalWorkspaceOrmManager: jest.Mocked; - let logicFunctionService: jest.Mocked; - let applicationService: jest.Mocked; + let logicFunctionMetadataService: jest.Mocked; let codeStepBuildService: jest.Mocked; let agentRepository: jest.Mocked; let roleTargetRepository: jest.Mocked; @@ -40,22 +38,34 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => { let flatEntityMapsCacheService: jest.Mocked; beforeEach(async () => { - applicationService = { - findWorkspaceTwentyStandardAndCustomApplicationOrThrow: jest - .fn() - .mockResolvedValue({ - workspaceCustomFlatApplication: { - universalIdentifier: 'app-universal-id', - }, - }), - } as unknown as jest.Mocked; - codeStepBuildService = { seedCodeStepFiles: jest.fn().mockResolvedValue({ sourceHandlerPath: 'workflow/logic-fn-id/src/index.ts', builtHandlerPath: 'workflow/logic-fn-id/src/index.mjs', checksum: 'seed-checksum', }), + createCodeStepLogicFunction: jest.fn().mockResolvedValue({ + id: 'new-function-id', + name: 'Test Function', + description: 'Test Description', + workspaceId: mockWorkspaceId, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + deletedAt: null, + runtime: LogicFunctionRuntime.NODE22, + timeoutSeconds: 30, + sourceHandlerPath: 'src/index.ts', + builtHandlerPath: 'index.mjs', + handlerName: 'main', + checksum: null, + toolInputSchema: null, + isTool: false, + universalIdentifier: 'universal-id', + applicationId: 'application-id', + cronTriggerSettings: null, + databaseEventTriggerSettings: null, + httpRouteTriggerSettings: null, + }), copySourceAndBuiltForNewCodeStep: jest.fn().mockResolvedValue(undefined), duplicateCodeStepLogicFunction: jest.fn().mockResolvedValue({ id: 'new-function-id', @@ -81,10 +91,10 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => { }), } as unknown as jest.Mocked; - logicFunctionService = { + logicFunctionMetadataService = { createOne: jest.fn(), destroyOne: jest.fn(), - } as unknown as jest.Mocked; + } as unknown as jest.Mocked; agentRepository = { findOne: jest.fn(), @@ -128,12 +138,8 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => { useValue: globalWorkspaceOrmManager, }, { - provide: LogicFunctionService, - useValue: logicFunctionService, - }, - { - provide: ApplicationService, - useValue: applicationService, + provide: LogicFunctionMetadataService, + useValue: logicFunctionMetadataService, }, { provide: CodeStepBuildService, @@ -207,7 +213,7 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => { workspaceId: mockWorkspaceId, }); - expect(logicFunctionService.destroyOne).toHaveBeenCalledWith({ + expect(logicFunctionMetadataService.destroyOne).toHaveBeenCalledWith({ id: 'function-id', workspaceId: mockWorkspaceId, }); @@ -317,7 +323,9 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => { httpRouteTriggerSettings: null, }; - logicFunctionService.createOne.mockResolvedValue(mockFlatLogicFunction); + logicFunctionMetadataService.createOne.mockResolvedValue( + mockFlatLogicFunction, + ); const result = await service.runStepCreationSideEffectsAndBuildStep({ type: WorkflowActionType.CODE, @@ -430,7 +438,7 @@ describe('WorkflowVersionStepOperationsWorkspaceService', () => { }, ); - logicFunctionService.createOne.mockResolvedValue( + logicFunctionMetadataService.createOne.mockResolvedValue( mockNewFlatLogicFunction, ); diff --git a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/code-step/constants/seed-project/code-step-default-input-schema.ts b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/code-step/constants/seed-project/code-step-default-input-schema.ts deleted file mode 100644 index 43310fc3ae9..00000000000 --- a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/code-step/constants/seed-project/code-step-default-input-schema.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const CODE_STEP_DEFAULT_INPUT_SCHEMA = { - a: null, - b: null, -}; diff --git a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/code-step/constants/seed-project/src/index.mjs b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/code-step/constants/seed-project/src/index.mjs deleted file mode 100644 index bd89c19f6c4..00000000000 --- a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/code-step/constants/seed-project/src/index.mjs +++ /dev/null @@ -1,8 +0,0 @@ -var main = async (params) => { - const { a, b } = params; - const message = `Hello, input: ${a} and ${b}`; - return { message }; -}; -export { - main -}; diff --git a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/code-step/constants/seed-project/src/index.ts b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/code-step/constants/seed-project/src/index.ts deleted file mode 100644 index 7306ee6f771..00000000000 --- a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/code-step/constants/seed-project/src/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -export const main = async (params: { - a: string; - b: number; -}): Promise => { - const { a, b } = params; - - // Rename the parameters and code below with your own logic - // This is just an example - const message = `Hello, input: ${a} and ${b}`; - - return { message }; -}; diff --git a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/code-step/services/code-step-build.service.ts b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/code-step/services/code-step-build.service.ts index 7485f9997c2..7e01db557f3 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/code-step/services/code-step-build.service.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/code-step/services/code-step-build.service.ts @@ -2,12 +2,16 @@ import { Injectable } from '@nestjs/common'; import { isDefined } from 'twenty-shared/utils'; import { v4 } from 'uuid'; +import { + CronTriggerSettings, + DatabaseEventTriggerSettings, + HttpRouteTriggerSettings, +} from 'twenty-shared/application'; import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; -import { LogicFunctionSourceBuilderService } from 'src/engine/core-modules/logic-function/logic-function-source-builder/logic-function-source-builder.service'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util'; -import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/services/logic-function.service'; +import { LogicFunctionMetadataService } from 'src/engine/metadata-modules/logic-function/services/logic-function-metadata.service'; import { type FlatLogicFunction } from 'src/engine/metadata-modules/logic-function/types/flat-logic-function.type'; import { findFlatLogicFunctionOrThrow } from 'src/engine/metadata-modules/logic-function/utils/find-flat-logic-function-or-throw.util'; import { fromCreateLogicFunctionInputToFlatLogicFunction } from 'src/engine/metadata-modules/logic-function/utils/from-create-logic-function-input-to-flat-logic-function.util'; @@ -15,6 +19,9 @@ import { WorkflowActionType, type WorkflowAction, } from 'src/modules/workflow/workflow-executor/workflow-actions/types/workflow-action.type'; +import { LogicFunctionResourceService } from 'src/engine/core-modules/logic-function/logic-function-resource/logic-function-resource.service'; +import { SEED_LOGIC_FUNCTION_INPUT_SCHEMA } from 'src/engine/core-modules/logic-function/logic-function-resource/constants/seed-logic-function-input-schema'; +import type { JsonbProperty } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/jsonb-property.type'; const WORKFLOW_BASE_FOLDER_PREFIX = 'workflow'; @@ -22,11 +29,52 @@ const WORKFLOW_BASE_FOLDER_PREFIX = 'workflow'; export class CodeStepBuildService { constructor( private readonly workspaceManyOrAllFlatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService, - private readonly logicFunctionService: LogicFunctionService, + private readonly logicFunctionMetadataService: LogicFunctionMetadataService, private readonly applicationService: ApplicationService, - private readonly logicFunctionSourceBuilderService: LogicFunctionSourceBuilderService, + private readonly logicFunctionResourceService: LogicFunctionResourceService, ) {} + private getSourceSubfolderForCodeStep(logicFunctionId: string) { + return `${WORKFLOW_BASE_FOLDER_PREFIX}/${logicFunctionId}`; + } + + async createCodeStepLogicFunction({ + logicFunctionId, + workspaceId, + }: { + logicFunctionId: string; + workspaceId: string; + }) { + const { workspaceCustomFlatApplication } = + await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow( + { + workspaceId, + }, + ); + const { sourceHandlerPath, builtHandlerPath, handlerName, checksum } = + await this.logicFunctionResourceService.seedSourceFiles({ + sourceSubfolder: this.getSourceSubfolderForCodeStep(logicFunctionId), + workspaceId, + applicationUniversalIdentifier: + workspaceCustomFlatApplication.universalIdentifier, + }); + + return await this.logicFunctionMetadataService.createOne({ + input: { + id: logicFunctionId, + name: 'A Logic Function Code Workflow Step', + description: '', + sourceHandlerPath, + builtHandlerPath, + handlerName, + checksum, + toolInputSchema: SEED_LOGIC_FUNCTION_INPUT_SCHEMA, + }, + workspaceId, + ownerFlatApplication: workspaceCustomFlatApplication, + }); + } + async duplicateCodeStepLogicFunction({ existingLogicFunctionId, workspaceId, @@ -57,36 +105,74 @@ export class CodeStepBuildService { resolvedOwnerFlatApplication.universalIdentifier; const newId = v4(); + + const newUniversalIdentifier = v4(); + + const { sourceHandlerPath, builtHandlerPath } = existingLogicFunction; + + const toSourceHandlerPath = sourceHandlerPath.replace( + existingLogicFunction.id, + newId, + ); + + const toBuiltHandlerPath = builtHandlerPath.replace( + existingLogicFunction.id, + newId, + ); + + await this.logicFunctionResourceService.copyResources({ + fromSourceHandlerPath: sourceHandlerPath, + fromBuiltHandlerPath: builtHandlerPath, + toSourceHandlerPath, + toBuiltHandlerPath, + workspaceId, + applicationUniversalIdentifier, + }); + const newFlatLogicFunction = fromCreateLogicFunctionInputToFlatLogicFunction({ createLogicFunctionInput: { - name: existingLogicFunction.name, - description: existingLogicFunction.description ?? undefined, - timeoutSeconds: existingLogicFunction.timeoutSeconds, + ...existingLogicFunction, id: newId, + universalIdentifier: newUniversalIdentifier, + description: existingLogicFunction.description ?? undefined, + builtHandlerPath: toBuiltHandlerPath, + sourceHandlerPath: toSourceHandlerPath, + toolInputSchema: existingLogicFunction.toolInputSchema ?? {}, + checksum: existingLogicFunction.checksum ?? '[default-checksum]', // TODO: checksum should never be null, update column in logicFunction entity to set it non nullable + cronTriggerSettings: existingLogicFunction.cronTriggerSettings as + | JsonbProperty + | undefined, + databaseEventTriggerSettings: + existingLogicFunction.databaseEventTriggerSettings as + | JsonbProperty + | undefined, + httpRouteTriggerSettings: + existingLogicFunction.httpRouteTriggerSettings as + | JsonbProperty + | undefined, }, workspaceId, ownerFlatApplication: resolvedOwnerFlatApplication, }); - await this.logicFunctionSourceBuilderService.copySourceAndBuilt({ - fromSourceHandlerPath: existingLogicFunction.sourceHandlerPath, - fromBuiltHandlerPath: existingLogicFunction.builtHandlerPath, - toSourceHandlerPath: newFlatLogicFunction.sourceHandlerPath, - toBuiltHandlerPath: newFlatLogicFunction.builtHandlerPath, - workspaceId, - applicationUniversalIdentifier, - }); - - const created = await this.logicFunctionService.createOne({ + const created = await this.logicFunctionMetadataService.createOne({ input: { - name: existingLogicFunction.name, - description: existingLogicFunction.description ?? undefined, - timeoutSeconds: existingLogicFunction.timeoutSeconds, - id: newFlatLogicFunction.id, - sourceHandlerPath: newFlatLogicFunction.sourceHandlerPath, - builtHandlerPath: newFlatLogicFunction.builtHandlerPath, - checksum: existingLogicFunction.checksum ?? undefined, + ...newFlatLogicFunction, + description: newFlatLogicFunction.description ?? undefined, + checksum: newFlatLogicFunction.checksum ?? '[default-checksum]', + toolInputSchema: newFlatLogicFunction.toolInputSchema ?? {}, + cronTriggerSettings: newFlatLogicFunction.cronTriggerSettings as + | JsonbProperty + | undefined, + databaseEventTriggerSettings: + newFlatLogicFunction.databaseEventTriggerSettings as + | JsonbProperty + | undefined, + httpRouteTriggerSettings: + newFlatLogicFunction.httpRouteTriggerSettings as + | JsonbProperty + | undefined, }, workspaceId, ownerFlatApplication: resolvedOwnerFlatApplication, @@ -161,14 +247,14 @@ export class CodeStepBuildService { } const { checksum } = - await this.logicFunctionSourceBuilderService.buildFromSource({ + await this.logicFunctionResourceService.buildFromSource({ sourceHandlerPath: flatLogicFunction.sourceHandlerPath, builtHandlerPath: flatLogicFunction.builtHandlerPath, workspaceId, applicationUniversalIdentifier, }); - await this.logicFunctionService.updateChecksum({ + await this.logicFunctionMetadataService.updateChecksum({ id: flatLogicFunction.id, checksum, workspaceId, diff --git a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/workflow-version-step-operations.workspace-service.ts b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/workflow-version-step-operations.workspace-service.ts index 1a813c36584..4b6929382f1 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/workflow-version-step-operations.workspace-service.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/workflow-version-step-operations.workspace-service.ts @@ -15,20 +15,18 @@ import { Repository } from 'typeorm'; import { v4 } from 'uuid'; import { getFlatFieldsFromFlatObjectMetadata } from 'src/engine/api/graphql/workspace-schema-builder/utils/get-flat-fields-for-flat-object-metadata.util'; -import { ApplicationService } from 'src/engine/core-modules/application/services/application.service'; import { type WorkflowStepPositionInput } from 'src/engine/core-modules/workflow/dtos/update-workflow-step-position-input.dto'; import { AiAgentRoleService } from 'src/engine/metadata-modules/ai/ai-agent-role/ai-agent-role.service'; import { AgentEntity } from 'src/engine/metadata-modules/ai/ai-agent/entities/agent.entity'; import { DEFAULT_SMART_MODEL } from 'src/engine/metadata-modules/ai/ai-models/constants/ai-models.const'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; -import { LogicFunctionService } from 'src/engine/metadata-modules/logic-function/services/logic-function.service'; +import { LogicFunctionMetadataService } from 'src/engine/metadata-modules/logic-function/services/logic-function-metadata.service'; import { findFlatLogicFunctionOrThrow } from 'src/engine/metadata-modules/logic-function/utils/find-flat-logic-function-or-throw.util'; import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; import { RoleTargetEntity } from 'src/engine/metadata-modules/role-target/role-target.entity'; import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager'; import { buildSystemAuthContext } from 'src/engine/twenty-orm/utils/build-system-auth-context.util'; import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service'; -import { CODE_STEP_DEFAULT_INPUT_SCHEMA } from 'src/modules/workflow/workflow-builder/workflow-version-step/code-step/constants/seed-project/code-step-default-input-schema'; import { CodeStepBuildService } from 'src/modules/workflow/workflow-builder/workflow-version-step/code-step/services/code-step-build.service'; import { WorkflowVersionStepException, @@ -66,8 +64,7 @@ const ITERATOR_EMPTY_STEP_POSITION_OFFSET = { export class WorkflowVersionStepOperationsWorkspaceService { constructor( private readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager, - private readonly logicFunctionService: LogicFunctionService, - private readonly applicationService: ApplicationService, + private readonly logicFunctionMetadataService: LogicFunctionMetadataService, private readonly codeStepBuildService: CodeStepBuildService, @InjectRepository(AgentEntity) private readonly agentRepository: Repository, @@ -90,7 +87,7 @@ export class WorkflowVersionStepOperationsWorkspaceService { }) { switch (step.type) { case WorkflowActionType.CODE: { - await this.logicFunctionService.destroyOne({ + await this.logicFunctionMetadataService.destroyOne({ id: step.settings.input.logicFunctionId, workspaceId, }); @@ -157,15 +154,11 @@ export class WorkflowVersionStepOperationsWorkspaceService { case WorkflowActionType.CODE: { const logicFunctionId = id ?? v4(); - // createOne handles seeding source files with default seed project - const newLogicFunction = await this.logicFunctionService.createOne({ - input: { - id: logicFunctionId, - name: 'A Logic Function Code Workflow Step', - description: '', - }, - workspaceId, - }); + const newLogicFunction = + await this.codeStepBuildService.createCodeStepLogicFunction({ + logicFunctionId, + workspaceId, + }); if (!isDefined(newLogicFunction)) { throw new WorkflowVersionStepException( @@ -192,7 +185,7 @@ export class WorkflowVersionStepOperationsWorkspaceService { }, input: { logicFunctionId: newLogicFunction.id, - logicFunctionInput: CODE_STEP_DEFAULT_INPUT_SCHEMA, + logicFunctionInput: newLogicFunction.toolInputSchema ?? {}, }, }, }, diff --git a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/workflow-version-step.module.ts b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/workflow-version-step.module.ts index 62f81c3b4d1..45c72050c37 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/workflow-version-step.module.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-builder/workflow-version-step/workflow-version-step.module.ts @@ -2,7 +2,6 @@ import { Module } from '@nestjs/common'; import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm'; -import { ApplicationModule } from 'src/engine/core-modules/application/application.module'; import { AiAgentRoleModule } from 'src/engine/metadata-modules/ai/ai-agent-role/ai-agent-role.module'; import { AgentEntity } from 'src/engine/metadata-modules/ai/ai-agent/entities/agent.entity'; import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module'; @@ -26,7 +25,6 @@ import { WorkflowVersionStepWorkspaceService } from 'src/modules/workflow/workfl WorkflowSchemaModule, LogicFunctionModule, WorkflowCommonModule, - ApplicationModule, CodeStepBuildModule, AiAgentRoleModule, WorkspaceCacheModule, diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/code-action.module.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/code-action.module.ts index 95b1147705b..c030c4a54ce 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/code-action.module.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/code-action.module.ts @@ -1,10 +1,10 @@ import { Module } from '@nestjs/common'; -import { LogicFunctionExecutorModule } from 'src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.module'; +import { LogicFunctionModule } from 'src/engine/core-modules/logic-function/logic-function.module'; import { CodeWorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/code/code.workflow-action'; @Module({ - imports: [LogicFunctionExecutorModule], + imports: [LogicFunctionModule], providers: [CodeWorkflowAction], exports: [CodeWorkflowAction], }) diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/code.workflow-action.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/code.workflow-action.ts index 9456c133b23..c1d8bf39077 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/code.workflow-action.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/code/code.workflow-action.ts @@ -4,7 +4,6 @@ import { resolveInput } from 'twenty-shared/utils'; import { type WorkflowAction } from 'src/modules/workflow/workflow-executor/interfaces/workflow-action.interface'; -import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/services/logic-function-executor.service'; import { WorkflowStepExecutorException, WorkflowStepExecutorExceptionCode, @@ -14,6 +13,7 @@ import { type WorkflowActionOutput } from 'src/modules/workflow/workflow-executo import { findStepOrThrow } from 'src/modules/workflow/workflow-executor/utils/find-step-or-throw.util'; import { isWorkflowCodeAction } from 'src/modules/workflow/workflow-executor/workflow-actions/code/guards/is-workflow-code-action.guard'; import { type WorkflowCodeActionInput } from 'src/modules/workflow/workflow-executor/workflow-actions/code/types/workflow-code-action-input.type'; +import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.service'; @Injectable() export class CodeWorkflowAction implements WorkflowAction { @@ -47,12 +47,11 @@ export class CodeWorkflowAction implements WorkflowAction { try { const { workspaceId } = runInfo; - const result = - await this.logicFunctionExecutorService.executeOneLogicFunction({ - id: workflowActionInput.logicFunctionId, - workspaceId, - payload: workflowActionInput.logicFunctionInput, - }); + const result = await this.logicFunctionExecutorService.execute({ + logicFunctionId: workflowActionInput.logicFunctionId, + workspaceId, + payload: workflowActionInput.logicFunctionInput, + }); if (result.error) { return { error: result.error.errorMessage }; diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/logic-function/logic-function-action.module.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/logic-function/logic-function-action.module.ts index 973416b27bd..38cdf996d31 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/logic-function/logic-function-action.module.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/logic-function/logic-function-action.module.ts @@ -1,14 +1,10 @@ import { Module } from '@nestjs/common'; -import { LogicFunctionExecutorModule } from 'src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.module'; import { WorkspaceManyOrAllFlatEntityMapsCacheModule } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module'; import { LogicFunctionWorkflowAction } from 'src/modules/workflow/workflow-executor/workflow-actions/logic-function/logic-function.workflow-action'; @Module({ - imports: [ - LogicFunctionExecutorModule, - WorkspaceManyOrAllFlatEntityMapsCacheModule, - ], + imports: [WorkspaceManyOrAllFlatEntityMapsCacheModule], providers: [LogicFunctionWorkflowAction], exports: [LogicFunctionWorkflowAction], }) diff --git a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/logic-function/logic-function.workflow-action.ts b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/logic-function/logic-function.workflow-action.ts index aaa5ac3cf4b..91b7a7c0501 100644 --- a/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/logic-function/logic-function.workflow-action.ts +++ b/packages/twenty-server/src/modules/workflow/workflow-executor/workflow-actions/logic-function/logic-function.workflow-action.ts @@ -4,7 +4,6 @@ import { resolveInput } from 'twenty-shared/utils'; import { type WorkflowAction } from 'src/modules/workflow/workflow-executor/interfaces/workflow-action.interface'; -import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/services/logic-function-executor.service'; import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util'; import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service'; import { @@ -16,6 +15,7 @@ import { type WorkflowActionOutput } from 'src/modules/workflow/workflow-executo import { findStepOrThrow } from 'src/modules/workflow/workflow-executor/utils/find-step-or-throw.util'; import { isWorkflowLogicFunctionAction } from 'src/modules/workflow/workflow-executor/workflow-actions/logic-function/guards/is-workflow-logic-function-action.guard'; import { WorkflowLogicFunctionActionInput } from 'src/modules/workflow/workflow-executor/workflow-actions/logic-function/types/workflow-logic-function-action-input.type'; +import { LogicFunctionExecutorService } from 'src/engine/core-modules/logic-function/logic-function-executor/logic-function-executor.service'; @Injectable() export class LogicFunctionWorkflowAction implements WorkflowAction { @@ -70,12 +70,11 @@ export class LogicFunctionWorkflowAction implements WorkflowAction { ); } - const result = - await this.logicFunctionExecutorService.executeOneLogicFunction({ - id: workflowActionInput.logicFunctionId, - workspaceId, - payload: workflowActionInput.logicFunctionInput, - }); + const result = await this.logicFunctionExecutorService.execute({ + logicFunctionId: workflowActionInput.logicFunctionId, + workspaceId, + payload: workflowActionInput.logicFunctionInput, + }); if (result.error) { return { error: result.error.errorMessage }; diff --git a/packages/twenty-server/test/integration/graphql/suites/workspace/successful-user-and-workspace-creation.integration-spec.ts b/packages/twenty-server/test/integration/graphql/suites/workspace/successful-user-and-workspace-creation.integration-spec.ts index 4bf205359e8..76445e61c9c 100644 --- a/packages/twenty-server/test/integration/graphql/suites/workspace/successful-user-and-workspace-creation.integration-spec.ts +++ b/packages/twenty-server/test/integration/graphql/suites/workspace/successful-user-and-workspace-creation.integration-spec.ts @@ -7,7 +7,7 @@ import { getAuthTokensFromLoginToken } from 'test/integration/graphql/utils/get- import { getCurrentUser } from 'test/integration/graphql/utils/get-current-user.util'; import { signUpInNewWorkspace } from 'test/integration/graphql/utils/sign-up-in-new-workspace.util'; import { signUp } from 'test/integration/graphql/utils/sign-up.util'; -import { createOneLogicFunction } from 'test/integration/metadata/suites/logic-function/utils/create-one-logic-function.util'; +import { createDefaultLogicFunction } from 'test/integration/metadata/suites/logic-function/utils/create-default-logic-function.util'; import { createOneObjectMetadata } from 'test/integration/metadata/suites/object-metadata/utils/create-one-object-metadata.util'; import { jestExpectToBeDefined } from 'test/utils/jest-expect-to-be-defined.util.test'; import { isDefined } from 'twenty-shared/utils'; @@ -190,13 +190,10 @@ describe('Successful user and workspace creation', () => { }); // Create a logic function for workspace deletion test - await createOneLogicFunction({ + await createDefaultLogicFunction({ input: { name: 'test-function-for-deletion', description: 'A test logic function for workspace deletion test', - code: { - 'src/index.ts': 'export const main = async () => { return {}; };', - }, }, token: newWorkspaceAccessToken, expectToFail: false, diff --git a/packages/twenty-server/test/integration/metadata/suites/logic-function/logic-function-execution.integration-spec.ts b/packages/twenty-server/test/integration/metadata/suites/logic-function/logic-function-execution.integration-spec.ts index 4d6618b2fc9..fa3f0c95250 100644 --- a/packages/twenty-server/test/integration/metadata/suites/logic-function/logic-function-execution.integration-spec.ts +++ b/packages/twenty-server/test/integration/metadata/suites/logic-function/logic-function-execution.integration-spec.ts @@ -1,6 +1,7 @@ -import { createOneLogicFunction } from 'test/integration/metadata/suites/logic-function/utils/create-one-logic-function.util'; +import { createDefaultLogicFunction } from 'test/integration/metadata/suites/logic-function/utils/create-default-logic-function.util'; import { deleteLogicFunction } from 'test/integration/metadata/suites/logic-function/utils/delete-logic-function.util'; import { executeLogicFunction } from 'test/integration/metadata/suites/logic-function/utils/execute-logic-function.util'; +import { updateLogicFunctionSource } from 'test/integration/metadata/suites/logic-function/utils/update-logic-function-source.util'; import { LogicFunctionExecutionStatus } from 'src/engine/metadata-modules/logic-function/dtos/logic-function-execution-result.dto'; @@ -53,24 +54,32 @@ describe('Logic Function Execution', () => { it('should execute the default logic function template', async () => { // Create the function with default template code - const { data: createData } = await createOneLogicFunction({ + const { data: createData } = await createDefaultLogicFunction({ input: { name: 'Test Default Function', - code: DEFAULT_TEMPLATE_FUNCTION_CODE, }, expectToFail: false, }); - const functionId = createData?.createOneLogicFunction?.id; + const functionId = createData?.createDefaultLogicFunction?.id; expect(functionId).toBeDefined(); createdFunctionIds.push(functionId); + await updateLogicFunctionSource({ + input: { + id: createData.createDefaultLogicFunction.id, + code: DEFAULT_TEMPLATE_FUNCTION_CODE, + }, + expectToFail: false, + }); + // Execute with the default template's expected params: { a: string, b: number } const { data: executeData } = await executeLogicFunction({ input: { id: functionId, payload: { a: 'hello', b: 42 }, + forceRebuild: true, }, expectToFail: false, }); @@ -90,19 +99,26 @@ describe('Logic Function Execution', () => { it('should execute a function with external packages (lodash.groupby)', async () => { // Create the function with the external packages code - const { data: createData } = await createOneLogicFunction({ + const { data: createData } = await createDefaultLogicFunction({ input: { name: 'External Packages Test', - code: EXTERNAL_PACKAGES_FUNCTION_CODE, }, expectToFail: false, }); - const functionId = createData?.createOneLogicFunction?.id; + const functionId = createData?.createDefaultLogicFunction?.id; expect(functionId).toBeDefined(); createdFunctionIds.push(functionId); + await updateLogicFunctionSource({ + input: { + id: createData.createDefaultLogicFunction.id, + code: EXTERNAL_PACKAGES_FUNCTION_CODE, + }, + expectToFail: false, + }); + // Execute the function with items to group const { data: executeData } = await executeLogicFunction({ input: { @@ -114,6 +130,7 @@ describe('Logic Function Execution', () => { { category: 'fruit', name: 'banana' }, ], }, + forceRebuild: true, }, expectToFail: false, }); @@ -145,24 +162,32 @@ describe('Logic Function Execution', () => { it('should handle errors thrown by logic functions', async () => { // Create the function with error-throwing code - const { data: createData } = await createOneLogicFunction({ + const { data: createData } = await createDefaultLogicFunction({ input: { name: 'Error Test Function', - code: ERROR_FUNCTION_CODE, }, expectToFail: false, }); - const functionId = createData?.createOneLogicFunction?.id; + const functionId = createData?.createDefaultLogicFunction?.id; expect(functionId).toBeDefined(); createdFunctionIds.push(functionId); + await updateLogicFunctionSource({ + input: { + id: createData.createDefaultLogicFunction.id, + code: ERROR_FUNCTION_CODE, + }, + expectToFail: false, + }); + // Execute with shouldFail = false (should succeed) const { data: successData } = await executeLogicFunction({ input: { id: functionId, payload: { shouldFail: false }, + forceRebuild: true, }, expectToFail: false, }); @@ -179,6 +204,7 @@ describe('Logic Function Execution', () => { input: { id: functionId, payload: { shouldFail: true }, + forceRebuild: true, }, expectToFail: false, // The GraphQL call succeeds, but the function execution fails }); diff --git a/packages/twenty-server/test/integration/metadata/suites/logic-function/utils/create-default-logic-function-query-factory.util.ts b/packages/twenty-server/test/integration/metadata/suites/logic-function/utils/create-default-logic-function-query-factory.util.ts new file mode 100644 index 00000000000..5f46171b1c9 --- /dev/null +++ b/packages/twenty-server/test/integration/metadata/suites/logic-function/utils/create-default-logic-function-query-factory.util.ts @@ -0,0 +1,32 @@ +import gql from 'graphql-tag'; +import { type PerformMetadataQueryParams } from 'test/integration/metadata/types/perform-metadata-query.type'; + +import { type CreateDefaultLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/create-default-logic-function.input'; + +export type CreateDefaultLogicFunctionFactoryInput = + CreateDefaultLogicFunctionInput; + +const DEFAULT_LOGIC_FUNCTION_GQL_FIELDS = ` + id + name + description + runtime + createdAt + updatedAt +`; + +export const createDefaultLogicFunctionQueryFactory = ({ + input, + gqlFields = DEFAULT_LOGIC_FUNCTION_GQL_FIELDS, +}: PerformMetadataQueryParams) => ({ + query: gql` + mutation CreateDefaultOneLogicFunction($input: CreateDefaultLogicFunctionInput!) { + createDefaultLogicFunction(input: $input) { + ${gqlFields} + } + } + `, + variables: { + input, + }, +}); diff --git a/packages/twenty-server/test/integration/metadata/suites/logic-function/utils/create-one-logic-function.util.ts b/packages/twenty-server/test/integration/metadata/suites/logic-function/utils/create-default-logic-function.util.ts similarity index 77% rename from packages/twenty-server/test/integration/metadata/suites/logic-function/utils/create-one-logic-function.util.ts rename to packages/twenty-server/test/integration/metadata/suites/logic-function/utils/create-default-logic-function.util.ts index e3432cd2eb1..a395fc5fa56 100644 --- a/packages/twenty-server/test/integration/metadata/suites/logic-function/utils/create-one-logic-function.util.ts +++ b/packages/twenty-server/test/integration/metadata/suites/logic-function/utils/create-default-logic-function.util.ts @@ -1,7 +1,7 @@ import { - type CreateOneLogicFunctionFactoryInput, - createOneLogicFunctionQueryFactory, -} from 'test/integration/metadata/suites/logic-function/utils/create-one-logic-function-query-factory.util'; + type CreateDefaultLogicFunctionFactoryInput, + createDefaultLogicFunctionQueryFactory, +} from 'test/integration/metadata/suites/logic-function/utils/create-default-logic-function-query-factory.util'; import { makeMetadataAPIRequest } from 'test/integration/metadata/suites/utils/make-metadata-api-request.util'; import { type CommonResponseBody } from 'test/integration/metadata/types/common-response-body.type'; import { type PerformMetadataQueryParams } from 'test/integration/metadata/types/perform-metadata-query.type'; @@ -10,15 +10,15 @@ import { warnIfNoErrorButExpectedToFail } from 'test/integration/metadata/utils/ import { type LogicFunctionDTO } from 'src/engine/metadata-modules/logic-function/dtos/logic-function.dto'; -export const createOneLogicFunction = async ({ +export const createDefaultLogicFunction = async ({ input, gqlFields, expectToFail = false, token, -}: PerformMetadataQueryParams): CommonResponseBody<{ - createOneLogicFunction: LogicFunctionDTO; +}: PerformMetadataQueryParams): CommonResponseBody<{ + createDefaultLogicFunction: LogicFunctionDTO; }> => { - const graphqlOperation = createOneLogicFunctionQueryFactory({ + const graphqlOperation = createDefaultLogicFunctionQueryFactory({ input, gqlFields, }); diff --git a/packages/twenty-server/test/integration/metadata/suites/logic-function/utils/create-one-logic-function-query-factory.util.ts b/packages/twenty-server/test/integration/metadata/suites/logic-function/utils/create-one-logic-function-query-factory.util.ts deleted file mode 100644 index ce9eb180629..00000000000 --- a/packages/twenty-server/test/integration/metadata/suites/logic-function/utils/create-one-logic-function-query-factory.util.ts +++ /dev/null @@ -1,31 +0,0 @@ -import gql from 'graphql-tag'; -import { type PerformMetadataQueryParams } from 'test/integration/metadata/types/perform-metadata-query.type'; - -import { type CreateLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/create-logic-function.input'; - -export type CreateOneLogicFunctionFactoryInput = CreateLogicFunctionInput; - -const DEFAULT_LOGIC_FUNCTION_GQL_FIELDS = ` - id - name - description - runtime - createdAt - updatedAt -`; - -export const createOneLogicFunctionQueryFactory = ({ - input, - gqlFields = DEFAULT_LOGIC_FUNCTION_GQL_FIELDS, -}: PerformMetadataQueryParams) => ({ - query: gql` - mutation CreateOneLogicFunction($input: CreateLogicFunctionInput!) { - createOneLogicFunction(input: $input) { - ${gqlFields} - } - } - `, - variables: { - input, - }, -}); diff --git a/packages/twenty-server/test/integration/metadata/suites/logic-function/utils/execute-logic-function-query-factory.util.ts b/packages/twenty-server/test/integration/metadata/suites/logic-function/utils/execute-logic-function-query-factory.util.ts index c3e257040f7..998571ff7fa 100644 --- a/packages/twenty-server/test/integration/metadata/suites/logic-function/utils/execute-logic-function-query-factory.util.ts +++ b/packages/twenty-server/test/integration/metadata/suites/logic-function/utils/execute-logic-function-query-factory.util.ts @@ -1,7 +1,11 @@ import gql from 'graphql-tag'; -export type ExecuteLogicFunctionFactoryInput = { - id: string; +import { type ExecuteOneLogicFunctionInput } from 'src/engine/metadata-modules/logic-function/dtos/execute-logic-function.input'; + +export type ExecuteLogicFunctionFactoryInput = Omit< + ExecuteOneLogicFunctionInput, + 'payload' +> & { payload: Record; }; diff --git a/packages/twenty-server/test/integration/metadata/suites/logic-function/utils/update-logic-function-source-query-factory.util.ts b/packages/twenty-server/test/integration/metadata/suites/logic-function/utils/update-logic-function-source-query-factory.util.ts new file mode 100644 index 00000000000..b7a62437d5e --- /dev/null +++ b/packages/twenty-server/test/integration/metadata/suites/logic-function/utils/update-logic-function-source-query-factory.util.ts @@ -0,0 +1,22 @@ +import gql from 'graphql-tag'; +import { type PerformMetadataQueryParams } from 'test/integration/metadata/types/perform-metadata-query.type'; + +import { type UpdateLogicFunctionSourceInput } from 'src/engine/metadata-modules/logic-function/dtos/update-logic-function-source.input'; + +export type UpdateLogicFunctionSourceFactoryInput = + UpdateLogicFunctionSourceInput; + +export const updateLogicFunctionSourceQueryFactory = ({ + input, +}: PerformMetadataQueryParams) => ({ + query: gql` + mutation UpdateLogicFunctionSource( + $input: UpdateLogicFunctionSourceInput! + ) { + updateLogicFunctionSource(input: $input) + } + `, + variables: { + input, + }, +}); diff --git a/packages/twenty-server/test/integration/metadata/suites/logic-function/utils/update-logic-function-source.util.ts b/packages/twenty-server/test/integration/metadata/suites/logic-function/utils/update-logic-function-source.util.ts new file mode 100644 index 00000000000..737d835d334 --- /dev/null +++ b/packages/twenty-server/test/integration/metadata/suites/logic-function/utils/update-logic-function-source.util.ts @@ -0,0 +1,43 @@ +import { makeMetadataAPIRequest } from 'test/integration/metadata/suites/utils/make-metadata-api-request.util'; +import { type CommonResponseBody } from 'test/integration/metadata/types/common-response-body.type'; +import { type PerformMetadataQueryParams } from 'test/integration/metadata/types/perform-metadata-query.type'; +import { warnIfErrorButNotExpectedToFail } from 'test/integration/metadata/utils/warn-if-error-but-not-expected-to-fail.util'; +import { warnIfNoErrorButExpectedToFail } from 'test/integration/metadata/utils/warn-if-no-error-but-expected-to-fail.util'; +import { + type UpdateLogicFunctionSourceFactoryInput, + updateLogicFunctionSourceQueryFactory, +} from 'test/integration/metadata/suites/logic-function/utils/update-logic-function-source-query-factory.util'; + +import { type LogicFunctionDTO } from 'src/engine/metadata-modules/logic-function/dtos/logic-function.dto'; + +export const updateLogicFunctionSource = async ({ + input, + gqlFields, + expectToFail = false, + token, +}: PerformMetadataQueryParams): CommonResponseBody<{ + updateOneLogicFunction: LogicFunctionDTO; +}> => { + const graphqlOperation = updateLogicFunctionSourceQueryFactory({ + input, + gqlFields, + }); + + const response = await makeMetadataAPIRequest(graphqlOperation, token); + + if (expectToFail === true) { + warnIfNoErrorButExpectedToFail({ + response, + errorMessage: 'Logic Function creation should have failed but did not', + }); + } + + if (expectToFail === false) { + warnIfErrorButNotExpectedToFail({ + response, + errorMessage: 'Logic Function creation has failed but should not', + }); + } + + return { data: response.body.data, errors: response.body.errors }; +}; diff --git a/packages/twenty-shared/src/application/applicationType.ts b/packages/twenty-shared/src/application/applicationType.ts index 42497b7b305..125f9105bfa 100644 --- a/packages/twenty-shared/src/application/applicationType.ts +++ b/packages/twenty-shared/src/application/applicationType.ts @@ -15,7 +15,7 @@ export type ApplicationMarketplaceData = { export type ApplicationManifest = SyncableEntityOptions & { defaultRoleUniversalIdentifier: string; displayName: string; - description?: string; + description: string; icon?: string; applicationVariables?: ApplicationVariables; marketplaceData?: ApplicationMarketplaceData; diff --git a/packages/twenty-shared/src/application/constants/NodeEsmCjsBanner.ts b/packages/twenty-shared/src/application/constants/NodeEsmCjsBanner.ts new file mode 100644 index 00000000000..5a8b4e0887e --- /dev/null +++ b/packages/twenty-shared/src/application/constants/NodeEsmCjsBanner.ts @@ -0,0 +1,3 @@ +export const NODE_ESM_CJS_BANNER = { + js: "import { createRequire as __createRequire } from 'module';\nconst require = __createRequire(import.meta.url);", +}; diff --git a/packages/twenty-shared/src/application/index.ts b/packages/twenty-shared/src/application/index.ts index 4358e344e83..5e41cdb3da6 100644 --- a/packages/twenty-shared/src/application/index.ts +++ b/packages/twenty-shared/src/application/index.ts @@ -17,6 +17,7 @@ export { ASSETS_DIR } from './constants/AssetDirectory'; export { DEFAULT_API_KEY_NAME } from './constants/DefaultApiKeyName'; export { DEFAULT_API_URL_NAME } from './constants/DefaultApiUrlName'; export { GENERATED_DIR } from './constants/GeneratedDirectory'; +export { NODE_ESM_CJS_BANNER } from './constants/NodeEsmCjsBanner'; export { OUTPUT_DIR } from './constants/OutputDirectory'; export { SyncableEntity } from './enums/syncable-entities.enum'; export type { @@ -28,10 +29,9 @@ export type { FrontComponentManifest } from './frontComponentManifestType'; export type { InputJsonSchema, LogicFunctionManifest, - DatabaseEventTrigger, - CronTrigger, - RouteTrigger, - LogicFunctionTriggerManifest, + CronTriggerSettings, + DatabaseEventTriggerSettings, + HttpRouteTriggerSettings, } from './logicFunctionManifestType'; export type { Manifest } from './manifestType'; export type { ObjectFieldManifest } from './objectFieldManifest.type'; diff --git a/packages/twenty-shared/src/application/logicFunctionManifestType.ts b/packages/twenty-shared/src/application/logicFunctionManifestType.ts index 6acc47b87fe..0634e518fc4 100644 --- a/packages/twenty-shared/src/application/logicFunctionManifestType.ts +++ b/packages/twenty-shared/src/application/logicFunctionManifestType.ts @@ -23,33 +23,29 @@ export type LogicFunctionManifest = SyncableEntityOptions & { name?: string; description?: string; timeoutSeconds?: number; - triggers: LogicFunctionTriggerManifest[]; + cronTriggerSettings?: CronTriggerSettings; + databaseEventTriggerSettings?: DatabaseEventTriggerSettings; + httpRouteTriggerSettings?: HttpRouteTriggerSettings; sourceHandlerPath: string; builtHandlerPath: string; - builtHandlerChecksum: string | null; + builtHandlerChecksum: string; handlerName: string; toolInputSchema?: InputJsonSchema; isTool?: boolean; }; -export type DatabaseEventTrigger = { - type: 'databaseEvent'; +export type CronTriggerSettings = { + pattern: string; +}; + +export type DatabaseEventTriggerSettings = { eventName: string; updatedFields?: string[]; }; -export type CronTrigger = { - type: 'cron'; - pattern: string; -}; - -export type RouteTrigger = { - type: 'route'; +export type HttpRouteTriggerSettings = { path: string; - httpMethod: `${HTTPMethod}`; + httpMethod: HTTPMethod | `${HTTPMethod}`; isAuthRequired: boolean; forwardedRequestHeaders?: string[]; }; - -export type LogicFunctionTriggerManifest = SyncableEntityOptions & - (CronTrigger | DatabaseEventTrigger | RouteTrigger);