chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
import rootConfig from '../../eslint.config.mjs'
|
||||
|
||||
export default [
|
||||
...rootConfig,
|
||||
{
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
project: ['./tsconfig.json'],
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
The Webhook integration allows your AI-powered chatbot to seamlessly connect with external systems and services using HTTP-based webhooks. With this integration, you can send and receive data from any system that supports webhooks, enabling your chatbot to interact with external APIs, databases, CRMs, and more. Customize your chatbot's behavior by triggering actions, retrieving information, and updating data through webhook interactions. Leverage the power of webhooks to integrate your chatbot with your existing infrastructure and external services, expanding its capabilities and enabling seamless integration with your preferred systems. Connect your chatbot to the world with the Webhook Integration for Botpress.
|
||||
@@ -0,0 +1,11 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" enable-background="new 0 0 431.45 120.114" xml:space="preserve" viewBox="0 0 129.02 120.11">
|
||||
<g>
|
||||
<g id="OvHZFw.tif">
|
||||
<g>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#C73A63" d="M60.467,50.345c-5.367,9.022-10.509,17.759-15.758,26.43 c-1.348,2.226-2.015,4.039-0.938,6.869c2.973,7.817-1.221,15.424-9.104,17.489c-7.434,1.948-14.677-2.938-16.152-10.897 c-1.307-7.045,4.16-13.951,11.927-15.052c0.651-0.093,1.315-0.104,2.409-0.186c3.806-6.382,7.705-12.919,11.815-19.812 c-7.431-7.389-11.854-16.027-10.875-26.73c0.692-7.566,3.667-14.104,9.105-19.463C53.311-1.269,69.2-2.931,81.463,4.946 c11.778,7.566,17.172,22.304,12.574,34.918c-3.467-0.94-6.958-1.888-10.796-2.929c1.444-7.013,0.376-13.311-4.354-18.706 c-3.125-3.562-7.135-5.429-11.695-6.117c-9.141-1.381-18.116,4.492-20.779,13.464C43.39,35.759,47.965,44.077,60.467,50.345z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#4B4B4B" d="M75.794,39.676c3.781,6.67,7.62,13.441,11.425,20.15 c19.232-5.95,33.732,4.696,38.934,16.094c6.283,13.768,1.988,30.075-10.352,38.569c-12.666,8.72-28.684,7.23-39.906-3.971 c2.86-2.394,5.734-4.799,8.805-7.368c11.084,7.179,20.778,6.841,27.975-1.66c6.137-7.252,6.004-18.065-0.311-25.165 c-7.288-8.193-17.05-8.443-28.85-0.578c-4.895-8.684-9.875-17.299-14.615-26.046c-1.598-2.948-3.363-4.658-6.965-5.282 c-6.016-1.043-9.9-6.209-10.133-11.997c-0.229-5.724,3.143-10.898,8.414-12.914c5.221-1.997,11.348-0.385,14.86,4.054 c2.87,3.627,3.782,7.709,2.272,12.182C76.927,36.991,76.383,38.198,75.794,39.676z"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" fill="#4A4A4A" d="M84.831,94.204c-7.605,0-15.238,0-23.152,0 c-2.219,9.127-7.012,16.496-15.271,21.182c-6.42,3.642-13.34,4.877-20.705,3.688c-13.56-2.187-24.648-14.394-25.624-28.14 c-1.105-15.571,9.598-29.412,23.864-32.521c0.985,3.577,1.98,7.188,2.965,10.756C13.819,75.847,9.289,84.261,12.952,94.782 c3.225,9.259,12.385,14.334,22.331,12.371c10.157-2.004,15.278-10.445,14.653-23.992c9.629,0,19.266-0.1,28.896,0.049 c3.76,0.059,6.663-0.331,9.496-3.646c4.664-5.455,13.248-4.963,18.271,0.189c5.133,5.265,4.887,13.737-0.545,18.78 c-5.241,4.866-13.521,4.606-18.424-0.637C86.622,96.815,85.828,95.532,84.831,94.204z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
@@ -0,0 +1,52 @@
|
||||
import { z, IntegrationDefinition } from '@botpress/sdk'
|
||||
|
||||
export default new IntegrationDefinition({
|
||||
name: 'webhook',
|
||||
version: '1.1.6',
|
||||
title: 'Webhook',
|
||||
description: 'Use webhooks to send and receive data from external systems and trigger workflows.',
|
||||
icon: 'icon.svg',
|
||||
readme: 'hub.md',
|
||||
configuration: {
|
||||
schema: z.object({
|
||||
secret: z
|
||||
.string()
|
||||
.optional()
|
||||
.title('Webhook Header Secret')
|
||||
.describe(
|
||||
'Secret that must be sent with the request as a header called "x-bp-secret." Leave empty to allow all requests without a secret.'
|
||||
),
|
||||
allowedOrigins: z
|
||||
.array(z.string())
|
||||
.optional()
|
||||
.title('Allowed Origins')
|
||||
.describe(
|
||||
'List of allowed origins for CORS. Leaving this field empty will block all requests originating from a browser and only allow requests from a server.'
|
||||
),
|
||||
}),
|
||||
},
|
||||
events: {
|
||||
event: {
|
||||
title: 'Event',
|
||||
description: 'The event triggered in the webhook',
|
||||
schema: z
|
||||
.object({
|
||||
body: z.any().describe('The body of the event').title('Body'),
|
||||
query: z.record(z.any()).describe('The query of the event').title('Query'),
|
||||
path: z.string().describe('The path of the event').title('Path'),
|
||||
headers: z
|
||||
.record(z.union([z.string(), z.string().array()]))
|
||||
.describe('The headers of the event')
|
||||
.title('Headers'),
|
||||
method: z.enum(['GET', 'POST']).describe('The method of the event').title('Method'),
|
||||
})
|
||||
.passthrough(),
|
||||
},
|
||||
},
|
||||
|
||||
attributes: {
|
||||
category: 'Developer Tools',
|
||||
guideSlug: 'webhook',
|
||||
repo: 'botpress',
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "@botpresshub/webhook",
|
||||
"description": "Webhook 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/sdk": "workspace:*",
|
||||
"@botpress/sdk-addons": "workspace:*",
|
||||
"qs": "^6.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@botpress/cli": "workspace:*",
|
||||
"@botpress/common": "workspace:*",
|
||||
"@botpress/sdk": "workspace:*",
|
||||
"@types/qs": "^6.9.7"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { type HandlerProps } from '.botpress'
|
||||
|
||||
const ACCESS_CONTROL_ALLOW_ORIGIN = 'Access-Control-Allow-Origin'
|
||||
|
||||
export const getCorsHeaders = (args: HandlerProps): Record<string, string> => {
|
||||
const { allowedOrigins } = args.ctx.configuration
|
||||
|
||||
if (!allowedOrigins || allowedOrigins.length === 0) {
|
||||
return {
|
||||
[ACCESS_CONTROL_ALLOW_ORIGIN]: '',
|
||||
}
|
||||
}
|
||||
|
||||
const reqOrigin = args.req.headers.origin
|
||||
|
||||
if (!reqOrigin) {
|
||||
return {
|
||||
[ACCESS_CONTROL_ALLOW_ORIGIN]: '',
|
||||
}
|
||||
}
|
||||
|
||||
if (allowedOrigins.includes(reqOrigin)) {
|
||||
return {
|
||||
[ACCESS_CONTROL_ALLOW_ORIGIN]: reqOrigin,
|
||||
}
|
||||
}
|
||||
|
||||
if (allowedOrigins.includes('*')) {
|
||||
return {
|
||||
[ACCESS_CONTROL_ALLOW_ORIGIN]: reqOrigin,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
[ACCESS_CONTROL_ALLOW_ORIGIN]: '',
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
import { RuntimeError } from '@botpress/client'
|
||||
import { reporting } from '@botpress/sdk-addons'
|
||||
import qs from 'qs'
|
||||
import { getCorsHeaders } from './cors'
|
||||
import * as bp from '.botpress'
|
||||
|
||||
type EventEvent = bp.events.event.Event
|
||||
type Method = EventEvent['method']
|
||||
|
||||
const methods = {
|
||||
GET: null,
|
||||
POST: null,
|
||||
} satisfies Record<Method, null>
|
||||
|
||||
const isMethod = (method: string): method is Method => method in methods
|
||||
|
||||
const truncate = (str: string, maxLength: number = 500): string =>
|
||||
str.length > maxLength ? `${str.slice(0, maxLength)}...` : str
|
||||
const debugRequest = ({ req, logger }: bp.HandlerProps): void => {
|
||||
const { method, path, query, body } = req
|
||||
const fullPath = query ? `${path}?${query}` : path
|
||||
const debug = truncate(`${method} ${fullPath} ${JSON.stringify(body)}`)
|
||||
logger.forBot().debug('Received webhook request:', debug)
|
||||
}
|
||||
|
||||
const integration = new bp.Integration({
|
||||
handler: async (args) => {
|
||||
debugRequest(args)
|
||||
|
||||
const corsHeaders = getCorsHeaders(args)
|
||||
|
||||
if (args.req.method.toLowerCase() === 'options') {
|
||||
// preflight request
|
||||
return {
|
||||
status: 200,
|
||||
headers: corsHeaders,
|
||||
}
|
||||
}
|
||||
|
||||
const { req, client, ctx } = args
|
||||
|
||||
if (ctx.configuration.secret && req.headers['x-bp-secret'] !== ctx.configuration.secret) {
|
||||
throw new RuntimeError('The provided secret is invalid.')
|
||||
}
|
||||
|
||||
const method = req.method.toUpperCase()
|
||||
if (!isMethod(method)) {
|
||||
throw new RuntimeError('Only GET and POST methods are supported.')
|
||||
}
|
||||
|
||||
const query = req.query ? qs.parse(req.query) : {}
|
||||
|
||||
let body = {}
|
||||
try {
|
||||
body = JSON.parse(req.body ?? '{}')
|
||||
} catch {}
|
||||
|
||||
await client.createEvent({
|
||||
type: 'event',
|
||||
payload: {
|
||||
body,
|
||||
query: query as Record<string, any>,
|
||||
method,
|
||||
headers: req.headers as Record<string, string>,
|
||||
path: req.path,
|
||||
},
|
||||
})
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
headers: corsHeaders,
|
||||
}
|
||||
},
|
||||
register: async () => {},
|
||||
unregister: async () => {},
|
||||
actions: {},
|
||||
channels: {},
|
||||
})
|
||||
|
||||
export default reporting.wrapIntegration(integration)
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"paths": { "*": ["./*"] },
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": [".botpress/**/*", "definitions/**/*", "src/**/*", "*.ts"]
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
import config from '../../vitest.config'
|
||||
export default config
|
||||
Reference in New Issue
Block a user