fmt(js): npm run fix on merge (#93563)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
hermes-seaeye[bot]
2026-08-24 05:05:16 +00:00
committed by GitHub
parent 34feb375ac
commit aff18ae21e
4 changed files with 209 additions and 176 deletions
+6 -2
View File
@@ -121,7 +121,9 @@ describe('withRetry', () => {
() => {
attempts += 1
if (attempts < 3) {return Promise.reject(errWithCode('ECONNRESET'))}
if (attempts < 3) {
return Promise.reject(errWithCode('ECONNRESET'))
}
return Promise.resolve('ok')
},
@@ -141,7 +143,9 @@ describe('withRetry', () => {
state.bodySent = true
attempts += 1
if (attempts < 2) {return Promise.reject(errWithCode('ECONNREFUSED'))}
if (attempts < 2) {
return Promise.reject(errWithCode('ECONNREFUSED'))
}
return Promise.resolve(null)
},
+30 -8
View File
@@ -62,7 +62,16 @@ function destroyKeepaliveAgents() {
}
// Transient transport errors: retry MAY be safe (subject to verb gating).
const TRANSIENT_CODES = new Set(['ECONNRESET', 'ECONNREFUSED', 'EPIPE', 'ETIMEDOUT', 'EAI_AGAIN', 'ENOTFOUND', 'EHOSTUNREACH', 'ENETUNREACH'])
const TRANSIENT_CODES = new Set([
'ECONNRESET',
'ECONNREFUSED',
'EPIPE',
'ETIMEDOUT',
'EAI_AGAIN',
'ENOTFOUND',
'EHOSTUNREACH',
'ENETUNREACH'
])
// Errors that prove the request never reached the server: the TCP connection
// (or name resolution) failed outright, so nothing was submitted.
@@ -75,9 +84,13 @@ function isIdempotentMethod(method) {
}
function isTransientTransportError(error) {
if (!error) {return false}
if (!error) {
return false
}
if (TRANSIENT_CODES.has(error.code)) {return true}
if (TRANSIENT_CODES.has(error.code)) {
return true
}
const msg = String(error.message || '')
return msg.includes('socket hang up') || msg.includes('read ECONNRESET')
@@ -93,14 +106,22 @@ function isTransientTransportError(error) {
* flushed, so a `false` here proves nothing went out.
*/
function shouldRetryRequest(error, method, requestState: any = {}) {
if (!isTransientTransportError(error)) {return false}
if (!isTransientTransportError(error)) {
return false
}
if (isIdempotentMethod(method)) {return true}
if (isIdempotentMethod(method)) {
return true
}
// Non-idempotent: only when the request provably never reached the server.
if (NEVER_SENT_CODES.has(error && error.code)) {return true}
if (NEVER_SENT_CODES.has(error && error.code)) {
return true
}
if (requestState.bodySent === false) {return true}
if (requestState.bodySent === false) {
return true
}
// Ambiguous (reset/hang-up after the body was flushed): the server may have
// processed it. Surface the error rather than risk a double submit.
@@ -118,7 +139,8 @@ function shouldRetryRequest(error, method, requestState: any = {}) {
async function withRetry(makeAttempt, options: any = {}) {
const method = String(options.method || 'GET').toUpperCase()
const maxRetries = Number.isInteger(options.maxRetries) ? options.maxRetries : 2
const delayFn = options.delayFn || (attempt => new Promise(r => setTimeout(r, Math.min(200 * Math.pow(2, attempt), 2000))))
const delayFn =
options.delayFn || (attempt => new Promise(r => setTimeout(r, Math.min(200 * Math.pow(2, attempt), 2000))))
let lastError
@@ -54,4 +54,3 @@ test('finalizeGatewayDownload prompts a save dialog then streams the response',
// HTTP errors carry their status so a 404 can trigger the fallback.
assert.match(fn, /error\.statusCode = statusCode/)
})
+173 -165
View File
@@ -4864,106 +4864,110 @@ function fetchJson(url, token, options: any = {}) {
// Retry policy lives in api-transport.ts: idempotent verbs retry on any
// transient transport error; POST/PUT/DELETE only when the request provably
// never reached the server (see shouldRetryRequest) — never double-submit.
return withRetry((requestState: any) => new Promise((resolve, reject) => {
const { body, contentType } = options.upload
? multipartBody(options.upload)
: {
body: options.body === undefined ? undefined : Buffer.from(JSON.stringify(options.body)),
contentType: 'application/json'
return withRetry(
(requestState: any) =>
new Promise((resolve, reject) => {
const { body, contentType } = options.upload
? multipartBody(options.upload)
: {
body: options.body === undefined ? undefined : Buffer.from(JSON.stringify(options.body)),
contentType: 'application/json'
}
const parsed = new URL(url)
const client = parsed.protocol === 'https:' ? https : http
const agent = jsonAgentFor(parsed.protocol)
const timeoutMs = resolveTimeoutMs(options.timeoutMs, DEFAULT_FETCH_TIMEOUT_MS)
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
reject(new Error(`Unsupported Hermes backend URL protocol: ${parsed.protocol}`))
return
}
const parsed = new URL(url)
const client = parsed.protocol === 'https:' ? https : http
const agent = jsonAgentFor(parsed.protocol)
const timeoutMs = resolveTimeoutMs(options.timeoutMs, DEFAULT_FETCH_TIMEOUT_MS)
const req = client.request(
parsed,
{
agent,
method: options.method || 'GET',
headers: {
...headersForRemoteRequest(url),
...(options.headers || {}),
'Content-Type': contentType,
'X-Hermes-Session-Token': token,
// RFC 8252 native flow authenticates the gated gateway with a bearer
// token instead of the loopback session-token header. When
// ``options.bearer`` is set we send Authorization: Bearer <token>;
// the gateway's OAuth gate verifies it via the provider stack with
// no cookie involved.
...(options.bearer ? { Authorization: `Bearer ${options.bearer}` } : {}),
...(body ? { 'Content-Length': String(body.length) } : {})
}
},
res => {
const chunks = []
res.on('error', reject)
res.on('data', chunk => chunks.push(chunk))
res.on('end', () => {
const text = Buffer.concat(chunks).toString('utf8')
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
reject(new Error(`Unsupported Hermes backend URL protocol: ${parsed.protocol}`))
if ((res.statusCode || 500) >= 400) {
reject(new Error(`${res.statusCode}: ${text || res.statusMessage}`))
return
}
return
}
const req = client.request(
parsed,
{
agent,
method: options.method || 'GET',
headers: {
...headersForRemoteRequest(url),
...(options.headers || {}),
'Content-Type': contentType,
'X-Hermes-Session-Token': token,
// RFC 8252 native flow authenticates the gated gateway with a bearer
// token instead of the loopback session-token header. When
// ``options.bearer`` is set we send Authorization: Bearer <token>;
// the gateway's OAuth gate verifies it via the provider stack with
// no cookie involved.
...(options.bearer ? { Authorization: `Bearer ${options.bearer}` } : {}),
...(body ? { 'Content-Length': String(body.length) } : {})
}
},
res => {
const chunks = []
res.on('error', reject)
res.on('data', chunk => chunks.push(chunk))
res.on('end', () => {
const text = Buffer.concat(chunks).toString('utf8')
if (!text) {
resolve(null)
if ((res.statusCode || 500) >= 400) {
reject(new Error(`${res.statusCode}: ${text || res.statusMessage}`))
return
}
return
// A 2xx response whose body is HTML means the request fell through
// to the SPA index.html (e.g. an unregistered /api path). JSON.parse
// would throw an opaque `Unexpected token '<'` here, so surface a
// clear diagnostic with the offending URL instead.
const looksHtml = /^\s*<(?:!doctype|html)/i.test(text)
const contentType = String(res.headers['content-type'] || '')
if (looksHtml || contentType.includes('text/html')) {
reject(
new Error(
`Expected JSON from ${url} but got HTML (status ${res.statusCode}). ` +
'The endpoint is likely missing on the Hermes backend.'
)
)
return
}
try {
resolve(JSON.parse(text))
} catch {
reject(new Error(`Invalid JSON from ${url} (status ${res.statusCode}): ${text.slice(0, 200)}`))
}
})
}
)
if (!text) {
resolve(null)
return
}
// A 2xx response whose body is HTML means the request fell through
// to the SPA index.html (e.g. an unregistered /api path). JSON.parse
// would throw an opaque `Unexpected token '<'` here, so surface a
// clear diagnostic with the offending URL instead.
const looksHtml = /^\s*<(?:!doctype|html)/i.test(text)
const contentType = String(res.headers['content-type'] || '')
if (looksHtml || contentType.includes('text/html')) {
reject(
new Error(
`Expected JSON from ${url} but got HTML (status ${res.statusCode}). ` +
'The endpoint is likely missing on the Hermes backend.'
)
)
return
}
try {
resolve(JSON.parse(text))
} catch {
reject(new Error(`Invalid JSON from ${url} (status ${res.statusCode}): ${text.slice(0, 200)}`))
}
req.on('error', reject)
req.setTimeout(timeoutMs, () => {
req.destroy(new Error(`Timed out connecting to Hermes backend after ${timeoutMs}ms`))
})
}
)
req.on('error', reject)
req.setTimeout(timeoutMs, () => {
req.destroy(new Error(`Timed out connecting to Hermes backend after ${timeoutMs}ms`))
})
// From here the request goes on the wire: a later transport error can no
// longer prove the server didn't process it, so non-idempotent verbs must
// not be retried past this point.
requestState.bodySent = true
// From here the request goes on the wire: a later transport error can no
// longer prove the server didn't process it, so non-idempotent verbs must
// not be retried past this point.
requestState.bodySent = true
if (body) {
req.write(body)
}
if (body) {
req.write(body)
}
req.end()
}), { method: options.method || 'GET' })
req.end()
}),
{ method: options.method || 'GET' }
)
}
// Token-auth download that streams the response body straight to a
@@ -5031,95 +5035,99 @@ function fetchPublicJson(url, options: any = {}) {
// NO ``X-Hermes-Session-Token`` header — used by the auth-mode probe before
// any credentials exist, and any time we must not leak a token to an
// endpoint that doesn't need one.
return withRetry((requestState: any) => new Promise((resolve, reject) => {
const body = options.body === undefined ? undefined : Buffer.from(JSON.stringify(options.body))
let parsed
return withRetry(
(requestState: any) =>
new Promise((resolve, reject) => {
const body = options.body === undefined ? undefined : Buffer.from(JSON.stringify(options.body))
let parsed
try {
parsed = new URL(url)
} catch (error) {
reject(new Error(`Invalid URL: ${error.message}`))
try {
parsed = new URL(url)
} catch (error) {
reject(new Error(`Invalid URL: ${error.message}`))
return
}
const client = parsed.protocol === 'https:' ? https : http
const agent = jsonAgentFor(parsed.protocol)
const timeoutMs = resolveTimeoutMs(options.timeoutMs, DEFAULT_FETCH_TIMEOUT_MS)
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
reject(new Error(`Unsupported Hermes backend URL protocol: ${parsed.protocol}`))
return
}
const req = client.request(
parsed,
{
agent,
method: options.method || 'GET',
headers: {
...headersForRemoteRequest(url),
...(options.headers || {}),
'Content-Type': 'application/json',
...(body ? { 'Content-Length': String(body.length) } : {})
return
}
},
res => {
const chunks = []
res.on('data', chunk => chunks.push(chunk))
res.on('end', () => {
const text = Buffer.concat(chunks).toString('utf8')
if ((res.statusCode || 500) >= 400) {
reject(new Error(`${res.statusCode}: ${text || res.statusMessage}`))
const client = parsed.protocol === 'https:' ? https : http
const agent = jsonAgentFor(parsed.protocol)
const timeoutMs = resolveTimeoutMs(options.timeoutMs, DEFAULT_FETCH_TIMEOUT_MS)
return
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
reject(new Error(`Unsupported Hermes backend URL protocol: ${parsed.protocol}`))
return
}
const req = client.request(
parsed,
{
agent,
method: options.method || 'GET',
headers: {
...headersForRemoteRequest(url),
...(options.headers || {}),
'Content-Type': 'application/json',
...(body ? { 'Content-Length': String(body.length) } : {})
}
},
res => {
const chunks = []
res.on('data', chunk => chunks.push(chunk))
res.on('end', () => {
const text = Buffer.concat(chunks).toString('utf8')
if ((res.statusCode || 500) >= 400) {
reject(new Error(`${res.statusCode}: ${text || res.statusMessage}`))
return
}
if (!text) {
resolve(null)
return
}
const looksHtml = /^\s*<(?:!doctype|html)/i.test(text)
const contentType = String(res.headers['content-type'] || '')
if (looksHtml || contentType.includes('text/html')) {
reject(
new Error(
`Expected JSON from ${url} but got HTML (status ${res.statusCode}). ` +
'The endpoint is likely missing on the Hermes backend.'
)
)
return
}
try {
resolve(JSON.parse(text))
} catch {
reject(new Error(`Invalid JSON from ${url} (status ${res.statusCode}): ${text.slice(0, 200)}`))
}
})
}
)
if (!text) {
resolve(null)
return
}
const looksHtml = /^\s*<(?:!doctype|html)/i.test(text)
const contentType = String(res.headers['content-type'] || '')
if (looksHtml || contentType.includes('text/html')) {
reject(
new Error(
`Expected JSON from ${url} but got HTML (status ${res.statusCode}). ` +
'The endpoint is likely missing on the Hermes backend.'
)
)
return
}
try {
resolve(JSON.parse(text))
} catch {
reject(new Error(`Invalid JSON from ${url} (status ${res.statusCode}): ${text.slice(0, 200)}`))
}
req.on('error', reject)
req.setTimeout(timeoutMs, () => {
req.destroy(new Error(`Timed out connecting to Hermes backend after ${timeoutMs}ms`))
})
}
)
req.on('error', reject)
req.setTimeout(timeoutMs, () => {
req.destroy(new Error(`Timed out connecting to Hermes backend after ${timeoutMs}ms`))
})
// Past this point the request is on the wire — see fetchJson.
requestState.bodySent = true
// Past this point the request is on the wire — see fetchJson.
requestState.bodySent = true
if (body) {
req.write(body)
}
if (body) {
req.write(body)
}
req.end()
}), { method: options.method || 'GET' })
req.end()
}),
{ method: options.method || 'GET' }
)
}
function mimeTypeForPath(filePath) {