diff --git a/.changeset/lovely-files-cross.md b/.changeset/lovely-files-cross.md new file mode 100644 index 00000000000..ff26c7dc699 --- /dev/null +++ b/.changeset/lovely-files-cross.md @@ -0,0 +1,5 @@ +--- +"@atproto/bsky": patch +--- + +Include new labeler service record properties on the `labelerViewDetailed` reponse from the app view. diff --git a/.changeset/six-fireants-hammer.md b/.changeset/six-fireants-hammer.md new file mode 100644 index 00000000000..bc7f0ca6909 --- /dev/null +++ b/.changeset/six-fireants-hammer.md @@ -0,0 +1,5 @@ +--- +"@atproto/api": patch +--- + +Mirror new labeler service record properties on `labelerViewDetailed`. diff --git a/lexicons/app/bsky/labeler/defs.json b/lexicons/app/bsky/labeler/defs.json index e122ef55f1d..b9ef3608052 100644 --- a/lexicons/app/bsky/labeler/defs.json +++ b/lexicons/app/bsky/labeler/defs.json @@ -35,6 +35,27 @@ "labels": { "type": "array", "items": { "type": "ref", "ref": "com.atproto.label.defs#label" } + }, + "reasonTypes": { + "description": "The set of report reason 'codes' which are in-scope for this service to review and action. These usually align to policy categories. If not defined (distinct from empty array), all reason types are allowed.", + "type": "array", + "items": { + "type": "ref", + "ref": "com.atproto.moderation.defs#reasonType" + } + }, + "subjectTypes": { + "description": "The set of subject types (account, record, etc) this service accepts reports on.", + "type": "array", + "items": { + "type": "ref", + "ref": "com.atproto.moderation.defs#subjectType" + } + }, + "subjectCollections": { + "type": "array", + "description": "Set of record types (collection NSIDs) which can be reported to this service. If not defined (distinct from empty array), default is any record type.", + "items": { "type": "string", "format": "nsid" } } } }, diff --git a/packages/api/src/client/lexicons.ts b/packages/api/src/client/lexicons.ts index 31f9cc6bf1c..23b00b79fb5 100644 --- a/packages/api/src/client/lexicons.ts +++ b/packages/api/src/client/lexicons.ts @@ -9044,6 +9044,33 @@ export const schemaDict = { ref: 'lex:com.atproto.label.defs#label', }, }, + reasonTypes: { + description: + "The set of report reason 'codes' which are in-scope for this service to review and action. These usually align to policy categories. If not defined (distinct from empty array), all reason types are allowed.", + type: 'array', + items: { + type: 'ref', + ref: 'lex:com.atproto.moderation.defs#reasonType', + }, + }, + subjectTypes: { + description: + 'The set of subject types (account, record, etc) this service accepts reports on.', + type: 'array', + items: { + type: 'ref', + ref: 'lex:com.atproto.moderation.defs#subjectType', + }, + }, + subjectCollections: { + type: 'array', + description: + 'Set of record types (collection NSIDs) which can be reported to this service. If not defined (distinct from empty array), default is any record type.', + items: { + type: 'string', + format: 'nsid', + }, + }, }, }, labelerViewerState: { diff --git a/packages/api/src/client/types/app/bsky/labeler/defs.ts b/packages/api/src/client/types/app/bsky/labeler/defs.ts index 453b010db5e..16ec81a3e90 100644 --- a/packages/api/src/client/types/app/bsky/labeler/defs.ts +++ b/packages/api/src/client/types/app/bsky/labeler/defs.ts @@ -7,6 +7,7 @@ import { validate as _validate } from '../../../../lexicons' import { $Typed, is$typed as _is$typed, OmitKey } from '../../../../util' import type * as AppBskyActorDefs from '../actor/defs.js' import type * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs.js' +import type * as ComAtprotoModerationDefs from '../../../com/atproto/moderation/defs.js' const is$typed = _is$typed, validate = _validate @@ -43,6 +44,12 @@ export interface LabelerViewDetailed { viewer?: LabelerViewerState indexedAt: string labels?: ComAtprotoLabelDefs.Label[] + /** The set of report reason 'codes' which are in-scope for this service to review and action. These usually align to policy categories. If not defined (distinct from empty array), all reason types are allowed. */ + reasonTypes?: ComAtprotoModerationDefs.ReasonType[] + /** The set of subject types (account, record, etc) this service accepts reports on. */ + subjectTypes?: ComAtprotoModerationDefs.SubjectType[] + /** Set of record types (collection NSIDs) which can be reported to this service. If not defined (distinct from empty array), default is any record type. */ + subjectCollections?: string[] } const hashLabelerViewDetailed = 'labelerViewDetailed' diff --git a/packages/bsky/src/lexicon/lexicons.ts b/packages/bsky/src/lexicon/lexicons.ts index df6a95efd66..dd2ab9fe455 100644 --- a/packages/bsky/src/lexicon/lexicons.ts +++ b/packages/bsky/src/lexicon/lexicons.ts @@ -9060,6 +9060,33 @@ export const schemaDict = { ref: 'lex:com.atproto.label.defs#label', }, }, + reasonTypes: { + description: + "The set of report reason 'codes' which are in-scope for this service to review and action. These usually align to policy categories. If not defined (distinct from empty array), all reason types are allowed.", + type: 'array', + items: { + type: 'ref', + ref: 'lex:com.atproto.moderation.defs#reasonType', + }, + }, + subjectTypes: { + description: + 'The set of subject types (account, record, etc) this service accepts reports on.', + type: 'array', + items: { + type: 'ref', + ref: 'lex:com.atproto.moderation.defs#subjectType', + }, + }, + subjectCollections: { + type: 'array', + description: + 'Set of record types (collection NSIDs) which can be reported to this service. If not defined (distinct from empty array), default is any record type.', + items: { + type: 'string', + format: 'nsid', + }, + }, }, }, labelerViewerState: { diff --git a/packages/bsky/src/lexicon/types/app/bsky/labeler/defs.ts b/packages/bsky/src/lexicon/types/app/bsky/labeler/defs.ts index 453b010db5e..16ec81a3e90 100644 --- a/packages/bsky/src/lexicon/types/app/bsky/labeler/defs.ts +++ b/packages/bsky/src/lexicon/types/app/bsky/labeler/defs.ts @@ -7,6 +7,7 @@ import { validate as _validate } from '../../../../lexicons' import { $Typed, is$typed as _is$typed, OmitKey } from '../../../../util' import type * as AppBskyActorDefs from '../actor/defs.js' import type * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs.js' +import type * as ComAtprotoModerationDefs from '../../../com/atproto/moderation/defs.js' const is$typed = _is$typed, validate = _validate @@ -43,6 +44,12 @@ export interface LabelerViewDetailed { viewer?: LabelerViewerState indexedAt: string labels?: ComAtprotoLabelDefs.Label[] + /** The set of report reason 'codes' which are in-scope for this service to review and action. These usually align to policy categories. If not defined (distinct from empty array), all reason types are allowed. */ + reasonTypes?: ComAtprotoModerationDefs.ReasonType[] + /** The set of subject types (account, record, etc) this service accepts reports on. */ + subjectTypes?: ComAtprotoModerationDefs.SubjectType[] + /** Set of record types (collection NSIDs) which can be reported to this service. If not defined (distinct from empty array), default is any record type. */ + subjectCollections?: string[] } const hashLabelerViewDetailed = 'labelerViewDetailed' diff --git a/packages/bsky/src/views/index.ts b/packages/bsky/src/views/index.ts index 3dd6d17446f..9c884727f78 100644 --- a/packages/bsky/src/views/index.ts +++ b/packages/bsky/src/views/index.ts @@ -592,12 +592,15 @@ export class Views { ): Un$Typed | undefined { const baseView = this.labeler(did, state) if (!baseView) return - const record = state.labelers?.get(did) - if (!record) return + const labeler = state.labelers?.get(did) + if (!labeler) return return { ...baseView, - policies: record.record.policies, + policies: labeler.record.policies, + reasonTypes: labeler.record.reasonTypes, + subjectTypes: labeler.record.subjectTypes, + subjectCollections: labeler.record.subjectCollections, } } diff --git a/packages/bsky/tests/views/__snapshots__/labeler-service.test.ts.snap b/packages/bsky/tests/views/__snapshots__/labeler-service.test.ts.snap index d5be53c4cbd..c5d40cef02d 100644 --- a/packages/bsky/tests/views/__snapshots__/labeler-service.test.ts.snap +++ b/packages/bsky/tests/views/__snapshots__/labeler-service.test.ts.snap @@ -170,3 +170,49 @@ Object { ], } `; + +exports[`labeler service views returns additional labeler data 1`] = ` +Object { + "views": Array [ + Object { + "$type": "app.bsky.labeler.defs#labelerViewDetailed", + "cid": "cids(0)", + "creator": Object { + "associated": Object { + "labeler": true, + }, + "did": "user(0)", + "handle": "carol.test", + "labels": Array [], + "viewer": Object { + "blockedBy": false, + "following": "record(1)", + "muted": false, + }, + }, + "indexedAt": "1970-01-01T00:00:00.000Z", + "labels": Array [], + "likeCount": 0, + "policies": Object { + "labelValues": Array [ + "spam", + "!hide", + "scam", + "impersonation", + ], + }, + "reasonTypes": Array [ + "com.atproto.moderation.defs#reasonOther", + ], + "subjectCollections": Array [ + "app.bsky.feed.post", + ], + "subjectTypes": Array [ + "record", + ], + "uri": "record(0)", + "viewer": Object {}, + }, + ], +} +`; diff --git a/packages/bsky/tests/views/labeler-service.test.ts b/packages/bsky/tests/views/labeler-service.test.ts index d3a03be3dc3..b497a2b99ba 100644 --- a/packages/bsky/tests/views/labeler-service.test.ts +++ b/packages/bsky/tests/views/labeler-service.test.ts @@ -1,5 +1,9 @@ import assert from 'node:assert' -import { AtpAgent } from '@atproto/api' +import { + AppBskyLabelerDefs, + AtpAgent, + ComAtprotoModerationDefs, +} from '@atproto/api' import { RecordRef, SeedClient, TestNetwork, basicSeed } from '@atproto/dev-env' import { ids } from '../../src/lexicon/lexicons' import { isView as isRecordEmbedView } from '../../src/lexicon/types/app/bsky/embed/record' @@ -14,6 +18,7 @@ describe('labeler service views', () => { // account dids, for convenience let alice: string let bob: string + let carol: string let aliceService: RecordRef @@ -27,6 +32,7 @@ describe('labeler service views', () => { await basicSeed(sc) alice = sc.dids.alice bob = sc.dids.bob + carol = sc.dids.carol const aliceRes = await pdsAgent.api.com.atproto.repo.createRecord( { @@ -190,4 +196,47 @@ describe('labeler service views', () => { // Cleanup await network.bsky.ctx.dataplane.untakedownActor({ did: alice }) }) + + it(`returns additional labeler data`, async () => { + await pdsAgent.api.com.atproto.repo.createRecord( + { + repo: carol, + collection: ids.AppBskyLabelerService, + rkey: 'self', + record: { + policies: { + labelValues: ['spam', '!hide', 'scam', 'impersonation'], + }, + createdAt: new Date().toISOString(), + reasonTypes: [ComAtprotoModerationDefs.REASONOTHER], + subjectTypes: ['record'], + subjectCollections: ['app.bsky.feed.post'], + }, + }, + { headers: sc.getHeaders(carol), encoding: 'application/json' }, + ) + await network.processAll() + + const view = await agent.api.app.bsky.labeler.getServices( + { dids: [carol], detailed: true }, + { + headers: await network.serviceHeaders( + bob, + ids.AppBskyLabelerGetServices, + ), + }, + ) + + const labelerView = view.data.views[0] + expect(AppBskyLabelerDefs.isLabelerViewDetailed(labelerView)).toBe(true) + // for TS only + if (!AppBskyLabelerDefs.isLabelerViewDetailed(labelerView)) return + expect(labelerView).toBeTruthy() + expect(labelerView.reasonTypes).toEqual([ + ComAtprotoModerationDefs.REASONOTHER, + ]) + expect(labelerView.subjectTypes).toEqual(['record']) + expect(labelerView.subjectCollections).toEqual(['app.bsky.feed.post']) + expect(forSnapshot(view.data)).toMatchSnapshot() + }) }) diff --git a/packages/ozone/src/lexicon/lexicons.ts b/packages/ozone/src/lexicon/lexicons.ts index 31f9cc6bf1c..23b00b79fb5 100644 --- a/packages/ozone/src/lexicon/lexicons.ts +++ b/packages/ozone/src/lexicon/lexicons.ts @@ -9044,6 +9044,33 @@ export const schemaDict = { ref: 'lex:com.atproto.label.defs#label', }, }, + reasonTypes: { + description: + "The set of report reason 'codes' which are in-scope for this service to review and action. These usually align to policy categories. If not defined (distinct from empty array), all reason types are allowed.", + type: 'array', + items: { + type: 'ref', + ref: 'lex:com.atproto.moderation.defs#reasonType', + }, + }, + subjectTypes: { + description: + 'The set of subject types (account, record, etc) this service accepts reports on.', + type: 'array', + items: { + type: 'ref', + ref: 'lex:com.atproto.moderation.defs#subjectType', + }, + }, + subjectCollections: { + type: 'array', + description: + 'Set of record types (collection NSIDs) which can be reported to this service. If not defined (distinct from empty array), default is any record type.', + items: { + type: 'string', + format: 'nsid', + }, + }, }, }, labelerViewerState: { diff --git a/packages/ozone/src/lexicon/types/app/bsky/labeler/defs.ts b/packages/ozone/src/lexicon/types/app/bsky/labeler/defs.ts index 453b010db5e..16ec81a3e90 100644 --- a/packages/ozone/src/lexicon/types/app/bsky/labeler/defs.ts +++ b/packages/ozone/src/lexicon/types/app/bsky/labeler/defs.ts @@ -7,6 +7,7 @@ import { validate as _validate } from '../../../../lexicons' import { $Typed, is$typed as _is$typed, OmitKey } from '../../../../util' import type * as AppBskyActorDefs from '../actor/defs.js' import type * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs.js' +import type * as ComAtprotoModerationDefs from '../../../com/atproto/moderation/defs.js' const is$typed = _is$typed, validate = _validate @@ -43,6 +44,12 @@ export interface LabelerViewDetailed { viewer?: LabelerViewerState indexedAt: string labels?: ComAtprotoLabelDefs.Label[] + /** The set of report reason 'codes' which are in-scope for this service to review and action. These usually align to policy categories. If not defined (distinct from empty array), all reason types are allowed. */ + reasonTypes?: ComAtprotoModerationDefs.ReasonType[] + /** The set of subject types (account, record, etc) this service accepts reports on. */ + subjectTypes?: ComAtprotoModerationDefs.SubjectType[] + /** Set of record types (collection NSIDs) which can be reported to this service. If not defined (distinct from empty array), default is any record type. */ + subjectCollections?: string[] } const hashLabelerViewDetailed = 'labelerViewDetailed' diff --git a/packages/pds/src/lexicon/lexicons.ts b/packages/pds/src/lexicon/lexicons.ts index 31f9cc6bf1c..23b00b79fb5 100644 --- a/packages/pds/src/lexicon/lexicons.ts +++ b/packages/pds/src/lexicon/lexicons.ts @@ -9044,6 +9044,33 @@ export const schemaDict = { ref: 'lex:com.atproto.label.defs#label', }, }, + reasonTypes: { + description: + "The set of report reason 'codes' which are in-scope for this service to review and action. These usually align to policy categories. If not defined (distinct from empty array), all reason types are allowed.", + type: 'array', + items: { + type: 'ref', + ref: 'lex:com.atproto.moderation.defs#reasonType', + }, + }, + subjectTypes: { + description: + 'The set of subject types (account, record, etc) this service accepts reports on.', + type: 'array', + items: { + type: 'ref', + ref: 'lex:com.atproto.moderation.defs#subjectType', + }, + }, + subjectCollections: { + type: 'array', + description: + 'Set of record types (collection NSIDs) which can be reported to this service. If not defined (distinct from empty array), default is any record type.', + items: { + type: 'string', + format: 'nsid', + }, + }, }, }, labelerViewerState: { diff --git a/packages/pds/src/lexicon/types/app/bsky/labeler/defs.ts b/packages/pds/src/lexicon/types/app/bsky/labeler/defs.ts index 453b010db5e..16ec81a3e90 100644 --- a/packages/pds/src/lexicon/types/app/bsky/labeler/defs.ts +++ b/packages/pds/src/lexicon/types/app/bsky/labeler/defs.ts @@ -7,6 +7,7 @@ import { validate as _validate } from '../../../../lexicons' import { $Typed, is$typed as _is$typed, OmitKey } from '../../../../util' import type * as AppBskyActorDefs from '../actor/defs.js' import type * as ComAtprotoLabelDefs from '../../../com/atproto/label/defs.js' +import type * as ComAtprotoModerationDefs from '../../../com/atproto/moderation/defs.js' const is$typed = _is$typed, validate = _validate @@ -43,6 +44,12 @@ export interface LabelerViewDetailed { viewer?: LabelerViewerState indexedAt: string labels?: ComAtprotoLabelDefs.Label[] + /** The set of report reason 'codes' which are in-scope for this service to review and action. These usually align to policy categories. If not defined (distinct from empty array), all reason types are allowed. */ + reasonTypes?: ComAtprotoModerationDefs.ReasonType[] + /** The set of subject types (account, record, etc) this service accepts reports on. */ + subjectTypes?: ComAtprotoModerationDefs.SubjectType[] + /** Set of record types (collection NSIDs) which can be reported to this service. If not defined (distinct from empty array), default is any record type. */ + subjectCollections?: string[] } const hashLabelerViewDetailed = 'labelerViewDetailed'