diff --git a/CLAUDE.md b/CLAUDE.md index 8c3d27d..167d4fe 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,10 +1,41 @@ # RobustMQ SDK — Project Guide -## What this repo is +## What is RobustMQ -Multi-language client SDK for RobustMQ, a unified messaging broker that supports MQTT, Kafka, -NATS, AMQP, and mq9 on a shared storage layer. This SDK focuses on **mq9** — the AI-native -async communication protocol built on top of NATS. +RobustMQ is a **unified messaging platform written in Rust** — one binary, one broker, zero external dependencies. +It natively runs MQTT, Kafka, NATS, AMQP, and mq9 on a **shared pluggable storage layer**. + +Core architecture (3-tier, fully decoupled): +- **Broker** (stateless compute): protocol parsing, TCP/TLS/WebSocket/WSS/QUIC +- **Meta Service**: Raft-based cluster coordination, replaces ZooKeeper +- **Storage Engine**: pluggable — Memory / RocksDB / File Segment, S3 tiering + +Key differentiators vs Kafka/NATS: +- Multi-protocol on one deployment (no bridging, no data silos) +- Compute-storage separation → scale independently in seconds (not hours) +- Rust: no GC pauses, predictable latency +- mq9: AI-native async mailbox protocol (see below) + +## What this SDK is + +Multi-language client SDK for RobustMQ. Currently implements **mq9** — more protocols (MQTT, Kafka, AMQP) +will be added as RobustMQ matures. + +**Package naming strategy (Method A — single SDK per language):** +Each language ships one package that grows to cover all protocols via sub-modules. +Users install one package and import the protocol they need. + +| Language | Published package | mq9 import/usage | +| ---------- | ---------------------------- | --------------------------------------------- | +| Python | `robustmq` (PyPI) | `from robustmq.mq9 import Client` | +| Go | `robustmq-sdk/go` (git tag) | `import "github.com/robustmq/robustmq-sdk/go/mq9"` | +| JavaScript | `@robustmq/sdk` (npm) | `import { MQ9Client } from '@robustmq/sdk/mq9'` | +| Java | `com.robustmq:robustmq` | `import com.robustmq.mq9.*` | +| Rust | `robustmq` (crates.io) | `use robustmq::mq9::MQ9Client` | +| C# | `RobustMQ` (NuGet) | `using RobustMQ.Mq9` | + +When new protocols are added (e.g. MQTT, Kafka), they live in sub-modules of the same package: +`robustmq.mqtt`, `@robustmq/sdk/mqtt`, `com.robustmq.mqtt`, `robustmq::mqtt`, etc. The owner does not intervene in implementation details. Claude makes all technical decisions and drives the project forward autonomously. @@ -13,29 +44,31 @@ and drives the project forward autonomously. ## Version management -Source of truth: root `VERSION` file (currently `1.0.0`). +Source of truth: root `VERSION` file (currently `0.3.5`). When bumping the version, update `VERSION` and all 6 build files in one commit: - Python: `python/pyproject.toml` + `python/robustmq/__init__.py` - Rust: `rust/Cargo.toml` -- Go: git tag only (e.g. `v1.0.0`) — no file to update +- Go: git tag only (e.g. `v0.3.5`) — no file to update - JavaScript: `javascript/package.json` - Java: `java/pom.xml` - C#: `csharp/RobustMQ.Mq9/RobustMQ.Mq9.csproj` +Also update version references in `demo/`, `docs/`, and `README.md`. + --- ## SDK implementation status -| Language | Package/Import | Class | NATS lib | Status | -| ---------- | ----------------- | ----------- | ------------ | -------------- | -| Python | `robustmq.mq9` | `MQ9Client` | `nats-py` | Implemented | -| Rust | `robustmq_mq9` | `MQ9Client` | `async-nats` | Scaffolded | -| Go | `mq9` (pkg) | `MQ9Client` | `nats.go` | Scaffolded | -| JavaScript | `@robustmq/mq9` | `MQ9Client` | `nats` v2 | Scaffolded | -| Java | `com.robustmq.mq9` | `MQ9Client` | `jnats` | Scaffolded | -| C# | `RobustMQ.Mq9` | `MQ9Client` | `NATS.Net` | Scaffolded | +| Language | Package/Import | Class | NATS lib | Status | +| ---------- | ----------------------- | ----------- | ------------ | -------------- | +| Python | `robustmq.mq9` | `MQ9Client` | `nats-py` | Implemented | +| Rust | `robustmq::mq9` | `MQ9Client` | `async-nats` | Scaffolded | +| Go | `mq9` (pkg) | `MQ9Client` | `nats.go` | Scaffolded | +| JavaScript | `@robustmq/sdk/mq9` | `MQ9Client` | `nats` v2 | Scaffolded | +| Java | `com.robustmq.mq9` | `MQ9Client` | `jnats` | Scaffolded | +| C# | `RobustMQ.Mq9` (ns) | `MQ9Client` | `NATS.Net` | Scaffolded | Go constructor convention: `NewMQ9Client(...)` (struct, not class). @@ -54,15 +87,23 @@ java/ # 🚧 Scaffolded only csharp/ # 🚧 Scaffolded only docs/ mq9-protocol.md # Authoritative protocol spec — read before implementing -demo/ # End-to-end demo scripts, one per language +demo/ + demo-python/ # Standalone Python demo project + demo-go/ # Standalone Go demo project + demo-javascript/ # Standalone JavaScript demo project + demo-java/ # Standalone Java demo project (Maven) + demo-rust/ # Standalone Rust demo project + demo-csharp/ # Standalone C# demo project ``` --- ## mq9 protocol -mq9 gives AI agents a durable mailbox. Messages persist until TTL expires; senders and -receivers do not need to be online simultaneously. +mq9 is RobustMQ's AI-native async communication protocol. It gives AI agents a durable mailbox — +messages persist until TTL expires; senders and receivers do not need to be online simultaneously. + +Built on top of NATS (transport layer), mq9 adds store-first semantics and priority queuing. ### Subject structure @@ -137,7 +178,7 @@ Return types: ### All languages - NATS client is the only required runtime dependency -- Use `request/reply` for CREATE, LIST, DELETE, PUBLIC.LIST +- Use `request/reply` for CREATE, LIST, DELETE - Use plain `publish` for SEND (no reply needed) - Raise a typed `MQ9Error` (with `.code: int`) on server error responses - Tests mock the NATS connection — no live server required @@ -182,15 +223,14 @@ Return types: ## Demo module -Location: `demo/` -One script per language, all running the same scenario: +Location: `demo/` +Each language has a standalone project that imports the published SDK v0.3.5. +All demos run the same scenario: 1. Connect to `nats://localhost:4222` 2. Create a private mailbox (TTL 60s) 3. Send 3 messages (high / normal / low priority) 4. Subscribe and print received messages -5. List mailbox, delete one message -6. Create a public mailbox and discover it via PUBLIC.LIST +5. List mailbox metadata, delete one message +6. Create a public mailbox 7. Close connection - -Demo scripts are standalone — they import the SDK from the local source tree, not a published package. diff --git a/README.md b/README.md index 6558545..fb28efb 100644 --- a/README.md +++ b/README.md @@ -34,12 +34,12 @@ Full spec: [docs/mq9-protocol.md](docs/mq9-protocol.md) | Language | Package | Version | Install | |----------|---------|---------|---------| -| Python | `robustmq-mq9` | 1.0.0 | `pip install robustmq-mq9` | -| Go | `github.com/robustmq/robustmq-sdk/go` | v1.0.0 | `go get github.com/robustmq/robustmq-sdk/go` | -| JavaScript | `@robustmq/mq9` | 1.0.0 | `npm install @robustmq/mq9` | -| Java | `com.robustmq:robustmq-sdk` | 1.0.0 | Maven / Gradle (see below) | -| Rust | `robustmq` | 1.0.0 | `cargo add robustmq` | -| C# | `RobustMQ.Mq9` | 1.0.0 | `dotnet add package RobustMQ.Mq9` | +| Python | `robustmq` | 0.3.5 | `pip install robustmq` | +| Go | `github.com/robustmq/robustmq-sdk/go` | v0.3.5 | `go get github.com/robustmq/robustmq-sdk/go` | +| JavaScript | `@robustmq/sdk` | 0.3.5 | `npm install @robustmq/sdk` | +| Java | `com.robustmq:robustmq` | 0.3.5 | Maven / Gradle (see below) | +| Rust | `robustmq` | 0.3.5 | `cargo add robustmq` | +| C# | `RobustMQ` | 0.3.5 | `dotnet add package RobustMQ` | --- @@ -47,12 +47,12 @@ Full spec: [docs/mq9-protocol.md](docs/mq9-protocol.md) **Python** ```bash -pip install robustmq-mq9 +pip install robustmq ``` ```python from robustmq.mq9 import Client, Priority -async with Client("nats://localhost:4222") as client: +async with Client("nats://demo.robustmq.com:4222") as client: mailbox = await client.create(ttl=3600) await client.send(mailbox.mail_id, b"hello", priority=Priority.NORMAL) @@ -69,7 +69,7 @@ go get github.com/robustmq/robustmq-sdk/go ```go import "github.com/robustmq/robustmq-sdk/go/mq9" -c := mq9.NewMQ9Client("nats://localhost:4222") +c := mq9.NewMQ9Client("nats://demo.robustmq.com:4222") c.Connect() mailbox, _ := c.Create(3600) c.Send(mailbox.MailID, []byte("hello"), mq9.Normal) @@ -77,12 +77,12 @@ c.Send(mailbox.MailID, []byte("hello"), mq9.Normal) **JavaScript / TypeScript** ```bash -npm install @robustmq/mq9 +npm install @robustmq/sdk ``` ```typescript -import { MQ9Client } from "@robustmq/mq9"; +import { MQ9Client } from "@robustmq/sdk/mq9"; -const client = new MQ9Client({ server: "nats://localhost:4222" }); +const client = new MQ9Client({ server: "nats://demo.robustmq.com:4222" }); await client.connect(); const mailbox = await client.create({ ttl: 3600 }); await client.send(mailbox.mailId, "hello", "normal"); @@ -92,14 +92,14 @@ await client.send(mailbox.mailId, "hello", "normal"); ```xml com.robustmq - robustmq-sdk - 1.0.0 + robustmq + 0.3.5 ``` ```java import com.robustmq.mq9.*; -MQ9Client client = new MQ9Client("nats://localhost:4222"); +MQ9Client client = new MQ9Client("nats://demo.robustmq.com:4222"); client.connect(); Mailbox mailbox = client.create(3600).get(); client.send(mailbox.getMailId(), "hello".getBytes(), Priority.NORMAL).get(); @@ -107,31 +107,31 @@ client.send(mailbox.getMailId(), "hello".getBytes(), Priority.NORMAL).get(); **Java (Gradle)** ```groovy -implementation 'com.robustmq:robustmq-sdk:1.0.0' +implementation 'com.robustmq:robustmq:0.3.5' ``` **Rust** ```toml [dependencies] -robustmq = "1.0" +robustmq = "0.3" tokio = { version = "1", features = ["full"] } ``` ```rust use robustmq::mq9::{MQ9Client, Priority}; -let client = MQ9Client::connect("nats://localhost:4222").await?; +let client = MQ9Client::connect("nats://demo.robustmq.com:4222").await?; let mailbox = client.create(3600, false, "", "").await?; client.send(&mailbox.mail_id, b"hello", Priority::Normal).await?; ``` **C#** ```bash -dotnet add package RobustMQ.Mq9 +dotnet add package RobustMQ ``` ```csharp using RobustMQ.Mq9; -await using var client = new MQ9Client("nats://localhost:4222"); +await using var client = new MQ9Client("nats://demo.robustmq.com:4222"); await client.ConnectAsync(); var mailbox = await client.CreateAsync(3600); await client.SendAsync(mailbox.MailId, "hello"u8.ToArray(), Priority.Normal); @@ -154,7 +154,7 @@ await client.SendAsync(mailbox.MailId, "hello"u8.ToArray(), Priority.Normal); ## Running the demo -Each demo is a standalone project that connects to `nats://localhost:4222` and runs the same scenario: +Each demo is a standalone project that connects to `nats://demo.robustmq.com:4222` and runs the same scenario: 1. Create a private mailbox (TTL 60s) 2. Send 3 messages (high / normal / low priority) 3. Subscribe and print received messages @@ -200,7 +200,7 @@ demo/ demo-java/ # Java standalone demo project (Maven) demo-rust/ # Rust standalone demo project demo-csharp/ # C# standalone demo project -VERSION # Canonical version (currently 1.0.0) +VERSION # Canonical version (currently 0.3.5) ``` --- diff --git a/VERSION b/VERSION index 3eefcb9..c2c0004 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.0 +0.3.5 diff --git a/csharp/RobustMQ.Mq9/MQ9Client.cs b/csharp/RobustMQ.Mq9/MQ9Client.cs index 65ded5e..d2407f9 100644 --- a/csharp/RobustMQ.Mq9/MQ9Client.cs +++ b/csharp/RobustMQ.Mq9/MQ9Client.cs @@ -213,20 +213,19 @@ private static Mq9Message ParseMessageNode(string mailId, JsonNode node) file sealed class SubscriptionHandle : IAsyncDisposable { - private readonly IDisposable _sub; + private readonly IAsyncDisposable _sub; private readonly CancellationTokenSource _cts; - public SubscriptionHandle(IDisposable sub, CancellationTokenSource cts) + public SubscriptionHandle(IAsyncDisposable sub, CancellationTokenSource cts) { _sub = sub; _cts = cts; } - public ValueTask DisposeAsync() + public async ValueTask DisposeAsync() { _cts.Cancel(); - _sub.Dispose(); + await _sub.DisposeAsync(); _cts.Dispose(); - return ValueTask.CompletedTask; } } diff --git a/csharp/RobustMQ.Mq9/RobustMQ.Mq9.csproj b/csharp/RobustMQ.Mq9/RobustMQ.Mq9.csproj index 4ae4626..1a6f203 100644 --- a/csharp/RobustMQ.Mq9/RobustMQ.Mq9.csproj +++ b/csharp/RobustMQ.Mq9/RobustMQ.Mq9.csproj @@ -4,10 +4,11 @@ net8.0 enable enable + RobustMQ RobustMQ.Mq9 - RobustMQ.Mq9 - 1.0.0 - RobustMQ C# SDK — mq9 AI-native async messaging + RobustMQ + 0.3.5 + RobustMQ SDK — unified messaging for AI, IoT, and data pipelines Apache-2.0 @@ -15,4 +16,10 @@ + + + <_Parameter1>RobustMQ.Mq9.Tests + + + diff --git a/demo/demo-csharp/Program.cs b/demo/demo-csharp/Program.cs index 7235b3b..7401715 100644 --- a/demo/demo-csharp/Program.cs +++ b/demo/demo-csharp/Program.cs @@ -1,5 +1,5 @@ /** - * mq9 C# demo — connects to nats://localhost:4222 and runs the full scenario. + * mq9 C# demo — connects to nats://demo.robustmq.com:4222 and runs the full scenario. * * Run: * cd demo/demo-csharp @@ -9,7 +9,8 @@ using System.Text; using RobustMQ.Mq9; -await using var client = new MQ9Client("nats://localhost:4222"); +// demo.robustmq.com 是公共的 RobustMQ 服务,可用于验证功能和测试,也可修改为自己的服务地址。 +await using var client = new MQ9Client("nats://demo.robustmq.com:4222"); await client.ConnectAsync(); Console.WriteLine("[csharp] connected"); diff --git a/demo/demo-csharp/demo-csharp.csproj b/demo/demo-csharp/demo-csharp.csproj index bc3f7b2..e61b430 100644 --- a/demo/demo-csharp/demo-csharp.csproj +++ b/demo/demo-csharp/demo-csharp.csproj @@ -8,7 +8,7 @@ - + diff --git a/demo/demo-go/main.go b/demo/demo-go/main.go index 81b0926..575b831 100644 --- a/demo/demo-go/main.go +++ b/demo/demo-go/main.go @@ -1,4 +1,4 @@ -// mq9 Go demo — connects to nats://localhost:4222 and runs the full scenario. +// mq9 Go demo — connects to nats://demo.robustmq.com:4222 and runs the full scenario. // // Run: // @@ -15,7 +15,8 @@ import ( ) func main() { - c := mq9.NewMQ9Client("nats://localhost:4222") + // demo.robustmq.com 是公共的 RobustMQ 服务,可用于验证功能和测试,也可修改为自己的服务地址。 + c := mq9.NewMQ9Client("nats://demo.robustmq.com:4222") if err := c.Connect(); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) diff --git a/demo/demo-java/pom.xml b/demo/demo-java/pom.xml index d573c04..6da7d8a 100644 --- a/demo/demo-java/pom.xml +++ b/demo/demo-java/pom.xml @@ -7,7 +7,7 @@ io.robustmq.demo demo-java - 1.0.0 + 0.3.5 jar RobustMQ mq9 Java Demo @@ -21,8 +21,8 @@ com.robustmq - robustmq-sdk - 1.0.0 + robustmq + 0.3.5 diff --git a/demo/demo-java/src/main/java/com/robustmq/demo/Demo.java b/demo/demo-java/src/main/java/com/robustmq/demo/Demo.java index f897b42..4f0d6b9 100644 --- a/demo/demo-java/src/main/java/com/robustmq/demo/Demo.java +++ b/demo/demo-java/src/main/java/com/robustmq/demo/Demo.java @@ -9,7 +9,7 @@ import java.util.concurrent.TimeUnit; /** - * mq9 Java demo — connects to nats://localhost:4222 and runs the full scenario. + * mq9 Java demo — connects to nats://demo.robustmq.com:4222 and runs the full scenario. * * Run: * cd demo/demo-java @@ -17,7 +17,8 @@ */ public class Demo { public static void main(String[] args) throws Exception { - MQ9Client client = new MQ9Client("nats://localhost:4222"); + // demo.robustmq.com 是公共的 RobustMQ 服务,可用于验证功能和测试,也可修改为自己的服务地址。 + MQ9Client client = new MQ9Client("nats://demo.robustmq.com:4222"); client.connect(); System.out.println("[java] connected"); diff --git a/demo/demo-javascript/demo.js b/demo/demo-javascript/demo.js index 0a48fd5..c82a8f9 100644 --- a/demo/demo-javascript/demo.js +++ b/demo/demo-javascript/demo.js @@ -1,5 +1,5 @@ /** - * mq9 JavaScript demo — connects to nats://localhost:4222 and runs the full scenario. + * mq9 JavaScript demo — connects to nats://demo.robustmq.com:4222 and runs the full scenario. * * Run: * cd demo/demo-javascript @@ -7,10 +7,11 @@ * npm start */ -const { MQ9Client } = require("@robustmq/mq9"); +const { MQ9Client } = require("@robustmq/sdk/mq9"); async function main() { - const client = new MQ9Client({ server: "nats://localhost:4222" }); + // demo.robustmq.com 是公共的 RobustMQ 服务,可用于验证功能和测试,也可修改为自己的服务地址。 + const client = new MQ9Client({ server: "nats://demo.robustmq.com:4222" }); await client.connect(); console.log("[js] connected"); diff --git a/demo/demo-javascript/package.json b/demo/demo-javascript/package.json index 5d3e5be..1a620cd 100644 --- a/demo/demo-javascript/package.json +++ b/demo/demo-javascript/package.json @@ -8,6 +8,6 @@ "start": "node demo.js" }, "dependencies": { - "@robustmq/mq9": "1.0.0" + "@robustmq/sdk": "0.3.5" } } diff --git a/demo/demo-python/demo.py b/demo/demo-python/demo.py index 5d0995e..c050c78 100644 --- a/demo/demo-python/demo.py +++ b/demo/demo-python/demo.py @@ -1,5 +1,5 @@ """ -mq9 Python demo — connects to nats://localhost:4222 and runs the full scenario. +mq9 Python demo — connects to nats://demo.robustmq.com:4222 and runs the full scenario. Run: cd demo/demo-python @@ -12,7 +12,8 @@ async def main() -> None: - client = Client(server="nats://localhost:4222") + # demo.robustmq.com 是公共的 RobustMQ 服务,可用于验证功能和测试,也可修改为自己的服务地址。 + client = Client(server="nats://demo.robustmq.com:4222") await client.connect() print("[python] connected") diff --git a/demo/demo-python/pyproject.toml b/demo/demo-python/pyproject.toml index 84e277a..3d39314 100644 --- a/demo/demo-python/pyproject.toml +++ b/demo/demo-python/pyproject.toml @@ -1,9 +1,9 @@ [project] name = "demo-python" -version = "1.0.0" +version = "0.3.5" requires-python = ">=3.10" dependencies = [ - "robustmq-mq9==1.0.0", + "robustmq==0.3.5", ] [build-system] diff --git a/demo/demo-python/requirements.txt b/demo/demo-python/requirements.txt index 20f1182..dc44c8e 100644 --- a/demo/demo-python/requirements.txt +++ b/demo/demo-python/requirements.txt @@ -1 +1 @@ -robustmq-mq9==1.0.0 +robustmq==0.3.5 diff --git a/demo/demo-rust/Cargo.toml b/demo/demo-rust/Cargo.toml index 42c8cae..23a42e9 100644 --- a/demo/demo-rust/Cargo.toml +++ b/demo/demo-rust/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "demo-rust" -version = "1.0.0" +version = "0.3.5" edition = "2021" [[bin]] @@ -8,5 +8,5 @@ name = "demo" path = "src/main.rs" [dependencies] -robustmq = { version = "1.0.0", features = ["mq9"] } +robustmq = { version = "0.3.5", features = ["mq9"] } tokio = { version = "1", features = ["full"] } diff --git a/demo/demo-rust/src/main.rs b/demo/demo-rust/src/main.rs index 04e7a1b..af662d0 100644 --- a/demo/demo-rust/src/main.rs +++ b/demo/demo-rust/src/main.rs @@ -1,4 +1,4 @@ -// mq9 Rust demo — connects to nats://localhost:4222 and runs the full scenario. +// mq9 Rust demo — connects to nats://demo.robustmq.com:4222 and runs the full scenario. // // Run: // cd demo/demo-rust @@ -9,7 +9,8 @@ use tokio::time::{sleep, Duration}; #[tokio::main] async fn main() -> Result<(), Box> { - let client = MQ9Client::connect("nats://localhost:4222").await?; + // demo.robustmq.com 是公共的 RobustMQ 服务,可用于验证功能和测试,也可修改为自己的服务地址。 + let client = MQ9Client::connect("nats://demo.robustmq.com:4222").await?; println!("[rust] connected"); // 1. Create a private mailbox (TTL 60s) diff --git a/docs/csharp.md b/docs/csharp.md index 7d2eaa2..7efdae7 100644 --- a/docs/csharp.md +++ b/docs/csharp.md @@ -1,12 +1,12 @@ # C# SDK -**Package:** `RobustMQ.Mq9` +**Package:** `RobustMQ` **Requires:** .NET 8+, `NATS.Net` ## Install ```bash -dotnet add package RobustMQ.Mq9 +dotnet add package RobustMQ ``` ## Quick start @@ -14,7 +14,7 @@ dotnet add package RobustMQ.Mq9 ```csharp using RobustMQ.Mq9; -await using var client = new MQ9Client("nats://localhost:4222"); +await using var client = new MQ9Client("nats://demo.robustmq.com:4222"); await client.ConnectAsync(); // Create mailbox @@ -39,7 +39,7 @@ await client.DeleteAsync(mailbox.MailId, metas[0].MsgId); ## API ```csharp -MQ9Client(string server = "nats://localhost:4222") // IAsyncDisposable +MQ9Client(string server = "nats://demo.robustmq.com:4222") // IAsyncDisposable Task ConnectAsync() ValueTask DisposeAsync() diff --git a/docs/go.md b/docs/go.md index 4a2b1ab..34b01d0 100644 --- a/docs/go.md +++ b/docs/go.md @@ -21,7 +21,7 @@ import ( ) func main() { - c := mq9.NewMQ9Client("nats://localhost:4222") + c := mq9.NewMQ9Client("nats://demo.robustmq.com:4222") c.Connect() defer c.Close() diff --git a/docs/java.md b/docs/java.md index eb7497d..d078547 100644 --- a/docs/java.md +++ b/docs/java.md @@ -8,8 +8,8 @@ ```xml com.robustmq - robustmq-sdk - 1.0.0 + robustmq + 0.3.5 ``` @@ -19,7 +19,7 @@ import com.robustmq.mq9.*; import java.util.List; -MQ9Client client = new MQ9Client("nats://localhost:4222"); +MQ9Client client = new MQ9Client("nats://demo.robustmq.com:4222"); client.connect(); // Create mailbox diff --git a/docs/javascript.md b/docs/javascript.md index 0e9e6fc..4679800 100644 --- a/docs/javascript.md +++ b/docs/javascript.md @@ -1,20 +1,20 @@ # JavaScript / TypeScript SDK -**Package:** `@robustmq/mq9` +**Package:** `@robustmq/sdk` **Requires:** Node.js 18+, `nats` v2 ## Install ```bash -npm install @robustmq/mq9 +npm install @robustmq/sdk ``` ## Quick start ```typescript -import { MQ9Client } from "@robustmq/mq9"; +import { MQ9Client } from "@robustmq/sdk/mq9"; -const client = new MQ9Client({ server: "nats://localhost:4222" }); +const client = new MQ9Client({ server: "nats://demo.robustmq.com:4222" }); await client.connect(); // Create mailbox diff --git a/docs/python.md b/docs/python.md index 5a73191..0aab513 100644 --- a/docs/python.md +++ b/docs/python.md @@ -6,7 +6,7 @@ ## Install ```bash -pip install robustmq-mq9 +pip install robustmq ``` ## Quick start @@ -16,7 +16,7 @@ import asyncio from robustmq.mq9 import Client, Priority async def main(): - async with Client(server="nats://localhost:4222") as client: + async with Client(server="nats://demo.robustmq.com:4222") as client: # Create mailbox mailbox = await client.create(ttl=3600) @@ -45,7 +45,7 @@ asyncio.run(main()) ## API ```python -Client(server="nats://localhost:4222", *, max_reconnect_attempts=10, +Client(server="nats://demo.robustmq.com:4222", *, max_reconnect_attempts=10, reconnect_time_wait=2.0, request_timeout=5.0) await client.connect() diff --git a/docs/rust.md b/docs/rust.md index 9cf5238..97852c6 100644 --- a/docs/rust.md +++ b/docs/rust.md @@ -7,7 +7,7 @@ ```toml [dependencies] -robustmq = "1.0" +robustmq = "0.3" tokio = { version = "1", features = ["full"] } ``` @@ -18,7 +18,7 @@ use robustmq::mq9::{MQ9Client, Priority}; #[tokio::main] async fn main() -> Result<(), Box> { - let client = MQ9Client::connect("nats://localhost:4222").await?; + let client = MQ9Client::connect("nats://demo.robustmq.com:4222").await?; // Create mailbox let mailbox = client.create(3600, false, "", "").await?; diff --git a/java/checkstyle.xml b/java/checkstyle.xml new file mode 100644 index 0000000..fe42e15 --- /dev/null +++ b/java/checkstyle.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/pom.xml b/java/pom.xml index 0a8ab66..461b4d0 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -6,12 +6,12 @@ 4.0.0 com.robustmq - robustmq-sdk - 1.0.0 + robustmq + 0.3.5 jar RobustMQ Java SDK - RobustMQ Java SDK — mq9 AI-native async messaging + RobustMQ Java SDK — unified messaging for AI, IoT, and data pipelines https://github.com/robustmq/robustmq-sdk @@ -99,6 +99,17 @@ + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.4.0 + + checkstyle.xml + true + true + warning + + diff --git a/java/src/main/java/com/robustmq/mq9/MQ9Client.java b/java/src/main/java/com/robustmq/mq9/MQ9Client.java index 55f1bad..2253c74 100644 --- a/java/src/main/java/com/robustmq/mq9/MQ9Client.java +++ b/java/src/main/java/com/robustmq/mq9/MQ9Client.java @@ -10,7 +10,6 @@ import io.nats.client.Options; import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.time.Duration; import java.util.ArrayList; import java.util.Base64; @@ -77,18 +76,18 @@ public void close() { // ── Create ──────────────────────────────────────────────────────────────── - public CompletableFuture create(int ttl) { + public CompletableFuture create(int ttl) { return createInternal(ttl, false, "", ""); } - public CompletableFuture createPublic(int ttl, String name, String desc) { + public CompletableFuture createPublic(int ttl, String name, String desc) { if (name == null || name.isEmpty()) { return CompletableFuture.failedFuture(new MQ9Error("name is required when public=true")); } return createInternal(ttl, true, name, desc != null ? desc : ""); } - private CompletableFuture createInternal(int ttl, boolean isPublic, + private CompletableFuture createInternal(int ttl, boolean isPublic, String name, String desc) { return CompletableFuture.supplyAsync(() -> { ObjectNode req = mapper.createObjectNode(); @@ -100,7 +99,7 @@ private CompletableFuture createInternal(int ttl, boole } JsonNode resp = doRequest(MAILBOX_CREATE, req); String mailId = resp.get("mail_id").asText(); - return new io.robustmq.mq9.Mailbox(mailId, isPublic, name, desc); + return new com.robustmq.mq9.Mailbox(mailId, isPublic, name, desc); }); } @@ -129,7 +128,7 @@ public CompletableFuture subscribe(String mailId, MessageHandler han : PREFIX + ".MAILBOX.MSG." + mailId + ".*"; Dispatcher dispatcher = nc.createDispatcher((Message msg) -> { - io.robustmq.mq9.Message m = parseIncoming(mailId, msg); + com.robustmq.mq9.Message m = parseIncoming(mailId, msg); handler.onMessage(m); }); @@ -201,7 +200,7 @@ private JsonNode doRequest(String subject, ObjectNode payload) { } } - private io.robustmq.mq9.Message parseIncoming(String mailId, Message raw) { + private com.robustmq.mq9.Message parseIncoming(String mailId, Message raw) { // Extract priority from subject last token String subject = raw.getSubject(); String[] parts = subject.split("\\."); @@ -218,14 +217,14 @@ private io.robustmq.mq9.Message parseIncoming(String mailId, Message raw) { // fall through to raw payload } - return new io.robustmq.mq9.Message("", mailId, priority, raw.getData()); + return new com.robustmq.mq9.Message("", mailId, priority, raw.getData()); } - private io.robustmq.mq9.Message parseMessageNode(String mailId, JsonNode node) { + private com.robustmq.mq9.Message parseMessageNode(String mailId, JsonNode node) { String msgId = node.path("msg_id").asText(""); Priority priority = Priority.fromString(node.path("priority").asText("normal")); String rawPayload = node.path("payload").asText(""); byte[] payload = rawPayload.isEmpty() ? new byte[0] : Base64.getDecoder().decode(rawPayload); - return new io.robustmq.mq9.Message(msgId, mailId, priority, payload); + return new com.robustmq.mq9.Message(msgId, mailId, priority, payload); } } diff --git a/javascript/eslint.config.js b/javascript/eslint.config.js new file mode 100644 index 0000000..aa57556 --- /dev/null +++ b/javascript/eslint.config.js @@ -0,0 +1,15 @@ +// @ts-check +const tseslint = require("typescript-eslint"); + +module.exports = tseslint.config( + ...tseslint.configs.recommended, + { + rules: { + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }], + }, + }, + { + ignores: ["dist/**", "node_modules/**"], + } +); diff --git a/javascript/package-lock.json b/javascript/package-lock.json index 727620a..ba30e9a 100644 --- a/javascript/package-lock.json +++ b/javascript/package-lock.json @@ -1,12 +1,12 @@ { - "name": "@robustmq/mq9", - "version": "1.0.0", + "name": "@robustmq/sdk", + "version": "0.3.5", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "@robustmq/mq9", - "version": "1.0.0", + "name": "@robustmq/sdk", + "version": "0.3.5", "license": "Apache-2.0", "dependencies": { "nats": "^2.27.0" @@ -14,9 +14,11 @@ "devDependencies": { "@types/jest": "^30.0.0", "@types/node": "^25.5.2", + "eslint": "^9.0.0", "jest": "^30.3.0", "ts-jest": "^29.0.0", - "typescript": "^6.0.2" + "typescript": "^6.0.2", + "typescript-eslint": "^8.0.0" } }, "node_modules/@babel/code-frame": { @@ -549,6 +551,270 @@ "tslib": "^2.4.0" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmmirror.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmmirror.com/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmmirror.com/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.13", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmmirror.com/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmmirror.com/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.5", + "resolved": "https://registry.npmmirror.com/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.13", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.4", + "resolved": "https://registry.npmmirror.com/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmmirror.com/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmmirror.com/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmmirror.com/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmmirror.com/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -1104,6 +1370,13 @@ "@babel/types": "^7.28.2" } }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmmirror.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", @@ -1142,6 +1415,13 @@ "pretty-format": "^30.0.0" } }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { "version": "25.5.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.2.tgz", @@ -1176,6 +1456,301 @@ "dev": true, "license": "MIT" }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.58.1", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.58.1.tgz", + "integrity": "sha512-eSkwoemjo76bdXl2MYqtxg51HNwUSkWfODUOQ3PaTLZGh9uIWWFZIjyjaJnex7wXDu+TRx+ATsnSxdN9YWfRTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.58.1", + "@typescript-eslint/type-utils": "8.58.1", + "@typescript-eslint/utils": "8.58.1", + "@typescript-eslint/visitor-keys": "8.58.1", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.58.1", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmmirror.com/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.58.1", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-8.58.1.tgz", + "integrity": "sha512-gGkiNMPqerb2cJSVcruigx9eHBlLG14fSdPdqMoOcBfh+vvn4iCq2C8MzUB89PrxOXk0y3GZ1yIWb9aOzL93bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.58.1", + "@typescript-eslint/types": "8.58.1", + "@typescript-eslint/typescript-estree": "8.58.1", + "@typescript-eslint/visitor-keys": "8.58.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.58.1", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/project-service/-/project-service-8.58.1.tgz", + "integrity": "sha512-gfQ8fk6cxhtptek+/8ZIqw8YrRW5048Gug8Ts5IYcMLCw18iUgrZAEY/D7s4hkI0FxEfGakKuPK/XUMPzPxi5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.58.1", + "@typescript-eslint/types": "^8.58.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.58.1", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-8.58.1.tgz", + "integrity": "sha512-TPYUEqJK6avLcEjumWsIuTpuYODTTDAtoMdt8ZZa93uWMTX13Nb8L5leSje1NluammvU+oI3QRr5lLXPgihX3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.58.1", + "@typescript-eslint/visitor-keys": "8.58.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.58.1", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.58.1.tgz", + "integrity": "sha512-JAr2hOIct2Q+qk3G+8YFfqkqi7sC86uNryT+2i5HzMa2MPjw4qNFvtjnw1IiA1rP7QhNKVe21mSSLaSjwA1Olw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.58.1", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-8.58.1.tgz", + "integrity": "sha512-HUFxvTJVroT+0rXVJC7eD5zol6ID+Sn5npVPWoFuHGg9Ncq5Q4EYstqR+UOqaNRFXi5TYkpXXkLhoCHe3G0+7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.58.1", + "@typescript-eslint/typescript-estree": "8.58.1", + "@typescript-eslint/utils": "8.58.1", + "debug": "^4.4.3", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.58.1", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-8.58.1.tgz", + "integrity": "sha512-io/dV5Aw5ezwzfPBBWLoT+5QfVtP8O7q4Kftjn5azJ88bYyp/ZMCsyW1lpKK46EXJcaYMZ1JtYj+s/7TdzmQMw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.58.1", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.58.1.tgz", + "integrity": "sha512-w4w7WR7GHOjqqPnvAYbazq+Y5oS68b9CzasGtnd6jIeOIeKUzYzupGTB2T4LTPSv4d+WPeccbxuneTFHYgAAWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.58.1", + "@typescript-eslint/tsconfig-utils": "8.58.1", + "@typescript-eslint/types": "8.58.1", + "@typescript-eslint/visitor-keys": "8.58.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.5.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.58.1", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-8.58.1.tgz", + "integrity": "sha512-Ln8R0tmWC7pTtLOzgJzYTXSCjJ9rDNHAqTaVONF4FEi2qwce8mD9iSOxOpLFFvWp/wBFlew0mjM1L1ihYWfBdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.58.1", + "@typescript-eslint/types": "8.58.1", + "@typescript-eslint/typescript-estree": "8.58.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.58.1", + "resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.58.1.tgz", + "integrity": "sha512-y+vH7QE8ycjoa0bWciFg7OpFcipUuem1ujhrdLtq1gByKwfbC7bPeKsiny9e0urg93DqwGcHey+bGRKCnF1nZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.58.1", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", @@ -1452,6 +2027,46 @@ "win32" ] }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.14.0", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -1983,6 +2598,13 @@ } } }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmmirror.com/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", @@ -2054,17 +2676,211 @@ "dev": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint": { + "version": "9.39.4", + "resolved": "https://registry.npmmirror.com/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.2", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.14.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.5", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.13", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmmirror.com/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esprima": { @@ -2081,6 +2897,52 @@ "node": ">=4" } }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmmirror.com/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -2133,6 +2995,13 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmmirror.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -2140,6 +3009,13 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmmirror.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, "node_modules/fb-watchman": { "version": "2.0.2", "resolved": "https://registry.npmmirror.com/fb-watchman/-/fb-watchman-2.0.2.tgz", @@ -2150,6 +3026,19 @@ "bser": "2.1.1" } }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmmirror.com/find-up/-/find-up-4.1.0.tgz", @@ -2164,6 +3053,27 @@ "node": ">=8" } }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmmirror.com/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true, + "license": "ISC" + }, "node_modules/foreground-child": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", @@ -2281,6 +3191,32 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmmirror.com/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -2337,6 +3273,43 @@ "node": ">=10.17.0" } }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/import-local": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", @@ -2393,6 +3366,16 @@ "dev": true, "license": "MIT" }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -2413,6 +3396,19 @@ "node": ">=6" } }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -3198,6 +4194,13 @@ "node": ">=6" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -3205,6 +4208,20 @@ "dev": true, "license": "MIT" }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmmirror.com/json5/-/json5-2.2.3.tgz", @@ -3218,6 +4235,16 @@ "node": ">=6" } }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmmirror.com/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -3228,6 +4255,20 @@ "node": ">=6" } }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -3255,6 +4296,13 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmmirror.com/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz", @@ -3488,6 +4536,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmmirror.com/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -3550,6 +4616,19 @@ "dev": true, "license": "BlueOak-1.0.0" }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -3666,6 +4745,16 @@ "node": ">=8" } }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/pretty-format": { "version": "30.3.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.3.0.tgz", @@ -3694,6 +4783,16 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/pure-rand": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", @@ -4106,6 +5205,54 @@ "node": "*" } }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmmirror.com/tmpl/-/tmpl-1.0.5.tgz", @@ -4113,6 +5260,19 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/ts-api-utils": { + "version": "2.5.0", + "resolved": "https://registry.npmmirror.com/ts-api-utils/-/ts-api-utils-2.5.0.tgz", + "integrity": "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, "node_modules/ts-jest": { "version": "29.4.9", "resolved": "https://registry.npmmirror.com/ts-jest/-/ts-jest-29.4.9.tgz", @@ -4206,6 +5366,19 @@ "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", "license": "Unlicense" }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -4243,6 +5416,30 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "8.58.1", + "resolved": "https://registry.npmmirror.com/typescript-eslint/-/typescript-eslint-8.58.1.tgz", + "integrity": "sha512-gf6/oHChByg9HJvhMO1iBexJh12AqqTfnuxscMDOVqfJW3htsdRJI/GfPpHTTcyeB8cSTUY2JcZmVgoyPqcrDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.58.1", + "@typescript-eslint/parser": "8.58.1", + "@typescript-eslint/typescript-estree": "8.58.1", + "@typescript-eslint/utils": "8.58.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" + } + }, "node_modules/uglify-js": { "version": "3.19.3", "resolved": "https://registry.npmmirror.com/uglify-js/-/uglify-js-3.19.3.tgz", @@ -4330,6 +5527,16 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/v8-to-istanbul": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", @@ -4371,6 +5578,16 @@ "node": ">= 8" } }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmmirror.com/wordwrap/-/wordwrap-1.0.0.tgz", diff --git a/javascript/package.json b/javascript/package.json index 599336b..1ba77a1 100644 --- a/javascript/package.json +++ b/javascript/package.json @@ -1,9 +1,21 @@ { - "name": "@robustmq/mq9", - "version": "1.0.0", - "description": "RobustMQ JavaScript/TypeScript SDK — mq9 AI-native async messaging", + "name": "@robustmq/sdk", + "version": "0.3.5", + "description": "RobustMQ JavaScript/TypeScript SDK", "main": "dist/index.js", "types": "dist/index.d.ts", + "exports": { + ".": { + "require": "./dist/index.js", + "import": "./dist/index.js", + "types": "./dist/index.d.ts" + }, + "./mq9": { + "require": "./dist/mq9/client.js", + "import": "./dist/mq9/client.js", + "types": "./dist/mq9/client.d.ts" + } + }, "license": "Apache-2.0", "scripts": { "build": "tsc", @@ -15,6 +27,8 @@ "devDependencies": { "@types/jest": "^30.0.0", "@types/node": "^25.5.2", + "eslint": "^9.0.0", + "typescript-eslint": "^8.0.0", "jest": "^30.3.0", "ts-jest": "^29.0.0", "typescript": "^6.0.2" diff --git a/javascript/src/mq9/client.test.ts b/javascript/src/mq9/client.test.ts index 0da7124..1c67aa6 100644 --- a/javascript/src/mq9/client.test.ts +++ b/javascript/src/mq9/client.test.ts @@ -1,4 +1,10 @@ -import { MQ9Client, MQ9Error, NatsTransport, Mq9Message, MessageMeta, Priority } from "./client.js"; +import { + MQ9Client, + MQ9Error, + NatsTransport, + MessageMeta, + Priority, +} from "./client.js"; // --------------------------------------------------------------------------- // Mock transport @@ -41,13 +47,15 @@ describe("create", () => { expect(t.request).toHaveBeenCalledWith( "$mq9.AI.MAILBOX.CREATE", expect.any(Uint8Array), - expect.anything() + expect.anything(), ); }); test("public mailbox", async () => { const t = mockTransport({ - request: jest.fn().mockResolvedValue(jsonReply({ mail_id: "task.queue" })), + request: jest + .fn() + .mockResolvedValue(jsonReply({ mail_id: "task.queue" })), }); const client = clientWith(t); const mb = await client.create({ @@ -61,7 +69,7 @@ describe("create", () => { expect(mb.public).toBe(true); const sentPayload = JSON.parse( - Buffer.from((t.request as jest.Mock).mock.calls[0][1]).toString() + Buffer.from((t.request as jest.Mock).mock.calls[0][1]).toString(), ); expect(sentPayload.public).toBe(true); expect(sentPayload.name).toBe("task.queue"); @@ -70,15 +78,15 @@ describe("create", () => { test("public without name throws MQ9Error", async () => { const client = clientWith(mockTransport()); await expect(client.create({ ttl: 3600, public: true })).rejects.toThrow( - MQ9Error + MQ9Error, ); }); test("server error throws MQ9Error with code", async () => { const t = mockTransport({ - request: jest.fn().mockResolvedValue( - jsonReply({ error: "quota exceeded", code: 429 }) - ), + request: jest + .fn() + .mockResolvedValue(jsonReply({ error: "quota exceeded", code: 429 })), }); const client = clientWith(t); const err = await client.create({ ttl: 3600 }).catch((e) => e); @@ -99,7 +107,7 @@ describe("send", () => { expect(t.publish).toHaveBeenCalledWith( "$mq9.AI.MAILBOX.MSG.m-001.normal", - expect.any(Uint8Array) + expect.any(Uint8Array), ); }); @@ -110,7 +118,7 @@ describe("send", () => { expect(t.publish).toHaveBeenCalledWith( "$mq9.AI.MAILBOX.MSG.m-001.high", - expect.any(Uint8Array) + expect.any(Uint8Array), ); }); @@ -129,7 +137,9 @@ describe("send", () => { await client.send("m-001", { task: "summarize" }); const data = (t.publish as jest.Mock).mock.calls[0][1] as Uint8Array; - expect(JSON.parse(Buffer.from(data).toString())).toEqual({ task: "summarize" }); + expect(JSON.parse(Buffer.from(data).toString())).toEqual({ + task: "summarize", + }); }); }); @@ -143,10 +153,8 @@ describe("list", () => { request: jest.fn().mockResolvedValue( jsonReply({ mail_id: "m-001", - messages: [ - { msg_id: "x1", priority: "high", ts: 100 }, - ], - }) + messages: [{ msg_id: "x1", priority: "high", ts: 100 }], + }), ), }); const client = clientWith(t); @@ -160,15 +168,15 @@ describe("list", () => { expect(t.request).toHaveBeenCalledWith( "$mq9.AI.MAILBOX.LIST.m-001", expect.any(Uint8Array), - expect.anything() + expect.anything(), ); }); test("returns empty array for empty mailbox", async () => { const t = mockTransport({ - request: jest.fn().mockResolvedValue( - jsonReply({ mail_id: "m-001", messages: [] }) - ), + request: jest + .fn() + .mockResolvedValue(jsonReply({ mail_id: "m-001", messages: [] })), }); const client = clientWith(t); const msgs = await client.list("m-001"); @@ -191,7 +199,7 @@ describe("delete", () => { expect(t.request).toHaveBeenCalledWith( "$mq9.AI.MAILBOX.DELETE.m-001.msg-42", expect.any(Uint8Array), - expect.anything() + expect.anything(), ); }); }); diff --git a/javascript/src/mq9/client.ts b/javascript/src/mq9/client.ts index 17c7991..b2ef5ba 100644 --- a/javascript/src/mq9/client.ts +++ b/javascript/src/mq9/client.ts @@ -2,11 +2,7 @@ * mq9 client — AI-native async Agent mailbox communication over NATS. */ -import { - connect, - NatsConnection, - Subscription, -} from "nats"; +import { connect, NatsConnection, Subscription } from "nats"; // --------------------------------------------------------------------------- // Types @@ -81,9 +77,14 @@ export interface NatsTransport { request( subject: string, data: Uint8Array, - opts?: { timeout?: number } + opts?: { timeout?: number }, ): Promise<{ data: Uint8Array }>; - subscribe(subject: string, opts?: { queue?: string }): AsyncIterable<{ subject: string; data: Uint8Array }> & { unsubscribe(): void }; + subscribe( + subject: string, + opts?: { queue?: string }, + ): AsyncIterable<{ subject: string; data: Uint8Array }> & { + unsubscribe(): void; + }; drain(): Promise; } @@ -148,7 +149,7 @@ export class MQ9Client { async send( mailId: string, payload: Uint8Array | string | object, - priority: Priority = "normal" + priority: Priority = "normal", ): Promise { this.ensureConnected(); const subject = subjectMsg(mailId, priority); @@ -161,7 +162,7 @@ export class MQ9Client { async subscribe( mailId: string, callback: (msg: Mq9Message) => Promise, - opts: SubscribeOptions = {} + opts: SubscribeOptions = {}, ): Promise<{ unsubscribe(): void }> { this.ensureConnected(); const priority = opts.priority ?? "*"; @@ -217,7 +218,7 @@ export class MQ9Client { private async request( subject: string, - payload: object + payload: object, ): Promise> { this.ensureConnected(); const data = encodePayload(payload); @@ -230,9 +231,10 @@ export class MQ9Client { const msg = err instanceof Error ? err.message : String(err); throw new MQ9Error(`request failed: ${msg}`); } - const resp = JSON.parse( - Buffer.from(reply.data).toString("utf8") - ) as Record; + const resp = JSON.parse(Buffer.from(reply.data).toString("utf8")) as Record< + string, + unknown + >; if (resp.error) { throw new MQ9Error(resp.error as string, (resp.code as number) ?? 0); } @@ -254,7 +256,7 @@ class RealTransport implements NatsTransport { async request( subject: string, data: Uint8Array, - opts?: { timeout?: number } + opts?: { timeout?: number }, ): Promise<{ data: Uint8Array }> { const msg = await this.nc.request(subject, data, { timeout: opts?.timeout ?? 5000, @@ -264,7 +266,7 @@ class RealTransport implements NatsTransport { subscribe( subject: string, - opts?: { queue?: string } + opts?: { queue?: string }, ): AsyncIterable<{ subject: string; data: Uint8Array }> & { unsubscribe(): void; } { @@ -299,16 +301,17 @@ function encodePayload(payload: Uint8Array | string | object): Uint8Array { function parseIncoming( mailId: string, subject: string, - data: Uint8Array + data: Uint8Array, ): Mq9Message { const parts = subject.split("."); const priorityStr = parts[parts.length - 1] ?? "normal"; const priority = toPriority(priorityStr); try { - const node = JSON.parse( - Buffer.from(data).toString("utf8") - ) as Record; + const node = JSON.parse(Buffer.from(data).toString("utf8")) as Record< + string, + unknown + >; if (node.msg_id !== undefined) { return parseMessageNode(mailId, node); } @@ -321,7 +324,7 @@ function parseIncoming( function parseMessageNode( mailId: string, - node: Record + node: Record, ): Mq9Message { const rawPayload = (node.payload as string) ?? ""; const payload = rawPayload diff --git a/python/pyproject.toml b/python/pyproject.toml index c3d0b28..8002a65 100644 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -4,8 +4,8 @@ build-backend = "hatchling.build" [project] name = "robustmq" -version = "1.0.0" -description = "RobustMQ Python SDK — mq9 AI-native async messaging" +version = "0.3.5" +description = "RobustMQ Python SDK — unified messaging for AI, IoT, and data pipelines" readme = "README.md" license = { text = "Apache-2.0" } requires-python = ">=3.10" diff --git a/python/robustmq/__init__.py b/python/robustmq/__init__.py index 6d388ec..9c47b8d 100644 --- a/python/robustmq/__init__.py +++ b/python/robustmq/__init__.py @@ -1,3 +1,3 @@ """RobustMQ Python SDK.""" -__version__ = "1.0.0" +__version__ = "0.3.5" diff --git a/python/robustmq/mq9/client.py b/python/robustmq/mq9/client.py index 4fee39f..11b7f06 100644 --- a/python/robustmq/mq9/client.py +++ b/python/robustmq/mq9/client.py @@ -6,7 +6,7 @@ import base64 import json import logging -from dataclasses import dataclass, field +from dataclasses import dataclass from enum import Enum from typing import Any, Awaitable, Callable @@ -225,7 +225,8 @@ async def subscribe( if priority == "*": subject = _MAILBOX_MSG.format(mail_id=mail_id, priority="*") else: - subject = _MAILBOX_MSG.format(mail_id=mail_id, priority=Priority(priority).value) + p = Priority(priority).value + subject = _MAILBOX_MSG.format(mail_id=mail_id, priority=p) async def _handler(raw: Msg) -> None: try: @@ -275,13 +276,17 @@ async def delete(self, mail_id: str, msg_id: str) -> None: def _ensure_connected(self) -> None: if self._nc is None or self._nc.is_closed: - raise RuntimeError("Client is not connected. Call await client.connect() first.") + raise RuntimeError( + "Client is not connected. Call await client.connect() first." + ) async def _request(self, subject: str, payload: dict[str, Any]) -> dict[str, Any]: self._ensure_connected() data = json.dumps(payload).encode() try: - reply = await self._nc.request(subject, data, timeout=self._request_timeout) # type: ignore[union-attr] + reply = await self._nc.request( # type: ignore[union-attr] + subject, data, timeout=self._request_timeout + ) except nats.errors.NoRespondersError as exc: raise Mq9Error(f"No responders for subject: {subject}") from exc except asyncio.TimeoutError as exc: @@ -317,6 +322,7 @@ async def __aexit__(self, *_: Any) -> None: # Module-level helpers # ------------------------------------------------------------------ + def _encode_payload(payload: bytes | str | dict[str, Any]) -> bytes: if isinstance(payload, bytes): return payload @@ -349,7 +355,11 @@ def _parse_incoming(mail_id: str, raw: Msg) -> Message: msg_id=envelope["msg_id"], mail_id=mail_id, priority=priority, - payload=base64.b64decode(envelope.get("payload", "")) if envelope.get("payload") else raw.data, + payload=( + base64.b64decode(envelope["payload"]) + if envelope.get("payload") + else raw.data + ), ) except (json.JSONDecodeError, KeyError): pass diff --git a/python/tests/test_client.py b/python/tests/test_client.py index 1bf827b..49ffaf9 100644 --- a/python/tests/test_client.py +++ b/python/tests/test_client.py @@ -21,6 +21,7 @@ # Helpers # --------------------------------------------------------------------------- + def _make_reply(data: dict[str, Any]) -> MagicMock: msg = MagicMock() msg.data = json.dumps(data).encode() @@ -47,10 +48,13 @@ async def _inject_nc(client: Client) -> AsyncMock: # connect / close # --------------------------------------------------------------------------- + @pytest.mark.asyncio async def test_connect_and_close(): client = _make_client() - with patch("robustmq.mq9.client.nats.connect", new_callable=AsyncMock) as mock_connect: + with patch( + "robustmq.mq9.client.nats.connect", new_callable=AsyncMock + ) as mock_connect: nc = AsyncMock() nc.is_closed = False mock_connect.return_value = nc @@ -66,7 +70,9 @@ async def test_connect_and_close(): @pytest.mark.asyncio async def test_context_manager(): client = _make_client() - with patch("robustmq.mq9.client.nats.connect", new_callable=AsyncMock) as mock_connect: + with patch( + "robustmq.mq9.client.nats.connect", new_callable=AsyncMock + ) as mock_connect: nc = AsyncMock() nc.is_closed = False mock_connect.return_value = nc @@ -80,6 +86,7 @@ async def test_context_manager(): # create # --------------------------------------------------------------------------- + @pytest.mark.asyncio async def test_create_private_mailbox(): client = _make_client() @@ -105,7 +112,9 @@ async def test_create_public_mailbox(): nc = await _inject_nc(client) nc.request = AsyncMock(return_value=_make_reply({"mail_id": "task.queue"})) - mailbox = await client.create(ttl=86400, public=True, name="task.queue", desc="Task queue") + mailbox = await client.create( + ttl=86400, public=True, name="task.queue", desc="Task queue" + ) assert mailbox.mail_id == "task.queue" assert mailbox.public is True @@ -143,6 +152,7 @@ async def test_create_server_error(): # send # --------------------------------------------------------------------------- + @pytest.mark.asyncio async def test_send_bytes_normal_priority(): client = _make_client() @@ -150,9 +160,7 @@ async def test_send_bytes_normal_priority(): await client.send("m-001", b"hello", priority=Priority.NORMAL) - nc.publish.assert_awaited_once_with( - "$mq9.AI.MAILBOX.MSG.m-001.normal", b"hello" - ) + nc.publish.assert_awaited_once_with("$mq9.AI.MAILBOX.MSG.m-001.normal", b"hello") @pytest.mark.asyncio @@ -191,6 +199,7 @@ async def test_send_invalid_priority(): # subscribe # --------------------------------------------------------------------------- + @pytest.mark.asyncio async def test_subscribe_all_priorities(): client = _make_client() @@ -270,6 +279,7 @@ async def handler(msg: Message) -> None: # list # --------------------------------------------------------------------------- + @pytest.mark.asyncio async def test_list_messages(): client = _make_client() @@ -298,7 +308,9 @@ async def test_list_messages(): async def test_list_empty_mailbox(): client = _make_client() nc = await _inject_nc(client) - nc.request = AsyncMock(return_value=_make_reply({"mail_id": "m-001", "messages": []})) + nc.request = AsyncMock( + return_value=_make_reply({"mail_id": "m-001", "messages": []}) + ) messages = await client.list("m-001") assert messages == [] @@ -308,6 +320,7 @@ async def test_list_empty_mailbox(): # delete # --------------------------------------------------------------------------- + @pytest.mark.asyncio async def test_delete_message(): client = _make_client() @@ -324,10 +337,9 @@ async def test_delete_message(): # Error handling # --------------------------------------------------------------------------- + @pytest.mark.asyncio async def test_request_timeout_raises_mq9_error(): - import nats.errors - client = _make_client() nc = await _inject_nc(client) nc.request = AsyncMock(side_effect=asyncio.TimeoutError()) @@ -360,6 +372,7 @@ async def test_not_connected_raises_runtime_error(): # _encode_payload helper # --------------------------------------------------------------------------- + def test_encode_bytes(): assert _encode_payload(b"raw") == b"raw" @@ -377,14 +390,17 @@ def test_encode_dict(): # _parse_incoming helper # --------------------------------------------------------------------------- + def test_parse_incoming_with_envelope(): raw = MagicMock() raw.subject = "$mq9.AI.MAILBOX.MSG.m-001.high" - raw.data = json.dumps({ - "msg_id": "x9", - "priority": "high", - "payload": base64.b64encode(b"data").decode(), - }).encode() + raw.data = json.dumps( + { + "msg_id": "x9", + "priority": "high", + "payload": base64.b64encode(b"data").decode(), + } + ).encode() msg = _parse_incoming("m-001", raw) assert msg.msg_id == "x9" diff --git a/rust/Cargo.lock b/rust/Cargo.lock index c9ddba9..d04e6d3 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -754,7 +754,7 @@ dependencies = [ [[package]] name = "robustmq" -version = "1.0.0" +version = "0.3.5" dependencies = [ "async-nats", "bytes", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 21eb1a4..766e96c 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "robustmq" -version = "1.0.0" +version = "0.3.5" edition = "2021" -description = "RobustMQ Rust SDK — mq9 AI-native async messaging" +description = "RobustMQ Rust SDK — unified messaging for AI, IoT, and data pipelines" license = "Apache-2.0" [dependencies] diff --git a/rust/examples/demo.rs b/rust/examples/demo.rs index 72de952..51b77bf 100644 --- a/rust/examples/demo.rs +++ b/rust/examples/demo.rs @@ -18,9 +18,15 @@ async fn main() -> Result<(), Box> { println!("[rust] private mailbox: {}", mailbox.mail_id); // 2. Send 3 messages with different priorities - client.send(&mailbox.mail_id, b"urgent task", Priority::High).await?; - client.send(&mailbox.mail_id, b"normal task", Priority::Normal).await?; - client.send(&mailbox.mail_id, b"background task", Priority::Low).await?; + client + .send(&mailbox.mail_id, b"urgent task", Priority::High) + .await?; + client + .send(&mailbox.mail_id, b"normal task", Priority::Normal) + .await?; + client + .send(&mailbox.mail_id, b"background task", Priority::Low) + .await?; println!("[rust] sent 3 messages (high / normal / low)"); // 3. Subscribe and print received messages @@ -44,7 +50,10 @@ async fn main() -> Result<(), Box> { let metas = client.list(&mailbox.mail_id).await?; println!("[rust] list: {} message(s) in mailbox", metas.len()); for m in &metas { - println!(" msg_id={} priority={} ts={}", m.msg_id, m.priority, m.ts); + println!( + " msg_id={} priority={} ts={}", + m.msg_id, m.priority, m.ts + ); } // 5. Delete first message diff --git a/rust/src/mq9/mod.rs b/rust/src/mq9/mod.rs index 04e9151..5a816e9 100644 --- a/rust/src/mq9/mod.rs +++ b/rust/src/mq9/mod.rs @@ -108,7 +108,7 @@ pub struct Message { } /// A raw incoming message from the transport (subject + payload bytes). -pub(crate) struct RawMsg { +pub struct RawMsg { pub subject: String, pub payload: Bytes, } @@ -189,10 +189,13 @@ impl NatsTransport for RealNats { payload: Bytes, ) -> std::pin::Pin> + Send + 'a>> { Box::pin(async move { - self.0.publish(subject, payload).await.map_err(|e| MQ9Error { - message: format!("publish failed: {e}"), - code: 0, - }) + self.0 + .publish(subject, payload) + .await + .map_err(|e| MQ9Error { + message: format!("publish failed: {e}"), + code: 0, + }) }) } @@ -202,10 +205,14 @@ impl NatsTransport for RealNats { payload: Bytes, ) -> std::pin::Pin> + Send + 'a>> { Box::pin(async move { - let reply = self.0.request(subject, payload).await.map_err(|e| MQ9Error { - message: format!("request failed: {e}"), - code: 0, - })?; + let reply = self + .0 + .request(subject, payload) + .await + .map_err(|e| MQ9Error { + message: format!("request failed: {e}"), + code: 0, + })?; Ok(reply.payload) }) } @@ -217,10 +224,13 @@ impl NatsTransport for RealNats { ) -> std::pin::Pin> + Send + 'a>> { Box::pin(async move { let sub = if let Some(queue) = queue_group { - self.0.queue_subscribe(subject, queue).await.map_err(|e| MQ9Error { - message: format!("queue_subscribe failed: {e}"), - code: 0, - })? + self.0 + .queue_subscribe(subject, queue) + .await + .map_err(|e| MQ9Error { + message: format!("queue_subscribe failed: {e}"), + code: 0, + })? } else { self.0.subscribe(subject).await.map_err(|e| MQ9Error { message: format!("subscribe failed: {e}"), @@ -390,11 +400,7 @@ impl MQ9Client { let resp = self.do_request(&subject, &serde_json::json!({})).await?; let metas = resp["messages"] .as_array() - .map(|arr| { - arr.iter() - .filter_map(|v| parse_message_meta(v)) - .collect() - }) + .map(|arr| arr.iter().filter_map(parse_message_meta).collect()) .unwrap_or_default(); Ok(metas) } @@ -482,7 +488,11 @@ fn parse_message_meta(v: &Value) -> Option { let msg_id = v["msg_id"].as_str()?.to_string(); let priority = Priority::from_str_lossy(v["priority"].as_str().unwrap_or("normal")); let ts = v["ts"].as_i64().unwrap_or(0); - Some(MessageMeta { msg_id, priority, ts }) + Some(MessageMeta { + msg_id, + priority, + ts, + }) } // --------------------------------------------------------------------------- @@ -577,7 +587,10 @@ mod tests { fn push_ok(&self, body: serde_json::Value) { let bytes = Bytes::from(serde_json::to_vec(&body).unwrap()); - self.responses.lock().unwrap().push_back(MockResponse::Ok(bytes)); + self.responses + .lock() + .unwrap() + .push_back(MockResponse::Ok(bytes)); } fn push_err(&self, message: &str, code: u32) { @@ -614,7 +627,10 @@ mod tests { subject: String, payload: Bytes, ) -> std::pin::Pin> + Send + 'a>> { - self.published.lock().unwrap().push((subject, payload.to_vec())); + self.published + .lock() + .unwrap() + .push((subject, payload.to_vec())); Box::pin(async { Ok(()) }) } @@ -623,7 +639,10 @@ mod tests { subject: String, payload: Bytes, ) -> std::pin::Pin> + Send + 'a>> { - self.requested.lock().unwrap().push((subject, payload.to_vec())); + self.requested + .lock() + .unwrap() + .push((subject, payload.to_vec())); let resp = self.responses.lock().unwrap().pop_front(); Box::pin(async move { match resp { @@ -633,7 +652,10 @@ mod tests { let body = json!({ "error": message, "code": code }); Ok(Bytes::from(serde_json::to_vec(&body).unwrap())) } - None => Err(MQ9Error { message: "no mock response queued".into(), code: 0 }), + None => Err(MQ9Error { + message: "no mock response queued".into(), + code: 0, + }), } }) } @@ -642,7 +664,8 @@ mod tests { &'a self, subject: String, queue_group: Option, - ) -> std::pin::Pin> + Send + 'a>> { + ) -> std::pin::Pin> + Send + 'a>> + { self.subscribed.lock().unwrap().push((subject, queue_group)); // Drain the pre-loaded messages into a stream that yields them all then ends. let messages: Vec = self.sub_messages.lock().unwrap().drain(..).collect(); @@ -703,7 +726,10 @@ mod tests { mock.push_ok(json!({ "mail_id": "task.queue" })); let client = make_client(mock); - let mailbox = client.create(86400, true, "task.queue", "Task queue").await.unwrap(); + let mailbox = client + .create(86400, true, "task.queue", "Task queue") + .await + .unwrap(); assert_eq!(mailbox.mail_id, "task.queue"); assert!(mailbox.public); @@ -729,7 +755,10 @@ mod tests { let arc = mock.clone(); let client = MQ9Client { transport: mock }; - client.create(86400, true, "task.queue", "Tasks").await.unwrap(); + client + .create(86400, true, "task.queue", "Tasks") + .await + .unwrap(); let calls = arc.requested(); let body: serde_json::Value = serde_json::from_slice(&calls[0].1).unwrap(); @@ -762,7 +791,10 @@ mod tests { let arc = mock.clone(); let client = MQ9Client { transport: mock }; - client.send("m-001", b"hello", Priority::Normal).await.unwrap(); + client + .send("m-001", b"hello", Priority::Normal) + .await + .unwrap(); let calls = arc.published(); assert_eq!(calls.len(), 1); @@ -776,7 +808,10 @@ mod tests { let arc = mock.clone(); let client = MQ9Client { transport: mock }; - client.send("m-001", b"urgent", Priority::High).await.unwrap(); + client + .send("m-001", b"urgent", Priority::High) + .await + .unwrap(); let calls = arc.published(); assert_eq!(calls[0].0, "$mq9.AI.MAILBOX.MSG.m-001.high"); @@ -801,7 +836,10 @@ mod tests { let client = MQ9Client { transport: mock }; let payload = b"binary\x00data\xff"; - client.send("m-001", payload, Priority::Normal).await.unwrap(); + client + .send("m-001", payload, Priority::Normal) + .await + .unwrap(); assert_eq!(&arc.published()[0].1, payload); } @@ -820,7 +858,10 @@ mod tests { let arc = mock.clone(); let client = MQ9Client { transport: mock }; - let _sub = client.subscribe("m-001", |_msg| async {}, None, "").await.unwrap(); + let _sub = client + .subscribe("m-001", |_msg| async {}, None, "") + .await + .unwrap(); let calls = arc.subscribed(); assert_eq!(calls.len(), 1); @@ -912,8 +953,16 @@ mod tests { let n = (b0 << 16) | (b1 << 8) | b2; out.push(ALPHA[((n >> 18) & 63) as usize] as char); out.push(ALPHA[((n >> 12) & 63) as usize] as char); - out.push(if chunk.len() > 1 { ALPHA[((n >> 6) & 63) as usize] as char } else { '=' }); - out.push(if chunk.len() > 2 { ALPHA[(n & 63) as usize] as char } else { '=' }); + out.push(if chunk.len() > 1 { + ALPHA[((n >> 6) & 63) as usize] as char + } else { + '=' + }); + out.push(if chunk.len() > 2 { + ALPHA[(n & 63) as usize] as char + } else { + '=' + }); } out } @@ -1016,7 +1065,10 @@ mod tests { #[test] fn test_mq9_error_display_with_code() { - let err = MQ9Error { message: "quota exceeded".into(), code: 429 }; + let err = MQ9Error { + message: "quota exceeded".into(), + code: 429, + }; let s = err.to_string(); assert!(s.contains("429")); assert!(s.contains("quota exceeded")); @@ -1024,14 +1076,20 @@ mod tests { #[test] fn test_mq9_error_display_no_code() { - let err = MQ9Error { message: "connection failed".into(), code: 0 }; + let err = MQ9Error { + message: "connection failed".into(), + code: 0, + }; let s = err.to_string(); assert!(s.contains("connection failed")); } #[test] fn test_mq9_error_is_std_error() { - let err: Box = Box::new(MQ9Error { message: "oops".into(), code: 500 }); + let err: Box = Box::new(MQ9Error { + message: "oops".into(), + code: 500, + }); assert!(err.to_string().contains("oops")); }