import type { AuthenticationMethod, ProjectRelation, RedactionFloor } from '@n8n/api-types';
import type { AuthProviderType, User, IWorkflowDb } from '@n8n/db';
import type {
	CancellationReason,
	HitlResponseTelemetryPayload,
	IPersonalizationSurveyAnswersV4,
	IRun,
	IWorkflowBase,
	IWorkflowExecutionDataProcess,
	JsonValue,
	WorkflowExecuteMode,
	WorkflowSettings,
} from 'n8n-workflow';

import type { ConcurrencyQueueType } from '@/concurrency/concurrency-control.service';
import type { CredentialAuthProbeOutcome } from '@/services/credentials-tester.service';
import type {
	CredentialExportPolicy,
	ExportPackageEventCounts,
	ImportAuditCredentialIds,
	ImportPackageEventCounts,
	ImportPackageEventOptions,
	PackageFailureReason,
} from '@/modules/n8n-packages/n8n-packages.types';
import type { TokenExchangeFailureReason } from '@/modules/token-exchange/token-exchange.types';
import type { AdminCredentialSelection as InstanceAiCredentialSelection } from '@/modules/instance-ai/instance-ai-settings.service';
import type { McpCallerAuth } from '@/services/oauth-token-verifier-proxy.service';

import type { AiEventMap } from './ai.event-map';

export type WorkflowActionSource =
	| 'ui'
	| 'api'
	| 'n8n-mcp'
	| 'n8n-ai'
	| 'import'
	| 'review-approval';

export type UserLike = {
	id: string;
	email?: string;
	firstName?: string;
	lastName?: string;
	role?: {
		slug: string;
	};
};

export type ProjectSummary = {
	id: string;
	name: string;
};

