@littlebigbrain/client 0.8.0 → 0.9.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/client.js CHANGED
@@ -1,9 +1,74 @@
1
1
  import { parseSparqlResults } from "./types.js";
2
2
  import { bodyMarksTerminal, errorCodeFromBody, fullJitterBackoffMs, parseLbbError, parseResponseJson, retryAllowed, retryableStatus, retryDelayMs, sleep, } from "./transport.js";
3
- import { ContextNamespace, EntityNamespace, GraphNamespace, IndexNamespace, OntologyNamespace, QueryNamespace, SchemaNamespace, SearchNamespace, } from "./namespaces.js";
3
+ import { LbbCapabilityError } from "./transport.js";
4
+ import { ContextNamespace, EntityNamespace, GraphNamespace, OntologyNamespace, QueryNamespace, SchemaNamespace, SearchNamespace, } from "./namespaces.js";
4
5
  export { parseSparqlResults } from "./types.js";
5
- export { LbbError } from "./transport.js";
6
- export { ContextNamespace, EntityNamespace, FactsNamespace, GraphNamespace, IndexNamespace, OntologyNamespace, QueryNamespace, SchemaNamespace, SearchNamespace, } from "./namespaces.js";
6
+ export { LbbCapabilityError, LbbError } from "./transport.js";
7
+ export { ContextNamespace, EntityNamespace, FactsNamespace, GraphNamespace, OntologyNamespace, QueryNamespace, SchemaNamespace, SearchNamespace, } from "./namespaces.js";
8
+ function durableImportBytes(line) {
9
+ if (line instanceof Uint8Array)
10
+ return line;
11
+ const encoded = typeof line === "string" ? line : JSON.stringify(line);
12
+ return new TextEncoder().encode(encoded.endsWith("\n") ? encoded : `${encoded}\n`);
13
+ }
14
+ function durableImportIterator(source) {
15
+ if (typeof source === "string") {
16
+ return (async function* () {
17
+ yield source;
18
+ })();
19
+ }
20
+ if (Symbol.asyncIterator in Object(source)) {
21
+ return source[Symbol.asyncIterator]();
22
+ }
23
+ const iterator = source[Symbol.iterator]();
24
+ return {
25
+ next: async () => iterator.next(),
26
+ return: async () => {
27
+ iterator.return?.();
28
+ return { done: true, value: undefined };
29
+ },
30
+ };
31
+ }
32
+ function durableImportBody(source) {
33
+ const iterator = durableImportIterator(source);
34
+ const Stream = globalThis.ReadableStream;
35
+ if (Stream) {
36
+ return new Stream({
37
+ async pull(controller) {
38
+ try {
39
+ const item = await iterator.next();
40
+ if (item.done) {
41
+ controller.close();
42
+ }
43
+ else {
44
+ controller.enqueue(durableImportBytes(item.value));
45
+ }
46
+ }
47
+ catch (error) {
48
+ controller.error(error);
49
+ }
50
+ },
51
+ async cancel() {
52
+ await iterator.return?.();
53
+ },
54
+ });
55
+ }
56
+ return {
57
+ async *[Symbol.asyncIterator]() {
58
+ try {
59
+ for (;;) {
60
+ const item = await iterator.next();
61
+ if (item.done)
62
+ return;
63
+ yield durableImportBytes(item.value);
64
+ }
65
+ }
66
+ finally {
67
+ await iterator.return?.();
68
+ }
69
+ },
70
+ };
71
+ }
7
72
  /**
8
73
  * A typed HTTP client for a little big brain graph server. One instance is scoped to a
9
74
  * single graph/branch; construct another for a different scope. All methods
@@ -24,11 +89,11 @@ export class LbbClient {
24
89
  onRequest;
25
90
  onResponse;
26
91
  onRetry;
92
+ capabilities;
27
93
  /** A5 default read consistency applied when a read omits its own value. */
28
94
  defaultConsistency;
29
95
  context;
30
96
  search;
