chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:34:48 +08:00
commit 77bb5bf71f
3762 changed files with 353249 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
.botpress
+13
View File
@@ -0,0 +1,13 @@
import rootConfig from '../../eslint.config.mjs'
export default [
...rootConfig,
{
languageOptions: {
parserOptions: {
project: ['./tsconfig.json'],
tsconfigRootDir: import.meta.dirname,
},
},
},
]
+1
View File
@@ -0,0 +1 @@
to_string!(parse_json!(.body).data.item.admin_assignee_id)
+10
View File
@@ -0,0 +1,10 @@
The Intercom integration empowers your conversational AI by seamlessly integrating Botpress with Intercom's powerful customer messaging platform. Connect your AI-powered chatbot to Intercom and engage with your customers in real-time through personalized conversations. With this integration, you can automate customer support, handle inquiries, collect feedback, and nurture leads directly within Intercom. Leverage Intercom's features such as live chat, user segmentation, event tracking, and in-app messaging to deliver exceptional customer experiences. Streamline your customer communication and take your conversational AI to new heights with the Intercom Integration for Botpress.
## Migration from 1.x to 2.x
The Intercom integration now supports the `getOrCreateConversation` and `getOrCreateUser` actions, allowing you to proactively start conversations with Intercom users.
### Key notes
- New action cards: `getOrCreateConversation` and `getOrCreateUser`.
- Made `adminId` optional within the manual configuration.
+1
View File
@@ -0,0 +1 @@
<svg width="2500" height="2500" viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid"><path d="M221.867 140.748a8.534 8.534 0 0 1-17.067 0V64a8.534 8.534 0 0 1 17.067 0v76.748zm-2.978 53.413c-1.319 1.129-32.93 27.655-90.889 27.655-57.958 0-89.568-26.527-90.887-27.656a8.535 8.535 0 0 1-.925-12.033 8.53 8.53 0 0 1 12.013-.942c.501.42 28.729 23.563 79.8 23.563 51.712 0 79.503-23.31 79.778-23.545 3.571-3.067 8.968-2.655 12.033.925a8.534 8.534 0 0 1-.923 12.033zM34.133 64A8.534 8.534 0 0 1 51.2 64v76.748a8.534 8.534 0 0 1-17.067 0V64zm42.668-17.067a8.534 8.534 0 0 1 17.066 0v114.001a8.534 8.534 0 0 1-17.066 0v-114zm42.666-4.318A8.532 8.532 0 0 1 128 34.082a8.532 8.532 0 0 1 8.534 8.533v123.733a8.534 8.534 0 0 1-17.067 0V42.615zm42.667 4.318a8.534 8.534 0 0 1 17.066 0v114.001a8.534 8.534 0 0 1-17.066 0v-114zM224 0H32C14.327 0 0 14.327 0 32v192c0 17.672 14.327 32 32 32h192c17.673 0 32-14.328 32-32V32c0-17.673-14.327-32-32-32z" fill="#1F8DED"/></svg>

After

Width:  |  Height:  |  Size: 990 B

