-
Notifications
You must be signed in to change notification settings - Fork 1k
Expand file tree
/
Copy pathapi.ts
More file actions
121 lines (105 loc) · 3.17 KB
/
Copy pathapi.ts
File metadata and controls
121 lines (105 loc) · 3.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import createClient, { FetchResponse } from 'openapi-fetch'
import type { components, paths } from './schema.gen'
import { ConnectionConfig } from '../connectionConfig'
import { createApiLogger } from '../logs'
import {
SandboxError,
InvalidArgumentError,
NotFoundError,
NotEnoughSpaceError,
formatSandboxTimeoutError,
AuthenticationError,
} from '../errors'
import { StartResponse, ConnectResponse } from './process/process_pb'
import { Code, ConnectError } from '@connectrpc/connect'
import { WatchDirResponse } from './filesystem/filesystem_pb'
export async function handleEnvdApiError<A, B, C extends `${string}/${string}`>(
res: FetchResponse<A, B, C>
) {
if (!res.error) {
return
}
const message: string =
typeof res.error == 'string'
? res.error
: res.error?.message || (await res.response.text())
switch (res.response.status) {
case 400:
return new InvalidArgumentError(message)
case 401:
return new AuthenticationError(message)
case 404:
return new NotFoundError(message)
case 429:
return new SandboxError(
`${res.response.status}: ${message}: The requests are being rate limited.`
)
case 502:
return formatSandboxTimeoutError(message)
case 507:
return new NotEnoughSpaceError(message)
default:
return new SandboxError(`${res.response.status}: ${message}`)
}
}
export async function handleProcessStartEvent(
events: AsyncIterable<StartResponse | ConnectResponse>
) {
let startEvent: StartResponse | ConnectResponse
try {
startEvent = (await events[Symbol.asyncIterator]().next()).value
} catch (err) {
if (err instanceof ConnectError) {
if (err.code === Code.Unavailable) {
throw new NotFoundError('Sandbox is probably not running anymore')
}
}
throw err
}
if (startEvent.event?.event.case !== 'start') {
throw new Error('Expected start event')
}
return startEvent.event.event.value.pid
}
export async function handleWatchDirStartEvent(
events: AsyncIterable<WatchDirResponse>
) {
let startEvent: WatchDirResponse
try {
startEvent = (await events[Symbol.asyncIterator]().next()).value
} catch (err) {
if (err instanceof ConnectError) {
if (err.code === Code.Unavailable) {
throw new NotFoundError('Sandbox is probably not running anymore')
}
}
throw err
}
if (startEvent.event?.case !== 'start') {
throw new Error('Expected start event')
}
return startEvent.event.value
}
class EnvdApiClient {
readonly api: ReturnType<typeof createClient<paths>>
readonly version: string | undefined
constructor(
config: Pick<ConnectionConfig, 'apiUrl' | 'logger' | 'accessToken'> & { fetch?: (request: Request) => ReturnType<typeof fetch>, headers?: Record<string, string> },
metadata: {
version?: string
},
) {
this.api = createClient({
baseUrl: config.apiUrl,
fetch: config?.fetch,
headers: config?.headers,
// keepalive: true, // TODO: Return keepalive
})
this.version = metadata.version
if (config.logger) {
this.api.use(createApiLogger(config.logger))
}
}
}
export type { components, paths }
export { EnvdApiClient }