UNPKG

eve

Version:

Filesystem-first framework for durable backend AI agents that run anywhere.

162 lines 6.64 kB
import { type Hook as WorldHook } from '#compiled/@workflow/world/index.js'; import { type PayloadKey } from '../serialization.js'; /** * A hook record with its serialized `metadata` omitted: everything a resume * actually reads. Resuming never looks at metadata, so the resume path accepts * both a raw {@link WorldHook} straight out of a World and a {@link Hook} * whose `metadata` is a Promise. */ type ResumableHook = Omit<WorldHook, 'metadata'>; /** * A hook as returned by {@link getHookByToken} and {@link resumeHook}: the * World's {@link WorldHook} record with its user-defined `metadata` hydrated * lazily. * * `metadata` is a getter that returns a Promise — the same shape as * `Run.returnValue` — so looking a hook up by token costs exactly one read. * Hydrating metadata is a decrypting READ that needs the owning run's payload * keys, and resolving those can cost a run fetch plus a `run-key` API round * trip (~350ms). Deferring that to first access keeps the lookup fast for the * many callers that only need `runId`/`token` — most importantly hook * resumption, which never reads metadata at all. * * The promise is memoized: hydration (and the key resolution behind it) runs at * most once per hook object. Awaiting it on a hook that stored no metadata * resolves `undefined` and performs no I/O. * * Like `Run.returnValue`, the accessor is non-enumerable, so it is absent from * `{ ...hook }` and `JSON.stringify(hook)` — read it explicitly and include the * awaited value if you need to forward it. * * @example * * ```ts * const hook = await getHookByToken(token); * console.log(hook.runId); // no metadata work * const metadata = (await hook.metadata) as { allowedUserId?: string } | undefined; * ``` */ export interface Hook extends ResumableHook { /** * The hook's user-defined metadata, hydrated on first access and memoized. * Resolves `undefined` when the hook carries no metadata. */ readonly metadata: Promise<unknown>; } /** * Get the hook by token to find the associated workflow run. * * This is a single read. The returned hook's `metadata` is a getter that * resolves a Promise (see {@link Hook}), so the run fetch and * `run-key` round trip that hydrating it can require are only paid by callers * that actually await it: * * ```ts * const hook = await getHookByToken(token); * const metadata = await hook.metadata; * ``` * * A Hook kept by minimum retention remains available here after its run ends, * but cannot be resumed. * * @param token - The unique token identifying the hook */ export declare function getHookByToken(token: string): Promise<Hook>; /** * The result of {@link resumeHook}: a {@link Hook} augmented * with an optional resilience signal. * * `resilientResume` is retained for source compatibility and is never set. * `resumeHook()` now requires the durable `hook_received` write and workflow * wake to both succeed before it resolves. Treat the result as a plain * {@link Hook}. */ export type ResumedHook = Hook & { resilientResume?: boolean; }; /** * Resumes a workflow run by sending a payload to a hook identified by its token. * * This function is called externally (e.g., from an API route or server action) * to send data to a hook and resume the associated workflow run. * * On an invoke-capable World, the serialized input is delivered to the run's * executor, which inspects it, writes `hook_received`, then responds. Resolving * means the executor accepted and persisted it, not that user code consumed it. * Other Worlds write the event here and then await queue acceptance of its wake. * On the existing path, a failure after the event write may leave a committed * event whose wake was not accepted. On the invoke path, a transport failure * leaves the executor's outcome unknown; do not retry by directly writing an * event. Event and response persistence may be separate backend operations. * * Prefer passing the token string over a cached {@link Hook} object. A token * is looked up fresh, so the live backend can attest its atomic resume claim * and the durable write becomes idempotent-on-retry (transport retries of the * same write converge on one event). A supplied Hook object may carry a stale * attestation, so it is deliberately ignored and the write is claim-less — * meaning a lost response cannot be retried safely: retrying at the * application level mints a fresh claim and can commit a second * `hook_received`. * * @param tokenOrHook - The unique token identifying the hook, or the hook object itself * @param payload - The data payload to send to the hook * @returns Promise resolving to the {@link ResumedHook} * @throws {HookNotFoundError} If the Hook does not exist or its run has ended * * @example * * ```ts * // In an API route * import { resumeHook } from '@workflow/core/runtime'; * * export async function POST(request: Request) { * const { token, data } = await request.json(); * * try { * const hook = await resumeHook(token, data); * return Response.json({ runId: hook.runId }); * } catch (error) { * return new Response('Hook not found', { status: 404 }); * } * } * ``` */ export declare function resumeHook<T = any>(tokenOrHook: string | ResumableHook, payload: T, encryptionKeyOverride?: PayloadKey): Promise<ResumedHook>; /** * Resumes a webhook by sending a {@link https://developer.mozilla.org/en-US/docs/Web/API/Request | Request} * object to a hook identified by its token. * * This function is called externally (e.g., from an API route or server action) * to send a request to a webhook and resume the associated workflow run. * * @param token - The unique token identifying the hook * @param request - The request to send to the hook * @returns Promise resolving to the response * @throws Error if the hook is not found or if there's an error during the process * * @example * * ```ts * // In an API route * import { resumeWebhook } from '@workflow/core/runtime'; * * export async function POST(request: Request) { * const url = new URL(request.url); * const token = url.searchParams.get('token'); * * if (!token) { * return new Response('Missing token', { status: 400 }); * } * * try { * const response = await resumeWebhook(token, request); * return response; * } catch (error) { * return new Response('Webhook not found', { status: 404 }); * } * } * ``` */ export declare function resumeWebhook(token: string, request: Request): Promise<Response>; export {}; //# sourceMappingURL=resume-hook.d.ts.map