Skip to content

Your first application

Install the published Core package and run ordinary async services with exact instance dependencies.

This path uses Bun 1.4.2 and published @lenso/core@0.2.0. It needs neither Engine nor Web. The example has been run against that actual npm artifact.

Create a directory

Use a new directory:

mkdir lenso-first-appcd lenso-first-appbun init -ybun add --exact @lenso/core@0.2.0

Keep the generated bun.lock. These commands do not imply an application scaffolder. create-lenso-docs@0.1.0 creates documentation sites, not runtime applications.

Write the service and assembly

Replace index.ts with:

import { defineApp, definePlugin, startApp } from "@lenso/core";
const greeting = definePlugin({  id: "greeting",  setup() {    return {      async greet(name: string) {        return { message: "Hello, " + name + "." };      },    };  },});
const report = definePlugin({  id: "report",  requires: [greeting],  setup(context) {    const service = context.get(greeting);    return { async run() { return service.greet("Lenso"); } };  },});
const app = await startApp(defineApp({ plugins: [report, greeting] }));try {  console.log(await app.get(report).run());} finally {  await app.stop();}

Run it

bun index.ts

Expected business output:

{ message: "Hello, Lenso." }

The array deliberately lists report first. Core initializes its declared greeting dependency before report setup. context.get(greeting) returns that exact object's service. app.get(report) reads an installed, initialized service; neither call discovers or installs a plugin by name.

Give resources an owner

Register cleanup immediately after setup acquires a resource:

const ticker = definePlugin({  id: "ticker",  setup(context) {    const timer = setInterval(() => {}, 1000);    context.onCleanup(() => clearInterval(timer));    return { async ready() { return true; } };  },});

Add ticker to the assembly before accessing it. Keep stop() in finally so a failed service call still releases resources. Core attempts cleanup in reverse acquisition order and reports failures. It does not undo business effects.

If the first run fails

SymptomCheck
Import failsInstall from this directory; confirm the exact Core version in package.json.
missing-dependencyInclude the same greeting object in plugins and requires.
duplicate-idGive independently installed instances distinct IDs.
Dependency access failsDeclare the exact object in requires; recreating its ID is insufficient.
Process stays aliveCheck owned timers/streams/listeners and whether stop settles.

Continue with composition and lifecycle. Before adding configured instances or Web, choose the matching published package matrix in installation.