@artemis-studio/plugin-sdk 2026.9.37

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 (53) hide show
  1. package/README.md +38 -0
  2. package/index.js +25 -0
  3. package/package.json +46 -0
  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/api/polling.d.ts +50 -0
  9. package/types/kernel/api/request.d.ts +45 -0
  10. package/types/kernel/api/schema.d.ts +9428 -0
  11. package/types/kernel/auth/Can.d.ts +9 -0
  12. package/types/kernel/auth/LoginView.d.ts +8 -0
  13. package/types/kernel/auth/api.d.ts +29 -0
  14. package/types/kernel/auth/useCan.d.ts +15 -0
  15. package/types/kernel/feature.d.ts +80 -0
  16. package/types/kernel/features.d.ts +5 -0
  17. package/types/kernel/manifest.d.ts +21 -0
  18. package/types/kernel/nav/groups.d.ts +22 -0
  19. package/types/kernel/plugins/PluginBoundary.d.ts +25 -0
  20. package/types/kernel/plugins/PluginUnavailable.d.ts +6 -0
  21. package/types/kernel/plugins/boot.d.ts +29 -0
  22. package/types/kernel/plugins/guarded.d.ts +3 -0
  23. package/types/kernel/plugins/usePluginsChanged.d.ts +6 -0
  24. package/types/kernel/plugins/validate.d.ts +19 -0
  25. package/types/kernel/registry.d.ts +12 -0
  26. package/types/kernel/routing/roots.d.ts +15 -0
  27. package/types/kernel/shell/AccountView.d.ts +9 -0
  28. package/types/kernel/shell/AdminView.d.ts +5 -0
  29. package/types/kernel/shell/ClusterLayout.d.ts +10 -0
  30. package/types/kernel/shell/ClusterViewNav.d.ts +12 -0
  31. package/types/kernel/shell/CommandPalette.d.ts +10 -0
  32. package/types/kernel/shell/FeatureDisabled.d.ts +13 -0
  33. package/types/kernel/shell/FeatureGate.d.ts +12 -0
  34. package/types/kernel/shell/FreshnessBar.d.ts +11 -0
  35. package/types/kernel/shell/HomeView.d.ts +5 -0
  36. package/types/kernel/shell/NavItem.d.ts +22 -0
  37. package/types/kernel/shell/NavToggle.d.ts +6 -0
  38. package/types/kernel/shell/RootLayout.d.ts +12 -0
  39. package/types/kernel/shell/UserMenu.d.ts +6 -0
  40. package/types/kernel/shell/useFreshness.d.ts +25 -0
  41. package/types/kernel/shell/useNavCollapsed.d.ts +10 -0
  42. package/types/kernel/slots.d.ts +130 -0
  43. package/types/kernel/stream/useClusterStream.d.ts +22 -0
  44. package/types/kernel/time/time.d.ts +89 -0
  45. package/types/kernel/time/timezone.d.ts +44 -0
  46. package/types/kernel/useDismissedNotice.d.ts +3 -0
  47. package/types/sdk/index.d.ts +44 -0
  48. package/types/ui/ConfirmByTyping.d.ts +15 -0
  49. package/types/ui/NodeOutcomeSummary.d.ts +69 -0
  50. package/types/ui/Pager.d.ts +19 -0
  51. package/types/ui/VirtualTable.d.ts +56 -0
  52. package/vite.d.ts +14 -0
  53. package/vite.js +60 -0
