@homeflare/alchemy 0.35.0 → 0.37.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -0
- package/dist/argocd/cluster.d.ts +102 -0
- package/dist/argocd/cluster.d.ts.map +1 -0
- package/dist/argocd/credentials.d.ts +37 -0
- package/dist/argocd/credentials.d.ts.map +1 -0
- package/dist/argocd/fake-argocd.d.ts +42 -0
- package/dist/argocd/fake-argocd.d.ts.map +1 -0
- package/dist/argocd/git-credentials.d.ts +29 -0
- package/dist/argocd/git-credentials.d.ts.map +1 -0
- package/dist/argocd/index.d.ts +19 -0
- package/dist/argocd/index.d.ts.map +1 -0
- package/dist/argocd/index.js +306 -0
- package/dist/argocd/index.js.map +17 -0
- package/dist/argocd/providers.d.ts +13 -0
- package/dist/argocd/providers.d.ts.map +1 -0
- package/dist/argocd/repo-creds.d.ts +67 -0
- package/dist/argocd/repo-creds.d.ts.map +1 -0
- package/dist/argocd/repository.d.ts +87 -0
- package/dist/argocd/repository.d.ts.map +1 -0
- package/dist/argocd/resource.d.ts +90 -0
- package/dist/argocd/resource.d.ts.map +1 -0
- package/dist/cloudflare/index.js +4 -4
- package/dist/cloudflare/index.js.map +3 -3
- package/dist/cloudflare/r2-bucket-lock.d.ts +14 -5
- package/dist/cloudflare/r2-bucket-lock.d.ts.map +1 -1
- package/dist/grafana/index.d.ts +5 -4
- package/dist/grafana/index.d.ts.map +1 -1
- package/dist/grafana/index.js +204 -90
- package/dist/grafana/index.js.map +7 -4
- package/dist/grafana/notification-policy-drop-warning.d.ts +27 -0
- package/dist/grafana/notification-policy-drop-warning.d.ts.map +1 -0
- package/dist/grafana/notification-policy-fixtures.d.ts +34 -0
- package/dist/grafana/notification-policy-fixtures.d.ts.map +1 -0
- package/dist/grafana/notification-policy-model.d.ts +53 -0
- package/dist/grafana/notification-policy-model.d.ts.map +1 -0
- package/dist/grafana/notification-policy.d.ts +57 -0
- package/dist/grafana/notification-policy.d.ts.map +1 -0
- package/dist/grafana/providers.d.ts +1 -1
- package/dist/grafana/providers.d.ts.map +1 -1
- package/dist/litellm/index.js.map +2 -2
- package/dist/litellm/operations.d.ts.map +1 -1
- package/dist/proxmox/ceph-daemon-form.d.ts +4 -5
- package/dist/proxmox/ceph-daemon-form.d.ts.map +1 -1
- package/dist/proxmox/ceph-daemon-wire.d.ts +33 -0
- package/dist/proxmox/ceph-daemon-wire.d.ts.map +1 -0
- package/dist/proxmox/ceph-daemon.d.ts +35 -0
- package/dist/proxmox/ceph-daemon.d.ts.map +1 -1
- package/dist/proxmox/ceph-fs-distilled.d.ts +14 -0
- package/dist/proxmox/ceph-fs-distilled.d.ts.map +1 -0
- package/dist/proxmox/ceph-fs-wire.d.ts +20 -11
- package/dist/proxmox/ceph-fs-wire.d.ts.map +1 -1
- package/dist/proxmox/ceph-fs.d.ts +31 -6
- package/dist/proxmox/ceph-fs.d.ts.map +1 -1
- package/dist/proxmox/ceph-osd-tree.d.ts +12 -3
- package/dist/proxmox/ceph-osd-tree.d.ts.map +1 -1
- package/dist/proxmox/ceph-osd-write.d.ts +17 -2
- package/dist/proxmox/ceph-osd-write.d.ts.map +1 -1
- package/dist/proxmox/ceph-osd.d.ts +6 -0
- package/dist/proxmox/ceph-osd.d.ts.map +1 -1
- package/dist/proxmox/ceph-pool-settle.d.ts +10 -4
- package/dist/proxmox/ceph-pool-settle.d.ts.map +1 -1
- package/dist/proxmox/ceph-pool-wire.d.ts +46 -0
- package/dist/proxmox/ceph-pool-wire.d.ts.map +1 -0
- package/dist/proxmox/ceph-pool.d.ts +10 -5
- package/dist/proxmox/ceph-pool.d.ts.map +1 -1
- package/dist/proxmox/group-wire.d.ts +1 -1
- package/dist/proxmox/group-wire.d.ts.map +1 -1
- package/dist/proxmox/index.js +611 -477
- package/dist/proxmox/index.js.map +15 -12
- package/dist/proxmox/storage-wire.d.ts +8 -1
- package/dist/proxmox/storage-wire.d.ts.map +1 -1
- package/dist/proxmox/user-wire.d.ts +1 -1
- package/dist/proxmox/user-wire.d.ts.map +1 -1
- package/docs/argocd-kubernetes.md +100 -0
- package/docs/argocd.md +139 -0
- package/docs/credentials.md +9 -0
- package/docs/grafana-alerting.md +3 -2
- package/docs/grafana-notification-policy.md +127 -0
- package/docs/grafana.md +12 -8
- package/docs/litellm.md +17 -0
- package/docs/peers.md +7 -0
- package/docs/unifi.md +45 -0
- package/docs/upstream-conformance.md +19 -5
- package/package.json +8 -3
- package/src/argocd/cluster.test.ts +120 -0
- package/src/argocd/cluster.ts +222 -0
- package/src/argocd/credentials.ts +38 -0
- package/src/argocd/fake-argocd.ts +60 -0
- package/src/argocd/git-credentials.ts +71 -0
- package/src/argocd/index.ts +40 -0
- package/src/argocd/providers.ts +17 -0
- package/src/argocd/repo-creds.test.ts +123 -0
- package/src/argocd/repo-creds.ts +115 -0
- package/src/argocd/repository.test.ts +167 -0
- package/src/argocd/repository.ts +165 -0
- package/src/argocd/resource.ts +150 -0
- package/src/cloudflare/r2-bucket-lock.test.ts +54 -18
- package/src/cloudflare/r2-bucket-lock.ts +25 -18
- package/src/grafana/index.ts +11 -4
- package/src/grafana/notification-policy-drop-warning.test.ts +163 -0
- package/src/grafana/notification-policy-drop-warning.ts +60 -0
- package/src/grafana/notification-policy-fixtures.ts +27 -0
- package/src/grafana/notification-policy-model.test.ts +104 -0
- package/src/grafana/notification-policy-model.ts +100 -0
- package/src/grafana/notification-policy-refusals.test.ts +119 -0
- package/src/grafana/notification-policy.test.ts +86 -0
- package/src/grafana/notification-policy.ts +191 -0
- package/src/grafana/providers.ts +2 -0
- package/src/litellm/operations.ts +8 -4
- package/src/proxmox/ceph-daemon-form.ts +7 -8
- package/src/proxmox/ceph-daemon-wire.ts +115 -0
- package/src/proxmox/ceph-daemon-write.test.ts +158 -0
- package/src/proxmox/ceph-daemon.ts +65 -47
- package/src/proxmox/ceph-fs-delete.test.ts +81 -0
- package/src/proxmox/ceph-fs-distilled.ts +102 -0
- package/src/proxmox/ceph-fs-wire.ts +17 -31
- package/src/proxmox/ceph-fs-write.test.ts +67 -0
- package/src/proxmox/ceph-fs.ts +66 -69
- package/src/proxmox/ceph-osd-tree.ts +14 -5
- package/src/proxmox/ceph-osd-write.test.ts +61 -0
- package/src/proxmox/ceph-osd-write.ts +33 -6
- package/src/proxmox/ceph-osd.ts +6 -0
- package/src/proxmox/ceph-pool-settle.ts +13 -7
- package/src/proxmox/ceph-pool-wire.ts +110 -0
- package/src/proxmox/ceph-pool-write.test.ts +145 -0
- package/src/proxmox/ceph-pool.ts +87 -98
- package/src/proxmox/distilled-task-await.test.ts +0 -124
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/grafana/alert-rule-group.ts", "../src/grafana/alert-rule-group-drop-warning.ts", "../src/grafana/alert-rule-group-model.ts", "../src/grafana/alerting-provenance.ts", "../src/grafana/provisioned.ts", "../src/grafana/resource.ts", "../src/grafana/subset-match.ts", "../src/grafana/datasource.ts", "../src/grafana/secret-refs.ts", "../src/grafana/dashboard.ts", "../src/grafana/dashboard-model.ts", "../src/grafana/folder.ts", "../src/grafana/contact-point.ts", "../src/grafana/message-template.ts", "../src/grafana/mute-timing.ts", "../src/grafana/credentials.ts", "../src/grafana/providers.ts"],
|
|
3
|
+
"sources": ["../src/grafana/alert-rule-group.ts", "../src/grafana/alert-rule-group-drop-warning.ts", "../src/grafana/alert-rule-group-model.ts", "../src/grafana/alerting-provenance.ts", "../src/grafana/provisioned.ts", "../src/grafana/resource.ts", "../src/grafana/subset-match.ts", "../src/grafana/notification-policy.ts", "../src/grafana/notification-policy-model.ts", "../src/grafana/notification-policy-drop-warning.ts", "../src/grafana/datasource.ts", "../src/grafana/secret-refs.ts", "../src/grafana/dashboard.ts", "../src/grafana/dashboard-model.ts", "../src/grafana/folder.ts", "../src/grafana/contact-point.ts", "../src/grafana/message-template.ts", "../src/grafana/mute-timing.ts", "../src/grafana/credentials.ts", "../src/grafana/providers.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
5
|
"/**\n * `Grafana.AlertRuleGroup` — one Grafana alert rule GROUP, keyed by `(folderUid, group)`.\n *\n * ★ GROUP, NOT PER-RULE — THE UNIT CHOICE, JUSTIFIED. MEASURED against the SDK's generated\n * operations: `PUT /v1/provisioning/folder/{FolderUID}/rule-groups/{Group}`\n * (`routePutAlertRuleGroup`) takes the evaluation `interval` AND the full ordered `rules[]`\n * TOGETHER, replacing the whole group in one call (`RoutePutAlertRuleGroupRequest.rules:\n * Array<ProvisionedAlertRuleInput>`) — the individual `routePostAlertRule`/`routePutAlertRule`\n * operations have no `interval` field at all and cannot reorder rules within a group. Declaring\n * rules one at a time (`Grafana.AlertRule`) would leave a group's evaluation interval and rule\n * order — both real, load-bearing Grafana state — either undeclarable or racy across N\n * independent resources with no shared source of truth for them. Grafana's own docs describe\n * `X-Disable-Provenance` on the rule-group PUT as setting \"the provenance for the rule group AND\n * ALL ITS ALERT RULES\" — further evidence the group, not the rule, is Grafana's own natural unit\n * of ownership here. Mirrors Terraform's own `grafana_rule_group` resource, which takes the\n * identical shape (a list of rules under one folder/name/interval).\n *\n * ★ `uid` IS REQUIRED ON EVERY DECLARED RULE — same doctrine as every other resource in this\n * family (`AlertRuleInput` in `alert-rule-group-model.ts`). `ProvisionedAlertRuleInput.uid` is\n * optional on the wire (Grafana assigns one if omitted), but locating a specific rule this\n * resource didn't just create would then mean matching by title — the same ambiguity\n * `resource.ts`'s header and netbox's `soleMatch` exist to catch everywhere else in this family.\n *\n * ⛔ RULE ORDER IS SIGNIFICANT — NEVER REORDERED. `subset-match.ts`'s array comparison is already\n * position-significant (length, then element-wise) — this resource relies on that as-is; nothing\n * here re-sorts `rules` before comparing. Declaring rules in a different order than what is live\n * is a genuine content change (Grafana evaluates and displays a group's rules in array order),\n * not a cosmetic one.\n *\n * ⛔ A FOREIGN-PROVENANCE GROUP REFUSES EVERY UPDATE AND DESTROY — `alerting-provenance.ts`. Unlike\n * `ContactPoint`/`MessageTemplate`, `AlertRuleGroup` (the type `routeGetAlertRuleGroup` returns)\n * carries NO top-level `provenance` field — MEASURED: `folderUid?`/`interval?`/`rules?`/`title?`\n * only. Each RULE inside `rules[]` has its own (`ProvisionedAlertRule.provenance`), and Grafana's\n * docs say a new rule's provenance \"must match the provenance value configured for its rule\n * group\" — so this resource checks every live rule and refuses if ANY carries a foreign\n * provenance, naming the first one found. An empty live group (no rules yet) has nothing to check\n * and is never foreign. `create` is never at risk: it only runs when `fetchLive` already found\n * nothing.\n *\n * ⛔ A DECLARED GROUP WHOSE FOLDER DOES NOT EXIST REFUSES — IT IS NEVER AUTO-CREATED. This resource\n * makes no \"does the folder exist\" call of its own and does not depend on or invoke\n * `Grafana.Folder`'s create path. MEASURED: `RoutePutAlertRuleGroupError` is\n * `BadRequest | Forbidden | GrafanaOpError` — no `NotFound` case at all — so a nonexistent\n * `folderUid` fails the PUT as a typed `BadRequest`, left uncaught and propagated (the house rule\n * against folding a non-not-found error into absent), which fails the whole `reconcile` and stops\n * the deploy. Declare a `Grafana.Folder` for it first — the two resources sharing one `folderUid`\n * string is the dependency; auto-creating a folder from inside this resource would blur ownership\n * the same way `provisioned.ts`'s \"one owner per resource\" principle already guards against\n * elsewhere in this family. ⚠️ NOT RE-MEASURED against a live instance in this PR — inferred from\n * the declared error union, the same evidentiary bar `folder.ts`'s own `version` note uses.\n *\n * ⛔ DELETE DEFAULTS TO `retain` — DELETING A GROUP DELETES EVERY RULE IN IT IN ONE CALL\n * (`routeDeleteAlertRuleGroup`, whole-group DELETE). The same multi-object-cascade class\n * `Grafana.Folder`/`openbao/mount.ts` already guard with `defaultRemovalPolicy: 'retain'` — a\n * stack that wants the cascade opts in with `.pipe(RemovalPolicy.destroy())`; `destroy` below\n * still implements the real DELETE in full either way (S11).\n *\n * ⚠️ `orgID` DEFAULTS TO `1` ON EVERY WRITTEN RULE — see `alert-rule-group-model.ts`'s own note;\n * not measured against a multi-org instance, since none exists in this house yet.\n *\n * ⚠️ `X-Disable-Provenance` IS NEVER SET — same reasoning as `contact-point.ts`'s file header.\n *\n * ⚠️ A WHOLE-GROUP WRITE SILENTLY DROPS ANY LIVE RULE THE DECLARATION DOESN'T MENTION — flagged by\n * an adversarial review of this PR. Unlike every other resource in this family, this one does\n * not compare one object's fields; `update`/`diff` REPLACE an entire collection, so a live rule\n * with no counterpart in `props.rules` (e.g. one a human just added in the Grafana UI, ordinary\n * writable provenance — nothing for the refusal above to catch) is removed with no error and no\n * distinct `Diff` action to report it under. This is accepted by design — the group is still the\n * unit — but never SILENT: `alert-rule-group-drop-warning.ts`'s `warnOnDroppedRules` logs every\n * dropped rule by title and uid, called from both the custom `diff` below (so `bun run plan`\n * shows it before anything is written) and from `update` itself (so it is visible wherever\n * `reconcile` runs directly too).\n */\nimport { isResolved } from 'alchemy/Diff';\nimport type { Input } from 'alchemy/Input';\nimport { Resource } from 'alchemy';\nimport * as Provider from 'alchemy/Provider';\nimport * as grafana from '@distilled.cloud/grafana';\nimport * as Effect from 'effect/Effect';\nimport { warnOnDroppedRules } from './alert-rule-group-drop-warning.ts';\nimport { type AlertRuleInput, normalizeRule, toWireRule } from './alert-rule-group-model.ts';\nimport {\n type GrafanaProvisionedObjectError,\n isForeignProvenance,\n refuseIfForeignProvenance,\n} from './alerting-provenance.ts';\nimport { type GrafanaSpec, grafanaHandlers } from './resource.ts';\nimport { declaredContentMatches } from './subset-match.ts';\n\nexport type { AlertRuleInput };\n\nexport interface AlertRuleGroupProps {\n folderUid: string;\n group: string;\n /** Evaluation interval, in seconds. */\n interval: number;\n /** Order is significant — see the file header. */\n rules: ReadonlyArray<AlertRuleInput>;\n}\n\nexport interface AlertRuleGroupAttributes {\n folderUid: string;\n group: string;\n interval: number;\n rules: ReadonlyArray<Record<string, unknown>>;\n}\n\nexport interface GrafanaAlertRuleGroup extends Resource<\n 'Grafana.AlertRuleGroup',\n AlertRuleGroupProps,\n AlertRuleGroupAttributes,\n never\n> {}\n\nexport const GrafanaAlertRuleGroup = Resource<GrafanaAlertRuleGroup>('Grafana.AlertRuleGroup', {\n defaultRemovalPolicy: 'retain',\n});\n\n/** The first live rule whose provenance this family may not write to, or `undefined` when every\n * rule (including none at all) is writable. */\nconst findForeignRule = (\n rules: ReadonlyArray<grafana.ProvisionedAlertRule> | undefined,\n): grafana.ProvisionedAlertRule | undefined =>\n (rules ?? []).find((rule) => isForeignProvenance(rule.provenance));\n\nconst body = (props: AlertRuleGroupProps) => ({\n folderUid: props.folderUid,\n interval: props.interval,\n rules: props.rules.map((rule) => toWireRule(rule, props.folderUid, props.group)),\n title: props.group,\n});\n\nconst refuseForForeignRule = (props: AlertRuleGroupProps, foreign: grafana.ProvisionedAlertRule) =>\n refuseIfForeignProvenance(\n 'Grafana.AlertRuleGroup',\n `${props.folderUid}/${props.group}`,\n foreign.provenance,\n );\n\nconst declaredUids = (props: AlertRuleGroupProps): ReadonlySet<string> =>\n new Set(props.rules.map((rule) => rule.uid));\n\nexport const spec: GrafanaSpec<\n AlertRuleGroupProps,\n grafana.AlertRuleGroup,\n AlertRuleGroupAttributes,\n | grafana.RouteGetAlertRuleGroupError\n | grafana.RoutePutAlertRuleGroupError\n | grafana.RouteDeleteAlertRuleGroupError\n | GrafanaProvisionedObjectError\n> = {\n attributes: (live, props) => ({\n folderUid: live.folderUid ?? props.folderUid,\n group: props.group,\n interval: live.interval ?? 0,\n rules: (live.rules ?? []).map((rule) =>\n normalizeRule(rule as unknown as Record<string, unknown>, props.folderUid, props.group),\n ),\n }),\n create: (props) =>\n grafana.routePutAlertRuleGroup({\n FolderUID: props.folderUid,\n Group: props.group,\n ...body(props),\n }),\n destroy: (props, live) =>\n Effect.gen(function* () {\n const foreign = findForeignRule(live.rules);\n if (foreign !== undefined) return yield* refuseForForeignRule(props, foreign);\n yield* grafana.routeDeleteAlertRuleGroup({ FolderUID: props.folderUid, Group: props.group });\n }),\n fetchLive: (props) =>\n grafana\n .routeGetAlertRuleGroup({ FolderUID: props.folderUid, Group: props.group })\n .pipe(Effect.catchTag('NotFound', () => Effect.succeed(undefined))),\n matches: (attributes, props) =>\n attributes.interval === props.interval &&\n declaredContentMatches(\n props.rules.map((rule) =>\n normalizeRule(rule as unknown as Record<string, unknown>, props.folderUid, props.group),\n ),\n attributes.rules,\n ),\n update: (props, live) =>\n Effect.gen(function* () {\n const foreign = findForeignRule(live.rules);\n if (foreign !== undefined) return yield* refuseForForeignRule(props, foreign);\n yield* warnOnDroppedRules(props.folderUid, props.group, declaredUids(props), live.rules);\n yield* grafana.routePutAlertRuleGroup({\n FolderUID: props.folderUid,\n Group: props.group,\n ...body(props),\n });\n }),\n};\n\n/**\n * ⚠️ A LOCAL REIMPLEMENTATION OF `resource.ts`'s GENERIC `diff`, NOT A WRAP OF IT — deliberately.\n * The generic `grafanaOperations(spec).diff` fetches live and maps it to `Attributes` entirely\n * inside itself, with no seam to run the drop warning against the rules it read; wrapping it\n * would mean a SECOND live fetch just to see what it saw. This resource's `diff` is the ONLY one\n * in the family that needs a resource-specific side effect mid-comparison, so it re-reads\n * `resource.ts`'s own logic here rather than changing the shared engine every other resource\n * also uses. Keep this in sync with `resource.ts`'s `grafanaOperations.diff` if that ever\n * changes shape.\n */\nconst diff = ({\n news,\n output,\n}: {\n news: Input<AlertRuleGroupProps>;\n output: AlertRuleGroupAttributes | undefined;\n}) =>\n Effect.gen(function* () {\n if (output === undefined || !isResolved(news)) return undefined;\n const live = yield* spec.fetchLive(news);\n if (live === undefined) return { action: 'update' } as const;\n yield* warnOnDroppedRules(news.folderUid, news.group, declaredUids(news), live.rules);\n const mapped = spec.attributes(live, news);\n return mapped !== undefined && spec.matches(mapped, news)\n ? ({ action: 'noop' } as const)\n : ({ action: 'update' } as const);\n });\n\nexport const handlers = { ...grafanaHandlers(spec), diff };\n\nexport const GrafanaAlertRuleGroupProvider = () =>\n Provider.effect(\n GrafanaAlertRuleGroup,\n Effect.succeed(GrafanaAlertRuleGroup.Provider.of(handlers)),\n );\n",
|
|
6
6
|
"/**\n * The warning `Grafana.AlertRuleGroup` logs when a whole-group PUT would silently drop a live rule\n * the declaration never mentions — flagged by an adversarial review of this PR: a human adding a\n * rule in the Grafana UI minutes before a deploy (ordinary, writable provenance — nothing foreign\n * to refuse on) would otherwise be removed with no visible reason, `diff` only ever saying\n * \"update\". `Grafana.AlertRuleGroup` is still the group as the unit BY DESIGN (that file's own\n * header) — this does not refuse the write, only makes the loss visible.\n *\n * ★ `Effect.logWarning`, NEVER A REFUSAL — mirrors the house pattern `proxmox/unreadable-read.ts`'s\n * `unreadableWarning` established. Alchemy's `Diff` type is exactly `NoopDiff | UpdateDiff |\n * ReplaceDiff` (no fourth action to carry \"update, but lossy\" through to `bun run plan`'s printed\n * action), and refusing here would contradict \"the group is the unit\": a whole-group replacement\n * dropping an out-of-band rule is EXPECTED behavior for this resource, not an error condition —\n * only a silent one worth surfacing loudly.\n *\n * ★ NO IMPORT OF `AlertRuleGroupProps` — deliberately primitive arguments (`folderUid`/`group`/a\n * plain `Set` of declared uids) rather than the whole props object, so this file has no\n * dependency back on `alert-rule-group.ts` and can be unit-tested with plain data.\n */\nimport * as Effect from 'effect/Effect';\n\nexport const warnOnDroppedRules = (\n folderUid: string,\n group: string,\n declaredUids: ReadonlySet<string>,\n liveRules: ReadonlyArray<{ readonly uid?: unknown; readonly title?: unknown }> | undefined,\n): Effect.Effect<void> =>\n Effect.gen(function* () {\n const dropped = (liveRules ?? [])\n .filter((rule): rule is { title?: unknown; uid: string } => typeof rule.uid === 'string')\n .filter((rule) => !declaredUids.has(rule.uid));\n if (dropped.length === 0) return;\n const names = dropped\n .map((rule) => `${typeof rule.title === 'string' ? rule.title : '(untitled)'} (${rule.uid})`)\n .join(', ');\n yield* Effect.logWarning(\n `Grafana.AlertRuleGroup ${folderUid}/${group}: this update REMOVES ${dropped.length} ` +\n `rule(s) not in the declaration: ${names}. Whole-group replacement is by design — add ` +\n `them to the declaration to keep them, or give them their own group.`,\n );\n });\n",
|
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
"/**\n * The shared refusal for a file-provisioned Grafana object — `Grafana.Folder` and\n * `Grafana.Dashboard` both carry a live signal Grafana itself treats as read-only through the\n * classic write API this family calls: `Folder.managedBy` (non-empty when something other than\n * this API manages the folder — provisioning is the case this house cares about, but the field\n * itself is Grafana's general \"who owns this\" marker) and `DashboardMeta.provisioned` (paired\n * with `provisionedExternalId`, the file path). A declaration must never attempt a write against\n * either — see docs/grafana-folder-dashboard.md's \"provisioned objects\" section.\n *\n * ⚠️ THE EXACT `managedBy` VALUES ARE INFERRED FROM THE SDK's SCHEMA, NOT MEASURED. No live\n * instance in this house currently has a file-provisioned FOLDER to read (docs/grafana.md:\n * `teslamate-grafana` has none at all; the mini's Grafana provisions dashboards, not folders) and\n * this PR makes no live calls. `Folder.managedBy` and `DashboardMeta.provisioned` are exactly\n * the fields the OpenAPI schema types for this purpose — treat any non-empty `managedBy` as\n * provisioned rather than special-casing specific string values that were never observed live.\n *\n * ⛔ ADOPTING A PROVISIONED OBJECT IS STILL FINE. `read`/`reconcile`'s no-write \"already converged\"\n * path (resource.ts) never calls `create`/`update`/`destroy` at all when the declaration already\n * matches what is live — only an actual attempted WRITE against a provisioned object is refused,\n * by the two callers of this function inside folder.ts/dashboard.ts's own `update`/`destroy`.\n */\nimport * as Data from 'effect/Data';\nimport * as Effect from 'effect/Effect';\n\nexport class GrafanaProvisionedObjectError extends Data.TaggedError(\n 'GrafanaProvisionedObjectError',\n)<{\n readonly message: string;\n}> {}\n\nexport const refuseIfProvisioned = (\n kind: 'Grafana.Folder' | 'Grafana.Dashboard',\n uid: string,\n owner: string | undefined,\n): Effect.Effect<never, GrafanaProvisionedObjectError> => {\n const ownerClause =\n owner === undefined || owner === ''\n ? `(this Grafana instance did not report an owning file)`\n : `by ${owner}`;\n return Effect.fail(\n new GrafanaProvisionedObjectError({\n message:\n `${kind} '${uid}' is file-provisioned ${ownerClause} and read-only through the classic ` +\n `write API this family calls. Edit the provisioning file instead — declaring this ` +\n `object read-only (a declaration matching what is live) is safe and will never reach ` +\n `this refusal.`,\n }),\n );\n};\n",
|
|
10
10
|
"/**\n * One shape for every Grafana object this family declares — mirroring `../forgejo/resource.ts`\n * and `../netbox/resource.ts` exactly, minus the credentials wrapping those two bake in.\n *\n * ★ CREDENTIALS ARE NOT PROVIDED HERE. Forgejo and NetBox each manage exactly one instance for\n * this house, so their engines close over a hardcoded `CredentialsFromEnv`. Grafana does not —\n * see `credentials.ts`'s note on `grafana.homeflare.dev` vs `teslamate-grafana` — so `Credentials`\n * stays a context requirement on every handler here, and `providers.ts`'s `grafanaProviders`\n * supplies it per target with `Layer.provide`, the same composition `litellm/providers.ts` uses.\n *\n * ⚠️ `NotFound` IS FOLDED TO \"ABSENT\" INSIDE EACH RESOURCE FILE'S OWN `fetchLive`, NOT HERE — the\n * same split forgejo's and netbox's engines use. `Effect.catchTag`'s tag-literal inference needs\n * a concrete error union to resolve `\"NotFound\"` against; a spec's `E` is only concrete at each\n * resource file's own call site.\n */\nimport { isResolved } from 'alchemy/Diff';\nimport type { Input } from 'alchemy/Input';\nimport type { GrafanaOpContext } from '@distilled.cloud/grafana/Protocol';\nimport * as Effect from 'effect/Effect';\n\n/**\n * One Grafana object's distilled calls. `Live` is whatever the SDK decodes (a `DataSource`, …) —\n * no untyped `Record<string, unknown>`. `E` is left to each resource file to declare (the union\n * of the distilled operations it actually calls plus any domain refusal, e.g. an unset secret-ref\n * env var), so a call site's precise error union flows straight through instead of being widened\n * by hand here.\n */\nexport type GrafanaSpec<Props extends object, Live, Attributes, E> = {\n /** Already folds the SDK's `NotFound` to `undefined` via its own `catchTag` — see the note above. */\n readonly fetchLive: (props: Props) => Effect.Effect<Live | undefined, E, GrafanaOpContext>;\n readonly attributes: (live: Live, props: Props) => Attributes | undefined;\n readonly matches: (attributes: Attributes, props: Props) => boolean;\n readonly create: (props: Props) => Effect.Effect<unknown, E, GrafanaOpContext>;\n readonly update?: (props: Props, live: Live) => Effect.Effect<unknown, E, GrafanaOpContext>;\n readonly destroy: (props: Props, live: Live) => Effect.Effect<unknown, E, GrafanaOpContext>;\n};\n\nexport const grafanaOperations = <Props extends object, Live, Attributes, E>(\n spec: GrafanaSpec<Props, Live, Attributes, E>,\n) => {\n const read = (props: Props) =>\n spec\n .fetchLive(props)\n .pipe(Effect.map((live) => (live === undefined ? undefined : spec.attributes(live, props))));\n\n return {\n read,\n\n diff: (news: Input<Props>, output: Attributes | undefined) =>\n Effect.gen(function* () {\n if (output === undefined || !isResolved(news)) return undefined;\n const live = yield* read(news);\n if (live === undefined) return { action: 'update' } as const;\n if (spec.matches(live, news)) return { action: 'noop' } as const;\n return spec.update === undefined\n ? ({ action: 'replace' } as const)\n : ({ action: 'update' } as const);\n }),\n\n /**\n * ★ OBSERVES BEFORE IT WRITES (S9, S10) — THE WHOLE OF \"ADOPT\" FOR THIS FAMILY. A `uid` this\n * Grafana instance already has is bound and, when it already matches the declaration,\n * left alone; only a genuinely absent `uid` is created. Declaring exactly what is live\n * changes nothing on `reconcile`, the same posture netbox/resource.ts documents as\n * \"adopt is the default posture, not a flag\".\n */\n reconcile: (news: Props) =>\n Effect.gen(function* () {\n const before = yield* spec.fetchLive(news);\n if (before === undefined) {\n yield* spec.create(news);\n } else if (spec.update !== undefined) {\n const mapped = spec.attributes(before, news);\n if (mapped === undefined || spec.matches(mapped, news)) {\n /* adoption or already converged — no write */\n } else {\n yield* spec.update(news, before);\n }\n }\n const after = yield* read(news);\n if (after === undefined) {\n return yield* Effect.die(\n new Error(\n 'grafanaOperations: the write returned no error but the object is still absent. ' +\n 'Read back rather than trusting the response status.',\n ),\n );\n }\n return after;\n }),\n\n destroy: (olds: Props) =>\n Effect.gen(function* () {\n const live = yield* spec.fetchLive(olds);\n if (live === undefined) return;\n yield* spec.destroy(olds, live);\n }),\n };\n};\n\n/**\n * The five provider handlers for a spec'd Grafana object, wired once. `Credentials` and\n * `HttpClient.HttpClient` stay ambient context requirements — see the file header.\n *\n * ⚠️ `list` answers empty — an org's full datasource list is not a page this family sweeps for\n * adoption; adoption stays explicit, the same reasoning forgejo's and netbox's engines give.\n */\nexport const grafanaHandlers = <Props extends object, Live, Attributes extends object, E>(\n spec: GrafanaSpec<Props, Live, Attributes, E>,\n) => {\n const ops = grafanaOperations(spec);\n return {\n list: () => Effect.succeed([]),\n read: ({ olds }: { olds: Props }) => ops.read(olds),\n diff: ({ news, output }: { news: Input<Props>; output: Attributes | undefined }) =>\n ops.diff(news, output),\n reconcile: ({ news }: { news: Props }) => ops.reconcile(news),\n delete: ({ olds }: { olds: Props }) => ops.destroy(olds),\n };\n};\n",
|
|
11
11
|
"/**\n * `declaredContentMatches` — \"is the declaration a subset of what is live\", not plain equality.\n * Extracted out of `dashboard-model.ts` (where it was introduced, after an adversarial review of\n * that PR found plain structural equality made an ordinary, never-edited dashboard show `update`\n * FOREVER) once a second shape needed the identical rule: `Grafana.ContactPoint`'s `settings` is\n * the same story — Grafana can inject default fields into a contact point's settings that the\n * declaration never mentioned, and `Grafana.AlertRuleGroup`'s per-rule `data`/`annotations`/\n * `labels` maps carry the same risk. Nothing about the reasoning below is dashboard-specific;\n * `dashboard-model.ts` now just re-exports this.\n *\n * ★ `declared` NEED ONLY BE A SUBSET OF `live`. Grafana's own save/decode path can decorate an\n * object with fields the declaration never set (a dashboard panel's auto-resolved `datasource`\n * reference is the documented example dashboard-model.ts found — Grafana's schema migration\n * decorates any panel/target whose `datasource` is absent with an explicit `{type, uid}`\n * reference on save). This function instead asks only \"does every field the DECLARATION\n * mentions, at any depth, still match what is live\" — `live` may carry additional fields, at any\n * depth, that `declared` never mentioned, without being compared at all. A field `declared` DOES\n * mention that is missing, or different, in `live` still fails the match — real content drift is\n * still caught exactly as before; only fields the declaration is silent about are now tolerated.\n *\n * ⚠️ THE TRADE-OFF THIS ACCEPTS, DELIBERATELY: removing a field from the declaration (rather than\n * changing its value) can no longer force Grafana to drop it. If a previous declaration set a\n * field and a later one deletes that key entirely, `live` keeps whatever the last write set — the\n * declaration is silent about that key now, so nothing compares it, so no `update` ever fires to\n * change it. This is the same \"undeclared means don't care, never means force-to-default\"\n * convention already used everywhere else in this kit for a plain optional prop; it now also\n * applies inside a nested JSON value, not just at the top-level props. Declare an explicit\n * replacement value to change a field; omission never clears one that was set by a previous\n * declaration or by Grafana itself.\n *\n * ⚠️ ARRAYS COMPARE BY LENGTH, THEN ELEMENT-WISE SUBSET — never a looser \"declared has fewer\n * items\" rule. A caller whose array IS order-significant (dashboard `panels`/`targets`) or\n * position-keyed (an alert rule group's `rules`) gets that for free; a caller with a genuinely\n * unordered array would need its own normalization first (this file has no `sortedSet`, and\n * nothing in this kit's Grafana family needs one — see dashboard-model.ts's own note).\n *\n * ⛔ NOT RE-MEASURED FOR EVERY CALLER — flagged by an adversarial review of this PR. The exact\n * length rule is confirmed for dashboards (the original, documented case), but whether Grafana\n * ever PADS or APPENDS a default entry to an array the way it decorates an object field (the\n * `datasource` auto-decoration above) is unverified for `Grafana.MuteTiming`'s `time_intervals`\n * specifically — no live mute timing exists in this house to observe (grafana.md's census), and\n * `mute-timing.test.ts`'s own fixtures are hand-authored, not captured. If a future live\n * observation finds Grafana appending an entry (e.g. a normalized default time range) to a\n * declared `time_intervals` array, the length check here would show a permanent false `update` —\n * the exact regression this whole file exists to prevent for OBJECT fields already. `mute-timing.\n * test.ts`'s \"array length is exact, not tolerant\" test pins today's behavior so that fix has an\n * obvious, single place to change (relax this rule, or give the mute-timing caller its own\n * length-tolerant wrapper) rather than being rediscovered from scratch.\n * ⚠️ `null` ON EITHER SIDE OF A LEAF NEVER MISMATCHES (mirrors `alchemy/Diff`'s `deepEqual` with\n * `stripNullish: true`, which this function replaces wherever a caller needs subset semantics).\n */\nconst isPlainObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nexport const declaredContentMatches = (declared: unknown, live: unknown): boolean => {\n if (declared == null) return true;\n if (Array.isArray(declared)) {\n return (\n Array.isArray(live) &&\n declared.length === live.length &&\n declared.every((item, index) => declaredContentMatches(item, live[index]))\n );\n }\n if (isPlainObject(declared)) {\n return (\n isPlainObject(live) &&\n Object.entries(declared).every(([key, value]) => declaredContentMatches(value, live[key]))\n );\n }\n return declared === live;\n};\n",
|
|
12
|
+
"/**\n * `Grafana.NotificationPolicy` — the notification policy tree. A SINGLETON: `GET`/`PUT`\n * `/v1/provisioning/policies` always address the ONE tree an instance has, there is no path\n * parameter, and `RouteGetPolicyTreeError` is `Forbidden | GrafanaOpError` — no `NotFound` case at\n * all, MEASURED. `fetchLive` therefore NEVER returns `undefined`: this resource has no create and\n * no delete in the sense every other resource in this family does — `reconcile`'s `before ===\n * undefined` branch (`resource.ts`) is dead code here, and `create` below exists only because\n * `GrafanaSpec.create` is a required field on the shared type, not because it is ever reached.\n * \"Declaring\" this resource means ADOPTING whatever tree is live and then keeping it in sync —\n * never creating or destroying the tree itself, only ever `PUT`-replacing its contents.\n *\n * ⛔ `routeResetPolicyTree` IS NEVER CALLED UNLESS `allowReset: true` IS EXPLICITLY DECLARED — a\n * second, independent gate on top of `defaultRemovalPolicy: 'retain'` below. Alchemy's own\n * removal-policy gate decides whether the engine calls this resource's `delete` handler AT ALL\n * (retain means it never does, unless a stack opts in with `.pipe(RemovalPolicy.destroy())` —\n * the convention every `Bao.*`/`Grafana.Folder`/`Grafana.AlertRuleGroup` family member already\n * uses); `allowReset` is a SEPARATE prop-level gate inside `destroy` itself, so even a stack that\n * opted into destroy at the Alchemy level still needs this resource's own explicit opt-in before\n * it will reset. Two gates, not one, because `routeResetPolicyTree` is uniquely destructive among\n * everything this family calls: it wipes every declared route, receiver reference and matcher\n * back to Grafana's own bare default in one call, for the WHOLE instance, not one object. Without\n * `allowReset`, `destroy` logs a warning and returns — retained, not reset.\n *\n * ★ PUT REPLACES THE WHOLE TREE — A DROPPED SUB-ROUTE IS WARNED ABOUT, NEVER SILENT. Same shape as\n * kit PR 254's `Grafana.AlertRuleGroup` fix (an adversarial review of that PR found the identical\n * risk for rule groups): `notification-policy-drop-warning.ts`'s `warnOnDroppedRoutes`, called\n * from both this resource's custom `diff` (so `bun run plan` shows it before anything is\n * written) and from `update` itself.\n *\n * ⛔ ROUTE ORDER IS SIGNIFICANT — NEVER REORDERED. Same as `Grafana.AlertRuleGroup`'s rules:\n * `subset-match.ts`'s array comparison is position-significant, and Alertmanager itself routes\n * an alert to the FIRST matching route in array order — reordering routes is a genuine routing\n * change, not cosmetic.\n *\n * ⛔ A FOREIGN-PROVENANCE TREE REFUSES EVERY UPDATE — `alerting-provenance.ts`, unchanged from kit\n * PR 250/254 (including the missing-means-foreign fix: `Route.provenance` is optional on the\n * wire, and `undefined` is never folded into `\"\"`). `create` is never at risk — see above, it is\n * unreachable.\n *\n * ⚠️ GRAFANA-INJECTED DEFAULTS ARE TOLERATED THE `declaredContentMatches` WAY, NOT HAND-NORMALIZED\n * — `matches()` below runs the (volatile-field-stripped) declared and live trees through\n * `subset-match.ts`'s tolerant-subset comparison, the same mechanism `Grafana.Dashboard`'s\n * panel-`datasource` auto-decoration and `Grafana.ContactPoint`'s settings defaults already rely\n * on: a live tree may carry additional fields, at any depth, the declaration never mentioned\n * (Grafana injecting a default `group_wait`/`group_interval`/`repeat_interval`/`group_by: []`\n * when the declaration omits them is the plausible case) without failing the match. ⚠️ NOT\n * MEASURED against a live instance — no live policy tree exists in this house to read (no live\n * calls in this PR either) — this is the documented, conservative default every unmeasured value\n * shape in this family takes, not a guess dressed up as a fact.\n *\n * ⚠️ `X-Disable-Provenance` IS NEVER SET — same reasoning as `contact-point.ts`'s file header.\n */\nimport { isResolved } from 'alchemy/Diff';\nimport type { Input } from 'alchemy/Input';\nimport { Resource } from 'alchemy';\nimport * as Provider from 'alchemy/Provider';\nimport * as grafana from '@distilled.cloud/grafana';\nimport * as Effect from 'effect/Effect';\nimport {\n type GrafanaProvisionedObjectError,\n isForeignProvenance,\n refuseIfForeignProvenance,\n} from './alerting-provenance.ts';\nimport { type PolicyRoute, normalizeRoute } from './notification-policy-model.ts';\nimport { warnOnDroppedRoutes } from './notification-policy-drop-warning.ts';\nimport { type GrafanaSpec, grafanaHandlers } from './resource.ts';\nimport { declaredContentMatches } from './subset-match.ts';\n\nexport type { PolicyRoute };\n\nexport interface NotificationPolicyProps {\n /** The root route and its full nested tree — Grafana's `Route` shape (`receiver`, `group_by`,\n * `matchers`, nested `routes[]`, …), passed through opaquely — see the file header. Order of\n * `routes[]` at every level is significant. */\n route: PolicyRoute;\n /** Lets `destroy` actually call `routeResetPolicyTree`. Defaults to `false` — see the file\n * header for why this is a second gate on top of Alchemy's own removal policy. */\n allowReset?: boolean;\n}\n\nexport interface NotificationPolicyAttributes {\n route: PolicyRoute;\n /** `\"\"`/`\"api\"` (this family may write); anything else, INCLUDING `undefined`, refuses — see\n * alerting-provenance.ts's \"fails open\" note. */\n provenance: string | undefined;\n}\n\nexport interface GrafanaNotificationPolicy extends Resource<\n 'Grafana.NotificationPolicy',\n NotificationPolicyProps,\n NotificationPolicyAttributes,\n never\n> {}\n\nexport const GrafanaNotificationPolicy = Resource<GrafanaNotificationPolicy>(\n 'Grafana.NotificationPolicy',\n { defaultRemovalPolicy: 'retain' },\n);\n\nconst body = (props: NotificationPolicyProps) =>\n props.route as unknown as grafana.RoutePutPolicyTreeRequest;\n\nexport const spec: GrafanaSpec<\n NotificationPolicyProps,\n grafana.Route,\n NotificationPolicyAttributes,\n | grafana.RouteGetPolicyTreeError\n | grafana.RoutePutPolicyTreeError\n | grafana.RouteResetPolicyTreeError\n | GrafanaProvisionedObjectError\n> = {\n attributes: (live) => ({\n provenance: live.provenance,\n route: normalizeRoute(live as unknown as PolicyRoute),\n }),\n // ⚠️ UNREACHABLE IN PRACTICE — see the file header. Implemented as the same PUT `update` sends,\n // defensively, rather than `Effect.die`, in case a future Grafana version ever does answer\n // `NotFound` here; `GrafanaSpec.create` is required by the shared type either way.\n create: (props) => grafana.routePutPolicyTree(body(props)),\n destroy: (props, live) =>\n Effect.gen(function* () {\n if (isForeignProvenance(live.provenance)) {\n return yield* refuseIfForeignProvenance(\n 'Grafana.NotificationPolicy',\n 'default',\n live.provenance,\n );\n }\n if (props.allowReset !== true) {\n yield* Effect.logWarning(\n 'Grafana.NotificationPolicy: destroy requested but allowReset is not set -- the policy ' +\n 'tree is RETAINED, not reset. Grafana always needs a root route; resetting wipes ' +\n \"every declared route/receiver/matcher back to Grafana's own default for the WHOLE \" +\n 'instance. Set allowReset: true to actually call routeResetPolicyTree.',\n );\n return;\n }\n yield* grafana.routeResetPolicyTree({});\n }),\n fetchLive: (_props) => grafana.routeGetPolicyTree({}),\n matches: (attributes, props) =>\n declaredContentMatches(normalizeRoute(props.route), attributes.route),\n update: (props, live) =>\n Effect.gen(function* () {\n if (isForeignProvenance(live.provenance)) {\n return yield* refuseIfForeignProvenance(\n 'Grafana.NotificationPolicy',\n 'default',\n live.provenance,\n );\n }\n yield* warnOnDroppedRoutes(props.route, live as unknown as PolicyRoute);\n yield* grafana.routePutPolicyTree(body(props));\n }),\n};\n\n/**\n * ⚠️ A LOCAL REIMPLEMENTATION OF `resource.ts`'s GENERIC `diff`, NOT A WRAP OF IT — same reasoning\n * as `alert-rule-group.ts`'s own `diff`: the generic version has no seam to run the drop-warning\n * side effect against the live tree it reads, and wrapping it would mean a second live fetch\n * just to see what it already saw.\n */\nconst diff = ({\n news,\n output,\n}: {\n news: Input<NotificationPolicyProps>;\n output: NotificationPolicyAttributes | undefined;\n}) =>\n Effect.gen(function* () {\n if (output === undefined || !isResolved(news)) return undefined;\n const live = yield* spec.fetchLive(news);\n // ⚠️ UNREACHABLE IN PRACTICE — see the file header: `routeGetPolicyTree` has no `NotFound`\n // case, so `live` is never actually `undefined`. `GrafanaSpec.fetchLive`'s shared return\n // type is `Live | undefined` for every resource in the family, so this check exists purely\n // to satisfy that type, the same defensive stance `create` above takes.\n if (live === undefined) return { action: 'update' } as const;\n yield* warnOnDroppedRoutes(news.route, live as unknown as PolicyRoute);\n const mapped = spec.attributes(live, news);\n return mapped !== undefined && spec.matches(mapped, news)\n ? ({ action: 'noop' } as const)\n : ({ action: 'update' } as const);\n });\n\nexport const handlers = { ...grafanaHandlers(spec), diff };\n\nexport const GrafanaNotificationPolicyProvider = () =>\n Provider.effect(\n GrafanaNotificationPolicy,\n Effect.succeed(GrafanaNotificationPolicy.Provider.of(handlers)),\n );\n",
|
|
13
|
+
"/**\n * Pure functions over the notification policy tree — no SDK call, no Effect. Split out of\n * `notification-policy.ts` the same way `dashboard-model.ts`/`alert-rule-group-model.ts` are split\n * out of their resources.\n *\n * ★ THE TREE IS OPAQUE `Record<string, unknown>`, NOT THE SDK's OWN `Route` TYPE — same reasoning\n * as `mute-timing.ts`'s `timeIntervals`: Grafana's `Matchers`/`ObjectMatchers`/`MatchRegexps`\n * (matcher expression shapes) are complex nested union/array types this family does not attempt\n * to model field-by-field. `routePutPolicyTree`'s request body encodes/decodes any key\n * verbatim regardless (the same unmodeled-key passthrough `mute-timing.ts`'s file header\n * documents for this SDK generally), so an opaque pass-through both round-trips correctly and\n * stays usable for every matcher/route shape Grafana accepts, not just the ones this file would\n * otherwise hand-model.\n */\nexport type PolicyRoute = Record<string, unknown>;\n\n/** Grafana-managed, never declared content. MEASURED against `Route` (services/grafana.ts):\n * `provenance` is the only field on this type that is unambiguously read-only (every other field\n * — `receiver`, `group_by`, `matchers`, `routes`, … — is exactly what a declaration sets). An\n * object this family just wrote reads back with `provenance: \"api\"`, which the declaration never\n * sets, so comparing it would show a false `update` forever — the same reasoning\n * `alert-rule-group-model.ts`'s own `RULE_VOLATILE_FIELDS` note gives for a rule's `provenance`.\n * Stripped RECURSIVELY: `Route.routes` is `Array<Route>`, so a nested route could in principle\n * carry its own `provenance` too — not measured live (no live policy tree in this house to read),\n * but stripping it everywhere is the conservative reading, the same one `provisioned.ts`'s\n * `managedBy` note takes for an unmeasured value shape. */\nconst ROUTE_VOLATILE_FIELDS = ['provenance'] as const;\n\nexport const normalizeRoute = (route: PolicyRoute): PolicyRoute => {\n const out: PolicyRoute = {};\n for (const [key, value] of Object.entries(route)) {\n if ((ROUTE_VOLATILE_FIELDS as readonly string[]).includes(key)) continue;\n if (key === 'routes' && Array.isArray(value)) {\n out.routes = value.map((child) => normalizeRoute(child as PolicyRoute));\n continue;\n }\n out[key] = value;\n }\n return out;\n};\n\nexport interface FlatRoute {\n /** Dotted child-index path from the root, e.g. `root.0.1` — WHERE this occurrence sits, for the\n * warning message only; never part of `key`. */\n readonly path: string;\n readonly receiver: string;\n /**\n * Identity for the dropped-route warning — MEASURED FIX (an adversarial review of this PR found\n * the first version's identity, plain per-node JSON in a `Set`, collided across the WHOLE TREE:\n * a duplicate route added anywhere, not just as a live-only sibling, silently matched an\n * unrelated declared node with the same fields and the drop went unwarned). `key` is now the\n * chain of ancestor own-fields from the root down to this node (this node's own fields included,\n * `routes` children excluded at every level, `\\0`-joined — a byte no route's own JSON can\n * contain): two nodes are \"the same\" only if they sit under the identical lineage of ancestors,\n * which makes an identical route under a DIFFERENT parent correctly distinct, while still being\n * ORDER-INSENSITIVE among siblings (a shared parent contributes the same ancestor key to every\n * child regardless of index) — a plain reorder is never reported as a drop.\n * `notification-policy-drop-warning.ts` counts occurrences of each `key` as a MULTISET (declared\n * count vs. live count), not set membership, so N live duplicates of the same node under the\n * same parent are only \"dropped\" past however many the declaration itself repeats.\n */\n readonly key: string;\n}\n\nconst ownFieldsJson = (route: PolicyRoute): string => {\n const { routes: _routes, ...ownFields } = route;\n return JSON.stringify(ownFields);\n};\n\n/**\n * Depth-first flatten of a (already-normalized) route tree, `root` itself included at `path:\n * 'root'` and `key` equal to its own fields alone (no ancestor to chain from). Used only by\n * `notification-policy-drop-warning.ts`'s best-effort \"what did this write remove\" detection —\n * `matches()` in `notification-policy.ts` never uses this, only `declaredContentMatches` on the\n * tree as a whole, so nothing about drift DETECTION depends on it.\n *\n * ⚠️ STILL A BEST-EFFORT KEY, NOT A STABLE ONE — Grafana's policy routes have no id/uid the way\n * every other object in this family does; `key` is a measured, deliberate improvement over plain\n * per-node identity (see `FlatRoute.key`'s own doc), not a claim of a real Grafana-side key. A\n * false negative here (missing a genuine drop) never hides real drift from `matches()`, which\n * compares the whole tree structurally regardless of this file.\n */\nexport const flattenRoutes = (\n route: PolicyRoute,\n path = 'root',\n ancestorKey = '',\n): ReadonlyArray<FlatRoute> => {\n const children = Array.isArray(route.routes) ? (route.routes as PolicyRoute[]) : [];\n const ownJson = ownFieldsJson(route);\n const key = ancestorKey === '' ? ownJson : `${ancestorKey}\\0${ownJson}`;\n const self: FlatRoute = {\n key,\n path,\n receiver: typeof route.receiver === 'string' ? route.receiver : '(inherited)',\n };\n return [\n self,\n ...children.flatMap((child, index) => flattenRoutes(child, `${path}.${index}`, key)),\n ];\n};\n",
|
|
14
|
+
"/**\n * The warning `Grafana.NotificationPolicy` logs when a whole-tree `PUT` would silently drop a live\n * sub-route the declaration doesn't account for — same shape as `alert-rule-group-drop-warning.ts`\n * (kit PR 254's own fix, after an adversarial review found the identical risk for rule groups):\n * `PUT /v1/provisioning/policies` REPLACES the entire tree, so a nested route someone added\n * out-of-band is removed with no error and no distinct `Diff` action to report it under.\n *\n * ★ `Effect.logWarning`, NEVER A REFUSAL — same reasoning as `alert-rule-group-drop-warning.ts`'s\n * own header, and further upstream `proxmox/unreadable-read.ts`'s `unreadableWarning`. A\n * whole-tree write dropping an out-of-band route is EXPECTED for a resource whose whole point is\n * to own the tree — only a silent one is worth surfacing loudly.\n *\n * ⛔ MULTISET COMPARISON, NOT SET MEMBERSHIP — fixed after an adversarial review of this PR found\n * the first version's `Set`-based check collided ACROSS THE WHOLE TREE: any two nodes anywhere\n * with identical own-fields shared one `Set` entry, so a duplicate route added out-of-band\n * (e.g. a second `severity=warning -> slack` alongside an already-declared one) matched the\n * existing entry and went unwarned even though the PUT would still drop it — worse than the\n * documented \"siblings only\" limitation the original comment claimed. Every key from\n * `FlatRoute.key` (ancestry-scoped — see that field's own doc) is now counted per side, and a\n * `key` is only \"dropped\" for the amount its LIVE count exceeds its DECLARED count — N identical\n * live occurrences under the same parent are dropped only past however many the declaration\n * itself repeats, never all of them at once just because one is declared.\n */\nimport * as Effect from 'effect/Effect';\nimport { type PolicyRoute, flattenRoutes, normalizeRoute } from './notification-policy-model.ts';\n\nconst countByKey = (routes: ReadonlyArray<{ readonly key: string }>): Map<string, number> => {\n const counts = new Map<string, number>();\n for (const route of routes) counts.set(route.key, (counts.get(route.key) ?? 0) + 1);\n return counts;\n};\n\nexport const warnOnDroppedRoutes = (\n declared: PolicyRoute,\n live: PolicyRoute,\n): Effect.Effect<void> =>\n Effect.gen(function* () {\n // Root is never \"dropped\" — it is always replaced, not removed (the file header's own note).\n const declaredNodes = flattenRoutes(normalizeRoute(declared)).filter((r) => r.path !== 'root');\n const liveNodes = flattenRoutes(normalizeRoute(live)).filter((r) => r.path !== 'root');\n const declaredCounts = countByKey(declaredNodes);\n const liveCounts = countByKey(liveNodes);\n\n const dropped: Array<{ readonly path: string; readonly receiver: string }> = [];\n for (const [key, liveCount] of liveCounts) {\n const extra = liveCount - (declaredCounts.get(key) ?? 0);\n if (extra <= 0) continue;\n // Report the LAST `extra` live occurrences of this key, by path — an arbitrary but\n // deterministic choice among indistinguishable duplicates (multiset identity, no position).\n const occurrences = liveNodes.filter((route) => route.key === key);\n dropped.push(...occurrences.slice(-extra));\n }\n if (dropped.length === 0) return;\n const names = dropped.map((route) => `${route.receiver} (${route.path})`).join(', ');\n yield* Effect.logWarning(\n `Grafana.NotificationPolicy: this update REMOVES ${dropped.length} route(s)/matcher(s) not ` +\n `in the declaration: ${names}. Whole-tree replacement is by design — add them to the ` +\n `declared tree to keep them.`,\n );\n });\n",
|
|
12
15
|
"/**\n * `Grafana.Datasource` — one Grafana data source, keyed by `uid`.\n *\n * ★ WHY `uid` IS REQUIRED, NOT GENERATED. `getDataSourceByUID`/`updateDataSourceByUID`/\n * `deleteDataSourceByUID` are all UID-keyed, and `getDataSources` (list) takes no filter — so\n * locating a datasource this resource didn't create means listing the whole org and matching by\n * name, the same ambiguity netbox/resource.ts's `soleMatch` exists to catch. Requiring `uid` up\n * front (Grafana accepts a caller-chosen one on create — `AddDataSourceRequest.uid`) sidesteps\n * it entirely: `read`/`reconcile`/`destroy` all key on the one field the API itself is keyed on.\n * `teslamate-grafana`'s live datasource (provisioned from a file, not this resource) has a\n * Grafana-generated uid; the census in the handoff script records it so a first declaration can\n * name it explicitly.\n *\n * ⛔ `secureJsonData` (e.g. a datasource password) NEVER APPEARS AS A LITERAL PROP (S25).\n * `secureJsonDataRefs` takes env var NAMES instead; `resolveSecureJsonData` reads them from\n * `process.env` fresh inside `create`/`update`'s own effect, never at plan time and never\n * returned in `attributes` — Grafana's own read API agrees: `DataSource.secureJsonFields` on a\n * GET is a map of booleans (is-it-set), never the value.\n */\nimport { Resource } from 'alchemy';\nimport * as Provider from 'alchemy/Provider';\nimport * as grafana from '@distilled.cloud/grafana';\nimport * as Effect from 'effect/Effect';\nimport { type GrafanaSpec, grafanaHandlers } from './resource.ts';\nimport { GrafanaSecretRefUnsetError, resolveSecretRefs } from './secret-refs.ts';\n\nexport { GrafanaSecretRefUnsetError };\n\nexport interface DatasourceProps {\n uid: string;\n name: string;\n /** e.g. `postgres`, `prometheus`, `influxdb` — the Grafana plugin id. */\n type: string;\n url?: string;\n access?: 'proxy' | 'direct';\n database?: string;\n user?: string;\n basicAuth?: boolean;\n basicAuthUser?: string;\n isDefault?: boolean;\n withCredentials?: boolean;\n jsonData?: Record<string, unknown>;\n /** Secure field name (e.g. `password`) -> env var NAME holding its value. Never the value. */\n secureJsonDataRefs?: Record<string, string>;\n}\n\nexport interface DatasourceAttributes {\n uid: string;\n id: number;\n name: string;\n type: string;\n url: string;\n access: string;\n orgId: number;\n isDefault: boolean;\n readOnly: boolean;\n version: number;\n}\n\nexport interface GrafanaDatasource extends Resource<\n 'Grafana.Datasource',\n DatasourceProps,\n DatasourceAttributes,\n never\n> {}\n\nexport const GrafanaDatasource = Resource<GrafanaDatasource>('Grafana.Datasource');\n\n/** Reads every named env var fresh, inside the caller's effect (S24) — never at plan time. */\nconst resolveSecureJsonData = (refs: Record<string, string> | undefined) =>\n resolveSecretRefs(refs, (field) => `secureJsonData.${field}`);\n\n/** `exactOptionalPropertyTypes` means an undeclared field must be OMITTED, never sent as `undefined`. */\nconst fields = (props: DatasourceProps) => ({\n name: props.name,\n type: props.type,\n ...(props.access === undefined ? {} : { access: props.access }),\n ...(props.basicAuth === undefined ? {} : { basicAuth: props.basicAuth }),\n ...(props.basicAuthUser === undefined ? {} : { basicAuthUser: props.basicAuthUser }),\n ...(props.database === undefined ? {} : { database: props.database }),\n ...(props.isDefault === undefined ? {} : { isDefault: props.isDefault }),\n ...(props.jsonData === undefined ? {} : { jsonData: props.jsonData }),\n ...(props.url === undefined ? {} : { url: props.url }),\n ...(props.user === undefined ? {} : { user: props.user }),\n ...(props.withCredentials === undefined ? {} : { withCredentials: props.withCredentials }),\n});\n\nexport const spec: GrafanaSpec<\n DatasourceProps,\n grafana.DataSource,\n DatasourceAttributes,\n | grafana.AddDataSourceError\n | grafana.GetDataSourceByUIDError\n | grafana.UpdateDataSourceByUIDError\n | grafana.DeleteDataSourceByUIDError\n | GrafanaSecretRefUnsetError\n> = {\n attributes: (live) => ({\n access: live.access ?? '',\n id: live.id ?? 0,\n isDefault: live.isDefault ?? false,\n name: live.name ?? '',\n orgId: live.orgId ?? 0,\n readOnly: live.readOnly ?? false,\n type: live.type ?? '',\n uid: live.uid ?? '',\n url: live.url ?? '',\n version: live.version ?? 0,\n }),\n create: (props) =>\n Effect.flatMap(resolveSecureJsonData(props.secureJsonDataRefs), (secureJsonData) =>\n grafana.addDataSource({\n ...fields(props),\n ...(secureJsonData === undefined ? {} : { secureJsonData }),\n uid: props.uid,\n }),\n ),\n destroy: (props) => grafana.deleteDataSourceByUID({ uid: props.uid }),\n fetchLive: (props) =>\n grafana\n .getDataSourceByUID({ uid: props.uid })\n .pipe(Effect.catchTag('NotFound', () => Effect.succeed(undefined))),\n /**\n * ⛔ AN UNDECLARED FIELD IS NEITHER COMPARED NOR SENT — the same rule every family in this\n * estate follows. `secureJsonDataRefs` is never compared: Grafana never returns the value to\n * diff against, only whether a field is set (`secureJsonFields`), so this resource cannot\n * detect drift in a secret's value — only in whether one is configured at all.\n */\n matches: (attributes, props) =>\n (props.name === undefined || attributes.name === props.name) &&\n (props.type === undefined || attributes.type === props.type) &&\n (props.url === undefined || attributes.url === props.url) &&\n (props.access === undefined || attributes.access === props.access) &&\n (props.isDefault === undefined || attributes.isDefault === props.isDefault),\n update: (props, live) =>\n Effect.flatMap(resolveSecureJsonData(props.secureJsonDataRefs), (secureJsonData) =>\n grafana.updateDataSourceByUID({\n ...fields(props),\n ...(secureJsonData === undefined ? {} : { secureJsonData }),\n ...(live.version === undefined ? {} : { version: live.version }),\n uid: props.uid,\n }),\n ),\n};\n\nexport const handlers = grafanaHandlers(spec);\n\nexport const GrafanaDatasourceProvider = () =>\n Provider.effect(GrafanaDatasource, Effect.succeed(GrafanaDatasource.Provider.of(handlers)));\n",
|
|
13
16
|
"/**\n * Shared \"secret stays in env, never in state\" resolution (S25) for this family —\n * `Grafana.Datasource`'s `secureJsonDataRefs` and `Grafana.ContactPoint`'s `secureSettingsRefs`\n * are the identical shape: a map of field name to an env var NAME, resolved fresh from\n * `process.env` inside the caller's own create/update effect (S24), never at plan time and never\n * returned in `attributes`. Extracted here once a second family needed the exact same loop\n * `datasource.ts` already had — see that file's original note for why this exists at all:\n * Grafana's own read APIs never return a secret value, only whether one is set\n * (`DataSource.secureJsonFields`'s booleans; a contact point's `settings` comes back with secure\n * keys replaced by a literal redaction placeholder instead — see contact-point.ts).\n */\nimport * as Data from 'effect/Data';\nimport * as Effect from 'effect/Effect';\n\n/** A named secure-field env var is unset — a domain refusal, not a distilled error. */\nexport class GrafanaSecretRefUnsetError extends Data.TaggedError('GrafanaSecretRefUnsetError')<{\n readonly message: string;\n}> {}\n\n/**\n * Reads every named env var fresh, inside the caller's effect (S24) — never at plan time.\n * `describeField` builds the refusal message's own field-specific phrase — each caller names its\n * declaration path differently (`secureJsonData.<field>` for a datasource,\n * `settings.<field>` for a contact point) — so the message stays accurate to what the caller\n * itself declares.\n */\nexport const resolveSecretRefs = (\n refs: Record<string, string> | undefined,\n describeField: (field: string) => string,\n): Effect.Effect<Record<string, string> | undefined, GrafanaSecretRefUnsetError> =>\n Effect.gen(function* () {\n if (refs === undefined) return undefined;\n const out: Record<string, string> = {};\n for (const [field, envVar] of Object.entries(refs)) {\n const raw = process.env[envVar];\n if (raw === undefined || raw.trim() === '') {\n return yield* Effect.fail(\n new GrafanaSecretRefUnsetError({\n message:\n `${envVar} is unset. Export the value of ${describeField(field)} there — ` +\n 'never as an Alchemy prop.',\n }),\n );\n }\n out[field] = raw.trim();\n }\n return out;\n });\n",
|
|
14
17
|
"/**\n * `Grafana.Dashboard` — one Grafana dashboard, keyed by `uid`. Same uid-required doctrine as\n * `datasource.ts`/`folder.ts` (`getDashboard`/`postDashboard`/`deleteDashboard` are all UID-keyed\n * on the wire — `postDashboard`'s own `uid` travels INSIDE the `dashboard` JSON body, not as a\n * request field, because Grafana's classic dashboard-save API has never had one; see\n * `dashboard-model.ts`'s `normalizeModel`, which is what puts it there).\n *\n * ★ THE DECLARED CONTENT IS THE DASHBOARD JSON MODEL — `DashboardProps.dashboard`, the same shape\n * Grafana's own \"Export as JSON\" produces. `dashboard-model.ts`'s `normalizeModel` strips the\n * volatile fields (`id`, `version`, `iteration`) and forces `uid` to this resource's own value\n * before ANY comparison, so a plan against an unchanged dashboard is a true noop despite those\n * fields moving on every live save — see that file for the full reasoning, including which\n * fields (`panels`, `targets`) are array-ORDER-significant and compared as such.\n *\n * ⛔ `matches` COMPARES \"IS THE DECLARATION A SUBSET OF WHAT IS LIVE\", NOT PLAIN EQUALITY —\n * `dashboard-model.ts`'s `declaredContentMatches`, added after an adversarial review of this PR\n * found plain `deepEqual` made an ordinary dashboard show `update` FOREVER: Grafana's own\n * schema-migration on save decorates any panel/target whose `datasource` is absent with an\n * explicit reference, so a declaration that never sets one would permanently disagree with what\n * it reads back. See that function's own header for the full reasoning and the trade-off it\n * accepts (an omitted field can no longer be used to CLEAR a previously-set one).\n *\n * ⛔ VERSION CONFLICTS (412) FAIL LOUDLY — NEVER OVERWRITTEN BLINDLY. `update` injects the\n * `version` this resource just read (`live.meta.version`, from the SAME `fetchLive` call\n * `resource.ts`'s `reconcile` already made before calling `update`) into the model it sends, and\n * `overwrite` is never set. If Grafana's own version check then still fails — someone else saved\n * in the gap between that read and this write — `postDashboard` answers `412` and\n * `PreconditionFailed` is left IN the error union below, uncaught: the whole reconcile fails, the\n * deploy stops, and nothing is written. The next run's `fetchLive` re-reads the new live version\n * fresh, which is the \"re-read\" half of \"re-read and fail loudly\" — there is no separate retry\n * loop in this file, because the next `plan`/`deploy` invocation already IS that re-read.\n *\n * ⛔ A PROVISIONED DASHBOARD (`meta.provisioned` — see provisioned.ts) REFUSES EVERY UPDATE AND\n * DESTROY, naming `meta.provisionedExternalId` (the file) when Grafana reports one. `matches`\n * still compares structurally regardless, so a mismatched declaration against a provisioned\n * dashboard shows `update` in a plan rather than a silent, permanently-hidden noop.\n *\n * ⚠️ NO RETAIN DEFAULT, UNLIKE `Grafana.Folder`. Deleting one dashboard is a single-object blast\n * radius — the same class `Grafana.Datasource` already accepts without a retain guard — not\n * folder.ts's multi-object cascade (a folder's delete takes its dashboards AND their alert rules\n * with it). See folder.ts's file header for the full contrast.\n */\nimport { Resource } from 'alchemy';\nimport * as Provider from 'alchemy/Provider';\nimport * as grafana from '@distilled.cloud/grafana';\nimport * as Effect from 'effect/Effect';\nimport {\n type DashboardModel,\n declaredContentMatches,\n modelTitle,\n normalizeModel,\n} from './dashboard-model.ts';\nimport { type GrafanaProvisionedObjectError, refuseIfProvisioned } from './provisioned.ts';\nimport { type GrafanaSpec, grafanaHandlers } from './resource.ts';\n\nexport type { DashboardModel };\n\nexport interface DashboardProps {\n uid: string;\n /** Omit for the General/root folder. */\n folderUid?: string;\n /** The dashboard JSON model — see the file header. `id`/`version`/`iteration`/`uid` inside it\n * are ignored; `uid` above is the single source of truth. */\n dashboard: DashboardModel;\n}\n\nexport interface DashboardAttributes {\n uid: string;\n title: string;\n version: number;\n folderUid: string;\n url: string;\n /** True when Grafana reports this dashboard as file-provisioned (read-only — see provisioned.ts). */\n provisioned: boolean;\n provisionedExternalId: string;\n /** The live model, normalized the same way `matches` compares it. */\n dashboard: DashboardModel;\n}\n\nexport interface GrafanaDashboard extends Resource<\n 'Grafana.Dashboard',\n DashboardProps,\n DashboardAttributes,\n never\n> {}\n\nexport const GrafanaDashboard = Resource<GrafanaDashboard>('Grafana.Dashboard');\n\nconst modelOf = (live: grafana.DashboardFullWithMeta): DashboardModel =>\n live.dashboard !== null && typeof live.dashboard === 'object'\n ? (live.dashboard as DashboardModel)\n : {};\n\nexport const spec: GrafanaSpec<\n DashboardProps,\n grafana.DashboardFullWithMeta,\n DashboardAttributes,\n | grafana.GetDashboardError\n | grafana.PostDashboardError\n | grafana.DeleteDashboardError\n | GrafanaProvisionedObjectError\n> = {\n attributes: (live, props) => {\n const model = normalizeModel(modelOf(live), props.uid);\n return {\n dashboard: model,\n folderUid: live.meta?.folderUid ?? '',\n provisioned: live.meta?.provisioned ?? false,\n provisionedExternalId: live.meta?.provisionedExternalId ?? '',\n title: modelTitle(model),\n uid: props.uid,\n url: live.meta?.url ?? '',\n version: live.meta?.version ?? 0,\n };\n },\n create: (props) =>\n grafana.postDashboard({\n dashboard: normalizeModel(props.dashboard, props.uid),\n ...(props.folderUid === undefined ? {} : { folderUid: props.folderUid }),\n }),\n destroy: (props, live) =>\n Effect.gen(function* () {\n if (live.meta?.provisioned) {\n return yield* refuseIfProvisioned(\n 'Grafana.Dashboard',\n props.uid,\n live.meta.provisionedExternalId,\n );\n }\n yield* grafana.deleteDashboard({ uid: props.uid });\n }),\n fetchLive: (props) =>\n grafana\n .getDashboard({ uid: props.uid })\n .pipe(Effect.catchTag('NotFound', () => Effect.succeed(undefined))),\n matches: (attributes, props) =>\n (props.folderUid === undefined || attributes.folderUid === props.folderUid) &&\n declaredContentMatches(normalizeModel(props.dashboard, props.uid), attributes.dashboard),\n update: (props, live) =>\n Effect.gen(function* () {\n if (live.meta?.provisioned) {\n return yield* refuseIfProvisioned(\n 'Grafana.Dashboard',\n props.uid,\n live.meta.provisionedExternalId,\n );\n }\n return yield* grafana.postDashboard({\n dashboard: {\n ...normalizeModel(props.dashboard, props.uid),\n ...(live.meta?.version === undefined ? {} : { version: live.meta.version }),\n },\n ...(props.folderUid === undefined ? {} : { folderUid: props.folderUid }),\n });\n }),\n};\n\nexport const handlers = grafanaHandlers(spec);\n\nexport const GrafanaDashboardProvider = () =>\n Provider.effect(GrafanaDashboard, Effect.succeed(GrafanaDashboard.Provider.of(handlers)));\n",
|
|
@@ -18,9 +21,9 @@
|
|
|
18
21
|
"/**\n * `Grafana.MessageTemplate` — one Grafana notification-template group, keyed by `name`.\n *\n * ⚠️ CREATE AND UPDATE ARE THE SAME WIRE CALL — MEASURED: `services/grafana.ts` has no\n * `routePostTemplate` at all, only `routePutTemplate` (`PUT /v1/provisioning/templates/{name}`,\n * upsert by name), `routeGetTemplate`/`routeGetTemplates` and `routeDeleteTemplate`. `spec.create`\n * and `spec.update` both call it — kept as two separate functions anyway (rather than omitting\n * `update` and letting them collapse into one) so the shared engine's `diff` reports a content\n * change as `update`, not the `replace` it would show for any resource whose `spec.update` is\n * undefined (`resource.ts`).\n *\n * ⛔ A FOREIGN-PROVENANCE TEMPLATE REFUSES EVERY UPDATE AND DESTROY — `alerting-provenance.ts`,\n * shared with `Grafana.ContactPoint`/`AlertRuleGroup`/`NotificationPolicy`; see that file's\n * header. `create` is never at risk: it only runs when `fetchLive` already found nothing.\n *\n * ⚠️ `version` IS SENT FOR OPTIMISTIC CONCURRENCY WHEN GRAFANA REPORTS ONE — `RoutePutTemplateRequest.\n * version`'s own doc comment: \"Version of template to use for optimistic concurrency. Leave empty\n * to disable validation.\" Unlike `Grafana.Dashboard`'s 412, no live call confirms what error this\n * produces on a genuine mismatch (no live calls in this PR) — whatever typed error the SDK\n * declares for `routePutTemplate` is left uncaught either way, per the house rule against\n * folding a non-not-found error into absent.\n *\n * ⚠️ `X-Disable-Provenance` IS NEVER SET — same reasoning as `contact-point.ts`'s file header.\n */\nimport { Resource } from 'alchemy';\nimport * as Provider from 'alchemy/Provider';\nimport * as grafana from '@distilled.cloud/grafana';\nimport * as Effect from 'effect/Effect';\nimport {\n type GrafanaProvisionedObjectError,\n isForeignProvenance,\n refuseIfForeignProvenance,\n} from './alerting-provenance.ts';\nimport { type GrafanaSpec, grafanaHandlers } from './resource.ts';\n\nexport interface MessageTemplateProps {\n name: string;\n /** The Go-template body, e.g. Grafana's own \"Export as JSON/YAML\" template text. */\n template: string;\n}\n\nexport interface MessageTemplateAttributes {\n name: string;\n template: string;\n /** `\"\"`/`\"api\"` (this family may write); anything else, INCLUDING `undefined` (Grafana didn't\n * report the field), refuses — see alerting-provenance.ts's \"fails open\" note. */\n provenance: string | undefined;\n}\n\nexport interface GrafanaMessageTemplate extends Resource<\n 'Grafana.MessageTemplate',\n MessageTemplateProps,\n MessageTemplateAttributes,\n never\n> {}\n\nexport const GrafanaMessageTemplate = Resource<GrafanaMessageTemplate>('Grafana.MessageTemplate');\n\nexport const spec: GrafanaSpec<\n MessageTemplateProps,\n grafana.NotificationTemplate,\n MessageTemplateAttributes,\n | grafana.RouteGetTemplateError\n | grafana.RoutePutTemplateError\n | grafana.RouteDeleteTemplateError\n | GrafanaProvisionedObjectError\n> = {\n attributes: (live) => ({\n name: live.name ?? '',\n // ⛔ NEVER `?? ''` — see alerting-provenance.ts's \"fails open\" note.\n provenance: live.provenance,\n template: live.template ?? '',\n }),\n create: (props) => grafana.routePutTemplate({ name: props.name, template: props.template }),\n destroy: (props, live) =>\n Effect.gen(function* () {\n if (isForeignProvenance(live.provenance)) {\n return yield* refuseIfForeignProvenance(\n 'Grafana.MessageTemplate',\n props.name,\n live.provenance,\n );\n }\n yield* grafana.routeDeleteTemplate({ name: props.name });\n }),\n fetchLive: (props) =>\n grafana\n .routeGetTemplate({ name: props.name })\n .pipe(Effect.catchTag('NotFound', () => Effect.succeed(undefined))),\n matches: (attributes, props) => attributes.template === props.template,\n update: (props, live) =>\n Effect.gen(function* () {\n if (isForeignProvenance(live.provenance)) {\n return yield* refuseIfForeignProvenance(\n 'Grafana.MessageTemplate',\n props.name,\n live.provenance,\n );\n }\n yield* grafana.routePutTemplate({\n name: props.name,\n template: props.template,\n ...(live.version === undefined ? {} : { version: live.version }),\n });\n }),\n};\n\nexport const handlers = grafanaHandlers(spec);\n\nexport const GrafanaMessageTemplateProvider = () =>\n Provider.effect(\n GrafanaMessageTemplate,\n Effect.succeed(GrafanaMessageTemplate.Provider.of(handlers)),\n );\n",
|
|
19
22
|
"/**\n * `Grafana.MuteTiming` — one Grafana alerting mute timing, keyed by `name` (there is no separate\n * `uid` — `routeGetMuteTiming`/`routePutMuteTiming`/`routeDeleteMuteTiming` are all name-keyed on\n * the wire, and `name` is the field a notification policy's own `mute_time_intervals` references).\n *\n * ★ `provenance`/`version` ARE READ THROUGH A WIDENED TYPE, NOT THE SDK's OWN `MuteTimeInterval` —\n * MEASURED, and a genuinely surprising result worth recording in full. The SDK's generated\n * `MuteTimeInterval` interface (`packages/distilled-grafana/src/services/grafana.ts`) declares\n * only `name`/`time_intervals` — no `provenance`, no `version` — unlike `EmbeddedContactPoint`/\n * `NotificationTemplate`/`ProvisionedAlertRule`/`Route`, which all carry `provenance`. A first\n * pass at this file assumed that meant the data was gone: decoding a raw payload containing both\n * fields through `S.decodeUnknownSync(MuteTimeInterval)` directly DOES strip them. But that is\n * the wrong code path — it is not what `routeGetMuteTiming` itself does. Proven empirically by\n * calling the REAL operation (through `fake-grafana.ts`'s harness, the exact path this file's own\n * `fetchLive` uses) with a response body containing `provenance`/`version`: both come through on\n * the decoded value intact. The mechanism, read from `@distilled.cloud/core@1.0.0-rc.12`'s\n * `protocol-rest.ts`/`protocol-http.ts` (the runtime this SDK's every operation shares): response\n * decoding is `JSON.parse` + `mapKeys` (renames only the field names a schema DOES declare) +\n * `wrapSensitive` (wraps only fields a schema marks sensitive in `Redacted`) — never a strict\n * `Schema.decode`. `protocol-http.ts`'s `mapKeys`, object branch: every response key NOT among a\n * type's declared `props` is copied to the output verbatim in a second pass\n * (`for (const [k, v] of Object.entries(value)) { if (consumed.has(k)) continue; out[k] = v; }`,\n * line ~297-311) — the doc comment on the sibling `wrapSensitive` states the same rule plainly:\n * \"Keys the schema doesn't model pass through verbatim.\" So the TS type is simply narrower than\n * the runtime value; `MuteTimeIntervalWire` below is that same runtime value, typed honestly.\n * This is a real, worth-fixing SDK type-generation gap (tracked in `docs/upstream-conformance.md`,\n * same S22 route as the other named gaps) but NOT a data-loss gap — unlike, say, a field the wire\n * protocol itself never sent, this one is fully recoverable without touching vendored `src/`.\n *\n * The same test proved the outbound direction too: an object with extra keys (`weekdays`, `times`\n * — the real Alertmanager time-interval fields Grafana's OpenAPI's own `TimeInterval` schema\n * apparently fails to model either, for the same reason) passed to `routePutMuteTiming` reaches\n * the wire body unchanged — `mapKeys`'s encode direction is the same verbatim-passthrough rule.\n * `MuteTimingProps.timeIntervals` is therefore typed as the opaque `Record<string, unknown>`\n * shape actually needed to declare a real mute timing (weekdays/times/months/etc.), not the\n * SDK's own too-narrow `TimeInterval`, and cast at the two call sites below.\n *\n * ⚠️ THE EVIDENCE ABOVE IS A HAND-AUTHORED FIXTURE, NOT A CAPTURED REAL RESPONSE — flagged by an\n * adversarial review of this PR. The estate has zero live mute timings to observe (grafana.md's\n * census), so nothing confirms Grafana always includes `provenance` on this route in practice,\n * or that some other SDK/version edge case never drops it. That is exactly why `attributes()`\n * below never coerces a missing `live.provenance` to `''` — see alerting-provenance.ts's \"fails\n * open\" note — an absent field refuses a write rather than being trusted as `ProvenanceNone`.\n *\n * ⛔ A FOREIGN-PROVENANCE MUTE TIMING REFUSES EVERY UPDATE AND DESTROY — `alerting-provenance.ts`,\n * shared with `Grafana.ContactPoint`/`MessageTemplate`/`AlertRuleGroup`/`NotificationPolicy`; see\n * that file's header. `create` is never at risk: it only runs when `fetchLive` already found\n * nothing with this `name`.\n *\n * ⚠️ `version` IS SENT ON DESTROY, NOT ON UPDATE — MEASURED: `RouteDeleteMuteTimingRequest.version`\n * (\"Version of mute timing to use for optimistic concurrency. Leave empty to disable validation\")\n * exists; `RoutePutMuteTimingRequest` has no `version` field at all, so an update has nothing to\n * send for it — a real Grafana API asymmetry between the two write routes, not an omission here.\n *\n * ⚠️ `X-Disable-Provenance` IS NEVER SET — same reasoning as `contact-point.ts`'s file header.\n */\nimport { Resource } from 'alchemy';\nimport * as Provider from 'alchemy/Provider';\nimport * as grafana from '@distilled.cloud/grafana';\nimport * as Effect from 'effect/Effect';\nimport {\n type GrafanaProvisionedObjectError,\n isForeignProvenance,\n refuseIfForeignProvenance,\n} from './alerting-provenance.ts';\nimport { type GrafanaSpec, grafanaHandlers } from './resource.ts';\nimport { declaredContentMatches } from './subset-match.ts';\n\nexport interface MuteTimingProps {\n name: string;\n /** Grafana's Alertmanager-style time-interval entries (`weekdays`/`times`/`months`/…), passed\n * through opaquely — see the file header for why this is not the SDK's own `TimeInterval`. */\n timeIntervals: ReadonlyArray<Record<string, unknown>>;\n}\n\nexport interface MuteTimingAttributes {\n name: string;\n timeIntervals: ReadonlyArray<Record<string, unknown>>;\n /** `\"\"`/`\"api\"` (this family may write); anything else, INCLUDING `undefined` (Grafana didn't\n * report the field, or the widened-type passthrough this file depends on turns out not to hold\n * for some response shape not yet observed), refuses — see alerting-provenance.ts's \"fails\n * open\" note. This is the field where that default matters most: unlike the other resources in\n * this family, `provenance` here is not even in the SDK's declared type. */\n provenance: string | undefined;\n}\n\nexport interface GrafanaMuteTiming extends Resource<\n 'Grafana.MuteTiming',\n MuteTimingProps,\n MuteTimingAttributes,\n never\n> {}\n\nexport const GrafanaMuteTiming = Resource<GrafanaMuteTiming>('Grafana.MuteTiming');\n\n/** The real runtime shape of a `GET`/list response — see the file header's \"measured\" note. */\ntype MuteTimeIntervalWire = grafana.MuteTimeInterval & {\n provenance?: string;\n version?: string;\n};\n\nexport const spec: GrafanaSpec<\n MuteTimingProps,\n MuteTimeIntervalWire,\n MuteTimingAttributes,\n | grafana.RouteGetMuteTimingError\n | grafana.RoutePostMuteTimingError\n | grafana.RoutePutMuteTimingError\n | grafana.RouteDeleteMuteTimingError\n | GrafanaProvisionedObjectError\n> = {\n attributes: (live) => ({\n name: live.name ?? '',\n // ⛔ NEVER `?? ''` — see alerting-provenance.ts's \"fails open\" note, and this file's own\n // Attributes doc comment on why it matters most here.\n provenance: live.provenance,\n timeIntervals: (live.time_intervals ?? []) as unknown as ReadonlyArray<Record<string, unknown>>,\n }),\n create: (props) =>\n grafana.routePostMuteTiming({\n name: props.name,\n time_intervals:\n props.timeIntervals as unknown as grafana.RoutePostMuteTimingRequestTimeIntervalsList,\n }),\n destroy: (props, live) =>\n Effect.gen(function* () {\n if (isForeignProvenance(live.provenance)) {\n return yield* refuseIfForeignProvenance('Grafana.MuteTiming', props.name, live.provenance);\n }\n yield* grafana.routeDeleteMuteTiming({\n name: props.name,\n ...(live.version === undefined ? {} : { version: live.version }),\n });\n }),\n fetchLive: (props) =>\n grafana.routeGetMuteTiming({ name: props.name }).pipe(\n Effect.map((live) => live as MuteTimeIntervalWire),\n Effect.catchTag('NotFound', () => Effect.succeed(undefined)),\n ),\n /** Subset match (subset-match.ts), not plain equality — tolerates a default Grafana might\n * inject into a time-interval entry the declaration never set. */\n matches: (attributes, props) =>\n declaredContentMatches(props.timeIntervals, attributes.timeIntervals),\n update: (props, live) =>\n Effect.gen(function* () {\n if (isForeignProvenance(live.provenance)) {\n return yield* refuseIfForeignProvenance('Grafana.MuteTiming', props.name, live.provenance);\n }\n yield* grafana.routePutMuteTiming({\n name: props.name,\n time_intervals:\n props.timeIntervals as unknown as grafana.RoutePutMuteTimingRequestTimeIntervalsList,\n });\n }),\n};\n\nexport const handlers = grafanaHandlers(spec);\n\nexport const GrafanaMuteTimingProvider = () =>\n Provider.effect(GrafanaMuteTiming, Effect.succeed(GrafanaMuteTiming.Provider.of(handlers)));\n",
|
|
20
23
|
"/**\n * Grafana credentials for this family — a URL plus a TOKEN REFERENCE (an env var NAME), never a\n * literal secret. Wraps `@distilled.cloud/grafana`'s own `Credentials` context directly (S23 —\n * reuse the SDK's own client rather than inventing a second one); this file only adds the house's\n * lazy, per-instance resolution on top of it.\n *\n * ★ ONE `GRAFANA_TOKEN`/`GRAFANA_URL` PAIR ISN'T ENOUGH FOR THIS HOUSE. Unlike Forgejo (one\n * instance), the estate runs at least two Grafanas — `grafana.homeflare.dev` and\n * `teslamate-grafana` on CT100, which the unit's own comment says has \"Own Access SaaS OIDC\n * client, never grafana.homeflare.dev's\". The SDK's `CredentialsFromEnv` reads one fixed pair\n * of names, so a stack declaring against more than one instance needs a target per instance —\n * `grafanaCredentials(target)` below, parameterized the way `litellm/credentials.ts` and\n * `proxmox/credentials.ts` already are in this kit.\n *\n * ⛔ THE TOKEN NEVER TOUCHES A PROP OR AN ATTRIBUTE (S25). `tokenEnv` is a NAME, resolved from\n * `process.env` fresh inside the credentials effect on every request (S24) — a layer built once\n * still re-reads the environment each time an operation runs, the same laziness\n * `litellm/credentials.ts` and the SDK's own `forgejo`/`netbox` `CredentialsFromEnv` have.\n *\n * ⚠️ THE SDK's `Credentials` SERVICE VALUE TYPE IS `Effect.Effect<Config, never, never>` — the\n * error channel is `never` (credentials.d.ts). A missing env var can only surface as a defect\n * here, via `Effect.orDie`, the same trade-off `forgejo/resource.ts` and `netbox/resource.ts`\n * already accept for their own `CredentialsFromEnv`; it is not a choice this file introduces.\n */\nimport { type Config, Credentials } from '@distilled.cloud/grafana/Credentials';\nimport { ConfigError } from '@distilled.cloud/grafana/Errors';\nimport * as Effect from 'effect/Effect';\nimport * as Layer from 'effect/Layer';\nimport * as Redacted from 'effect/Redacted';\n\nexport interface GrafanaTarget {\n /** Instance origin, e.g. `https://tesla.homeflare.dev/dash` — never `/api`; the SDK appends it. */\n readonly baseUrl: string;\n /** Env var NAME holding a Grafana service-account token. Never the value itself. */\n readonly tokenEnv: string;\n /** Selects the org a call applies to, via `X-Grafana-Org-Id`. Omit for the default org. */\n readonly orgId?: number | string;\n}\n\nconst resolve = (target: GrafanaTarget): Effect.Effect<Config, never, never> =>\n Effect.sync(() => process.env[target.tokenEnv]).pipe(\n Effect.flatMap((raw) =>\n raw === undefined || raw.trim() === ''\n ? Effect.fail(\n new ConfigError({\n message:\n `${target.tokenEnv} is not set. Export the Grafana service-account token there ` +\n `— never as an Alchemy prop — before running a stack that declares a resource ` +\n `against ${target.baseUrl}.`,\n }),\n )\n : Effect.succeed({\n apiBaseUrl: target.baseUrl.replace(/\\/+$/, ''),\n token: Redacted.make(raw.trim()),\n ...(target.orgId === undefined ? {} : { orgId: target.orgId }),\n } satisfies Config),\n ),\n Effect.orDie,\n );\n\n/** The lazy, per-instance layer `grafanaProviders(target)` composes by default. */\nexport const grafanaCredentials = (target: GrafanaTarget): Layer.Layer<Credentials> =>\n Layer.succeed(Credentials, resolve(target));\n\nexport type { Credentials };\n",
|
|
21
|
-
"/**\n * The Grafana providers for one instance, with its credentials, as one layer for a stack.\n *\n * Layer.mergeAll(grafanaProviders({ baseUrl: '...', tokenEnv: 'GRAFANA_TOKEN' }), …)\n *\n * ★ ONE CALL PER INSTANCE. A stack declaring resources against both `grafana.homeflare.dev` and\n * `teslamate-grafana` composes `grafanaProviders(targetA)` and `grafanaProviders(targetB)` —\n * each resource type's `Resource` constructor is a single global registration, so the SAME\n * `Grafana.Datasource` type serves both; only the credential layer differs per call.\n * ⚠️ `HttpClient` is NOT provided here. It is ambient in every Alchemy runtime, the same as\n * `litellmProviders`/`netboxProviders`-style families in this kit assume; a stack that already\n * deploys anything over HTTP already has one.\n */\nimport * as Layer from 'effect/Layer';\nimport { GrafanaAlertRuleGroupProvider } from './alert-rule-group.ts';\nimport { GrafanaContactPointProvider } from './contact-point.ts';\nimport { type GrafanaTarget, grafanaCredentials } from './credentials.ts';\nimport { GrafanaDashboardProvider } from './dashboard.ts';\nimport { GrafanaDatasourceProvider } from './datasource.ts';\nimport { GrafanaFolderProvider } from './folder.ts';\nimport { GrafanaMessageTemplateProvider } from './message-template.ts';\nimport { GrafanaMuteTimingProvider } from './mute-timing.ts';\n\nexport const grafanaProviders = (target: GrafanaTarget) =>\n Layer.mergeAll(\n GrafanaDatasourceProvider(),\n GrafanaFolderProvider(),\n GrafanaDashboardProvider(),\n GrafanaContactPointProvider(),\n GrafanaMuteTimingProvider(),\n GrafanaMessageTemplateProvider(),\n GrafanaAlertRuleGroupProvider(),\n ).pipe(Layer.provide(grafanaCredentials(target)));\n"
|
|
24
|
+
"/**\n * The Grafana providers for one instance, with its credentials, as one layer for a stack.\n *\n * Layer.mergeAll(grafanaProviders({ baseUrl: '...', tokenEnv: 'GRAFANA_TOKEN' }), …)\n *\n * ★ ONE CALL PER INSTANCE. A stack declaring resources against both `grafana.homeflare.dev` and\n * `teslamate-grafana` composes `grafanaProviders(targetA)` and `grafanaProviders(targetB)` —\n * each resource type's `Resource` constructor is a single global registration, so the SAME\n * `Grafana.Datasource` type serves both; only the credential layer differs per call.\n * ⚠️ `HttpClient` is NOT provided here. It is ambient in every Alchemy runtime, the same as\n * `litellmProviders`/`netboxProviders`-style families in this kit assume; a stack that already\n * deploys anything over HTTP already has one.\n */\nimport * as Layer from 'effect/Layer';\nimport { GrafanaAlertRuleGroupProvider } from './alert-rule-group.ts';\nimport { GrafanaContactPointProvider } from './contact-point.ts';\nimport { type GrafanaTarget, grafanaCredentials } from './credentials.ts';\nimport { GrafanaDashboardProvider } from './dashboard.ts';\nimport { GrafanaDatasourceProvider } from './datasource.ts';\nimport { GrafanaFolderProvider } from './folder.ts';\nimport { GrafanaMessageTemplateProvider } from './message-template.ts';\nimport { GrafanaMuteTimingProvider } from './mute-timing.ts';\nimport { GrafanaNotificationPolicyProvider } from './notification-policy.ts';\n\nexport const grafanaProviders = (target: GrafanaTarget) =>\n Layer.mergeAll(\n GrafanaDatasourceProvider(),\n GrafanaFolderProvider(),\n GrafanaDashboardProvider(),\n GrafanaContactPointProvider(),\n GrafanaMuteTimingProvider(),\n GrafanaMessageTemplateProvider(),\n GrafanaAlertRuleGroupProvider(),\n GrafanaNotificationPolicyProvider(),\n ).pipe(Layer.provide(grafanaCredentials(target)));\n"
|
|
22
25
|
],
|
|
23
|
-
"mappings": "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",
|
|
24
|
-
"debugId": "
|
|
26
|
+
"mappings": "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",
|
|
27
|
+
"debugId": "5578DCEDF956037C64756E2164756E21",
|
|
25
28
|
"names": []
|
|
26
29
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The warning `Grafana.NotificationPolicy` logs when a whole-tree `PUT` would silently drop a live
|
|
3
|
+
* sub-route the declaration doesn't account for — same shape as `alert-rule-group-drop-warning.ts`
|
|
4
|
+
* (kit PR 254's own fix, after an adversarial review found the identical risk for rule groups):
|
|
5
|
+
* `PUT /v1/provisioning/policies` REPLACES the entire tree, so a nested route someone added
|
|
6
|
+
* out-of-band is removed with no error and no distinct `Diff` action to report it under.
|
|
7
|
+
*
|
|
8
|
+
* ★ `Effect.logWarning`, NEVER A REFUSAL — same reasoning as `alert-rule-group-drop-warning.ts`'s
|
|
9
|
+
* own header, and further upstream `proxmox/unreadable-read.ts`'s `unreadableWarning`. A
|
|
10
|
+
* whole-tree write dropping an out-of-band route is EXPECTED for a resource whose whole point is
|
|
11
|
+
* to own the tree — only a silent one is worth surfacing loudly.
|
|
12
|
+
*
|
|
13
|
+
* ⛔ MULTISET COMPARISON, NOT SET MEMBERSHIP — fixed after an adversarial review of this PR found
|
|
14
|
+
* the first version's `Set`-based check collided ACROSS THE WHOLE TREE: any two nodes anywhere
|
|
15
|
+
* with identical own-fields shared one `Set` entry, so a duplicate route added out-of-band
|
|
16
|
+
* (e.g. a second `severity=warning -> slack` alongside an already-declared one) matched the
|
|
17
|
+
* existing entry and went unwarned even though the PUT would still drop it — worse than the
|
|
18
|
+
* documented "siblings only" limitation the original comment claimed. Every key from
|
|
19
|
+
* `FlatRoute.key` (ancestry-scoped — see that field's own doc) is now counted per side, and a
|
|
20
|
+
* `key` is only "dropped" for the amount its LIVE count exceeds its DECLARED count — N identical
|
|
21
|
+
* live occurrences under the same parent are dropped only past however many the declaration
|
|
22
|
+
* itself repeats, never all of them at once just because one is declared.
|
|
23
|
+
*/
|
|
24
|
+
import * as Effect from 'effect/Effect';
|
|
25
|
+
import { type PolicyRoute } from './notification-policy-model.ts';
|
|
26
|
+
export declare const warnOnDroppedRoutes: (declared: PolicyRoute, live: PolicyRoute) => Effect.Effect<void>;
|
|
27
|
+
//# sourceMappingURL=notification-policy-drop-warning.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification-policy-drop-warning.d.ts","sourceRoot":"","sources":["../../src/grafana/notification-policy-drop-warning.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,KAAK,WAAW,EAAiC,MAAM,gCAAgC,CAAC;AAQjG,eAAO,MAAM,mBAAmB,aACpB,WAAW,QACf,WAAW,KAChB,MAAM,CAAC,MAAM,CAAC,IAAI,CAwBjB,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared fixtures for the `notification-policy*.test.ts` files — split to keep each file under
|
|
3
|
+
* the house's 250-line cap. Deliberately NOT named `*.test.ts` — see `contact-point-fixtures.ts`'s
|
|
4
|
+
* own header for why.
|
|
5
|
+
*/
|
|
6
|
+
export declare const PATH = "/api/v1/provisioning/policies";
|
|
7
|
+
export declare const liveTree: {
|
|
8
|
+
group_by: string[];
|
|
9
|
+
provenance: string;
|
|
10
|
+
receiver: string;
|
|
11
|
+
routes: {
|
|
12
|
+
matchers: string[];
|
|
13
|
+
receiver: string;
|
|
14
|
+
}[];
|
|
15
|
+
};
|
|
16
|
+
export declare const declaredRoute: {
|
|
17
|
+
group_by: string[];
|
|
18
|
+
receiver: string;
|
|
19
|
+
routes: {
|
|
20
|
+
matchers: string[];
|
|
21
|
+
receiver: string;
|
|
22
|
+
}[];
|
|
23
|
+
};
|
|
24
|
+
export declare const props: {
|
|
25
|
+
route: {
|
|
26
|
+
group_by: string[];
|
|
27
|
+
receiver: string;
|
|
28
|
+
routes: {
|
|
29
|
+
matchers: string[];
|
|
30
|
+
receiver: string;
|
|
31
|
+
}[];
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
//# sourceMappingURL=notification-policy-fixtures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification-policy-fixtures.d.ts","sourceRoot":"","sources":["../../src/grafana/notification-policy-fixtures.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,IAAI,kCAAkC,CAAC;AAEpD,eAAO,MAAM,QAAQ;;;;;;;;CAQpB,CAAC;AAEF,eAAO,MAAM,aAAa;;;;;;;CAOzB,CAAC;AAEF,eAAO,MAAM,KAAK;IAAK,KAAK;;;;;;;;CAAiB,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure functions over the notification policy tree — no SDK call, no Effect. Split out of
|
|
3
|
+
* `notification-policy.ts` the same way `dashboard-model.ts`/`alert-rule-group-model.ts` are split
|
|
4
|
+
* out of their resources.
|
|
5
|
+
*
|
|
6
|
+
* ★ THE TREE IS OPAQUE `Record<string, unknown>`, NOT THE SDK's OWN `Route` TYPE — same reasoning
|
|
7
|
+
* as `mute-timing.ts`'s `timeIntervals`: Grafana's `Matchers`/`ObjectMatchers`/`MatchRegexps`
|
|
8
|
+
* (matcher expression shapes) are complex nested union/array types this family does not attempt
|
|
9
|
+
* to model field-by-field. `routePutPolicyTree`'s request body encodes/decodes any key
|
|
10
|
+
* verbatim regardless (the same unmodeled-key passthrough `mute-timing.ts`'s file header
|
|
11
|
+
* documents for this SDK generally), so an opaque pass-through both round-trips correctly and
|
|
12
|
+
* stays usable for every matcher/route shape Grafana accepts, not just the ones this file would
|
|
13
|
+
* otherwise hand-model.
|
|
14
|
+
*/
|
|
15
|
+
export type PolicyRoute = Record<string, unknown>;
|
|
16
|
+
export declare const normalizeRoute: (route: PolicyRoute) => PolicyRoute;
|
|
17
|
+
export interface FlatRoute {
|
|
18
|
+
/** Dotted child-index path from the root, e.g. `root.0.1` — WHERE this occurrence sits, for the
|
|
19
|
+
* warning message only; never part of `key`. */
|
|
20
|
+
readonly path: string;
|
|
21
|
+
readonly receiver: string;
|
|
22
|
+
/**
|
|
23
|
+
* Identity for the dropped-route warning — MEASURED FIX (an adversarial review of this PR found
|
|
24
|
+
* the first version's identity, plain per-node JSON in a `Set`, collided across the WHOLE TREE:
|
|
25
|
+
* a duplicate route added anywhere, not just as a live-only sibling, silently matched an
|
|
26
|
+
* unrelated declared node with the same fields and the drop went unwarned). `key` is now the
|
|
27
|
+
* chain of ancestor own-fields from the root down to this node (this node's own fields included,
|
|
28
|
+
* `routes` children excluded at every level, `\0`-joined — a byte no route's own JSON can
|
|
29
|
+
* contain): two nodes are "the same" only if they sit under the identical lineage of ancestors,
|
|
30
|
+
* which makes an identical route under a DIFFERENT parent correctly distinct, while still being
|
|
31
|
+
* ORDER-INSENSITIVE among siblings (a shared parent contributes the same ancestor key to every
|
|
32
|
+
* child regardless of index) — a plain reorder is never reported as a drop.
|
|
33
|
+
* `notification-policy-drop-warning.ts` counts occurrences of each `key` as a MULTISET (declared
|
|
34
|
+
* count vs. live count), not set membership, so N live duplicates of the same node under the
|
|
35
|
+
* same parent are only "dropped" past however many the declaration itself repeats.
|
|
36
|
+
*/
|
|
37
|
+
readonly key: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Depth-first flatten of a (already-normalized) route tree, `root` itself included at `path:
|
|
41
|
+
* 'root'` and `key` equal to its own fields alone (no ancestor to chain from). Used only by
|
|
42
|
+
* `notification-policy-drop-warning.ts`'s best-effort "what did this write remove" detection —
|
|
43
|
+
* `matches()` in `notification-policy.ts` never uses this, only `declaredContentMatches` on the
|
|
44
|
+
* tree as a whole, so nothing about drift DETECTION depends on it.
|
|
45
|
+
*
|
|
46
|
+
* ⚠️ STILL A BEST-EFFORT KEY, NOT A STABLE ONE — Grafana's policy routes have no id/uid the way
|
|
47
|
+
* every other object in this family does; `key` is a measured, deliberate improvement over plain
|
|
48
|
+
* per-node identity (see `FlatRoute.key`'s own doc), not a claim of a real Grafana-side key. A
|
|
49
|
+
* false negative here (missing a genuine drop) never hides real drift from `matches()`, which
|
|
50
|
+
* compares the whole tree structurally regardless of this file.
|
|
51
|
+
*/
|
|
52
|
+
export declare const flattenRoutes: (route: PolicyRoute, path?: string, ancestorKey?: string) => ReadonlyArray<FlatRoute>;
|
|
53
|
+
//# sourceMappingURL=notification-policy-model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification-policy-model.d.ts","sourceRoot":"","sources":["../../src/grafana/notification-policy-model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAclD,eAAO,MAAM,cAAc,UAAW,WAAW,KAAG,WAWnD,CAAC;AAEF,MAAM,WAAW,SAAS;IACxB;qDACiD;IACjD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAOD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,aAAa,UACjB,WAAW,0CAGjB,aAAa,CAAC,SAAS,CAazB,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Input } from 'alchemy/Input';
|
|
2
|
+
import { Resource } from 'alchemy';
|
|
3
|
+
import * as Provider from 'alchemy/Provider';
|
|
4
|
+
import * as grafana from '@distilled.cloud/grafana';
|
|
5
|
+
import * as Effect from 'effect/Effect';
|
|
6
|
+
import { type GrafanaProvisionedObjectError } from './alerting-provenance.ts';
|
|
7
|
+
import { type PolicyRoute } from './notification-policy-model.ts';
|
|
8
|
+
import { type GrafanaSpec } from './resource.ts';
|
|
9
|
+
export type { PolicyRoute };
|
|
10
|
+
export interface NotificationPolicyProps {
|
|
11
|
+
/** The root route and its full nested tree — Grafana's `Route` shape (`receiver`, `group_by`,
|
|
12
|
+
* `matchers`, nested `routes[]`, …), passed through opaquely — see the file header. Order of
|
|
13
|
+
* `routes[]` at every level is significant. */
|
|
14
|
+
route: PolicyRoute;
|
|
15
|
+
/** Lets `destroy` actually call `routeResetPolicyTree`. Defaults to `false` — see the file
|
|
16
|
+
* header for why this is a second gate on top of Alchemy's own removal policy. */
|
|
17
|
+
allowReset?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface NotificationPolicyAttributes {
|
|
20
|
+
route: PolicyRoute;
|
|
21
|
+
/** `""`/`"api"` (this family may write); anything else, INCLUDING `undefined`, refuses — see
|
|
22
|
+
* alerting-provenance.ts's "fails open" note. */
|
|
23
|
+
provenance: string | undefined;
|
|
24
|
+
}
|
|
25
|
+
export interface GrafanaNotificationPolicy extends Resource<'Grafana.NotificationPolicy', NotificationPolicyProps, NotificationPolicyAttributes, never> {
|
|
26
|
+
}
|
|
27
|
+
export declare const GrafanaNotificationPolicy: import("alchemy").ResourceClass<GrafanaNotificationPolicy>;
|
|
28
|
+
export declare const spec: GrafanaSpec<NotificationPolicyProps, grafana.Route, NotificationPolicyAttributes, grafana.RouteGetPolicyTreeError | grafana.RoutePutPolicyTreeError | grafana.RouteResetPolicyTreeError | GrafanaProvisionedObjectError>;
|
|
29
|
+
/**
|
|
30
|
+
* ⚠️ A LOCAL REIMPLEMENTATION OF `resource.ts`'s GENERIC `diff`, NOT A WRAP OF IT — same reasoning
|
|
31
|
+
* as `alert-rule-group.ts`'s own `diff`: the generic version has no seam to run the drop-warning
|
|
32
|
+
* side effect against the live tree it reads, and wrapping it would mean a second live fetch
|
|
33
|
+
* just to see what it already saw.
|
|
34
|
+
*/
|
|
35
|
+
declare const diff: ({ news, output, }: {
|
|
36
|
+
news: Input<NotificationPolicyProps>;
|
|
37
|
+
output: NotificationPolicyAttributes | undefined;
|
|
38
|
+
}) => Effect.Effect<{
|
|
39
|
+
readonly action: 'update';
|
|
40
|
+
} | {
|
|
41
|
+
readonly action: 'noop';
|
|
42
|
+
} | undefined, grafana.BadGateway | import("@distilled.cloud/caddy").BadRequest | grafana.BadRequest | grafana.ConfigError | import("@distilled.cloud/caddy").Conflict | grafana.Conflict | import("@distilled.cloud/caddy").Forbidden | grafana.Forbidden | grafana.GatewayTimeout | GrafanaProvisionedObjectError | import("effect/unstable/http/HttpClientError").HttpClientError | grafana.InternalServerError | grafana.Locked | import("@distilled.cloud/caddy").NotFound | grafana.ServiceUnavailable | grafana.TooManyRequests | grafana.Unauthorized | grafana.UnknownGrafanaError | import("@distilled.cloud/caddy").UnprocessableEntity, grafana.GrafanaOpContext>;
|
|
43
|
+
export declare const handlers: {
|
|
44
|
+
list: () => Effect.Effect<never[], never, never>;
|
|
45
|
+
read: ({ olds }: {
|
|
46
|
+
olds: NotificationPolicyProps;
|
|
47
|
+
}) => Effect.Effect<NotificationPolicyAttributes | undefined, grafana.BadGateway | import("@distilled.cloud/caddy").BadRequest | grafana.BadRequest | grafana.ConfigError | import("@distilled.cloud/caddy").Conflict | grafana.Conflict | import("@distilled.cloud/caddy").Forbidden | grafana.Forbidden | grafana.GatewayTimeout | GrafanaProvisionedObjectError | import("effect/unstable/http/HttpClientError").HttpClientError | grafana.InternalServerError | grafana.Locked | import("@distilled.cloud/caddy").NotFound | grafana.ServiceUnavailable | grafana.TooManyRequests | grafana.Unauthorized | grafana.UnknownGrafanaError | import("@distilled.cloud/caddy").UnprocessableEntity, grafana.GrafanaOpContext>;
|
|
48
|
+
reconcile: ({ news }: {
|
|
49
|
+
news: NotificationPolicyProps;
|
|
50
|
+
}) => Effect.Effect<NotificationPolicyAttributes, grafana.BadGateway | import("@distilled.cloud/caddy").BadRequest | grafana.BadRequest | grafana.ConfigError | import("@distilled.cloud/caddy").Conflict | grafana.Conflict | import("@distilled.cloud/caddy").Forbidden | grafana.Forbidden | grafana.GatewayTimeout | GrafanaProvisionedObjectError | import("effect/unstable/http/HttpClientError").HttpClientError | grafana.InternalServerError | grafana.Locked | import("@distilled.cloud/caddy").NotFound | grafana.ServiceUnavailable | grafana.TooManyRequests | grafana.Unauthorized | grafana.UnknownGrafanaError | import("@distilled.cloud/caddy").UnprocessableEntity, grafana.GrafanaOpContext>;
|
|
51
|
+
delete: ({ olds }: {
|
|
52
|
+
olds: NotificationPolicyProps;
|
|
53
|
+
}) => Effect.Effect<void, grafana.BadGateway | import("@distilled.cloud/caddy").BadRequest | grafana.BadRequest | grafana.ConfigError | import("@distilled.cloud/caddy").Conflict | grafana.Conflict | import("@distilled.cloud/caddy").Forbidden | grafana.Forbidden | grafana.GatewayTimeout | GrafanaProvisionedObjectError | import("effect/unstable/http/HttpClientError").HttpClientError | grafana.InternalServerError | grafana.Locked | import("@distilled.cloud/caddy").NotFound | grafana.ServiceUnavailable | grafana.TooManyRequests | grafana.Unauthorized | grafana.UnknownGrafanaError | import("@distilled.cloud/caddy").UnprocessableEntity, grafana.GrafanaOpContext>;
|
|
54
|
+
diff: typeof diff;
|
|
55
|
+
};
|
|
56
|
+
export declare const GrafanaNotificationPolicyProvider: () => import("effect/Layer").Layer<Provider.Provider<GrafanaNotificationPolicy>, never, grafana.GrafanaOpContext>;
|
|
57
|
+
//# sourceMappingURL=notification-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notification-policy.d.ts","sourceRoot":"","sources":["../../src/grafana/notification-policy.ts"],"names":[],"mappings":"AAqDA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,OAAO,MAAM,0BAA0B,CAAC;AACpD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,EACL,KAAK,6BAA6B,EAGnC,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,KAAK,WAAW,EAAkB,MAAM,gCAAgC,CAAC;AAElF,OAAO,EAAE,KAAK,WAAW,EAAmB,MAAM,eAAe,CAAC;AAGlE,YAAY,EAAE,WAAW,EAAE,CAAC;AAE5B,MAAM,WAAW,uBAAuB;IACtC;;oDAEgD;IAChD,KAAK,EAAE,WAAW,CAAC;IACnB;uFACmF;IACnF,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,4BAA4B;IAC3C,KAAK,EAAE,WAAW,CAAC;IACnB;sDACkD;IAClD,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED,MAAM,WAAW,yBAA0B,SAAQ,QAAQ,CACzD,4BAA4B,EAC5B,uBAAuB,EACvB,4BAA4B,EAC5B,KAAK,CACN;CAAG;AAEJ,eAAO,MAAM,yBAAyB,4DAGrC,CAAC;AAKF,eAAO,MAAM,IAAI,EAAE,WAAW,CAC5B,uBAAuB,EACvB,OAAO,CAAC,KAAK,EACb,4BAA4B,EAC1B,OAAO,CAAC,uBAAuB,GAC/B,OAAO,CAAC,uBAAuB,GAC/B,OAAO,CAAC,yBAAyB,GACjC,6BAA6B,CA6ChC,CAAC;AAEF;;;;;GAKG;AACH,QAAA,MAAM,IAAI,sBAGP;IACD,IAAI,EAAE,KAAK,CAAC,uBAAuB,CAAC,CAAC;IACrC,MAAM,EAAE,4BAA4B,GAAG,SAAS,CAAC;CAClD;qBAQ4C,QAAQ;;qBAIlC,MAAM;6oBAErB,CAAC;AAEL,eAAO,MAAM,QAAQ;;;;;;;;;;;;CAAqC,CAAC;AAE3D,eAAO,MAAM,iCAAiC,mHAI3C,CAAC"}
|
|
@@ -13,5 +13,5 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import * as Layer from 'effect/Layer';
|
|
15
15
|
import { type GrafanaTarget } from './credentials.ts';
|
|
16
|
-
export declare const grafanaProviders: (target: GrafanaTarget) => Layer.Layer<import("alchemy").Provider<import("./alert-rule-group.ts").GrafanaAlertRuleGroup> | import("alchemy").Provider<import("./contact-point.ts").GrafanaContactPoint> | import("alchemy").Provider<import("./dashboard.ts").GrafanaDashboard> | import("alchemy").Provider<import("./datasource.ts").GrafanaDatasource> | import("alchemy").Provider<import("./folder.ts").GrafanaFolder> | import("alchemy").Provider<import("./message-template.ts").GrafanaMessageTemplate> | import("alchemy").Provider<import("./mute-timing.ts").GrafanaMuteTiming>, never, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
16
|
+
export declare const grafanaProviders: (target: GrafanaTarget) => Layer.Layer<import("alchemy").Provider<import("./alert-rule-group.ts").GrafanaAlertRuleGroup> | import("alchemy").Provider<import("./contact-point.ts").GrafanaContactPoint> | import("alchemy").Provider<import("./dashboard.ts").GrafanaDashboard> | import("alchemy").Provider<import("./datasource.ts").GrafanaDatasource> | import("alchemy").Provider<import("./folder.ts").GrafanaFolder> | import("alchemy").Provider<import("./message-template.ts").GrafanaMessageTemplate> | import("alchemy").Provider<import("./mute-timing.ts").GrafanaMuteTiming> | import("alchemy").Provider<import("./notification-policy.ts").GrafanaNotificationPolicy>, never, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
17
17
|
//# sourceMappingURL=providers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/grafana/providers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAGtC,OAAO,EAAE,KAAK,aAAa,EAAsB,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/grafana/providers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAGtC,OAAO,EAAE,KAAK,aAAa,EAAsB,MAAM,kBAAkB,CAAC;AAQ1E,eAAO,MAAM,gBAAgB,WAAY,aAAa,8rBAUH,CAAC"}
|