export type RelayEventMap = {
	// #region Lifecycle

	'server-started': {};

	'session-started': {
		pushRef?: string;
	};

	'instance-stopped': {};

	'instance-owner-setup': {
		userId: string;
	};

	'first-production-workflow-succeeded': {
		projectId: string;
		workflowId: string;
		userId: string | null;
	};

	'instance-first-production-workflow-failed': {
		projectId: string;
		workflowId: string;
		workflowName: string;
		userId: string;
	};

	'first-workflow-data-loaded': {
		userId: string;
		workflowId: string;
		nodeType: string;
		nodeId: string;
		credentialType?: string;
		credentialId?: string;
	};

	// #endregion

	// #region Workflow

	'workflow-created': {
		user: UserLike;
		workflow: IWorkflowBase;
		publicApi: boolean;
		projectId: string;
		projectType: string;
		uiContext?: string;
		source?: WorkflowActionSource;
	};

	'n8n-package-imported': {
		user: UserLike;
		projectIds: string[];
		folderId: string | null;
		workflowIds: string[];
		options: ImportPackageEventOptions;
		packageSourceId: string;
		packageVersion: string;
		credentialIds: ImportAuditCredentialIds;
		counts: ImportPackageEventCounts;
	};

	'n8n-package-exported': {
		user: UserLike;
		workflowIds?: string[];
		folderIds?: string[];
		projectIds?: string[];
		counts: ExportPackageEventCounts;
		credentialExportPolicy: CredentialExportPolicy;
	};

	'n8n-package-export-failed': {
		user: UserLike;
		reason: PackageFailureReason;
		workflowIds?: string[];
		folderIds?: string[];
		projectIds?: string[];
	};

	'n8n-package-import-failed': {
		user: UserLike;
		reason: PackageFailureReason;
		projectId?: string;
		folderId?: string;
	};

	'workflow-deleted': {
		user: UserLike;
		workflowId: string;
		publicApi: boolean;
	};

	'workflow-archived': {
		user: UserLike;
		workflowId: string;
		publicApi: boolean;
	};

	'workflow-unarchived': {
		user: UserLike;
		workflowId: string;
		publicApi: boolean;
	};

	'workflow-saved': {
		user: UserLike;
		workflow: IWorkflowDb;
		publicApi: boolean;
		previousWorkflow?: IWorkflowDb;
		aiBuilderAssisted?: boolean;
		settingsChanged?: Record<string, { from: JsonValue; to: JsonValue }>;
		source?: WorkflowActionSource;
	};

	'workflow-activated': {
		user: UserLike;
		workflowId: string;
		workflow: IWorkflowDb;
		publicApi: boolean;
		source?: WorkflowActionSource;
	};

	'workflow-deactivated': {
		user: UserLike;
		workflowId: string;
		workflow: IWorkflowDb;
		publicApi: boolean;
		deactivatedVersionId: string | null;
		source?: WorkflowActionSource;
	};

	'workflow-pre-execute': {
		executionId: string;
		data: IWorkflowExecutionDataProcess /* main process */ | IWorkflowBase /* worker */;
		mode: WorkflowExecuteMode;
		projectId?: string;
		projectName?: string;
	};

	'workflow-post-execute': {
		executionId: string;
		userId?: string;
		workflow: IWorkflowBase;
		runData?: IRun;
		projectId?: string;
		projectName?: string;
		source?: IWorkflowExecutionDataProcess['source'];
		telemetryMetadata?: IWorkflowExecutionDataProcess['telemetryMetadata'];
	};

	'workflow-sharing-updated': {
		workflowId: string;
		userIdSharer: string;
		userIdList: string[];
	};

	'workflow-executed': {
		user?: UserLike;
		workflowId: string;
		workflowName: string;
		executionId: string;
		projectId: string;
		projectName: string;
		source:
			| 'user-manual'
			| 'user-retry'
			| 'webhook'
			| 'trigger'
			| 'error'
			| 'cli'
			| 'integrated'
			| 'evaluation'
			| 'chat';
	};

	'workflow-version-updated': {
		user: UserLike;
		workflowId: string;
		workflowName: string;
		versionId: string;
		versionName?: string | null;
		versionDescription?: string | null;
	};

	// #endregion

	// #region Node

	'node-pre-execute': {
		executionId: string;
		workflow: IWorkflowBase;
		nodeId?: string;
		nodeName: string;
		nodeType?: string;
	};

	'node-post-execute': {
		executionId: string;
		workflow: IWorkflowBase;
		nodeId?: string;
		nodeName: string;
		nodeType?: string;
	};

	'hitl-response-actioned': HitlResponseTelemetryPayload;

	// #endregion

	// #region User

	'user-submitted-personalization-survey': {
		userId: string;
		answers: IPersonalizationSurveyAnswersV4;
	};

	'user-deleted': {
		user: UserLike;
		publicApi: boolean;
		targetUserOldStatus: 'active' | 'invited';
		migrationStrategy?: 'transfer_data' | 'delete_data';
		targetUserId?: string;
		migrationUserId?: string;
	};

	'user-invited': {
		user: UserLike;
		targetUserId: string[];
		publicApi: boolean;
		emailSent: boolean;
		inviteeRole: string;
	};

	'user-reinvited': {
		user: UserLike;
		targetUserId: string[];
	};

	'user-updated': {
		user: UserLike;
		fieldsChanged: string[];
	};

	'user-mfa-enabled': {
		user: UserLike;
	};

	'user-mfa-disabled': {
		user: UserLike;
		disableMethod: 'mfaCode' | 'recoveryCode';
	};

	'user-signed-up': {
		user: UserLike;
		userType: AuthProviderType;
		wasDisabledLdapUser: boolean;
	};

	'user-logged-in': {
		user: UserLike;
		authenticationMethod: AuthenticationMethod;
	};

	'user-login-failed': {
		userEmail: string;
		authenticationMethod: AuthenticationMethod;
		reason?: string;
	};

	'user-changed-role': {
		userId: string;
		targetUserId: string;
		publicApi: boolean;
		targetUserNewRole: string;
	};

	'user-retrieved-user': {
		userId: string;
		publicApi: boolean;
	};

	'user-retrieved-all-users': {
		userId: string;
		publicApi: boolean;
	};

	'user-retrieved-execution': {
		userId: string;
		publicApi: boolean;
	};

	'user-retrieved-all-executions': {
		userId: string;
		publicApi: boolean;
	};

	'user-retried-execution': {
		userId: string;
		publicApi: boolean;
	};

	'user-retrieved-workflow': {
		userId: string;
		publicApi: boolean;
	};

	'user-retrieved-workflow-version': {
		userId: string;
		publicApi: boolean;
	};

	'user-retrieved-all-workflows': {
		userId: string;
		publicApi: boolean;
	};

	// #endregion

	// #region Click

	'user-invite-email-click': {
		inviter: UserLike;
		invitee: UserLike;
	};

	'user-password-reset-email-click': {
		user: UserLike;
	};

	'user-password-reset-request-click': {
		user: UserLike;
	};

	'user-transactional-email-sent': {
		userId: string;
		messageType:
			| 'Reset password'
			| 'New user invite'
			| 'Resend invite'
			| 'Workflow auto-deactivated'
			| 'Workflow shared'
			| 'Credentials shared'
			| 'Project shared';
		publicApi: boolean;
	};

	// #endregion

	// #region Public API

	'public-api-key-created': {
		user: UserLike;
		publicApi: boolean;
	};

	'public-api-key-deleted': {
		user: UserLike;
		publicApi: boolean;
		isOwn: boolean;
	};

	'public-api-key-rotated': {
		user: UserLike;
		publicApi: boolean;
	};

	'public-api-invoked': {
		userId: string;
		path: string;
		method: string;
		apiVersion: string;
		userAgent?: string;
	};

	// #endregion

	// #region Email

	'email-failed': {
		user: UserLike;
		messageType:
			| 'Reset password'
			| 'New user invite'
			| 'Resend invite'
			| 'Workflow shared'
			| 'Workflow auto-deactivated'
			| 'Credentials shared'
			| 'Project shared';
		publicApi: boolean;
	};

	// #endregion

	// #region Credentials

	'credentials-created': {
		user: UserLike;
		credentialType: string;
		credentialId: string;
		publicApi: boolean;
		projectId?: string;
		projectType?: string;
		uiContext?: string;
		isDynamic?: boolean;
		usesExternalSecrets?: boolean;
		jweEnabled?: boolean;
		supportsManagedAuth?: boolean;
		usesManagedAuth?: boolean;
	};

	'credentials-shared': {
		user: UserLike;
		credentialType: string;
		credentialId: string;
		userIdSharer: string;
		userIdsShareesAdded: string[];
		shareesRemoved: number | null;
	};

	'credentials-updated': {
		user: UserLike;
		credentialType: string;
		credentialId: string;
		isDynamic?: boolean;
		usesExternalSecrets?: boolean;
		jweEnabled?: boolean;
		supportsManagedAuth?: boolean;
		usesManagedAuth?: boolean;
	};

	'credentials-deleted': {
		user: UserLike;
		credentialType: string;
		credentialId: string;
	};

	'credentials-user-disconnected': {
		user: UserLike;
		credentialType: string;
		credentialId: string;
	};

	'credentials-probed': {
		user: UserLike;
		credentialId: string;
		outcome: CredentialAuthProbeOutcome;
	};

	'oauth-callback-binding-rejected': {
		reason: 'cookie-missing' | 'hash-mismatch';
		credentialId?: string;
		origin?: 'static-credential' | 'dynamic-credential';
	};

	'dynamic-credential-authorize-rejected': {
		reason: 'unauthenticated' | 'user-mismatch';
		credentialId?: string;
	};

	'private-credential-created': {
		user: UserLike;
		credentialType: string;
		credentialId: string;
		projectId?: string;
		projectType?: string;
	};

	'private-credential-toggled-to-private': {
		user: UserLike;
		credentialType: string;
		credentialId: string;
	};

	'private-credential-toggled-to-static': {
		user: UserLike;
		credentialType: string;
		credentialId: string;
	};

	'private-credential-connections-cleared': {
		user: UserLike;
		credentialType: string;
		credentialId: string;
	};

	'private-credential-deleted': {
		user: UserLike;
		credentialType: string;
		credentialId: string;
	};

	'private-credential-user-connected': {
		user: UserLike;
		credentialType: string;
		credentialId: string;
		supportsManagedAuth?: boolean;
		usesManagedAuth?: boolean;
	};

	// #endregion

	// #region Community package

	'community-package-installed': {
		user: UserLike;
		inputString: string;
		packageName: string;
		success: boolean;
		packageVersion?: string;
		packageNodeNames?: string[];
		packageAuthor?: string;
		packageAuthorEmail?: string;
		failureReason?: string;
	};

	'community-package-updated': {
		user: UserLike;
		packageName: string;
		packageVersionCurrent: string;
		packageVersionNew: string;
		packageNodeNames: string[];
		packageAuthor?: string;
		packageAuthorEmail?: string;
	};

	'community-package-deleted': {
		user: UserLike;
		packageName: string;
		packageVersion: string;
		packageNodeNames: string[];
		packageAuthor?: string;
		packageAuthorEmail?: string;
	};

	// #endregion

	// #region Execution

	'execution-throttled': {
		executionId: string;
		type: ConcurrencyQueueType;
	};

	'execution-started-during-bootup': {
		executionId: string;
	};

	'execution-cancelled': {
		executionId: string;
		workflowId?: string;
		workflowName?: string;
		reason: CancellationReason;
	};

	'execution-deleted': {
		user: UserLike;
		executionIds: string[];
		deleteBefore?: Date;
	};

	'execution-waiting': {
		executionId: string;
		workflowId: string;
	};

	'execution-resumed': {
		executionId: string;
		workflowId: string;
		resumeSource: 'webhook';
		responseAt: Date;
	};

	'execution-data-revealed': {
		user: UserLike;
		executionId: string;
		workflowId: string;
		ipAddress: string;
		userAgent: string;
		redactionPolicy: WorkflowSettings.RedactionPolicy;
	};

	'execution-data-reveal-failure': {
		user: UserLike;
		executionId: string;
		workflowId: string;
		ipAddress: string;
		userAgent: string;
		redactionPolicy: WorkflowSettings.RedactionPolicy;
		rejectionReason: string;
	};

	// #endregion

	// #region Project

	'team-project-updated': {
		userId: string;
		role: string;
		members?: ProjectRelation[];
		projectId: string;
		otelProjectCustomTagsCount?: number;
	};

	'team-project-deleted': {
		userId: string;
		role: string;
		projectId: string;
		removalType: 'transfer' | 'delete';
		targetProjectId?: string;
	};

	'team-project-created': {
		userId: string;
		role: string;
		uiContext?: string;
	};

	// #endregion

	// #region Source control

	'source-control-settings-updated': {
		branchName: string;
		readOnlyInstance: boolean;
		repoType: 'github' | 'gitlab' | 'other';
		connected: boolean;
		connectionType: 'ssh' | 'https';
	};

	'source-control-user-started-pull-ui': {
		userId?: string;
		workflowUpdates: number;
		workflowConflicts: number;
		credConflicts: number;
	};

	'source-control-user-finished-pull-ui': {
		userId?: string;
		workflowUpdates: number;
	};

	'source-control-user-pulled-api': {
		workflowUpdates: number;
		forced: boolean;
	};

	'source-control-user-started-push-ui': {
		userId?: string;
		workflowsEligible: number;
		workflowsEligibleWithConflicts: number;
		credsEligible: number;
		credsEligibleWithConflicts: number;
		variablesEligible: number;
	};

	'source-control-user-finished-push-ui': {
		userId: string;
		workflowsEligible: number;
		workflowsPushed: number;
		credsPushed: number;
		variablesPushed: number;
	};

	// #endregion

	// #region License

	'license-renewal-attempted': {
		success: boolean;
	};

	'license-community-plus-registered': {
		userId: User['id'];
		email: string;
		licenseKey: string;
	};

	// #endregion

	// #region Variable

	'variable-created': {
		user: UserLike;
		variableId: string;
		variableKey: string;
		projectId?: string;
	};

	'variable-updated': {
		user: UserLike;
		variableId: string;
		variableKey: string;
		projectId?: string;
	};

	'variable-deleted': {
		user: UserLike;
		variableId: string;
		variableKey: string;
		projectId?: string;
	};

	// #endregion

	// #region External secrets

	'external-secrets-provider-settings-saved': {
		userId?: string;
		vaultType: string;
		isValid: boolean;
		isNew: boolean;
		errorMessage?: string;
	};

	'external-secrets-provider-reloaded': {
		vaultType: string;
	};

	'external-secrets-connection-created': {
		userId: string;
		userRole?: string;
		providerKey: string;
		vaultType: string;
		projects: ProjectSummary[];
	};

	'external-secrets-connection-updated': {
		userId: string;
		userRole?: string;
		providerKey: string;
		vaultType: string;
		projects: ProjectSummary[];
	};

	'external-secrets-connection-deleted': {
		userId: string;
		userRole?: string;
		providerKey: string;
		vaultType: string;
		projects: ProjectSummary[];
	};

	'external-secrets-connection-tested': {
		userId: string;
		userRole?: string;
		providerKey: string;
		vaultType: string;
		projects: ProjectSummary[];
		isValid: boolean;
		errorMessage?: string;
	};

	'external-secrets-connection-reloaded': {
		userId: string;
		userRole?: string;
		providerKey: string;
		vaultType: string;
		projects: ProjectSummary[];
	};

	'external-secrets-system-roles-toggled': {
		userId: string;
		enabled: boolean;
	};

	// #endregion

	// #region LDAP

	'ldap-general-sync-finished': {
		type: string;
		succeeded: boolean;
		usersSynced: number;
		error: string;
	};

	'ldap-settings-updated': {
		userId: string;
		loginIdAttribute: string;
		firstNameAttribute: string;
		lastNameAttribute: string;
		emailAttribute: string;
		ldapIdAttribute: string;
		searchPageSize: number;
		searchTimeout: number;
		synchronizationEnabled: boolean;
		synchronizationInterval: number;
		loginLabel: string;
		loginEnabled: boolean;
	};

	'ldap-login-sync-failed': {
		error: string;
	};

	'login-failed-due-to-ldap-disabled': {
		userId: string;
	};

	// #endregion

	// #region SSO

	'sso-user-project-access-updated': {
		projectsRemoved: number;
		projectsAdded: number;
		userId: string;
	};

	'sso-user-instance-role-updated': {
		role: string;
		userId: string;
	};

	// #endregion

	// #region Role Mapping

	'expression-mapping-roles-resolved': {
		userId: string;
		userEmail: string;
		provider: 'oidc' | 'saml' | 'ldap';
		instanceRole: {
			role: string;
			previousRole: string;
			changed: boolean;
			matchedRuleId: string | null;
			expression: string | null;
			isFallback: boolean;
		};
		projectRoles: Array<{
			projectId: string;
			role: string;
			previousRole: string | null;
			changed: boolean;
			matchedRuleId: string;
			expression: string;
		}>;
		removedProjectIds: string[];
	};

	'role-mapping-rule-created': {
		user: UserLike;
		ruleId: string;
		ruleType: 'instance' | 'project';
		expression: string;
		role: string;
	};

	'role-mapping-rule-updated': {
		user: UserLike;
		ruleId: string;
		ruleType: 'instance' | 'project';
		patchedFields: string[];
	};

	'role-mapping-rule-deleted': {
		user: UserLike;
		ruleId: string;
		ruleType: 'instance' | 'project';
	};

	'role-mapping-rules-bulk-deleted': {
		ruleType: 'instance' | 'project';
		count: number;
		reason: 'strategy-switch';
	};

	// #endregion

	// #region Token exchange

	'token-exchange-succeeded': {
		subject: string;
		actor?: string;
		scopes?: string;
		resource?: string;
		grantType: string;
		kid?: string;
		issuer: string;
		tokenId?: string;
		clientIp: string;
	};

	'token-exchange-failed': {
		subject?: string;
		failureReason: TokenExchangeFailureReason;
		grantType: string;
		clientIp: string;
	};

	'embed-login': {
		subject: string;
		issuer: string;
		kid: string;
		clientIp: string;
	};

	'embed-login-failed': {
		failureReason: TokenExchangeFailureReason;
		clientIp: string;
	};

	'token-exchange-identity-linked': {
		userId: string;
		sub: string;
		email: string;
		kid: string;
		issuer: string;
	};

	'token-exchange-identity-rebound': {
		userId: string;
		sub: string;
		kid: string;
		issuer: string;
	};

	'token-exchange-user-provisioned': {
		userId: string;
		sub: string;
		email: string;
		role: string;
		kid: string;
		issuer: string;
	};

	'token-exchange-role-updated': {
		userId: string;
		previousRole: string;
		newRole: string;
		kid: string;
		issuer: string;
	};

	// #endregion

	// #region runner

	'runner-task-requested': {
		taskId: string;
		nodeId: string;
		workflowId: string;
		executionId: string;
	};

	'runner-response-received': {
		taskId: string;
		nodeId: string;
		workflowId: string;
		executionId: string;
	};

	'runner-disconnected': {
		reason: 'failed-heartbeat-check' | 'runner-unresponsive';
		mode: 'internal' | 'external';
	};

	// #endregion

	// #region queue

	'job-enqueued': {
		executionId: string;
		workflowId: string;
		hostId: string;
		jobId: string;
	};

	'job-dequeued': {
		executionId: string;
		workflowId: string;
		hostId: string;
		jobId: string;
	};

	'job-stalled': {
		executionId: string;
		workflowId: string;
		hostId: string;
		jobId: string;
	};

	// #endregion

	// #region workflow history compaction
	'history-compacted': {
		workflowsProcessed: number;
		totalVersionsSeen: number;
		totalVersionsDeleted: number;
		errorCount: number;
		durationMs: number;
		windowStartIso: string;
		windowEndIso: string;
		compactionStartTime: Date;
	};
	// #endregion

	// #region Data Tables

	'data-table-deleted': {
		dataTableId: string;
		projectId: string;
	};

	// #endregion

	// #region Folders

	'folder-deleted': {
		folderId: string;
		projectId: string;
	};

	// #endregion

	// region Agents
	'agent-saved': {
		agentId: string;
	};

	'agent-deleted': {
		agentId: string;
		projectId: string;
	};

	// #region Instance Policies

	'instance-policies-updated': { user: UserLike } & (
		| {
				settingName:
					| '2fa_enforcement'
					| 'workflow_publishing'
					| 'workflow_sharing'
					| 'workflow_reviews';
				value: boolean;
		  }
		| {
				settingName: 'data_redaction_enforcement_floor';
				value: RedactionFloor;
		  }
	);

	'redaction-enforcement-updated': {
		user: UserLike;
		before: RedactionFloor;
		after: RedactionFloor;
	};

	// #endregion

	// #region Workflow Reviews

	'workflow-review-requested': {
		user: UserLike;
		workflowReviewRequestId: string;
		/** The project owning the review when it was opened. */
		projectId: string;
		workflowId: string;
		workflowVersionId: string;
		reviewerCount: number;
	};

	'workflow-review-version-updated': {
		user: UserLike;
		workflowReviewRequestId: string;
		workflowId: string;
		workflowVersionId: string;
	};

	'workflow-review-decided': {
		user: UserLike;
		workflowReviewRequestId: string;
		workflowId: string;
		/** Null when the pinned version was pruned before the decision. */
		workflowVersionId: string | null;
		decision: 'approved' | 'changes_requested';
		decidedVia: 'assigned-reviewer' | 'admin-override';
		reviewCreatedAt: Date;
	};

	/**
	 * Closed without a decision, by the workflow lifecycle hooks or the reconciliation
	 * sweep. An approval closes the request too but emits 'workflow-review-decided'
	 * instead, never both: every close path filters `state = 'open'` and `decide()`
	 * closes in-line.
	 */
	'workflow-review-closed': {
		workflowReviewRequestId: string;
		/**
		 * What left the review with no reviewable workflow, and who caused that — not who
		 * closed the review, which nobody does. `'unknown'` is not the activity feed's
		 * `no-reviewable-workflows`: the feed records that value on every close, whatever the
		 * trigger, while `'unknown'` says the trigger itself went unrecorded.
		 */
		cause: {
			trigger: 'workflow-archived' | 'workflow-moved' | 'workflow-deleted' | 'unknown';
			/** 'system' means no actor was recorded, not that automation acted. */
			actorKind: 'user' | 'system';
			userId: string | null;
		};
	};

	'workflow-review-comment-created': {
		user: UserLike;
		workflowReviewRequestId: string;
	};

	// #endregion

	// #region Custom Roles

	'custom-role-created': {
		userId: string;
		roleSlug: string;
		scopes: string[];
	};

	'custom-role-updated': {
		userId: string;
		roleSlug: string;
		scopes: string[];
	};

	'custom-role-deleted': {
		userId: string;
		roleSlug: string;
	};

	// #endregion

	// #region Instance AI

	'instance-ai-settings-updated': {
		mcpSettingsChanged: boolean;
		/** Instance credential assignments before and after the save; absent when the update carried none (e.g. multi-main reload). Ids and model names only, never credential data. */
		credentialSelections?: {
			previous: InstanceAiCredentialSelection;
			next: InstanceAiCredentialSelection;
			/** Components whose connection payload was written in this save. Same-provider key rotations update the credential in place and keep its id, so an id diff alone cannot see them. */
			connectionsUpdated: {
				model: boolean;
				sandbox: boolean;
				search: boolean;
			};
		};
	};

	'instance-ai-mcp-registry-connection-created': {
		userId: string;
		serverSlug: string;
	};

	'instance-ai-mcp-registry-connection-deleted': {
		userId: string;
		serverSlug: string;
	};

	// #endregion

	// #region Server CLI

	'server-cli-import': {
		activeState: 'false' | 'fromJson';
		workflowCount: number;
		separate: boolean;
	};

	'server-cli-export': {
		selector: 'all' | 'id' | 'projectId';
		published: boolean;
		separate: boolean;
		backup: boolean;
		workflowCount: number;
	};

	// #endregion

	// #region MCP server

	'mcp-oauth-completed': {
		userId: string;
		clientId: string;
		clientName?: string;
	};

	/**
	 * `authType` reports how the call authenticated, so an absent `clientId` is
	 * explicit rather than inferred. `api_key` covers every non-OAuth bearer
	 * token the MCP server admits, including token-exchange scoped JWTs, which
	 * is the same grouping the MCP connection telemetry uses.
	 *
	 * `clientId` is the OAuth client the call was authenticated with, as
	 * registered with this instance. Unlike `clientName` (self-reported by the
	 * client), it identifies the client, so it is what usage can be attributed
	 * by. Treat it as opaque: a first-party client's id is a URL rather than a
	 * generated id.
	 *
	 * The two travel paired because they are not independent: verification
	 * rejects an OAuth token carrying no `client_id` claim, and an API key is
	 * never issued to a client. The pair is absent only where no caller was
	 * resolved.
	 */
	'mcp-tool-called': {
		user: UserLike;
		toolName: string;
		workflowId?: string;
		status: 'success' | 'error';
		errorMessage?: string;
		clientName?: string;
	} & (McpCallerAuth | { authType?: undefined; clientId?: undefined });

	'mcp-access-updated': {
		user: UserLike;
		enabled: boolean;
	};

	// #endregion
} & AiEventMap;
