mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-07-02 02:58:10 +02:00
refactor(ts): make client gateway effect native
This commit is contained in:
parent
174d636178
commit
a7bdbb9257
16 changed files with 1168 additions and 1262 deletions
|
|
@ -7,16 +7,12 @@
|
|||
import { Effect } from "effect";
|
||||
import * as Argument from "effect/unstable/cli/Argument";
|
||||
import * as Command from "effect/unstable/cli/Command";
|
||||
import { cliCommandError, withSocket, writeJson } from "./util.js";
|
||||
import { gatewayDispatch, withGatewayClient, writeJson } from "./util.js";
|
||||
|
||||
const show = Command.make("show", {}, () =>
|
||||
withSocket((socket) =>
|
||||
withGatewayClient((client) =>
|
||||
Effect.gen(function* () {
|
||||
const cfg = socket.config();
|
||||
const resp = yield* Effect.tryPromise({
|
||||
try: () => cfg.getConfigAll(),
|
||||
catch: (error) => cliCommandError("config.show", error),
|
||||
});
|
||||
const resp = yield* gatewayDispatch(client, "config.show", "config", { operation: "config" }, { timeoutMs: 60000 });
|
||||
yield* writeJson(resp);
|
||||
}),
|
||||
),
|
||||
|
|
@ -25,19 +21,17 @@ const show = Command.make("show", {}, () =>
|
|||
const get = Command.make("get", {
|
||||
key: Argument.string("key").pipe(Argument.withDescription("Config key (format: type/key)")),
|
||||
}, ({ key }) =>
|
||||
withSocket((socket) =>
|
||||
withGatewayClient((client) =>
|
||||
Effect.gen(function* () {
|
||||
const cfg = socket.config();
|
||||
// Support "type/key" format; fall back to using the whole string as key
|
||||
const parts = key.split("/");
|
||||
const configKey =
|
||||
parts.length >= 2
|
||||
? { type: parts[0], key: parts.slice(1).join("/") }
|
||||
: { type: "config", key };
|
||||
const resp = yield* Effect.tryPromise({
|
||||
try: () => cfg.getConfig([configKey]),
|
||||
catch: (error) => cliCommandError("config.get", error),
|
||||
});
|
||||
const parts = key.split("/");
|
||||
const configKey =
|
||||
parts.length >= 2
|
||||
? { type: parts[0], key: parts.slice(1).join("/") }
|
||||
: { type: "config", key };
|
||||
const resp = yield* gatewayDispatch(client, "config.get", "config", {
|
||||
operation: "get",
|
||||
keys: [configKey],
|
||||
}, { timeoutMs: 60000 });
|
||||
yield* writeJson(resp);
|
||||
}),
|
||||
),
|
||||
|
|
@ -47,18 +41,17 @@ const set = Command.make("set", {
|
|||
key: Argument.string("key").pipe(Argument.withDescription("Config key (format: type/key)")),
|
||||
value: Argument.string("value").pipe(Argument.withDescription("Config value (JSON)")),
|
||||
}, ({ key, value }) =>
|
||||
withSocket((socket) =>
|
||||
withGatewayClient((client) =>
|
||||
Effect.gen(function* () {
|
||||
const cfg = socket.config();
|
||||
const parts = key.split("/");
|
||||
const configEntry =
|
||||
parts.length >= 2
|
||||
? { type: parts[0], key: parts.slice(1).join("/"), value }
|
||||
: { type: "config", key, value };
|
||||
const resp = yield* Effect.tryPromise({
|
||||
try: () => cfg.putConfig([configEntry]),
|
||||
catch: (error) => cliCommandError("config.set", error),
|
||||
});
|
||||
const parts = key.split("/");
|
||||
const configEntry =
|
||||
parts.length >= 2
|
||||
? { type: parts[0], key: parts.slice(1).join("/"), value }
|
||||
: { type: "config", key, value };
|
||||
const resp = yield* gatewayDispatch(client, "config.set", "config", {
|
||||
operation: "put",
|
||||
values: [configEntry],
|
||||
}, { timeoutMs: 60000 });
|
||||
yield* writeJson(resp);
|
||||
}),
|
||||
),
|
||||
|
|
@ -70,13 +63,12 @@ const list = Command.make("list", {
|
|||
Argument.withDefault("config"),
|
||||
),
|
||||
}, ({ type }) =>
|
||||
withSocket((socket) =>
|
||||
withGatewayClient((client) =>
|
||||
Effect.gen(function* () {
|
||||
const cfg = socket.config();
|
||||
const resp = yield* Effect.tryPromise({
|
||||
try: () => cfg.list(type),
|
||||
catch: (error) => cliCommandError("config.list", error),
|
||||
});
|
||||
const resp = yield* gatewayDispatch(client, "config.list", "config", {
|
||||
operation: "list",
|
||||
type,
|
||||
}, { timeoutMs: 60000 });
|
||||
yield* writeJson(resp);
|
||||
}),
|
||||
),
|
||||
|
|
@ -85,18 +77,17 @@ const list = Command.make("list", {
|
|||
const deleteCommand = Command.make("delete", {
|
||||
key: Argument.string("key").pipe(Argument.withDescription("Config key (format: type/key)")),
|
||||
}, ({ key }) =>
|
||||
withSocket((socket) =>
|
||||
withGatewayClient((client) =>
|
||||
Effect.gen(function* () {
|
||||
const cfg = socket.config();
|
||||
const parts = key.split("/");
|
||||
const configKey =
|
||||
parts.length >= 2
|
||||
? { type: parts[0], key: parts.slice(1).join("/") }
|
||||
: { type: "config", key };
|
||||
const resp = yield* Effect.tryPromise({
|
||||
try: () => cfg.deleteConfig(configKey),
|
||||
catch: (error) => cliCommandError("config.delete", error),
|
||||
});
|
||||
const parts = key.split("/");
|
||||
const configKey =
|
||||
parts.length >= 2
|
||||
? { type: parts[0], key: parts.slice(1).join("/") }
|
||||
: { type: "config", key };
|
||||
const resp = yield* gatewayDispatch(client, "config.delete", "config", {
|
||||
operation: "delete",
|
||||
keys: [configKey],
|
||||
}, { timeoutMs: 30000 });
|
||||
yield* writeJson(resp);
|
||||
}),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
import { Effect } from "effect";
|
||||
import * as Argument from "effect/unstable/cli/Argument";
|
||||
import * as Command from "effect/unstable/cli/Command";
|
||||
import { cliCommandError, withSocket, writeJson } from "./util.js";
|
||||
import { gatewayDispatch, withGatewayClient, writeJson } from "./util.js";
|
||||
|
||||
export const embeddingsCommand = Command.make("embeddings", {
|
||||
texts: Argument.string("text").pipe(
|
||||
|
|
@ -15,14 +15,13 @@ export const embeddingsCommand = Command.make("embeddings", {
|
|||
Argument.variadic({ min: 1 }),
|
||||
),
|
||||
}, ({ texts }) =>
|
||||
withSocket((socket, opts) =>
|
||||
withGatewayClient((client, opts) =>
|
||||
Effect.gen(function* () {
|
||||
const flow = socket.flow(opts.flow);
|
||||
const vectors = yield* Effect.tryPromise({
|
||||
try: () => flow.embeddings(Array.from(texts)),
|
||||
catch: (error) => cliCommandError("embeddings", error),
|
||||
});
|
||||
yield* writeJson(vectors);
|
||||
const response = yield* gatewayDispatch(client, "embeddings", "embeddings", {
|
||||
texts: Array.from(texts),
|
||||
}, { flow: opts.flow, timeoutMs: 30000 });
|
||||
const record = response as Record<string, unknown>;
|
||||
yield* writeJson(record.vectors ?? []);
|
||||
}),
|
||||
),
|
||||
).pipe(Command.withDescription("Generate text embeddings"));
|
||||
|
|
|
|||
|
|
@ -9,16 +9,14 @@ import * as S from "effect/Schema";
|
|||
import * as Argument from "effect/unstable/cli/Argument";
|
||||
import * as Command from "effect/unstable/cli/Command";
|
||||
import * as Flag from "effect/unstable/cli/Flag";
|
||||
import { cliCommandError, withSocket, writeJson } from "./util.js";
|
||||
import { cliCommandError, gatewayDispatch, withGatewayClient, writeJson } from "./util.js";
|
||||
|
||||
const list = Command.make("list", {}, () =>
|
||||
withSocket((socket) =>
|
||||
withGatewayClient((client) =>
|
||||
Effect.gen(function* () {
|
||||
const flows = socket.flows();
|
||||
const ids = yield* Effect.tryPromise({
|
||||
try: () => flows.getFlows(),
|
||||
catch: (error) => cliCommandError("flow.list", error),
|
||||
});
|
||||
const response = yield* gatewayDispatch(client, "flow.list", "flow", { operation: "list-flows" }, { timeoutMs: 60000 });
|
||||
const record = response as Record<string, unknown>;
|
||||
const ids = Array.isArray(record["flow-ids"]) ? record["flow-ids"] : [];
|
||||
yield* writeJson(ids);
|
||||
}),
|
||||
),
|
||||
|
|
@ -27,13 +25,16 @@ const list = Command.make("list", {}, () =>
|
|||
const get = Command.make("get", {
|
||||
id: Argument.string("id").pipe(Argument.withDescription("Flow ID")),
|
||||
}, ({ id }) =>
|
||||
withSocket((socket) =>
|
||||
withGatewayClient((client) =>
|
||||
Effect.gen(function* () {
|
||||
const flows = socket.flows();
|
||||
const def = yield* Effect.tryPromise({
|
||||
try: () => flows.getFlow(id),
|
||||
catch: (error) => cliCommandError("flow.get", error),
|
||||
});
|
||||
const response = yield* gatewayDispatch(client, "flow.get", "flow", {
|
||||
operation: "get-flow",
|
||||
"flow-id": id,
|
||||
}, { timeoutMs: 60000 });
|
||||
const record = response as Record<string, unknown>;
|
||||
const def = typeof record.flow === "string"
|
||||
? yield* S.decodeUnknownEffect(S.UnknownFromJsonString)(record.flow)
|
||||
: record.flow;
|
||||
yield* writeJson(def);
|
||||
}),
|
||||
),
|
||||
|
|
@ -56,26 +57,23 @@ const start = Command.make("start", {
|
|||
Flag.optional,
|
||||
),
|
||||
}, ({ id, blueprint, description, parameters }) =>
|
||||
withSocket((socket) =>
|
||||
withGatewayClient((client) =>
|
||||
Effect.gen(function* () {
|
||||
const flows = socket.flows();
|
||||
const rawParameters = parameters._tag === "Some" ? parameters.value : undefined;
|
||||
const params = rawParameters !== undefined && rawParameters.length > 0
|
||||
? yield* S.decodeUnknownEffect(S.UnknownFromJsonString)(rawParameters).pipe(
|
||||
? yield* S.decodeUnknownEffect(S.UnknownFromJsonString)(rawParameters).pipe(
|
||||
Effect.flatMap(S.decodeUnknownEffect(S.Record(S.String, S.Unknown))),
|
||||
Effect.mapError((error) => cliCommandError("flow.start.parameters", error)),
|
||||
)
|
||||
: undefined;
|
||||
const resp = yield* Effect.tryPromise({
|
||||
try: () =>
|
||||
flows.startFlow(
|
||||
id,
|
||||
blueprint,
|
||||
description,
|
||||
params,
|
||||
),
|
||||
catch: (error) => cliCommandError("flow.start", error),
|
||||
});
|
||||
const request = {
|
||||
operation: "start-flow",
|
||||
"flow-id": id,
|
||||
"blueprint-name": blueprint,
|
||||
description,
|
||||
...(params !== undefined && Object.keys(params).length > 0 ? { parameters: params } : {}),
|
||||
};
|
||||
const resp = yield* gatewayDispatch(client, "flow.start", "flow", request, { timeoutMs: 30000 });
|
||||
yield* writeJson(resp);
|
||||
}),
|
||||
),
|
||||
|
|
@ -84,13 +82,12 @@ const start = Command.make("start", {
|
|||
const stop = Command.make("stop", {
|
||||
id: Argument.string("id").pipe(Argument.withDescription("Flow ID")),
|
||||
}, ({ id }) =>
|
||||
withSocket((socket) =>
|
||||
withGatewayClient((client) =>
|
||||
Effect.gen(function* () {
|
||||
const flows = socket.flows();
|
||||
const resp = yield* Effect.tryPromise({
|
||||
try: () => flows.stopFlow(id),
|
||||
catch: (error) => cliCommandError("flow.stop", error),
|
||||
});
|
||||
const resp = yield* gatewayDispatch(client, "flow.stop", "flow", {
|
||||
operation: "stop-flow",
|
||||
"flow-id": id,
|
||||
}, { timeoutMs: 30000 });
|
||||
yield* writeJson(resp);
|
||||
}),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import * as O from "effect/Option";
|
|||
import * as Argument from "effect/unstable/cli/Argument";
|
||||
import * as Command from "effect/unstable/cli/Command";
|
||||
import * as Flag from "effect/unstable/cli/Flag";
|
||||
import { cliCommandError, withSocket, writeLine } from "./util.js";
|
||||
import { gatewayDispatch, withGatewayClient, writeLine } from "./util.js";
|
||||
|
||||
export const graphRagCommand = Command.make("graph-rag", {
|
||||
query: Argument.string("query").pipe(Argument.withDescription("Natural language query")),
|
||||
|
|
@ -26,22 +26,17 @@ export const graphRagCommand = Command.make("graph-rag", {
|
|||
Flag.optional,
|
||||
),
|
||||
}, ({ query, entityLimit, tripleLimit, collection }) =>
|
||||
withSocket((socket, opts) =>
|
||||
withGatewayClient((client, opts) =>
|
||||
Effect.gen(function* () {
|
||||
const flow = socket.flow(opts.flow);
|
||||
const response = yield* Effect.tryPromise({
|
||||
try: () =>
|
||||
flow.graphRag(
|
||||
query,
|
||||
{
|
||||
entityLimit,
|
||||
tripleLimit,
|
||||
},
|
||||
O.getOrUndefined(collection),
|
||||
),
|
||||
catch: (error) => cliCommandError("graph-rag", error),
|
||||
});
|
||||
yield* writeLine(response);
|
||||
const response = yield* gatewayDispatch(client, "graph-rag", "graph-rag", {
|
||||
query,
|
||||
user: opts.user,
|
||||
collection: O.getOrUndefined(collection) ?? "default",
|
||||
"entity-limit": entityLimit,
|
||||
"triple-limit": tripleLimit,
|
||||
}, { flow: opts.flow, timeoutMs: 60000 });
|
||||
const record = response as Record<string, unknown>;
|
||||
yield* writeLine(typeof record.response === "string" ? record.response : "");
|
||||
}),
|
||||
),
|
||||
).pipe(Command.withDescription("Query the knowledge graph using RAG"));
|
||||
|
|
@ -57,19 +52,16 @@ export const documentRagCommand = Command.make("document-rag", {
|
|||
Flag.optional,
|
||||
),
|
||||
}, ({ query, docLimit, collection }) =>
|
||||
withSocket((socket, opts) =>
|
||||
withGatewayClient((client, opts) =>
|
||||
Effect.gen(function* () {
|
||||
const flow = socket.flow(opts.flow);
|
||||
const response = yield* Effect.tryPromise({
|
||||
try: () =>
|
||||
flow.documentRag(
|
||||
query,
|
||||
docLimit,
|
||||
O.getOrUndefined(collection),
|
||||
),
|
||||
catch: (error) => cliCommandError("document-rag", error),
|
||||
});
|
||||
yield* writeLine(response);
|
||||
const response = yield* gatewayDispatch(client, "document-rag", "document-rag", {
|
||||
query,
|
||||
user: opts.user,
|
||||
collection: O.getOrUndefined(collection) ?? "default",
|
||||
"doc-limit": docLimit,
|
||||
}, { flow: opts.flow, timeoutMs: 60000 });
|
||||
const record = response as Record<string, unknown>;
|
||||
yield* writeLine(typeof record.response === "string" ? record.response : "");
|
||||
}),
|
||||
),
|
||||
).pipe(Command.withDescription("Query documents using RAG"));
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@
|
|||
* Manages documents stored in the TrustGraph library.
|
||||
*/
|
||||
|
||||
import { Effect, Match } from "effect";
|
||||
import { Clock, Effect, Match } from "effect";
|
||||
import * as O from "effect/Option";
|
||||
import * as Argument from "effect/unstable/cli/Argument";
|
||||
import * as Command from "effect/unstable/cli/Command";
|
||||
import * as Flag from "effect/unstable/cli/Flag";
|
||||
import { cliCommandError, withSocket, writeJson } from "./util.js";
|
||||
import { cliCommandError, gatewayDispatch, withGatewayClient, writeJson } from "./util.js";
|
||||
|
||||
function basenamePath(filepath: string): string {
|
||||
const normalized = filepath.replace(/\/+$/, "");
|
||||
|
|
@ -34,14 +34,14 @@ export function guessMimeType(filepath: string): string {
|
|||
}
|
||||
|
||||
const list = Command.make("list", {}, () =>
|
||||
withSocket((socket) =>
|
||||
withGatewayClient((client, opts) =>
|
||||
Effect.gen(function* () {
|
||||
const lib = socket.librarian();
|
||||
const docs = yield* Effect.tryPromise({
|
||||
try: () => lib.getDocuments(),
|
||||
catch: (error) => cliCommandError("library.list", error),
|
||||
});
|
||||
yield* writeJson(docs);
|
||||
const response = yield* gatewayDispatch(client, "library.list", "librarian", {
|
||||
operation: "list-documents",
|
||||
user: opts.user,
|
||||
}, { timeoutMs: 60000 });
|
||||
const record = response as Record<string, unknown>;
|
||||
yield* writeJson(record["document-metadatas"] ?? record.documents ?? []);
|
||||
}),
|
||||
),
|
||||
).pipe(Command.withDescription("List documents in the library"));
|
||||
|
|
@ -72,9 +72,8 @@ const load = Command.make("load", {
|
|||
Flag.optional,
|
||||
),
|
||||
}, ({ file, title, mimeType, comments, tags, id }) =>
|
||||
withSocket((socket) =>
|
||||
withGatewayClient((client, opts) =>
|
||||
Effect.gen(function* () {
|
||||
const lib = socket.librarian();
|
||||
const data = new Uint8Array(yield* Effect.tryPromise({
|
||||
try: () => Bun.file(file).arrayBuffer(),
|
||||
catch: (error) => cliCommandError("library.load.read-file", error),
|
||||
|
|
@ -82,19 +81,25 @@ const load = Command.make("load", {
|
|||
const b64 = Buffer.from(data).toString("base64");
|
||||
const resolvedMimeType = O.getOrUndefined(mimeType) ?? guessMimeType(file);
|
||||
const resolvedTitle = O.getOrUndefined(title) ?? basenamePath(file);
|
||||
|
||||
const resp = yield* Effect.tryPromise({
|
||||
try: () =>
|
||||
lib.loadDocument(
|
||||
b64,
|
||||
resolvedMimeType,
|
||||
resolvedTitle,
|
||||
comments,
|
||||
Array.from(tags),
|
||||
O.getOrUndefined(id),
|
||||
),
|
||||
catch: (error) => cliCommandError("library.load", error),
|
||||
});
|
||||
const timestamp = yield* Clock.currentTimeMillis;
|
||||
const documentId = O.getOrUndefined(id);
|
||||
const documentMetadata = {
|
||||
time: Math.floor(timestamp / 1000),
|
||||
kind: resolvedMimeType,
|
||||
title: resolvedTitle,
|
||||
comments,
|
||||
user: opts.user,
|
||||
tags: Array.from(tags),
|
||||
"document-type": "source",
|
||||
documentType: "source",
|
||||
...(documentId !== undefined ? { id: documentId } : {}),
|
||||
};
|
||||
const resp = yield* gatewayDispatch(client, "library.load", "librarian", {
|
||||
operation: "add-document",
|
||||
"document-metadata": documentMetadata,
|
||||
documentMetadata,
|
||||
content: b64,
|
||||
}, { timeoutMs: 30000 });
|
||||
yield* writeJson(resp);
|
||||
}),
|
||||
),
|
||||
|
|
@ -107,27 +112,29 @@ const remove = Command.make("remove", {
|
|||
Flag.optional,
|
||||
),
|
||||
}, ({ id, collection }) =>
|
||||
withSocket((socket) =>
|
||||
withGatewayClient((client, opts) =>
|
||||
Effect.gen(function* () {
|
||||
const lib = socket.librarian();
|
||||
const resp = yield* Effect.tryPromise({
|
||||
try: () => lib.removeDocument(id, O.getOrUndefined(collection)),
|
||||
catch: (error) => cliCommandError("library.remove", error),
|
||||
});
|
||||
const resp = yield* gatewayDispatch(client, "library.remove", "librarian", {
|
||||
operation: "remove-document",
|
||||
"document-id": id,
|
||||
documentId: id,
|
||||
user: opts.user,
|
||||
collection: O.getOrUndefined(collection) ?? "default",
|
||||
}, { timeoutMs: 30000 });
|
||||
yield* writeJson(resp);
|
||||
}),
|
||||
),
|
||||
).pipe(Command.withDescription("Remove a document from the library"));
|
||||
|
||||
const processing = Command.make("processing", {}, () =>
|
||||
withSocket((socket) =>
|
||||
withGatewayClient((client, opts) =>
|
||||
Effect.gen(function* () {
|
||||
const lib = socket.librarian();
|
||||
const items = yield* Effect.tryPromise({
|
||||
try: () => lib.getProcessing(),
|
||||
catch: (error) => cliCommandError("library.processing", error),
|
||||
});
|
||||
yield* writeJson(items);
|
||||
const response = yield* gatewayDispatch(client, "library.processing", "librarian", {
|
||||
operation: "list-processing",
|
||||
user: opts.user,
|
||||
}, { timeoutMs: 60000 });
|
||||
const record = response as Record<string, unknown>;
|
||||
yield* writeJson(record["processing-metadatas"] ?? record.processing ?? record["processing-metadata"] ?? []);
|
||||
}),
|
||||
),
|
||||
).pipe(Command.withDescription("List documents currently being processed"));
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { Effect } from "effect";
|
|||
import * as O from "effect/Option";
|
||||
import * as Command from "effect/unstable/cli/Command";
|
||||
import * as Flag from "effect/unstable/cli/Flag";
|
||||
import { cliCommandError, withSocket, writeJson } from "./util.js";
|
||||
import { gatewayDispatch, withGatewayClient, writeJson } from "./util.js";
|
||||
|
||||
export const triplesCommand = Command.make("triples", {
|
||||
subject: Flag.string("subject").pipe(
|
||||
|
|
@ -37,9 +37,8 @@ export const triplesCommand = Command.make("triples", {
|
|||
Flag.optional,
|
||||
),
|
||||
}, ({ subject, predicate, object, limit, collection }) =>
|
||||
withSocket((socket, opts) =>
|
||||
withGatewayClient((client, opts) =>
|
||||
Effect.gen(function* () {
|
||||
const flow = socket.flow(opts.flow);
|
||||
const subjectValue = O.getOrUndefined(subject);
|
||||
const predicateValue = O.getOrUndefined(predicate);
|
||||
const objectValue = O.getOrUndefined(object);
|
||||
|
|
@ -53,18 +52,16 @@ export const triplesCommand = Command.make("triples", {
|
|||
? { t: "i", i: objectValue }
|
||||
: undefined;
|
||||
|
||||
const triples = yield* Effect.tryPromise({
|
||||
try: () =>
|
||||
flow.triplesQuery(
|
||||
s,
|
||||
p,
|
||||
o,
|
||||
limit,
|
||||
O.getOrUndefined(collection),
|
||||
),
|
||||
catch: (error) => cliCommandError("triples", error),
|
||||
});
|
||||
yield* writeJson(triples);
|
||||
const response = yield* gatewayDispatch(client, "triples", "triples", {
|
||||
limit,
|
||||
user: opts.user,
|
||||
collection: O.getOrUndefined(collection) ?? "default",
|
||||
...(s !== undefined ? { s } : {}),
|
||||
...(p !== undefined ? { p } : {}),
|
||||
...(o !== undefined ? { o } : {}),
|
||||
}, { flow: opts.flow, timeoutMs: 30000 });
|
||||
const record = response as Record<string, unknown>;
|
||||
yield* writeJson(record.triples ?? record.response ?? []);
|
||||
}),
|
||||
),
|
||||
).pipe(Command.withDescription("Query knowledge graph triples"));
|
||||
|
|
|
|||
|
|
@ -3,14 +3,13 @@
|
|||
*/
|
||||
|
||||
import type {
|
||||
BaseApi,
|
||||
DispatchOptions,
|
||||
TrustGraphGatewayClient,
|
||||
} from "@trustgraph/client";
|
||||
import {
|
||||
createTrustGraphSocket,
|
||||
makeTrustGraphGatewayClientScoped,
|
||||
} from "@trustgraph/client";
|
||||
import { Duration, Effect } from "effect";
|
||||
import { Effect } from "effect";
|
||||
import * as O from "effect/Option";
|
||||
import * as S from "effect/Schema";
|
||||
import * as Command from "effect/unstable/cli/Command";
|
||||
|
|
@ -85,37 +84,6 @@ export const writeJson = (value: unknown) =>
|
|||
Effect.flatMap(writeLine),
|
||||
);
|
||||
|
||||
/**
|
||||
* Create a BaseApi socket client and wait for the connection to be established.
|
||||
* The client auto-connects; we listen for the first "connected/authenticated"
|
||||
* state before handing it back to the caller.
|
||||
*/
|
||||
export function createSocketEffect(opts: CliOpts): Effect.Effect<BaseApi, CliCommandError> {
|
||||
const socket = createTrustGraphSocket(opts.user, opts.token, opts.gateway);
|
||||
|
||||
return Effect.callback<void, CliCommandError>((resume) => {
|
||||
const unsub = socket.onConnectionStateChange((state) => {
|
||||
if (state.status === "authenticated" || state.status === "unauthenticated") {
|
||||
unsub();
|
||||
resume(Effect.void);
|
||||
} else if (state.status === "failed") {
|
||||
unsub();
|
||||
resume(Effect.fail(cliCommandError("connect", state.lastError ?? "WebSocket connection failed")));
|
||||
}
|
||||
});
|
||||
|
||||
return Effect.sync(() => {
|
||||
unsub();
|
||||
});
|
||||
}).pipe(
|
||||
Effect.timeout(Duration.seconds(15)),
|
||||
Effect.catchTag("TimeoutError", () =>
|
||||
Effect.fail(cliCommandError("connect", "Timed out waiting for WebSocket connection")),
|
||||
),
|
||||
Effect.as(socket),
|
||||
);
|
||||
}
|
||||
|
||||
function gatewayUrlWithToken(opts: CliOpts): string {
|
||||
if (opts.token === undefined || opts.token.length === 0) return opts.gateway;
|
||||
const separator = opts.gateway.includes("?") ? "&" : "?";
|
||||
|
|
@ -133,16 +101,37 @@ export const withGatewayClient = Effect.fn("withGatewayClient")(function* <A, E,
|
|||
);
|
||||
});
|
||||
|
||||
export const withSocket = Effect.fn("withSocket")(function* <A, E, R>(
|
||||
use: (socket: BaseApi, opts: CliOpts) => Effect.Effect<A, E, R>,
|
||||
export interface GatewayDispatchOptions {
|
||||
readonly flow?: string;
|
||||
readonly timeoutMs?: number;
|
||||
readonly retries?: number;
|
||||
}
|
||||
|
||||
export const gatewayDispatch = Effect.fn("gatewayDispatch")(function*(
|
||||
client: TrustGraphGatewayClient,
|
||||
operation: string,
|
||||
service: string,
|
||||
request: Record<string, unknown>,
|
||||
options: GatewayDispatchOptions = {},
|
||||
) {
|
||||
const opts = yield* getOpts;
|
||||
return yield* Effect.acquireUseRelease(
|
||||
createSocketEffect(opts),
|
||||
(socket) => use(socket, opts),
|
||||
(socket) =>
|
||||
Effect.sync(() => {
|
||||
socket.close();
|
||||
}),
|
||||
const input = options.flow === undefined
|
||||
? {
|
||||
scope: "global" as const,
|
||||
service,
|
||||
request,
|
||||
}
|
||||
: {
|
||||
scope: "flow" as const,
|
||||
service,
|
||||
flow: options.flow,
|
||||
request,
|
||||
};
|
||||
const dispatchOptions: DispatchOptions = {
|
||||
...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),
|
||||
...(options.retries !== undefined ? { retries: options.retries } : {}),
|
||||
};
|
||||
|
||||
return yield* client.dispatch(input, dispatchOptions).pipe(
|
||||
Effect.mapError((error) => cliCommandError(operation, error)),
|
||||
);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue