mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
509 lines
14 KiB
TypeScript
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
|
|
}
|