Add app.bsky.graph.getAssertions() ()

* Add app.bsky.graph.getAssertions()

* Update getAssertions to support query by author or subject

* Revert accidental change to members test
This commit is contained in:
Paul Frazee 2022-11-11 12:38:25 -06:00 committed by GitHub
parent 962041e6c1
commit a1bee406e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 2362 additions and 0 deletions
lexicons/app/bsky/graph
packages
api/src/client
pds
src
api/app/bsky
lexicon
tests/views

@ -0,0 +1,90 @@
{
"lexicon": 1,
"id": "app.bsky.graph.getAssertions",
"type": "query",
"description": "General-purpose query for assertions.",
"parameters": {
"type": "object",
"properties": {
"author": {"type": "string"},
"subject": {"type": "string"},
"assertion": {"type": "string"},
"confirmed": {"type": "boolean"},
"limit": {"type": "number", "maximum": 100},
"before": {"type": "string"}
}
},
"output": {
"encoding": "application/json",
"schema": {
"type": "object",
"required": ["assertions"],
"properties": {
"cursor": {"type": "string"},
"assertions": {
"type": "array",
"items": {
"type": "object",
"required": ["uri", "cid", "assertion", "author", "subject", "indexedAt", "createdAt"],
"properties": {
"uri": {"type": "string"},
"cid": {"type": "string"},
"assertion": {"type": "string"},
"confirmation": {"$ref": "#/defs/confirmation"},
"author": {"$ref": "#/defs/actor"},
"subject": {"$ref": "#/defs/actor"},
"indexedAt": {"type": "string", "format": "date-time"},
"createdAt": {"type": "string", "format": "date-time"}
}
}
}
}
}
},
"defs": {
"confirmation": {
"type": "object",
"required": ["uri", "cid", "indexedAt", "createdAt"],
"properties": {
"uri": {"type": "string"},
"cid": {"type": "string"},
"indexedAt": {"type": "string", "format": "date-time"},
"createdAt": {"type": "string", "format": "date-time"}
}
},
"actor": {
"type": "object",
"required": ["did", "declaration", "handle"],
"properties": {
"did": {"type": "string"},
"declaration": {"$ref": "#/defs/declaration"},
"handle": {"type": "string"},
"displayName": {
"type": "string",
"maxLength": 64
}
}
},
"declaration": {
"type": "object",
"required": ["cid", "actorType"],
"properties": {
"cid": {"type": "string"},
"actorType": {
"oneOf": [
{"$ref": "#/defs/actorKnown"},
{"$ref": "#/defs/actorUnknown"}
]
}
}
},
"actorKnown": {
"type": "string",
"enum": ["app.bsky.system.actorUser", "app.bsky.system.actorScene"]
},
"actorUnknown": {
"type": "string",
"not": {"enum": ["app.bsky.system.actorUser", "app.bsky.system.actorScene"]}
}
}
}

