Skip to content
Moku
@moku-labs/system pages

Quick start

Save a counter that survives a reload, then see what a missing capability looks like.

On this page

A counter in four steps

  1. Install. @moku-labs/core and @moku-labs/common are required peers, so your app and every Moku framework share one copy.

    install
    bun add @moku-labs/system @moku-labs/core @moku-labs/common
  2. Compose the capabilities you use. Plugins come from subpaths. A store-only app carries no code of the other capabilities.

  3. Start the app. start() picks each capability's provider. A method called before it answers unavailable.

  4. Read the result. Every method returns SystemResult<T>. Check ok before you read value.

The code

src/counter.ts
import { createApp } from "@moku-labs/system";
import { storePlugin } from "@moku-labs/system/store";

const system = createApp({
  plugins: [storePlugin],
  pluginConfigs: { store: { name: "my-app" } }
});

await system.start();

const saved = await system.store.get<number>("count");
const count = saved.ok ? (saved.value ?? 0) : 0;

const written = await system.store.set("count", count + 1);
if (!written.ok) console.warn(written.reason, written.message);

await system.stop();
  1. The IndexedDB database on the web, the store file my-app.json in Tauri.
  2. An absent key is ok with undefined, not a failure.

The same file runs in a browser and in the native shell. Nothing in it names a runtime.

When a capability is missing

A tray icon does not exist on the web. The call still answers, with data you can act on:

src/tray.ts
import { createApp } from "@moku-labs/system";
import { trayPlugin } from "@moku-labs/system/tray";

const system = createApp({ plugins: [trayPlugin] });
await system.start();

const result = await system.tray.setTooltip("Syncing");
if (!result.ok && result.reason === "unsupported") {
  console.log(`no tray on ${result.provider}`);
}
  1. In a browser: no tray on web. Hide the feature.

Add the native shell

The Tauri packages are optional peers. Install only the ones your capabilities load:

native only
bun add @tauri-apps/api @tauri-apps/plugin-store

Then package the app with @moku-labs/native. It generates the Tauri permissions from the capabilities you list.