Files
mesh-catalog/modules/umami/provisioner/index.ts
T
jschoubben 1fb7ca3d72 A withdrawn consumer keeps its data, in every provider that holds some (hq issue 241)
mssql disables the login, mongodb takes the user's roles, minio revokes the key and keeps the bucket,
mailu disables the mailbox, gitea prohibits the login instead of purging the user and their
repositories, umami keeps the website. Each provider's create already enables what this locks.
2026-10-05 00:34:40 +02:00

38 lines
2.0 KiB
TypeScript

// 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<void> {
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<void> {
// The website and its analytics are kept (novox/hq issue 241: a withdrawal never destroys a consumer's data — on 2026-10-04 a misread grants file withdrew every consumer at once); a person deletes a site, never this loop.
console.error(`[umami] ${p.as} withdrawn: website and its analytics kept`);
},
});