Files
mesh-sdk/src/contracts/index.ts
T

81 lines
3.6 KiB
TypeScript

// The runtime shapes a module's own code touches — NOT the manifest schema, which the control
// plane owns and parses (in Go). These are what a running module receives and returns: a grant
// and its credentials, the mesh interface a provider and consumer both conform to, and the tool
// and event types. They change rarely and deliberately (novox/hq ADR 0039).
/** A request for one instance of a provided resource, addressed to a provider. */
export interface Grant {
/** The mesh interface being provisioned, e.g. "analytics", "postgres-database". */
readonly resource: string;
/** Who asked — the consumer module, on which node. */
readonly consumer: string;
readonly node: string;
/** What the consumer contributed (per the interface's spec keys), e.g. `{ name: "umami" }`. */
readonly values: Readonly<Record<string, string>>;
}
/** What a provider hands back for a grant. Sealed by the harness before it leaves the machine. */
export interface Credential {
/** The fields the interface promises a consumer, e.g. `{ host, port, as, password }`. */
readonly fields: Readonly<Record<string, string>>;
}
/**
* A mesh interface: the provider-neutral contract for a capability (novox/hq ADR 0040). Both a
* provider (which adapts its software to it) and a consumer (which depends on it, never on a
* provider) conform. `spec` names what a consumer may contribute; `credential` names what it
* receives. The interface is drawn at the consumer's real coupling: neutral where thin
* (`analytics`), the protocol where the consumer speaks one (`postgres-database`).
*/
export interface Interface {
readonly name: string;
/** Keys a consumer may contribute when requesting it. */
readonly spec: readonly string[];
/** Fields a consumer receives in its credential. */
readonly credential: readonly string[];
}
/** A tool a module exposes through the mesh's command surface. */
export interface ToolDefinition {
readonly name: string;
readonly description: string;
/** JSON-schema-shaped input contract; kept opaque here so tools own their own shapes. */
readonly input: Readonly<Record<string, unknown>>;
readonly run: (args: Readonly<Record<string, unknown>>) => Promise<unknown>;
}
/**
* The metadata that rides an event as AMQP headers (novox/hq ADR 0042). An event's identity and
* provenance live here, not in the body, so a consumer — or the broker, or an audit tool — reads
* who/when/what without parsing the payload. An unknown `x-` header is ignored, not refused: an
* event is observed by parties that need not all understand every header.
*/
export interface EventHeaders {
/** A unique id — for dedup and audit (delivery is at-least-once). */
readonly "x-event-id": string;
/** The emitter: the module, context or node name. */
readonly "x-source": string;
/** The node it was emitted from. */
readonly "x-node": string;
/** Emit time, RFC-3339. */
readonly "x-time": string;
/** Always `application/json`. */
readonly "content-type": string;
/** The event or command that caused this one — tracing. */
readonly "x-causation-id"?: string;
/** A version of the body's shape, so a body evolves without silent misreads. */
readonly "x-schema"?: string;
readonly [header: string]: string | undefined;
}
/**
* A message crossing the broker: a routing key and a JSON body, per-node addressed. For an event,
* `headers` carries the ADR 0042 metadata; plain request/reply transport leaves it absent.
*/
export interface Envelope<T = unknown> {
readonly key: string;
readonly node: string;
readonly body: T;
readonly headers?: EventHeaders;
}