🐛 (whatsapp) Fix WA preview not starting and accept audio and documents messages
This commit is contained in:
@ -10,15 +10,6 @@ import { OpenAI, ClientOptions } from 'openai'
|
||||
import { defaultOpenAIOptions } from '@typebot.io/schemas/features/blocks/integrations/openai/constants'
|
||||
|
||||
export const listModels = authenticatedProcedure
|
||||
.meta({
|
||||
openapi: {
|
||||
method: 'GET',
|
||||
path: '/openai/models',
|
||||
protect: true,
|
||||
summary: 'List OpenAI models',
|
||||
tags: ['OpenAI'],
|
||||
},
|
||||
})
|
||||
.input(
|
||||
z.object({
|
||||
credentialsId: z.string(),
|
||||
@ -28,11 +19,6 @@ export const listModels = authenticatedProcedure
|
||||
type: z.enum(['gpt', 'tts']),
|
||||
})
|
||||
)
|
||||
.output(
|
||||
z.object({
|
||||
models: z.array(z.string()),
|
||||
})
|
||||
)
|
||||
.query(
|
||||
async ({
|
||||
input: { credentialsId, workspaceId, baseUrl, apiVersion, type },
|
||||
|
@ -8,31 +8,12 @@ import { ZemanticAiCredentials } from '@typebot.io/schemas/features/blocks/integ
|
||||
import got from 'got'
|
||||
|
||||
export const listProjects = authenticatedProcedure
|
||||
.meta({
|
||||
openapi: {
|
||||
method: 'GET',
|
||||
path: '/zemantic-ai/projects',
|
||||
protect: true,
|
||||
summary: 'List Zemantic AI projects',
|
||||
tags: ['ZemanticAi'],
|
||||
},
|
||||
})
|
||||
.input(
|
||||
z.object({
|
||||
credentialsId: z.string(),
|
||||
workspaceId: z.string(),
|
||||
})
|
||||
)
|
||||
.output(
|
||||
z.object({
|
||||
projects: z.array(
|
||||
z.object({
|
||||
label: z.string(),
|
||||
value: z.string(),
|
||||
})
|
||||
),
|
||||
})
|
||||
)
|
||||
.query(async ({ input: { credentialsId, workspaceId }, ctx: { user } }) => {
|
||||
const workspace = await prisma.workspace.findFirst({
|
||||
where: { id: workspaceId },
|
||||
|
@ -14,13 +14,6 @@ const inputShape = {
|
||||
} as const
|
||||
|
||||
export const createCredentials = authenticatedProcedure
|
||||
.meta({
|
||||
openapi: {
|
||||
method: 'POST',
|
||||
path: '/credentials',
|
||||
protect: true,
|
||||
},
|
||||
})
|
||||
.input(
|
||||
z.object({
|
||||
credentials: z.discriminatedUnion(
|
||||
@ -31,11 +24,6 @@ export const createCredentials = authenticatedProcedure
|
||||
),
|
||||
})
|
||||
)
|
||||
.output(
|
||||
z.object({
|
||||
credentialsId: z.string(),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input: { credentials }, ctx: { user } }) => {
|
||||
const workspace = await prisma.workspace.findFirst({
|
||||
where: {
|
||||
|
@ -11,11 +11,6 @@ export const deleteCredentials = authenticatedProcedure
|
||||
workspaceId: z.string(),
|
||||
})
|
||||
)
|
||||
.output(
|
||||
z.object({
|
||||
credentialsId: z.string(),
|
||||
})
|
||||
)
|
||||
.mutation(
|
||||
async ({ input: { credentialsId, workspaceId }, ctx: { user } }) => {
|
||||
const workspace = await prisma.workspace.findFirst({
|
||||
|
@ -12,11 +12,6 @@ export const listCredentials = authenticatedProcedure
|
||||
type: z.enum(enabledBlocks),
|
||||
})
|
||||
)
|
||||
.output(
|
||||
z.object({
|
||||
credentials: z.array(z.object({ id: z.string(), name: z.string() })),
|
||||
})
|
||||
)
|
||||
.query(async ({ input: { workspaceId, type }, ctx: { user } }) => {
|
||||
const workspace = await prisma.workspace.findFirst({
|
||||
where: {
|
||||
|
@ -1,10 +0,0 @@
|
||||
import { router } from '@/helpers/server/trpc'
|
||||
import { createCredentials } from './createCredentials'
|
||||
import { deleteCredentials } from './deleteCredentials'
|
||||
import { listCredentials } from './listCredentials'
|
||||
|
||||
export const forgedCredentialsRouter = router({
|
||||
createCredentials,
|
||||
listCredentials,
|
||||
deleteCredentials,
|
||||
})
|
@ -15,13 +15,6 @@ export const fetchSelectItems = authenticatedProcedure
|
||||
workspaceId: z.string(),
|
||||
})
|
||||
)
|
||||
.output(
|
||||
z.object({
|
||||
items: z.array(
|
||||
z.string().or(z.object({ label: z.string(), value: z.string() }))
|
||||
),
|
||||
})
|
||||
)
|
||||
.query(
|
||||
async ({
|
||||
input: { workspaceId, integrationId, fetcherId, options },
|
||||
|
@ -1,6 +1,12 @@
|
||||
import { router } from '@/helpers/server/trpc'
|
||||
import { fetchSelectItems } from './fetchSelectItems'
|
||||
import { createCredentials } from './credentials/createCredentials'
|
||||
import { deleteCredentials } from './credentials/deleteCredentials'
|
||||
import { listCredentials } from './credentials/listCredentials'
|
||||
|
||||
export const integrationsRouter = router({
|
||||
export const forgeRouter = router({
|
||||
fetchSelectItems,
|
||||
createCredentials,
|
||||
listCredentials,
|
||||
deleteCredentials,
|
||||
})
|
||||
|
@ -54,7 +54,7 @@ export const ForgeSelectInput = ({
|
||||
return fetchers.find((fetcher) => fetcher.id === fetcherId)
|
||||
}, [baseFetcher, blockDef.actions, fetcherId])
|
||||
|
||||
const { data } = trpc.integrations.fetchSelectItems.useQuery(
|
||||
const { data } = trpc.forge.fetchSelectItems.useQuery(
|
||||
{
|
||||
integrationId: blockDef.id,
|
||||
options: pick(options, [
|
||||
|
@ -34,14 +34,13 @@ export const ForgedCredentialsDropdown = ({
|
||||
const router = useRouter()
|
||||
const { showToast } = useToast()
|
||||
const { workspace, currentRole } = useWorkspace()
|
||||
const { data, refetch, isLoading } =
|
||||
trpc.integrationCredentials.listCredentials.useQuery(
|
||||
{
|
||||
workspaceId: workspace?.id as string,
|
||||
type: blockDef.id,
|
||||
},
|
||||
{ enabled: !!workspace?.id }
|
||||
)
|
||||
const { data, refetch, isLoading } = trpc.forge.listCredentials.useQuery(
|
||||
{
|
||||
workspaceId: workspace?.id as string,
|
||||
type: blockDef.id,
|
||||
},
|
||||
{ enabled: !!workspace?.id }
|
||||
)
|
||||
const [isDeleting, setIsDeleting] = useState<string>()
|
||||
|
||||
const { mutate } = trpc.credentials.deleteCredentials.useMutation({
|
||||
|
@ -42,7 +42,7 @@ export const ForgedCredentialsModal = ({
|
||||
listCredentials: { refetch: refetchCredentials },
|
||||
},
|
||||
} = trpc.useContext()
|
||||
const { mutate } = trpc.integrationCredentials.createCredentials.useMutation({
|
||||
const { mutate } = trpc.forge.createCredentials.useMutation({
|
||||
onMutate: () => setIsCreating(true),
|
||||
onSettled: () => setIsCreating(false),
|
||||
onError: (err) => {
|
||||
|
@ -100,12 +100,13 @@ export const WhatsAppCredentialsModal = ({
|
||||
},
|
||||
})
|
||||
|
||||
const { data: tokenInfoData } = trpc.whatsApp.getSystemTokenInfo.useQuery(
|
||||
{
|
||||
token: systemUserAccessToken,
|
||||
},
|
||||
{ enabled: isNotEmpty(systemUserAccessToken) }
|
||||
)
|
||||
const { data: tokenInfoData } =
|
||||
trpc.whatsAppInternal.getSystemTokenInfo.useQuery(
|
||||
{
|
||||
token: systemUserAccessToken,
|
||||
},
|
||||
{ enabled: isNotEmpty(systemUserAccessToken) }
|
||||
)
|
||||
|
||||
const resetForm = () => {
|
||||
setActiveStep(0)
|
||||
@ -133,7 +134,7 @@ export const WhatsAppCredentialsModal = ({
|
||||
setIsVerifying(true)
|
||||
try {
|
||||
const { expiresAt, scopes } =
|
||||
await trpcVanilla.whatsApp.getSystemTokenInfo.query({
|
||||
await trpcVanilla.whatsAppInternal.getSystemTokenInfo.query({
|
||||
token: systemUserAccessToken,
|
||||
})
|
||||
if (expiresAt !== 0) {
|
||||
@ -167,16 +168,18 @@ export const WhatsAppCredentialsModal = ({
|
||||
const isPhoneNumberAvailable = async () => {
|
||||
setIsVerifying(true)
|
||||
try {
|
||||
const { name } = await trpcVanilla.whatsApp.getPhoneNumber.query({
|
||||
const { name } = await trpcVanilla.whatsAppInternal.getPhoneNumber.query({
|
||||
systemToken: systemUserAccessToken,
|
||||
phoneNumberId,
|
||||
})
|
||||
setPhoneNumberName(name)
|
||||
try {
|
||||
const { message } =
|
||||
await trpcVanilla.whatsApp.verifyIfPhoneNumberAvailable.query({
|
||||
phoneNumberDisplayName: name,
|
||||
})
|
||||
await trpcVanilla.whatsAppInternal.verifyIfPhoneNumberAvailable.query(
|
||||
{
|
||||
phoneNumberDisplayName: name,
|
||||
}
|
||||
)
|
||||
|
||||
if (message === 'taken') {
|
||||
setIsVerifying(false)
|
||||
@ -186,7 +189,7 @@ export const WhatsAppCredentialsModal = ({
|
||||
return false
|
||||
}
|
||||
const { verificationToken } =
|
||||
await trpcVanilla.whatsApp.generateVerificationToken.mutate()
|
||||
await trpcVanilla.whatsAppInternal.generateVerificationToken.mutate()
|
||||
setVerificationToken(verificationToken)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
|
@ -56,14 +56,15 @@ export const WhatsAppModal = ({ isOpen, onClose }: ModalProps): JSX.Element => {
|
||||
|
||||
const whatsAppSettings = typebot?.settings.whatsApp
|
||||
|
||||
const { data: phoneNumberData } = trpc.whatsApp.getPhoneNumber.useQuery(
|
||||
{
|
||||
credentialsId: typebot?.whatsAppCredentialsId as string,
|
||||
},
|
||||
{
|
||||
enabled: !!typebot?.whatsAppCredentialsId,
|
||||
}
|
||||
)
|
||||
const { data: phoneNumberData } =
|
||||
trpc.whatsAppInternal.getPhoneNumber.useQuery(
|
||||
{
|
||||
credentialsId: typebot?.whatsAppCredentialsId as string,
|
||||
},
|
||||
{
|
||||
enabled: !!typebot?.whatsAppCredentialsId,
|
||||
}
|
||||
)
|
||||
|
||||
const toggleEnableWhatsApp = (isChecked: boolean) => {
|
||||
if (!phoneNumberData?.id || !typebot) return
|
||||
|
@ -42,22 +42,7 @@ export type FilePathUploadProps = z.infer<
|
||||
>
|
||||
|
||||
export const generateUploadUrl = authenticatedProcedure
|
||||
.meta({
|
||||
openapi: {
|
||||
method: 'POST',
|
||||
path: '/generate-upload-url',
|
||||
summary: 'Generate upload URL',
|
||||
description: 'Generate the needed URL to upload a file from the client',
|
||||
},
|
||||
})
|
||||
.input(inputSchema)
|
||||
.output(
|
||||
z.object({
|
||||
presignedUrl: z.string(),
|
||||
formData: z.record(z.string(), z.any()),
|
||||
fileUrl: z.string(),
|
||||
})
|
||||
)
|
||||
.mutation(async ({ input: { filePathProps, fileType }, ctx: { user } }) => {
|
||||
if (!env.S3_ENDPOINT || !env.S3_ACCESS_KEY || !env.S3_SECRET_KEY)
|
||||
throw new TRPCError({
|
||||
|
@ -1,23 +1,9 @@
|
||||
import { authenticatedProcedure } from '@/helpers/server/trpc'
|
||||
import { z } from 'zod'
|
||||
import prisma from '@typebot.io/lib/prisma'
|
||||
import { createId } from '@paralleldrive/cuid2'
|
||||
|
||||
export const generateVerificationToken = authenticatedProcedure
|
||||
.meta({
|
||||
openapi: {
|
||||
method: 'POST',
|
||||
path: '/verficiationTokens',
|
||||
protect: true,
|
||||
},
|
||||
})
|
||||
.input(z.void())
|
||||
.output(
|
||||
z.object({
|
||||
verificationToken: z.string(),
|
||||
})
|
||||
)
|
||||
.mutation(async () => {
|
||||
export const generateVerificationToken = authenticatedProcedure.mutation(
|
||||
async () => {
|
||||
const oneHourLater = new Date(Date.now() + 1000 * 60 * 60)
|
||||
const verificationToken = await prisma.verificationToken.create({
|
||||
data: {
|
||||
@ -28,4 +14,5 @@ export const generateVerificationToken = authenticatedProcedure
|
||||
})
|
||||
|
||||
return { verificationToken: verificationToken.token }
|
||||
})
|
||||
}
|
||||
)
|
||||
|
@ -13,20 +13,7 @@ const inputSchema = z.object({
|
||||
})
|
||||
|
||||
export const getPhoneNumber = authenticatedProcedure
|
||||
.meta({
|
||||
openapi: {
|
||||
method: 'GET',
|
||||
path: '/whatsapp/phoneNumber',
|
||||
protect: true,
|
||||
},
|
||||
})
|
||||
.input(inputSchema)
|
||||
.output(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
})
|
||||
)
|
||||
.query(async ({ input, ctx: { user } }) => {
|
||||
const credentials = await getCredentials(user.id, input)
|
||||
if (!credentials)
|
||||
|
@ -12,22 +12,7 @@ const inputSchema = z.object({
|
||||
})
|
||||
|
||||
export const getSystemTokenInfo = authenticatedProcedure
|
||||
.meta({
|
||||
openapi: {
|
||||
method: 'GET',
|
||||
path: '/whatsapp/systemToken',
|
||||
protect: true,
|
||||
},
|
||||
})
|
||||
.input(inputSchema)
|
||||
.output(
|
||||
z.object({
|
||||
appId: z.string(),
|
||||
appName: z.string(),
|
||||
expiresAt: z.number(),
|
||||
scopes: z.array(z.string()),
|
||||
})
|
||||
)
|
||||
.query(async ({ input, ctx: { user } }) => {
|
||||
if (!input.token && !input.credentialsId)
|
||||
throw new TRPCError({
|
||||
|
@ -10,7 +10,7 @@ export const receiveMessagePreview = publicProcedure
|
||||
.meta({
|
||||
openapi: {
|
||||
method: 'POST',
|
||||
path: '/whatsapp/preview/webhook',
|
||||
path: '/v1/whatsapp/preview/webhook',
|
||||
summary: 'Message webhook',
|
||||
tags: ['WhatsApp'],
|
||||
},
|
||||
|
@ -7,11 +7,14 @@ import { startWhatsAppPreview } from './startWhatsAppPreview'
|
||||
import { subscribePreviewWebhook } from './subscribePreviewWebhook'
|
||||
import { receiveMessagePreview } from './receiveMessagePreview'
|
||||
|
||||
export const whatsAppRouter = router({
|
||||
export const internalWhatsAppRouter = router({
|
||||
getPhoneNumber,
|
||||
getSystemTokenInfo,
|
||||
verifyIfPhoneNumberAvailable,
|
||||
generateVerificationToken,
|
||||
})
|
||||
|
||||
export const publicWhatsAppRouter = router({
|
||||
startWhatsAppPreview,
|
||||
subscribePreviewWebhook,
|
||||
receiveMessagePreview,
|
||||
|
@ -16,7 +16,7 @@ export const startWhatsAppPreview = authenticatedProcedure
|
||||
.meta({
|
||||
openapi: {
|
||||
method: 'POST',
|
||||
path: '/typebots/{typebotId}/whatsapp/start-preview',
|
||||
path: '/v1/typebots/{typebotId}/whatsapp/start-preview',
|
||||
summary: 'Start preview',
|
||||
tags: ['WhatsApp'],
|
||||
protect: true,
|
||||
|
@ -7,7 +7,7 @@ export const subscribePreviewWebhook = publicProcedure
|
||||
.meta({
|
||||
openapi: {
|
||||
method: 'GET',
|
||||
path: '/whatsapp/preview/webhook',
|
||||
path: '/v1/whatsapp/preview/webhook',
|
||||
summary: 'Subscribe webhook',
|
||||
tags: ['WhatsApp'],
|
||||
},
|
||||
|
@ -3,19 +3,7 @@ import { z } from 'zod'
|
||||
import prisma from '@typebot.io/lib/prisma'
|
||||
|
||||
export const verifyIfPhoneNumberAvailable = authenticatedProcedure
|
||||
.meta({
|
||||
openapi: {
|
||||
method: 'GET',
|
||||
path: '/whatsapp/phoneNumber/{phoneNumberDisplayName}/available',
|
||||
protect: true,
|
||||
},
|
||||
})
|
||||
.input(z.object({ phoneNumberDisplayName: z.string() }))
|
||||
.output(
|
||||
z.object({
|
||||
message: z.enum(['available', 'taken']),
|
||||
})
|
||||
)
|
||||
.query(async ({ input: { phoneNumberDisplayName } }) => {
|
||||
const existingWhatsAppCredentials = await prisma.credentials.findFirst({
|
||||
where: {
|
||||
|
@ -2,20 +2,18 @@ import { getAppVersionProcedure } from '@/features/dashboard/api/getAppVersionPr
|
||||
import { router } from '../trpc'
|
||||
import { generateUploadUrl } from '@/features/upload/api/generateUploadUrl'
|
||||
import { openAIRouter } from '@/features/blocks/integrations/openai/api/router'
|
||||
import { whatsAppRouter } from '@/features/whatsapp/router'
|
||||
import { internalWhatsAppRouter } from '@/features/whatsapp/router'
|
||||
import { zemanticAiRouter } from '@/features/blocks/integrations/zemanticAi/api/router'
|
||||
import { forgedCredentialsRouter } from '@/features/forge/api/credentials/router'
|
||||
import { integrationsRouter } from '@/features/forge/api/router'
|
||||
import { forgeRouter } from '@/features/forge/api/router'
|
||||
import { googleSheetsRouter } from '@/features/blocks/integrations/googleSheets/api/router'
|
||||
|
||||
export const internalRouter = router({
|
||||
getAppVersionProcedure,
|
||||
generateUploadUrl,
|
||||
whatsApp: whatsAppRouter,
|
||||
whatsAppInternal: internalWhatsAppRouter,
|
||||
openAI: openAIRouter,
|
||||
zemanticAI: zemanticAiRouter,
|
||||
integrationCredentials: forgedCredentialsRouter,
|
||||
integrations: integrationsRouter,
|
||||
forge: forgeRouter,
|
||||
sheets: googleSheetsRouter,
|
||||
})
|
||||
|
||||
|
@ -11,6 +11,7 @@ import { analyticsRouter } from '@/features/analytics/api/router'
|
||||
import { collaboratorsRouter } from '@/features/collaboration/api/router'
|
||||
import { customDomainsRouter } from '@/features/customDomains/api/router'
|
||||
import { processTelemetryEvent } from '@/features/telemetry/api/processTelemetryEvent'
|
||||
import { publicWhatsAppRouter } from '@/features/whatsapp/router'
|
||||
|
||||
export const publicRouter = router({
|
||||
getLinkedTypebots,
|
||||
@ -25,6 +26,7 @@ export const publicRouter = router({
|
||||
collaborators: collaboratorsRouter,
|
||||
customDomains: customDomainsRouter,
|
||||
processTelemetryEvent,
|
||||
whatsApp: publicWhatsAppRouter,
|
||||
})
|
||||
|
||||
export type PublicRouter = typeof publicRouter
|
||||
|
@ -56965,6 +56965,551 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/typebots/{typebotId}/whatsapp/start-preview": {
|
||||
"post": {
|
||||
"operationId": "whatsApp-startWhatsAppPreview",
|
||||
"summary": "Start preview",
|
||||
"tags": [
|
||||
"WhatsApp"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"Authorization": []
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"to": {
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
},
|
||||
"startFrom": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"group"
|
||||
]
|
||||
},
|
||||
"groupId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"type",
|
||||
"groupId"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"event"
|
||||
]
|
||||
},
|
||||
"eventId": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"type",
|
||||
"eventId"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"to"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [
|
||||
{
|
||||
"name": "typebotId",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"message"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"$ref": "#/components/responses/error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/v1/whatsapp/preview/webhook": {
|
||||
"get": {
|
||||
"operationId": "whatsApp-subscribePreviewWebhook",
|
||||
"summary": "Subscribe webhook",
|
||||
"tags": [
|
||||
"WhatsApp"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "hub.challenge",
|
||||
"in": "query",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "hub.verify_token",
|
||||
"in": "query",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"$ref": "#/components/responses/error"
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"operationId": "whatsApp-receiveMessagePreview",
|
||||
"summary": "Message webhook",
|
||||
"tags": [
|
||||
"WhatsApp"
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"entry": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"changes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"value": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"metadata": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"phone_number_id": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"phone_number_id"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"contacts": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"profile": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"profile"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"messages": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"from": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"text"
|
||||
]
|
||||
},
|
||||
"text": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"body": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"body"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"from",
|
||||
"type",
|
||||
"text",
|
||||
"timestamp"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"from": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"button"
|
||||
]
|
||||
},
|
||||
"button": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"text": {
|
||||
"type": "string"
|
||||
},
|
||||
"payload": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"text",
|
||||
"payload"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"from",
|
||||
"type",
|
||||
"button",
|
||||
"timestamp"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"from": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"interactive"
|
||||
]
|
||||
},
|
||||
"interactive": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"button_reply": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"title"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"button_reply"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"from",
|
||||
"type",
|
||||
"interactive",
|
||||
"timestamp"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"from": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"image"
|
||||
]
|
||||
},
|
||||
"image": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"from",
|
||||
"type",
|
||||
"image",
|
||||
"timestamp"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"from": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"video"
|
||||
]
|
||||
},
|
||||
"video": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"from",
|
||||
"type",
|
||||
"video",
|
||||
"timestamp"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"from": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"audio"
|
||||
]
|
||||
},
|
||||
"audio": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"from",
|
||||
"type",
|
||||
"audio",
|
||||
"timestamp"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"from": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"document"
|
||||
]
|
||||
},
|
||||
"document": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"from",
|
||||
"type",
|
||||
"document",
|
||||
"timestamp"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"metadata"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"value"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"changes"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"entry"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful response",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"message"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
"$ref": "#/components/responses/error"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
|
@ -1,4 +1,8 @@
|
||||
const urlRegex =
|
||||
/^(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})$/
|
||||
|
||||
export const validateUrl = (url: string) => urlRegex.test(url)
|
||||
export const validateUrl = (url: string) => {
|
||||
try {
|
||||
new URL(url)
|
||||
return true
|
||||
} catch (_) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -445,7 +445,9 @@ const parseReply =
|
||||
return block.options?.isRequired ?? defaultFileInputOptions.isRequired
|
||||
? { status: 'fail' }
|
||||
: { status: 'skip' }
|
||||
return { status: 'success', reply: inputValue }
|
||||
const urls = inputValue.split(', ')
|
||||
const status = urls.some((url) => validateUrl(url)) ? 'success' : 'fail'
|
||||
return { status, reply: inputValue }
|
||||
}
|
||||
case InputBlockType.PAYMENT: {
|
||||
if (!inputValue) return { status: 'fail' }
|
||||
|
@ -140,11 +140,15 @@ const getIncomingMessageContent = async ({
|
||||
}
|
||||
case 'document':
|
||||
case 'audio':
|
||||
return
|
||||
case 'video':
|
||||
case 'image':
|
||||
if (!typebotId) return
|
||||
const mediaId = 'video' in message ? message.video.id : message.image.id
|
||||
let mediaId: string | undefined
|
||||
if (message.type === 'video') mediaId = message.video.id
|
||||
if (message.type === 'image') mediaId = message.image.id
|
||||
if (message.type === 'audio') mediaId = message.audio.id
|
||||
if (message.type === 'document') mediaId = message.document.id
|
||||
if (!mediaId) return
|
||||
return (
|
||||
env.NEXTAUTH_URL +
|
||||
`/api/typebots/${typebotId}/whatsapp/media/${mediaId}`
|
||||
|
Reference in New Issue
Block a user