@hansenexus/hud 0.3.0 → 0.4.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 +186 -4
- package/dist/access-CNvJOwKM.d.ts +54 -0
- package/dist/capabilities-CjulXFQX.js +189 -0
- package/dist/{define-hud-BHQR8Lbv.d.ts → define-hud-BBzsSl8b.d.ts} +6 -1
- package/dist/env-DfxpPfs9.js +28 -0
- package/dist/env-vEjyJfPW.d.ts +17 -0
- package/dist/force-state-BaqWsmrf.js +153 -0
- package/dist/force-state-CCqoTfVB.d.ts +23 -0
- package/dist/handler-WmE4Lu7l.d.ts +39 -0
- package/dist/index-BYsdS-7d.d.ts +55 -0
- package/dist/index.d.ts +6 -36
- package/dist/index.js +119 -202
- package/dist/marker-C66LxOhJ.d.ts +9 -0
- package/dist/marker-CMrvxPmS.d.ts +12 -0
- package/dist/marker-DjeGvL-F.js +9 -0
- package/dist/marker-uZYPOJ4M.js +12 -0
- package/dist/markers.d.ts +3 -0
- package/dist/markers.js +3 -0
- package/dist/next.d.ts +3 -18
- package/dist/next.js +3 -28
- package/dist/payload-CLKDVZWl.d.ts +68 -0
- package/dist/plugins/access/server.d.ts +122 -0
- package/dist/plugins/access/server.js +339 -0
- package/dist/plugins/access.d.ts +41 -0
- package/dist/plugins/access.js +250 -0
- package/dist/plugins/agent/server.d.ts +129 -0
- package/dist/plugins/agent/server.js +429 -0
- package/dist/plugins/agent.d.ts +37 -0
- package/dist/plugins/agent.js +411 -0
- package/dist/plugins/design.d.ts +125 -0
- package/dist/plugins/design.js +619 -0
- package/dist/plugins/observe.d.ts +64 -0
- package/dist/plugins/observe.js +617 -0
- package/dist/plugins/ops/server.d.ts +82 -0
- package/dist/plugins/ops/server.js +380 -0
- package/dist/plugins/ops.d.ts +26 -0
- package/dist/plugins/ops.js +362 -0
- package/dist/plugins/vitals.js +3 -86
- package/dist/{plugins-1QmTmZyL.d.ts → plugins-CQ_0w1ot.d.ts} +39 -1
- package/dist/{plugins-CzUiTn_r.js → plugins-DVy_vaYr.js} +3 -1
- package/dist/review.d.ts +181 -0
- package/dist/review.js +1017 -0
- package/dist/selector-NSYSe7AZ.js +28 -0
- package/dist/server.d.ts +3 -39
- package/dist/server.js +1 -1
- package/dist/shortcut-U6ftVY06.js +222 -0
- package/dist/state-boundary.d.ts +26 -0
- package/dist/state-boundary.js +61 -0
- package/dist/styles--slk86ZQ.js +332 -0
- package/dist/types-DADBRiGk.d.ts +50 -0
- package/dist/types-QJUajwWq.js +35 -0
- package/dist/types-f3jlNxzw.d.ts +92 -0
- package/dist/vitals-panel-Dvc5dnR-.js +87 -0
- package/package.json +23 -3
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
import { i as definePlugin } from "../../plugins-DVy_vaYr.js";
|
|
2
|
+
import { i as OPS_CAPABILITY, n as combineStates, t as TELEMETRY_RANGES } from "../../types-QJUajwWq.js";
|
|
3
|
+
//#region src/plugins/ops/errors.ts
|
|
4
|
+
/**
|
|
5
|
+
* A provider failure whose message is safe to send to the client (it names
|
|
6
|
+
* the upstream and its status, never a URL with credentials or a token).
|
|
7
|
+
* The routes answer 502 with it; any other error becomes a generic 502.
|
|
8
|
+
*/
|
|
9
|
+
var OpsProviderError = class extends Error {
|
|
10
|
+
constructor(message) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = "OpsProviderError";
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
/** Upstream calls give up after this, so a dead host never hangs a panel. */
|
|
16
|
+
const UPSTREAM_TIMEOUT_MS = 5e3;
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/plugins/ops/env.ts
|
|
19
|
+
/** Reads a server env var. Absent `process` (MSW in a browser) reads as unset. */
|
|
20
|
+
function readEnv(name) {
|
|
21
|
+
if (typeof process === "undefined") return void 0;
|
|
22
|
+
const value = process.env[name];
|
|
23
|
+
return value === "" ? void 0 : value;
|
|
24
|
+
}
|
|
25
|
+
/** `process.cwd()`, or undefined where there is none. */
|
|
26
|
+
function currentDir() {
|
|
27
|
+
const proc = globalThis.process;
|
|
28
|
+
return typeof proc?.cwd === "function" ? proc.cwd() : void 0;
|
|
29
|
+
}
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/plugins/ops/git-head.ts
|
|
32
|
+
/**
|
|
33
|
+
* Branch named by a `HEAD` file: `ref: refs/heads/feat/x` → `feat/x`.
|
|
34
|
+
* A detached HEAD (a bare sha) names no branch.
|
|
35
|
+
*/
|
|
36
|
+
function parseHead(head) {
|
|
37
|
+
return /^ref:\s*refs\/heads\/(.+)$/.exec(head.trim())?.[1] ?? null;
|
|
38
|
+
}
|
|
39
|
+
/** Git dir a worktree's `.git` file points at: `gitdir: /repo/.git/worktrees/x`. */
|
|
40
|
+
function parseGitFile(content) {
|
|
41
|
+
return /^gitdir:\s*(.+)$/m.exec(content)?.[1]?.trim() ?? null;
|
|
42
|
+
}
|
|
43
|
+
function parents(dir) {
|
|
44
|
+
const parts = dir.replace(/[\\/]+$/, "").split(/[\\/]/);
|
|
45
|
+
const dirs = [];
|
|
46
|
+
for (let i = parts.length; i > 0; i--) dirs.push(parts.slice(0, i).join("/") || "/");
|
|
47
|
+
return dirs;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Branch of the git checkout containing `cwd` (default `process.cwd()`), read
|
|
51
|
+
* from `.git/HEAD` without spawning git. Walks up, so an app inside a monorepo
|
|
52
|
+
* finds the root's `.git`; follows a worktree's `.git` file. Null when there
|
|
53
|
+
* is no checkout, no filesystem (edge runtime, browser) or HEAD is detached.
|
|
54
|
+
*/
|
|
55
|
+
async function readGitBranch(cwd = currentDir()) {
|
|
56
|
+
if (!cwd) return null;
|
|
57
|
+
let fs;
|
|
58
|
+
try {
|
|
59
|
+
fs = await import("node:fs/promises");
|
|
60
|
+
} catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
for (const dir of parents(cwd)) {
|
|
64
|
+
const dotGit = `${dir === "/" ? "" : dir}/.git`;
|
|
65
|
+
try {
|
|
66
|
+
return parseHead(await fs.readFile(`${dotGit}/HEAD`, "utf8"));
|
|
67
|
+
} catch {}
|
|
68
|
+
try {
|
|
69
|
+
const gitDir = parseGitFile(await fs.readFile(dotGit, "utf8"));
|
|
70
|
+
if (gitDir) {
|
|
71
|
+
const absolute = /^([\\/]|[A-Za-z]:)/.test(gitDir) ? gitDir : `${dir}/${gitDir}`;
|
|
72
|
+
return parseHead(await fs.readFile(`${absolute}/HEAD`, "utf8"));
|
|
73
|
+
}
|
|
74
|
+
} catch {}
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
//#endregion
|
|
79
|
+
//#region src/plugins/ops/github-actions.ts
|
|
80
|
+
const BRANCH_ENV = [
|
|
81
|
+
"HUD_GIT_BRANCH",
|
|
82
|
+
"VERCEL_GIT_COMMIT_REF",
|
|
83
|
+
"GITHUB_HEAD_REF",
|
|
84
|
+
"GITHUB_REF_NAME"
|
|
85
|
+
];
|
|
86
|
+
const REPO = /^[\w.-]+\/[\w.-]+$/;
|
|
87
|
+
/** GitHub's status + conclusion pair as one state. */
|
|
88
|
+
function githubRunState(status, conclusion) {
|
|
89
|
+
if (status === "in_progress") return "running";
|
|
90
|
+
if (status !== "completed") return "queued";
|
|
91
|
+
switch (conclusion) {
|
|
92
|
+
case "success": return "success";
|
|
93
|
+
case "failure":
|
|
94
|
+
case "timed_out":
|
|
95
|
+
case "startup_failure":
|
|
96
|
+
case "action_required": return "failure";
|
|
97
|
+
case "cancelled":
|
|
98
|
+
case "stale": return "cancelled";
|
|
99
|
+
default: return "neutral";
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function toRun(run) {
|
|
103
|
+
const name = run.name ?? `workflow ${run.workflow_id}`;
|
|
104
|
+
const title = run.display_title ?? run.head_commit?.message.split("\n")[0] ?? name;
|
|
105
|
+
return {
|
|
106
|
+
id: String(run.id),
|
|
107
|
+
name,
|
|
108
|
+
title,
|
|
109
|
+
state: githubRunState(run.status, run.conclusion),
|
|
110
|
+
...run.head_branch ? { branch: run.head_branch } : {},
|
|
111
|
+
sha: run.head_sha.slice(0, 7),
|
|
112
|
+
url: run.html_url,
|
|
113
|
+
startedAt: run.created_at
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* State of the newest commit among `runs` (newest first): the latest run of
|
|
118
|
+
* each workflow on that commit, combined.
|
|
119
|
+
*/
|
|
120
|
+
function headState(runs) {
|
|
121
|
+
const head = runs[0]?.head_sha;
|
|
122
|
+
if (!head) return {
|
|
123
|
+
sha: null,
|
|
124
|
+
state: null
|
|
125
|
+
};
|
|
126
|
+
const latest = /* @__PURE__ */ new Map();
|
|
127
|
+
for (const run of runs) if (run.head_sha === head && !latest.has(run.workflow_id)) latest.set(run.workflow_id, run);
|
|
128
|
+
const states = [...latest.values()].map((run) => githubRunState(run.status, run.conclusion));
|
|
129
|
+
return {
|
|
130
|
+
sha: head.slice(0, 7),
|
|
131
|
+
state: combineStates(states)
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* GitHub Actions as the `ops` plugin's CI provider. Server only: the token is
|
|
136
|
+
* read from env on each request and only ever sent to GitHub.
|
|
137
|
+
*
|
|
138
|
+
* ```ts
|
|
139
|
+
* ops({ ci: githubActions({ repo: "hansenexus/hud" }) })
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
function githubActions(options) {
|
|
143
|
+
const { repo, tokenEnv = "GITHUB_TOKEN", limit = 10, cacheSeconds = 15 } = options;
|
|
144
|
+
if (!REPO.test(repo)) throw new Error(`hud ops: githubActions repo "${repo}" must be owner/name`);
|
|
145
|
+
const apiUrl = (options.apiUrl ?? "https://api.github.com").replace(/\/+$/, "");
|
|
146
|
+
const cache = /* @__PURE__ */ new Map();
|
|
147
|
+
async function resolveBranch() {
|
|
148
|
+
const { branch } = options;
|
|
149
|
+
if (typeof branch === "string") return branch;
|
|
150
|
+
if (typeof branch === "function") return await branch() ?? null;
|
|
151
|
+
for (const name of BRANCH_ENV) {
|
|
152
|
+
const value = readEnv(name);
|
|
153
|
+
if (value) return value;
|
|
154
|
+
}
|
|
155
|
+
return readGitBranch();
|
|
156
|
+
}
|
|
157
|
+
async function fetchRuns(token, branch) {
|
|
158
|
+
const params = new URLSearchParams({ per_page: String(Math.max(limit, 20)) });
|
|
159
|
+
if (branch) params.set("branch", branch);
|
|
160
|
+
let res;
|
|
161
|
+
try {
|
|
162
|
+
res = await fetch(`${apiUrl}/repos/${repo}/actions/runs?${params}`, {
|
|
163
|
+
headers: {
|
|
164
|
+
authorization: `Bearer ${token}`,
|
|
165
|
+
accept: "application/vnd.github+json",
|
|
166
|
+
"x-github-api-version": "2022-11-28"
|
|
167
|
+
},
|
|
168
|
+
signal: AbortSignal.timeout(UPSTREAM_TIMEOUT_MS)
|
|
169
|
+
});
|
|
170
|
+
} catch {
|
|
171
|
+
throw new OpsProviderError("GitHub unreachable");
|
|
172
|
+
}
|
|
173
|
+
if (!res.ok) throw new OpsProviderError(`GitHub answered ${res.status}`);
|
|
174
|
+
return (await res.json()).workflow_runs ?? [];
|
|
175
|
+
}
|
|
176
|
+
function cachedRuns(token, branch) {
|
|
177
|
+
const key = branch ?? "";
|
|
178
|
+
const hit = cache.get(key);
|
|
179
|
+
if (hit && Date.now() - hit.at < cacheSeconds * 1e3) return hit.value;
|
|
180
|
+
const value = fetchRuns(token, branch);
|
|
181
|
+
cache.set(key, {
|
|
182
|
+
at: Date.now(),
|
|
183
|
+
value
|
|
184
|
+
});
|
|
185
|
+
value.catch(() => cache.delete(key));
|
|
186
|
+
return value;
|
|
187
|
+
}
|
|
188
|
+
return {
|
|
189
|
+
name: "github-actions",
|
|
190
|
+
async snapshot() {
|
|
191
|
+
const branch = await resolveBranch();
|
|
192
|
+
const base = {
|
|
193
|
+
provider: "github-actions",
|
|
194
|
+
repo,
|
|
195
|
+
branch
|
|
196
|
+
};
|
|
197
|
+
const token = readEnv(tokenEnv);
|
|
198
|
+
if (!token) return {
|
|
199
|
+
...base,
|
|
200
|
+
configured: false,
|
|
201
|
+
missing: tokenEnv,
|
|
202
|
+
state: null,
|
|
203
|
+
sha: null,
|
|
204
|
+
runs: []
|
|
205
|
+
};
|
|
206
|
+
const runs = await cachedRuns(token, branch);
|
|
207
|
+
const head = branch ? headState(runs) : {
|
|
208
|
+
sha: null,
|
|
209
|
+
state: null
|
|
210
|
+
};
|
|
211
|
+
return {
|
|
212
|
+
...base,
|
|
213
|
+
configured: true,
|
|
214
|
+
...head,
|
|
215
|
+
runs: runs.slice(0, limit).map(toRun)
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
//#endregion
|
|
221
|
+
//#region src/plugins/ops/signoz.ts
|
|
222
|
+
const SERVICE = /^[\w.-]{1,128}$/;
|
|
223
|
+
const RANGE_SECONDS = {
|
|
224
|
+
"1h": 3600,
|
|
225
|
+
"24h": 86400,
|
|
226
|
+
"7d": 604800
|
|
227
|
+
};
|
|
228
|
+
const RANGE_STEP = {
|
|
229
|
+
"1h": "5m",
|
|
230
|
+
"24h": "15m",
|
|
231
|
+
"7d": "1h"
|
|
232
|
+
};
|
|
233
|
+
/** PromQL for the three numbers, from SigNoz's span metrics. */
|
|
234
|
+
function signozQueries(service) {
|
|
235
|
+
const label = `service_name="${service}"`;
|
|
236
|
+
return {
|
|
237
|
+
errorRate: `sum(rate(signoz_calls_total{${label},status_code="STATUS_CODE_ERROR"}[5m]))`,
|
|
238
|
+
p95Ms: `histogram_quantile(0.95, sum(rate(signoz_latency_bucket{${label}}[5m])) by (le))`,
|
|
239
|
+
requestRate: `sum(rate(signoz_calls_total{${label}}[5m]))`
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
/** Latest sample of the first series; null when there is none or it is not a number. */
|
|
243
|
+
function latestValue(result) {
|
|
244
|
+
const values = result.data?.result?.[0]?.values;
|
|
245
|
+
const last = values?.[values.length - 1];
|
|
246
|
+
if (!last) return null;
|
|
247
|
+
const value = Number.parseFloat(last[1]);
|
|
248
|
+
return Number.isFinite(value) ? value : null;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* SigNoz as the `ops` plugin's telemetry provider: error rate, p95 latency and
|
|
252
|
+
* request rate of one service over its PromQL `query_range` API. Server only:
|
|
253
|
+
* the URL and API key come from env on each request.
|
|
254
|
+
*
|
|
255
|
+
* ```ts
|
|
256
|
+
* ops({ telemetry: signoz({ service: "hansenexus" }) })
|
|
257
|
+
* ```
|
|
258
|
+
*/
|
|
259
|
+
function signoz(options) {
|
|
260
|
+
const { service, urlEnv = "SIGNOZ_QUERY_URL", apiKeyEnv = "SIGNOZ_API_KEY" } = options;
|
|
261
|
+
if (!SERVICE.test(service)) throw new Error(`hud ops: signoz service "${service}" is not a valid name`);
|
|
262
|
+
const queries = signozQueries(service);
|
|
263
|
+
async function query(baseUrl, apiKey, promql, range) {
|
|
264
|
+
const end = Math.floor(Date.now() / 1e3);
|
|
265
|
+
const params = new URLSearchParams({
|
|
266
|
+
query: promql,
|
|
267
|
+
start: String(end - RANGE_SECONDS[range]),
|
|
268
|
+
end: String(end),
|
|
269
|
+
step: RANGE_STEP[range]
|
|
270
|
+
});
|
|
271
|
+
const res = await fetch(`${baseUrl.replace(/\/+$/, "")}/api/v1/query_range?${params}`, {
|
|
272
|
+
headers: apiKey ? { "SIGNOZ-API-KEY": apiKey } : {},
|
|
273
|
+
signal: AbortSignal.timeout(UPSTREAM_TIMEOUT_MS)
|
|
274
|
+
});
|
|
275
|
+
if (!res.ok) throw new OpsProviderError(`SigNoz answered ${res.status}`);
|
|
276
|
+
return latestValue(await res.json());
|
|
277
|
+
}
|
|
278
|
+
return {
|
|
279
|
+
name: "signoz",
|
|
280
|
+
async snapshot(range) {
|
|
281
|
+
const base = {
|
|
282
|
+
provider: "signoz",
|
|
283
|
+
service,
|
|
284
|
+
range
|
|
285
|
+
};
|
|
286
|
+
const url = readEnv(urlEnv);
|
|
287
|
+
if (!url) return {
|
|
288
|
+
...base,
|
|
289
|
+
configured: false,
|
|
290
|
+
missing: urlEnv,
|
|
291
|
+
errorRate: null,
|
|
292
|
+
p95Ms: null,
|
|
293
|
+
requestRate: null
|
|
294
|
+
};
|
|
295
|
+
const apiKey = readEnv(apiKeyEnv);
|
|
296
|
+
const [errorRate, p95Ms, requestRate] = await Promise.allSettled([
|
|
297
|
+
query(url, apiKey, queries.errorRate, range),
|
|
298
|
+
query(url, apiKey, queries.p95Ms, range),
|
|
299
|
+
query(url, apiKey, queries.requestRate, range)
|
|
300
|
+
]);
|
|
301
|
+
if (errorRate.status === "rejected" && p95Ms.status === "rejected" && requestRate.status === "rejected") throw errorRate.reason instanceof OpsProviderError ? errorRate.reason : new OpsProviderError("SigNoz unreachable");
|
|
302
|
+
const value = (r) => r.status === "fulfilled" ? r.value : null;
|
|
303
|
+
return {
|
|
304
|
+
...base,
|
|
305
|
+
configured: true,
|
|
306
|
+
errorRate: value(errorRate),
|
|
307
|
+
p95Ms: value(p95Ms),
|
|
308
|
+
requestRate: value(requestRate)
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
//#endregion
|
|
314
|
+
//#region src/plugins/ops/server.ts
|
|
315
|
+
const NO_STORE = { "cache-control": "no-store" };
|
|
316
|
+
function failed(error, what) {
|
|
317
|
+
if (error instanceof OpsProviderError) return Response.json({
|
|
318
|
+
ok: false,
|
|
319
|
+
error: error.message
|
|
320
|
+
}, {
|
|
321
|
+
status: 502,
|
|
322
|
+
headers: NO_STORE
|
|
323
|
+
});
|
|
324
|
+
console.error(`hud ops: ${what} failed`, error);
|
|
325
|
+
return Response.json({
|
|
326
|
+
ok: false,
|
|
327
|
+
error: `${what} failed`
|
|
328
|
+
}, {
|
|
329
|
+
status: 502,
|
|
330
|
+
headers: NO_STORE
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
function isRange(value) {
|
|
334
|
+
return TELEMETRY_RANGES.includes(value);
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Server half of the `ops` plugin. Pass it to `createHudHandler`; each
|
|
338
|
+
* provider adds its route, so an app without telemetry serves no
|
|
339
|
+
* `/telemetry`. Tokens and keys stay in the providers: responses carry
|
|
340
|
+
* run data, numbers and the name of a missing env var, never a secret.
|
|
341
|
+
*/
|
|
342
|
+
function ops({ ci, telemetry } = {}) {
|
|
343
|
+
const routes = {};
|
|
344
|
+
if (ci) routes["/ci"] = { GET: async () => {
|
|
345
|
+
try {
|
|
346
|
+
const [snapshot, deployment] = await Promise.all([ci.snapshot(), ci.deployment?.()]);
|
|
347
|
+
const body = {
|
|
348
|
+
ok: true,
|
|
349
|
+
...snapshot,
|
|
350
|
+
...ci.deployment ? { deployment: deployment ?? null } : {}
|
|
351
|
+
};
|
|
352
|
+
return Response.json(body, { headers: NO_STORE });
|
|
353
|
+
} catch (error) {
|
|
354
|
+
return failed(error, ci.name);
|
|
355
|
+
}
|
|
356
|
+
} };
|
|
357
|
+
if (telemetry) routes["/telemetry"] = { GET: async (request) => {
|
|
358
|
+
const range = new URL(request.url).searchParams.get("range") ?? "1h";
|
|
359
|
+
if (!isRange(range)) return Response.json({
|
|
360
|
+
ok: false,
|
|
361
|
+
error: `range must be one of ${TELEMETRY_RANGES.join(", ")}`
|
|
362
|
+
}, { status: 400 });
|
|
363
|
+
try {
|
|
364
|
+
const body = {
|
|
365
|
+
ok: true,
|
|
366
|
+
...await telemetry.snapshot(range)
|
|
367
|
+
};
|
|
368
|
+
return Response.json(body, { headers: NO_STORE });
|
|
369
|
+
} catch (error) {
|
|
370
|
+
return failed(error, telemetry.name);
|
|
371
|
+
}
|
|
372
|
+
} };
|
|
373
|
+
return definePlugin({
|
|
374
|
+
id: "ops",
|
|
375
|
+
capability: OPS_CAPABILITY,
|
|
376
|
+
routes
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
//#endregion
|
|
380
|
+
export { OpsProviderError, githubActions, ops, signoz };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { c as HudPluginProps } from "../plugins-CQ_0w1ot.js";
|
|
2
|
+
import { c as TelemetryRange, i as CiRun, l as TelemetryResponse, o as CiState, r as CiResponse, t as CiDeployment } from "../types-f3jlNxzw.js";
|
|
3
|
+
//#region src/plugins/ops/index.d.ts
|
|
4
|
+
declare function OpsPill({ ctx }: HudPluginProps): import("react").JSX.Element;
|
|
5
|
+
export interface OpsOptions {
|
|
6
|
+
/** Show the CI section and the CI state in the pill. Default true. */
|
|
7
|
+
ci?: boolean;
|
|
8
|
+
/** Show the telemetry section. Default true. */
|
|
9
|
+
telemetry?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* CI and telemetry: the pill shows the CI state of the branch the server runs
|
|
13
|
+
* on, the panel lists recent runs, the deployment (when the CI provider knows
|
|
14
|
+
* it) and error rate, p95 and request rate. Client half; the providers live in
|
|
15
|
+
* the server half, `@hansenexus/hud/plugins/ops/server`, which reads tokens
|
|
16
|
+
* from env and never sends them to the browser.
|
|
17
|
+
*/
|
|
18
|
+
export declare function ops({ ci, telemetry }?: OpsOptions): {
|
|
19
|
+
readonly id: "ops";
|
|
20
|
+
readonly title: "Ops";
|
|
21
|
+
readonly capability: "cicd.read";
|
|
22
|
+
readonly panel: ({ ctx }: HudPluginProps) => import("react").JSX.Element;
|
|
23
|
+
readonly pill?: typeof OpsPill;
|
|
24
|
+
};
|
|
25
|
+
//#endregion
|
|
26
|
+
export type { CiDeployment, CiResponse, CiRun, CiState, TelemetryRange, TelemetryResponse };
|