(sessionId: string, req: FsReadRequest)
| 161 | } |
| 162 | |
| 163 | async read(sessionId: string, req: FsReadRequest): Promise<FsReadResponse> { |
| 164 | const session = await this.sessions.get(sessionId); |
| 165 | const cwd = session.metadata.cwd; |
| 166 | const safe = await resolveSafePath(cwd, req.path); |
| 167 | |
| 168 | let st: import('node:fs').Stats; |
| 169 | try { |
| 170 | st = await fs.stat(safe.absolute); |
| 171 | } catch (err) { |
| 172 | throw mapStatError(err, req.path); |
| 173 | } |
| 174 | if (st.isDirectory()) { |
| 175 | throw new FsIsDirectoryError(req.path); |
| 176 | } |
| 177 | if (st.size > FS_READ_MAX_BYTES) { |
| 178 | throw new FsTooLargeError(req.path, st.size); |
| 179 | } |
| 180 | |
| 181 | const sampleSize = Math.min(FS_BINARY_SAMPLE_BYTES, st.size); |
| 182 | const sample = await readFileRange(safe.absolute, 0, sampleSize); |
| 183 | const isBinaryHeuristic = detectBinary(sample); |
| 184 | |
| 185 | if (isBinaryHeuristic && req.encoding === 'utf-8') { |
| 186 | |
| 187 | throw new FsIsBinaryError(req.path); |
| 188 | } |
| 189 | |
| 190 | const effectiveLength = Math.min(req.length, st.size - req.offset); |
| 191 | const bytes = |
| 192 | effectiveLength <= 0 |
| 193 | ? Buffer.alloc(0) |
| 194 | : await readFileRange( |
| 195 | safe.absolute, |
| 196 | req.offset, |
| 197 | req.offset + effectiveLength, |
| 198 | ); |
| 199 | |
| 200 | const encoding: 'utf-8' | 'base64' = |
| 201 | req.encoding === 'base64' || (req.encoding === 'auto' && isBinaryHeuristic) |
| 202 | ? 'base64' |
| 203 | : 'utf-8'; |
| 204 | const content = encoding === 'utf-8' ? bytes.toString('utf-8') : bytes.toString('base64'); |
| 205 | const truncated = req.offset + effectiveLength < st.size; |
| 206 | |
| 207 | const mime = guessMime(safe.relative, isBinaryHeuristic); |
| 208 | const languageId = encoding === 'utf-8' ? guessLanguageId(safe.relative) : undefined; |
| 209 | const etag = buildEtag(st); |
| 210 | |
| 211 | const out: FsReadResponse = { |
| 212 | path: safe.relative, |
| 213 | content, |
| 214 | encoding, |
| 215 | size: st.size, |
| 216 | truncated, |
| 217 | etag, |
| 218 | mime, |
| 219 | is_binary: isBinaryHeuristic, |
| 220 | }; |
nothing calls this directly
no test coverage detected