@brownandroot/api 1.2.1 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -469
- package/dist/businessUnits.remote.d.ts +1 -1
- package/dist/businessUnits.remote.js +16 -1
- package/dist/cache.d.ts +51 -28
- package/dist/cache.js +193 -39
- package/dist/costcodes.remote.d.ts +1 -1
- package/dist/costcodes.remote.js +16 -1
- package/dist/employees.remote.d.ts +1 -1
- package/dist/employees.remote.js +16 -1
- package/dist/index.d.ts +63 -1
- package/dist/index.js +133 -14
- package/dist/jobtypejobsteps.remote.d.ts +1 -1
- package/dist/jobtypejobsteps.remote.js +16 -1
- package/dist/llm.remote.d.ts +1 -0
- package/dist/llm.remote.js +1 -0
- package/dist/paytypes.remote.d.ts +1 -1
- package/dist/paytypes.remote.js +16 -1
- package/dist/workorders.remote.d.ts +1 -1
- package/dist/workorders.remote.js +16 -1
- package/package.json +1 -37
package/README.md
CHANGED
|
@@ -1,31 +1,33 @@
|
|
|
1
1
|
# @brownandroot/api
|
|
2
2
|
|
|
3
|
-
TypeScript
|
|
3
|
+
Unified TypeScript API for Brown & Root APIHub data.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
|
|
8
|
+
bun add @brownandroot/api
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
## One Import Path
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Use only:
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
```ts
|
|
16
|
+
import { employees, workorders, clearCache } from '@brownandroot/api'
|
|
17
|
+
```
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
No domain subpath imports are required.
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
## Setup
|
|
20
22
|
|
|
21
|
-
Add to your app
|
|
23
|
+
Add to your app `.env`:
|
|
22
24
|
|
|
23
|
-
```
|
|
25
|
+
```bash
|
|
24
26
|
APIHUB_URL=https://your-apihub-url.com
|
|
25
27
|
APIHUB_API_KEY=your-api-key
|
|
26
28
|
```
|
|
27
29
|
|
|
28
|
-
Enable remote functions
|
|
30
|
+
Enable SvelteKit remote functions if needed:
|
|
29
31
|
|
|
30
32
|
```js
|
|
31
33
|
kit: {
|
|
@@ -35,511 +37,135 @@ kit: {
|
|
|
35
37
|
}
|
|
36
38
|
```
|
|
37
39
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
```svelte
|
|
41
|
-
<script lang="ts">
|
|
42
|
-
import { getWorkordersDropdown, getEmployees, clearCache } from '@brownandroot/api/cache'
|
|
43
|
-
|
|
44
|
-
// First page load: fetches from server and caches in IndexedDB.
|
|
45
|
-
// Subsequent loads: returns from IndexedDB instantly, refreshes in background.
|
|
46
|
-
const workorders = $derived(await getWorkordersDropdown({ businessUnitId: 'BU001' }))
|
|
47
|
-
|
|
48
|
-
// Multiple filters compose freely
|
|
49
|
-
const employees = $derived(await getEmployees({
|
|
50
|
-
hbu: 'TX01',
|
|
51
|
-
payClass: 'H',
|
|
52
|
-
q: 'john',
|
|
53
|
-
}))
|
|
54
|
-
|
|
55
|
-
// After a mutation, clear the affected entity so the next read re-fetches
|
|
56
|
-
async function onCreate() {
|
|
57
|
-
await createWorkorder(formData)
|
|
58
|
-
clearCache('workorders')
|
|
59
|
-
}
|
|
60
|
-
</script>
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
### Filter reference
|
|
64
|
-
|
|
65
|
-
All filter fields are optional. Omit the filter object entirely to return all records.
|
|
66
|
-
|
|
67
|
-
#### Workorders
|
|
68
|
-
|
|
69
|
-
```typescript
|
|
70
|
-
import { getWorkorders, getWorkordersDropdown } from '@brownandroot/api/cache'
|
|
71
|
-
|
|
72
|
-
interface WorkorderFilters {
|
|
73
|
-
businessUnitId?: string // exact match
|
|
74
|
-
costCodeId?: string // exact match
|
|
75
|
-
isActive?: boolean // exact match
|
|
76
|
-
completed?: boolean // exact match
|
|
77
|
-
area?: string // exact match
|
|
78
|
-
parentWorkOrder?: string // exact match
|
|
79
|
-
q?: string // partial match on description or clientWorkOrderId
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Returns Workorder[]
|
|
83
|
-
const all = await getWorkorders()
|
|
84
|
-
const active = await getWorkorders({ isActive: true })
|
|
85
|
-
const byBu = await getWorkorders({ businessUnitId: 'BU001', isActive: true })
|
|
86
|
-
const search = await getWorkorders({ q: 'pipe' })
|
|
87
|
-
|
|
88
|
-
// Returns { value, label }[] — always applies isActive: true by default
|
|
89
|
-
const dropdown = await getWorkordersDropdown({ businessUnitId: 'BU001' })
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
#### Employees
|
|
93
|
-
|
|
94
|
-
```typescript
|
|
95
|
-
import { getEmployees, getEmployeesDropdown } from '@brownandroot/api/cache'
|
|
96
|
-
|
|
97
|
-
interface EmployeeFilters {
|
|
98
|
-
businessUnitId?: string // exact match
|
|
99
|
-
hbu?: string // exact match on home business unit
|
|
100
|
-
supervisor?: string // exact match on supervisor employee ID
|
|
101
|
-
payClass?: string // exact match
|
|
102
|
-
jobType?: string // exact match
|
|
103
|
-
jobStep?: string // exact match
|
|
104
|
-
sector?: string // exact match
|
|
105
|
-
division?: string // exact match
|
|
106
|
-
q?: string // partial match on name or email
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const byHbu = await getEmployees({ hbu: 'TX01' })
|
|
110
|
-
const byName = await getEmployees({ q: 'john' })
|
|
111
|
-
const dropdown = await getEmployeesDropdown({ businessUnitId: 'BU001' })
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
#### Cost Codes
|
|
115
|
-
|
|
116
|
-
```typescript
|
|
117
|
-
import { getCostcodes, getCostcodesDropdown } from '@brownandroot/api/cache'
|
|
118
|
-
|
|
119
|
-
interface CostcodeFilters {
|
|
120
|
-
businessUnitId?: string // exact match
|
|
121
|
-
isActive?: boolean // exact match
|
|
122
|
-
entryFlag?: boolean // exact match
|
|
123
|
-
payTypeCode?: string // resolves pay type → objectAccount, filters by match
|
|
124
|
-
q?: string // partial match on description or jdeCostCode
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const byBu = await getCostcodes({ businessUnitId: 'BU001' })
|
|
128
|
-
const search = await getCostcodes({ q: 'labor' })
|
|
129
|
-
|
|
130
|
-
// Dropdown applies isActive: true and entryFlag: true by default,
|
|
131
|
-
// and also excludes expired cost codes
|
|
132
|
-
const dropdown = await getCostcodesDropdown({ businessUnitId: 'BU001' })
|
|
133
|
-
const dropdownByPayType = await getCostcodesDropdown({
|
|
134
|
-
businessUnitId: 'BU001',
|
|
135
|
-
payTypeCode: 'PT01',
|
|
136
|
-
})
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
> **payTypeCode cross-reference:** When `payTypeCode` is set, the filter looks up that pay type's `objectAccount` from the (also cached) pay types list and only returns cost codes whose `objectAccount` matches. If the pay type has no `objectAccount`, all cost codes pass this filter.
|
|
140
|
-
|
|
141
|
-
#### Pay Types
|
|
142
|
-
|
|
143
|
-
```typescript
|
|
144
|
-
import { getPaytypes, getPaytypesDropdown } from '@brownandroot/api/cache'
|
|
145
|
-
|
|
146
|
-
interface PaytypeFilters {
|
|
147
|
-
payClass?: string // exact match
|
|
148
|
-
category?: string // exact match
|
|
149
|
-
type?: string // exact match
|
|
150
|
-
isActive?: boolean // exact match
|
|
151
|
-
perDiemPayType?: boolean // exact match
|
|
152
|
-
q?: string // partial match on description
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const hourly = await getPaytypes({ payClass: 'H' })
|
|
156
|
-
const dropdown = await getPaytypesDropdown({ isActive: true })
|
|
157
|
-
// Dropdown returns { value, label, payClass }[]
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
#### Business Units
|
|
161
|
-
|
|
162
|
-
```typescript
|
|
163
|
-
import { getBusinessUnits, getBusinessUnitsDropdown } from '@brownandroot/api/cache'
|
|
164
|
-
|
|
165
|
-
interface BusinessUnitFilters {
|
|
166
|
-
subsector?: string // exact match
|
|
167
|
-
isActive?: boolean // exact match
|
|
168
|
-
clientId?: string // exact match
|
|
169
|
-
q?: string // partial match on description or clientDescription
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const active = await getBusinessUnits({ isActive: true })
|
|
173
|
-
const dropdown = await getBusinessUnitsDropdown({ subsector: 'Gulf Coast' })
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
#### Job Type / Job Steps
|
|
177
|
-
|
|
178
|
-
```typescript
|
|
179
|
-
import { getJobtypejobsteps, getJobtypejobstepsDropdown } from '@brownandroot/api/cache'
|
|
180
|
-
|
|
181
|
-
interface JobtypejobstepFilters {
|
|
182
|
-
jobType?: string // exact match
|
|
183
|
-
payclass?: string // exact match
|
|
184
|
-
isActive?: boolean // exact match
|
|
185
|
-
grp?: string // exact match
|
|
186
|
-
q?: string // partial match on description, jobType, or jobStep
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
const welders = await getJobtypejobsteps({ jobType: 'WE' })
|
|
190
|
-
const dropdown = await getJobtypejobstepsDropdown({ isActive: true })
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
### Single-record lookups
|
|
194
|
-
|
|
195
|
-
Single-record functions always fetch fresh from the server (no IndexedDB):
|
|
196
|
-
|
|
197
|
-
```typescript
|
|
198
|
-
import {
|
|
199
|
-
getEmployee,
|
|
200
|
-
getSupervisorChain,
|
|
201
|
-
getJdeFromEmail,
|
|
202
|
-
verifyIdentity,
|
|
203
|
-
getWorkorder,
|
|
204
|
-
getCostcode,
|
|
205
|
-
getPaytype,
|
|
206
|
-
getBusinessUnit,
|
|
207
|
-
getJobtypejobstep,
|
|
208
|
-
} from '@brownandroot/api/cache'
|
|
209
|
-
|
|
210
|
-
const emp = await getEmployee('12345')
|
|
211
|
-
const chain = await getSupervisorChain('12345')
|
|
212
|
-
const { jde, employee } = await getJdeFromEmail('john@example.com')
|
|
213
|
-
const verified = await verifyIdentity({
|
|
214
|
-
first3FirstName: 'joh',
|
|
215
|
-
first3LastName: 'doe',
|
|
216
|
-
dob: '1985-03-15',
|
|
217
|
-
ssn4: '4321',
|
|
218
|
-
})
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
### Cache management
|
|
222
|
-
|
|
223
|
-
```typescript
|
|
224
|
-
import { clearCache } from '@brownandroot/api/cache'
|
|
225
|
-
|
|
226
|
-
clearCache() // clear all entities
|
|
227
|
-
clearCache('workorders') // clear a specific entity
|
|
228
|
-
clearCache('employees')
|
|
229
|
-
clearCache('costcodes')
|
|
230
|
-
clearCache('paytypes')
|
|
231
|
-
clearCache('businessUnits')
|
|
232
|
-
clearCache('jobtypejobsteps')
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
Call `clearCache(entity)` immediately after any mutation that changes that entity so the next read fetches fresh data.
|
|
40
|
+
## Unified Domain Contract
|
|
236
41
|
|
|
237
|
-
|
|
42
|
+
Each listable domain exposes the same shape:
|
|
238
43
|
|
|
239
|
-
|
|
44
|
+
- `getAll(filters?)`
|
|
45
|
+
- `dropdown(filters?)`
|
|
46
|
+
- `get(id)` -> returns item or `null`
|
|
240
47
|
|
|
241
|
-
|
|
48
|
+
Domains:
|
|
242
49
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
50
|
+
- `employees`
|
|
51
|
+
- `workorders`
|
|
52
|
+
- `costcodes`
|
|
53
|
+
- `paytypes`
|
|
54
|
+
- `businessUnits`
|
|
55
|
+
- `jobtypejobsteps`
|
|
56
|
+
- `llm`
|
|
57
|
+
- `rag`
|
|
247
58
|
|
|
248
|
-
|
|
249
|
-
const employees = $derived(await getEmployees())
|
|
250
|
-
const businessUnits = $derived(await getBusinessUnits())
|
|
251
|
-
</script>
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
Or compose with your own remote functions:
|
|
59
|
+
## Caching Behavior
|
|
255
60
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
61
|
+
- Browser/client: IndexedDB stale-while-revalidate cache for `getAll` and `dropdown`
|
|
62
|
+
- Server/SSR: in-memory TTL cache for `getAll` and `dropdown`
|
|
63
|
+
- Single-record `get(id)` reads are fresh and return `null` when not found
|
|
64
|
+
- Read failures in SSR fail open by default in unified domain APIs:
|
|
65
|
+
- list reads return `[]`
|
|
66
|
+
- single reads return `null`
|
|
67
|
+
- chain/lookup helpers return safe empty defaults
|
|
259
68
|
|
|
260
|
-
|
|
261
|
-
return (await getSupervisorChain('12345')).slice(0, 2)
|
|
262
|
-
})
|
|
263
|
-
```
|
|
69
|
+
## Error Diagnostics
|
|
264
70
|
|
|
265
|
-
|
|
71
|
+
The package now throws structured `ApiHubError` instances for request-layer failures.
|
|
266
72
|
|
|
267
|
-
|
|
73
|
+
`ApiHubError` includes:
|
|
268
74
|
|
|
269
|
-
|
|
75
|
+
- `status`
|
|
76
|
+
- `path`
|
|
77
|
+
- `url`
|
|
78
|
+
- `responseBody`
|
|
79
|
+
- `retriable`
|
|
80
|
+
- `service`
|
|
270
81
|
|
|
271
|
-
|
|
82
|
+
Request layer behavior:
|
|
272
83
|
|
|
273
|
-
|
|
84
|
+
- timeout with `AbortController` (default `10000ms`)
|
|
85
|
+
- retries for idempotent GETs on `429/502/503/504` (default `retryCount: 2`)
|
|
86
|
+
- optional `onError` callback via `ApiHubClient` options
|
|
274
87
|
|
|
275
|
-
|
|
88
|
+
Dropdown defaults:
|
|
276
89
|
|
|
277
|
-
|
|
278
|
-
|
|
90
|
+
- Domains with `isActive` automatically default `isActive: true` for `dropdown(filters?)`
|
|
91
|
+
- Caller can override by passing `isActive` explicitly
|
|
279
92
|
|
|
280
|
-
|
|
281
|
-
baseUrl: 'https://your-apihub-url.com',
|
|
282
|
-
apiKey: 'your-api-key',
|
|
283
|
-
cacheTtl: 5 * 60 * 1000, // optional, default 5 minutes (0 to disable)
|
|
284
|
-
})
|
|
285
|
-
```
|
|
93
|
+
## Examples
|
|
286
94
|
|
|
287
|
-
|
|
95
|
+
### Workorders
|
|
288
96
|
|
|
289
|
-
|
|
97
|
+
```ts
|
|
98
|
+
import { workorders } from '@brownandroot/api'
|
|
290
99
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
const employees = await client.getEmployees()
|
|
295
|
-
const dropdown = await client.getEmployeesDropdown() // { value: employeeId, label: name }[]
|
|
296
|
-
const employee = await client.getEmployee('12345') // throws if not found
|
|
297
|
-
const employeePrivileged = await client.getEmployeePrivileged('12345') // includes hourlyRate and annualSalary
|
|
100
|
+
const rows = await workorders.getAll({ businessUnitId: 'BU001' })
|
|
101
|
+
const options = await workorders.dropdown({ businessUnitId: 'BU001' })
|
|
102
|
+
const one = await workorders.get('WO001') // Workorder | null
|
|
298
103
|
```
|
|
299
104
|
|
|
300
|
-
###
|
|
301
|
-
|
|
302
|
-
```typescript
|
|
303
|
-
const chain = await client.getSupervisorChain('12345')
|
|
304
|
-
```
|
|
105
|
+
### Employees
|
|
305
106
|
|
|
306
|
-
|
|
107
|
+
```ts
|
|
108
|
+
import { employees } from '@brownandroot/api'
|
|
307
109
|
|
|
308
|
-
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
// employee: Employee | null
|
|
312
|
-
```
|
|
110
|
+
const crew = await employees.getAll({ hbu: 'TX01', q: 'john' })
|
|
111
|
+
const list = await employees.dropdown({ businessUnitId: 'BU001' })
|
|
112
|
+
const emp = await employees.get('12345')
|
|
313
113
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
const
|
|
114
|
+
const privileged = await employees.getPrivileged('12345')
|
|
115
|
+
const chain = await employees.getSupervisorChain('12345')
|
|
116
|
+
const jde = await employees.getJdeFromEmail('john@example.com')
|
|
117
|
+
const verified = await employees.verifyIdentity({
|
|
318
118
|
first3FirstName: 'joh',
|
|
319
119
|
first3LastName: 'doe',
|
|
320
120
|
dob: '1985-03-15',
|
|
321
121
|
ssn4: '4321',
|
|
322
122
|
})
|
|
323
|
-
// Employee on match, null on no match
|
|
324
|
-
// Throws on 400 (missing fields) or 503 (not configured server-side)
|
|
325
123
|
```
|
|
326
124
|
|
|
327
|
-
###
|
|
328
|
-
|
|
329
|
-
```typescript
|
|
330
|
-
interface Employee {
|
|
331
|
-
employeeId: string
|
|
332
|
-
name: string | null
|
|
333
|
-
email: string | null
|
|
334
|
-
personalEmail: string | null
|
|
335
|
-
clientEmail: string | null
|
|
336
|
-
workEmail: string | null
|
|
337
|
-
badgeNumber: string | null
|
|
338
|
-
nccerNumber: string | null
|
|
339
|
-
company: string | null
|
|
340
|
-
businessUnitId: string | null
|
|
341
|
-
hbu: string | null
|
|
342
|
-
departmentCode: string | null
|
|
343
|
-
division: string | null
|
|
344
|
-
sector: string | null
|
|
345
|
-
subsector: string | null
|
|
346
|
-
phone: string | null
|
|
347
|
-
employementStatus: string | null
|
|
348
|
-
employeePayStatus: string | null
|
|
349
|
-
recordType: string | null
|
|
350
|
-
jobType: string | null
|
|
351
|
-
jobStep: string | null
|
|
352
|
-
jobDescription: string | null
|
|
353
|
-
workSchedule: string | null
|
|
354
|
-
shift: string | null
|
|
355
|
-
payClass: string | null
|
|
356
|
-
payFrequency: string | null
|
|
357
|
-
payCycleCode: string | null
|
|
358
|
-
checkRouteCode: string | null
|
|
359
|
-
residentTaxArea: string | null
|
|
360
|
-
workTaxArea: string | null
|
|
361
|
-
benefitGroup: string | null
|
|
362
|
-
topFlexPtoDate: string | null
|
|
363
|
-
clientPtoDate: string | null
|
|
364
|
-
securityLevel: string | null
|
|
365
|
-
reportingLevel: string | null
|
|
366
|
-
supervisor: string | null
|
|
367
|
-
mentor: string | null
|
|
368
|
-
hireDate: string | null
|
|
369
|
-
termDate: string | null
|
|
370
|
-
adjustedServiceDate: string | null
|
|
371
|
-
identityHash: string | null
|
|
372
|
-
source: string | null
|
|
373
|
-
createdAt: string | null
|
|
374
|
-
updatedAtJulian: number | null
|
|
375
|
-
updatedAt: string | null
|
|
376
|
-
}
|
|
125
|
+
### LLM and RAG
|
|
377
126
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
annualSalary: string | null
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
getEmployees, getEmployee, employee searches, getJdeFromEmail, and verifyIdentity all return the public Employee shape (without compensation fields). Use getEmployeePrivileged when compensation fields are required.
|
|
384
|
-
```
|
|
385
|
-
|
|
386
|
-
---
|
|
387
|
-
|
|
388
|
-
## Business Units
|
|
389
|
-
|
|
390
|
-
```typescript
|
|
391
|
-
const units = await client.getBusinessUnits()
|
|
392
|
-
const dropdown = await client.getBusinessUnitsDropdown() // { value, label }[]
|
|
393
|
-
const unit = await client.getBusinessUnit('BU001')
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
---
|
|
397
|
-
|
|
398
|
-
## Cost Codes
|
|
399
|
-
|
|
400
|
-
```typescript
|
|
401
|
-
const codes = await client.getCostcodes()
|
|
402
|
-
const dropdown = await client.getCostcodesDropdown() // { value, label }[]
|
|
403
|
-
const code = await client.getCostcode('CC001')
|
|
404
|
-
```
|
|
405
|
-
|
|
406
|
-
---
|
|
407
|
-
|
|
408
|
-
## Pay Types
|
|
409
|
-
|
|
410
|
-
```typescript
|
|
411
|
-
const types = await client.getPaytypes()
|
|
412
|
-
const dropdown = await client.getPaytypesDropdown() // { value, label, payClass }[]
|
|
413
|
-
const type = await client.getPaytype('PT001')
|
|
414
|
-
```
|
|
127
|
+
```ts
|
|
128
|
+
import { llm, rag } from '@brownandroot/api'
|
|
415
129
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
```typescript
|
|
421
|
-
const orders = await client.getWorkorders()
|
|
422
|
-
const dropdown = await client.getWorkordersDropdown() // { value, label }[]
|
|
423
|
-
const order = await client.getWorkorder('WO001')
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
---
|
|
427
|
-
|
|
428
|
-
## Job Type / Job Steps
|
|
429
|
-
|
|
430
|
-
```typescript
|
|
431
|
-
const items = await client.getJobtypejobsteps()
|
|
432
|
-
const dropdown = await client.getJobtypejobstepsDropdown() // { value, label }[]
|
|
433
|
-
const item = await client.getJobtypejobstep('JTJS001')
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
---
|
|
437
|
-
|
|
438
|
-
## LLM
|
|
439
|
-
|
|
440
|
-
### Chat completion
|
|
441
|
-
|
|
442
|
-
```typescript
|
|
443
|
-
const result = await client.chat({
|
|
444
|
-
messages: [{ role: 'user', content: 'Summarize this document...' }],
|
|
130
|
+
const logs = await llm.getLogs()
|
|
131
|
+
const chat = await llm.chat({
|
|
132
|
+
messages: [{ role: 'user', content: 'Summarize this document.' }],
|
|
445
133
|
source: 'my-app',
|
|
446
134
|
user: 'jane.doe',
|
|
447
|
-
|
|
448
|
-
temperature: 0.7,
|
|
449
|
-
maxTokens: 1000,
|
|
450
|
-
})
|
|
451
|
-
|
|
452
|
-
console.log(result.message.content)
|
|
453
|
-
console.log(result.usage) // { tokensIn, tokensOut, totalTokens }
|
|
454
|
-
```
|
|
455
|
-
|
|
456
|
-
### Streaming chat
|
|
457
|
-
|
|
458
|
-
```typescript
|
|
459
|
-
const response = await client.chatStream({
|
|
460
|
-
messages: [{ role: 'user', content: 'Hello' }],
|
|
461
|
-
userContext: { name: 'Jane Doe', department: 'Engineering', roles: ['admin'] },
|
|
462
|
-
useRag: true,
|
|
463
|
-
source: 'my-app',
|
|
135
|
+
enableRag: true,
|
|
464
136
|
})
|
|
465
|
-
// Proxy to the browser, or read the SSE stream directly
|
|
466
|
-
```
|
|
467
137
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
```typescript
|
|
471
|
-
const logs = await client.getLlmLogs() // newest first
|
|
138
|
+
const docs = await rag.list()
|
|
139
|
+
const results = await rag.search({ query: 'overtime policy', topK: 5 })
|
|
472
140
|
```
|
|
473
141
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
## Documents (RAG)
|
|
142
|
+
`llm.chat` RAG flags:
|
|
477
143
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
const results = await client.searchDocuments('overtime policy', 5)
|
|
482
|
-
// results: { chunkId, content, fileName, documentType, score }[]
|
|
483
|
-
await client.deleteDocument(doc.id)
|
|
484
|
-
```
|
|
144
|
+
- `enableRag: true` tells the backend to enrich the chat prompt with retrieved document context before generating a response.
|
|
145
|
+
- `enableRag: false` (or omitted) sends a normal chat request without forcing retrieval augmentation.
|
|
146
|
+
- `enableRag` is the single supported parameter for toggling default tools/RAG retrieval.
|
|
485
147
|
|
|
486
|
-
|
|
148
|
+
## Cache Management
|
|
487
149
|
|
|
488
|
-
|
|
150
|
+
```ts
|
|
151
|
+
import { clearCache } from '@brownandroot/api'
|
|
489
152
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
153
|
+
clearCache()
|
|
154
|
+
clearCache('workorders')
|
|
155
|
+
clearCache('employees')
|
|
493
156
|
```
|
|
494
157
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
## Types
|
|
498
|
-
|
|
499
|
-
```typescript
|
|
500
|
-
import type {
|
|
501
|
-
Employee,
|
|
502
|
-
BusinessUnit,
|
|
503
|
-
Costcode,
|
|
504
|
-
Paytype,
|
|
505
|
-
Workorder,
|
|
506
|
-
Jobtypejobstep,
|
|
507
|
-
LlmLog,
|
|
508
|
-
ChatMessage,
|
|
509
|
-
ChatRequest,
|
|
510
|
-
ChatResponse,
|
|
511
|
-
StreamChatRequest,
|
|
512
|
-
StreamChatUserContext,
|
|
513
|
-
DocumentRecord,
|
|
514
|
-
SearchResult,
|
|
515
|
-
ApiHubClientOptions,
|
|
516
|
-
DropdownOption,
|
|
517
|
-
PaytypeDropdownOption,
|
|
518
|
-
} from '@brownandroot/api'
|
|
519
|
-
|
|
520
|
-
// Filter interfaces (from cache module)
|
|
521
|
-
import type {
|
|
522
|
-
EmployeeFilters,
|
|
523
|
-
WorkorderFilters,
|
|
524
|
-
CostcodeFilters,
|
|
525
|
-
PaytypeFilters,
|
|
526
|
-
BusinessUnitFilters,
|
|
527
|
-
JobtypejobstepFilters,
|
|
528
|
-
} from '@brownandroot/api/cache'
|
|
529
|
-
```
|
|
158
|
+
Call `clearCache(entity)` after mutations so next reads fetch fresh data.
|
|
530
159
|
|
|
531
|
-
|
|
160
|
+
## Advanced Direct Client
|
|
532
161
|
|
|
533
|
-
|
|
162
|
+
`ApiHubClient` is still available for advanced usage (streaming/proxy control/custom behavior):
|
|
534
163
|
|
|
535
|
-
|
|
164
|
+
```ts
|
|
165
|
+
import { ApiHubClient } from '@brownandroot/api'
|
|
536
166
|
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
}
|
|
541
|
-
console.error(err.message) // "Employee not found"
|
|
542
|
-
}
|
|
167
|
+
const client = new ApiHubClient({
|
|
168
|
+
baseUrl: process.env.APIHUB_URL!,
|
|
169
|
+
apiKey: process.env.APIHUB_API_KEY!,
|
|
170
|
+
})
|
|
543
171
|
```
|
|
544
|
-
|
|
545
|
-
`verifyIdentity` returns `null` when no employee matches the inputs, and only throws for request errors (400, 503, network failure).
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export declare const getBusinessUnits: import("@sveltejs/kit").RemoteQueryFunction<void, import("./index.js").BusinessUnit[]>;
|
|
2
2
|
export declare const getBusinessUnitsDropdown: import("@sveltejs/kit").RemoteQueryFunction<void, import("./index.js").DropdownOption[]>;
|
|
3
|
-
export declare const getBusinessUnit: import("@sveltejs/kit").RemoteQueryFunction<string, import("./index.js").BusinessUnit>;
|
|
3
|
+
export declare const getBusinessUnit: import("@sveltejs/kit").RemoteQueryFunction<string, import("./index.js").BusinessUnit | null>;
|
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import { query } from '$app/server';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { getClient } from './client.js';
|
|
4
|
+
function isNotFoundError(error) {
|
|
5
|
+
if (!(error instanceof Error))
|
|
6
|
+
return false;
|
|
7
|
+
return /not found/i.test(error.message);
|
|
8
|
+
}
|
|
9
|
+
async function asNullable(fetcher) {
|
|
10
|
+
try {
|
|
11
|
+
return await fetcher();
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
if (isNotFoundError(error))
|
|
15
|
+
return null;
|
|
16
|
+
throw error;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
4
19
|
export const getBusinessUnits = query(async () => getClient().getBusinessUnits());
|
|
5
20
|
export const getBusinessUnitsDropdown = query(async () => getClient().getBusinessUnitsDropdown());
|
|
6
|
-
export const getBusinessUnit = query(z.string(), async (id) => getClient().getBusinessUnit(id));
|
|
21
|
+
export const getBusinessUnit = query(z.string(), async (id) => asNullable(() => getClient().getBusinessUnit(id)));
|