npm package: @karaoke-cms/contracts
Description: Shared type contracts for karaoke-cms — interfaces for modules, themes, and configuration
Latest version: 0.20.10

# @karaoke-cms/contracts

Shared type contracts for karaoke-cms. Every interface that crosses a package boundary — modules, themes, configuration, menus, CSS contracts — is declared here. All other karaoke-cms packages import from this package rather than from each other.

## Installation

```bash
npm install @karaoke-cms/contracts
```

Module and theme authors use this package as a peer dependency. End users typically don't install it directly — it is a dependency of `@karaoke-cms/astro`.

## Usage

```ts
import { defineModule, defineTheme } from '@karaoke-cms/contracts';
import type { ModuleInstance, ThemeInstance, KaraokeConfig } from '@karaoke-cms/contracts';
```

## Configuration

### `defineModule(def)`

Define a karaoke-cms module. Returns a factory function — call the factory with `{ mount }` to get a `ModuleInstance`.

```ts
import { defineModule } from '@karaoke-cms/contracts';

export const myModule = defineModule({
  id: 'my-module',
  cssContract: {
    'my-card': { description: 'Module card wrapper', required: true },
  },
  routes: (mount) => [
    { pattern: mount, entrypoint: '@my-org/my-module/pages/index' },
  ],
  menuEntries: (mount, id) => [
    { id, name: 'My Module', path: mount, section: 'main', weight: 50 },
  ],
});

// In karaoke.config.ts:
// modules: [myModule({ mount: '/my-module' })]
```

### `defineTheme(def)`

Define a karaoke-cms theme. Returns a factory function — call the factory to get a `ThemeInstance`.

```ts
import { defineTheme } from '@karaoke-cms/contracts';

export const myTheme = defineTheme({
  id: 'my-theme',
  toAstroIntegration: (config, modules) => ({
    name: 'my-theme',
    hooks: {
      'astro:config:setup': ({ injectRoute }) => {
        injectRoute({ pattern: '/', entrypoint: '...' });
      },
    },
  }),
});

// In karaoke.config.ts:
// theme: myTheme()
```

### Key exported types

| Export | Description |
|--------|-------------|
| `KaraokeConfig` | Full config shape for `defineConfig()` in `karaoke.config.ts` |
| `ModuleInstance` | Resolved module — returned by any module factory call |
| `ThemeInstance` | Resolved theme — returned by any theme factory call |
| `CssContract` | Record mapping CSS class names to `{ description, required }` |
| `DocsSection` | One entry in the `docs([...])` array-form call |
| `ModuleMenuEntry` | Menu entry registered by a module instance |
| `CommentsConfig` | Giscus comments configuration shape |
| `ResolvedMenus` | Resolved menu structure available at build time |
| `RouteDefinition` | `{ pattern, entrypoint }` pair passed to `injectRoute` |

## What's new in 0.18.2

- **`VariantLayoutDeclaration`** -- new type describing per-variant region layouts (which components appear in `main`, `left`, and `right` for a given page type). Each region entry is `{ component: string; weight: number }`.
- **`LayoutConfig`** -- `Record<string, VariantLayoutDeclaration>` mapping variant keys to region layouts. Used by themes (`layoutOverrides`) and users (`variantLayouts` in `karaoke.config.ts`).
- **`defineLayoutConfig(config)`** -- identity helper providing type inference for `layout.config.ts` files in themes.
- **`ModuleInstance.variantLayouts`** -- modules declare default per-variant layouts using local keys (e.g. `'post'`). At resolution time, keys are prefixed with the module's namespace to form full variant keys (e.g. `karaoke.blog.post`).
- **`ThemeInstance.layoutOverrides`** -- themes ship per-variant layout overrides that win over module defaults but lose to user config.
- **`KaraokeConfig.variantLayouts`** -- user-level per-variant layout overrides (highest priority in the three-layer merge).
- **`ModuleRegionComponentDeclaration.componentExport`** -- modules can now declare the npm subpath export that resolves to the `.astro` component for a region widget. Used by `virtual:karaoke-cms/region-registry` to auto-generate imports.

## What's new in 0.18.0

- **`ModuleInstance.modes`** — added `modes?: ('dev' | 'prod')[]` to `ModuleInstance`. Modules can now declare which build modes they participate in directly, replacing external `collections.yaml` overrides for dev/prod control.

## What's new in 0.17.0

- **`DocsSection.comments`** — added `comments?: boolean` to `DocsSection` so the array-form `docs([...])` can set per-section comment defaults.
- **`DocsSection.parent`** — added `parent?: string` to `DocsSection` for nesting docs sections as submenus in the main nav.
- **`DocsSection.weight`** — added `weight?: number` for explicit menu ordering. Reserved weights: Blog = 10, Tags = 30.
- **`MenuEntryConfig.static`** — added `static?: string` for non-interactive text labels in `menus.yaml`.
- **`MenuEntryConfig.parent`** — added `parent?: string` for submenu nesting in `menus.yaml`.
- **`ModuleInstance.meta`** — added `meta?: Record<string, unknown>` for modules to pass config through the core without modifying `KaraokeConfig`.
- **`KaraokeConfig.modules`** accepts `(ModuleInstance | ModuleInstance[])[]` — array-returning factories (e.g. `docs([...])`) can be passed directly; `karaoke()` flattens them automatically.