Closed martmull closed 3 months ago
Create Functions Section in Settings
Functions
.Define Function Storage
STORAGE_TYPE
env variable (s3
or local
).Create Function Table
<workspace_schema>.function
to store function metadata.Implement Code Executor
code-executor
service to handle function execution.lambda
context:
<workspace_schema>.function
.sync_status
to ready
.local
context:
eval
or child_process.exec
.Update WorkspacePreQueryHookService
workspace-pre-query-hook.service.ts
for executing hooks.Handle Jobs
call-webhook-jobs.job.ts
for job handling logic.// Example: code-executor.service.ts
import { Injectable } from '@nestjs/common';
import { exec } from 'child_process';
import * as AWS from 'aws-sdk';
@Injectable()
export class CodeExecutorService {
async executeFunction(event: any, context: any, functionId: string) {
const functionData = await this.getFunctionData(functionId);
if (process.env.FUNCTION_EXECUTION_CONTEXT === 'lambda') {
return this.executeLambdaFunction(functionData, event);
} else {
return this.executeLocalFunction(functionData, event);
}
}
private async executeLambdaFunction(functionData: any, event: any) {
const lambda = new AWS.Lambda();
const params = {
FunctionName: functionData.lambdaId,
Payload: JSON.stringify(event)
};
return lambda.invoke(params).promise();
}
private async executeLocalFunction(functionData: any, event: any) {
return new Promise((resolve, reject) => {
exec(`node ${functionData.filePath}`, (error, stdout, stderr) => {
if (error) {
reject(error);
} else {
resolve(stdout);
}
});
});
}
private async getFunctionData(functionId: string) {
// Fetch function data from the database
}
}
/packages/twenty-server/src/workspace/workspace-query-runner/workspace-pre-query-hook/interfaces/workspace-pre-query-hook.interface.ts /packages/twenty-server/src/workspace/workspace-query-runner/workspace-pre-query-hook/workspace-pre-query-hook.service.ts /packages/twenty-server/src/workspace/workspace-query-runner/workspace-pre-query-hook/workspace-pre-query-hook.module.ts /packages/twenty-server/src/workspace/workspace-query-runner/jobs/call-webhook-jobs.job.ts /packages/twenty-server/src/workspace/workspace-query-runner/workspace-pre-query-hook/workspace-pre-query-hook.config.ts /packages/twenty-server/src/workspace/workspace-query-runner/workspace-pre-query-hook/types/workspace-query-hook.type.ts /packages/twenty-server/src/workspace/workspace-query-runner /packages/twenty-server/src/workspace/workspace-resolver-builder /packages/twenty-server/src/integrations/exception-handler/hooks
Scope & Context
We are working on enabling users to run custom code in their workspace. This ticket is about creating a way to execute safely custom code on our server
What
Functions
index.ts
file that contains aexport const handler = async (event, context) => {}
that will be executed by atwenty-code-executor
STORAGE_TYPE
env variable (s3
orlocal
)code-executor
using either awslambda
or local node execution context depending on a env variableFUNCTION_EXECUTION_CONTEXT
(lambda
orlocal
)<workspace_schema>.function
table that will persist the location of the functionlambda
FUNCTION_EXECUTION_CONTEXT
, we will create the lambda on aws by:handler
function into javascript functionnode_modules
in an aws layer<workspace_schema>.function
<workspace_schema>.function
(eg:sync_status
=ready
)local
FUNCTION_EXECUTION_CONTEXT
, we:handler
function into javascript function<workspace_schema>.function
<workspace_schema>.function
(eg:sync_status
=ready
)event
provided to thecode-executor
:lambda
FUNCTION_EXECUTION_CONTEXT
use invokelocal
FUNCTION_EXECUTION_CONTEXT
useeval
(same node context)code-executor
will then return the result of the function