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

@brownandroot/api

v3.4.0

Published

Unified TypeScript API for Brown & Root APIHub data.

Readme

@brownandroot/api

Unified TypeScript API for Brown & Root APIHub data.

Installation

bun add @brownandroot/api

One Import Path

Use only:

import { employees, workorders, clearCache } from '@brownandroot/api'

No domain subpath imports are required.

Setup

Add to your app .env:

APIHUB_URL=https://your-apihub-url.com
APIHUB_API_KEY=your-api-key

Enable SvelteKit remote functions if needed:

kit: {
	experimental: {
		remoteFunctions: true
	}
}

Unified Domain Contract

Each listable domain exposes the same shape:

  • getAll(filters?)
  • getDropdown(filters?)
  • get(id) -> returns item or null

dropdown(filters?) remains available as a backward-compatible alias.

Domains:

  • employees
  • workorders
  • costcodes
  • paytypes
  • businessUnits
  • jobtypejobsteps
  • chat
  • llm
  • rag

Caching Behavior

  • Browser/client: IndexedDB stale-while-revalidate cache for getAll and dropdown
  • Server/SSR: in-memory TTL cache for getAll and dropdown
  • Single-record get(id) reads are fresh and return null when not found
  • Read failures in SSR fail open by default in unified domain APIs:
    • list reads return []
    • single reads return null
    • chain/lookup helpers return safe empty defaults

Error Diagnostics

The package now throws structured ApiHubError instances for request-layer failures.

ApiHubError includes:

  • status
  • path
  • url
  • responseBody
  • retriable
  • service

Request layer behavior:

  • timeout with AbortController (default 60000ms)
  • retries for idempotent GETs on 429/502/503/504 (default retryCount: 2)
  • optional onError callback via ApiHubClient options

Dropdown defaults:

  • Domains with isActive automatically default isActive: true for getDropdown(filters?)
  • Caller can override by passing isActive explicitly

Examples

Workorders

import { workorders } from '@brownandroot/api'

const rows = await workorders.getAll({ businessUnitId: 'BU001' })
const options = await workorders.getDropdown({ businessUnitId: 'BU001' })
const one = await workorders.get('WO001') // Workorder | null

Employees

import { employees } from '@brownandroot/api'

const crew = await employees.getAll({ hbu: 'TX01', q: 'john' })
const list = await employees.getDropdown({ businessUnitId: 'BU001' })
const emp = await employees.get('12345')

const privileged = await employees.getPrivileged('12345')
const chain = await employees.getSupervisorChain('12345')
const jde = await employees.getJdeFromEmail('[email protected]')
const verified = await employees.verifyIdentity({
	first3FirstName: 'joh',
	first3LastName: 'doe',
	dob: '1985-03-15',
	ssn4: '4321',
})

Chat

import { chat, rag } from '@brownandroot/api'

const result = await chat.complete({
	messages: [{ role: 'user', content: 'What tools do you have?' }],
	grounded: true,
})

console.log(result.message.content)
console.log(result.trace.toolCalls)

for await (const event of chat.stream({
	messages: [{ role: 'user', content: 'Summarize the overtime policy.' }],
})) {
	if (event.type === 'delta') {
		process.stdout.write(event.chunk)
	}
}

chat.complete and chat.stream are server-side APIs. They read API Hub credentials from APIHUB_URL and APIHUB_API_KEY by default, so consuming apps do not need to manually construct an ApiHubClient for the common case.

Chat request options:

  • grounded — default true; enables Brown & Root grounded chat behavior, including knowledge retrieval and the default tool bundle
  • instructions — appended to the default system prompt
  • systemPrompt — fully replaces the default system prompt
  • userContext — optional personalization context
  • source — optional application identifier for logging

Default grounded tool bundle includes:

  • searchDocs
  • searchDocsByType
  • listKnowledgeDocuments
  • searchBusinessUnits
  • searchWorkOrders
  • searchAppCatalog
  • searchAppCatalogRecords
  • getAppCatalogOverview

When the user asks broad app catalog questions (for example, "what is the app catalog" or "show everything in the app catalog"), the stream agent now prefers getAppCatalogOverview before generating the final response.

If systemPrompt is provided, it takes precedence over instructions.

Legacy LLM and RAG

import { llm, rag } from '@brownandroot/api'

const logs = await llm.getLogs()
const chat = await llm.chat({
	messages: [{ role: 'user', content: 'Summarize this document.' }],
	source: 'my-app',
	user: 'jane.doe',
	enableRag: true,
})

const docs = await rag.list()
const results = await rag.search({ query: 'overtime policy', topK: 5 })

llm.chat remains available for lower-level request/response usage.

llm.chat RAG flags:

  • enableRag: true tells the backend to enrich the chat prompt with retrieved document context before generating a response.
  • enableRag: false (or omitted) sends a normal chat request without forcing retrieval augmentation.
  • enableRag is the single supported parameter for toggling default tools/RAG retrieval.

Cache Management

import { clearCache } from '@brownandroot/api'

clearCache()
clearCache('workorders')
clearCache('employees')

Call clearCache(entity) after mutations so next reads fetch fresh data.

Advanced Direct Client

ApiHubClient is still available for advanced usage (streaming/proxy control/custom behavior):

import { ApiHubClient } from '@brownandroot/api'

const client = new ApiHubClient({
	baseUrl: process.env.APIHUB_URL!,
	apiKey: process.env.APIHUB_API_KEY!,
})

You can also let the package resolve those env vars for you:

import { getApiHubClientFromEnv } from '@brownandroot/api'

const client = getApiHubClientFromEnv()