refactor: fix types

This commit is contained in:
syuilo 2023-02-12 18:47:30 +09:00
parent d7a2d59f41
commit 451bc0b444
24 changed files with 142 additions and 130 deletions

View File

@ -32,7 +32,7 @@ export class AccountUpdateService {
// フォロワーがリモートユーザーかつ投稿者がローカルユーザーならUpdateを配信
if (this.userEntityService.isLocalUser(user)) {
const content = this.apRendererService.renderActivity(this.apRendererService.renderUpdate(await this.apRendererService.renderPerson(user), user));
const content = this.apRendererService.addContext(this.apRendererService.renderUpdate(await this.apRendererService.renderPerson(user), user));
this.apDeliverManagerService.deliverToFollowers(user, content);
this.relayService.deliverToRelays(user, content);
}

View File

@ -135,7 +135,7 @@ export class MessagingService {
}))),
} as Note;
const activity = this.apRendererService.renderActivity(this.apRendererService.renderCreate(await this.apRendererService.renderNote(note, false, true), note));
const activity = this.apRendererService.addContext(this.apRendererService.renderCreate(await this.apRendererService.renderNote(note, false, true), note));
this.queueService.deliver(user, activity, recipientUser.inbox);
}
@ -158,7 +158,7 @@ export class MessagingService {
if (this.userEntityService.isLocalUser(recipient)) this.globalEventService.publishMessagingStream(message.recipientId, message.userId, 'deleted', message.id);
if (this.userEntityService.isLocalUser(user) && this.userEntityService.isRemoteUser(recipient)) {
const activity = this.apRendererService.renderActivity(this.apRendererService.renderDelete(this.apRendererService.renderTombstone(`${this.config.url}/notes/${message.id}`), user));
const activity = this.apRendererService.addContext(this.apRendererService.renderDelete(this.apRendererService.renderTombstone(`${this.config.url}/notes/${message.id}`), user));
this.queueService.deliver(user, activity, recipient.inbox);
}
} else if (message.groupId) {
@ -297,10 +297,10 @@ export class MessagingService {
if (contents.length > 1) {
const collection = this.apRendererService.renderOrderedCollection(null, contents.length, undefined, undefined, contents);
this.queueService.deliver(user, this.apRendererService.renderActivity(collection), recipient.inbox);
this.queueService.deliver(user, this.apRendererService.addContext(collection), recipient.inbox);
} else {
for (const content of contents) {
this.queueService.deliver(user, this.apRendererService.renderActivity(content), recipient.inbox);
this.queueService.deliver(user, this.apRendererService.addContext(content), recipient.inbox);
}
}
}

View File

@ -711,7 +711,7 @@ export class NoteCreateService {
? this.apRendererService.renderAnnounce(data.renote.uri ? data.renote.uri : `${this.config.url}/notes/${data.renote.id}`, note)
: this.apRendererService.renderCreate(await this.apRendererService.renderNote(note, false), note);
return this.apRendererService.renderActivity(content);
return this.apRendererService.addContext(content);
}
@bindThis

View File

@ -78,7 +78,7 @@ export class NoteDeleteService {
});
}
const content = this.apRendererService.renderActivity(renote
const content = this.apRendererService.addContext(renote
? this.apRendererService.renderUndo(this.apRendererService.renderAnnounce(renote.uri ?? `${this.config.url}/notes/${renote.id}`, note), user)
: this.apRendererService.renderDelete(this.apRendererService.renderTombstone(`${this.config.url}/notes/${note.id}`), user));
@ -90,7 +90,7 @@ export class NoteDeleteService {
for (const cascadingNote of cascadingNotes) {
if (!cascadingNote.user) continue;
if (!this.userEntityService.isLocalUser(cascadingNote.user)) continue;
const content = this.apRendererService.renderActivity(this.apRendererService.renderDelete(this.apRendererService.renderTombstone(`${this.config.url}/notes/${cascadingNote.id}`), cascadingNote.user));
const content = this.apRendererService.addContext(this.apRendererService.renderDelete(this.apRendererService.renderTombstone(`${this.config.url}/notes/${cascadingNote.id}`), cascadingNote.user));
this.deliverToConcerned(cascadingNote.user, cascadingNote, content);
}
//#endregion

View File

@ -115,7 +115,7 @@ export class NotePiningService {
const target = `${this.config.url}/users/${user.id}/collections/featured`;
const item = `${this.config.url}/notes/${noteId}`;
const content = this.apRendererService.renderActivity(isAddition ? this.apRendererService.renderAdd(user, target, item) : this.apRendererService.renderRemove(user, target, item));
const content = this.apRendererService.addContext(isAddition ? this.apRendererService.renderAdd(user, target, item) : this.apRendererService.renderRemove(user, target, item));
this.apDeliverManagerService.deliverToFollowers(user, content);
this.relayService.deliverToRelays(user, content);

View File

@ -97,7 +97,7 @@ export class PollService {
if (user == null) throw new Error('note not found');
if (this.userEntityService.isLocalUser(user)) {
const content = this.apRendererService.renderActivity(this.apRendererService.renderUpdate(await this.apRendererService.renderNote(note, false), user));
const content = this.apRendererService.addContext(this.apRendererService.renderUpdate(await this.apRendererService.renderNote(note, false), user));
this.apDeliverManagerService.deliverToFollowers(user, content);
this.relayService.deliverToRelays(user, content);
}

View File

@ -85,7 +85,7 @@ export class ReactionService {
}
@bindThis
public async create(user: { id: User['id']; host: User['host']; isBot: User['isBot'] }, note: Note, reaction?: string) {
public async create(user: { id: User['id']; host: User['host']; isBot: User['isBot'] }, note: Note, reaction?: string | null) {
// Check blocking
if (note.userId !== user.id) {
const blocked = await this.userBlockingService.checkBlocked(note.userId, user.id);
@ -177,7 +177,7 @@ export class ReactionService {
//#region 配信
if (this.userEntityService.isLocalUser(user) && !note.localOnly) {
const content = this.apRendererService.renderActivity(await this.apRendererService.renderLike(record, note));
const content = this.apRendererService.addContext(await this.apRendererService.renderLike(record, note));
const dm = this.apDeliverManagerService.createDeliverManager(user, content);
if (note.userHost !== null) {
const reactee = await this.usersRepository.findOneBy({ id: note.userId });
@ -235,7 +235,7 @@ export class ReactionService {
//#region 配信
if (this.userEntityService.isLocalUser(user) && !note.localOnly) {
const content = this.apRendererService.renderActivity(this.apRendererService.renderUndo(await this.apRendererService.renderLike(exist, note), user));
const content = this.apRendererService.addContext(this.apRendererService.renderUndo(await this.apRendererService.renderLike(exist, note), user));
const dm = this.apDeliverManagerService.createDeliverManager(user, content);
if (note.userHost !== null) {
const reactee = await this.usersRepository.findOneBy({ id: note.userId });

View File

@ -56,7 +56,7 @@ export class RelayService {
const relayActor = await this.getRelayActor();
const follow = await this.apRendererService.renderFollowRelay(relay, relayActor);
const activity = this.apRendererService.renderActivity(follow);
const activity = this.apRendererService.addContext(follow);
this.queueService.deliver(relayActor, activity, relay.inbox);
return relay;
@ -75,7 +75,7 @@ export class RelayService {
const relayActor = await this.getRelayActor();
const follow = this.apRendererService.renderFollowRelay(relay, relayActor);
const undo = this.apRendererService.renderUndo(follow, relayActor);
const activity = this.apRendererService.renderActivity(undo);
const activity = this.apRendererService.addContext(undo);
this.queueService.deliver(relayActor, activity, relay.inbox);
await this.relaysRepository.delete(relay.id);

View File

@ -117,7 +117,7 @@ export class UserBlockingService implements OnApplicationShutdown {
});
if (this.userEntityService.isLocalUser(blocker) && this.userEntityService.isRemoteUser(blockee)) {
const content = this.apRendererService.renderActivity(this.apRendererService.renderBlock(blocking));
const content = this.apRendererService.addContext(this.apRendererService.renderBlock(blocking));
this.queueService.deliver(blocker, content, blockee.inbox);
}
}
@ -162,13 +162,13 @@ export class UserBlockingService implements OnApplicationShutdown {
// リモートにフォローリクエストをしていたらUndoFollow送信
if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) {
const content = this.apRendererService.renderActivity(this.apRendererService.renderUndo(this.apRendererService.renderFollow(follower, followee), follower));
const content = this.apRendererService.addContext(this.apRendererService.renderUndo(this.apRendererService.renderFollow(follower, followee), follower));
this.queueService.deliver(follower, content, followee.inbox);
}
// リモートからフォローリクエストを受けていたらReject送信
if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
const content = this.apRendererService.renderActivity(this.apRendererService.renderReject(this.apRendererService.renderFollow(follower, followee, request.requestId!), followee));
const content = this.apRendererService.addContext(this.apRendererService.renderReject(this.apRendererService.renderFollow(follower, followee, request.requestId!), followee));
this.queueService.deliver(followee, content, follower.inbox);
}
}
@ -210,13 +210,13 @@ export class UserBlockingService implements OnApplicationShutdown {
// リモートにフォローをしていたらUndoFollow送信
if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) {
const content = this.apRendererService.renderActivity(this.apRendererService.renderUndo(this.apRendererService.renderFollow(follower, followee), follower));
const content = this.apRendererService.addContext(this.apRendererService.renderUndo(this.apRendererService.renderFollow(follower, followee), follower));
this.queueService.deliver(follower, content, followee.inbox);
}
// リモートからフォローをされていたらRejectFollow送信
if (this.userEntityService.isLocalUser(followee) && this.userEntityService.isRemoteUser(follower)) {
const content = this.apRendererService.renderActivity(this.apRendererService.renderReject(this.apRendererService.renderFollow(follower, followee), followee));
const content = this.apRendererService.addContext(this.apRendererService.renderReject(this.apRendererService.renderFollow(follower, followee), followee));
this.queueService.deliver(followee, content, follower.inbox);
}
}
@ -261,7 +261,7 @@ export class UserBlockingService implements OnApplicationShutdown {
// deliver if remote bloking
if (this.userEntityService.isLocalUser(blocker) && this.userEntityService.isRemoteUser(blockee)) {
const content = this.apRendererService.renderActivity(this.apRendererService.renderUndo(this.apRendererService.renderBlock(blocking), blocker));
const content = this.apRendererService.addContext(this.apRendererService.renderUndo(this.apRendererService.renderBlock(blocking), blocker));
this.queueService.deliver(blocker, content, blockee.inbox);
}
}

View File

@ -45,10 +45,10 @@ export class UserCacheService implements OnApplicationShutdown {
case 'userChangeSuspendedState':
case 'remoteUserUpdated': {
const user = await this.usersRepository.findOneByOrFail({ id: body.id });
this.userByIdCache.set(user.id, user);
this.userByIdCache.set(user.id, user as CacheableUser);
for (const [k, v] of this.uriPersonCache.cache.entries()) {
if (v.value?.id === user.id) {
this.uriPersonCache.set(k, user);
this.uriPersonCache.set(k, user as CacheableUser);
}
}
if (this.userEntityService.isLocalUser(user)) {
@ -78,7 +78,7 @@ export class UserCacheService implements OnApplicationShutdown {
@bindThis
public findById(userId: User['id']) {
return this.userByIdCache.fetch(userId, () => this.usersRepository.findOneByOrFail({ id: userId }));
return this.userByIdCache.fetch(userId, () => this.usersRepository.findOneByOrFail({ id: userId }) as Promise<CacheableUser>);
}
@bindThis

View File

@ -81,7 +81,7 @@ export class UserFollowingService {
if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee) && blocked) {
// リモートフォローを受けてブロックしていた場合は、エラーにするのではなくRejectを送り返しておしまい。
const content = this.apRendererService.renderActivity(this.apRendererService.renderReject(this.apRendererService.renderFollow(follower, followee, requestId), followee));
const content = this.apRendererService.addContext(this.apRendererService.renderReject(this.apRendererService.renderFollow(follower, followee, requestId), followee));
this.queueService.deliver(followee, content, follower.inbox);
return;
} else if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee) && blocking) {
@ -130,7 +130,7 @@ export class UserFollowingService {
await this.insertFollowingDoc(followee, follower);
if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
const content = this.apRendererService.renderActivity(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee, requestId), followee));
const content = this.apRendererService.addContext(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee, requestId), followee));
this.queueService.deliver(followee, content, follower.inbox);
}
}
@ -293,13 +293,13 @@ export class UserFollowingService {
}
if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) {
const content = this.apRendererService.renderActivity(this.apRendererService.renderUndo(this.apRendererService.renderFollow(follower, followee), follower));
const content = this.apRendererService.addContext(this.apRendererService.renderUndo(this.apRendererService.renderFollow(follower, followee), follower));
this.queueService.deliver(follower, content, followee.inbox);
}
if (this.userEntityService.isLocalUser(followee) && this.userEntityService.isRemoteUser(follower)) {
// local user has null host
const content = this.apRendererService.renderActivity(this.apRendererService.renderReject(this.apRendererService.renderFollow(follower, followee), followee));
const content = this.apRendererService.addContext(this.apRendererService.renderReject(this.apRendererService.renderFollow(follower, followee), followee));
this.queueService.deliver(followee, content, follower.inbox);
}
}
@ -388,7 +388,7 @@ export class UserFollowingService {
}
if (this.userEntityService.isLocalUser(follower) && this.userEntityService.isRemoteUser(followee)) {
const content = this.apRendererService.renderActivity(this.apRendererService.renderFollow(follower, followee));
const content = this.apRendererService.addContext(this.apRendererService.renderFollow(follower, followee));
this.queueService.deliver(follower, content, followee.inbox);
}
}
@ -403,7 +403,7 @@ export class UserFollowingService {
},
): Promise<void> {
if (this.userEntityService.isRemoteUser(followee)) {
const content = this.apRendererService.renderActivity(this.apRendererService.renderUndo(this.apRendererService.renderFollow(follower, followee), follower));
const content = this.apRendererService.addContext(this.apRendererService.renderUndo(this.apRendererService.renderFollow(follower, followee), follower));
if (this.userEntityService.isLocalUser(follower)) { // 本来このチェックは不要だけどTSに怒られるので
this.queueService.deliver(follower, content, followee.inbox);
@ -448,7 +448,7 @@ export class UserFollowingService {
await this.insertFollowingDoc(followee, follower);
if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
const content = this.apRendererService.renderActivity(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee, request.requestId!), followee));
const content = this.apRendererService.addContext(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee, request.requestId!), followee));
this.queueService.deliver(followee, content, follower.inbox);
}
@ -556,7 +556,7 @@ export class UserFollowingService {
followerId: follower.id,
});
const content = this.apRendererService.renderActivity(this.apRendererService.renderReject(this.apRendererService.renderFollow(follower, followee, request?.requestId ?? undefined), followee));
const content = this.apRendererService.addContext(this.apRendererService.renderReject(this.apRendererService.renderFollow(follower, followee, request?.requestId ?? undefined), followee));
this.queueService.deliver(followee, content, follower.inbox);
}

