diff --git a/packages/backend/src/server/api/EndpointsModule.ts b/packages/backend/src/server/api/EndpointsModule.ts index ca89d82853..dcf09de83b 100644 --- a/packages/backend/src/server/api/EndpointsModule.ts +++ b/packages/backend/src/server/api/EndpointsModule.ts @@ -254,6 +254,7 @@ import * as ep___notes_localTimeline from './endpoints/notes/local-timeline.js'; import * as ep___notes_mentions from './endpoints/notes/mentions.js'; import * as ep___notes_polls_recommendation from './endpoints/notes/polls/recommendation.js'; import * as ep___notes_polls_vote from './endpoints/notes/polls/vote.js'; +import * as ep___notes_events_search from './endpoints/notes/events/search.js'; import * as ep___notes_reactions from './endpoints/notes/reactions.js'; import * as ep___notes_reactions_create from './endpoints/notes/reactions/create.js'; import * as ep___notes_reactions_delete from './endpoints/notes/reactions/delete.js'; @@ -588,6 +589,7 @@ const $notes_localTimeline: Provider = { provide: 'ep:notes/local-timeline', use const $notes_mentions: Provider = { provide: 'ep:notes/mentions', useClass: ep___notes_mentions.default }; const $notes_polls_recommendation: Provider = { provide: 'ep:notes/polls/recommendation', useClass: ep___notes_polls_recommendation.default }; const $notes_polls_vote: Provider = { provide: 'ep:notes/polls/vote', useClass: ep___notes_polls_vote.default }; +const $notes_events_search: Provider = { provide: 'ep:notes/events/search', useClass: ep___notes_events_search.default }; const $notes_reactions: Provider = { provide: 'ep:notes/reactions', useClass: ep___notes_reactions.default }; const $notes_reactions_create: Provider = { provide: 'ep:notes/reactions/create', useClass: ep___notes_reactions_create.default }; const $notes_reactions_delete: Provider = { provide: 'ep:notes/reactions/delete', useClass: ep___notes_reactions_delete.default }; @@ -926,6 +928,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention $notes_mentions, $notes_polls_recommendation, $notes_polls_vote, + $notes_events_search, $notes_reactions, $notes_reactions_create, $notes_reactions_delete, @@ -1258,6 +1261,7 @@ const $retention: Provider = { provide: 'ep:retention', useClass: ep___retention $notes_mentions, $notes_polls_recommendation, $notes_polls_vote, + $notes_events_search, $notes_reactions, $notes_reactions_create, $notes_reactions_delete, diff --git a/packages/backend/src/server/api/endpoints.ts b/packages/backend/src/server/api/endpoints.ts index dab897117d..292f18a880 100644 --- a/packages/backend/src/server/api/endpoints.ts +++ b/packages/backend/src/server/api/endpoints.ts @@ -254,6 +254,7 @@ import * as ep___notes_localTimeline from './endpoints/notes/local-timeline.js'; import * as ep___notes_mentions from './endpoints/notes/mentions.js'; import * as ep___notes_polls_recommendation from './endpoints/notes/polls/recommendation.js'; import * as ep___notes_polls_vote from './endpoints/notes/polls/vote.js'; +import * as ep___notes_events_search from './endpoints/notes/events/search.js'; import * as ep___notes_reactions from './endpoints/notes/reactions.js'; import * as ep___notes_reactions_create from './endpoints/notes/reactions/create.js'; import * as ep___notes_reactions_delete from './endpoints/notes/reactions/delete.js'; @@ -586,6 +587,7 @@ const eps = [ ['notes/mentions', ep___notes_mentions], ['notes/polls/recommendation', ep___notes_polls_recommendation], ['notes/polls/vote', ep___notes_polls_vote], + ['notes/events/search', ep___notes_events_search], ['notes/reactions', ep___notes_reactions], ['notes/reactions/create', ep___notes_reactions_create], ['notes/reactions/delete', ep___notes_reactions_delete], diff --git a/packages/backend/src/server/api/endpoints/notes/events/search.ts b/packages/backend/src/server/api/endpoints/notes/events/search.ts new file mode 100644 index 0000000000..51c192714d --- /dev/null +++ b/packages/backend/src/server/api/endpoints/notes/events/search.ts @@ -0,0 +1,134 @@ +import { Inject, Injectable } from '@nestjs/common'; +import { Brackets } from 'typeorm'; +import { Event } from '@/models/entities/Event.js'; +import type { NotesRepository } from '@/models/index.js'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { QueryService } from '@/core/QueryService.js'; +import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; +import type { Config } from '@/config.js'; +import { DI } from '@/di-symbols.js'; +import { RoleService } from '@/core/RoleService.js'; +import { ApiError } from '../../../error.js'; + +export const meta = { + tags: ['notes'], + + requireCredential: false, + + res: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + optional: false, nullable: false, + ref: 'Note', + }, + }, + + errors: { + unavailable: { + message: 'Search of notes unavailable.', + code: 'UNAVAILABLE', + id: '0b44998d-77aa-4427-80d0-d2c9b8523011', + }, + invalidParam: { + message: 'Invalid Parameter', + code: 'INVALID_PARAM', + id: 'e70903d3-0aa2-44d5-a955-4de5723c603d', + } + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 }, + host: { + type: 'string', + nullable: true, + description: 'The local host is represented with `null`.', + }, + users: { type: 'array', nullable: true, items: { type: 'object', format: 'misskey:id' } }, + sinceDate: { type: 'integer', nullable: true }, + untilDate: { type: 'integer', nullable: true }, + filters: { + type: 'object', + nullable: true, + description: 'mapping of string -> [string] that filters events based on metadata', + }, + sortBy: { type: 'string', nullable: true, default: 'startDate', enum: ['startDate', 'createdAt'] }, + }, +} as const; + +// eslint-disable-next-line import/no-default-export +@Injectable() +export default class extends Endpoint { + constructor( + @Inject(DI.config) + private config: Config, + + @Inject(DI.notesRepository) + private notesRepository: NotesRepository, + + private noteEntityService: NoteEntityService, + private queryService: QueryService, + private roleService: RoleService, + ) { + super(meta, paramDef, async (ps, me) => { + const policies = await this.roleService.getUserPolicies(me ? me.id : null); + if (!policies.canSearchNotes) { + throw new ApiError(meta.errors.unavailable); + } + + const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), ps.sinceId, ps.untilId); + + if (ps.users) { + if (ps.users.length < 1) throw new ApiError(meta.errors.invalidParam); + query.andWhere('note.userId IN (:...users)', { users: ps.users }); + } + + query + .innerJoinAndSelect(Event, 'event', 'event.noteId = note.id') + .innerJoinAndSelect('note.user', 'user'); + + if (ps.filters) { + const filters: Record = ps.filters; + + Object.keys(filters).forEach(f => { + const matches = filters[f].filter(x => x !== null); + if (matches.length < 1) throw new ApiError(meta.errors.invalidParam); + query.andWhere(new Brackets((qb) => { + qb.where('event.metadata ->> :key IN (:...values)', { key: f, values: filters[f].filter(x => x !== null) }); + if (filters[f].filter(x => x === null).length > 0) { + qb.orWhere('event.metadata ->> :key IS NULL', { key: f }); + } + })); + }); + } + + if (ps.sinceDate && ps.untilDate && ps.sinceDate > ps.untilDate) throw new ApiError(meta.errors.invalidParam); + const sinceDate = ps.sinceDate ? new Date(ps.sinceDate) : new Date(); + query.andWhere('event.start > :sinceDate', { sinceDate: sinceDate }) + .andWhere('(event.end IS NULL OR event.end > :sinceDate)', { sinceDate: sinceDate }); + if (ps.untilDate) { + query.andWhere('event.start < :untilDate', { untilDate: new Date(ps.untilDate) }); + } + + if (ps.sortBy === 'createdAt') { + query.orderBy('note.createdAt', 'ASC'); + } else { + query.orderBy('event.start', 'ASC'); + } + + this.queryService.generateVisibilityQuery(query, me); + if (me) this.queryService.generateMutedUserQuery(query, me); + if (me) this.queryService.generateBlockedUserQuery(query, me); + + const notes = await query.take(ps.limit).getMany(); + + return await this.noteEntityService.packMany(notes, me); + }); + } +} diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index 67d12000b8..1936d8fb50 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -1757,971 +1757,991 @@ export type Endpoints = { }; res: null; }; - 'notes/reactions': { - req: { - noteId: Note['id']; - type?: string | null; - limit?: number; + 'notes/events/search': { + req: { + sinceId?: Note['id']; + untilId?: Note['id']; + limit?: number; + offset?: number; + host?: string; + users?: User['id'][]; + sinceDate?: number; + untilDate?: number; + filters?: Record; + sortBy?: 'startDate' | 'createAt' + res: Note[]; + }; + 'notes/reactions': { + req: { + noteId: Note['id']; + type?: string | null; + limit?: number; + }; + res: NoteReaction[]; }; - res: NoteReaction[]; - }; - 'notes/reactions/create': { - req: { - noteId: Note['id']; - reaction: string; + 'notes/reactions/create': { + req: { + noteId: Note['id']; + reaction: string; + }; + res: null; }; - res: null; - }; - 'notes/reactions/delete': { - req: { - noteId: Note['id']; + 'notes/reactions/delete': { + req: { + noteId: Note['id']; + }; + res: null; }; - res: null; - }; - 'notes/renotes': { - req: { - limit?: number; - sinceId?: Note['id']; - untilId?: Note['id']; - noteId: Note['id']; + 'notes/renotes': { + req: { + limit?: number; + sinceId?: Note['id']; + untilId?: Note['id']; + noteId: Note['id']; + }; + res: Note[]; }; - res: Note[]; - }; - 'notes/replies': { - req: { - limit?: number; - sinceId?: Note['id']; - untilId?: Note['id']; - noteId: Note['id']; + 'notes/replies': { + req: { + limit?: number; + sinceId?: Note['id']; + untilId?: Note['id']; + noteId: Note['id']; + }; + res: Note[]; }; - res: Note[]; - }; - 'notes/search-by-tag': { - req: TODO; - res: TODO; - }; - 'notes/search': { - req: TODO; - res: TODO; - }; - 'notes/show': { - req: { - noteId: Note['id']; + 'notes/search-by-tag': { + req: TODO; + res: TODO; }; - res: Note; - }; - 'notes/state': { - req: TODO; - res: TODO; - }; - 'notes/timeline': { - req: { - limit?: number; - sinceId?: Note['id']; - untilId?: Note['id']; - sinceDate?: number; - untilDate?: number; + 'notes/search': { + req: TODO; + res: TODO; }; - res: Note[]; - }; - 'notes/unrenote': { - req: { - noteId: Note['id']; + 'notes/show': { + req: { + noteId: Note['id']; + }; + res: Note; }; - res: null; - }; - 'notes/user-list-timeline': { - req: { - listId: UserList['id']; - limit?: number; - sinceId?: Note['id']; - untilId?: Note['id']; - sinceDate?: number; - untilDate?: number; + 'notes/state': { + req: TODO; + res: TODO; }; - res: Note[]; - }; - 'notes/watching/create': { - req: TODO; - res: TODO; - }; - 'notes/watching/delete': { - req: { - noteId: Note['id']; + 'notes/timeline': { + req: { + limit?: number; + sinceId?: Note['id']; + untilId?: Note['id']; + sinceDate?: number; + untilDate?: number; + }; + res: Note[]; }; - res: null; - }; - 'notifications/create': { - req: { - body: string; - header?: string | null; - icon?: string | null; + 'notes/unrenote': { + req: { + noteId: Note['id']; + }; + res: null; }; - res: null; - }; - 'notifications/mark-all-as-read': { - req: NoParams; - res: null; - }; - 'page-push': { - req: { - pageId: Page['id']; - event: string; - var?: any; + 'notes/user-list-timeline': { + req: { + listId: UserList['id']; + limit?: number; + sinceId?: Note['id']; + untilId?: Note['id']; + sinceDate?: number; + untilDate?: number; + }; + res: Note[]; }; - res: null; - }; - 'pages/create': { - req: TODO; - res: Page; - }; - 'pages/delete': { - req: { - pageId: Page['id']; + 'notes/watching/create': { + req: TODO; + res: TODO; }; - res: null; - }; - 'pages/featured': { - req: NoParams; - res: Page[]; - }; - 'pages/like': { - req: { - pageId: Page['id']; + 'notes/watching/delete': { + req: { + noteId: Note['id']; + }; + res: null; }; - res: null; - }; - 'pages/show': { - req: { - pageId?: Page['id']; - name?: string; - username?: string; + 'notifications/create': { + req: { + body: string; + header?: string | null; + icon?: string | null; + }; + res: null; }; - res: Page; - }; - 'pages/unlike': { - req: { - pageId: Page['id']; + 'notifications/mark-all-as-read': { + req: NoParams; + res: null; }; - res: null; - }; - 'pages/update': { - req: TODO; - res: null; - }; - 'ping': { - req: NoParams; - res: { - pong: number; + 'page-push': { + req: { + pageId: Page['id']; + event: string; + var?: any; + }; + res: null; }; - }; - 'pinned-users': { - req: TODO; - res: TODO; - }; - 'promo/read': { - req: TODO; - res: TODO; - }; - 'request-reset-password': { - req: { - username: string; - email: string; + 'pages/create': { + req: TODO; + res: Page; }; - res: null; - }; - 'reset-password': { - req: { - token: string; - password: string; + 'pages/delete': { + req: { + pageId: Page['id']; + }; + res: null; }; - res: null; - }; - 'room/show': { - req: TODO; - res: TODO; - }; - 'room/update': { - req: TODO; - res: TODO; - }; - 'stats': { - req: NoParams; - res: Stats; - }; - 'server-info': { - req: NoParams; - res: ServerInfo; - }; - 'sw/register': { - req: TODO; - res: TODO; - }; - 'username/available': { - req: { - username: string; + 'pages/featured': { + req: NoParams; + res: Page[]; }; - res: { - available: boolean; + 'pages/like': { + req: { + pageId: Page['id']; + }; + res: null; }; - }; - 'users': { - req: { - limit?: number; - offset?: number; - sort?: UserSorting; - origin?: OriginType; + 'pages/show': { + req: { + pageId?: Page['id']; + name?: string; + username?: string; + }; + res: Page; }; - res: User[]; - }; - 'users/clips': { - req: TODO; - res: TODO; - }; - 'users/followers': { - req: { - userId?: User['id']; - username?: User['username']; - host?: User['host'] | null; - limit?: number; - sinceId?: Following['id']; - untilId?: Following['id']; + 'pages/unlike': { + req: { + pageId: Page['id']; + }; + res: null; }; - res: FollowingFollowerPopulated[]; - }; - 'users/following': { - req: { - userId?: User['id']; - username?: User['username']; - host?: User['host'] | null; - limit?: number; - sinceId?: Following['id']; - untilId?: Following['id']; + 'pages/update': { + req: TODO; + res: null; }; - res: FollowingFolloweePopulated[]; - }; - 'users/gallery/posts': { - req: TODO; - res: TODO; - }; - 'users/get-frequently-replied-users': { - req: TODO; - res: TODO; - }; - 'users/groups/create': { - req: TODO; - res: TODO; - }; - 'users/groups/delete': { - req: { - groupId: UserGroup['id']; - }; - res: null; - }; - 'users/groups/invitations/accept': { - req: TODO; - res: TODO; - }; - 'users/groups/invitations/reject': { - req: TODO; - res: TODO; - }; - 'users/groups/invite': { - req: TODO; - res: TODO; - }; - 'users/groups/joined': { - req: TODO; - res: TODO; - }; - 'users/groups/owned': { - req: TODO; - res: TODO; - }; - 'users/groups/pull': { - req: TODO; - res: TODO; - }; - 'users/groups/show': { - req: TODO; - res: TODO; - }; - 'users/groups/transfer': { - req: TODO; - res: TODO; - }; - 'users/groups/update': { - req: TODO; - res: TODO; - }; - 'users/lists/create': { - req: { - name: string; - }; - res: UserList; - }; - 'users/lists/delete': { - req: { - listId: UserList['id']; - }; - res: null; - }; - 'users/lists/list': { - req: NoParams; - res: UserList[]; - }; - 'users/lists/pull': { - req: { - listId: UserList['id']; - userId: User['id']; - }; - res: null; - }; - 'users/lists/push': { - req: { - listId: UserList['id']; - userId: User['id']; - }; - res: null; - }; - 'users/lists/show': { - req: { - listId: UserList['id']; - }; - res: UserList; - }; - 'users/lists/update': { - req: { - listId: UserList['id']; - name: string; - }; - res: UserList; - }; - 'users/notes': { - req: { - userId: User['id']; - limit?: number; - sinceId?: Note['id']; - untilId?: Note['id']; - sinceDate?: number; - untilDate?: number; - }; - res: Note[]; - }; - 'users/pages': { - req: TODO; - res: TODO; - }; - 'users/recommendation': { - req: TODO; - res: TODO; - }; - 'users/relation': { - req: TODO; - res: TODO; - }; - 'users/report-abuse': { - req: TODO; - res: TODO; - }; - 'users/search-by-username-and-host': { - req: TODO; - res: TODO; - }; - 'users/search': { - req: TODO; - res: TODO; - }; - 'users/show': { - req: ShowUserReq | { - userIds: User['id'][]; - }; - res: { - $switch: { - $cases: [ - [ - { - userIds: User['id'][]; - }, - UserDetailed[] - ] - ]; - $default: UserDetailed; + 'ping': { + req: NoParams; + res: { + pong: number; }; }; + 'pinned-users': { + req: TODO; + res: TODO; + }; + 'promo/read': { + req: TODO; + res: TODO; + }; + 'request-reset-password': { + req: { + username: string; + email: string; + }; + res: null; + }; + 'reset-password': { + req: { + token: string; + password: string; + }; + res: null; + }; + 'room/show': { + req: TODO; + res: TODO; + }; + 'room/update': { + req: TODO; + res: TODO; + }; + 'stats': { + req: NoParams; + res: Stats; + }; + 'server-info': { + req: NoParams; + res: ServerInfo; + }; + 'sw/register': { + req: TODO; + res: TODO; + }; + 'username/available': { + req: { + username: string; + }; + res: { + available: boolean; + }; + }; + 'users': { + req: { + limit?: number; + offset?: number; + sort?: UserSorting; + origin?: OriginType; + }; + res: User[]; + }; + 'users/clips': { + req: TODO; + res: TODO; + }; + 'users/followers': { + req: { + userId?: User['id']; + username?: User['username']; + host?: User['host'] | null; + limit?: number; + sinceId?: Following['id']; + untilId?: Following['id']; + }; + res: FollowingFollowerPopulated[]; + }; + 'users/following': { + req: { + userId?: User['id']; + username?: User['username']; + host?: User['host'] | null; + limit?: number; + sinceId?: Following['id']; + untilId?: Following['id']; + }; + res: FollowingFolloweePopulated[]; + }; + 'users/gallery/posts': { + req: TODO; + res: TODO; + }; + 'users/get-frequently-replied-users': { + req: TODO; + res: TODO; + }; + 'users/groups/create': { + req: TODO; + res: TODO; + }; + 'users/groups/delete': { + req: { + groupId: UserGroup['id']; + }; + res: null; + }; + 'users/groups/invitations/accept': { + req: TODO; + res: TODO; + }; + 'users/groups/invitations/reject': { + req: TODO; + res: TODO; + }; + 'users/groups/invite': { + req: TODO; + res: TODO; + }; + 'users/groups/joined': { + req: TODO; + res: TODO; + }; + 'users/groups/owned': { + req: TODO; + res: TODO; + }; + 'users/groups/pull': { + req: TODO; + res: TODO; + }; + 'users/groups/show': { + req: TODO; + res: TODO; + }; + 'users/groups/transfer': { + req: TODO; + res: TODO; + }; + 'users/groups/update': { + req: TODO; + res: TODO; + }; + 'users/lists/create': { + req: { + name: string; + }; + res: UserList; + }; + 'users/lists/delete': { + req: { + listId: UserList['id']; + }; + res: null; + }; + 'users/lists/list': { + req: NoParams; + res: UserList[]; + }; + 'users/lists/pull': { + req: { + listId: UserList['id']; + userId: User['id']; + }; + res: null; + }; + 'users/lists/push': { + req: { + listId: UserList['id']; + userId: User['id']; + }; + res: null; + }; + 'users/lists/show': { + req: { + listId: UserList['id']; + }; + res: UserList; + }; + 'users/lists/update': { + req: { + listId: UserList['id']; + name: string; + }; + res: UserList; + }; + 'users/notes': { + req: { + userId: User['id']; + limit?: number; + sinceId?: Note['id']; + untilId?: Note['id']; + sinceDate?: number; + untilDate?: number; + }; + res: Note[]; + }; + 'users/pages': { + req: TODO; + res: TODO; + }; + 'users/recommendation': { + req: TODO; + res: TODO; + }; + 'users/relation': { + req: TODO; + res: TODO; + }; + 'users/report-abuse': { + req: TODO; + res: TODO; + }; + 'users/search-by-username-and-host': { + req: TODO; + res: TODO; + }; + 'users/search': { + req: TODO; + res: TODO; + }; + 'users/show': { + req: ShowUserReq | { + userIds: User['id'][]; + }; + res: { + $switch: { + $cases: [ + [ + { + userIds: User['id'][]; + }, + UserDetailed[] + ] + ]; + $default: UserDetailed; + }; + }; + }; + 'users/stats': { + req: TODO; + res: TODO; + }; }; - 'users/stats': { - req: TODO; - res: TODO; - }; -}; -declare namespace entities { - export { - ID, - DateString, - User, - UserLite, - UserDetailed, - UserGroup, - UserList, - MeDetailed, - DriveFile, - DriveFolder, - GalleryPost, - Note, - NoteReaction, - Notification_2 as Notification, - MessagingMessage, - CustomEmoji, - LiteInstanceMetadata, - DetailedInstanceMetadata, - InstanceMetadata, - ServerInfo, - Stats, - Page, - PageEvent, - Announcement, - Antenna, - App, - AuthSession, - Ad, - Clip, - NoteFavorite, - FollowRequest, - Channel, - Following, - FollowingFolloweePopulated, - FollowingFollowerPopulated, - Blocking, - Instance, - Signin, - UserSorting, - OriginType + declare namespace entities { + export { + ID, + DateString, + User, + UserLite, + UserDetailed, + UserGroup, + UserList, + MeDetailed, + DriveFile, + DriveFolder, + GalleryPost, + Note, + NoteReaction, + Notification_2 as Notification, + MessagingMessage, + CustomEmoji, + LiteInstanceMetadata, + DetailedInstanceMetadata, + InstanceMetadata, + ServerInfo, + Stats, + Page, + PageEvent, + Announcement, + Antenna, + App, + AuthSession, + Ad, + Clip, + NoteFavorite, + FollowRequest, + Channel, + Following, + FollowingFolloweePopulated, + FollowingFollowerPopulated, + Blocking, + Instance, + Signin, + UserSorting, + OriginType + } } -} -export { entities } + export { entities } -// @public (undocumented) -type FetchLike = (input: string, init?: { - method?: string; - body?: string; - credentials?: RequestCredentials; - cache?: RequestCache; - headers: { - [key in string]: string; - }; -}) => Promise<{ - status: number; - json(): Promise; -}>; + // @public (undocumented) + type FetchLike = (input: string, init?: { + method?: string; + body?: string; + credentials?: RequestCredentials; + cache?: RequestCache; + headers: { + [key in string]: string; + }; + }) => Promise<{ + status: number; + json(): Promise; + }>; -// @public (undocumented) -export const ffVisibility: readonly ["public", "followers", "private"]; + // @public (undocumented) + export const ffVisibility: readonly ["public", "followers", "private"]; -// @public (undocumented) -type Following = { - id: ID; - createdAt: DateString; - followerId: User['id']; - followeeId: User['id']; -}; - -// @public (undocumented) -type FollowingFolloweePopulated = Following & { - followee: UserDetailed; -}; - -// @public (undocumented) -type FollowingFollowerPopulated = Following & { - follower: UserDetailed; -}; - -// @public (undocumented) -type FollowRequest = { - id: ID; - follower: User; - followee: User; -}; - -// @public (undocumented) -type GalleryPost = { - id: ID; - createdAt: DateString; - updatedAt: DateString; - userId: User['id']; - user: User; - title: string; - description: string | null; - fileIds: DriveFile['id'][]; - files: DriveFile[]; - isSensitive: boolean; - likedCount: number; - isLiked?: boolean; -}; - -// @public (undocumented) -type ID = string; - -// @public (undocumented) -type Instance = { - id: ID; - caughtAt: DateString; - host: string; - usersCount: number; - notesCount: number; - followingCount: number; - followersCount: number; - driveUsage: number; - driveFiles: number; - latestRequestSentAt: DateString | null; - latestStatus: number | null; - latestRequestReceivedAt: DateString | null; - lastCommunicatedAt: DateString; - isNotResponding: boolean; - isSuspended: boolean; - softwareName: string | null; - softwareVersion: string | null; - openRegistrations: boolean | null; - name: string | null; - description: string | null; - maintainerName: string | null; - maintainerEmail: string | null; - iconUrl: string | null; - faviconUrl: string | null; - themeColor: string | null; - infoUpdatedAt: DateString | null; -}; - -// @public (undocumented) -type InstanceMetadata = LiteInstanceMetadata | DetailedInstanceMetadata; - -// @public (undocumented) -function isAPIError(reason: any): reason is APIError; - -// @public (undocumented) -type LiteInstanceMetadata = { - maintainerName: string | null; - maintainerEmail: string | null; - version: string; - name: string | null; - uri: string; - description: string | null; - langs: string[]; - tosUrl: string | null; - repositoryUrl: string; - feedbackUrl: string; - disableRegistration: boolean; - disableLocalTimeline: boolean; - disableGlobalTimeline: boolean; - driveCapacityPerLocalUserMb: number; - driveCapacityPerRemoteUserMb: number; - emailRequiredForSignup: boolean; - enableHcaptcha: boolean; - hcaptchaSiteKey: string | null; - enableRecaptcha: boolean; - recaptchaSiteKey: string | null; - enableTurnstile: boolean; - turnstileSiteKey: string | null; - swPublickey: string | null; - themeColor: string | null; - mascotImageUrl: string | null; - bannerUrl: string | null; - errorImageUrl: string | null; - iconUrl: string | null; - backgroundImageUrl: string | null; - logoImageUrl: string | null; - maxNoteTextLength: number; - enableEmail: boolean; - enableTwitterIntegration: boolean; - enableGithubIntegration: boolean; - enableDiscordIntegration: boolean; - enableServiceWorker: boolean; - emojis: CustomEmoji[]; - defaultDarkTheme: string | null; - defaultLightTheme: string | null; - ads: { + // @public (undocumented) + type Following = { id: ID; - ratio: number; - place: string; - url: string; - imageUrl: string; - }[]; - translatorAvailable: boolean; -}; + createdAt: DateString; + followerId: User['id']; + followeeId: User['id']; + }; -// @public (undocumented) -type MeDetailed = UserDetailed & { - avatarId: DriveFile['id']; - bannerId: DriveFile['id']; - autoAcceptFollowed: boolean; - alwaysMarkNsfw: boolean; - carefulBot: boolean; - emailNotificationTypes: string[]; - hasPendingReceivedFollowRequest: boolean; - hasUnreadAnnouncement: boolean; - hasUnreadAntenna: boolean; - hasUnreadMentions: boolean; - hasUnreadMessagingMessage: boolean; - hasUnreadNotification: boolean; - hasUnreadSpecifiedNotes: boolean; - hideOnlineStatus: boolean; - injectFeaturedNote: boolean; - integrations: Record; - isDeleted: boolean; - isExplorable: boolean; - mutedWords: string[][]; - mutingNotificationTypes: string[]; - noCrawle: boolean; - receiveAnnouncementEmail: boolean; - usePasswordLessLogin: boolean; - [other: string]: any; -}; + // @public (undocumented) + type FollowingFolloweePopulated = Following & { + followee: UserDetailed; + }; -// @public (undocumented) -type MessagingMessage = { - id: ID; - createdAt: DateString; - file: DriveFile | null; - fileId: DriveFile['id'] | null; - isRead: boolean; - reads: User['id'][]; - text: string | null; - user: User; - userId: User['id']; - recipient?: User | null; - recipientId: User['id'] | null; - group?: UserGroup | null; - groupId: UserGroup['id'] | null; -}; + // @public (undocumented) + type FollowingFollowerPopulated = Following & { + follower: UserDetailed; + }; -// @public (undocumented) -export const mutedNoteReasons: readonly ["word", "manual", "spam", "other"]; + // @public (undocumented) + type FollowRequest = { + id: ID; + follower: User; + followee: User; + }; -// @public (undocumented) -type Note = { - id: ID; - createdAt: DateString; - text: string | null; - cw: string | null; - user: User; - userId: User['id']; - reply?: Note; - replyId: Note['id']; - renote?: Note; - renoteId: Note['id']; - files: DriveFile[]; - fileIds: DriveFile['id'][]; - visibility: 'public' | 'home' | 'followers' | 'specified'; - visibleUserIds?: User['id'][]; - localOnly?: boolean; - myReaction?: string; - reactions: Record; - renoteCount: number; - repliesCount: number; - poll?: { - expiresAt: DateString | null; - multiple: boolean; - choices: { - isVoted: boolean; - text: string; - votes: number; + // @public (undocumented) + type GalleryPost = { + id: ID; + createdAt: DateString; + updatedAt: DateString; + userId: User['id']; + user: User; + title: string; + description: string | null; + fileIds: DriveFile['id'][]; + files: DriveFile[]; + isSensitive: boolean; + likedCount: number; + isLiked?: boolean; + }; + + // @public (undocumented) + type ID = string; + + // @public (undocumented) + type Instance = { + id: ID; + caughtAt: DateString; + host: string; + usersCount: number; + notesCount: number; + followingCount: number; + followersCount: number; + driveUsage: number; + driveFiles: number; + latestRequestSentAt: DateString | null; + latestStatus: number | null; + latestRequestReceivedAt: DateString | null; + lastCommunicatedAt: DateString; + isNotResponding: boolean; + isSuspended: boolean; + softwareName: string | null; + softwareVersion: string | null; + openRegistrations: boolean | null; + name: string | null; + description: string | null; + maintainerName: string | null; + maintainerEmail: string | null; + iconUrl: string | null; + faviconUrl: string | null; + themeColor: string | null; + infoUpdatedAt: DateString | null; + }; + + // @public (undocumented) + type InstanceMetadata = LiteInstanceMetadata | DetailedInstanceMetadata; + + // @public (undocumented) + function isAPIError(reason: any): reason is APIError; + + // @public (undocumented) + type LiteInstanceMetadata = { + maintainerName: string | null; + maintainerEmail: string | null; + version: string; + name: string | null; + uri: string; + description: string | null; + langs: string[]; + tosUrl: string | null; + repositoryUrl: string; + feedbackUrl: string; + disableRegistration: boolean; + disableLocalTimeline: boolean; + disableGlobalTimeline: boolean; + driveCapacityPerLocalUserMb: number; + driveCapacityPerRemoteUserMb: number; + emailRequiredForSignup: boolean; + enableHcaptcha: boolean; + hcaptchaSiteKey: string | null; + enableRecaptcha: boolean; + recaptchaSiteKey: string | null; + enableTurnstile: boolean; + turnstileSiteKey: string | null; + swPublickey: string | null; + themeColor: string | null; + mascotImageUrl: string | null; + bannerUrl: string | null; + errorImageUrl: string | null; + iconUrl: string | null; + backgroundImageUrl: string | null; + logoImageUrl: string | null; + maxNoteTextLength: number; + enableEmail: boolean; + enableTwitterIntegration: boolean; + enableGithubIntegration: boolean; + enableDiscordIntegration: boolean; + enableServiceWorker: boolean; + emojis: CustomEmoji[]; + defaultDarkTheme: string | null; + defaultLightTheme: string | null; + ads: { + id: ID; + ratio: number; + place: string; + url: string; + imageUrl: string; }[]; + translatorAvailable: boolean; }; - emojis: { - name: string; - url: string; - }[]; - uri?: string; - url?: string; - isHidden?: boolean; -}; -// @public (undocumented) -type NoteFavorite = { - id: ID; - createdAt: DateString; - noteId: Note['id']; - note: Note; -}; - -// @public (undocumented) -type NoteReaction = { - id: ID; - createdAt: DateString; - user: UserLite; - type: string; -}; - -// @public (undocumented) -export const noteVisibilities: readonly ["public", "home", "followers", "specified"]; - -// @public (undocumented) -type Notification_2 = { - id: ID; - createdAt: DateString; - isRead: boolean; -} & ({ - type: 'reaction'; - reaction: string; - user: User; - userId: User['id']; - note: Note; -} | { - type: 'reply'; - user: User; - userId: User['id']; - note: Note; -} | { - type: 'renote'; - user: User; - userId: User['id']; - note: Note; -} | { - type: 'quote'; - user: User; - userId: User['id']; - note: Note; -} | { - type: 'mention'; - user: User; - userId: User['id']; - note: Note; -} | { - type: 'pollVote'; - user: User; - userId: User['id']; - note: Note; -} | { - type: 'follow'; - user: User; - userId: User['id']; -} | { - type: 'followRequestAccepted'; - user: User; - userId: User['id']; -} | { - type: 'receiveFollowRequest'; - user: User; - userId: User['id']; -} | { - type: 'groupInvited'; - invitation: UserGroup; - user: User; - userId: User['id']; -} | { - type: 'app'; - header?: string | null; - body: string; - icon?: string | null; -}); - -// @public (undocumented) -export const notificationTypes: readonly ["follow", "mention", "reply", "renote", "quote", "reaction", "pollVote", "pollEnded", "receiveFollowRequest", "followRequestAccepted", "groupInvited", "app"]; - -// @public (undocumented) -type OriginType = 'combined' | 'local' | 'remote'; - -// @public (undocumented) -type Page = { - id: ID; - createdAt: DateString; - updatedAt: DateString; - userId: User['id']; - user: User; - content: Record[]; - variables: Record[]; - title: string; - name: string; - summary: string | null; - hideTitleWhenPinned: boolean; - alignCenter: boolean; - font: string; - script: string; - eyeCatchingImageId: DriveFile['id'] | null; - eyeCatchingImage: DriveFile | null; - attachedFiles: any; - likedCount: number; - isLiked?: boolean; -}; - -// @public (undocumented) -type PageEvent = { - pageId: Page['id']; - event: string; - var: any; - userId: User['id']; - user: User; -}; - -// @public (undocumented) -export const permissions: string[]; - -// @public (undocumented) -type ServerInfo = { - machine: string; - cpu: { - model: string; - cores: number; + // @public (undocumented) + type MeDetailed = UserDetailed & { + avatarId: DriveFile['id']; + bannerId: DriveFile['id']; + autoAcceptFollowed: boolean; + alwaysMarkNsfw: boolean; + carefulBot: boolean; + emailNotificationTypes: string[]; + hasPendingReceivedFollowRequest: boolean; + hasUnreadAnnouncement: boolean; + hasUnreadAntenna: boolean; + hasUnreadMentions: boolean; + hasUnreadMessagingMessage: boolean; + hasUnreadNotification: boolean; + hasUnreadSpecifiedNotes: boolean; + hideOnlineStatus: boolean; + injectFeaturedNote: boolean; + integrations: Record; + isDeleted: boolean; + isExplorable: boolean; + mutedWords: string[][]; + mutingNotificationTypes: string[]; + noCrawle: boolean; + receiveAnnouncementEmail: boolean; + usePasswordLessLogin: boolean; + [other: string]: any; }; - mem: { - total: number; + + // @public (undocumented) + type MessagingMessage = { + id: ID; + createdAt: DateString; + file: DriveFile | null; + fileId: DriveFile['id'] | null; + isRead: boolean; + reads: User['id'][]; + text: string | null; + user: User; + userId: User['id']; + recipient?: User | null; + recipientId: User['id'] | null; + group?: UserGroup | null; + groupId: UserGroup['id'] | null; }; - fs: { - total: number; - used: number; + + // @public (undocumented) + export const mutedNoteReasons: readonly ["word", "manual", "spam", "other"]; + + // @public (undocumented) + type Note = { + id: ID; + createdAt: DateString; + text: string | null; + cw: string | null; + user: User; + userId: User['id']; + reply?: Note; + replyId: Note['id']; + renote?: Note; + renoteId: Note['id']; + event?: { + title: string; + start: DateString; + end: DateString | null; + metadata: Record; + }; + files: DriveFile[]; + fileIds: DriveFile['id'][]; + visibility: 'public' | 'home' | 'followers' | 'specified'; + visibleUserIds?: User['id'][]; + localOnly?: boolean; + myReaction?: string; + reactions: Record; + renoteCount: number; + repliesCount: number; + poll?: { + expiresAt: DateString | null; + multiple: boolean; + choices: { + isVoted: boolean; + text: string; + votes: number; + }[]; + }; + emojis: { + name: string; + url: string; + }[]; + uri?: string; + url?: string; + isHidden?: boolean; }; -}; -// @public (undocumented) -type Signin = { - id: ID; - createdAt: DateString; - ip: string; - headers: Record; - success: boolean; -}; + // @public (undocumented) + type NoteFavorite = { + id: ID; + createdAt: DateString; + noteId: Note['id']; + note: Note; + }; -// @public (undocumented) -type Stats = { - notesCount: number; - originalNotesCount: number; - usersCount: number; - originalUsersCount: number; - instances: number; - driveUsageLocal: number; - driveUsageRemote: number; -}; + // @public (undocumented) + type NoteReaction = { + id: ID; + createdAt: DateString; + user: UserLite; + type: string; + }; -// Warning: (ae-forgotten-export) The symbol "StreamEvents" needs to be exported by the entry point index.d.ts -// -// @public (undocumented) -export class Stream extends EventEmitter { - constructor(origin: string, user: { - token: string; - } | null, options?: { - WebSocket?: any; + // @public (undocumented) + export const noteVisibilities: readonly ["public", "home", "followers", "specified"]; + + // @public (undocumented) + type Notification_2 = { + id: ID; + createdAt: DateString; + isRead: boolean; + } & ({ + type: 'reaction'; + reaction: string; + user: User; + userId: User['id']; + note: Note; + } | { + type: 'reply'; + user: User; + userId: User['id']; + note: Note; + } | { + type: 'renote'; + user: User; + userId: User['id']; + note: Note; + } | { + type: 'quote'; + user: User; + userId: User['id']; + note: Note; + } | { + type: 'mention'; + user: User; + userId: User['id']; + note: Note; + } | { + type: 'pollVote'; + user: User; + userId: User['id']; + note: Note; + } | { + type: 'follow'; + user: User; + userId: User['id']; + } | { + type: 'followRequestAccepted'; + user: User; + userId: User['id']; + } | { + type: 'receiveFollowRequest'; + user: User; + userId: User['id']; + } | { + type: 'groupInvited'; + invitation: UserGroup; + user: User; + userId: User['id']; + } | { + type: 'app'; + header?: string | null; + body: string; + icon?: string | null; }); - // (undocumented) - close(): void; - // Warning: (ae-forgotten-export) The symbol "NonSharedConnection" needs to be exported by the entry point index.d.ts - // - // (undocumented) - disconnectToChannel(connection: NonSharedConnection): void; - // Warning: (ae-forgotten-export) The symbol "SharedConnection" needs to be exported by the entry point index.d.ts - // - // (undocumented) - removeSharedConnection(connection: SharedConnection): void; - // Warning: (ae-forgotten-export) The symbol "Pool" needs to be exported by the entry point index.d.ts - // - // (undocumented) - removeSharedConnectionPool(pool: Pool): void; - // (undocumented) - send(typeOrPayload: string): void; - // (undocumented) - send(typeOrPayload: string, payload: any): void; - // (undocumented) - send(typeOrPayload: Record | any[]): void; - // (undocumented) - state: 'initializing' | 'reconnecting' | 'connected'; - // (undocumented) - useChannel(channel: C, params?: Channels[C]['params'], name?: string): ChannelConnection; -} -// @public (undocumented) -type User = UserLite | UserDetailed; + // @public (undocumented) + export const notificationTypes: readonly ["follow", "mention", "reply", "renote", "quote", "reaction", "pollVote", "pollEnded", "receiveFollowRequest", "followRequestAccepted", "groupInvited", "app"]; -// @public (undocumented) -type UserDetailed = UserLite & { - bannerBlurhash: string | null; - bannerColor: string | null; - bannerUrl: string | null; - birthday: string | null; - createdAt: DateString; - description: string | null; - ffVisibility: 'public' | 'followers' | 'private'; - fields: { + // @public (undocumented) + type OriginType = 'combined' | 'local' | 'remote'; + + // @public (undocumented) + type Page = { + id: ID; + createdAt: DateString; + updatedAt: DateString; + userId: User['id']; + user: User; + content: Record[]; + variables: Record[]; + title: string; name: string; - value: string; - }[]; - followersCount: number; - followingCount: number; - hasPendingFollowRequestFromYou: boolean; - hasPendingFollowRequestToYou: boolean; - isAdmin: boolean; - isBlocked: boolean; - isBlocking: boolean; - isBot: boolean; - isCat: boolean; - isFollowed: boolean; - isFollowing: boolean; - isLocked: boolean; - isModerator: boolean; - isMuted: boolean; - isSilenced: boolean; - isSuspended: boolean; - lang: string | null; - lastFetchedAt?: DateString; - location: string | null; - notesCount: number; - pinnedNoteIds: ID[]; - pinnedNotes: Note[]; - pinnedPage: Page | null; - pinnedPageId: string | null; - publicReactions: boolean; - securityKeys: boolean; - twoFactorEnabled: boolean; - updatedAt: DateString | null; - uri: string | null; - url: string | null; -}; - -// @public (undocumented) -type UserGroup = TODO_2; - -// @public (undocumented) -type UserList = { - id: ID; - createdAt: DateString; - name: string; - userIds: User['id'][]; -}; - -// @public (undocumented) -type UserLite = { - id: ID; - username: string; - host: string | null; - name: string; - onlineStatus: 'online' | 'active' | 'offline' | 'unknown'; - avatarUrl: string; - avatarBlurhash: string; - alsoKnownAs: string[]; - movedToUri: any; - emojis: { - name: string; - url: string; - }[]; - instance?: { - name: Instance['name']; - softwareName: Instance['softwareName']; - softwareVersion: Instance['softwareVersion']; - iconUrl: Instance['iconUrl']; - faviconUrl: Instance['faviconUrl']; - themeColor: Instance['themeColor']; + summary: string | null; + hideTitleWhenPinned: boolean; + alignCenter: boolean; + font: string; + script: string; + eyeCatchingImageId: DriveFile['id'] | null; + eyeCatchingImage: DriveFile | null; + attachedFiles: any; + likedCount: number; + isLiked?: boolean; }; -}; -// @public (undocumented) -type UserSorting = '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+updatedAt' | '-updatedAt'; + // @public (undocumented) + type PageEvent = { + pageId: Page['id']; + event: string; + var: any; + userId: User['id']; + user: User; + }; -// Warnings were encountered during analysis: -// -// src/api.types.ts:16:32 - (ae-forgotten-export) The symbol "TODO" needs to be exported by the entry point index.d.ts -// src/api.types.ts:18:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts -// src/api.types.ts:596:18 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts -// src/streaming.types.ts:33:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts + // @public (undocumented) + export const permissions: string[]; -// (No @packageDocumentation comment for this package) + // @public (undocumented) + type ServerInfo = { + machine: string; + cpu: { + model: string; + cores: number; + }; + mem: { + total: number; + }; + fs: { + total: number; + used: number; + }; + }; -``` + // @public (undocumented) + type Signin = { + id: ID; + createdAt: DateString; + ip: string; + headers: Record; + success: boolean; + }; + + // @public (undocumented) + type Stats = { + notesCount: number; + originalNotesCount: number; + usersCount: number; + originalUsersCount: number; + instances: number; + driveUsageLocal: number; + driveUsageRemote: number; + }; + + // Warning: (ae-forgotten-export) The symbol "StreamEvents" needs to be exported by the entry point index.d.ts + // + // @public (undocumented) + export class Stream extends EventEmitter { + constructor(origin: string, user: { + token: string; + } | null, options?: { + WebSocket?: any; + }); + // (undocumented) + close(): void; + // Warning: (ae-forgotten-export) The symbol "NonSharedConnection" needs to be exported by the entry point index.d.ts + // + // (undocumented) + disconnectToChannel(connection: NonSharedConnection): void; + // Warning: (ae-forgotten-export) The symbol "SharedConnection" needs to be exported by the entry point index.d.ts + // + // (undocumented) + removeSharedConnection(connection: SharedConnection): void; + // Warning: (ae-forgotten-export) The symbol "Pool" needs to be exported by the entry point index.d.ts + // + // (undocumented) + removeSharedConnectionPool(pool: Pool): void; + // (undocumented) + send(typeOrPayload: string): void; + // (undocumented) + send(typeOrPayload: string, payload: any): void; + // (undocumented) + send(typeOrPayload: Record | any[]): void; + // (undocumented) + state: 'initializing' | 'reconnecting' | 'connected'; + // (undocumented) + useChannel(channel: C, params?: Channels[C]['params'], name?: string): ChannelConnection; + } + + // @public (undocumented) + type User = UserLite | UserDetailed; + + // @public (undocumented) + type UserDetailed = UserLite & { + bannerBlurhash: string | null; + bannerColor: string | null; + bannerUrl: string | null; + birthday: string | null; + createdAt: DateString; + description: string | null; + ffVisibility: 'public' | 'followers' | 'private'; + fields: { + name: string; + value: string; + }[]; + followersCount: number; + followingCount: number; + hasPendingFollowRequestFromYou: boolean; + hasPendingFollowRequestToYou: boolean; + isAdmin: boolean; + isBlocked: boolean; + isBlocking: boolean; + isBot: boolean; + isCat: boolean; + isFollowed: boolean; + isFollowing: boolean; + isLocked: boolean; + isModerator: boolean; + isMuted: boolean; + isSilenced: boolean; + isSuspended: boolean; + lang: string | null; + lastFetchedAt?: DateString; + location: string | null; + notesCount: number; + pinnedNoteIds: ID[]; + pinnedNotes: Note[]; + pinnedPage: Page | null; + pinnedPageId: string | null; + publicReactions: boolean; + securityKeys: boolean; + twoFactorEnabled: boolean; + updatedAt: DateString | null; + uri: string | null; + url: string | null; + }; + + // @public (undocumented) + type UserGroup = TODO_2; + + // @public (undocumented) + type UserList = { + id: ID; + createdAt: DateString; + name: string; + userIds: User['id'][]; + }; + + // @public (undocumented) + type UserLite = { + id: ID; + username: string; + host: string | null; + name: string; + onlineStatus: 'online' | 'active' | 'offline' | 'unknown'; + avatarUrl: string; + avatarBlurhash: string; + alsoKnownAs: string[]; + movedToUri: any; + emojis: { + name: string; + url: string; + }[]; + instance?: { + name: Instance['name']; + softwareName: Instance['softwareName']; + softwareVersion: Instance['softwareVersion']; + iconUrl: Instance['iconUrl']; + faviconUrl: Instance['faviconUrl']; + themeColor: Instance['themeColor']; + }; + }; + + // @public (undocumented) + type UserSorting = '+follower' | '-follower' | '+createdAt' | '-createdAt' | '+updatedAt' | '-updatedAt'; + + // Warnings were encountered during analysis: + // + // src/api.types.ts:16:32 - (ae-forgotten-export) The symbol "TODO" needs to be exported by the entry point index.d.ts + // src/api.types.ts:18:25 - (ae-forgotten-export) The symbol "NoParams" needs to be exported by the entry point index.d.ts + // src/api.types.ts:602:27 - (ae-forgotten-export) The symbol "ShowUserReq" needs to be exported by the entry point index.d.ts + // src/streaming.types.ts:33:4 - (ae-forgotten-export) The symbol "FIXME" needs to be exported by the entry point index.d.ts + + // (No @packageDocumentation comment for this package) + + ``` diff --git a/packages/misskey-js/src/api.types.ts b/packages/misskey-js/src/api.types.ts index aed9f5bf84..3ca1f3d36d 100644 --- a/packages/misskey-js/src/api.types.ts +++ b/packages/misskey-js/src/api.types.ts @@ -499,6 +499,7 @@ export type Endpoints = { 'notes/mentions': { req: { following?: boolean; limit?: number; sinceId?: Note['id']; untilId?: Note['id']; }; res: Note[]; }; 'notes/polls/recommendation': { req: TODO; res: TODO; }; 'notes/polls/vote': { req: { noteId: Note['id']; choice: number; }; res: null; }; + 'notes/events/search': { req: TODO; res: Note[]; }; 'notes/reactions': { req: { noteId: Note['id']; type?: string | null; limit?: number; }; res: NoteReaction[]; }; 'notes/reactions/create': { req: { noteId: Note['id']; reaction: string; }; res: null; }; 'notes/reactions/delete': { req: { noteId: Note['id']; }; res: null; };