import type { BrokerTransport } from "./broker-tls.js"; import { type DeprovisionTarget } from "./subjects.js"; import { type EpCapability } from "./endpoint-grants.js"; import { type EpServeGrant, type EpIssuanceGate } from "./endpoint-service.js"; import { type IssuanceSeam } from "./issued-authority.js"; import { type RunDriverGrantArgs, type RunOperatorGrantArgs } from "./run-driver-grants.js"; import { type Identity } from "./identity.js"; import { type BackupPermissionScope, type RestorePermissionScope } from "./backup.js"; /** Cred profiles. Each profile has an explicit permission arm and a D5 lifetime classification. */ export type Profile = "agent" | "observer" | "admin" | "supervisor" | "provisioner" | "deprovisioner" | "retirement-requester" | "lifecycle-executor" | "endpoint-serve-executor" | "operator" | "purger" | "backup" | "restore" | "delivery" | "membership-rw" | "probe" | "channel-writer" | "channel-purger" | "teardown" | "control-caller-privileged" | "control-caller-admin" | "deployer" | "endpoint-serve" | "goal-writer" | "session-caller" | "session-serving" | "session-ledger" | "run-driver" | "run-mediator" | "run-operator" | "endpoint-evictor" | "issuer" | "run-admitter" | "remote-manager"; export type CredentialLifetimeClass = "standing-renewable" | "rotation-renewed" | "one-shot" | "static-operator-managed" | "mixed"; export type CredentialKind = Profile | "membership-observer" | "connection-evictor"; export interface CredentialLifetimePolicy { class: CredentialLifetimeClass; /** Default max age for profiles safe to expire before the renewal slice. Undefined = no default exp yet. */ defaultTtlSeconds?: number; renewalOwner?: string; note: string; } /** Bounded lifetime for `standing-renewable` credentials whose renewal owner is ONLINE (D5 slice 5): * the holder (or its launcher) re-mints at 75% of the lifetime via the endpoint's creds-source seam, * so a copied cred is broker-dead within a day while renewal never involves an operator. 24h keeps * the remaining-25% loud-failure window at ~6h — wide enough to notice and repair before expiry. */ export declare const STANDING_RENEWABLE_TTL_SEC: number; /** Bounded lifetime for the `rotation-renewed` $SYS credentials (membership-observer + connection- * evictor). They are NOT online-renewable (the $SYS seed dies at end of `up`), so this exp is the * credential-death horizon: a copied observer/evictor cred becomes broker-dead after it, and the * operator is expected to have run a coordinated system-account rotation + broker restart within it * (the doctor surface warns ahead — slice 6). 30 days balances "copied cred eventually dies" against * a comfortable monthly rotation cadence; tune here as one named knob. */ export declare const ROTATION_RENEWED_TTL_SEC: number; /** D5 profile matrix. This is intentionally centralized so every new mint profile must classify its * credential-death behavior instead of silently inheriting non-expiring static creds. */ export declare const CREDENTIAL_LIFETIMES: Record; export declare function credentialLifetime(kind: CredentialKind): CredentialLifetimePolicy; /** A local credential file's health, by the SAME convention the renewal seam runs on: renewal is due * at 75% of the iat→exp lifetime, so `near-expiry` means "past the point where a healthy renewal * owner would already have re-signed this" — the doctor's yellow. `unreadable` (not a throw) is for * a corrupt/spliced file: the doctor must render it red with a repair, not crash the diagnosis. */ export type CredHealthState = "healthy" | "near-expiry" | "expired" | "unbounded" | "unreadable"; export interface CredHealth { state: CredHealthState; /** Issue time (epoch sec) — the "last renewal" timestamp for reminted creds. */ iat?: number; exp?: number; /** The 75%-of-lifetime renewal point (epoch sec); past it = near-expiry. */ renewAt?: number; /** Present only for `unreadable`. */ error?: string; } export declare function inspectCredHealth(creds: string, nowSec?: number): CredHealth; /** BROKER-level trust: the operator root and the system account. A nats-server trusts exactly ONE * operator and one system account, so this is the per-BROKER authority, not a per-space one. With * many spaces on one broker (W4) every space's accounts are signed by this one operator. * * `sys.signingSeed` is minting capability for system-account users (the membership observer and the * connection evictor). It is in-memory only on a fresh {@link createBrokerAuth} and is NOT written * by the local filesystem persistence, so on that path a space added after first boot cannot mint * its `$SYS` users. A hosted composition that needs incremental space provisioning must hold this * seed in a BROKER-scoped secret store (never a tenant-scoped one, which would give each tenant its * own operator or duplicate the seed and so recreate multiple owners). */ export interface BrokerAuth { operator: { seed: string; jwt: string; }; sys: { pub: string; jwt: string; signingSeed?: string; }; /** Monotonic generation of the system-account authority. {@link rotateSystemAccount} bumps it * IN MEMORY (each rotation is the next generation of the value it derived from); persistence * (`saveBrokerAuth`) then only accepts a sys-changing write that is the DIRECT successor of the * current record, refusing anything else as stale. Absent = 0 (in-memory creates and * pre-generation records). The JWT `iat` cannot carry this ordering — it is second-resolution, * so two generations minted within one second are unordered by it. */ gen?: number; } /** SPACE-level trust: one space's data account, signed by its broker's operator. This is the only * part of a space's trust material a space actually OWNS; broker trust is referenced, never owned * (a per-space restore or rotation must not be able to move the broker's root). The `signingSeed` * is the sensitive provisioner secret that mints this account's users. */ export interface SpaceAccountAuth { space: string; account: { pub: string; seed: string; jwt: string; signingSeed: string; signingPub: string; }; } /** The COMPOSED read view of one space's full trust chain: broker authority plus that space's * account. Deliberately structurally identical to the pre-W4 single-space shape, so the many * existing readers compose rather than churn. * * This is a read adapter, never a persistence authority: it is produced by loading the two * persisted records and validating their binding. Writing a composed value back as one document * would let a mutation made through space A resurrect a stale broker copy when space B next loads * it, which is exactly the ownership bug the split exists to prevent. */ export interface SpaceAuth extends BrokerAuth, SpaceAccountAuth { } /** Compose the read view from its two persisted authorities. Fails loud when the space account was * not signed by THIS broker's operator: a self-consistent account signed by a FOREIGN operator is * perfectly valid on its own and would otherwise be rendered into the resolver as untrusted trust. */ export declare function composeSpaceAuth(broker: BrokerAuth, spaceAccount: SpaceAccountAuth): SpaceAuth; /** The binding check behind {@link composeSpaceAuth} and registry admission: this space's data * account JWT must be issued by this broker's operator identity. */ export declare function assertAccountSignedByBroker(broker: BrokerAuth, spaceAccount: SpaceAccountAuth): void; /** Reduce a {@link SpaceAuth} to just the material a *minting* host needs: `space`, * `account.pub`, and `account.signingSeed` (the only fields {@link mintCreds} reads). * The operator root-of-trust, system account, and the account's own seed are blanked. * * This is the file you hand a manager that should mint per-agent creds but must never * hold the operator key — e.g. a containerized team. A leaked stripped file only lets * someone mint *users within this one account*, which the account boundary already * contains; it cannot mint new accounts or touch the system account. */ export declare function stripSpaceAuth(auth: SpaceAuth): SpaceAuth; /** Rotate the DATA-account signing key and re-issue the data-account JWT so the old data signer is no * longer trusted by the broker once it loads the returned auth. This does NOT rotate the system account: * persisted `membership-observer` creds remain valid until the system-account renewal/rotation slice. */ export declare function rotateDataAccountSigningKey(auth: SpaceAuth): Promise; /** Rotate the SYSTEM account and re-issue the operator JWT so persisted system-account users (currently * `membership-observer`) become broker-dead once the broker loads the returned auth. The fresh * `sys.signingSeed` is intentionally in-memory only; callers must mint replacement observer creds before * persisting via `saveSpaceAuth`, which strips the seed again. */ export declare function rotateSystemAccount(auth: SpaceAuth): Promise; /** Generate a fresh BROKER trust root: operator → system account. One per broker, NOT one per space. * `label` names the operator (cosmetic, but it lands in the operator JWT); multi-space brokers pass * a broker label, and the single-space compatibility path passes the space name so existing * operator names are unchanged. * * The returned `sys.signingSeed` is the ONLY window in which system-account users (the membership * observer and the connection evictor) can be minted, because the local filesystem persistence does * not write it. Callers that need to add spaces later must retain it in a broker-scoped store. */ export declare function createBrokerAuth(label: string): Promise; /** Generate one space's data account (+ signing key), signed by an EXISTING broker operator. This is * the per-tenant half of provisioning: call it once per space against the same {@link BrokerAuth} * to put many spaces on one broker, each in its own NATS account. */ export declare function createSpaceAccountAuth(broker: BrokerAuth, space: string): Promise; /** Generate a fresh operator → account(+signing key) → system-account chain for a space. * The single-space composition of {@link createBrokerAuth} + {@link createSpaceAccountAuth}: one * broker whose only tenant is this space, which is exactly the pre-W4 shape. */ export declare function createSpaceAuth(space: string): Promise; /** Options shaping a minted user's permissions. */ export interface MintOpts { /** The owner+actor principal to mint for. Omitted ⇒ the no-login dev default (owner `"local"`, actor * = the connection id) via {@link principalOf}. User mode supplies the derived owner + ledger actor. */ principal?: { owner: string; actor: string; }; /** Read ACL — channels an "agent" MAY read (the agent file's `allowSubscribe`, already resolved * by the caller). Minted as per-channel single-filter history-consumer create grants * (`CONSUMER.CREATE...`) — the broker boundary on chat **history** * reads (join-backfill / focus-recall). Each is run through the chat-subject builder so a * wildcard subtree `team.>` becomes `chat.*.team.>`. Omitted or empty ⇒ NO channel read rows at * all (the cred carries no chat history grant and no `chat.*.` sub row); DM, presence, * anycast and the control rails are unaffected. The live read is the agent's own native * `sub.allow` over `chat.*.` (also minted from this list, below). */ allowSubscribe?: string[]; /** Post ACL — channels an "agent" may publish to (the agent file's `allowPublish`, already * resolved by the caller). Each becomes a `chat..` publish grant. **Default-deny**: * omitted/empty ⇒ no chat publish grant at all — publishing must be declared. */ allowPublish?: string[]; /** The agent's role — scopes its TASK-queue consumer to svc_. */ role?: string; /** Capabilities declared in the agent file (e.g. `"spawn"`). A capability gates the * privileged control-subject grant in {@link permissionsFor}: `spawn` → the agent may * publish to the privileged control subject (start/purge/definePersona/named stop). * Default-deny when absent — nats-server rejects the publish, no handler involved. */ capabilities?: string[]; /** v0.4 endpoint request capabilities (SPEC §13.9 caller rows): each mints its exact * request-publish rows (+ optional journal-append row) and, when any is present, the * caller's own reply-rail read row. Requires {@link MintOpts.lifecycleUid} — the rows pin * the full caller triple. Default-deny when absent. */ endpointCapabilities?: EpCapability[]; /** The caller's lifecycle UID (SPEC §13.1), minted by the managing authority BEFORE the * entity is reachable. REQUIRED with `endpointCapabilities` — every endpoint-rail row * forge-locks it as the third caller token. */ lifecycleUid?: string; /** v0.4 SERVE identity (SPEC §13.9 serve rows), `endpoint-serve` profile ONLY: mints the * instance's queue-qualified class subscribes (no plain class-rail subscribe exists on any * credential), the plain scatter and own `inst` rails for the FULL registered command set * plus the derived `describe`, the own epoch-pinned timer-fire read, and the epoch-pinned * egress (reply/epe/ept-schedule/epr). MUST be the branded ARTIFACT `authorizeServeGrant` * returned — a raw literal, a structural copy, or a diverging value refuses at the mint, and * the mint context is bound to the artifact (same space; the minted principal IS the * registered owner). The freshness FENCE is the durable issuance gate ({@link serveIssuance} * / SPEC §13.1), not this artifact. Every other profile refuses it (a serve credential is * per-instance, never an agent-baseline cred). The `$JS.API` bind rows (effects/pool * durables) ride the D14 credential assembly, not this subject-space builder. */ endpointServe?: EpServeGrant; /** v0.4 SERVE mint fence (SPEC §13.1), `endpoint-serve` profile ONLY and REQUIRED there: the * durable, single-key issuance gate whose revision-pinned CAS `mintCreds` must WIN to release * the serve credential. Both the takeover and re-registration barriers freeze this same gate, * so a mint racing either loses the CAS and releases nothing. Production wires it to the * credential ledger's endpoint family `epgate..` (the auth * implementation's `kvServeIssuanceGate`); a test provides a faithful CAS fake. */ serveIssuance?: EpIssuanceGate; /** Delivery-daemon shard seam (`delivery` profile only). N=1 is the only operating mode; these do * not change permissions in this build (the daemon owns the whole space at N=1). Present so the * N>1 follow-up is a small diff. Default `{0,1}`. */ shard?: number; shards?: number; /** The departed LIFECYCLE whose footprint a `deprovisioner` cred may tear down: the target's * principal PLUS the exact lifecycle uid being retired (SPEC §13.1). REQUIRED for that profile (it * throws without one): the grants are pinned to exactly this incarnation's * `dm_--`/`dlv_--` durables + `..` ACL row, so a leaked or * REPLAYED deprovisioner cred can delete ONE retired incarnation's footprint and nothing else — * never a peer's, never the role-shared `svc_`, and structurally never a same-alias * successor's (its names carry a different uid). Ignored by every other profile. */ deprovisionTarget?: DeprovisionTarget; /** `retirement-requester` profile only: the REQUESTING CALLER TRIPLE (the current space-manager's * own `owner`/`actor`/`uid`) whose auth-endpoint request subject the credential may publish, and * whose reply rail it may read. The subject IS the attribution: the auth plane's rail derives * the caller principal from the subject the broker admitted, and refuses unless the serve * registration the request names belongs to THAT principal — so a requester cannot be authorized * by another instance's registration. * * The `uid` is why this carries a triple and not the pre-#350 `{owner, actor}` pair: the `ctl` * rail's two-token subject could express only a recyclable alias, while the `ep` caller triple * is `..` and the grant pins all three. Ignored by every other profile. */ retirementRequester?: { owner: string; actor: string; uid: string; /** The ONE incarnation this credential may ask to retire. It rides the SUBJECT as the * `handle` target, so the grant pins it: a leaked requester cannot be re-aimed. */ target: { owner: string; actor: string; lifecycleUid: string; }; }; /** `lifecycle-executor` profile only (Unit B, the static §13.1 executor): the ONE incarnation * whose lifecycle-state keys this credential may write — the head `lifecycle..`, * the reservation `uid.`, the gate `gate.`, the ledger family * `cred..>`, and the manager's durable slot row `mgrslot..`. * REQUIRED for that profile (it throws without one). EVERY key is DERIVED inside the profile * from (owner, actor, lifecycleUid, alias) — none is a caller-supplied literal — so the pin is * coherent by construction and a leaked executor cred can move exactly one incarnation's state * machine and nothing else. Ignored by every other profile. */ lifecycleExecutor?: { owner: string; actor: string; lifecycleUid: string; alias: string; }; /** `endpoint-serve-executor` profile only (P2 item 1, 1a-serve): the ONE endpoint instance whose * endpoint-serve state this credential may write — the endpoint gate `epgate.. * ` (the registration barrier's freeze/reopen CAS + the provisioner create) and the * serving ledger family `epcred...>` (the mint fence's stage + the barrier's * revoke). REQUIRED for that profile. Every key is DERIVED inside the profile from * (endpoint, instanceId) — none is a caller literal — so the manager drives the gate CAS + serve * mint through THIS scoped executor and nothing else (critic #1: the manager-specific "no seed * shortcut"; the standing seed connection never writes the epgate or the epcred family). Ignored * by every other profile. */ endpointServeExecutor?: { endpoint: string; instanceId: string; }; /** `goal-writer` profile only (P2 item 2, spawn-as-action): the endpoint whose action goals this * standing connection may bind + commit ({@link goalWriterGrants}). REQUIRED for that profile; * ignored by every other. */ goalWriter?: { endpoint: string; }; /** `session-caller` profile only (P2 item 6): the ONE §13.6 session whose two eps rails this * credential may use — the serving endpoint, the fresh sessionId, and the serving epoch. REQUIRED * for that profile; ignored by every other. The rows pin all three, so the cred authorizes * exactly that session's `in`+`out` and nothing else. */ sessionCaller?: { endpoint: string; sessionId: string; epoch: number; }; /** `session-serving` profile only (P2 item 6): the ONE §13.6 session this SERVING credential may * serve — same three coordinates as {@link sessionCaller}, with the rail directions swapped. * REQUIRED for that profile; ignored by every other. The `session-ledger` profile takes no pin * at all: it holds no rail, so it has nothing to pin. */ sessionServing?: { endpoint: string; sessionId: string; epoch: number; }; /** `run-driver` profile only (SPEC 14.6): the ONE run this credential drives, the takeover attempt * it is minted for (names the replay durable), and the driving instance's id and epoch (the * coordinates its timer schedules are addressed by). REQUIRED for that profile; ignored by every * other. The ep caller triple is DERIVED from the run id ({@link runDriverCaller}), never supplied. */ runDriver?: RunDriverGrantArgs; /** Trusted host only: the run and takeover whose journal authorizes its effects. */ runMediator?: RunDriverGrantArgs; /** `run-operator` profile only (SPEC 14.3): the ONE endpoint whose runs this credential may read, * the takeover id its journal replays are named by, and, for the answering half of a * `run-answer`, the ONE checkpoint token its answer and settle writes are pinned to. REQUIRED * for that profile; ignored by every other. */ runOperator?: RunOperatorGrantArgs; /** `remote-manager` profile only: the server-derived owner, fixed server-selected actor, and the * ONE locally-selected manager instance id this credential may supervise. REQUIRED for that profile. The builder pins its * manager lease/presence and same-owner provisioning resources; no caller-supplied subject rows * or profile fallback are accepted. */ remoteManager?: { instanceId: string; owner: string; actor: string; }; /** `deployer` profile only: which v0.4 ep instrument set its `launch`/`ps` rows carry. Defaults * to `"admin"` (the static operator's ephemeral deploy cred). The user-mode `deployer` VIEW * mints `"privileged"` instead, so a spawn-scoped deploy reaches the manager where its * owner-equality launch authorization governs — never the admin any-mode reach. Ignored by * every other profile. */ controlTier?: "privileged" | "admin"; /** Override the profile default lifetime. Internal/test hook; command surfaces should prefer the * centralized {@link CREDENTIAL_LIFETIMES} defaults so profile behavior stays auditable. */ expiresInSeconds?: number; /** Absolute JWT `exp` timestamp in seconds. Used by cutover/test code that needs already-expired creds. */ expiresAt?: number; /** Issued authority (SPEC 13.15): mint this credential's ep-rail rows on the VERSIONED rail, * pinned to `generation`, and grant the per-key read of its accepted row. The issuer chose the * generation and persisted its evidence before calling; the client chose `acceptedToken` and * learns the accepted generation by reading that one row after it connects. Taken by the * profiles that hold caller rails (`agent`, the operator instruments); every other profile * refuses it. */ issued?: { generation: string; acceptedToken: string; }; /** The durable half of an issuance, REQUIRED beside {@link MintOpts.issued} on {@link mintCreds}: * the credential is built first, then its evidence is staged create-only, the existing * finalizer runs, and the attempt activates by CAS at the revision the stage observed; only * then is the accepted row written and the material returned (SPEC 13.15). `renew` confirms an * existing generation's ceiling is unchanged and stages nothing. */ issuance?: IssuanceSeam; /** `run-admitter` profile only: the ONE hosted run whose admission record and revocation marker * this connection may create. */ runAdmitter?: { endpoint: string; runId: string; }; /** `backup` profile only: one discriminated inspector or snapshot phase. */ backup?: BackupPermissionScope; /** `restore` profile only: one discriminated initiate, upload, validate, or checkpoint phase. */ restore?: RestorePermissionScope; } /** Options for {@link provisionAgent} — {@link MintOpts} plus the active read set. */ export interface ProvisionOpts extends MintOpts { /** The active read set: the channels the agent subscribes to (live core-sub) at boot, and whose * `durable`-class ones the agent self-joins for a Plane-3 backstop at connect (via the delivery * daemon). Must be ⊆ `allowSubscribe`. Omitted or empty ⇒ no boot channels at all. */ subscribe?: string[]; /** Record this agent's read ACL so it can participate in durable delivery (default true). A durable * backstop needs the agent's read ACL in the registry — the server-side delivery daemon re-authorizes * every durable entry against it — written here at provision. Set FALSE for a LIVE-ONLY launcher * (e.g. a direct foreground `cotal spawn` with no durable intent): no ACL row is written, so the daemon * refuses to authorize a durable backstop and the agent stays live-only. Boot durable MEMBERSHIP itself * is not written here — the agent self-joins its durable channels via the daemon's `ctl.delivery` op at * connect. */ durableMembership?: boolean; } /** The privileged onboarding ops a launcher needs at spawn — implemented by a connected, permissive * endpoint (the manager at `cotal start`/`cotal up`, or a short-lived provisioner that `cotal spawn` * opens). It pre-creates the agent's own mailboxes and records its read ACL; it does NOT host Plane-3 * delivery (that is the server-side delivery daemon). */ export interface DurableProvisioner { /** Pre-create the lifecycle's bind-only DM durable (`dm_--`). The implementation * captures the DM stream's ACTIVATION FRONTIER (its `last_seq` at first creation) and starts * delivery at frontier+1 (SPEC §8) — a same-alias successor inherits no predecessor DMs. * Idempotent PER LIFECYCLE: a re-provision of the same uid keeps the existing durable (and so the * ORIGINAL frontier — the activation moment does not move on manager restart). */ provisionDmInbox(owner: string, actor: string, lifecycleUid: string): Promise; /** Pre-create the lifecycle's bind-only Plane-3 DELIVER durable (`dlv_--`, * filtered to the lifecycle-scoped `dlv...`) so it can BIND its per-member * durable handoff without holding CONSUMER.CREATE on the DLV stream. */ provisionDlvInbox(owner: string, actor: string, lifecycleUid: string): Promise; /** Record the lifecycle's read ACL (`allowSubscribe`) in the durable ACL registry, keyed * `..` (SPEC §13.1) — the same act as baking it into the JWT, persisted * so the **server-side delivery daemon** can re-authorize the agent's durable entries and validate * its runtime durable-joins (it holds no in-memory ledger). Replaces the old manager-written boot * membership: boot durable membership is now the agent SELF-JOINING its durable channels via the * daemon's `ctl.delivery` op at connect. */ commitAcl(principal: string, lifecycleUid: string, allowSubscribe: string[]): Promise; /** * Raise the mint-time ceiling. Only the provisioning path that also remints the JWT. * Process discipline, not crypto binding — see {@link reissueAcl}. */ reissueAcl(principal: string, lifecycleUid: string, allowSubscribe: string[]): Promise; provisionTaskQueue(role: string): Promise; } /** The identity a cred is minted for: the owner+actor wire principal PLUS the connection nkey the cred * authenticates as. The wire grammar, per-agent KV keys, durables and presence key off owner+actor; the * private reply inbox (`_INBOX_`) keys off the connection nkey — under the auth callout that is a * per-connection ephemeral the client always knows, whereas the derived owner is not known pre-connect. */ export interface MintPrincipal { owner: string; actor: string; connId: string; /** The incarnation's lifecycle UID (SPEC §13.1). REQUIRED for the `agent` profile — its * dm/dlv/chathist grants are lifecycle-keyed EXACT names, so a credential cannot name another * incarnation's resources. Other profiles ignore it. */ lifecycleUid?: string; } /** Onboard an agent for launch (auth mode): pre-create its bind-only DM (+ Plane-3 DELIVER + role * TASK) durables, RECORD its read ACL in the durable registry (unless `durableMembership:false`), and * mint its scoped creds. Live delivery is the agent's own core subscription — there is no per-instance * chat durable. Boot durable MEMBERSHIP is not written here: the agent self-joins its durable channels * via the server-side delivery daemon's `ctl.delivery` op at connect. A deliberately live-only * launcher (`durableMembership:false`, e.g. `cotal spawn --live-only`) gets no ACL row, so the * daemon never authorizes a durable backstop for it. */ export declare function provisionAgent(provisioner: DurableProvisioner, auth: SpaceAuth, identity: Identity, opts?: ProvisionOpts): Promise; /** The DURABLE half of agent onboarding, principal-keyed and credential-agnostic: pre-create the * bind-only DM + DELIVER durables, record the read ACL, ensure the role TASK queue. The static * path ({@link provisionAgent}) follows it with a mint; the USER-MODE spawn path runs it alone — * a user agent's credential is its bearer (callout-minted per connect), never a static cred. * Returns the resolved read ACL so both callers scope from the same computed set. */ export declare function provisionAgentDurables(provisioner: DurableProvisioner, pr: { owner: string; actor: string; lifecycleUid: string; }, opts?: ProvisionOpts): Promise; /** Mint a user creds file for an agent {@link Identity} (its stable id+seed from * {@link newIdentity}). The account signing key signs over ONLY the public key * (`fromPublic`) — the agent seed is never part of the signature, it's only folded into * the resulting creds file. The "agent" profile is scoped to publish only as itself and only to * its declared `allowPublish` channels (post ACL, default-deny), and to read only within * `allowSubscribe` (live tail bind-only + per-channel history grants). Every profile is now * enumerated least-privilege — there is no allow-all cred (the former `manager` is deleted). */ export declare function mintCreds(auth: SpaceAuth, identity: Identity, profile: Profile, opts?: MintOpts): Promise; /** Issue a host-signed NATS user JWT for a caller-generated nkey. The private seed stays with * the remote manager. This is deliberately narrower than {@link mintCreds}: only the typed remote * manager protocol may request it, and every profile still goes through the same permission and * lifetime builders. */ export declare function mintPublicUserJwt(auth: SpaceAuth, publicId: string, profile: Profile, opts: MintOpts): Promise<{ jwt: string; exp: number; }>; export declare function permissionsFor(profile: Profile, space: string, pr: MintPrincipal, opts: MintOpts): Record; /** Mint the scoped `membership-observer` creds — a SYSTEM-account user (conn A of the graph feed), * signed with the in-memory `auth.sys.signingSeed` from a fresh {@link createSpaceAuth}. THROWS if that * seed is absent (a re-`up` of an already-provisioned space, whose `$SYS` seed was discarded at its * original `up`): the observer can only be minted at the (re-)provision that creates the account — a * documented migration property, not a silent no-op. The CONNZ/event subjects pin the DATA account id * (`auth.account.pub`). Mirrors {@link mintCreds} but issues into the system account. */ export declare function mintMembershipObserverCreds(auth: SpaceAuth, identity: Identity, opts?: MintOpts): Promise; /** Mint the scoped `connection-evictor` creds — the kick-only SYSTEM-account user D5 slice 4's live * eviction holds. Same mint-only-at-provision property as the observer (the $SYS seed is in-memory * only), same fail-loud when it's absent. Paired with the observer at `up`. */ export declare function mintConnectionEvictorCreds(auth: SpaceAuth, identity: Identity, opts?: MintOpts): Promise; /** Render the `nats-server` config that trusts ONE broker operator and serves N spaces' accounts via * the in-config MEMORY resolver. * * Broker trust (operator + system account) comes from `broker` and has exactly one owner; the * per-space data accounts are listed in `spaces`. Every space account is asserted to be signed by * THIS broker's operator before it is preloaded: rendering a foreign-signed account would either * refuse broker boot or, worse, advertise a tenant the broker cannot actually authenticate. * * NOTE (W4): the MEMORY resolver is one static whole-broker map, so every mutation rewrites all of * it. Concurrent add/remove of spaces needs a broker-authoritative inventory with generation/CAS * and atomic promotion above this function; this renderer is deliberately pure. */ /** * Render the config for an OPEN (no-auth) broker. * * This exists so that no path reaches a listener without naming its transport. Open mode used to * start nats-server from bare CLI flags (`-js -sd … -p … -a …`) and never called `serverConfig` at * all, which meant the required `transport` union protected the auth path and was silent on the * open one: an operator could pass a cert and key, watch `up` print its normal banner, and get a * cleartext listener. That is the silent downgrade this feature exists to prevent, reachable by * someone who did everything right — so open mode renders a config too. * * It deliberately does NOT reuse `serverConfig`: that renders the operator, system account and * MEMORY resolver, none of which a no-auth broker should carry. What the two share is the thing * that matters — a REQUIRED transport, so the choice cannot be omitted on either path. * * IMPORTANT, and it must be said wherever open-mode TLS is surfaced to an operator: TLS ON AN * OPEN MESH GIVES CONFIDENTIALITY, NOT AUTHENTICATION. It hides traffic from a passive observer. * It does not verify who is connecting, because an open broker has no credentials to check — so * anyone who can reach the port still gets in, encrypted. It is a legitimate configuration for a * mesh crossing a network nobody controls, and it is NOT "secure" in the sense a reader will * assume from seeing `cotals://`. Describe it as the caveat it is rather than as a feature. */ export declare function openServerConfig(opts: { port?: number; host?: string; storeDir: string; transport: BrokerTransport; }): string; export declare function serverConfig(broker: BrokerAuth, spaces: readonly SpaceAccountAuth[], opts: { port?: number; host?: string; storeDir: string; /** Additional operator-signed accounts to preload in the MEMORY resolver — e.g. the dedicated * auth-callout account (`@cotal-ai/auth`), which must never share the data account. */ extraAccounts?: Array<{ pub: string; jwt: string; }>; /** How the client port is served. REQUIRED, and required on purpose: an optional TLS field * would let any future path that regenerates this config omit it and silently render a * plaintext listener. Callers must say `{ kind: "plaintext" }` when that is what they mean. * TLS is listener-wide, so it lives here in the broker options rather than per space — * no space can enable, disable or rotate it independently. */ transport: BrokerTransport; /** OPT-IN NATS websocket listener port (P2 item 6): browsers cannot speak raw NATS TCP, so the * console session client (a real mesh caller) needs one. This is a NEW ATTACK SURFACE the broker * did not have — emitted only when set, DEFAULT-BOUND TO LOCALHOST ({@link wsHost}), no TLS * (dev loopback; a remote/TLS dashboard is a later explicit opt-in). Omit it and no listener * exists (a broker with no console need adds no surface). */ wsPort?: number; /** Bind host for the websocket listener; defaults to loopback. Widening it (a remote dashboard) * is a deliberate operator choice, never the default. */ wsHost?: string; }): string; //# sourceMappingURL=provision.d.ts.map