cograph 0.1.24 → 0.1.27

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.
@@ -0,0 +1,978 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ readConfig
4
+ } from "./chunk-7VVBEUZQ.js";
5
+
6
+ // src/client.ts
7
+ import { existsSync, readFileSync, statSync } from "fs";
8
+ import { extname } from "path";
9
+ var CographError = class extends Error {
10
+ status;
11
+ body;
12
+ constructor(message, opts) {
13
+ super(message);
14
+ this.name = "CographError";
15
+ this.status = opts?.status;
16
+ this.body = opts?.body;
17
+ }
18
+ };
19
+ var SCHEMA_SAMPLE_CAP = 5e3;
20
+ function stridedSample(rows, cap = SCHEMA_SAMPLE_CAP) {
21
+ if (rows.length <= cap) return rows;
22
+ const out = [];
23
+ for (let i = 0; i < cap; i++) out.push(rows[Math.floor(i * rows.length / cap)]);
24
+ return out;
25
+ }
26
+ function envVar(name, fallback) {
27
+ return process.env[`COGRAPH_${name}`] || process.env[`OMNIX_${name}`] || fallback;
28
+ }
29
+ var EXT_FORMAT = {
30
+ ".csv": "csv",
31
+ ".json": "json",
32
+ ".jsonl": "json",
33
+ ".txt": "text"
34
+ };
35
+ function parseCsv(content) {
36
+ const rows = [];
37
+ let cur = [];
38
+ let field = "";
39
+ let inQuotes = false;
40
+ for (let i = 0; i < content.length; i++) {
41
+ const ch = content[i];
42
+ if (inQuotes) {
43
+ if (ch === '"') {
44
+ if (content[i + 1] === '"') {
45
+ field += '"';
46
+ i++;
47
+ } else {
48
+ inQuotes = false;
49
+ }
50
+ } else {
51
+ field += ch;
52
+ }
53
+ } else {
54
+ if (ch === '"') {
55
+ inQuotes = true;
56
+ } else if (ch === ",") {
57
+ cur.push(field);
58
+ field = "";
59
+ } else if (ch === "\n") {
60
+ cur.push(field);
61
+ rows.push(cur);
62
+ cur = [];
63
+ field = "";
64
+ } else if (ch === "\r") {
65
+ if (content[i + 1] !== "\n") {
66
+ cur.push(field);
67
+ rows.push(cur);
68
+ cur = [];
69
+ field = "";
70
+ }
71
+ } else {
72
+ field += ch;
73
+ }
74
+ }
75
+ }
76
+ if (field.length > 0 || cur.length > 0) {
77
+ cur.push(field);
78
+ rows.push(cur);
79
+ }
80
+ if (rows.length === 0) return [];
81
+ const headers = rows[0].map((h) => h.trim());
82
+ const out = [];
83
+ for (let r = 1; r < rows.length; r++) {
84
+ const row = rows[r];
85
+ if (row.length === 1 && row[0] === "") continue;
86
+ const obj = {};
87
+ for (let c = 0; c < headers.length; c++) {
88
+ obj[headers[c]] = row[c] ?? "";
89
+ }
90
+ out.push(obj);
91
+ }
92
+ return out;
93
+ }
94
+ var Client = class {
95
+ apiKey;
96
+ baseUrl;
97
+ tenant;
98
+ /**
99
+ * Raw / passthrough API — one method per canonical backend operation, with
100
+ * the path encoded inside the SDK. Each method returns the backend
101
+ * {@link Response} VERBATIM: it does NOT throw on non-2xx and does NOT reshape
102
+ * the body. This is the seam the webapp's proxy layer adopts so per-operation
103
+ * paths live in one place (here) instead of being hand-rolled at each call
104
+ * site. See {@link RawApi}. The typed methods on this class (which throw on
105
+ * non-2xx and reshape some payloads) are left unchanged — this is additive.
106
+ */
107
+ raw;
108
+ constructor(opts = {}) {
109
+ const cfg = readConfig();
110
+ this.apiKey = opts.apiKey ?? envVar("API_KEY") ?? cfg.apiKey;
111
+ const url = opts.baseUrl ?? envVar("API_URL") ?? cfg.apiUrl ?? "https://api.cograph.cloud";
112
+ this.baseUrl = url.replace(/\/+$/, "");
113
+ this.tenant = opts.tenant ?? envVar("TENANT") ?? cfg.tenant ?? "demo-tenant";
114
+ this.raw = new RawApi(this);
115
+ }
116
+ headers() {
117
+ const h = { "Content-Type": "application/json" };
118
+ if (this.apiKey) h["X-API-Key"] = this.apiKey;
119
+ return h;
120
+ }
121
+ base() {
122
+ return `${this.baseUrl}/graphs/${this.tenant}`;
123
+ }
124
+ // --- Path builders -------------------------------------------------------- #
125
+ // SINGLE source of truth for every canonical backend path. Both the raw API
126
+ // and the new typed parsed methods build URLs through these, so a path lives
127
+ // in exactly one place. Tenant-scoped paths hang off `base()`
128
+ // (`{baseUrl}/graphs/{tenant}`); the handful of account-level paths
129
+ // (e.g. tenant CRUD) hang off `baseUrl` directly.
130
+ //
131
+ // These are marked `@internal` (not part of the public SDK surface) but are
132
+ // not `private`, so the sibling {@link RawApi} can build the same canonical
133
+ // paths without duplicating them.
134
+ /** @internal */
135
+ pAgent() {
136
+ return `${this.base()}/agent`;
137
+ }
138
+ /** @internal */
139
+ pAsk() {
140
+ return `${this.base()}/ask`;
141
+ }
142
+ /** @internal */
143
+ pIngest() {
144
+ return `${this.base()}/ingest`;
145
+ }
146
+ /** @internal */
147
+ pIngestCsvSchema() {
148
+ return `${this.base()}/ingest/csv/schema`;
149
+ }
150
+ /** @internal */
151
+ pIngestCsvRows() {
152
+ return `${this.base()}/ingest/csv/rows`;
153
+ }
154
+ /** @internal */
155
+ pEnrichJobs() {
156
+ return `${this.base()}/enrich/jobs`;
157
+ }
158
+ /** @internal */
159
+ pEnrichJob(jobId) {
160
+ return `${this.base()}/enrich/jobs/${encodeURIComponent(jobId)}`;
161
+ }
162
+ /** @internal */
163
+ pEnrichJobConflicts(jobId) {
164
+ return `${this.pEnrichJob(jobId)}/conflicts`;
165
+ }
166
+ /** @internal */
167
+ pEnrichJobApply(jobId) {
168
+ return `${this.pEnrichJob(jobId)}/apply`;
169
+ }
170
+ /** @internal */
171
+ pOntologyTypes() {
172
+ return `${this.base()}/ontology/types`;
173
+ }
174
+ /** @internal */
175
+ pOntologyResolve() {
176
+ return `${this.base()}/ontology/resolve`;
177
+ }
178
+ /** @internal Targets the premium ontology-recommender route, mounted only on
179
+ * deployments with the proprietary layer — 404s on bare OSS. */
180
+ pOntologyRecommend() {
181
+ return `${this.base()}/ontology/recommend`;
182
+ }
183
+ /** @internal */
184
+ pOntologyApply() {
185
+ return `${this.base()}/ontology/apply`;
186
+ }
187
+ /** @internal */
188
+ pKgs() {
189
+ return `${this.base()}/kgs`;
190
+ }
191
+ /** @internal */
192
+ pKg(name) {
193
+ return `${this.base()}/kgs/${encodeURIComponent(name)}`;
194
+ }
195
+ /** @internal */
196
+ pTypeCounts(kg) {
197
+ return `${this.pKg(kg)}/type-counts`;
198
+ }
199
+ /** @internal */
200
+ pExploreSummary(kg, typeName) {
201
+ return `${this.base()}/explore/kgs/${encodeURIComponent(kg)}/types/${encodeURIComponent(typeName)}/summary`;
202
+ }
203
+ /** @internal */
204
+ pExploreRecords(kg, typeName, query) {
205
+ return `${this.base()}/explore/kgs/${encodeURIComponent(kg)}/types/${encodeURIComponent(typeName)}/records${query ?? ""}`;
206
+ }
207
+ /** @internal */
208
+ pExploreTypeEdges(kg) {
209
+ return `${this.base()}/explore/kgs/${encodeURIComponent(kg)}/type-edges`;
210
+ }
211
+ /** @internal */
212
+ pExploreSearch(query) {
213
+ return `${this.base()}/explore/search${query}`;
214
+ }
215
+ /** @internal */
216
+ pNormalizeSuggest(query) {
217
+ return `${this.base()}/normalize/suggest${query}`;
218
+ }
219
+ /** @internal */
220
+ pNormalizeRules(query) {
221
+ return `${this.base()}/normalize/rules${query ?? ""}`;
222
+ }
223
+ /** @internal */
224
+ pNormalizeRule(ruleId, action) {
225
+ return `${this.base()}/normalize/rules/${encodeURIComponent(ruleId)}/${action}`;
226
+ }
227
+ /** @internal */
228
+ pTenants() {
229
+ return `${this.baseUrl}/v1/me/tenants`;
230
+ }
231
+ /** @internal */
232
+ pTenant(tenantId) {
233
+ return `${this.baseUrl}/v1/me/tenants/${encodeURIComponent(tenantId)}`;
234
+ }
235
+ /**
236
+ * Low-level passthrough request. Centralizes the absolute URL (already built
237
+ * by a path-builder, so it carries the base URL + `/graphs/{tenant}` prefix),
238
+ * the `X-API-Key` header, JSON content-type, body stringification, and a
239
+ * timeout/abort — then returns the backend {@link Response} UNCHANGED.
240
+ *
241
+ * Unlike {@link request}, this does NOT inspect `res.ok` and does NOT parse or
242
+ * reshape the body. A 4xx/5xx comes back as a resolved `Response` (the caller
243
+ * reads `.status`/`.headers`/`.body`), NOT a thrown {@link CographError}. The
244
+ * only rejection paths are a genuine network failure or a timeout abort —
245
+ * exactly the cases where there is no HTTP response to hand back.
246
+ *
247
+ * `init.headers` is merged last so a caller can add/override headers; `init.body`,
248
+ * when a non-string is passed, is JSON-stringified for convenience.
249
+ */
250
+ async requestRaw(method, path, init = {}) {
251
+ const timeoutMs = init.timeoutMs ?? 12e4;
252
+ const controller = new AbortController();
253
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
254
+ let body;
255
+ if (init.body !== void 0) {
256
+ body = typeof init.body === "string" ? init.body : JSON.stringify(init.body);
257
+ }
258
+ try {
259
+ return await fetch(path, {
260
+ method,
261
+ headers: { ...this.headers(), ...init.headers ?? {} },
262
+ body,
263
+ signal: controller.signal
264
+ });
265
+ } catch (err) {
266
+ if (err instanceof Error && err.name === "AbortError") {
267
+ throw new CographError(`Request to ${path} timed out after ${timeoutMs}ms`);
268
+ }
269
+ throw new CographError(
270
+ `Network error contacting ${path}: ${err instanceof Error ? err.message : String(err)}`
271
+ );
272
+ } finally {
273
+ clearTimeout(timer);
274
+ }
275
+ }
276
+ /**
277
+ * Probe the backend to determine reachability and whether endpoints
278
+ * require an X-API-Key header. Used at shell startup to distinguish
279
+ * cloud (auth required) from self-hosted open-access deployments.
280
+ */
281
+ async healthCheck() {
282
+ const healthUrl = `${this.baseUrl}/health`;
283
+ try {
284
+ const res = await fetch(healthUrl, {
285
+ signal: AbortSignal.timeout(5e3)
286
+ });
287
+ if (!res.ok) return { ok: false, requiresAuth: false, url: this.baseUrl };
288
+ } catch {
289
+ return { ok: false, requiresAuth: false, url: this.baseUrl };
290
+ }
291
+ try {
292
+ const res = await fetch(`${this.base()}/kgs`, {
293
+ headers: { "Content-Type": "application/json" },
294
+ signal: AbortSignal.timeout(5e3)
295
+ });
296
+ return {
297
+ ok: true,
298
+ requiresAuth: res.status === 401,
299
+ url: this.baseUrl
300
+ };
301
+ } catch {
302
+ return { ok: true, requiresAuth: true, url: this.baseUrl };
303
+ }
304
+ }
305
+ async request(method, url, body, timeoutMs = 12e4) {
306
+ const controller = new AbortController();
307
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
308
+ let res;
309
+ try {
310
+ res = await fetch(url, {
311
+ method,
312
+ headers: this.headers(),
313
+ body: body === void 0 ? void 0 : JSON.stringify(body),
314
+ signal: controller.signal
315
+ });
316
+ } catch (err) {
317
+ clearTimeout(timer);
318
+ if (err instanceof Error && err.name === "AbortError") {
319
+ throw new CographError(`Request to ${url} timed out after ${timeoutMs}ms`);
320
+ }
321
+ throw new CographError(
322
+ `Network error contacting ${url}: ${err instanceof Error ? err.message : String(err)}`
323
+ );
324
+ }
325
+ clearTimeout(timer);
326
+ if (!res.ok) {
327
+ let text2 = "";
328
+ try {
329
+ text2 = await res.text();
330
+ } catch {
331
+ }
332
+ throw new CographError(`HTTP ${res.status}: ${text2}`, {
333
+ status: res.status,
334
+ body: text2
335
+ });
336
+ }
337
+ if (res.status === 204) return void 0;
338
+ const ct = res.headers.get("content-type") ?? "";
339
+ if (ct.includes("application/json")) {
340
+ return await res.json();
341
+ }
342
+ const text = await res.text();
343
+ try {
344
+ return JSON.parse(text);
345
+ } catch {
346
+ return text;
347
+ }
348
+ }
349
+ /**
350
+ * Ingest a file path or raw text into a knowledge graph.
351
+ *
352
+ * If `pathOrText` points to an existing file, its contents are read and the
353
+ * format is inferred from the extension (.csv, .json, .txt) unless
354
+ * `contentType` is given. CSV files use the two-step schema-inference + row
355
+ * mapping flow.
356
+ */
357
+ async ingest(pathOrText, opts = {}) {
358
+ let content;
359
+ let fmt;
360
+ let isFile = false;
361
+ try {
362
+ isFile = existsSync(pathOrText) && statSync(pathOrText).isFile();
363
+ } catch {
364
+ isFile = false;
365
+ }
366
+ if (isFile) {
367
+ const ext = extname(pathOrText).toLowerCase();
368
+ if (ext === ".pdf") {
369
+ throw new CographError(
370
+ "PDF ingest not yet supported in the Node CLI; use the Python CLI or POST raw bytes to the API."
371
+ );
372
+ }
373
+ content = readFileSync(pathOrText, "utf-8");
374
+ fmt = opts.contentType ?? EXT_FORMAT[ext] ?? "text";
375
+ if (fmt === "csv") {
376
+ return this.ingestCsv(content, opts);
377
+ }
378
+ } else {
379
+ content = pathOrText;
380
+ fmt = opts.contentType ?? "text";
381
+ }
382
+ const body = {
383
+ content,
384
+ content_type: fmt,
385
+ source: "client"
386
+ };
387
+ if (opts.kg) body.kg_name = opts.kg;
388
+ return this.request("POST", `${this.base()}/ingest`, body, 12e4);
389
+ }
390
+ async ingestCsv(content, opts) {
391
+ const kgName = opts.kg;
392
+ const batchSize = opts.batchSize ?? 200;
393
+ const concurrency = opts.concurrency ?? 4;
394
+ const rows = parseCsv(content);
395
+ if (rows.length === 0) throw new CographError("CSV is empty");
396
+ const headers = Object.keys(rows[0]);
397
+ const sampleRows = stridedSample(rows);
398
+ const schemaBody = {
399
+ headers,
400
+ sample_rows: sampleRows,
401
+ total_rows: rows.length
402
+ };
403
+ const mapping = await this.request(
404
+ "POST",
405
+ `${this.base()}/ingest/csv/schema`,
406
+ schemaBody,
407
+ 3e5
408
+ );
409
+ let mappingToPost = mapping;
410
+ if (opts.onSchemaInferred) {
411
+ const reviewed = await opts.onSchemaInferred(mapping, {
412
+ totalRows: rows.length,
413
+ rowsProfiled: sampleRows.length
414
+ });
415
+ if (reviewed == null) {
416
+ return { cancelled: true, message: "Ingest cancelled before any rows were written." };
417
+ }
418
+ mappingToPost = reviewed;
419
+ }
420
+ const batches = [];
421
+ for (let i = 0; i < rows.length; i += batchSize) {
422
+ batches.push(rows.slice(i, i + batchSize));
423
+ }
424
+ let totalEntities = 0;
425
+ let totalTriples = 0;
426
+ let rowsProcessed = 0;
427
+ let nextBatch = 0;
428
+ const postBatch = async (batch) => {
429
+ const body = {
430
+ mapping: mappingToPost,
431
+ rows: batch,
432
+ source: "client"
433
+ };
434
+ if (kgName) body.kg_name = kgName;
435
+ const result = await this.request("POST", `${this.base()}/ingest/csv/rows`, body, 3e5);
436
+ return {
437
+ entities: result.entities_resolved ?? 0,
438
+ triples: result.triples_inserted ?? 0,
439
+ size: batch.length
440
+ };
441
+ };
442
+ const worker = async () => {
443
+ while (true) {
444
+ const idx = nextBatch++;
445
+ if (idx >= batches.length) return;
446
+ const r = await postBatch(batches[idx]);
447
+ totalEntities += r.entities;
448
+ totalTriples += r.triples;
449
+ rowsProcessed += r.size;
450
+ opts.onProgress?.({
451
+ rowsProcessed,
452
+ totalRows: rows.length,
453
+ entitiesResolved: totalEntities,
454
+ triplesInserted: totalTriples
455
+ });
456
+ }
457
+ };
458
+ const workers = [];
459
+ for (let i = 0; i < Math.min(concurrency, batches.length); i++) {
460
+ workers.push(worker());
461
+ }
462
+ await Promise.all(workers);
463
+ if (kgName) {
464
+ try {
465
+ await this.request(
466
+ "POST",
467
+ `${this.base()}/explore/kgs/${encodeURIComponent(kgName)}/recompute-stats`,
468
+ {},
469
+ 15e3
470
+ );
471
+ } catch {
472
+ }
473
+ }
474
+ return {
475
+ entities_resolved: totalEntities,
476
+ triples_inserted: totalTriples,
477
+ mapping
478
+ };
479
+ }
480
+ /** Ask a natural language question and return the parsed response. */
481
+ async ask(question, opts = {}) {
482
+ const body = { question };
483
+ if (opts.kg) body.kg_name = opts.kg;
484
+ if (opts.model) body.model = opts.model;
485
+ return this.request("POST", `${this.base()}/ask`, body, 6e4);
486
+ }
487
+ /**
488
+ * One turn of the unified Ask-AI agent — the SINGLE conversational surface
489
+ * (`POST /graphs/{tenant}/agent`, COG-118). Mirrors the HTTP contract exactly:
490
+ *
491
+ * - `confirmPlanId` set → the server runs `execute_plan` (the only mutating
492
+ * path) and returns `{kind:"result", steps}`.
493
+ * - otherwise → the server runs `planner.handle(message)` and returns one of
494
+ * `{kind:"answer"}` / `{kind:"clarify"}` / `{kind:"plan"}`.
495
+ *
496
+ * The agent classifies intent server-side and drives the underlying engines
497
+ * through its capability registry — the client never talks to `/ask`,
498
+ * `/enrich/*` etc. for an agent turn. ENTITLEMENT for any paid step a plan
499
+ * contains is enforced server-side at execute time (the same authorization the
500
+ * direct paid routes apply), so confirming a plan here cannot bypass a gate the
501
+ * direct path enforces — the gate lives behind the endpoint, not in this client.
502
+ */
503
+ async agent(opts) {
504
+ const body = {
505
+ message: opts.message ?? "",
506
+ context: {
507
+ kg_name: opts.kgName ?? "",
508
+ type_name: opts.typeName ?? null
509
+ }
510
+ };
511
+ if (opts.sessionId) body.session_id = opts.sessionId;
512
+ if (opts.confirmPlanId) body.confirm = { plan_id: opts.confirmPlanId };
513
+ return this.request(
514
+ "POST",
515
+ `${this.base()}/agent`,
516
+ body,
517
+ // Generous: a confirmed plan can kick off enrichment/dedup work, and a
518
+ // question turn runs an LLM round-trip server-side.
519
+ 12e4
520
+ );
521
+ }
522
+ /** List the tenants the authenticated user can access (GET /v1/me/tenants).
523
+ * Keyed by the API key (X-API-Key → user), so it's independent of the active
524
+ * tenant. Throws CographError with status 501 on deployments without a tenant
525
+ * provider (e.g. OSS-only). */
526
+ async listTenants() {
527
+ return this.request(
528
+ "GET",
529
+ `${this.baseUrl}/v1/me/tenants`,
530
+ void 0,
531
+ 15e3
532
+ );
533
+ }
534
+ /** List all knowledge graphs for the current tenant. */
535
+ async listKgs() {
536
+ const data = await this.request(
537
+ "GET",
538
+ `${this.base()}/kgs`,
539
+ void 0,
540
+ 15e3
541
+ );
542
+ if (Array.isArray(data)) return data;
543
+ if (data && typeof data === "object" && "kgs" in data) {
544
+ const kgs = data.kgs;
545
+ if (Array.isArray(kgs)) return kgs;
546
+ }
547
+ return [];
548
+ }
549
+ /** Create a knowledge graph. */
550
+ async createKg(name, description) {
551
+ const body = { name };
552
+ if (description) body.description = description;
553
+ return this.request("POST", `${this.base()}/kgs`, body, 15e3);
554
+ }
555
+ /** Delete a knowledge graph by name. */
556
+ async deleteKg(name) {
557
+ return this.request(
558
+ "DELETE",
559
+ `${this.base()}/kgs/${encodeURIComponent(name)}`,
560
+ void 0,
561
+ 3e4
562
+ );
563
+ }
564
+ /** List ontology types. */
565
+ async ontologyTypes() {
566
+ const data = await this.request(
567
+ "GET",
568
+ `${this.base()}/ontology/types`,
569
+ void 0,
570
+ 15e3
571
+ );
572
+ return Array.isArray(data) ? data : [];
573
+ }
574
+ /**
575
+ * Resolve a natural-language ontology change against the existing ontology.
576
+ * The caller does not need to know exact type/attribute/relationship names —
577
+ * the server matches the plain-language `ask` to the current schema and
578
+ * returns auto-applied changes plus proposals that need confirmation.
579
+ */
580
+ async ontologyResolve(ask, opts = {}) {
581
+ const body = { ask };
582
+ if (opts.knowledge_graph) body.knowledge_graph = opts.knowledge_graph;
583
+ return this.request(
584
+ "POST",
585
+ `${this.base()}/ontology/resolve`,
586
+ body,
587
+ 6e4
588
+ );
589
+ }
590
+ /**
591
+ * Apply a single resolved ontology change — one of the `proposals` returned
592
+ * by {@link ontologyResolve}. Pass the proposal object through unchanged.
593
+ */
594
+ async ontologyApply(proposal) {
595
+ return this.request(
596
+ "POST",
597
+ `${this.base()}/ontology/apply`,
598
+ proposal,
599
+ 6e4
600
+ );
601
+ }
602
+ /**
603
+ * Second-pass entity resolution: re-run ER over an already-ingested KG to
604
+ * collapse intra-batch fragments. Synchronous on the server; returns a
605
+ * per-type before/after report. Generous timeout — it rewrites triples.
606
+ */
607
+ async erRebuild(kg) {
608
+ return this.request(
609
+ "POST",
610
+ `${this.base()}/explore/kgs/${encodeURIComponent(kg)}/er-rebuild`,
611
+ {},
612
+ 3e5
613
+ );
614
+ }
615
+ /** Per-KG type counts: every type with ≥1 instance, sorted desc. */
616
+ async typeCounts(kg) {
617
+ const data = await this.request(
618
+ "GET",
619
+ `${this.base()}/kgs/${encodeURIComponent(kg)}/type-counts`,
620
+ void 0,
621
+ 3e4
622
+ );
623
+ return Array.isArray(data) ? data : [];
624
+ }
625
+ /** Plan + run an enrichment job. Returns immediately with the job id. */
626
+ async enrichRun(req) {
627
+ return this.request(
628
+ "POST",
629
+ `${this.base()}/enrich/jobs`,
630
+ req,
631
+ 3e4
632
+ );
633
+ }
634
+ /** List recent enrichment jobs for the current tenant. */
635
+ async enrichJobs() {
636
+ const data = await this.request(
637
+ "GET",
638
+ `${this.base()}/enrich/jobs`,
639
+ void 0,
640
+ 15e3
641
+ );
642
+ return Array.isArray(data) ? data : [];
643
+ }
644
+ /** Fetch a single enrichment job (with truncated results). */
645
+ async enrichJob(jobId) {
646
+ return this.request(
647
+ "GET",
648
+ `${this.base()}/enrich/jobs/${encodeURIComponent(jobId)}`,
649
+ void 0,
650
+ 15e3
651
+ );
652
+ }
653
+ /** Fetch the conflict review queue for a job. */
654
+ async enrichConflicts(jobId) {
655
+ const data = await this.request(
656
+ "GET",
657
+ `${this.base()}/enrich/jobs/${encodeURIComponent(jobId)}/conflicts`,
658
+ void 0,
659
+ 3e4
660
+ );
661
+ return Array.isArray(data) ? data : [];
662
+ }
663
+ /** Apply a set of conflict review decisions to a job. */
664
+ async enrichApply(jobId, decisions) {
665
+ return this.request(
666
+ "POST",
667
+ `${this.base()}/enrich/jobs/${encodeURIComponent(jobId)}/apply`,
668
+ { decisions },
669
+ 6e4
670
+ );
671
+ }
672
+ /** Cancel an enrichment job. */
673
+ async enrichCancel(jobId) {
674
+ await this.request(
675
+ "DELETE",
676
+ `${this.base()}/enrich/jobs/${encodeURIComponent(jobId)}`,
677
+ void 0,
678
+ 15e3
679
+ );
680
+ }
681
+ /** Per-type breakdown for one type in one KG: definition + counts + samples.
682
+ *
683
+ * System predicates (rdfs:label, ingested_at, source) are hidden by default
684
+ * — they're attached to every entity at 100% and drown out the columns the
685
+ * user cares about. Pass `includeSystem: true` to see them. */
686
+ async typeUsage(kg, typeName, opts = {}) {
687
+ const qs = opts.includeSystem ? "?include_system=true" : "";
688
+ return this.request(
689
+ "GET",
690
+ `${this.base()}/kgs/${encodeURIComponent(kg)}/types/${encodeURIComponent(typeName)}/usage${qs}`,
691
+ void 0,
692
+ 3e4
693
+ );
694
+ }
695
+ /** Explorer summary for a type — like typeUsage but adds coverage_pct + avg_degree. */
696
+ async typeSummary(kg, typeName) {
697
+ return this.request(
698
+ "GET",
699
+ `${this.base()}/explore/kgs/${encodeURIComponent(kg)}/types/${encodeURIComponent(typeName)}/summary`,
700
+ void 0,
701
+ 3e4
702
+ );
703
+ }
704
+ /** Search types or attributes by name substring within a KG. */
705
+ async exploreSearch(kg, q, kind = "type") {
706
+ const qs = new URLSearchParams({ kg, q, kind }).toString();
707
+ const data = await this.request(
708
+ "GET",
709
+ this.pExploreSearch(`?${qs}`),
710
+ void 0,
711
+ 15e3
712
+ );
713
+ return Array.isArray(data) ? data : [];
714
+ }
715
+ // --- New typed methods (COG-128) ------------------------------------------ #
716
+ // Parsed/throwing variants of the previously-MISSING ops, sharing the same
717
+ // path-builders as the raw API. These follow the existing typed-method
718
+ // contract (throw on non-2xx, light reshape) — the raw equivalents under
719
+ // `client.raw.*` are the non-throwing, non-reshaping passthrough versions.
720
+ /**
721
+ * One page of entity instances of a type for the Explorer Data table
722
+ * (`GET /explore/kgs/{kg}/types/{type}/records`). Keyset-paginated by entity
723
+ * URI: pass the previous page's `next_cursor` as `cursor`. `limit` is clamped
724
+ * server-side to 1..200 (default 50).
725
+ */
726
+ async exploreRecords(kg, typeName, opts = {}) {
727
+ const qs = new URLSearchParams();
728
+ if (opts.limit != null) qs.set("limit", String(opts.limit));
729
+ if (opts.cursor) qs.set("cursor", opts.cursor);
730
+ const query = qs.toString() ? `?${qs.toString()}` : "";
731
+ return this.request(
732
+ "GET",
733
+ this.pExploreRecords(kg, typeName, query),
734
+ void 0,
735
+ 3e4
736
+ );
737
+ }
738
+ /** Undirected type→type edges for the Explorer overview graph
739
+ * (`GET /explore/kgs/{kg}/type-edges`). Returns `[{source, target, weight}]`. */
740
+ async exploreTypeEdges(kg) {
741
+ const data = await this.request(
742
+ "GET",
743
+ this.pExploreTypeEdges(kg),
744
+ void 0,
745
+ 3e4
746
+ );
747
+ return Array.isArray(data) ? data : [];
748
+ }
749
+ /** Infer + persist normalization rules for a type's predicates, returned ranked
750
+ * by confidence desc (`POST /normalize/suggest?kg&type`). */
751
+ async normalizeSuggest(kg, type) {
752
+ const qs = new URLSearchParams({ kg, type }).toString();
753
+ const data = await this.request(
754
+ "POST",
755
+ this.pNormalizeSuggest(`?${qs}`),
756
+ void 0,
757
+ 6e4
758
+ );
759
+ return Array.isArray(data) ? data : [];
760
+ }
761
+ /** List stored normalization rules, optionally filtered by KG and/or status
762
+ * (`GET /normalize/rules?kg&status`). */
763
+ async normalizeRules(opts = {}) {
764
+ const qs = new URLSearchParams();
765
+ if (opts.kg) qs.set("kg", opts.kg);
766
+ if (opts.status) qs.set("status", opts.status);
767
+ const query = qs.toString() ? `?${qs.toString()}` : "";
768
+ const data = await this.request(
769
+ "GET",
770
+ this.pNormalizeRules(query),
771
+ void 0,
772
+ 15e3
773
+ );
774
+ return Array.isArray(data) ? data : [];
775
+ }
776
+ /** Confirm a suggested normalization rule (`POST /normalize/rules/{id}/confirm`). */
777
+ async normalizeConfirmRule(ruleId) {
778
+ return this.request(
779
+ "POST",
780
+ this.pNormalizeRule(ruleId, "confirm"),
781
+ void 0,
782
+ 15e3
783
+ );
784
+ }
785
+ /** Reject a suggested normalization rule (`POST /normalize/rules/{id}/reject`). */
786
+ async normalizeRejectRule(ruleId) {
787
+ return this.request(
788
+ "POST",
789
+ this.pNormalizeRule(ruleId, "reject"),
790
+ void 0,
791
+ 15e3
792
+ );
793
+ }
794
+ /** Apply a confirmed normalization rule in the background; the server acks 202
795
+ * (`POST /normalize/rules/{id}/apply`). */
796
+ async normalizeApplyRule(ruleId) {
797
+ return this.request(
798
+ "POST",
799
+ this.pNormalizeRule(ruleId, "apply"),
800
+ {},
801
+ 6e4
802
+ );
803
+ }
804
+ /** Recommend ontology relationships/changes for the active KG
805
+ * (`POST /ontology/recommend`). Body shape is passed through unchanged.
806
+ *
807
+ * NOTE: this targets the *premium* ontology-recommender route, which is only
808
+ * mounted on deployments carrying the proprietary layer. It 404s on a bare
809
+ * OSS deployment. */
810
+ async ontologyRecommend(body = {}) {
811
+ return this.request(
812
+ "POST",
813
+ this.pOntologyRecommend(),
814
+ body,
815
+ 6e4
816
+ );
817
+ }
818
+ };
819
+ var RawApi = class {
820
+ constructor(client) {
821
+ this.client = client;
822
+ }
823
+ client;
824
+ // -- agent / ask --------------------------------------------------------- #
825
+ /** `POST /graphs/{tenant}/agent` — one turn of the unified Ask-AI agent. */
826
+ agent(body, init) {
827
+ return this.client.requestRaw("POST", this.client.pAgent(), { body, ...init });
828
+ }
829
+ /** `POST /graphs/{tenant}/ask` — natural-language question. */
830
+ ask(body, init) {
831
+ return this.client.requestRaw("POST", this.client.pAsk(), { body, ...init });
832
+ }
833
+ // -- ingest -------------------------------------------------------------- #
834
+ /** `POST /graphs/{tenant}/ingest` — ingest text/json (or csv) content. */
835
+ ingest(body, init) {
836
+ return this.client.requestRaw("POST", this.client.pIngest(), { body, ...init });
837
+ }
838
+ /** `POST /graphs/{tenant}/ingest/csv/schema` — infer a CSV schema mapping. */
839
+ ingestCsvSchema(body, init) {
840
+ return this.client.requestRaw("POST", this.client.pIngestCsvSchema(), { body, ...init });
841
+ }
842
+ /** `POST /graphs/{tenant}/ingest/csv/rows` — write a batch of mapped rows. */
843
+ ingestCsvRows(body, init) {
844
+ return this.client.requestRaw("POST", this.client.pIngestCsvRows(), { body, ...init });
845
+ }
846
+ // -- enrich jobs --------------------------------------------------------- #
847
+ /** `POST /graphs/{tenant}/enrich/jobs` — plan + run an enrichment job. */
848
+ enrichCreateJob(body, init) {
849
+ return this.client.requestRaw("POST", this.client.pEnrichJobs(), { body, ...init });
850
+ }
851
+ /** `GET /graphs/{tenant}/enrich/jobs` — list recent enrichment jobs. */
852
+ enrichJobs(init) {
853
+ return this.client.requestRaw("GET", this.client.pEnrichJobs(), init);
854
+ }
855
+ /** `GET /graphs/{tenant}/enrich/jobs/{id}` — fetch a single job. */
856
+ enrichJob(jobId, init) {
857
+ return this.client.requestRaw("GET", this.client.pEnrichJob(jobId), init);
858
+ }
859
+ /** `GET /graphs/{tenant}/enrich/jobs/{id}/conflicts` — conflict review queue. */
860
+ enrichConflicts(jobId, init) {
861
+ return this.client.requestRaw("GET", this.client.pEnrichJobConflicts(jobId), init);
862
+ }
863
+ /** `POST /graphs/{tenant}/enrich/jobs/{id}/apply` — apply review decisions. */
864
+ enrichApply(jobId, body, init) {
865
+ return this.client.requestRaw("POST", this.client.pEnrichJobApply(jobId), { body, ...init });
866
+ }
867
+ /** `DELETE /graphs/{tenant}/enrich/jobs/{id}` — cancel a job. */
868
+ enrichCancel(jobId, init) {
869
+ return this.client.requestRaw("DELETE", this.client.pEnrichJob(jobId), init);
870
+ }
871
+ // -- ontology ------------------------------------------------------------ #
872
+ /** `GET /graphs/{tenant}/ontology/types` — list ontology types. */
873
+ ontologyTypes(init) {
874
+ return this.client.requestRaw("GET", this.client.pOntologyTypes(), init);
875
+ }
876
+ /** `POST /graphs/{tenant}/ontology/resolve` — resolve an NL ontology change. */
877
+ ontologyResolve(body, init) {
878
+ return this.client.requestRaw("POST", this.client.pOntologyResolve(), { body, ...init });
879
+ }
880
+ /** `POST /graphs/{tenant}/ontology/recommend` — recommend ontology changes.
881
+ * Premium route: only mounted on deployments with the proprietary layer,
882
+ * 404s on bare OSS. */
883
+ ontologyRecommend(body, init) {
884
+ return this.client.requestRaw("POST", this.client.pOntologyRecommend(), { body, ...init });
885
+ }
886
+ /** `POST /graphs/{tenant}/ontology/apply` — apply one resolved change. */
887
+ ontologyApply(body, init) {
888
+ return this.client.requestRaw("POST", this.client.pOntologyApply(), { body, ...init });
889
+ }
890
+ // -- knowledge graphs ---------------------------------------------------- #
891
+ /** `GET /graphs/{tenant}/kgs` — list knowledge graphs. */
892
+ kgs(init) {
893
+ return this.client.requestRaw("GET", this.client.pKgs(), init);
894
+ }
895
+ /** `POST /graphs/{tenant}/kgs` — create a knowledge graph. */
896
+ createKg(body, init) {
897
+ return this.client.requestRaw("POST", this.client.pKgs(), { body, ...init });
898
+ }
899
+ /** `DELETE /graphs/{tenant}/kgs/{name}` — delete a knowledge graph. */
900
+ deleteKg(name, init) {
901
+ return this.client.requestRaw("DELETE", this.client.pKg(name), init);
902
+ }
903
+ // -- explore ------------------------------------------------------------- #
904
+ /** `GET /graphs/{tenant}/explore/kgs/{kg}/types/{type}/summary`. */
905
+ exploreSummary(kg, typeName, init) {
906
+ return this.client.requestRaw("GET", this.client.pExploreSummary(kg, typeName), init);
907
+ }
908
+ /** `GET /graphs/{tenant}/explore/kgs/{kg}/types/{type}/records?limit&cursor`. */
909
+ exploreRecords(kg, typeName, opts = {}, init) {
910
+ const qs = new URLSearchParams();
911
+ if (opts.limit != null) qs.set("limit", String(opts.limit));
912
+ if (opts.cursor) qs.set("cursor", opts.cursor);
913
+ const query = qs.toString() ? `?${qs.toString()}` : "";
914
+ return this.client.requestRaw("GET", this.client.pExploreRecords(kg, typeName, query), init);
915
+ }
916
+ /** `GET /graphs/{tenant}/explore/kgs/{kg}/type-edges`. */
917
+ exploreTypeEdges(kg, init) {
918
+ return this.client.requestRaw("GET", this.client.pExploreTypeEdges(kg), init);
919
+ }
920
+ /** `GET /graphs/{tenant}/kgs/{kg}/type-counts`. */
921
+ typeCounts(kg, init) {
922
+ return this.client.requestRaw("GET", this.client.pTypeCounts(kg), init);
923
+ }
924
+ /** `GET /graphs/{tenant}/explore/search?kg&q&kind`. */
925
+ exploreSearch(kg, q, kind = "type", init) {
926
+ const qs = new URLSearchParams({ kg, q, kind }).toString();
927
+ return this.client.requestRaw("GET", this.client.pExploreSearch(`?${qs}`), init);
928
+ }
929
+ // -- normalize ----------------------------------------------------------- #
930
+ /** `POST /graphs/{tenant}/normalize/suggest?kg&type` — infer + persist rules. */
931
+ normalizeSuggest(kg, type, init) {
932
+ const qs = new URLSearchParams({ kg, type }).toString();
933
+ return this.client.requestRaw("POST", this.client.pNormalizeSuggest(`?${qs}`), init);
934
+ }
935
+ /** `GET /graphs/{tenant}/normalize/rules?kg&status` — list stored rules. */
936
+ normalizeRules(opts = {}, init) {
937
+ const qs = new URLSearchParams();
938
+ if (opts.kg) qs.set("kg", opts.kg);
939
+ if (opts.status) qs.set("status", opts.status);
940
+ const query = qs.toString() ? `?${qs.toString()}` : "";
941
+ return this.client.requestRaw("GET", this.client.pNormalizeRules(query), init);
942
+ }
943
+ /** `POST /graphs/{tenant}/normalize/rules` — create a user-authored rule. */
944
+ normalizeCreateRule(body, init) {
945
+ return this.client.requestRaw("POST", this.client.pNormalizeRules(), { body, ...init });
946
+ }
947
+ /** `POST /graphs/{tenant}/normalize/rules/{id}/confirm`. */
948
+ normalizeConfirmRule(ruleId, init) {
949
+ return this.client.requestRaw("POST", this.client.pNormalizeRule(ruleId, "confirm"), init);
950
+ }
951
+ /** `POST /graphs/{tenant}/normalize/rules/{id}/reject`. */
952
+ normalizeRejectRule(ruleId, init) {
953
+ return this.client.requestRaw("POST", this.client.pNormalizeRule(ruleId, "reject"), init);
954
+ }
955
+ /** `POST /graphs/{tenant}/normalize/rules/{id}/apply`. */
956
+ normalizeApplyRule(ruleId, init) {
957
+ return this.client.requestRaw("POST", this.client.pNormalizeRule(ruleId, "apply"), init);
958
+ }
959
+ // -- tenants (account-level, NOT tenant-scoped) -------------------------- #
960
+ /** `POST /v1/me/tenants` — create/grant a tenant for the authed user. */
961
+ createTenant(body, init) {
962
+ return this.client.requestRaw("POST", this.client.pTenants(), { body, ...init });
963
+ }
964
+ /** `DELETE /v1/me/tenants/{id}` — remove a tenant grant. */
965
+ deleteTenant(tenantId, init) {
966
+ return this.client.requestRaw("DELETE", this.client.pTenant(tenantId), init);
967
+ }
968
+ /** `GET /v1/me/tenants` — list tenants the authed user can access. */
969
+ tenants(init) {
970
+ return this.client.requestRaw("GET", this.client.pTenants(), init);
971
+ }
972
+ };
973
+
974
+ export {
975
+ CographError,
976
+ Client
977
+ };
978
+ //# sourceMappingURL=chunk-PE2EOIGT.js.map