@kbforge/sdk 0.1.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.cjs ADDED
@@ -0,0 +1,283 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ KBForge: () => KBForge,
24
+ KBForgeError: () => KBForgeError
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+
28
+ // src/client.ts
29
+ var DEFAULT_BASE_URL = "https://kbforge.app";
30
+ var KBForgeError = class extends Error {
31
+ constructor(message, status) {
32
+ super(message);
33
+ this.name = "KBForgeError";
34
+ this.status = status;
35
+ }
36
+ };
37
+ var KBForge = class {
38
+ constructor(config) {
39
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
40
+ // Knowledge Bases (permission: "manage")
41
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
42
+ this.knowledgeBases = {
43
+ list: () => {
44
+ return this.request("GET", "/knowledge-bases");
45
+ },
46
+ create: (options) => {
47
+ return this.request("POST", "/knowledge-bases", options);
48
+ },
49
+ delete: (id) => {
50
+ return this.request("DELETE", `/knowledge-bases/${id}`);
51
+ }
52
+ };
53
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
54
+ // Documents (permission: "ingest" for upload, "manage" for list/delete)
55
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
56
+ this.documents = {
57
+ list: (knowledgeBaseId) => {
58
+ return this.request("GET", `/documents?kb=${knowledgeBaseId}`);
59
+ },
60
+ upload: async (options) => {
61
+ const formData = new FormData();
62
+ formData.append("file", options.file, options.fileName);
63
+ formData.append("knowledgeBaseId", options.knowledgeBaseId);
64
+ const res = await this.requestRaw("POST", "/documents", formData, {});
65
+ return res.json();
66
+ },
67
+ uploadText: (options) => {
68
+ return this.request("POST", "/documents", options);
69
+ },
70
+ delete: (id) => {
71
+ return this.request("DELETE", `/documents/${id}`);
72
+ }
73
+ };
74
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
75
+ // Chunks (permission: "chunks")
76
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
77
+ this.chunks = {
78
+ list: (documentId, options) => {
79
+ const params = new URLSearchParams({ document_id: documentId });
80
+ if (options?.activeOnly) params.set("active_only", "true");
81
+ return this.request("GET", `/chunks?${params}`);
82
+ },
83
+ get: (id) => {
84
+ return this.request("GET", `/chunks/${id}`);
85
+ },
86
+ create: (options) => {
87
+ return this.request("POST", "/chunks", options);
88
+ },
89
+ update: (id, options) => {
90
+ return this.request("PATCH", `/chunks/${id}`, options);
91
+ },
92
+ delete: (id) => {
93
+ return this.request("DELETE", `/chunks/${id}`);
94
+ },
95
+ split: (id, position) => {
96
+ return this.request("POST", `/chunks/${id}/split`, { position });
97
+ },
98
+ bulk: (options) => {
99
+ return this.request("POST", "/chunks/bulk", options);
100
+ },
101
+ merge: (chunkIds) => {
102
+ return this.request("POST", "/chunks/merge", { chunkIds });
103
+ }
104
+ };
105
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
106
+ // Tags (permission: "manage")
107
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
108
+ this.tags = {
109
+ list: (knowledgeBaseId) => {
110
+ return this.request("GET", `/tags?kb=${knowledgeBaseId}`);
111
+ },
112
+ create: (options) => {
113
+ return this.request("POST", "/tags", options);
114
+ },
115
+ update: (id, options) => {
116
+ return this.request("PATCH", `/tags/${id}`, options);
117
+ },
118
+ delete: (id) => {
119
+ return this.request("DELETE", `/tags/${id}`);
120
+ },
121
+ addDocuments: (tagId, documentIds) => {
122
+ return this.request("POST", `/tags/${tagId}/documents`, { documentIds });
123
+ },
124
+ removeDocument: (tagId, documentId) => {
125
+ return this.request("DELETE", `/tags/${tagId}/documents/${documentId}`);
126
+ }
127
+ };
128
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
129
+ // Segments (permission: "manage")
130
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
131
+ this.segments = {
132
+ list: (knowledgeBaseId) => {
133
+ return this.request("GET", `/segments?kb=${knowledgeBaseId}`);
134
+ },
135
+ create: (options) => {
136
+ return this.request("POST", "/segments", options);
137
+ },
138
+ update: (id, options) => {
139
+ return this.request("PATCH", `/segments/${id}`, options);
140
+ },
141
+ delete: (id) => {
142
+ return this.request("DELETE", `/segments/${id}`);
143
+ },
144
+ addDocuments: (segmentId, documentIds) => {
145
+ return this.request("POST", `/segments/${segmentId}/documents`, {
146
+ documentIds
147
+ });
148
+ },
149
+ removeDocument: (segmentId, documentId) => {
150
+ return this.request(
151
+ "DELETE",
152
+ `/segments/${segmentId}/documents/${documentId}`
153
+ );
154
+ }
155
+ };
156
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
157
+ // Analytics (permission: "admin")
158
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
159
+ this.analytics = {
160
+ overview: (knowledgeBaseId) => {
161
+ return this.request("GET", `/analytics?kb=${knowledgeBaseId}`);
162
+ },
163
+ queriesPerDay: (knowledgeBaseId, days) => {
164
+ const params = new URLSearchParams({ kb: knowledgeBaseId });
165
+ if (days) params.set("days", String(days));
166
+ return this.request("GET", `/analytics/queries-per-day?${params}`);
167
+ },
168
+ topQueries: (knowledgeBaseId, limit) => {
169
+ const params = new URLSearchParams({ kb: knowledgeBaseId });
170
+ if (limit) params.set("limit", String(limit));
171
+ return this.request("GET", `/analytics/top-queries?${params}`);
172
+ },
173
+ topDocuments: (knowledgeBaseId, limit) => {
174
+ const params = new URLSearchParams({ kb: knowledgeBaseId });
175
+ if (limit) params.set("limit", String(limit));
176
+ return this.request("GET", `/analytics/top-documents?${params}`);
177
+ },
178
+ gaps: (knowledgeBaseId, limit) => {
179
+ const params = new URLSearchParams({ kb: knowledgeBaseId });
180
+ if (limit) params.set("limit", String(limit));
181
+ return this.request("GET", `/analytics/gaps?${params}`);
182
+ }
183
+ };
184
+ if (!config.apiKey) throw new Error("apiKey is required");
185
+ this.apiKey = config.apiKey;
186
+ this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
187
+ }
188
+ async request(method, path, body) {
189
+ const url = `${this.baseUrl}/api/v1${path}`;
190
+ const res = await fetch(url, {
191
+ method,
192
+ headers: {
193
+ Authorization: `Bearer ${this.apiKey}`,
194
+ "Content-Type": "application/json"
195
+ },
196
+ body: body ? JSON.stringify(body) : void 0
197
+ });
198
+ if (!res.ok) {
199
+ const data = await res.json().catch(() => ({ error: res.statusText }));
200
+ throw new KBForgeError(
201
+ data.error || `Request failed with status ${res.status}`,
202
+ res.status
203
+ );
204
+ }
205
+ return res.json();
206
+ }
207
+ async requestRaw(method, path, body, headers) {
208
+ const url = `${this.baseUrl}/api/v1${path}`;
209
+ const res = await fetch(url, {
210
+ method,
211
+ headers: {
212
+ Authorization: `Bearer ${this.apiKey}`,
213
+ ...headers,
214
+ ...body && !headers?.["Content-Type"] ? { "Content-Type": "application/json" } : {}
215
+ },
216
+ body: body instanceof FormData ? body : body ? JSON.stringify(body) : void 0
217
+ });
218
+ if (!res.ok) {
219
+ const data = await res.json().catch(() => ({ error: res.statusText }));
220
+ throw new KBForgeError(
221
+ data.error || `Request failed with status ${res.status}`,
222
+ res.status
223
+ );
224
+ }
225
+ return res;
226
+ }
227
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
228
+ // Retrieve (permission: "retrieve")
229
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
230
+ async retrieve(options) {
231
+ return this.request("POST", "/retrieve", options);
232
+ }
233
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
234
+ // Chat (permission: "retrieve")
235
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
236
+ async chat(options) {
237
+ const res = await this.requestRaw("POST", "/chat", options);
238
+ if (!res.body) {
239
+ throw new KBForgeError("No response body", 500);
240
+ }
241
+ return this.parseSSE(res.body);
242
+ }
243
+ async chatText(options) {
244
+ const stream = await this.chat(options);
245
+ let text = "";
246
+ for await (const event of stream) {
247
+ text += event.content;
248
+ }
249
+ return text;
250
+ }
251
+ async *parseSSE(body) {
252
+ const reader = body.getReader();
253
+ const decoder = new TextDecoder();
254
+ let buffer = "";
255
+ try {
256
+ while (true) {
257
+ const { done, value } = await reader.read();
258
+ if (done) break;
259
+ buffer += decoder.decode(value, { stream: true });
260
+ const lines = buffer.split("\n");
261
+ buffer = lines.pop() || "";
262
+ for (const line of lines) {
263
+ const trimmed = line.trim();
264
+ if (!trimmed || !trimmed.startsWith("data: ")) continue;
265
+ const data = trimmed.slice(6);
266
+ if (data === "[DONE]") return;
267
+ try {
268
+ const parsed = JSON.parse(data);
269
+ if (parsed.content) yield parsed;
270
+ } catch {
271
+ }
272
+ }
273
+ }
274
+ } finally {
275
+ reader.releaseLock();
276
+ }
277
+ }
278
+ };
279
+ // Annotate the CommonJS export names for ESM import in node:
280
+ 0 && (module.exports = {
281
+ KBForge,
282
+ KBForgeError
283
+ });
@@ -0,0 +1,337 @@
1
+ interface RetrieveOptions {
2
+ query: string;
3
+ knowledgeBase: string;
4
+ limit?: number;
5
+ threshold?: number;
6
+ segment?: string;
7
+ tag?: string;
8
+ }
9
+ interface RetrieveChunk {
10
+ content: string;
11
+ score: number;
12
+ documentTitle: string;
13
+ documentId: string;
14
+ chunkId: string;
15
+ metadata: Record<string, unknown>;
16
+ pinned: boolean;
17
+ boost: number;
18
+ }
19
+ interface RetrieveResponse {
20
+ chunks: RetrieveChunk[];
21
+ query: string;
22
+ model: string;
23
+ latencyMs: number;
24
+ }
25
+ interface ChatMessage {
26
+ role: "user" | "assistant";
27
+ content: string;
28
+ }
29
+ interface ChatOptions {
30
+ knowledgeBase: string;
31
+ messages: ChatMessage[];
32
+ systemPrompt?: string;
33
+ segment?: string;
34
+ tag?: string;
35
+ }
36
+ interface ChatStreamEvent {
37
+ content: string;
38
+ }
39
+ interface KnowledgeBase {
40
+ id: string;
41
+ name: string;
42
+ slug: string;
43
+ description: string | null;
44
+ embeddingModel: string | null;
45
+ documentCount: number | null;
46
+ status: string | null;
47
+ createdAt: string;
48
+ }
49
+ interface CreateKnowledgeBaseOptions {
50
+ name: string;
51
+ description?: string;
52
+ }
53
+ interface Document {
54
+ id: string;
55
+ title: string;
56
+ fileName: string | null;
57
+ mimeType: string | null;
58
+ fileSizeBytes: number | null;
59
+ status: string | null;
60
+ chunkCount: number | null;
61
+ createdAt: string;
62
+ }
63
+ interface UploadDocumentOptions {
64
+ knowledgeBaseId: string;
65
+ file: File | Blob;
66
+ fileName?: string;
67
+ }
68
+ interface UploadTextDocumentOptions {
69
+ knowledgeBaseId: string;
70
+ title: string;
71
+ content: string;
72
+ }
73
+ interface Chunk {
74
+ id: string;
75
+ documentId: string;
76
+ knowledgeBaseId: string;
77
+ content: string;
78
+ chunkIndex: number;
79
+ tokenCount: number;
80
+ isActive: boolean;
81
+ isEdited: boolean;
82
+ pinned: boolean;
83
+ boost: number;
84
+ originalContent: string | null;
85
+ modality: string;
86
+ createdAt: string;
87
+ }
88
+ interface ChunkListItem {
89
+ id: string;
90
+ content: string;
91
+ chunkIndex: number;
92
+ tokenCount: number;
93
+ isActive: boolean;
94
+ isEdited: boolean;
95
+ pinned: boolean;
96
+ boost: number;
97
+ modality: string;
98
+ createdAt: string;
99
+ }
100
+ interface ChunkListResponse {
101
+ chunks: ChunkListItem[];
102
+ documentId: string;
103
+ total: number;
104
+ }
105
+ interface CreateChunkOptions {
106
+ documentId: string;
107
+ knowledgeBaseId: string;
108
+ content: string;
109
+ insertAfterIndex?: number;
110
+ }
111
+ interface CreateChunkResponse {
112
+ id: string;
113
+ chunkIndex: number;
114
+ tokenCount: number;
115
+ status: string;
116
+ }
117
+ interface UpdateChunkOptions {
118
+ content?: string;
119
+ isActive?: boolean;
120
+ pinned?: boolean;
121
+ boost?: number;
122
+ }
123
+ interface UpdateChunkResponse {
124
+ id: string;
125
+ updated: boolean;
126
+ reembedding: boolean;
127
+ }
128
+ interface SplitChunkResponse {
129
+ split: boolean;
130
+ originalId: string;
131
+ chunks: {
132
+ id: string;
133
+ chunkIndex: number;
134
+ tokenCount: number;
135
+ }[];
136
+ }
137
+ type BulkAction = "activate" | "deactivate" | "pin" | "unpin" | "boost" | "delete";
138
+ interface BulkChunkOptions {
139
+ action: BulkAction;
140
+ chunkIds: string[];
141
+ boostValue?: number;
142
+ }
143
+ interface BulkChunkResponse {
144
+ action: string;
145
+ affected: number;
146
+ requested: number;
147
+ }
148
+ interface MergeChunkResponse {
149
+ merged: boolean;
150
+ originalIds: string[];
151
+ chunk: {
152
+ id: string;
153
+ chunkIndex: number;
154
+ tokenCount: number;
155
+ };
156
+ }
157
+ interface Tag {
158
+ id: string;
159
+ name: string;
160
+ description: string | null;
161
+ color: string | null;
162
+ documentCount?: number;
163
+ createdAt: string;
164
+ }
165
+ interface CreateTagOptions {
166
+ knowledgeBaseId: string;
167
+ name: string;
168
+ description?: string;
169
+ color?: string;
170
+ }
171
+ interface UpdateTagOptions {
172
+ name?: string;
173
+ description?: string;
174
+ color?: string;
175
+ }
176
+ interface Segment {
177
+ id: string;
178
+ name: string;
179
+ description: string | null;
180
+ color: string | null;
181
+ documentCount?: number;
182
+ createdAt: string;
183
+ }
184
+ interface CreateSegmentOptions {
185
+ knowledgeBaseId: string;
186
+ name: string;
187
+ description?: string;
188
+ color?: string;
189
+ }
190
+ interface UpdateSegmentOptions {
191
+ name?: string;
192
+ description?: string;
193
+ color?: string;
194
+ }
195
+ interface AnalyticsOverview {
196
+ totalQueries: number;
197
+ queriesToday: number;
198
+ queriesThisWeek: number;
199
+ avgLatencyMs: number;
200
+ avgResultCount: number;
201
+ avgTopScore: number;
202
+ }
203
+ interface QueriesPerDay {
204
+ date: string;
205
+ count: number;
206
+ }
207
+ interface TopQuery {
208
+ queryText: string;
209
+ count: number;
210
+ avgScore: number;
211
+ }
212
+ interface TopDocument {
213
+ documentId: string;
214
+ documentTitle: string;
215
+ hitCount: number;
216
+ }
217
+ interface GapQuery {
218
+ queryText: string;
219
+ count: number;
220
+ avgScore: number;
221
+ lastSeen: string;
222
+ }
223
+ interface KBForgeConfig {
224
+ apiKey: string;
225
+ baseUrl?: string;
226
+ }
227
+
228
+ declare class KBForgeError extends Error {
229
+ status: number;
230
+ constructor(message: string, status: number);
231
+ }
232
+ declare class KBForge {
233
+ private apiKey;
234
+ private baseUrl;
235
+ constructor(config: KBForgeConfig);
236
+ private request;
237
+ private requestRaw;
238
+ retrieve(options: RetrieveOptions): Promise<RetrieveResponse>;
239
+ chat(options: ChatOptions): Promise<AsyncIterable<ChatStreamEvent>>;
240
+ chatText(options: ChatOptions): Promise<string>;
241
+ private parseSSE;
242
+ readonly knowledgeBases: {
243
+ list: () => Promise<{
244
+ knowledgeBases: KnowledgeBase[];
245
+ }>;
246
+ create: (options: CreateKnowledgeBaseOptions) => Promise<KnowledgeBase>;
247
+ delete: (id: string) => Promise<{
248
+ deleted: boolean;
249
+ }>;
250
+ };
251
+ readonly documents: {
252
+ list: (knowledgeBaseId: string) => Promise<{
253
+ documents: Document[];
254
+ total: number;
255
+ }>;
256
+ upload: (options: UploadDocumentOptions) => Promise<{
257
+ id: string;
258
+ title: string;
259
+ status: string;
260
+ }>;
261
+ uploadText: (options: UploadTextDocumentOptions) => Promise<{
262
+ id: string;
263
+ title: string;
264
+ status: string;
265
+ }>;
266
+ delete: (id: string) => Promise<{
267
+ deleted: boolean;
268
+ }>;
269
+ };
270
+ readonly chunks: {
271
+ list: (documentId: string, options?: {
272
+ activeOnly?: boolean;
273
+ }) => Promise<ChunkListResponse>;
274
+ get: (id: string) => Promise<Chunk>;
275
+ create: (options: CreateChunkOptions) => Promise<CreateChunkResponse>;
276
+ update: (id: string, options: UpdateChunkOptions) => Promise<UpdateChunkResponse>;
277
+ delete: (id: string) => Promise<{
278
+ deleted: boolean;
279
+ }>;
280
+ split: (id: string, position: number) => Promise<SplitChunkResponse>;
281
+ bulk: (options: BulkChunkOptions) => Promise<BulkChunkResponse>;
282
+ merge: (chunkIds: string[]) => Promise<MergeChunkResponse>;
283
+ };
284
+ readonly tags: {
285
+ list: (knowledgeBaseId: string) => Promise<{
286
+ tags: Tag[];
287
+ }>;
288
+ create: (options: CreateTagOptions) => Promise<Tag>;
289
+ update: (id: string, options: UpdateTagOptions) => Promise<{
290
+ updated: boolean;
291
+ }>;
292
+ delete: (id: string) => Promise<{
293
+ deleted: boolean;
294
+ }>;
295
+ addDocuments: (tagId: string, documentIds: string[]) => Promise<{
296
+ added: number;
297
+ }>;
298
+ removeDocument: (tagId: string, documentId: string) => Promise<{
299
+ removed: boolean;
300
+ }>;
301
+ };
302
+ readonly segments: {
303
+ list: (knowledgeBaseId: string) => Promise<{
304
+ segments: Segment[];
305
+ }>;
306
+ create: (options: CreateSegmentOptions) => Promise<Segment>;
307
+ update: (id: string, options: UpdateSegmentOptions) => Promise<{
308
+ updated: boolean;
309
+ }>;
310
+ delete: (id: string) => Promise<{
311
+ deleted: boolean;
312
+ }>;
313
+ addDocuments: (segmentId: string, documentIds: string[]) => Promise<{
314
+ added: number;
315
+ }>;
316
+ removeDocument: (segmentId: string, documentId: string) => Promise<{
317
+ removed: boolean;
318
+ }>;
319
+ };
320
+ readonly analytics: {
321
+ overview: (knowledgeBaseId: string) => Promise<AnalyticsOverview>;
322
+ queriesPerDay: (knowledgeBaseId: string, days?: number) => Promise<{
323
+ data: QueriesPerDay[];
324
+ }>;
325
+ topQueries: (knowledgeBaseId: string, limit?: number) => Promise<{
326
+ data: TopQuery[];
327
+ }>;
328
+ topDocuments: (knowledgeBaseId: string, limit?: number) => Promise<{
329
+ data: TopDocument[];
330
+ }>;
331
+ gaps: (knowledgeBaseId: string, limit?: number) => Promise<{
332
+ data: GapQuery[];
333
+ }>;
334
+ };
335
+ }
336
+
337
+ export { type AnalyticsOverview, type BulkAction, type BulkChunkOptions, type BulkChunkResponse, type ChatMessage, type ChatOptions, type ChatStreamEvent, type Chunk, type ChunkListItem, type ChunkListResponse, type CreateChunkOptions, type CreateChunkResponse, type CreateKnowledgeBaseOptions, type CreateSegmentOptions, type CreateTagOptions, type Document, type GapQuery, KBForge, type KBForgeConfig, KBForgeError, type KnowledgeBase, type MergeChunkResponse, type QueriesPerDay, type RetrieveChunk, type RetrieveOptions, type RetrieveResponse, type Segment, type SplitChunkResponse, type Tag, type TopDocument, type TopQuery, type UpdateChunkOptions, type UpdateChunkResponse, type UpdateSegmentOptions, type UpdateTagOptions, type UploadDocumentOptions, type UploadTextDocumentOptions };
@@ -0,0 +1,337 @@
1
+ interface RetrieveOptions {
2
+ query: string;
3
+ knowledgeBase: string;
4
+ limit?: number;
5
+ threshold?: number;
6
+ segment?: string;
7
+ tag?: string;
8
+ }
9
+ interface RetrieveChunk {
10
+ content: string;
11
+ score: number;
12
+ documentTitle: string;
13
+ documentId: string;
14
+ chunkId: string;
15
+ metadata: Record<string, unknown>;
16
+ pinned: boolean;
17
+ boost: number;
18
+ }
19
+ interface RetrieveResponse {
20
+ chunks: RetrieveChunk[];
21
+ query: string;
22
+ model: string;
23
+ latencyMs: number;
24
+ }
25
+ interface ChatMessage {
26
+ role: "user" | "assistant";
27
+ content: string;
28
+ }
29
+ interface ChatOptions {
30
+ knowledgeBase: string;
31
+ messages: ChatMessage[];
32
+ systemPrompt?: string;
33
+ segment?: string;
34
+ tag?: string;
35
+ }
36
+ interface ChatStreamEvent {
37
+ content: string;
38
+ }
39
+ interface KnowledgeBase {
40
+ id: string;
41
+ name: string;
42
+ slug: string;
43
+ description: string | null;
44
+ embeddingModel: string | null;
45
+ documentCount: number | null;
46
+ status: string | null;
47
+ createdAt: string;
48
+ }
49
+ interface CreateKnowledgeBaseOptions {
50
+ name: string;
51
+ description?: string;
52
+ }
53
+ interface Document {
54
+ id: string;
55
+ title: string;
56
+ fileName: string | null;
57
+ mimeType: string | null;
58
+ fileSizeBytes: number | null;
59
+ status: string | null;
60
+ chunkCount: number | null;
61
+ createdAt: string;
62
+ }
63
+ interface UploadDocumentOptions {
64
+ knowledgeBaseId: string;
65
+ file: File | Blob;
66
+ fileName?: string;
67
+ }
68
+ interface UploadTextDocumentOptions {
69
+ knowledgeBaseId: string;
70
+ title: string;
71
+ content: string;
72
+ }
73
+ interface Chunk {
74
+ id: string;
75
+ documentId: string;
76
+ knowledgeBaseId: string;
77
+ content: string;
78
+ chunkIndex: number;
79
+ tokenCount: number;
80
+ isActive: boolean;
81
+ isEdited: boolean;
82
+ pinned: boolean;
83
+ boost: number;
84
+ originalContent: string | null;
85
+ modality: string;
86
+ createdAt: string;
87
+ }
88
+ interface ChunkListItem {
89
+ id: string;
90
+ content: string;
91
+ chunkIndex: number;
92
+ tokenCount: number;
93
+ isActive: boolean;
94
+ isEdited: boolean;
95
+ pinned: boolean;
96
+ boost: number;
97
+ modality: string;
98
+ createdAt: string;
99
+ }
100
+ interface ChunkListResponse {
101
+ chunks: ChunkListItem[];
102
+ documentId: string;
103
+ total: number;
104
+ }
105
+ interface CreateChunkOptions {
106
+ documentId: string;
107
+ knowledgeBaseId: string;
108
+ content: string;
109
+ insertAfterIndex?: number;
110
+ }
111
+ interface CreateChunkResponse {
112
+ id: string;
113
+ chunkIndex: number;
114
+ tokenCount: number;
115
+ status: string;
116
+ }
117
+ interface UpdateChunkOptions {
118
+ content?: string;
119
+ isActive?: boolean;
120
+ pinned?: boolean;
121
+ boost?: number;
122
+ }
123
+ interface UpdateChunkResponse {
124
+ id: string;
125
+ updated: boolean;
126
+ reembedding: boolean;
127
+ }
128
+ interface SplitChunkResponse {
129
+ split: boolean;
130
+ originalId: string;
131
+ chunks: {
132
+ id: string;
133
+ chunkIndex: number;
134
+ tokenCount: number;
135
+ }[];
136
+ }
137
+ type BulkAction = "activate" | "deactivate" | "pin" | "unpin" | "boost" | "delete";
138
+ interface BulkChunkOptions {
139
+ action: BulkAction;
140
+ chunkIds: string[];
141
+ boostValue?: number;
142
+ }
143
+ interface BulkChunkResponse {
144
+ action: string;
145
+ affected: number;
146
+ requested: number;
147
+ }
148
+ interface MergeChunkResponse {
149
+ merged: boolean;
150
+ originalIds: string[];
151
+ chunk: {
152
+ id: string;
153
+ chunkIndex: number;
154
+ tokenCount: number;
155
+ };
156
+ }
157
+ interface Tag {
158
+ id: string;
159
+ name: string;
160
+ description: string | null;
161
+ color: string | null;
162
+ documentCount?: number;
163
+ createdAt: string;
164
+ }
165
+ interface CreateTagOptions {
166
+ knowledgeBaseId: string;
167
+ name: string;
168
+ description?: string;
169
+ color?: string;
170
+ }
171
+ interface UpdateTagOptions {
172
+ name?: string;
173
+ description?: string;
174
+ color?: string;
175
+ }
176
+ interface Segment {
177
+ id: string;
178
+ name: string;
179
+ description: string | null;
180
+ color: string | null;
181
+ documentCount?: number;
182
+ createdAt: string;
183
+ }
184
+ interface CreateSegmentOptions {
185
+ knowledgeBaseId: string;
186
+ name: string;
187
+ description?: string;
188
+ color?: string;
189
+ }
190
+ interface UpdateSegmentOptions {
191
+ name?: string;
192
+ description?: string;
193
+ color?: string;
194
+ }
195
+ interface AnalyticsOverview {
196
+ totalQueries: number;
197
+ queriesToday: number;
198
+ queriesThisWeek: number;
199
+ avgLatencyMs: number;
200
+ avgResultCount: number;
201
+ avgTopScore: number;
202
+ }
203
+ interface QueriesPerDay {
204
+ date: string;
205
+ count: number;
206
+ }
207
+ interface TopQuery {
208
+ queryText: string;
209
+ count: number;
210
+ avgScore: number;
211
+ }
212
+ interface TopDocument {
213
+ documentId: string;
214
+ documentTitle: string;
215
+ hitCount: number;
216
+ }
217
+ interface GapQuery {
218
+ queryText: string;
219
+ count: number;
220
+ avgScore: number;
221
+ lastSeen: string;
222
+ }
223
+ interface KBForgeConfig {
224
+ apiKey: string;
225
+ baseUrl?: string;
226
+ }
227
+
228
+ declare class KBForgeError extends Error {
229
+ status: number;
230
+ constructor(message: string, status: number);
231
+ }
232
+ declare class KBForge {
233
+ private apiKey;
234
+ private baseUrl;
235
+ constructor(config: KBForgeConfig);
236
+ private request;
237
+ private requestRaw;
238
+ retrieve(options: RetrieveOptions): Promise<RetrieveResponse>;
239
+ chat(options: ChatOptions): Promise<AsyncIterable<ChatStreamEvent>>;
240
+ chatText(options: ChatOptions): Promise<string>;
241
+ private parseSSE;
242
+ readonly knowledgeBases: {
243
+ list: () => Promise<{
244
+ knowledgeBases: KnowledgeBase[];
245
+ }>;
246
+ create: (options: CreateKnowledgeBaseOptions) => Promise<KnowledgeBase>;
247
+ delete: (id: string) => Promise<{
248
+ deleted: boolean;
249
+ }>;
250
+ };
251
+ readonly documents: {
252
+ list: (knowledgeBaseId: string) => Promise<{
253
+ documents: Document[];
254
+ total: number;
255
+ }>;
256
+ upload: (options: UploadDocumentOptions) => Promise<{
257
+ id: string;
258
+ title: string;
259
+ status: string;
260
+ }>;
261
+ uploadText: (options: UploadTextDocumentOptions) => Promise<{
262
+ id: string;
263
+ title: string;
264
+ status: string;
265
+ }>;
266
+ delete: (id: string) => Promise<{
267
+ deleted: boolean;
268
+ }>;
269
+ };
270
+ readonly chunks: {
271
+ list: (documentId: string, options?: {
272
+ activeOnly?: boolean;
273
+ }) => Promise<ChunkListResponse>;
274
+ get: (id: string) => Promise<Chunk>;
275
+ create: (options: CreateChunkOptions) => Promise<CreateChunkResponse>;
276
+ update: (id: string, options: UpdateChunkOptions) => Promise<UpdateChunkResponse>;
277
+ delete: (id: string) => Promise<{
278
+ deleted: boolean;
279
+ }>;
280
+ split: (id: string, position: number) => Promise<SplitChunkResponse>;
281
+ bulk: (options: BulkChunkOptions) => Promise<BulkChunkResponse>;
282
+ merge: (chunkIds: string[]) => Promise<MergeChunkResponse>;
283
+ };
284
+ readonly tags: {
285
+ list: (knowledgeBaseId: string) => Promise<{
286
+ tags: Tag[];
287
+ }>;
288
+ create: (options: CreateTagOptions) => Promise<Tag>;
289
+ update: (id: string, options: UpdateTagOptions) => Promise<{
290
+ updated: boolean;
291
+ }>;
292
+ delete: (id: string) => Promise<{
293
+ deleted: boolean;
294
+ }>;
295
+ addDocuments: (tagId: string, documentIds: string[]) => Promise<{
296
+ added: number;
297
+ }>;
298
+ removeDocument: (tagId: string, documentId: string) => Promise<{
299
+ removed: boolean;
300
+ }>;
301
+ };
302
+ readonly segments: {
303
+ list: (knowledgeBaseId: string) => Promise<{
304
+ segments: Segment[];
305
+ }>;
306
+ create: (options: CreateSegmentOptions) => Promise<Segment>;
307
+ update: (id: string, options: UpdateSegmentOptions) => Promise<{
308
+ updated: boolean;
309
+ }>;
310
+ delete: (id: string) => Promise<{
311
+ deleted: boolean;
312
+ }>;
313
+ addDocuments: (segmentId: string, documentIds: string[]) => Promise<{
314
+ added: number;
315
+ }>;
316
+ removeDocument: (segmentId: string, documentId: string) => Promise<{
317
+ removed: boolean;
318
+ }>;
319
+ };
320
+ readonly analytics: {
321
+ overview: (knowledgeBaseId: string) => Promise<AnalyticsOverview>;
322
+ queriesPerDay: (knowledgeBaseId: string, days?: number) => Promise<{
323
+ data: QueriesPerDay[];
324
+ }>;
325
+ topQueries: (knowledgeBaseId: string, limit?: number) => Promise<{
326
+ data: TopQuery[];
327
+ }>;
328
+ topDocuments: (knowledgeBaseId: string, limit?: number) => Promise<{
329
+ data: TopDocument[];
330
+ }>;
331
+ gaps: (knowledgeBaseId: string, limit?: number) => Promise<{
332
+ data: GapQuery[];
333
+ }>;
334
+ };
335
+ }
336
+
337
+ export { type AnalyticsOverview, type BulkAction, type BulkChunkOptions, type BulkChunkResponse, type ChatMessage, type ChatOptions, type ChatStreamEvent, type Chunk, type ChunkListItem, type ChunkListResponse, type CreateChunkOptions, type CreateChunkResponse, type CreateKnowledgeBaseOptions, type CreateSegmentOptions, type CreateTagOptions, type Document, type GapQuery, KBForge, type KBForgeConfig, KBForgeError, type KnowledgeBase, type MergeChunkResponse, type QueriesPerDay, type RetrieveChunk, type RetrieveOptions, type RetrieveResponse, type Segment, type SplitChunkResponse, type Tag, type TopDocument, type TopQuery, type UpdateChunkOptions, type UpdateChunkResponse, type UpdateSegmentOptions, type UpdateTagOptions, type UploadDocumentOptions, type UploadTextDocumentOptions };
package/dist/index.js ADDED
@@ -0,0 +1,255 @@
1
+ // src/client.ts
2
+ var DEFAULT_BASE_URL = "https://kbforge.app";
3
+ var KBForgeError = class extends Error {
4
+ constructor(message, status) {
5
+ super(message);
6
+ this.name = "KBForgeError";
7
+ this.status = status;
8
+ }
9
+ };
10
+ var KBForge = class {
11
+ constructor(config) {
12
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
13
+ // Knowledge Bases (permission: "manage")
14
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
15
+ this.knowledgeBases = {
16
+ list: () => {
17
+ return this.request("GET", "/knowledge-bases");
18
+ },
19
+ create: (options) => {
20
+ return this.request("POST", "/knowledge-bases", options);
21
+ },
22
+ delete: (id) => {
23
+ return this.request("DELETE", `/knowledge-bases/${id}`);
24
+ }
25
+ };
26
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
27
+ // Documents (permission: "ingest" for upload, "manage" for list/delete)
28
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
29
+ this.documents = {
30
+ list: (knowledgeBaseId) => {
31
+ return this.request("GET", `/documents?kb=${knowledgeBaseId}`);
32
+ },
33
+ upload: async (options) => {
34
+ const formData = new FormData();
35
+ formData.append("file", options.file, options.fileName);
36
+ formData.append("knowledgeBaseId", options.knowledgeBaseId);
37
+ const res = await this.requestRaw("POST", "/documents", formData, {});
38
+ return res.json();
39
+ },
40
+ uploadText: (options) => {
41
+ return this.request("POST", "/documents", options);
42
+ },
43
+ delete: (id) => {
44
+ return this.request("DELETE", `/documents/${id}`);
45
+ }
46
+ };
47
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
48
+ // Chunks (permission: "chunks")
49
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
50
+ this.chunks = {
51
+ list: (documentId, options) => {
52
+ const params = new URLSearchParams({ document_id: documentId });
53
+ if (options?.activeOnly) params.set("active_only", "true");
54
+ return this.request("GET", `/chunks?${params}`);
55
+ },
56
+ get: (id) => {
57
+ return this.request("GET", `/chunks/${id}`);
58
+ },
59
+ create: (options) => {
60
+ return this.request("POST", "/chunks", options);
61
+ },
62
+ update: (id, options) => {
63
+ return this.request("PATCH", `/chunks/${id}`, options);
64
+ },
65
+ delete: (id) => {
66
+ return this.request("DELETE", `/chunks/${id}`);
67
+ },
68
+ split: (id, position) => {
69
+ return this.request("POST", `/chunks/${id}/split`, { position });
70
+ },
71
+ bulk: (options) => {
72
+ return this.request("POST", "/chunks/bulk", options);
73
+ },
74
+ merge: (chunkIds) => {
75
+ return this.request("POST", "/chunks/merge", { chunkIds });
76
+ }
77
+ };
78
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
79
+ // Tags (permission: "manage")
80
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
81
+ this.tags = {
82
+ list: (knowledgeBaseId) => {
83
+ return this.request("GET", `/tags?kb=${knowledgeBaseId}`);
84
+ },
85
+ create: (options) => {
86
+ return this.request("POST", "/tags", options);
87
+ },
88
+ update: (id, options) => {
89
+ return this.request("PATCH", `/tags/${id}`, options);
90
+ },
91
+ delete: (id) => {
92
+ return this.request("DELETE", `/tags/${id}`);
93
+ },
94
+ addDocuments: (tagId, documentIds) => {
95
+ return this.request("POST", `/tags/${tagId}/documents`, { documentIds });
96
+ },
97
+ removeDocument: (tagId, documentId) => {
98
+ return this.request("DELETE", `/tags/${tagId}/documents/${documentId}`);
99
+ }
100
+ };
101
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
102
+ // Segments (permission: "manage")
103
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
104
+ this.segments = {
105
+ list: (knowledgeBaseId) => {
106
+ return this.request("GET", `/segments?kb=${knowledgeBaseId}`);
107
+ },
108
+ create: (options) => {
109
+ return this.request("POST", "/segments", options);
110
+ },
111
+ update: (id, options) => {
112
+ return this.request("PATCH", `/segments/${id}`, options);
113
+ },
114
+ delete: (id) => {
115
+ return this.request("DELETE", `/segments/${id}`);
116
+ },
117
+ addDocuments: (segmentId, documentIds) => {
118
+ return this.request("POST", `/segments/${segmentId}/documents`, {
119
+ documentIds
120
+ });
121
+ },
122
+ removeDocument: (segmentId, documentId) => {
123
+ return this.request(
124
+ "DELETE",
125
+ `/segments/${segmentId}/documents/${documentId}`
126
+ );
127
+ }
128
+ };
129
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
130
+ // Analytics (permission: "admin")
131
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
132
+ this.analytics = {
133
+ overview: (knowledgeBaseId) => {
134
+ return this.request("GET", `/analytics?kb=${knowledgeBaseId}`);
135
+ },
136
+ queriesPerDay: (knowledgeBaseId, days) => {
137
+ const params = new URLSearchParams({ kb: knowledgeBaseId });
138
+ if (days) params.set("days", String(days));
139
+ return this.request("GET", `/analytics/queries-per-day?${params}`);
140
+ },
141
+ topQueries: (knowledgeBaseId, limit) => {
142
+ const params = new URLSearchParams({ kb: knowledgeBaseId });
143
+ if (limit) params.set("limit", String(limit));
144
+ return this.request("GET", `/analytics/top-queries?${params}`);
145
+ },
146
+ topDocuments: (knowledgeBaseId, limit) => {
147
+ const params = new URLSearchParams({ kb: knowledgeBaseId });
148
+ if (limit) params.set("limit", String(limit));
149
+ return this.request("GET", `/analytics/top-documents?${params}`);
150
+ },
151
+ gaps: (knowledgeBaseId, limit) => {
152
+ const params = new URLSearchParams({ kb: knowledgeBaseId });
153
+ if (limit) params.set("limit", String(limit));
154
+ return this.request("GET", `/analytics/gaps?${params}`);
155
+ }
156
+ };
157
+ if (!config.apiKey) throw new Error("apiKey is required");
158
+ this.apiKey = config.apiKey;
159
+ this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\/$/, "");
160
+ }
161
+ async request(method, path, body) {
162
+ const url = `${this.baseUrl}/api/v1${path}`;
163
+ const res = await fetch(url, {
164
+ method,
165
+ headers: {
166
+ Authorization: `Bearer ${this.apiKey}`,
167
+ "Content-Type": "application/json"
168
+ },
169
+ body: body ? JSON.stringify(body) : void 0
170
+ });
171
+ if (!res.ok) {
172
+ const data = await res.json().catch(() => ({ error: res.statusText }));
173
+ throw new KBForgeError(
174
+ data.error || `Request failed with status ${res.status}`,
175
+ res.status
176
+ );
177
+ }
178
+ return res.json();
179
+ }
180
+ async requestRaw(method, path, body, headers) {
181
+ const url = `${this.baseUrl}/api/v1${path}`;
182
+ const res = await fetch(url, {
183
+ method,
184
+ headers: {
185
+ Authorization: `Bearer ${this.apiKey}`,
186
+ ...headers,
187
+ ...body && !headers?.["Content-Type"] ? { "Content-Type": "application/json" } : {}
188
+ },
189
+ body: body instanceof FormData ? body : body ? JSON.stringify(body) : void 0
190
+ });
191
+ if (!res.ok) {
192
+ const data = await res.json().catch(() => ({ error: res.statusText }));
193
+ throw new KBForgeError(
194
+ data.error || `Request failed with status ${res.status}`,
195
+ res.status
196
+ );
197
+ }
198
+ return res;
199
+ }
200
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
201
+ // Retrieve (permission: "retrieve")
202
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
203
+ async retrieve(options) {
204
+ return this.request("POST", "/retrieve", options);
205
+ }
206
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
207
+ // Chat (permission: "retrieve")
208
+ // ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
209
+ async chat(options) {
210
+ const res = await this.requestRaw("POST", "/chat", options);
211
+ if (!res.body) {
212
+ throw new KBForgeError("No response body", 500);
213
+ }
214
+ return this.parseSSE(res.body);
215
+ }
216
+ async chatText(options) {
217
+ const stream = await this.chat(options);
218
+ let text = "";
219
+ for await (const event of stream) {
220
+ text += event.content;
221
+ }
222
+ return text;
223
+ }
224
+ async *parseSSE(body) {
225
+ const reader = body.getReader();
226
+ const decoder = new TextDecoder();
227
+ let buffer = "";
228
+ try {
229
+ while (true) {
230
+ const { done, value } = await reader.read();
231
+ if (done) break;
232
+ buffer += decoder.decode(value, { stream: true });
233
+ const lines = buffer.split("\n");
234
+ buffer = lines.pop() || "";
235
+ for (const line of lines) {
236
+ const trimmed = line.trim();
237
+ if (!trimmed || !trimmed.startsWith("data: ")) continue;
238
+ const data = trimmed.slice(6);
239
+ if (data === "[DONE]") return;
240
+ try {
241
+ const parsed = JSON.parse(data);
242
+ if (parsed.content) yield parsed;
243
+ } catch {
244
+ }
245
+ }
246
+ }
247
+ } finally {
248
+ reader.releaseLock();
249
+ }
250
+ }
251
+ };
252
+ export {
253
+ KBForge,
254
+ KBForgeError
255
+ };
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@kbforge/sdk",
3
+ "version": "0.1.0",
4
+ "description": "TypeScript SDK for the KBForge API — semantic search and RAG chat over your knowledge bases",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsup",
21
+ "dev": "tsup --watch",
22
+ "prepublishOnly": "npm run build"
23
+ },
24
+ "devDependencies": {
25
+ "tsup": "^8.5.1",
26
+ "typescript": "^5.9.3"
27
+ },
28
+ "keywords": [
29
+ "kbforge",
30
+ "knowledge-base",
31
+ "rag",
32
+ "semantic-search",
33
+ "sdk",
34
+ "api"
35
+ ],
36
+ "license": "MIT",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "https://github.com/Avililla/kbforge",
40
+ "directory": "packages/sdk"
41
+ }
42
+ }