import { readFile } from 'node:fs/promises' import { isAbsolute, join } from 'node:path' import { getRequiredStringFlag, getRequiredStringFlagAllowingEmpty } from './flags' import { RuntimeClientError } from './runtime-client' type BodyOptions = { required: boolean maximumCharacters: number tooLargeCode: string label: string } export function readCommandBody( flags: Map, cwd: string, options: BodyOptions & { required: true } ): Promise export function readCommandBody( flags: Map, cwd: string, options: BodyOptions ): Promise export async function readCommandBody( flags: Map, cwd: string, options: BodyOptions ): Promise { const body = await readTextOrFileFlag(flags, cwd, 'body', options.required) if (body !== undefined && body.length > options.maximumCharacters) { throw new RuntimeClientError( options.tooLargeCode, `${options.label} must be at most ${options.maximumCharacters} characters` ) } return body } /** Reads `-- ` or `---file `, refusing both. */ export async function readTextOrFileFlag( flags: Map, cwd: string, flag: string, required: boolean ): Promise { const fileFlag = `${flag}-file` const hasText = flags.has(flag) const hasFile = flags.has(fileFlag) if (hasText && hasFile) { throw new RuntimeClientError( 'invalid_argument', `Use either --${flag} or --${fileFlag}, not both` ) } if (!hasText && !hasFile) { if (required) { throw new RuntimeClientError('invalid_argument', `Missing --${flag} or --${fileFlag}`) } return undefined } return hasText ? getRequiredStringFlagAllowingEmpty(flags, flag) : readBodyFile(getRequiredStringFlag(flags, fileFlag), cwd) } async function readBodyFile(path: string, cwd: string): Promise { if (path !== '-') { return readFile(isAbsolute(path) ? path : join(cwd, path), 'utf8') } if (process.stdin.isTTY) { throw new RuntimeClientError('invalid_argument', 'stdin body requested but stdin is a TTY') } const chunks: Buffer[] = [] for await (const chunk of process.stdin) { chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))) } return Buffer.concat(chunks).toString('utf8') }