import {z} from 'zod' export type Os = {type: 'linux' | 'windows' | 'unknown', name: 'debian' | 'kali' | 'ubuntu' | 'redhat' | 'centos' | 'fedora' | 'suse' | 'oracle' | 'scientific' | 'slackware' | 'xp' | 'vista' | 'seven' | '10' | '2000' | '2003' | '2008 r2' | '2012' | '2012 r2' | '2016', version: string, fullName: string, servicePack?: string | undefined}; export type AgentKey = {value: unknown, status?: ('certified' | 'undefined') | undefined}; export type Timezone = {name: string, offset: string}; export type NodeAdd = Array<{id: string, hostname: string, status: 'accepted' | 'pending', os: Os, policyServerId?: string | undefined, machineType?: ('physical' | 'vm' | 'hyperv' | 'qemu' | 'vbox' | 'vmware' | 'xen') | undefined, machine?: ({type: 'Physical' | 'Virtual', provider?: ('hyperv' | 'qemu' | 'vbox' | 'vmware' | 'xen') | undefined, manufacturer?: string | undefined, serialNumber?: string | undefined}) | undefined, state?: ('enabled' | 'ignored' | 'empty-policies' | 'initializing' | 'preparing-eol') | undefined, policyMode?: ('enforce' | 'audit') | undefined, agentKey?: AgentKey | undefined, properties: Array<{name: string, value: unknown}>, ipAddresses: Array, timezone?: Timezone | undefined}>; export type UpdateApiNodesArgs = {body: NodeAdd}; export type UpdateApiNodesOptions = {baseUrl?: string | undefined, APITokens?: string | undefined, fetch?: typeof fetch | undefined}; export const updateApiNodesResponse = z.object({result: z.enum(["success", "error"]), action: z.literal("createNode"), data: z.object({created: z.array(z.string()), failed: z.array(z.string())})}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * Create one or several new nodes * * PUT /nodes */ export const updateApiNodes = async (args: UpdateApiNodesArgs, options?: UpdateApiNodesOptions) => { const {baseUrl = "https://rudder.example.com/rudder/api/latest", fetch: fetchFn = fetch, APITokens} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (APITokens !== undefined) headers.set("X-API-Token", APITokens) const url = `${baseUrl.replace(/\/+$/, '')}/nodes${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "PUT", headers, body: JSON.stringify(args.body)}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(updateApiNodesResponse, await res.json()) };