# seniority/plugin

> Every export of seniority/plugin, with its signature and doc comment: validate, register, reset, registered, sources, CONTRACT and 1 more, plus 5 types.

Source: https://seniority.interlace.tools/docs/api/plugin

<!-- Generated by scripts/api-reference.ts from the built dist/*.d.ts. Do not edit; run `npx tsx scripts/api-reference.ts`. -->

The plugin host for seniority's half of the contract (`plugin-contract` R1, R5a, R6, R7, R8).

A plugin is one plain object shared by the whole family. This file keeps the key seniority
understands — `sources`, a resolution source — and **ignores every other key without
complaining**, which is what makes the same object work on any subset of the family that
is installed. A plugin written for flagstaff registers here and contributes nothing; its
`spinners` and `components` are not seniority's business and are not an error.

**Nothing here imports another layer, and the shape is declared rather than imported.**
Types erase, so an import would cost nothing at run time — and it would still put another
package in seniority's dependency story, which is the one thing the family promises it
does not do.

**A plugin adds a source; it cannot reorder the five.** `rank` slots a source between two
built-ins and nothing else: below `RANK.flag`, so what the user typed on the command line
always wins, and above `RANK.default`, so a declared default stays the floor. Both bounds
are refused at the door rather than clamped, because a source silently demoted to last
looks like it worked and the author debugs the wrong thing. "The order is not
configurable" survives extension exactly this far, and no further.

**Reading happens here, not in `resolve`.** `resolve` is pure over the layers it is
handed (R2) and nothing in this package reads `process.*` (R11) — so `sources(runtime)`
is the seam: the caller passes its own `{ env, cwd }`, this file calls each `read`, and
what `resolve` receives is data.

```ts
import { validate, register, reset, … } from 'seniority/plugin';
```

## Functions

### register

Register a plugin. Later wins at an equal rank, like ESLint flat config: the array is
ordered, a caller reads it top to bottom, and the last word on a source is the one nearest
the program.

```ts
function register(plugin: unknown): void;
```

| Parameter | Type |
| :-- | :-- |
| `plugin` | `unknown` |

**Returns** `void`

### registered

The plugins registered, in registration order.

```ts
function registered(): readonly Plugin[];
```

**Returns** `readonly Plugin[]`

### reset

Forget every registered plugin. For tests, and for a program that re-registers at runtime.

```ts
function reset(): void;
```

**Returns** `void`

### sources

Every registered source, read against this runtime and sorted by rank — the array
`resolve` takes as `layers.sources`.

A source whose `read` returns `undefined` had nothing for this run and contributes no
candidate at all, which is different from contributing an empty one: `--explain` should
not list a vault that was never reachable as a source that was consulted and lost.

```ts
function sources(runtime: SourceRuntime): SourceLayer[];
```

| Parameter | Type |
| :-- | :-- |
| `runtime` | `SourceRuntime` |

**Returns** `SourceLayer[]`

### validate

Refuse a plugin that cannot contribute a source, at the door.

```ts
function validate(plugin: unknown): asserts plugin is Plugin;
```

| Parameter | Type |
| :-- | :-- |
| `plugin` | `unknown` |

**Returns** `asserts plugin is Plugin`

## Classes

### PluginError

A refused plugin says what is wrong and what to do about it — the family's one vocabulary.

```ts
class PluginError extends Error {
    readonly code: PluginErrorCode;
    readonly fix: string;
    constructor(code: PluginErrorCode, message: string, fix: string);
}
```

## Constants

### CONTRACT

The plugin contract version. One number for the family — the same `1` flagstaff declares,
written out rather than imported for the reason in the file comment above.

```ts
const CONTRACT = 1;
```

## Interfaces

### Plugin

The keys seniority reads. Declared structurally: any object with these fields is a plugin
here, whatever else it carries.

```ts
interface Plugin {
    name: string;
    contract?: number;
    sources?: Record<string, SourceSpec>;
}
```

### SourceRead

What a `read` returns when it has something to say.

```ts
interface SourceRead {
    values: Record<string, unknown>;
    /** Where a person would look. Falls back to the source's `location`, then to its name. */
    location?: string;
}
```

### SourceRuntime

What a source is handed. Declared structurally and deliberately small: `env` and `cwd` are
what a vault, a CI variable set or a remote config needs, and anything a plugin could do
with `process` directly it should be given instead (R11, Y9).

```ts
interface SourceRuntime {
    env: Record<string, string | undefined>;
    cwd: string;
}
```

### SourceSpec

One source a plugin contributes, keyed in `sources` by the name `--explain` prints.

Exactly one of `values` and `read`. `values` is the data-first form R7 asks for — a source
that is a constant is inspectable without being run — and `read` is the dynamic form R5a
names, for the vault or the remote config that has to go and look.

```ts
interface SourceSpec {
    /** Against `RANK`: strictly between `RANK.flag` and `RANK.default`. */
    rank: number;
    values?: Record<string, unknown>;
    location?: string;
    read?: (runtime: SourceRuntime) => SourceRead | undefined;
}
```

## Types

### PluginErrorCode

```ts
type PluginErrorCode = 'E_PLUGIN_SCHEMA' | 'E_PLUGIN_CONTRACT' | 'E_NO_CONTRIBUTION';
```
