Ctrl K
ComunidadGuías…

chatd/src/personal/capabilities.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import type { PersonalGateway } from "./gateway.ts";
import {
	MalformedRequest,
	inboxWindowOf,
	optionalLoopbackTypingURL,
	optionalLoopbackWithdrawalsURL,
	parseCredentialAnswers,
	parseMemberExternalIDs,
	parseNewChannel,
	parsePersonRequest,
	requireConversation,
	requireExternalID,
	requireLargestBytes,
	requireMediaRange,
	requireMediaSource,
	requireMediaURL,
	requireMessage,
	requireLoopbackArrivalsURL,
	requireName,
	requireQuery,
	requireReadAt,
} from "./parse.ts";

// The agent's own account on the messenger, when the platform knows it. A
// direct conversation with the agent is a conversation with the product, and
// only the product knows which account that is.
export type PersonCapability = (
	gateway: PersonalGateway,
	requestBody: unknown,
	agentExternalID?: string,
) => Promise<object | Response>;

export const personCapabilities: Record<string, PersonCapability> = {
	"person.credential.requirement": async (gateway) => gateway.credentialRequirement(),
	"person.credential.issue": async (gateway, body) =>
		await gateway.issueCredential(parseCredentialAnswers(body)),
	"person.identity": async (gateway, body) => {
		const request = parsePersonRequest(body);
		return await gateway.identity(request.actor);
	},
	"person.conversations.list": async (gateway, body, agentExternalID) => {
		const request = parsePersonRequest(body);
		const conversations = await gateway.listConversations(request.actor);
		return {
			agentExternalID,
			conversations: conversations.map((conversation) => ({
				...conversation,
				isWithTheAgent: Boolean(
					agentExternalID && (conversation.participantExternalIDs ?? []).includes(agentExternalID),
				),
			})),
		};
	},
	"person.people.list": async (gateway, body, agentExternalID) => {
		const request = parsePersonRequest(body);
		return { agentExternalID, people: await gateway.listPeople(request.actor) };
	},
	"person.dm.ensure": async (gateway, body) => {
		const request = parsePersonRequest(body);
		return await gateway.ensureDirectConversation(request.actor, request.counterpartExternalIDs);
	},
	"person.dm.hide": async (gateway, body) => {
		const request = parsePersonRequest(body);
		await gateway.hideDirectConversation(request.actor, requireConversation(request));
		return {};
	},
	"person.dm.reveal": async (gateway, body) => {
		const request = parsePersonRequest(body);
		await gateway.revealDirectConversation(request.actor, requireConversation(request));
		return {};
	},
	"person.channel.create": async (gateway, body) => {
		const request = parsePersonRequest(body);
		return await gateway.createChannel(request.actor, parseNewChannel(body));
	},
	"person.channels.open.list": async (gateway, body) => {
		const request = parsePersonRequest(body);
		return { channels: await gateway.listOpenChannels(request.actor) };
	},
	"person.channel.join": async (gateway, body) => {
		const request = parsePersonRequest(body);
		await gateway.joinChannel(request.actor, requireConversation(request));
		return {};
	},
	"person.channel.members.add": async (gateway, body) => {
		const request = parsePersonRequest(body);
		const members = parseMemberExternalIDs(body);
		if (members.length === 0) throw new MalformedRequest("memberExternalIDs must name someone to add");
		return await gateway.addChannelMembers(request.actor, requireConversation(request), members);
	},
	"person.channel.member.remove": async (gateway, body) => {
		const request = parsePersonRequest(body);
		await gateway.removeChannelMember(request.actor, requireConversation(request), requireExternalID(request));
		return {};
	},
	"person.channel.leave": async (gateway, body) => {
		const request = parsePersonRequest(body);
		await gateway.leaveChannel(request.actor, requireConversation(request));
		return {};
	},
	"person.channel.owner.set": async (gateway, body) => {
		const request = parsePersonRequest(body);
		await gateway.handOverChannel(request.actor, requireConversation(request), requireExternalID(request));
		return {};
	},
	"person.channel.owner.add": async (gateway, body) => {
		const request = parsePersonRequest(body);
		return gateway.addChannelOwner(request.actor, requireConversation(request), requireExternalID(request));
	},
	"person.channel.delete": async (gateway, body) => {
		const request = parsePersonRequest(body);
		await gateway.deleteChannel(request.actor, requireConversation(request));
		return {};
	},
	"person.read_state.mark": async (gateway, body) => {
		const request = parsePersonRequest(body);
		await gateway.markConversationRead(
			request.actor,
			requireConversation(request),
			requireReadAt(request),
			request.parentID,
		);
		return {};
	},
	"person.inbox.list": async (gateway, body, agentExternalID) => {
		const request = parsePersonRequest(body);
		return { agentExternalID, ...(await gateway.listInbox(request.actor, inboxWindowOf(request))) };
	},
	"person.messages.list": async (gateway, body) => {
		const request = parsePersonRequest(body);
		return await gateway.listMessages(request.actor, requireConversation(request), request.before);
	},
	"person.messages.search": async (gateway, body) => {
		const request = parsePersonRequest(body);
		return {
			matches: await gateway.searchMessages(request.actor, requireConversation(request), requireQuery(request)),
		};
	},
	"person.message.send": async (gateway, body) => {
		const request = parsePersonRequest(body);
		return await gateway.sendMessage(
			request.actor,
			requireConversation(request),
			request.body ?? "",
			request.parentID,
			request.attachments,
			request.mentions,
			request.timeZone,
		);
	},
	"person.message.edit": async (gateway, body) => {
		const request = parsePersonRequest(body);
		return await gateway.editMessage(
			request.actor,
			requireConversation(request),
			requireMessage(request),
			request.body ?? "",
			request.mentions,
		);
	},
	"person.message.delete": async (gateway, body) => {
		const request = parsePersonRequest(body);
		await gateway.deleteMessage(request.actor, requireConversation(request), requireMessage(request));
		return {};
	},
	"person.reaction.add": async (gateway, body) => {
		const request = parsePersonRequest(body);
		await gateway.addReaction(
			request.actor,
			requireConversation(request),
			requireMessage(request),
			requireEmoji(request.emoji),
		);
		return {};
	},
	"person.reaction.remove": async (gateway, body) => {
		const request = parsePersonRequest(body);
		await gateway.removeReaction(
			request.actor,
			requireConversation(request),
			requireMessage(request),
			requireEmoji(request.emoji),
		);
		return {};
	},
	"person.emoji.list": async (gateway, body) => {
		const request = parsePersonRequest(body);
		return { emoji: await gateway.listCustomEmoji(request.actor) };
	},
	"person.emoji.image": async (gateway, body) => {
		const request = parsePersonRequest(body);
		return {
			image: await gateway.readCustomEmojiImage(
				request.actor,
				requireName(request),
				requireLargestBytes(request),
			),
		};
	},
	"person.picture": async (gateway, body) => {
		const request = parsePersonRequest(body);
		return {
			image: await gateway.readProfilePicture(
				request.actor,
				requireExternalID(request),
				requireLargestBytes(request),
			),
		};
	},
	"person.arrivals.watch": async (gateway, body) => {
		const request = parsePersonRequest(body);
		await gateway.watchArrivals(
			request.actor,
			requireLoopbackArrivalsURL(request),
			optionalLoopbackTypingURL(request),
			optionalLoopbackWithdrawalsURL(request),
		);
		return {};
	},
	"person.typing.send": async (gateway, body) => {
		const request = parsePersonRequest(body);
		await gateway.announceTyping(request.actor, requireConversation(request));
		return {};
	},
	"person.media.read": async (gateway, body) => {
		const request = parsePersonRequest(body);
		return await gateway.readMedia(request.actor, requireMediaURL(request), requireMediaRange(request));
	},
	"person.media.upload": async (gateway, body) => {
		const request = parsePersonRequest(body);
		return { media: await gateway.uploadMedia(request.actor, requireMediaSource(request)) };
	},
};

function requireEmoji(emoji: string | undefined): string {
	if (!emoji) throw new MalformedRequest("missing required field emoji");
	return emoji;
}