# Classes

Import these from `@grafloria/renderer`.

## Classes

### `DisposableStore`

A bag of disposers with a single `dispose()`. Extensions accumulate their
registrations here so the host can tear the whole extension down atomically.

Disposal runs in REVERSE registration order (like a stack unwind) and is
failure-tolerant: one throwing disposer must not strand the rest, or a single
bad extension would leak every registry behind it.

```ts
class DisposableStore implements Disposable
```

**Methods**

- `add(disposer: Disposer): Disposer` — Track a disposer. If the store is ALREADY disposed, run it immediately.
- `get size(): number` — How many live registrations this store holds (tests assert on this).
- `get isDisposed(): boolean`
- `dispose(): void`

### `ExtensionHost`

```ts
class ExtensionHost
```

**Methods**

- `constructor(options: ExtensionHostOptions)`
- `get engine(): DiagramEngine` — The engine this host is bound to (hosts, not extensions, may ask).
- `register<C extends CapabilityName>(extension: Extension<C>): Disposer` — Register and ACTIVATE an extension.

Throws — deliberately, and before any side effect — when the manifest is
malformed, the id is taken, the engine range excludes this host, or the
extension asks for a capability this host cannot grant. A plugin that half-
loads is worse than one that refuses to.
- `registerLazy<C extends CapabilityName>( manifest: ExtensionManifest<C>, load: LazyExtension<C> ): Disposer` — Register WITHOUT loading. The factory is not called until `activate(id)`,
so a 500 KB plugin costs nothing until something needs it.

The manifest is supplied up front precisely so the host can answer "what
shapes/routers exist?" and validate compatibility WITHOUT paying the import.
- `async activate(id: string): Promise<void>` — Activate a lazily-registered extension (imports it on first call).
- `dispose(id: string): void` — Tear one extension down. Every registration it made is undone.
- `disposeAll(): void` — Tear everything down. The host is unusable afterwards.
- `has(id: string): boolean`
- `get(id: string): RegisteredExtension | undefined`
- `list(): RegisteredExtension[]` — Everything registered, loaded or not.

### `RegistryScope`

One diagram's private overlay over the process-global registries.

An entry here SHADOWS the global one of the same name for reads taken inside
this scope; a name absent here falls through. That layering is what lets a
diagram override a built-in (or an app-wide `registerShape()` at import time)
for itself alone, without mutating what anybody else sees.

```ts
class RegistryScope
```

**Methods**

- `table<V>(name: string): Map<string, V>` — The named table, created on demand. Use for WRITES.
- `peek<V>(name: string): Map<string, V> | undefined` — The named table if it exists, WITHOUT creating it. Use for READS.
- `isEmpty(): boolean` — True when this diagram has contributed nothing — i.e. it is pure fall-through.
- `clear(): void` — Drop every contribution (instance teardown).
