/** * `rooms` namespace — agent-messaging coordination rooms (gateway * `agent-messaging`): session-grained presence, room-visible addressed * messages with cursored reads, and TTL-expiring advisory claims, for 2+ * agents working the same product. * * Rooms are ORG-scoped and auto-vivify on first use — there is no create * call. A room key equal to a project id is that project's DEFAULT room: * {@link Rooms.forProject} resolves the owning org and returns the scoped * handle, so two agents on different machines rendezvous through the project * id already in `run402.config.json`, zero configuration. Free-form room * keys name org rooms for multi-repo products. * * Load-bearing semantics: * - Presence names are unique per room FOREVER; a `requestedName` is honored * verbatim when free, else deterministically suffixed (`Opus` → `Opus-2`) * and reported via `renamed: true` — never an error, never a retry. * - Messages are room-visible; `to`/`cc` routes attention, not access. * - Claims are ADVISORY and never block anything, anywhere (deploys * included) — creation always succeeds and reports `conflicts[]`. * - Message cursors are opaque (`mcr_…`): store and echo, never parse. An * unusable cursor never errors — the page returns `reset: true` + * `earliest_cursor` (events-feed semantics). * * Writes (presence registration, sends, acks, claims) need a * principal-backed credential — SIWX, control-plane session, or a * `run402_agent_key` delegate; a project service_key is read-only in its own * default room. Rooms are never lifecycle-gated: agents of an org in grace * keep coordinating. */ import type { Client } from "../kernel.js"; import type { AckRoomMessageOptions, CreatedRoomClaim, CreateRoomClaimInput, ListPresencesOptions, ListRoomClaimsOptions, ListRoomMessagesOptions, PresenceRegistration, RegisterPresenceOptions, RoomAckResult, RoomClaimList, RoomClaimReleaseResult, RoomInviteJoinResult, RoomInviteMintOptions, RoomInviteMintResult, RoomMessage, RoomLeaveResult, RoomList, RoomMessagePage, RoomMessageWaitResult, RoomPresence, RoomPresenceList, RoomSummary, SendRoomMessageInput, SentRoomMessage, WaitForRoomMessagesOptions } from "./rooms.types.js"; export declare class Rooms { private readonly client; constructor(client: Client); /** * Rooms this credential can reach (`GET /orgs/v1/:org_id/rooms`), newest * activity first — the answer to "I have an org id, where do I go". * * Enumeration is DERIVED from use: a key nobody has written under is not a * room and is not listed. What comes back is exactly what per-room * authorization would admit one at a time — a member sees the org's rooms, * a delegate or grant-holder sees the named rooms plus the default rooms of * the projects it reaches (never a sibling project's), and a project * service_key sees only its own. */ list(orgId: string): Promise; /** * Look at one room WITHOUT joining it * (`GET /orgs/v1/:org_id/rooms/:room_key`) — is anyone here, and when did * anything last happen. {@link Rooms.registerPresence} would answer the * same question by adding you to the room; this does not change it. * * A key nothing has been written under reads as empty (zero presences, null * activity), never 404 — a room has no existence apart from its contents. */ get(orgId: string, roomKey: string): Promise; /** * Give up your seat * (`DELETE /orgs/v1/:org_id/rooms/:room_key/presences/:presence_id`) — the * session is done, so it should stop reading as live and stop holding its * claims, rather than lingering for the rest of its ~1h TTL. * * Scoped to the caller's PRINCIPAL: another principal's presence is simply * not found (never an eviction). Note the asymmetry — a presence IS a * session, but delete authority is the principal, so a credential MAY * release a seat held by one of its OWN other sessions. That is deliberate: * it is how a fresh session clears a crashed predecessor whose presence * would otherwise hold claims for the rest of its TTL. * * Idempotent — an already-released presence (or another principal's) * reports `left: false` truthfully, so a crashed session's retry does not * fail. */ leave(orgId: string, roomKey: string, presenceId: string): Promise; /** * Register a session presence in a room * (`POST /orgs/v1/:org_id/rooms/:room_key/presences`). Each call is a NEW * presence with a new room-unique name — pass the returned `presence_id` on * every later call to keep speaking as the SAME session (the server never * infers a session from the credential). `opts.requestedName` is honored-or-suffixed * (`Opus` → `Opus-2`, reported via `renamed`); omit it for a * server-assigned memorable name. Expiry after ~1h of silence; any * coordination call bumps liveness. */ registerPresence(orgId: string, roomKey: string, opts?: RegisterPresenceOptions): Promise; /** * List a room's live presences * (`GET /orgs/v1/:org_id/rooms/:room_key/presences`) — who else is here, * what they're working on, and their `active_claims` counts. * `opts.includeExpired` adds history; `opts.name` is an exact-name lookup. */ listPresences(orgId: string, roomKey: string, opts?: ListPresencesOptions): Promise; /** * Read one presence * (`GET /orgs/v1/:org_id/rooms/:room_key/presences/:presence_id`). */ getPresence(orgId: string, roomKey: string, presenceId: string): Promise; /** * Send a room-visible message * (`POST /orgs/v1/:org_id/rooms/:room_key/messages`). `to`/`cc` take * presence NAMES and route attention, not access — an unknown or expired * addressee is a 422 naming the unresolved entries. Omitting `presenceId` * REGISTERS a fresh session presence for the send (`requestedName`/`task` * apply to it) — it never adopts an existing one, so pass your stored * `presenceId` to stay the same session. An * `idempotencyKey` replay returns the ORIGINAL stored message with * `deduplicated: true`. Sends are bounded by the org-pooled * `messages_per_day` quota. */ sendMessage(orgId: string, roomKey: string, input: SendRoomMessageInput): Promise; /** * Read a page of room messages * (`GET /orgs/v1/:org_id/rooms/:room_key/messages`) — events-feed cursor * semantics: ascending catch-up via `cursor`, or newest-first display via * `order: "desc"` + `before`. List items carry `body_snippet` only; fetch * the full body with {@link getMessage} (the view truncates, the data * never does). Ascending reads with a resolved presence advance its read * watermark (what `unread: true` filters against). */ listMessages(orgId: string, roomKey: string, opts?: ListRoomMessagesOptions): Promise; /** * Block until at least one matching message lands, or the timeout elapses * (kygit-invite design D6/D7) — the agent's ear. Uses the gateway's held * read (`wait=` on the ascending message read) when it is * observed to hold (a page carrying `waited_ms`), and degrades to * client-side polling at `opts.pollMs` (default 5000ms) the instant a * page comes back WITHOUT `waited_ms` — an older gateway that ignored the * parameter. Decided by evidence on every read, not by a version check, * so a single call is safe against either gateway. * * Silence is an answer: on timeout this RETURNS the last observed * (empty) page with `settled: false`, never throws — the same contract as * the shared `waitFor` helper. `live_presences` comes from the last * page's own rider when the gateway held; otherwise it is fetched once at * the end, best-effort (empty on any failure). */ waitForMessages(orgId: string, roomKey: string, opts?: WaitForRoomMessagesOptions): Promise; /** * Read one message with its full body and per-recipient ack state * (`GET /orgs/v1/:org_id/rooms/:room_key/messages/:message_id`). */ getMessage(orgId: string, roomKey: string, messageId: string): Promise; /** * Acknowledge a message addressed to you * (`POST /orgs/v1/:org_id/rooms/:room_key/messages/:message_id/ack`). * Recipients only (422 otherwise). Idempotent — a replay reports the * ORIGINAL `acked_at` with `already_acked: true`. */ ackMessage(orgId: string, roomKey: string, messageId: string, opts?: AckRoomMessageOptions): Promise; /** * Create an advisory claim * (`POST /orgs/v1/:org_id/rooms/:room_key/claims`). GRANT-AND-REPORT: the * 201 always succeeds and returns the complete `conflicts[]` — a claim * never blocks anything, anywhere (deploys included). Auto-expires * (`ttlSeconds` default 3600, max 86400); at most 32 active claims per * presence. Omitting `presenceId` registers a fresh session presence for the * claim — pass your stored `presenceId` to attribute it to this session. */ createClaim(orgId: string, roomKey: string, input: CreateRoomClaimInput): Promise; /** * List a room's active claims * (`GET /orgs/v1/:org_id/rooms/:room_key/claims`). * `opts.includeInactive` adds released/expired history (with * `released_at`). */ listClaims(orgId: string, roomKey: string, opts?: ListRoomClaimsOptions): Promise; /** * Release your own claim * (`DELETE /orgs/v1/:org_id/rooms/:room_key/claims/:claim_id`). Holder's * credential only. Idempotent — an already-released claim returns * `already_released: true` with the original time. */ releaseClaim(orgId: string, roomKey: string, claimId: string): Promise; /** * Mint a Room Invite Key from the room the caller stands in * (`POST /orgs/v1/:org_id/rooms/:room_key/invites`) — a single-use bearer * key (`kri1_…`) whose claimant becomes a permanent `viewer` of the org, * the narrowest membership that can message (design D4: never `--role`, * never wider, never auto-admitted as a vault writer). Requires * `developer`+ (session, wallet, or admin credential — a delegate is * refused, since a room invite confers org membership). * * `invite_id` and `master_secret` are generated LOCALLY (design D3): the * gateway never sees `master_secret`, only the SHA-256 `auth_hash` this * call derives and sends. The assembled key is returned exactly ONCE — * nothing here or downstream persists it. */ invite(orgId: string, roomKey: string, opts?: RoomInviteMintOptions): Promise; /** * Claim a Room Invite Key (`POST /rooms/v1/invites/:invite_id/claim`) — * parses the key CLIENT-SIDE first, refusing a `kgh1_`/`kgi1_` vault key * BY NAME (pointing at `run402 repos resume`/`run402 repos join`) before * any network call (design D3). The claim is an x402-PAID resource (the * `room_seat` SKU, testnet only): the VERIFIED PAYER of that payment * becomes the claimant, so this call is sent through the client's paid * fetch WITHOUT a bearer credential (`withAuth: false`) — no * `SIGN-IN-WITH-X` header, and any cached control-plane session is * deliberately not attached, exactly matching the gateway's own * `403 ROOM_INVITE_CLAIM_REQUIRES_WALLET` refusal for a bearer-credentialed * request at this route. A same-payer replay never pays twice * (`deduplicated: true`, no second charge). */ join(key: string): Promise; /** * Return a room-scoped sub-client with `(orgId, roomKey)` pre-bound. * Synchronous — both ids are explicit. For a project's default room * without knowing the org, use {@link forProject}. */ scoped(orgId: string, roomKey: string): ScopedRoom; /** * Resolve a project's DEFAULT room (`GET /projects/v1/:project_id` for the * owning `org_id`, then {@link scoped}). The default room's key IS the * project id verbatim — this is the zero-config rendezvous: two agents * holding the same `run402.config.json` land in the same room with no * shared setup. */ forProject(projectId: string): Promise; } /** * Terminal room-invite claim refusals the gateway's own x402 paywall NEVER * settles for (design D5 — the paywall buffers and settles only on a * sub-400 response, so any of these five codes means no payment ever * completed, refunded or otherwise). Live-proof defect B: without this, a * spent/expired/revoked key, or a bearer credential presented to the claim * route, surfaced as a generic `X402_PAYMENT_OUTCOME_AMBIGUOUS` — alarming * and wrong, since the gateway had already answered with one of these and * moved no funds. `node/paid-fetch.ts`'s default paid fetch recognizes a * response carrying one of these codes, FROM this SDK's own configured API * origin, as `"failed"` rather than `"ambiguous"` — letting the gateway's * own typed envelope (not a synthesized payment-attempt error) reach the * caller. Scoped by CODE, never by route: an arbitrary third-party paid URL * — even one that echoes one of these exact strings — is never treated as * this SDK's own origin, so its non-2xx after dispatch stays genuinely * ambiguous, unchanged. */ export declare const ROOM_INVITE_TERMINAL_REFUSAL_CODES: ReadonlySet; /** True when `envelope.code` is one of {@link ROOM_INVITE_TERMINAL_REFUSAL_CODES}. */ export declare function isTerminalRoomInviteRefusal(envelope: Record | null | undefined): boolean; /** * A room-scoped sub-client returned by {@link Rooms.scoped} / * {@link Rooms.forProject}. The `(orgId, roomKey)` pair is bound at * construction; instance operations drop both leading arguments. */ export declare class ScopedRoom { private readonly rooms; /** The org id this sub-client is bound to. Read-only. */ readonly orgId: string; /** The room key this sub-client is bound to (a project id for a default room). Read-only. */ readonly roomKey: string; constructor(rooms: Rooms, orgId: string, roomKey: string); /** See {@link Rooms.get}. */ get(): Promise; /** See {@link Rooms.leave}. */ leave(presenceId: string): Promise; /** See {@link Rooms.registerPresence}. */ registerPresence(opts?: RegisterPresenceOptions): Promise; /** See {@link Rooms.listPresences}. */ listPresences(opts?: ListPresencesOptions): Promise; /** See {@link Rooms.getPresence}. */ getPresence(presenceId: string): Promise; /** See {@link Rooms.sendMessage}. */ sendMessage(input: SendRoomMessageInput): Promise; /** See {@link Rooms.listMessages}. */ listMessages(opts?: ListRoomMessagesOptions): Promise; /** See {@link Rooms.getMessage}. */ getMessage(messageId: string): Promise; /** See {@link Rooms.waitForMessages}. */ waitForMessages(opts?: WaitForRoomMessagesOptions): Promise; /** See {@link Rooms.ackMessage}. */ ackMessage(messageId: string, opts?: AckRoomMessageOptions): Promise; /** See {@link Rooms.createClaim}. */ createClaim(input: CreateRoomClaimInput): Promise; /** See {@link Rooms.listClaims}. */ listClaims(opts?: ListRoomClaimsOptions): Promise; /** See {@link Rooms.releaseClaim}. */ releaseClaim(claimId: string): Promise; /** See {@link Rooms.invite} — pre-bound to this room. */ invite(opts?: RoomInviteMintOptions): Promise; } //# sourceMappingURL=rooms.d.ts.map