Disruptor.Surreal
1.0.0
dotnet add package Disruptor.Surreal --version 1.0.0
NuGet\Install-Package Disruptor.Surreal -Version 1.0.0
<PackageReference Include="Disruptor.Surreal" Version="1.0.0" />
<PackageVersion Include="Disruptor.Surreal" Version="1.0.0" />
<PackageReference Include="Disruptor.Surreal" />
paket add Disruptor.Surreal --version 1.0.0
#r "nuget: Disruptor.Surreal, 1.0.0"
#:package Disruptor.Surreal@1.0.0
#addin nuget:?package=Disruptor.Surreal&version=1.0.0
#tool nuget:?package=Disruptor.Surreal&version=1.0.0
Disruptor.Surreal
A .NET 10 client for SurrealDB, modeled on the official Rust client. CBOR over WebSocket. Single package. No embedded mode.
Unofficial. Not affiliated with the SurrealDB project. The
Disruptor.Surrealname keeps that unambiguous. MIT; contributions welcome.
Why this exists
Targeted to our design goals — not intended as a general-purpose drop-in replacement for the official SDK.
(yet. evil laugh.)
Built alongside Disruptor.Surface, an ORM/source-generator
project whose transport needs drive the v1 surface here: CBOR over WS, typed
bindings, server-side transactions, faithful Value-tree round-tripping for
SurrealDB's wire types (RecordId, decimal, DateTimeOffset, Guid,
Datetime / Duration with full nanosecond precision). Embedded is
permanently out — we trust the database.
Install
The project targets net10.0. Install from NuGet:
dotnet add package Disruptor.Surreal
or add a PackageReference:
<PackageReference Include="Disruptor.Surreal" Version="1.0.0" />
Quick start
using Disruptor.Surreal;
using Disruptor.Surreal.Connection;
using Disruptor.Surreal.Values;
// One-shot connect: parse the connection string, dial WS, signin, switch ns/db.
await using var db = await SurrealClient.ConnectAsync(SurrealOptions.Parse(
"Url=ws://localhost:8000;Namespace=test;Database=test;User=root;Password=root"));
var jaime = new SurrealRecordId("person", "jaime");
// Create a record at a known id
await db.CreateAsync(jaime, new SurrealObject
{
["name"] = "Jaime",
["age"] = 30L,
["joined"] = DateTimeOffset.UtcNow, // CBOR tag 12
["balance"] = 1234.56m, // CBOR tag 10
["session"] = Guid.NewGuid(), // CBOR tag 37
});
// Multi-statement query with bindings
var response = await db.QueryAsync(
"SELECT * FROM person WHERE age >= $minAge",
new SurrealObject { ["minAge"] = 21L });
var rows = response.Take(0); // SurrealValue (a SurrealListValue of SurrealObjectValue)
// Server-side transaction with rollback
await using var tx = await db.BeginTransactionAsync();
await tx.UpdateAsync(jaime, new SurrealObject { ["balance"] = 9999m });
await tx.CommitAsync(); // or tx.CancelAsync() to roll back
Wire format
CBOR over WebSocket using the SurrealDB-flavoured tag scheme:
| Tag | Meaning | .NET surface |
|---|---|---|
| 0 | Spec datetime (text) | decode-only |
| 6 | NONE sentinel |
SurrealNoneValue |
| 7 | Table reference | SurrealTable / SurrealTableValue |
| 8 | RecordId [table, key] |
SurrealRecordId / SurrealRecordIdKey |
| 9 | UUID (text) | decode-only |
| 10 | Decimal (text, canonical) | decimal |
| 12 | Datetime [seconds, nanos] |
SurrealDateTime ↔ DateTimeOffset |
| 13 | Duration (text) | decode-only |
| 14 | Duration [secs?, nanos?] |
SurrealDuration ↔ TimeSpan |
| 37 | UUID (16-byte big-endian) | Guid |
Datetimes preserve full nanosecond precision via an explicit Nanos field
(since DateTimeOffset only resolves to 100ns ticks).
Feature matrix
Compared against the official Rust client as the de-facto reference implementation. (Status legend: yes = supported, no = open work, partial = some sub-features only, out = permanently out of scope, n/a = no wire representation in the protocol.)
Transports
| Transport | Rust | Disruptor.Surreal | Notes |
|---|---|---|---|
WebSocket (ws, wss) |
yes | yes | CBOR sub-protocol |
| HTTP / HTTPS | yes | out | WS-only by design — single transport path, type-preserving CBOR, live queries possible |
Embedded mem |
yes | out | We trust the database |
Embedded rocksdb |
yes | out | — |
Embedded surrealkv |
yes | out | — |
Embedded file |
yes | out | — |
Embedded indxdb (WASM) |
yes | out | — |
Distributed tikv |
yes | out | — |
Wire format
| Format | Rust | Disruptor.Surreal | Notes |
|---|---|---|---|
| CBOR | yes | yes | Via System.Formats.Cbor |
| JSON | partial | out | Server supports it; lossy for record-id / datetime / decimal types — we won't add it |
| Flatbuffers | yes (default) | out | Rust client's current default; brings an IDL/codegen workflow we don't want |
RPC methods
| Method | Rust | Disruptor.Surreal |
|---|---|---|
use_ns / use_db |
yes | yes |
signin / signup |
yes | yes |
authenticate / invalidate |
yes | yes |
refresh (rotate token) |
yes | yes — RefreshAsync; mirrors Rust Command::Refresh |
set / unset (session vars) |
yes | yes |
query (with bindings) |
yes | yes |
select (table or RecordId) |
yes | yes |
create (table or RecordId, with content) |
yes | yes |
update (table or RecordId) |
yes | yes |
delete (table or RecordId) |
yes | yes |
upsert (table or RecordId) |
yes | yes |
merge (table or RecordId) |
yes | yes |
patch (JSON-Patch ops) |
yes | yes — see Patch.Add/Replace/Remove/Move/Copy/Test/Change helpers |
insert (single or bulk) |
yes | yes |
insert_relation (single or bulk edges) |
yes | yes |
relate (graph edge) |
yes | yes |
run (server-side function, optional version) |
yes | yes |
version / ping (health) |
yes | yes |
begin / commit / cancel (txn id) |
yes | yes |
live / kill (live queries) |
yes | yes (LiveAsync returns a SurrealLiveQueryHandle : IAsyncEnumerable<SurrealNotification>; DroppedCount exposes back-pressure-induced loss) |
export / import |
yes | out — server-side these are HTTP endpoints (/export, /import), not RPC methods; out of scope alongside the HTTP transport |
| ML model export | yes | out |
Auth credentials
| Credential | Rust | Disruptor.Surreal |
|---|---|---|
| Root | yes | yes |
| Namespace | yes | yes |
| Database | yes | yes |
| Record (scope, params object) | yes | yes |
| Access token (bearer) | yes | yes |
| Refresh token / rotation | yes | yes (SurrealToken { SurrealAccess, Refresh? }, RefreshAsync) |
Value tree
| Variant | CBOR tag | Rust | Disruptor.Surreal |
|---|---|---|---|
| None / Null / Bool | 6 / — | yes | yes |
| Number (Int / Float / Decimal) | — / — / 10 | yes | yes |
| String / Bytes | — / — | yes | yes |
| Datetime (full nanosecond precision) | 0 / 12 | yes | yes (SurrealDateTime) |
| Duration | 13 / 14 | yes | yes (SurrealDuration) |
| Uuid | 9 / 37 | yes | yes |
| Table | 7 | yes | yes (SurrealTable) |
| RecordId (string / int / uuid / ulid keys) | 8 | yes | yes (SurrealRecordId, Surreal{String,Integer,Uuid,Ulid,List,Object,Range}RecordIdKey) |
| Array / Object | — / — | yes | yes (SurrealList, SurrealObject) |
| Set | 56 | yes | yes (SurrealSet, SurrealSetValue) |
| Range / RecordIdKeyRange | 49 / 50 / 51 | yes | yes (SurrealRange, SurrealBound<T>, RecordIdKeyRange, SurrealRangeRecordIdKey) |
| Geometry (Point/Line/Polygon/Multi*/Collection) | 88–94 | yes | yes (SurrealGeometry.Point/Line/Polygon/MultiPoint/MultiLine/MultiPolygon/Collection) |
| File (bucket reference) | 55 | yes | yes (SurrealFile, SurrealFileValue) |
| Regex | — | yes | n/a — Rust source explicitly errors on CBOR encoding for regex (convert.rs:450); no wire shape exists |
Connection lifecycle
| Feature | Rust | Disruptor.Surreal |
|---|---|---|
| Connection-string parsing | yes | yes (ADO-style) |
| One-shot connect + signin + use_ns/db | n/a | yes |
| Auto re-auth on token expiry (transparent retry) | yes | yes |
| Reconnect with session replay (outside txn) | yes | out — explicit drop = explicit reconnect; we don't paper over connection state for the consumer |
| Server version compatibility check | yes | yes (>=3.0.0-alpha.1, <4.0.0; opt out via SurrealConnectionConfig.SkipVersionCheck) |
| Multi-session per connection | yes | out — one SurrealClient instance owns its WS 1:1; spin up a second for a second session |
Error / diagnostics
| Feature | Rust | Disruptor.Surreal |
|---|---|---|
| Typed exception hierarchy | yes | yes (Auth / Conflict / TransactionAborted / Constraint / Connection / Protocol / Rpc) |
| Token-expiry signal | yes | yes (SurrealAuthException.IsTokenExpired) |
| Retry-on-conflict helper | n/a | yes (SurrealRetryPolicy.WithRetryAsync) |
Consumer-side mapping
| Feature | Rust | Disruptor.Surreal |
|---|---|---|
ISurrealRecordId interop interface |
yes (Sealed trait) |
yes |
| POCO mapping (attribute / source-gen / reflection) | yes (SurrealValue derive) |
out — consumer brings the mapper |
Layout
src/Disruptor.Surreal/ — the library (one package)
Auth/ — credentials + SurrealAccessToken
Cbor/ — tag table, reader, writer
Connection/ — SurrealEndpoint, Command, Rpc{Request,Response},
ISurrealConnection, SurrealWebSocketConnection,
SurrealOptions, SurrealConnectionConfig,
ServerVersion
Errors/ — exception hierarchy
Live/ — SurrealLiveQueryHandle, SurrealNotification,
SurrealLiveQueryOptions
Query/ — SurrealQueryResponse, SurrealQueryStatement
Values/ — Value tree + scalar wrappers
(SurrealDateTime, SurrealDuration, etc.)
+ ISurrealRecordId
Patch.cs — JSON-Patch op factories
SurrealClient.cs — main client class
SurrealRetryPolicy.cs — retry-on-conflict helper
SurrealTransaction.cs — transaction handle (auto-cancel on dispose)
tests/Disruptor.Surreal.Tests/ — xUnit (CBOR roundtrip, endpoint parsing,
value semantics, error classifier,
options parsing)
samples/Disruptor.Surreal.Sample/ — runnable demo
Run the tests
dotnet test
Run the sample (needs a local server)
docker run -d --rm --name surrealdb -p 8000:8000 surrealdb/surrealdb:latest \
start --user root --pass root memory
dotnet run --project samples/Disruptor.Surreal.Sample
License
MIT. See LICENSE.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- System.Formats.Cbor (>= 10.0.0)
- Ulid (>= 1.4.1)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Disruptor.Surreal:
| Package | Downloads |
|---|---|
|
Disruptor.Surface.Runtime
Runtime types for Disruptor.Surface — typed RecordId structs, SurrealSession, relation markers, hydration helpers, and query primitives. Pair with Disruptor.Surface.Generator (analyzer-style PackageReference) to drive [Table]-based code generation. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated | |
|---|---|---|---|
| 1.0.0 | 159 | 7/3/2026 | |
| 0.1.0-preview.11 | 136 | 5/13/2026 |