import type { MemberEnforcementService, MessageResponse, PrivacyCaptureInput, PrivacyCapturePage, PrivacyEraseInput, PrivacyErasePage, ServiceAccess } from "./index.js"; import type { ViolationEvidenceReference, ViolationThreadDeliveryResult } from "./violation-threads.js"; export declare const MODERATION_ACTION_PROVIDER_ID = "helyx.moderation-actions"; export declare const MODERATION_ACTION_CONTRACT_VERSION = 2; export declare const AUTOMOD_ENFORCEMENT_POLICY_PROVIDER_ID = "helyx.automod-enforcement-policy"; export declare const AUTOMOD_ENFORCEMENT_POLICY_CONTRACT_VERSION = 1; export declare const AUTOMOD_TIMEOUT_SECONDS: readonly [60, 300, 600, 3600, 86400, 604800]; export declare const MODERATION_CASE_RETENTION_TASK: Readonly<{ moduleId: "helyx.platform"; taskKind: "moderation.case-retention"; taskVersion: 1; delivery: "one-shot"; runWhenDisabled: true; }>; export declare const MODERATION_ACTION_RECONCILIATION_TASK: Readonly<{ moduleId: "helyx.moderation"; taskKind: "moderation.action-reconcile"; taskVersion: 1; delivery: "one-shot"; }>; export declare const MODERATION_CONTRACT_LIMITS: Readonly<{ reasonCharacters: 500; privateNoteCharacters: 1000; timeoutSeconds: 2419200; automaticDemotionRoles: 10; ignoredRolesPerScope: 25; }>; export type ModerationSeverity = "low" | "medium" | "high" | "critical"; export type ModerationConfidenceClass = "exact" | "native_equivalent" | "high" | "medium" | "low"; export type AutoModerationTimeoutSeconds = (typeof AUTOMOD_TIMEOUT_SECONDS)[number]; export type ModerationBanDeleteMessageSeconds = 0 | 3_600 | 21_600 | 86_400 | 259_200 | 604_800; export type ModerationEnforcementAction = { type: "case_only"; } | { type: "delete_message"; } | { type: "warn"; } | { type: "timeout"; durationSeconds: AutoModerationTimeoutSeconds; } | { type: "kick"; } | { type: "ban"; deleteMessageSeconds: ModerationBanDeleteMessageSeconds; } | { type: "demote"; roleIds: readonly string[]; }; export interface ModerationRepeatActionPolicy { first: ModerationEnforcementAction; second: ModerationEnforcementAction; thirdAndLater: ModerationEnforcementAction; } export type ModerationObservedAction = { type: "discord_native_block_message"; } | { type: "discord_native_timeout"; durationSeconds: AutoModerationTimeoutSeconds; }; interface ModerationActionRequestBase { operationKey: string; detectionSource: "native" | "enhanced"; guildId: string; subjectUserId: string; sourceMessage: { channelId: string; messageId: string | null; } | null; sourceEventId: string; occurredAt: Date; callerModuleId: string; ruleId: string; configurationRevision: string; reasonCode: string; severity: ModerationSeverity; confidenceClass: ModerationConfidenceClass; /** Enhanced engine score only; Discord-native execution does not provide a score. */ confidenceScore?: number; evidenceReference?: ViolationEvidenceReference; } export type ModerationActionRequestV2 = (ModerationActionRequestBase & { requestKind: "detection"; observedAction?: never; }) | (ModerationActionRequestBase & { requestKind: "observation"; observedAction: ModerationObservedAction; }); export interface ResolvedModerationActionPolicy { /** Current rule label resolved by its owner, never inferred from scanner input. */ ruleName?: string; policyFingerprint: string; ruleRevision: number; configurationRevision: string; windowStartsAt: Date; globalIgnoredRoleIds: readonly string[]; ruleIgnoredRoleIds: readonly string[]; actionPolicy: ModerationRepeatActionPolicy; openViolationThread: boolean; /** Enhanced-only removal of the posted source message, separate from the offence action. */ deleteSourceMessage?: boolean; } export type AutoModerationEnforcementPolicyResolution = ({ outcome: "eligible"; } & ResolvedModerationActionPolicy) | { outcome: "rejected"; code: "module_unavailable" | "feature_unavailable" | "stale_revision" | "stale_operation" | "source_unresolved" | "source_exempt" | "action_not_allowed"; }; export interface AutoModerationEnforcementPolicyProviderContributionV1 { providerId: typeof AUTOMOD_ENFORCEMENT_POLICY_PROVIDER_ID; contractVersion: typeof AUTOMOD_ENFORCEMENT_POLICY_CONTRACT_VERSION; resolve(context: AutoModerationEnforcementPolicyProviderContext, request: ModerationActionRequestV2): Promise; } export interface AutoModerationEnforcementPolicyProviderContext { services: ServiceAccess; } export type ResolvedModerationActionRequestV2 = ModerationActionRequestV2 & { policy: ResolvedModerationActionPolicy; revalidatePolicy(): Promise; }; export type ModerationActionResultV2 = { outcome: "applied" | "already_applied"; caseId: string; caseNumber: number; offenceOrdinal: 1 | 2 | 3; selectedAction: ModerationEnforcementAction; actionOutcome: "succeeded" | "already_applied"; threadOutcome: "not_requested" | "created" | "already_exists" | "retry_pending" | "review_required"; replayed: boolean; /** Optional secondary delivery failure; the confirmed offence/action is retained. */ safeCode?: string; } | { outcome: "rejected"; code: "caller_not_allowed" | "module_unavailable" | "feature_unavailable" | "stale_revision" | "stale_operation" | "subject_exempt" | "action_not_allowed" | "invalid_request" | "operation_key_conflict"; } | { outcome: "failed" | "ambiguous" | "review_required"; caseId: string; caseNumber: number; safeCode?: string; replayed: boolean; }; export interface ModerationActionProviderContext { services: ServiceAccess; violationEvidence: { /** Request-bound capability available only to the Moderation provider. */ deliver(input: { guildId: string; caseId: string; threadId: string; openingMessageId?: string; operationKey: string; }): Promise; }; } /** Owned only by the Moderation module and registered by core by ID/version. */ export interface ModerationActionProviderContributionV2 { providerId: typeof MODERATION_ACTION_PROVIDER_ID; contractVersion: typeof MODERATION_ACTION_CONTRACT_VERSION; allowedCallerModuleIds: readonly string[]; execute(context: ModerationActionProviderContext, request: ResolvedModerationActionRequestV2): Promise; } /** Closed caller-facing registry; it is not a generic module RPC facility. */ export interface ModerationActionRegistryService { execute(input: { providerId: typeof MODERATION_ACTION_PROVIDER_ID; contractVersion: typeof MODERATION_ACTION_CONTRACT_VERSION; callerModuleId: string; request: ModerationActionRequestV2; }): Promise; } export type ModerationCaseAction = "warn" | "timeout" | "timeout_remove" | "kick" | "ban" | "demote" | "unban" | "delete_message" | "case_only"; export type ModerationCaseSource = "staff_command" | "auto_moderation"; export interface AtomicModerationCaseInput { operationKey: string; guildId: string; subjectUserId: string; actorUserId: string | null; source: ModerationCaseSource; sourceModuleId: string; action: ModerationCaseAction; reason: string; privateNote?: string; evidenceMessage?: { channelId: string; messageId: string; }; relatedCaseId?: string; requestedDurationSeconds?: number; deleteMessageSeconds?: ModerationBanDeleteMessageSeconds; demoteRoleIds?: readonly string[]; occurredAt: Date; } export type AtomicModerationCaseResult = { outcome: "created" | "replayed"; caseId: string; caseNumber: number; revision: number; state: ModerationCaseState; attemptId: string; attemptNumber: number; attemptOutcome: ModerationPersistedAttemptOutcome; } | { outcome: "rejected"; code: "invalid_input" | "operation_key_conflict"; }; export type ModerationActionAttemptTerminalOutcome = "succeeded" | "already_applied" | "no_longer_required" | "member_missing" | "missing_permission" | "hierarchy_blocked" | "failed" | "ambiguous" | "review_required"; export type ModerationPersistedAttemptOutcome = "pending" | ModerationActionAttemptTerminalOutcome; export type ModerationCaseState = "pending" | "applied" | "failed" | "review" | "rejected" | "corrected" | "void"; export interface ModerationActionAttemptSettlementInput { operationKey: string; guildId: string; caseId: string; attemptId: string; expectedRevision: number; outcome: ModerationActionAttemptTerminalOutcome; safeCode?: string; removedRoleIds?: readonly string[]; retentionExpiresAt?: Date; occurredAt: Date; } export interface ModerationReconciliationCandidate { caseId: string; caseNumber: number; revision: number; subjectUserId: string | null; action: ModerationCaseAction; reason: string; requestedDurationSeconds: number | null; deleteMessageSeconds: ModerationBanDeleteMessageSeconds | null; demoteRoleIds: readonly string[]; latestAttemptId: string; latestAttemptNumber: number; latestAttemptAction: ModerationCaseAction; latestAttemptOutcome: "pending" | "ambiguous" | "failed" | "review_required"; latestAttemptCreatedAt: Date; updatedAt: Date; } /** * Deployment-wide atomic operation. Core allocates the per-guild sequence and * inserts the pending case plus first attempt in one transaction. */ export interface AtomicModerationCaseService { createPendingCase(input: AtomicModerationCaseInput): Promise; /** * Called only after the detection and current policy are accepted. The * offence association is confirmed in this transaction; a later Discord * effect failure changes the attempt, not the confirmed offence count. */ createConfirmedAutoModerationOffenceCase(input: { operationKey: string; guildId: string; subjectUserId: string; sourceModuleId: string; sourceEventId: string; sourceMessage: { channelId: string; messageId: string | null; } | null; ruleId: string; ruleRevision: number; configurationRevision: string; policyFingerprint: string; actionPolicy: ModerationRepeatActionPolicy; repeatWindowStartsAt: Date; reasonCode: string; evidenceReference?: ViolationEvidenceReference; openViolationThread: boolean; occurredAt: Date; observedAction?: ModerationObservedAction; }): Promise<{ outcome: "created" | "replayed"; caseId: string; caseNumber: number; revision: number; state: ModerationCaseState; attemptId: string; attemptNumber: number; attemptOutcome: ModerationPersistedAttemptOutcome; offenceOrdinal: 1 | 2 | 3; offenceCount: number; selectedAction: ModerationEnforcementAction; } | { outcome: "rejected"; code: "invalid_input" | "operation_key_conflict" | "stale_policy"; }>; createAdditionalPendingAttempt(input: { operationKey: string; guildId: string; caseId: string; expectedRevision: number; purpose: "reconciliation" | "thread_control"; action: ModerationCaseAction; requestedDurationSeconds?: number; demoteRoleIds?: readonly string[]; actorUserId: string | null; reason: string; occurredAt: Date; }): Promise<{ outcome: "created" | "replayed"; caseId: string; caseNumber: number; revision: number; state: ModerationCaseState; attemptId: string; attemptNumber: number; action: ModerationCaseAction; purpose: "reconciliation" | "thread_control"; attemptOutcome: ModerationPersistedAttemptOutcome; } | { outcome: "rejected"; code: "invalid_input" | "not_found" | "revision_conflict" | "case_not_reconcilable" | "operation_key_conflict"; }>; createCorrectionCase(input: { operationKey: string; guildId: string; caseId: string; expectedRevision: number; actorUserId: string; reason: string; occurredAt: Date; }): Promise<{ outcome: "corrected" | "replayed"; originalCaseId: string; originalCaseNumber: number; originalRevision: number; correctionCaseId: string; correctionCaseNumber: number; } | { outcome: "rejected"; code: "invalid_input" | "not_found" | "revision_conflict" | "case_not_correctable" | "operation_key_conflict"; }>; settleActionAttempt(input: ModerationActionAttemptSettlementInput): Promise<{ outcome: "settled" | "replayed"; caseId: string; caseNumber: number; revision: number; state: ModerationCaseState; attemptId: string; attemptNumber: number; } | { outcome: "rejected"; code: "invalid_input" | "not_found" | "revision_conflict" | "attempt_not_pending" | "operation_key_conflict"; }>; recordObservedAction(input: { operationKey: string; guildId: string; caseId: string; expectedRevision: number; observedAction: ModerationObservedAction; occurredAt: Date; }): Promise<{ outcome: "recorded" | "replayed"; caseId: string; caseNumber: number; revision: number; } | { outcome: "rejected"; code: "invalid_input" | "not_found" | "revision_conflict" | "observation_conflict" | "operation_key_conflict"; }>; listReconciliationCandidates(input: { guildId: string; updatedBefore: Date; limit: number; cursor?: string; }): Promise<{ items: readonly ModerationReconciliationCandidate[]; nextCursor?: string; }>; disassociateCase(input: { operationKey: string; guildId: string; caseId: string; expectedRevision: number; actorUserId: string; occurredAt: Date; }): Promise<{ outcome: "disassociated" | "already_disassociated"; caseId: string; caseNumber: number; revision: number; repeatAssociationRemoved: boolean; } | { outcome: "rejected"; code: "invalid_input" | "not_found" | "revision_conflict" | "case_not_correctable" | "operation_key_conflict"; }>; executeRetention(input: { guildId: string; caseId: string; occurredAt: Date; }): Promise<{ outcome: "completed" | "already_completed" | "not_found"; } | { outcome: "deferred"; deferredUntil: Date; code: "not_due" | "review" | "active_ban"; }>; } /** Closed database join boundary used only by Moderation's privacy provider. */ export interface ModerationCasePrivacyService { captureAccess(input: PrivacyCaptureInput): Promise; erase(input: PrivacyEraseInput): Promise; } export type MemberEnforcementInspection = { outcome: "present"; memberUserId: string; isGuildOwner: boolean; isAdministrator: boolean; isBot: boolean; roleIds: readonly string[]; effectivePermissionNames: readonly string[]; actorHierarchy: "above" | "equal_or_below" | "unknown"; helyxHierarchy: "above" | "equal_or_below" | "unknown"; timeoutEndsAt: Date | null; } | { outcome: "member_missing"; } | { outcome: "failed"; safeCode?: string; }; export type BanStateInspection = { outcome: "banned"; userId: string; } | { outcome: "not_banned"; } | { outcome: "missing_permission" | "failed"; safeCode?: string; }; export type ExtendedMemberEnforcementOutcome = "succeeded" | "already_applied" | "no_longer_required" | "member_missing" | "missing_permission" | "hierarchy_blocked" | "failed" | "ambiguous"; export interface ModerationMemberEnforcementService extends MemberEnforcementService { inspectMember(input: { guildId: string; memberUserId: string; actorUserId?: string; }): Promise; inspectBan(input: { guildId: string; userId: string; }): Promise; kickMember(input: { guildId: string; memberUserId: string; actorUserId?: string; moduleId: string; reason: string; operationKey: string; directMessage?: MessageResponse; revalidate(): Promise; }): Promise<{ outcome: ExtendedMemberEnforcementOutcome; directMessage: "sent" | "closed" | "failed" | "not_requested"; safeCode?: string; }>; banMember(input: { guildId: string; memberUserId: string; actorUserId?: string; moduleId: string; reason: string; deleteMessageSeconds: 0 | 3600 | 21600 | 86400 | 259200 | 604800; operationKey: string; directMessage?: MessageResponse; revalidate(): Promise; }): Promise<{ outcome: ExtendedMemberEnforcementOutcome; directMessage: "sent" | "closed" | "failed" | "not_requested"; safeCode?: string; }>; timeout(input: { guildId: string; memberUserId: string; actorUserId?: string; moduleId: string; reason: string; durationSeconds: number; operationKey: string; directMessage?: MessageResponse; revalidate(): Promise; }): Promise<{ outcome: ExtendedMemberEnforcementOutcome; directMessage: "sent" | "closed" | "failed" | "not_requested"; safeCode?: string; }>; removeTimeout(input: { guildId: string; memberUserId: string; actorUserId?: string; moduleId: string; reason: string; operationKey: string; revalidate(): Promise; }): Promise<{ outcome: ExtendedMemberEnforcementOutcome; safeCode?: string; }>; unban(input: { guildId: string; userId: string; actorUserId?: string; moduleId: string; reason: string; operationKey: string; revalidate(): Promise; }): Promise<{ outcome: ExtendedMemberEnforcementOutcome; safeCode?: string; }>; removeConfiguredRoles(input: { guildId: string; memberUserId: string; actorUserId?: string; moduleId: string; reason: string; roleIds: readonly string[]; protectedRoleIds: readonly string[]; operationKey: string; revalidate(): Promise; }): Promise<{ outcome: "succeeded" | "already_applied"; removedRoleIds: readonly string[]; alreadyAbsentRoleIds: readonly string[]; } | { outcome: "hierarchy_blocked"; blockedRoleIds: readonly string[]; } | { outcome: Exclude; safeCode?: string; }>; } export type MessageEnforcementOutcome = "deleted" | "already_absent" | "author_mismatch" | "missing_permission" | "failed" | "ambiguous"; /** Guild-owner-routed and initially callable only by Moderation. */ export interface MessageEnforcementService { deleteMemberMessage(input: { guildId: string; channelId: string; messageId: string; expectedAuthorUserId: string; callerModuleId: string; reason: string; operationKey: string; revalidate(): Promise; }): Promise<{ outcome: MessageEnforcementOutcome; safeCode?: string; }>; } export {};