JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 870
  • Score
    100M100P100Q111096F
  • License Apache-2.0

Node.js adapter for bijou — chalk styling, readline I/O, process runtime.

Package Exports

  • @flyingrobots/bijou-node
  • @flyingrobots/bijou-node/package.json

Readme

@flyingrobots/bijou-node

Node.js adapters and runtime utilities for Bijou.

@flyingrobots/bijou-node bridges the pure core and the TUI runtime to the Node.js environment. It owns platform detection, terminal I/O, Chalk-backed styling, and worker-thread helpers.

Role

  • Port Implementation: Maps Node.js APIs to the Bijou port interfaces.
  • Worker Runtime: Offloads heavy TEA logic to worker threads while maintaining main-thread responsiveness.
  • Bootstrapping: One-call hosted app startup with startApp().

Install

npm install @flyingrobots/bijou @flyingrobots/bijou-node

Quick Start

import { stringToSurface } from '@flyingrobots/bijou';
import { startApp } from '@flyingrobots/bijou-node';
import { isKeyMsg, quit, type App } from '@flyingrobots/bijou-tui';

const app: App<{ count: number }> = {
  init: () => [{ count: 0 }, []],
  update: (msg, model) => {
    if (isKeyMsg(msg) && msg.key === 'q') return [model, [quit()]];
    return [model, []];
  },
  view: (model) => stringToSurface(`Count: ${model.count}\\nPress q to quit`, 16, 2),
};

await startApp(app);

Port Mapping

Port Node.js Implementation Responsibility
RuntimePort nodeRuntime() process.env, TTY detection, dimensions
IOPort nodeIO() stdout/stdin, readline, resize events
StylePort chalkStyle() RGB/hex styling, NO_COLOR support

API

  • createNodeContext(): Returns a wired BijouContext without setting it as the global default.
  • createNodeContext({ theme }): The explicit programmatic path for a custom theme on a Node-owned context.
  • createNodeContext({ themes, themeMode, themeOverride }): Picks from a named theme set with automatic light/dark selection and optional app-owned override state.
  • initDefaultContext(): Registers the first context as the global default for all Bijou components.
  • startApp(): Initializes a default Node context when needed and runs a TUI app through the hosted runtime. Pass startApp(app, { theme }) for the one-line programmatic custom-theme path, or startApp(app, { themes, themeMode, themeOverride }) for automatic light/dark selection plus override support. When the app is a self-running framed shell, startApp() delegates to that hosted runner instead of bypassing it.
  • Ambient default initializer: Importing @flyingrobots/bijou-node registers a lazy Node default-context initializer so low-level run(app) flows can still resolve ctx without a separate initDefaultContext() call.
  • BijouBootstrapError: Typed startup failure with reason, hint, and optional cause fields for terminal/context initialization errors.
  • scopedNodeIO(): Wraps the Node file adapter in a rooted filesystem boundary for app-level reads and guarded path resolution.
  • runInWorker(): Starts a TEA app inside a worker thread.
  • recordDemoGif(): Captures surface frames and rasterizes them to GIF for documentation.

Scoped File Access

Prefer scopedNodeIO() over raw nodeIO() when the app should only read assets from one project directory.

import { scopedNodeIO } from '@flyingrobots/bijou-node';

const io = scopedNodeIO({ root: process.cwd() });

const theme = io.readFile('themes/app.json');
const outputPath = io.resolvePath('captures/demo.gif');

readFile(), readDir(), and joinPath() now stay inside the declared root. resolvePath() gives hosts the same boundary check before they hand a path to raw Node writes such as fs.writeFileSync(). Both resolvePath() and joinPath() may return a realpath-normalized path rather than the lexical input path, because the boundary check resolves symlinks before validating the final location. A path with a valid lexical prefix is still rejected when it resolves through a symlink escape outside the scoped root.

Documentation


Built with 💎 by FLYING ROBOTS