lavinmq becomes a provider of a user-facing amqp interface: a consumer
that requires a message queue is given its OWN broker — a scoped vhost
and user on a lavinmq provider — not an account on the mesh's own
control-plane broker (ADR 0048). Vhost-per-login is the isolation model,
the exact analog of postgres's database-per-login: the provider names a
vhost after the consumer's login and a user with full rights on that
vhost and none elsewhere, so a login is a broker the consumer alone can
reach.
The provider drives lavinmq through its HTTP management API (client.ts,
the module's one impure seam), with a run-once bootstrap that computes
the RabbitMQ-compatible password hash lavinmq's config wants from the
plain admin secret the mesh mints — the value no ${secret:...}
placeholder can produce and the reason the bootstrap exists (ADR 0052).
serves.amqp carries the port so consumers reference ${bound:amqp:port}.
amqp-ping is a demo consumer: it contributes nothing (the vhost is the
login), reads its grant from an env-file the mesh fills, and uses
${bound:amqp:as} for BOTH its username and its vhost — the db-name
lesson applied to AMQP. It speaks AMQP 0-9-1 over a raw socket with no
npm dependency (the way redis speaks RESP) and round-trips one message.
It carries a slug so its identity fits the 20-char backend bound
(ADR 0049).
Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
33 lines
1.3 KiB
TypeScript
33 lines
1.3 KiB
TypeScript
// lavinmq's tools — lavinmq's own code (novox/hq ADR 0039), importing lavinmq's own management
|
|
// client. They return structured data; the mesh serves them through the sdk's tool harness.
|
|
|
|
import { registerModuleTools, type ToolDefinition } from "@novox/mesh-sdk/tools";
|
|
import { LavinmqClient } from "../client.js";
|
|
|
|
export function getLavinmqTools(lavinmq: LavinmqClient): ToolDefinition[] {
|
|
return [
|
|
{
|
|
name: "amqp_list_vhosts",
|
|
description: "List the lavinmq virtual hosts — one per consumer that was granted a broker.",
|
|
input: {},
|
|
run: async () => ({ vhosts: await lavinmq.listVhosts() }),
|
|
},
|
|
{
|
|
name: "amqp_list_queues",
|
|
description: "List the queues on a vhost with message and consumer counts. Omit vhost for the root '/'.",
|
|
input: { vhost: { type: "string", description: "the vhost to list, e.g. a consumer's login; defaults to '/'" } },
|
|
run: async (args) => ({ queues: await lavinmq.listQueues(args.vhost ? String(args.vhost) : undefined) }),
|
|
},
|
|
];
|
|
}
|
|
|
|
// The tools exist only when the server can be reached from the environment; without it, lavinmq
|
|
// contributes none rather than failing the whole tool runtime.
|
|
registerModuleTools("lavinmq", (env) => {
|
|
try {
|
|
return getLavinmqTools(LavinmqClient.fromEnv(env));
|
|
} catch {
|
|
return [];
|
|
}
|
|
});
|