chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
# n8n
|
||||
|
||||
This integration connects your Botpress bot to n8n, letting you trigger workflows from your bot and receive results back as events.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- An n8n instance
|
||||
- An n8n API key — found under **Settings → n8n API**. Generating an API key requires a paid n8n plan and is not available on the free trial.
|
||||
|
||||
## Receiving data back from n8n
|
||||
|
||||
To send data back to Botpress after an n8n workflow finishes, add an **HTTP Request** node at the end of your workflow and configure it to POST to your integration's webhook URL.
|
||||
|
||||
You can find the webhook URL in your Botpress dashboard under **Integrations → n8n → Webhook URL**.
|
||||
|
||||
**Trigger Workflow** automatically sends `conversationId` to n8n, so `{{ $json.body.conversationId }}` is available in your workflow without any extra configuration.
|
||||
Set the action's **Conversation ID** input to `{{ event.conversationId }}`.
|
||||
|
||||
Set the request body to:
|
||||
|
||||
```json
|
||||
{
|
||||
"conversationId": "{{ $json.body.conversationId }}",
|
||||
"workflowId": "{{ $workflow.id }}",
|
||||
"workflowName": "{{ $workflow.name }}",
|
||||
"data": {
|
||||
"anyKey": "anyValue"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Limitations
|
||||
|
||||
- **Trigger Workflow** only works on workflows that have a **Webhook** node (`n8n-nodes-base.webhook`) with a path configured.
|
||||
- **List Workflows** returns a paginated response. Use the `limit` and `cursor` inputs to page through results for many workflows.
|
||||
@@ -0,0 +1 @@
|
||||
<svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>n8n</title><path clip-rule="evenodd" d="M24 8.4c0 1.325-1.102 2.4-2.462 2.4-1.146 0-2.11-.765-2.384-1.8h-3.436c-.602 0-1.115.424-1.214 1.003l-.101.592a2.38 2.38 0 01-.8 1.405c.412.354.704.844.8 1.405l.1.592A1.222 1.222 0 0015.719 15h.975c.273-1.035 1.237-1.8 2.384-1.8 1.36 0 2.461 1.075 2.461 2.4S20.436 18 19.078 18c-1.147 0-2.11-.765-2.384-1.8h-.975c-1.204 0-2.23-.848-2.428-2.005l-.101-.592a1.222 1.222 0 00-1.214-1.003H10.97c-.308.984-1.246 1.7-2.356 1.7-1.11 0-2.048-.716-2.355-1.7H4.817c-.308.984-1.246 1.7-2.355 1.7C1.102 14.3 0 13.225 0 11.9s1.102-2.4 2.462-2.4c1.183 0 2.172.815 2.408 1.9h1.337c.236-1.085 1.225-1.9 2.408-1.9 1.184 0 2.172.815 2.408 1.9h.952c.601 0 1.115-.424 1.213-1.003l.102-.592c.198-1.157 1.225-2.005 2.428-2.005h3.436c.274-1.035 1.238-1.8 2.384-1.8C22.898 6 24 7.075 24 8.4zm-1.23 0c0 .663-.552 1.2-1.232 1.2-.68 0-1.23-.537-1.23-1.2 0-.663.55-1.2 1.23-1.2.68 0 1.231.537 1.231 1.2zM2.461 13.1c.68 0 1.23-.537 1.23-1.2 0-.663-.55-1.2-1.23-1.2-.68 0-1.231.537-1.231 1.2 0 .663.55 1.2 1.23 1.2zm6.153 0c.68 0 1.231-.537 1.231-1.2 0-.663-.55-1.2-1.23-1.2-.68 0-1.231.537-1.231 1.2 0 .663.55 1.2 1.23 1.2zm10.462 3.7c.68 0 1.23-.537 1.23-1.2 0-.663-.55-1.2-1.23-1.2-.68 0-1.23.537-1.23 1.2 0 .663.55 1.2 1.23 1.2z" fill="#EA4B71" fill-rule="evenodd"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,133 @@
|
||||
import { z, IntegrationDefinition } from '@botpress/sdk'
|
||||
|
||||
export default new IntegrationDefinition({
|
||||
name: 'n8n',
|
||||
title: 'n8n',
|
||||
description: 'This integration allows you to interact with n8n workflows.',
|
||||
version: '0.1.1',
|
||||
readme: 'hub.md',
|
||||
icon: 'icon.svg',
|
||||
configuration: {
|
||||
schema: z.object({
|
||||
baseUrl: z
|
||||
.string()
|
||||
.url()
|
||||
.title('Base URL')
|
||||
.describe('The base URL of your n8n instance, for example https://example.app.n8n.cloud'),
|
||||
accessKey: z
|
||||
.string()
|
||||
.min(1)
|
||||
.title('Access Key')
|
||||
.describe('Your n8n API key. Found in n8n under Settings → n8n API.'),
|
||||
}),
|
||||
},
|
||||
actions: {
|
||||
listWorkflows: {
|
||||
title: 'List Workflows',
|
||||
description: 'Retrieves workflows from n8n.',
|
||||
input: {
|
||||
schema: z.object({
|
||||
active: z.boolean().optional().title('Active').describe('Filter by workflow active state'),
|
||||
name: z.string().optional().title('Name').describe('Filter by workflow name'),
|
||||
tags: z.string().optional().title('Tags').describe('Comma-separated tag filter'),
|
||||
projectId: z.string().optional().title('Project ID').describe('Filter by project ID'),
|
||||
excludePinnedData: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.default(true)
|
||||
.title('Exclude Pinned Data')
|
||||
.describe('Exclude pinned data from the response'),
|
||||
limit: z
|
||||
.number()
|
||||
.int()
|
||||
.max(250)
|
||||
.optional()
|
||||
.title('Limit')
|
||||
.describe('Maximum number of workflows to return (1-250)'),
|
||||
cursor: z.string().optional().title('Cursor').describe('Pagination cursor from a previous request'),
|
||||
}),
|
||||
},
|
||||
output: {
|
||||
schema: z.object({
|
||||
data: z.array(z.any()).title('Workflows').describe('List of workflows returned by n8n'),
|
||||
nextCursor: z
|
||||
.string()
|
||||
.optional()
|
||||
.title('Next Cursor')
|
||||
.describe('Cursor for fetching the next page of results'),
|
||||
}),
|
||||
},
|
||||
},
|
||||
getWorkflow: {
|
||||
title: 'Get Workflow',
|
||||
description: 'Retrieves a single workflow from n8n by ID.',
|
||||
input: {
|
||||
schema: z.object({
|
||||
workflowId: z.string().min(1).title('Workflow ID').describe('The workflow ID'),
|
||||
excludePinnedData: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.default(true)
|
||||
.title('Exclude Pinned Data')
|
||||
.describe('Exclude pinned data from the response'),
|
||||
}),
|
||||
},
|
||||
output: {
|
||||
schema: z.object({
|
||||
workflow: z.any().title('Workflow').describe('The full workflow object returned by n8n'),
|
||||
}),
|
||||
},
|
||||
},
|
||||
triggerWorkflow: {
|
||||
title: 'Trigger Workflow',
|
||||
description: 'Resolves an n8n workflow webhook and posts data to it.',
|
||||
input: {
|
||||
schema: z.object({
|
||||
workflowIdOrName: z.string().min(1).title('Workflow ID or Name').describe('The workflow ID or name'),
|
||||
conversationId: z
|
||||
.string()
|
||||
.min(1)
|
||||
.placeholder('{{ event.conversationId }}')
|
||||
.title('Conversation ID')
|
||||
.describe('The current Botpress conversation ID — use {{event.conversationId}}'),
|
||||
payload: z
|
||||
.record(z.string(), z.any())
|
||||
.optional()
|
||||
.default({})
|
||||
.title('Payload')
|
||||
.describe('The JSON payload to send to the workflow'),
|
||||
}),
|
||||
},
|
||||
output: {
|
||||
schema: z.object({
|
||||
workflowId: z.string().optional().title('Workflow ID').describe('The ID of the triggered workflow'),
|
||||
workflowName: z.string().optional().title('Workflow Name').describe('The name of the triggered workflow'),
|
||||
response: z.any().optional().title('Response').describe('The response body returned by the n8n webhook'),
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
events: {
|
||||
n8nEvent: {
|
||||
title: 'n8n event',
|
||||
description: 'Triggered when n8n posts data back to Botpress.',
|
||||
schema: z.object({
|
||||
workflowId: z
|
||||
.string()
|
||||
.optional()
|
||||
.title('Workflow ID')
|
||||
.describe('The ID of the workflow that posted this event'),
|
||||
workflowName: z
|
||||
.string()
|
||||
.optional()
|
||||
.title('Workflow Name')
|
||||
.describe('The name of the workflow that posted this event'),
|
||||
data: z.record(z.string(), z.any()).title('Data').describe('Arbitrary data payload sent by the n8n workflow'),
|
||||
}),
|
||||
},
|
||||
},
|
||||
attributes: {
|
||||
category: 'Developer Tools',
|
||||
repo: 'botpress',
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "@botpresshub/n8n",
|
||||
"scripts": {
|
||||
"check:type": "tsc --noEmit",
|
||||
"build": "bp add -y && bp build",
|
||||
"check:bplint": "bp lint"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@botpress/common": "workspace:*",
|
||||
"@botpress/sdk": "workspace:*",
|
||||
"axios": "^1.7.9"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@botpress/cli": "workspace:*",
|
||||
"@botpress/sdk": "workspace:*"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import { createActionWrapper } from '@botpress/common'
|
||||
import { N8nClient } from './client'
|
||||
import * as bp from '.botpress'
|
||||
|
||||
const _wrapAction = createActionWrapper<bp.IntegrationProps>()({
|
||||
toolFactories: {
|
||||
n8nClient: ({ ctx }) => new N8nClient(ctx.configuration),
|
||||
},
|
||||
})
|
||||
|
||||
export const wrapAction: typeof _wrapAction = (meta, actionImpl) =>
|
||||
_wrapAction(meta, (props) => {
|
||||
props.logger.forBot().debug(`Running action "${meta.actionName}"`, { input: props.input })
|
||||
return actionImpl(props as Parameters<typeof actionImpl>[0], props.input)
|
||||
})
|
||||
@@ -0,0 +1,6 @@
|
||||
import { wrapAction } from '../action-wrapper'
|
||||
|
||||
export const getWorkflow = wrapAction({ actionName: 'getWorkflow' }, async ({ n8nClient }, input) => {
|
||||
const workflow = await n8nClient.getWorkflow(input.workflowId, input.excludePinnedData ?? true)
|
||||
return { workflow }
|
||||
})
|
||||
@@ -0,0 +1,9 @@
|
||||
import { getWorkflow } from './get-workflow'
|
||||
import { listWorkflows } from './list-workflows'
|
||||
import { triggerWorkflow } from './trigger-workflow'
|
||||
|
||||
export default {
|
||||
listWorkflows,
|
||||
getWorkflow,
|
||||
triggerWorkflow,
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { wrapAction } from '../action-wrapper'
|
||||
|
||||
export const listWorkflows = wrapAction({ actionName: 'listWorkflows' }, async ({ n8nClient }, input) =>
|
||||
n8nClient.listWorkflows(input)
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
import { wrapAction } from '../action-wrapper'
|
||||
|
||||
export const triggerWorkflow = wrapAction({ actionName: 'triggerWorkflow' }, async ({ n8nClient }, input) =>
|
||||
n8nClient.triggerWorkflowWebhook({
|
||||
workflowIdOrName: input.workflowIdOrName,
|
||||
body: {
|
||||
conversationId: input.conversationId,
|
||||
data: input.payload ?? {},
|
||||
},
|
||||
})
|
||||
)
|
||||
@@ -0,0 +1,160 @@
|
||||
import * as sdk from '@botpress/sdk'
|
||||
import axios, { type AxiosInstance } from 'axios'
|
||||
import { isNotFoundResponse, wrapN8nError, wrapRegistrationError } from './errors'
|
||||
import type { N8nConfiguration, N8nWorkflow, ListWorkflowsInput, TriggerWorkflowWebhookInput } from './types'
|
||||
|
||||
const WEBHOOK_NODE_TYPE = 'n8n-nodes-base.webhook'
|
||||
|
||||
export class N8nClient {
|
||||
private readonly _baseUrl: string
|
||||
private readonly _client: AxiosInstance
|
||||
|
||||
public constructor(configuration: N8nConfiguration) {
|
||||
this._baseUrl = configuration.baseUrl
|
||||
this._client = axios.create({
|
||||
baseURL: this._buildApiUrl('/'),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-N8N-API-KEY': configuration.accessKey,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
public async validateConnection(): Promise<void> {
|
||||
try {
|
||||
await this._client.get('/workflows', {
|
||||
params: {
|
||||
limit: 1,
|
||||
excludePinnedData: true,
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
return wrapRegistrationError(error, this._baseUrl)
|
||||
}
|
||||
}
|
||||
|
||||
public async listWorkflows(input: ListWorkflowsInput) {
|
||||
try {
|
||||
const { data } = await this._client.get('/workflows', {
|
||||
params: {
|
||||
active: input.active,
|
||||
name: input.name,
|
||||
tags: input.tags,
|
||||
projectId: input.projectId,
|
||||
excludePinnedData: input.excludePinnedData,
|
||||
limit: input.limit,
|
||||
cursor: input.cursor,
|
||||
},
|
||||
})
|
||||
|
||||
return {
|
||||
data: data?.data ?? [],
|
||||
nextCursor: data?.nextCursor ?? undefined,
|
||||
}
|
||||
} catch (error) {
|
||||
return wrapN8nError(error)
|
||||
}
|
||||
}
|
||||
|
||||
public async getWorkflow(workflowId: string, excludePinnedData = true): Promise<N8nWorkflow> {
|
||||
try {
|
||||
return await this._getWorkflowById(workflowId, excludePinnedData)
|
||||
} catch (error) {
|
||||
if (isNotFoundResponse(error)) {
|
||||
throw new sdk.RuntimeError(`n8n workflow "${workflowId}" not found`)
|
||||
}
|
||||
return wrapN8nError(error)
|
||||
}
|
||||
}
|
||||
|
||||
public async triggerWorkflowWebhook(input: TriggerWorkflowWebhookInput) {
|
||||
const workflow = await this._resolveWorkflowByIdOrName(input.workflowIdOrName)
|
||||
const webhookPath = this._getWebhookPath(workflow)
|
||||
|
||||
if (!webhookPath) {
|
||||
throw new sdk.RuntimeError('Unable to find an n8n webhook node with a path parameter in the selected workflow')
|
||||
}
|
||||
|
||||
const webhookUrl = this._buildPublicUrl(`/webhook/${webhookPath.replace(/^\/+/, '')}`)
|
||||
|
||||
try {
|
||||
// Webhook URLs are public endpoints, no need to use the API key.
|
||||
const response = await axios.post(webhookUrl, {
|
||||
...input.body,
|
||||
workflowId: workflow.id,
|
||||
workflowName: workflow.name,
|
||||
})
|
||||
|
||||
return {
|
||||
workflowId: workflow.id,
|
||||
workflowName: workflow.name,
|
||||
response: response.data,
|
||||
}
|
||||
} catch (error) {
|
||||
return wrapN8nError(error, 'n8n webhook trigger')
|
||||
}
|
||||
}
|
||||
|
||||
private async _resolveWorkflowByIdOrName(workflowIdOrName: string): Promise<N8nWorkflow> {
|
||||
try {
|
||||
return await this._getWorkflowById(workflowIdOrName)
|
||||
} catch (error) {
|
||||
if (!isNotFoundResponse(error)) {
|
||||
return wrapN8nError(error)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const { data } = await this._client.get<{ data?: N8nWorkflow[] }>('/workflows', {
|
||||
params: {
|
||||
name: workflowIdOrName,
|
||||
excludePinnedData: true,
|
||||
},
|
||||
})
|
||||
|
||||
const exactMatch = (data?.data ?? []).find(
|
||||
(workflow) => workflow?.name === workflowIdOrName || workflow?.id === workflowIdOrName
|
||||
)
|
||||
|
||||
if (exactMatch?.id) {
|
||||
return await this._getWorkflowById(exactMatch.id)
|
||||
}
|
||||
} catch (error) {
|
||||
return wrapN8nError(error)
|
||||
}
|
||||
|
||||
throw new sdk.RuntimeError(`Unable to resolve n8n workflow "${workflowIdOrName}"`)
|
||||
}
|
||||
|
||||
private async _getWorkflowById(workflowId: string, excludePinnedData = true): Promise<N8nWorkflow> {
|
||||
const { data } = await this._client.get<N8nWorkflow>(`/workflows/${encodeURIComponent(workflowId)}`, {
|
||||
params: {
|
||||
excludePinnedData,
|
||||
},
|
||||
})
|
||||
return data
|
||||
}
|
||||
|
||||
private _getWebhookPath(workflow: N8nWorkflow): string | undefined {
|
||||
const nodes = workflow?.nodes ?? workflow?.activeVersion?.nodes ?? []
|
||||
const webhookNode = nodes.find((node) => node?.type === WEBHOOK_NODE_TYPE)
|
||||
const path = webhookNode?.parameters?.path
|
||||
|
||||
return typeof path === 'string' ? path : undefined
|
||||
}
|
||||
|
||||
private _buildApiUrl(path: string): string {
|
||||
return this._buildUrl(path, true)
|
||||
}
|
||||
|
||||
private _buildPublicUrl(path: string): string {
|
||||
return this._buildUrl(path, false)
|
||||
}
|
||||
|
||||
private _buildUrl(path: string, api: boolean): string {
|
||||
const base = this._baseUrl.replace(/\/+$/, '')
|
||||
const prefix = api ? '/api/v1' : ''
|
||||
const normalizedPath = path.startsWith('/') ? path : `/${path}`
|
||||
return `${base}${prefix}${normalizedPath}`
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import * as sdk from '@botpress/sdk'
|
||||
import axios from 'axios'
|
||||
|
||||
export const isNotFoundResponse = (error: unknown): boolean =>
|
||||
axios.isAxiosError(error) && error.response?.status === 404
|
||||
|
||||
export const wrapN8nError = (error: unknown, context = 'n8n request'): never => {
|
||||
if (axios.isAxiosError(error)) {
|
||||
const status = error.response?.status
|
||||
const detail = status ? `HTTP ${status}` : (error.code ?? error.message ?? 'network error')
|
||||
throw new sdk.RuntimeError(`${context} failed: ${detail}`)
|
||||
}
|
||||
throw new sdk.RuntimeError(error instanceof Error ? error.message : String(error))
|
||||
}
|
||||
|
||||
export const wrapRegistrationError = (error: unknown, baseUrl: string): never => {
|
||||
if (axios.isAxiosError(error)) {
|
||||
const status = error.response?.status
|
||||
const code = error.code
|
||||
const message = status ? `n8n responded with HTTP ${status}` : (code ?? error.message ?? 'network error')
|
||||
|
||||
if (status === 401 || status === 403) {
|
||||
throw new sdk.RuntimeError(
|
||||
`Registration failed: authentication rejected (${message}). Check your Access Key and permissions.`
|
||||
)
|
||||
}
|
||||
|
||||
if (status === 404) {
|
||||
throw new sdk.RuntimeError(
|
||||
`Registration failed: the n8n API was not found at ${baseUrl}/api/v1 (HTTP 404). Ensure your Base URL points to the root of your n8n instance (for example https://example.app.n8n.cloud).`
|
||||
)
|
||||
}
|
||||
|
||||
throw new sdk.RuntimeError(
|
||||
`Registration failed: unable to reach n8n (${message}). Verify the Base URL is correct and reachable from this host.`
|
||||
)
|
||||
}
|
||||
|
||||
const message = error instanceof Error ? error.message : String(error)
|
||||
throw new sdk.RuntimeError(`Registration failed: ${message}`)
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
import { z } from '@botpress/sdk'
|
||||
import actions from './actions'
|
||||
import { N8nClient } from './client'
|
||||
import * as bp from '.botpress'
|
||||
|
||||
const webhookPayloadSchema = z.object({
|
||||
conversationId: z.string().optional(),
|
||||
workflowId: z.string().optional(),
|
||||
workflowName: z.string().optional(),
|
||||
data: z.union([z.record(z.string(), z.any()), z.string()]).optional(),
|
||||
})
|
||||
|
||||
const parseJsonBody = (body: unknown): unknown | null => {
|
||||
if (typeof body !== 'string') {
|
||||
return body
|
||||
}
|
||||
try {
|
||||
return JSON.parse(body)
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export default new bp.Integration({
|
||||
register: async ({ ctx }) => {
|
||||
await new N8nClient(ctx.configuration).validateConnection()
|
||||
},
|
||||
unregister: async () => undefined,
|
||||
actions,
|
||||
channels: {},
|
||||
handler: async ({ req, client, logger }) => {
|
||||
const log = logger.forBot()
|
||||
|
||||
const body = parseJsonBody(req.body)
|
||||
if (!body || typeof body !== 'object') {
|
||||
log.error('n8n webhook request must contain a valid JSON object body')
|
||||
return
|
||||
}
|
||||
|
||||
const result = webhookPayloadSchema.safeParse(body)
|
||||
if (!result.success) {
|
||||
log.error('Invalid n8n webhook payload structure')
|
||||
return
|
||||
}
|
||||
|
||||
const payload = result.data
|
||||
|
||||
if (!payload.conversationId) {
|
||||
log.error('Missing conversationId in n8n webhook payload — ensure your n8n workflow echoes it back')
|
||||
return
|
||||
}
|
||||
|
||||
let data: Record<string, any>
|
||||
if (typeof payload.data === 'string') {
|
||||
try {
|
||||
data = JSON.parse(payload.data)
|
||||
} catch {
|
||||
log.error('n8n webhook payload.data contained invalid JSON')
|
||||
return
|
||||
}
|
||||
} else if (typeof payload.data === 'object' && payload.data !== null) {
|
||||
data = payload.data
|
||||
} else {
|
||||
data = {}
|
||||
}
|
||||
|
||||
try {
|
||||
await client.createEvent({
|
||||
type: 'n8nEvent',
|
||||
conversationId: payload.conversationId,
|
||||
payload: {
|
||||
workflowId: payload.workflowId,
|
||||
workflowName: payload.workflowName,
|
||||
data,
|
||||
},
|
||||
})
|
||||
} catch (err) {
|
||||
log.error(`Failed to create n8n event: ${err instanceof Error ? err.message : String(err)}`)
|
||||
return
|
||||
}
|
||||
|
||||
return { status: 200, body: JSON.stringify({ ok: true }) }
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,33 @@
|
||||
export type N8nNode = {
|
||||
type: string
|
||||
parameters?: Record<string, unknown>
|
||||
}
|
||||
|
||||
export type N8nWorkflow = {
|
||||
id?: string
|
||||
name?: string
|
||||
nodes?: N8nNode[]
|
||||
activeVersion?: {
|
||||
nodes?: N8nNode[]
|
||||
}
|
||||
}
|
||||
|
||||
export type N8nConfiguration = {
|
||||
baseUrl: string
|
||||
accessKey: string
|
||||
}
|
||||
|
||||
export type ListWorkflowsInput = {
|
||||
active?: boolean
|
||||
name?: string
|
||||
tags?: string
|
||||
projectId?: string
|
||||
excludePinnedData?: boolean
|
||||
limit?: number
|
||||
cursor?: string
|
||||
}
|
||||
|
||||
export type TriggerWorkflowWebhookInput = {
|
||||
workflowIdOrName: string
|
||||
body: Record<string, any>
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"paths": { "*": ["./*"] },
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": [".botpress/**/*", "definitions/**/*", "src/**/*", "*.ts"]
|
||||
}
|
||||
Reference in New Issue
Block a user