summaryrefslogtreecommitdiffhomepage
path: root/packages/surface-loaded-extensions/src/spec.ts
blob: e4883819f527d1ab6ee96f82a05eb450b0f1e3b9 (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],
  };
}