import { clampInt, cursorApi, trimString } from './lib/client.ts' export type ListWorkersParams = { status?: 'all' | 'in_use' | 'idle' limit?: number nextPageToken?: string } /** * List self-hosted pool workers (requires pool service account key). * * @param params.status - Filter by `all`, `in_use`, or `idle`. * @param params.limit - Page size (1–100); default 50. * @returns Worker list and optional pagination token. * @example * import { listWorkers } from 'kody:@kentcdodds/cursor/workers' * const workers = await listWorkers({ status: 'idle', limit: 50 }) * // => { workers: [...], nextPageToken: '...' } */ export async function listWorkers(params: ListWorkersParams = {}) { const query: Record = {} if (params.status) query.status = params.status if (params.limit !== undefined) { query.limit = clampInt(params.limit, 1, 100, 50) } if (params.nextPageToken) query.nextPageToken = params.nextPageToken return cursorApi({ path: '/v0/private-workers', query, }) } /** * Return connected and in-use worker counts for fleet autoscaling. * * @returns User and team worker utilization summary. * @example * import { getFleetSummary } from 'kody:@kentcdodds/cursor/workers' * const summary = await getFleetSummary() * // => { teamSummary: { totalConnected: 10, inUse: 8 } } */ export async function getFleetSummary() { return cursorApi({ path: '/v0/private-workers/summary' }) } /** * Retrieve a single self-hosted pool worker by id. * * @param params.id - Worker id (e.g. `pw_123`). * @returns Worker details. * @example * import { getWorker } from 'kody:@kentcdodds/cursor/workers' * const worker = await getWorker({ id: 'pw_123' }) * // => { id: 'pw_123', status: 'idle' } */ export async function getWorker(params: { id: string }) { const id = trimString(params.id) if (!id) throw new Error('id is required') return cursorApi({ path: `/v0/private-workers/${id}` }) } export type ListPendingPoolRequestsParams = { limit?: number pageToken?: string repository?: string } /** * List pending pool requests not yet assigned to a worker. * * @param params.limit - Page size; default 50. * @param params.repository - Required for repo-scoped service account keys. * @returns Pending requests and pagination token. * @example * import { listPendingPoolRequests } from 'kody:@kentcdodds/cursor/workers' * const pending = await listPendingPoolRequests({ limit: 50 }) * // => { requests: [...], nextPageToken: '...' } */ export async function listPendingPoolRequests( params: ListPendingPoolRequestsParams = {}, ) { const query: Record = {} if (params.limit !== undefined) { query.limit = clampInt(params.limit, 1, 100, 50) } if (params.pageToken) query.pageToken = params.pageToken if (params.repository) query.repository = params.repository return cursorApi({ path: '/v0/private-workers/pending-requests', query, }) } export type CreateWorkerTokenParams = { forUserEmail?: string forUserId?: number } /** * Create a one-hour user-scoped worker token (service account key required). * * @param params.forUserEmail - Target team member email. * @param params.forUserId - Target team member user id (alternative to email). * @returns Short-lived access token and expiry. * @example * import { createWorkerToken } from 'kody:@kentcdodds/cursor/workers' * const token = await createWorkerToken({ forUserEmail: 'alice@company.com' }) * // => { accessToken: 'eyJ...', expiresAt: '...' } */ export async function createWorkerToken(params: CreateWorkerTokenParams) { const email = trimString(params.forUserEmail) const userId = params.forUserId if (!email && userId === undefined) { throw new Error('Provide forUserEmail or forUserId') } const body: Record = {} if (email) body.forUserEmail = email if (userId !== undefined) body.forUserId = userId return cursorApi({ method: 'POST', path: '/v1/sub-tokens', body, }) } /** Default export: fleet utilization summary. */ export default getFleetSummary