swap the moderation core to the sdk moderation module

Point the moderation primitives - the label definitions, the cause/UI/decision
types and the label-info hooks - at `@bsky.app/sdk/moderation` instead of
`@atproto/api`.

The two implementations are mutually unassignable: the sdk's subject types are
the generated `#/lexicons` views, so their `did`/`uri`/`cid` fields are
branded (`DidString`, `AtUriString`) where the `@atproto/api` views type the
same fields as plain `string`. That rules out a partial swap - a decision made
by one implementation cannot be read by the other - so the whole moderation
layer moves together.

`lib/moderation/subjects.ts` is the transitional seam for the brand mismatch.
Every `moderate*` entry point is re-exported through a wrapper that widens its
subject parameter to accept a view from either world, because many read paths
still emit `@atproto/api` views while the moderation runtime only ever reads
`.did`, `.labels` and `.viewer` - none of which the brand affects. It is
deleted in the `@atproto/api` removal pass.
This commit is contained in:
Samuel Newman
2026-08-04 02:35:38 +03:00
parent 5e9a437f53
commit 9aa6b49daf
22 changed files with 179 additions and 59 deletions
+7 -8
View File
@@ -1,18 +1,17 @@
import {useMemo} from 'react'
import {AtpAgent, type ComAtprotoLabelDefs} from '@atproto/api'
import {
type AppBskyLabelerDefs,
AtpAgent,
type ComAtprotoLabelDefs,
type InterpretedLabelValueDefinition,
LABELS,
type ModerationCause,
type ModerationOpts,
type ModerationUI,
} from '@atproto/api'
} from '@bsky.app/sdk/moderation'
import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {sanitizeHandle} from '#/lib/strings/handles'
import {type AppModerationCause} from '#/components/Pills'
import {type app} from '#/lexicons'
export const ADULT_CONTENT_LABELS = ['sexual', 'nudity', 'porn'] as const
export const OTHER_SELF_LABELS = ['graphic-media'] as const
@@ -102,8 +101,8 @@ export function lookupLabelValueDefinition(
export function isAppLabeler(
labeler:
| string
| AppBskyLabelerDefs.LabelerView
| AppBskyLabelerDefs.LabelerViewDetailed,
| app.bsky.labeler.defs.LabelerView
| app.bsky.labeler.defs.LabelerViewDetailed,
): boolean {
if (typeof labeler === 'string') {
return AtpAgent.appLabelers.includes(labeler)
@@ -114,8 +113,8 @@ export function isAppLabeler(
export function isLabelerSubscribed(
labeler:
| string
| AppBskyLabelerDefs.LabelerView
| AppBskyLabelerDefs.LabelerViewDetailed,
| app.bsky.labeler.defs.LabelerView
| app.bsky.labeler.defs.LabelerViewDetailed,
modOpts: ModerationOpts,
) {
labeler = typeof labeler === 'string' ? labeler : labeler.creator.did