@brownandroot/api 0.6.0 → 0.8.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @brownandroot/api
2
2
 
3
- TypeScript client for the Brown & Root APIHub employee data service.
3
+ TypeScript client for the Brown & Root APIHub data service. Provides read-only access to company data and an LLM chat endpoint powered by Azure AI Foundry.
4
4
 
5
5
  ## Installation
6
6
 
@@ -21,47 +21,80 @@ const client = new ApiHubClient({
21
21
 
22
22
  ## Usage
23
23
 
24
- ### Get all employees
24
+ ### Employees
25
25
 
26
26
  ```typescript
27
27
  const employees = await client.getEmployees()
28
+ const employee = await client.getEmployee(12345)
29
+ const results = await client.searchByName('John')
30
+ const results = await client.searchByEmail('john@example.com')
31
+ const reports = await client.getBySupervisor(12345)
32
+ const chain = await client.getSupervisorChain(12345)
33
+ const { jde, employee } = await client.getJdeFromEmail('john@example.com')
28
34
  ```
29
35
 
30
- ### Get a single employee
36
+ ### Business Units
31
37
 
32
38
  ```typescript
33
- const employee = await client.getEmployee(12345)
39
+ const units = await client.getBusinessUnits()
40
+ const unit = await client.getBusinessUnit('BU001')
34
41
  ```
35
42
 
36
- ### Search by name
37
-
38
- Case-insensitive partial match:
43
+ ### Cost Codes
39
44
 
40
45
  ```typescript
41
- const results = await client.searchByName('John')
46
+ const codes = await client.getCostcodes()
47
+ const code = await client.getCostcode('CC001')
42
48
  ```
43
49
 
44
- ### Get employees by supervisor
50
+ ### Pay Types
45
51
 
46
52
  ```typescript
47
- const reports = await client.getBySupervisor(12345)
53
+ const types = await client.getPaytypes()
54
+ const type = await client.getPaytype('PT001')
48
55
  ```
49
56
 
50
- ### Get supervisor chain
57
+ ### Work Orders
58
+
59
+ ```typescript
60
+ const orders = await client.getWorkorders()
61
+ const order = await client.getWorkorder('WO001')
62
+ ```
51
63
 
52
- Returns the chain of supervisors above an employee (excludes the employee themselves):
64
+ ### LLM
53
65
 
54
66
  ```typescript
55
- const chain = await client.getSupervisorChain(12345)
56
- // [directSupervisor, theirSupervisor, ...]
67
+ // List logs
68
+ const logs = await client.getLlmLogs()
69
+
70
+ // Chat completion
71
+ const result = await client.chat({
72
+ messages: [{ role: 'user', content: 'Summarize this document...' }],
73
+ source: 'my-app',
74
+ user: 'jane.doe',
75
+ function: 'summarize',
76
+ })
77
+ console.log(result.message.content)
78
+ console.log(result.usage) // { tokensIn, tokensOut, totalTokens }
57
79
  ```
58
80
 
59
81
  ## Types
60
82
 
61
- The package exports the `Employee` interface and `ApiHubClientOptions`:
83
+ The package exports interfaces for all resource types:
62
84
 
63
85
  ```typescript
64
- import type { Employee, ApiHubClientOptions } from '@brownandroot/api'
86
+ import type {
87
+ Employee,
88
+ BusinessUnit,
89
+ Costcode,
90
+ Paytype,
91
+ Workorder,
92
+ LlmLog,
93
+ ChatMessage,
94
+ ChatRequest,
95
+ ChatResponse,
96
+ ApiHubClientOptions,
97
+ } from '@brownandroot/api'
65
98
  ```
66
99
 
67
100
  ## Error Handling
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * Employee type matching the API response shape.
3
3
  */
4
4
  export interface Employee {
5
- employeeId: number | null;
5
+ employeeId: string;
6
6
  name: string | null;
7
7
  email: string | null;
8
8
  badgeNumber: string | null;
@@ -26,22 +26,25 @@ export interface Employee {
26
26
  reportingLevel: string | null;
27
27
  recordType: string | null;
28
28
  payCycleCode: string | null;
29
- dateTimeStamps: string | null;
30
29
  benefitGroup: string | null;
31
- supervisor: number | null;
30
+ supervisor: string | null;
32
31
  adjustedServiceDate: string | null;
33
32
  departmentCode: string | null;
34
- dateUpdated: string | null;
35
33
  nccerNumber: string | null;
36
- mentor: number | null;
34
+ mentor: string | null;
37
35
  source: string | null;
38
36
  createdAt: string | null;
37
+ updatedAtJulian: number | null;
39
38
  updatedAt: string | null;
40
39
  }
41
40
  export interface ApiHubClientOptions {
42
41
  baseUrl: string;
43
42
  apiKey: string;
44
43
  }
44
+ export interface DropdownOption {
45
+ value: number | string;
46
+ label: string;
47
+ }
45
48
  /**
46
49
  * LLM log entry matching the API response shape.
47
50
  */
@@ -55,21 +58,25 @@ export interface LlmLog {
55
58
  totalTokens: number | null;
56
59
  createdAt: string | null;
57
60
  }
58
- export interface CreateLlmLogInput {
61
+ export interface ChatMessage {
62
+ role: 'system' | 'user' | 'assistant';
63
+ content: string;
64
+ }
65
+ export interface ChatRequest {
66
+ messages: ChatMessage[];
59
67
  source: string;
60
68
  user: string;
61
69
  function?: string;
62
- tokensIn?: number;
63
- tokensOut?: number;
64
- totalTokens?: number;
70
+ temperature?: number;
71
+ maxTokens?: number;
65
72
  }
66
- export interface UpdateLlmLogInput {
67
- source?: string;
68
- user?: string;
69
- function?: string;
70
- tokensIn?: number;
71
- tokensOut?: number;
72
- totalTokens?: number;
73
+ export interface ChatResponse {
74
+ message: ChatMessage;
75
+ usage: {
76
+ tokensIn: number | null;
77
+ tokensOut: number | null;
78
+ totalTokens: number | null;
79
+ };
73
80
  }
74
81
  export interface BusinessUnit {
75
82
  id: string;
@@ -115,21 +122,6 @@ export interface Paytype {
115
122
  perDiemPayType: boolean;
116
123
  type: string | null;
117
124
  }
118
- export interface Shift {
119
- drky: string;
120
- drsy: string | null;
121
- drrt: string | null;
122
- drdl01: string | null;
123
- drdl02: string | null;
124
- drsphd: string | null;
125
- drudco: string | null;
126
- drhrdc: string | null;
127
- druser: string | null;
128
- drpid: string | null;
129
- drumpmj: string | null;
130
- drjobn: string | null;
131
- drupmt: string | null;
132
- }
133
125
  export interface Workorder {
134
126
  id: string;
135
127
  businessUnitId: string;
@@ -152,19 +144,20 @@ export declare class ApiHubClient {
152
144
  private apiKey;
153
145
  constructor(options: ApiHubClientOptions);
154
146
  private request;
155
- private requestWithBody;
156
147
  /** Get all employees */
157
148
  getEmployees(): Promise<Employee[]>;
149
+ /** Get employees formatted for dropdown controls */
150
+ getEmployeesDropdown(): Promise<DropdownOption[]>;
158
151
  /** Get a single employee by employeeId */
159
- getEmployee(employeeId: number): Promise<Employee>;
152
+ getEmployee(employeeId: string): Promise<Employee>;
160
153
  /** Search employees by name (case-insensitive partial match) */
161
154
  searchByName(name: string): Promise<Employee[]>;
162
155
  /** Get all employees reporting to a supervisor */
163
- getBySupervisor(supervisorId: number): Promise<Employee[]>;
156
+ getBySupervisor(supervisorId: string): Promise<Employee[]>;
164
157
  /** Search employees by email (case-insensitive partial match) */
165
158
  searchByEmail(email: string): Promise<Employee[]>;
166
159
  /** Get the supervisor chain above an employee */
167
- getSupervisorChain(employeeId: number): Promise<Employee[]>;
160
+ getSupervisorChain(employeeId: string): Promise<Employee[]>;
168
161
  /** Look up JDE number and employee data from email (with JDEService/CoreService fallback) */
169
162
  getJdeFromEmail(email: string): Promise<{
170
163
  jde: string | null;
@@ -172,33 +165,18 @@ export declare class ApiHubClient {
172
165
  }>;
173
166
  /** List all LLM log entries (newest first) */
174
167
  getLlmLogs(): Promise<LlmLog[]>;
175
- /** Create a new LLM log entry */
176
- createLlmLog(input: CreateLlmLogInput): Promise<LlmLog>;
177
- /** Update an existing LLM log entry */
178
- updateLlmLog(id: number, input: UpdateLlmLogInput): Promise<LlmLog>;
168
+ /** Send a chat completion request to the LLM */
169
+ chat(request: ChatRequest): Promise<ChatResponse>;
179
170
  getBusinessUnits(): Promise<BusinessUnit[]>;
171
+ getBusinessUnitsDropdown(): Promise<DropdownOption[]>;
180
172
  getBusinessUnit(id: string): Promise<BusinessUnit>;
181
- createBusinessUnit(input: Partial<BusinessUnit>): Promise<BusinessUnit>;
182
- updateBusinessUnit(id: string, input: Partial<BusinessUnit>): Promise<BusinessUnit>;
183
- deleteBusinessUnit(id: string): Promise<BusinessUnit>;
184
173
  getCostcodes(): Promise<Costcode[]>;
174
+ getCostcodesDropdown(): Promise<DropdownOption[]>;
185
175
  getCostcode(id: string): Promise<Costcode>;
186
- createCostcode(input: Partial<Costcode>): Promise<Costcode>;
187
- updateCostcode(id: string, input: Partial<Costcode>): Promise<Costcode>;
188
- deleteCostcode(id: string): Promise<Costcode>;
189
176
  getPaytypes(): Promise<Paytype[]>;
177
+ getPaytypesDropdown(): Promise<DropdownOption[]>;
190
178
  getPaytype(id: string): Promise<Paytype>;
191
- createPaytype(input: Partial<Paytype>): Promise<Paytype>;
192
- updatePaytype(id: string, input: Partial<Paytype>): Promise<Paytype>;
193
- deletePaytype(id: string): Promise<Paytype>;
194
- getShifts(): Promise<Shift[]>;
195
- getShift(id: string): Promise<Shift>;
196
- createShift(input: Partial<Shift>): Promise<Shift>;
197
- updateShift(id: string, input: Partial<Shift>): Promise<Shift>;
198
- deleteShift(id: string): Promise<Shift>;
199
179
  getWorkorders(): Promise<Workorder[]>;
180
+ getWorkordersDropdown(): Promise<DropdownOption[]>;
200
181
  getWorkorder(id: string): Promise<Workorder>;
201
- createWorkorder(input: Partial<Workorder>): Promise<Workorder>;
202
- updateWorkorder(id: string, input: Partial<Workorder>): Promise<Workorder>;
203
- deleteWorkorder(id: string): Promise<Workorder>;
204
182
  }
package/dist/index.js CHANGED
@@ -15,25 +15,17 @@ export class ApiHubClient {
15
15
  }
16
16
  return res.json();
17
17
  }
18
- async requestWithBody(path, method, body) {
19
- const res = await fetch(`${this.baseUrl}${path}`, {
20
- method,
21
- headers: { 'x-api-key': this.apiKey, 'Content-Type': 'application/json' },
22
- body: JSON.stringify(body),
23
- });
24
- if (!res.ok) {
25
- const respBody = await res.json().catch(() => ({}));
26
- throw new Error(respBody.error ?? `Request failed: ${res.status}`);
27
- }
28
- return res.json();
29
- }
30
18
  /** Get all employees */
31
19
  async getEmployees() {
32
20
  return this.request('/employees');
33
21
  }
22
+ /** Get employees formatted for dropdown controls */
23
+ async getEmployeesDropdown() {
24
+ return this.request('/employees/dropdown');
25
+ }
34
26
  /** Get a single employee by employeeId */
35
27
  async getEmployee(employeeId) {
36
- return this.request(`/employees/${employeeId}`);
28
+ return this.request(`/employees/${encodeURIComponent(employeeId)}`);
37
29
  }
38
30
  /** Search employees by name (case-insensitive partial match) */
39
31
  async searchByName(name) {
@@ -41,7 +33,7 @@ export class ApiHubClient {
41
33
  }
42
34
  /** Get all employees reporting to a supervisor */
43
35
  async getBySupervisor(supervisorId) {
44
- return this.request(`/employees/by-supervisor/${supervisorId}`);
36
+ return this.request(`/employees/by-supervisor/${encodeURIComponent(supervisorId)}`);
45
37
  }
46
38
  /** Search employees by email (case-insensitive partial match) */
47
39
  async searchByEmail(email) {
@@ -49,7 +41,7 @@ export class ApiHubClient {
49
41
  }
50
42
  /** Get the supervisor chain above an employee */
51
43
  async getSupervisorChain(employeeId) {
52
- return this.request(`/employees/${employeeId}/supervisor-chain`);
44
+ return this.request(`/employees/${encodeURIComponent(employeeId)}/supervisor-chain`);
53
45
  }
54
46
  /** Look up JDE number and employee data from email (with JDEService/CoreService fallback) */
55
47
  async getJdeFromEmail(email) {
@@ -62,13 +54,21 @@ export class ApiHubClient {
62
54
  async getLlmLogs() {
63
55
  return this.request('/llm-logs');
64
56
  }
65
- /** Create a new LLM log entry */
66
- async createLlmLog(input) {
67
- return this.requestWithBody('/llm-logs', 'POST', input);
68
- }
69
- /** Update an existing LLM log entry */
70
- async updateLlmLog(id, input) {
71
- return this.requestWithBody(`/llm-logs/${id}`, 'PATCH', input);
57
+ /** Send a chat completion request to the LLM */
58
+ async chat(request) {
59
+ const res = await fetch(`${this.baseUrl}/llm/chat`, {
60
+ method: 'POST',
61
+ headers: {
62
+ 'x-api-key': this.apiKey,
63
+ 'Content-Type': 'application/json',
64
+ },
65
+ body: JSON.stringify(request),
66
+ });
67
+ if (!res.ok) {
68
+ const body = await res.json().catch(() => ({}));
69
+ throw new Error(body.error ?? `Request failed: ${res.status}`);
70
+ }
71
+ return res.json();
72
72
  }
73
73
  // -----------------------------------------------------------------------
74
74
  // Business Units
@@ -76,88 +76,46 @@ export class ApiHubClient {
76
76
  async getBusinessUnits() {
77
77
  return this.request('/business-units');
78
78
  }
79
+ async getBusinessUnitsDropdown() {
80
+ return this.request('/business-units/dropdown');
81
+ }
79
82
  async getBusinessUnit(id) {
80
83
  return this.request(`/business-units/${encodeURIComponent(id)}`);
81
84
  }
82
- async createBusinessUnit(input) {
83
- return this.requestWithBody('/business-units', 'POST', input);
84
- }
85
- async updateBusinessUnit(id, input) {
86
- return this.requestWithBody(`/business-units/${encodeURIComponent(id)}`, 'PATCH', input);
87
- }
88
- async deleteBusinessUnit(id) {
89
- return this.requestWithBody(`/business-units/${encodeURIComponent(id)}`, 'DELETE', {});
90
- }
91
85
  // -----------------------------------------------------------------------
92
86
  // Cost Codes
93
87
  // -----------------------------------------------------------------------
94
88
  async getCostcodes() {
95
89
  return this.request('/costcodes');
96
90
  }
91
+ async getCostcodesDropdown() {
92
+ return this.request('/costcodes/dropdown');
93
+ }
97
94
  async getCostcode(id) {
98
95
  return this.request(`/costcodes/${encodeURIComponent(id)}`);
99
96
  }
100
- async createCostcode(input) {
101
- return this.requestWithBody('/costcodes', 'POST', input);
102
- }
103
- async updateCostcode(id, input) {
104
- return this.requestWithBody(`/costcodes/${encodeURIComponent(id)}`, 'PATCH', input);
105
- }
106
- async deleteCostcode(id) {
107
- return this.requestWithBody(`/costcodes/${encodeURIComponent(id)}`, 'DELETE', {});
108
- }
109
97
  // -----------------------------------------------------------------------
110
98
  // Pay Types
111
99
  // -----------------------------------------------------------------------
112
100
  async getPaytypes() {
113
101
  return this.request('/paytypes');
114
102
  }
103
+ async getPaytypesDropdown() {
104
+ return this.request('/paytypes/dropdown');
105
+ }
115
106
  async getPaytype(id) {
116
107
  return this.request(`/paytypes/${encodeURIComponent(id)}`);
117
108
  }
118
- async createPaytype(input) {
119
- return this.requestWithBody('/paytypes', 'POST', input);
120
- }
121
- async updatePaytype(id, input) {
122
- return this.requestWithBody(`/paytypes/${encodeURIComponent(id)}`, 'PATCH', input);
123
- }
124
- async deletePaytype(id) {
125
- return this.requestWithBody(`/paytypes/${encodeURIComponent(id)}`, 'DELETE', {});
126
- }
127
- // -----------------------------------------------------------------------
128
- // Shifts
129
- // -----------------------------------------------------------------------
130
- async getShifts() {
131
- return this.request('/shifts');
132
- }
133
- async getShift(id) {
134
- return this.request(`/shifts/${encodeURIComponent(id)}`);
135
- }
136
- async createShift(input) {
137
- return this.requestWithBody('/shifts', 'POST', input);
138
- }
139
- async updateShift(id, input) {
140
- return this.requestWithBody(`/shifts/${encodeURIComponent(id)}`, 'PATCH', input);
141
- }
142
- async deleteShift(id) {
143
- return this.requestWithBody(`/shifts/${encodeURIComponent(id)}`, 'DELETE', {});
144
- }
145
109
  // -----------------------------------------------------------------------
146
110
  // Work Orders
147
111
  // -----------------------------------------------------------------------
148
112
  async getWorkorders() {
149
113
  return this.request('/workorders');
150
114
  }
115
+ async getWorkordersDropdown() {
116
+ return this.request('/workorders/dropdown');
117
+ }
151
118
  async getWorkorder(id) {
152
119
  return this.request(`/workorders/${encodeURIComponent(id)}`);
153
120
  }
154
- async createWorkorder(input) {
155
- return this.requestWithBody('/workorders', 'POST', input);
156
- }
157
- async updateWorkorder(id, input) {
158
- return this.requestWithBody(`/workorders/${encodeURIComponent(id)}`, 'PATCH', input);
159
- }
160
- async deleteWorkorder(id) {
161
- return this.requestWithBody(`/workorders/${encodeURIComponent(id)}`, 'DELETE', {});
162
- }
163
121
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brownandroot/api",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",