// umami's provisioner — the adapter that makes umami a provider of the mesh `analytics` interface. // The reconcile loop and the contributions file are the sdk harness's; this writes only the // per-service half: how umami creates and removes a tracked site (novox/hq ADR 0039/0040/0048). // // The `analytics` interface: a consumer contributes `{ domain }` (the site it wants tracked) and // receives `{ siteId, snippet, dashboard }`. // // **A note on scope (ADR 0048).** ADR 0048 corrects *credential* provisions: the mesh mints a secret // and the provider creates a login with it. Analytics is not that shape — it mints no secret the // consumer authenticates with; what the consumer needs back is data umami *generates* (the siteId). // The credential-provisioner contract returns nothing, so the siteId does not travel back to the // consumer here. That return path — for a provider that generates data rather than being handed a // secret — is a separate concern and is not solved by this decision. umami still reconciles its // sites off the mesh's contributions (it keys on the login the mesh derived), which is what this // keeps working. import { runProvisioner, type Provision } from "@novox/mesh-sdk/provisioner"; import { UmamiClient } from "../client.js"; const umami = UmamiClient.fromEnv(); runProvisioner("analytics", { async create(p: Provision): Promise { const domain = String(p.values.domain ?? p.as); const name = String(p.values.name ?? domain); const token = await umami.getToken(); // Idempotent: only create the site if it is not already there. if (!(await umami.findWebsite(token, domain))) { await umami.createWebsite(token, domain, name); } }, async remove(p: { as: string }): Promise { const token = await umami.getToken(); // Keyed on the mesh-derived login, the one identity the harness carries into removal. const site = await umami.findWebsite(token, p.as); if (site) await umami.deleteWebsite(token, site.id); }, });