31
- indexes;
32
97
  entities;
33
98
  schema;
34
99
  ontology;
@@ -43,7 +108,7 @@ export class LbbClient {
43
108
  this.graphName = options.graph;
44
109
  this.branchName = options.branch;
45
110
  this.stack = options.stack;
46
- this.apiVersion = options.apiVersion ?? "2026-06-22";
111
+ this.apiVersion = options.apiVersion ?? "2026-07-23";
47
112
  this.maxRetries = options.maxRetries ?? 6;
48
113
  this.retryDelayMs = options.retryDelayMs ?? 100;
49
114
  this.retryBudgetMs = options.retryBudgetMs ?? 60_000;
@@ -72,7 +137,6 @@ export class LbbClient {
72
137
  this.fetchImpl = chosen;
73
138
  this.context = new ContextNamespace(this);
74
139
  this.search = new SearchNamespace(this);
75
- this.indexes = new IndexNamespace(this);
76
140
  this.entities = new EntityNamespace(this);
77
141
  this.schema = new SchemaNamespace(this);
78
142
  this.ontology = new OntologyNamespace(this);
@@ -174,6 +238,7 @@ export class LbbClient {
174
238
  method,
175
239
  headers,
176
240
  body,
241
+ ...(opts.duplex ? { duplex: opts.duplex } : {}),
177
242
  };
178
243
  const timeoutMs = opts.timeoutMs ?? this.timeoutMs;
179
244
  const maxRetries = opts.maxRetries ?? this.maxRetries;
@@ -209,10 +274,16 @@ export class LbbClient {
209
274
  maxAttempts: maxRetries + 1,
210
275
  idempotencyKey: opts.idempotencyKey,
211
276
  });
212
- response = await this.fetchImpl(url, {
277
+ const requestInit = {
213
278
  ...init,
214
279
  signal: controller?.signal ?? opts.signal,
215
- });
280
+ };
281
+ // Keep FetchLike's long-standing string-body test-double contract while
282
+ // allowing this one endpoint to pass a native streaming body to fetch.
283
+ // Native browser/Node fetch implementations accept the extended shape;
284
+ // custom transports that need durable imports can inspect it at runtime.
285
+ const streamingFetch = this.fetchImpl;
286
+ response = await streamingFetch(url, requestInit);
216
287
  text = await response.text();
217
288
  }
