summaryrefslogtreecommitdiffhomepage
path: root/packages/surface-loaded-extensions/src/spec.ts
blob: 72e8d4115892f4532f3c7c0fdc7e3047ee6f8bb9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import type { Manifest } from "@dispatch/kernel";
import type { CustomField, StatField, SurfaceSpec } from "@dispatch/ui-contract";

/**
 * The typed payload of the `rendererId: "table"` custom field (CR-1). Exported
 * so a client renderer narrows `CustomField.payload` via this symbol instead of
 * a blind `unknown`. Each row aligns cell-for-cell to `columns`.
 */
export interface TablePayload {
	readonly columns: readonly string[];
	readonly rows: ReadonlyArray<ReadonlyArray<string | number | boolean>>;
}

/** The renderer id clients dispatch on for the extensions table. */
export const TABLE_RENDERER_ID = "table";

/**
 * Pure core — builds the SurfaceSpec for the loaded-extensions surface.
 * Zero I/O, zero ambient state. Decision logic only: input → output.
 *
 * Emits a "Loaded" count stat plus ONE `custom`/"table" field enumerating EVERY
 * loaded extension (all trust tiers) as real columns (CR-1). A client without a
 * "table" renderer gracefully skips the field and still sees the count.
 */
export function buildLoadedExtensionsSpec(manifests: readonly Manifest[]): SurfaceSpec {
	const count: StatField = { kind: "stat", label: "Loaded", value: String(manifests.length) };

	const payload: TablePayload = {
		columns: ["Name", "Version", "Trust", "Activation"],
		rows: manifests.map((manifest) => [
			manifest.name,
			manifest.version,
			manifest.trust,
			// Activation is optional in the manifest; "eager" is the declared default.
			manifest.activation ?? "eager",
		]),
	};

	const table: CustomField = {
		kind: "custom",
		rendererId: TABLE_RENDERER_ID,
		payload,
	};

	return {
		id: "loaded-extensions",
		region: "side",
		title: "Loaded Extensions",
		fields: [count, table],
	};
}