@rahdar/plugin-sdk 0.0.0-stage → 2026.10.50

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.
Files changed (154) hide show
  1. package/README.md +37 -2
  2. package/index.js +52 -0
  3. package/package.json +44 -4
  4. package/peers.json +8 -0
  5. package/shared.d.ts +3 -0
  6. package/shared.js +24 -0
  7. package/types/branding.d.ts +14 -0
  8. package/types/kernel/actions/ActionHost.d.ts +16 -0
  9. package/types/kernel/actions/hostContext.d.ts +4 -0
  10. package/types/kernel/actions/types.d.ts +130 -0
  11. package/types/kernel/api/paging.d.ts +39 -0
  12. package/types/kernel/api/polling.d.ts +37 -0
  13. package/types/kernel/api/request.d.ts +84 -0
  14. package/types/kernel/api/schema.d.ts +24077 -0
  15. package/types/kernel/approvals/ApprovalView.d.ts +6 -0
  16. package/types/kernel/approvals/ApprovalsView.d.ts +7 -0
  17. package/types/kernel/approvals/ApproverQuorumNotice.d.ts +8 -0
  18. package/types/kernel/approvals/BreakGlassBanner.d.ts +5 -0
  19. package/types/kernel/approvals/CancelRequest.d.ts +13 -0
  20. package/types/kernel/approvals/DecisionPanel.d.ts +11 -0
  21. package/types/kernel/approvals/ExpiresIn.d.ts +10 -0
  22. package/types/kernel/approvals/MyRequests.d.ts +5 -0
  23. package/types/kernel/approvals/Recap.d.ts +9 -0
  24. package/types/kernel/approvals/api.d.ts +130 -0
  25. package/types/kernel/approvals/columns.d.ts +22 -0
  26. package/types/kernel/approvals/words.d.ts +31 -0
  27. package/types/kernel/auth/Can.d.ts +9 -0
  28. package/types/kernel/auth/LoginView.d.ts +9 -0
  29. package/types/kernel/auth/SecondFactorForm.d.ts +25 -0
  30. package/types/kernel/auth/StepUp.d.ts +17 -0
  31. package/types/kernel/auth/api.d.ts +115 -0
  32. package/types/kernel/auth/freshSignIn.d.ts +2 -0
  33. package/types/kernel/auth/useCan.d.ts +49 -0
  34. package/types/kernel/auth/webauthn.d.ts +19 -0
  35. package/types/kernel/feature.d.ts +90 -0
  36. package/types/kernel/features.d.ts +5 -0
  37. package/types/kernel/inbox/InboxBell.d.ts +6 -0
  38. package/types/kernel/inbox/InboxView.d.ts +6 -0
  39. package/types/kernel/inbox/NoticeRow.d.ts +17 -0
  40. package/types/kernel/inbox/api.d.ts +53 -0
  41. package/types/kernel/keyboard/ShortcutsHelp.d.ts +6 -0
  42. package/types/kernel/keyboard/filterShortcut.d.ts +5 -0
  43. package/types/kernel/keyboard/keys.d.ts +14 -0
  44. package/types/kernel/keyboard/shortcuts.d.ts +5 -0
  45. package/types/kernel/keyboard/useKeySequences.d.ts +16 -0
  46. package/types/kernel/manifest.d.ts +21 -0
  47. package/types/kernel/metrics/ChartPanel.d.ts +28 -0
  48. package/types/kernel/metrics/MetricChart.d.ts +13 -0
  49. package/types/kernel/metrics/axis.d.ts +71 -0
  50. package/types/kernel/metrics/pluginSeries.d.ts +17 -0
  51. package/types/kernel/nav/currentView.d.ts +21 -0
  52. package/types/kernel/nav/groups.d.ts +22 -0
  53. package/types/kernel/plugins/PluginBoundary.d.ts +25 -0
  54. package/types/kernel/plugins/PluginUnavailable.d.ts +6 -0
  55. package/types/kernel/plugins/boot.d.ts +33 -0
  56. package/types/kernel/plugins/guarded.d.ts +3 -0
  57. package/types/kernel/plugins/usePluginsChanged.d.ts +6 -0
  58. package/types/kernel/plugins/validate.d.ts +19 -0
  59. package/types/kernel/registry.d.ts +12 -0
  60. package/types/kernel/routing/roots.d.ts +24 -0
  61. package/types/kernel/shell/AccountView.d.ts +11 -0
  62. package/types/kernel/shell/AdminView.d.ts +7 -0
  63. package/types/kernel/shell/Breadcrumb.d.ts +6 -0
  64. package/types/kernel/shell/ClusterLayout.d.ts +14 -0
  65. package/types/kernel/shell/ClusterViewNav.d.ts +13 -0
  66. package/types/kernel/shell/CommandPalette.d.ts +15 -0
  67. package/types/kernel/shell/FeatureDisabled.d.ts +13 -0
  68. package/types/kernel/shell/FeatureGate.d.ts +12 -0
  69. package/types/kernel/shell/FreshnessBar.d.ts +11 -0
  70. package/types/kernel/shell/GlobalContext.d.ts +7 -0
  71. package/types/kernel/shell/HomeView.d.ts +6 -0
  72. package/types/kernel/shell/NavGroup.d.ts +13 -0
  73. package/types/kernel/shell/NavItem.d.ts +33 -0
  74. package/types/kernel/shell/NavToggle.d.ts +13 -0
  75. package/types/kernel/shell/RootLayout.d.ts +15 -0
  76. package/types/kernel/shell/SectionNav.d.ts +41 -0
  77. package/types/kernel/shell/UserMenu.d.ts +10 -0
  78. package/types/kernel/shell/lastPlace.d.ts +17 -0
  79. package/types/kernel/shell/pageTitle.d.ts +13 -0
  80. package/types/kernel/shell/recents.d.ts +16 -0
  81. package/types/kernel/shell/useColorSchemeToggle.d.ts +10 -0
  82. package/types/kernel/shell/useFreshness.d.ts +25 -0
  83. package/types/kernel/shell/useNavCollapsed.d.ts +14 -0
  84. package/types/kernel/slots.d.ts +206 -0
  85. package/types/kernel/stream/sse.d.ts +22 -0
  86. package/types/kernel/stream/useClusterStream.d.ts +27 -0
  87. package/types/kernel/stream/useUserStream.d.ts +11 -0
  88. package/types/kernel/time/Ago.d.ts +9 -0
  89. package/types/kernel/time/ranges.d.ts +32 -0
  90. package/types/kernel/time/time.d.ts +89 -0
  91. package/types/kernel/time/timezone.d.ts +44 -0
  92. package/types/kernel/useDismissedNotice.d.ts +3 -0
  93. package/types/sdk/index.d.ts +92 -0
  94. package/types/ui/ActionMenuItem.d.ts +27 -0
  95. package/types/ui/AnchoredMenu.d.ts +20 -0
  96. package/types/ui/CapabilityGate.d.ts +23 -0
  97. package/types/ui/CapabilityReason.d.ts +11 -0
  98. package/types/ui/CodeEditor.d.ts +31 -0
  99. package/types/ui/ConfirmDialog.d.ts +51 -0
  100. package/types/ui/DescriptionList.d.ts +26 -0
  101. package/types/ui/DiagramView.d.ts +35 -0
  102. package/types/ui/DialogActions.d.ts +26 -0
  103. package/types/ui/EmptyState.d.ts +42 -0
  104. package/types/ui/ErrorState.d.ts +36 -0
  105. package/types/ui/FieldRow.d.ts +9 -0
  106. package/types/ui/HeldRequestLink.d.ts +4 -0
  107. package/types/ui/HoldToConfirm.d.ts +22 -0
  108. package/types/ui/LoadingState.d.ts +16 -0
  109. package/types/ui/NodeOutcomeSummary.d.ts +59 -0
  110. package/types/ui/Notice.d.ts +18 -0
  111. package/types/ui/Page.d.ts +13 -0
  112. package/types/ui/PageHeader.d.ts +18 -0
  113. package/types/ui/Pager.d.ts +21 -0
  114. package/types/ui/Section.d.ts +22 -0
  115. package/types/ui/Stat.d.ts +20 -0
  116. package/types/ui/StatusBadge.d.ts +11 -0
  117. package/types/ui/Toolbar.d.ts +19 -0
  118. package/types/ui/capabilityGate.d.ts +43 -0
  119. package/types/ui/codeDiagnostics.d.ts +11 -0
  120. package/types/ui/codeMirrorTheme.d.ts +11 -0
  121. package/types/ui/diagram.d.ts +49 -0
  122. package/types/ui/errorReading.d.ts +30 -0
  123. package/types/ui/formErrors.d.ts +10 -0
  124. package/types/ui/graph/ViewControls.d.ts +19 -0
  125. package/types/ui/graph/elk.d.ts +3 -0
  126. package/types/ui/held.d.ts +12 -0
  127. package/types/ui/inAppNavigation.d.ts +5 -0
  128. package/types/ui/nodeOutcome.d.ts +13 -0
  129. package/types/ui/notify.d.ts +77 -0
  130. package/types/ui/safeHref.d.ts +8 -0
  131. package/types/ui/table/ColumnsMenu.d.ts +26 -0
  132. package/types/ui/table/DataTable.d.ts +109 -0
  133. package/types/ui/table/GridFind.d.ts +16 -0
  134. package/types/ui/table/GridTable.d.ts +49 -0
  135. package/types/ui/table/HeaderCell.d.ts +25 -0
  136. package/types/ui/table/MiddleTruncate.d.ts +21 -0
  137. package/types/ui/table/StaticTable.d.ts +14 -0
  138. package/types/ui/table/TableStates.d.ts +35 -0
  139. package/types/ui/table/columns.d.ts +49 -0
  140. package/types/ui/table/density.d.ts +13 -0
  141. package/types/ui/table/gridFind.d.ts +7 -0
  142. package/types/ui/table/index.d.ts +5 -0
  143. package/types/ui/table/layout.d.ts +48 -0
  144. package/types/ui/table/measure.d.ts +16 -0
  145. package/types/ui/table/measurement.d.ts +92 -0
  146. package/types/ui/table/menuAnchor.d.ts +12 -0
  147. package/types/ui/table/rovingGrid.d.ts +37 -0
  148. package/types/ui/table/sort.d.ts +14 -0
  149. package/types/ui/table/tableState.d.ts +51 -0
  150. package/types/ui/table/useGridFind.d.ts +18 -0
  151. package/types/ui/trustedTypes.d.ts +16 -0
  152. package/types/ui/useTruncated.d.ts +8 -0
  153. package/vite.d.ts +14 -0
  154. package/vite.js +62 -0
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The signed-in user's inbox: every notice Rahdar and its plugins posted to them that is still kept, newest
3
+ * first, a page at a time. Unread or all is in the URL (`?filter=unread`), so the view can be shared and
4
+ * restored. Opening a notice marks it read; dismissing one deletes it.
5
+ */
6
+ export declare function InboxView(): import("react").JSX.Element;
@@ -0,0 +1,17 @@
1
+ import type { ReactNode } from 'react';
2
+ import { type InboxItem } from './api.ts';
3
+ /**
4
+ * One notice, in the header's popover and on the inbox page: its severity, whether it is unread, its title
5
+ * (a link when it has one), the body on the page, and when it arrived. Opening it marks it read.
6
+ *
7
+ * <p>The severity and the unread state are in words for assistive technology; the icon and the dot repeat
8
+ * them. A warning or critical notice is the only one with colour.
9
+ */
10
+ export declare function NoticeRow({ item, now, onOpen, showBody, actions, }: Readonly<{
11
+ item: InboxItem;
12
+ now: number;
13
+ /** Called when the notice is opened: followed, or for one without a link, activated. */
14
+ onOpen: (item: InboxItem) => void;
15
+ showBody?: boolean;
16
+ actions?: ReactNode;
17
+ }>): import("react").JSX.Element;
@@ -0,0 +1,53 @@
1
+ import type { components } from '../api/schema.d.ts';
2
+ type Schemas = components['schemas'];
3
+ export type InboxItem = Schemas['ItemView'];
4
+ export type InboxPage = Schemas['PageView'];
5
+ export type InboxCount = Schemas['CountView'];
6
+ export type InboxSeverity = InboxItem['severity'];
7
+ /** Which notices a list shows: only the unread ones, or every one still kept. */
8
+ export type InboxFilter = 'unread' | 'all';
9
+ /** Every inbox query key starts from `inboxKeys.all`, so one invalidation (a stream signal) reaches all of them. */
10
+ export declare const inboxKeys: {
11
+ all: readonly ["inbox"];
12
+ count: readonly ["inbox", "count"];
13
+ latest: readonly ["inbox", "latest"];
14
+ list: (filter: InboxFilter) => readonly ["inbox", "list", InboxFilter];
15
+ };
16
+ /** The count as the badge shows it: "99+" once the server stops counting. */
17
+ export declare function unreadLabel(count: InboxCount | undefined): string;
18
+ /**
19
+ * Whether a notice's link is a path inside Rahdar. The server refuses any other on posting; this is the
20
+ * second check, so a notice can never send the operator to another site.
21
+ */
22
+ export declare function isInAppPath(link: string | null | undefined): link is string;
23
+ /** How many notices the header's popover shows. */
24
+ export declare const LATEST_LIMIT = 10;
25
+ /**
26
+ * The unread count the bell shows. While the user stream is `live` it keeps the count current and nothing
27
+ * polls; while it is not, the count is asked for every minute, so a lost connection never freezes it.
28
+ */
29
+ export declare function useInboxCount(live: boolean): import("@tanstack/react-query").UseQueryResult<{
30
+ unread: number;
31
+ capped: boolean;
32
+ }, Error>;
33
+ /** The newest notices, read or not, for the header's popover. Fetched only while the popover is open. */
34
+ export declare function useLatestNotices(enabled: boolean): import("@tanstack/react-query").UseQueryResult<{
35
+ items: components["schemas"]["ItemView"][];
36
+ next?: number | null;
37
+ }, Error>;
38
+ /** The inbox page's list, newest first, a page at a time by keyset (`before` the last id shown). */
39
+ export declare function useInboxList(filter: InboxFilter): import("@tanstack/react-query").UseInfiniteQueryResult<import("@tanstack/query-core").InfiniteData<{
40
+ items: components["schemas"]["ItemView"][];
41
+ next?: number | null;
42
+ }, unknown>, Error>;
43
+ /** Marks the given notices read, or with `upTo` every notice up to that id (what "Mark all read" sends). */
44
+ export declare function useMarkRead(): import("@tanstack/react-query").UseMutationResult<{
45
+ updated: number;
46
+ }, Error, {
47
+ ids: number[];
48
+ } | {
49
+ upTo: number;
50
+ }, unknown>;
51
+ /** Dismisses one notice: it is deleted, not just read. */
52
+ export declare function useDismissNotice(): import("@tanstack/react-query").UseMutationResult<void, Error, number, unknown>;
53
+ export {};
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Every keyboard shortcut, in one place (ADR-0109), with the switch that turns the single-key ones
3
+ * off: a header button and the popover it opens, like the refresh control beside it. `?` opens the
4
+ * same popover; the button keeps it reachable when the single-key shortcuts are off.
5
+ */
6
+ export declare function ShortcutsHelp(): import("react").JSX.Element;
@@ -0,0 +1,5 @@
1
+ import { type RefObject } from 'react';
2
+ /** Registers a view's filter field for `/` while the view is mounted. */
3
+ export declare function useFilterShortcut(ref: RefObject<HTMLInputElement | null>): void;
4
+ /** Focuses the registered filter field; false when the view has none, so the key is left alone. */
5
+ export declare function focusFilter(): boolean;
@@ -0,0 +1,14 @@
1
+ /** A modified shortcut as this platform names it: `⌘K` on a Mac, `Ctrl+K` everywhere else. */
2
+ export declare function modShortcut(key: string): string;
3
+ /**
4
+ * The printable key an event stands for, in the Latin layout the shortcuts are named in. On a
5
+ * non-Latin layout (Persian, Russian, Greek) `event.key` is that script's letter, so the physical
6
+ * key decides instead: an operator does not switch layout to press `g q`.
7
+ */
8
+ export declare function latinKey(event: KeyboardEvent): string;
9
+ /**
10
+ * Whether a key press belongs to something else and must not be taken as a shortcut (ADR-0109):
11
+ * typing into a field or an editor, a modified key, an IME composition, a key already handled, and
12
+ * anything inside a dialog or a menu — a confirmation is never navigated away from by a stray key.
13
+ */
14
+ export declare function ignoredForShortcuts(event: KeyboardEvent): boolean;
@@ -0,0 +1,5 @@
1
+ export declare function singleKeyShortcutsEnabled(): boolean;
2
+ export declare function setSingleKeyShortcuts(next: boolean): void;
3
+ export declare function useSingleKeyShortcuts(): [boolean, (next: boolean) => void];
4
+ export declare function setShortcutsHelpOpen(next: boolean): void;
5
+ export declare function useShortcutsHelpOpen(): boolean;
@@ -0,0 +1,16 @@
1
+ import { type NavContribution } from '../feature.ts';
2
+ /**
3
+ * The views that have a `g` letter: built-in views only — a plugin's letter is ignored, so a plugin
4
+ * can never take a letter an operator already relies on (ADR-0109).
5
+ */
6
+ export declare function viewHotkeys(features: {
7
+ id: string;
8
+ nav?: NavContribution[];
9
+ }[]): Map<string, NavContribution>;
10
+ /**
11
+ * The single-key shortcuts (ADR-0109), as one document listener mounted by the shell:
12
+ * `g` then a view's letter goes to that view of the open cluster, `?` opens the list of shortcuts,
13
+ * and `/` focuses the view's filter when it has one. All of them are off when the operator turned
14
+ * single-key shortcuts off, and ignored while typing, with a modifier, and inside dialogs and menus.
15
+ */
16
+ export declare function useKeySequences(): void;
@@ -0,0 +1,21 @@
1
+ import { type UseQueryResult } from '@tanstack/react-query';
2
+ import { type ApiError } from './api/request.ts';
3
+ import type { components } from './api/schema.d.ts';
4
+ import type { ModuleId, RahdarFeature } from './feature.ts';
5
+ export type ManifestView = components['schemas']['ManifestView'];
6
+ export type ManifestFeatureView = components['schemas']['ManifestFeatureView'];
7
+ export declare const manifestKey: readonly ["manifest"];
8
+ /**
9
+ * What this installation offers (feature-modules spec). It describes and never authorizes: every
10
+ * endpoint enforces its permission whatever a screen derived from this. Read once per page load:
11
+ * plugin bundles are loaded before the router exists, so a plugin change needs a reload anyway,
12
+ * and `usePluginsChanged` offers one when the server's `version` moves on.
13
+ */
14
+ export declare function useManifest(): UseQueryResult<ManifestView, ApiError>;
15
+ /** The manifest's entry for a module; undefined until the manifest has loaded. */
16
+ export declare function useManifestFeature(id: ModuleId): ManifestFeatureView | undefined;
17
+ /**
18
+ * The given features less those this installation has disabled. Until the manifest answers, every
19
+ * feature counts as enabled: hiding a view before then would state something nobody has checked.
20
+ */
21
+ export declare function useEnabledFeatures(features: RahdarFeature[]): RahdarFeature[];
@@ -0,0 +1,28 @@
1
+ import type { ApiError } from '../api/request.ts';
2
+ /** Every metric plot is this tall, whatever it is currently able to show. */
3
+ export declare const CHART_HEIGHT = "13.75rem";
4
+ /**
5
+ * A titled panel around one metric plot, and the three states it can be in.
6
+ *
7
+ * Failure, emptiness and loading are rendered as three different things at one
8
+ * fixed height (ADR-0055). Both halves of that matter:
9
+ *
10
+ * - a metrics read that returned 500 used to render "No samples in this window
11
+ * yet", which presents an outage as a fact about the cluster — and a flat empty
12
+ * chart during an incident reads as "quiet", the most expensive possible
13
+ * misreading;
14
+ * - a panel that collapses while loading and expands when data arrives moves the
15
+ * page under a pointer already travelling towards something else.
16
+ */
17
+ export declare function ChartPanel({ title, unit, isPending, error, isEmpty, emptyLabel, note, children, }: Readonly<{
18
+ title: string;
19
+ unit: string;
20
+ isPending: boolean;
21
+ error: ApiError | null;
22
+ /** True when the read succeeded and carried nothing for this window. */
23
+ isEmpty: boolean;
24
+ emptyLabel: string;
25
+ /** A coverage caveat that belongs beside the title, not inside a tooltip. */
26
+ note?: React.ReactNode;
27
+ children: React.ReactNode;
28
+ }>): import("react").JSX.Element;
@@ -0,0 +1,13 @@
1
+ import type { MetricRange } from '../time/ranges.ts';
2
+ /**
3
+ * Rahdar's time-proportional chart of one plugin metric for one subject (ADR-0055, ADR-0113):
4
+ * a titled panel that tells loading, failure and an empty window apart, over a live range.
5
+ */
6
+ export declare function MetricChart({ clusterId, metric, subject, title, range, emptyLabel, }: Readonly<{
7
+ clusterId: string;
8
+ metric: string;
9
+ subject: string;
10
+ title: string;
11
+ range?: MetricRange;
12
+ emptyLabel?: string;
13
+ }>): import("react").JSX.Element;
@@ -0,0 +1,71 @@
1
+ import type { components } from '../api/schema.d.ts';
2
+ import { type MetricRange } from '../time/ranges.ts';
3
+ type MetricSeries = components['schemas']['MetricSeries'];
4
+ /**
5
+ * Format an instant in the operator's chosen zone.
6
+ *
7
+ * Bare `dayjs(ms).format(...)` renders in the browser's zone, which used to leave
8
+ * the charts and the tables disagreeing on every deployment where the two differed
9
+ * — the axis in local time, every table in UTC, and nothing saying so. Everything
10
+ * that renders a metric timestamp goes through here.
11
+ */
12
+ export declare function formatInZone(ms: number, pattern: string): string;
13
+ export declare function tickFormatter(range: MetricRange): (ms: number) => string;
14
+ export declare function labelFormatter(range: MetricRange): (ms: number) => string;
15
+ /**
16
+ * Props for the recharts `XAxis` behind every metric chart.
17
+ *
18
+ * `type: 'number'` with `scale: 'time'` is the whole decision. The explicit
19
+ * `[from, to]` domain — rather than `['dataMin', 'dataMax']` — keeps the plotted
20
+ * width equal to the *requested* window, so a series that stops halfway through
21
+ * the range renders as a chart that is half empty rather than one that silently
22
+ * rescales to whatever data survived.
23
+ */
24
+ export declare function timeAxisProps(range: MetricRange, from: number, to: number): {
25
+ type: "number";
26
+ scale: "time";
27
+ domain: [number, number];
28
+ tickFormatter: (ms: number) => string;
29
+ minTickGap: number;
30
+ stroke: string;
31
+ };
32
+ /**
33
+ * `integral` is for a metric that only ever takes whole values — a consumer
34
+ * count. Without it recharts picks fractional ticks for a small domain, and the
35
+ * integer formatter renders every one of them as the same "0": an axis of five
36
+ * identical labels beside bars of visibly different heights.
37
+ */
38
+ export declare function yAxisProps(options?: {
39
+ integral?: boolean;
40
+ }): {
41
+ allowDecimals?: boolean | undefined;
42
+ stroke: string;
43
+ width: number;
44
+ };
45
+ export declare function gridProps(): {
46
+ stroke: string;
47
+ };
48
+ /** Bucket boundaries a series is expected to cover, used to size the empty case. */
49
+ export declare function bucketCount(range: MetricRange): number;
50
+ /**
51
+ * Merge any number of series onto one row per timestamp, keyed by epoch ms.
52
+ *
53
+ * Series are merged by timestamp rather than by index because a metric with no
54
+ * samples in a bucket is simply omitted from its series, so two series over the
55
+ * same window can carry different bucket sets. Zipping them by position would
56
+ * silently pair a value with the wrong instant.
57
+ */
58
+ export declare function mergeByTimestamp(named: Array<{
59
+ name: string;
60
+ series: MetricSeries | undefined;
61
+ field?: 'value' | 'peak';
62
+ }>): Array<Record<string, number>>;
63
+ /** The last point of a series, or `null` when there is none to state. */
64
+ export declare function latest(series: MetricSeries | undefined): number | null;
65
+ /** The first point of a series, for stating movement across the window. */
66
+ export declare function earliest(series: MetricSeries | undefined): number | null;
67
+ /** Depth runs to millions on a real cluster; an axis tick cannot carry the digits. */
68
+ export declare function formatCount(value: number): string;
69
+ export declare function formatExact(value: number): string;
70
+ export declare function formatRate(value: number): string;
71
+ export {};
@@ -0,0 +1,17 @@
1
+ import { type UseQueryResult } from '@tanstack/react-query';
2
+ import { ApiError } from '../api/request.ts';
3
+ import type { components } from '../api/schema.d.ts';
4
+ import { type MetricRange } from '../time/ranges.ts';
5
+ type MetricSeriesResponse = components['schemas']['MetricSeriesResponse'];
6
+ /**
7
+ * A plugin metric's series for one subject over a live range (ADR-0113). Needs the permission the
8
+ * plugin declared for the metric; without it the read fails like any cluster read the user may
9
+ * not make.
10
+ */
11
+ export declare function usePluginSeries(clusterId: string, metric: string, subject: string, range?: MetricRange): UseQueryResult<MetricSeriesResponse, ApiError> & {
12
+ window: {
13
+ from: string;
14
+ to: string;
15
+ };
16
+ };
17
+ export {};
@@ -0,0 +1,21 @@
1
+ import type { NavContribution, RahdarFeature } from '../feature.ts';
2
+ export interface CurrentView {
3
+ clusterId: string;
4
+ /** The navigation entry the address is under, when there is one. */
5
+ item?: NavContribution;
6
+ /** Its group's label. */
7
+ groupLabel?: string;
8
+ }
9
+ /**
10
+ * Which cluster view an address is under (ADR-0109): the navigation entry whose path is the longest
11
+ * prefix of the path after `/clusters/<id>/`, so a queue's message browser is under Queues and a
12
+ * bulk run under Bulk runs. Null outside any cluster.
13
+ */
14
+ export declare function matchView(pathname: string, features: RahdarFeature[]): CurrentView | null;
15
+ export declare function useCurrentView(): CurrentView | null;
16
+ /**
17
+ * The address of the same view on another cluster (ADR-0109): an operator comparing two clusters
18
+ * stays on Queues. The view's search is not carried — its filter and its open resource name things
19
+ * that may not exist there. Without a current view, the cluster's landing page.
20
+ */
21
+ export declare function sameViewOn(clusterId: string, view: CurrentView | null): string;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * The navigation groups, in the order the rail shows them (ADR-0070). The list is closed:
3
+ * a feature names one of these for each view it contributes, and adding a group is a
4
+ * kernel change, which keeps the rail coherent as features are added.
5
+ */
6
+ export declare const NAV_GROUPS: readonly [{
7
+ readonly id: "observe";
8
+ readonly label: "Observe";
9
+ }, {
10
+ readonly id: "messaging";
11
+ readonly label: "Messaging";
12
+ }, {
13
+ readonly id: "resources";
14
+ readonly label: "Resources";
15
+ }, {
16
+ readonly id: "configuration";
17
+ readonly label: "Configuration";
18
+ }, {
19
+ readonly id: "activity";
20
+ readonly label: "Activity";
21
+ }];
22
+ export type NavGroupId = (typeof NAV_GROUPS)[number]['id'];
@@ -0,0 +1,25 @@
1
+ import { Component, type ErrorInfo, type ReactNode } from 'react';
2
+ interface Props {
3
+ pluginId: string;
4
+ /** What to render instead: nothing for a badge or a palette source, a sentence for a panel. */
5
+ quiet?: boolean;
6
+ children: ReactNode;
7
+ }
8
+ /**
9
+ * Keeps a plugin's failure to itself (ADR-0100): a plugin component that throws while rendering
10
+ * is replaced by a sentence naming the plugin — or by nothing, where a sentence would not fit —
11
+ * and the screen around it keeps working.
12
+ */
13
+ export declare class PluginBoundary extends Component<Props, {
14
+ error: unknown;
15
+ }> {
16
+ state: {
17
+ error: unknown;
18
+ };
19
+ static getDerivedStateFromError(error: unknown): {
20
+ error: {};
21
+ };
22
+ componentDidCatch(error: unknown, info: ErrorInfo): void;
23
+ render(): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import("react").JSX.Element | null | undefined;
24
+ }
25
+ export {};
@@ -0,0 +1,6 @@
1
+ /**
2
+ * What an address under `/p/<id>/` shows when no plugin page answers it (ADR-0100): whether the
3
+ * plugin is installed at all, and if so the state that keeps its page away — never a blank page
4
+ * or a bare not-found. Administrators are pointed at the plugin's row.
5
+ */
6
+ export declare function PluginUnavailable(): import("react").JSX.Element;
@@ -0,0 +1,33 @@
1
+ import { type RahdarFeature } from '../feature.ts';
2
+ import type { ManifestFeatureView, ManifestView } from '../manifest.ts';
3
+ /** How long the shell waits for the manifest, and for each plugin bundle, before going on without it. */
4
+ export declare const MANIFEST_TIMEOUT_MS = 5000;
5
+ export declare const REMOTE_TIMEOUT_MS = 10000;
6
+ /** What the page learned while starting: the manifest (when it could be read) and every plugin that did not load. */
7
+ export interface Boot {
8
+ manifest?: ManifestView;
9
+ /** Why the manifest could not be read; the built-in screens load regardless. */
10
+ manifestError?: string;
11
+ plugins: RahdarFeature[];
12
+ /** Plugin id → why its screens are not here. */
13
+ failures: Map<string, string>;
14
+ }
15
+ export declare function bootState(): Boot;
16
+ /** For tests. */
17
+ export declare function setBootState(boot: Boot): void;
18
+ /** The Module Federation container name a plugin's bundle is built with: its id, in snake_case. */
19
+ export declare function remoteName(id: string): string;
20
+ type Federation = Pick<typeof import('@module-federation/runtime'), 'registerRemotes' | 'loadRemote'>;
21
+ /**
22
+ * Loads every active plugin's bundle, each bounded by {@link REMOTE_TIMEOUT_MS}, and keeps the
23
+ * ones that pass {@link checkPlugin}. A bundle that fails, is slow or breaks the rules is left
24
+ * out with its reason; nothing a plugin does here can keep Rahdar's own screens from loading.
25
+ */
26
+ export declare function loadPlugins(entries: ManifestFeatureView[], federation?: () => Promise<Federation>): Promise<Pick<Boot, 'plugins' | 'failures'>>;
27
+ /**
28
+ * Everything the page needs before it builds its router: the manifest, then the plugins it names.
29
+ * The sign-in page asks for neither, because nobody is signed in to be answered; the sign-in that
30
+ * follows reloads the page, which then boots signed in (`LoginView`).
31
+ */
32
+ export declare function boot(): Promise<Boot>;
33
+ export {};
@@ -0,0 +1,3 @@
1
+ import type { ComponentType } from 'react';
2
+ /** `Inner` inside a {@link PluginBoundary}, with the same props. */
3
+ export declare function guarded<P extends object>(pluginId: string, Inner: ComponentType<P>, quiet?: boolean): ComponentType<P>;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Offers a reload once the server's plugins differ from the ones this page started with (ADR-0100):
3
+ * checked when the window regains focus and every minute. It never reloads on its own — the
4
+ * operator may be halfway through something — and says so once, until they act.
5
+ */
6
+ export declare function usePluginsChanged(onChange?: () => void): void;
@@ -0,0 +1,19 @@
1
+ import { type RahdarFeature } from '../feature.ts';
2
+ import type { ManifestFeatureView } from '../manifest.ts';
3
+ /** A loaded plugin module, accepted and made safe to mount, or the reason it was not. */
4
+ export type Checked = {
5
+ ok: true;
6
+ feature: RahdarFeature;
7
+ } | {
8
+ ok: false;
9
+ reason: string;
10
+ };
11
+ /** The first segment a plugin route's path must have: everything it adds lives under `p/<id>/`. */
12
+ export declare function pluginPathPrefix(id: string): string;
13
+ /**
14
+ * Accepts what a plugin's bundle exported only when it keeps to its own namespace (ADR-0100):
15
+ * the contract it was built for, its own id, routes and navigation under `p/<id>/`, slot entries
16
+ * named `<id>.…`, only the stream topics its descriptor declared, and navigation and administration
17
+ * groups the shell has. Every component it contributes to a shared screen is wrapped so a throw stays its own.
18
+ */
19
+ export declare function checkPlugin(entry: ManifestFeatureView, exported: unknown): Checked;
@@ -0,0 +1,12 @@
1
+ import type { NavContribution, RahdarFeature } from './feature.ts';
2
+ import { type NavGroupId } from './nav/groups.ts';
3
+ export interface NavGroup {
4
+ id: NavGroupId;
5
+ label: string;
6
+ items: NavContribution[];
7
+ }
8
+ /**
9
+ * The features' views under the kernel's groups (ADR-0070): groups in their fixed order, views in
10
+ * their declared order, and a group none of the features contributes to left out.
11
+ */
12
+ export declare function navGroups(features: RahdarFeature[]): NavGroup[];
@@ -0,0 +1,24 @@
1
+ import { type ComponentType, type ReactElement } from 'react';
2
+ import type { ModuleId } from '../feature.ts';
3
+ /** The root every page renders inside: the shell. A feature's `routes.root` are its children. */
4
+ export declare const rootRoute: import("@tanstack/react-router").RootRoute<import("@tanstack/router-core").Register, undefined, {}, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, {}, undefined, unknown, unknown, unknown, unknown, undefined>;
5
+ /** One cluster's layout. A feature's `routes.cluster` are its children. */
6
+ export declare const clusterRoute: import("@tanstack/react-router").Route<unknown, import("@tanstack/react-router").RootRoute<import("@tanstack/router-core").Register, undefined, {}, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, {}, undefined, unknown, unknown, unknown, unknown, undefined>, "clusters/$clusterId", "/clusters/$clusterId", string, "/clusters/$clusterId", undefined, import("@tanstack/router-core").ResolveParams<"clusters/$clusterId">, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, {}, undefined, unknown, unknown, unknown, unknown, undefined>;
7
+ export declare const pluginClusterFallback: import("@tanstack/react-router").Route<unknown, import("@tanstack/react-router").Route<unknown, import("@tanstack/react-router").RootRoute<import("@tanstack/router-core").Register, undefined, {}, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, {}, undefined, unknown, unknown, unknown, unknown, undefined>, "clusters/$clusterId", "/clusters/$clusterId", string, "/clusters/$clusterId", undefined, import("@tanstack/router-core").ResolveParams<"clusters/$clusterId">, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, {}, undefined, unknown, unknown, unknown, unknown, undefined>, "p/$pluginId/$", "/clusters/$clusterId/p/$pluginId/$", string, "/clusters/$clusterId/p/$pluginId/$", undefined, import("@tanstack/router-core").ResolveParams<"p/$pluginId/$">, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, {}, undefined, unknown, unknown, unknown, unknown, undefined>;
8
+ /** The shell's own pages, beside the cluster layout. */
9
+ export declare const shellRoutes: (import("@tanstack/react-router").Route<unknown, import("@tanstack/react-router").RootRoute<import("@tanstack/router-core").Register, undefined, {}, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, {}, undefined, unknown, unknown, unknown, unknown, undefined>, "/", "/", string, "/", undefined, import("@tanstack/router-core").ResolveParams<"/">, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, {}, undefined, unknown, unknown, unknown, unknown, undefined> | import("@tanstack/react-router").Route<unknown, import("@tanstack/react-router").RootRoute<import("@tanstack/router-core").Register, undefined, {}, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, {}, undefined, unknown, unknown, unknown, unknown, undefined>, "login", "/login", string, "/login", undefined, import("@tanstack/router-core").ResolveParams<"login">, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, {}, undefined, unknown, unknown, unknown, unknown, undefined> | import("@tanstack/react-router").Route<unknown, import("@tanstack/react-router").RootRoute<import("@tanstack/router-core").Register, undefined, {}, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, {}, undefined, unknown, unknown, unknown, unknown, undefined>, "admin", "/admin", string, "/admin", (raw: Record<string, unknown>) => {
10
+ tab?: string;
11
+ plugin?: string;
12
+ upload?: string;
13
+ view?: "retention" | "health";
14
+ team?: string;
15
+ teamTab?: string;
16
+ teamQ?: string;
17
+ teamSort?: string;
18
+ }, import("@tanstack/router-core").ResolveParams<"admin">, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, {}, undefined, unknown, unknown, unknown, unknown, undefined> | import("@tanstack/react-router").Route<unknown, import("@tanstack/react-router").RootRoute<import("@tanstack/router-core").Register, undefined, {}, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, {}, undefined, unknown, unknown, unknown, unknown, undefined>, "account", "/account", string, "/account", undefined, import("@tanstack/router-core").ResolveParams<"account">, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, {}, undefined, unknown, unknown, unknown, unknown, undefined> | import("@tanstack/react-router").Route<unknown, import("@tanstack/react-router").RootRoute<import("@tanstack/router-core").Register, undefined, {}, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, {}, undefined, unknown, unknown, unknown, unknown, undefined>, "inbox", "/inbox", string, "/inbox", (raw: Record<string, unknown>) => {
19
+ filter?: "unread";
20
+ }, import("@tanstack/router-core").ResolveParams<"inbox">, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, {}, undefined, unknown, unknown, unknown, unknown, undefined> | import("@tanstack/react-router").Route<unknown, import("@tanstack/react-router").RootRoute<import("@tanstack/router-core").Register, undefined, {}, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, {}, undefined, unknown, unknown, unknown, unknown, undefined>, "approvals", "/approvals", string, "/approvals", (raw: Record<string, unknown>) => {
21
+ tab?: "mine";
22
+ }, import("@tanstack/router-core").ResolveParams<"approvals">, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, {}, undefined, unknown, unknown, unknown, unknown, undefined> | import("@tanstack/react-router").Route<unknown, import("@tanstack/react-router").RootRoute<import("@tanstack/router-core").Register, undefined, {}, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, {}, undefined, unknown, unknown, unknown, unknown, undefined>, "approvals/$id", "/approvals/$id", string, "/approvals/$id", undefined, import("@tanstack/router-core").ResolveParams<"approvals/$id">, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, {}, undefined, unknown, unknown, unknown, unknown, undefined> | import("@tanstack/react-router").Route<unknown, import("@tanstack/react-router").RootRoute<import("@tanstack/router-core").Register, undefined, {}, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, {}, undefined, unknown, unknown, unknown, unknown, undefined>, "p/$pluginId/$", "/p/$pluginId/$", string, "/p/$pluginId/$", undefined, import("@tanstack/router-core").ResolveParams<"p/$pluginId/$">, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, import("@tanstack/router-core").AnyContext, {}, undefined, unknown, unknown, unknown, unknown, undefined>)[];
23
+ /** A feature's view, or the page explaining that the feature is disabled on this installation (feature-modules spec). */
24
+ export declare function featureView(feature: ModuleId, View: ComponentType): () => ReactElement;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The signed-in user's own page: who you are, the approval requests you made while approvals are on
3
+ * (what a requester comes back for, so it comes first), then what the features contribute — how to
4
+ * change your password, the keys you hold, how to connect an assistant with one, and your display
5
+ * preferences. Prose and forms keep a readable width; a section with a table keeps the page's.
6
+ *
7
+ * <p>API keys used to live under Administration, which made a per-user
8
+ * credential look like an operator's tool and hid it from everyone without
9
+ * {@code user:admin}. Every user has an account, so this route is ungated.
10
+ */
11
+ export declare function AccountView(): import("react").JSX.Element;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Rahdar-wide administration (authorization spec): one section per contribution, such as users, roles,
3
+ * environments and identity provider group mappings, under fixed headings — who may do what, what is
4
+ * installed, what rules data and changes follow, then support (operator-ui spec). The open section is in
5
+ * the URL. Each panel brings its own heading.
6
+ */
7
+ export declare function AdminView(): import("react").JSX.Element;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Where the operator is inside a cluster (ADR-0109): cluster › group › view › open resource. The
3
+ * last crumb is the current page, at text colour; the ones before it that are places are dimmed links
4
+ * back to them, and a group, which is not a place, is dimmed text.
5
+ */
6
+ export declare function Breadcrumb(): import("react").JSX.Element | null;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * One cluster's screen: one context line, then the routed view, whose own `PageHeader` is the page's
3
+ * one h1 (ADR-0163). The line is the breadcrumb at its start and, at its end, whatever a
4
+ * `cluster.header` contribution marks with `data-context-line` (the clusters feature's environment,
5
+ * nodes and health); every other part of a contribution, such as a health notice, takes a row of its
6
+ * own below the line. Nothing in it is a heading.
7
+ *
8
+ * It hosts the dialogs row actions open (ADR-0107), and mounts the cluster's one SSE stream, subscribed
9
+ * to the topics of every enabled feature (ADR-0018, ADR-0070). A view never opens a second one for a
10
+ * topic a feature handles: a second `EventSource` is a second connection. The stream reconnects
11
+ * indefinitely and reports its state to the header's freshness indicator (ADR-0052); while it is down
12
+ * the per-hook refetch intervals keep every view updating.
13
+ */
14
+ export declare function ClusterLayout(): import("react").JSX.Element;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The per-cluster view nav (ADR-0034), grouped (ADR-0070). Each enabled feature contributes its
3
+ * views to one of the kernel's groups; a group with no enabled view is not shown. Expanded, a group
4
+ * has a visible title; collapsed, a rule in the title's place, and its title stays available to a screen reader. The title
5
+ * names its group but is not a heading: the page's headings are the page's own, starting at its one h1.
6
+ * A view the operator lacks the read permission for stays listed and disabled, with the reason:
7
+ * a missing entry would read as a product that cannot do it. Only rendered while a cluster is the
8
+ * active route.
9
+ */
10
+ export declare function ClusterViewNav({ clusterId, collapsed }: Readonly<{
11
+ clusterId: string;
12
+ collapsed: boolean;
13
+ }>): import("react").JSX.Element;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * ⌘K navigation across the console: jump to a view, a recent place, a cluster, or a queue by name, or
3
+ * search a live view (ADR-0109). Mounted once in the root layout; the shortcut is registered by
4
+ * {@link Spotlight}, and the header's Search button opens it too.
5
+ *
6
+ * The typed query reaches the features' sources, debounced, together with whether the palette is
7
+ * open, so a source searches only while someone is looking — and only what Rahdar already holds.
8
+ * A view the operator may not open is still listed, disabled, with the reason: the rail shows it the
9
+ * same way.
10
+ *
11
+ * Pause is here too, so every header control is reachable from the keyboard without a hotkey of its
12
+ * own (ADR-0052, ADR-0118), and so are the user menu's colour scheme and table density (ADR-0159,
13
+ * ADR-0162).
14
+ */
15
+ export declare function CommandPalette(): import("react").JSX.Element;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * What a disabled feature's address shows (feature-modules spec): that the feature is off on this
3
+ * installation rather than missing or broken, the startup property that turns it on, and the way
4
+ * back. Never a blank page or a not-found, which would teach the operator the view does not exist.
5
+ */
6
+ export declare function FeatureDisabled({ title, property, clusterId, }: Readonly<{
7
+ /** The feature's title, as the manifest names it. */
8
+ title: string;
9
+ /** The startup property that enables it, as the manifest names it. */
10
+ property: string;
11
+ /** The cluster the address belongs to, when it is a cluster view. */
12
+ clusterId?: string;
13
+ }>): import("react").JSX.Element;
@@ -0,0 +1,12 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { ModuleId } from '../feature.ts';
3
+ /**
4
+ * A feature's view, or the page that explains the feature is disabled on this installation
5
+ * (feature-modules spec). It waits for the manifest rather than rendering a disabled view whose
6
+ * every request would fail as not found. If the manifest cannot be read the view renders: the
7
+ * server still refuses a disabled feature's calls, so nothing is exposed by trying.
8
+ */
9
+ export declare function FeatureGate({ feature, children }: Readonly<{
10
+ feature: ModuleId;
11
+ children: ReactNode;
12
+ }>): import("react").JSX.Element;
@@ -0,0 +1,11 @@
1
+ export type FreshnessState = 'live' | 'polling' | 'reconnecting' | 'offline' | 'paused';
2
+ /**
3
+ * The one place that answers "is this current?" — in the header, on every route
4
+ * (ADR-0052).
5
+ *
6
+ * Stream health and data health are separate states. A cluster whose stream is
7
+ * down but whose queries are succeeding is `Polling`, not `Offline`; conflating
8
+ * them would cry wolf on every proxy hiccup. A route that mounts no stream is
9
+ * `Polling` too, which is the literal truth there.
10
+ */
11
+ export declare function FreshnessBar(): import("react").JSX.Element;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The strip above a page outside any cluster: the way back to where the operator was, and where they
3
+ * are. These pages have no sidebar, because it would only hold a cluster picker; this line is how an
4
+ * operator leaves them, in one click, for the view they came from. With no previous place it offers
5
+ * to open a cluster.
6
+ */
7
+ export declare function GlobalContext(): import("react").JSX.Element;