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
@@ -0,0 +1,55 @@
import { z, ActionDefinition } from '@botpress/sdk'
export const contactSchema = z.object({
id: z.number().describe('Contact ID'),
name: z.string().describe('Contact name'),
firstName: z.string().describe('First name'),
lastName: z.string().describe('Last name'),
responsibleUserId: z.number().describe('User responsible for this contact'),
groupId: z.number().describe('Group ID'),
updatedBy: z.number().describe('User who last updated this contact'),
createdAt: z.number().describe('When created (Unix timestamp)'),
updatedAt: z.number().describe('When last updated (Unix timestamp)'),
closestTaskAt: z.number().optional().describe('Closest task timestamp'),
isDeleted: z.boolean().describe('Whether contact is deleted'),
accountId: z.number().describe('Account ID'),
})
const createContact: ActionDefinition = {
title: 'Create Contact',
description: 'Creates a new contact',
input: {
schema: z.object({
name: z.string().optional().title('Full contact name').describe('Full contact name'),
firstName: z.string().optional().title('First name').describe('First name'),
lastName: z.string().optional().title('Last name').describe('Last name'),
responsibleUserId: z.number().title('Responsible User ID').describe('User ID to assign this contact to'),
createdBy: z.number().title('Created By').describe('User ID who creates this contact'),
updatedBy: z.number().optional().title('Updated By').describe('User ID who updates this contact'),
}),
},
output: {
schema: z.object({
contact: contactSchema.describe('The created contact'),
}),
},
}
const searchContacts: ActionDefinition = {
title: 'Search Contacts',
description: 'Search for contacts by name, phone number, or email',
input: {
schema: z.object({
query: z.string().describe('Search query (name, phone number, or email)'),
}),
},
output: {
schema: z.object({
contacts: z.array(contactSchema).describe('Array of matching contacts (empty if none found)'),
}),
},
}
export const actions = {
createContact,
searchContacts,
} as const
@@ -0,0 +1,8 @@
import * as sdk from '@botpress/sdk'
import { actions as contactActions } from './contact'
import { actions as leadActions } from './lead'
export const actions = {
...leadActions,
...contactActions,
} as const satisfies sdk.IntegrationDefinitionProps['actions']
@@ -0,0 +1,74 @@
import { z, ActionDefinition } from '@botpress/sdk'
// Lead Schema: defines what a Kommo lead looks like in Botpress
export const leadSchema = z.object({
id: z.number().describe('Lead ID'),
name: z.string().describe('Lead name'),
price: z.number().optional().describe('Lead value in dollars'),
responsibleUserId: z.number().optional().describe('User responsible for this lead'),
pipelineId: z.number().optional().describe('Which sales pipeline'),
statusId: z.number().optional().describe('Which stage in the pipeline'),
createdAt: z.number().describe('When created (Unix timestamp)'),
updatedAt: z.number().describe('When last updated (Unix timestamp)'),
})
const createLead: ActionDefinition = {
title: 'Create Lead',
description: 'Creates a new lead in Kommo CRM',
input: {
schema: z.object({
name: z.string().title('Lead name').describe('Lead name (required)'),
price: z.number().optional().title('Lead value').describe('Lead value in dollars'),
responsibleUserId: z.number().optional().title('Responsible User ID').describe('User ID to assign this lead to'),
pipelineId: z.number().optional().title('Pipeline ID').describe('Pipeline ID (defaults to main pipeline)'),
statusId: z.number().optional().title('Status ID').describe('Initial status/stage ID'),
}),
},
output: {
schema: z.object({
lead: leadSchema.describe('The created lead'),
}),
},
}
const updateLead: ActionDefinition = {
title: 'Update Lead',
description: 'Updates an existing lead in Kommo',
input: {
schema: z.object({
leadId: z.number().title('Lead ID').describe('Lead ID to update'),
name: z.string().optional().title('New name').describe('New name'),
price: z.number().optional().title('New price').describe('New price'),
responsibleUserId: z.number().optional().title('New responsible user').describe('New responsible user'),
pipelineId: z.number().optional().title('New pipeline ID').describe('New pipeline ID'),
statusId: z.number().optional().title('New status/stage ID').describe('New status/stage ID'),
}),
},
output: {
schema: z.object({
lead: leadSchema.describe('The updated lead'),
}),
},
}
const searchLeads: ActionDefinition = {
title: 'Search Leads',
description: 'search for leads by name or other fields',
input: {
schema: z.object({
query: z.string().describe('Search query'),
}),
},
output: {
schema: z.object({
leads: z.array(leadSchema).describe('Array of matching leads (empty if none found)'),
}),
},
}
// Export all lead actions
export const actions = {
createLead,
searchLeads,
updateLead,
} as const
+2
View File
@@ -0,0 +1,2 @@
// Re-export everything from definitions
export * from './actions'
+39
View File
@@ -0,0 +1,39 @@
# Kommo Integration
The Kommo integration allows you to connect your Botpress chatbot with Kommo. With this integration, your chatbot can create and update leads, manage contacts, and search through your CRM data.
## Prerequisites
Before using this integration, you need:
1. A **Kommo account** with administrator access
2. A **private integration** created in your Kommo account
3. A **long-lived access token** from your private integration
## Configuration
To set up the Kommo integration in Botpress:
### Step 1: Create a Private Integration in Kommo
1. Log in to your Kommo account.
2. Navigate to **Settings****Integrations marketplace**.
3. Click **Create Integration** at the top-right corner.
4. Give your integration a name.
5. Select all scopes.
6. Save the integration.
### Step 2: Generate an Access Token
1. In your integration settings, click **Generate long-lived token**
2. Select an expiration date.
3. Copy the **long-lived token**.
### Step 3: Configure Botpress Integration
In your Botpress integration settings, provide:
- **Base Domain**: Your Kommo subdomain (e.g., `yourcompany.kommo.com`)
- Do not include `https://` or trailing slashes
- Example: `mycompany.kommo.com`
- **Access Token**: Paste the long-lived access token from Step 2
+33
View File
@@ -0,0 +1,33 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="1200.000000pt" height="1200.000000pt" viewBox="0 0 1200.000000 1200.000000"
preserveAspectRatio="xMidYMid meet">
<metadata>
Created by potrace 1.16, written by Peter Selinger 2001-2019
</metadata>
<rect width="1200" height="1200" rx="150" ry="150" fill="white"/>
<g transform="translate(0.000000,1200.000000) scale(0.100000,-0.100000)"
fill="#6043D0" stroke="none">
<path d="M815 11983 c-201 -43 -364 -132 -515 -283 -118 -119 -183 -216 -236
-358 -70 -188 -64 309 -64 -5342 0 -5651 -6 -5154 64 -5342 53 -142 118 -239
236 -358 119 -118 216 -183 358 -236 188 -70 -309 -64 5342 -64 5651 0 5154
-6 5342 64 142 53 239 118 358 236 118 119 183 216 236 358 70 188 64 -309 64
5342 0 5651 6 5154 -64 5342 -53 142 -118 239 -236 358 -119 118 -216 183
-358 236 -188 70 310 64 -5349 63 -4495 -1 -5116 -2 -5178 -16z m9115 -2191
c19 -9 45 -33 58 -52 51 -75 121 35 -1089 -1712 -765 -1104 -1118 -1622 -1151
-1688 -26 -52 -57 -131 -68 -175 -82 -321 -25 -608 180 -900 35 -49 124 -178
198 -285 75 -107 151 -217 171 -245 19 -27 167 -241 330 -475 280 -404 402
-579 656 -945 61 -88 132 -189 156 -225 25 -36 124 -177 219 -315 96 -137 236
-339 311 -448 76 -109 141 -212 144 -228 9 -40 -9 -90 -46 -125 l-30 -29 -867
0 -867 0 -115 23 c-356 72 -626 217 -880 471 -121 121 -155 163 -305 381 -93
135 -199 288 -235 340 -37 52 -254 365 -482 695 -943 1365 -860 1250 -932
1287 -123 63 -280 14 -354 -110 l-27 -47 -5 -1350 -5 -1350 -22 -55 c-51 -124
-154 -228 -265 -267 -50 -17 -101 -18 -793 -18 l-740 0 -78 37 c-130 62 -218
174 -247 314 -8 36 -10 373 -7 1106 4 1130 2 1072 56 1285 145 566 596 1028
1164 1192 185 54 259 63 564 68 244 5 285 8 310 23 16 10 109 133 214 286 103
148 352 508 554 799 202 292 612 884 912 1316 300 433 576 822 616 866 290
326 685 524 1127 566 19 2 395 5 835 5 744 2 802 1 835 -16z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

