import { JOB_NIMBUS_CUSTOM_FIELDS_SCHEMA, JOB_NIMBUS_GEO_SCHEMA, JOB_NIMBUS_ID_SCHEMA, JobNimbusApiError, downloadJobNimbusFile as downloadJobNimbusContractFile, getJobNimbusApi as getJobNimbusContractApi, toJobNimbus, } from "@automate.ax/integration-contracts/jobnimbus" import * as z from "zod" import { parseRetryAfter, retryableActionError, terminalActionError, } from "../../../automation/actions" export const JOB_NIMBUS_ACCOUNT = "jobnimbus" /** * Creates a JobNimbus client whose failures carry action disposition. * * @param secret - Resolved JobNimbus account secret. * @param apiName - Provider API root to call. */ export function getJobNimbusApi( secret: unknown, apiName: Parameters[1], ): ReturnType { const api = getJobNimbusContractApi(secret, apiName) const request = api.request.bind(api) api.request = async (path, options) => { try { return await request(path, options) } catch (error) { throw classifyJobNimbusApiError(error) } } return api } /** * Downloads a JobNimbus file with action-aware provider classification. * * @param secret - Resolved JobNimbus account secret. * @param fileId - Attachment JNID. */ export async function downloadJobNimbusFile(secret: unknown, fileId: string) { try { return await downloadJobNimbusContractFile(secret, fileId) } catch (error) { throw classifyJobNimbusApiError(error) } } /** * Marks one known JobNimbus response without replacing its error identity. * * @param error - Provider error to classify. */ function classifyJobNimbusApiError(error: unknown) { if (!(error instanceof JobNimbusApiError)) return error if (error.status === 429) { return retryableActionError(error, { retryAt: parseRetryAfter(error.retryAfter), }) } return error.status < 500 ? terminalActionError(error) : error } export const JOB_NIMBUS_LIST_FIELDS = { actor: z.email().optional(), fields: z.string().trim().min(1).array().optional(), filter: z.record(z.string(), z.json()).optional(), from: z.number().int().nonnegative().prefault(0), size: z.number().int().min(1).max(1_000).prefault(100), sortDirection: z.enum(["asc", "desc"]).prefault("desc"), sortField: z.string().trim().min(1).prefault("dateCreated"), } export const JOB_NIMBUS_MUTATION_FIELDS = { actor: z.email().optional(), bulk: z.boolean().optional(), skip: z.enum(["automation", "notification"]).array().optional(), } export const JOB_NIMBUS_ADDRESS_FIELDS = { addressLine1: z.string().nullable().optional(), addressLine2: z.string().nullable().optional(), city: z.string().nullable().optional(), countryName: z.string().nullable().optional(), stateText: z.string().nullable().optional(), zip: z.string().nullable().optional(), } export const JOB_NIMBUS_WORKFLOW_INPUT_FIELDS = { customFields: JOB_NIMBUS_CUSTOM_FIELDS_SCHEMA.optional(), description: z.string().nullable().optional(), geo: JOB_NIMBUS_GEO_SCHEMA.nullable().optional(), owners: z.object({ id: JOB_NIMBUS_ID_SCHEMA }).array().optional(), recordTypeName: z.string().trim().min(1).optional(), sourceName: z.string().trim().min(1).nullable().optional(), statusName: z.string().trim().min(1).optional(), tags: z.string().array().optional(), } /** * Converts shared public list controls to legacy provider query fields. * * @param input - Parsed public list controls. */ export function jobNimbusListQuery( input: z.output>, ) { return { actor: input.actor, fields: input.fields?.map(toProviderField), filter: input.filter ? JSON.stringify(toJobNimbus(input.filter)) : undefined, from: input.from, size: input.size, sort_direction: input.sortDirection, sort_field: toProviderField(input.sortField), } } /** * Selects provider-native controls shared by legacy mutations. * * @param input - Parsed action input containing optional mutation controls. * @param input.actor - Administrator-key actor override. * @param input.bulk - Whether JobNimbus should apply the mutation in bulk. * @param input.skip - Provider side effects to skip. */ export function jobNimbusMutationQuery(input: { actor?: string bulk?: boolean skip?: ("automation" | "notification")[] }) { return { actor: input.actor, bulk: input.bulk, skip: input.skip, } } /** * Checks whether an update input contains a mutable provider field. * * @param input - Parsed action input. * @param ignoredKeys - Routing and mutation-control keys to ignore. */ export function hasJobNimbusUpdate( input: Record, ignoredKeys: readonly string[], ) { return Object.entries(input).some( ([key, value]) => !ignoredKeys.includes(key) && value !== undefined, ) } /** * Converts a public date input to the legacy Unix-seconds representation. * * @param value - JavaScript date or existing Unix-seconds value. */ export function toJobNimbusUnixSeconds(value: Date | number) { return value instanceof Date ? Math.floor(value.getTime() / 1_000) : value } export const JOB_NIMBUS_DATE_INPUT_SCHEMA = z.union([ z.date(), z.number().int().nonnegative(), ]) export { JOB_NIMBUS_ID_SCHEMA } /** * Converts a public field selector to its legacy provider name. * * @param value - Public field selector. */ function toProviderField(value: string) { return value .replace(/([a-zA-Z])([0-9])/g, "$1_$2") .replace(/[A-Z]/g, (character) => `_${character.toLowerCase()}`) }