/** * @file * * Node-side "kick off, then poll" helper over {@link evalInObsidian}. * * A single `evalInObsidian` closure cannot run longer than the transport's * per-eval cap — `DEFAULT_EVAL_CAP_IN_MILLISECONDS` (30s) on both, one shared * declared number rather than an inherited one: desktop enforces it as * `commandTimeoutInMilliseconds`, Android as `scriptTimeoutInMilliseconds`, * which it also sends as its W3C `timeouts.script` capability. Either * way an overrun is reported as `EvalCapExceededError`, which names the * cap and points here. So a long-running in-Obsidian operation (e.g. a whole * plugin/vault bootstrap) cannot be awaited inside one closure. This helper does * it from Node instead: it optionally runs a short `start` closure once to kick * the work off, then repeatedly runs a short `poll` closure — each a separate, * well-under-30s eval — until the Node-side `until` predicate accepts a poll * result, or a Node-side timeout elapses. It removes the per-test hand-rolled * `evalInObsidian` + `sleep` loop. * * The timing loop lives in the pure, unit-tested {@link pollUntil}; this module is * the integration-only wiring (it drives a live Obsidian), covered by an * integration test. */ import type { Promisable } from 'type-fest'; import type { ContextArguments } from './context-id.cjs'; import type { CommonArguments, GenericObject } from './eval-in-obsidian.cjs'; import type { ObsidianTransport } from './transport.cjs'; import { ContextId } from './context-id.cjs'; /** * Parameters for {@link pollInObsidian}. Mirrors {@link EvalInObsidianParams} for * the shared forwarded fields (`input` / `contextId` / `transport` / `vaultPath`); * `start` / `poll` are the in-Obsidian closures and `until` is the Node-side * acceptance predicate. */ export interface PollInObsidianParams | undefined = undefined> { /** * A {@link ContextId} shared by `start` and `poll`, so `start` can stash * non-serializable state that `poll` later reads. When omitted, each closure * gets a fresh empty `context`. */ readonly contextId?: TContextId; /** * Additional arguments passed to both `start` and `poll` (serialized like * {@link EvalInObsidianParams.input}). */ readonly input?: Input; /** * Delay between `poll` attempts, in milliseconds. * * @default `500` */ readonly intervalInMilliseconds?: number; /** * The closure polled repeatedly inside Obsidian. Keep it short (well under the * ~30s CDP cap): it should read and return a JSON-serializable status, not * await the long operation itself. */ readonly poll: (this: void, input: CommonArguments & ContextArguments & Input) => Promisable; /** * An optional closure run **once** before polling begins, to kick off the * long-running work (fire-and-forget from Node's perspective). Keep it short — * start the work and return; do not await it to completion here. */ readonly start?: (this: void, input: CommonArguments & ContextArguments & Input) => Promisable; /** * Total budget before the poll rejects, in milliseconds. * * @default `120000` */ readonly timeoutInMilliseconds?: number; /** * Optional detail appended to the timeout error message. */ readonly timeoutMessage?: string; /** * Override the transport (forwarded to every underlying `evalInObsidian`). */ readonly transport?: ObsidianTransport; /** * Whether a given `poll` result is acceptable, evaluated in **Node**. Returning * `true` resolves {@link pollInObsidian} with that result. */ readonly until: (this: void, result: PollResult) => boolean; /** * The vault path to evaluate against (forwarded to every underlying * `evalInObsidian`). */ readonly vaultPath?: string; } /** * Kicks off an optional `start` closure once, then polls `poll` from Node until * `until` accepts a result or the timeout elapses. * * @param params - The poll parameters. * @returns A {@link Promise} that resolves with the first accepted `poll` result. */ export declare function pollInObsidian | undefined = undefined>(params: PollInObsidianParams): Promise;