Amer Agovic aa872bdd6b Release 1.0.10 with subpath deployment and modal menu invokes.
Add app_base/router_base config, compat path helpers, and scoped service worker
registration so apps can mount under a URL prefix. Wire invoke_type modal through
a handler registry and open the notification center from the standard menu flow.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-16 16:44:32 -05:00

@reliancy/bface

Base UI and platform library for building Progressive Web Applications (PWAs) with React and Tamagui: shells, routing, env/config, storage, menus, security primitives, and data helpers.

Installation

npm install @reliancy/bface

If your organization hosts this package on a private registry, configure npm for that registry (see publishConfig in package.json) before installing.

Peer dependencies

Install React in the consuming app (versions should match peerDependencies in package.json):

npm install react react-dom

Tamagui packages are dependencies of @reliancy/bface, so you do not need to add @tamagui/* or tamagui separately unless you want a single shared version across packages (then align versions with this library).

Quick Start

1. Basic App Setup

The library provides an App component that manages the application shell, routing, theming, and platform services.

import { App } from '@reliancy/bface/ui/App';
import { CONFIG_KEYS } from '@reliancy/bface/platform/env';
import { sw } from '@reliancy/bface/platform/worker';

async function handleInit(services, { initialProfile } = {}) {
  // Application profile (camelCase or snake_case field names are accepted where noted in env mapping)
  const profile = {
    name: 'MyApp',
    displayName: 'My Application',
    brandLogo: '/logo.svg',
    ui_shell: 'DashboardShell',
    modules: ['core'],
    storage: { backend: 'localStorage' },
    api: { baseURL: '/api' }
  };

  services.env.initEnv(profile);

  for (const moduleName of profile.modules) {
    // await loadModule(moduleName, services);
  }

  await sw.registerServiceWorker();

  return profile;
}

function MyApp() {
  return <App onInit={handleInit} />;
}

2. Using platform services

App calls onInit(services, { initialProfile }) once platform services exist. The services object includes:

  • services.api_client — HTTP client (get, post, …)
  • services.storage — storage module (getProvider, …)
  • services.ui_router — UI routing helpers
  • services.menu — menu registration and queries
  • services.envinitEnv, getConfig, setConfig, CONFIG_KEYS, tracing helpers, etc.

Service worker registration is not on services; import sw from @reliancy/bface/platform/worker (or the package root) and call sw.registerServiceWorker() from onInit when you are ready. Service-worker API interception belongs in app/module sw.js files that run inside the worker.

async function handleInit(services) {
  // Example: Get configuration
  const appName = await services.env.getConfig(CONFIG_KEYS.APP_NAME);
  
  // Example: Make API call
  const data = await services.api_client.get('/users');
  
  // Example: Store data (KeyValueStore via getProvider)
  const kv = services.storage.getProvider('kv', 'myStore');
  await kv.set('user', { id: 1, name: 'John' });
}

3. Using UI Components

Import and use UI components directly:

import { Page, Panel, MenuItemButton } from '@reliancy/bface/ui/components';
import { SideBar, TopBar } from '@reliancy/bface/ui/components';

function MyPage() {
  return (
    <Page title="Dashboard" icon="dashboard">
      <Panel>
        <Text>Welcome to your dashboard</Text>
      </Panel>
    </Page>
  );
}

4. Using Platform Modules

Import platform utilities:

import { getConfig, setConfig, CONFIG_KEYS } from '@reliancy/bface/platform/env';
import { api } from '@reliancy/bface/platform/api';
import { getProvider } from '@reliancy/bface/platform/storage';
import { queryMenuItems } from '@reliancy/bface/platform/menu';

// Get configuration
const theme = await getConfig('theme.mode', 'system');

// Set configuration
await setConfig('theme.mode', 'dark');

// Use storage
const storage = getProvider('kv', 'myStore');
await storage.set('key', 'value');
const value = await storage.get('key');

// HTTP (singleton; base URL comes from env when wired in App)
await api.get('/status');

// Query menu items
const menuItems = queryMenuItems('/primary');

Library structure

Exports (package.jsonexports)

  • @reliancy/bface — main entry: platform, App, UI components index, general settings, security, and data helpers
  • @reliancy/bface/platform/* — platform modules (env, api, storage, menu, worker, compat, host, …)
  • @reliancy/bface/ui/* — UI entry points such as App and components

Security and data types are re-exported from the root entry; there are no separate exports subpaths for ./security/* or ./data/* today—import them from @reliancy/bface or add deep links if your bundler resolves source.

Platform modules

  • platform/env.js — profile → config dictionary, getConfig / setConfig, logging and tracing helpers
  • platform/api.js — API client
  • platform/storage.js — storage abstraction (localStorage, IndexedDB, OPFS)
  • platform/menu.js — menu model and queries
  • platform/worker.js — browser worker/runtime helpers, currently exposed through the sw namespace
  • platform/compat.js — environment detection and compatibility
  • platform/host.js — host detection (e.g. Electron)

UI

  • ui/App.jsx — Tamagui provider, theme controller, security bootstrap, shell selection, onInit
  • ui/components/ — shells (EmptyShell, LandingShell, DashboardShell, …), layout, grid/DirView, forms, router
  • ui/styles/ — Tamagui style themes (material, minimal, colorful)

Other areas

  • security/ — policies, models, login and account pages, route guards, securityService
  • data/RecordsModel

Application profile and initEnv

initEnv maps the profile object onto internal config keys. For convenience, several fields accept either camelCase or snake_case:

Concept Accepted profile fields Internal key
Display title displayName, then short_name, then name APP_DISPLAY_NAME
Stable app id id, then name APP_NAME
Logo brandLogo or brand_logo, or PWA manifest-style icons[0].src BRAND_LOGO
API base api.baseURL or api.base_url API_BASE_URL
Shell uiShell or ui_shell UI_SHELL

Shell names (ui_shell / UI_SHELL)

Resolved case-insensitively in App:

Profile value Component
EmptyShell (default) EmptyShell
LandingShell LandingShell
TopBarShell Same layout as LandingShell (top bar shell)
DashboardShell DashboardShell

Complete Example

Here's a complete example of using the library in a project:

// app.jsx
import { App } from '@reliancy/bface/ui/App';
import { CONFIG_KEYS } from '@reliancy/bface/platform/env';
import { sw } from '@reliancy/bface/platform/worker';

async function loadProfile() {
  // Load your app profile (from JSON, API, etc.)
  const response = await fetch('/profile.json');
  return await response.json();
}

async function loadModule(moduleName, services) {
  // Dynamically import and initialize your modules
  const module = await import(`./modules/${moduleName}/index.js`);
  if (module.publishModule) {
    module.publishModule(services);
  }
}

async function handleInit(services, { initialProfile } = {}) {
  // 1. Load profile (use embedded profile from App when provided)
  const profile = initialProfile ?? await loadProfile();
  
  // 2. Initialize environment
  services.env.initEnv(profile);
  
  // 3. Load modules
  const modules = await services.env.getConfig(CONFIG_KEYS.MODULES, []);
  for (const moduleName of modules) {
    await loadModule(moduleName, services);
  }
  
  // 4. Register service worker
  await sw.registerServiceWorker();
  
  return profile;
}

export default function MyApp() {
  return <App onInit={handleInit} />;
}

Theming

The library supports multiple themes. Configure the theme in your profile:

{
  "name": "MyApp",
  "ui_shell": "DashboardShell",
  "theme": {
    "name": "material",
    "mode": "system"
  }
}

Available themes:

  • material - Material Design theme
  • minimal - Minimal theme
  • colorful - Colorful theme

Menu System

Register menu items in your modules:

// In your module
import { publishMenuItem, MENU_DIRS } from '@reliancy/bface/platform/menu';

export function publishModule(platform) {
  publishMenuItem(MENU_DIRS.PRIMARY('dashboard'), {
    label: 'Dashboard',
    icon: 'dashboard',
    invoke: () => {
      platform.ui_router.navigate('/dashboard');
    }
  });
}

Storage

The library provides a unified storage API:

import { getProvider } from '@reliancy/bface/platform/storage';

// Get storage provider
const storage = getProvider('kv', 'myStore');

// Use storage
await storage.set('key', { data: 'value' });
const value = await storage.get('key');
const exists = await storage.hasKey('key');
await storage.remove('key');
await storage.clear();

Supported backends:

  • localStorage - Browser localStorage
  • indexedDB - IndexedDB
  • opfs - Origin Private File System

API Client

Make HTTP requests using the API client:

// In your onInit callback — paths are relative to the API base URL from the profile (`api.baseURL` / `api.base_url`)
const data = await services.api_client.get('/users');
const user = await services.api_client.post('/users', { name: 'John' });
await services.api_client.put('/users/1', { name: 'Jane' });
await services.api_client.delete('/users/1');

Development

Clone the repository, install dependencies (npm install), then:

Build

npm run build

Produces ESM under dist/ with .d.ts declaration files (via vite-plugin-dts) for the published exports map. The dist/ folder is gitignored in this repo; the npm package tarball is built from files in package.json.

Tests

npm test

Uses Nodes built-in test runner. The npm script passes --localstorage-file=.node-localstorage so getConfig / storage-backed paths work under Node without noisy SecurityError warnings.

Watch mode (library)

npm run dev

Runs vite build --watch for iterative work on the package.

License

Copyright and licensing terms are defined by the organization that publishes this package.

Description
react + tamagui based ui library to support pwa and in general any project in need of ui
Readme 818 KiB
Languages
JavaScript 100%