npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@bardioc/app-sdk

v0.4.10

Published

SDK for building apps for the Bardioc OS

Readme

@bardioc/app-sdk

SDK and Vite integration for building apps for the Bardioc OS.

This package focuses on the runtime SDK and Vite plugin only:

  1. Bridge communication between an app and the OS, IndexedDB, and host APIs.
  2. Validate app manifests and wire Vite apps for iframe-based development.

Requirements

  • Node.js >=20.19.0
  • TypeScript >=6.0.0
  • For React apps, install react and react-dom in the consuming project

Install into an existing project

pnpm add @bardioc/app-sdk

Apps can be developed independently outside the Bardioc OS and then tested through a live AppStore development session. That keeps the local development loop fast while still exercising the real host communication path.

Quick start

import { AppSdkProvider, useNotify } from '@bardioc/app-sdk/react';
import { createRoot } from 'react-dom/client';

function App() {
  const notify = useNotify();

  function sayHello() {
    notify('Hello from my app', 'success');
  }

  return <button onClick={sayHello}>Say hello</button>;
}

const isInsideIframe = globalThis.window.parent !== globalThis.window;

createRoot(document.getElementById('root')!).render(
  isInsideIframe ? (
    <AppSdkProvider appId="my-app">
      <App />
    </AppSdkProvider>
  ) : (
    <div>Open this app from the Bardioc OS dock to use SDK features.</div>
  )
);

Exports

| Path | Contents | | --------------------------- | ------------------------------------------- | | @bardioc/app-sdk | createHostBridge, errors, types, manifest | | @bardioc/app-sdk/react | AppSdkProvider, hooks (useSdk, etc.) | | @bardioc/app-sdk/dev | standalone dev bridge helpers | | @bardioc/app-sdk/types | Type-only TypeScript exports | | @bardioc/app-sdk/protocol | SDK_MSG constants, wire format types | | @bardioc/app-sdk/vite | bardiocApp() Vite plugin |

Key exports

// Bridge and types
import {
  createHostBridge,
  type HostBridge,
  type HostBridgeConfig,
  type GraphNodeRaw,
  type GraphEdgeRaw,
  type UserProfile,
  type OrgStructure,
} from '@bardioc/app-sdk';

// Errors
import {
  EntityNotFoundError,
  ValidationError,
  PermissionError,
  TimeoutError,
  NetworkError,
  SdkError,
} from '@bardioc/app-sdk';

// React hooks
import { AppSdkProvider, useSdk, useNotify, useSendToKernel } from '@bardioc/app-sdk/react';

// Standalone dev helpers
import { installDevBridge, isDevStandalone, isInsideIframe } from '@bardioc/app-sdk/dev';

Vite plugin

// vite.config.ts
import { bardiocApp } from '@bardioc/app-sdk/vite';
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [react(), bardiocApp({ appName: 'my-app', port: 3005 })],
});

Handles dev base path, port config, host session proxy routes, platform fonts, and manifest validation on build.

Platform fonts

The Bardioc platform guarantees a stable font endpoint wherever an app runs — like /api/transport, it is a public contract that will never be renamed or removed. Load it with one line in index.html and do not bundle font packages into your app:

<link rel="stylesheet" href="/fonts/bardioc-fonts.css" />

It provides Nunito Sans Variable (normal + italic) and Geist Mono Variable as variable fonts (latin subset), matching the --font-nunito-sans / --font-geist-mono theme variables that @bardioc/ui resolves by default.

  • Embedded in the OS the URL resolves same-origin against the host, which serves it with immutable caching — one download shared by the host and every app.
  • Standalone dev the bardiocApp() plugin serves the same files from assets shipped inside this package (dev server only — they are never added to your bundle). This applies to Vite-based apps; the angular and nextjs templates run their own dev servers, where the link is a harmless 404 standalone and resolves normally embedded in the OS.

New apps scaffolded with create-bardioc-app include the <link> already.

