basant307/AI_Governance_Project
048
1/**2 * @license3 * Copyright 2025 Google LLC4 * SPDX-License-Identifier: Apache-2.05 */6 7import { writeStderrLine } from './stdioHelpers.js';8 9function takeUtf8Prefix(value: string, maxBytes: number): string {10 let bytes = 0;11 let end = 0;12 13 for (const char of value) {14 const charBytes = Buffer.byteLength(char, 'utf8');15 if (bytes + charBytes > maxBytes) {16 break;17 }18 bytes += charBytes;19 end += char.length;20 }21 22 return value.slice(0, end);23}24 25export async function readStdin(): Promise<string> {26 const MAX_STDIN_SIZE = 8 * 1024 * 1024; // 8MB27 return new Promise((resolve, reject) => {28 let data = '';29 let totalSize = 0;30 let settled = false;31 process.stdin.setEncoding('utf8');32 33 const pipedInputShouldBeAvailableInMs = 500;34 let pipedInputTimerId: null | NodeJS.Timeout = setTimeout(() => {35 // stop reading if input is not available yet, this is needed36 // in terminals where stdin is never TTY and nothing's piped37 // which causes the program to get stuck expecting data from stdin38 onEnd();39 }, pipedInputShouldBeAvailableInMs);40 41 const onReadable = () => {42 let chunk;43 while ((chunk = process.stdin.read()) !== null) {44 if (pipedInputTimerId) {45 clearTimeout(pipedInputTimerId);46 pipedInputTimerId = null;47 }48 49 const chunkSize = Buffer.byteLength(chunk, 'utf8');50 if (totalSize + chunkSize > MAX_STDIN_SIZE) {51 const remainingSize = MAX_STDIN_SIZE - totalSize;52 const prefix = takeUtf8Prefix(chunk, remainingSize);53 data += prefix;54 totalSize += Buffer.byteLength(prefix, 'utf8');55 writeStderrLine(56 `Warning: stdin input truncated to ${MAX_STDIN_SIZE} bytes.`,57 );58 finish();59 process.stdin.destroy(); // Stop reading further60 return;61 }62 data += chunk;63 totalSize += chunkSize;64 }65 };66 67 const finish = () => {68 if (settled) return;69 settled = true;70 cleanup();71 resolve(data);72 };73 74 const onEnd = () => {75 finish();76 };77 78 const onError = (err: Error) => {79 if (settled) return;80 settled = true;81 cleanup();82 reject(err);83 };84 85 const cleanup = () => {86 if (pipedInputTimerId) {87 clearTimeout(pipedInputTimerId);88 pipedInputTimerId = null;89 }90 process.stdin.removeListener('readable', onReadable);91 process.stdin.removeListener('end', onEnd);92 process.stdin.removeListener('error', onError);93 };94 95 process.stdin.on('readable', onReadable);96 process.stdin.on('end', onEnd);97 process.stdin.on('error', onError);98 });99}100 