229 lines
5.6 KiB
TypeScript
229 lines
5.6 KiB
TypeScript
// @ts-nocheck
|
|
|
|
type GhlMirrorConfig = {
|
|
token: string
|
|
locationId: string
|
|
baseUrl: string
|
|
version: string
|
|
}
|
|
|
|
function normalizeBaseUrl(value?: string) {
|
|
return String(value || "https://services.leadconnectorhq.com").replace(
|
|
/\/+$/,
|
|
""
|
|
)
|
|
}
|
|
|
|
export function readGhlMirrorConfig() {
|
|
const token = String(
|
|
process.env.GHL_PRIVATE_INTEGRATION_TOKEN || process.env.GHL_API_TOKEN || ""
|
|
).trim()
|
|
const locationId = String(process.env.GHL_LOCATION_ID || "").trim()
|
|
const baseUrl = normalizeBaseUrl(process.env.GHL_API_BASE_URL)
|
|
const version = String(process.env.GHL_API_VERSION || "2021-07-28").trim()
|
|
|
|
if (!token || !locationId) {
|
|
return null
|
|
}
|
|
|
|
return {
|
|
token,
|
|
locationId,
|
|
baseUrl,
|
|
version,
|
|
} satisfies GhlMirrorConfig
|
|
}
|
|
|
|
export async function fetchGhlMirrorJson(
|
|
config: GhlMirrorConfig,
|
|
pathname: string,
|
|
init?: RequestInit
|
|
) {
|
|
const response = await fetch(`${config.baseUrl}${pathname}`, {
|
|
...init,
|
|
headers: {
|
|
Authorization: `Bearer ${config.token}`,
|
|
Version: config.version,
|
|
Accept: "application/json",
|
|
"Content-Type": "application/json",
|
|
...(init?.headers || {}),
|
|
},
|
|
cache: "no-store",
|
|
})
|
|
|
|
const text = await response.text()
|
|
let body: any = null
|
|
if (text) {
|
|
try {
|
|
body = JSON.parse(text)
|
|
} catch {
|
|
body = null
|
|
}
|
|
}
|
|
|
|
if (!response.ok) {
|
|
throw new Error(
|
|
`GHL request failed (${response.status}) for ${pathname}: ${body?.message || text || "Unknown error"}`
|
|
)
|
|
}
|
|
|
|
return body
|
|
}
|
|
|
|
export async function fetchGhlContactsPage(
|
|
config: GhlMirrorConfig,
|
|
args?: {
|
|
limit?: number
|
|
cursor?: string
|
|
}
|
|
) {
|
|
const searchParams = new URLSearchParams({
|
|
locationId: config.locationId,
|
|
limit: String(Math.min(100, Math.max(1, args?.limit || 100))),
|
|
})
|
|
|
|
if (args?.cursor) {
|
|
searchParams.set("startAfterId", args.cursor)
|
|
}
|
|
|
|
const payload = await fetchGhlMirrorJson(
|
|
config,
|
|
`/contacts/?${searchParams.toString()}`
|
|
)
|
|
|
|
const contacts = Array.isArray(payload?.contacts)
|
|
? payload.contacts
|
|
: Array.isArray(payload?.data?.contacts)
|
|
? payload.data.contacts
|
|
: []
|
|
|
|
const nextCursor =
|
|
contacts.length > 0 ? String(contacts[contacts.length - 1]?.id || "") : ""
|
|
|
|
return {
|
|
items: contacts,
|
|
nextCursor: nextCursor || undefined,
|
|
}
|
|
}
|
|
|
|
export async function fetchGhlMessagesPage(
|
|
config: GhlMirrorConfig,
|
|
args?: {
|
|
limit?: number
|
|
cursor?: string
|
|
channel?: "Call" | "SMS"
|
|
}
|
|
) {
|
|
const url = new URL(`${config.baseUrl}/conversations/messages/export`)
|
|
url.searchParams.set("locationId", config.locationId)
|
|
url.searchParams.set("limit", String(Math.min(100, Math.max(1, args?.limit || 100))))
|
|
url.searchParams.set("channel", args?.channel || "SMS")
|
|
|
|
if (args?.cursor) {
|
|
url.searchParams.set("cursor", args.cursor)
|
|
}
|
|
|
|
const payload = await fetchGhlMirrorJson(config, url.pathname + url.search)
|
|
|
|
return {
|
|
items: Array.isArray(payload?.messages) ? payload.messages : [],
|
|
nextCursor:
|
|
typeof payload?.nextCursor === "string" && payload.nextCursor
|
|
? payload.nextCursor
|
|
: undefined,
|
|
}
|
|
}
|
|
|
|
export async function fetchGhlConversationsPage(
|
|
config: GhlMirrorConfig,
|
|
args?: {
|
|
limit?: number
|
|
}
|
|
) {
|
|
const url = new URL(`${config.baseUrl}/conversations/search`)
|
|
url.searchParams.set("locationId", config.locationId)
|
|
url.searchParams.set("limit", String(Math.min(100, Math.max(1, args?.limit || 100))))
|
|
|
|
const payload = await fetchGhlMirrorJson(config, url.pathname + url.search)
|
|
|
|
return {
|
|
items: Array.isArray(payload?.conversations) ? payload.conversations : [],
|
|
total:
|
|
typeof payload?.total === "number"
|
|
? payload.total
|
|
: Array.isArray(payload?.conversations)
|
|
? payload.conversations.length
|
|
: 0,
|
|
}
|
|
}
|
|
|
|
export async function fetchGhlConversationMessages(
|
|
config: GhlMirrorConfig,
|
|
args: {
|
|
conversationId: string
|
|
}
|
|
) {
|
|
const payload = await fetchGhlMirrorJson(
|
|
config,
|
|
`/conversations/${encodeURIComponent(args.conversationId)}/messages`
|
|
)
|
|
|
|
return {
|
|
items: Array.isArray(payload?.messages?.messages)
|
|
? payload.messages.messages
|
|
: Array.isArray(payload?.messages)
|
|
? payload.messages
|
|
: Array.isArray(payload?.data?.messages?.messages)
|
|
? payload.data.messages.messages
|
|
: Array.isArray(payload?.data?.messages)
|
|
? payload.data.messages
|
|
: Array.isArray(payload)
|
|
? payload
|
|
: [],
|
|
}
|
|
}
|
|
|
|
export async function sendGhlConversationMessage(
|
|
config: GhlMirrorConfig,
|
|
args: {
|
|
conversationId?: string
|
|
contactId?: string
|
|
message: string
|
|
type?: string
|
|
}
|
|
) {
|
|
return await fetchGhlMirrorJson(config, "/conversations/messages", {
|
|
method: "POST",
|
|
body: JSON.stringify({
|
|
type: args.type || "SMS",
|
|
message: args.message,
|
|
conversationId: args.conversationId,
|
|
contactId: args.contactId,
|
|
}),
|
|
})
|
|
}
|
|
|
|
export async function fetchGhlCallLogsPage(
|
|
config: GhlMirrorConfig,
|
|
args?: {
|
|
page?: number
|
|
pageSize?: number
|
|
}
|
|
) {
|
|
const url = new URL(`${config.baseUrl}/voice-ai/dashboard/call-logs`)
|
|
url.searchParams.set("locationId", config.locationId)
|
|
url.searchParams.set("page", String(Math.max(1, args?.page || 1)))
|
|
url.searchParams.set(
|
|
"pageSize",
|
|
String(Math.min(50, Math.max(1, args?.pageSize || 50)))
|
|
)
|
|
|
|
const payload = await fetchGhlMirrorJson(config, url.pathname + url.search)
|
|
|
|
return {
|
|
items: Array.isArray(payload?.callLogs) ? payload.callLogs : [],
|
|
page: Number(payload?.page || args?.page || 1),
|
|
total: Number(payload?.total || 0),
|
|
pageSize: Number(payload?.pageSize || args?.pageSize || 50),
|
|
}
|
|
}
|