@@ -0,0 +1,130 @@
import { z, IntegrationDefinition, messages } from '@botpress/sdk'
import proactiveConversation from 'bp_modules/proactive-conversation'
import proactiveUser from 'bp_modules/proactive-user'
export default new IntegrationDefinition({
name: 'intercom',
version: '2.0.6',
title: 'Intercom',
description: 'Engage with customers in realtime with personalized messaging.',
icon: 'icon.svg',
readme: 'hub.md',
configuration: {
schema: z.object({
accessToken: z.string().min(1).title('Access Token').describe('The access token of the Intercom app'),
adminId: z.string().optional().title('Admin ID').describe('The admin ID of the Bot'),
clientSecret: z
.string()
.secret()
.optional()
.title('Client Secret')
.describe('The client secret of the Intercom app, used for event signature validation'),
}),
// TODO: Uncomment this once the Intercom app is approved
// identifier: {
// linkTemplateScript: 'linkTemplate.vrl',
// required: true,
// },
// schema: z.object({
// adminId: z.string().min(1).describe('The admin ID of the Bot'),
// }),
// },
// configurations: {
// manual: {
// title: 'Manual Configuration',
// description: 'Manual configuration, use your own Intercom app (for advanced use cases only)',
// schema: z.object({
// adminId: z.string().min(1).describe('The admin ID of the Bot'),
// accessToken: z.string().min(1).describe('The access token of the Intercom app'),
// clientSecret: z
// .string()
// .min(1)
// .secret()
// .describe(
// 'The client secret of the Intercom app. Required for event signature validation, even if not authenticated by OAuth'
// ),
// }),
// },
// },
},
channels: {
channel: {
title: 'Intercom conversation',
description: 'Channel for a Intercom conversation',
messages: { ...messages.defaults, bloc: messages.markdownBloc },
message: {
tags: {
id: {
title: 'Message ID',
description: 'The Intercom message ID',
},
},
},
conversation: {
tags: {
id: {
title: 'Conversation ID',
description: 'The Intercom conversation ID',
},
},
},
},
},
actions: {},
events: {},
identifier: {
extractScript: 'extract.vrl',
},
secrets: {
CLIENT_ID: { description: "The Client ID in your app's basic informations" },
CLIENT_SECRET: { description: "The Client secret in your app's basic informations" },
},
user: {
tags: {
id: {
title: 'User ID',
description: 'The Intercom user ID',
},
email: {
title: 'User Email',
description: 'The Intercom user email',
},
},
},
states: {
credentials: {
type: 'integration',
schema: z.object({
adminId: z.string().min(1).title('Admin ID').describe('The admin ID of the Bot'),
accessToken: z.string().min(1).title('Access Token').describe('The access token obtained from OAuth'),
}),
},
},
entities: {
user: {
schema: z.object({
id: z.string().min(1).title('User ID').describe('The ID of the Intercom user'),
}),
},
conversation: {
schema: z.object({
id: z.string().min(1).title('Conversation ID').describe('The ID of the Intercom conversation'),
}),
},
},
attributes: {
category: 'Customer Support',
guideSlug: 'intercom',
repo: 'botpress',
},
})
.extend(proactiveUser, ({ entities }) => ({
entities: {
user: entities.user,
},
}))
.extend(proactiveConversation, ({ entities }) => ({
entities: {
conversation: entities.conversation,
},
}))
+10
View File
@@ -0,0 +1,10 @@
env = to_string!(.env)
webhookId = to_string!(.webhookId)
clientId = "5eba547d-60b2-4ca6-91bf-053a37bd7710"
if env == "production" {
clientId = "f153fcea-a0db-48a0-8575-bbd2a7cfc05e"
}
"https://app.intercom.com/oauth?client_id={{ clientId }}&state={{ webhookId }}"
+28
View File
@@ -0,0 +1,28 @@
{
"name": "@botpresshub/intercom",
"description": "Intercom integration for Botpress",
"private": true,
"scripts": {
"build": "bp add -y && bp build",
"check:type": "tsc --noEmit",
"check:bplint": "bp lint",
"test": "vitest --run"
},
"dependencies": {
"@botpress/cli": "workspace:*",
"@botpress/client": "workspace:*",
"@botpress/common": "workspace:*",
"@botpress/sdk": "workspace:*",
"@botpress/sdk-addons": "workspace:*",
"axios": "^1.7.8",
"intercom-client": "^4.0.0"
},
"devDependencies": {
"@botpress/cli": "workspace:*",
"@botpress/sdk": "workspace:*"
},
"bpDependencies": {
"proactive-user": "../../interfaces/proactive-user",
"proactive-conversation": "../../interfaces/proactive-conversation"
}
}
@@ -0,0 +1,8 @@
import { getOrCreateConversation } from './proactive-conversation'
import { getOrCreateUser } from './proactive-user'
import * as bp from '.botpress'
export const actions = {
getOrCreateConversation,
getOrCreateUser,
} satisfies bp.IntegrationProps['actions']
@@ -0,0 +1,21 @@
import { RuntimeError } from '@botpress/sdk'
import { getAuthenticatedIntercomClient } from '../auth'
import * as bp from '.botpress'
export const getOrCreateConversation: bp.IntegrationProps['actions']['getOrCreateConversation'] = async (props) => {
const { client, ctx, input } = props
const { id: conversationId } = input.conversation
if (!conversationId) {
throw new RuntimeError('Conversation ID is required')
}
const intercomClient = await getAuthenticatedIntercomClient(client, ctx)
const chat = await intercomClient.conversations.find({ id: conversationId })
const { conversation } = await client.getOrCreateConversation({
channel: 'channel',
tags: { id: chat.id },
})
return { conversationId: conversation.id }
}
@@ -0,0 +1,20 @@
import { RuntimeError } from '@botpress/sdk'
import { getAuthenticatedIntercomClient } from '../auth'
import * as bp from '.botpress'
export const getOrCreateUser: bp.IntegrationProps['actions']['getOrCreateUser'] = async (props) => {
const { client, ctx, input } = props
const { id: userId } = input.user
if (!userId) {
throw new RuntimeError('User ID is required')
}
const intercomClient = await getAuthenticatedIntercomClient(client, ctx)
const { id, email } = await intercomClient.contacts.find({ id: userId })
if (!id || !email) {
throw new RuntimeError('User not found')
}
const { user } = await client.getOrCreateUser({ tags: { id, email }, discriminateByTags: ['id'] })
return { userId: user.id }
}
+105
View File
@@ -0,0 +1,105 @@
import { generateRedirection, getInterstitialUrl } from '@botpress/common/src/oauth-wizard/interstitial'
import * as sdk from '@botpress/sdk'
import { RuntimeError, z } from '@botpress/sdk'
import axios from 'axios'
import { Client as IntercomClient } from 'intercom-client'
import * as bp from '.botpress'
export const getAuthenticatedIntercomClient = async (client: bp.Client, ctx: bp.Context): Promise<IntercomClient> => {
// TODO: Change null for 'manual' once the Intercom app is approved
if (ctx.configurationType === null) {
return new IntercomClient({ tokenAuth: { token: ctx.configuration.accessToken } })
}
const { state } = await client.getState({
id: ctx.integrationId,
name: 'credentials',
type: 'integration',
})
const { accessToken } = state.payload
return new IntercomClient({ tokenAuth: { token: accessToken } })
}
const saveAuthCredentials = async (
client: bp.Client,
ctx: bp.Context,
{ accessToken, adminId }: { accessToken: string; adminId: string }
): Promise<void> => {
await client.setState({
id: ctx.integrationId,
name: 'credentials',
type: 'integration',
payload: { accessToken, adminId },
})
}
const exchangeCodeForAccessToken = async (code: string): Promise<string> => {
const response = await axios.post('https://api.intercom.io/auth/eagle/token', {
code,
client_id: bp.secrets.CLIENT_ID,
client_secret: bp.secrets.CLIENT_SECRET,
})
const responseSchema = z.object({
access_token: z.string(),
})
const accessToken = responseSchema.safeParse(response.data).data?.access_token
if (!accessToken) {
throw new RuntimeError('Failed to exchange code for access token')
}
return accessToken
}
export const getSignatureSecret = (ctx: bp.Context): string | undefined => {
// TODO: Change null for 'manual' once the Intercom app is approved
if (ctx.configurationType === null) {
return ctx.configuration.clientSecret
}
return bp.secrets.CLIENT_SECRET
}
export const handleOAuth = async ({ client, ctx, req, logger }: bp.HandlerProps): Promise<sdk.Response> => {
logger.forBot().info('Handling OAuth callback')
try {
const searchParams = new URLSearchParams(req.query)
const error = searchParams.get('error')
if (error) {
throw new Error(`${error} - ${searchParams.get('error_description') ?? ''}`)
}
const code = searchParams.get('code')
if (!code) {
throw new Error('Authorization code not present in OAuth callback')
}
const accessToken = await exchangeCodeForAccessToken(code)
const adminId = await getAdminId(ctx)
await saveAuthCredentials(client, ctx, { accessToken, adminId })
await client.configureIntegration({ identifier: adminId })
return generateRedirection(getInterstitialUrl(true))
} catch (err) {
const msg = err instanceof Error ? err.message : String(err)
const errorMessage = 'OAuth error: ' + msg
logger.forBot().error(errorMessage)
return generateRedirection(getInterstitialUrl(false, errorMessage))
}
}
const responseSchema = z.object({
type: z.string(),
id: z.string(),
})
export const getAdminId = async (ctx: bp.Context): Promise<string> => {
const response = await axios.get('https://api.intercom.io/me', {
headers: {
Authorization: `Bearer ${ctx.configuration.accessToken}`,
},
})
const parsedResponse = responseSchema.safeParse(response.data)
if (!parsedResponse.success) {
throw new RuntimeError('Failed to parse admin ID from response')
}
return parsedResponse.data.id
}
+185
View File
@@ -0,0 +1,185 @@
import { RuntimeError } from '@botpress/client'
import { ReplyToConversationMessageType } from 'intercom-client'
import { getAuthenticatedIntercomClient } from './auth'
import * as html from './html.utils'
import * as types from './types'
import * as bp from '.botpress'
type Card = bp.channels.channel.card.Card
type Location = bp.channels.channel.location.Location
export const channels: bp.IntegrationProps['channels'] = {
channel: {
messages: {
text: async ({ payload, conversation, ack, client, ctx }) => {
await sendMessage({
body: payload.text,
conversation,
client,
ctx,
ack,
})
},
image: async ({ payload, client, ctx, conversation, ack }) => {
await sendMessage({
body: '',
conversation,
client,
ctx,
ack,
attachmentUrls: [payload.imageUrl],
})
},
audio: async ({ client, ctx, conversation, ack, payload }) => {
await sendMessage({
body: '',
conversation,
client,
ctx,
ack,
attachmentUrls: [payload.audioUrl],
})
},
video: async ({ client, ctx, conversation, ack, payload }) => {
await sendMessage({
body: '',
conversation,
client,
ctx,
ack,
attachmentUrls: [payload.videoUrl],
})
},
file: async ({ client, ctx, conversation, ack, payload }) => {
await sendMessage({
body: '',
conversation,
client,
ctx,
ack,
attachmentUrls: [payload.fileUrl],
})
},
location: async ({ client, ctx, conversation, ack, payload }) => {
await sendMessage({
body: formatGoogleMapLink(payload),
conversation,
client,
ctx,
ack,
})
},
carousel: async ({ client, ctx, conversation, ack, payload }) => {
const carousel = payload.items.map((card) => createCard(card)).join('')
await sendMessage({
body: carousel,
conversation,
client,
ctx,
ack,
})
},
card: async ({ client, ctx, conversation, ack, payload }) => {
await sendMessage({
body: createCard(payload),
conversation,
client,
ctx,
ack,
})
},
dropdown: async ({ client, ctx, conversation, ack, payload }) => {
const choices = payload.options.map((choice) => html.li(choice.value))
const message = composeMessage(
html.p(payload.text),
html.p('Type one of the following options:'),
choices.length > 0 ? html.ol(choices.join('')) : ''
)
await sendMessage({
body: message,
conversation,
client,
ctx,
ack,
})
},
choice: async ({ client, ctx, conversation, ack, payload }) => {
const choices = payload.options.map((choice) => html.li(choice.value))
const message = composeMessage(
html.p(payload.text),
html.p('Type one of the following options:'),
choices.length > 0 ? html.ol(choices.join('')) : ''
)
await sendMessage({
body: message,
conversation,
client,
ctx,
ack,
})
},
bloc: () => {
throw new RuntimeError('Not implemented')
},
},
},
}
async function sendMessage(
props: Pick<types.MessageHandlerProps, 'conversation' | 'client' | 'ctx' | 'ack'> & {
body: string
attachmentUrls?: string[]
}
) {
const { body, attachmentUrls, client, ctx, conversation, ack } = props
const { state } = await client.getState({ type: 'integration', name: 'credentials', id: ctx.integrationId })
const { adminId } = state.payload
const intercomClient = await getAuthenticatedIntercomClient(client, ctx)
const {
conversation_parts: { conversation_parts: conversationParts },
} = await intercomClient.conversations.replyByIdAsAdmin({
id: conversation.tags.id ?? '',
adminId,
messageType: ReplyToConversationMessageType.COMMENT,
body,
attachmentUrls,
})
const lastMessageId = conversationParts.at(-1)?.id
await ack({ tags: { id: lastMessageId } })
}
function composeMessage(...parts: string[]) {
return parts.join('')
}
function createCard({ title, subtitle, imageUrl, actions }: Card) {
const image = imageUrl ? html.img(imageUrl) : ''
const text = html.b(title) + html.p(subtitle ? subtitle : '')
const links = actions.filter((item) => item.action === 'url').map((item) => html.li(html.a(item.value, item.label)))
const choices = actions
.filter((item) => item.action !== 'url')
.map((item) => html.li(item.value))
.join('')
return composeMessage(
image,
text,
links.length > 0 ? html.ul(links.join('')) : '',
html.p('Type one of the following options:'),
html.ol(choices)
)
}
function formatGoogleMapLink(payload: Location) {
return `https://www.google.com/maps/search/?api=1&query=${payload.latitude},${payload.longitude}`
}
+210
View File
@@ -0,0 +1,210 @@
import { RuntimeError } from '@botpress/client'
import { Request, z } from '@botpress/sdk'
import * as crypto from 'crypto'
import { getSignatureSecret, handleOAuth } from './auth'
import * as html from './html.utils'
import * as bp from '.botpress'
type IntercomMessage = z.infer<typeof conversationSourceSchema>
type VerifyResult =
| { result: 'success'; isError: false; parsedNotification: z.infer<typeof webhookNotificationSchema> }
| { result: 'error'; isError: true; message: string }
| { result: 'ignore'; isError: false; message?: string }
const conversationSourceSchema = z.object({
id: z.string(),
author: z.object({
id: z.string(),
email: z.string().nullable(),
type: z.string(),
}),
body: z.string().nullable(),
})
const conversationPartSchema = conversationSourceSchema.extend({
type: z.literal('conversation_part'),
})
const conversationSchema = z.object({
type: z.literal('conversation'),
admin_assignee_id: z
.number()
.nullable()
.transform((val) => (val ? val.toString() : null)),
id: z.string(),
source: conversationSourceSchema,
conversation_parts: z.object({
conversation_parts: z.array(conversationPartSchema),
}),
})
const pingSchema = z.object({
type: z.literal('ping'),
})
const webhookNotificationSchema = z.object({
type: z.literal('notification_event'),
topic: z.string(),
data: z.object({
item: z.union([conversationSchema, pingSchema]),
}),
})
export const handler: bp.IntegrationProps['handler'] = async (props) => {
console.info('Handler received request')
const { req, client, ctx } = props
if (req.path.startsWith('/oauth')) {
return await handleOAuth(props)
}
const { state } = await client.getState({ type: 'integration', name: 'credentials', id: ctx.integrationId })
const { adminId } = state.payload
const verifyResult = verifyRequest(req, ctx, adminId)
if (verifyResult.isError) {
throw new RuntimeError(`Invalid request received: ${verifyResult.message}`)
} else if (verifyResult.result === 'ignore') {
console.info(`Handler ignored request: ${verifyResult.message ?? 'Unknown reason'}`)
return
}
const notification = verifyResult.parsedNotification
if (notification.data.item.type === 'ping') {
console.info('Handler received a ping event')
return
}
const {
topic,
data: {
item: {
id: conversationId,
conversation_parts: { conversation_parts },
source: firstConversationPart,
},
},
} = notification
const { conversation } = await client.getOrCreateConversation({
channel: 'channel',
tags: {
id: conversationId,
},
})
// this uses the message payload from intercom to create the message in the bot
const createMessage = async (intercomMessage: IntercomMessage) => {
const {
author: { id: authorId, email, type: authorType },
body,
id: messageId,
} = intercomMessage
if (!messageId) {
throw new Error('Handler received an empty message id')
}
if (!body) {
return // ignore no body messages
}
if (authorType === 'bot') {
console.info(`Handler received a bot message with id ${messageId}`)
return // ignore bot messages
}
const user = await getOrCreateUserAndUpdate(client, {
id: authorId,
email,
})
await client.getOrCreateMessage({
tags: { id: messageId },
type: 'text',
userId: user.id,
conversationId: conversation.id,
payload: { text: html.stripTags(body) },
})
}
if (topic === 'conversation.user.created') {
await createMessage(firstConversationPart) // important, intercom keeps the first message in a separate object
}
for (const part of conversation_parts) {
await createMessage(part)
}
console.info('Handler finished processing request')
return
}
function extractSignature(req: Request) {
const signatureKv = req.headers['x-hub-signature']
if (!signatureKv) {
return undefined
}
const signature = signatureKv.split('=')[1]
return signature
}
function isSignatureValid(signature: string, body: string, secret: string) {
const hash = crypto.createHmac('sha1', secret).update(body).digest('hex')
return hash === signature
}
function verifyRequest(req: Request, ctx: bp.Context, adminId: string): VerifyResult {
if (!req.body) {
return { result: 'error', isError: true, message: 'Handler received an empty body' }
}
const signature = extractSignature(req)
const secret = getSignatureSecret(ctx)
if (secret && (!signature || !isSignatureValid(signature, req.body, secret))) {
return { result: 'error', isError: true, message: 'Handler received request with invalid signature' }
}
let parsedJSON
try {
parsedJSON = JSON.parse(req.body)
} catch {
return { result: 'error', isError: true, message: 'Handler received an invalid JSON body' }
}
const parsedBody = webhookNotificationSchema.safeParse(parsedJSON)
if (!parsedBody.success) {
return { result: 'error', isError: true, message: `Handler received an invalid body: ${parsedBody.error}` }
}
const parsedNotification = parsedBody.data
if (parsedNotification.data.item.type === 'ping') {
// No further validation for ping events
return { result: 'success', isError: false, parsedNotification }
}
const SUBSCRIBED_TOPICS = ['conversation.user.created', 'conversation.user.replied']
if (!SUBSCRIBED_TOPICS.includes(parsedNotification.topic)) {
return { result: 'ignore', isError: false, message: `Ignoring topic: ${parsedNotification.topic}` }
}
if (adminId !== parsedNotification.data.item.admin_assignee_id) {
// Ignore conversations not assigned to the bot
return { result: 'ignore', isError: false, message: 'Ignoring conversations not assigned to the bot' }
}
return { result: 'success', isError: false, parsedNotification }
}
const getOrCreateUserAndUpdate = async (client: bp.Client, { id, email }: { id: string; email?: string | null }) => {
let { user } = await client.getOrCreateUser({
tags: { id },
})
if (email && email !== user.tags.email) {
const updateResponse = await client.updateUser({
id: user.id,
tags: { email },
})
user = updateResponse.user
}
return user
}
+45
View File
@@ -0,0 +1,45 @@
export type HtmlTag = 'p' | 'b' | 'h1' | 'h2' | 'ul' | 'ol' | 'li' | 'pre' | 'code' | 'i' | 'em' | 'strong'
export function stripTags(str: string) {
return str.replace(/<[^>]*>?/gm, '')
}
export function ol(str: string) {
return addHtmlTag(str, 'ol')
}
export function li(str: string) {
return addHtmlTag(str, 'li')
}
export function ul(str: string) {
return addHtmlTag(str, 'ul')
}
export function p(str: string) {
return addHtmlTag(str, 'p')
}
export function b(str: string) {
return addHtmlTag(str, 'b')
}
export function h1(str: string) {
return addHtmlTag(str, 'h1')
}
export function h2(str: string) {
return addHtmlTag(str, 'h2')
}
export function img(src: string) {
return `<img src="${src}" />`
}
export function a(href: string, text: string) {
return `<a href="${href}">${text}</a>`
}
function addHtmlTag(str: string, tag: HtmlTag) {
return `<${tag}>${str}</${tag}>`
}
+29
View File
@@ -0,0 +1,29 @@
import { reporting } from '@botpress/sdk-addons'
import { actions } from './actions'
import { getAdminId } from './auth'
import { channels } from './channels'
import { handler } from './handler'
import * as bp from '.botpress'
const integration = new bp.Integration({
register: async ({ client, ctx }) => {
const adminId = ctx.configuration.adminId || (await getAdminId(ctx))
await client.setState({
id: ctx.integrationId,
name: 'credentials',
type: 'integration',
payload: { adminId, accessToken: ctx.configuration.accessToken },
})
await client.updateUser({
id: ctx.botUserId,
tags: { id: adminId },
})
},
unregister: async () => {},
actions,
channels,
handler,
})
export default reporting.wrapIntegration(integration)
+22
View File
@@ -0,0 +1,22 @@
import * as sdk from '@botpress/sdk'
import * as bp from '.botpress'
export type Handler = bp.IntegrationProps['handler']
export type HandlerProps = bp.HandlerProps
export type IntegrationCtx = bp.Context
export type Logger = bp.Logger
export type Client = bp.Client
export type Conversation = bp.ClientResponses['getConversation']['conversation']
export type Message = bp.ClientResponses['getMessage']['message']
export type User = bp.ClientResponses['getUser']['user']
export type Event = bp.ClientResponses['getEvent']['event']
export type EventDefinition = sdk.EventDefinition
export type ActionDefinition = sdk.ActionDefinition
export type ChannelDefinition = sdk.ChannelDefinition
export type MessageDefinition = sdk.MessageDefinition
export type ActionProps = bp.AnyActionProps
export type MessageHandlerProps = bp.AnyMessageProps
export type AckFunction = bp.AnyAckFunction
+8
View File
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"paths": { "*": ["./*"] },
"outDir": "dist"
},
"include": [".botpress/**/*", "definitions/**/*", "src/**/*", "*.ts"]
}
+2
View File
@@ -0,0 +1,2 @@
import config from '../../vitest.config'
export default config