> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lodemc.net/llms.txt
> Use this file to discover all available pages before exploring further.

# sdk reference

> Every SDK point

```ts theme={null}
import sdk from 'sdk'            // sdk.pages.register(...)
import { pages, events } from 'sdk'   // the same objects
```

Both styles work; the default export is the namespace.

## Ids

Ids you choose are local to your expansion. `pages.register('home', …)` registers `my_expansion.home`, so two expansions can both have a `home` page. The qualified id is what the call returns, and what appears in routes. Local ids are letters, digits, `_` and `-`.

## About

```ts theme={null}
sdk.version          // '2.0.0', the SDK the app provides
sdk.expansion.id     // your id, from meta.json
sdk.expansion.name
sdk.expansion.version
sdk.expansion.permissions  // the ones you declared
```

## pages

```ts theme={null}
sdk.pages.register(pageId, Component): string
```

Registers a page. Open it with a [sidebar button](#sidebar) or [`useNavigate().page(id)`](/ui-reference#usenavigate). It renders at `/project/<projectId>/custom/<expansionId>.<pageId>`.

## sidebar

```ts theme={null}
sdk.sidebar.add({ id, page, label?, icon? }): string
```

Adds a button to the project sidebar that opens one of your pages.

* `page` is a page id you passed to `pages.register`.
* `icon` is a [Lucide](https://lucide.dev/icons) icon name such as `'Star'`, or an imported image. Defaults to a puzzle piece.
* `label` defaults to your expansion's name.

Users can reorder or hide it like any built-in button.

## injections

```ts theme={null}
sdk.injections.add(slotId, Component, { order?, metadata? }): Dispose
```

Renders a component inside an existing app screen. Returns a function that removes it.

Slots today, all in the item editor:

```
item-editor:header:before        item-editor:header:after
item-editor:model-viewer:before  item-editor:model-viewer:after
item-editor:assets:before        item-editor:assets:after
item-editor:modules:before       item-editor:modules:after
```

The component receives `injectionContext` (for the item editor: `{ data, projectId }`), `injectionMetadata`, `slotId` and `expansionId`. Lower `order` renders first; the default is 100.

## editors

```ts theme={null}
sdk.editors.register(editorId, Component, metadata?): string
sdk.editors.forType(elementType, editorId): void
```

A full editor for a kind of item, and the mapping that makes items of `elementType` open in it. The component receives `itemId`, `itemData`, `content`, `setContent` and `readItems`.

## creators

```ts theme={null}
sdk.creators.register(creatorId, Component, metadata?): string
```

Adds an entry to the Create menu. `metadata` may carry `label`, `icon`, `description` and `compatibility`.

## items

```ts theme={null}
sdk.items.registerType(typeId, config?): void
```

Registers a new item type for the browser. Type ids are written into project files, so they are **not** prefixed with your expansion id, and registering one that already exists is refused.

`config.editor` names one of your editors; `displayName`, `svgIcon` and `tabIcon` control how items appear.

## modules

```ts theme={null}
sdk.modules.register({ name, component?, display?, description?, icon?, plugins?, type?, default? }): string
```

Adds a module to the item editor. With `component`, your component renders it; without, `type` selects a built-in input.

## settings

```ts theme={null}
sdk.settings.appTab(section): string
sdk.settings.projectTab(section): string
```

Adds a tab to app or project settings. A section is `{ id, title, description?, icon?, elements }`, where `elements` are the app's settings elements (`text`, `checkbox`, `dropdown`, `slider`, `static-text`, …). Element ids are namespaced with your expansion id automatically.

## theme

```ts theme={null}
sdk.theme.setVariables({ '--accent': '#ce75e0' }): void
sdk.theme.addStyle(css): Dispose
```

`setVariables` sets CSS variables on the app. `addStyle` adds a stylesheet that is **not** scoped to your expansion, for when you deliberately want to restyle the app; both are undone when your expansion unloads.

For styling your own UI, import a CSS file instead: it is scoped for you.

## i18n

```ts theme={null}
sdk.i18n.addLanguage({ local, label, translations }): void
```

Registers a UI language, e.g. `{ local: 'es', label: 'Español', translations: { … } }`.

## events

```ts theme={null}
sdk.events.on(name, handler): Dispose
sdk.events.emit(name, payload?): Promise<unknown>
```

Listen to what the user does, or send your own event. Any number of listeners per event, including several from one expansion; each `on` returns its own unsubscribe, and all of them are removed when your expansion unloads.

Events the app fires:

```
item:open      item:delete    item:rename   item:duplicate   item:import
folder:create  folder:rename  folder:delete folder:open
namespace:open namespace:delete
module:add     module:delete
editor:save    tab:switch     tab:close
modal:open     modal:confirm  modal:cancel
contextmenu:open  browser:open  button:click  error
```

`emit` reaches every expansion, including legacy ones, so it is also how two of your own expansions talk to each other. Namespace your own events, e.g. `my_expansion:thing-happened`.

## project

```ts theme={null}
sdk.project.current(): string | null
sdk.project.items(projectId?): Promise<any[]>                       // project:read
sdk.project.readFile(fileName, projectId?): Promise<FileResult>     // project:read
sdk.project.writeFile(fileName, content, projectId?): Promise<FileResult>  // project:write
sdk.project.updateItem({ path, changes }): Promise<unknown>         // project:write
```

* `current()` is the open project's id, or null outside a project.
* `items()` returns the project's items as an array.
* `readFile` returns `{ success, data, parsed, error }`: `data` is the text, `parsed` is the value for `.json`/`.yml` files.
* `writeFile` returns `{ success, error }`. `fileName` is a path inside the project folder; subfolders are created as needed and paths cannot escape the project.
* `updateItem` applies `changes` to the item's YAML at `path`.

<Warning>
  Without the permission, these throw `SdkPermissionError` and the refusal is logged.
</Warning>

## clipboard

```ts theme={null}
sdk.clipboard.readText(): Promise<string>   // clipboard
sdk.clipboard.writeText(text): Promise<void> // clipboard
```

## notify and log

```ts theme={null}
sdk.notify('Saved', { type: 'success' })   // info | success | warning | error
sdk.log.debug(...), sdk.log.info(...), sdk.log.warn(...), sdk.log.error(...)
```

`notify` shows a toast. `log` writes to your expansion's log, visible on the Expansions page, and to devtools. Plain `console.*` inside your expansion goes to the same place.

## Expansion

```ts theme={null}
import { Expansion } from 'sdk'
export default class extends Expansion { onLoad() { this.sdk … } }
```

The optional base class for a [class-based expansion](/writing-style).

## Errors

```ts theme={null}
import { SdkPermissionError } from 'sdk'
```

Thrown when a call needs a permission your `meta.json` does not declare.

## Not available yet

```ts theme={null}
sdk.run(file)   // background scripts: throws today
```