Standalone Dev Session

Standalone local development is host-backed only.

  1. Set DEV_SECRET and API_BASE_URL in your local .env.
  2. Run pnpm dev.

The Vite plugin proxies /rest/* requests to API_BASE_URL with the X-Dev-Secret header, and installDevBridge() handles SDK messages when running in standalone dev.

Dev servers that cannot host the Vite plugin (angular, nextjs) run the same proxy as a standalone server:

import { startDevAuthProxy } from '@bardioc/app-sdk/dev-proxy';

// Reads DEV_SECRET / API_BASE_URL from the project's .env files; resolves to null when unset.
await startDevAuthProxy({ projectDir: process.cwd(), port: 3105 });

Point the app at it with installDevBridge({ apiBaseUrl: 'http://127.0.0.1:3105/rest' }).

React hooks

  • useSdk() — raw bridge instance
  • useNotify() — fire-and-forget toast
  • useSendToKernel() — proxy a whitelisted message to the OS service worker

IndexedDB persistence

useSdk() exposes bridge.idb(storeName) for app-scoped persistence:

const drafts = bridge.idb('drafts');

await drafts.put('welcome', {
  title: 'Q2 rollout',
  summary: 'Publish SDK changes before updating the host workspace.',
});
const draft = await drafts.get<{ title: string; summary: string }>('welcome');
const items = await drafts.query({ prefix: 'wel', limit: 20 });
await drafts.delete('welcome');

Each handle is scoped by the host to the app's manifest id, so two apps can use the same storeName without colliding.

Transport API

The bridge provides namespaced transport APIs for graph database and OS operations.

Note: For multiple graph/OS instances or contexts, the Host OS is responsible for routing requests. The SDK proxies all transport requests to the host via postMessage - one bridge = one iframe = one host connection.

Graph API

Access the graph database via bridge.transport.graph.*:

const sdk = useSdk();

// Get single node
const node = await sdk.transport.graph.get<GraphNodeRaw>('node-id');

// Query with Lucene
const people = await sdk.transport.graph.query<GraphNodeRaw>(
  'ogit/_type:ogit/Person AND ogit/name:John*',
  { limit: 50, offset: 0, scopeId: 'instance-scope-id' }
);

// Gremlin traversal
const edges = await sdk.transport.graph.gremlin(rootId, "outE('ogit/relates')");

// Create node
const newNode = await sdk.transport.graph.create('ogit/Person', {
  'ogit/name': 'Jane Doe',
  'ogit/email': '[email protected]',
});

// Update node
await sdk.transport.graph.update('node-id', {
  'ogit/name': 'Updated Name',
});

// Create edge
await sdk.transport.graph.connect(fromId, toId, 'ogit/relates');

// Delete node
await sdk.transport.graph.delete('node-id');

// Combined query: Elasticsearch picks the start vertices, Gremlin traverses from them
const speeches = await sdk.transport.graph.combined(
  '+(ogit\\/_type: "ogit/Politics/AgendaItem")',
  "inE().outV().has('ogit/_type', 'ogit/Politics/Discussion')",
  { limit: 1000 }
);

// Time series
const values = await sdk.transport.graph.timeseries.get('ts-id', {
  from: '2026-01-01',
  to: '2026-01-31',
});

// Several series in one request, averaged per timestamp
const merged = await sdk.transport.graph.timeseries.get('ts-id', {
  from: '2026-01-01',
  to: '2026-01-31',
  withIds: ['ts-id-2', 'ts-id-3'],
  aggregate: 'avg',
});

Available methods: get, getMany, getByXid, query, gremlin, combined, create, update, delete, connect, history, batch.delete, timeseries.get, timeseries.add, timeseries.query, timeseries.history, content.set, content.get.

combined and multi-ID time series reads both return one flat result set: a combined query carries no marker for which start vertex a row came from (label and select() in the traversal when you need it), and time series entries carry only timestamp and value (read one ID per request when values must stay attributable).

All graph request option types accept optional scopeId when a request must target a specific scope.

OS API

Access OS features via bridge.transport.os.*:

const sdk = useSdk();

// User profile
const profile = await sdk.transport.os.profile.get();
const avatar = await sdk.transport.os.profile.getAvatar();
await sdk.transport.os.profile.setAvatar(imageBlob);

// Organization
const org = await sdk.transport.os.organization.getStructure();
const unit = await sdk.transport.os.organization.createUnit({
  name: 'Engineering',
  parentId: 'parent-unit-id',
});

// Applications
const apps = await sdk.transport.os.applications.list();
const app = await sdk.transport.os.applications.get('app-id');
await sdk.transport.os.applications.upload('app-id', zipBlob);
await sdk.transport.os.request({
  path: '/custom/endpoint',
  method: 'GET',
  scopeId: 'instance-scope-id',
});

Available namespaces:

  • os.profile.*get, getAvatar, setAvatar, getInstances
  • os.organization.*getStructure, createUnit, updateUnit, createMember, updateMember, deleteMember, inviteMember
  • os.applications.*list, get, upload, download, getFiles, getFile, getConfigurations

Error handling

All transport methods throw structured errors:

import {
  EntityNotFoundError,
  ValidationError,
  PermissionError,
  TimeoutError,
  NetworkError,
  SdkError,
} from '@bardioc/app-sdk';

try {
  const node = await sdk.transport.graph.get('node-id');
} catch (error) {
  if (error instanceof EntityNotFoundError) {
    console.log('Node not found:', error.context.id);
  } else if (error instanceof ValidationError) {
    console.log('Invalid data:', error.context?.field);
  } else if (error instanceof PermissionError) {
    console.log('Missing permission:', error.context.permission);
  } else if (error instanceof TimeoutError) {
    console.log('Request timed out:', error.context.operation);
  } else if (error instanceof NetworkError) {
    console.log('Network error:', error.statusCode, error.message);
  }
}

All errors extend SdkError with properties: code, statusCode, context, message.

App manifest

Every app must include public/app-manifest.json:

{
  "manifestVersion": 2,
  "id": "my-app",
  "name": "My App",
  "version": "1.0.0",
  "permissions": ["notify", "transport"]
}

Available permissions:

  • notify — Show toast notifications via bridge.notify()
  • storage — Key-value storage via bridge.storage.*
  • indexdb — App-scoped IndexedDB via bridge.idb()
  • kernel-proxy — Message the OS service worker via bridge.sendToKernel()
  • transport — Access graph and OS APIs via bridge.transport.*

The Vite plugin validates this automatically and fails the build when the manifest is missing or invalid.

Window

Optionally control how the OS frames the app via a window block:

{
  "manifestVersion": 2,
  "id": "my-app",
  "name": "My App",
  "version": "1.0.0",
  "permissions": ["notify"],
  "window": {
    "size": "md",
    "resizable": true
  }
}

size picks a tier (default md):

| Tier | Size (w × h) | Min (w × h) | | ---- | ------------ | ----------- | | xs | 480 × 320 | 360 × 280 | | sm | 640 × 480 | 480 × 320 | | md | 800 × 600 | 480 × 320 | | lg | 1024 × 800 | 640 × 480 | | xl | 1280 × 800 | 800 × 600 |

Instead of a tier, size may be a custom dimensions object — { width, height } (px), with optional minWidth/minHeight (each defaults to a floor when omitted). Custom dimensions are literal, so orientation does not swap them:

{
  "window": { "size": { "width": 720, "height": 540, "minWidth": 400, "minHeight": 300 } }
}

Other flags (all optional booleans): canHaveMultipleWindows, isInstanceAware, resizable, maximizable, minimizable, customScroll, centered, isHeaderless.

Support

For support, contact [email protected].

License

MIT.

Copyright (c) 2026 ALMATO AG. All rights reserved.

This is an internal library for ALMATO AG.