@littlebigbrain/client 0.1.0 → 0.3.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/LICENSE +56 -0
- package/README.md +56 -15
- package/dist/client.d.ts +213 -460
- package/dist/client.js +391 -350
- package/dist/index.d.ts +1 -1
- package/dist/namespaces.d.ts +185 -0
- package/dist/namespaces.js +469 -0
- package/dist/schema.d.ts +10857 -3600
- package/dist/transport.d.ts +44 -0
- package/dist/transport.js +93 -0
- package/dist/types.d.ts +299 -0
- package/dist/types.js +47 -0
- package/package.json +35 -6
- package/dist/client.test.d.ts +0 -1
- package/dist/client.test.js +0 -591
- package/dist/contract-routes.test.d.ts +0 -1
- package/dist/contract-routes.test.js +0 -74
- package/src/client.test.ts +0 -673
- package/src/client.ts +0 -1428
- package/src/contract-routes.test.ts +0 -91
- package/src/index.ts +0 -16
- package/src/node-test-shim.d.ts +0 -16
- package/src/schema.ts +0 -13865
package/src/client.ts
DELETED
|
@@ -1,1428 +0,0 @@
|
|
|
1
|
-
import type { components } from "./schema.js";
|
|
2
|
-
|
|
3
|
-
/** Request/response types, generated from the committed OpenAPI spec. */
|
|
4
|
-
export type Schemas = components["schemas"];
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* The unified list-response envelope returned by every collection read
|
|
8
|
-
* (`/v1/graph/entities`, `/v1/graph/edges`, `/v1/graph/observations`): the rows
|
|
9
|
-
* in `data`, plus `next_cursor` (echo back as `cursor` for the next page) and
|
|
10
|
-
* the pre-page `total_count`. Walk pages with {@link LbbClient.listAll}.
|
|
11
|
-
*/
|
|
12
|
-
export interface ListResponse<T> {
|
|
13
|
-
object: "list";
|
|
14
|
-
data: T[];
|
|
15
|
-
has_more: boolean;
|
|
16
|
-
next_cursor: string | null;
|
|
17
|
-
snapshot: Schemas["SnapshotView"];
|
|
18
|
-
total_count: number;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* A flat `{ field: value }` property map. Values are coerced to each field's
|
|
23
|
-
* declared type server-side, so a string like `"2026-06-26"` lands in a
|
|
24
|
-
* `date_time` field and `"52"` in an `i64` field. The verbose
|
|
25
|
-
* `Schemas["PropertyInput"][]` form is also accepted.
|
|
26
|
-
*/
|
|
27
|
-
export type FlatProperties = Record<string, string | number | boolean>;
|
|
28
|
-
|
|
29
|
-
/** A single entity-properties record for commit/import, with flat or verbose properties. */
|
|
30
|
-
export type EntityPropertiesLine = {
|
|
31
|
-
type: string;
|
|
32
|
-
name: string;
|
|
33
|
-
/** Optional stable external key; identity becomes `(type, key)`. */
|
|
34
|
-
key?: string;
|
|
35
|
-
properties: FlatProperties | Schemas["PropertyInput"][];
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
/** One bulk-import line: a triplet, or an entity-properties record. */
|
|
39
|
-
export type ImportLine = Schemas["TripletInput"] | EntityPropertiesLine;
|
|
40
|
-
|
|
41
|
-
export type AttributeFilterOp = "eq" | "ne" | "lt" | "le" | "gt" | "ge";
|
|
42
|
-
|
|
43
|
-
export type AttributeFilterValue =
|
|
44
|
-
| string
|
|
45
|
-
| number
|
|
46
|
-
| boolean
|
|
47
|
-
| { dateTime: string }
|
|
48
|
-
| { entity: Schemas["EntitySelector"] };
|
|
49
|
-
|
|
50
|
-
export interface AttributeFilter {
|
|
51
|
-
/** Query variable whose typed property should be compared. Defaults to the first bound pattern variable. */
|
|
52
|
-
var?: string;
|
|
53
|
-
/** Ontology property field name, e.g. `status`, `score`, or `committed_at`. */
|
|
54
|
-
field: string;
|
|
55
|
-
/** Comparison operator. Defaults to `eq`. */
|
|
56
|
-
op?: AttributeFilterOp;
|
|
57
|
-
value: AttributeFilterValue;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export interface EntityAttributeFilterOptions {
|
|
61
|
-
/** Relation patterns that bind the entity variable(s) before attribute filters run. */
|
|
62
|
-
patterns: Schemas["AnalyticTriplePattern"][];
|
|
63
|
-
/** One or more typed-property comparisons. */
|
|
64
|
-
where: AttributeFilter | AttributeFilter[];
|
|
65
|
-
/** Additional raw structured-SPARQL filters to AND with `where`. */
|
|
66
|
-
filters?: Schemas["SparqlFilter"][];
|
|
67
|
-
select?: string[];
|
|
68
|
-
limit?: number;
|
|
69
|
-
offset?: number;
|
|
70
|
-
asOfValidTime?: string;
|
|
71
|
-
asOfCommitSeq?: number;
|
|
72
|
-
orderBy?: Schemas["SparqlOrderBy"][];
|
|
73
|
-
reason?: boolean;
|
|
74
|
-
maxSolutions?: number;
|
|
75
|
-
maxObjectReads?: number;
|
|
76
|
-
maxFetchedBytes?: number;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Minimal structural shape of `fetch`, so the client depends on neither the DOM
|
|
81
|
-
* lib nor a specific runtime. Native `fetch` (Node 18+, browsers, workers)
|
|
82
|
-
* satisfies it; tests can pass a fake.
|
|
83
|
-
*/
|
|
84
|
-
export type FetchLike = (
|
|
85
|
-
input: string,
|
|
86
|
-
init?: { method?: string; headers?: Record<string, string>; body?: string },
|
|
87
|
-
) => Promise<{
|
|
88
|
-
ok: boolean;
|
|
89
|
-
status: number;
|
|
90
|
-
headers?: { get(name: string): string | null };
|
|
91
|
-
text(): Promise<string>;
|
|
92
|
-
}>;
|
|
93
|
-
|
|
94
|
-
/** One term in a SPARQL result binding (the standard results-JSON term object). */
|
|
95
|
-
export interface SparqlTerm {
|
|
96
|
-
type: "uri" | "literal" | "bnode" | "typed-literal";
|
|
97
|
-
value: string;
|
|
98
|
-
datatype?: string;
|
|
99
|
-
"xml:lang"?: string;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/** The standard SPARQL 1.1 Query Results JSON document. */
|
|
103
|
-
export interface SparqlResultsJson {
|
|
104
|
-
head: { vars?: string[]; link?: string[] };
|
|
105
|
-
results?: { bindings: Record<string, SparqlTerm>[] };
|
|
106
|
-
boolean?: boolean;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/** Parsed SPARQL results: the head vars, the ASK boolean (or null), the raw
|
|
110
|
-
* typed bindings, and the bindings flattened to `{ variable: lexicalValue }`. */
|
|
111
|
-
export interface SparqlResults {
|
|
112
|
-
vars: string[];
|
|
113
|
-
boolean: boolean | null;
|
|
114
|
-
bindings: Record<string, SparqlTerm>[];
|
|
115
|
-
rows: Record<string, string>[];
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Parse a {@link Schemas.SparqlTextResponse} (whose `results` field carries the
|
|
120
|
-
* SPARQL Results document as a JSON *string*) into typed bindings plus flat
|
|
121
|
-
* `{ variable: lexicalValue }` rows — the form most callers want, so they never
|
|
122
|
-
* have to `JSON.parse` and zip `head.vars` with binding values by hand.
|
|
123
|
-
*/
|
|
124
|
-
export function parseSparqlResults(response: Schemas["SparqlTextResponse"]): SparqlResults {
|
|
125
|
-
const doc = JSON.parse(response.results) as SparqlResultsJson;
|
|
126
|
-
const vars = doc.head?.vars ?? [];
|
|
127
|
-
if (typeof doc.boolean === "boolean") {
|
|
128
|
-
return { vars, boolean: doc.boolean, bindings: [], rows: [] };
|
|
129
|
-
}
|
|
130
|
-
const bindings = doc.results?.bindings ?? [];
|
|
131
|
-
const rows = bindings.map((binding) =>
|
|
132
|
-
Object.fromEntries(Object.entries(binding).map(([name, term]) => [name, term.value])),
|
|
133
|
-
);
|
|
134
|
-
return { vars, boolean: null, bindings, rows };
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
function firstPatternVariable(patterns: Schemas["AnalyticTriplePattern"][]): string {
|
|
138
|
-
for (const pattern of patterns) {
|
|
139
|
-
if ("var" in pattern.subject) return pattern.subject.var;
|
|
140
|
-
if ("var" in pattern.object) return pattern.object.var;
|
|
141
|
-
}
|
|
142
|
-
return "entity";
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function attributeFilterValue(value: AttributeFilterValue): Schemas["SparqlValue"] {
|
|
146
|
-
if (typeof value === "boolean") return { bool: value };
|
|
147
|
-
if (typeof value === "number") return Number.isInteger(value) ? { i64: value } : { f64: value };
|
|
148
|
-
if (typeof value === "string") return { str: value };
|
|
149
|
-
if ("dateTime" in value) return { date_time: value.dateTime };
|
|
150
|
-
return { entity: value.entity };
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
function attributeFilter(filter: AttributeFilter, defaultVar: string): Schemas["SparqlFilter"] {
|
|
154
|
-
return {
|
|
155
|
-
compare: {
|
|
156
|
-
op: filter.op ?? "eq",
|
|
157
|
-
left: { property: { var: filter.var ?? defaultVar, field: filter.field } },
|
|
158
|
-
right: { value: attributeFilterValue(filter.value) },
|
|
159
|
-
},
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
export interface LbbClientOptions {
|
|
164
|
-
/** Base URL of the Little Big Brain server, e.g. `https://db.eu.littlebigbrain.com`. */
|
|
165
|
-
baseUrl: string;
|
|
166
|
-
/** Stack API key (`lbb_sk_test_…` / `lbb_sk_live_…`) or single-mode token. */
|
|
167
|
-
apiKey?: string;
|
|
168
|
-
/** Graph name (sent as `?graph=`; server default is `main`). */
|
|
169
|
-
graph?: string;
|
|
170
|
-
/** Branch name (sent as `?branch=`; server default is `main`). */
|
|
171
|
-
branch?: string;
|
|
172
|
-
/**
|
|
173
|
-
* Stack slug (sent as `?stack=`). Needed only with a session-token `apiKey`
|
|
174
|
-
* (`lbb_ses_…`), which authorizes an account rather than a single stack; a
|
|
175
|
-
* stack API key (`lbb_sk_test_…` / `lbb_sk_live_…`) already fixes the stack and ignores this.
|
|
176
|
-
*/
|
|
177
|
-
stack?: string;
|
|
178
|
-
/** Override the fetch implementation (defaults to the global `fetch`). */
|
|
179
|
-
fetch?: FetchLike;
|
|
180
|
-
/** API version header sent on every request. Defaults to the beta reset contract. */
|
|
181
|
-
apiVersion?: string;
|
|
182
|
-
/** Retry count for 429/5xx responses and network failures. Defaults to 2. */
|
|
183
|
-
maxRetries?: number;
|
|
184
|
-
/** Base delay between retries. Defaults to 100ms. Tests can set 0. */
|
|
185
|
-
retryDelayMs?: number;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
export interface LbbStackView {
|
|
189
|
-
stack_id: string;
|
|
190
|
-
owner_id?: string;
|
|
191
|
-
name: string;
|
|
192
|
-
slug: string;
|
|
193
|
-
tenant_id: string;
|
|
194
|
-
default_graph: string;
|
|
195
|
-
default_branch: string;
|
|
196
|
-
created_at_micros: number;
|
|
197
|
-
api_key_hint: string;
|
|
198
|
-
api_key_rotated_at_micros: number;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
export interface LbbAdminStackCreateRequest {
|
|
202
|
-
owner_id: string;
|
|
203
|
-
name: string;
|
|
204
|
-
slug?: string;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
export interface LbbAdminStackResponse {
|
|
208
|
-
ok: true;
|
|
209
|
-
stack: LbbStackView;
|
|
210
|
-
api_key?: string;
|
|
211
|
-
active_api_key_count?: number;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
export type LbbStackActivityWindow = "1h" | "4h" | "12h" | "24h";
|
|
215
|
-
|
|
216
|
-
export interface LbbStackActivityResponse {
|
|
217
|
-
ok: true;
|
|
218
|
-
stack: {
|
|
219
|
-
slug: string;
|
|
220
|
-
name?: string;
|
|
221
|
-
};
|
|
222
|
-
window: {
|
|
223
|
-
range: LbbStackActivityWindow;
|
|
224
|
-
from_micros: number;
|
|
225
|
-
to_micros: number;
|
|
226
|
-
bucket_seconds: number;
|
|
227
|
-
freshness_seconds: number;
|
|
228
|
-
};
|
|
229
|
-
totals: {
|
|
230
|
-
requests: number;
|
|
231
|
-
errors: number;
|
|
232
|
-
p50_latency_ms: number;
|
|
233
|
-
p95_latency_ms: number;
|
|
234
|
-
p99_latency_ms: number;
|
|
235
|
-
storage_read_ops: number;
|
|
236
|
-
storage_read_bytes: number;
|
|
237
|
-
storage_write_ops: number;
|
|
238
|
-
storage_write_bytes: number;
|
|
239
|
-
index_read_ops: number;
|
|
240
|
-
index_read_bytes: number;
|
|
241
|
-
};
|
|
242
|
-
details: {
|
|
243
|
-
total_bucket_count: number;
|
|
244
|
-
active_bucket_count: number;
|
|
245
|
-
error_rate: number;
|
|
246
|
-
storage_total_ops: number;
|
|
247
|
-
storage_total_bytes: number;
|
|
248
|
-
non_index_storage_read_ops: number;
|
|
249
|
-
non_index_storage_read_bytes: number;
|
|
250
|
-
index_read_share: number;
|
|
251
|
-
first_activity_bucket_start_micros?: number;
|
|
252
|
-
last_activity_bucket_start_micros?: number;
|
|
253
|
-
};
|
|
254
|
-
series: Array<{
|
|
255
|
-
bucket_start_micros: number;
|
|
256
|
-
requests: number;
|
|
257
|
-
errors: number;
|
|
258
|
-
p50_latency_ms: number;
|
|
259
|
-
p95_latency_ms: number;
|
|
260
|
-
p99_latency_ms: number;
|
|
261
|
-
storage_read_ops: number;
|
|
262
|
-
storage_read_bytes: number;
|
|
263
|
-
storage_write_ops: number;
|
|
264
|
-
storage_write_bytes: number;
|
|
265
|
-
index_read_ops: number;
|
|
266
|
-
index_read_bytes: number;
|
|
267
|
-
}>;
|
|
268
|
-
routes: Array<{
|
|
269
|
-
family: string;
|
|
270
|
-
requests: number;
|
|
271
|
-
errors: number;
|
|
272
|
-
error_rate: number;
|
|
273
|
-
request_share: number;
|
|
274
|
-
p50_latency_ms: number;
|
|
275
|
-
p95_latency_ms: number;
|
|
276
|
-
p99_latency_ms: number;
|
|
277
|
-
}>;
|
|
278
|
-
storage: Array<{
|
|
279
|
-
family: string;
|
|
280
|
-
read_ops: number;
|
|
281
|
-
read_bytes: number;
|
|
282
|
-
write_ops: number;
|
|
283
|
-
write_bytes: number;
|
|
284
|
-
total_ops: number;
|
|
285
|
-
total_bytes: number;
|
|
286
|
-
op_share: number;
|
|
287
|
-
byte_share: number;
|
|
288
|
-
}>;
|
|
289
|
-
partial: boolean;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
export interface LbbAdminSessionResponse {
|
|
293
|
-
ok: true;
|
|
294
|
-
/** A `lbb_ses_…` session token scoped to the account. */
|
|
295
|
-
token: string;
|
|
296
|
-
expires_at_micros: number;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
export interface LbbAdminStackDeleteResponse {
|
|
300
|
-
ok: true;
|
|
301
|
-
deleted_stack: LbbStackView;
|
|
302
|
-
tenant_prefix: string;
|
|
303
|
-
objects_deleted: number;
|
|
304
|
-
bytes_deleted: number;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
export interface LbbErrorPayload {
|
|
308
|
-
type?: string;
|
|
309
|
-
code?: string;
|
|
310
|
-
message?: string;
|
|
311
|
-
param?: string | null;
|
|
312
|
-
request_id?: string | null;
|
|
313
|
-
doc_url?: string | null;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
export interface RawLbbResponse<T> {
|
|
317
|
-
data: T;
|
|
318
|
-
status: number;
|
|
319
|
-
requestId?: string;
|
|
320
|
-
version?: string;
|
|
321
|
-
headers?: { get(name: string): string | null };
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
export interface RequestOptions {
|
|
325
|
-
query?: Query;
|
|
326
|
-
body?: unknown;
|
|
327
|
-
/** Pre-serialized request body (e.g. NDJSON). Takes precedence over `body`. */
|
|
328
|
-
rawBody?: string;
|
|
329
|
-
/** Overrides the default `application/json` content type (used with `rawBody`). */
|
|
330
|
-
contentType?: string;
|
|
331
|
-
idempotencyKey?: string;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
/** Thrown when the server responds with a non-2xx status. */
|
|
335
|
-
export class LbbError extends Error {
|
|
336
|
-
readonly type?: string;
|
|
337
|
-
readonly code?: string;
|
|
338
|
-
readonly param?: string | null;
|
|
339
|
-
readonly requestId?: string | null;
|
|
340
|
-
readonly docUrl?: string | null;
|
|
341
|
-
|
|
342
|
-
constructor(
|
|
343
|
-
readonly status: number,
|
|
344
|
-
readonly body: string,
|
|
345
|
-
readonly error?: LbbErrorPayload,
|
|
346
|
-
) {
|
|
347
|
-
super(error?.message ?? `Little Big Brain ${status}: ${body}`);
|
|
348
|
-
this.name = "LbbError";
|
|
349
|
-
this.type = error?.type;
|
|
350
|
-
this.code = error?.code;
|
|
351
|
-
this.param = error?.param;
|
|
352
|
-
this.requestId = error?.request_id;
|
|
353
|
-
this.docUrl = error?.doc_url;
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
type QueryValue = string | number | boolean | undefined;
|
|
358
|
-
type Query = Record<string, QueryValue>;
|
|
359
|
-
|
|
360
|
-
function sleep(ms: number): Promise<void> {
|
|
361
|
-
if (ms <= 0) return Promise.resolve();
|
|
362
|
-
const timer = (globalThis as { setTimeout?: (callback: () => void, ms: number) => unknown })
|
|
363
|
-
.setTimeout;
|
|
364
|
-
return new Promise((resolve) => {
|
|
365
|
-
if (timer) {
|
|
366
|
-
timer(resolve, ms);
|
|
367
|
-
} else {
|
|
368
|
-
resolve();
|
|
369
|
-
}
|
|
370
|
-
});
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
function retryableStatus(status: number): boolean {
|
|
374
|
-
return status === 429 || status >= 500;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
function retryAllowed(method: string, idempotencyKey?: string): boolean {
|
|
378
|
-
const upper = method.toUpperCase();
|
|
379
|
-
return upper === "GET" || upper === "HEAD" || upper === "OPTIONS" || idempotencyKey !== undefined;
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
function parseLbbError(status: number, body: string, fallbackRequestId?: string): LbbError {
|
|
383
|
-
try {
|
|
384
|
-
const parsed = JSON.parse(body) as { error?: LbbErrorPayload };
|
|
385
|
-
if (parsed.error) {
|
|
386
|
-
return new LbbError(status, body, {
|
|
387
|
-
...parsed.error,
|
|
388
|
-
request_id: parsed.error.request_id ?? fallbackRequestId ?? null,
|
|
389
|
-
});
|
|
390
|
-
}
|
|
391
|
-
} catch {
|
|
392
|
-
// Fall through to an unstructured error.
|
|
393
|
-
}
|
|
394
|
-
return new LbbError(status, body, {
|
|
395
|
-
type: "api_error",
|
|
396
|
-
code: "unstructured_error",
|
|
397
|
-
message: body || `Little Big Brain ${status}`,
|
|
398
|
-
request_id: fallbackRequestId ?? null,
|
|
399
|
-
});
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
/**
|
|
403
|
-
* A typed HTTP client for a Little Big Brain graph server. One instance is scoped to a
|
|
404
|
-
* single graph/branch; construct another for a different scope. All methods
|
|
405
|
-
* return the parsed JSON response and throw {@link LbbError} on failure.
|
|
406
|
-
*/
|
|
407
|
-
export class LbbClient {
|
|
408
|
-
private readonly baseUrl: string;
|
|
409
|
-
private readonly apiKey?: string;
|
|
410
|
-
private readonly graphName?: string;
|
|
411
|
-
private readonly branchName?: string;
|
|
412
|
-
private readonly stack?: string;
|
|
413
|
-
private readonly fetchImpl: FetchLike;
|
|
414
|
-
private readonly apiVersion: string;
|
|
415
|
-
private readonly maxRetries: number;
|
|
416
|
-
private readonly retryDelayMs: number;
|
|
417
|
-
|
|
418
|
-
readonly search: SearchNamespace;
|
|
419
|
-
readonly indexes: IndexNamespace;
|
|
420
|
-
readonly entities: EntityNamespace;
|
|
421
|
-
readonly schema: SchemaNamespace;
|
|
422
|
-
|
|
423
|
-
constructor(options: LbbClientOptions) {
|
|
424
|
-
this.baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
425
|
-
this.apiKey = options.apiKey;
|
|
426
|
-
this.graphName = options.graph;
|
|
427
|
-
this.branchName = options.branch;
|
|
428
|
-
this.stack = options.stack;
|
|
429
|
-
this.apiVersion = options.apiVersion ?? "2026-06-22";
|
|
430
|
-
this.maxRetries = options.maxRetries ?? 2;
|
|
431
|
-
this.retryDelayMs = options.retryDelayMs ?? 100;
|
|
432
|
-
const fallback = (globalThis as { fetch?: FetchLike }).fetch;
|
|
433
|
-
const chosen = options.fetch ?? (fallback ? fallback.bind(globalThis) : undefined);
|
|
434
|
-
if (!chosen) {
|
|
435
|
-
throw new Error("no fetch implementation available; pass options.fetch");
|
|
436
|
-
}
|
|
437
|
-
this.fetchImpl = chosen;
|
|
438
|
-
this.search = new SearchNamespace(this);
|
|
439
|
-
this.indexes = new IndexNamespace(this);
|
|
440
|
-
this.entities = new EntityNamespace(this);
|
|
441
|
-
this.schema = new SchemaNamespace(this);
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
graph(name: string, opts: { branch?: string; stack?: string } = {}): GraphNamespace {
|
|
445
|
-
return new GraphNamespace(
|
|
446
|
-
this.withScope({
|
|
447
|
-
graph: name,
|
|
448
|
-
branch: opts.branch ?? this.branchName,
|
|
449
|
-
stack: opts.stack ?? this.stack,
|
|
450
|
-
}),
|
|
451
|
-
);
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
/**
|
|
455
|
-
* A new client for a different graph/branch on the same server and credential.
|
|
456
|
-
* Each instance is scoped to one graph/branch, so use this to target another
|
|
457
|
-
* scope (e.g. creating a fresh graph) without mutating the current client.
|
|
458
|
-
*/
|
|
459
|
-
withScope(scope: { graph?: string; branch?: string; stack?: string }): LbbClient {
|
|
460
|
-
return new LbbClient({
|
|
461
|
-
baseUrl: this.baseUrl,
|
|
462
|
-
apiKey: this.apiKey,
|
|
463
|
-
graph: scope.graph ?? this.graphName,
|
|
464
|
-
branch: scope.branch ?? this.branchName,
|
|
465
|
-
stack: scope.stack ?? this.stack,
|
|
466
|
-
fetch: this.fetchImpl,
|
|
467
|
-
apiVersion: this.apiVersion,
|
|
468
|
-
maxRetries: this.maxRetries,
|
|
469
|
-
retryDelayMs: this.retryDelayMs,
|
|
470
|
-
});
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
private buildUrl(path: string, query?: Query): string {
|
|
474
|
-
const params: string[] = [];
|
|
475
|
-
const push = (key: string, value: string | number | boolean) =>
|
|
476
|
-
params.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
|
|
477
|
-
if (this.graphName !== undefined) push("graph", this.graphName);
|
|
478
|
-
if (this.branchName !== undefined) push("branch", this.branchName);
|
|
479
|
-
if (this.stack !== undefined) push("stack", this.stack);
|
|
480
|
-
for (const [key, value] of Object.entries(query ?? {})) {
|
|
481
|
-
if (value !== undefined) push(key, value);
|
|
482
|
-
}
|
|
483
|
-
const qs = params.length > 0 ? `?${params.join("&")}` : "";
|
|
484
|
-
return `${this.baseUrl}${path}${qs}`;
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
async rawRequest<T>(
|
|
488
|
-
method: string,
|
|
489
|
-
path: string,
|
|
490
|
-
opts: RequestOptions = {},
|
|
491
|
-
): Promise<RawLbbResponse<T>> {
|
|
492
|
-
const headers: Record<string, string> = {
|
|
493
|
-
"content-type": opts.contentType ?? "application/json",
|
|
494
|
-
"lbb-version": this.apiVersion,
|
|
495
|
-
};
|
|
496
|
-
if (this.apiKey !== undefined) headers["authorization"] = `Bearer ${this.apiKey}`;
|
|
497
|
-
if (opts.idempotencyKey !== undefined) headers["idempotency-key"] = opts.idempotencyKey;
|
|
498
|
-
const canRetry = retryAllowed(method, opts.idempotencyKey);
|
|
499
|
-
const body =
|
|
500
|
-
opts.rawBody !== undefined
|
|
501
|
-
? opts.rawBody
|
|
502
|
-
: opts.body !== undefined
|
|
503
|
-
? JSON.stringify(opts.body)
|
|
504
|
-
: undefined;
|
|
505
|
-
const init = {
|
|
506
|
-
method,
|
|
507
|
-
headers,
|
|
508
|
-
body,
|
|
509
|
-
};
|
|
510
|
-
let response: Awaited<ReturnType<FetchLike>> | undefined;
|
|
511
|
-
let text = "";
|
|
512
|
-
for (let attempt = 0; attempt <= this.maxRetries; attempt += 1) {
|
|
513
|
-
try {
|
|
514
|
-
response = await this.fetchImpl(this.buildUrl(path, opts.query), init);
|
|
515
|
-
text = await response.text();
|
|
516
|
-
} catch (error) {
|
|
517
|
-
if (canRetry && attempt < this.maxRetries) {
|
|
518
|
-
await sleep(this.retryDelayMs * (attempt + 1));
|
|
519
|
-
continue;
|
|
520
|
-
}
|
|
521
|
-
throw error;
|
|
522
|
-
}
|
|
523
|
-
if (response.ok || !retryableStatus(response.status) || attempt === this.maxRetries) {
|
|
524
|
-
break;
|
|
525
|
-
}
|
|
526
|
-
if (!canRetry) {
|
|
527
|
-
break;
|
|
528
|
-
}
|
|
529
|
-
await sleep(this.retryDelayMs * (attempt + 1));
|
|
530
|
-
}
|
|
531
|
-
if (response === undefined) throw new Error("request did not produce a response");
|
|
532
|
-
const requestId = response.headers?.get("x-request-id") ?? undefined;
|
|
533
|
-
const version = response.headers?.get("lbb-version") ?? undefined;
|
|
534
|
-
if (!response.ok) throw parseLbbError(response.status, text.trim(), requestId);
|
|
535
|
-
return {
|
|
536
|
-
data: (text ? JSON.parse(text) : undefined) as T,
|
|
537
|
-
status: response.status,
|
|
538
|
-
requestId,
|
|
539
|
-
version,
|
|
540
|
-
headers: response.headers,
|
|
541
|
-
};
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
async request<T>(
|
|
545
|
-
method: string,
|
|
546
|
-
path: string,
|
|
547
|
-
opts: RequestOptions = {},
|
|
548
|
-
): Promise<T> {
|
|
549
|
-
const response = await this.rawRequest<T>(method, path, opts);
|
|
550
|
-
return response.data;
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
private mutationKey(prefix: string): string {
|
|
554
|
-
const random = Math.random().toString(36).slice(2);
|
|
555
|
-
return `${prefix}:${Date.now()}:${random}`;
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
idempotencyKey(prefix = "request"): string {
|
|
559
|
-
return this.mutationKey(prefix);
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
// --- writes ---
|
|
563
|
-
|
|
564
|
-
/** Commit triplets and optional entity embeddings. Prefer `client.graph("main").facts.create(...)`. */
|
|
565
|
-
commit(
|
|
566
|
-
body: Schemas["TripletCommitFile"],
|
|
567
|
-
opts: { idempotencyKey?: string } = {},
|
|
568
|
-
): Promise<Schemas["GraphCommitResponse"]> {
|
|
569
|
-
return this.request("POST", "/v1/graph/commit", {
|
|
570
|
-
body,
|
|
571
|
-
idempotencyKey: opts.idempotencyKey ?? this.idempotencyKey("facts.create"),
|
|
572
|
-
});
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
/**
|
|
576
|
-
* Validate-only preflight: run the same ontology/schema validation a real
|
|
577
|
-
* commit would and report the would-be effect (`op_count`, `written_properties`,
|
|
578
|
-
* `schema_validation`) without writing. A rejected request fails exactly as a
|
|
579
|
-
* real commit would, so this is a safe check before mutating. No idempotency
|
|
580
|
-
* key needed — nothing is persisted.
|
|
581
|
-
*/
|
|
582
|
-
commitDryRun(
|
|
583
|
-
body: Schemas["TripletCommitFile"],
|
|
584
|
-
): Promise<Schemas["GraphCommitDryRunResponse"]> {
|
|
585
|
-
return this.request("POST", "/v1/graph/commit", {
|
|
586
|
-
body,
|
|
587
|
-
query: { dry_run: true },
|
|
588
|
-
});
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
/**
|
|
592
|
-
* Bulk-ingest a dataset as NDJSON. Each line is either a triplet or an
|
|
593
|
-
* `{type,name,properties}` entity-properties record; lines are batched into
|
|
594
|
-
* bounded internal commits server-side, so a whole dataset loads in one
|
|
595
|
-
* streamed request without a single oversized commit. Pass `lines` as an array
|
|
596
|
-
* (serialized to NDJSON here) or a pre-built NDJSON string.
|
|
597
|
-
*/
|
|
598
|
-
import(
|
|
599
|
-
lines: ImportLine[] | string,
|
|
600
|
-
opts: {
|
|
601
|
-
batch?: number;
|
|
602
|
-
strict?: boolean;
|
|
603
|
-
observedAt?: string;
|
|
604
|
-
idempotencyKey?: string;
|
|
605
|
-
} = {},
|
|
606
|
-
): Promise<Schemas["GraphImportResponse"]> {
|
|
607
|
-
const ndjson =
|
|
608
|
-
typeof lines === "string"
|
|
609
|
-
? lines
|
|
610
|
-
: lines.map((line) => JSON.stringify(line)).join("\n");
|
|
611
|
-
return this.request("POST", "/v1/graph/import", {
|
|
612
|
-
rawBody: ndjson,
|
|
613
|
-
contentType: "application/x-ndjson",
|
|
614
|
-
query: { batch: opts.batch, strict: opts.strict, observed_at: opts.observedAt },
|
|
615
|
-
idempotencyKey: opts.idempotencyKey,
|
|
616
|
-
});
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
/**
|
|
620
|
-
* Bulk-ingest N-Triples without client-side conversion. Resource-object
|
|
621
|
-
* triples become keyed Resource edges; literal-object triples become text
|
|
622
|
-
* properties on the subject Resource.
|
|
623
|
-
*/
|
|
624
|
-
importRdf(
|
|
625
|
-
ntriples: string,
|
|
626
|
-
opts: {
|
|
627
|
-
batch?: number;
|
|
628
|
-
strict?: boolean;
|
|
629
|
-
observedAt?: string;
|
|
630
|
-
resourceType?: string;
|
|
631
|
-
edgeIdempotency?: "append" | "skip_unchanged";
|
|
632
|
-
idempotencyKey?: string;
|
|
633
|
-
} = {},
|
|
634
|
-
): Promise<Schemas["GraphRdfImportResponse"]> {
|
|
635
|
-
return this.request("POST", "/v1/graph/import/rdf", {
|
|
636
|
-
rawBody: ntriples,
|
|
637
|
-
contentType: "application/n-triples",
|
|
638
|
-
query: {
|
|
639
|
-
batch: opts.batch,
|
|
640
|
-
strict: opts.strict,
|
|
641
|
-
observed_at: opts.observedAt,
|
|
642
|
-
format: "ntriples",
|
|
643
|
-
resource_type: opts.resourceType,
|
|
644
|
-
edge_idempotency: opts.edgeIdempotency,
|
|
645
|
-
},
|
|
646
|
-
idempotencyKey: opts.idempotencyKey,
|
|
647
|
-
});
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
/**
|
|
651
|
-
* Retract specific edges and/or every edge touching given entities. Appends
|
|
652
|
-
* superseding retract events rather than deleting — history stays visible in an
|
|
653
|
-
* `as_of` read before the retraction, but the edges drop out of current state.
|
|
654
|
-
* The surgical alternative to {@link deleteGraph}.
|
|
655
|
-
*/
|
|
656
|
-
retract(
|
|
657
|
-
body: Schemas["GraphRetractRequest"],
|
|
658
|
-
opts: { idempotencyKey?: string } = {},
|
|
659
|
-
): Promise<Schemas["GraphRetractResponse"]> {
|
|
660
|
-
return this.request("POST", "/v1/graph/retract", {
|
|
661
|
-
body,
|
|
662
|
-
idempotencyKey: opts.idempotencyKey ?? this.idempotencyKey("retract"),
|
|
663
|
-
});
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
/** Create the scoped graph/branch. Construct the client with the desired graph/branch first. */
|
|
667
|
-
createGraph(): Promise<Schemas["CreateGraphResponse"]> {
|
|
668
|
-
return this.request("POST", "/v1/graph/create");
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
/** Fork the scoped branch from an existing branch in the same graph. */
|
|
672
|
-
createBranch(
|
|
673
|
-
body: Schemas["GraphBranchCreateRequest"],
|
|
674
|
-
): Promise<Schemas["GraphBranchCreateResponse"]> {
|
|
675
|
-
return this.request("POST", "/v1/graph/branch", { body });
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
/**
|
|
679
|
-
* Delete every object under the scoped graph/branch — a destructive reset.
|
|
680
|
-
* `confirm` must equal the scoped graph id; the next commit re-initializes the
|
|
681
|
-
* graph. Branch-scoped: sibling branches are untouched.
|
|
682
|
-
*/
|
|
683
|
-
deleteGraph(opts: { confirm: string }): Promise<unknown> {
|
|
684
|
-
return this.request("POST", "/v1/graph/delete", { query: { confirm: opts.confirm } });
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
// --- search ---
|
|
688
|
-
|
|
689
|
-
/** Full semantic hybrid search from a request body (`POST /v1/graph/search`). */
|
|
690
|
-
graphSearch(
|
|
691
|
-
body: Schemas["SemanticGraphSearchRequest"],
|
|
692
|
-
): Promise<Schemas["SemanticGraphSearchResponse"]> {
|
|
693
|
-
return this.request("POST", "/v1/graph/search", { body });
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
/** Reciprocal-rank-fusion across sub-queries. */
|
|
697
|
-
multiSearch(
|
|
698
|
-
body: Schemas["HybridMultiSearchRequest"],
|
|
699
|
-
): Promise<Schemas["HybridMultiSearchResponse"]> {
|
|
700
|
-
return this.request("POST", "/v1/search/multi", { body });
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
/**
|
|
704
|
-
* Append relevance labels for a set of search results — how Little Big Brain
|
|
705
|
-
* gathers customer-specific qrels. Grade results (3 ideal/good, 1 partial,
|
|
706
|
-
* 0 bad), referencing the search response's `search_id` so labels tie back to
|
|
707
|
-
* that ranking. Stored apart from customer facts and exported via
|
|
708
|
-
* {@link searchFeedbackExport} as training/eval data for embedding fine-tuning.
|
|
709
|
-
*/
|
|
710
|
-
searchFeedback(
|
|
711
|
-
body: Schemas["SearchFeedbackRequest"],
|
|
712
|
-
opts: { idempotencyKey?: string } = {},
|
|
713
|
-
): Promise<Schemas["SearchFeedbackResponse"]> {
|
|
714
|
-
return this.request("POST", "/v1/search/feedback", {
|
|
715
|
-
body,
|
|
716
|
-
idempotencyKey: opts.idempotencyKey,
|
|
717
|
-
});
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
/** Export the stored relevance labels as qrels-style rows for training. */
|
|
721
|
-
searchFeedbackExport(): Promise<Schemas["SearchFeedbackExportResponse"]> {
|
|
722
|
-
return this.request("GET", "/v1/search/feedback/export");
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
/** BM25 search. */
|
|
726
|
-
fullTextSearch(
|
|
727
|
-
body: Schemas["FullTextSearchRequest"],
|
|
728
|
-
): Promise<Schemas["FullTextSearchResponse"]> {
|
|
729
|
-
return this.request("POST", "/v1/search/full-text", { body });
|
|
730
|
-
}
|
|
731
|
-
|
|
732
|
-
/** ANN/vector search. */
|
|
733
|
-
embeddingSearch(
|
|
734
|
-
body: Schemas["EmbeddingSearchRequest"],
|
|
735
|
-
): Promise<Schemas["EmbeddingSearchResponse"]> {
|
|
736
|
-
return this.request("POST", "/v1/search/embedding", { body });
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
// --- traversal ---
|
|
740
|
-
|
|
741
|
-
/** Bounded k-hop graph traversal. */
|
|
742
|
-
traverse(body: Schemas["TraverseRequest"]): Promise<Schemas["TraverseResponse"]> {
|
|
743
|
-
return this.request("POST", "/v1/graph/traverse", { body });
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
/** Resolve a query to seed entities, then return bounded paths. */
|
|
747
|
-
semanticTraverse(
|
|
748
|
-
body: Schemas["SemanticTraverseRequest"],
|
|
749
|
-
): Promise<Schemas["SemanticTraverseResponse"]> {
|
|
750
|
-
return this.request("POST", "/v1/graph/semantic-traverse", { body });
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
/** Ranked incoming/outgoing neighborhood for a graph entity. */
|
|
754
|
-
entityNeighborhood(opts: {
|
|
755
|
-
id?: string;
|
|
756
|
-
type?: string;
|
|
757
|
-
name?: string;
|
|
758
|
-
relations?: string[];
|
|
759
|
-
asOf?: string;
|
|
760
|
-
}): Promise<Schemas["EntityNeighborhoodResponse"]> {
|
|
761
|
-
return this.request("GET", "/v1/graph/entity/neighborhood", {
|
|
762
|
-
query: {
|
|
763
|
-
id: opts.id,
|
|
764
|
-
type: opts.type,
|
|
765
|
-
name: opts.name,
|
|
766
|
-
relations: opts.relations?.join(","),
|
|
767
|
-
as_of: opts.asOf,
|
|
768
|
-
},
|
|
769
|
-
});
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
/** Stored entity object-ref status and index-coverage metadata (no
|
|
773
|
-
* attributes — read those from `entityDetail`'s top-level `attributes`). */
|
|
774
|
-
entityMetadata(opts: {
|
|
775
|
-
id?: string;
|
|
776
|
-
type?: string;
|
|
777
|
-
name?: string;
|
|
778
|
-
asOf?: string;
|
|
779
|
-
}): Promise<Schemas["EntityMetadataResponse"]> {
|
|
780
|
-
return this.request("GET", "/v1/graph/entity/metadata", {
|
|
781
|
-
query: {
|
|
782
|
-
id: opts.id,
|
|
783
|
-
type: opts.type,
|
|
784
|
-
name: opts.name,
|
|
785
|
-
as_of: opts.asOf,
|
|
786
|
-
},
|
|
787
|
-
});
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
/**
|
|
791
|
-
* Entity detail: metadata, attributes, current state, edge history, and
|
|
792
|
-
* observations. Pass `asOf` / `asOfCommitSeq` to reproduce the node as of a
|
|
793
|
-
* past instant / commit (the state, edges, and history are pinned to it).
|
|
794
|
-
*/
|
|
795
|
-
entityDetail(opts: {
|
|
796
|
-
id?: string;
|
|
797
|
-
type?: string;
|
|
798
|
-
name?: string;
|
|
799
|
-
asOf?: string;
|
|
800
|
-
asOfCommitSeq?: number;
|
|
801
|
-
}): Promise<Schemas["EntityDetailResponse"]> {
|
|
802
|
-
return this.request("GET", "/v1/graph/entity", {
|
|
803
|
-
query: {
|
|
804
|
-
id: opts.id,
|
|
805
|
-
type: opts.type,
|
|
806
|
-
name: opts.name,
|
|
807
|
-
as_of: opts.asOf,
|
|
808
|
-
as_of_commit_seq: opts.asOfCommitSeq,
|
|
809
|
-
},
|
|
810
|
-
});
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
/**
|
|
814
|
-
* Paged edge listing. Scope to one node with `id` (or `type`+`name`) and a
|
|
815
|
-
* `direction` (`out`/`in`/`both`) to walk **every** edge of a high-degree node
|
|
816
|
-
* — `entityDetail` returns the full set but is awkward to page; this carries
|
|
817
|
-
* `offset`/`limit` and reports `total_count`. Optional `relation`/`q` filters
|
|
818
|
-
* and an `asOf`/`asOfCommitSeq` snapshot pin. Each row carries `valid_time`, so
|
|
819
|
-
* the page is enough to reconstruct a per-edge timeline.
|
|
820
|
-
*/
|
|
821
|
-
graphEdges(
|
|
822
|
-
opts: {
|
|
823
|
-
id?: string;
|
|
824
|
-
type?: string;
|
|
825
|
-
name?: string;
|
|
826
|
-
direction?: "out" | "in" | "both";
|
|
827
|
-
relation?: string;
|
|
828
|
-
q?: string;
|
|
829
|
-
limit?: number;
|
|
830
|
-
/** Opaque cursor from a previous page's `next_cursor`. */
|
|
831
|
-
cursor?: string | number;
|
|
832
|
-
/** @deprecated Legacy alias for `cursor` (still accepted by the server). */
|
|
833
|
-
offset?: number;
|
|
834
|
-
asOf?: string;
|
|
835
|
-
asOfCommitSeq?: number;
|
|
836
|
-
} = {},
|
|
837
|
-
): Promise<ListResponse<Schemas["GraphEdgeRow"]>> {
|
|
838
|
-
return this.request("GET", "/v1/graph/edges", {
|
|
839
|
-
query: {
|
|
840
|
-
id: opts.id,
|
|
841
|
-
type: opts.type,
|
|
842
|
-
name: opts.name,
|
|
843
|
-
direction: opts.direction,
|
|
844
|
-
relation: opts.relation,
|
|
845
|
-
q: opts.q,
|
|
846
|
-
limit: opts.limit,
|
|
847
|
-
cursor: opts.cursor,
|
|
848
|
-
offset: opts.offset,
|
|
849
|
-
as_of: opts.asOf,
|
|
850
|
-
as_of_commit_seq: opts.asOfCommitSeq,
|
|
851
|
-
},
|
|
852
|
-
});
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
/**
|
|
856
|
-
* Page through every row of a list endpoint, following `next_cursor` until
|
|
857
|
-
* exhausted. Pass a fetcher that takes a cursor and returns a
|
|
858
|
-
* {@link ListResponse}:
|
|
859
|
-
* ```ts
|
|
860
|
-
* for await (const e of client.listAll((cursor) =>
|
|
861
|
-
* client.entities.list({ cursor, fields: "title" }))) { … }
|
|
862
|
-
* ```
|
|
863
|
-
*/
|
|
864
|
-
async *listAll<T>(
|
|
865
|
-
fetchPage: (cursor?: string) => Promise<ListResponse<T>>,
|
|
866
|
-
): AsyncGenerator<T, void, unknown> {
|
|
867
|
-
let cursor: string | undefined;
|
|
868
|
-
for (;;) {
|
|
869
|
-
const page = await fetchPage(cursor);
|
|
870
|
-
for (const row of page.data) yield row;
|
|
871
|
-
if (!page.has_more || page.next_cursor == null) return;
|
|
872
|
-
cursor = page.next_cursor;
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
// --- temporal / lineage / shapes ---
|
|
877
|
-
|
|
878
|
-
/** Current state of an entity's relations, optionally as-of a timestamp. */
|
|
879
|
-
currentState(body: Schemas["CurrentStateRequest"]): Promise<Schemas["CurrentStateResponse"]> {
|
|
880
|
-
return this.request("POST", "/v1/query/state", { body });
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
/** Full edge-event history for a relationship. */
|
|
884
|
-
history(
|
|
885
|
-
body: Schemas["RelationshipHistoryRequest"],
|
|
886
|
-
): Promise<Schemas["RelationshipHistoryResponse"]> {
|
|
887
|
-
return this.request("POST", "/v1/query/history", { body });
|
|
888
|
-
}
|
|
889
|
-
|
|
890
|
-
/** Ordered state-transition log for an entity's relation, with dwell time. */
|
|
891
|
-
transitions(
|
|
892
|
-
body: Schemas["EntityTransitionsRequest"],
|
|
893
|
-
): Promise<Schemas["EntityTransitionsResponse"]> {
|
|
894
|
-
return this.request("POST", "/v1/query/transitions", { body });
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
/** Lineage and evidence for a single edge. */
|
|
898
|
-
why(body: Schemas["WhyRequest"]): Promise<Schemas["WhyResponse"]> {
|
|
899
|
-
return this.request("POST", "/v1/query/why", { body });
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
/** SHACL-style shape/pattern query. */
|
|
903
|
-
shacl(body: Schemas["ShaclQueryRequest"]): Promise<Schemas["ShaclQueryResponse"]> {
|
|
904
|
-
return this.request("POST", "/v1/query/shacl", { body });
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
/**
|
|
908
|
-
* SPARQL-subset SELECT/ASK/aggregate query (FILTER, HAVING, ORDER BY, ASK,
|
|
909
|
-
* COUNT/SUM/AVG/MIN/MAX). GROUP BY is not limited to entity identity:
|
|
910
|
-
* `group_by` keys on a variable's entity, and `group_keys` adds typed scalar
|
|
911
|
-
* keys — a `property` value, or a `date_bucket` calendar truncation
|
|
912
|
-
* (`year`/`month`/`week`/`day`/`hour`) of a datetime property — so a
|
|
913
|
-
* per-category breakdown or a time series is one server-side query. Scalar
|
|
914
|
-
* keys come back per group in `groups[].value_keys[<as>]`, entity keys in
|
|
915
|
-
* `groups[].keys`.
|
|
916
|
-
*/
|
|
917
|
-
sparql(body: Schemas["SparqlSelectRequest"]): Promise<Schemas["SparqlSelectResponse"]> {
|
|
918
|
-
return this.request("POST", "/v1/query/sparql", { body });
|
|
919
|
-
}
|
|
920
|
-
|
|
921
|
-
/** SPARQL 1.1 query from text (SELECT/ASK) over the live graph; `results` is SPARQL 1.1 Query Results JSON. */
|
|
922
|
-
sparqlText(body: Schemas["SparqlTextRequest"]): Promise<Schemas["SparqlTextResponse"]> {
|
|
923
|
-
return this.request("POST", "/v1/query/sparql-text", { body });
|
|
924
|
-
}
|
|
925
|
-
|
|
926
|
-
/**
|
|
927
|
-
* Run a SPARQL 1.1 text query and return parsed results — the ergonomic
|
|
928
|
-
* complement to {@link sparqlText} (which hands back the raw results string).
|
|
929
|
-
* Returns `{ vars, boolean, bindings, rows }` via {@link parseSparqlResults}:
|
|
930
|
-
* `rows` is the bindings flattened to `{ variable: lexicalValue }`, `boolean`
|
|
931
|
-
* is the ASK answer (or `null` for a SELECT).
|
|
932
|
-
*/
|
|
933
|
-
async sparqlRows(body: Schemas["SparqlTextRequest"]): Promise<SparqlResults> {
|
|
934
|
-
return parseSparqlResults(await this.sparqlText(body));
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
/**
|
|
938
|
-
* Basic-graph-pattern query with group-graph-pattern combinators
|
|
939
|
-
* (UNION / OPTIONAL / MINUS / EXISTS / NOT EXISTS) folded over the base
|
|
940
|
-
* patterns. The complement to {@link sparql}: this route carries the
|
|
941
|
-
* combinators (but not FILTER/aggregation), so use it when a query needs an
|
|
942
|
-
* optional/union/negated leg rather than a grouped aggregate.
|
|
943
|
-
*/
|
|
944
|
-
analytics(body: Schemas["AnalyticQueryRequest"]): Promise<Schemas["AnalyticQueryResponse"]> {
|
|
945
|
-
return this.request("POST", "/v1/query/analytics", { body });
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
/**
|
|
949
|
-
* Run inference rules (SHACL-AF `sh:TripleRule` shape) to a bounded fixpoint
|
|
950
|
-
* and return the derived edges as a **preview** — derived facts are never
|
|
951
|
-
* written to the asserted graph. Each rule is a BGP `body`/`where` plus a
|
|
952
|
-
* `head` triple template instantiated per binding.
|
|
953
|
-
*/
|
|
954
|
-
infer(body: Schemas["InferenceRunRequest"]): Promise<Schemas["InferenceRunResponse"]> {
|
|
955
|
-
return this.request("POST", "/v1/inference/run", { body });
|
|
956
|
-
}
|
|
957
|
-
|
|
958
|
-
/**
|
|
959
|
-
* Define (replace) the versioned rule set stored on the scoped graph branch.
|
|
960
|
-
* The stored set is what SHACL `include_derived` and `infer` use when a
|
|
961
|
-
* request carries no inline rules. Returns the new `rules_version`.
|
|
962
|
-
*/
|
|
963
|
-
defineRules(
|
|
964
|
-
body: Schemas["RuleSetDefineRequest"],
|
|
965
|
-
): Promise<Schemas["RuleSetDefineResponse"]> {
|
|
966
|
-
return this.request("POST", "/v1/inference/rules", { body });
|
|
967
|
-
}
|
|
968
|
-
|
|
969
|
-
/** The rule set stored on the scoped graph branch (version + rules). */
|
|
970
|
-
graphRules(): Promise<Schemas["RuleSet"]> {
|
|
971
|
-
return this.request("GET", "/v1/inference/rules");
|
|
972
|
-
}
|
|
973
|
-
|
|
974
|
-
/**
|
|
975
|
-
* Stage G — derive edges from calibrated retrieval matches (preview): each
|
|
976
|
-
* candidate scored `P >= threshold` becomes a derived edge `(anchor, relation,
|
|
977
|
-
* matched)` with a typed `Retrieval` provenance leaf. Pass either explicit
|
|
978
|
-
* `candidates` or a `query` the server runs as BM25 entity retrieval.
|
|
979
|
-
*/
|
|
980
|
-
retrievalPremises(
|
|
981
|
-
body: Schemas["RetrievalPremiseRequest"],
|
|
982
|
-
): Promise<Schemas["RetrievalPremiseResponse"]> {
|
|
983
|
-
return this.request("POST", "/v1/inference/retrieval-premises", { body });
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
// --- ontology ---
|
|
987
|
-
|
|
988
|
-
/**
|
|
989
|
-
* The active ontology (entity types and relations) for the scoped graph.
|
|
990
|
-
* Pass `{ counts: true }` to include a per-relation current-edge count
|
|
991
|
-
* (`OntologyRelationView.edge_count`) so a caller can see which declared
|
|
992
|
-
* relations are actually populated — at the cost of a snapshot load.
|
|
993
|
-
*/
|
|
994
|
-
ontologyView(opts: { counts?: boolean } = {}): Promise<Schemas["OntologyView"]> {
|
|
995
|
-
return this.request("GET", "/v1/ontology", {
|
|
996
|
-
query: opts.counts ? { counts: true } : undefined,
|
|
997
|
-
});
|
|
998
|
-
}
|
|
999
|
-
|
|
1000
|
-
/**
|
|
1001
|
-
* Audit the current snapshot against the ontology's *implied* constraints —
|
|
1002
|
-
* capped `cardinality` derived as `sh:maxCount` — returning a SHACL-shaped
|
|
1003
|
-
* report. Whole-snapshot and never blocks a write. Unlike
|
|
1004
|
-
* {@link SchemaNamespace.audit}, this needs no published shape bundle: the
|
|
1005
|
-
* shapes come from the ontology itself. See the `decoration_status` catalog on
|
|
1006
|
-
* {@link ontologyView} for which decorations are enforced.
|
|
1007
|
-
*/
|
|
1008
|
-
ontologyConformance(): Promise<Schemas["SchemaAuditReport"]> {
|
|
1009
|
-
return this.request("GET", "/v1/ontology/conformance");
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
/** Discover ontology concepts, terms, and relations. */
|
|
1013
|
-
ontologySearch(
|
|
1014
|
-
body: Schemas["OntologySearchRequest"],
|
|
1015
|
-
): Promise<Schemas["OntologySearchResponse"]> {
|
|
1016
|
-
return this.request("POST", "/v1/ontology/search", { body });
|
|
1017
|
-
}
|
|
1018
|
-
|
|
1019
|
-
/** Resolve mentions to concepts/entities. */
|
|
1020
|
-
ontologyResolve(
|
|
1021
|
-
body: Schemas["OntologyResolveRequest"],
|
|
1022
|
-
): Promise<Schemas["OntologyResolveResponse"]> {
|
|
1023
|
-
return this.request("POST", "/v1/ontology/resolve", { body });
|
|
1024
|
-
}
|
|
1025
|
-
|
|
1026
|
-
/** Define the active ontology before the scoped graph's first commit. */
|
|
1027
|
-
ontologyDefine(
|
|
1028
|
-
body: Schemas["OntologyDefineRequest"],
|
|
1029
|
-
): Promise<Schemas["OntologyDefineResponse"]> {
|
|
1030
|
-
return this.request("POST", "/v1/ontology/define", { body });
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
|
-
/**
|
|
1034
|
-
* Additively evolve the active ontology of an existing graph: widen relation
|
|
1035
|
-
* domains/ranges and declare new entity types (all by name), bumping the
|
|
1036
|
-
* ontology version. Additive-only — every existing record stays valid, so no
|
|
1037
|
-
* migration is needed — and a request that changes nothing is a no-op.
|
|
1038
|
-
*/
|
|
1039
|
-
evolveOntology(
|
|
1040
|
-
body: Schemas["OntologyEvolveRequest"],
|
|
1041
|
-
): Promise<Schemas["OntologyEvolveResponse"]> {
|
|
1042
|
-
return this.request("POST", "/v1/ontology/evolve", { body });
|
|
1043
|
-
}
|
|
1044
|
-
|
|
1045
|
-
// --- index lifecycle ---
|
|
1046
|
-
|
|
1047
|
-
/**
|
|
1048
|
-
* Build default ANN + BM25 indexes. With `{ background: true }` the build
|
|
1049
|
-
* runs detached on the server and the call returns immediately — use it for
|
|
1050
|
-
* large corpora whose synchronous build would exceed a fronting gateway's
|
|
1051
|
-
* timeout (a 504), then poll `metadata()` for completion.
|
|
1052
|
-
*/
|
|
1053
|
-
indexBuild(opts: { background?: boolean } = {}): Promise<unknown> {
|
|
1054
|
-
return this.request("POST", "/v1/index/build", { query: { background: opts.background || undefined } });
|
|
1055
|
-
}
|
|
1056
|
-
|
|
1057
|
-
/**
|
|
1058
|
-
* Build BM25, ANN/vector, and adjacency index families. With
|
|
1059
|
-
* `{ background: true }` the build runs detached on the server and the call
|
|
1060
|
-
* returns immediately — use it for large corpora whose synchronous build would
|
|
1061
|
-
* exceed a fronting gateway's timeout, then poll `metadata()` for completion.
|
|
1062
|
-
*/
|
|
1063
|
-
indexRun(opts: { background?: boolean } = {}): Promise<unknown> {
|
|
1064
|
-
return this.request("POST", "/v1/index/run", { query: { background: opts.background || undefined } });
|
|
1065
|
-
}
|
|
1066
|
-
|
|
1067
|
-
/** Append a BM25 delta segment for the unindexed WAL tail. */
|
|
1068
|
-
indexDelta(): Promise<Schemas["IndexDeltaResponse"]> {
|
|
1069
|
-
return this.request("POST", "/v1/index/delta");
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1072
|
-
/** Preview or delete superseded persisted index runs. */
|
|
1073
|
-
indexGc(opts: { keepRuns?: number; dryRun?: boolean } = {}): Promise<Schemas["IndexGcResponse"]> {
|
|
1074
|
-
return this.request("POST", "/v1/index/gc", {
|
|
1075
|
-
query: { keep_runs: opts.keepRuns, dry_run: opts.dryRun },
|
|
1076
|
-
});
|
|
1077
|
-
}
|
|
1078
|
-
|
|
1079
|
-
/** Fold the WAL tail into snapshot segments. */
|
|
1080
|
-
compact(
|
|
1081
|
-
opts: { minTailCommits?: number; maxSegments?: number } = {},
|
|
1082
|
-
): Promise<Schemas["WalCompactResponse"]> {
|
|
1083
|
-
return this.request("POST", "/v1/graph/compact", {
|
|
1084
|
-
query: { min_tail_commits: opts.minTailCommits, max_segments: opts.maxSegments },
|
|
1085
|
-
});
|
|
1086
|
-
}
|
|
1087
|
-
|
|
1088
|
-
// --- inspection ---
|
|
1089
|
-
|
|
1090
|
-
/** Server, graph, and persisted-index status. */
|
|
1091
|
-
status(): Promise<unknown> {
|
|
1092
|
-
return this.request("GET", "/v1/status");
|
|
1093
|
-
}
|
|
1094
|
-
|
|
1095
|
-
/** Graph footprint, WAL tail, and index coverage. */
|
|
1096
|
-
metadata(): Promise<Schemas["GraphMetadataResponse"]> {
|
|
1097
|
-
return this.request("GET", "/v1/graph/metadata");
|
|
1098
|
-
}
|
|
1099
|
-
|
|
1100
|
-
/** Graph counts and type/relation buckets. */
|
|
1101
|
-
summary(): Promise<Schemas["GraphSummaryResponse"]> {
|
|
1102
|
-
return this.request("GET", "/v1/graph/summary");
|
|
1103
|
-
}
|
|
1104
|
-
|
|
1105
|
-
/** List the graphs (and branches) under the scoped tenant. */
|
|
1106
|
-
listGraphs(): Promise<Schemas["GraphListResponse"]> {
|
|
1107
|
-
return this.request("GET", "/v1/graphs");
|
|
1108
|
-
}
|
|
1109
|
-
|
|
1110
|
-
// --- database admin ---
|
|
1111
|
-
|
|
1112
|
-
/** Create a database stack and return its one-time stack API key. */
|
|
1113
|
-
adminCreateStack(body: LbbAdminStackCreateRequest): Promise<LbbAdminStackResponse> {
|
|
1114
|
-
return this.request("POST", "/api/admin/stacks", { body });
|
|
1115
|
-
}
|
|
1116
|
-
|
|
1117
|
-
/** Inspect a database stack without returning secret key material. */
|
|
1118
|
-
adminStack(slug: string): Promise<LbbAdminStackResponse> {
|
|
1119
|
-
return this.request("GET", "/api/admin/stacks", { query: { stack: slug } });
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
|
-
/** Rotate a database stack key and return the new one-time API key. */
|
|
1123
|
-
adminRotateStackKey(slug: string): Promise<LbbAdminStackResponse> {
|
|
1124
|
-
return this.request("POST", "/api/admin/stacks/rotate-key", { query: { stack: slug } });
|
|
1125
|
-
}
|
|
1126
|
-
|
|
1127
|
-
/** Delete a database stack after confirming the slug. */
|
|
1128
|
-
adminDeleteStack(slug: string): Promise<LbbAdminStackDeleteResponse> {
|
|
1129
|
-
return this.request("DELETE", "/api/admin/stacks", { query: { stack: slug, confirm: slug } });
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1132
|
-
/**
|
|
1133
|
-
* Mint a short-lived `lbb_ses_…` session token for an account. A trusted
|
|
1134
|
-
* co-located service uses it (with `?stack=<slug>`) to call the data plane on
|
|
1135
|
-
* the account's behalf without handling the stack's mode-bearing stack key.
|
|
1136
|
-
*/
|
|
1137
|
-
adminMintSession(accountId: string): Promise<LbbAdminSessionResponse> {
|
|
1138
|
-
return this.request("POST", "/api/admin/sessions", { body: { account_id: accountId } });
|
|
1139
|
-
}
|
|
1140
|
-
|
|
1141
|
-
/** Customer-visible activity for one database stack. */
|
|
1142
|
-
adminStackActivity(slug: string, window: LbbStackActivityWindow = "24h"): Promise<LbbStackActivityResponse> {
|
|
1143
|
-
return this.request("GET", "/api/admin/stacks/activity", { query: { stack: slug, window } });
|
|
1144
|
-
}
|
|
1145
|
-
|
|
1146
|
-
/** Activity for the stack selected by the bearer stack key or session. */
|
|
1147
|
-
stackActivity(window: LbbStackActivityWindow = "24h"): Promise<LbbStackActivityResponse> {
|
|
1148
|
-
return this.request("GET", "/v1/stack/activity", { query: { window } });
|
|
1149
|
-
}
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
|
-
export class GraphNamespace {
|
|
1153
|
-
readonly facts: FactsNamespace;
|
|
1154
|
-
|
|
1155
|
-
constructor(private readonly client: LbbClient) {
|
|
1156
|
-
this.facts = new FactsNamespace(client);
|
|
1157
|
-
}
|
|
1158
|
-
|
|
1159
|
-
branch(name: string): GraphNamespace {
|
|
1160
|
-
return new GraphNamespace(this.client.withScope({ branch: name }));
|
|
1161
|
-
}
|
|
1162
|
-
|
|
1163
|
-
create(): Promise<Schemas["CreateGraphResponse"]> {
|
|
1164
|
-
return this.client.createGraph();
|
|
1165
|
-
}
|
|
1166
|
-
|
|
1167
|
-
delete(opts: { confirm: string }): Promise<unknown> {
|
|
1168
|
-
return this.client.deleteGraph(opts);
|
|
1169
|
-
}
|
|
1170
|
-
|
|
1171
|
-
/** Retract edges/entities from the scoped graph. See {@link LbbClient.retract}. */
|
|
1172
|
-
retract(
|
|
1173
|
-
body: Schemas["GraphRetractRequest"],
|
|
1174
|
-
opts: { idempotencyKey?: string } = {},
|
|
1175
|
-
): Promise<Schemas["GraphRetractResponse"]> {
|
|
1176
|
-
return this.client.retract(body, opts);
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1179
|
-
|
|
1180
|
-
export class FactsNamespace {
|
|
1181
|
-
constructor(private readonly client: LbbClient) {}
|
|
1182
|
-
|
|
1183
|
-
create(
|
|
1184
|
-
body: Schemas["TripletCommitFile"],
|
|
1185
|
-
opts: { idempotencyKey?: string } = {},
|
|
1186
|
-
): Promise<Schemas["GraphCommitResponse"]> {
|
|
1187
|
-
return this.client.request("POST", "/v1/graph/commit", {
|
|
1188
|
-
body,
|
|
1189
|
-
idempotencyKey: opts.idempotencyKey ?? this.client.idempotencyKey("facts.create"),
|
|
1190
|
-
});
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
/** Bulk-load a dataset as NDJSON. See {@link LbbClient.import}. */
|
|
1194
|
-
import(
|
|
1195
|
-
lines: ImportLine[] | string,
|
|
1196
|
-
opts: {
|
|
1197
|
-
batch?: number;
|
|
1198
|
-
strict?: boolean;
|
|
1199
|
-
observedAt?: string;
|
|
1200
|
-
idempotencyKey?: string;
|
|
1201
|
-
} = {},
|
|
1202
|
-
): Promise<Schemas["GraphImportResponse"]> {
|
|
1203
|
-
return this.client.import(lines, opts);
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
|
-
/**
|
|
1207
|
-
* Bulk-load N-Triples through the native RDF import endpoint.
|
|
1208
|
-
*
|
|
1209
|
-
* Statements are committed through the fixed RDF_TRIPLE relation; source RDF
|
|
1210
|
-
* predicates and literal term details are preserved as edge metadata.
|
|
1211
|
-
*/
|
|
1212
|
-
importRdf(
|
|
1213
|
-
ntriples: string,
|
|
1214
|
-
opts: {
|
|
1215
|
-
batch?: number;
|
|
1216
|
-
strict?: boolean;
|
|
1217
|
-
observedAt?: string;
|
|
1218
|
-
resourceType?: string;
|
|
1219
|
-
edgeIdempotency?: "append" | "skip_unchanged";
|
|
1220
|
-
idempotencyKey?: string;
|
|
1221
|
-
} = {},
|
|
1222
|
-
): Promise<Schemas["GraphRdfImportResponse"]> {
|
|
1223
|
-
return this.client.importRdf(ntriples, opts);
|
|
1224
|
-
}
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1227
|
-
export class SearchNamespace {
|
|
1228
|
-
constructor(private readonly client: LbbClient) {}
|
|
1229
|
-
|
|
1230
|
-
hybrid(
|
|
1231
|
-
query: string,
|
|
1232
|
-
opts?: {
|
|
1233
|
-
topK?: number;
|
|
1234
|
-
source?: string;
|
|
1235
|
-
consistency?: string;
|
|
1236
|
-
lexical?: boolean;
|
|
1237
|
-
bm25?: boolean;
|
|
1238
|
-
vector?: boolean;
|
|
1239
|
-
targets?: string[];
|
|
1240
|
-
profile?: string;
|
|
1241
|
-
/** Opt-in impression logging (L1): durably record this search's full
|
|
1242
|
-
* ranking context, keyed by `search_id`, so a later feedback label on it
|
|
1243
|
-
* carries the ranking it was judged against. Off by default. */
|
|
1244
|
-
logImpression?: boolean;
|
|
1245
|
-
},
|
|
1246
|
-
): Promise<Schemas["SemanticGraphSearchResponse"]>;
|
|
1247
|
-
hybrid(
|
|
1248
|
-
body: Schemas["SemanticGraphSearchRequest"],
|
|
1249
|
-
): Promise<Schemas["SemanticGraphSearchResponse"]>;
|
|
1250
|
-
hybrid(
|
|
1251
|
-
input: string | Schemas["SemanticGraphSearchRequest"],
|
|
1252
|
-
opts: {
|
|
1253
|
-
topK?: number;
|
|
1254
|
-
source?: string;
|
|
1255
|
-
consistency?: string;
|
|
1256
|
-
lexical?: boolean;
|
|
1257
|
-
bm25?: boolean;
|
|
1258
|
-
vector?: boolean;
|
|
1259
|
-
targets?: string[];
|
|
1260
|
-
profile?: string;
|
|
1261
|
-
logImpression?: boolean;
|
|
1262
|
-
} = {},
|
|
1263
|
-
): Promise<Schemas["SemanticGraphSearchResponse"]> {
|
|
1264
|
-
if (typeof input !== "string") {
|
|
1265
|
-
return this.client.request("POST", "/v1/graph/search", { body: input });
|
|
1266
|
-
}
|
|
1267
|
-
return this.client.request("GET", "/v1/search", {
|
|
1268
|
-
query: {
|
|
1269
|
-
query: input,
|
|
1270
|
-
top_k: opts.topK,
|
|
1271
|
-
source: opts.source,
|
|
1272
|
-
consistency: opts.consistency,
|
|
1273
|
-
lexical: opts.lexical,
|
|
1274
|
-
bm25: opts.bm25,
|
|
1275
|
-
vector: opts.vector,
|
|
1276
|
-
targets: opts.targets?.join(","),
|
|
1277
|
-
profile: opts.profile,
|
|
1278
|
-
log_impression: opts.logImpression,
|
|
1279
|
-
},
|
|
1280
|
-
});
|
|
1281
|
-
}
|
|
1282
|
-
|
|
1283
|
-
multi(body: Schemas["HybridMultiSearchRequest"]): Promise<Schemas["HybridMultiSearchResponse"]> {
|
|
1284
|
-
return this.client.multiSearch(body);
|
|
1285
|
-
}
|
|
1286
|
-
|
|
1287
|
-
feedback(
|
|
1288
|
-
body: Schemas["SearchFeedbackRequest"],
|
|
1289
|
-
opts: { idempotencyKey?: string } = {},
|
|
1290
|
-
): Promise<Schemas["SearchFeedbackResponse"]> {
|
|
1291
|
-
return this.client.searchFeedback(body, opts);
|
|
1292
|
-
}
|
|
1293
|
-
|
|
1294
|
-
feedbackExport(): Promise<Schemas["SearchFeedbackExportResponse"]> {
|
|
1295
|
-
return this.client.searchFeedbackExport();
|
|
1296
|
-
}
|
|
1297
|
-
|
|
1298
|
-
fullText(body: Schemas["FullTextSearchRequest"]): Promise<Schemas["FullTextSearchResponse"]> {
|
|
1299
|
-
return this.client.fullTextSearch(body);
|
|
1300
|
-
}
|
|
1301
|
-
|
|
1302
|
-
vector(body: Schemas["EmbeddingSearchRequest"]): Promise<Schemas["EmbeddingSearchResponse"]> {
|
|
1303
|
-
return this.client.embeddingSearch(body);
|
|
1304
|
-
}
|
|
1305
|
-
}
|
|
1306
|
-
|
|
1307
|
-
export class SchemaNamespace {
|
|
1308
|
-
constructor(private readonly client: LbbClient) {}
|
|
1309
|
-
|
|
1310
|
-
/** Active graph schema bundle: ontology plus activated SHACL shapes. */
|
|
1311
|
-
view(opts: { audit?: boolean } = {}): Promise<Schemas["SchemaBundleView"]> {
|
|
1312
|
-
return this.client.request("GET", "/v1/schema", {
|
|
1313
|
-
query: { audit: opts.audit || undefined },
|
|
1314
|
-
});
|
|
1315
|
-
}
|
|
1316
|
-
|
|
1317
|
-
/** Preview a proposed RDF/SHACL schema bundle and audit current data. */
|
|
1318
|
-
preview(body: Schemas["SchemaPreviewRequest"]): Promise<Schemas["SchemaPreviewResponse"]> {
|
|
1319
|
-
return this.client.request("POST", "/v1/schema/preview", { body });
|
|
1320
|
-
}
|
|
1321
|
-
|
|
1322
|
-
/** Activate a previewed SHACL schema bundle for this graph branch. */
|
|
1323
|
-
publish(body: Schemas["SchemaPublishRequest"]): Promise<Schemas["SchemaPublishResponse"]> {
|
|
1324
|
-
return this.client.request("POST", "/v1/schema/publish", { body });
|
|
1325
|
-
}
|
|
1326
|
-
|
|
1327
|
-
/** Audit current data against the active SHACL schema bundle. */
|
|
1328
|
-
audit(): Promise<Schemas["SchemaAuditReport"]> {
|
|
1329
|
-
return this.client.request("POST", "/v1/schema/audit");
|
|
1330
|
-
}
|
|
1331
|
-
}
|
|
1332
|
-
|
|
1333
|
-
export class IndexNamespace {
|
|
1334
|
-
constructor(private readonly client: LbbClient) {}
|
|
1335
|
-
|
|
1336
|
-
run(opts: { wait?: boolean; background?: boolean; body?: unknown } = {}): Promise<unknown> {
|
|
1337
|
-
const background = opts.background ?? (opts.wait === false ? true : undefined);
|
|
1338
|
-
return this.client.request("POST", "/v1/index/run", {
|
|
1339
|
-
query: { background },
|
|
1340
|
-
body: opts.body,
|
|
1341
|
-
});
|
|
1342
|
-
}
|
|
1343
|
-
|
|
1344
|
-
build(): Promise<unknown> {
|
|
1345
|
-
return this.client.indexBuild();
|
|
1346
|
-
}
|
|
1347
|
-
|
|
1348
|
-
delta(): Promise<Schemas["IndexDeltaResponse"]> {
|
|
1349
|
-
return this.client.indexDelta();
|
|
1350
|
-
}
|
|
1351
|
-
|
|
1352
|
-
gc(opts: { keepRuns?: number; dryRun?: boolean } = {}): Promise<Schemas["IndexGcResponse"]> {
|
|
1353
|
-
return this.client.indexGc(opts);
|
|
1354
|
-
}
|
|
1355
|
-
}
|
|
1356
|
-
|
|
1357
|
-
export class EntityNamespace {
|
|
1358
|
-
constructor(private readonly client: LbbClient) {}
|
|
1359
|
-
|
|
1360
|
-
/**
|
|
1361
|
-
* Browse entities as the unified list envelope. Pass `fields` (names or `*`)
|
|
1362
|
-
* to inline each row's typed attributes as native JSON (under `attributes`) —
|
|
1363
|
-
* "list entities and their titles" in one call instead of a list plus N point
|
|
1364
|
-
* lookups — or `ids`
|
|
1365
|
-
* to fetch a specific set. Page with `cursor` from the previous `next_cursor`.
|
|
1366
|
-
*/
|
|
1367
|
-
list(
|
|
1368
|
-
opts: {
|
|
1369
|
-
type?: string;
|
|
1370
|
-
limit?: number;
|
|
1371
|
-
cursor?: string | number;
|
|
1372
|
-
/** @deprecated Legacy alias for `cursor`. */
|
|
1373
|
-
offset?: number;
|
|
1374
|
-
query?: string;
|
|
1375
|
-
/** Property names to inline per row (or `"*"` / `["*"]` for all). */
|
|
1376
|
-
fields?: string | string[];
|
|
1377
|
-
/** Specific entity ids to fetch in one call (bulk lookup). */
|
|
1378
|
-
ids?: string | string[];
|
|
1379
|
-
} = {},
|
|
1380
|
-
): Promise<ListResponse<Schemas["EntityExplorerRow"]>> {
|
|
1381
|
-
const csv = (v: string | string[] | undefined) =>
|
|
1382
|
-
Array.isArray(v) ? v.join(",") : v;
|
|
1383
|
-
return this.client.request("GET", "/v1/graph/entities", {
|
|
1384
|
-
query: {
|
|
1385
|
-
type: opts.type,
|
|
1386
|
-
limit: opts.limit,
|
|
1387
|
-
cursor: opts.cursor,
|
|
1388
|
-
offset: opts.offset,
|
|
1389
|
-
q: opts.query,
|
|
1390
|
-
fields: csv(opts.fields),
|
|
1391
|
-
ids: csv(opts.ids),
|
|
1392
|
-
},
|
|
1393
|
-
});
|
|
1394
|
-
}
|
|
1395
|
-
|
|
1396
|
-
get(opts: { id?: string; type?: string; name?: string; asOf?: string }): Promise<Schemas["EntityMetadataResponse"]> {
|
|
1397
|
-
return this.client.entityMetadata(opts);
|
|
1398
|
-
}
|
|
1399
|
-
|
|
1400
|
-
detail(opts: { id?: string; type?: string; name?: string }): Promise<Schemas["EntityDetailResponse"]> {
|
|
1401
|
-
return this.client.entityDetail(opts);
|
|
1402
|
-
}
|
|
1403
|
-
|
|
1404
|
-
/**
|
|
1405
|
-
* Filter entities already bound by relation patterns using typed attributes,
|
|
1406
|
-
* without writing RDF property IRIs by hand. This is a convenience wrapper over
|
|
1407
|
-
* the structured SPARQL route: relation `patterns` bind variables, and `where`
|
|
1408
|
-
* compares ontology property fields on those bound variables.
|
|
1409
|
-
*/
|
|
1410
|
-
filterByAttributes(opts: EntityAttributeFilterOptions): Promise<Schemas["SparqlSelectResponse"]> {
|
|
1411
|
-
const defaultVar = firstPatternVariable(opts.patterns);
|
|
1412
|
-
const where = Array.isArray(opts.where) ? opts.where : [opts.where];
|
|
1413
|
-
return this.client.sparql({
|
|
1414
|
-
patterns: opts.patterns,
|
|
1415
|
-
filters: [...(opts.filters ?? []), ...where.map((filter) => attributeFilter(filter, defaultVar))],
|
|
1416
|
-
select: opts.select,
|
|
1417
|
-
limit: opts.limit,
|
|
1418
|
-
offset: opts.offset,
|
|
1419
|
-
as_of_valid_time: opts.asOfValidTime,
|
|
1420
|
-
as_of_commit_seq: opts.asOfCommitSeq,
|
|
1421
|
-
order_by: opts.orderBy,
|
|
1422
|
-
reason: opts.reason,
|
|
1423
|
-
max_solutions: opts.maxSolutions,
|
|
1424
|
-
max_object_reads: opts.maxObjectReads,
|
|
1425
|
-
max_fetched_bytes: opts.maxFetchedBytes,
|
|
1426
|
-
});
|
|
1427
|
-
}
|
|
1428
|
-
}
|