Add security/index, security/model/index, security/policy/index, and security/pages/index as explicit lib entries. Under preserveModules these re-export barrels were never reachable from an entry (internal code imports the concrete files directly), so dist shipped only their .d.ts and consumer imports like `@reliancy/bface/security/model/index.js` failed to resolve. Not republished; picked up on the next release. Co-authored-by: Cursor <cursoragent@cursor.com>
@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 helpersservices.menu— menu registration and queriesservices.env—initEnv,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.json → exports)
@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 asAppandcomponents
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 helpersplatform/api.js— API clientplatform/storage.js— storage abstraction (localStorage, IndexedDB, OPFS)platform/menu.js— menu model and queriesplatform/worker.js— browser worker/runtime helpers, currently exposed through theswnamespaceplatform/compat.js— environment detection and compatibilityplatform/host.js— host detection (e.g. Electron)
UI
ui/App.jsx— Tamagui provider, theme controller, security bootstrap, shell selection,onInitui/components/— shells (EmptyShell,LandingShell,DashboardShell, …), layout, grid/DirView, forms, routerui/styles/— Tamagui style themes (material,minimal,colorful)
Other areas
security/— policies, models, login and account pages, route guards,securityServicedata/—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 thememinimal- Minimal themecolorful- 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 localStorageindexedDB- IndexedDBopfs- 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 Node’s 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.