Skip to content

src/list.ts

72 lines · 2.1 KB · TypeScript
Raw
import {
	listChannelMappings,
	readCategoryId,
	type ChannelMapping,
} from './discord-map.ts'
import { plusAddressFor } from './plus-alias.ts'
import {
	listBotRecords,
	listWakeSecrets,
	normalizeName,
	secretNameFor,
	secretUseStatusFrom,
	urlHostOf,
	type BotSummary,
} from './registry.ts'
import { plainClone } from './plain.ts'

export type ListResult = {
	categoryId: string
	channels: ChannelMapping[]
	bots: BotSummary[]
}

/**
 * List registered Grok Bots without full webhook URLs.
 *
 * @returns Roster summaries with urlHost, pendingSecret, needsHostApproval, channelId, and plus-alias emailAddress
 * @example
 * import list from 'kody:@kentcdodds/grok-bot/list'
 * const roster = await list()
 * // => { categoryId, channels, bots: [{ id, name, aliases, secretName, pendingSecret, needsHostApproval, urlHost, channelId, emailAddress }] }
 */
export default async function list(): Promise<ListResult> {
	const [records, secrets, categoryId, channels] = await Promise.all([
		listBotRecords(),
		listWakeSecrets(),
		readCategoryId(),
		listChannelMappings(),
	])
	const bots: BotSummary[] = records.map((record) => {
		const secret = secretUseStatusFrom(secrets, record.secretName)
		return {
			id: record.id,
			name: record.name,
			aliases: record.aliases,
			secretName: record.secretName,
			pendingSecret: !secret.exists,
			needsHostApproval: secret.needsHostApproval,
			urlHost: urlHostOf(record.url),
			emailAddress: plusAddressFor(record.name),
			...(secret.approvalUrl && secret.needsHostApproval
				? { approvalUrl: secret.approvalUrl }
				: {}),
			...(record.channelId ? { channelId: record.channelId } : {}),
		}
	})
	for (const channel of channels) {
		if (bots.some((bot) => bot.id === channel.botId)) continue
		bots.push({
			id: channel.botId,
			name: channel.name,
			aliases: [normalizeName(channel.name)],
			secretName: secretNameFor(channel.botId),
			pendingSecret: true,
			needsHostApproval: false,
			urlHost: '',
			emailAddress: plusAddressFor(channel.name),
			channelId: channel.channelId,
		})
	}
	return plainClone({ categoryId, channels, bots })
}