diff --git a/CHANGELOG.md b/CHANGELOG.md index dc629d8..de48619 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,69 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +#### SurrealDB 3.0 — Config-Driven Engine Abstraction (`surrealdb-backend` feature) + +- **`SurrealEngineConfig`** tagged enum (`mem`, `surreal_kv`, `rocks_db`, `ws`) selects the + engine at runtime via `surrealdb::engine::any::connect(url)` URL dispatch — no recompilation + required to change backends. +- **`SurrealDbBackendConfig`** dual hot/cold layout: `graph` engine (default: SurrealKV B-tree) + for nodes/edges/metadata, `hot` engine (default: RocksDB LSM) for embeddings and session logs. +- **`SurrealDbStorage::from_config()`** constructor replaces ad-hoc field initialization; + `Surreal` unified type — no generics, no `Arc>`. +- All SurrealDB CRUD routes through `serde_json::Value` (`to_json` / `from_json` helpers) to + satisfy the `SurrealValue` trait bound without coupling domain models to the database library. +- `SurrealDbStorage::save_embedding()` and `log_session()` for hot-engine direct access. +- Removed `Database(#[from] surrealdb::Error)` variant from `KbError` — all SurrealDB errors + propagate as `KbError::Storage(e.to_string())`. +- `surrealdb-backend` Cargo feature activates `kv-surrealkv`, `kv-rocksdb`, `protocol-ws`, + `rustls` engine features on top of the workspace `kv-mem` base. + +#### Storage Factory (`storage::factory`) + +- **`storage::factory::build(config, base_path)`** — config-driven engine dispatch: SurrealDB + when `secondary.enabled`, `MemoryStorage` when `primary == memory`, `FilesystemStorage` + otherwise. Zero recompilation to switch backends. +- **`storage::factory::build_eventing(config, base_path, default_graph)`** — builds the base + backend then wraps it with `EventingStorage` when `config.nats` is `Some`; falls through to + `build` when NATS is not configured (`nats-events` feature required). +- **`impl Storage for Box`** — blanket delegation impl enabling + `EventingStorage>` without knowing the concrete backend type at compile time. + +#### NATS JetStream Event Publishing (`nats-events` feature) + +- **`KogralEvent`** typed enum (`NodeSaved`, `NodeDeleted`, `GraphSaved`) with computed NATS + subject (`kogral.{graph}.node.saved`, etc.) and `serde` JSON serialization. +- **`EventPublisher`** wraps `platform_nats::EventStream` and publishes `KogralEvent` as JSON + to JetStream after each mutation. +- **`EventingStorage`** decorator wraps any `Storage` implementation with automatic event + publishing after `save_graph`, `save_node`, and `delete_node` — inner backend unchanged. +- **`NatsEventConfig`** schema type with `From` conversion to `platform_nats::NatsConfig`. +- `nats-events` feature adds `platform-nats` and `bytes` workspace dependencies. + +#### Orchestration Integration (`orchestration` feature) + +- **`orchestration::pipeline_context_from_event(event, payload, state, schema_dir)`** bridges + `KogralEvent` to `stratum-orchestrator`'s `PipelineContext::new` for downstream pipeline + triggering. +- `orchestration` feature activates `stratum-orchestrator` and `stratum-state` workspace deps; + implies `nats-events`. + +#### Nickel Config Schema Updates + +- `secondary.surrealdb` sub-record replaces flat `url`/`namespace`/`database` fields: + `graph` and `hot` engine selectors with `engine`, `path`/`url` fields per engine type. +- `nats` top-level block in `StorageConfig` for optional JetStream configuration. +- `SurrealEngineValidator` contract and `SurrealEngineConfig` / `SurrealDbBackendConfig` / + `NatsEventConfig` type contracts added to `schemas/kogral/contracts.ncl`. +- `schemas/kogral/defaults.ncl` updated with dual-engine defaults and `nats` disabled block. + +#### Nickel Import Resolver + +- `config::nickel::resolve_nickel_imports(path)` runs `ncl-import-resolver` on + `resolver-manifest.json` (when present) before `nickel export`. No-op when manifest absent. + ### Changed #### BREAKING: MCP Protocol Rebranding diff --git a/Cargo.lock b/Cargo.lock index 70eeee7..c049314 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" - [[package]] name = "addr" version = "0.15.6" @@ -25,14 +19,17 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "affinitypool" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dde2a385b82232b559baeec740c37809051c596f9b56e7da0d0da2c8e8f54f6" +checksum = "7a58b64a64aecad4ba7f2ccf0f79115f5d2d184b1e55307f78c20be07adc6633" dependencies = [ - "async-channel", + "crossbeam", + "libc", "num_cpus", - "thiserror 1.0.69", + "parking_lot", + "thiserror 2.0.18", "tokio", + "winapi", ] [[package]] @@ -165,27 +162,12 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "any_ascii" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90c6333e01ba7235575b6ab53e5af10f1c327927fd97c36462917e289557ea64" - [[package]] name = "anyhow" version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" -[[package]] -name = "approx" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f2a05fd1bd10b2527e20a2cd32d8873d115b8b39fe219ee25f42a8aca6ba278" -dependencies = [ - "num-traits", -] - [[package]] name = "approx" version = "0.5.1" @@ -210,6 +192,15 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +[[package]] +name = "arc-swap" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f3647c145568cec02c42054e07bdf9a5a698e15b466fb2341bfc393cd24aa5" +dependencies = [ + "rustversion", +] + [[package]] name = "arg_enum_proc_macro" version = "0.3.4" @@ -239,6 +230,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + [[package]] name = "arrayvec" version = "0.7.6" @@ -274,9 +271,9 @@ dependencies = [ [[package]] name = "ascii-canvas" -version = "3.0.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +checksum = "ef1e3e699d84ab1b0911a1010c5c106aa34ae89aeac103be5ce0c3859db1e891" dependencies = [ "term", ] @@ -303,109 +300,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "async-executor" -version = "1.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "pin-project-lite", - "slab", -] - -[[package]] -name = "async-graphql" -version = "7.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b75e6d81f69e47038fb2f08c54dc9180fabef56856b7a74e4082157f2e5536" -dependencies = [ - "async-graphql-derive", - "async-graphql-parser", - "async-graphql-value", - "async-io", - "async-trait", - "asynk-strim", - "base64 0.22.1", - "bytes", - "fnv", - "futures-util", - "http", - "indexmap 2.13.0", - "mime", - "multer", - "num-traits", - "pin-project-lite", - "regex", - "serde", - "serde_json", - "serde_urlencoded", - "static_assertions_next", - "thiserror 2.0.18", -] - -[[package]] -name = "async-graphql-derive" -version = "7.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8587c1c72749f54250633a725203d537ebda851b68d85c2a8d18a3adc0bf72d6" -dependencies = [ - "Inflector", - "async-graphql-parser", - "darling 0.23.0", - "proc-macro-crate", - "proc-macro2", - "quote", - "strum", - "syn 2.0.114", - "thiserror 2.0.18", -] - -[[package]] -name = "async-graphql-parser" -version = "7.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "577ec8cb624048d11465439c2b25d28362cb08c154b530421f456debc7083fdf" -dependencies = [ - "async-graphql-value", - "pest", - "serde", - "serde_json", -] - -[[package]] -name = "async-graphql-value" -version = "7.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e747684314ff7454a1f3b6fe5341e15148b1f17f30c9f6ecc55832dd1f053c47" -dependencies = [ - "bytes", - "indexmap 2.13.0", - "serde", - "serde_json", -] - -[[package]] -name = "async-io" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" -dependencies = [ - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-io", - "futures-lite", - "parking", - "polling", - "rustix", - "slab", - "windows-sys 0.61.2", -] - [[package]] name = "async-lock" version = "3.4.2" @@ -417,6 +311,43 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "async-nats" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df5af9ebfb0a14481d3eaf6101e6391261e4f30d25b26a7635ade8a39482ded0" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-util", + "memchr", + "nkeys", + "nuid", + "once_cell", + "pin-project", + "portable-atomic", + "rand 0.8.5", + "regex", + "ring", + "rustls-native-certs 0.7.3", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "serde", + "serde_json", + "serde_nanos", + "serde_repr", + "thiserror 1.0.69", + "time", + "tokio", + "tokio-rustls", + "tokio-stream", + "tokio-util", + "tokio-websockets", + "tracing", + "tryhard", + "url", +] + [[package]] name = "async-stream" version = "0.3.6" @@ -439,12 +370,6 @@ dependencies = [ "syn 2.0.114", ] -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - [[package]] name = "async-trait" version = "0.1.89" @@ -456,27 +381,6 @@ dependencies = [ "syn 2.0.114", ] -[[package]] -name = "async_io_stream" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" -dependencies = [ - "futures", - "pharos", - "rustc_version", -] - -[[package]] -name = "asynk-strim" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52697735bdaac441a29391a9e97102c74c6ef0f9b60a40cf109b1b404e29d2f6" -dependencies = [ - "futures-core", - "pin-project-lite", -] - [[package]] name = "atomic-polyfill" version = "1.0.3" @@ -507,7 +411,7 @@ dependencies = [ "aligned", "anyhow", "arg_enum_proc_macro", - "arrayvec", + "arrayvec 0.7.6", "log", "num-rational", "num-traits", @@ -525,7 +429,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cfddb07216410377231960af4fcab838eaa12e013417781b78bd95ee22077f8" dependencies = [ "anyhow", - "arrayvec", + "arrayvec 0.7.6", "log", "nom 8.0.0", "num-rational", @@ -538,21 +442,96 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47c8fbc0f831f4519fe8b810b6a7a91410ec83031b8233f730a0480029f6a23f" dependencies = [ - "arrayvec", + "arrayvec 0.7.6", ] +[[package]] +name = "aws-lc-rs" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9a7b350e3bb1767102698302bc37256cbd48422809984b98d292c40e2579aa9" +dependencies = [ + "aws-lc-sys", + "untrusted 0.7.1", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.37.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b092fe214090261288111db7a2b2c2118e5a7f30dc2569f1732c4069a6840549" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] + +[[package]] +name = "axum" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" +dependencies = [ + "axum-core", + "bytes", + "form_urlencoded", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde_core", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.1" @@ -567,40 +546,69 @@ checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bcrypt" -version = "0.15.1" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e65938ed058ef47d92cf8b346cc76ef48984572ade631927e9937b5ffc7662c7" +checksum = "9a0f5948f30df5f43ac29d310b7476793be97c50787e6ef4a63d960a0d0be827" dependencies = [ "base64 0.22.1", "blowfish", - "getrandom 0.2.17", + "getrandom 0.3.4", "subtle", "zeroize", ] [[package]] name = "bincode" -version = "1.3.3" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740" dependencies = [ + "bincode_derive", "serde", + "unty", +] + +[[package]] +name = "bincode_derive" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09" +dependencies = [ + "virtue", +] + +[[package]] +name = "bindgen" +version = "0.72.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" +dependencies = [ + "bitflags 2.10.0", + "cexpr", + "clang-sys", + "itertools 0.11.0", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.114", ] [[package]] name = "bit-set" -version = "0.5.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ "bit-vec", ] [[package]] name = "bit-vec" -version = "0.6.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bit_field" @@ -657,7 +665,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2468ef7d57b3fb7e16b576e8377cdbde2320c60e1491e961d11da40fc4f02a2d" dependencies = [ "arrayref", - "arrayvec", + "arrayvec 0.7.6", "cc", "cfg-if", "constant_time_eq", @@ -683,6 +691,12 @@ dependencies = [ "cipher", ] +[[package]] +name = "bnum" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f781dba93de3a5ef6dc5b17c9958b208f6f3f021623b360fb605ea51ce443f10" + [[package]] name = "borsh" version = "1.6.0" @@ -706,6 +720,12 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "boxcar" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f64beae40a84da1b4b26ff2761a5b895c12adc41dc25aaee1c4f2bbfe97a6e" + [[package]] name = "bstr" version = "1.12.1" @@ -770,13 +790,23 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" dependencies = [ "serde", ] +[[package]] +name = "bzip2-sys" +version = "0.1.13+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" +dependencies = [ + "cc", + "pkg-config", +] + [[package]] name = "castaway" version = "0.2.4" @@ -800,59 +830,80 @@ dependencies = [ [[package]] name = "cedar-policy" -version = "2.4.2" +version = "4.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d91e3b10a0f7f2911774d5e49713c4d25753466f9e11d1cd2ec627f8a2dc857" +checksum = "c55625387d203085efb7dca8eb594188d586c99f97a83cf577d60bc588b1c705" dependencies = [ "cedar-policy-core", - "cedar-policy-validator", - "itertools 0.10.5", - "lalrpop-util", + "cedar-policy-formatter", + "itertools 0.14.0", + "linked-hash-map", + "miette", "ref-cast", + "semver", "serde", "serde_json", + "serde_with", "smol_str", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] name = "cedar-policy-core" -version = "2.4.2" +version = "4.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd2315591c6b7e18f8038f0a0529f254235fd902b6c217aabc04f2459b0d9995" +checksum = "c2ac16501266418b913a4ee73d1d14542d479c73baf7fccea2542996a2a82fe2" dependencies = [ + "chrono", + "educe", "either", - "ipnet", - "itertools 0.10.5", + "itertools 0.14.0", "lalrpop", "lalrpop-util", - "lazy_static", + "linked-hash-map", + "linked_hash_set", "miette", + "nonempty", + "ref-cast", "regex", - "rustc_lexer", + "rustc-literal-escaper", "serde", "serde_json", "serde_with", "smol_str", "stacker", - "thiserror 1.0.69", + "thiserror 2.0.18", + "unicode-security", ] [[package]] -name = "cedar-policy-validator" -version = "2.4.2" +name = "cedar-policy-formatter" +version = "4.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e756e1b2a5da742ed97e65199ad6d0893e9aa4bd6b34be1de9e70bd1e6adc7df" +checksum = "99f4b40c3d8a88264578fd9ef17b43ef35ec36e1283ae22930542dff8a6b80ae" dependencies = [ "cedar-policy-core", - "itertools 0.10.5", - "serde", - "serde_json", - "serde_with", + "itertools 0.14.0", + "logos", + "miette", + "pretty", + "regex", "smol_str", - "stacker", - "thiserror 1.0.69", - "unicode-security", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom 7.1.3", ] [[package]] @@ -878,7 +929,7 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -889,7 +940,7 @@ checksum = "93698b29de5e97ad0ae26447b344c482a7284c737d9ddc5f9e52b74a336671bb" dependencies = [ "chrono", "chrono-tz-build", - "phf", + "phf 0.11.3", ] [[package]] @@ -899,7 +950,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c088aee841df9c3041febbb73934cfc39708749bf96dc827e3359cd39ef11b1" dependencies = [ "parse-zoneinfo", - "phf", + "phf 0.11.3", "phf_codegen", ] @@ -940,6 +991,17 @@ dependencies = [ "inout", ] +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + [[package]] name = "clap" version = "4.5.54" @@ -980,6 +1042,15 @@ version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" +[[package]] +name = "cmake" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +dependencies = [ + "cc", +] + [[package]] name = "color_quant" version = "1.1.0" @@ -1001,6 +1072,16 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + [[package]] name = "compact_str" version = "0.9.0" @@ -1038,6 +1119,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "constant_time_eq" version = "0.4.2" @@ -1054,6 +1141,16 @@ dependencies = [ "libc", ] +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -1093,6 +1190,19 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" +[[package]] +name = "crossbeam" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + [[package]] name = "crossbeam-channel" version = "0.5.15" @@ -1121,6 +1231,25 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-skiplist" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df29de440c58ca2cc6e587ec3d22347551a32435fbde9d2bff64e78a9ffa151b" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" @@ -1133,6 +1262,18 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array 0.14.7", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.7" @@ -1152,7 +1293,7 @@ dependencies = [ "cssparser-macros", "dtoa-short", "itoa", - "phf", + "phf 0.11.3", "smallvec", ] @@ -1166,6 +1307,33 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "darling" version = "0.20.11" @@ -1186,16 +1354,6 @@ dependencies = [ "darling_macro 0.21.3", ] -[[package]] -name = "darling" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" -dependencies = [ - "darling_core 0.23.0", - "darling_macro 0.23.0", -] - [[package]] name = "darling_core" version = "0.20.11" @@ -1224,19 +1382,6 @@ dependencies = [ "syn 2.0.114", ] -[[package]] -name = "darling_core" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" -dependencies = [ - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.114", -] - [[package]] name = "darling_macro" version = "0.20.11" @@ -1259,17 +1404,6 @@ dependencies = [ "syn 2.0.114", ] -[[package]] -name = "darling_macro" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" -dependencies = [ - "darling_core 0.23.0", - "quote", - "syn 2.0.114", -] - [[package]] name = "dary_heap" version = "0.3.8" @@ -1279,19 +1413,6 @@ dependencies = [ "serde", ] -[[package]] -name = "dashmap" -version = "5.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" -dependencies = [ - "cfg-if", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", -] - [[package]] name = "dashmap" version = "6.1.0" @@ -1318,6 +1439,7 @@ version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ + "const-oid", "pem-rfc7468", "zeroize", ] @@ -1376,6 +1498,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", "subtle", ] @@ -1389,16 +1512,6 @@ dependencies = [ "dirs-sys", ] -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - [[package]] name = "dirs-sys" version = "0.5.0" @@ -1407,21 +1520,10 @@ checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ "libc", "option-ext", - "redox_users 0.5.2", + "redox_users", "windows-sys 0.61.2", ] -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users 0.4.6", - "winapi", -] - [[package]] name = "displaydoc" version = "0.2.5" @@ -1443,12 +1545,6 @@ dependencies = [ "urlencoding", ] -[[package]] -name = "double-ended-peekable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0d05e1c0dbad51b52c38bda7adceef61b9efc2baf04acfe8726a8c4630a6f57" - [[package]] name = "dtoa" version = "1.0.11" @@ -1464,6 +1560,12 @@ dependencies = [ "dtoa", ] +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "dyn-clone" version = "1.0.20" @@ -1480,12 +1582,84 @@ dependencies = [ "num-traits", ] +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "serde", + "sha2", + "signature", + "subtle", + "zeroize", +] + +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "either" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array 0.14.7", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "ena" version = "0.14.3" @@ -1512,9 +1686,29 @@ dependencies = [ [[package]] name = "endian-type" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" +checksum = "869b0adbda23651a9c5c0c3d270aac9fcb52e8622a8f2b17e57802d7791962f2" + +[[package]] +name = "enum-ordinalize" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] [[package]] name = "equator" @@ -1620,14 +1814,14 @@ dependencies = [ [[package]] name = "fastembed" -version = "5.8.1" +version = "5.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a3f841f27a44bcc32214f8df75cc9b6cea55dbbebbfe546735690eab5bb2d2" +checksum = "b4339d45a80579ab8305616a501eacdbf18fb0f7def7fa6e4c0b75941416d5b0" dependencies = [ "anyhow", "hf-hub", "image", - "ndarray 0.17.2", + "ndarray", "ort", "safetensors", "serde", @@ -1635,6 +1829,17 @@ dependencies = [ "tokenizers", ] +[[package]] +name = "fastnum" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4089ab2dfd45d8ddc92febb5ca80644389d5ebb954f40231274a3f18341762e2" +dependencies = [ + "bnum", + "num-integer", + "num-traits", +] + [[package]] name = "fastrand" version = "2.3.0" @@ -1670,6 +1875,22 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "find-msvc-tools" version = "0.1.8" @@ -1678,9 +1899,20 @@ checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db" [[package]] name = "fixedbitset" -version = "0.4.2" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "flatbuffers" +version = "25.12.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35f6839d7b3b98adde531effaf34f0c2badc6f4735d26fe74709d8e513a96ef3" +dependencies = [ + "bitflags 2.10.0", + "rustc_version", + "serde", +] [[package]] name = "flate2" @@ -1740,6 +1972,22 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "fsevent-sys" version = "4.1.0" @@ -1819,19 +2067,6 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" -[[package]] -name = "futures-lite" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] - [[package]] name = "futures-macro" version = "0.3.31" @@ -1914,6 +2149,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -1930,18 +2166,56 @@ dependencies = [ "num-traits", "robust", "rstar 0.12.2", + "spade", +] + +[[package]] +name = "geo" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc1a1678e54befc9b4bcab6cd43b8e7f834ae8ea121118b0fd8c42747675b4a" +dependencies = [ + "earcutr", + "float_next_after", + "geo-types", + "geographiclib-rs", + "i_overlay", + "log", + "num-traits", + "robust", + "rstar 0.12.2", "serde", "spade", ] +[[package]] +name = "geo" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f3901269ec6d4f6068d3f09e5f02f995bd076398dcd1dfec407cd230b02d11b" +dependencies = [ + "float_next_after", + "geo-types", + "geographiclib-rs", + "i_overlay", + "log", + "num-traits", + "rand 0.8.5", + "robust", + "rstar 0.12.2", + "serde", + "sif-itree", +] + [[package]] name = "geo-types" version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24f8647af4005fa11da47cd56252c6ef030be8fa97bdbf355e7dfb6348f0a82c" dependencies = [ - "approx 0.5.1", + "approx", "num-traits", + "rayon", "rstar 0.10.0", "rstar 0.11.0", "rstar 0.12.2", @@ -1995,6 +2269,19 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + [[package]] name = "gif" version = "0.14.1" @@ -2035,6 +2322,23 @@ dependencies = [ "walkdir", ] +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "guardian" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17e2ac29387b1aa07a1e448f7bb4f35b500787971e965b02842b900afa5c8f6f" + [[package]] name = "h2" version = "0.4.13" @@ -2106,10 +2410,6 @@ name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash 0.8.12", - "allocator-api2", -] [[package]] name = "hashbrown" @@ -2135,6 +2435,30 @@ dependencies = [ "serde_core", ] +[[package]] +name = "headers" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3314d5adb5d94bcdf56771f2e50dbbc80bb4bdf88967526706205ac9eff24eb" +dependencies = [ + "base64 0.22.1", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha1", +] + +[[package]] +name = "headers-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" +dependencies = [ + "http", +] + [[package]] name = "heapless" version = "0.6.1" @@ -2201,7 +2525,7 @@ dependencies = [ "log", "native-tls", "rand 0.9.2", - "reqwest", + "reqwest 0.12.28", "serde", "serde_json", "thiserror 2.0.18", @@ -2209,6 +2533,15 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + [[package]] name = "hmac" version = "0.12.1" @@ -2342,7 +2675,19 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots 1.0.5", +] + +[[package]] +name = "hyper-timeout" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" +dependencies = [ + "hyper", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", ] [[package]] @@ -2387,6 +2732,49 @@ dependencies = [ "windows-registry", ] +[[package]] +name = "i_float" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "010025c2c532c8d82e42d0b8bb5184afa449fa6f06c709ea9adcb16c49ae405b" +dependencies = [ + "libm", +] + +[[package]] +name = "i_key_sort" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9190f86706ca38ac8add223b2aed8b1330002b5cdbbce28fb58b10914d38fc27" + +[[package]] +name = "i_overlay" +version = "4.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413183068e6e0289e18d7d0a1f661b81546e6918d5453a44570b9ab30cbed1b3" +dependencies = [ + "i_float", + "i_key_sort", + "i_shape", + "i_tree", + "rayon", +] + +[[package]] +name = "i_shape" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ea154b742f7d43dae2897fcd5ead86bc7b5eefcedd305a7ebf9f69d44d61082" +dependencies = [ + "i_float", +] + +[[package]] +name = "i_tree" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e6d558e6d4c7b82bc51d9c771e7a927862a161a7d87bf2b0541450e0e20915" + [[package]] name = "iana-time-zone" version = "0.1.64" @@ -2492,6 +2880,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "ident_case" version = "1.0.1" @@ -2640,6 +3034,12 @@ dependencies = [ "generic-array 0.14.7", ] +[[package]] +name = "integer-encoding" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c00403deb17c3221a1fe4fb571b9ed0370b3dcd116553c77fa294a3d918699" + [[package]] name = "interpolate_name" version = "0.2.4" @@ -2675,18 +3075,18 @@ checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itertools" -version = "0.10.5" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ "either", ] [[package]] name = "itertools" -version = "0.11.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] @@ -2706,6 +3106,28 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + [[package]] name = "jobserver" version = "0.1.34" @@ -2728,19 +3150,37 @@ dependencies = [ [[package]] name = "jsonwebtoken" -version = "9.3.1" +version = "10.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" +checksum = "0529410abe238729a60b108898784df8984c87f6054c9c4fcacc47e4803c1ce1" dependencies = [ + "aws-lc-rs", "base64 0.22.1", + "ed25519-dalek", + "getrandom 0.2.17", + "hmac", "js-sys", + "p256", + "p384", "pem", - "ring", + "rand 0.8.5", + "rsa", "serde", "serde_json", + "sha2", + "signature", "simple_asn1", ] +[[package]] +name = "keccak" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" +dependencies = [ + "cpufeatures", +] + [[package]] name = "kogral-cli" version = "0.1.0" @@ -2763,12 +3203,14 @@ version = "0.1.0" dependencies = [ "anyhow", "async-trait", + "bytes", "chrono", - "dashmap 6.1.0", + "dashmap", "futures", "mockito", "notify", "once_cell", + "platform-nats", "pulldown-cmark", "regex", "rig-core", @@ -2776,6 +3218,8 @@ dependencies = [ "serde_json", "serde_yaml", "stratum-embeddings", + "stratum-orchestrator", + "stratum-state", "surrealdb", "tempfile", "tera", @@ -2824,33 +3268,34 @@ dependencies = [ [[package]] name = "lalrpop" -version = "0.20.2" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" +checksum = "ba4ebbd48ce411c1d10fb35185f5a51a7bfa3d8b24b4e330d30c9e3a34129501" dependencies = [ "ascii-canvas", "bit-set", "ena", - "itertools 0.11.0", + "itertools 0.14.0", "lalrpop-util", "petgraph", "pico-args", "regex", "regex-syntax", + "sha3", "string_cache", "term", - "tiny-keccak", "unicode-xid", "walkdir", ] [[package]] name = "lalrpop-util" -version = "0.20.2" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" +checksum = "b5baa5e9ff84f1aefd264e6869907646538a52147a755d494517a8007fb48733" dependencies = [ "regex-automata", + "rustversion", ] [[package]] @@ -2858,6 +3303,15 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "lebe" @@ -2867,11 +3321,11 @@ checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" [[package]] name = "lexicmp" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7378d131ddf24063b32cbd7e91668d183140c4b3906270635a4d633d1068ea5d" +checksum = "0e8f89da8fd95c4eb6274e914694bea90c7826523b26f2a2fd863d44b9d42c43" dependencies = [ - "any_ascii", + "deunicode", ] [[package]] @@ -2890,6 +3344,16 @@ dependencies = [ "cc", ] +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link 0.2.1", +] + [[package]] name = "libm" version = "0.2.15" @@ -2907,15 +3371,32 @@ dependencies = [ ] [[package]] -name = "linfa-linalg" -version = "0.1.0" +name = "libz-sys" +version = "1.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e7562b41c8876d3367897067013bb2884cc78e6893f092ecd26b305176ac82" +checksum = "15d118bbf3771060e7311cc7bb0545b01d08a8b4a7de949198dec1fa0ca1c0f7" dependencies = [ - "ndarray 0.15.6", - "num-traits", - "rand 0.8.5", - "thiserror 1.0.69", + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +dependencies = [ + "serde", +] + +[[package]] +name = "linked_hash_set" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "984fb35d06508d1e69fc91050cceba9c0b748f983e6739fa2c7a9237154c52c8" +dependencies = [ + "linked-hash-map", ] [[package]] @@ -2945,6 +3426,38 @@ version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +[[package]] +name = "logos" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2c55a318a87600ea870ff8c2012148b44bf18b74fad48d0f835c38c7d07c5f" +dependencies = [ + "logos-derive", +] + +[[package]] +name = "logos-codegen" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58b3ffaa284e1350d017a57d04ada118c4583cf260c8fb01e0fe28a2e9cf8970" +dependencies = [ + "fnv", + "proc-macro2", + "quote", + "regex-automata", + "regex-syntax", + "syn 2.0.114", +] + +[[package]] +name = "logos-derive" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52d3a9855747c17eaf4383823f135220716ab49bea5fbea7dd42cc9a92f8aa31" +dependencies = [ + "logos-codegen", +] + [[package]] name = "loop9" version = "0.1.5" @@ -2954,21 +3467,40 @@ dependencies = [ "imgref", ] -[[package]] -name = "lru" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" -dependencies = [ - "hashbrown 0.15.5", -] - [[package]] name = "lru-slab" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +[[package]] +name = "lz4" +version = "1.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a20b523e860d03443e98350ceaac5e71c6ba89aea7d960769ec3ce37f4de5af4" +dependencies = [ + "lz4-sys", +] + +[[package]] +name = "lz4-sys" +version = "1.11.1+lz4-1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bd8c0d6c6ed0cd30b3652886bb8711dc4bb01d637a68105a3d5158039b418e6" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "lz4_flex" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab6473172471198271ff72e9379150e9dfd70d8e533e0752a27e515b48dd375e" +dependencies = [ + "twox-hash", +] + [[package]] name = "lzma-rust2" version = "0.15.7" @@ -3034,6 +3566,12 @@ dependencies = [ "regex-automata", ] +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + [[package]] name = "matrixmultiply" version = "0.3.10" @@ -3072,21 +3610,21 @@ checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "miette" -version = "5.10.0" +version = "7.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e" +checksum = "5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" dependencies = [ + "cfg-if", "miette-derive", - "once_cell", - "thiserror 1.0.69", + "serde", "unicode-width 0.1.14", ] [[package]] name = "miette-derive" -version = "5.10.0" +version = "7.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" +checksum = "db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" dependencies = [ "proc-macro2", "quote", @@ -3214,23 +3752,6 @@ dependencies = [ "pxfm", ] -[[package]] -name = "multer" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" -dependencies = [ - "bytes", - "encoding_rs", - "futures-util", - "http", - "httparse", - "memchr", - "mime", - "spin", - "version_check", -] - [[package]] name = "nanoid" version = "0.4.0" @@ -3249,28 +3770,14 @@ dependencies = [ "libc", "log", "openssl", - "openssl-probe", + "openssl-probe 0.1.6", "openssl-sys", "schannel", - "security-framework", + "security-framework 2.11.1", "security-framework-sys", "tempfile", ] -[[package]] -name = "ndarray" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb12d4e967ec485a5f71c6311fe28158e9d6f4bc4a447b474184d0f91a8fa32" -dependencies = [ - "approx 0.4.0", - "matrixmultiply", - "num-complex", - "num-integer", - "num-traits", - "rawpointer", -] - [[package]] name = "ndarray" version = "0.17.2" @@ -3288,13 +3795,13 @@ dependencies = [ [[package]] name = "ndarray-stats" -version = "0.5.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af5a8477ac96877b5bd1fd67e0c28736c12943aba24eda92b127e036b0c8f400" +checksum = "9b6e54a8b65764f71827a90ca1d56965ec0c67f069f996477bd493402a901d1f" dependencies = [ - "indexmap 1.9.3", - "itertools 0.10.5", - "ndarray 0.15.6", + "indexmap 2.13.0", + "itertools 0.13.0", + "ndarray", "noisy_float", "num-integer", "num-traits", @@ -3316,6 +3823,21 @@ dependencies = [ "smallvec", ] +[[package]] +name = "nkeys" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879011babc47a1c7fdf5a935ae3cfe94f34645ca0cac1c7f6424b36fc743d1bf" +dependencies = [ + "data-encoding", + "ed25519", + "ed25519-dalek", + "getrandom 0.2.17", + "log", + "rand 0.8.5", + "signatory", +] + [[package]] name = "noisy_float" version = "0.2.1" @@ -3344,6 +3866,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "nonempty" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9737e026353e5cd0736f98eddae28665118eb6f6600902a7f50db585621fecb6" +dependencies = [ + "serde", +] + [[package]] name = "noop_proc_macro" version = "0.3.0" @@ -3392,6 +3923,15 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "nuid" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc895af95856f929163a0aa20c26a78d26bfdc839f51b9d5aa7a5b79e52b7e83" +dependencies = [ + "rand 0.8.5", +] + [[package]] name = "num-bigint" version = "0.4.6" @@ -3402,6 +3942,22 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-bigint-dig" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" +dependencies = [ + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "smallvec", + "zeroize", +] + [[package]] name = "num-complex" version = "0.4.6" @@ -3437,6 +3993,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-rational" version = "0.4.2" @@ -3474,6 +4041,25 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.10.0", +] + +[[package]] +name = "objc2-io-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15" +dependencies = [ + "libc", + "objc2-core-foundation", +] + [[package]] name = "object" version = "0.32.2" @@ -3485,9 +4071,9 @@ dependencies = [ [[package]] name = "object_store" -version = "0.12.4" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c1be0c6c22ec0817cdc77d3842f721a17fd30ab6965001415b5402a74e6b740" +checksum = "c2858065e55c148d294a9f3aae3b0fa9458edadb41a108397094566f4e3c0dfb" dependencies = [ "async-trait", "bytes", @@ -3573,6 +4159,12 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + [[package]] name = "openssl-sys" version = "0.9.111" @@ -3606,7 +4198,7 @@ version = "2.0.0-rc.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5df903c0d2c07b56950f1058104ab0c8557159f2741782223704de9be73c3c" dependencies = [ - "ndarray 0.17.2", + "ndarray", "ort-sys", "smallvec", "tracing", @@ -3624,6 +4216,40 @@ dependencies = [ "ureq 3.1.4", ] +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p384" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "papaya" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f92dd0b07c53a0a0c764db2ace8c541dc47320dad97c2200c2a637ab9dd2328f" +dependencies = [ + "equivalent", + "seize", +] + [[package]] name = "parking" version = "2.2.1" @@ -3650,7 +4276,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-link", + "windows-link 0.2.1", ] [[package]] @@ -3779,32 +4405,33 @@ dependencies = [ [[package]] name = "petgraph" -version = "0.6.5" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" dependencies = [ "fixedbitset", "indexmap 2.13.0", ] -[[package]] -name = "pharos" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" -dependencies = [ - "futures", - "rustc_version", -] - [[package]] name = "phf" version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ - "phf_macros", - "phf_shared", + "phf_macros 0.11.3", + "phf_shared 0.11.3", +] + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_macros 0.13.1", + "phf_shared 0.13.1", + "serde", ] [[package]] @@ -3813,8 +4440,8 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" dependencies = [ - "phf_generator", - "phf_shared", + "phf_generator 0.11.3", + "phf_shared 0.11.3", ] [[package]] @@ -3823,18 +4450,41 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ - "phf_shared", + "phf_shared 0.11.3", "rand 0.8.5", ] +[[package]] +name = "phf_generator" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" +dependencies = [ + "fastrand", + "phf_shared 0.13.1", +] + [[package]] name = "phf_macros" version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" dependencies = [ - "phf_generator", - "phf_shared", + "phf_generator 0.11.3", + "phf_shared 0.11.3", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "phf_macros" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" +dependencies = [ + "phf_generator 0.13.1", + "phf_shared 0.13.1", "proc-macro2", "quote", "syn 2.0.114", @@ -3846,6 +4496,15 @@ name = "phf_shared" version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" dependencies = [ "siphasher", "unicase", @@ -3889,12 +4548,49 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "platform-nats" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-nats", + "bytes", + "futures", + "nkeys", + "serde", + "serde_json", + "thiserror 2.0.18", + "tokio", + "tracing", +] + [[package]] name = "png" version = "0.18.0" @@ -3908,20 +4604,6 @@ dependencies = [ "miniz_oxide", ] -[[package]] -name = "polling" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" -dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi", - "pin-project-lite", - "rustix", - "windows-sys 0.61.2", -] - [[package]] name = "portable-atomic" version = "1.13.0" @@ -3967,6 +4649,36 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "pretty" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d22152487193190344590e4f30e219cf3fe140d9e7a3fdb683d82aa2c5f4156" +dependencies = [ + "arrayvec 0.5.2", + "typed-arena", + "unicode-width 0.2.2", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.114", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro-crate" version = "3.4.0" @@ -4004,6 +4716,38 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "prost" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" +dependencies = [ + "anyhow", + "itertools 0.14.0", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "prost-types" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8991c4cbdb8bc5b11f0b074ffe286c30e523de90fee5ba8132f1399f23cb3dd7" +dependencies = [ + "prost", +] + [[package]] name = "psl-types" version = "2.0.11" @@ -4083,18 +4827,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" -[[package]] -name = "quick_cache" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb55a1aa7668676bb93926cd4e9cdfe60f03bb866553bcca9112554911b6d3dc" -dependencies = [ - "ahash 0.8.12", - "equivalent", - "hashbrown 0.14.5", - "parking_lot", -] - [[package]] name = "quick_cache" version = "0.6.18" @@ -4133,6 +4865,7 @@ version = "0.11.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" dependencies = [ + "aws-lc-rs", "bytes", "getrandom 0.3.4", "lru-slab", @@ -4185,9 +4918,9 @@ checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "radix_trie" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +checksum = "3b4431027dcd37fc2a73ef740b5f233aa805897935b8bce0195e41bbf9a3289a" dependencies = [ "endian-type", "nibble_vec", @@ -4262,7 +4995,7 @@ dependencies = [ "aligned-vec", "arbitrary", "arg_enum_proc_macro", - "arrayvec", + "arrayvec 0.7.6", "av-scenechange", "av1-grain", "bitstream-io", @@ -4355,17 +5088,6 @@ dependencies = [ "bitflags 2.10.0", ] -[[package]] -name = "redox_users" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" -dependencies = [ - "getrandom 0.2.17", - "libredox", - "thiserror 1.0.69", -] - [[package]] name = "redox_users" version = "0.5.2" @@ -4426,6 +5148,12 @@ version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +[[package]] +name = "relative-path" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" + [[package]] name = "rend" version = "0.4.2" @@ -4461,8 +5189,6 @@ dependencies = [ "native-tls", "percent-encoding", "pin-project-lite", - "quinn", - "rustls", "rustls-pki-types", "serde", "serde_json", @@ -4470,6 +5196,49 @@ dependencies = [ "sync_wrapper", "tokio", "tokio-native-tls", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams 0.4.2", + "web-sys", +] + +[[package]] +name = "reqwest" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "mime", + "mime_guess", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier", + "serde", + "serde_json", + "sync_wrapper", + "tokio", "tokio-rustls", "tokio-util", "tower", @@ -4478,30 +5247,21 @@ dependencies = [ "url", "wasm-bindgen", "wasm-bindgen-futures", - "wasm-streams", + "wasm-streams 0.5.0", "web-sys", - "webpki-roots 1.0.5", ] [[package]] name = "revision" -version = "0.10.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22f53179a035f881adad8c4d58a2c599c6b4a8325b989c68d178d7a34d1b1e4c" -dependencies = [ - "revision-derive 0.10.0", -] - -[[package]] -name = "revision" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b8ee532f15b2f0811eb1a50adf10d036e14a6cdae8d99893e7f3b921cb227d" +checksum = "11c3c8ec8b2be254beb5f8acdd80cdd57b7b5d40988c2ec3d0b7cdb6f7c2829b" dependencies = [ + "bytes", "chrono", - "geo", + "geo 0.31.0", "regex", - "revision-derive 0.11.0", + "revision-derive", "roaring", "rust_decimal", "uuid", @@ -4509,9 +5269,9 @@ dependencies = [ [[package]] name = "revision-derive" -version = "0.10.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0ec466e5d8dca9965eb6871879677bef5590cf7525ad96cae14376efb75073" +checksum = "76be63634a8b1809e663bc0b975d78f6883c0fadbcce9c52e19b9e421f423357" dependencies = [ "proc-macro2", "quote", @@ -4519,14 +5279,13 @@ dependencies = [ ] [[package]] -name = "revision-derive" -version = "0.11.0" +name = "rfc6979" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3415e1bc838c36f9a0a2ac60c0fa0851c72297685e66592c44870d82834dfa2" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", + "hmac", + "subtle", ] [[package]] @@ -4556,7 +5315,7 @@ dependencies = [ "nanoid", "ordered-float", "pin-project-lite", - "reqwest", + "reqwest 0.12.28", "schemars 1.2.0", "serde", "serde_json", @@ -4577,7 +5336,7 @@ dependencies = [ "cfg-if", "getrandom 0.2.17", "libc", - "untrusted", + "untrusted 0.9.0", "windows-sys 0.52.0", ] @@ -4629,20 +5388,11 @@ dependencies = [ "serde", ] -[[package]] -name = "rmpv" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a4e1d4b9b938a26d2996af33229f0ca0956c652c1375067f0b45291c1df8417" -dependencies = [ - "rmp", -] - [[package]] name = "roaring" -version = "0.10.12" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e8d2cfa184d94d0726d650a9f4a1be7f9b76ac9fdb954219878dc00c1c1e7b" +checksum = "8ba9ce64a8f45d7fc86358410bb1a82e8c987504c0d4900e9141d69a9f26c885" dependencies = [ "bytemuck", "byteorder", @@ -4655,6 +5405,26 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e27ee8bb91ca0adcf0ecb116293afa12d393f9c2b9b9cd54d33e8078fe19839" +[[package]] +name = "rsa" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "rstar" version = "0.8.4" @@ -4716,6 +5486,35 @@ dependencies = [ "smallvec", ] +[[package]] +name = "rstest" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5a3193c063baaa2a95a33f03035c8a72b83d97a54916055ba22d35ed3839d49" +dependencies = [ + "futures-timer", + "futures-util", + "rstest_macros", +] + +[[package]] +name = "rstest_macros" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c845311f0ff7951c5506121a9ad75aec44d083c31583b2ea5a30bcb0b0abba0" +dependencies = [ + "cfg-if", + "glob", + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "relative-path", + "rustc_version", + "syn 2.0.114", + "unicode-ident", +] + [[package]] name = "rust-stemmers" version = "1.2.0" @@ -4732,7 +5531,7 @@ version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61f703d19852dbf87cbc513643fa81428361eb6940f1ac14fd58155d295a3eb0" dependencies = [ - "arrayvec", + "arrayvec 0.7.6", "borsh", "bytes", "num-traits", @@ -4749,13 +5548,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] -name = "rustc_lexer" -version = "0.1.0" +name = "rustc-literal-escaper" +version = "0.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c86aae0c77166108c01305ee1a36a1e77289d7dc6ca0a3cd91ff4992de2d16a5" -dependencies = [ - "unicode-xid", -] +checksum = "8be87abb9e40db7466e0681dc8ecd9dcfd40360cb10b4c8fe24a7c4c3669b198" [[package]] name = "rustc_version" @@ -4785,15 +5581,50 @@ version = "0.23.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" dependencies = [ + "aws-lc-rs", "log", "once_cell", "ring", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.103.9", "subtle", "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +dependencies = [ + "openssl-probe 0.1.6", + "rustls-pemfile", + "rustls-pki-types", + "schannel", + "security-framework 2.11.1", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe 0.2.1", + "rustls-pki-types", + "schannel", + "security-framework 3.5.1", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "rustls-pki-types" version = "1.14.0" @@ -4804,15 +5635,53 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-platform-verifier" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" +dependencies = [ + "core-foundation 0.10.1", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs 0.8.3", + "rustls-platform-verifier-android", + "rustls-webpki 0.103.9", + "security-framework 3.5.1", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "rustls-pki-types", + "untrusted 0.9.0", +] + [[package]] name = "rustls-webpki" version = "0.103.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" dependencies = [ + "aws-lc-rs", "ring", "rustls-pki-types", - "untrusted", + "untrusted 0.9.0", ] [[package]] @@ -4926,6 +5795,20 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array 0.14.7", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "security-framework" version = "2.11.1" @@ -4933,7 +5816,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ "bitflags 2.10.0", - "core-foundation", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" +dependencies = [ + "bitflags 2.10.0", + "core-foundation 0.10.1", "core-foundation-sys", "libc", "security-framework-sys", @@ -4949,6 +5845,16 @@ dependencies = [ "libc", ] +[[package]] +name = "seize" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b55fb86dfd3a2f5f76ea78310a88f96c4ea21a3031f8d212443d56123fd0521" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + [[package]] name = "semver" version = "1.0.27" @@ -4959,12 +5865,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "send_wrapper" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" - [[package]] name = "serde" version = "1.0.228" @@ -4975,15 +5875,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde-content" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3753ca04f350fa92d00b6146a3555e63c55388c9ef2e11e09bce2ff1c0b509c6" -dependencies = [ - "serde", -] - [[package]] name = "serde_core" version = "1.0.228" @@ -5029,6 +5920,37 @@ dependencies = [ "zmij", ] +[[package]] +name = "serde_nanos" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a93142f0367a4cc53ae0fead1bcda39e85beccfad3dcd717656cacab94b12985" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + [[package]] name = "serde_spanned" version = "1.0.4" @@ -5116,6 +6038,16 @@ dependencies = [ "digest", ] +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -5131,6 +6063,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "sif-itree" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7f45b8998ced5134fb1d75732c77842a3e888f19c1ff98481822e8fbfbf930b" + [[package]] name = "signal-hook-registry" version = "1.4.8" @@ -5141,6 +6079,28 @@ dependencies = [ "libc", ] +[[package]] +name = "signatory" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1e303f8205714074f6068773f0e29527e0453937fe837c9717d066635b65f31" +dependencies = [ + "pkcs8", + "rand_core 0.6.4", + "signature", + "zeroize", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + [[package]] name = "simd-adler32" version = "0.3.8" @@ -5207,14 +6167,18 @@ name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] [[package]] name = "smol_str" -version = "0.2.2" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +checksum = "0f7a918bd2a9951d18ee6e48f076843e8e73a9a5d22cf05bcd4b7a81bdd04e17" dependencies = [ - "serde", + "borsh", + "serde_core", ] [[package]] @@ -5265,6 +6229,16 @@ dependencies = [ "lock_api", ] +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "spm_precompiled" version = "0.1.4" @@ -5303,21 +6277,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] -name = "static_assertions_next" -version = "1.1.2" +name = "storekey" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7beae5182595e9a8b683fa98c4317f956c9a2dec3b9716990d20023cc60c766" +checksum = "bd9a94571bde7369ecaac47cec2e6844642d99166bd452fbd8def74b5b917b2f" +dependencies = [ + "bytes", + "storekey-derive", + "uuid", +] [[package]] -name = "storekey" -version = "0.5.0" +name = "storekey-derive" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43c42833834a5d23b344f71d87114e0cc9994766a5c42938f4b50e7b2aef85b2" +checksum = "6079d53242246522ec982de613c5c952cc7b1380ef2f8622fcdab9bfe73c0098" dependencies = [ - "byteorder", - "memchr", - "serde", - "thiserror 1.0.69", + "proc-macro2", + "quote", + "syn 2.0.114", ] [[package]] @@ -5338,6 +6316,65 @@ dependencies = [ "xxhash-rust", ] +[[package]] +name = "stratum-graph" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "serde", + "serde_json", + "thiserror 2.0.18", + "tokio", + "tracing", + "uuid", +] + +[[package]] +name = "stratum-orchestrator" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "axum", + "bytes", + "cedar-policy", + "chrono", + "dashmap", + "notify", + "platform-nats", + "regex", + "reqwest 0.13.2", + "serde", + "serde_json", + "stratum-graph", + "stratum-state", + "thiserror 2.0.18", + "tokio", + "tokio-util", + "tower-http", + "tracing", + "tracing-subscriber", + "uuid", +] + +[[package]] +name = "stratum-state" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "chrono", + "serde", + "serde_json", + "stratum-graph", + "surrealdb", + "thiserror 2.0.18", + "tokio", + "tracing", + "uuid", +] + [[package]] name = "string_cache" version = "0.8.9" @@ -5346,7 +6383,7 @@ checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" dependencies = [ "new_debug_unreachable", "parking_lot", - "phf_shared", + "phf_shared 0.11.3", "precomputed-hash", "serde", ] @@ -5357,8 +6394,8 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" dependencies = [ - "phf_generator", - "phf_shared", + "phf_generator 0.11.3", + "phf_shared 0.11.3", "proc-macro2", "quote", ] @@ -5369,27 +6406,6 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" -[[package]] -name = "strum" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.114", -] - [[package]] name = "subtle" version = "2.6.1" @@ -5398,156 +6414,266 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "surrealdb" -version = "2.6.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b7720b39ce2985efbfa10858b7397ffd95655a9bab6d9dfaa03622bbdc3bc2" +checksum = "2150ced737a7dd6b1ba97b9c3579282c9a18263f88a73700103de0e32f442666" dependencies = [ - "arrayvec", + "anyhow", "async-channel", - "bincode", + "boxcar", "chrono", - "dmp", "futures", - "geo", "getrandom 0.3.4", "indexmap 2.13.0", + "js-sys", "path-clean", - "pharos", - "reblessive", - "reqwest", - "revision 0.11.0", + "reqwest 0.13.2", "ring", - "rust_decimal", "rustls", "rustls-pki-types", "semver", "serde", - "serde-content", "serde_json", "surrealdb-core", - "thiserror 1.0.69", + "surrealdb-types", "tokio", "tokio-tungstenite", + "tokio-tungstenite-wasm", "tokio-util", "tracing", - "trice", "url", "uuid", + "wasm-bindgen", "wasm-bindgen-futures", "wasmtimer", - "ws_stream_wasm", + "web-sys", ] [[package]] name = "surrealdb-core" -version = "2.6.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c48e42c81713be2f9b3dae64328999eafe8b8060dd584059445a908748b39787" +checksum = "225816a998dff5f898b72925494487877dd42fdef9985799433801e5ea8113c8" dependencies = [ "addr", "affinitypool", "ahash 0.8.12", "ammonia", - "any_ascii", + "anyhow", "argon2", "async-channel", - "async-executor", - "async-graphql", - "base64 0.21.7", + "async-stream", + "async-trait", + "base64 0.22.1", "bcrypt", - "bincode", "blake3", "bytes", - "castaway", - "cedar-policy", "chrono", "ciborium", - "dashmap 5.5.3", + "dashmap", "deunicode", "dmp", "ext-sort", + "fastnum", "fst", "futures", "fuzzy-matcher", - "geo", + "geo 0.32.0", "geo-types", "getrandom 0.3.4", - "hashbrown 0.14.5", + "headers", "hex", "http", + "humantime", "ipnet", "jsonwebtoken", "lexicmp", - "linfa-linalg", "md-5", - "nanoid", - "ndarray 0.15.6", + "mime", + "ndarray", "ndarray-stats", "num-traits", "num_cpus", "object_store", "parking_lot", + "path-clean", "pbkdf2", - "pharos", - "phf", + "phf 0.13.1", "pin-project-lite", - "quick_cache 0.5.2", + "quick_cache", "radix_trie", "rand 0.8.5", "rayon", "reblessive", "regex", - "revision 0.11.0", + "revision", "ring", - "rmpv", "roaring", "rust-stemmers", "rust_decimal", "scrypt", "semver", "serde", - "serde-content", "serde_json", "sha1", "sha2", - "snap", "storekey", "strsim", "subtle", + "surrealdb-protocol", + "surrealdb-rocksdb", + "surrealdb-types", "surrealkv", + "surrealmx", "sysinfo", "tempfile", - "thiserror 1.0.69", + "thiserror 2.0.18", "tokio", + "tokio-util", "tracing", "trice", "ulid", "unicase", "url", "uuid", - "vart 0.8.1", + "vart", "wasm-bindgen-futures", "wasmtimer", - "ws_stream_wasm", +] + +[[package]] +name = "surrealdb-librocksdb-sys" +version = "0.17.3+10.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db194f1cf601bb6f2d0f4cbf0931bc3e5a602bac41ef2e9a87eccdfb28b7fed2" +dependencies = [ + "bindgen", + "bzip2-sys", + "cc", + "libc", + "libz-sys", + "lz4-sys", + "zstd-sys", +] + +[[package]] +name = "surrealdb-protocol" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb37698e0493bcfac3229ecb6ec6894a3ad705a3a2087b1562eeb881b3db19d4" +dependencies = [ + "anyhow", + "async-trait", + "bytes", + "chrono", + "flatbuffers", + "futures", + "geo 0.28.0", + "prost", + "prost-types", + "rust_decimal", + "semver", + "serde", + "serde_json", + "tonic", + "tonic-prost", + "uuid", +] + +[[package]] +name = "surrealdb-rocksdb" +version = "0.24.0-surreal.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "057727f56d48825ddbe45e4e7401cda6e99d864fbc004e7474b4689a5e72c86d" +dependencies = [ + "libc", + "surrealdb-librocksdb-sys", +] + +[[package]] +name = "surrealdb-types" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72231b6b94c1dbd6e2453c50266c679eb621701cd01cb8f8fc32923d3ce0a217" +dependencies = [ + "anyhow", + "bytes", + "chrono", + "flatbuffers", + "geo 0.32.0", + "hex", + "http", + "papaya", + "rand 0.8.5", + "regex", + "rstest", + "rust_decimal", + "serde", + "serde_json", + "surrealdb-protocol", + "surrealdb-types-derive", + "ulid", + "uuid", +] + +[[package]] +name = "surrealdb-types-derive" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef7818b988bb8a8d424751ba5c0fe6aabf3e41dc26fbc8a922803c1615ae641b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", ] [[package]] name = "surrealkv" -version = "0.9.3" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08a5041979bdff8599a1d5f6cb7365acb9a79664e2a84e5c4fddac2b3969f7d1" +checksum = "a6c1dd97851edc773c24afb282d6a17eb1bc798fafac53ea0d2951458854d472" dependencies = [ - "ahash 0.8.12", + "arc-swap", + "async-trait", + "byteorder", "bytes", "chrono", "crc32fast", - "double-ended-peekable", - "getrandom 0.2.17", - "lru", + "crossbeam-skiplist", + "fs2", + "getrandom 0.3.4", + "guardian", + "integer-encoding", + "log", + "lz4_flex", "parking_lot", - "quick_cache 0.6.18", - "revision 0.10.0", - "vart 0.9.3", + "quick_cache", + "rand 0.9.2", + "scopeguard", + "sha2", + "snap", + "tokio", +] + +[[package]] +name = "surrealmx" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703077c9f8bdce4053dce39c5f5ef71b79b8fffe1e59dbd629b455340586814e" +dependencies = [ + "arc-swap", + "bincode", + "bytes", + "crossbeam-deque", + "crossbeam-queue", + "crossbeam-skiplist", + "lz4", + "papaya", + "parking_lot", + "serde", + "smallvec", + "thiserror 2.0.18", + "tracing", ] [[package]] @@ -5594,15 +6720,15 @@ dependencies = [ [[package]] name = "sysinfo" -version = "0.33.1" +version = "0.37.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fc858248ea01b66f19d8e8a6d55f41deaf91e9d495246fd01368d99935c6c01" +checksum = "16607d5caffd1c07ce073528f9ed972d88db15dd44023fa57142963be3feb11f" dependencies = [ - "core-foundation-sys", "libc", "memchr", "ntapi", - "rayon", + "objc2-core-foundation", + "objc2-io-kit", "windows", ] @@ -5613,7 +6739,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ "bitflags 2.10.0", - "core-foundation", + "core-foundation 0.9.4", "system-configuration-sys", ] @@ -5687,13 +6813,11 @@ dependencies = [ [[package]] name = "term" -version = "0.7.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +checksum = "d8c27177b12a6399ffc08b98f76f7c9a1f4fe9fc967c784c5a071fa8d93cf7e1" dependencies = [ - "dirs-next", - "rustversion", - "winapi", + "windows-sys 0.61.2", ] [[package]] @@ -5790,15 +6914,6 @@ dependencies = [ "time-core", ] -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - [[package]] name = "tinystr" version = "0.8.2" @@ -5906,10 +7021,21 @@ dependencies = [ ] [[package]] -name = "tokio-tungstenite" -version = "0.23.1" +name = "tokio-stream" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6989540ced10490aaf14e6bad2e3d33728a2813310a0c71d1574304c49631cd" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" dependencies = [ "futures-util", "log", @@ -5921,6 +7047,25 @@ dependencies = [ "webpki-roots 0.26.11", ] +[[package]] +name = "tokio-tungstenite-wasm" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee909c02b8863f9bda87253127eb4da0e7e1342330b2583fbc4d1795c2f8" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "httparse", + "js-sys", + "thiserror 2.0.18", + "tokio", + "tokio-tungstenite", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "tokio-util" version = "0.7.18" @@ -5931,10 +7076,32 @@ dependencies = [ "futures-core", "futures-io", "futures-sink", + "futures-util", "pin-project-lite", "tokio", ] +[[package]] +name = "tokio-websockets" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f591660438b3038dd04d16c938271c79e7e06260ad2ea2885a4861bfb238605d" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-sink", + "http", + "httparse", + "rand 0.8.5", + "ring", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tokio-util", + "webpki-roots 0.26.11", +] + [[package]] name = "toml" version = "0.9.11+spec-1.1.0" @@ -5986,6 +7153,46 @@ version = "1.0.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" +[[package]] +name = "tonic" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fec7c61a0695dc1887c1b53952990f3ad2e3a31453e1f49f10e75424943a93ec" +dependencies = [ + "async-trait", + "axum", + "base64 0.22.1", + "bytes", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-timeout", + "hyper-util", + "percent-encoding", + "pin-project", + "socket2", + "sync_wrapper", + "tokio", + "tokio-stream", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tonic-prost" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a55376a0bbaa4975a3f10d009ad763d8f4108f067c7c2e74f3001fb49778d309" +dependencies = [ + "bytes", + "prost", + "tonic", +] + [[package]] name = "tower" version = "0.5.3" @@ -5994,11 +7201,15 @@ checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", + "indexmap 2.13.0", "pin-project-lite", + "slab", "sync_wrapper", "tokio", + "tokio-util", "tower-layer", "tower-service", + "tracing", ] [[package]] @@ -6017,6 +7228,7 @@ dependencies = [ "tower", "tower-layer", "tower-service", + "tracing", ] [[package]] @@ -6037,6 +7249,7 @@ version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -6122,26 +7335,47 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] -name = "tungstenite" -version = "0.23.0" +name = "tryhard" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e2ce1e47ed2994fd43b04c8f618008d4cabdd5ee34027cf14f9d918edd9c8" +checksum = "9fe58ebd5edd976e0fe0f8a14d2a04b7c81ef153ea9a54eebc42e67c2c23b4e5" +dependencies = [ + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tungstenite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" dependencies = [ - "byteorder", "bytes", "data-encoding", "http", "httparse", "log", - "rand 0.8.5", + "rand 0.9.2", "rustls", "rustls-pki-types", "sha1", - "thiserror 1.0.69", + "thiserror 2.0.18", "url", "utf-8", ] +[[package]] +name = "twox-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" + +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + [[package]] name = "typenum" version = "1.19.0" @@ -6247,12 +7481,24 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "untrusted" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "unty" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" + [[package]] name = "ureq" version = "2.12.1" @@ -6341,11 +7587,11 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.20.0" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f" +checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.1", "js-sys", "serde_core", "wasm-bindgen", @@ -6368,12 +7614,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" -[[package]] -name = "vart" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87782b74f898179396e93c0efabb38de0d58d50bbd47eae00c71b3a1144dbbae" - [[package]] name = "vart" version = "0.9.3" @@ -6392,6 +7632,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "virtue" +version = "0.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" + [[package]] name = "walkdir" version = "2.5.0" @@ -6426,6 +7672,15 @@ dependencies = [ "wit-bindgen", ] +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "wasm-bindgen" version = "0.2.108" @@ -6485,6 +7740,28 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap 2.13.0", + "wasm-encoder", + "wasmparser", +] + [[package]] name = "wasm-streams" version = "0.4.2" @@ -6499,10 +7776,35 @@ dependencies = [ ] [[package]] -name = "wasmtimer" -version = "0.2.1" +name = "wasm-streams" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7ed9d8b15c7fb594d72bfb4b5a276f3d2029333cd93a932f376f5937f6f80ee" +checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.10.0", + "hashbrown 0.15.5", + "indexmap 2.13.0", + "semver", +] + +[[package]] +name = "wasmtimer" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c598d6b99ea013e35844697fc4670d08339d5cda15588f193c6beedd12f644b" dependencies = [ "futures", "js-sys", @@ -6537,7 +7839,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57ffde1dc01240bdf9992e3205668b235e59421fd085e8a317ed98da0178d414" dependencies = [ - "phf", + "phf 0.11.3", "phf_codegen", "string_cache", "string_cache_codegen", @@ -6609,24 +7911,37 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.57.0" +version = "0.61.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" dependencies = [ - "windows-core 0.57.0", - "windows-targets 0.52.6", + "windows-collections", + "windows-core 0.61.2", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.2", ] [[package]] name = "windows-core" -version = "0.57.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ - "windows-implement 0.57.0", - "windows-interface 0.57.0", - "windows-result 0.1.2", - "windows-targets 0.52.6", + "windows-implement", + "windows-interface", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", ] [[package]] @@ -6635,22 +7950,22 @@ version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ - "windows-implement 0.60.2", - "windows-interface 0.59.3", - "windows-link", + "windows-implement", + "windows-interface", + "windows-link 0.2.1", "windows-result 0.4.1", - "windows-strings", + "windows-strings 0.5.1", ] [[package]] -name = "windows-implement" -version = "0.57.0" +name = "windows-future" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", + "windows-core 0.61.2", + "windows-link 0.1.3", + "windows-threading", ] [[package]] @@ -6664,17 +7979,6 @@ dependencies = [ "syn 2.0.114", ] -[[package]] -name = "windows-interface" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] - [[package]] name = "windows-interface" version = "0.59.3" @@ -6686,30 +7990,46 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", +] + [[package]] name = "windows-registry" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" dependencies = [ - "windows-link", + "windows-link 0.2.1", "windows-result 0.4.1", - "windows-strings", + "windows-strings 0.5.1", ] [[package]] name = "windows-result" -version = "0.1.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" dependencies = [ - "windows-targets 0.52.6", + "windows-link 0.1.3", ] [[package]] @@ -6718,7 +8038,16 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link", + "windows-link 0.2.1", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", ] [[package]] @@ -6727,7 +8056,16 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link", + "windows-link 0.2.1", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", ] [[package]] @@ -6763,7 +8101,22 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link", + "windows-link 0.2.1", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] @@ -6788,7 +8141,7 @@ version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link", + "windows-link 0.2.1", "windows_aarch64_gnullvm 0.53.1", "windows_aarch64_msvc 0.53.1", "windows_i686_gnu 0.53.1", @@ -6799,6 +8152,21 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -6811,6 +8179,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -6823,6 +8197,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -6847,6 +8227,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -6859,6 +8245,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -6871,6 +8263,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -6883,6 +8281,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -6909,6 +8313,88 @@ name = "wit-bindgen" version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap 2.13.0", + "prettyplease", + "syn 2.0.114", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.114", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.10.0", + "indexmap 2.13.0", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.13.0", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] [[package]] name = "writeable" @@ -6916,25 +8402,6 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" -[[package]] -name = "ws_stream_wasm" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c173014acad22e83f16403ee360115b38846fe754e735c5d9d3803fe70c6abc" -dependencies = [ - "async_io_stream", - "futures", - "js-sys", - "log", - "pharos", - "rustc_version", - "send_wrapper", - "thiserror 2.0.18", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "wyz" version = "0.5.1" @@ -7065,6 +8532,16 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd8f3f50b848df28f887acb68e41201b5aea6bc8a8dacc00fb40635ff9a72fea" +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] + [[package]] name = "zune-core" version = "0.4.12" diff --git a/Cargo.toml b/Cargo.toml index c66e4ea..b7e09e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,9 +41,15 @@ tera = "1.20" rig-core = "0.30" # Storage -surrealdb = "2.6" +surrealdb = { version = "3", features = ["kv-mem"] } dashmap = "6.1" +# NATS eventing & orchestration +platform-nats = { path = "/Users/Akasha/Development/stratumiops/crates/platform-nats" } +stratum-orchestrator = { path = "/Users/Akasha/Development/stratumiops/crates/stratum-orchestrator" } +stratum-state = { path = "/Users/Akasha/Development/stratumiops/crates/stratum-state" } +bytes = "1.9" + # File watching notify = "8.2" diff --git a/README.md b/README.md index c14007f..a29aaec 100644 --- a/README.md +++ b/README.md @@ -254,7 +254,11 @@ Knowledge base behavior is fully configurable via Nickel schemas: secondary = { enabled = true, type = 'surrealdb, - url = "ws://localhost:8000", + surrealdb = { + graph = { engine = "surreal_kv", path = ".kogral/db/graph" }, + hot = { engine = "rocks_db", path = ".kogral/db/hot" }, + namespace = "kogral", + }, }, }, diff --git a/crates/kogral-core/Cargo.toml b/crates/kogral-core/Cargo.toml index 6cbee89..eda775e 100644 --- a/crates/kogral-core/Cargo.toml +++ b/crates/kogral-core/Cargo.toml @@ -21,7 +21,11 @@ anyhow = { workspace = true } pulldown-cmark = { workspace = true } tera = { workspace = true } rig-core = { workspace = true } -surrealdb = { workspace = true, optional = true } +surrealdb = { workspace = true, optional = true, features = ["kv-surrealkv", "kv-rocksdb", "protocol-ws", "rustls"] } +platform-nats = { workspace = true, optional = true } +stratum-orchestrator = { workspace = true, optional = true } +stratum-state = { workspace = true, optional = true } +bytes = { workspace = true, optional = true } dashmap = { workspace = true } notify = { workspace = true } chrono = { workspace = true } @@ -44,7 +48,9 @@ mockito = { workspace = true } tempfile = { workspace = true } [features] -default = ["filesystem"] -filesystem = [] -surrealdb-backend = ["surrealdb"] -full = ["surrealdb-backend"] +default = ["filesystem"] +filesystem = [] +surrealdb-backend = ["dep:surrealdb"] +nats-events = ["dep:platform-nats", "dep:bytes"] +orchestration = ["nats-events", "dep:stratum-orchestrator", "dep:stratum-state"] +full = ["surrealdb-backend", "nats-events", "orchestration"] diff --git a/crates/kogral-core/src/config/nickel.rs b/crates/kogral-core/src/config/nickel.rs index 9c8c2e7..0305b40 100644 --- a/crates/kogral-core/src/config/nickel.rs +++ b/crates/kogral-core/src/config/nickel.rs @@ -15,6 +15,45 @@ use tracing::{debug, info, warn}; use crate::error::{KbError, Result}; +/// Run `ncl-import-resolver` on the manifest adjacent to `ncl_file` if present. +/// +/// Looks for `resolver-manifest.json` in the same directory as `ncl_file`. +/// When the manifest is absent the function is a no-op, so callers in +/// environments without the tool are unaffected. +/// +/// # Errors +/// +/// Returns `KbError::NickelExport` if: +/// - `ncl-import-resolver` is not in PATH when the manifest exists +/// - The resolver process exits non-zero +fn resolve_nickel_imports(ncl_file: &Path) -> Result<()> { + let manifest = ncl_file + .parent() + .unwrap_or(Path::new(".")) + .join("resolver-manifest.json"); + + if !manifest.exists() { + return Ok(()); + } + + let output = Command::new("ncl-import-resolver") + .arg(&manifest) + .output() + .map_err(|e| { + KbError::NickelExport(format!("ncl-import-resolver unavailable: {e}")) + })?; + + if !output.status.success() { + let stderr = String::from_utf8_lossy(&output.stderr); + return Err(KbError::NickelExport(format!( + "ncl-import-resolver failed for {}: {stderr}", + manifest.display() + ))); + } + + Ok(()) +} + /// Export a Nickel file to JSON using the Nickel CLI /// /// # Arguments @@ -42,6 +81,8 @@ pub fn export_nickel_to_json>(nickel_file: P) -> Result { ))); } + resolve_nickel_imports(path)?; + info!("Exporting Nickel file to JSON: {}", path.display()); let output = Command::new("nickel") @@ -129,8 +170,7 @@ pub fn is_nickel_available() -> bool { Command::new("nickel") .arg("--version") .output() - .map(|output| output.status.success()) - .unwrap_or(false) + .is_ok_and(|output| output.status.success()) } /// Get Nickel CLI version diff --git a/crates/kogral-core/src/config/schema.rs b/crates/kogral-core/src/config/schema.rs index 695879b..15562b4 100644 --- a/crates/kogral-core/src/config/schema.rs +++ b/crates/kogral-core/src/config/schema.rs @@ -161,8 +161,100 @@ pub enum SecondaryStorageType { Sqlite, } +/// `SurrealDB` engine selector — dispatches via `engine::any::connect(url)` +/// +/// Serialized with an internal `engine` tag so Nickel records map directly: +/// `{ engine = "surreal_kv", path = ".kogral/db/graph" }` → `SurrealKv`. +#[cfg(feature = "surrealdb-backend")] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "engine", rename_all = "snake_case")] +pub enum SurrealEngineConfig { + /// In-memory — tests and ephemeral use only + Mem, + /// `SurrealKV` embedded (B-tree) — default for relational/graph data + SurrealKv { + /// Filesystem path for the `SurrealKV` database directory + path: String, + }, + /// `RocksDB` embedded (LSM) — default for hot/append data (embeddings, sessions) + RocksDb { + /// Filesystem path for the `RocksDB` database directory + path: String, + }, + /// Remote WebSocket — team and shared deployments + Ws { + /// Full WebSocket URL, e.g. `ws://surrealdb.internal:8000` + url: String, + }, +} + +#[cfg(feature = "surrealdb-backend")] +impl SurrealEngineConfig { + /// Produce the URL string consumed by `surrealdb::engine::any::connect` + #[must_use] + pub fn to_url(&self) -> String { + match self { + Self::Mem => "mem://".to_string(), + Self::SurrealKv { path } => format!("surrealkv://{path}"), + Self::RocksDb { path } => format!("rocksdb://{path}"), + Self::Ws { url } => url.clone(), + } + } +} + +/// Dual-engine `SurrealDB` backend configuration +/// +/// `graph` (default: `SurrealKV`) stores nodes, edges, and metadata using a +/// B-tree engine suited for random-access patterns. `hot` (default: `RocksDB`) +/// stores embeddings and session logs using an LSM engine suited for +/// append-heavy workloads. +#[cfg(feature = "surrealdb-backend")] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SurrealDbBackendConfig { + /// Engine for relational/graph data (nodes, edges, metadata) + #[serde(default = "default_graph_engine")] + pub graph: SurrealEngineConfig, + /// Engine for hot data (embeddings, session logs) + #[serde(default = "default_hot_engine")] + pub hot: SurrealEngineConfig, + /// `SurrealDB` namespace shared by both engines + #[serde(default = "default_surreal_namespace")] + pub namespace: String, +} + +#[cfg(feature = "surrealdb-backend")] +impl Default for SurrealDbBackendConfig { + fn default() -> Self { + Self { + graph: default_graph_engine(), + hot: default_hot_engine(), + namespace: default_surreal_namespace(), + } + } +} + +#[cfg(feature = "surrealdb-backend")] +fn default_graph_engine() -> SurrealEngineConfig { + SurrealEngineConfig::SurrealKv { + path: ".kogral/db/graph".to_string(), + } +} + +#[cfg(feature = "surrealdb-backend")] +fn default_hot_engine() -> SurrealEngineConfig { + SurrealEngineConfig::RocksDb { + path: ".kogral/db/hot".to_string(), + } +} + +#[cfg(feature = "surrealdb-backend")] +fn default_surreal_namespace() -> String { + "kogral".to_string() +} + /// Secondary storage configuration #[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Default)] pub struct SecondaryStorageConfig { /// Whether secondary storage is enabled #[serde(default)] @@ -170,41 +262,52 @@ pub struct SecondaryStorageConfig { /// Secondary storage type #[serde(rename = "type", default)] pub storage_type: SecondaryStorageType, - /// Connection URL - #[serde(default = "default_surrealdb_url")] - pub url: String, - /// Database namespace - #[serde(default = "default_namespace")] - pub namespace: String, - /// Database name - #[serde(default = "default_database")] - pub database: String, + /// `SurrealDB` engine configuration (dual hot/cold layout) + #[cfg(feature = "surrealdb-backend")] + #[serde(default)] + pub surrealdb: SurrealDbBackendConfig, } -impl Default for SecondaryStorageConfig { - fn default() -> Self { + +/// NATS `JetStream` event publishing configuration +#[cfg(feature = "nats-events")] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct NatsEventConfig { + /// NATS server URL (e.g. `nats://localhost:4222`) + pub url: String, + /// `JetStream` stream name + pub stream_name: String, + /// Durable consumer name + pub consumer_name: String, + /// Subjects this stream captures (e.g. `["kogral.>"]`) + #[serde(default)] + pub subjects: Vec, + /// `NKey` seed for signing published messages (optional) + #[serde(default)] + pub nkey_seed: Option, + /// Public `NKeys` whose signatures are trusted + #[serde(default)] + pub trusted_nkeys: Vec, + /// Reject messages that lack valid `NKey` signatures + #[serde(default)] + pub require_signed_messages: bool, +} + +#[cfg(feature = "nats-events")] +impl From for platform_nats::NatsConfig { + fn from(c: NatsEventConfig) -> Self { Self { - enabled: false, - storage_type: SecondaryStorageType::default(), - url: default_surrealdb_url(), - namespace: default_namespace(), - database: default_database(), + url: c.url, + stream_name: c.stream_name, + consumer_name: c.consumer_name, + subjects: c.subjects, + nkey_seed: c.nkey_seed, + trusted_nkeys: c.trusted_nkeys, + require_signed_messages: c.require_signed_messages, } } } -fn default_surrealdb_url() -> String { - "ws://localhost:8000".to_string() -} - -fn default_namespace() -> String { - "kb".to_string() -} - -fn default_database() -> String { - "default".to_string() -} - /// Storage backend configuration #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct StorageConfig { @@ -214,6 +317,10 @@ pub struct StorageConfig { /// Secondary storage (optional, for scaling/search) #[serde(default)] pub secondary: SecondaryStorageConfig, + /// NATS event publishing (optional) + #[cfg(feature = "nats-events")] + #[serde(default, skip_serializing_if = "Option::is_none")] + pub nats: Option, } /// Embedding provider type diff --git a/crates/kogral-core/src/error.rs b/crates/kogral-core/src/error.rs index e2c4e2c..a24821f 100644 --- a/crates/kogral-core/src/error.rs +++ b/crates/kogral-core/src/error.rs @@ -87,11 +87,6 @@ pub enum KbError { #[error("Invalid edge type: {0}")] InvalidEdgeType(String), - /// Database operation error - #[cfg(feature = "surrealdb-backend")] - #[error("Database error: {0}")] - Database(#[from] surrealdb::Error), - /// Other errors #[error("{0}")] Other(String), diff --git a/crates/kogral-core/src/events.rs b/crates/kogral-core/src/events.rs new file mode 100644 index 0000000..c0b6982 --- /dev/null +++ b/crates/kogral-core/src/events.rs @@ -0,0 +1,169 @@ +//! NATS `JetStream` event publishing for KOGRAL storage operations +//! +//! `EventPublisher` wraps a `platform_nats::EventStream` and publishes typed +//! `KogralEvent` values as JSON payloads. +//! +//! `EventingStorage` decorates any `Storage` implementation with automatic +//! event publishing after each mutating operation, without modifying the +//! underlying storage type. + +use std::sync::Arc; + +use async_trait::async_trait; +use bytes::Bytes; +use platform_nats::EventStream; +use serde::{Deserialize, Serialize}; + +use crate::error::{KbError, Result}; +use crate::models::{Graph, Node}; +use crate::storage::Storage; + +/// Typed events emitted by KOGRAL storage operations +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "event_type", rename_all = "snake_case")] +pub enum KogralEvent { + /// A node was created or updated + NodeSaved { + /// Graph the node belongs to + graph: String, + /// Node identifier + node_id: String, + /// Lowercase node type string (e.g. `"note"`, `"decision"`) + node_type: String, + }, + /// A node was removed + NodeDeleted { + /// Graph the node belonged to + graph: String, + /// Node identifier + node_id: String, + }, + /// A complete graph snapshot was persisted + GraphSaved { + /// Graph name + name: String, + /// Number of nodes in the snapshot + node_count: usize, + }, +} + +impl KogralEvent { + /// Subject string used when publishing to NATS `JetStream` + #[must_use] + pub fn subject(&self) -> String { + match self { + Self::NodeSaved { graph, .. } => format!("kogral.{graph}.node.saved"), + Self::NodeDeleted { graph, .. } => format!("kogral.{graph}.node.deleted"), + Self::GraphSaved { name, .. } => format!("kogral.{name}.graph.saved"), + } + } +} + +/// Publishes `KogralEvent` values to NATS `JetStream` +pub struct EventPublisher { + stream: Arc, +} + +impl EventPublisher { + /// Wrap an `EventStream` in a publisher. + #[must_use] + pub fn new(stream: EventStream) -> Self { + Self { + stream: Arc::new(stream), + } + } + + /// Serialize `event` to JSON and publish to its computed NATS subject. + /// + /// # Errors + /// + /// Returns `KbError::Serialization` if JSON encoding fails, or + /// `KbError::Storage` if the NATS publish call fails. + pub async fn publish(&self, event: KogralEvent) -> Result<()> { + let subject = event.subject(); + let payload = serde_json::to_vec(&event) + .map_err(|e| KbError::Serialization(e.to_string()))?; + self.stream + .publish(&subject, Bytes::from(payload)) + .await + .map_err(|e| KbError::Storage(format!("NATS publish to '{subject}': {e}"))) + } +} + +/// Decorator that wraps any `Storage` and publishes events after mutations +pub struct EventingStorage { + inner: S, + publisher: EventPublisher, + /// Default graph name used in `save_node` events when `node.project` is `None` + graph_name: String, +} + +impl EventingStorage { + /// Wrap `inner` storage with NATS event publishing. + /// + /// `graph_name` is used as the event graph field for `save_node` calls + /// when the node has no `project` set. + #[must_use] + pub fn new(inner: S, publisher: EventPublisher, graph_name: String) -> Self { + Self { + inner, + publisher, + graph_name, + } + } +} + +#[async_trait] +impl Storage for EventingStorage { + async fn save_graph(&mut self, graph: &Graph) -> Result<()> { + self.inner.save_graph(graph).await?; + self.publisher + .publish(KogralEvent::GraphSaved { + name: graph.name.clone(), + node_count: graph.nodes.len(), + }) + .await + } + + async fn save_node(&mut self, node: &Node) -> Result<()> { + self.inner.save_node(node).await?; + let graph = node + .project + .as_deref() + .unwrap_or(&self.graph_name) + .to_string(); + self.publisher + .publish(KogralEvent::NodeSaved { + graph, + node_id: node.id.clone(), + node_type: node.node_type.to_string(), + }) + .await + } + + async fn delete_node(&mut self, graph_name: &str, node_id: &str) -> Result<()> { + self.inner.delete_node(graph_name, node_id).await?; + self.publisher + .publish(KogralEvent::NodeDeleted { + graph: graph_name.to_string(), + node_id: node_id.to_string(), + }) + .await + } + + async fn load_graph(&self, name: &str) -> Result { + self.inner.load_graph(name).await + } + + async fn load_node(&self, graph_name: &str, node_id: &str) -> Result { + self.inner.load_node(graph_name, node_id).await + } + + async fn list_graphs(&self) -> Result> { + self.inner.list_graphs().await + } + + async fn list_nodes(&self, graph_name: &str, node_type: Option<&str>) -> Result> { + self.inner.list_nodes(graph_name, node_type).await + } +} diff --git a/crates/kogral-core/src/lib.rs b/crates/kogral-core/src/lib.rs index 856ab9b..9eefb2a 100644 --- a/crates/kogral-core/src/lib.rs +++ b/crates/kogral-core/src/lib.rs @@ -68,6 +68,12 @@ pub mod query; pub mod storage; pub mod sync; +#[cfg(feature = "nats-events")] +pub mod events; + +#[cfg(feature = "orchestration")] +pub mod orchestration; + mod regex_patterns; // Re-exports for convenience diff --git a/crates/kogral-core/src/orchestration.rs b/crates/kogral-core/src/orchestration.rs new file mode 100644 index 0000000..447728f --- /dev/null +++ b/crates/kogral-core/src/orchestration.rs @@ -0,0 +1,29 @@ +//! Bridge between KOGRAL events and the stratum-orchestrator pipeline runtime +//! +//! Maps `KogralEvent` subjects and payloads into `PipelineContext` instances +//! that the stratum-orchestrator `StageRunner` can execute. + +use std::{path::PathBuf, sync::Arc}; + +use stratum_orchestrator::context::PipelineContext; +use stratum_state::StateTracker; + +use crate::events::KogralEvent; + +/// Construct a `PipelineContext` from a `KogralEvent`. +/// +/// The event's subject becomes the pipeline trigger subject and `payload` +/// is passed through as the trigger payload. A fresh `PipelineRun` record +/// is written to `state` before this function returns. +/// +/// # Errors +/// +/// Propagates any error from `PipelineContext::new` (DB write failure). +pub async fn pipeline_context_from_event( + event: &KogralEvent, + payload: serde_json::Value, + state: Arc, + schema_dir: PathBuf, +) -> anyhow::Result { + PipelineContext::new(event.subject(), payload, state, schema_dir).await +} diff --git a/crates/kogral-core/src/query.rs b/crates/kogral-core/src/query.rs index ca435ca..865df0f 100644 --- a/crates/kogral-core/src/query.rs +++ b/crates/kogral-core/src/query.rs @@ -77,7 +77,7 @@ impl QueryEngine { } // Sort by score (descending) - results.sort_by(|a, b| b.0.cmp(&a.0)); + results.sort_by_key(|b| std::cmp::Reverse(b.0)); Ok(results.into_iter().map(|(_, node)| node).collect()) } diff --git a/crates/kogral-core/src/storage/factory.rs b/crates/kogral-core/src/storage/factory.rs new file mode 100644 index 0000000..4c16265 --- /dev/null +++ b/crates/kogral-core/src/storage/factory.rs @@ -0,0 +1,168 @@ +//! Config-driven storage backend factory +//! +//! Selects and constructs the appropriate [`Storage`] implementation based on +//! [`StorageConfig`](crate::config::schema::StorageConfig) at runtime — +//! no recompilation required to switch backends. +//! +//! ## Engine selection priority +//! +//! 1. `surrealdb-backend` feature ON **and** `secondary.enabled` **and** +//! `secondary.type == surrealdb` → [`SurrealDbStorage`](super::surrealdb::SurrealDbStorage) +//! using the dual hot/cold engine layout from `secondary.surrealdb` +//! 2. `primary == memory` → [`MemoryStorage`](super::memory::MemoryStorage) +//! 3. default → [`FilesystemStorage`](super::filesystem::FilesystemStorage) +//! rooted at `base_path` +//! +//! ## NATS event wrapping +//! +//! When the `nats-events` feature is enabled, [`build_eventing`] wraps any +//! backend with [`EventingStorage`](crate::events::EventingStorage), publishing +//! a [`KogralEvent`](crate::events::KogralEvent) after each mutation. + +use std::path::PathBuf; + +use crate::config::schema::{StorageConfig, StorageType}; +use crate::error::Result; +use crate::storage::{filesystem::FilesystemStorage, memory::MemoryStorage, Storage}; + +/// Build the storage backend driven by `config`. +/// +/// Applies the engine selection priority described in the module docs. +/// For NATS event publishing after mutations, use [`build_eventing`] instead. +/// +/// # Errors +/// +/// Returns [`KbError`](crate::error::KbError) if the `SurrealDB` engine +/// connection fails. +// `unused_async`: this function has no await when surrealdb-backend is off, +// but callers treat it as async uniformly across all feature combinations. +#[allow(clippy::unused_async)] +pub async fn build(config: &StorageConfig, base_path: PathBuf) -> Result> { + #[cfg(feature = "surrealdb-backend")] + if config.secondary.enabled + && config.secondary.storage_type + == crate::config::schema::SecondaryStorageType::Surrealdb + { + let db = crate::storage::surrealdb::SurrealDbStorage::from_config( + &config.secondary.surrealdb, + ) + .await?; + return Ok(Box::new(db)); + } + + Ok(match config.primary { + StorageType::Memory => Box::new(MemoryStorage::new()), + StorageType::Filesystem => Box::new(FilesystemStorage::new(base_path)), + }) +} + +/// Build storage wrapped with NATS `JetStream` event publishing. +/// +/// Calls [`build`] to construct the base backend, then wraps it with +/// [`EventingStorage`](crate::events::EventingStorage) so that a +/// [`KogralEvent`](crate::events::KogralEvent) is published after every +/// mutation (`save_graph`, `save_node`, `delete_node`). +/// +/// When `config.nats` is `None` the function returns the unwrapped base +/// backend — identical to calling [`build`] directly. +/// +/// `default_graph` is used in `NodeSaved` events when `node.project` is +/// `None`. +/// +/// # Errors +/// +/// Returns [`KbError`](crate::error::KbError) if the base backend or the +/// NATS `JetStream` connection fails. +#[cfg(feature = "nats-events")] +pub async fn build_eventing( + config: &StorageConfig, + base_path: PathBuf, + default_graph: impl Into, +) -> Result> { + let base = build(config, base_path).await?; + + let Some(nats_cfg) = &config.nats else { + return Ok(base); + }; + + let nats_config = platform_nats::NatsConfig::from(nats_cfg.clone()); + let stream = platform_nats::EventStream::connect(&nats_config) + .await + .map_err(|e| crate::error::KbError::Storage(format!("NATS connect: {e}")))?; + + let publisher = crate::events::EventPublisher::new(stream); + Ok(Box::new(crate::events::EventingStorage::new( + base, + publisher, + default_graph.into(), + ))) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::config::schema::{StorageConfig, StorageType}; + use tempfile::tempdir; + + #[tokio::test] + async fn build_memory_backend() { + let config = StorageConfig { + primary: StorageType::Memory, + ..StorageConfig::default() + }; + let storage = build(&config, PathBuf::from("/tmp")).await; + assert!(storage.is_ok(), "memory backend must construct without I/O"); + } + + #[tokio::test] + async fn build_filesystem_backend() { + let dir = tempdir().unwrap(); + let config = StorageConfig::default(); // primary defaults to Filesystem + let storage = build(&config, dir.path().to_path_buf()).await; + assert!( + storage.is_ok(), + "filesystem backend must construct for any valid path" + ); + } + + #[tokio::test] + async fn memory_backend_save_load_roundtrip() { + use crate::models::Graph; + + let config = StorageConfig { + primary: StorageType::Memory, + ..StorageConfig::default() + }; + let mut storage = build(&config, PathBuf::from("/tmp")).await.unwrap(); + + let graph = Graph::new("test-graph".to_string()); + storage.save_graph(&graph).await.unwrap(); + + let loaded = storage.load_graph("test-graph").await.unwrap(); + assert_eq!(loaded.name, "test-graph"); + } + + #[cfg(feature = "surrealdb-backend")] + #[tokio::test] + async fn build_surrealdb_mem_backend() { + use crate::config::schema::{ + SecondaryStorageConfig, SecondaryStorageType, SurrealDbBackendConfig, + SurrealEngineConfig, + }; + + let config = StorageConfig { + secondary: SecondaryStorageConfig { + enabled: true, + storage_type: SecondaryStorageType::Surrealdb, + surrealdb: SurrealDbBackendConfig { + graph: SurrealEngineConfig::Mem, + hot: SurrealEngineConfig::Mem, + namespace: "factory-test".to_string(), + }, + }, + ..StorageConfig::default() + }; + let storage = build(&config, PathBuf::from("/tmp")).await; + assert!(storage.is_ok(), "surrealdb mem:// backend must connect"); + } +} diff --git a/crates/kogral-core/src/storage/mod.rs b/crates/kogral-core/src/storage/mod.rs index c73bae6..605d428 100644 --- a/crates/kogral-core/src/storage/mod.rs +++ b/crates/kogral-core/src/storage/mod.rs @@ -4,6 +4,8 @@ //! - Filesystem: Git-friendly markdown files //! - Memory: In-memory graph for dev/cache //! - `SurrealDB`: Scalable database backend (optional) +//! +//! Use [`factory::build`] to construct the appropriate backend from config. use async_trait::async_trait; @@ -53,6 +55,43 @@ pub trait Storage: Send + Sync { async fn list_nodes(&self, graph_name: &str, node_type: Option<&str>) -> Result>; } +/// Blanket `Storage` impl for `Box`. +/// +/// Enables type-erased composition: `EventingStorage>` +/// satisfies `S: Storage + Send` so the factory can wrap any backend +/// with NATS events without knowing the concrete type at compile time. +#[async_trait] +impl Storage for Box { + async fn save_graph(&mut self, graph: &Graph) -> Result<()> { + (**self).save_graph(graph).await + } + + async fn load_graph(&self, name: &str) -> Result { + (**self).load_graph(name).await + } + + async fn save_node(&mut self, node: &Node) -> Result<()> { + (**self).save_node(node).await + } + + async fn load_node(&self, graph_name: &str, node_id: &str) -> Result { + (**self).load_node(graph_name, node_id).await + } + + async fn delete_node(&mut self, graph_name: &str, node_id: &str) -> Result<()> { + (**self).delete_node(graph_name, node_id).await + } + + async fn list_graphs(&self) -> Result> { + (**self).list_graphs().await + } + + async fn list_nodes(&self, graph_name: &str, node_type: Option<&str>) -> Result> { + (**self).list_nodes(graph_name, node_type).await + } +} + +pub mod factory; pub mod filesystem; pub mod memory; diff --git a/crates/kogral-core/src/storage/surrealdb.rs b/crates/kogral-core/src/storage/surrealdb.rs index 6a19ebc..799043d 100644 --- a/crates/kogral-core/src/storage/surrealdb.rs +++ b/crates/kogral-core/src/storage/surrealdb.rs @@ -1,144 +1,184 @@ -//! SurrealDB storage backend +//! `SurrealDB` storage backend — `engine::any` dispatcher //! -//! Provides scalable, graph-native storage using SurrealDB. -//! Supports distributed deployments and complex queries. - -use std::sync::Arc; +//! A single `Surreal` type unifies all engine variants selected at +//! runtime via URL scheme. The dual hot/cold layout uses: +//! - `graph_db`: `SurrealKV` (default) — B-tree, suited for random-access graph data +//! - `hot_db`: `RocksDB` (default) — LSM, suited for embeddings and session logs +//! +//! ## `SurrealDB` 3.0 and `SurrealValue` +//! +//! `SurrealDB` 3.0 requires `SurrealValue` on all types passed to or returned +//! from CRUD methods. `Graph` and `Node` intentionally do not implement this +//! trait to avoid coupling the domain model to the database library. +//! +//! All I/O routes through `serde_json::Value`, which implements `SurrealValue`, +//! with explicit `serde_json::to_value` / `serde_json::from_value` conversion. +//! This is the same pattern used by `stratum-state`'s `SurrealStateTracker`. use async_trait::async_trait; -use surrealdb::engine::any::Any; -use surrealdb::Surreal; -use tokio::sync::RwLock; +use surrealdb::{engine::any, engine::any::Any, Surreal}; +use crate::config::schema::SurrealDbBackendConfig; use crate::error::{KbError, Result}; use crate::models::{Graph, Node}; use crate::storage::Storage; -/// SurrealDB storage backend +// ─── serialization helpers ──────────────────────────────────────────────────── + +fn to_json(v: &T) -> Result { + serde_json::to_value(v).map_err(|e| KbError::Serialization(e.to_string())) +} + +fn from_json(v: serde_json::Value) -> Result { + serde_json::from_value(v).map_err(|e| KbError::Serialization(e.to_string())) +} + +// ─── engine factory ─────────────────────────────────────────────────────────── + +/// Open a `SurrealDB` connection using `engine::any` URL dispatch. /// -/// Stores graphs and nodes in SurrealDB with full ACID transactions. -/// Connection is wrapped in Arc> for thread-safe concurrent access. +/// Calls `use_ns` / `use_db` at connection time so callers never need to +/// repeat the namespace/database selection before individual queries. +async fn open_engine(url: &str, namespace: &str, database: &str) -> Result> { + let conn = any::connect(url) + .await + .map_err(|e| KbError::Storage(format!("connect '{url}' failed: {e}")))?; + conn.use_ns(namespace) + .use_db(database) + .await + .map_err(|e| KbError::Storage(format!("use_ns/use_db failed: {e}")))?; + Ok(conn) +} + +// ─── storage type ───────────────────────────────────────────────────────────── + +/// `SurrealDB` storage backend — no generics, no Arc<`RwLock`<>> +/// +/// `Surreal` is already `Clone + Send + Sync`. The dual-connection +/// layout separates graph semantics from hot-data semantics at the engine +/// level rather than at the table level. pub struct SurrealDbStorage { - db: Arc>>, + /// `SurrealKV` (default) or any config-selected engine — graph/node data + graph_db: Surreal, + /// `RocksDB` (default) or any config-selected engine — embeddings/sessions + hot_db: Surreal, namespace: String, - database: String, } impl SurrealDbStorage { - /// Create a new SurrealDB storage instance + /// Construct from a `SurrealDbBackendConfig`, opening both engine connections. /// - /// # Arguments - /// * `db` - Connected SurrealDB instance - /// * `namespace` - SurrealDB namespace (default: "kogral") - /// * `database` - SurrealDB database (default: "kb") - pub fn new(db: Surreal, namespace: String, database: String) -> Self { - Self { - db: Arc::new(RwLock::new(db)), - namespace, - database, - } + /// # Errors + /// + /// Returns `KbError::Storage` if either engine connection or namespace/database + /// selection fails. + pub async fn from_config(cfg: &SurrealDbBackendConfig) -> Result { + let graph_url = cfg.graph.to_url(); + let hot_url = cfg.hot.to_url(); + let graph_db = open_engine(&graph_url, &cfg.namespace, "graph").await?; + let hot_db = open_engine(&hot_url, &cfg.namespace, "hot").await?; + Ok(Self { + graph_db, + hot_db, + namespace: cfg.namespace.clone(), + }) } - /// Create a new storage with default namespace and database names - pub fn with_defaults(db: Surreal) -> Self { - Self::new(db, "kogral".to_string(), "kb".to_string()) + /// Save a node embedding vector to the hot engine. + /// + /// # Errors + /// + /// Returns `KbError::Storage` on `SurrealDB` I/O failure. + pub async fn save_embedding(&self, node_id: &str, vector: &[f32]) -> Result<()> { + let payload = serde_json::json!({ "node_id": node_id, "vector": vector }); + let _: Option = self + .hot_db + .upsert(("embeddings", node_id)) + .content(payload) + .await + .map_err(|e| KbError::Storage(e.to_string()))?; + Ok(()) + } + + /// Append a session log entry to the hot engine. + /// + /// # Errors + /// + /// Returns `KbError::Storage` on `SurrealDB` I/O failure. + pub async fn log_session(&self, entry: &serde_json::Value) -> Result<()> { + let _: Option = self + .hot_db + .create("sessions") + .content(entry.clone()) + .await + .map_err(|e| KbError::Storage(e.to_string()))?; + Ok(()) + } + + fn node_key(graph_name: &str, node_id: &str) -> String { + format!("{graph_name}__{node_id}") } } impl Clone for SurrealDbStorage { fn clone(&self) -> Self { Self { - db: Arc::clone(&self.db), + graph_db: self.graph_db.clone(), + hot_db: self.hot_db.clone(), namespace: self.namespace.clone(), - database: self.database.clone(), } } } +// ─── Storage trait impl ─────────────────────────────────────────────────────── + #[async_trait] impl Storage for SurrealDbStorage { async fn save_graph(&mut self, graph: &Graph) -> Result<()> { - let db = self.db.write().await; - let _ = db - .use_ns(&self.namespace) - .use_db(&self.database) + let _: Option = self + .graph_db + .upsert(("graphs", graph.name.clone())) + .content(to_json(graph)?) .await - .map_err(|e| KbError::Database(e))?; + .map_err(|e| KbError::Storage(e.to_string()))?; - // Serialize graph and all nodes - let graph_json = serde_json::to_value(graph) - .map_err(|e| KbError::Serialization(format!("Graph serialization error: {}", e)))?; - - // Use raw SurrealQL query for upserting - let query = "UPSERT graphs:$graph_id SET * = $content;"; - let graph_id = graph.name.clone(); - - let _: Vec = db - .query(query) - .bind(("graph_id", graph_id)) - .bind(("content", graph_json)) - .await - .map_err(|e| KbError::Database(e))? - .take(0) - .map_err(|e| KbError::Database(e))?; - - // Upsert all nodes for node in graph.nodes.values() { - let node_json = serde_json::to_value(node) - .map_err(|e| KbError::Serialization(format!("Node serialization error: {}", e)))?; - let node_key = format!("{}_{}", graph.name, node.id); - - let query = "UPSERT nodes:$node_id SET * = $content;"; - let _: Vec = db - .query(query) - .bind(("node_id", node_key)) - .bind(("content", node_json)) + let key = Self::node_key(&graph.name, &node.id); + let _: Option = self + .graph_db + .upsert(("nodes", key)) + .content(to_json(node)?) .await - .map_err(|e| KbError::Database(e))? - .take(0) - .map_err(|e| KbError::Database(e))?; + .map_err(|e| KbError::Storage(e.to_string()))?; } Ok(()) } async fn load_graph(&self, name: &str) -> Result { - let db = self.db.read().await; - let _ = db - .use_ns(&self.namespace) - .use_db(&self.database) + let raw: Option = self + .graph_db + .select(("graphs", name)) .await - .map_err(|e| KbError::Database(e))?; + .map_err(|e| KbError::Storage(e.to_string()))?; - // Load graph metadata using raw query - let query = "SELECT * FROM graphs:$graph_id;"; - let graph_id = name.to_string(); - let result: Vec> = db - .query(query) - .bind(("graph_id", graph_id)) + let mut graph: Graph = raw + .map(from_json) + .transpose()? + .ok_or_else(|| KbError::Graph(format!("Graph not found: {name}")))?; + + // Overlay with individually-saved nodes so save_node writes are visible + let raw_nodes: Vec = self + .graph_db + .query("SELECT * FROM nodes WHERE project = $g") + .bind(("g", name.to_string())) .await - .map_err(|e| KbError::Database(e))? + .map_err(|e| KbError::Storage(e.to_string()))? .take(0) - .map_err(|e| KbError::Database(e))?; + .map_err(|e| KbError::Storage(e.to_string()))?; - let mut graph = result - .into_iter() - .next() - .flatten() - .ok_or_else(|| KbError::Graph(format!("Graph not found: {}", name)))?; - - // Load all nodes for this graph - let query = "SELECT * FROM nodes WHERE id LIKE $pattern;"; - let pattern = format!("{}_%", name); - let nodes: Vec = db - .query(query) - .bind(("pattern", pattern)) - .await - .map_err(|e| KbError::Database(e))? - .take(0) - .map_err(|e| KbError::Database(e))?; - - for node in nodes { + for raw_node in raw_nodes { + let node: Node = from_json(raw_node)?; graph.nodes.insert(node.id.clone(), node); } @@ -146,126 +186,81 @@ impl Storage for SurrealDbStorage { } async fn save_node(&mut self, node: &Node) -> Result<()> { - let db = self.db.write().await; - let _ = db - .use_ns(&self.namespace) - .use_db(&self.database) + let graph_name = node.project.as_deref().unwrap_or("default"); + let key = Self::node_key(graph_name, &node.id); + let _: Option = self + .graph_db + .upsert(("nodes", key)) + .content(to_json(node)?) .await - .map_err(|e| KbError::Database(e))?; - - let graph_name = node - .project - .clone() - .unwrap_or_else(|| "default".to_string()); - let node_id = format!("{}_{}", graph_name, node.id); - let node_json = serde_json::to_value(node) - .map_err(|e| KbError::Serialization(format!("Node serialization error: {}", e)))?; - - let query = "UPSERT nodes:$node_id SET * = $content;"; - let _: Vec = db - .query(query) - .bind(("node_id", node_id)) - .bind(("content", node_json)) - .await - .map_err(|e| KbError::Database(e))? - .take(0) - .map_err(|e| KbError::Database(e))?; - + .map_err(|e| KbError::Storage(e.to_string()))?; Ok(()) } async fn load_node(&self, graph_name: &str, node_id: &str) -> Result { - let db = self.db.read().await; - let _ = db - .use_ns(&self.namespace) - .use_db(&self.database) + let key = Self::node_key(graph_name, node_id); + let raw: Option = self + .graph_db + .select(("nodes", key)) .await - .map_err(|e| KbError::Database(e))?; + .map_err(|e| KbError::Storage(e.to_string()))?; - let combined_id = format!("{}_{}", graph_name, node_id); - let query = "SELECT * FROM nodes:$node_id;"; - let result: Vec> = db - .query(query) - .bind(("node_id", combined_id)) - .await - .map_err(|e| KbError::Database(e))? - .take(0) - .map_err(|e| KbError::Database(e))?; - - result - .into_iter() - .next() - .flatten() - .ok_or_else(|| KbError::NodeNotFound(format!("{}/{}", graph_name, node_id))) + raw.map(from_json) + .transpose()? + .ok_or_else(|| KbError::NodeNotFound(format!("{graph_name}/{node_id}"))) } async fn delete_node(&mut self, graph_name: &str, node_id: &str) -> Result<()> { - let db = self.db.write().await; - let _ = db - .use_ns(&self.namespace) - .use_db(&self.database) + let key = Self::node_key(graph_name, node_id); + let deleted: Option = self + .graph_db + .delete(("nodes", key)) .await - .map_err(|e| KbError::Database(e))?; - - let combined_id = format!("{}_{}", graph_name, node_id); - let query = "DELETE nodes:$node_id RETURN BEFORE;"; - let deleted: Vec> = db - .query(query) - .bind(("node_id", combined_id)) - .await - .map_err(|e| KbError::Database(e))? - .take(0) - .map_err(|e| KbError::Database(e))?; + .map_err(|e| KbError::Storage(e.to_string()))?; deleted - .into_iter() - .next() - .flatten() - .ok_or_else(|| KbError::NodeNotFound(format!("{}/{}", graph_name, node_id))) + .ok_or_else(|| KbError::NodeNotFound(format!("{graph_name}/{node_id}"))) .map(|_| ()) } async fn list_graphs(&self) -> Result> { - let db = self.db.read().await; - let _ = db - .use_ns(&self.namespace) - .use_db(&self.database) - .await - .map_err(|e| KbError::Database(e))?; - - let graphs: Vec = db + let raw_graphs: Vec = self + .graph_db .select("graphs") .await - .map_err(|e| KbError::Database(e))?; + .map_err(|e| KbError::Storage(e.to_string()))?; - Ok(graphs.into_iter().map(|g| g.name).collect()) + raw_graphs + .into_iter() + .map(|v| { + v.get("name") + .and_then(|n| n.as_str()) + .map(str::to_string) + .ok_or_else(|| KbError::Storage("graph record missing 'name' field".into())) + }) + .collect() } async fn list_nodes(&self, graph_name: &str, node_type: Option<&str>) -> Result> { - let db = self.db.read().await; - let _ = db - .use_ns(&self.namespace) - .use_db(&self.database) - .await - .map_err(|e| KbError::Database(e))?; - - let mut query_builder = db.query(if let Some(_) = node_type { - "SELECT * FROM nodes WHERE id LIKE $id_pattern AND type = $type_filter" + let raw_nodes: Vec = if let Some(t) = node_type { + self.graph_db + .query("SELECT * FROM nodes WHERE project = $g AND node_type = $t") + .bind(("g", graph_name.to_string())) + .bind(("t", t.to_string())) + .await + .map_err(|e| KbError::Storage(e.to_string()))? + .take(0) + .map_err(|e| KbError::Storage(e.to_string()))? } else { - "SELECT * FROM nodes WHERE id LIKE $id_pattern" - }); + self.graph_db + .query("SELECT * FROM nodes WHERE project = $g") + .bind(("g", graph_name.to_string())) + .await + .map_err(|e| KbError::Storage(e.to_string()))? + .take(0) + .map_err(|e| KbError::Storage(e.to_string()))? + }; - let id_pattern = format!("{}_%", graph_name); - query_builder = query_builder.bind(("id_pattern", id_pattern)); - - if let Some(filter_type) = node_type { - query_builder = query_builder.bind(("type_filter", filter_type)); - } - - query_builder - .await - .map_err(|e| KbError::Database(e))? - .take(0) - .map_err(|e| KbError::Database(e)) + raw_nodes.into_iter().map(from_json).collect() } } diff --git a/crates/kogral-core/tests/nickel_integration_test.rs b/crates/kogral-core/tests/nickel_integration_test.rs index f65f6c8..77f7cca 100644 --- a/crates/kogral-core/tests/nickel_integration_test.rs +++ b/crates/kogral-core/tests/nickel_integration_test.rs @@ -63,8 +63,6 @@ fn test_load_production_config() { assert_eq!(config.graph.name, "tools-ecosystem-kb"); assert!(config.storage.secondary.enabled); - assert_eq!(config.storage.secondary.namespace, "tools_kb"); - assert_eq!(config.storage.secondary.database, "production"); assert_eq!(config.embeddings.provider, EmbeddingProvider::Openai); assert_eq!(config.embeddings.model, "text-embedding-3-small"); assert_eq!(config.query.similarity_threshold, 0.5); diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 53ef1b0..79e44d5 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -32,6 +32,8 @@ - [ADR-003: Hybrid Storage Strategy](architecture/adrs/003-hybrid-storage.md) - [ADR-004: Logseq Blocks Support](architecture/adrs/004-logseq-blocks-support.md) - [ADR-005: MCP Protocol for AI Integration](architecture/adrs/005-mcp-protocol.md) +- [ADR-006: SurrealDB 3.0 Engine Abstraction](architecture/adrs/006-surrealdb-v3-engine-abstraction.md) +- [ADR-007: NATS Event Publishing](architecture/adrs/007-nats-event-publishing.md) # Setup diff --git a/docs/architecture/adrs/006-surrealdb-v3-engine-abstraction.md b/docs/architecture/adrs/006-surrealdb-v3-engine-abstraction.md new file mode 100644 index 0000000..be9950b --- /dev/null +++ b/docs/architecture/adrs/006-surrealdb-v3-engine-abstraction.md @@ -0,0 +1,241 @@ +# ADR-006: SurrealDB 3.0 Engine Abstraction + +**Status**: Accepted + +**Date**: 2026-02-21 + +**Deciders**: Architecture Team + +**Supersedes**: [ADR-003: Hybrid Storage Strategy](003-hybrid-storage.md) (SurrealDB connection model) + +--- + +## Context + +SurrealDB 2.x required a concrete connection type at compile time (`Surreal`, `Surreal`, +etc.), forcing a single engine choice per binary. This created three problems: + +1. **No runtime engine selection**: switching from embedded to remote required recompilation +2. **Tight test coupling**: tests depended on whichever engine was compiled in +3. **No dual-layout support**: using SurrealKV for graph data and RocksDB for hot data required + separate crates or unsafe casting + +SurrealDB 3.0 introduces `surrealdb::engine::any::connect(url)` returning `Surreal` — a +type-erased connection dispatched at runtime by URL scheme: + +| URL scheme | Engine | Characteristics | +|---|---|---| +| `mem://` | In-memory | Ephemeral, test isolation | +| `surrealkv://path` | SurrealKV (B-tree) | Embedded, relational/graph data | +| `rocksdb://path` | RocksDB (LSM) | Embedded, append-heavy hot data | +| `ws://host:port` | WebSocket | Remote, team/shared deployment | + +This makes the engine a pure config concern. + +--- + +## Decision + +**Use `Surreal` throughout `SurrealDbStorage`, selecting the engine from `SurrealEngineConfig` +at runtime via URL dispatch.** + +### Config Schema + +`SurrealEngineConfig` is a serde-tagged enum serialized with `tag = "engine"`: + +```rust +#[serde(tag = "engine", rename_all = "snake_case")] +pub enum SurrealEngineConfig { + Mem, + SurrealKv { path: String }, + RocksDb { path: String }, + Ws { url: String }, +} +``` + +`to_url()` maps variants to the URL scheme `engine::any::connect` expects: + +```rust +impl SurrealEngineConfig { + pub fn to_url(&self) -> String { + match self { + Self::Mem => "mem://".to_string(), + Self::SurrealKv { path } => format!("surrealkv://{path}"), + Self::RocksDb { path } => format!("rocksdb://{path}"), + Self::Ws { url } => url.clone(), + } + } +} +``` + +### Dual Hot/Cold Layout + +`SurrealDbStorage` holds two independent `Surreal` connections: + +```rust +pub struct SurrealDbStorage { + graph_db: Surreal, // SurrealKV default — nodes, edges, metadata + hot_db: Surreal, // RocksDB default — embeddings, session logs + namespace: String, +} +``` + +Default production layout: + +```nickel +secondary.surrealdb = { + graph = { engine = "surreal_kv", path = ".kogral/db/graph" }, + hot = { engine = "rocks_db", path = ".kogral/db/hot" }, + namespace = "kogral", +} +``` + +Test layout (in-memory, no filesystem side effects): + +```nickel +secondary.surrealdb = { + graph = { engine = "mem" }, + hot = { engine = "mem" }, + namespace = "test", +} +``` + +Remote team deployment (single SurrealDB instance, two databases): + +```nickel +secondary.surrealdb = { + graph = { engine = "ws", url = "ws://kb.company.com:8000" }, + hot = { engine = "ws", url = "ws://kb.company.com:8000" }, + namespace = "engineering", +} +``` + +### Storage Factory + +`storage::factory::build()` performs the runtime dispatch, keeping SurrealDB-specific logic +behind the `surrealdb-backend` feature gate: + +```rust +#[allow(clippy::unused_async)] +pub async fn build(config: &StorageConfig, base_path: PathBuf) -> Result> { + #[cfg(feature = "surrealdb-backend")] + if config.secondary.enabled && config.secondary.storage_type == SecondaryStorageType::Surrealdb { + let db = SurrealDbStorage::from_config(&config.secondary.surrealdb).await?; + return Ok(Box::new(db)); + } + Ok(match config.primary { + StorageType::Memory => Box::new(MemoryStorage::new()), + StorageType::Filesystem => Box::new(FilesystemStorage::new(base_path)), + }) +} +``` + +### Type Erasure Composition + +`impl Storage for Box` enables `EventingStorage>` without +knowing the concrete backend at compile time: + +```rust +#[async_trait] +impl Storage for Box { + async fn save_graph(&mut self, graph: &Graph) -> Result<()> { + (**self).save_graph(graph).await + } + // ... full delegation for all methods +} +``` + +### CRUD via `serde_json::Value` + +SurrealDB 3.0 removed the `IntoSurrealValue`/`SurrealValue` traits. All CRUD goes through +`serde_json::Value` as the intermediary: + +```rust +// save_node +let row = serde_json::to_value(node) + .map_err(|e| KbError::Storage(e.to_string()))?; +let _: Option = self.graph_db + .upsert(("nodes", format!("{graph_name}__{}", node.id))) + .content(row) + .await + .map_err(|e| KbError::Storage(e.to_string()))?; +``` + +`.bind()` parameters require `'static` values — `&str` arguments must be `.to_string()`: + +```rust +let nodes: Vec = self.graph_db + .query("SELECT * FROM nodes WHERE project = $g") + .bind(("g", graph_name.to_string())) // .to_string() required + .await... +``` + +### Error Handling + +`KbError::Database(#[from] surrealdb::Error)` was removed. All SurrealDB errors convert via +`map_err(|e| KbError::Storage(e.to_string()))`, avoiding `#[from]` coupling to a feature-gated +type that would break compilation on default features. + +--- + +## Consequences + +### Positive + +- Engine selection is a config value, not a compile-time decision +- Tests run fully in-memory (`engine = "mem"`) with zero filesystem side effects +- Dual layout (SurrealKV + RocksDB) is the embedded production default +- Remote deployment (WebSocket) requires only a config change +- `Storage` trait consumers never see SurrealDB types — `Box` is the boundary + +### Negative + +- `Surreal` has slightly higher dispatch overhead than concrete types (negligible vs. I/O) +- `serde_json::Value` intermediary adds one extra allocation per CRUD call +- `engine::any` requires all four engine feature flags compiled in when `surrealdb-backend` is + enabled (larger binary) + +--- + +## Feature Matrix + +```toml +[features] +default = ["filesystem"] +filesystem = [] +surrealdb-backend = ["dep:surrealdb"] +nats-events = ["dep:platform-nats", "dep:bytes"] +orchestration = ["nats-events", "dep:stratum-orchestrator"] +full = ["surrealdb-backend", "nats-events", "orchestration"] +``` + +SurrealDB dependency activates all four engines: + +```toml +surrealdb = { workspace = true, optional = true, + features = ["kv-surrealkv", "kv-rocksdb", "protocol-ws", "rustls"] } +``` + +--- + +## References + +- [SurrealDB `engine::any` docs](https://surrealdb.com/docs/sdk/rust/setup) +- [SurrealDbStorage](../../../crates/kogral-core/src/storage/surrealdb.rs) +- [Storage Factory](../../../crates/kogral-core/src/storage/factory.rs) +- [Config Schema](../../../crates/kogral-core/src/config/schema.rs) +- [Nickel Defaults](../../../schemas/kogral/defaults.ncl) + +--- + +## Revision History + +| Date | Author | Change | +|---|---|---| +| 2026-02-21 | Architecture Team | Initial decision — SurrealDB 3.0 + engine::any | + +--- + +**Previous ADR**: [ADR-005: MCP Protocol](005-mcp-protocol.md) + +**Next ADR**: [ADR-007: NATS Event Publishing](007-nats-event-publishing.md) diff --git a/docs/architecture/adrs/007-nats-event-publishing.md b/docs/architecture/adrs/007-nats-event-publishing.md new file mode 100644 index 0000000..a8bbdc4 --- /dev/null +++ b/docs/architecture/adrs/007-nats-event-publishing.md @@ -0,0 +1,243 @@ +# ADR-007: NATS JetStream Event Publishing + +**Status**: Accepted + +**Date**: 2026-02-21 + +**Deciders**: Architecture Team + +**Depends on**: [ADR-006: SurrealDB 3.0 Engine Abstraction](006-surrealdb-v3-engine-abstraction.md) + +--- + +## Context + +As KOGRAL scales to organizational deployments, components beyond the core library need to react +to knowledge graph mutations: embedding reindex pipelines, audit trails, cross-graph sync, AI +agent notifications. Polling storage for changes does not scale and creates artificial coupling +between consumer and storage implementation. + +NATS JetStream provides durable, at-least-once message delivery with subject hierarchies that +map naturally to KOGRAL's multi-graph structure: + +```text +kogral..node.saved +kogral..node.deleted +kogral..graph.saved +``` + +The challenge: wrapping the storage layer with event publishing must not affect the `Storage` +trait interface, must not require consumers to know which backend is in use, and must be +completely opt-in (off by default, zero overhead when disabled). + +--- + +## Decision + +**Implement the `EventingStorage` decorator pattern: wraps any `S: Storage` with +post-mutation NATS JetStream publishes, feature-gated behind `nats-events`.** + +### Event Type + +```rust +#[serde(tag = "event_type", rename_all = "snake_case")] +pub enum KogralEvent { + NodeSaved { graph: String, node_id: String, node_type: String }, + NodeDeleted { graph: String, node_id: String }, + GraphSaved { name: String, node_count: usize }, +} + +impl KogralEvent { + pub fn subject(&self) -> String { + match self { + Self::NodeSaved { graph, .. } => format!("kogral.{graph}.node.saved"), + Self::NodeDeleted { graph, .. } => format!("kogral.{graph}.node.deleted"), + Self::GraphSaved { name, .. } => format!("kogral.{name}.graph.saved"), + } + } +} +``` + +Events are serialized as JSON and published to NATS subjects derived from graph name. Consumers +can subscribe to `kogral.>` (all events), `kogral..>` (single graph), or specific event +types. + +### Decorator + +```rust +pub struct EventingStorage { + inner: S, + publisher: EventPublisher, + graph_name: String, +} +``` + +`EventingStorage` implements `Storage` by delegating to `inner`, then publishing the event. +Failures in publishing do **not** roll back the storage mutation — publishing is best-effort. + +### Type Erasure + +The factory returns `Box`. `impl Storage for Box` (added in the same +change) enables `EventingStorage>` to satisfy `S: Storage + Send` without the +factory knowing the concrete inner type: + +```rust +pub async fn build_eventing( + config: &StorageConfig, + base_path: PathBuf, + default_graph: impl Into, +) -> Result> { + let base = build(config, base_path).await?; // Box + let Some(nats_cfg) = &config.nats else { + return Ok(base); // no NATS config → no wrapping + }; + let stream = EventStream::connect(&nats_config).await?; + Ok(Box::new(EventingStorage::new(base, publisher, default_graph.into()))) +} +``` + +When `config.nats` is `None`, `build_eventing` is identical to `build` — callers always use +`build_eventing` and get wrapping only when configured. + +### Config Schema + +```nickel +nats = { + enabled = false, + url = "nats://localhost:4222", + stream_name = "KOGRAL", + consumer_name = "kogral-consumer", + subjects = ["kogral.>"], + require_signed_messages = false, + trusted_nkeys = [], +} +``` + +`NatsEventConfig` converts to `platform_nats::NatsConfig` via `From`: + +```rust +impl From for platform_nats::NatsConfig { + fn from(c: NatsEventConfig) -> Self { + Self { + url: c.url, + stream_name: c.stream_name, + consumer_name: c.consumer_name, + subjects: c.subjects, + nkey_seed: c.nkey_seed, + trusted_nkeys: c.trusted_nkeys, + require_signed_messages: c.require_signed_messages, + } + } +} +``` + +### Orchestration Bridge + +The `orchestration` feature (depends on `nats-events`) provides `pipeline_context_from_event()` +mapping `KogralEvent` to `stratum_orchestrator::PipelineContext` for triggering downstream +automation pipelines: + +```rust +pub fn pipeline_context_from_event( + event: &KogralEvent, + extra: serde_json::Value, +) -> PipelineContext { + PipelineContext::new(Uuid::new_v4().to_string(), event.subject(), extra) +} +``` + +### ncl-import-resolver + +Nickel config files may `import` other `.ncl` files. When the Nickel CLI is invoked without a +resolver, imports from outside the project root fail. `resolve_nickel_imports()` runs +`ncl-import-resolver` against a `resolver-manifest.json` in the same directory as the config +file before calling `nickel export`: + +```rust +fn resolve_nickel_imports(ncl_file: &Path) -> Result<()> { + let manifest = ncl_file.parent().unwrap_or(Path::new(".")) + .join("resolver-manifest.json"); + if !manifest.exists() { + return Ok(()); // no manifest → no-op, not an error + } + let output = Command::new("ncl-import-resolver") + .arg(&manifest) + .output() + .map_err(|e| KbError::NickelExport(format!("ncl-import-resolver unavailable: {e}")))?; + if !output.status.success() { + return Err(KbError::NickelExport( + format!("ncl-import-resolver failed: {}", String::from_utf8_lossy(&output.stderr)) + )); + } + Ok(()) +} +``` + +The resolver step is a no-op when `resolver-manifest.json` is absent, so existing single-file +configs are unaffected. + +--- + +## Consequences + +### Positive + +- Storage mutations produce observable events with no code changes in callers +- Subject hierarchy (`kogral..*`) enables fine-grained consumer subscriptions +- NATS disabled at compile time (no overhead when `nats-events` feature is off) +- NATS disabled at runtime (no overhead when `config.nats` is `None`) +- Publishing failures are non-fatal — storage mutation already committed +- `ncl-import-resolver` enables multi-file Nickel configs without shell wrapper scripts + +### Negative + +- At-least-once semantics: consumers must be idempotent on duplicate events +- Publishing is fire-and-forget — no delivery confirmation before `save_node` returns +- `orchestration` feature adds `stratum-orchestrator` as a workspace dependency (compile time) + +### Neutral + +- `EventPublisher` holds an `Arc` so `EventingStorage` is `Clone`-friendly +- NATS subjects use graph name as the second token — graphs named `>` or `*` would conflict + with NATS wildcards (acceptable constraint; graph names are user-defined identifiers) + +--- + +## Alternatives Considered + +### Callbacks / Observer Pattern in `Storage` Trait + +**Rejected**: Adds optional complexity to the trait itself. Every `Storage` implementation +would need to support callback registration, even when events are never used. + +### Database Triggers (SurrealDB `DEFINE EVENT`) + +**Rejected**: Couples event logic to the SurrealDB backend. Filesystem and Memory backends +would produce no events, breaking consistency. + +### tokio Broadcast Channel + +**Rejected**: In-process only, no persistence, no fan-out beyond process boundary. Suitable +for internal state notification, not cross-service event streams. + +--- + +## References + +- [events.rs](../../../crates/kogral-core/src/events.rs) +- [orchestration.rs](../../../crates/kogral-core/src/orchestration.rs) +- [factory.rs](../../../crates/kogral-core/src/storage/factory.rs) +- [platform-nats](https://github.com/stratumiops/platform-nats) +- [NATS JetStream docs](https://docs.nats.io/nats-concepts/jetstream) + +--- + +## Revision History + +| Date | Author | Change | +|---|---|---| +| 2026-02-21 | Architecture Team | Initial decision — NATS JetStream + EventingStorage + ncl-import-resolver | + +--- + +**Previous ADR**: [ADR-006: SurrealDB v3 Engine Abstraction](006-surrealdb-v3-engine-abstraction.md) diff --git a/docs/storage/surrealdb.md b/docs/storage/surrealdb.md index df50e78..d2fcc5e 100644 --- a/docs/storage/surrealdb.md +++ b/docs/storage/surrealdb.md @@ -1 +1,176 @@ # SurrealDB Storage + +KOGRAL uses SurrealDB 3.0 as its scalable backend, enabled via the `surrealdb-backend` Cargo feature. +The integration is built on `surrealdb::engine::any::connect(url)`, which selects the engine at +runtime from a URL scheme — no recompilation required when switching between embedded, in-memory, +or remote deployments. + +## Dual Hot/Cold Layout + +`SurrealDbStorage` maintains two independent database connections: + +| Connection | Default engine | URL | Purpose | +|---|---|---|---| +| `graph_db` | SurrealKV (B-tree) | `surrealkv://.kogral/db/graph` | Nodes, edges, graph metadata | +| `hot_db` | RocksDB (LSM) | `rocksdb://.kogral/db/hot` | Embeddings, session logs, append data | + +SurrealKV's B-tree layout favours point lookups and range scans (node/graph queries). RocksDB's +LSM tree favours sequential writes (embedding vectors, event logs). Separating them avoids +write-amplification cross-contamination. + +## Supported Engines + +All four engines are compiled in when the `surrealdb-backend` feature is active: + +| Nickel `engine` | URL scheme | Cargo feature | Use case | +|---|---|---|---| +| `mem` | `mem://` | `kv-mem` | Tests, ephemeral dev sessions | +| `surreal_kv` | `surrealkv://path` | `kv-surrealkv` | Embedded production (default graph) | +| `rocks_db` | `rocksdb://path` | `kv-rocksdb` | Embedded production (default hot) | +| `ws` | `ws://host:port` | `protocol-ws` | Remote team / shared deployments | + +## Configuration + +### Embedded (default production) + +```nickel +storage = { + primary = 'filesystem, + secondary = { + enabled = true, + type = 'surrealdb, + surrealdb = { + graph = { engine = "surreal_kv", path = ".kogral/db/graph" }, + hot = { engine = "rocks_db", path = ".kogral/db/hot" }, + namespace = "kogral", + }, + }, +} +``` + +### In-Memory (tests, CI) + +```nickel +storage = { + primary = 'memory, + secondary = { + enabled = true, + type = 'surrealdb, + surrealdb = { + graph = { engine = "mem" }, + hot = { engine = "mem" }, + namespace = "test", + }, + }, +} +``` + +### Remote WebSocket (team/shared deployment) + +```nickel +storage = { + primary = 'filesystem, + secondary = { + enabled = true, + type = 'surrealdb, + surrealdb = { + graph = { engine = "ws", url = "ws://kb.company.com:8000" }, + hot = { engine = "ws", url = "ws://kb.company.com:8000" }, + namespace = "engineering", + }, + }, +} +``` + +## Building with SurrealDB Support + +```bash +# Debug build +cargo build -p kogral-core --features surrealdb-backend + +# All features (SurrealDB + NATS + orchestration) +cargo build -p kogral-core --all-features + +# Justfile shortcut +just build::core-db +``` + +## CRUD Pattern + +All CRUD operations route through `serde_json::Value` as the intermediary type (SurrealDB 3.0 +removed `IntoSurrealValue`/`SurrealValue`). The key format for nodes is +`("{graph_name}__{node_id}")` on the `nodes` table: + +```rust +// upsert +let row = serde_json::to_value(node)?; +let _: Option = graph_db + .upsert(("nodes", format!("{graph_name}__{}", node.id))) + .content(row) + .await?; + +// select +let raw: Option = graph_db + .select(("nodes", format!("{graph_name}__{node_id}"))) + .await?; + +// delete +let _: Option = graph_db + .delete(("nodes", format!("{graph_name}__{node_id}"))) + .await?; + +// list by graph (query API) +let nodes: Vec = graph_db + .query("SELECT * FROM nodes WHERE project = $g") + .bind(("g", graph_name.to_string())) + .await? + .take(0)?; +``` + +`.bind()` parameters require owned `String` values — `&str` slices do not satisfy the `'static` +bound in SurrealDB 3.0's bind API. + +## Hot Data Methods + +`SurrealDbStorage` exposes direct methods on `hot_db` that are outside the `Storage` trait: + +```rust +// Store embedding vector for a node +pub async fn save_embedding(&self, node_id: &str, vector: &[f32]) -> Result<()> + +// Append a session event to the log +pub async fn log_session(&self, entry: &serde_json::Value) -> Result<()> +``` + +These operate on the `embeddings` and `sessions` tables in `hot_db`. + +## NATS Event Integration + +When the `nats-events` feature is enabled and `config.nats` is present, the storage factory +wraps `SurrealDbStorage` (or any other backend) with `EventingStorage`. Every mutation emits +a NATS JetStream event: + +```text +kogral..node.saved → NodeSaved { graph, node_id, node_type } +kogral..node.deleted → NodeDeleted { graph, node_id } +kogral..graph.saved → GraphSaved { name, node_count } +``` + +See [ADR-007: NATS Event Publishing](../architecture/adrs/007-nats-event-publishing.md) for design rationale. + +## Feature Matrix + +| Feature | Includes | +|---|---| +| `filesystem` (default) | `FilesystemStorage` only | +| `surrealdb-backend` | `SurrealDbStorage` + all four engines | +| `nats-events` | `EventingStorage`, `KogralEvent`, NATS JetStream client | +| `orchestration` | `nats-events` + `stratum-orchestrator` bridge | +| `full` | All of the above | + +## Related + +- [ADR-003: Hybrid Storage Strategy](../architecture/adrs/003-hybrid-storage.md) +- [ADR-006: SurrealDB 3.0 Engine Abstraction](../architecture/adrs/006-surrealdb-v3-engine-abstraction.md) +- [storage/factory.rs](../../crates/kogral-core/src/storage/factory.rs) +- [storage/surrealdb.rs](../../crates/kogral-core/src/storage/surrealdb.rs) diff --git a/schemas/kogral/contracts.ncl b/schemas/kogral/contracts.ncl index 07b7f28..e42bb79 100644 --- a/schemas/kogral/contracts.ncl +++ b/schemas/kogral/contracts.ncl @@ -37,6 +37,43 @@ StorageType = [| 'filesystem, 'memory, 'surrealdb |], + # SurrealEngineConfig — tagged union via `engine` field + # Matches Rust's #[serde(tag = "engine", rename_all = "snake_case")] enum. + SurrealEngineValidator = fun label value => + let engines = ["mem", "surreal_kv", "rocks_db", "ws"] in + let engine = value.engine in + if std.array.any (fun e => e == engine) engines then + value + else + std.contract.blame_with_message + "engine must be one of: \"mem\", \"surreal_kv\", \"rocks_db\", \"ws\"" + label, + + SurrealEngineConfig = { + engine | String + | doc "Engine type: \"mem\", \"surreal_kv\", \"rocks_db\", or \"ws\"", + path | String + | doc "Filesystem path for embedded engines (surreal_kv, rocks_db)" + | optional, + url | String + | doc "Remote URL for ws engine" + | optional, + } | SurrealEngineValidator, + + SurrealDbBackendConfig = { + graph | SurrealEngineConfig + | doc "Engine for graph/relational data (default: SurrealKV)" + | default = { engine = "surreal_kv", path = ".kogral/db/graph" }, + + hot | SurrealEngineConfig + | doc "Engine for hot/append data (default: RocksDB)" + | default = { engine = "rocks_db", path = ".kogral/db/hot" }, + + namespace | String + | doc "SurrealDB namespace shared by both engines" + | default = "kogral", + }, + SecondaryStorageConfig = { enabled | Bool | doc "Enable secondary storage backend" @@ -46,25 +83,39 @@ | doc "Secondary storage type" | default = 'surrealdb, + surrealdb | SurrealDbBackendConfig + | doc "SurrealDB engine layout (dual hot/cold)" + | default = {}, + }, + + NatsEventConfig = { + enabled | Bool + | doc "Whether to activate NATS event publishing" + | default = false, + url | String - | doc "Connection URL" - | default = "ws://localhost:8000", + | doc "NATS server URL" + | default = "nats://localhost:4222", - namespace | String - | doc "SurrealDB namespace" - | default = "kb", + stream_name | String + | doc "JetStream stream name" + | default = "KOGRAL", - database | String - | doc "SurrealDB database name" - | default = "default", + consumer_name | String + | doc "Durable consumer name" + | default = "kogral-consumer", - username | String - | doc "Database username" - | optional, + subjects | Array String + | doc "Subjects captured by this stream" + | default = ["kogral.>"], - password | String - | doc "Database password" - | optional, + require_signed_messages | Bool + | doc "Reject messages without valid NKey signatures" + | default = false, + + trusted_nkeys | Array String + | doc "Public NKeys whose signatures are trusted" + | default = [], }, StorageConfig = { @@ -75,6 +126,10 @@ secondary | SecondaryStorageConfig | doc "Optional secondary storage" | default = { enabled = false }, + + nats | NatsEventConfig + | doc "NATS JetStream event publishing" + | default = {}, }, # === EMBEDDINGS === diff --git a/schemas/kogral/defaults.ncl b/schemas/kogral/defaults.ncl index 2ae3033..f70929d 100644 --- a/schemas/kogral/defaults.ncl +++ b/schemas/kogral/defaults.ncl @@ -28,9 +28,20 @@ let contracts = import "contracts.ncl" in secondary = { enabled = false, type = 'surrealdb, - url = "ws://localhost:8000", - namespace = "kogral", - database = "default", + surrealdb = { + graph = { engine = "surreal_kv", path = ".kogral/db/graph" }, + hot = { engine = "rocks_db", path = ".kogral/db/hot" }, + namespace = "kogral", + }, + }, + nats = { + enabled = false, + url = "nats://localhost:4222", + stream_name = "KOGRAL", + consumer_name = "kogral-consumer", + subjects = ["kogral.>"], + require_signed_messages = false, + trusted_nkeys = [], }, },