@@ -0,0 +1,25 @@
import { z, IntegrationDefinition } from '@botpress/sdk'
import { actions } from './definitions'
export default new IntegrationDefinition({
name: 'kommo',
title: 'Kommo',
description: 'Manage leads and contacts in your Kommo CRM directly from your chatbot.',
version: '0.1.1',
readme: 'hub.md',
icon: 'icon.svg',
configuration: {
schema: z.object({
baseDomain: z.string().title('Subdomain').describe('Your Kommo subdomain (e.g., yourcompany.kommo.com)'),
accessToken: z
.string()
.title('Access token')
.describe('Long-lived access token from your Kommo private integration'),
}),
},
actions,
attributes: {
category: 'CRM & Sales',
repo: 'botpress',
},
})
+17
View File
@@ -0,0 +1,17 @@
{
"name": "@botpresshub/kommo",
"private": true,
"scripts": {
"build": "bp add -y && bp build",
"check:type": "tsc --noEmit",
"check:bplint": "bp lint"
},
"dependencies": {
"@botpress/client": "workspace:*",
"@botpress/sdk": "workspace:*",
"axios": "^1.13.2"
},
"devDependencies": {
"@botpress/cli": "workspace:*"
}
}
+68
View File
@@ -0,0 +1,68 @@
import * as sdk from '@botpress/sdk'
import { KommoClient, CreateContactRequest, KommoContact, getErrorMessage } from '../kommo-api'
import * as bp from '.botpress'
// mapping kommo to local schema
function mapKommoContactToBotpress(contact: KommoContact) {
return {
id: contact.id,
name: contact.name,
firstName: contact.first_name,
lastName: contact.last_name,
responsibleUserId: contact.responsible_user_id,
groupId: contact.group_id,
updatedBy: contact.updated_by,
createdAt: contact.created_at,
updatedAt: contact.updated_at,
closestTaskAt: contact.closest_task_at ?? undefined,
isDeleted: contact.is_deleted,
accountId: contact.account_id,
}
}
export const createContact: bp.IntegrationProps['actions']['createContact'] = async ({ ctx, input, logger }) => {
try {
logger.forBot().info('Creating contact with input:', input)
const { baseDomain, accessToken } = ctx.configuration
const kommoClient = new KommoClient(accessToken, baseDomain, logger)
const contactData: CreateContactRequest = {
name: input.name,
first_name: input.firstName,
last_name: input.lastName,
responsible_user_id: input.responsibleUserId,
created_by: input.createdBy,
updated_by: input.updatedBy,
}
logger.forBot().info('Contact data to send:', contactData)
const kommoContact = await kommoClient.createContact(contactData)
logger.forBot().info('Contact created successfully:', { contactId: kommoContact.id })
return {
contact: mapKommoContactToBotpress(kommoContact),
}
} catch (error) {
logger.forBot().error('Failed to create contact', { error })
throw new sdk.RuntimeError(getErrorMessage(error))
}
}
export const searchContacts: bp.IntegrationProps['actions']['searchContacts'] = async ({ ctx, input, logger }) => {
try {
logger.forBot().info('Searching contacts:', { query: input.query })
const { baseDomain, accessToken } = ctx.configuration
const kommoClient = new KommoClient(accessToken, baseDomain, logger)
const kommoContacts = await kommoClient.searchContacts(input.query)
const contacts = kommoContacts.map(mapKommoContactToBotpress)
logger.forBot().info('Search complete:', { count: contacts.length })
return { contacts }
} catch (error) {
logger.forBot().error('Failed to search contacts', { error })
throw new sdk.RuntimeError(getErrorMessage(error))
}
}
+2
View File
@@ -0,0 +1,2 @@
export * from './lead'
export * from './contact'
+95
View File
@@ -0,0 +1,95 @@
import * as sdk from '@botpress/sdk'
import { KommoClient, CreateLeadRequest, UpdateLeadRequest, KommoLead, getErrorMessage } from '../kommo-api'
import * as bp from '.botpress'
// mapping kommo to local schema
function mapKommoLeadToBotpress(lead: KommoLead) {
return {
id: lead.id,
name: lead.name,
price: lead.price,
responsibleUserId: lead.responsible_user_id,
pipelineId: lead.pipeline_id,
statusId: lead.status_id,
createdAt: lead.created_at,
updatedAt: lead.updated_at,
}
}
export const createLead: bp.IntegrationProps['actions']['createLead'] = async ({ ctx, input, logger }) => {
try {
logger.forBot().debug('Creating lead with input:', input)
logger.forBot().debug('Configuration:', { baseDomain: ctx.configuration.baseDomain })
const { baseDomain, accessToken } = ctx.configuration
const kommoClient = new KommoClient(accessToken, baseDomain, logger)
const leadData: CreateLeadRequest = {
name: input.name,
price: input.price,
responsible_user_id: input.responsibleUserId,
pipeline_id: input.pipelineId,
status_id: input.statusId,
}
logger.forBot().info('Lead data to send:', leadData)
const kommoLead = await kommoClient.createLead(leadData)
logger.forBot().info('Lead created successfully:', { leadId: kommoLead.id })
return {
lead: mapKommoLeadToBotpress(kommoLead),
}
} catch (error) {
logger.forBot().error('Error creating lead:', { error })
throw new sdk.RuntimeError(getErrorMessage(error))
}
}
// handler for updating lead
export const updateLead: bp.IntegrationProps['actions']['updateLead'] = async ({ ctx, input, logger }) => {
try {
logger.forBot().info('Updating lead:', input)
const { baseDomain, accessToken } = ctx.configuration
const kommoClient = new KommoClient(accessToken, baseDomain, logger)
const updateData: UpdateLeadRequest = {
name: input.name,
price: input.price,
responsible_user_id: input.responsibleUserId,
pipeline_id: input.pipelineId,
status_id: input.statusId,
}
logger.forBot().info('Update data to send:', updateData)
const kommoLead = await kommoClient.updateLead(input.leadId, updateData)
logger.forBot().info('Lead updated successfully:', { leadId: kommoLead.id })
return {
lead: mapKommoLeadToBotpress(kommoLead),
}
} catch (error) {
logger.forBot().error('Error updating lead:', { error })
throw new sdk.RuntimeError(getErrorMessage(error))
}
}
// search for lead action
export const searchLeads: bp.IntegrationProps['actions']['searchLeads'] = async ({ ctx, input, logger }) => {
try {
logger.forBot().info('Searching leads:', { query: input.query })
const { baseDomain, accessToken } = ctx.configuration
const kommoClient = new KommoClient(accessToken, baseDomain, logger)
const kommoLeads = await kommoClient.searchLeads(input.query)
const leads = kommoLeads.map(mapKommoLeadToBotpress)
logger.forBot().info('Search complete:', { count: leads.length })
return { leads }
} catch (error) {
logger.forBot().error('Failed to search leads', { error })
throw new sdk.RuntimeError(getErrorMessage(error))
}
}
+30
View File
@@ -0,0 +1,30 @@
import { RuntimeError } from '@botpress/sdk'
import { createLead, updateLead, createContact, searchContacts, searchLeads } from './actions'
import { KommoClient } from './kommo-api'
import * as bp from '.botpress'
export default new bp.Integration({
register: async ({ ctx, logger }) => {
const { baseDomain, accessToken } = ctx.configuration
const kommoClient = new KommoClient(accessToken, baseDomain, logger)
try {
await kommoClient.searchLeads('')
logger.forBot().info('Connection to Kommo Successful')
} catch (error) {
logger.forBot().error('Connection to Kommo Failed', { error })
throw new RuntimeError('failed to connect to Kommo, Please check your access token and subdomain are correct. ')
}
},
unregister: async () => {},
actions: {
createLead,
updateLead,
searchLeads,
createContact,
searchContacts,
},
channels: {},
handler: async () => {},
})
@@ -0,0 +1,69 @@
import { z } from '@botpress/sdk'
import { isAxiosError } from 'axios'
import { KommoErrorResponse } from './types'
const _isZodError = (error: any): error is z.ZodError => {
return error && typeof error === 'object' && z.is.zuiError(error) && 'errors' in error
}
const formatZodErrors = (issues: z.ZodIssue[]) =>
'Validation Error: ' +
issues
.map((issue) => {
const path = issue.path?.length ? `${issue.path.join('.')}: ` : ''
return path ? `${path}${issue.message}` : issue.message
})
.join('\n')
export const getErrorMessage = (err: unknown): string => {
if (isAxiosError(err)) {
// server dependent error
const status = err.response?.status
const data = err.response?.data
// always present
const message = err.message
if (data && typeof data === 'object') {
const kommoError = data as KommoErrorResponse
if (kommoError.detail) {
let errorMsg = kommoError.detail
if (kommoError.validation_errors && kommoError.validation_errors.length > 0) {
const validationDetails = kommoError.validation_errors
.flatMap((ve) => ve.errors.map((e) => `${e.path}: ${e.detail}`))
.join(', ')
errorMsg += ` - ${validationDetails}`
}
return status ? `${errorMsg} (Status: ${status})` : errorMsg
}
}
// Fallback for generic axios errors
if (typeof data === 'string' && data.trim()) {
return status ? `${data} (Status: ${status})` : data
}
return status ? `${message} (Status: ${status})` : message
}
if (_isZodError(err)) {
return formatZodErrors(err.errors)
}
if (err instanceof Error) {
return err.message
}
if (typeof err === 'string') {
return err
}
if (err && typeof err === 'object' && 'message' in err) {
const message = (err as { message: unknown }).message
if (typeof message === 'string') {
return message
}
}
return 'An unexpected error occurred'
}
@@ -0,0 +1,3 @@
export * from './types'
export * from './kommo-client'
export * from './error-handler'
@@ -0,0 +1,186 @@
import axios, { AxiosInstance } from 'axios'
import * as bp from '../../.botpress'
import { getErrorMessage } from './error-handler'
import {
CreateLeadRequest,
KommoLead,
KommoCreateResponse,
UpdateLeadRequest,
CreateContactRequest,
KommoContact,
KommoCreateContactResponse,
KommoSearchContactsResponse,
KommoSearchLeadResponse,
} from './types'
export class KommoClient {
private _axios: AxiosInstance
private _logger: bp.Logger
public constructor(accessToken: string, baseDomain: string, logger: bp.Logger) {
this._logger = logger
// Ensure basedomain doesn't have protocol prefix or trailing slash
const cleanDomain = baseDomain.replace(/^https?:\/\//, '').replace(/\/$/, '')
// Create axios instance with Kommo API configuration
this._axios = axios.create({
baseURL: `https://${cleanDomain}/api/v4`,
headers: {
Authorization: `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
})
this._logger.forBot().debug('KommoClient initialized', {
baseURL: `https://${cleanDomain}/api/v4`,
})
}
// -----LEADS------
public async createLead(data: CreateLeadRequest): Promise<KommoLead> {
try {
this._logger.forBot().debug('Creating lead in Kommo', { name: data.name })
const response = await this._axios.post<KommoCreateResponse>('/leads', [data])
const createdLeadId = response.data._embedded.leads[0]?.id
if (!createdLeadId) {
throw new Error('No lead ID returned from Kommo')
}
const lead = await this.getLead(createdLeadId)
if (!lead) {
throw new Error('Failed to fetch created lead')
}
this._logger.forBot().info('Lead created successfully', { leadId: lead.id })
return lead
} catch (error) {
throw new Error(getErrorMessage(error))
}
}
// gets a lead by id
public async getLead(leadId: number): Promise<KommoLead | undefined> {
try {
this._logger.forBot().debug('Fetching lead from Kommo', { leadId })
const response = await this._axios.get<KommoLead>(`/leads/${leadId}`)
const lead = response.data
return lead
} catch (error) {
if (axios.isAxiosError(error) && error.response?.status === 404) {
this._logger.forBot().info('Lead not found', { leadId })
return undefined
}
throw new Error(getErrorMessage(error))
}
}
// update a single lead
public async updateLead(leadId: number, data: UpdateLeadRequest): Promise<KommoLead> {
try {
this._logger.forBot().debug('Updating lead in Kommo', { leadId, data })
await this._axios.patch(`/leads/${leadId}`, data)
const lead = await this.getLead(leadId)
if (!lead) {
throw new Error('Failed to fetch updated lead')
}
this._logger.forBot().info('Lead updated successfully', { leadId: lead.id })
return lead
} catch (error) {
throw new Error(getErrorMessage(error))
}
}
// search leads by query
public async searchLeads(query: string): Promise<KommoLead[]> {
try {
this._logger.forBot().debug('Searching for leads', { query })
const response = await this._axios.get<KommoSearchLeadResponse>('/leads', {
params: { query },
})
const leads = response.data._embedded?.leads || []
this._logger.forBot().info('Leads found:', { count: leads.length })
return leads
} catch (error) {
if (axios.isAxiosError(error) && error.response?.status === 404) {
this._logger.forBot().info('No leads found', { query })
return []
}
throw new Error(getErrorMessage(error))
}
}
// -----Contacts-----
public async createContact(data: CreateContactRequest): Promise<KommoContact> {
try {
this._logger.forBot().debug('Creating contact in Kommo', { name: data.name })
// contacts sent to kommo as an array
const response = await this._axios.post<KommoCreateContactResponse>('/contacts', [data])
// get the ID from the response
const createdContactId = response.data._embedded.contacts[0]?.id
if (!createdContactId) {
throw new Error('No contact ID returned from Kommo')
}
// fetch full contact details to return to user
const contact = await this.getContact(createdContactId)
if (!contact) {
throw new Error('Failed to fetch created contact')
}
this._logger.forBot().info('Contact created successfully', { contactId: contact.id })
return contact
} catch (error) {
throw new Error(getErrorMessage(error))
}
}
// internal method for create contact
public async getContact(contactId: number): Promise<KommoContact | undefined> {
try {
this._logger.forBot().debug('Fetching contact from Kommo', { contactId })
const response = await this._axios.get<KommoContact>(`/contacts/${contactId}`)
const contact = response.data
return contact
} catch (error) {
if (axios.isAxiosError(error) && error.response?.status === 404) {
this._logger.forBot().info('Contact not found', { contactId })
return undefined
}
throw new Error(getErrorMessage(error))
}
}
// method to search contacts by phone number, name or email
public async searchContacts(query: string): Promise<KommoContact[]> {
try {
this._logger.forBot().debug('Searching contacts in Kommo', { query })
const response = await this._axios.get<KommoSearchContactsResponse>('/contacts', {
params: { query },
})
const contacts = response.data._embedded?.contacts || []
this._logger.forBot().info('Contacts found:', { count: contacts.length })
return contacts
} catch (error) {
if (axios.isAxiosError(error) && error.response?.status === 404) {
this._logger.forBot().info('No contacts found', { query })
return []
}
throw new Error(getErrorMessage(error))
}
}
}
+311
View File
@@ -0,0 +1,311 @@
import { z } from '@botpress/sdk'
// -----LEADS------
export const kommoLeadSchema = z.object({
id: z.number(),
name: z.string(),
price: z.number(),
responsible_user_id: z.number(),
group_id: z.number(),
status_id: z.number(),
pipeline_id: z.number(),
loss_reason_id: z.number().nullable(),
created_by: z.number(),
updated_by: z.number(),
created_at: z.number(),
updated_at: z.number(),
closed_at: z.number().nullable(),
closest_task_at: z.number().nullable(),
is_deleted: z.boolean(),
score: z.number().nullable(),
account_id: z.number(),
labor_cost: z.number().nullable(),
is_price_computed: z.boolean(),
custom_fields_values: z
.array(
z.object({
field_id: z.number(),
field_name: z.string(),
field_code: z.string().nullable().optional(),
field_type: z.string(),
values: z.array(
z.object({
value: z.union([z.string(), z.number()]),
enum_id: z.number().optional(),
})
),
})
)
.optional(),
_embedded: z
.object({
tags: z
.array(
z.object({
id: z.number(),
name: z.string(),
})
)
.optional(),
companies: z
.array(
z.object({
id: z.number(),
_links: z.object({
self: z.object({
href: z.string(),
}),
}),
})
)
.optional(),
contacts: z
.array(
z.object({
id: z.number(),
is_main: z.boolean(),
_links: z.object({
self: z.object({
href: z.string(),
}),
}),
})
)
.optional(),
})
.optional(),
_links: z
.object({
self: z.object({
href: z.string(),
}),
})
.optional(),
})
export type KommoLead = z.infer<typeof kommoLeadSchema>
export const createLeadRequestSchema = z.object({
name: z.string(),
price: z.number().optional(),
responsible_user_id: z.number().optional(),
pipeline_id: z.number().optional(),
status_id: z.number().optional(),
created_by: z.number().optional(),
updated_by: z.number().optional(),
created_at: z.number().optional(),
updated_at: z.number().optional(),
closed_at: z.number().optional(),
custom_fields_values: z
.array(
z.object({
field_id: z.number(),
values: z.array(
z.object({
value: z.union([z.string(), z.number()]),
})
),
})
)
.optional(),
_embedded: z
.object({
tags: z
.array(
z.object({
id: z.number().optional(),
name: z.string().optional(),
})
)
.optional(),
contacts: z
.array(
z.object({
id: z.number(),
is_main: z.boolean().optional(),
})
)
.optional(),
companies: z
.array(
z.object({
id: z.number(),
})
)
.optional(),
})
.optional(),
})
export type CreateLeadRequest = z.infer<typeof createLeadRequestSchema>
export const updateLeadRequestSchema = z.object({
id: z.number().optional(),
name: z.string().optional(),
price: z.number().optional(),
responsible_user_id: z.number().optional(),
status_id: z.number().optional(),
pipeline_id: z.number().optional(),
custom_fields_values: z
.array(
z.object({
field_id: z.number(),
values: z.array(
z.object({
value: z.union([z.string(), z.number()]),
})
),
})
)
.optional(),
})
export type UpdateLeadRequest = z.infer<typeof updateLeadRequestSchema>
export const kommoCreateResponseSchema = z.object({
_links: z.object({
self: z.object({
href: z.string(),
}),
}),
_embedded: z.object({
leads: z.array(
z.object({
id: z.number(),
request_id: z.string(),
_links: z.object({
self: z.object({
href: z.string(),
}),
}),
})
),
}),
})
export type KommoCreateResponse = z.infer<typeof kommoCreateResponseSchema>
export const kommoUpdateResponseSchema = z.object({
_links: z.object({
self: z.object({
href: z.string(),
}),
}),
_embedded: z.object({
leads: z.array(kommoLeadSchema),
}),
})
export type KommoUpdateResponse = z.infer<typeof kommoUpdateResponseSchema>
export const kommoSearchLeadResponseSchema = z.object({
_page: z.number(),
_links: z.object({
self: z.object({
href: z.string(),
}),
}),
_embedded: z.object({
leads: z.array(kommoLeadSchema),
}),
})
export type KommoSearchLeadResponse = z.infer<typeof kommoSearchLeadResponseSchema>
// -------------CONTACTS-------------
export const kommoContactSchema = z.object({
id: z.number(),
name: z.string(),
first_name: z.string(),
last_name: z.string(),
responsible_user_id: z.number(),
group_id: z.number(),
updated_by: z.number(),
created_at: z.number(),
updated_at: z.number(),
closest_task_at: z.number().nullable(),
is_deleted: z.boolean(),
account_id: z.number(),
})
export type KommoContact = z.infer<typeof kommoContactSchema>
export const createContactRequestSchema = z.object({
name: z.string().optional(),
first_name: z.string().optional(),
last_name: z.string().optional(),
responsible_user_id: z.number(),
created_by: z.number(),
updated_by: z.number().optional(),
})
export type CreateContactRequest = z.infer<typeof createContactRequestSchema>
export const kommoCreateContactResponseSchema = z.object({
_links: z.object({
self: z.object({
href: z.string(),
}),
}),
_embedded: z.object({
contacts: z.array(
z.object({
id: z.number(),
request_id: z.string(),
_links: z.object({
self: z.object({
href: z.string(),
}),
}),
})
),
}),
})
export type KommoCreateContactResponse = z.infer<typeof kommoCreateContactResponseSchema>
export const kommoSearchContactsResponseSchema = z.object({
_page: z.number(),
_links: z.object({
self: z.object({
href: z.string(),
}),
next: z
.object({
href: z.string(),
})
.optional(),
}),
_embedded: z.object({
contacts: z.array(kommoContactSchema),
}),
})
export type KommoSearchContactsResponse = z.infer<typeof kommoSearchContactsResponseSchema>
//----General-----
export const kommoErrorResponseSchema = z.object({
title: z.string(),
type: z.string(),
status: z.number(),
detail: z.string(),
validation_errors: z
.array(
z.object({
request_id: z.string(),
errors: z.array(
z.object({
code: z.string(),
path: z.string(),
detail: z.string(),
})
),
})
)
.optional(),
})
export type KommoErrorResponse = z.infer<typeof kommoErrorResponseSchema>
+8
View File
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"paths": { "*": ["./*"] },
"outDir": "dist"
},
"include": [".botpress/**/*", "definitions/**/*", "src/**/*", "*.ts"]
}