123 lines
6.7 KiB
Markdown
123 lines
6.7 KiB
Markdown
[](https://dvalin.robotico.dev/robotico/robotico-nexus-client-csharp)
|
|
|
|
[](https://dotnet.microsoft.com/download/dotnet/10.0)
|
|
[](https://learn.microsoft.com/dotnet/csharp/)
|
|
[](https://grpc.io/)
|
|
[](https://download.robotico.dev/nuget/)
|
|
[](https://brokkr.robotico.dev/robotico/robotico-nexus-client-csharp)
|
|
|
|
# Robotico.Nexus.Client
|
|
|
|
Unified client SDK for a remote [Mishima Nexus](https://brokkr.robotico.dev/robotico/mishima-suite)
|
|
server: connect via a `nexus+*://` URI and get `Robotico.Graph` / `Robotico.Time` ports bound to a
|
|
logical database over gRPC, plus thin Document/Relational connect helpers.
|
|
|
|
- NuGet: `Robotico.Nexus.Client`
|
|
- Feed: `https://download.robotico.dev/nuget/v3/index.json`
|
|
- Brokkr: `https://brokkr.robotico.dev/robotico/robotico-nexus-client-csharp`
|
|
|
|
This package does **not** reference `Mishima.Nexus.Node.*` (the server host assemblies) — it only
|
|
depends on the generated `Mishima.Nexus.Wire.V1` gRPC stubs, `Robotico.Graph`, and `Robotico.Time`.
|
|
|
|
## Quick start
|
|
|
|
```csharp
|
|
using Robotico.Nexus.Client;
|
|
|
|
Result<NexusClient> connected = NexusClient.Connect("nexus+graph://localhost:50051/pathways");
|
|
using NexusClient client = connected.ExpectSuccess();
|
|
|
|
client.CheckHealth().ExpectSuccess();
|
|
|
|
Result<IGraphSession> opened = client.Graph.Open("pathways");
|
|
using IGraphSession session = opened.ExpectSuccess();
|
|
session.RegisterLabel("Person").ExpectSuccess();
|
|
session.UpsertVertex(1, ["Person"]).ExpectSuccess();
|
|
```
|
|
|
|
## Connection URIs
|
|
|
|
| Scheme | Plane | Default database (empty path) |
|
|
|-----------------------|------------|--------------------------------|
|
|
| `nexus+graph://` | Graph | `pathways` |
|
|
| `nexus+time://` | Time | `telemetry` |
|
|
| `nexus+document://` | Document | `catalog` |
|
|
| `nexus+relational://` | Relational | `ledger` |
|
|
| `nexus+sql://` | — | rejected — use `Mishima.Nexus.Sql` directly |
|
|
|
|
- The URI **host:port** is the gRPC endpoint; the **port is always explicit** (no default port is
|
|
ever inferred, so a typo can't silently connect to the wrong service).
|
|
- The URI **path** (e.g. `/pathways`) is the **logical database name**, sent as the
|
|
`x-nexus-database` gRPC metadata header on every call — it is not a filesystem path, even though
|
|
the underlying `IGraphStore`/`ITimeStore` port parameter is historically named
|
|
`databaseFilePath`.
|
|
- One `NexusClient` is bound to a single scheme + logical database from the connect URI. Open a
|
|
second client to talk to another plane or database.
|
|
|
|
## TLS / mTLS / bearer auth
|
|
|
|
`NexusClientOptions` mirrors `Mishima.Nexus.Wire.Clients.WireTlsMaterial`'s environment variables
|
|
(same names, no shared assembly dependency):
|
|
|
|
| Variable | Purpose |
|
|
|---------------------------------|-------------------------------------------|
|
|
| `NEXUS_TLS_CA_FILE` | CA certificate PEM (trust root) |
|
|
| `NEXUS_TLS_CLIENT_CERT_FILE` | Client (machine credential) certificate |
|
|
| `NEXUS_TLS_CLIENT_KEY_FILE` | Client private key PEM |
|
|
| `NEXUS_TLS_MODE` | `https` (default) or `insecure` |
|
|
| `NEXUS_WIRE_BEARER` | Bearer token attached as `Authorization` |
|
|
| `NEXUS_WIRE_DEFAULT_BEARER` | Fallback bearer token |
|
|
|
|
Pass an explicit `NexusTlsMaterial` / `BearerToken` via `NexusClientOptions` to override the
|
|
environment. When no TLS material is present and `UseHttps` is unset, the client dials plaintext
|
|
h2c (loopback/dev only).
|
|
|
|
## Create / Open / OpenOrCreate semantics (POLA)
|
|
|
|
Nexus provisions logical databases lazily — the host creates a database's on-disk state the first
|
|
time an RPC actually touches it, not via a separate "create database" call on the Graph/Time wire
|
|
services. This client documents that behavior explicitly rather than pretending otherwise:
|
|
|
|
- **`Open(name)`** — pings the engine with `x-nexus-database: name` and returns a session bound to
|
|
that logical name. Succeeds even for a database the host hasn't materialized yet (the host
|
|
creates it lazily on first write).
|
|
- **`OpenOrCreate(name)`** — identical to `Open(name)`. There is no separate provisioning step to
|
|
race against, so "open if exists, else create" collapses to "open" once the engine is reachable.
|
|
- **`Create(name)`** — fails with `NXS_ALREADY_EXISTS` when `Ping` against `name` succeeds, because
|
|
Nexus's `Ping` is an **engine-liveness** probe, not a **per-database existence** check — once the
|
|
Graph/Time engine is reachable at all, `Create` cannot distinguish "database already has data"
|
|
from "database is merely reachable". Use `OpenOrCreate` for greenfield databases instead.
|
|
|
|
## Document / Relational
|
|
|
|
`NexusClient.CreateDocumentClient()` / `CreateRelationalClient()` return small façades (`Ping` plus,
|
|
for Document, single-document upsert/get/delete) — enough for MVP smoke usage. They are **not** a
|
|
full `IMishimaDatabase` façade. For the complete generated RPC surface, use
|
|
`CreateDocumentWireClient()` / `CreateRelationalWireClient()`, which return the raw
|
|
`Mishima.Nexus.Wire.V1` gRPC clients bound to the same channel and `x-nexus-database` metadata.
|
|
|
|
## Error codes
|
|
|
|
All failures map to `Robotico.Result.Result` with `NXS_*` codes (`NexusErrors`): `NXS_URI_INVALID`,
|
|
`NXS_URI_UNSUPPORTED_SCHEME`, `NXS_CONNECT_FAILED`, `NXS_TLS_REJECTED`, `NXS_ALREADY_EXISTS`,
|
|
`NXS_NOT_FOUND`, `NXS_INVALID_ARGUMENT`, `NXS_DISPOSED`, `NXS_UNAVAILABLE`, `NXS_WIRE_FAILED`.
|
|
`Robotico.Graph` (`GR_*`) and `Robotico.Time` (`TM_*`) codes surface unchanged from the ports.
|
|
|
|
## Quality gate
|
|
|
|
Same Library 10 bar as other Robotico C# packages:
|
|
|
|
- Analyzers on (`TreatWarningsAsErrors`, Meziantou MA0004/MA0042/MA0155, IDE0008/IDE0090/IDE0301/IDE0330)
|
|
- `dotnet test` with coverlet **≥ 90%** line coverage on `Robotico.Nexus.Client`, exercised against
|
|
an in-process fake gRPC server (Kestrel + in-memory fake `NexusGraphEngineService` /
|
|
`NexusTimeEngineService` / `NexusDocumentEngineService` / `NexusRelationalEngineService` /
|
|
`NexusHealthService`) — no live Nexus process required.
|
|
- Woodpecker / GitHub CI run `bash scripts/woodpecker-verify.sh`
|
|
|
|
## Build
|
|
|
|
```bash
|
|
bash scripts/woodpecker-verify.sh
|
|
bash scripts/pack-release.sh
|
|
```
|