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
26 lines
1.1 KiB
TypeScript
26 lines
1.1 KiB
TypeScript
// lavinmq's events entrypoint, loaded by the per-node tool host (the provisioner container runs
|
|
// ./provisioner separately). The broker lifecycle events are EMITTED from the provisioner, where the
|
|
// lifecycle actually happens (novox/hq ADR 0041/0042):
|
|
// module.lavinmq.amqp.provisioned — a consumer's vhost + user was created
|
|
// module.lavinmq.amqp.deprovisioned — that vhost + user was removed
|
|
// Here in the tool host we react to them, keeping a lightweight audit trail of who was granted a
|
|
// broker and who lost one — observability the provider itself is best placed to log.
|
|
|
|
import { on } from "@novox/mesh-sdk/events";
|
|
|
|
interface AmqpEvent {
|
|
consumer?: string;
|
|
user: string;
|
|
vhost?: string;
|
|
}
|
|
|
|
await on<AmqpEvent>("module.lavinmq.amqp.provisioned", async (e) => {
|
|
console.log(`[lavinmq] broker provisioned for ${e.body.consumer ?? "?"} (user ${e.body.user}, vhost ${e.body.vhost})`);
|
|
});
|
|
|
|
await on<AmqpEvent>("module.lavinmq.amqp.deprovisioned", async (e) => {
|
|
console.log(`[lavinmq] broker deprovisioned (user ${e.body.user})`);
|
|
});
|
|
|
|
console.log("[lavinmq] auditing broker lifecycle events");
|