# Creating XLibrary plugins

This directory is the canonical developer documentation for XLibrary plugins.
It describes the contracts validated by the application and exposed through
`@xlibrary/plugin-sdk`.

## Getting started

1. Install Node.js 20+ and pnpm 10+.
2. Create a project with `pnpm dlx @xlibrary/plugin-sdk create my-plugin`.
3. Run `pnpm install`, `pnpm test`, and `pnpm demo` in the generated folder.
4. Declare only the required permissions and contributions in `manifest.json`.
5. Implement the default export of an `XLibraryPlugin` object in `src/index.ts`.
6. Run `pnpm package` to build `runtime/index.js` and package only the manifest
   and runtime into a `.xlplugin` archive.

The generated starter is intentionally small but runnable: its local demo
performs a deterministic game-source search and resolve through the SDK test
host, so a new plugin author can see a working result before connecting a real
catalog or browser source.

## Documentation map

- [`manifest.md`](./manifest.md) — manifest structure, permissions,
  contributions, and localization.
- [`runtime-api.md`](./runtime-api.md) — lifecycle, invocation contracts, and
  the constrained host API.
- [`contributions.md`](./contributions.md) — importing, exporting, provider
  search, UI, filters, tracking, fields, actions, jobs, and backup.
- [`testing.md`](./testing.md) — the test host, file/network/auth mocks,
  browser captures, and contract error diagnostics.
- [`security-and-release.md`](./security-and-release.md) — the security model,
  migrations, versions, packaging, and the pre-release checklist.

## Minimal entry module

```ts
import type {XLibraryPlugin} from '@xlibrary/plugin-sdk';

const plugin: XLibraryPlugin = {
  async initialize(context, host) {
    await host.diagnostics.log({
      level: 'info',
      event: 'plugin.initialized',
      message: `Started ${context.plugin.id}`,
    });
  },

  async invoke(invocation, host) {
    if (invocation.method === 'game-sources.search') {
      return {candidates: []};
    }
    throw new Error(`Unsupported method: ${invocation.method}`);
  },

  async deactivate(_context, host) {
    await host.diagnostics.log({
      level: 'info',
      event: 'plugin.deactivated',
      message: 'Plugin stopped',
    });
  },
};

export default plugin;
```

Import the SDK with `import type` only. The production package does not need to
include the SDK itself: the runtime must contain the plugin's compiled
JavaScript and its normal runtime dependencies.
