chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:47:58 +08:00
commit b16403ea71
789 changed files with 115226 additions and 0 deletions
@@ -0,0 +1,152 @@
import { assert, test, describe } from 'vitest'
import { handleEnvdApiError, handleEnvdApiFetchError } from '../../src/envd/api'
import {
AuthenticationError,
InvalidArgumentError,
NotEnoughSpaceError,
NotFoundError,
RateLimitError,
SandboxError,
TimeoutError,
} from '../../src/errors'
function createMockResponse(
status: number,
error?: { message?: string } | string
): {
error?: { message?: string } | string
response: Response
} {
return {
error,
response: {
status,
ok: status >= 200 && status < 300,
statusText: '',
// openapi-fetch consumes the body whenever it produces an error value
bodyUsed: error !== undefined,
text: async () => (typeof error === 'string' ? error : ''),
} as unknown as Response,
}
}
describe('handleEnvdApiError', () => {
test('returns undefined for a successful response', async () => {
const err = await handleEnvdApiError(createMockResponse(200))
assert.isUndefined(err)
})
test('returns an error for non-2xx response without content', async () => {
// openapi-fetch leaves `error` undefined for responses with
// Content-Length: 0
const res = createMockResponse(500)
const err = await handleEnvdApiError(res)
assert.instanceOf(err, SandboxError)
assert.include(err?.message, '500')
})
test('returns an error for non-2xx response with empty string error', async () => {
const res = createMockResponse(500, '')
const err = await handleEnvdApiError(res)
assert.instanceOf(err, SandboxError)
assert.include(err?.message, '500')
})
test('returns a mapped error for non-2xx response without content', async () => {
const res = createMockResponse(404)
const err = await handleEnvdApiError(res)
assert.instanceOf(err, NotFoundError)
})
test('returns InvalidArgumentError for 400', async () => {
const res = createMockResponse(400, { message: 'Bad request' })
const err = await handleEnvdApiError(res)
assert.instanceOf(err, InvalidArgumentError)
})
test('returns AuthenticationError for 401', async () => {
const res = createMockResponse(401, { message: 'Invalid token' })
const err = await handleEnvdApiError(res)
assert.instanceOf(err, AuthenticationError)
})
test('returns NotFoundError for 404', async () => {
const res = createMockResponse(404, { message: 'Not found' })
const err = await handleEnvdApiError(res)
assert.instanceOf(err, NotFoundError)
})
test('returns RateLimitError for 429', async () => {
const res = createMockResponse(429, { message: 'Too many requests' })
const err = await handleEnvdApiError(res)
assert.instanceOf(err, RateLimitError)
assert.include(err?.message, 'rate limited')
})
test('returns TimeoutError for 502', async () => {
const res = createMockResponse(502, { message: 'Bad gateway' })
const err = await handleEnvdApiError(res)
assert.instanceOf(err, TimeoutError)
})
test('returns NotEnoughSpaceError for 507', async () => {
const res = createMockResponse(507, { message: 'No space left' })
const err = await handleEnvdApiError(res)
assert.instanceOf(err, NotEnoughSpaceError)
})
test('falls back to SandboxError for unmapped status', async () => {
const res = createMockResponse(500, { message: 'Internal error' })
const err = await handleEnvdApiError(res)
assert.instanceOf(err, SandboxError)
assert.include(err?.message, '500')
})
})
describe('handleEnvdApiFetchError', () => {
test('returns the original error for terminated fetch without a health check', async () => {
const original = new TypeError('terminated')
const err = await handleEnvdApiFetchError(original)
assert.strictEqual(err, original)
})
test('returns a TimeoutError when the health check says the sandbox is not running', async () => {
const err = await handleEnvdApiFetchError(
new TypeError('terminated'),
async () => false
)
assert.instanceOf(err, TimeoutError)
assert.include(err.message, 'sandbox was killed or reached its end of life')
})
// Each JS runtime surfaces a dropped connection with different wording, and not
// always as a TypeError (Bun raises a plain Error), so match by message
const runtimeTerminatedErrors = {
Node: new TypeError('terminated'),
Bun: new Error('The socket connection was closed unexpectedly'),
Deno: new TypeError('error reading a body from connection'),
}
for (const [runtime, error] of Object.entries(runtimeTerminatedErrors)) {
test(`treats the ${runtime} dropped-connection error as terminated`, async () => {
const err = await handleEnvdApiFetchError(error, async () => false)
assert.instanceOf(err, TimeoutError)
assert.include(
err.message,
'sandbox was killed or reached its end of life'
)
})
}
test('returns the original error when the health check says the sandbox is running', async () => {
const original = new TypeError('terminated')
const err = await handleEnvdApiFetchError(original, async () => true)
assert.strictEqual(err, original)
})
test('returns the original error for other fetch failures', async () => {
const original = new TypeError('fetch failed')
const err = await handleEnvdApiFetchError(original)
assert.strictEqual(err, original)
})
})
@@ -0,0 +1,138 @@
import { assert, test, describe } from 'vitest'
import { Code, ConnectError } from '@connectrpc/connect'
import {
handleRpcError,
handleRpcErrorWithHealthCheck,
} from '../../src/envd/rpc'
import {
AuthenticationError,
InvalidArgumentError,
NotFoundError,
RateLimitError,
SandboxError,
TimeoutError,
} from '../../src/errors'
describe('handleRpcError', () => {
test('returns InvalidArgumentError for InvalidArgument', () => {
const err = handleRpcError(new ConnectError('bad', Code.InvalidArgument))
assert.instanceOf(err, InvalidArgumentError)
})
test('returns AuthenticationError for Unauthenticated', () => {
const err = handleRpcError(new ConnectError('nope', Code.Unauthenticated))
assert.instanceOf(err, AuthenticationError)
})
test('returns NotFoundError for NotFound', () => {
const err = handleRpcError(new ConnectError('missing', Code.NotFound))
assert.instanceOf(err, NotFoundError)
})
test('returns RateLimitError for ResourceExhausted', () => {
const err = handleRpcError(
new ConnectError('too many', Code.ResourceExhausted)
)
assert.instanceOf(err, RateLimitError)
assert.include(err.message, 'Rate limit')
})
test('returns TimeoutError for Unavailable', () => {
const err = handleRpcError(new ConnectError('gone', Code.Unavailable))
assert.instanceOf(err, TimeoutError)
})
test('falls back to SandboxError for unmapped code', () => {
const err = handleRpcError(new ConnectError('boom', Code.Internal))
assert.instanceOf(err, SandboxError)
})
test('falls back to generic SandboxError for Unknown "terminated"', () => {
const err = handleRpcError(new ConnectError('terminated', Code.Unknown))
assert.instanceOf(err, SandboxError)
assert.include(err.message, 'terminated')
assert.notInclude(err.message, 'killed')
})
test('returns the original error when not a ConnectError', () => {
const original = new Error('not connect')
const err = handleRpcError(original)
assert.strictEqual(err, original)
})
})
describe('handleRpcErrorWithHealthCheck', () => {
const terminated = () => new ConnectError('terminated', Code.Unknown)
// Each JS runtime surfaces a dropped connection with different wording
const runtimeTerminatedMessages = {
Node: 'terminated',
Bun: 'The socket connection was closed unexpectedly',
Deno: 'error reading a body from connection',
}
test('returns a TimeoutError when the health check says the sandbox is not running', async () => {
const err = await handleRpcErrorWithHealthCheck(
terminated(),
async () => false
)
assert.instanceOf(err, TimeoutError)
assert.include(err.message, 'sandbox was killed or reached its end of life')
})
for (const [runtime, message] of Object.entries(runtimeTerminatedMessages)) {
test(`treats the ${runtime} dropped-connection message as terminated`, async () => {
const err = await handleRpcErrorWithHealthCheck(
new ConnectError(message, Code.Unknown),
async () => false
)
assert.instanceOf(err, TimeoutError)
assert.include(
err.message,
'sandbox was killed or reached its end of life'
)
})
}
test('falls back to the generic mapping when the health check says the sandbox is running', async () => {
const err = await handleRpcErrorWithHealthCheck(
terminated(),
async () => true
)
assert.instanceOf(err, SandboxError)
assert.notInstanceOf(err, TimeoutError)
assert.notInclude(err.message, 'killed')
})
test('falls back to the generic mapping when the sandbox state is unknown', async () => {
const err = await handleRpcErrorWithHealthCheck(
terminated(),
async () => undefined
)
assert.instanceOf(err, SandboxError)
assert.notInstanceOf(err, TimeoutError)
assert.notInclude(err.message, 'killed')
})
test('falls back to the generic mapping when the health check itself fails', async () => {
const err = await handleRpcErrorWithHealthCheck(terminated(), async () => {
throw new Error('health check failed')
})
assert.instanceOf(err, SandboxError)
assert.notInstanceOf(err, TimeoutError)
assert.notInclude(err.message, 'killed')
})
test('does not run the health check for other errors', async () => {
let called = false
const err = await handleRpcErrorWithHealthCheck(
new ConnectError('missing', Code.NotFound),
async () => {
called = true
return false
}
)
assert.instanceOf(err, NotFoundError)
assert.isFalse(called)
})
})
+276
View File
@@ -0,0 +1,276 @@
import { afterEach, expect, test, vi } from 'vitest'
afterEach(() => {
vi.restoreAllMocks()
vi.resetModules()
vi.doUnmock('undici')
vi.doUnmock('../../src/utils')
delete process.env.E2B_ENVD_RPC_CONNECTIONS
delete process.env.E2B_ENVD_INFLIGHT_REQUESTS
delete process.env.E2B_ENVD_RPC_INFLIGHT_REQUESTS
})
test('uses undici with HTTP/2 enabled in Node', async () => {
const agents: Array<{ allowH2?: boolean; connections?: number }> = []
const requests: Array<{ init?: RequestInit & { dispatcher?: unknown } }> = []
class Agent {
constructor(options: { allowH2?: boolean; connections?: number }) {
agents.push(options)
}
}
const undiciFetch = vi.fn((input, init) => {
requests.push({ init })
return Promise.resolve(new Response('ok'))
})
const { createEnvdFetchForRuntime } = await import('../../src/envd/http2')
const fetcher = createEnvdFetchForRuntime('node', {
connectionLimit: 1,
loadUndici: () => Promise.resolve({ Agent, fetch: undiciFetch }),
})
const res = await fetcher('https://example.com/status')
expect(await res.text()).toBe('ok')
expect(agents).toEqual([{ allowH2: true, connections: 1 }])
expect(requests[0].init?.dispatcher).toBeInstanceOf(Agent)
})
test('uses a ProxyAgent dispatcher when a proxy is configured', async () => {
const proxyAgents: Array<{
uri?: string
allowH2?: boolean
connections?: number
}> = []
const agents: Array<unknown> = []
const requests: Array<{ init?: RequestInit & { dispatcher?: unknown } }> = []
class Agent {
constructor() {
agents.push(this)
}
}
class ProxyAgent {
constructor(options: {
uri?: string
allowH2?: boolean
connections?: number
}) {
proxyAgents.push(options)
}
}
const undiciFetch = vi.fn((input, init) => {
requests.push({ init })
return Promise.resolve(new Response('ok'))
})
const { createEnvdFetchForRuntime } = await import('../../src/envd/http2')
const fetcher = createEnvdFetchForRuntime('node', {
connectionLimit: 1,
proxy: 'http://127.0.0.1:8080',
loadUndici: () =>
Promise.resolve({ Agent, ProxyAgent, fetch: undiciFetch }),
})
await fetcher('https://example.com/status')
expect(agents).toHaveLength(0)
expect(proxyAgents).toEqual([
{ uri: 'http://127.0.0.1:8080', allowH2: true, connections: 1 },
])
expect(requests[0].init?.dispatcher).toBeInstanceOf(ProxyAgent)
})
test('caches envd fetchers per proxy', async () => {
const { createEnvdFetch, createEnvdRpcFetch } = await import(
'../../src/envd/http2'
)
const noProxy = createEnvdFetch()
const proxyA = createEnvdFetch('http://127.0.0.1:8080')
expect(createEnvdFetch()).toBe(noProxy)
expect(createEnvdFetch('http://127.0.0.1:8080')).toBe(proxyA)
expect(proxyA).not.toBe(noProxy)
const rpcNoProxy = createEnvdRpcFetch()
const rpcProxyA = createEnvdRpcFetch('http://127.0.0.1:8080')
expect(createEnvdRpcFetch()).toBe(rpcNoProxy)
expect(createEnvdRpcFetch('http://127.0.0.1:8080')).toBe(rpcProxyA)
expect(rpcProxyA).not.toBe(rpcNoProxy)
})
test('passes Request objects to undici as URL plus init', async () => {
const requests: Array<{ input: RequestInfo | URL; init?: RequestInit }> = []
class Agent {}
const undiciFetch = vi.fn((input, init) => {
requests.push({ input, init })
return Promise.resolve(new Response('ok'))
})
const { createEnvdFetchForRuntime } = await import('../../src/envd/http2')
const fetcher = createEnvdFetchForRuntime('node', {
connectionLimit: 1,
loadUndici: () => Promise.resolve({ Agent, fetch: undiciFetch }),
})
const body = JSON.stringify({ ok: true })
await fetcher(
new Request('https://example.com/rpc', {
body,
headers: { 'content-type': 'application/json' },
method: 'POST',
})
)
expect(requests[0].input).toBe('https://example.com/rpc')
expect(requests[0].init?.method).toBe('POST')
expect(requests[0].init?.headers).toBeInstanceOf(Headers)
expect(requests[0].init?.body).toBeInstanceOf(ReadableStream)
})
test('can create a bounded dispatcher for RPC streams', async () => {
const agents: Array<{ allowH2?: boolean; connections?: number }> = []
class Agent {
constructor(options: { allowH2?: boolean; connections?: number }) {
agents.push(options)
}
}
const undiciFetch = vi.fn(() => Promise.resolve(new Response('ok')))
const { createEnvdFetchForRuntime } = await import('../../src/envd/http2')
const fetcher = createEnvdFetchForRuntime('node', {
connectionLimit: 100,
loadUndici: () => Promise.resolve({ Agent, fetch: undiciFetch }),
})
await fetcher('https://example.com/rpc')
expect(agents).toEqual([{ allowH2: true, connections: 100 }])
})
test('reads RPC stream dispatcher connection limit from env', async () => {
process.env.E2B_ENVD_RPC_CONNECTIONS = '200'
const { getEnvdRpcConnectionLimit } = await import('../../src/envd/http2')
expect(getEnvdRpcConnectionLimit()).toBe(200)
})
test('getEnvdRpcConnectionLimit throws on malformed env value', async () => {
process.env.E2B_ENVD_RPC_CONNECTIONS = 'bogus'
const { getEnvdRpcConnectionLimit } = await import('../../src/envd/http2')
expect(() => getEnvdRpcConnectionLimit()).toThrow(/E2B_ENVD_RPC_CONNECTIONS/)
})
test('getEnvdInflightLimit throws on malformed env value', async () => {
process.env.E2B_ENVD_INFLIGHT_REQUESTS = 'bogus'
const { getEnvdInflightLimit } = await import('../../src/envd/http2')
expect(() => getEnvdInflightLimit()).toThrow(/E2B_ENVD_INFLIGHT_REQUESTS/)
})
test('getEnvdRpcInflightLimit throws on malformed env value', async () => {
process.env.E2B_ENVD_RPC_INFLIGHT_REQUESTS = 'bogus'
const { getEnvdRpcInflightLimit } = await import('../../src/envd/http2')
expect(() => getEnvdRpcInflightLimit()).toThrow(
/E2B_ENVD_RPC_INFLIGHT_REQUESTS/
)
})
test('inflight limit env vars return 0 when explicitly disabled', async () => {
process.env.E2B_ENVD_INFLIGHT_REQUESTS = '0'
process.env.E2B_ENVD_RPC_INFLIGHT_REQUESTS = '0'
const { getEnvdInflightLimit, getEnvdRpcInflightLimit } = await import(
'../../src/envd/http2'
)
expect(getEnvdInflightLimit()).toBe(0)
expect(getEnvdRpcInflightLimit()).toBe(0)
})
test('getEnvdInflightLimit throws on negative env value', async () => {
process.env.E2B_ENVD_INFLIGHT_REQUESTS = '-1'
const { getEnvdInflightLimit } = await import('../../src/envd/http2')
expect(() => getEnvdInflightLimit()).toThrow(/E2B_ENVD_INFLIGHT_REQUESTS=-1/)
})
test('getEnvdRpcInflightLimit throws on negative env value', async () => {
process.env.E2B_ENVD_RPC_INFLIGHT_REQUESTS = '-5'
const { getEnvdRpcInflightLimit } = await import('../../src/envd/http2')
expect(() => getEnvdRpcInflightLimit()).toThrow(
/E2B_ENVD_RPC_INFLIGHT_REQUESTS=-5/
)
})
test('defers loading undici until the first Node request', async () => {
const Agent = vi.fn()
const undiciFetch = vi.fn(() => Promise.resolve(new Response('ok')))
const loadUndici = vi.fn(() => Promise.resolve({ Agent, fetch: undiciFetch }))
const { createEnvdFetchForRuntime } = await import('../../src/envd/http2')
const fetcher = createEnvdFetchForRuntime('node', {
connectionLimit: 1,
loadUndici,
})
expect(loadUndici).not.toHaveBeenCalled()
expect(Agent).not.toHaveBeenCalled()
expect(undiciFetch).not.toHaveBeenCalled()
await fetcher('https://example.com/status')
expect(loadUndici).toHaveBeenCalledOnce()
expect(Agent).toHaveBeenCalledOnce()
expect(undiciFetch).toHaveBeenCalledOnce()
})
test('falls back to global fetch when undici cannot be loaded', async () => {
const fallbackFetch = vi.fn(() =>
Promise.resolve(new Response('fallback ok'))
) as unknown as typeof fetch
vi.stubGlobal('fetch', fallbackFetch)
const { createEnvdFetchForRuntime } = await import('../../src/envd/http2')
const fetcher = createEnvdFetchForRuntime('node', {
loadUndici: () => Promise.resolve(undefined),
})
const res = await fetcher('https://example.com/status')
expect(await res.text()).toBe('fallback ok')
expect(fallbackFetch).toHaveBeenCalledWith(
'https://example.com/status',
undefined
)
})
test('uses global fetch outside Node', async () => {
const fallbackFetch = vi.fn() as unknown as typeof fetch
vi.stubGlobal('fetch', fallbackFetch)
const { createEnvdFetchForRuntime } = await import('../../src/envd/http2')
expect(createEnvdFetchForRuntime('browser')).toBe(fallbackFetch)
expect(createEnvdFetchForRuntime('vercel-edge')).toBe(fallbackFetch)
})