218
289
  catch (error) {
@@ -323,6 +394,12 @@ export class LbbClient {
323
394
  idempotencyKey(prefix = "request") {
324
395
  return this.mutationKey(prefix);
325
396
  }
397
+ async requireCapability(capability) {
398
+ this.capabilities ??= this.request("GET", "/version").then((version) => new Set(version.capabilities));
399
+ if (!(await this.capabilities).has(capability)) {
400
+ throw new LbbCapabilityError(capability);
401
+ }
402
+ }
326
403
  // --- writes ---
327
404
  /** Commit triplets and optional entity embeddings. Prefer `client.graph("main").facts.create(...)`. */
328
405
  async commit(body, opts = {}) {
@@ -354,12 +431,10 @@ export class LbbClient {
354
431
  * streamed request without a single oversized commit. Pass `lines` as an array
355
432
  * (serialized to NDJSON here) or a pre-built NDJSON string.
356
433
  *
357
- * Set `index: true` to run one full index build after the last batch, so the
358
- * data is served from the persisted runs (not just the ephemeral snapshot
359
- * fallback) by the time the call returns — the "bulk load, queryable on return"
360
- * path. Prefer this over indexing per batch (which serializes builds and races
361
- * the throttle): import the whole dataset, index once. The response's `index`
362
- * object reports whether the build ran or was skipped.
434
+ * A successful import durably enqueues one complete published-generation
435
+ * build after the final batch. It does not build index families or wait for
436
+ * visibility; the response's `published_generation` object carries the
437
+ * durable job and due sequence to observe.
363
438
  */
364
439
  async import(lines, opts = {}) {
365
440
  const ndjson = typeof lines === "string"
@@ -372,7 +447,6 @@ export class LbbClient {
372
447
  batch: opts.batch,
373
448
  strict: opts.strict,
374
449
  observed_at: opts.observedAt,
375
- index: opts.index,
376
450
  },
377
451
  idempotencyKey: opts.idempotencyKey ?? this.idempotencyKey("import"),
378
452
  });
@@ -380,6 +454,72 @@ export class LbbClient {
380
454
  // write→floor→read loop reads naturally after a bulk load.
381
455
  return { ...response, commitSeq: response.committed_commit_seq ?? null };
382
456
  }
457
+ /**
458
+ * Stream NDJSON into immutable storage and enqueue a durable import job.
459
+ *
460
+ * The idempotency key is mandatory and binds the key to the uploaded content.
461
+ * Streaming uploads are attempted once: a one-shot async iterator cannot be
462
+ * replayed safely by an automatic HTTP retry. Call this method again with a
463
+ * fresh iterable and the same key to perform an explicit idempotent replay.
464
+ */
465
+ async submitImport(lines, opts) {
466
+ if (!opts?.idempotencyKey?.trim()) {
467
+ throw new TypeError("submitImport requires a non-empty idempotencyKey");
468
+ }
469
+ await this.requireCapability("durable_import_jobs_v1");
470
+ return this.request("POST", "/v1/graph/import-jobs", {
471
+ rawBody: durableImportBody(lines),
472
+ contentType: "application/x-ndjson",
473
+ duplex: "half",
474
+ query: {
475
+ batch: opts.batch,
476
+ strict: opts.strict,
477
+ observed_at: opts.observedAt,
478
+ },
479
+ idempotencyKey: opts.idempotencyKey,
480
+ maxRetries: 0,
481
+ retry: false,
482
+ signal: opts.signal,
483
+ });
484
+ }
485
+ async getImportJob(jobId) {
486
+ await this.requireCapability("durable_import_jobs_v1");
487
+ return this.request("GET", "/v1/graph/import-jobs", {
488
+ query: { job_id: jobId },
489
+ });
490
+ }
491
+ async cancelImportJob(jobId) {
492
+ await this.requireCapability("durable_import_jobs_v1");
493
+ return this.request("DELETE", "/v1/graph/import-jobs", {
494
+ query: { job_id: jobId },
495
+ });
496
+ }
497
+ async waitForImportJob(jobId, opts = {}) {
498
+ const pollIntervalMs = opts.pollIntervalMs ?? 1_000;
499
+ const timeoutMs = opts.timeoutMs ?? 0;
500
+ if (!Number.isFinite(pollIntervalMs) || pollIntervalMs < 0) {
501
+ throw new RangeError("pollIntervalMs must be a non-negative number");
502
+ }
503
+ if (!Number.isFinite(timeoutMs) || timeoutMs < 0) {
504
+ throw new RangeError("timeoutMs must be a non-negative number");
505
+ }
506
+ const deadline = timeoutMs > 0 ? Date.now() + timeoutMs : undefined;
507
+ for (;;) {
508
+ if (opts.signal?.aborted) {
509
+ throw opts.signal.reason ?? new Error("request aborted");
510
+ }
511
+ const status = await this.getImportJob(jobId);
512
+ if (status.state === "succeeded" ||
513
+ status.state === "failed" ||
514
+ status.state === "cancelled") {
515
+ return status;
516
+ }
517
+ if (deadline !== undefined && Date.now() >= deadline) {
518
+ throw new Error(`timed out waiting for durable import job ${jobId}`);
519
+ }
520
+ await sleep(pollIntervalMs);
521
+ }
522
+ }
383
523
  /**
384
524
  * Bulk-ingest N-Triples, Turtle, N-Quads, or TriG without client-side conversion. Resource-object
385
525
  * triples become keyed Resource edges; literal-object triples become text
@@ -410,19 +550,6 @@ export class LbbClient {
410
550
  idempotencyKey: opts.idempotencyKey ?? this.idempotencyKey("import-rdf"),
411
551
  });
412
552
  }
413
- /** Export the snapshot-visible RDF projection as Turtle, N-Triples, TriG, or N-Quads. */
414
- exportRdf(opts = {}) {
415
- return this.request("GET", "/v1/graph/export/rdf", {
416
- query: {
417
- format: opts.format === "ntriples" ? "nt" : opts.format,
418
- max_triples: opts.maxTriples,
419
- as_of_valid_time: opts.asOfValidTime,
420
- as_of_commit_seq: opts.asOfCommitSeq,
421
- entailment: opts.entailment,
422
- reason: opts.reason,
423
- },
424
- });
425
- }
426
553
  /**
427
554
  * Retract specific edges and/or every edge touching given entities. Appends
428
555
  * superseding retract events rather than deleting — history stays visible in an
@@ -640,23 +767,19 @@ export class LbbClient {
640
767
  query: { kind: opts.kind, run: opts.run },
641
768
  });
642
769
  }
643
- /**
644
- * Champion vs challenger retrieval over one pinned snapshot. Returns
645
- * promotion evidence (hit-rate@k, latency, overlap); never promotes.
646
- */
647
- shadowEval(body) {
648
- return this.request("POST", "/v1/models/shadow-eval", { body });
649
- }
650
- /**
651
- * Execution-verified QA probes generated from the graph's current edges —
652
- * labels are the executed projections, so they are verified by construction.
653
- * Feeds `shadowEval` directly.
654
- */
770
+ /** Execution-verified QA probes generated from the graph's current edges. */
655
771
  syntheticEval(opts = {}) {
656
772
  return this.request("GET", "/v1/models/synthetic-eval", {
657
773
  query: { limit: opts.limit },
658
774
  });
659
775
  }
776
+ /**
777
+ * Compare champion and challenger retrieval over one pinned published
778
+ * snapshot. The endpoint returns promotion evidence but never promotes.
779
+ */
780
+ shadowEval(body) {
781
+ return this.request("POST", "/v1/models/shadow-eval", { body });
782
+ }
660
783
  /** The doubling retrain policy: is a retrain due for this model kind? */
661
784
  modelCadence(opts) {
662
785
  return this.request("GET", "/v1/models/cadence", {
@@ -682,18 +805,6 @@ export class LbbClient {
682
805
  setTrainingConfig(body) {
683
806
  return this.request("POST", "/v1/models/training-config", { body });
684
807
  }
685
- /**
686
- * Verdict on an ask (`accepted` | `rejected` | `corrected` + the right
687
- * plan), joined to the ask's trace by `ask_id` — the planner fine-tune's
688
- * explicit feedback capture. `accepted: false` in the response means
689
- * signal capture is off on this deployment (the contract is identical).
690
- */
691
- askFeedback(body, opts = {}) {
692
- return this.request("POST", "/v1/ask/feedback", {
693
- body,
694
- idempotencyKey: opts.idempotencyKey ?? this.idempotencyKey("ask-feedback"),
695
- });
696
- }
697
808
  ingestSignals(body, opts = {}) {
698
809
  return this.request("POST", "/v1/signals", {
699
810
  body,
@@ -718,39 +829,25 @@ export class LbbClient {
718
829
  ],
719
830
  }, opts);
720
831
  }
721
- /**
722
- * The planner fine-tune's training feed: accepted/corrected feedback
723
- * joined to its traces (signals ≤ the split pin), topped up with
724
- * execution-verified synthetic plans.
725
- */
832
+ /** Planner training examples at or before an optional signal split. */
726
833
  plannerDataset(opts = {}) {
727
834
  return this.request("GET", "/v1/models/planner-dataset", {
728
835
  query: { limit: opts.limit, split_seq: opts.splitSeq },
729
836
  });
730
837
  }
731
- /**
732
- * The DPO pass's training feed: preference pairs from corrected verdicts,
733
- * paired rejections, and synthetic corrupted-slot pairs.
734
- */
838
+ /** Planner preference pairs at or before an optional signal split. */
735
839
  plannerPreferenceDataset(opts = {}) {
736
840
  return this.request("GET", "/v1/models/planner-preference-dataset", {
737
841
  query: { limit: opts.limit, split_seq: opts.splitSeq },
738
842
  });
739
843
  }
740
- /**
741
- * The suggest-ranker trainer's probe feed: `suggestion_adopted` signals
742
- * (typed prefix + adopted text) ≤ the split pin, topped up with
743
- * execution-verified synthetic vocabulary pairs.
744
- */
844
+ /** Suggest-ranker examples at or before an optional signal split. */
745
845
  suggestDataset(opts = {}) {
746
846
  return this.request("GET", "/v1/models/suggest-dataset", {
747
847
  query: { limit: opts.limit, split_seq: opts.splitSeq },
748
848
  });
749
849
  }
750
- /**
751
- * The extractor fine-tune's training feed: EPISODE transcripts joined to
752
- * the facts the observe pipeline committed from them.
753
- */
850
+ /** Extractor examples at or before an optional signal split. */
754
851
  extractorDataset(opts = {}) {
755
852
  return this.request("GET", "/v1/models/extractor-dataset", {
756
853
  query: { limit: opts.limit, split_seq: opts.splitSeq },
@@ -768,8 +865,7 @@ export class LbbClient {
768
865
  }
769
866
  /**
770
867
  * Promote a finished `planner_lora` training run: gated on held-out slot
771
- * exactness, recorded as a `kind=planner` training run whose adapter `/v1/ask`
772
- * then serves.
868
+ * exactness and recorded as a `kind=planner` training run.
773
869
  */
774
870
  promotePlanner(opts) {
775
871
  return this.request("POST", "/v1/models/promote-planner", {
@@ -800,37 +896,18 @@ export class LbbClient {
800
896
  suggest(body) {
801
897
  return this.request("POST", "/v1/search/suggest", { body });
802
898
  }
803
- /**
804
- * Snap free text to the nearest real vocabulary item. Embedding cosine
805
- * on a managed graph, else lexical; never fabricates a term.
806
- */
899
+ /** Snap free text to the nearest term in the pinned published vocabulary. */
807
900
  resolveTerm(body) {
808
901
  return this.request("POST", "/v1/search/resolve-term", { body });
809
902
  }
810
- /**
811
- * Ground a natural-language question to the graph's real vocabulary, retrieve
812
- * against the pinned snapshot, and answer with citations (`/v1/ask`).
813
- */
814
- ask(body) {
815
- return this.request("POST", "/v1/ask", { body });
816
- }
817
- /**
818
- * Name the relation between two entities (`/v1/decode`): the DB narrows the
819
- * candidates to the type pair's admissible relations, answers alone
820
- * when the pair forces a single relation, and otherwise decodes it with the
821
- * graph-native fine-tuned model — the "DB narrows, cheap model decodes" call.
822
- */
903
+ /** Decode a relation from the graph's admissible published vocabulary. */
823
904
  decode(body) {
824
905
  return this.request("POST", "/v1/decode", { body });
825
906
  }
826
- /**
827
- * Report which completion mechanisms will carry on this graph:
828
- * signature sparsity, name semantics, sampled narrowing recall, and a
829
- * narrow / narrow+finetune / lexical-first recommendation.
830
- */
907
+ /** Report completion strategy fitness for the pinned published graph. */
831
908
  groundability(opts = {}) {
832
909
  return this.request("GET", "/v1/graph/groundability", {
833
- query: opts.sample != null ? { sample: String(opts.sample) } : undefined,
910
+ query: opts.sample == null ? undefined : { sample: opts.sample },
834
911
  });
835
912
  }
836
913
  /**
@@ -880,7 +957,6 @@ export class LbbClient {
880
957
  name: opts.name,
881
958
  relations: opts.relations?.join(","),
882
959
  as_of: opts.asOf,
883
- indexed: opts.indexed,
884
960
  },
885
961
  });
886
962
  }
@@ -920,39 +996,11 @@ export class LbbClient {
920
996
  },
921
997
  });
922
998
  }
923
- /**
924
- * Paged edge listing. Scope to one node with `id` (or `type`+`name`) and a
925
- * `direction` (`out`/`in`/`both`) to walk **every** edge of a high-degree node
926
- * — `entityDetail` returns the full set but is awkward to page; this carries
927
- * `offset`/`limit` and reports `total_count`. Optional `relation`/`q` filters
928
- * and an `asOf`/`asOfCommitSeq` snapshot pin. Each row carries `valid_time`, so
929
- * the page is enough to reconstruct a per-edge timeline.
930
- */
931
- graphEdges(opts = {}) {
932
- return this.request("GET", "/v1/graph/edges", {
933
- query: {
934
- id: opts.id,
935
- type: opts.type,
936
- name: opts.name,
937
- direction: opts.direction,
938
- relation: opts.relation,
939
- q: opts.q,
940
- limit: opts.limit,
941
- cursor: opts.cursor,
942
- offset: opts.offset,
943
- as_of: opts.asOf,
944
- as_of_commit_seq: opts.asOfCommitSeq,
945
- },
946
- });
947
- }
948
999
  /**
949
1000
  * Page through every row of a list endpoint, following `next_cursor` until
950
1001
  * exhausted. Pass a fetcher that takes a cursor and returns a
951
1002
  * {@link ListResponse}:
952
- * ```ts
953
- * for await (const e of client.listAll((cursor) =>
954
- * client.entities.list({ cursor, fields: "title" }))) { … }
955
- * ```
1003
+ * The caller supplies a bounded collection endpoint and its cursor.
956
1004
  */
957
1005
  async *listAll(fetchPage) {
958
1006
  let cursor;
@@ -982,10 +1030,6 @@ export class LbbClient {
982
1030
  why(body) {
983
1031
  return this.request("POST", "/v1/query/why", { body });
984
1032
  }
985
- /** SHACL-style shape/pattern query. */
986
- shacl(body) {
987
- return this.request("POST", "/v1/query/shacl", { body });
988
- }
989
1033
  /**
990
1034
  * SPARQL-subset SELECT/ASK/aggregate query (FILTER, HAVING, ORDER BY, ASK,
991
1035
  * COUNT/SUM/AVG/MIN/MAX). GROUP BY is not limited to entity identity:
@@ -1028,36 +1072,6 @@ export class LbbClient {
1028
1072
  analytics(body) {
1029
1073
  return this.request("POST", "/v1/query/analytics", { body });
1030
1074
  }
1031
- /**
1032
- * Run inference rules (SHACL-AF `sh:TripleRule` shape) to a bounded fixpoint
1033
- * and return the derived edges as a **preview** — derived facts are never
1034
- * written to the asserted graph. Each rule is a BGP `body`/`where` plus a
1035
- * `head` triple template instantiated per binding.
1036
- */
1037
- infer(body) {
1038
- return this.request("POST", "/v1/inference/run", { body });
1039
- }
1040
- /**
1041
- * Define (replace) the versioned rule set stored on the scoped graph branch.
1042
- * The stored set is what SHACL `include_derived` and `infer` use when a
1043
- * request carries no inline rules. Returns the new `rules_version`.
1044
- */
1045
- defineRules(body) {
1046
- return this.request("POST", "/v1/inference/rules", { body });
1047
- }
1048
- /** The rule set stored on the scoped graph branch (version + rules). */
1049
- graphRules() {
1050
- return this.request("GET", "/v1/inference/rules");
1051
- }
1052
- /**
1053
- * Derive edges from calibrated retrieval matches (preview): each
1054
- * candidate scored `P >= threshold` becomes a derived edge `(anchor, relation,
1055
- * matched)` with a typed `Retrieval` provenance leaf. Pass either explicit
1056
- * `candidates` or a `query` the server runs as BM25 entity retrieval.
1057
- */
1058
- retrievalPremises(body) {
1059
- return this.request("POST", "/v1/inference/retrieval-premises", { body });
1060
- }
1061
1075
  // --- ontology ---
1062
1076
  /**
1063
1077
  * The active ontology (entity types and relations) for the scoped graph.
@@ -1074,12 +1088,13 @@ export class LbbClient {
1074
1088
  * Audit the current snapshot against the ontology's *implied* constraints —
1075
1089
  * capped `cardinality` derived as `sh:maxCount` — returning a SHACL-shaped
1076
1090
  * report. Whole-snapshot and never blocks a write. Unlike
1077
- * {@link SchemaNamespace.audit}, this needs no published shape bundle: the
1078
- * shapes come from the ontology itself. See the `decoration_status` catalog on
1079
- * {@link ontologyView} for which decorations are enforced.
1091
+ * The report is referenced by the pinned published read root and carries its
1092
+ * own validation watermark and ontology/shapes provenance.
1080
1093
  */
1081
- ontologyConformance() {
1082
- return this.request("GET", "/v1/ontology/conformance");
1094
+ ontologyConformance(opts) {
1095
+ return this.request("GET", "/v1/ontology/conformance", {
1096
+ query: { consistency: this.resolveConsistency(opts) },
1097
+ });
1083
1098
  }
1084
1099
  /** Discover ontology concepts, terms, and relations. */
1085
1100
  ontologySearch(body) {
@@ -1106,75 +1121,6 @@ export class LbbClient {
1106
1121
  induceOntology(body) {
1107
1122
  return this.request("POST", "/v1/ontology/induce", { body, retry: true });
1108
1123
  }
1109
- // --- index lifecycle ---
1110
- /**
1111
- * Build default ANN + BM25 indexes. With `{ background: true }` the build
1112
- * runs detached on the server and the call returns immediately — use it for
1113
- * large corpora whose synchronous build would exceed a fronting gateway's
1114
- * timeout (a 504), then poll `metadata()` for completion.
1115
- */
1116
- indexBuild(opts = {}) {
1117
- return this.request("POST", "/v1/index/build", {
1118
- query: { background: opts.background || undefined },
1119
- });
1120
- }
1121
- /**
1122
- * Build BM25, ANN/vector, and adjacency index families. With
1123
- * `{ background: true }` the build runs detached on the server and the call
1124
- * returns immediately — use it for large corpora whose synchronous build would
1125
- * exceed a fronting gateway's timeout, then poll `metadata()` for completion.
1126
- */
1127
- indexRun(opts = {}) {
1128
- return this.request("POST", "/v1/index/run", {
1129
- query: { background: opts.background || undefined },
1130
- });
1131
- }
1132
- /** Submit a durable full-index build. Requires a reconnect-safe idempotency key. */
1133
- indexSubmit(body = {}, opts) {
1134
- return this.request("POST", "/v1/index/jobs", {
1135
- body,
1136
- idempotencyKey: opts.idempotencyKey,
1137
- });
1138
- }
1139
- /** Poll a durable full-index build. */
1140
- indexJob(jobId) {
1141
- return this.request("GET", "/v1/index/jobs", { query: { job_id: jobId } });
1142
- }
1143
- /** Cancel a durable full-index build. Repeated cancellation returns its current terminal status. */
1144
- cancelIndexJob(jobId) {
1145
- return this.request("DELETE", "/v1/index/jobs", {
1146
- query: { job_id: jobId },
1147
- });
1148
- }
1149
- /** Append a BM25 delta segment for the unindexed WAL tail. */
1150
- indexDelta() {
1151
- return this.request("POST", "/v1/index/delta");
1152
- }
1153
- /** Preview or delete superseded persisted index runs. */
1154
- indexGc(opts = {}) {
1155
- return this.request("POST", "/v1/index/gc", {
1156
- query: { keep_runs: opts.keepRuns, dry_run: opts.dryRun },
1157
- });
1158
- }
1159
- /** Submit durable, cancellable index garbage collection. */
1160
- indexGcSubmit(body = {}, opts) {
1161
- return this.request("POST", "/v1/index/gc-jobs", {
1162
- body,
1163
- idempotencyKey: opts.idempotencyKey,
1164
- });
1165
- }
1166
- /** Poll exact planning/deletion progress for durable index garbage collection. */
1167
- indexGcJob(jobId) {
1168
- return this.request("GET", "/v1/index/gc-jobs", {
1169
- query: { job_id: jobId },
1170
- });
1171
- }
1172
- /** Cancel durable index garbage collection. */
1173
- cancelIndexGcJob(jobId) {
1174
- return this.request("DELETE", "/v1/index/gc-jobs", {
1175
- query: { job_id: jobId },
1176
- });
1177
- }
1178
1124
  /** Fold the WAL tail into snapshot segments. */
1179
1125
  compact(opts = {}) {
1180
1126
  return this.request("POST", "/v1/graph/compact", {
@@ -1189,13 +1135,11 @@ export class LbbClient {
1189
1135
  status() {
1190
1136
  return this.request("GET", "/v1/status");
1191
1137
  }
1192
- /** Graph footprint, WAL tail, and index coverage. Exact object inventory is opt-in. */
1138
+ /** Graph footprint, WAL tail, and published-index coverage. */
1193
1139
  metadata(opts = {}) {
1194
1140
  return this.request("GET", "/v1/graph/metadata", {
1195
1141
  query: {
1196
- include_objects: opts.includeObjects,
1197
1142
  include_indexes: opts.includeIndexes,
1198
- include_temporal_coverage: opts.includeTemporalCoverage,
1199
1143
  },
1200
1144
  });
1201
1145
  }
@@ -1236,6 +1180,10 @@ export class LbbClient {
1236
1180
  query: this.readConsistencyQuery(opts),
1237
1181
  });
1238
1182
  }
1183
+ /** Pinned published read root and its query/conformance lag against one coherent head. */
1184
+ readSnapshot() {
1185
+ return this.request("GET", "/v1/graph/read-snapshot");
1186
+ }
1239
1187
  /** List the graphs (and branches) under the scoped tenant. */
1240
1188
  listGraphs() {
1241
1189
  return this.request("GET", "/v1/graphs");
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { LbbClient, LbbError, parseSparqlResults } from "./client.js";
2
- export type { LbbClientOptions, CallOptions, RequestOptions, EntityListOptions, HybridSearchOptions, LbbRequestEvent, LbbResponseEvent, FetchLike, ReadConsistencyOptions, SearchConsistency, Schemas, SparqlResults, SparqlResultsJson, SparqlTerm, AskRequest, AskResponse, CommitRequest, CommitResponse, Entity, EntitySelector, GraphMetadata, GraphSummary, SchemaView, SearchRequest, SearchResponse, SearchResult, Snapshot, } from "./client.js";
1
+ export { LbbCapabilityError, LbbClient, LbbError, parseSparqlResults, } from "./client.js";
2
+ export type { DurableImportLine, DurableImportSource, LbbClientOptions, CallOptions, RequestOptions, HybridSearchOptions, LbbRequestEvent, LbbResponseEvent, FetchLike, ReadConsistencyOptions, SearchConsistency, Schemas, SparqlResults, SparqlResultsJson, SparqlTerm, CommitRequest, CommitResponse, Entity, EntitySelector, GraphMetadata, GraphSummary, SchemaView, SearchRequest, SearchResponse, SearchResult, Snapshot, } from "./client.js";
3
3
  export type { components, paths, operations } from "./schema.js";
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export { LbbClient, LbbError, parseSparqlResults } from "./client.js";
1
+ export { LbbCapabilityError, LbbClient, LbbError, parseSparqlResults, } from "./client.js";