Skip to content

@storyshelf/app

View as Markdown

@storyshelf/app is the HTTP app for StoryShelf. createShelfApp() composes database, storage, capture, auth, and notifier (chat, email, git) adapters (all from @storyshelf/core) into a Hono application: a JSON API under /api/v1 plus server-rendered HTML pages (hono/jsx + HTMX, no client framework).

Terminal window
npm i @storyshelf/app

JSR JSR Score

import { createShelfApp } from "@storyshelf/app";
const app = createShelfApp({ database, storage, testing: { runner: captureRunner } });
// Leave `testing` out to host Storybooks only: createShelfApp({ database, storage })
await app.lifecycle.setup();
serve({ fetch: app.fetch, port: 3000 });

Adapter init hooks kick off in the background when the app is created. Await them before serving for fail-fast startup (or let the first request gate on settlement), and close adapters on shutdown:

await app.lifecycle.setup();
const server = serve({ fetch: app.fetch, port: 3000 });
process.on("SIGTERM", () => {
app.lifecycle
.teardown()
.then(() => server.close())
.catch(() => {});
});

Three tiers, pick the shallowest that fits:

  1. Defaults — omit logger and import nothing. The app creates its own instance; LOG_LEVEL env sets the level (debug, info, …; default "info").

  2. Configured app — createShelfLogger (re-exported from @storyshelf/app, canonical home @storyshelf/core/logger), pass it in, and read it back via app.lifecycle.logger for your own logs:

    import { createShelfLogger, createShelfApp } from "@storyshelf/app";
    const app = createShelfApp({ database, storage, logger: createShelfLogger() });
    await app.lifecycle.setup();
    const logger = app.lifecycle.logger;
  3. A process that only consumes jobs or runs forked capture — import createShelfLogger from @storyshelf/core/logger directly, never the router barrel (it must not pull Hono).

The barrel exports only the app and its types (createShelfApp, ShelfApp, ShelfRouter, ShelfContext, ShelfLifecycle, the logger factory + types, plus the option types re-exported from core). Everything domain-level lives under @storyshelf/core/* subpaths.

Two-tier, neither gated by adapter init: GET /api/v1/health is open liveness for orchestrators; POST /api/v1/health is site-admin deep readiness with per-adapter states.

Choose the default adapters in deployment or see the CLI guide for the packaged server entry point.