import type { ZoomQuery } from './types.ts'
export function asRecord(value: unknown): Record<string, unknown> {
return value && typeof value === 'object' ? (value as Record<string, unknown>) : {}
}
export function asString(value: unknown): string | null {
return typeof value === 'string' ? value : null
}
export function asNumber(value: unknown): number | null {
return typeof value === 'number' && Number.isFinite(value) ? value : null
}
export function asBoolean(value: unknown): boolean | null {
return typeof value === 'boolean' ? value : null
}
export function pickQuery(
params: Record<string, unknown>,
keys: readonly string[],
): ZoomQuery {
const query: ZoomQuery = {}
for (const key of keys) {
const value = params[key]
if (value === undefined || value === null) continue
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
query[key] = value
}
}
return query
}
export function readOptionalBoolean(value: unknown): boolean | undefined {
return typeof value === 'boolean' ? value : undefined
}
export function readOptionalNumber(value: unknown): number | undefined {
if (typeof value === 'number' && Number.isFinite(value)) return value
if (typeof value === 'string' && value.trim() && Number.isFinite(Number(value))) {
return Number(value)
}
return undefined
}
export function readOptionalString(value: unknown): string | undefined {
return typeof value === 'string' && value.trim() ? value.trim() : undefined
}
export function slimUser(data: Record<string, unknown>) {
return {
id: asString(data.id),
email: asString(data.email),
displayName: asString(data.display_name),
firstName: asString(data.first_name),
lastName: asString(data.last_name),
type: asNumber(data.type),
status: asString(data.status),
timezone: asString(data.timezone),
dept: asString(data.dept),
}
}
export function slimMeeting(data: Record<string, unknown>) {
return {
id: asNumber(data.id) ?? asString(data.id),
uuid: asString(data.uuid),
topic: asString(data.topic),
type: asNumber(data.type),
status: asString(data.status),
startTime: asString(data.start_time),
duration: asNumber(data.duration),
timezone: asString(data.timezone),
joinUrl: asString(data.join_url),
hostId: asString(data.host_id),
hostEmail: asString(data.host_email),
agenda: asString(data.agenda),
createdAt: asString(data.created_at),
}
}
export function slimRecordingMeeting(data: Record<string, unknown>) {
const files = Array.isArray(data.recording_files)
? data.recording_files.map((file) => slimRecordingFile(asRecord(file)))
: []
return {
id: asNumber(data.id) ?? asString(data.id),
uuid: asString(data.uuid),
topic: asString(data.topic),
startTime: asString(data.start_time),
duration: asNumber(data.duration),
shareUrl: asString(data.share_url),
totalSize: asNumber(data.total_size),
recordingCount: asNumber(data.recording_count),
files,
}
}
export function slimRecordingFile(data: Record<string, unknown>) {
return {
id: asString(data.id),
meetingId: asString(data.meeting_id),
recordingStart: asString(data.recording_start),
recordingEnd: asString(data.recording_end),
fileType: asString(data.file_type),
fileSize: asNumber(data.file_size),
playUrl: asString(data.play_url),
downloadUrl: asString(data.download_url),
status: asString(data.status),
recordingType: asString(data.recording_type),
}
}
export function slimWebinar(data: Record<string, unknown>) {
return {
id: asNumber(data.id) ?? asString(data.id),
uuid: asString(data.uuid),
topic: asString(data.topic),
type: asNumber(data.type),
status: asString(data.status),
startTime: asString(data.start_time),
duration: asNumber(data.duration),
timezone: asString(data.timezone),
joinUrl: asString(data.join_url),
hostId: asString(data.host_id),
agenda: asString(data.agenda),
}
}
export function pageMeta(data: Record<string, unknown>) {
return {
pageCount: asNumber(data.page_count),
pageNumber: asNumber(data.page_number),
pageSize: asNumber(data.page_size),
totalRecords: asNumber(data.total_records),
nextPageToken: asString(data.next_page_token),
}
}
const MEETING_BODY_KEYS = [
'topic',
'type',
'start_time',
'duration',
'timezone',
'password',
'agenda',
'schedule_for',
'recurrence',
'settings',
'tracking_fields',
'template_id',
] as const
const WEBINAR_BODY_KEYS = [
'topic',
'type',
'start_time',
'duration',
'timezone',
'password',
'agenda',
'schedule_for',
'recurrence',
'settings',
'tracking_fields',
] as const
export function buildMeetingBody(params: Record<string, unknown>): Record<string, unknown> {
return pickBody(params, MEETING_BODY_KEYS, {
start_time: ['start_time', 'startTime'],
schedule_for: ['schedule_for', 'scheduleFor'],
template_id: ['template_id', 'templateId'],
tracking_fields: ['tracking_fields', 'trackingFields'],
})
}
export function buildWebinarBody(params: Record<string, unknown>): Record<string, unknown> {
return pickBody(params, WEBINAR_BODY_KEYS, {
start_time: ['start_time', 'startTime'],
schedule_for: ['schedule_for', 'scheduleFor'],
tracking_fields: ['tracking_fields', 'trackingFields'],
})
}
function pickBody(
params: Record<string, unknown>,
keys: readonly string[],
aliases: Record<string, readonly string[]> = {},
): Record<string, unknown> {
const body: Record<string, unknown> = {}
for (const key of keys) {
const names = aliases[key] ?? [key]
for (const name of names) {
if (params[name] !== undefined) {
body[key] = params[name]
break
}
}
}
return body
}