@@ -0,0 +1,9 @@
1
+ import type { ReactNode } from 'react';
2
+ export interface CanProps {
3
+ permission: string;
4
+ clusterId?: string;
5
+ children: ReactNode;
6
+ fallback?: ReactNode;
7
+ }
8
+ /** Renders `children` only if the current user holds `permission` (optionally scoped to `clusterId`). */
9
+ export declare function Can({ permission, clusterId, children, fallback }: CanProps): import("react").JSX.Element;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * The login screen, built only from the installation's identity providers
3
+ * (identity-and-sessions spec): a username and password form when a credential
4
+ * provider exists — with a choice when there is more than one — and one sign-in
5
+ * action per redirect provider. While the list loads the form is offered, so a
6
+ * slow request never reads as "sign-in unavailable".
7
+ */
8
+ export declare function LoginView(): import("react").JSX.Element;
@@ -0,0 +1,29 @@
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
+ type Schemas = components["schemas"];
5
+ export type GrantView = Schemas["GrantView"];
6
+ export type IdentityProviderView = Schemas["IdentityProviderView"];
7
+ export type LoginRequest = Schemas["LoginRequest"];
8
+ export type MeView = Schemas["MeView"];
9
+ export declare const keys: {
10
+ authProviders: readonly ["auth", "providers"];
11
+ me: readonly ["auth", "me"];
12
+ };
13
+ /** `retry: false` — a 401 here means "not logged in," which retrying cannot fix. */
14
+ export declare function useMe(): UseQueryResult<MeView, ApiError>;
15
+ /** Public, unauthenticated — the login screen needs this before any session exists. */
16
+ export declare function useAuthProviders(): UseQueryResult<IdentityProviderView[], ApiError>;
17
+ export declare function useLogin(): import("@tanstack/react-query").UseMutationResult<{
18
+ id: string;
19
+ username: string;
20
+ mustChangePassword: boolean;
21
+ grants: components["schemas"]["GrantView"][];
22
+ reauthentication: components["schemas"]["ReauthenticationView"];
23
+ }, ApiError, {
24
+ provider?: string | null;
25
+ username: string;
26
+ password: string;
27
+ }, unknown>;
28
+ export declare function useLogout(): import("@tanstack/react-query").UseMutationResult<void, ApiError, void, unknown>;
29
+ export {};
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Client-side reflection of the server's permission model (authorization
3
+ * spec) — used only to hide/disable controls a request would be rejected for
4
+ * anyway. The server's `@PreAuthorize`/`ClusterAccessGuard` checks are the
5
+ * real enforcement; this never substitutes for them.
6
+ */
7
+ export declare function useCan(): {
8
+ can: (permission: string, clusterId?: string) => boolean;
9
+ grants: {
10
+ scopeType: string;
11
+ scopeId?: string | null;
12
+ permissions: string[];
13
+ }[];
14
+ loading: boolean;
15
+ };
@@ -0,0 +1,80 @@
1
+ import type { ComponentType } from 'react';
2
+ import type { SpotlightActionGroupData } from '@mantine/spotlight';
3
+ import type { Icon } from '@tabler/icons-react';
4
+ import type { AnyRoute } from '@tanstack/react-router';
5
+ import type { NavGroupId } from './nav/groups.ts';
6
+ import type { SlotContributions } from './slots.ts';
7
+ /** The extension contract version, shared with the backend's `Contract.VERSION` (ADR-0070). */
8
+ export declare const CONTRACT = 1;
9
+ /** The module ids the backend manifest reports. A frontend feature uses the same id as its backend module. */
10
+ export declare const FEATURE_IDS: readonly ["security", "audit", "settings", "stream", "broker", "clusters", "governance", "scrape", "mcp", "queues", "resources", "messages", "routing", "metrics", "alerting", "events", "rr", "sql", "brokerconfig", "flow", "triage", "bulk", "transfer", "setupreview", "apitokens", "plugins", "identity-local", "identity-oidc"];
11
+ export type FeatureId = (typeof FEATURE_IDS)[number];
12
+ /**
13
+ * An installed plugin's id, as its `plugin.json` declares it: lowercase kebab-case, vendor first,
14
+ * at least two segments (ADR-0099). A plugin's routes, slot ids and topics are all namespaced by it.
15
+ */
16
+ export type PluginId = `${string}-${string}`;
17
+ /** A built-in module or an installed plugin — whatever the manifest lists. */
18
+ export type ModuleId = FeatureId | PluginId;
19
+ /**
20
+ * The routes a feature adds, each created with a kernel root from `routing/roots.ts` as its parent. The
21
+ * composition root adds every installed feature's routes whether or not the feature is enabled, so a deep
22
+ * link to a disabled feature reaches the page that explains it rather than a not-found.
23
+ */
24
+ export interface RouteContributions {
25
+ /** Pages outside any cluster, children of `rootRoute`. */
26
+ root?: AnyRoute[];
27
+ /** Views of one cluster, children of `clusterRoute`. */
28
+ cluster?: AnyRoute[];
29
+ }
30
+ /** One view in a cluster's navigation and command palette. */
31
+ export interface NavContribution {
32
+ group: NavGroupId;
33
+ /** Position within the group; lower comes first. */
34
+ order: number;
35
+ label: string;
36
+ icon: Icon;
37
+ /** The view's path below `/clusters/$clusterId/`. */
38
+ path: string;
39
+ /**
40
+ * The permission the view reads with. Without it the entry stays visible and disabled,
41
+ * and says why; the server enforces it regardless.
42
+ */
43
+ permission?: string;
44
+ /** Shown after the label, such as a count of what needs attention. */
45
+ Badge?: ComponentType<{
46
+ clusterId: string;
47
+ }>;
48
+ }
49
+ /**
50
+ * A feature's command-palette groups. It is rendered inside the palette, so it may use hooks, and calls
51
+ * `report` whenever its groups change; `clusterId` is the cluster in view, if there is one.
52
+ */
53
+ export type PaletteSource = ComponentType<{
54
+ clusterId?: string;
55
+ report: (groups: SpotlightActionGroupData[]) => void;
56
+ }>;
57
+ /** Handles one frame of a stream topic the feature owns (ADR-0070). */
58
+ export type TopicHandler = (frame: {
59
+ clusterId: string;
60
+ /** The frame's payload, as the server sent it. */
61
+ data: string;
62
+ /** Invalidates a query key, or only marks it stale while refreshing is paused. */
63
+ invalidate: (queryKey: readonly unknown[]) => void;
64
+ }) => void;
65
+ /** What a frontend feature contributes to the shell (ADR-0070). */
66
+ export interface StudioFeature {
67
+ contract: typeof CONTRACT;
68
+ /** A built-in's module id, or a plugin's id (a plugin is loaded from its own bundle at startup). */
69
+ id: ModuleId;
70
+ routes?: RouteContributions;
71
+ nav?: NavContribution[];
72
+ palette?: PaletteSource;
73
+ slots?: SlotContributions;
74
+ /**
75
+ * A handler per stream topic the feature's backend module declares. A cluster's layout subscribes to
76
+ * the topics of every enabled feature.
77
+ */
78
+ streamTopics?: Record<string, TopicHandler>;
79
+ }
80
+ export declare function defineFeature<T extends StudioFeature>(feature: T): T;
@@ -0,0 +1,5 @@
1
+ import type { StudioFeature } from './feature.ts';
2
+ /** The composition root's features. The kernel never imports them; `FeatureProvider` hands them in (ADR-0069). */
3
+ export declare const FeaturesContext: import("react").Context<StudioFeature[] | null>;
4
+ /** The installed features this installation has enabled, in composition order. */
5
+ export declare function useFeatures(): StudioFeature[];
@@ -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, StudioFeature } 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: StudioFeature[]): StudioFeature[];
@@ -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
+ failed: boolean;
15
+ }> {
16
+ state: {
17
+ failed: boolean;
18
+ };
19
+ static getDerivedStateFromError(): {
20
+ failed: boolean;
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,29 @@
1
+ import { type StudioFeature } 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: StudioFeature[];
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 Studio's own screens from loading.
25
+ */
26
+ export declare function loadPlugins(entries: ManifestFeatureView[], federation?: () => Promise<Federation>): Promise<Pick<Boot, 'plugins' | 'failures'>>;
27
+ /** Everything the page needs before it builds its router: the manifest, then the plugins it names. */
28
+ export declare function boot(): Promise<Boot>;
29
+ 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 StudioFeature } 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: StudioFeature;
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 groups the shell
17
+ * 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, StudioFeature } 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: StudioFeature[]): NavGroup[];
@@ -0,0 +1,15 @@
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
+ }, 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>, "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>)[];
14
+ /** A feature's view, or the page explaining that the feature is disabled on this installation (feature-modules spec). */
15
+ export declare function featureView(feature: ModuleId, View: ComponentType): () => ReactElement;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The signed-in user's own page: who you are, then what the features contribute — how to change
3
+ * your password, the keys you hold, and how to connect an assistant with one.
4
+ *
5
+ * <p>API keys used to live under Administration, which made a per-user
6
+ * credential look like an operator's tool and hid it from everyone without
7
+ * {@code user:admin}. Every user has an account, so this route is ungated.
8
+ */
9
+ export declare function AccountView(): import("react").JSX.Element;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Studio-wide administration (authorization spec): one tab per contribution, such as users, roles,
3
+ * environments and identity provider group mappings. The open tab is in the URL.
4
+ */
5
+ export declare function AdminView(): import("react").JSX.Element;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * One cluster's screen: the header its features contribute, then the routed view.
3
+ *
4
+ * It mounts the cluster's one SSE stream, subscribed to the topics of every enabled feature
5
+ * (ADR-0018, ADR-0070). A view never opens a second one for a topic a feature handles: a second
6
+ * `EventSource` is a second connection, and it fights over the shared stream-status store. The
7
+ * stream reconnects indefinitely and reports its state to the header's freshness indicator
8
+ * (ADR-0052); while it is down the per-hook refetch intervals keep every view updating.
9
+ */
10
+ export declare function ClusterLayout(): import("react").JSX.Element;
@@ -0,0 +1,12 @@
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 heading; collapsed, a divider, and its heading stays available to a screen reader.
5
+ * A view the operator lacks the read permission for stays listed and disabled, with the reason:
6
+ * a missing entry would read as a product that cannot do it. Only rendered while a cluster is the
7
+ * active route.
8
+ */
9
+ export declare function ClusterViewNav({ clusterId, collapsed }: {
10
+ clusterId: string;
11
+ collapsed: boolean;
12
+ }): import("react").JSX.Element;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * ⌘K navigation across the console: jump to a view, or to whatever the features contribute — a
3
+ * cluster, a queue by name. Mounted once in the root layout; the shortcut is registered by
4
+ * {@link Spotlight}.
5
+ *
6
+ * Refresh and pause live here rather than on a hotkey: the browser owns both
7
+ * shortcuts an operator would reach for (⌘R and ⇧⌘R), and taking either would be
8
+ * worse than not having one (ADR-0052).
9
+ */
10
+ 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, }: {
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 }: {
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,5 @@
1
+ /**
2
+ * The landing page, with no cluster open: what the features contribute for it. The clusters feature
3
+ * sends the operator to the first cluster, or teaches how to register one.
4
+ */
5
+ export declare function HomeView(): import("react").JSX.Element;
@@ -0,0 +1,22 @@
1
+ import { type ReactNode } from 'react';
2
+ /**
3
+ * One sidebar row, shared by the cluster switcher and the per-cluster view nav
4
+ * (ADR-0034). Collapsed state hides the label visually but never from a screen
5
+ * reader — `aria-label` carries it, and the `Tooltip` supplies the mouse
6
+ * equivalent, opened late enough (350ms) that sweeping the rail doesn't flicker
7
+ * a tooltip per row.
8
+ *
9
+ * A row with a `disabledReason` is not a link. It stays in the tab order, so the
10
+ * reason is reachable by keyboard: the tooltip opens on focus as well as hover,
11
+ * and a screen reader hears the reason as the row's description.
12
+ */
13
+ export declare function NavItem({ to, label, leading, trailing, collapsed, disabledReason, }: {
14
+ to: string;
15
+ label: string;
16
+ /** An icon, a health mark, or a monogram — whatever leads the row. */
17
+ leading: ReactNode;
18
+ trailing?: ReactNode;
19
+ collapsed: boolean;
20
+ /** Why the row cannot be opened; the row is disabled while this is set. */
21
+ disabledReason?: string;
22
+ }): import("react").JSX.Element;
@@ -0,0 +1,6 @@
1
+ /** A real button — `aria-expanded`/`aria-controls` so the collapse is announced. */
2
+ export declare function NavToggle({ collapsed, onToggle, controls, }: {
3
+ collapsed: boolean;
4
+ onToggle: () => void;
5
+ controls: string;
6
+ }): import("react").JSX.Element;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The desktop workspace chrome: a fixed header, the collapsible sidebar (the features' way between
3
+ * clusters, then the open cluster's view nav, ADR-0034), and the routed detail column.
4
+ * Desktop-first — no mobile breakpoint (`breakpoint: 0`).
5
+ *
6
+ * The sidebar collapses to a 64px icon rail rather than disappearing: `AppShell`'s
7
+ * own `collapsed` prop removes the navbar's width entirely, which is the wrong
8
+ * shape for a rail that stays present with icons. Animating `navbar.width`
9
+ * instead lets `AppShell` transition both the navbar and the `Main` offset in
10
+ * lockstep under one `transitionDuration` (design.md Decision 7).
11
+ */
12
+ export declare function RootLayout(): import("react").JSX.Element | null;
@@ -0,0 +1,6 @@
1
+ import { type MeView } from '../auth/api.ts';
2
+ export interface UserMenuProps {
3
+ me: MeView | undefined;
4
+ }
5
+ /** The signed-in user's identity, admin entry point, account page, and logout (identity-and-sessions spec). */
6
+ export declare function UserMenu({ me }: UserMenuProps): import("react").JSX.Element | null;
@@ -0,0 +1,25 @@
1
+ /** What the header can say about the data on the screen right now (ADR-0052). */
2
+ export interface Freshness {
3
+ /** Newest successful fetch among the queries this screen is observing, in epoch ms. */
4
+ lastUpdatedAt: number | null;
5
+ isFetching: boolean;
6
+ /** At least one query the screen depends on is in error. */
7
+ hasError: boolean;
8
+ /** How many queries the screen is observing. Zero means there is nothing to report. */
9
+ observed: number;
10
+ }
11
+ /**
12
+ * Freshness derived from the query cache rather than wired per screen.
13
+ *
14
+ * The queries with **active observers** are exactly the ones the screen on the
15
+ * display depends on, so no screen can forget to opt in and a screen added later
16
+ * is covered the day it is written. A query nobody is watching has no freshness
17
+ * worth reporting.
18
+ *
19
+ * `lastUpdatedAt` is the *newest* success, not the oldest: the oldest is
20
+ * pessimistic in a misleading way — one slow background query would make a live
21
+ * screen read as stale — and the honesty lives in `hasError` instead, which puts
22
+ * the whole indicator into its offline state rather than letting a fresh sibling
23
+ * paper over a failing one.
24
+ */
25
+ export declare function useFreshness(): Freshness;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Sidebar collapse state, persisted per browser (ADR-0034). A boolean local to
3
+ * one component doesn't need a global store (non-negotiable #9) — `localStorage`
4
+ * is the whole state layer. `getInitialValueInEffect: false` reads synchronously
5
+ * so there is no expand→collapse flash on first paint.
6
+ */
7
+ export declare function useNavCollapsed(): {
8
+ collapsed: boolean;
9
+ toggle: () => void;
10
+ };