← Public packages
@cameronpak/box
Full Box Public API v1 client: lifecycle, prompts, files, commands, snapshots, environments, webhooks, desktop, hosting, and account.
src/wait-for-box.ts
63 lines · 2.1 KB · TypeScriptimport { assertBoxId, failure, success, type Result } from './client.ts'
import getBox from './get-box.ts'
import type { Box, BoxState } from './types.ts'
const DEFAULT_TARGETS: Array<BoxState> = ['ready', 'idle']
const TERMINAL: Array<BoxState> = ['archived', 'error']
export type WaitForBoxInput = {
boxId: string
/** States that end the wait. Defaults to ready and idle. */
targetStates?: Array<BoxState>
/** Seconds to keep polling. Defaults to 60. Kody execute stops near 90 seconds. */
timeoutSeconds?: number
/** Milliseconds between polls. Defaults to 3000. */
pollIntervalMs?: number
}
export type WaitForBoxOutput = {
box: Box
/** True when the box reached one of the target states. */
reached: boolean
waitedMs: number
}
/**
* Poll a box until it reaches a target state, goes terminal, or the wait times out.
* A timeout is not an error: reached is false and the last box snapshot comes back.
*/
export default async function waitForBox(
input: WaitForBoxInput,
): Promise<Result<WaitForBoxOutput>> {
const invalid = assertBoxId(input?.boxId)
if (invalid) return failure<WaitForBoxOutput>(invalid)
const targets = input.targetStates ?? DEFAULT_TARGETS
const timeoutMs = (input.timeoutSeconds ?? 60) * 1000
const intervalMs = input.pollIntervalMs ?? 3000
const startedAt = Date.now()
let last: Box | null = null
while (Date.now() - startedAt < timeoutMs) {
const read = await getBox({ boxId: input.boxId })
if (!read.ok) return failure<WaitForBoxOutput>(read.error)
last = read.data.box
if (targets.includes(last.state)) {
return success({ box: last, reached: true, waitedMs: Date.now() - startedAt })
}
if (TERMINAL.includes(last.state) && !targets.includes(last.state)) {
return success({ box: last, reached: false, waitedMs: Date.now() - startedAt })
}
await new Promise((resolve) => setTimeout(resolve, intervalMs))
}
if (last) {
return success({ box: last, reached: false, waitedMs: Date.now() - startedAt })
}
return failure<WaitForBoxOutput>({
code: 'wait_timeout',
message: 'The box was never read before the wait timed out.',
status: 0,
})
}