2023-12-22 09:13:53 +01:00
|
|
|
import { z } from '../zod'
|
2023-11-08 15:34:16 +01:00
|
|
|
import { credentialsBaseSchema } from './blocks/shared'
|
|
|
|
import {
|
|
|
|
ComparisonOperators,
|
|
|
|
LogicalOperator,
|
|
|
|
} from './blocks/logic/condition/constants'
|
2023-08-29 10:01:28 +02:00
|
|
|
|
|
|
|
const mediaSchema = z.object({ link: z.string() })
|
|
|
|
|
|
|
|
const headerSchema = z
|
|
|
|
.object({
|
|
|
|
type: z.literal('image'),
|
|
|
|
image: mediaSchema,
|
|
|
|
})
|
|
|
|
.or(
|
|
|
|
z.object({
|
|
|
|
type: z.literal('video'),
|
|
|
|
video: mediaSchema,
|
|
|
|
})
|
|
|
|
)
|
|
|
|
.or(
|
|
|
|
z.object({
|
|
|
|
type: z.literal('text'),
|
|
|
|
text: z.string(),
|
|
|
|
})
|
|
|
|
)
|
|
|
|
|
|
|
|
const bodySchema = z.object({
|
|
|
|
text: z.string(),
|
|
|
|
})
|
|
|
|
|
|
|
|
const actionSchema = z.object({
|
|
|
|
buttons: z.array(
|
|
|
|
z.object({
|
|
|
|
type: z.literal('reply'),
|
|
|
|
reply: z.object({ id: z.string(), title: z.string() }),
|
|
|
|
})
|
|
|
|
),
|
|
|
|
})
|
|
|
|
|
|
|
|
const templateSchema = z.object({
|
2023-09-19 11:53:18 +02:00
|
|
|
name: z.string(),
|
2023-08-29 10:01:28 +02:00
|
|
|
language: z.object({
|
2023-09-19 11:53:18 +02:00
|
|
|
code: z.string(),
|
2023-08-29 10:01:28 +02:00
|
|
|
}),
|
|
|
|
})
|
|
|
|
|
|
|
|
const interactiveSchema = z.object({
|
|
|
|
type: z.literal('button'),
|
|
|
|
header: headerSchema.optional(),
|
|
|
|
body: bodySchema.optional(),
|
|
|
|
action: actionSchema,
|
|
|
|
})
|
|
|
|
|
|
|
|
// https://developers.facebook.com/docs/whatsapp/cloud-api/reference/messages#message-object
|
|
|
|
const sendingMessageSchema = z.discriminatedUnion('type', [
|
|
|
|
z.object({
|
|
|
|
type: z.literal('text'),
|
|
|
|
text: z.object({
|
|
|
|
body: z.string(),
|
|
|
|
preview_url: z.boolean().optional(),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
z.object({
|
|
|
|
type: z.literal('image'),
|
|
|
|
image: mediaSchema,
|
|
|
|
}),
|
|
|
|
z.object({
|
|
|
|
type: z.literal('audio'),
|
|
|
|
audio: mediaSchema,
|
|
|
|
}),
|
|
|
|
z.object({
|
|
|
|
type: z.literal('video'),
|
|
|
|
video: mediaSchema,
|
|
|
|
}),
|
|
|
|
z.object({
|
|
|
|
type: z.literal('interactive'),
|
|
|
|
interactive: interactiveSchema,
|
|
|
|
}),
|
|
|
|
z.object({
|
|
|
|
type: z.literal('template'),
|
|
|
|
template: templateSchema,
|
|
|
|
}),
|
|
|
|
])
|
|
|
|
|
|
|
|
export const incomingMessageSchema = z.discriminatedUnion('type', [
|
|
|
|
z.object({
|
|
|
|
from: z.string(),
|
|
|
|
type: z.literal('text'),
|
|
|
|
text: z.object({
|
|
|
|
body: z.string(),
|
|
|
|
}),
|
|
|
|
timestamp: z.string(),
|
|
|
|
}),
|
|
|
|
z.object({
|
|
|
|
from: z.string(),
|
|
|
|
type: z.literal('button'),
|
|
|
|
button: z.object({
|
|
|
|
text: z.string(),
|
|
|
|
payload: z.string(),
|
|
|
|
}),
|
|
|
|
timestamp: z.string(),
|
|
|
|
}),
|
|
|
|
z.object({
|
|
|
|
from: z.string(),
|
|
|
|
type: z.literal('interactive'),
|
|
|
|
interactive: z.object({
|
|
|
|
button_reply: z.object({
|
|
|
|
id: z.string(),
|
|
|
|
title: z.string(),
|
|
|
|
}),
|
|
|
|
}),
|
|
|
|
timestamp: z.string(),
|
|
|
|
}),
|
|
|
|
z.object({
|
|
|
|
from: z.string(),
|
|
|
|
type: z.literal('image'),
|
2024-06-26 10:13:38 +02:00
|
|
|
image: z.object({ id: z.string(), caption: z.string().optional() }),
|
2023-08-29 10:01:28 +02:00
|
|
|
timestamp: z.string(),
|
|
|
|
}),
|
|
|
|
z.object({
|
|
|
|
from: z.string(),
|
|
|
|
type: z.literal('video'),
|
2024-06-26 10:13:38 +02:00
|
|
|
video: z.object({ id: z.string(), caption: z.string().optional() }),
|
2023-08-29 10:01:28 +02:00
|
|
|
timestamp: z.string(),
|
|
|
|
}),
|
|
|
|
z.object({
|
|
|
|
from: z.string(),
|
|
|
|
type: z.literal('audio'),
|
|
|
|
audio: z.object({ id: z.string() }),
|
|
|
|
timestamp: z.string(),
|
|
|
|
}),
|
|
|
|
z.object({
|
|
|
|
from: z.string(),
|
|
|
|
type: z.literal('document'),
|
2024-06-26 10:13:38 +02:00
|
|
|
document: z.object({ id: z.string(), caption: z.string().optional() }),
|
2023-08-29 10:01:28 +02:00
|
|
|
timestamp: z.string(),
|
|
|
|
}),
|
2024-01-18 14:01:22 +01:00
|
|
|
z.object({
|
|
|
|
from: z.string(),
|
|
|
|
type: z.literal('location'),
|
|
|
|
location: z.object({
|
|
|
|
latitude: z.number(),
|
2024-02-02 14:49:41 +01:00
|
|
|
longitude: z.number(),
|
2024-01-18 14:01:22 +01:00
|
|
|
}),
|
|
|
|
timestamp: z.string(),
|
|
|
|
}),
|
2023-08-29 10:01:28 +02:00
|
|
|
])
|
|
|
|
|
|
|
|
export const whatsAppWebhookRequestBodySchema = z.object({
|
|
|
|
entry: z.array(
|
|
|
|
z.object({
|
|
|
|
changes: z.array(
|
|
|
|
z.object({
|
|
|
|
value: z.object({
|
2023-09-29 09:59:38 +02:00
|
|
|
metadata: z.object({
|
|
|
|
phone_number_id: z.string(),
|
|
|
|
}),
|
2023-08-29 10:01:28 +02:00
|
|
|
contacts: z
|
|
|
|
.array(
|
|
|
|
z.object({
|
|
|
|
profile: z.object({
|
|
|
|
name: z.string(),
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
)
|
|
|
|
.optional(),
|
|
|
|
messages: z.array(incomingMessageSchema).optional(),
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
),
|
|
|
|
})
|
|
|
|
),
|
|
|
|
})
|
|
|
|
|
2024-03-21 10:23:23 +01:00
|
|
|
export type WhatsAppWebhookRequestBody = z.infer<
|
|
|
|
typeof whatsAppWebhookRequestBodySchema
|
|
|
|
>
|
|
|
|
|
2023-08-29 10:01:28 +02:00
|
|
|
export const whatsAppCredentialsSchema = z
|
|
|
|
.object({
|
|
|
|
type: z.literal('whatsApp'),
|
|
|
|
data: z.object({
|
|
|
|
systemUserAccessToken: z.string(),
|
|
|
|
phoneNumberId: z.string(),
|
|
|
|
}),
|
|
|
|
})
|
|
|
|
.merge(credentialsBaseSchema)
|
|
|
|
|
|
|
|
const whatsAppComparisonSchema = z.object({
|
|
|
|
id: z.string(),
|
|
|
|
comparisonOperator: z.nativeEnum(ComparisonOperators).optional(),
|
|
|
|
value: z.string().optional(),
|
|
|
|
})
|
|
|
|
export type WhatsAppComparison = z.infer<typeof whatsAppComparisonSchema>
|
|
|
|
|
|
|
|
const startConditionSchema = z.object({
|
|
|
|
logicalOperator: z.nativeEnum(LogicalOperator),
|
|
|
|
comparisons: z.array(
|
|
|
|
z.object({
|
|
|
|
id: z.string(),
|
|
|
|
comparisonOperator: z.nativeEnum(ComparisonOperators).optional(),
|
|
|
|
value: z.string().optional(),
|
|
|
|
})
|
|
|
|
),
|
|
|
|
})
|
|
|
|
|
|
|
|
export const whatsAppSettingsSchema = z.object({
|
2023-09-22 11:08:41 +02:00
|
|
|
isEnabled: z.boolean().optional(),
|
2023-08-29 10:01:28 +02:00
|
|
|
startCondition: startConditionSchema.optional(),
|
2023-09-22 17:12:15 +02:00
|
|
|
sessionExpiryTimeout: z
|
|
|
|
.number()
|
|
|
|
.max(48)
|
|
|
|
.min(0.01)
|
|
|
|
.optional()
|
|
|
|
.describe('Expiration delay in hours after latest interaction'),
|
2023-08-29 10:01:28 +02:00
|
|
|
})
|
|
|
|
|
2023-10-03 10:53:37 +02:00
|
|
|
export const defaultSessionExpiryTimeout = 4
|
2023-09-22 17:12:15 +02:00
|
|
|
|
2023-08-29 10:01:28 +02:00
|
|
|
export type WhatsAppIncomingMessage = z.infer<typeof incomingMessageSchema>
|
|
|
|
export type WhatsAppSendingMessage = z.infer<typeof sendingMessageSchema>
|
|
|
|
export type WhatsAppCredentials = z.infer<typeof whatsAppCredentialsSchema>
|