import { type NatsConnection } from "@nats-io/transport-node"; import { type CompiledContract } from "./schema-profile.js"; import { type EpCaller } from "./endpoint-subjects.js"; import type { EpVerbTarget, EpAttributedReply, EpScatterResult, EpInstanceLiveness } from "./endpoint-verbs.js"; /** A resolved command contract: the compiled input/output validators (recompiled from the store, * digest-verified against the registered declaration) plus the command's §13.2 admission facts. */ export interface ResolvedCommand { command: string; contract: { input: CompiledContract; output: CompiledContract; }; class: string; targeted: boolean; modes: readonly string[]; capability: string; } /** An endpoint's resolved invocation surface: every command the caller may see, with recompiled * digest-verified contracts. Built from a fresh `describe` + store fetch. Carries the `caller` * triple the describe ran as, so {@link invokeCommand} reuses the same authenticated identity, * and the ANSWERING incarnation's identity off the describe reply SUBJECT (broker-authenticated: * the §13.9 serve publish row pins `instanceId`+`epoch`, a responder cannot stamp another's) - * {@link invokeCommand}'s default currency check binds the invoke to this incarnation. */ export interface ResolvedService { endpoint: string; owner: string; caller: EpCaller; responder: { instanceId: string; epoch: number; }; commands: Map; /** Set when the service was resolved PINNED to one instance's `inst` route (P2 item 3 `--on`): * {@link invokeCommand} then routes commands to that exact instance, never the class `one` queue, * so a multi-manager space can be addressed per-instance. Absent ⇒ class anycast (the default). */ pinnedInstanceId?: string; } /** * The reserved `describe` command as a raw request/reply (§13.7: describe pins NO contract, so it * carries no `op` digests — {@link epCall} always stamps digests and the serve boundary rejects a * digest-bearing describe as `contract-mismatch`, so this is a purpose-built raw path). It * REQUEST-BINDS its reply exactly as {@link epCall}'s `parseAttributedReply` does (§13.2): the * responder grant `epResponderReplyPattern` spans EVERY caller suffix, so any live responder can * publish on the caller's rail at any nonce — acceptance therefore checks the reply SUBJECT's * endpoint + nonce AND the body's echoed request id, not just "first `{ok:true}` on the rail". * A reply that fails any of these is IGNORED (not rejected: an attacker racing a wrong-nonce reply * must not be able to fail an honest describe), and the wait continues to the deadline. */ export declare function describeEndpoint(nc: NatsConnection, space: string, endpoint: string, caller: EpCaller, opts?: { deadlineMs?: number; instanceId?: string; }): Promise<{ answer: DescribeAnswer; responder: { instanceId: string; epoch: number; }; }>; /** The describe answer shape a caller reads (a subset — the fields the resolver needs). */ interface DescribeAnswer { public: boolean; descriptor: { endpoint: string; owner: string; clusters: { digest: string; commands: string[]; }[]; }; } /** * DESCRIBE an endpoint and resolve its full invocation surface: send the reserved `describe` * command (untargeted, void args), then for every VISIBLE cluster fetch + verify its document * from the store and recompile each command's input/output contracts. The result lets a caller * invoke any visible command by name with no compile-time knowledge of the endpoint's schemas. * * `describe` itself pins no contract (§13.7), so it is issued as a raw void-arg request * ({@link describeEndpoint}), never through the digest-stamping {@link epCall}. */ export declare function resolveService(nc: NatsConnection, space: string, endpoint: string, caller: EpCaller, opts?: { deadlineMs?: number; instanceId?: string; }): Promise; /** * INVOKE one named command on a resolved service: validate nothing here (the compiled input * contract in {@link epCall}'s request builder gates args before publish, and the responder's * digest-bound boundary re-validates), route on the `one` rail, return the attributed reply. A * command absent from the resolved surface is `not-found` (the caller cannot see it, or it does * not exist); a targeted command needs its `target`. * * Currency: `opts.currentEpoch` (e.g. the registry-read `serviceEpochReader`) when supplied; * otherwise the DESCRIBE-BOUND default - accept exactly the incarnation that answered this * service's resolve (its broker-authenticated `instanceId`+`epoch` off the describe reply * subject) and refuse `failed-precondition` when a DIFFERENT instance wins the `one` queue * (a superseded-or-split responder; re-resolve to adopt a legitimate successor). The bind needs * no registry read grant, and it is strictly stronger than no check: two live instances of a * single-instance endpoint can never both pass one resolved handle. */ export declare function invokeCommand(nc: NatsConnection, space: string, service: ResolvedService, command: string, args: Record | undefined, opts: { target?: EpVerbTarget; deadlineMs?: number; currentEpoch?: (instanceId: string) => Promise | number; /** A caller-pinned envelope id (see {@link EpVerbOp.id}): a goal-accepting command binds its * goal under it, which is what lets a durable caller resubmit idempotently. */ id?: string; }): Promise; /** Submit an ACTION command and FOLLOW its goal to the terminal (P2 item 2, 2b): since 2a a * spawn/launch reply is the ACCEPTANCE (returned before the agent is live), so a consumer that * wants the old block-until-outcome behaviour follows the caller-scoped progress subtree to the * terminal here. The subscription opens BEFORE `submit` runs (a fast join could terminalize within * milliseconds of the acceptance), buffering terminals by goalId. The reply is then RESOLVED from * the terminal: `succeeded` → the terminal's data (today's live reply — name/id/role/agent/mode/ * lifecycleUid), `failed`/`uncertain`/`cancelled` → a non-ok reply carrying the cause. A reply with * NO goalId (a refuse-at-accept, or a non-action command) passes through unchanged. UX is preserved: * the call still returns on the real outcome. The caller needs the per-goal progress read row * ({@link epGoalProgressGrantRow}) — minted with any goal-bearing capability. */ export declare function submitAndFollowGoal(nc: NatsConnection, space: string, endpoint: string, caller: EpCaller, deadlineMs: number, submit: () => Promise): Promise; /** * SCATTER one untargeted command to the LIVE class (§13.5): resolve the command's contract off the * same digest-verified surface {@link invokeCommand} uses, then run the registry-wired scatter — * freeze the expected set from the records registry, publish ONCE on the `all` rail, gather one * attributed reply per instance, and reconcile registration currency post-classification. The * returned `replies` map is keyed by instanceId (per-instance attribution, SPEC §13.5); a frozen * instance that produced no on-time reply is a `missing` slot — reported UNREACHABLE, never silently * omitted. The caller's connection carries the §13.9 records-read grant the freeze/reconcile ride (a * scoped read of the endpoint's `svc` registry); `jsm`/`kv` are opened over it here. * * A scatter addresses EVERY instance, so a targeted command is refused (a per-instance target is * incoherent with the `all` rail) and a handle PINNED to one instance is refused (a pin is the * anti-scatter — use {@link invokeCommand} for `--on`). "No args" marshals to the contract's * canonical empty form exactly as {@link invokeCommand}. */ export declare function scatterCommand(nc: NatsConnection, space: string, service: ResolvedService, command: string, args: Record | undefined, opts: { deadlineMs: number; reconcileDeadlineMs?: number; lateDrainMs?: number; /** Forwarded verbatim to {@link epScatterService} (§13.5 liveness). The caller owns it because * the caller owns the grant: a probe publishes on an instance rail, and only the credential's * minter knows which instance rails it carries. */ probeLiveness?: (instanceId: string) => Promise; }): Promise; /** A digest reference's bare hex, exported so a CLI can print the resolved surface's digests. */ export declare function contractDigestHexOf(value: unknown): string; export {}; //# sourceMappingURL=endpoint-invoke.d.ts.map