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: slackByoConnectUrl(), reconnectUrl: 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)) }