View File

@ -35,7 +35,7 @@ export class UserSuspendService {
if (this.userEntityService.isLocalUser(user)) {
// 知り得る全SharedInboxにDelete配信
const content = this.apRendererService.renderActivity(this.apRendererService.renderDelete(`${this.config.url}/users/${user.id}`, user));
const content = this.apRendererService.addContext(this.apRendererService.renderDelete(`${this.config.url}/users/${user.id}`, user));
const queue: string[] = [];
@ -65,7 +65,7 @@ export class UserSuspendService {
if (this.userEntityService.isLocalUser(user)) {
// 知り得る全SharedInboxにUndo Delete配信
const content = this.apRendererService.renderActivity(this.apRendererService.renderUndo(this.apRendererService.renderDelete(`${this.config.url}/users/${user.id}`, user), user));
const content = this.apRendererService.addContext(this.apRendererService.renderUndo(this.apRendererService.renderDelete(`${this.config.url}/users/${user.id}`, user), user));
const queue: string[] = [];

View File

@ -130,11 +130,11 @@ export class ApDbResolverService {
return await this.userCacheService.userByIdCache.fetchMaybe(parsed.id, () => this.usersRepository.findOneBy({
id: parsed.id,
}).then(x => x ?? undefined)) ?? null;
}).then(x => (x as CacheableUser | null) ?? undefined)) ?? null;
} else {
return await this.userCacheService.uriPersonCache.fetch(parsed.uri, () => this.usersRepository.findOneBy({
uri: parsed.uri,
}));
}) as Promise<CacheableUser | null>);
}
}

