Skip to content

Built for people who want to own their automations. Join the waitlist for an invite.

Package listing

@kody/notify

src/connect.ts

119 lines · 3.5 KB · TypeScript
export const EMAIL_DESTINATION = 'email'
export const SLACK_DESTINATION = 'slack'
export const DISCORD_DESTINATION = 'discord'
export const TELEGRAM_DESTINATION = 'telegram'

export const DESTINATIONS = [
	EMAIL_DESTINATION,
	SLACK_DESTINATION,
	DISCORD_DESTINATION,
	TELEGRAM_DESTINATION,
] as const

export type Destination = (typeof DESTINATIONS)[number]

export const SLACK_INTEGRATION = 'slack'
export const DISCORD_BOT_TOKEN_SECRET = 'discordBotToken'
export const TELEGRAM_BOT_TOKEN_SECRET = 'telegramBotToken'
export const SLACK_CHAT_WRITE_SCOPE = 'chat:write'
export const DISCORD_BOT_PERMISSIONS = 68608

const SLACK_SCOPES = [
	'chat:write',
	'channels:history',
	'channels:read',
	'groups:history',
	'groups:read',
	'im:history',
	'im:read',
	'mpim:history',
	'mpim:read',
	'users:read',
].join(',')

export function slackConnectUrl(integration = SLACK_INTEGRATION): string {
	return 'https://kody.codes/connect/oauth?provider=' + encodeURIComponent(integration)
}

export function slackByoConnectUrl(integration = SLACK_INTEGRATION): string {
	return [
		'https://kody.codes/connect/oauth?provider=' + encodeURIComponent(integration),
		'authorizeUrl=https%3A%2F%2Fslack.com%2Foauth%2Fv2_user%2Fauthorize',
		'tokenUrl=https%3A%2F%2Fslack.com%2Fapi%2Foauth.v2.user.access',
		'apiBaseUrl=https%3A%2F%2Fslack.com%2Fapi',
		'flow=confidential',
		'tokenExchangeStyle=form',
		'scopeSeparator=%2C',
		'scopes=' + encodeURIComponent(SLACK_SCOPES),
		'allowedHosts=slack.com',
		'dashboardUrl=https%3A%2F%2Fapi.slack.com%2Fapps',
	].join('&')
}

export function discordSecretUrl(secretName = DISCORD_BOT_TOKEN_SECRET): string {
	return (
		'https://kody.codes/account/secrets/new?name=' +
		encodeURIComponent(secretName) +
		'&description=Discord%20bot%20token&allowedHosts=discord.com&scope=user'
	)
}

export function telegramSecretUrl(secretName = TELEGRAM_BOT_TOKEN_SECRET): string {
	return (
		'https://kody.codes/account/secrets/new?name=' +
		encodeURIComponent(secretName) +
		'&description=Telegram%20bot%20token%20from%20BotFather&allowedHosts=api.telegram.org&scope=user'
	)
}

export function discordBotInstallUrl(): string {
	return (
		'https://discord.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&scope=bot&permissions=' +
		DISCORD_BOT_PERMISSIONS
	)
}

export function secretPlaceholder(name: string): string {
	return '{{secret:' + name + '|scope=user}}'
}

export const CONNECT = {
	origin: 'https://kody.codes',
	email: {
		capability: 'email_send',
		note: 'No extra destination. kody.email_send delivers to the signed-in account email.',
	},
	slack: {
		integration: SLACK_INTEGRATION,
		redirectUri: 'https://kody.codes/connect/oauth',
		authorizeUrl: 'https://slack.com/oauth/v2_user/authorize',
		tokenUrl: 'https://slack.com/api/oauth.v2.user.access',
		requiredScope: SLACK_CHAT_WRITE_SCOPE,
		url: slackConnectUrl(),
		byoUrl: slackByoConnectUrl(),
	},
	discord: {
		secretName: DISCORD_BOT_TOKEN_SECRET,
		developerPortal: 'https://discord.com/developers/applications',
		host: 'discord.com',
		url: discordSecretUrl(),
		installUrl: discordBotInstallUrl(),
	},
	telegram: {
		secretName: TELEGRAM_BOT_TOKEN_SECRET,
		botFather: 'https://t.me/BotFather',
		host: 'api.telegram.org',
		url: telegramSecretUrl(),
	},
} as const

export function isDestination(value: unknown): value is Destination {
	return (
		typeof value === 'string' &&
		(DESTINATIONS as readonly string[]).includes(value)
	)
}

export function assertNever(value: never): never {
	throw new Error('Unhandled notify destination: ' + String(value))
}