Skip to content

Built for people who want to own their automations. Join the waitlist for an invite.

Package listing

@kody/zendesk

src/models.ts

150 lines · 4.2 KB · TypeScript
import type {
	JsonRecord,
	ZendeskArticle,
	ZendeskMe,
	ZendeskPageInfo,
	ZendeskTicket,
	ZendeskTicketComment,
	ZendeskUser,
} from './types.ts'

function asRecord(value: unknown): JsonRecord {
	return value && typeof value === 'object' && !Array.isArray(value)
		? (value as JsonRecord)
		: {}
}

function asString(value: unknown): string | null {
	return typeof value === 'string' && value.length > 0 ? value : null
}

function asNumber(value: unknown): number | null {
	if (typeof value === 'number' && Number.isFinite(value)) return value
	if (typeof value === 'string' && value.trim().length > 0) {
		const parsed = Number(value)
		return Number.isFinite(parsed) ? parsed : null
	}
	return null
}

function asBoolean(value: unknown): boolean | null {
	return typeof value === 'boolean' ? value : null
}

function requireId(value: unknown): number | null {
	const id = asNumber(value)
	return id === null ? null : id
}

export function mapMe(value: unknown): ZendeskMe {
	const record = asRecord(value)
	const user = record.user ? asRecord(record.user) : record
	const id = requireId(user.id)
	if (id === null) throw new Error('Zendesk /users/me did not return a user id.')
	return {
		id,
		name: asString(user.name),
		role: asString(user.role),
		active: asBoolean(user.active),
	}
}

export function mapTicket(value: unknown): ZendeskTicket | null {
	const record = asRecord(value)
	const ticket = record.ticket ? asRecord(record.ticket) : record
	const id = requireId(ticket.id)
	if (id === null) return null
	return {
		id,
		subject: asString(ticket.subject),
		status: asString(ticket.status),
		priority: asString(ticket.priority),
		type: asString(ticket.type),
		requesterId: asNumber(ticket.requester_id),
		assigneeId: asNumber(ticket.assignee_id),
		createdAt: asString(ticket.created_at),
		updatedAt: asString(ticket.updated_at),
	}
}

export function mapTicketComment(value: unknown): ZendeskTicketComment | null {
	const record = asRecord(value)
	const id = requireId(record.id)
	if (id === null) return null
	return {
		id,
		authorId: asNumber(record.author_id),
		public: asBoolean(record.public),
		body: asString(record.plain_body) ?? asString(record.body),
		createdAt: asString(record.created_at),
	}
}

export function mapUser(value: unknown): ZendeskUser | null {
	const record = asRecord(value)
	const user = record.user ? asRecord(record.user) : record
	const id = requireId(user.id)
	if (id === null) return null
	return {
		id,
		name: asString(user.name),
		email: asString(user.email),
		role: asString(user.role),
		active: asBoolean(user.active),
		createdAt: asString(user.created_at),
		updatedAt: asString(user.updated_at),
	}
}

export function mapArticle(value: unknown): ZendeskArticle | null {
	const record = asRecord(value)
	const article = record.article ? asRecord(record.article) : record
	const id = requireId(article.id)
	if (id === null) return null
	return {
		id,
		title: asString(article.title),
		locale: asString(article.locale),
		sectionId: asNumber(article.section_id),
		draft: asBoolean(article.draft),
		htmlUrl: asString(article.html_url),
		createdAt: asString(article.created_at),
		updatedAt: asString(article.updated_at),
	}
}

export function extractPageInfo(payload: unknown): ZendeskPageInfo {
	const record = asRecord(payload)
	const nextPage = asString(record.next_page)
	const previousPage = asString(record.previous_page)
	const count = asNumber(record.count)
	const links = asRecord(record.links)
	const meta = asRecord(record.meta)
	const cursorNext = asString(links.next)
	const hasMore = asBoolean(meta.has_more)
	return {
		hasNextPage: Boolean(nextPage || cursorNext || hasMore === true),
		nextPage: nextPage ?? cursorNext,
		previousPage,
		count,
	}
}

export function extractListItems(payload: unknown, keys: Array<string>): Array<unknown> {
	if (Array.isArray(payload)) return payload
	const record = asRecord(payload)
	if (Array.isArray(record.results)) return record.results
	for (const key of keys) {
		if (Array.isArray(record[key])) return record[key] as Array<unknown>
	}
	return []
}

export function compactDefined<T extends JsonRecord>(value: T): T {
	const output: JsonRecord = {}
	for (const [key, item] of Object.entries(value)) {
		if (item === undefined) continue
		output[key] = item
	}
	return output as T
}