@brownandroot/api 0.11.0 → 0.13.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/dist/index.d.ts +53 -0
- package/dist/index.js +149 -14
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -40,6 +40,8 @@ export interface Employee {
|
|
|
40
40
|
export interface ApiHubClientOptions {
|
|
41
41
|
baseUrl: string;
|
|
42
42
|
apiKey: string;
|
|
43
|
+
/** Default cache TTL in milliseconds. Set to 0 to disable caching. Default: 5 minutes. */
|
|
44
|
+
cacheTtl?: number;
|
|
43
45
|
}
|
|
44
46
|
export interface DropdownOption {
|
|
45
47
|
value: number | string;
|
|
@@ -81,6 +83,38 @@ export interface ChatResponse {
|
|
|
81
83
|
totalTokens: number | null;
|
|
82
84
|
};
|
|
83
85
|
}
|
|
86
|
+
export interface DocumentRecord {
|
|
87
|
+
id: number;
|
|
88
|
+
fileName: string;
|
|
89
|
+
fileType: 'pdf' | 'csv';
|
|
90
|
+
documentType: string | null;
|
|
91
|
+
summary: string | null;
|
|
92
|
+
totalChunks: number;
|
|
93
|
+
uploadedAt: string | null;
|
|
94
|
+
uploadedBy: string | null;
|
|
95
|
+
}
|
|
96
|
+
export interface SearchResult {
|
|
97
|
+
chunkId: number;
|
|
98
|
+
content: string;
|
|
99
|
+
fileName: string;
|
|
100
|
+
documentType: string | null;
|
|
101
|
+
score: number;
|
|
102
|
+
}
|
|
103
|
+
export interface StreamChatUserContext {
|
|
104
|
+
name: string;
|
|
105
|
+
department?: string;
|
|
106
|
+
roles?: string[];
|
|
107
|
+
}
|
|
108
|
+
export interface StreamChatRequest {
|
|
109
|
+
messages: {
|
|
110
|
+
role: 'user' | 'assistant';
|
|
111
|
+
content: string;
|
|
112
|
+
}[];
|
|
113
|
+
userContext?: StreamChatUserContext;
|
|
114
|
+
useRag?: boolean;
|
|
115
|
+
tools?: string[];
|
|
116
|
+
source?: string;
|
|
117
|
+
}
|
|
84
118
|
export interface BusinessUnit {
|
|
85
119
|
id: string;
|
|
86
120
|
companyId: string;
|
|
@@ -158,7 +192,12 @@ export interface Jobtypejobstep {
|
|
|
158
192
|
export declare class ApiHubClient {
|
|
159
193
|
private baseUrl;
|
|
160
194
|
private apiKey;
|
|
195
|
+
private cacheTtl;
|
|
196
|
+
private cache;
|
|
161
197
|
constructor(options: ApiHubClientOptions);
|
|
198
|
+
/** Clear all cached responses, or a specific path */
|
|
199
|
+
clearCache(path?: string): void;
|
|
200
|
+
private cachedRequest;
|
|
162
201
|
private request;
|
|
163
202
|
/** Get all employees */
|
|
164
203
|
getEmployees(): Promise<Employee[]>;
|
|
@@ -183,12 +222,26 @@ export declare class ApiHubClient {
|
|
|
183
222
|
getLlmLogs(): Promise<LlmLog[]>;
|
|
184
223
|
/** Send a chat completion request to the LLM */
|
|
185
224
|
chat(request: ChatRequest): Promise<ChatResponse>;
|
|
225
|
+
/** Start a streaming chat session — returns the raw SSE Response for proxying */
|
|
226
|
+
chatStream(request: StreamChatRequest): Promise<Response>;
|
|
227
|
+
/** Upload and process a document */
|
|
228
|
+
uploadDocument(fileName: string, base64Content: string, uploadedBy: string): Promise<DocumentRecord>;
|
|
229
|
+
/** List all documents in the knowledge base */
|
|
230
|
+
listDocuments(): Promise<DocumentRecord[]>;
|
|
231
|
+
/** Delete a document and its chunks */
|
|
232
|
+
deleteDocument(id: number): Promise<void>;
|
|
233
|
+
/** Search the knowledge base with a natural language query */
|
|
234
|
+
searchDocuments(query: string, topK?: number): Promise<SearchResult[]>;
|
|
186
235
|
getBusinessUnits(): Promise<BusinessUnit[]>;
|
|
187
236
|
getBusinessUnitsDropdown(): Promise<DropdownOption[]>;
|
|
188
237
|
getBusinessUnit(id: string): Promise<BusinessUnit>;
|
|
189
238
|
getCostcodes(): Promise<Costcode[]>;
|
|
190
239
|
getCostcodesDropdown(): Promise<DropdownOption[]>;
|
|
191
240
|
getCostcode(id: string): Promise<Costcode>;
|
|
241
|
+
/** Get cost codes for a specific business unit, formatted for dropdown controls */
|
|
242
|
+
getCostcodesDropdownByBu(businessUnitId: string): Promise<DropdownOption[]>;
|
|
243
|
+
/** Get cost codes for a specific business unit and pay type, formatted for dropdown controls */
|
|
244
|
+
getCostcodesDropdownByBuAndPayType(businessUnitId: string, payTypeCode: string): Promise<DropdownOption[]>;
|
|
192
245
|
getPaytypes(): Promise<Paytype[]>;
|
|
193
246
|
getPaytypesDropdown(): Promise<PaytypeDropdownOption[]>;
|
|
194
247
|
getPaytype(id: string): Promise<Paytype>;
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,35 @@
|
|
|
1
1
|
export class ApiHubClient {
|
|
2
2
|
baseUrl;
|
|
3
3
|
apiKey;
|
|
4
|
+
cacheTtl;
|
|
5
|
+
cache = new Map();
|
|
4
6
|
constructor(options) {
|
|
5
7
|
this.baseUrl = options.baseUrl.replace(/\/+$/, '');
|
|
6
8
|
this.apiKey = options.apiKey;
|
|
9
|
+
this.cacheTtl = options.cacheTtl ?? 5 * 60 * 1000;
|
|
10
|
+
}
|
|
11
|
+
/** Clear all cached responses, or a specific path */
|
|
12
|
+
clearCache(path) {
|
|
13
|
+
if (path) {
|
|
14
|
+
this.cache.delete(path);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
this.cache.clear();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
async cachedRequest(path, ttl) {
|
|
21
|
+
const effectiveTtl = ttl ?? this.cacheTtl;
|
|
22
|
+
if (effectiveTtl > 0) {
|
|
23
|
+
const entry = this.cache.get(path);
|
|
24
|
+
if (entry && entry.expires > Date.now()) {
|
|
25
|
+
return entry.data;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const data = await this.request(path);
|
|
29
|
+
if (effectiveTtl > 0) {
|
|
30
|
+
this.cache.set(path, { data, expires: Date.now() + effectiveTtl });
|
|
31
|
+
}
|
|
32
|
+
return data;
|
|
7
33
|
}
|
|
8
34
|
async request(path) {
|
|
9
35
|
let res;
|
|
@@ -25,11 +51,11 @@ export class ApiHubClient {
|
|
|
25
51
|
}
|
|
26
52
|
/** Get all employees */
|
|
27
53
|
async getEmployees() {
|
|
28
|
-
return this.
|
|
54
|
+
return this.cachedRequest('/employees');
|
|
29
55
|
}
|
|
30
56
|
/** Get employees formatted for dropdown controls */
|
|
31
57
|
async getEmployeesDropdown() {
|
|
32
|
-
return this.
|
|
58
|
+
return this.cachedRequest('/employees/dropdown');
|
|
33
59
|
}
|
|
34
60
|
/** Get a single employee by employeeId */
|
|
35
61
|
async getEmployee(employeeId) {
|
|
@@ -60,7 +86,7 @@ export class ApiHubClient {
|
|
|
60
86
|
// -----------------------------------------------------------------------
|
|
61
87
|
/** List all LLM log entries (newest first) */
|
|
62
88
|
async getLlmLogs() {
|
|
63
|
-
return this.
|
|
89
|
+
return this.cachedRequest('/llm-logs');
|
|
64
90
|
}
|
|
65
91
|
/** Send a chat completion request to the LLM */
|
|
66
92
|
async chat(request) {
|
|
@@ -87,13 +113,114 @@ export class ApiHubClient {
|
|
|
87
113
|
return res.json();
|
|
88
114
|
}
|
|
89
115
|
// -----------------------------------------------------------------------
|
|
116
|
+
// Streaming Chat
|
|
117
|
+
// -----------------------------------------------------------------------
|
|
118
|
+
/** Start a streaming chat session — returns the raw SSE Response for proxying */
|
|
119
|
+
async chatStream(request) {
|
|
120
|
+
let res;
|
|
121
|
+
try {
|
|
122
|
+
res = await fetch(`${this.baseUrl}/ai/chat/stream`, {
|
|
123
|
+
method: 'POST',
|
|
124
|
+
headers: {
|
|
125
|
+
'x-api-key': this.apiKey,
|
|
126
|
+
'Content-Type': 'application/json',
|
|
127
|
+
},
|
|
128
|
+
body: JSON.stringify(request),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
throw new Error(`APIHub unavailable: ${this.baseUrl}/ai/chat/stream`);
|
|
133
|
+
}
|
|
134
|
+
if (!res.ok) {
|
|
135
|
+
const body = await res.json().catch(() => null);
|
|
136
|
+
const message = (body && typeof body === 'object' && 'error' in body && typeof body.error === 'string' ? body.error : null) ??
|
|
137
|
+
`Request failed: ${res.status} ${res.statusText}`;
|
|
138
|
+
throw new Error(message);
|
|
139
|
+
}
|
|
140
|
+
return res;
|
|
141
|
+
}
|
|
142
|
+
// -----------------------------------------------------------------------
|
|
143
|
+
// RAG Documents
|
|
144
|
+
// -----------------------------------------------------------------------
|
|
145
|
+
/** Upload and process a document */
|
|
146
|
+
async uploadDocument(fileName, base64Content, uploadedBy) {
|
|
147
|
+
let res;
|
|
148
|
+
try {
|
|
149
|
+
res = await fetch(`${this.baseUrl}/ai/documents`, {
|
|
150
|
+
method: 'POST',
|
|
151
|
+
headers: {
|
|
152
|
+
'x-api-key': this.apiKey,
|
|
153
|
+
'Content-Type': 'application/json',
|
|
154
|
+
},
|
|
155
|
+
body: JSON.stringify({ fileName, base64Content, uploadedBy }),
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
throw new Error(`APIHub unavailable: ${this.baseUrl}/ai/documents`);
|
|
160
|
+
}
|
|
161
|
+
if (!res.ok) {
|
|
162
|
+
const body = await res.json().catch(() => null);
|
|
163
|
+
const message = (body && typeof body === 'object' && 'error' in body && typeof body.error === 'string' ? body.error : null) ??
|
|
164
|
+
`Request failed: ${res.status} ${res.statusText}`;
|
|
165
|
+
throw new Error(message);
|
|
166
|
+
}
|
|
167
|
+
return res.json();
|
|
168
|
+
}
|
|
169
|
+
/** List all documents in the knowledge base */
|
|
170
|
+
async listDocuments() {
|
|
171
|
+
return this.cachedRequest('/ai/documents');
|
|
172
|
+
}
|
|
173
|
+
/** Delete a document and its chunks */
|
|
174
|
+
async deleteDocument(id) {
|
|
175
|
+
let res;
|
|
176
|
+
try {
|
|
177
|
+
res = await fetch(`${this.baseUrl}/ai/documents/${id}`, {
|
|
178
|
+
method: 'DELETE',
|
|
179
|
+
headers: { 'x-api-key': this.apiKey },
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
throw new Error(`APIHub unavailable: ${this.baseUrl}/ai/documents/${id}`);
|
|
184
|
+
}
|
|
185
|
+
if (!res.ok) {
|
|
186
|
+
const body = await res.json().catch(() => null);
|
|
187
|
+
const message = (body && typeof body === 'object' && 'error' in body && typeof body.error === 'string' ? body.error : null) ??
|
|
188
|
+
`Request failed: ${res.status} ${res.statusText}`;
|
|
189
|
+
throw new Error(message);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/** Search the knowledge base with a natural language query */
|
|
193
|
+
async searchDocuments(query, topK) {
|
|
194
|
+
let res;
|
|
195
|
+
try {
|
|
196
|
+
res = await fetch(`${this.baseUrl}/ai/search`, {
|
|
197
|
+
method: 'POST',
|
|
198
|
+
headers: {
|
|
199
|
+
'x-api-key': this.apiKey,
|
|
200
|
+
'Content-Type': 'application/json',
|
|
201
|
+
},
|
|
202
|
+
body: JSON.stringify({ query, topK }),
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
throw new Error(`APIHub unavailable: ${this.baseUrl}/ai/search`);
|
|
207
|
+
}
|
|
208
|
+
if (!res.ok) {
|
|
209
|
+
const body = await res.json().catch(() => null);
|
|
210
|
+
const message = (body && typeof body === 'object' && 'error' in body && typeof body.error === 'string' ? body.error : null) ??
|
|
211
|
+
`Request failed: ${res.status} ${res.statusText}`;
|
|
212
|
+
throw new Error(message);
|
|
213
|
+
}
|
|
214
|
+
return res.json();
|
|
215
|
+
}
|
|
216
|
+
// -----------------------------------------------------------------------
|
|
90
217
|
// Business Units
|
|
91
218
|
// -----------------------------------------------------------------------
|
|
92
219
|
async getBusinessUnits() {
|
|
93
|
-
return this.
|
|
220
|
+
return this.cachedRequest('/business-units');
|
|
94
221
|
}
|
|
95
222
|
async getBusinessUnitsDropdown() {
|
|
96
|
-
return this.
|
|
223
|
+
return this.cachedRequest('/business-units/dropdown');
|
|
97
224
|
}
|
|
98
225
|
async getBusinessUnit(id) {
|
|
99
226
|
return this.request(`/business-units/${encodeURIComponent(id)}`);
|
|
@@ -102,22 +229,30 @@ export class ApiHubClient {
|
|
|
102
229
|
// Cost Codes
|
|
103
230
|
// -----------------------------------------------------------------------
|
|
104
231
|
async getCostcodes() {
|
|
105
|
-
return this.
|
|
232
|
+
return this.cachedRequest('/costcodes');
|
|
106
233
|
}
|
|
107
234
|
async getCostcodesDropdown() {
|
|
108
|
-
return this.
|
|
235
|
+
return this.cachedRequest('/costcodes/dropdown');
|
|
109
236
|
}
|
|
110
237
|
async getCostcode(id) {
|
|
111
238
|
return this.request(`/costcodes/${encodeURIComponent(id)}`);
|
|
112
239
|
}
|
|
240
|
+
/** Get cost codes for a specific business unit, formatted for dropdown controls */
|
|
241
|
+
async getCostcodesDropdownByBu(businessUnitId) {
|
|
242
|
+
return this.cachedRequest(`/costcodes/by-bu/${encodeURIComponent(businessUnitId)}/dropdown`);
|
|
243
|
+
}
|
|
244
|
+
/** Get cost codes for a specific business unit and pay type, formatted for dropdown controls */
|
|
245
|
+
async getCostcodesDropdownByBuAndPayType(businessUnitId, payTypeCode) {
|
|
246
|
+
return this.cachedRequest(`/costcodes/by-bu/${encodeURIComponent(businessUnitId)}/by-paytype/${encodeURIComponent(payTypeCode)}/dropdown`);
|
|
247
|
+
}
|
|
113
248
|
// -----------------------------------------------------------------------
|
|
114
249
|
// Pay Types
|
|
115
250
|
// -----------------------------------------------------------------------
|
|
116
251
|
async getPaytypes() {
|
|
117
|
-
return this.
|
|
252
|
+
return this.cachedRequest('/paytypes');
|
|
118
253
|
}
|
|
119
254
|
async getPaytypesDropdown() {
|
|
120
|
-
return this.
|
|
255
|
+
return this.cachedRequest('/paytypes/dropdown');
|
|
121
256
|
}
|
|
122
257
|
async getPaytype(id) {
|
|
123
258
|
return this.request(`/paytypes/${encodeURIComponent(id)}`);
|
|
@@ -126,14 +261,14 @@ export class ApiHubClient {
|
|
|
126
261
|
// Work Orders
|
|
127
262
|
// -----------------------------------------------------------------------
|
|
128
263
|
async getWorkorders() {
|
|
129
|
-
return this.
|
|
264
|
+
return this.cachedRequest('/workorders');
|
|
130
265
|
}
|
|
131
266
|
async getWorkordersDropdown() {
|
|
132
|
-
return this.
|
|
267
|
+
return this.cachedRequest('/workorders/dropdown');
|
|
133
268
|
}
|
|
134
269
|
/** Get work orders for a specific business unit, formatted for dropdown controls */
|
|
135
270
|
async getWorkordersDropdownByBu(businessUnitId) {
|
|
136
|
-
return this.
|
|
271
|
+
return this.cachedRequest(`/workorders/by-bu/${encodeURIComponent(businessUnitId)}/dropdown`);
|
|
137
272
|
}
|
|
138
273
|
async getWorkorder(id) {
|
|
139
274
|
return this.request(`/workorders/${encodeURIComponent(id)}`);
|
|
@@ -142,10 +277,10 @@ export class ApiHubClient {
|
|
|
142
277
|
// Job Type / Job Steps
|
|
143
278
|
// -----------------------------------------------------------------------
|
|
144
279
|
async getJobtypejobsteps() {
|
|
145
|
-
return this.
|
|
280
|
+
return this.cachedRequest('/jobtypejobsteps');
|
|
146
281
|
}
|
|
147
282
|
async getJobtypejobstepsDropdown() {
|
|
148
|
-
return this.
|
|
283
|
+
return this.cachedRequest('/jobtypejobsteps/dropdown');
|
|
149
284
|
}
|
|
150
285
|
async getJobtypejobstep(id) {
|
|
151
286
|
return this.request(`/jobtypejobsteps/${encodeURIComponent(id)}`);
|