@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
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { LbbErrorPayload } from "./types.js";
|
|
2
|
+
export interface CallOptions {
|
|
3
|
+
idempotencyKey?: string;
|
|
4
|
+
/** Override the client's per-attempt timeout. Set 0 to disable it. */
|
|
5
|
+
timeoutMs?: number;
|
|
6
|
+
/** Override the client's retry count for this request. */
|
|
7
|
+
maxRetries?: number;
|
|
8
|
+
/** Override retry safety classification. Read-only POST namespaces set this automatically. */
|
|
9
|
+
retry?: boolean;
|
|
10
|
+
/** Abort the request and suppress any further retries. */
|
|
11
|
+
signal?: AbortSignal;
|
|
12
|
+
/** Additional request headers. Values override SDK defaults intentionally. */
|
|
13
|
+
headers?: Record<string, string>;
|
|
14
|
+
}
|
|
15
|
+
export interface RequestOptions extends CallOptions {
|
|
16
|
+
query?: Query;
|
|
17
|
+
body?: unknown;
|
|
18
|
+
/** Pre-serialized request body (e.g. NDJSON). Takes precedence over `body`. */
|
|
19
|
+
rawBody?: string;
|
|
20
|
+
/** Overrides the default `application/json` content type (used with `rawBody`). */
|
|
21
|
+
contentType?: string;
|
|
22
|
+
}
|
|
23
|
+
/** Thrown when the server responds with a non-2xx status. */
|
|
24
|
+
export declare class LbbError extends Error {
|
|
25
|
+
readonly status: number;
|
|
26
|
+
readonly body: string;
|
|
27
|
+
readonly error?: LbbErrorPayload | undefined;
|
|
28
|
+
readonly type?: string;
|
|
29
|
+
readonly code?: string;
|
|
30
|
+
readonly param?: string | null;
|
|
31
|
+
readonly requestId?: string | null;
|
|
32
|
+
readonly docUrl?: string | null;
|
|
33
|
+
constructor(status: number, body: string, error?: LbbErrorPayload | undefined);
|
|
34
|
+
}
|
|
35
|
+
export type QueryValue = string | number | boolean | undefined;
|
|
36
|
+
export type Query = Record<string, QueryValue>;
|
|
37
|
+
export declare function sleep(ms: number): Promise<void>;
|
|
38
|
+
export declare function retryableStatus(status: number): boolean;
|
|
39
|
+
export declare function retryAllowed(method: string, idempotencyKey?: string): boolean;
|
|
40
|
+
/** Parse a Retry-After delta-seconds or HTTP-date value, capped at one minute. */
|
|
41
|
+
export declare function parseRetryAfterMs(value: string | null | undefined, nowMs?: number): number | undefined;
|
|
42
|
+
export declare function retryDelayForAttempt(baseDelayMs: number, attempt: number, retryAfter?: string | null): number;
|
|
43
|
+
export declare function parseResponseJson<T>(text: string, status: number, requestId?: string): T;
|
|
44
|
+
export declare function parseLbbError(status: number, body: string, fallbackRequestId?: string): LbbError;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/** Thrown when the server responds with a non-2xx status. */
|
|
2
|
+
export class LbbError extends Error {
|
|
3
|
+
status;
|
|
4
|
+
body;
|
|
5
|
+
error;
|
|
6
|
+
type;
|
|
7
|
+
code;
|
|
8
|
+
param;
|
|
9
|
+
requestId;
|
|
10
|
+
docUrl;
|
|
11
|
+
constructor(status, body, error) {
|
|
12
|
+
super(error?.message ?? `Little Big Brain ${status}: ${body}`);
|
|
13
|
+
this.status = status;
|
|
14
|
+
this.body = body;
|
|
15
|
+
this.error = error;
|
|
16
|
+
this.name = "LbbError";
|
|
17
|
+
this.type = error?.type;
|
|
18
|
+
this.code = error?.code;
|
|
19
|
+
this.param = error?.param;
|
|
20
|
+
this.requestId = error?.request_id;
|
|
21
|
+
this.docUrl = error?.doc_url;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export function sleep(ms) {
|
|
25
|
+
if (ms <= 0)
|
|
26
|
+
return Promise.resolve();
|
|
27
|
+
const timer = globalThis.setTimeout;
|
|
28
|
+
return new Promise((resolve) => {
|
|
29
|
+
if (timer) {
|
|
30
|
+
timer(resolve, ms);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
resolve();
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
export function retryableStatus(status) {
|
|
38
|
+
return status === 429 || status >= 500;
|
|
39
|
+
}
|
|
40
|
+
export function retryAllowed(method, idempotencyKey) {
|
|
41
|
+
const upper = method.toUpperCase();
|
|
42
|
+
return (upper === "GET" ||
|
|
43
|
+
upper === "HEAD" ||
|
|
44
|
+
upper === "OPTIONS" ||
|
|
45
|
+
idempotencyKey !== undefined);
|
|
46
|
+
}
|
|
47
|
+
const MAX_RETRY_AFTER_MS = 60_000;
|
|
48
|
+
/** Parse a Retry-After delta-seconds or HTTP-date value, capped at one minute. */
|
|
49
|
+
export function parseRetryAfterMs(value, nowMs = Date.now()) {
|
|
50
|
+
if (!value)
|
|
51
|
+
return undefined;
|
|
52
|
+
const seconds = Number(value);
|
|
53
|
+
if (Number.isFinite(seconds) && seconds >= 0) {
|
|
54
|
+
return Math.min(seconds * 1_000, MAX_RETRY_AFTER_MS);
|
|
55
|
+
}
|
|
56
|
+
const dateMs = Date.parse(value);
|
|
57
|
+
if (!Number.isFinite(dateMs))
|
|
58
|
+
return undefined;
|
|
59
|
+
return Math.min(Math.max(0, dateMs - nowMs), MAX_RETRY_AFTER_MS);
|
|
60
|
+
}
|
|
61
|
+
export function retryDelayForAttempt(baseDelayMs, attempt, retryAfter) {
|
|
62
|
+
const fallback = Math.max(0, baseDelayMs) * (attempt + 1);
|
|
63
|
+
return parseRetryAfterMs(retryAfter) ?? fallback;
|
|
64
|
+
}
|
|
65
|
+
export function parseResponseJson(text, status, requestId) {
|
|
66
|
+
try {
|
|
67
|
+
return JSON.parse(text);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
const request = requestId ? ` (request ${requestId})` : "";
|
|
71
|
+
throw new SyntaxError(`Little Big Brain returned invalid JSON with HTTP ${status}${request}`, { cause: error });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
export function parseLbbError(status, body, fallbackRequestId) {
|
|
75
|
+
try {
|
|
76
|
+
const parsed = JSON.parse(body);
|
|
77
|
+
if (parsed.error) {
|
|
78
|
+
return new LbbError(status, body, {
|
|
79
|
+
...parsed.error,
|
|
80
|
+
request_id: parsed.error.request_id ?? fallbackRequestId ?? null,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// Fall through to an unstructured error.
|
|
86
|
+
}
|
|
87
|
+
return new LbbError(status, body, {
|
|
88
|
+
type: "api_error",
|
|
89
|
+
code: "unstructured_error",
|
|
90
|
+
message: body || `Little Big Brain ${status}`,
|
|
91
|
+
request_id: fallbackRequestId ?? null,
|
|
92
|
+
});
|
|
93
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import type { components } from "./schema.js";
|
|
2
|
+
/** Request/response types, generated from the committed OpenAPI spec. */
|
|
3
|
+
export type Schemas = components["schemas"];
|
|
4
|
+
export type SearchRequest = Schemas["SemanticGraphSearchRequest"];
|
|
5
|
+
export type SearchResponse = Schemas["SemanticGraphSearchResponse"];
|
|
6
|
+
export type SearchResult = SearchResponse["entities"][number] | SearchResponse["assertions"][number] | SearchResponse["concepts"][number] | SearchResponse["observations"][number] | SearchResponse["paths"][number];
|
|
7
|
+
export type Entity = Schemas["EntityExplorerRow"];
|
|
8
|
+
export type EntitySelector = Schemas["EntitySelector"];
|
|
9
|
+
export type GraphSummary = Schemas["GraphSummaryResponse"];
|
|
10
|
+
export type GraphMetadata = Schemas["GraphMetadataResponse"];
|
|
11
|
+
export type Snapshot = Schemas["SnapshotView"];
|
|
12
|
+
export type CommitRequest = Schemas["TripletCommitFile"];
|
|
13
|
+
export type CommitResponse = Schemas["GraphCommitResponse"];
|
|
14
|
+
export type AskRequest = Schemas["AskRequest"];
|
|
15
|
+
export type AskResponse = Schemas["AskResponse"];
|
|
16
|
+
export type SchemaView = Schemas["SchemaBundleView"];
|
|
17
|
+
/**
|
|
18
|
+
* The unified list-response envelope returned by every collection read
|
|
19
|
+
* (`/v1/graph/entities`, `/v1/graph/edges`, `/v1/graph/observations`): the rows
|
|
20
|
+
* in `data`, plus `next_cursor` (echo back as `cursor` for the next page) and
|
|
21
|
+
* the pre-page `total_count`. Walk pages with {@link LbbClient.listAll}.
|
|
22
|
+
*/
|
|
23
|
+
export interface ListResponse<T> {
|
|
24
|
+
object: "list";
|
|
25
|
+
data: T[];
|
|
26
|
+
has_more: boolean;
|
|
27
|
+
next_cursor: string | null;
|
|
28
|
+
snapshot: Schemas["SnapshotView"];
|
|
29
|
+
total_count: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* A flat `{ field: value }` property map. Values are coerced to each field's
|
|
33
|
+
* declared type server-side, so a string like `"2026-06-26"` lands in a
|
|
34
|
+
* `date_time` field and `"52"` in an `i64` field. The verbose
|
|
35
|
+
* `Schemas["PropertyInput"][]` form is also accepted.
|
|
36
|
+
*/
|
|
37
|
+
export type FlatProperties = Record<string, string | number | boolean>;
|
|
38
|
+
/** A single entity-properties record for commit/import, with flat or verbose properties. */
|
|
39
|
+
export type EntityPropertiesLine = {
|
|
40
|
+
type: string;
|
|
41
|
+
name: string;
|
|
42
|
+
/** Optional stable external key; identity becomes `(type, key)`. */
|
|
43
|
+
key?: string;
|
|
44
|
+
properties: FlatProperties | Schemas["PropertyInput"][];
|
|
45
|
+
};
|
|
46
|
+
/** One bulk-import line: a triplet, or an entity-properties record. */
|
|
47
|
+
export type ImportLine = Schemas["TripletInput"] | EntityPropertiesLine;
|
|
48
|
+
export interface RdfImportOptions {
|
|
49
|
+
format?: "ntriples" | "turtle" | "nquads" | "trig";
|
|
50
|
+
baseIri?: string;
|
|
51
|
+
graphUri?: string;
|
|
52
|
+
/** Stable document scope for blank labels across chunks; omit for legacy stable labels. */
|
|
53
|
+
blankNodeScope?: string;
|
|
54
|
+
batch?: number;
|
|
55
|
+
strict?: boolean;
|
|
56
|
+
observedAt?: string;
|
|
57
|
+
resourceType?: string;
|
|
58
|
+
edgeIdempotency?: "append" | "skip_unchanged";
|
|
59
|
+
idempotencyKey?: string;
|
|
60
|
+
}
|
|
61
|
+
export interface RdfExportOptions {
|
|
62
|
+
format?: "turtle" | "ntriples" | "trig" | "nquads";
|
|
63
|
+
maxTriples?: number;
|
|
64
|
+
asOfValidTime?: string;
|
|
65
|
+
asOfCommitSeq?: number;
|
|
66
|
+
entailment?: "subclass" | "none";
|
|
67
|
+
reason?: boolean;
|
|
68
|
+
}
|
|
69
|
+
export type AttributeFilterOp = "eq" | "ne" | "lt" | "le" | "gt" | "ge";
|
|
70
|
+
export type AttributeFilterValue = string | number | boolean | {
|
|
71
|
+
dateTime: string;
|
|
72
|
+
} | {
|
|
73
|
+
entity: Schemas["EntitySelector"];
|
|
74
|
+
};
|
|
75
|
+
export interface AttributeFilter {
|
|
76
|
+
/** Query variable whose typed property should be compared. Defaults to the first bound pattern variable. */
|
|
77
|
+
var?: string;
|
|
78
|
+
/** Ontology property field name, e.g. `status`, `score`, or `committed_at`. */
|
|
79
|
+
field: string;
|
|
80
|
+
/** Comparison operator. Defaults to `eq`. */
|
|
81
|
+
op?: AttributeFilterOp;
|
|
82
|
+
value: AttributeFilterValue;
|
|
83
|
+
}
|
|
84
|
+
export interface EntityAttributeFilterOptions {
|
|
85
|
+
/** Relation patterns that bind the entity variable(s) before attribute filters run. */
|
|
86
|
+
patterns: Schemas["AnalyticTriplePattern"][];
|
|
87
|
+
/** One or more typed-property comparisons. */
|
|
88
|
+
where: AttributeFilter | AttributeFilter[];
|
|
89
|
+
/** Additional raw structured-SPARQL filters to AND with `where`. */
|
|
90
|
+
filters?: Schemas["SparqlFilter"][];
|
|
91
|
+
select?: string[];
|
|
92
|
+
limit?: number;
|
|
93
|
+
offset?: number;
|
|
94
|
+
asOfValidTime?: string;
|
|
95
|
+
asOfCommitSeq?: number;
|
|
96
|
+
orderBy?: Schemas["SparqlOrderBy"][];
|
|
97
|
+
reason?: boolean;
|
|
98
|
+
maxSolutions?: number;
|
|
99
|
+
maxObjectReads?: number;
|
|
100
|
+
maxFetchedBytes?: number;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Minimal structural shape of `fetch`, so the client depends on neither the DOM
|
|
104
|
+
* lib nor a specific runtime. Native `fetch` (Node 18+, browsers, workers)
|
|
105
|
+
* satisfies it; tests can pass a fake.
|
|
106
|
+
*/
|
|
107
|
+
export type FetchLike = (input: string, init?: {
|
|
108
|
+
method?: string;
|
|
109
|
+
headers?: Record<string, string>;
|
|
110
|
+
body?: string;
|
|
111
|
+
signal?: AbortSignal;
|
|
112
|
+
}) => Promise<{
|
|
113
|
+
ok: boolean;
|
|
114
|
+
status: number;
|
|
115
|
+
headers?: {
|
|
116
|
+
get(name: string): string | null;
|
|
117
|
+
};
|
|
118
|
+
text(): Promise<string>;
|
|
119
|
+
}>;
|
|
120
|
+
/** One term in a SPARQL result binding (the standard results-JSON term object). */
|
|
121
|
+
export interface SparqlTerm {
|
|
122
|
+
type: "uri" | "literal" | "bnode" | "typed-literal";
|
|
123
|
+
value: string;
|
|
124
|
+
datatype?: string;
|
|
125
|
+
"xml:lang"?: string;
|
|
126
|
+
}
|
|
127
|
+
/** The standard SPARQL 1.1 Query Results JSON document. */
|
|
128
|
+
export interface SparqlResultsJson {
|
|
129
|
+
head: {
|
|
130
|
+
vars?: string[];
|
|
131
|
+
link?: string[];
|
|
132
|
+
};
|
|
133
|
+
results?: {
|
|
134
|
+
bindings: Record<string, SparqlTerm>[];
|
|
135
|
+
};
|
|
136
|
+
boolean?: boolean;
|
|
137
|
+
}
|
|
138
|
+
/** Parsed SPARQL results: the head vars, the ASK boolean (or null), the raw
|
|
139
|
+
* typed bindings, and the bindings flattened to `{ variable: lexicalValue }`. */
|
|
140
|
+
export interface SparqlResults {
|
|
141
|
+
vars: string[];
|
|
142
|
+
boolean: boolean | null;
|
|
143
|
+
bindings: Record<string, SparqlTerm>[];
|
|
144
|
+
rows: Record<string, string>[];
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Parse a {@link Schemas.SparqlTextResponse} (whose `results` field carries the
|
|
148
|
+
* SPARQL Results document as a JSON *string*) into typed bindings plus flat
|
|
149
|
+
* `{ variable: lexicalValue }` rows — the form most callers want, so they never
|
|
150
|
+
* have to `JSON.parse` and zip `head.vars` with binding values by hand.
|
|
151
|
+
*/
|
|
152
|
+
export declare function parseSparqlResults(response: Schemas["SparqlTextResponse"]): SparqlResults;
|
|
153
|
+
export declare function firstPatternVariable(patterns: Schemas["AnalyticTriplePattern"][]): string;
|
|
154
|
+
export declare function attributeFilter(filter: AttributeFilter, defaultVar: string): Schemas["SparqlFilter"];
|
|
155
|
+
export interface LbbClientOptions {
|
|
156
|
+
/** Base URL of the little big brain server, e.g. `https://db.eu.littlebigbrain.com`. */
|
|
157
|
+
baseUrl: string;
|
|
158
|
+
/** Stack API key (`lbb_sk_test_…` / `lbb_sk_live_…`) or single-mode token. */
|
|
159
|
+
apiKey?: string;
|
|
160
|
+
/** Graph name (sent as `?graph=`; server default is `main`). */
|
|
161
|
+
graph?: string;
|
|
162
|
+
/** Branch name (sent as `?branch=`; server default is `main`). */
|
|
163
|
+
branch?: string;
|
|
164
|
+
/**
|
|
165
|
+
* Stack slug (sent as `?stack=`). Needed only with a session-token `apiKey`
|
|
166
|
+
* (`lbb_ses_…`), which authorizes an account rather than a single stack; a
|
|
167
|
+
* stack API key (`lbb_sk_test_…` / `lbb_sk_live_…`) already fixes the stack and ignores this.
|
|
168
|
+
*/
|
|
169
|
+
stack?: string;
|
|
170
|
+
/** Override the fetch implementation (defaults to the global `fetch`). */
|
|
171
|
+
fetch?: FetchLike;
|
|
172
|
+
/** API version header sent on every request. Defaults to the beta reset contract. */
|
|
173
|
+
apiVersion?: string;
|
|
174
|
+
/** Retry count for 429/5xx responses and network failures. Defaults to 2. */
|
|
175
|
+
maxRetries?: number;
|
|
176
|
+
/** Base delay between retries. Defaults to 100ms. Tests can set 0. */
|
|
177
|
+
retryDelayMs?: number;
|
|
178
|
+
/** Per-attempt timeout, including response-body reads. Defaults to 120 seconds; 0 disables it. */
|
|
179
|
+
timeoutMs?: number;
|
|
180
|
+
/** Called immediately before each network attempt. Bodies and credentials are never included. */
|
|
181
|
+
onRequest?: (event: LbbRequestEvent) => void;
|
|
182
|
+
/** Called once after the final HTTP response. Bodies and credentials are never included. */
|
|
183
|
+
onResponse?: (event: LbbResponseEvent) => void;
|
|
184
|
+
}
|
|
185
|
+
export interface LbbRequestEvent {
|
|
186
|
+
method: string;
|
|
187
|
+
url: string;
|
|
188
|
+
attempt: number;
|
|
189
|
+
maxAttempts: number;
|
|
190
|
+
idempotencyKey?: string;
|
|
191
|
+
}
|
|
192
|
+
export interface LbbResponseEvent {
|
|
193
|
+
method: string;
|
|
194
|
+
url: string;
|
|
195
|
+
status: number;
|
|
196
|
+
requestId?: string;
|
|
197
|
+
attempts: number;
|
|
198
|
+
retryCount: number;
|
|
199
|
+
elapsedMs: number;
|
|
200
|
+
}
|
|
201
|
+
export type LbbStackActivityWindow = "1h" | "4h" | "12h" | "24h";
|
|
202
|
+
export interface LbbStackActivityResponse {
|
|
203
|
+
ok: true;
|
|
204
|
+
stack: {
|
|
205
|
+
slug: string;
|
|
206
|
+
name?: string;
|
|
207
|
+
};
|
|
208
|
+
window: {
|
|
209
|
+
range: LbbStackActivityWindow;
|
|
210
|
+
from_micros: number;
|
|
211
|
+
to_micros: number;
|
|
212
|
+
bucket_seconds: number;
|
|
213
|
+
freshness_seconds: number;
|
|
214
|
+
};
|
|
215
|
+
totals: {
|
|
216
|
+
requests: number;
|
|
217
|
+
errors: number;
|
|
218
|
+
p50_latency_ms: number;
|
|
219
|
+
p95_latency_ms: number;
|
|
220
|
+
p99_latency_ms: number;
|
|
221
|
+
storage_read_ops: number;
|
|
222
|
+
storage_read_bytes: number;
|
|
223
|
+
storage_write_ops: number;
|
|
224
|
+
storage_write_bytes: number;
|
|
225
|
+
index_read_ops: number;
|
|
226
|
+
index_read_bytes: number;
|
|
227
|
+
};
|
|
228
|
+
details: {
|
|
229
|
+
total_bucket_count: number;
|
|
230
|
+
active_bucket_count: number;
|
|
231
|
+
error_rate: number;
|
|
232
|
+
storage_total_ops: number;
|
|
233
|
+
storage_total_bytes: number;
|
|
234
|
+
non_index_storage_read_ops: number;
|
|
235
|
+
non_index_storage_read_bytes: number;
|
|
236
|
+
index_read_share: number;
|
|
237
|
+
first_activity_bucket_start_micros?: number;
|
|
238
|
+
last_activity_bucket_start_micros?: number;
|
|
239
|
+
};
|
|
240
|
+
series: Array<{
|
|
241
|
+
bucket_start_micros: number;
|
|
242
|
+
requests: number;
|
|
243
|
+
errors: number;
|
|
244
|
+
p50_latency_ms: number;
|
|
245
|
+
p95_latency_ms: number;
|
|
246
|
+
p99_latency_ms: number;
|
|
247
|
+
storage_read_ops: number;
|
|
248
|
+
storage_read_bytes: number;
|
|
249
|
+
storage_write_ops: number;
|
|
250
|
+
storage_write_bytes: number;
|
|
251
|
+
index_read_ops: number;
|
|
252
|
+
index_read_bytes: number;
|
|
253
|
+
}>;
|
|
254
|
+
routes: Array<{
|
|
255
|
+
family: string;
|
|
256
|
+
requests: number;
|
|
257
|
+
errors: number;
|
|
258
|
+
error_rate: number;
|
|
259
|
+
request_share: number;
|
|
260
|
+
p50_latency_ms: number;
|
|
261
|
+
p95_latency_ms: number;
|
|
262
|
+
p99_latency_ms: number;
|
|
263
|
+
}>;
|
|
264
|
+
storage: Array<{
|
|
265
|
+
family: string;
|
|
266
|
+
read_ops: number;
|
|
267
|
+
read_bytes: number;
|
|
268
|
+
write_ops: number;
|
|
269
|
+
write_bytes: number;
|
|
270
|
+
total_ops: number;
|
|
271
|
+
total_bytes: number;
|
|
272
|
+
op_share: number;
|
|
273
|
+
byte_share: number;
|
|
274
|
+
}>;
|
|
275
|
+
partial: boolean;
|
|
276
|
+
}
|
|
277
|
+
export interface LbbErrorPayload {
|
|
278
|
+
type?: string;
|
|
279
|
+
code?: string;
|
|
280
|
+
message?: string;
|
|
281
|
+
param?: string | null;
|
|
282
|
+
request_id?: string | null;
|
|
283
|
+
doc_url?: string | null;
|
|
284
|
+
}
|
|
285
|
+
export interface RawLbbResponse<T> {
|
|
286
|
+
data: T;
|
|
287
|
+
status: number;
|
|
288
|
+
requestId?: string;
|
|
289
|
+
version?: string;
|
|
290
|
+
headers?: {
|
|
291
|
+
get(name: string): string | null;
|
|
292
|
+
};
|
|
293
|
+
/** Total HTTP attempts, including the successful/final attempt. */
|
|
294
|
+
attempts: number;
|
|
295
|
+
/** Convenience alias for `attempts - 1`. */
|
|
296
|
+
retryCount: number;
|
|
297
|
+
/** Total wall-clock duration across attempts and retry delays. */
|
|
298
|
+
elapsedMs: number;
|
|
299
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a {@link Schemas.SparqlTextResponse} (whose `results` field carries the
|
|
3
|
+
* SPARQL Results document as a JSON *string*) into typed bindings plus flat
|
|
4
|
+
* `{ variable: lexicalValue }` rows — the form most callers want, so they never
|
|
5
|
+
* have to `JSON.parse` and zip `head.vars` with binding values by hand.
|
|
6
|
+
*/
|
|
7
|
+
export function parseSparqlResults(response) {
|
|
8
|
+
const doc = JSON.parse(response.results);
|
|
9
|
+
const vars = doc.head?.vars ?? [];
|
|
10
|
+
if (typeof doc.boolean === "boolean") {
|
|
11
|
+
return { vars, boolean: doc.boolean, bindings: [], rows: [] };
|
|
12
|
+
}
|
|
13
|
+
const bindings = doc.results?.bindings ?? [];
|
|
14
|
+
const rows = bindings.map((binding) => Object.fromEntries(Object.entries(binding).map(([name, term]) => [name, term.value])));
|
|
15
|
+
return { vars, boolean: null, bindings, rows };
|
|
16
|
+
}
|
|
17
|
+
export function firstPatternVariable(patterns) {
|
|
18
|
+
for (const pattern of patterns) {
|
|
19
|
+
if ("var" in pattern.subject)
|
|
20
|
+
return pattern.subject.var;
|
|
21
|
+
if ("var" in pattern.object)
|
|
22
|
+
return pattern.object.var;
|
|
23
|
+
}
|
|
24
|
+
return "entity";
|
|
25
|
+
}
|
|
26
|
+
function attributeFilterValue(value) {
|
|
27
|
+
if (typeof value === "boolean")
|
|
28
|
+
return { bool: value };
|
|
29
|
+
if (typeof value === "number")
|
|
30
|
+
return Number.isInteger(value) ? { i64: value } : { f64: value };
|
|
31
|
+
if (typeof value === "string")
|
|
32
|
+
return { str: value };
|
|
33
|
+
if ("dateTime" in value)
|
|
34
|
+
return { date_time: value.dateTime };
|
|
35
|
+
return { entity: value.entity };
|
|
36
|
+
}
|
|
37
|
+
export function attributeFilter(filter, defaultVar) {
|
|
38
|
+
return {
|
|
39
|
+
compare: {
|
|
40
|
+
op: filter.op ?? "eq",
|
|
41
|
+
left: {
|
|
42
|
+
property: { var: filter.var ?? defaultVar, field: filter.field },
|
|
43
|
+
},
|
|
44
|
+
right: { value: attributeFilterValue(filter.value) },
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@littlebigbrain/client",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "TypeScript client for the
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "TypeScript client for the little big brain graph + hybrid search HTTP API",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/littlebigbrains/lbb-typescript.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://docs.littlebigbrain.com/sdks/typescript/",
|
|
11
|
+
"bugs": "https://github.com/littlebigbrains/lbb-typescript/issues",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"little-big-brain",
|
|
14
|
+
"graph",
|
|
15
|
+
"search",
|
|
16
|
+
"sdk",
|
|
17
|
+
"typescript"
|
|
18
|
+
],
|
|
6
19
|
"type": "module",
|
|
20
|
+
"sideEffects": false,
|
|
7
21
|
"main": "./dist/index.js",
|
|
8
22
|
"types": "./dist/index.d.ts",
|
|
9
23
|
"exports": {
|
|
@@ -12,17 +26,32 @@
|
|
|
12
26
|
"import": "./dist/index.js"
|
|
13
27
|
}
|
|
14
28
|
},
|
|
15
|
-
"files": [
|
|
16
|
-
|
|
29
|
+
"files": [
|
|
30
|
+
"dist",
|
|
31
|
+
"README.md",
|
|
32
|
+
"LICENSE"
|
|
33
|
+
],
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=18"
|
|
39
|
+
},
|
|
17
40
|
"scripts": {
|
|
41
|
+
"clean": "node clean.mjs",
|
|
42
|
+
"clean:test": "node clean.mjs test-dist",
|
|
18
43
|
"generate": "openapi-typescript ../../contracts/openapi.json -o src/schema.ts",
|
|
19
|
-
"build": "tsc -p tsconfig.json",
|
|
44
|
+
"build": "npm run clean && tsc -p tsconfig.build.json",
|
|
45
|
+
"pack:check": "npm run build && publint --strict && attw --pack . --profile esm-only",
|
|
20
46
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
21
|
-
"test": "tsc -p tsconfig.json && node --test \"dist/**/*.test.js\""
|
|
47
|
+
"test": "npm run clean:test && tsc -p tsconfig.test.json && node --test \"test-dist/**/*.test.js\"",
|
|
48
|
+
"test:coverage": "npm run clean:test && tsc -p tsconfig.test.json && node --test --experimental-test-coverage --test-coverage-include=test-dist/*.js --test-coverage-exclude=test-dist/schema.js --test-coverage-exclude=test-dist/*.test.js --test-coverage-lines=75 --test-coverage-branches=80 --test-coverage-functions=45 \"test-dist/**/*.test.js\""
|
|
22
49
|
},
|
|
23
50
|
"devDependencies": {
|
|
51
|
+
"@arethetypeswrong/cli": "^0.18.4",
|
|
24
52
|
"@types/node": "^22",
|
|
25
53
|
"openapi-typescript": "^7",
|
|
54
|
+
"publint": "^0.3.21",
|
|
26
55
|
"typescript": "^5.6"
|
|
27
56
|
}
|
|
28
57
|
}
|
package/dist/client.test.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|