sermon-js 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +239 -2
- package/dist/api/index.cjs +174 -0
- package/dist/api/index.cjs.map +1 -0
- package/dist/api/index.d.cts +77 -0
- package/dist/api/index.d.ts +77 -0
- package/dist/api/index.js +171 -0
- package/dist/api/index.js.map +1 -0
- package/dist/chunk-2M4UBCDM.js +178 -0
- package/dist/chunk-2M4UBCDM.js.map +1 -0
- package/dist/chunk-AH372HLN.js +98 -0
- package/dist/chunk-AH372HLN.js.map +1 -0
- package/dist/chunk-APC2HVSI.js +154 -0
- package/dist/chunk-APC2HVSI.js.map +1 -0
- package/dist/chunk-D7BBJTYU.cjs +335 -0
- package/dist/chunk-D7BBJTYU.cjs.map +1 -0
- package/dist/chunk-ELV4ZU6G.cjs +51 -0
- package/dist/chunk-ELV4ZU6G.cjs.map +1 -0
- package/dist/chunk-EMP7XVKC.js +334 -0
- package/dist/chunk-EMP7XVKC.js.map +1 -0
- package/dist/chunk-I3346MUL.js +49 -0
- package/dist/chunk-I3346MUL.js.map +1 -0
- package/dist/chunk-NP3YYVRZ.cjs +163 -0
- package/dist/chunk-NP3YYVRZ.cjs.map +1 -0
- package/dist/chunk-PARE6EUZ.cjs +184 -0
- package/dist/chunk-PARE6EUZ.cjs.map +1 -0
- package/dist/chunk-XHXEKB3Q.cjs +241 -0
- package/dist/chunk-XHXEKB3Q.cjs.map +1 -0
- package/dist/chunk-XPXIDJUU.js +229 -0
- package/dist/chunk-XPXIDJUU.js.map +1 -0
- package/dist/chunk-ZI442ZA5.cjs +100 -0
- package/dist/chunk-ZI442ZA5.cjs.map +1 -0
- package/dist/config-BEbP-uLf.d.cts +125 -0
- package/dist/config-w1tm1bdu.d.ts +125 -0
- package/dist/generic-BJmlgtUM.d.ts +31 -0
- package/dist/generic-lmrGxMDC.d.cts +31 -0
- package/dist/index.cjs +407 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +93 -0
- package/dist/index.d.ts +93 -0
- package/dist/index.js +330 -0
- package/dist/index.js.map +1 -0
- package/dist/presets/index.cjs +1012 -0
- package/dist/presets/index.cjs.map +1 -0
- package/dist/presets/index.d.cts +516 -0
- package/dist/presets/index.d.ts +516 -0
- package/dist/presets/index.js +971 -0
- package/dist/presets/index.js.map +1 -0
- package/dist/react/heroui/index.cjs +822 -0
- package/dist/react/heroui/index.cjs.map +1 -0
- package/dist/react/heroui/index.d.cts +122 -0
- package/dist/react/heroui/index.d.ts +122 -0
- package/dist/react/heroui/index.js +821 -0
- package/dist/react/heroui/index.js.map +1 -0
- package/dist/react/heroui/styles.css +11 -0
- package/dist/react/index.cjs +71 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.cts +53 -0
- package/dist/react/index.d.ts +53 -0
- package/dist/react/index.js +70 -0
- package/dist/react/index.js.map +1 -0
- package/dist/status-DsWzgb9Q.d.cts +146 -0
- package/dist/status-zd04ZQ98.d.ts +146 -0
- package/dist/store-DybhDphS.d.cts +77 -0
- package/dist/store-_GuzSP0z.d.ts +77 -0
- package/dist/stores/mongodb.cjs +99 -0
- package/dist/stores/mongodb.cjs.map +1 -0
- package/dist/stores/mongodb.d.cts +40 -0
- package/dist/stores/mongodb.d.ts +40 -0
- package/dist/stores/mongodb.js +97 -0
- package/dist/stores/mongodb.js.map +1 -0
- package/dist/stores/redis.cjs +23 -0
- package/dist/stores/redis.cjs.map +1 -0
- package/dist/stores/redis.d.cts +31 -0
- package/dist/stores/redis.d.ts +31 -0
- package/dist/stores/redis.js +21 -0
- package/dist/stores/redis.js.map +1 -0
- package/dist/stores/sql.cjs +164 -0
- package/dist/stores/sql.cjs.map +1 -0
- package/dist/stores/sql.d.cts +39 -0
- package/dist/stores/sql.d.ts +39 -0
- package/dist/stores/sql.js +162 -0
- package/dist/stores/sql.js.map +1 -0
- package/dist/stores/upstash.cjs +27 -0
- package/dist/stores/upstash.cjs.map +1 -0
- package/dist/stores/upstash.d.cts +19 -0
- package/dist/stores/upstash.d.ts +19 -0
- package/dist/stores/upstash.js +25 -0
- package/dist/stores/upstash.js.map +1 -0
- package/dist/testing/index.cjs +209 -0
- package/dist/testing/index.cjs.map +1 -0
- package/dist/testing/index.d.cts +66 -0
- package/dist/testing/index.d.ts +66 -0
- package/dist/testing/index.js +205 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/tree-BXbXfjF1.d.cts +236 -0
- package/dist/tree-BXbXfjF1.d.ts +236 -0
- package/dist/types-CctvUAs2.d.cts +192 -0
- package/dist/types-CctvUAs2.d.ts +192 -0
- package/package.json +233 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/testing/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { resolveTree, type ServiceDefinition } from \"../config\";\nimport { runService } from \"../runner\";\nimport { collectSecretValues } from \"../sanitize\";\nimport type { CheckSample, RunSummary, StatusStore } from \"../store\";\nimport type { CheckResult } from \"../types\";\n\nconst summary = (overrides: Partial<RunSummary> = {}): RunSummary => ({\n at: 1_000,\n trigger: \"scheduled\",\n full: true,\n score: 100,\n label: \"operational\",\n failing: {},\n ...overrides,\n});\n\nconst result = (overrides: Partial<CheckResult> = {}): CheckResult => ({\n key: \"api\",\n status: \"up\",\n checkedAt: 1_000,\n probed: true,\n latencyMs: 120,\n ...overrides,\n});\n\nconst sample = (overrides: Partial<CheckSample> = {}): CheckSample => ({\n key: \"api\",\n at: 1_000,\n status: \"up\",\n latencyMs: 120,\n ...overrides,\n});\n\n/** Stores may drop `undefined` fields or not: compare what matters */\nconst clean = <T>(value: T): T => JSON.parse(JSON.stringify(value)) as T;\n\n/** The few test-runner functions the suite needs. Vitest and Jest both fit. */\nexport type TestHarness = {\n describe: (name: string, fn: () => void) => void;\n it: (name: string, fn: () => Promise<void> | void) => void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n expect: (actual: any) => any;\n};\n\nfunction resolveHarness(harness?: TestHarness): TestHarness {\n if (harness) return harness;\n const globals = globalThis as Partial<TestHarness>;\n if (globals.describe && globals.it && globals.expect) {\n return { describe: globals.describe, it: globals.it, expect: globals.expect };\n }\n throw new Error(\n \"sermon-js/testing: pass your test runner's { describe, it, expect } as the third argument \" +\n \"(or enable the runner's globals).\"\n );\n}\n\n/**\n * The contract every `StatusStore` must honour. Call it from a test file of your adapter:\n *\n * ```ts\n * import { describe, expect, it } from \"vitest\"; // or Jest's globals\n * import { runStoreConformance } from \"sermon-js/testing\";\n * runStoreConformance(\"my store\", () => myStore({ … }), { describe, it, expect });\n * ```\n *\n * `createStore` must return a fresh, empty store each time.\n */\nexport function runStoreConformance(\n name: string,\n createStore: () => StatusStore | Promise<StatusStore>,\n harness?: TestHarness\n) {\n const { describe, it, expect } = resolveHarness(harness);\n describe(`${name}: StatusStore conformance`, () => {\n it(\"starts empty\", async () => {\n const store = await createStore();\n expect(await store.latest()).toEqual({});\n expect(await store.runs({ since: 0, until: 10_000 })).toEqual([]);\n expect(await store.samples(\"api\", { since: 0, until: 10_000 })).toEqual([]);\n });\n\n it(\"keeps the latest result of each service, with all its fields\", async () => {\n const store = await createStore();\n const rich = result({\n key: \"fly\",\n status: \"degraded\",\n httpStatus: 200,\n error: \"1/2 machine(s) down: sin\",\n metrics: { machines: \"1/2 running\", count: 2 },\n usage: [{ label: \"Requests\", used: 15, limit: 100, unit: \"requests\", resetsAt: 9_999 }],\n instances: [\n { key: \"ams\", region: \"ams\", id: \"m1\", state: \"started\", status: \"up\", latencyMs: 80, httpStatus: 200 },\n { key: \"sin\", region: \"sin\", id: \"m2\", state: \"stopped\", status: \"down\", error: \"Out of memory\" },\n ],\n });\n await store.saveRun({\n summary: summary(),\n results: [result(), rich, result({ key: \"off\", status: \"unconfigured\", probed: false, latencyMs: undefined })],\n samples: [sample(), sample({ key: \"fly\", status: \"degraded\" })],\n });\n await store.saveRun({\n summary: summary({ at: 2_000, full: false }),\n results: [result({ checkedAt: 2_000, status: \"down\", error: \"HTTP 500\", latencyMs: 300 })],\n samples: [sample({ at: 2_000, status: \"down\", error: \"HTTP 500\", latencyMs: 300 })],\n });\n\n const latest = await store.latest();\n expect(Object.keys(latest).sort()).toEqual([\"api\", \"fly\", \"off\"]);\n expect(clean(latest.api)).toEqual(clean(result({ checkedAt: 2_000, status: \"down\", error: \"HTTP 500\", latencyMs: 300 })));\n expect(clean(latest.fly)).toEqual(clean(rich));\n expect(latest.off?.status).toBe(\"unconfigured\");\n });\n\n it(\"returns runs within an inclusive range, oldest first\", async () => {\n const store = await createStore();\n for (const at of [3_000, 1_000, 2_000]) {\n await store.saveRun({\n summary: summary({ at, score: at / 100, failing: at === 2_000 ? { api: \"down\" } : {} }),\n results: [],\n samples: [],\n });\n }\n const runs = await store.runs({ since: 1_000, until: 2_000 });\n expect(runs.map((run) => run.at)).toEqual([1_000, 2_000]);\n expect(clean(runs[1])).toEqual(\n clean(summary({ at: 2_000, score: 20, failing: { api: \"down\" } }))\n );\n expect((await store.runs({ since: 0, until: 9_000 })).map((run) => run.at)).toEqual([1_000, 2_000, 3_000]);\n });\n\n it(\"returns samples of one service within an inclusive range, oldest first\", async () => {\n const store = await createStore();\n await store.saveRun({\n summary: summary({ at: 2_000 }),\n results: [],\n samples: [\n sample({ at: 2_000, instances: { ams: [\"up\", 80], sin: [\"sleeping\"] } }),\n sample({ key: \"other\", at: 2_000 }),\n ],\n });\n await store.saveRun({ summary: summary({ at: 1_000 }), results: [], samples: [sample({ at: 1_000 })] });\n await store.saveRun({ summary: summary({ at: 3_000 }), results: [], samples: [sample({ at: 3_000 })] });\n\n const samples = await store.samples(\"api\", { since: 1_000, until: 2_000 });\n expect(samples.map((s) => s.at)).toEqual([1_000, 2_000]);\n expect(samples.every((s) => s.key === \"api\")).toBe(true);\n expect(clean(samples[1]?.instances)).toEqual({ ams: [\"up\", 80], sin: [\"sleeping\"] });\n });\n\n it(\"prunes old runs and samples\", async () => {\n const store = await createStore();\n for (const at of [1_000, 2_000, 3_000]) {\n await store.saveRun({ summary: summary({ at }), results: [result({ checkedAt: at })], samples: [sample({ at })] });\n }\n await store.prune({ before: 2_000 });\n expect((await store.runs({ since: 0, until: 9_000 })).map((run) => run.at)).toEqual([2_000, 3_000]);\n expect((await store.samples(\"api\", { since: 0, until: 9_000 })).map((s) => s.at)).toEqual([2_000, 3_000]);\n // Latest results are not history: pruning by time keeps them\n expect(Object.keys(await store.latest())).toEqual([\"api\"]);\n });\n\n it(\"drops services that are not in keepKeys\", async () => {\n const store = await createStore();\n await store.saveRun({\n summary: summary(),\n results: [result(), result({ key: \"removed\" })],\n samples: [sample(), sample({ key: \"removed\" })],\n });\n await store.prune({ before: 0, keepKeys: [\"api\"] });\n expect(Object.keys(await store.latest())).toEqual([\"api\"]);\n expect(await store.samples(\"removed\", { since: 0, until: 9_000 })).toEqual([]);\n expect(await store.samples(\"api\", { since: 0, until: 9_000 })).toHaveLength(1);\n expect(await store.runs({ since: 0, until: 9_000 })).toHaveLength(1);\n });\n\n it(\"locks by name until the time-to-live passes (when supported)\", async () => {\n const store = await createStore();\n if (!store.lock) return;\n expect(await store.lock(\"run-all\", 60_000)).toEqual({ ok: true });\n const second = await store.lock(\"run-all\", 60_000);\n expect(second.ok).toBe(false);\n if (!second.ok) {\n expect(second.retryAfterMs).toBeGreaterThan(0);\n expect(second.retryAfterMs).toBeLessThanOrEqual(60_000);\n }\n expect(await store.lock(\"another\", 60_000)).toEqual({ ok: true });\n\n expect(await store.lock(\"short\", 20)).toEqual({ ok: true });\n await new Promise((resolve) => setTimeout(resolve, 60));\n expect(await store.lock(\"short\", 20)).toEqual({ ok: true });\n\n if (store.unlock) {\n await store.unlock(\"run-all\");\n expect(await store.lock(\"run-all\", 60_000)).toEqual({ ok: true });\n // Releasing a lock nobody holds is fine\n await store.unlock(\"never-taken\");\n }\n });\n\n it(\"caches small values with a time-to-live (when supported)\", async () => {\n const store = await createStore();\n if (!store.cache) return;\n expect(await store.cache.get(\"missing\")).toBeNull();\n await store.cache.set(\"stats\", '{\"a\":1}', 60_000);\n expect(await store.cache.get(\"stats\")).toBe('{\"a\":1}');\n await store.cache.set(\"stats\", '{\"a\":2}', 60_000);\n expect(await store.cache.get(\"stats\")).toBe('{\"a\":2}');\n\n await store.cache.set(\"brief\", \"x\", 20);\n await new Promise((resolve) => setTimeout(resolve, 60));\n expect(await store.cache.get(\"brief\")).toBeNull();\n });\n });\n}\n\nexport type MockRoute = {\n /** Matches when the request URL contains this string, or matches this pattern */\n url: string | RegExp;\n method?: string;\n status?: number;\n /** JSON-serialized when it's an object */\n body?: unknown;\n headers?: Record<string, string>;\n /** Reject the request like a network failure */\n error?: Error;\n /** Delay the response, to simulate latency */\n delayMs?: number;\n};\n\nexport type MockFetch = typeof fetch & {\n /** Every request made, in order */\n calls: Array<{ url: string; method: string; headers: Record<string, string>; body?: string }>;\n};\n\n/**\n * A `fetch` that answers from a list of routes (first match wins) and records every call.\n * Unmatched requests fail, so tests prove that nothing unexpected is called.\n */\nexport function mockFetch(routes: MockRoute[]): MockFetch {\n const calls: MockFetch[\"calls\"] = [];\n const impl = async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n const url = typeof input === \"string\" ? input : input instanceof URL ? input.href : input.url;\n const method = (init?.method ?? \"GET\").toUpperCase();\n const headers = Object.fromEntries(new Headers(init?.headers).entries());\n calls.push({ url, method, headers, body: typeof init?.body === \"string\" ? init.body : undefined });\n\n const route = routes.find(\n (candidate) =>\n (typeof candidate.url === \"string\" ? url.includes(candidate.url) : candidate.url.test(url)) &&\n (!candidate.method || candidate.method.toUpperCase() === method)\n );\n if (!route) throw new TypeError(`mockFetch: no route for ${method} ${url}`);\n if (route.delayMs) await new Promise((resolve) => setTimeout(resolve, route.delayMs));\n if (route.error) throw route.error;\n const body =\n route.body === undefined ? \"\" : typeof route.body === \"string\" ? route.body : JSON.stringify(route.body);\n // Null-body statuses (204, 304…) reject a body, even an empty one\n return new Response(body || null, { status: route.status ?? 200, headers: route.headers });\n };\n return Object.assign(impl as typeof fetch, { calls });\n}\n\n/**\n * Run one service exactly as the engine would (shared rules, redaction, timing) and return\n * its result. For testing presets and custom checks:\n *\n * ```ts\n * const fetch = mockFetch([{ url: \"/health\", status: 200 }]);\n * const result = await runCheck(myPreset({ … }), { fetch });\n * ```\n */\nexport async function runCheck(\n service: ServiceDefinition,\n options: { fetch?: typeof fetch; now?: () => number; cache?: Map<string, string>; hideResponseBodies?: boolean } = {}\n): Promise<CheckResult> {\n const [resolved] = [...resolveTree([service]).services.values()];\n const cache = options.cache ?? new Map<string, string>();\n return runService({\n service: resolved!,\n secretValues: collectSecretValues([...Object.values(service.secrets), ...(service.sensitive ?? [])]),\n fetch: options.fetch,\n now: options.now,\n hideResponseBodies: options.hideResponseBodies,\n cache: {\n get: async (key) => cache.get(key) ?? null,\n set: async (key, value) => void cache.set(key, value),\n },\n });\n}\n"]}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/** The five statuses every service reports */
|
|
2
|
+
type Status = "up" | "degraded" | "down" | "sleeping" | "unconfigured";
|
|
3
|
+
/** What a check itself can report: "unconfigured" is decided by the library, never by a check */
|
|
4
|
+
type OutcomeStatus = Exclude<Status, "unconfigured">;
|
|
5
|
+
type ScoreLabel = "operational" | "degraded" | "outage" | "unknown";
|
|
6
|
+
/** Small labelled values shown as chips (balance, machine count, VM state…) */
|
|
7
|
+
type Metrics = Record<string, string | number>;
|
|
8
|
+
/** A consumable quota, rendered as a usage bar */
|
|
9
|
+
type Usage = {
|
|
10
|
+
label: string;
|
|
11
|
+
used: number;
|
|
12
|
+
limit: number;
|
|
13
|
+
unit?: string;
|
|
14
|
+
/** When the quota resets (ms epoch), if the provider says */
|
|
15
|
+
resetsAt?: number;
|
|
16
|
+
};
|
|
17
|
+
/** One machine/region of a multi-instance service, tracked individually */
|
|
18
|
+
type Instance = {
|
|
19
|
+
/** Stable across deploys (e.g. the region, suffixed when a region runs several machines) */
|
|
20
|
+
key: string;
|
|
21
|
+
region?: string;
|
|
22
|
+
/** Platform identifier of the machine/instance */
|
|
23
|
+
id?: string;
|
|
24
|
+
/** Raw platform state: started, suspended, RUNNING… */
|
|
25
|
+
state?: string;
|
|
26
|
+
status: OutcomeStatus;
|
|
27
|
+
latencyMs?: number;
|
|
28
|
+
httpStatus?: number;
|
|
29
|
+
error?: string;
|
|
30
|
+
};
|
|
31
|
+
/** What a check returns */
|
|
32
|
+
type CheckOutcome = {
|
|
33
|
+
status: OutcomeStatus;
|
|
34
|
+
/** Measured for you (wall time of the check) when omitted */
|
|
35
|
+
latencyMs?: number;
|
|
36
|
+
httpStatus?: number;
|
|
37
|
+
/** Shown publicly: secrets are redacted and long text is truncated */
|
|
38
|
+
error?: string;
|
|
39
|
+
metrics?: Metrics;
|
|
40
|
+
usage?: Usage[];
|
|
41
|
+
instances?: Instance[];
|
|
42
|
+
/** Set to false when the target was deliberately not touched (e.g. a sleeping machine) */
|
|
43
|
+
probed?: boolean;
|
|
44
|
+
};
|
|
45
|
+
/** The stored result of one check run */
|
|
46
|
+
type CheckResult = Omit<CheckOutcome, "status" | "probed"> & {
|
|
47
|
+
key: string;
|
|
48
|
+
status: Status;
|
|
49
|
+
checkedAt: number;
|
|
50
|
+
probed: boolean;
|
|
51
|
+
};
|
|
52
|
+
/** Per-service statistics computed from history */
|
|
53
|
+
type InstanceStats = {
|
|
54
|
+
uptime24h: number | null;
|
|
55
|
+
p50: number | null;
|
|
56
|
+
samples24h: number;
|
|
57
|
+
};
|
|
58
|
+
type ServiceStats = {
|
|
59
|
+
/** Share of runs that were not "down", in percent */
|
|
60
|
+
uptime24h: number | null;
|
|
61
|
+
uptime7d: number | null;
|
|
62
|
+
p50: number | null;
|
|
63
|
+
p95: number | null;
|
|
64
|
+
samples24h: number;
|
|
65
|
+
/** Latency series over the last 24h, oldest first (for sparklines) */
|
|
66
|
+
latency: Array<number | null>;
|
|
67
|
+
lastFailure?: {
|
|
68
|
+
at: number;
|
|
69
|
+
status: Status;
|
|
70
|
+
error?: string;
|
|
71
|
+
};
|
|
72
|
+
instances?: Record<string, InstanceStats>;
|
|
73
|
+
};
|
|
74
|
+
type ServiceSnapshot = {
|
|
75
|
+
type: "service";
|
|
76
|
+
/** Derived, internal: only used for anchors, single-service runs and history routes */
|
|
77
|
+
key: string;
|
|
78
|
+
/** The preset kind: "custom", "generic.http", "fly.app"… */
|
|
79
|
+
kind: string;
|
|
80
|
+
name: string;
|
|
81
|
+
description?: string;
|
|
82
|
+
critical: boolean;
|
|
83
|
+
slowMs: number;
|
|
84
|
+
configured: boolean;
|
|
85
|
+
/** Which required secrets/fields are missing when not configured */
|
|
86
|
+
missing?: string[];
|
|
87
|
+
result?: CheckResult;
|
|
88
|
+
stats?: ServiceStats;
|
|
89
|
+
};
|
|
90
|
+
type GroupSnapshot = {
|
|
91
|
+
type: "group";
|
|
92
|
+
key: string;
|
|
93
|
+
title: string;
|
|
94
|
+
description?: string;
|
|
95
|
+
children: SnapshotNode[];
|
|
96
|
+
};
|
|
97
|
+
type SnapshotNode = GroupSnapshot | ServiceSnapshot;
|
|
98
|
+
type Trigger = "scheduled" | "manual";
|
|
99
|
+
type StatusSnapshot = {
|
|
100
|
+
schemaVersion: 1;
|
|
101
|
+
generatedAt: number;
|
|
102
|
+
/** Most recent check of any service */
|
|
103
|
+
lastCheckedAt: number | null;
|
|
104
|
+
/** Last run of every service, and how it was triggered */
|
|
105
|
+
lastRunAt: number | null;
|
|
106
|
+
lastRunTrigger: Trigger | null;
|
|
107
|
+
/** When the next full run is due, based on `interval` */
|
|
108
|
+
nextDueAt: number | null;
|
|
109
|
+
intervalMs: number;
|
|
110
|
+
/** How long history is kept */
|
|
111
|
+
retentionMs: number;
|
|
112
|
+
score: number | null;
|
|
113
|
+
label: ScoreLabel;
|
|
114
|
+
counts: Record<Status, number>;
|
|
115
|
+
tree: SnapshotNode[];
|
|
116
|
+
};
|
|
117
|
+
type HistoryRange = "24h" | "7d";
|
|
118
|
+
type HistoryBar = {
|
|
119
|
+
start: number;
|
|
120
|
+
/** Worst score in the bucket; null when no run happened */
|
|
121
|
+
score: number | null;
|
|
122
|
+
label: ScoreLabel;
|
|
123
|
+
runs: number;
|
|
124
|
+
/** Services that were degraded or down in the bucket ("down" wins) */
|
|
125
|
+
failing: Record<string, Status>;
|
|
126
|
+
};
|
|
127
|
+
type HistoryPayload = {
|
|
128
|
+
schemaVersion: 1;
|
|
129
|
+
range: HistoryRange;
|
|
130
|
+
bucketMs: number;
|
|
131
|
+
bars: HistoryBar[];
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
/** One entry per service per run: drives uptime, latency percentiles and sparklines */
|
|
135
|
+
type CheckSample = {
|
|
136
|
+
key: string;
|
|
137
|
+
at: number;
|
|
138
|
+
status: Status;
|
|
139
|
+
latencyMs?: number;
|
|
140
|
+
httpStatus?: number;
|
|
141
|
+
error?: string;
|
|
142
|
+
/** Per instance (e.g. region): key → [status, latency] */
|
|
143
|
+
instances?: Record<string, [Status, number?]>;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
type ServiceHistory = {
|
|
147
|
+
schemaVersion: 1;
|
|
148
|
+
key: string;
|
|
149
|
+
range: HistoryRange;
|
|
150
|
+
samples: CheckSample[];
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
/** Thrown when an on-demand run is refused because one happened too recently */
|
|
154
|
+
declare class RateLimitError extends Error {
|
|
155
|
+
readonly retryAfter: number;
|
|
156
|
+
constructor(retryAfter: number);
|
|
157
|
+
}
|
|
158
|
+
type StatusClient = {
|
|
159
|
+
status(): Promise<StatusSnapshot>;
|
|
160
|
+
history(range: HistoryRange): Promise<HistoryPayload>;
|
|
161
|
+
serviceHistory(key: string, range: HistoryRange): Promise<ServiceHistory>;
|
|
162
|
+
/** Run everything, or one service; resolves with the fresh snapshot */
|
|
163
|
+
run(key?: string): Promise<StatusSnapshot>;
|
|
164
|
+
};
|
|
165
|
+
/** Talks to the routes of `createStatusHandler` */
|
|
166
|
+
declare function createStatusClient({ baseUrl, fetch: fetchImpl, }?: {
|
|
167
|
+
/** Where the API is mounted (default "/api"); may be an absolute URL */
|
|
168
|
+
baseUrl?: string;
|
|
169
|
+
fetch?: typeof fetch;
|
|
170
|
+
}): StatusClient;
|
|
171
|
+
|
|
172
|
+
type Tone = "success" | "warning" | "danger" | "default" | "accent";
|
|
173
|
+
declare const STATUS_TONE: Record<Status, Tone>;
|
|
174
|
+
declare const STATUS_TEXT: Record<Status, string>;
|
|
175
|
+
declare const LABEL_TONE: Record<ScoreLabel, Tone>;
|
|
176
|
+
declare const LABEL_TEXT: Record<ScoreLabel, string>;
|
|
177
|
+
declare function timeAgo(timestamp: number, now?: number): string;
|
|
178
|
+
declare function formatMs(ms: number | null | undefined): string;
|
|
179
|
+
declare function formatPct(pct: number | null | undefined): string;
|
|
180
|
+
declare function formatDateTime(timestamp: number): string;
|
|
181
|
+
/** A duration in words: 300000 → "5 minutes" */
|
|
182
|
+
declare function formatDuration(ms: number): string;
|
|
183
|
+
/** "quotaUsed" → "Quota used" */
|
|
184
|
+
declare function humanize(key: string): string;
|
|
185
|
+
|
|
186
|
+
/** The status to show for a service: its latest result, or "unconfigured" */
|
|
187
|
+
declare const statusOf: (service: ServiceSnapshot) => Status;
|
|
188
|
+
/** Failing first, then critical, then by name */
|
|
189
|
+
declare function sortServices(services: ServiceSnapshot[]): ServiceSnapshot[];
|
|
190
|
+
/** Every service of a tree, in declaration order */
|
|
191
|
+
declare function flattenServices(nodes: SnapshotNode[]): ServiceSnapshot[];
|
|
192
|
+
/** A group ready to render: its own services, sorted, and its nested groups */
|
|
193
|
+
type Section = {
|
|
194
|
+
key: string;
|
|
195
|
+
title: string;
|
|
196
|
+
description?: string;
|
|
197
|
+
services: ServiceSnapshot[];
|
|
198
|
+
groups: Section[];
|
|
199
|
+
};
|
|
200
|
+
/** A page is a list of blocks: sections (cards), or a heading introducing several sections */
|
|
201
|
+
type LayoutBlock = {
|
|
202
|
+
type: "section";
|
|
203
|
+
section: Section;
|
|
204
|
+
} | {
|
|
205
|
+
type: "heading";
|
|
206
|
+
key: string;
|
|
207
|
+
title: string;
|
|
208
|
+
description?: string;
|
|
209
|
+
sections: Section[];
|
|
210
|
+
};
|
|
211
|
+
/**
|
|
212
|
+
* Turn the snapshot tree into page blocks:
|
|
213
|
+
* - a top-level group with services of its own is one section
|
|
214
|
+
* - a top-level group that only contains groups is a heading, followed by one section per group
|
|
215
|
+
* - services outside any group are gathered into a section titled `ungroupedTitle`
|
|
216
|
+
*/
|
|
217
|
+
declare function buildLayout(tree: StatusSnapshot["tree"], { ungroupedTitle }?: {
|
|
218
|
+
ungroupedTitle?: string;
|
|
219
|
+
}): LayoutBlock[];
|
|
220
|
+
/** Every service of a section, including its nested groups */
|
|
221
|
+
declare function servicesOf(section: Section): ServiceSnapshot[];
|
|
222
|
+
/** Every section of a layout, flattened (headings contribute their sections) */
|
|
223
|
+
declare function sectionsOf(blocks: LayoutBlock[]): Section[];
|
|
224
|
+
/** True when the last full run is older than twice the interval: the scheduler probably stopped */
|
|
225
|
+
declare function isStale(snapshot: Pick<StatusSnapshot, "lastRunAt" | "intervalMs">, now?: number): boolean;
|
|
226
|
+
/**
|
|
227
|
+
* Fit history bars into a narrow space by merging neighbours: each merged bar keeps the
|
|
228
|
+
* worst score and label of its group, the sum of runs and every failure ("down" wins).
|
|
229
|
+
* Returns the bars and how many original bars each one now covers.
|
|
230
|
+
*/
|
|
231
|
+
declare function mergeBars(bars: HistoryBar[], maxBars: number): {
|
|
232
|
+
bars: HistoryBar[];
|
|
233
|
+
factor: number;
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
export { type HistoryRange as H, type Instance as I, type LayoutBlock as L, RateLimitError as R, type StatusClient as S, type Tone as T, type Usage as U, type StatusSnapshot as a, type Section as b, type ServiceSnapshot as c, type ServiceStats as d, type HistoryPayload as e, LABEL_TEXT as f, LABEL_TONE as g, STATUS_TEXT as h, STATUS_TONE as i, buildLayout as j, createStatusClient as k, flattenServices as l, formatDateTime as m, formatDuration as n, formatMs as o, formatPct as p, humanize as q, isStale as r, mergeBars as s, sectionsOf as t, servicesOf as u, sortServices as v, statusOf as w, timeAgo as x };
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/** The five statuses every service reports */
|
|
2
|
+
type Status = "up" | "degraded" | "down" | "sleeping" | "unconfigured";
|
|
3
|
+
/** What a check itself can report: "unconfigured" is decided by the library, never by a check */
|
|
4
|
+
type OutcomeStatus = Exclude<Status, "unconfigured">;
|
|
5
|
+
type ScoreLabel = "operational" | "degraded" | "outage" | "unknown";
|
|
6
|
+
/** Small labelled values shown as chips (balance, machine count, VM state…) */
|
|
7
|
+
type Metrics = Record<string, string | number>;
|
|
8
|
+
/** A consumable quota, rendered as a usage bar */
|
|
9
|
+
type Usage = {
|
|
10
|
+
label: string;
|
|
11
|
+
used: number;
|
|
12
|
+
limit: number;
|
|
13
|
+
unit?: string;
|
|
14
|
+
/** When the quota resets (ms epoch), if the provider says */
|
|
15
|
+
resetsAt?: number;
|
|
16
|
+
};
|
|
17
|
+
/** One machine/region of a multi-instance service, tracked individually */
|
|
18
|
+
type Instance = {
|
|
19
|
+
/** Stable across deploys (e.g. the region, suffixed when a region runs several machines) */
|
|
20
|
+
key: string;
|
|
21
|
+
region?: string;
|
|
22
|
+
/** Platform identifier of the machine/instance */
|
|
23
|
+
id?: string;
|
|
24
|
+
/** Raw platform state: started, suspended, RUNNING… */
|
|
25
|
+
state?: string;
|
|
26
|
+
status: OutcomeStatus;
|
|
27
|
+
latencyMs?: number;
|
|
28
|
+
httpStatus?: number;
|
|
29
|
+
error?: string;
|
|
30
|
+
};
|
|
31
|
+
/** What a check returns */
|
|
32
|
+
type CheckOutcome = {
|
|
33
|
+
status: OutcomeStatus;
|
|
34
|
+
/** Measured for you (wall time of the check) when omitted */
|
|
35
|
+
latencyMs?: number;
|
|
36
|
+
httpStatus?: number;
|
|
37
|
+
/** Shown publicly: secrets are redacted and long text is truncated */
|
|
38
|
+
error?: string;
|
|
39
|
+
metrics?: Metrics;
|
|
40
|
+
usage?: Usage[];
|
|
41
|
+
instances?: Instance[];
|
|
42
|
+
/** Set to false when the target was deliberately not touched (e.g. a sleeping machine) */
|
|
43
|
+
probed?: boolean;
|
|
44
|
+
};
|
|
45
|
+
/** The stored result of one check run */
|
|
46
|
+
type CheckResult = Omit<CheckOutcome, "status" | "probed"> & {
|
|
47
|
+
key: string;
|
|
48
|
+
status: Status;
|
|
49
|
+
checkedAt: number;
|
|
50
|
+
probed: boolean;
|
|
51
|
+
};
|
|
52
|
+
/** Per-service statistics computed from history */
|
|
53
|
+
type InstanceStats = {
|
|
54
|
+
uptime24h: number | null;
|
|
55
|
+
p50: number | null;
|
|
56
|
+
samples24h: number;
|
|
57
|
+
};
|
|
58
|
+
type ServiceStats = {
|
|
59
|
+
/** Share of runs that were not "down", in percent */
|
|
60
|
+
uptime24h: number | null;
|
|
61
|
+
uptime7d: number | null;
|
|
62
|
+
p50: number | null;
|
|
63
|
+
p95: number | null;
|
|
64
|
+
samples24h: number;
|
|
65
|
+
/** Latency series over the last 24h, oldest first (for sparklines) */
|
|
66
|
+
latency: Array<number | null>;
|
|
67
|
+
lastFailure?: {
|
|
68
|
+
at: number;
|
|
69
|
+
status: Status;
|
|
70
|
+
error?: string;
|
|
71
|
+
};
|
|
72
|
+
instances?: Record<string, InstanceStats>;
|
|
73
|
+
};
|
|
74
|
+
type ServiceSnapshot = {
|
|
75
|
+
type: "service";
|
|
76
|
+
/** Derived, internal: only used for anchors, single-service runs and history routes */
|
|
77
|
+
key: string;
|
|
78
|
+
/** The preset kind: "custom", "generic.http", "fly.app"… */
|
|
79
|
+
kind: string;
|
|
80
|
+
name: string;
|
|
81
|
+
description?: string;
|
|
82
|
+
critical: boolean;
|
|
83
|
+
slowMs: number;
|
|
84
|
+
configured: boolean;
|
|
85
|
+
/** Which required secrets/fields are missing when not configured */
|
|
86
|
+
missing?: string[];
|
|
87
|
+
result?: CheckResult;
|
|
88
|
+
stats?: ServiceStats;
|
|
89
|
+
};
|
|
90
|
+
type GroupSnapshot = {
|
|
91
|
+
type: "group";
|
|
92
|
+
key: string;
|
|
93
|
+
title: string;
|
|
94
|
+
description?: string;
|
|
95
|
+
children: SnapshotNode[];
|
|
96
|
+
};
|
|
97
|
+
type SnapshotNode = GroupSnapshot | ServiceSnapshot;
|
|
98
|
+
type Trigger = "scheduled" | "manual";
|
|
99
|
+
type StatusSnapshot = {
|
|
100
|
+
schemaVersion: 1;
|
|
101
|
+
generatedAt: number;
|
|
102
|
+
/** Most recent check of any service */
|
|
103
|
+
lastCheckedAt: number | null;
|
|
104
|
+
/** Last run of every service, and how it was triggered */
|
|
105
|
+
lastRunAt: number | null;
|
|
106
|
+
lastRunTrigger: Trigger | null;
|
|
107
|
+
/** When the next full run is due, based on `interval` */
|
|
108
|
+
nextDueAt: number | null;
|
|
109
|
+
intervalMs: number;
|
|
110
|
+
/** How long history is kept */
|
|
111
|
+
retentionMs: number;
|
|
112
|
+
score: number | null;
|
|
113
|
+
label: ScoreLabel;
|
|
114
|
+
counts: Record<Status, number>;
|
|
115
|
+
tree: SnapshotNode[];
|
|
116
|
+
};
|
|
117
|
+
type HistoryRange = "24h" | "7d";
|
|
118
|
+
type HistoryBar = {
|
|
119
|
+
start: number;
|
|
120
|
+
/** Worst score in the bucket; null when no run happened */
|
|
121
|
+
score: number | null;
|
|
122
|
+
label: ScoreLabel;
|
|
123
|
+
runs: number;
|
|
124
|
+
/** Services that were degraded or down in the bucket ("down" wins) */
|
|
125
|
+
failing: Record<string, Status>;
|
|
126
|
+
};
|
|
127
|
+
type HistoryPayload = {
|
|
128
|
+
schemaVersion: 1;
|
|
129
|
+
range: HistoryRange;
|
|
130
|
+
bucketMs: number;
|
|
131
|
+
bars: HistoryBar[];
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
/** One entry per service per run: drives uptime, latency percentiles and sparklines */
|
|
135
|
+
type CheckSample = {
|
|
136
|
+
key: string;
|
|
137
|
+
at: number;
|
|
138
|
+
status: Status;
|
|
139
|
+
latencyMs?: number;
|
|
140
|
+
httpStatus?: number;
|
|
141
|
+
error?: string;
|
|
142
|
+
/** Per instance (e.g. region): key → [status, latency] */
|
|
143
|
+
instances?: Record<string, [Status, number?]>;
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
type ServiceHistory = {
|
|
147
|
+
schemaVersion: 1;
|
|
148
|
+
key: string;
|
|
149
|
+
range: HistoryRange;
|
|
150
|
+
samples: CheckSample[];
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
/** Thrown when an on-demand run is refused because one happened too recently */
|
|
154
|
+
declare class RateLimitError extends Error {
|
|
155
|
+
readonly retryAfter: number;
|
|
156
|
+
constructor(retryAfter: number);
|
|
157
|
+
}
|
|
158
|
+
type StatusClient = {
|
|
159
|
+
status(): Promise<StatusSnapshot>;
|
|
160
|
+
history(range: HistoryRange): Promise<HistoryPayload>;
|
|
161
|
+
serviceHistory(key: string, range: HistoryRange): Promise<ServiceHistory>;
|
|
162
|
+
/** Run everything, or one service; resolves with the fresh snapshot */
|
|
163
|
+
run(key?: string): Promise<StatusSnapshot>;
|
|
164
|
+
};
|
|
165
|
+
/** Talks to the routes of `createStatusHandler` */
|
|
166
|
+
declare function createStatusClient({ baseUrl, fetch: fetchImpl, }?: {
|
|
167
|
+
/** Where the API is mounted (default "/api"); may be an absolute URL */
|
|
168
|
+
baseUrl?: string;
|
|
169
|
+
fetch?: typeof fetch;
|
|
170
|
+
}): StatusClient;
|
|
171
|
+
|
|
172
|
+
type Tone = "success" | "warning" | "danger" | "default" | "accent";
|
|
173
|
+
declare const STATUS_TONE: Record<Status, Tone>;
|
|
174
|
+
declare const STATUS_TEXT: Record<Status, string>;
|
|
175
|
+
declare const LABEL_TONE: Record<ScoreLabel, Tone>;
|
|
176
|
+
declare const LABEL_TEXT: Record<ScoreLabel, string>;
|
|
177
|
+
declare function timeAgo(timestamp: number, now?: number): string;
|
|
178
|
+
declare function formatMs(ms: number | null | undefined): string;
|
|
179
|
+
declare function formatPct(pct: number | null | undefined): string;
|
|
180
|
+
declare function formatDateTime(timestamp: number): string;
|
|
181
|
+
/** A duration in words: 300000 → "5 minutes" */
|
|
182
|
+
declare function formatDuration(ms: number): string;
|
|
183
|
+
/** "quotaUsed" → "Quota used" */
|
|
184
|
+
declare function humanize(key: string): string;
|
|
185
|
+
|
|
186
|
+
/** The status to show for a service: its latest result, or "unconfigured" */
|
|
187
|
+
declare const statusOf: (service: ServiceSnapshot) => Status;
|
|
188
|
+
/** Failing first, then critical, then by name */
|
|
189
|
+
declare function sortServices(services: ServiceSnapshot[]): ServiceSnapshot[];
|
|
190
|
+
/** Every service of a tree, in declaration order */
|
|
191
|
+
declare function flattenServices(nodes: SnapshotNode[]): ServiceSnapshot[];
|
|
192
|
+
/** A group ready to render: its own services, sorted, and its nested groups */
|
|
193
|
+
type Section = {
|
|
194
|
+
key: string;
|
|
195
|
+
title: string;
|
|
196
|
+
description?: string;
|
|
197
|
+
services: ServiceSnapshot[];
|
|
198
|
+
groups: Section[];
|
|
199
|
+
};
|
|
200
|
+
/** A page is a list of blocks: sections (cards), or a heading introducing several sections */
|
|
201
|
+
type LayoutBlock = {
|
|
202
|
+
type: "section";
|
|
203
|
+
section: Section;
|
|
204
|
+
} | {
|
|
205
|
+
type: "heading";
|
|
206
|
+
key: string;
|
|
207
|
+
title: string;
|
|
208
|
+
description?: string;
|
|
209
|
+
sections: Section[];
|
|
210
|
+
};
|
|
211
|
+
/**
|
|
212
|
+
* Turn the snapshot tree into page blocks:
|
|
213
|
+
* - a top-level group with services of its own is one section
|
|
214
|
+
* - a top-level group that only contains groups is a heading, followed by one section per group
|
|
215
|
+
* - services outside any group are gathered into a section titled `ungroupedTitle`
|
|
216
|
+
*/
|
|
217
|
+
declare function buildLayout(tree: StatusSnapshot["tree"], { ungroupedTitle }?: {
|
|
218
|
+
ungroupedTitle?: string;
|
|
219
|
+
}): LayoutBlock[];
|
|
220
|
+
/** Every service of a section, including its nested groups */
|
|
221
|
+
declare function servicesOf(section: Section): ServiceSnapshot[];
|
|
222
|
+
/** Every section of a layout, flattened (headings contribute their sections) */
|
|
223
|
+
declare function sectionsOf(blocks: LayoutBlock[]): Section[];
|
|
224
|
+
/** True when the last full run is older than twice the interval: the scheduler probably stopped */
|
|
225
|
+
declare function isStale(snapshot: Pick<StatusSnapshot, "lastRunAt" | "intervalMs">, now?: number): boolean;
|
|
226
|
+
/**
|
|
227
|
+
* Fit history bars into a narrow space by merging neighbours: each merged bar keeps the
|
|
228
|
+
* worst score and label of its group, the sum of runs and every failure ("down" wins).
|
|
229
|
+
* Returns the bars and how many original bars each one now covers.
|
|
230
|
+
*/
|
|
231
|
+
declare function mergeBars(bars: HistoryBar[], maxBars: number): {
|
|
232
|
+
bars: HistoryBar[];
|
|
233
|
+
factor: number;
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
export { type HistoryRange as H, type Instance as I, type LayoutBlock as L, RateLimitError as R, type StatusClient as S, type Tone as T, type Usage as U, type StatusSnapshot as a, type Section as b, type ServiceSnapshot as c, type ServiceStats as d, type HistoryPayload as e, LABEL_TEXT as f, LABEL_TONE as g, STATUS_TEXT as h, STATUS_TONE as i, buildLayout as j, createStatusClient as k, flattenServices as l, formatDateTime as m, formatDuration as n, formatMs as o, formatPct as p, humanize as q, isStale as r, mergeBars as s, sectionsOf as t, servicesOf as u, sortServices as v, statusOf as w, timeAgo as x };
|