import type { VehicleClient, VehicleEventHandler, VehicleInvocationOptions, VehicleJobSnapshot, VehicleJobSubmitOptions, VehicleJobSubmitResult, VehicleJobTailResult, VehicleManifest, VehicleProtocolAgreement, VehicleProtocolOffer, VehicleSubscription } from "@danypops/vehicle-core"; export interface RemoteVehicleClientOptions { /** e.g. "http://127.0.0.1:4242" -- no trailing slash. */ baseUrl: string; token: string; /** Defaults to the global fetch. Injectable for tests. */ fetch?: typeof globalThis.fetch; /** * Caches manifest() for this many milliseconds instead of hitting * /vehicle/manifest on every call. Default (undefined) is today's exact * behavior -- always fetch fresh, zero caching. The cache is a single * slot (one manifest per client, not keyed) and is invalidated * automatically the moment any non-"read"-effect invoke() through this * same client succeeds, since that's the only way this client's own * actions could have changed what the daemon now reports as available. */ manifestCacheTtlMs?: number; /** * WebSocket URL for the push-invalidation channel this Vehicle's events * are bridged onto (see push-channel.ts / bridgeVehicleEventsToPushChannel * in vehicle-server). Only resolved the first time subscribe() is * actually called -- a client that never subscribes pays zero cost. * Defaults to baseUrl with http(s) swapped for ws(s) and "/push" * appended, matching startDaemon()'s own default pushPath. */ pushUrl?: string; /** Defaults to the global WebSocket. Injectable for tests, passed straight through to connectPushChannel(). */ WebSocketImpl?: typeof WebSocket; } /** * A `VehicleClient` that talks to a remote daemon's * `@danypops/vehicle-server`'s `./http` provider over the same * Bearer-authenticated loopback transport every Vehicle server uses -- * preserving `LocalVehicleClient`'s exact semantics over the wire (every * `VehicleInvocationOptions` field sent in the request body, a relative * `deadlineMs`, cancellation aborting the underlying fetch AND * best-effort notifying the provider's `/vehicle/cancel`, progress via SSE * when `onProgress` is set, and a `VehicleError` round-tripping with its * original code/category/details rather than becoming a generic HTTP * error) -- so a daemon-backed Pi extension can project a remote Vehicle * through `@danypops/vehicle-client-pi` exactly as it would a local one. */ export declare class RemoteVehicleClient implements VehicleClient { private readonly options; private readonly fetchImpl; private closed; private cachedManifest; constructor(options: RemoteVehicleClientOptions); manifest(): Promise; negotiate(offer: VehicleProtocolOffer): Promise; invoke(name: string, version: number, input: unknown, options?: VehicleInvocationOptions): Promise; /** * A cached manifest only ever reflects what /vehicle/manifest reported at * fetch time; a successful non-"read" invoke() through this same client * is the one signal this client has that availability might now differ. * Looked up against the cached manifest itself (never a fresh fetch) -- * an operation this client has never seen via manifest() can't be judged * write-or-not, so it's left alone rather than guessed at. */ private invalidateManifestCacheIfWrite; /** * Subscribes to one declared Vehicle event over the daemon's push channel, * with the same reconnect/backoff/jitter/heartbeat resilience every other * connectPushChannel() consumer gets -- not a new hand-rolled WebSocket. * Each call opens its own connection (one per subscription, not shared/ * pooled) so close() on the returned VehicleSubscription is unambiguous. */ subscribe(name: string, version: number, handler: VehicleEventHandler): VehicleSubscription; /** Best-effort: notifies the provider to abort a still-in-flight operation. The local fetch's own AbortSignal already stops this client's wait regardless of whether this succeeds. */ cancel(operationId: string): Promise; close(): Promise; /** Vehicle Jobs -- see VehicleClient's own doc comment. Mirrors invoke()'s own request/error conventions (Bearer auth, JSON body, VehicleError round trip). */ submitJob(name: string, version: number, input: unknown, options?: VehicleJobSubmitOptions): Promise; pollJob(jobId: string): Promise; tailJob(jobId: string, cursor?: number): Promise; steerJob(jobId: string, input: unknown): Promise; cancelJob(jobId: string): Promise; private postJobRequest; private invokePlain; private invokeStreaming; private handleSseFrame; private ensureOpen; private errorFromPayload; private errorFromResponse; }