View File

@ -2,7 +2,7 @@ import { Inject, Injectable } from '@nestjs/common';
import { In } from 'typeorm';
import { DI } from '@/di-symbols.js';
import type { Config } from '@/config.js';
import type { CacheableRemoteUser } from '@/models/entities/User.js';
import type { CacheableRemoteUser, CacheableUser } from '@/models/entities/User.js';
import { UserFollowingService } from '@/core/UserFollowingService.js';
import { ReactionService } from '@/core/ReactionService.js';
import { RelayService } from '@/core/RelayService.js';
@ -22,6 +22,7 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { QueueService } from '@/core/QueueService.js';
import { MessagingService } from '@/core/MessagingService.js';
import type { UsersRepository, NotesRepository, FollowingsRepository, MessagingMessagesRepository, AbuseUserReportsRepository, FollowRequestsRepository } from '@/models/index.js';
import { bindThis } from '@/decorators.js';
import { getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isPost, isRead, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js';
import { ApNoteService } from './models/ApNoteService.js';
import { ApLoggerService } from './ApLoggerService.js';
@ -32,7 +33,6 @@ import { ApPersonService } from './models/ApPersonService.js';
import { ApQuestionService } from './models/ApQuestionService.js';
import type { Resolver } from './ApResolverService.js';
import type { IAccept, IAdd, IAnnounce, IBlock, ICreate, IDelete, IFlag, IFollow, ILike, IObject, IRead, IReject, IRemove, IUndo, IUpdate } from './type.js';
import { bindThis } from '@/decorators.js';
@Injectable()
export class ApInboxService {
@ -687,7 +687,7 @@ export class ApInboxService {
return 'skip: ブロック解除しようとしているユーザーはローカルユーザーではありません';
}
await this.userBlockingService.unblock(await this.usersRepository.findOneByOrFail({ id: actor.id }), blockee);
await this.userBlockingService.unblock(await this.usersRepository.findOneByOrFail({ id: actor.id }) as CacheableUser, blockee);
return 'ok';
}

View File

@ -24,7 +24,7 @@ import type { UsersRepository, UserProfilesRepository, NotesRepository, DriveFil
import { bindThis } from '@/decorators.js';
import { LdSignatureService } from './LdSignatureService.js';
import { ApMfmService } from './ApMfmService.js';
import type { IActivity, IObject } from './type.js';
import type { IAccept, IActivity, IAdd, IAnnounce, IApDocument, IApEmoji, IApHashtag, IApImage, IApMention, IBlock, ICreate, IDelete, IFlag, IFollow, IKey, ILike, IObject, IQuestion, IRead, IReject, IRemove, ITombstone, IUndo, IUpdate } from './type.js';
import type { IIdentifier } from './models/identifier.js';
@Injectable()
@ -61,7 +61,7 @@ export class ApRendererService {
}
@bindThis
public renderAccept(object: any, user: { id: User['id']; host: null }) {
public renderAccept(object: any, user: { id: User['id']; host: null }): IAccept {
return {
type: 'Accept',
actor: `${this.config.url}/users/${user.id}`,
@ -70,7 +70,7 @@ export class ApRendererService {
}
@bindThis
public renderAdd(user: ILocalUser, target: any, object: any) {
public renderAdd(user: ILocalUser, target: any, object: any): IAdd {
return {
type: 'Add',
actor: `${this.config.url}/users/${user.id}`,
@ -80,7 +80,7 @@ export class ApRendererService {
}
@bindThis
public renderAnnounce(object: any, note: Note) {
public renderAnnounce(object: any, note: Note): IAnnounce {
const attributedTo = `${this.config.url}/users/${note.userId}`;
let to: string[] = [];
@ -93,7 +93,7 @@ export class ApRendererService {
to = [`${attributedTo}/followers`];
cc = ['https://www.w3.org/ns/activitystreams#Public'];
} else {
return null;
throw new Error('renderAnnounce: cannot render non-public note');
}
return {
@ -113,7 +113,7 @@ export class ApRendererService {
* @param block The block to be rendered. The blockee relation must be loaded.
*/
@bindThis
public renderBlock(block: Blocking) {
public renderBlock(block: Blocking): IBlock {
if (block.blockee?.uri == null) {
throw new Error('renderBlock: missing blockee uri');
}
@ -127,14 +127,14 @@ export class ApRendererService {
}
@bindThis
public renderCreate(object: any, note: Note) {
public renderCreate(object: IObject, note: Note): ICreate {
const activity = {
id: `${this.config.url}/notes/${note.id}/activity`,
actor: `${this.config.url}/users/${note.userId}`,
type: 'Create',
published: note.createdAt.toISOString(),
object,
} as any;
} as ICreate;
if (object.to) activity.to = object.to;
if (object.cc) activity.cc = object.cc;
@ -143,7 +143,7 @@ export class ApRendererService {
}
@bindThis
public renderDelete(object: any, user: { id: User['id']; host: null }) {
public renderDelete(object: IObject | string, user: { id: User['id']; host: null }): IDelete {
return {
type: 'Delete',
actor: `${this.config.url}/users/${user.id}`,
@ -153,7 +153,7 @@ export class ApRendererService {
}
@bindThis
public renderDocument(file: DriveFile) {
public renderDocument(file: DriveFile): IApDocument {
return {
type: 'Document',
mediaType: file.type,
@ -163,12 +163,12 @@ export class ApRendererService {
}
@bindThis
public renderEmoji(emoji: Emoji) {
public renderEmoji(emoji: Emoji): IApEmoji {
return {
id: `${this.config.url}/emojis/${emoji.name}`,
type: 'Emoji',
name: `:${emoji.name}:`,
updated: emoji.updatedAt != null ? emoji.updatedAt.toISOString() : new Date().toISOString,
updated: emoji.updatedAt != null ? emoji.updatedAt.toISOString() : new Date().toISOString(),
icon: {
type: 'Image',
mediaType: emoji.type ?? 'image/png',
@ -181,7 +181,7 @@ export class ApRendererService {
// to anonymise reporters, the reporting actor must be a system user
// object has to be a uri or array of uris
@bindThis
public renderFlag(user: ILocalUser, object: [string], content: string) {
public renderFlag(user: ILocalUser, object: IObject, content: string): IFlag {
return {
type: 'Flag',
actor: `${this.config.url}/users/${user.id}`,
@ -191,15 +191,13 @@ export class ApRendererService {
}
@bindThis
public renderFollowRelay(relay: Relay, relayActor: ILocalUser) {
const follow = {
public renderFollowRelay(relay: Relay, relayActor: ILocalUser): IFollow {
return {
id: `${this.config.url}/activities/follow-relay/${relay.id}`,
type: 'Follow',
actor: `${this.config.url}/users/${relayActor.id}`,
object: 'https://www.w3.org/ns/activitystreams#Public',
};
return follow;
}
/**
@ -217,19 +215,17 @@ export class ApRendererService {
follower: { id: User['id']; host: User['host']; uri: User['host'] },
followee: { id: User['id']; host: User['host']; uri: User['host'] },
requestId?: string,
) {
const follow = {
): IFollow {
return {
id: requestId ?? `${this.config.url}/follows/${follower.id}/${followee.id}`,
type: 'Follow',
actor: this.userEntityService.isLocalUser(follower) ? `${this.config.url}/users/${follower.id}` : follower.uri,
object: this.userEntityService.isLocalUser(followee) ? `${this.config.url}/users/${followee.id}` : followee.uri,
} as any;
return follow;
actor: this.userEntityService.isLocalUser(follower) ? `${this.config.url}/users/${follower.id}` : follower.uri!,
object: this.userEntityService.isLocalUser(followee) ? `${this.config.url}/users/${followee.id}` : followee.uri!,
};
}
@bindThis
public renderHashtag(tag: string) {
public renderHashtag(tag: string): IApHashtag {
return {
type: 'Hashtag',
href: `${this.config.url}/tags/${encodeURIComponent(tag)}`,
@ -238,7 +234,7 @@ export class ApRendererService {
}
@bindThis
public renderImage(file: DriveFile) {
public renderImage(file: DriveFile): IApImage {
return {
type: 'Image',
url: this.driveFileEntityService.getPublicUrl(file),
@ -248,7 +244,7 @@ export class ApRendererService {
}
@bindThis
public renderKey(user: ILocalUser, key: UserKeypair, postfix?: string) {
public renderKey(user: ILocalUser, key: UserKeypair, postfix?: string): IKey {
return {
id: `${this.config.url}/users/${user.id}${postfix ?? '/publickey'}`,
type: 'Key',
@ -261,7 +257,7 @@ export class ApRendererService {
}
@bindThis
public async renderLike(noteReaction: NoteReaction, note: { uri: string | null }) {
public async renderLike(noteReaction: NoteReaction, note: { uri: string | null }): Promise<ILike> {
const reaction = noteReaction.reaction;
const object = {
@ -271,10 +267,11 @@ export class ApRendererService {
object: note.uri ? note.uri : `${this.config.url}/notes/${noteReaction.noteId}`,
content: reaction,
_misskey_reaction: reaction,
} as any;
} as ILike;
if (reaction.startsWith(':')) {
const name = reaction.replaceAll(':', '');
// TODO: cache
const emoji = await this.emojisRepository.findOneBy({
name,
host: IsNull(),
@ -287,10 +284,10 @@ export class ApRendererService {
}
@bindThis
public renderMention(mention: User) {
public renderMention(mention: User): IApMention {
return {
type: 'Mention',
href: this.userEntityService.isRemoteUser(mention) ? mention.uri : `${this.config.url}/users/${(mention as ILocalUser).id}`,
href: this.userEntityService.isRemoteUser(mention) ? mention.uri! : `${this.config.url}/users/${(mention as ILocalUser).id}`,
name: this.userEntityService.isRemoteUser(mention) ? `@${mention.username}@${mention.host}` : `@${(mention as ILocalUser).username}`,
};
}
@ -518,8 +515,8 @@ export class ApRendererService {
}
@bindThis
public async renderQuestion(user: { id: User['id'] }, note: Note, poll: Poll) {
const question = {
public async renderQuestion(user: { id: User['id'] }, note: Note, poll: Poll): IQuestion {
return {
type: 'Question',
id: `${this.config.url}/questions/${note.id}`,
actor: `${this.config.url}/users/${user.id}`,
@ -533,21 +530,19 @@ export class ApRendererService {
},
})),
};
return question;
}
@bindThis
public renderRead(user: { id: User['id'] }, message: MessagingMessage) {
public renderRead(user: { id: User['id'] }, message: MessagingMessage): IRead {
return {
type: 'Read',
actor: `${this.config.url}/users/${user.id}`,
object: message.uri,
object: message.uri!,
};
}
@bindThis
public renderReject(object: any, user: { id: User['id'] }) {
public renderReject(object: any, user: { id: User['id'] }): IReject {
return {
type: 'Reject',
actor: `${this.config.url}/users/${user.id}`,
@ -556,7 +551,7 @@ export class ApRendererService {
}
@bindThis
public renderRemove(user: { id: User['id'] }, target: any, object: any) {
public renderRemove(user: { id: User['id'] }, target: any, object: any): IRemove {
return {
type: 'Remove',
actor: `${this.config.url}/users/${user.id}`,
@ -566,7 +561,7 @@ export class ApRendererService {
}
@bindThis
public renderTombstone(id: string) {
public renderTombstone(id: string): ITombstone {
return {
id,
type: 'Tombstone',
@ -574,8 +569,7 @@ export class ApRendererService {
}
@bindThis
public renderUndo(object: any, user: { id: User['id'] }) {
if (object == null) return null;
public renderUndo(object: any, user: { id: User['id'] }): IUndo {
const id = typeof object.id === 'string' && object.id.startsWith(this.config.url) ? `${object.id}/undo` : undefined;
return {
@ -588,21 +582,19 @@ export class ApRendererService {
}
@bindThis
public renderUpdate(object: any, user: { id: User['id'] }) {
const activity = {
public renderUpdate(object: any, user: { id: User['id'] }): IUpdate {
return {
id: `${this.config.url}/users/${user.id}#updates/${new Date().getTime()}`,
actor: `${this.config.url}/users/${user.id}`,
type: 'Update',
to: ['https://www.w3.org/ns/activitystreams#Public'],
object,
published: new Date().toISOString(),
} as any;
return activity;
};
}
@bindThis
public renderVote(user: { id: User['id'] }, vote: PollVote, note: Note, poll: Poll, pollOwner: IRemoteUser) {
public renderVote(user: { id: User['id'] }, vote: PollVote, note: Note, poll: Poll, pollOwner: IRemoteUser): ICreate {
return {
id: `${this.config.url}/users/${user.id}#votes/${vote.id}/activity`,
actor: `${this.config.url}/users/${user.id}`,
@ -621,9 +613,7 @@ export class ApRendererService {
}
@bindThis
public renderActivity(x: any): IActivity | null {
if (x == null) return null;
public addContext<T extends IObject>(x: T): T & { '@context': any; id: string; } {
if (typeof x === 'object' && x.id == null) {
x.id = `${this.config.url}/${uuid()}`;
}
@ -659,7 +649,7 @@ export class ApRendererService {
vcard: 'http://www.w3.org/2006/vcard/ns#',
},
],
}, x);
}, x as T & { id: string; });
}
@bindThis

View File

@ -38,8 +38,7 @@ export class Resolver {
private recursionLimit = 100,
) {
this.history = new Set();
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
this.logger = this.loggerService?.getLogger('ap-resolve'); // なぜか TypeError: Cannot read properties of undefined (reading 'getLogger') と言われる
this.logger = this.loggerService.getLogger('ap-resolve');
}
@bindThis
@ -124,10 +123,10 @@ export class Resolver {
switch (parsed.type) {
case 'notes':
return this.notesRepository.findOneByOrFail({ id: parsed.id })
.then(note => {
.then(async note => {
if (parsed.rest === 'activity') {
// this refers to the create activity and not the note itself
return this.apRendererService.renderActivity(this.apRendererService.renderCreate(this.apRendererService.renderNote(note), note));
return this.apRendererService.addContext(this.apRendererService.renderCreate(await this.apRendererService.renderNote(note), note));
} else {
return this.apRendererService.renderNote(note);
}
@ -143,8 +142,8 @@ export class Resolver {
])
.then(([note, poll]) => this.apRendererService.renderQuestion({ id: note.userId }, note, poll));
case 'likes':
return this.noteReactionsRepository.findOneByOrFail({ id: parsed.id }).then(reaction =>
this.apRendererService.renderActivity(this.apRendererService.renderLike(reaction, { uri: null }))!);
return this.noteReactionsRepository.findOneByOrFail({ id: parsed.id }).then(async reaction =>
this.apRendererService.addContext(await this.apRendererService.renderLike(reaction, { uri: null })));
case 'follows':
// rest should be <followee id>
if (parsed.rest == null || !/^\w+$/.test(parsed.rest)) throw new Error('resolveLocal: invalid follow URI');
@ -152,7 +151,7 @@ export class Resolver {
return Promise.all(
[parsed.id, parsed.rest].map(id => this.usersRepository.findOneByOrFail({ id })),
)
.then(([follower, followee]) => this.apRendererService.renderActivity(this.apRendererService.renderFollow(follower, followee, url)));
.then(([follower, followee]) => this.apRendererService.addContext(this.apRendererService.renderFollow(follower, followee, url)));
default:
throw new Error(`resolveLocal: type ${parsed.type} unhandled`);
}
@ -184,6 +183,7 @@ export class ApResolverService {
private httpRequestService: HttpRequestService,
private apRendererService: ApRendererService,
private apDbResolverService: ApDbResolverService,
private loggerService: LoggerService,
) {
}
@ -202,6 +202,7 @@ export class ApResolverService {
this.httpRequestService,
this.apRendererService,
this.apDbResolverService,
this.loggerService,
);
}
}

View File

@ -114,7 +114,7 @@ export class ApNoteService {
public async createNote(value: string | IObject, resolver?: Resolver, silent = false): Promise<Note | null> {
if (resolver == null) resolver = this.apResolverService.createResolver();
const object: any = await resolver.resolve(value);
const object = await resolver.resolve(value);
const entryUri = getApId(value);
const err = this.validateNote(object, entryUri);
@ -129,7 +129,7 @@ export class ApNoteService {
throw new Error('invalid note');
}
const note: IPost = object;
const note: IPost = object as any;
this.logger.debug(`Note fetched: ${JSON.stringify(note, null, 2)}`);
@ -146,7 +146,7 @@ export class ApNoteService {
this.logger.info(`Creating the Note: ${note.id}`);
// 投稿者をフェッチ
const actor = await this.apPersonService.resolvePerson(getOneApId(note.attributedTo), resolver) as CacheableRemoteUser;
const actor = await this.apPersonService.resolvePerson(getOneApId(note.attributedTo!), resolver) as CacheableRemoteUser;
// 投稿者が凍結されていたらスキップ
if (actor.isSuspended) {

View File

@ -206,13 +206,13 @@ export class ApPersonService implements OnModuleInit {
// URIがこのサーバーを指しているならデータベースからフェッチ
if (uri.startsWith(this.config.url + '/')) {
const id = uri.split('/').pop();
const u = await this.usersRepository.findOneBy({ id });
const u = await this.usersRepository.findOneBy({ id }) as null | CacheableUser;
if (u) this.userCacheService.uriPersonCache.set(uri, u);
return u;
}
//#region このサーバーに既に登録されていたらそれを返す
const exist = await this.usersRepository.findOneBy({ uri });
const exist = await this.usersRepository.findOneBy({ uri }) as null | CacheableUser;
if (exist) {
this.userCacheService.uriPersonCache.set(uri, exist);
@ -513,7 +513,7 @@ export class ApPersonService implements OnModuleInit {
// リモートサーバーからフェッチしてきて登録
if (resolver == null) resolver = this.apResolverService.createResolver();
return await this.createPerson(uri, resolver);
return await this.createPerson(uri, resolver) as CacheableUser;
}
@bindThis

View File

@ -2,24 +2,24 @@ export type obj = { [x: string]: any };
export type ApObject = IObject | string | (IObject | string)[];
export interface IObject {
'@context': string | string[] | obj | obj[];
'@context'?: string | string[] | obj | obj[];
type: string | string[];
id?: string;
name?: string | null;
summary?: string;
published?: string;
cc?: ApObject;
to?: ApObject;
attributedTo: ApObject;
attributedTo?: ApObject;
attachment?: any[];
inReplyTo?: any;
replies?: ICollection;
content?: string;
name?: string;
startTime?: Date;
endTime?: Date;
icon?: any;
image?: any;
url?: ApObject;
url?: ApObject | string;
href?: string;
tag?: IObject | IObject[];
sensitive?: boolean;
@ -118,6 +118,7 @@ export interface IPost extends IObject {
export interface IQuestion extends IObject {
type: 'Note' | 'Question';
actor: string;
source?: {
content: string;
mediaType: string;
@ -200,6 +201,7 @@ export const isPropertyValue = (object: IObject): object is IApPropertyValue =>
export interface IApMention extends IObject {
type: 'Mention';
href: string;
name: string;
}
export const isMention = (object: IObject): object is IApMention =>
@ -217,12 +219,30 @@ export const isHashtag = (object: IObject): object is IApHashtag =>
export interface IApEmoji extends IObject {
type: 'Emoji';
updated: Date;
name: string;
updated: string;
}
export const isEmoji = (object: IObject): object is IApEmoji =>
getApType(object) === 'Emoji' && !Array.isArray(object.icon) && object.icon.url != null;
export interface IKey extends IObject {
type: 'Key';
owner: string;
publicKeyPem: string | Buffer;
}
export interface IApDocument extends IObject {
type: 'Document';
name: string | null;
mediaType: string;
}
export interface IApImage extends IObject {
type: 'Image';
name: string | null;
}
export interface ICreate extends IActivity {
type: 'Create';
}

View File

@ -11,9 +11,9 @@ import type { DriveFile } from '@/models/entities/DriveFile.js';
import { appendQuery, query } from '@/misc/prelude/url.js';
import { deepClone } from '@/misc/clone.js';
import { UtilityService } from '../UtilityService.js';
import { VideoProcessingService } from '../VideoProcessingService.js';
import { UserEntityService } from './UserEntityService.js';
import { DriveFolderEntityService } from './DriveFolderEntityService.js';
import { VideoProcessingService } from '../VideoProcessingService.js';
type PackOptions = {
detail?: boolean,
@ -74,14 +74,14 @@ export class DriveFileEntityService {
}
@bindThis
private getProxiedUrl(url: string, mode?: 'static' | 'avatar'): string | null {
private getProxiedUrl(url: string, mode?: 'static' | 'avatar'): string {
return appendQuery(
`${this.config.mediaProxy}/${mode ?? 'image'}.webp`,
query({
url,
...(mode ? { [mode]: '1' } : {}),
})
)
}),
);
}
@bindThis
@ -110,7 +110,7 @@ export class DriveFileEntityService {
}
@bindThis
public getPublicUrl(file: DriveFile, mode?: 'avatar'): string | null { // static = thumbnail
public getPublicUrl(file: DriveFile, mode?: 'avatar'): string { // static = thumbnail
// リモートかつメディアプロキシ
if (file.uri != null && file.userHost != null && this.config.externalMediaProxyEnabled) {
return this.getProxiedUrl(file.uri, mode);

View File

@ -221,6 +221,7 @@ export interface ILocalUser extends User {
export interface IRemoteUser extends User {
host: string;
uri: string;
}
export type CacheableLocalUser = ILocalUser;

View File

@ -183,13 +183,13 @@ export class ActivityPubServerService {
);
this.setResponseType(request, reply);
return (this.apRendererService.renderActivity(rendered));
return (this.apRendererService.addContext(rendered));
} else {
// index page
const rendered = this.apRendererService.renderOrderedCollection(partOf, user.followersCount, `${partOf}?page=true`);
reply.header('Cache-Control', 'public, max-age=180');
this.setResponseType(request, reply);
return (this.apRendererService.renderActivity(rendered));
return (this.apRendererService.addContext(rendered));
}
}
@ -271,13 +271,13 @@ export class ActivityPubServerService {
);
this.setResponseType(request, reply);
return (this.apRendererService.renderActivity(rendered));
return (this.apRendererService.addContext(rendered));
} else {
// index page
const rendered = this.apRendererService.renderOrderedCollection(partOf, user.followingCount, `${partOf}?page=true`);
reply.header('Cache-Control', 'public, max-age=180');
this.setResponseType(request, reply);
return (this.apRendererService.renderActivity(rendered));
return (this.apRendererService.addContext(rendered));
}
}
@ -312,7 +312,7 @@ export class ActivityPubServerService {
reply.header('Cache-Control', 'public, max-age=180');
this.setResponseType(request, reply);
return (this.apRendererService.renderActivity(rendered));
return (this.apRendererService.addContext(rendered));
}
@bindThis
@ -389,7 +389,7 @@ export class ActivityPubServerService {
);
this.setResponseType(request, reply);
return (this.apRendererService.renderActivity(rendered));
return (this.apRendererService.addContext(rendered));
} else {
// index page
const rendered = this.apRendererService.renderOrderedCollection(partOf, user.notesCount,
@ -398,7 +398,7 @@ export class ActivityPubServerService {
);
reply.header('Cache-Control', 'public, max-age=180');
this.setResponseType(request, reply);
return (this.apRendererService.renderActivity(rendered));
return (this.apRendererService.addContext(rendered));
}
}
@ -411,7 +411,7 @@ export class ActivityPubServerService {
reply.header('Cache-Control', 'public, max-age=180');
this.setResponseType(request, reply);
return (this.apRendererService.renderActivity(await this.apRendererService.renderPerson(user as ILocalUser)));
return (this.apRendererService.addContext(await this.apRendererService.renderPerson(user as ILocalUser)));
}
@bindThis
@ -481,7 +481,7 @@ export class ActivityPubServerService {
reply.header('Cache-Control', 'public, max-age=180');
this.setResponseType(request, reply);
return (this.apRendererService.renderActivity(await this.apRendererService.renderNote(note, false)));
return this.apRendererService.addContext(await this.apRendererService.renderNote(note, false));
});
// note activity
@ -502,7 +502,7 @@ export class ActivityPubServerService {
reply.header('Cache-Control', 'public, max-age=180');
this.setResponseType(request, reply);
return (this.apRendererService.renderActivity(await this.packActivity(note)));
return (this.apRendererService.addContext(await this.packActivity(note)));
});
// outbox
@ -545,7 +545,7 @@ export class ActivityPubServerService {
if (this.userEntityService.isLocalUser(user)) {
reply.header('Cache-Control', 'public, max-age=180');
this.setResponseType(request, reply);
return (this.apRendererService.renderActivity(this.apRendererService.renderKey(user, keypair)));
return (this.apRendererService.addContext(this.apRendererService.renderKey(user, keypair)));
} else {
reply.code(400);
return;
@ -589,7 +589,7 @@ export class ActivityPubServerService {
reply.header('Cache-Control', 'public, max-age=180');
this.setResponseType(request, reply);
return (this.apRendererService.renderActivity(await this.apRendererService.renderEmoji(emoji)));
return (this.apRendererService.addContext(await this.apRendererService.renderEmoji(emoji)));
});
// like
@ -610,7 +610,7 @@ export class ActivityPubServerService {
reply.header('Cache-Control', 'public, max-age=180');
this.setResponseType(request, reply);
return (this.apRendererService.renderActivity(await this.apRendererService.renderLike(reaction, note)));
return (this.apRendererService.addContext(await this.apRendererService.renderLike(reaction, note)));
});
// follow
@ -636,7 +636,7 @@ export class ActivityPubServerService {
reply.header('Cache-Control', 'public, max-age=180');
this.setResponseType(request, reply);
return (this.apRendererService.renderActivity(this.apRendererService.renderFollow(follower, followee)));
return (this.apRendererService.addContext(this.apRendererService.renderFollow(follower, followee)));
});
done();

View File

@ -49,7 +49,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
const actor = await this.instanceActorService.getInstanceActor();
const targetUser = await this.usersRepository.findOneByOrFail({ id: report.targetUserId });
this.queueService.deliver(actor, this.apRendererService.renderActivity(this.apRendererService.renderFlag(actor, [targetUser.uri!], report.comment)), targetUser.inbox);
this.queueService.deliver(actor, this.apRendererService.addContext(this.apRendererService.renderFlag(actor, [targetUser.uri!], report.comment)), targetUser.inbox);
}
await this.abuseUserReportsRepository.update(report.id, {

View File

@ -162,7 +162,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
if (note.userHost != null) {
const pollOwner = await this.usersRepository.findOneByOrFail({ id: note.userId }) as IRemoteUser;
this.queueService.deliver(me, this.apRendererService.renderActivity(await this.apRendererService.renderVote(me, vote, note, poll, pollOwner)), pollOwner.inbox);
this.queueService.deliver(me, this.apRendererService.addContext(await this.apRendererService.renderVote(me, vote, note, poll, pollOwner)), pollOwner.inbox);
}
// リモートフォロワーにUpdate配信