@ -49,6 +49,7 @@ import * as AppBskyFeedVote from './types/app/bsky/feed/vote'
import * as AppBskyGraphAssertion from './types/app/bsky/graph/assertion'
import * as AppBskyGraphConfirmation from './types/app/bsky/graph/confirmation'
import * as AppBskyGraphFollow from './types/app/bsky/graph/follow'
import * as AppBskyGraphGetAssertions from './types/app/bsky/graph/getAssertions'
import * as AppBskyGraphGetFollowers from './types/app/bsky/graph/getFollowers'
import * as AppBskyGraphGetFollows from './types/app/bsky/graph/getFollows'
import * as AppBskyGraphGetMembers from './types/app/bsky/graph/getMembers'
@ -101,6 +102,7 @@ export * as AppBskyFeedVote from './types/app/bsky/feed/vote'
export * as AppBskyGraphAssertion from './types/app/bsky/graph/assertion'
export * as AppBskyGraphConfirmation from './types/app/bsky/graph/confirmation'
export * as AppBskyGraphFollow from './types/app/bsky/graph/follow'
export * as AppBskyGraphGetAssertions from './types/app/bsky/graph/getAssertions'
export * as AppBskyGraphGetFollowers from './types/app/bsky/graph/getFollowers'
export * as AppBskyGraphGetFollows from './types/app/bsky/graph/getFollows'
export * as AppBskyGraphGetMembers from './types/app/bsky/graph/getMembers'
@ -1043,6 +1045,17 @@ export class GraphNS {
this.follow = new FollowRecord(service)
}
getAssertions(
params?: AppBskyGraphGetAssertions.QueryParams,
opts?: AppBskyGraphGetAssertions.CallOptions
): Promise<AppBskyGraphGetAssertions.Response> {
return this._service.xrpc
.call('app.bsky.graph.getAssertions', params, undefined, opts)
.catch((e) => {
throw AppBskyGraphGetAssertions.toKnownErr(e)
})
}
getFollowers(
params?: AppBskyGraphGetFollowers.QueryParams,
opts?: AppBskyGraphGetFollowers.CallOptions

@ -3005,6 +3005,231 @@ export const methodSchemaDict: Record<string, MethodSchema> = {
},
},
},
'app.bsky.graph.getAssertions': {
lexicon: 1,
id: 'app.bsky.graph.getAssertions',
type: 'query',
description: 'General-purpose query for assertions.',
parameters: {
type: 'object',
properties: {
author: {
type: 'string',
},
subject: {
type: 'string',
},
assertion: {
type: 'string',
},
confirmed: {
type: 'boolean',
},
limit: {
type: 'number',
maximum: 100,
},
before: {
type: 'string',
},
},
},
output: {
encoding: 'application/json',
schema: {
type: 'object',
required: ['assertions'],
properties: {
cursor: {
type: 'string',
},
assertions: {
type: 'array',
items: {
type: 'object',
required: [
'uri',
'cid',
'assertion',
'author',
'subject',
'indexedAt',
'createdAt',
],
properties: {
uri: {
type: 'string',
},
cid: {
type: 'string',
},
assertion: {
type: 'string',
},
confirmation: {
$ref: '#/$defs/confirmation',
},
author: {
$ref: '#/$defs/actor',
},
subject: {
$ref: '#/$defs/actor',
},
indexedAt: {
type: 'string',
format: 'date-time',
},
createdAt: {
type: 'string',
format: 'date-time',
},
},
},
},
},
$defs: {
confirmation: {
type: 'object',
required: ['uri', 'cid', 'indexedAt', 'createdAt'],
properties: {
uri: {
type: 'string',
},
cid: {
type: 'string',
},
indexedAt: {
type: 'string',
format: 'date-time',
},
createdAt: {
type: 'string',
format: 'date-time',
},
},
},
actor: {
type: 'object',
required: ['did', 'declaration', 'handle'],
properties: {
did: {
type: 'string',
},
declaration: {
$ref: '#/$defs/declaration',
},
handle: {
type: 'string',
},
displayName: {
type: 'string',
maxLength: 64,
},
},
},
declaration: {
type: 'object',
required: ['cid', 'actorType'],
properties: {
cid: {
type: 'string',
},
actorType: {
oneOf: [
{
$ref: '#/$defs/actorKnown',
},
{
$ref: '#/$defs/actorUnknown',
},
],
},
},
},
actorKnown: {
type: 'string',
enum: ['app.bsky.system.actorUser', 'app.bsky.system.actorScene'],
},
actorUnknown: {
type: 'string',
not: {
enum: ['app.bsky.system.actorUser', 'app.bsky.system.actorScene'],
},
},
},
},
},
defs: {
confirmation: {
type: 'object',
required: ['uri', 'cid', 'indexedAt', 'createdAt'],
properties: {
uri: {
type: 'string',
},
cid: {
type: 'string',
},
indexedAt: {
type: 'string',
format: 'date-time',
},
createdAt: {
type: 'string',
format: 'date-time',
},
},
},
actor: {
type: 'object',
required: ['did', 'declaration', 'handle'],
properties: {
did: {
type: 'string',
},
declaration: {
$ref: '#/$defs/declaration',
},
handle: {
type: 'string',
},
displayName: {
type: 'string',
maxLength: 64,
},
},
},
declaration: {
type: 'object',
required: ['cid', 'actorType'],
properties: {
cid: {
type: 'string',
},
actorType: {
oneOf: [
{
$ref: '#/$defs/actorKnown',
},
{
$ref: '#/$defs/actorUnknown',
},
],
},
},
},
actorKnown: {
type: 'string',
enum: ['app.bsky.system.actorUser', 'app.bsky.system.actorScene'],
},
actorUnknown: {
type: 'string',
not: {
enum: ['app.bsky.system.actorUser', 'app.bsky.system.actorScene'],
},
},
},
},
'app.bsky.graph.getFollowers': {
lexicon: 1,
id: 'app.bsky.graph.getFollowers',

@ -0,0 +1,66 @@
/**
* GENERATED CODE - DO NOT MODIFY
*/
import { Headers, XRPCError } from '@atproto/xrpc'
export interface QueryParams {
author?: string;
subject?: string;
assertion?: string;
confirmed?: boolean;
limit?: number;
before?: string;
}
export interface CallOptions {
headers?: Headers;
}
export type InputSchema = undefined
export type ActorKnown =
| 'app.bsky.system.actorUser'
| 'app.bsky.system.actorScene'
export type ActorUnknown = string
export interface OutputSchema {
cursor?: string;
assertions: {
uri: string,
cid: string,
assertion: string,
confirmation?: Confirmation,
author: Actor,
subject: Actor,
indexedAt: string,
createdAt: string,
}[];
}
export interface Confirmation {
uri: string;
cid: string;
indexedAt: string;
createdAt: string;
}
export interface Actor {
did: string;
declaration: Declaration;
handle: string;
displayName?: string;
}
export interface Declaration {
cid: string;
actorType: ActorKnown | ActorUnknown;
}
export interface Response {
success: boolean;
headers: Headers;
data: OutputSchema;
}
export function toKnownErr(e: any) {
if (e instanceof XRPCError) {
}
return e
}

@ -0,0 +1,149 @@
import { Server } from '../../../../lexicon'
import { InvalidRequestError } from '@atproto/xrpc-server'
import * as GetAssertions from '../../../../lexicon/types/app/bsky/graph/getAssertions'
import { getActorInfo } from '../util'
import * as locals from '../../../../locals'
import { paginate } from '../../../../db/util'
export default function (server: Server) {
server.app.bsky.graph.getAssertions(
async (params: GetAssertions.QueryParams, _input, _req, res) => {
const { author, subject, assertion, confirmed, limit, before } = params
const { db } = locals.get(res)
const { ref } = db.db.dynamic
if (!author && !subject) {
throw new InvalidRequestError(`Must provide an author or subject`)
}
const authorInfo =
author &&
(await getActorInfo(db.db, author).catch((_e) => {
throw new InvalidRequestError(`Actor not found: ${author}`)
}))
const subjectInfo =
subject &&
(await getActorInfo(db.db, subject).catch((_e) => {
throw new InvalidRequestError(`Actor not found: ${subject}`)
}))
let assertionsReq = db.db
.selectFrom('assertion')
.if(typeof assertion === 'string', (q) =>
q.where('assertion.assertion', '=', assertion as string),
)
.if(confirmed === true, (q) =>
q.where('assertion.confirmUri', 'is not', null),
)
.if(confirmed === false, (q) =>
q.where('assertion.confirmUri', 'is', null),
)
.innerJoin('did_handle as author', 'author.did', 'assertion.creator')
.leftJoin(
'profile as authorProfile',
'authorProfile.creator',
'author.did',
)
.innerJoin(
'did_handle as subject',
'subject.did',
'assertion.subjectDid',
)
.leftJoin(
'profile as subjectProfile',
'subjectProfile.creator',
'subject.did',
)
.select([
'assertion.uri as uri',
'assertion.cid as cid',
'assertion.assertion as assertionType',
'assertion.confirmUri',
'assertion.confirmCid',
'assertion.confirmCreated',
'assertion.confirmIndexed',
'author.did as authorDid',
'author.handle as authorHandle',
'author.declarationCid as authorDeclarationCid',
'author.actorType as authorActorType',
'authorProfile.displayName as authorDisplayName',
'subject.did as subjectDid',
'subject.handle as subjectHandle',
'subject.declarationCid as subjectDeclarationCid',
'subject.actorType as subjectActorType',
'subjectProfile.displayName as subjectDisplayName',
'assertion.createdAt as createdAt',
'assertion.indexedAt as indexedAt',
])
if (authorInfo) {
assertionsReq = assertionsReq.where(
'assertion.creator',
'=',
authorInfo.did,
)
}
if (subjectInfo) {
assertionsReq = assertionsReq.where(
'assertion.subjectDid',
'=',
subjectInfo.did,
)
}
assertionsReq = paginate(assertionsReq, {
limit,
before,
by: ref('assertion.createdAt'),
})
const assertionsRes = await assertionsReq.execute()
const assertions = assertionsRes.map((row) => ({
uri: row.uri,
cid: row.cid,
assertion: row.assertionType,
confirmation:
row.confirmUri &&
row.confirmCid &&
row.confirmIndexed &&
row.confirmCreated
? {
uri: row.confirmUri,
cid: row.confirmCid,
indexedAt: row.confirmIndexed,
createdAt: row.confirmCreated,
}
: undefined,
author: {
did: row.authorDid,
handle: row.authorHandle,
declaration: {
cid: row.authorDeclarationCid,
actorType: row.authorActorType,
},
displayName: row.authorDisplayName || undefined,
},
subject: {
did: row.subjectDid,
handle: row.subjectHandle,
declaration: {
cid: row.subjectDeclarationCid,
actorType: row.subjectActorType,
},
displayName: row.subjectDisplayName || undefined,
},
createdAt: row.createdAt,
indexedAt: row.indexedAt,
}))
return {
encoding: 'application/json',
body: {
assertions,
cursor: assertions.at(-1)?.createdAt,
},
}
},
)
}

@ -12,6 +12,7 @@ import getFollowers from './graph/getFollowers'
import getFollows from './graph/getFollows'
import getMembers from './graph/getMembers'
import getMemberships from './graph/getMemberships'
import getAssertions from './graph/getAssertions'
import getUsersSearch from './actor/search'
import getUsersTypeahead from './actor/searchTypeahead'
import getNotifications from './notification/list'
@ -33,6 +34,7 @@ export default function (server: Server) {
getFollows(server)
getMembers(server)
getMemberships(server)
getAssertions(server)
getUsersSearch(server)
getUsersTypeahead(server)
getNotifications(server)

@ -40,6 +40,7 @@ import * as AppBskyFeedGetRepostedBy from './types/app/bsky/feed/getRepostedBy'
import * as AppBskyFeedGetTimeline from './types/app/bsky/feed/getTimeline'
import * as AppBskyFeedGetVotes from './types/app/bsky/feed/getVotes'
import * as AppBskyFeedSetVote from './types/app/bsky/feed/setVote'
import * as AppBskyGraphGetAssertions from './types/app/bsky/graph/getAssertions'
import * as AppBskyGraphGetFollowers from './types/app/bsky/graph/getFollowers'
import * as AppBskyGraphGetFollows from './types/app/bsky/graph/getFollows'
import * as AppBskyGraphGetMembers from './types/app/bsky/graph/getMembers'
@ -371,6 +372,11 @@ export class GraphNS {
this._server = server
}
getAssertions(handler: AppBskyGraphGetAssertions.Handler) {
const schema = 'app.bsky.graph.getAssertions' // @ts-ignore
return this._server.xrpc.method(schema, handler)
}
getFollowers(handler: AppBskyGraphGetFollowers.Handler) {
const schema = 'app.bsky.graph.getFollowers' // @ts-ignore
return this._server.xrpc.method(schema, handler)

@ -3005,6 +3005,231 @@ export const methodSchemaDict: Record<string, MethodSchema> = {
},
},
},
'app.bsky.graph.getAssertions': {
lexicon: 1,
id: 'app.bsky.graph.getAssertions',
type: 'query',
description: 'General-purpose query for assertions.',
parameters: {
type: 'object',
properties: {
author: {
type: 'string',
},
subject: {
type: 'string',
},
assertion: {
type: 'string',
},
confirmed: {
type: 'boolean',
},
limit: {
type: 'number',
maximum: 100,
},
before: {
type: 'string',
},
},
},
output: {
encoding: 'application/json',
schema: {
type: 'object',
required: ['assertions'],
properties: {
cursor: {
type: 'string',
},
assertions: {
type: 'array',
items: {
type: 'object',
required: [
'uri',
'cid',
'assertion',
'author',
'subject',
'indexedAt',
'createdAt',
],
properties: {
uri: {
type: 'string',
},
cid: {
type: 'string',
},
assertion: {
type: 'string',
},
confirmation: {
$ref: '#/$defs/confirmation',
},
author: {
$ref: '#/$defs/actor',
},
subject: {
$ref: '#/$defs/actor',
},
indexedAt: {
type: 'string',
format: 'date-time',
},
createdAt: {
type: 'string',
format: 'date-time',
},
},
},
},
},
$defs: {
confirmation: {
type: 'object',
required: ['uri', 'cid', 'indexedAt', 'createdAt'],
properties: {
uri: {
type: 'string',
},
cid: {
type: 'string',
},
indexedAt: {
type: 'string',
format: 'date-time',
},
createdAt: {
type: 'string',
format: 'date-time',
},
},
},
actor: {
type: 'object',
required: ['did', 'declaration', 'handle'],
properties: {
did: {
type: 'string',
},
declaration: {
$ref: '#/$defs/declaration',
},
handle: {
type: 'string',
},
displayName: {
type: 'string',
maxLength: 64,
},
},
},
declaration: {
type: 'object',
required: ['cid', 'actorType'],
properties: {
cid: {
type: 'string',
},
actorType: {
oneOf: [
{
$ref: '#/$defs/actorKnown',
},
{
$ref: '#/$defs/actorUnknown',
},
],
},
},
},
actorKnown: {
type: 'string',
enum: ['app.bsky.system.actorUser', 'app.bsky.system.actorScene'],
},
actorUnknown: {
type: 'string',
not: {
enum: ['app.bsky.system.actorUser', 'app.bsky.system.actorScene'],
},
},
},
},
},
defs: {
confirmation: {
type: 'object',
required: ['uri', 'cid', 'indexedAt', 'createdAt'],
properties: {
uri: {
type: 'string',
},
cid: {
type: 'string',
},
indexedAt: {
type: 'string',
format: 'date-time',
},
createdAt: {
type: 'string',
format: 'date-time',
},
},
},
actor: {
type: 'object',
required: ['did', 'declaration', 'handle'],
properties: {
did: {
type: 'string',
},
declaration: {
$ref: '#/$defs/declaration',
},
handle: {
type: 'string',
},
displayName: {
type: 'string',
maxLength: 64,
},
},
},
declaration: {
type: 'object',
required: ['cid', 'actorType'],
properties: {
cid: {
type: 'string',
},
actorType: {
oneOf: [
{
$ref: '#/$defs/actorKnown',
},
{
$ref: '#/$defs/actorUnknown',
},
],
},
},
},
actorKnown: {
type: 'string',
enum: ['app.bsky.system.actorUser', 'app.bsky.system.actorScene'],
},
actorUnknown: {
type: 'string',
not: {
enum: ['app.bsky.system.actorUser', 'app.bsky.system.actorScene'],
},
},
},
},
'app.bsky.graph.getFollowers': {
lexicon: 1,
id: 'app.bsky.graph.getFollowers',

@ -0,0 +1,69 @@
/**
* GENERATED CODE - DO NOT MODIFY
*/
import express from 'express'
export interface QueryParams {
author?: string;
subject?: string;
assertion?: string;
confirmed?: boolean;
limit?: number;
before?: string;
}
export type HandlerInput = undefined
export interface HandlerSuccess {
encoding: 'application/json';
body: OutputSchema;
}
export interface HandlerError {
status: number;
message?: string;
}
export type HandlerOutput = HandlerError | HandlerSuccess
export type ActorKnown =
| 'app.bsky.system.actorUser'
| 'app.bsky.system.actorScene'
export type ActorUnknown = string
export interface OutputSchema {
cursor?: string;
assertions: {
uri: string,
cid: string,
assertion: string,
confirmation?: Confirmation,
author: Actor,
subject: Actor,
indexedAt: string,
createdAt: string,
}[];
}
export interface Confirmation {
uri: string;
cid: string;
indexedAt: string;
createdAt: string;
}
export interface Actor {
did: string;
declaration: Declaration;
handle: string;
displayName?: string;
}
export interface Declaration {
cid: string;
actorType: ActorKnown | ActorUnknown;
}
export type Handler = (
params: QueryParams,
input: HandlerInput,
req: express.Request,
res: express.Response
) => Promise<HandlerOutput> | HandlerOutput

File diff suppressed because it is too large Load Diff

@ -0,0 +1,207 @@
import AtpApi, { ServiceClient as AtpServiceClient } from '@atproto/api'
import {
runTestServer,
forSnapshot,
CloseFn,
constantDate,
paginateAll,
} from '../_util'
import { SeedClient } from '../seeds/client'
import basicSeed from '../seeds/basic'
describe('pds assertion views', () => {
let client: AtpServiceClient
let close: CloseFn
let sc: SeedClient
// account dids, for convenience
let alice: string
const scene = 'scene.test'
const otherScene = 'other-scene.test'
const carolScene = 'carol-scene.test'
beforeAll(async () => {
const server = await runTestServer({
dbPostgresSchema: 'views_assertions',
})
close = server.close
client = AtpApi.service(server.url)
sc = new SeedClient(client)
await basicSeed(sc)
alice = sc.dids.alice
})
afterAll(async () => {
await close()
})
const getCursors = (items: { createdAt?: string }[]) =>
items.map((item) => item.createdAt ?? constantDate)
const getSortedCursors = (items: { createdAt?: string }[]) =>
getCursors(items).sort((a, b) => tstamp(b) - tstamp(a))
const tstamp = (x: string) => new Date(x).getTime()
it('requires an author or subject', async () => {
const promise = client.app.bsky.graph.getAssertions()
await expect(promise).rejects.toThrow('Must provide an author or subject')
})
it('fetches assertions by author', async () => {
const sceneAssertions = await client.app.bsky.graph.getAssertions({
author: sc.scenes[scene].did,
})
expect(forSnapshot(sceneAssertions.data)).toMatchSnapshot()
expect(getCursors(sceneAssertions.data.assertions)).toEqual(
getSortedCursors(sceneAssertions.data.assertions),
)
const otherSceneAssertions = await client.app.bsky.graph.getAssertions({
author: sc.scenes[otherScene].did,
})
expect(forSnapshot(otherSceneAssertions.data)).toMatchSnapshot()
expect(getCursors(otherSceneAssertions.data.assertions)).toEqual(
getSortedCursors(otherSceneAssertions.data.assertions),
)
const carolSceneAssertions = await client.app.bsky.graph.getAssertions({
author: sc.scenes[carolScene].did,
})
expect(forSnapshot(carolSceneAssertions.data)).toMatchSnapshot()
expect(getCursors(carolSceneAssertions.data.assertions)).toEqual(
getSortedCursors(carolSceneAssertions.data.assertions),
)
})
it('fetches assertions by subject', async () => {
const aliceAssertions = await client.app.bsky.graph.getAssertions({
subject: sc.accounts[alice].did,
})
expect(forSnapshot(aliceAssertions.data)).toMatchSnapshot()
expect(getCursors(aliceAssertions.data.assertions)).toEqual(
getSortedCursors(aliceAssertions.data.assertions),
)
})
it('fetches assertions by author & subject', async () => {
const aliceSceneAssertions = await client.app.bsky.graph.getAssertions({
author: sc.scenes[scene].did,
subject: sc.accounts[alice].did,
})
expect(forSnapshot(aliceSceneAssertions.data)).toMatchSnapshot()
expect(getCursors(aliceSceneAssertions.data.assertions)).toEqual(
getSortedCursors(aliceSceneAssertions.data.assertions),
)
})
it('fetches assertions by author filtered by confirmation status', async () => {
const sceneAssertionsConfirmed = await client.app.bsky.graph.getAssertions({
author: sc.scenes[scene].did,
confirmed: true,
})
expect(forSnapshot(sceneAssertionsConfirmed.data)).toMatchSnapshot()
expect(getCursors(sceneAssertionsConfirmed.data.assertions)).toEqual(
getSortedCursors(sceneAssertionsConfirmed.data.assertions),
)
const sceneAssertionsUnconfirmed =
await client.app.bsky.graph.getAssertions({
author: sc.scenes[scene].did,
confirmed: false,
})
expect(forSnapshot(sceneAssertionsUnconfirmed.data)).toMatchSnapshot()
expect(getCursors(sceneAssertionsUnconfirmed.data.assertions)).toEqual(
getSortedCursors(sceneAssertionsUnconfirmed.data.assertions),
)
const otherSceneAssertionsConfirmed =
await client.app.bsky.graph.getAssertions({
author: sc.scenes[otherScene].did,
confirmed: true,
})
expect(forSnapshot(otherSceneAssertionsConfirmed.data)).toMatchSnapshot()
expect(getCursors(otherSceneAssertionsConfirmed.data.assertions)).toEqual(
getSortedCursors(otherSceneAssertionsConfirmed.data.assertions),
)
const otherSceneAssertionsUnconfirmed =
await client.app.bsky.graph.getAssertions({
author: sc.scenes[otherScene].did,
confirmed: false,
})
expect(forSnapshot(otherSceneAssertionsUnconfirmed.data)).toMatchSnapshot()
expect(getCursors(otherSceneAssertionsUnconfirmed.data.assertions)).toEqual(
getSortedCursors(otherSceneAssertionsUnconfirmed.data.assertions),
)
const carolSceneAssertionsConfirmed =
await client.app.bsky.graph.getAssertions({
author: sc.scenes[carolScene].did,
confirmed: true,
})
expect(forSnapshot(carolSceneAssertionsConfirmed.data)).toMatchSnapshot()
expect(getCursors(carolSceneAssertionsConfirmed.data.assertions)).toEqual(
getSortedCursors(carolSceneAssertionsConfirmed.data.assertions),
)
const carolSceneAssertionsUnconfirmed =
await client.app.bsky.graph.getAssertions({
author: sc.scenes[carolScene].did,
confirmed: true,
})
expect(forSnapshot(carolSceneAssertionsUnconfirmed.data)).toMatchSnapshot()
expect(getCursors(carolSceneAssertionsUnconfirmed.data.assertions)).toEqual(
getSortedCursors(carolSceneAssertionsUnconfirmed.data.assertions),
)
})
it('fetches assertions by author filtered by type', async () => {
const sceneAssertionsMember = await client.app.bsky.graph.getAssertions({
author: sc.scenes[scene].did,
assertion: 'app.bsky.graph.assertMember',
})
expect(forSnapshot(sceneAssertionsMember.data)).toMatchSnapshot()
expect(getCursors(sceneAssertionsMember.data.assertions)).toEqual(
getSortedCursors(sceneAssertionsMember.data.assertions),
)
const sceneAssertionsCreator = await client.app.bsky.graph.getAssertions({
author: sc.scenes[scene].did,
assertion: 'app.bsky.graph.assertCreator',
})
expect(forSnapshot(sceneAssertionsCreator.data)).toMatchSnapshot()
expect(getCursors(sceneAssertionsCreator.data.assertions)).toEqual(
getSortedCursors(sceneAssertionsCreator.data.assertions),
)
})
it('paginates assertions', async () => {
const paginator = async (cursor?: string) => {
const res = await client.app.bsky.graph.getAssertions({
author: sc.scenes[scene].did,
before: cursor,
limit: 2,
})
return res.data
}
const paginatedAll = await paginateAll(paginator)
paginatedAll.forEach((res) =>
expect(res.assertions.length).toBeLessThanOrEqual(2),
)
})
})