@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/apiOne 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-keyEnable 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 ornull
dropdown(filters?) remains available as a backward-compatible alias.
Domains:
employeesworkorderscostcodespaytypesbusinessUnitsjobtypejobstepschatllmrag
Caching Behavior
- Browser/client: IndexedDB stale-while-revalidate cache for
getAllanddropdown - Server/SSR: in-memory TTL cache for
getAllanddropdown - Single-record
get(id)reads are fresh and returnnullwhen 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
- list reads return
Error Diagnostics
The package now throws structured ApiHubError instances for request-layer failures.
ApiHubError includes:
statuspathurlresponseBodyretriableservice
Request layer behavior:
- timeout with
AbortController(default60000ms) - retries for idempotent GETs on
429/502/503/504(defaultretryCount: 2) - optional
onErrorcallback viaApiHubClientoptions
Dropdown defaults:
- Domains with
isActiveautomatically defaultisActive: trueforgetDropdown(filters?) - Caller can override by passing
isActiveexplicitly
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 | nullEmployees
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— defaulttrue; enables Brown & Root grounded chat behavior, including knowledge retrieval and the default tool bundleinstructions— appended to the default system promptsystemPrompt— fully replaces the default system promptuserContext— optional personalization contextsource— optional application identifier for logging
Default grounded tool bundle includes:
searchDocssearchDocsByTypelistKnowledgeDocumentssearchBusinessUnitssearchWorkOrderssearchAppCatalogsearchAppCatalogRecordsgetAppCatalogOverview
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: truetells 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.enableRagis 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()