# @lia-labs/sdk

> The Lia SDK for apps with a build step. Every feature as a typed, tree-shakeable export, with the same checks and error codes as the script tag, and state you can watch. From the Lia developer docs: https://docs.lialabs.org/packages/sdk

```sh
npm install @lia-labs/sdk
```

## Start

```ts
import { init, isLia, mockLia, ready } from '@lia-labs/sdk';

if (!isLia()) mockLia(); // building in a desktop browser

const me = await init();
render(me);
ready();
```

`init(options?)` calls Lia once and answers with the same result as [`Lia.init()`](/reference/sdk-lifecycle#lia-init); calling it again answers with the first result. It also:

- keeps the `--lia-*` [CSS variables](/concepts/look-and-feel#lias-theme) current on your page (turn off with `{ cssVars: false }`, or call `bindCssVars()` yourself),
- sets your page's `lang` and `dir` from the person's language (turn off with `{ documentLanguage: false }`),
- keeps the SDK's [state](/packages#state-you-can-watch) current from Lia's events.

## From the script tag to imports

Everything on the script tag's `Lia` object is a named export here, with the same arguments, answers and error codes. Import only what you use; the rest is left out of your bundle.

| Script tag | @lia-labs/sdk |
| --- | --- |
| `Lia.init()`, `Lia.ready()`, `Lia.session()`, `Lia.close()` | `init()`, `ready()`, `session()`, `close()` |
| `Lia.pay(id, opts)`, `Lia.charges()`, `Lia.onCharge(fn)` | `pay(id, opts)`, `charges()`, `onCharge(fn)` |
| `Lia.showAd(opts)` and its shortcuts, `Lia.onAd(fn)` | `showAd(opts)`, `showRewardedAd()`, `showRewardedInterstitialAd()`, `showInterstitialAd()`, `onAd(fn)` |
| `Lia.requestNotifications()` | `requestNotifications()` |
| `Lia.inviteFriend(opts)`, `Lia.inviteLink(p)`, `Lia.share(text)` | `inviteFriend(opts)`, `inviteLink(p)`, `share(text)` |
| `Lia.confirm`, `Lia.showPopup`, `Lia.showAlert`, `Lia.showConfirm`, `Lia.toast` | The same names |
| `Lia.expand()`, `Lia.requestFullscreen()`, `Lia.exitFullscreen()` | The same names |
| `Lia.enableExpand()` … `Lia.disableClosingConfirmation()` | The same names |
| `Lia.setBackgroundColor(c)`, `Lia.setHeaderColor(c)` | The same names |
| `Lia.mainButton`, `Lia.secondaryButton`, `Lia.backButton`, `Lia.settingsButton` | `mainButton`, `secondaryButton`, `backButton`, `settingsButton` |
| `Lia.haptic`, `Lia.scanQr`, `Lia.copyText`, `Lia.readClipboard`, `Lia.openLink`, `Lia.openLiaLink` | The same names |
| `Lia.submitScore`, `Lia.leaderboard` | The same names |
| `Lia.cloudStorage`, `Lia.deviceStorage`, `Lia.secureStorage`, `Lia.biometric` | The same names |
| `Lia.accelerometer`, `Lia.gyroscope`, `Lia.deviceOrientation` | The same names, with `reading` and `isStarted` to watch |
| `Lia.on(event, fn)`, `Lia.off`, `Lia.onPause`, `Lia.onResume` | `on(event, fn)`, `off`, `once`, `onAny`, `onPause`, `onResume` |
| `Lia.language`, `Lia.theme`, `Lia.viewport` and the other properties | `language.get()`, `themeParams.get()`, `viewport.get()` and the rest |

Every method's arguments, answers and errors are in the [SDK reference](/reference/sdk).

## Watching state

```ts
import { colorScheme, language, viewport } from '@lia-labs/sdk';

language.get(); // "en"
const stop = colorScheme.subscribe((scheme, previous) => repaint(scheme));
viewport.subscribe(({ height }) => resizeCanvas(height));
```

A listener hears changes only (never on subscribe) and `subscribe` returns its own stop function. You can make your own with `signal(initial)` and `computed(sources, fn)`.

## Buttons

The buttons work as on the script tag, and also tell you their state:

```ts
import { mainButton } from '@lia-labs/sdk';

mainButton.setParams({ text: 'Buy for 5 LIA', isVisible: true });
const stop = mainButton.onClick(buy);
mainButton.state.subscribe((s) => console.log(s.isProgressVisible));
```

`setParams` takes camelCase names: `text`, `color`, `textColor`, `isVisible`, `isActive`, `isProgressVisible`, `hasShineEffect`, `position`. `onClick` returns a function that stops listening. `backButton.isVisible` and `settingsButton.isVisible` can be watched too.

To show a button only while part of your page is on screen, `controlBottomButton(button, options)` and `controlHeaderButton(button, onClick)` give you `update(…)` and `dispose()` (dispose hides it). The framework packages use these.

## Errors

Every failure is a `LiaError` with a `code`, the same codes as the [script tag](/reference/errors). `isLiaError(error, 'cancelled')` checks one.

```ts
import { isLiaError, pay } from '@lia-labs/sdk';

try {
  await pay('extra-lives', { idempotencyKey: orderId });
} catch (error) {
  if (isLiaError(error, 'cancelled')) return;
  throw error;
}
```

Arguments are checked before anything reaches Lia, and those checks reject the promise (or throw, for the few calls that don't return one).

## Without a bundler

The package also has a script build that puts everything on `window.liaSdk`:

```html
<script src="https://unpkg.com/@lia-labs/sdk/dist/index.global.js"></script>
<script>
  liaSdk.init().then(function (me) { liaSdk.ready(); });
</script>
```

Use this or the original script tag on a page, not both.

## TypeScript

Everything is typed, including every method's params and answer, and every event's data (`Methods`, `Events`, `InitResult`, `ThemeParams`, `Charge`, `AdResult` and the rest are exported).
