n8n/packages/cli/src/events/log-streaming-event-relay.ts

509 lines
14 KiB
TypeScript

import { Service } from 'typedi';
import { MessageEventBus } from '@/eventbus/message-event-bus/message-event-bus';
import { Redactable } from '@/decorators/redactable';
import { EventRelay } from '@/events/event-relay';
import type { RelayEventMap } from '@/events/relay-event-map';
import type { IWorkflowBase } from 'n8n-workflow';
import { EventService } from './event.service';
@Service()
export class LogStreamingEventRelay extends EventRelay {
constructor(
readonly eventService: EventService,
private readonly eventBus: MessageEventBus,
) {
super(eventService);
}
init() {
this.setupListeners({
'workflow-created': (event) => this.workflowCreated(event),
'workflow-deleted': (event) => this.workflowDeleted(event),
'workflow-saved': (event) => this.workflowSaved(event),
'workflow-pre-execute': (event) => this.workflowPreExecute(event),
'workflow-post-execute': (event) => this.workflowPostExecute(event),
'node-pre-execute': (event) => this.nodePreExecute(event),
'node-post-execute': (event) => this.nodePostExecute(event),
'user-deleted': (event) => this.userDeleted(event),
'user-invited': (event) => this.userInvited(event),
'user-reinvited': (event) => this.userReinvited(event),
'user-updated': (event) => this.userUpdated(event),
'user-signed-up': (event) => this.userSignedUp(event),
'user-logged-in': (event) => this.userLoggedIn(event),
'user-login-failed': (event) => this.userLoginFailed(event),
'user-invite-email-click': (event) => this.userInviteEmailClick(event),
'user-password-reset-email-click': (event) => this.userPasswordResetEmailClick(event),
'user-password-reset-request-click': (event) => this.userPasswordResetRequestClick(event),
'public-api-key-created': (event) => this.publicApiKeyCreated(event),
'public-api-key-deleted': (event) => this.publicApiKeyDeleted(event),
'email-failed': (event) => this.emailFailed(event),
'credentials-created': (event) => this.credentialsCreated(event),
'credentials-deleted': (event) => this.credentialsDeleted(event),
'credentials-shared': (event) => this.credentialsShared(event),
'credentials-updated': (event) => this.credentialsUpdated(event),
'community-package-installed': (event) => this.communityPackageInstalled(event),
'community-package-updated': (event) => this.communityPackageUpdated(event),
'community-package-deleted': (event) => this.communityPackageDeleted(event),
'execution-throttled': (event) => this.executionThrottled(event),
'execution-started-during-bootup': (event) => this.executionStartedDuringBootup(event),
'ai-messages-retrieved-from-memory': (event) => this.aiMessagesRetrievedFromMemory(event),
'ai-message-added-to-memory': (event) => this.aiMessageAddedToMemory(event),
'ai-output-parsed': (event) => this.aiOutputParsed(event),
'ai-documents-retrieved': (event) => this.aiDocumentsRetrieved(event),
'ai-document-embedded': (event) => this.aiDocumentEmbedded(event),
'ai-query-embedded': (event) => this.aiQueryEmbedded(event),
'ai-document-processed': (event) => this.aiDocumentProcessed(event),
'ai-text-split': (event) => this.aiTextSplitIntoChunks(event),
'ai-tool-called': (event) => this.aiToolCalled(event),
'ai-vector-store-searched': (event) => this.aiVectorStoreSearched(event),
'ai-llm-generated-output': (event) => this.aiLlmGeneratedOutput(event),
'ai-llm-errored': (event) => this.aiLlmErrored(event),
'ai-vector-store-populated': (event) => this.aiVectorStorePopulated(event),
'ai-vector-store-updated': (event) => this.aiVectorStoreUpdated(event),
});
}
// #region Workflow
@Redactable()
private workflowCreated({ user, workflow }: RelayEventMap['workflow-created']) {
void this.eventBus.sendAuditEvent({
eventName: 'n8n.audit.workflow.created',
payload: {
...user,
workflowId: workflow.id,
workflowName: workflow.name,
},
});
}
@Redactable()
private workflowDeleted({ user, workflowId }: RelayEventMap['workflow-deleted']) {
void this.eventBus.sendAuditEvent({
eventName: 'n8n.audit.workflow.deleted',
payload: { ...user, workflowId },
});
}
@Redactable()
private workflowSaved({ user, workflow }: RelayEventMap['workflow-saved']) {
void this.eventBus.sendAuditEvent({
eventName: 'n8n.audit.workflow.updated',
payload: {
...user,
workflowId: workflow.id,
workflowName: workflow.name,
},
});
}
private workflowPreExecute({ data, executionId }: RelayEventMap['workflow-pre-execute']) {
const payload =
'executionData' in data
? {
executionId,
userId: data.userId,
workflowId: data.workflowData.id,
isManual: data.executionMode === 'manual',
workflowName: data.workflowData.name,
}
: {
executionId,
userId: undefined,
workflowId: (data as IWorkflowBase).id,
isManual: false,
workflowName: (data as IWorkflowBase).name,
};
void this.eventBus.sendWorkflowEvent({
eventName: 'n8n.workflow.started',
payload,
});
}
private workflowPostExecute(event: RelayEventMap['workflow-post-execute']) {
const { runData, workflow, ...rest } = event;
const payload = {
...rest,
success: !!runData?.finished, // despite the `success` name, this reports `finished` state
isManual: runData?.mode === 'manual',
workflowId: workflow.id,
workflowName: workflow.name,
};
if (payload.success) {
void this.eventBus.sendWorkflowEvent({
eventName: 'n8n.workflow.success',
payload,
});
return;
}
void this.eventBus.sendWorkflowEvent({
eventName: 'n8n.workflow.failed',
payload: {
...payload,
lastNodeExecuted: runData?.data.resultData.lastNodeExecuted,
errorNodeType:
runData?.data.resultData.error && 'node' in runData?.data.resultData.error
? runData?.data.resultData.error.node?.type
: undefined,
errorMessage: runData?.data.resultData.error?.message.toString(),
},
});
}
// #endregion
// #region Node
private nodePreExecute({ workflow, executionId, nodeName }: RelayEventMap['node-pre-execute']) {
void this.eventBus.sendNodeEvent({
eventName: 'n8n.node.started',
payload: {
workflowId: workflow.id,
workflowName: workflow.name,
executionId,
nodeType: workflow.nodes.find((n) => n.name === nodeName)?.type,
nodeName,
},
});
}
private nodePostExecute({ workflow, executionId, nodeName }: RelayEventMap['node-post-execute']) {
void this.eventBus.sendNodeEvent({
eventName: 'n8n.node.finished',
payload: {
workflowId: workflow.id,
workflowName: workflow.name,
executionId,
nodeType: workflow.nodes.find((n) => n.name === nodeName)?.type,
nodeName,
},
});
}
// #endregion
// #region User
@Redactable()
private userDeleted({ user }: RelayEventMap['user-deleted']) {
void this.eventBus.sendAuditEvent({
eventName: 'n8n.audit.user.deleted',
payload: user,
});
}
@Redactable()
private userInvited({ user, targetUserId }: RelayEventMap['user-invited']) {
void this.eventBus.sendAuditEvent({
eventName: 'n8n.audit.user.invited',
payload: { ...user, targetUserId },
});
}
@Redactable()
private userReinvited({ user, targetUserId }: RelayEventMap['user-reinvited']) {
void this.eventBus.sendAuditEvent({
eventName: 'n8n.audit.user.reinvited',
payload: { ...user, targetUserId },
});
}
@Redactable()
private userUpdated({ user, fieldsChanged }: RelayEventMap['user-updated']) {
void this.eventBus.sendAuditEvent({
eventName: 'n8n.audit.user.updated',
payload: { ...user, fieldsChanged },
});
}
// #endregion
// #region Auth
@Redactable()
private userSignedUp({ user }: RelayEventMap['user-signed-up']) {
void this.eventBus.sendAuditEvent({
eventName: 'n8n.audit.user.signedup',
payload: user,
});
}
@Redactable()
private userLoggedIn({ user, authenticationMethod }: RelayEventMap['user-logged-in']) {
void this.eventBus.sendAuditEvent({
eventName: 'n8n.audit.user.login.success',
payload: { ...user, authenticationMethod },
});
}
private userLoginFailed(
event: RelayEventMap['user-login-failed'] /* exception: no `UserLike` to redact */,
) {
void this.eventBus.sendAuditEvent({
eventName: 'n8n.audit.user.login.failed',
payload: event,
});
}
// #endregion
// #region Click
@Redactable('inviter')
@Redactable('invitee')
private userInviteEmailClick(event: RelayEventMap['user-invite-email-click']) {
void this.eventBus.sendAuditEvent({
eventName: 'n8n.audit.user.invitation.accepted',
payload: event,
});
}
@Redactable()
private userPasswordResetEmailClick({ user }: RelayEventMap['user-password-reset-email-click']) {
void this.eventBus.sendAuditEvent({
eventName: 'n8n.audit.user.reset',
payload: user,
});
}
@Redactable()
private userPasswordResetRequestClick({
user,
}: RelayEventMap['user-password-reset-request-click']) {
void this.eventBus.sendAuditEvent({
eventName: 'n8n.audit.user.reset.requested',
payload: user,
});
}
// #endregion
// #region Public API
@Redactable()
private publicApiKeyCreated({ user }: RelayEventMap['public-api-key-created']) {
void this.eventBus.sendAuditEvent({
eventName: 'n8n.audit.user.api.created',
payload: user,
});
}
@Redactable()
private publicApiKeyDeleted({ user }: RelayEventMap['public-api-key-deleted']) {
void this.eventBus.sendAuditEvent({
eventName: 'n8n.audit.user.api.deleted',
payload: user,
});
}
// #endregion
// #region Email
@Redactable()
private emailFailed({ user, messageType }: RelayEventMap['email-failed']) {
void this.eventBus.sendAuditEvent({
eventName: 'n8n.audit.user.email.failed',
payload: { ...user, messageType },
});
}
// #endregion
// #region Credentials
@Redactable()
private credentialsCreated({ user, ...rest }: RelayEventMap['credentials-created']) {
void this.eventBus.sendAuditEvent({
eventName: 'n8n.audit.user.credentials.created',
payload: { ...user, ...rest },
});
}
@Redactable()
private credentialsDeleted({ user, ...rest }: RelayEventMap['credentials-deleted']) {
void this.eventBus.sendAuditEvent({
eventName: 'n8n.audit.user.credentials.deleted',
payload: { ...user, ...rest },
});
}
@Redactable()
private credentialsShared({ user, ...rest }: RelayEventMap['credentials-shared']) {
void this.eventBus.sendAuditEvent({
eventName: 'n8n.audit.user.credentials.shared',
payload: { ...user, ...rest },
});
}
@Redactable()
private credentialsUpdated({ user, ...rest }: RelayEventMap['credentials-updated']) {
void this.eventBus.sendAuditEvent({
eventName: 'n8n.audit.user.credentials.updated',
payload: { ...user, ...rest },
});
}
// #endregion
// #region Community package
@Redactable()
private communityPackageInstalled({
user,
...rest
}: RelayEventMap['community-package-installed']) {
void this.eventBus.sendAuditEvent({
eventName: 'n8n.audit.package.installed',
payload: { ...user, ...rest },
});
}
@Redactable()
private communityPackageUpdated({ user, ...rest }: RelayEventMap['community-package-updated']) {
void this.eventBus.sendAuditEvent({
eventName: 'n8n.audit.package.updated',
payload: { ...user, ...rest },
});
}
@Redactable()
private communityPackageDeleted({ user, ...rest }: RelayEventMap['community-package-deleted']) {
void this.eventBus.sendAuditEvent({
eventName: 'n8n.audit.package.deleted',
payload: { ...user, ...rest },
});
}
// #endregion
// #region Execution
private executionThrottled({ executionId }: RelayEventMap['execution-throttled']) {
void this.eventBus.sendExecutionEvent({
eventName: 'n8n.execution.throttled',
payload: { executionId },
});
}
private executionStartedDuringBootup({
executionId,
}: RelayEventMap['execution-started-during-bootup']) {
void this.eventBus.sendExecutionEvent({
eventName: 'n8n.execution.started-during-bootup',
payload: { executionId },
});
}
// #endregion
// #region AI
private aiMessagesRetrievedFromMemory(
payload: RelayEventMap['ai-messages-retrieved-from-memory'],
) {
void this.eventBus.sendAiNodeEvent({
eventName: 'n8n.ai.memory.get.messages',
payload,
});
}
private aiMessageAddedToMemory(payload: RelayEventMap['ai-message-added-to-memory']) {
void this.eventBus.sendAiNodeEvent({
eventName: 'n8n.ai.memory.added.message',
payload,
});
}
private aiOutputParsed(payload: RelayEventMap['ai-output-parsed']) {
void this.eventBus.sendAiNodeEvent({
eventName: 'n8n.ai.output.parser.parsed',
payload,
});
}
private aiDocumentsRetrieved(payload: RelayEventMap['ai-documents-retrieved']) {
void this.eventBus.sendAiNodeEvent({
eventName: 'n8n.ai.retriever.get.relevant.documents',
payload,
});
}
private aiDocumentEmbedded(payload: RelayEventMap['ai-document-embedded']) {
void this.eventBus.sendAiNodeEvent({
eventName: 'n8n.ai.embeddings.embedded.document',
payload,
});
}
private aiQueryEmbedded(payload: RelayEventMap['ai-query-embedded']) {
void this.eventBus.sendAiNodeEvent({
eventName: 'n8n.ai.embeddings.embedded.query',
payload,
});
}
private aiDocumentProcessed(payload: RelayEventMap['ai-document-processed']) {
void this.eventBus.sendAiNodeEvent({
eventName: 'n8n.ai.document.processed',
payload,
});
}
private aiTextSplitIntoChunks(payload: RelayEventMap['ai-text-split']) {
void this.eventBus.sendAiNodeEvent({
eventName: 'n8n.ai.text.splitter.split',
payload,
});
}
private aiToolCalled(payload: RelayEventMap['ai-tool-called']) {
void this.eventBus.sendAiNodeEvent({
eventName: 'n8n.ai.tool.called',
payload,
});
}
private aiVectorStoreSearched(payload: RelayEventMap['ai-vector-store-searched']) {
void this.eventBus.sendAiNodeEvent({
eventName: 'n8n.ai.vector.store.searched',
payload,
});
}
private aiLlmGeneratedOutput(payload: RelayEventMap['ai-llm-generated-output']) {
void this.eventBus.sendAiNodeEvent({
eventName: 'n8n.ai.llm.generated',
payload,
});
}
private aiLlmErrored(payload: RelayEventMap['ai-llm-errored']) {
void this.eventBus.sendAiNodeEvent({
eventName: 'n8n.ai.llm.error',
payload,
});
}
private aiVectorStorePopulated(payload: RelayEventMap['ai-vector-store-populated']) {
void this.eventBus.sendAiNodeEvent({
eventName: 'n8n.ai.vector.store.populated',
payload,
});
}
private aiVectorStoreUpdated(payload: RelayEventMap['ai-vector-store-updated']) {
void this.eventBus.sendAiNodeEvent({
eventName: 'n8n.ai.vector.store.updated',
payload,
});
}
// #endregion
}