b5a1aed24b
## Summary Implements the server-level logic-function tier in the simplest shape: a logic function is "server-exposed" iff its manifest entry carries `serverWebhookTriggerSettings`. Execution delegates to the owner-workspace copy of that function — billing, throttling, env vars, and the existing executor all apply uniformly against that workspace. Supersedes #21971 with the simplified design from that discussion (no `applicationRegistrationLogicFunction` registry, no dedicated manifest type, no separate SDK helper, no special throttling). ## Design - **Manifest**: `LogicFunctionManifest` gains `serverWebhookTriggerSettings?`. The declarative `workspaceIdResolver` shape is dropped. - **Materialization**: those settings become two new jsonb columns on `LogicFunctionEntity`. The manifest → flat converter and the create-from-source DTO/util forward them; the property-config map and editable-properties list are extended. - **Lookup**: a single QB query joins `logicFunction → application → applicationRegistration` and filters on `lf.workspaceId = reg.workspaceId` to get only the owner workspace's copy. - **Webhook**: `POST /webhooks/server/:logicFunctionUniversalIdentifier` → `ServerWebhookTriggerService.handle` → join lookup → `LogicFunctionTriggerService.run`. No registry table, no `:applicationRegistrationUniversalIdentifier` segment, no resolver. - **Gate**: `IS_SERVER_LOGIC_FUNCTION_ENABLED` config var (disabled by default). ## Test plan - [x] `npx jest server-webhook-trigger` — 9 unit tests across the webhook service. - [x] `npx jest logic-function` — 88 existing tests stay green. - [x] `npx nx typecheck twenty-server`. - [x] `npx nx lint:diff-with-main twenty-server`. - [x] Reset DB → init → run `database:migrate:prod` → run `database:migrate:generate --name pending-migration-check` → no drift. - [ ] Manual: hit `/webhooks/server/<uid>` end-to-end against a manifest carrying `serverWebhookTriggerSettings`. https://claude.ai/code/session_01GgsnCGmYJ26xRirx8va1Yh --- _Generated by [Claude Code](https://claude.ai/code/session_01GgsnCGmYJ26xRirx8va1Yh)_ <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/22002?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. -->
95 lines
4.6 KiB
TypeScript
95 lines
4.6 KiB
TypeScript
import { Module } from '@nestjs/common';
|
|
import { APP_FILTER } from '@nestjs/core';
|
|
|
|
import { AiAgentMonitorModule } from 'src/engine/metadata-modules/ai/ai-agent-monitor/ai-agent-monitor.module';
|
|
import { AiAgentModule } from 'src/engine/metadata-modules/ai/ai-agent/ai-agent.module';
|
|
import { AiChatModule } from 'src/engine/metadata-modules/ai/ai-chat/ai-chat.module';
|
|
import { AiGenerateTextModule } from 'src/engine/metadata-modules/ai/ai-generate-text/ai-generate-text.module';
|
|
import { AiWorkspaceStatsModule } from 'src/engine/metadata-modules/ai/ai-workspace-stats/ai-workspace-stats.module';
|
|
import { ApplicationConnectionsModule } from 'src/engine/core-modules/application/connection-provider/connections/application-connections.module';
|
|
import { CalendarChannelMetadataModule } from 'src/engine/metadata-modules/calendar-channel/calendar-channel-metadata.module';
|
|
import { ConnectedAccountMetadataModule } from 'src/engine/metadata-modules/connected-account/connected-account-metadata.module';
|
|
import { CommandMenuItemModule } from 'src/engine/metadata-modules/command-menu-item/command-menu-item.module';
|
|
import { FieldMetadataModule } from 'src/engine/metadata-modules/field-metadata/field-metadata.module';
|
|
import { FlatEntityMapsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/flat-entity/filters/flat-entity-maps-graphql-api-exception.filter';
|
|
import { FrontComponentModule } from 'src/engine/metadata-modules/front-component/front-component.module';
|
|
import { LogicFunctionLayerModule } from 'src/engine/metadata-modules/logic-function-layer/logic-function-layer.module';
|
|
import { LogicFunctionModule } from 'src/engine/metadata-modules/logic-function/logic-function.module';
|
|
import { MessageChannelMetadataModule } from 'src/engine/metadata-modules/message-channel/message-channel-metadata.module';
|
|
import { MessageFolderMetadataModule } from 'src/engine/metadata-modules/message-folder/message-folder-metadata.module';
|
|
import { NavigationMenuItemModule } from 'src/engine/metadata-modules/navigation-menu-item/navigation-menu-item.module';
|
|
import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module';
|
|
import { PermissionFlagModule } from 'src/engine/metadata-modules/permission-flag/permission-flag.module';
|
|
import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module';
|
|
import { MinimalMetadataModule } from 'src/engine/metadata-modules/minimal-metadata/minimal-metadata.module';
|
|
import { ServerRouteTriggerModule } from 'src/engine/core-modules/server-route-trigger/server-route-trigger.module';
|
|
import { RoleModule } from 'src/engine/metadata-modules/role/role.module';
|
|
import { RouteTriggerModule } from 'src/engine/metadata-modules/route-trigger/route-trigger.module';
|
|
import { SearchFieldMetadataModule } from 'src/engine/metadata-modules/search-field-metadata/search-field-metadata.module';
|
|
import { SkillModule } from 'src/engine/metadata-modules/skill/skill.module';
|
|
import { ViewModule } from 'src/engine/metadata-modules/view/view.module';
|
|
import { WebhookModule } from 'src/engine/metadata-modules/webhook/webhook.module';
|
|
import { WorkspaceMetadataVersionModule } from 'src/engine/metadata-modules/workspace-metadata-version/workspace-metadata-version.module';
|
|
|
|
@Module({
|
|
imports: [
|
|
FieldMetadataModule,
|
|
FrontComponentModule,
|
|
ObjectMetadataModule,
|
|
SearchFieldMetadataModule,
|
|
LogicFunctionModule,
|
|
LogicFunctionLayerModule,
|
|
SkillModule,
|
|
CommandMenuItemModule,
|
|
NavigationMenuItemModule,
|
|
AiAgentModule,
|
|
AiAgentMonitorModule,
|
|
AiChatModule,
|
|
AiGenerateTextModule,
|
|
AiWorkspaceStatsModule,
|
|
ApplicationConnectionsModule,
|
|
MinimalMetadataModule,
|
|
ViewModule,
|
|
WorkspaceMetadataVersionModule,
|
|
RoleModule,
|
|
PermissionsModule,
|
|
PermissionFlagModule,
|
|
RouteTriggerModule,
|
|
ServerRouteTriggerModule,
|
|
WebhookModule,
|
|
ConnectedAccountMetadataModule,
|
|
MessageChannelMetadataModule,
|
|
CalendarChannelMetadataModule,
|
|
MessageFolderMetadataModule,
|
|
],
|
|
providers: [
|
|
{
|
|
provide: APP_FILTER,
|
|
useClass: FlatEntityMapsGraphqlApiExceptionFilter,
|
|
},
|
|
],
|
|
exports: [
|
|
FieldMetadataModule,
|
|
FrontComponentModule,
|
|
ObjectMetadataModule,
|
|
SearchFieldMetadataModule,
|
|
LogicFunctionModule,
|
|
SkillModule,
|
|
CommandMenuItemModule,
|
|
NavigationMenuItemModule,
|
|
AiAgentModule,
|
|
AiChatModule,
|
|
MinimalMetadataModule,
|
|
ViewModule,
|
|
RoleModule,
|
|
PermissionsModule,
|
|
PermissionFlagModule,
|
|
WebhookModule,
|
|
ConnectedAccountMetadataModule,
|
|
MessageChannelMetadataModule,
|
|
CalendarChannelMetadataModule,
|
|
MessageFolderMetadataModule,
|
|
],
|
|
})
|
|
export class MetadataEngineModule {}
|