Stand up mesh-sdk — the stable spine a module builds against

Per novox/hq ADR 0044/0045: the sdk holds only what rarely changes and
is shared across modules; per-module code (a client, tool impls, a
create-a-resource adapter) lives in the module.

Five areas, real and tested:
- contracts: the runtime shapes module code touches (grant, credential,
  a mesh Interface, tool + envelope types) — not the manifest schema,
  which the control plane owns.
- provisioner: the reconcile harness every provider shares (watch grants,
  create via the module's adapter, seal + write the credential, remove on
  withdrawal). A module writes only the adapter.
- tools: registerModuleTools + collectTools — the serving harness; tools
  and their client live in the module.
- messaging: the Broker/Envelope/event contract over the mesh broker; the
  concrete binding is provided by the hosting runtime.
- primitives: AES-256-GCM seal/unseal, semver, resolved-env access.

Compiles (tsc, NodeNext) and passes tests: sealing round-trip + wrong-key
rejection, semver, tool registration (a thrower is skipped not fatal), and
the provisioner creating then removing a sealed grant.

Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
This commit is contained in:
2026-09-03 23:01:59 +02:00
commit a19a2f5cf0
12 changed files with 639 additions and 0 deletions
+52
View File
@@ -0,0 +1,52 @@
// 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 0044).
/** 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 0045). 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>;
}
/** A message crossing the broker: a routing key and a JSON body, per-node addressed. */
export interface Envelope<T = unknown> {
readonly key: string;
readonly node: string;
readonly body: T;
}