From a398cdecde0bbbb95e762bf70592e91fba4d4fe0 Mon Sep 17 00:00:00 2001 From: spetz Date: Sun, 1 Feb 2026 08:53:17 +0100 Subject: [PATCH 1/3] feat(server,sdk): add reserved u64 to iggy message header --- .github/workflows/_test_examples.yml | 11 +- Cargo.lock | 34 +- Cargo.toml | 8 +- DEPENDENCIES.md | 34 +- core/ai/mcp/Cargo.toml | 2 +- core/bench/Cargo.toml | 2 +- core/binary_protocol/Cargo.toml | 2 +- core/cli/Cargo.toml | 2 +- core/common/Cargo.toml | 2 +- core/common/src/types/message/iggy_message.rs | 1 + .../src/types/message/message_header.rs | 82 +- .../src/types/message/message_header_view.rs | 8 + core/connectors/runtime/Cargo.toml | 2 +- core/connectors/sdk/Cargo.toml | 2 +- .../sinks/elasticsearch_sink/Cargo.toml | 2 +- core/connectors/sinks/iceberg_sink/Cargo.toml | 2 +- .../connectors/sinks/postgres_sink/Cargo.toml | 2 +- .../connectors/sinks/quickwit_sink/Cargo.toml | 2 +- core/connectors/sinks/stdout_sink/Cargo.toml | 2 +- .../sources/elasticsearch_source/Cargo.toml | 2 +- .../sources/postgres_source/Cargo.toml | 2 +- .../sources/random_source/Cargo.toml | 2 +- .../tests/server/scenarios/system_scenario.rs | 2 +- core/sdk/Cargo.toml | 2 +- core/server/Cargo.toml | 2 +- .../producer/MessageEnvelopeProducer.java | 4 +- examples/node/package-lock.json | 774 +++++++----------- examples/node/package.json | 2 +- examples/node/src/basic/producer.ts | 123 +-- examples/node/src/getting-started/producer.ts | 89 +- examples/node/src/message-headers/producer.ts | 75 +- .../StreamsTests.cs | 4 +- .../Iggy_SDK.Tests.Integration/TopicsTests.cs | 2 +- .../Iggy_SDK/Contracts/Tcp/TcpContracts.cs | 7 +- foreign/csharp/Iggy_SDK/Iggy_SDK.csproj | 2 +- .../csharp/Iggy_SDK/Mappers/BinaryMapper.cs | 14 +- foreign/csharp/Iggy_SDK/Messages/Message.cs | 4 +- .../csharp/Iggy_SDK/Messages/MessageHeader.cs | 5 + .../Iggy_SDK/Utils/TcpMessageStreamHelpers.cs | 2 +- .../Iggy_SDK_Tests/Utils/BinaryFactory.cs | 5 +- .../send_messages_request_serializer_test.go | 2 +- foreign/go/contracts/message_header.go | 8 +- .../connector/flink/sink/IggySinkWriter.java | 11 +- foreign/java/gradle.properties | 2 +- .../java/org/apache/iggy/message/Message.java | 6 +- .../apache/iggy/message/MessageHeader.java | 6 +- .../apache/iggy/serde/BytesDeserializer.java | 5 +- .../apache/iggy/serde/BytesSerializer.java | 1 + .../blocking/tcp/BytesSerializerTest.java | 9 +- .../iggy/serde/BytesDeserializerTest.java | 9 +- foreign/node/package-lock.json | 4 +- foreign/node/package.json | 2 +- .../src/wire/message/iggy-header.utils.ts | 35 +- .../message/send-messages.command.test.ts | 2 +- foreign/python/Cargo.toml | 4 +- foreign/python/src/send_message.rs | 1 + 56 files changed, 701 insertions(+), 732 deletions(-) diff --git a/.github/workflows/_test_examples.yml b/.github/workflows/_test_examples.yml index 6ffe4a4268..38a3a32818 100644 --- a/.github/workflows/_test_examples.yml +++ b/.github/workflows/_test_examples.yml @@ -48,7 +48,7 @@ jobs: uses: ./.github/actions/utils/setup-rust-with-cache with: cache-targets: false # Only cache registry and git deps, not target dir (sccache handles that) - save-cache: "false" # Only builds server+examples, let Rust test job save comprehensive cache + save-cache: "false" # Only builds server+examples, let Rust test job save comprehensive cache - name: Setup Node with cache for examples if: inputs.component == 'examples-suite' @@ -152,6 +152,15 @@ jobs: if: inputs.component == 'examples-suite' && inputs.task == 'examples-node' run: | echo "Running Node.js examples tests..." + # Build the local Node SDK first (examples use file: link to it) + cd foreign/node + npm ci + npm run build + cd ../.. + # Install examples dependencies (will use the local SDK) + cd examples/node + npm ci + cd ../.. ./scripts/run-node-examples-from-readme.sh - name: Run Java examples diff --git a/Cargo.lock b/Cargo.lock index b43d62fe0d..24850ca59b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4423,7 +4423,7 @@ dependencies = [ [[package]] name = "iggy" -version = "0.8.2-edge.2" +version = "0.8.3-edge.1" dependencies = [ "async-broadcast", "async-dropper", @@ -4455,7 +4455,7 @@ dependencies = [ [[package]] name = "iggy-bench" -version = "0.3.2-edge.1" +version = "0.3.3-edge.1" dependencies = [ "async-trait", "bench-report", @@ -4510,7 +4510,7 @@ dependencies = [ [[package]] name = "iggy-cli" -version = "0.10.2-edge.1" +version = "0.10.3-edge.1" dependencies = [ "ahash 0.8.12", "anyhow", @@ -4530,7 +4530,7 @@ dependencies = [ [[package]] name = "iggy-connectors" -version = "0.2.2-edge.1" +version = "0.2.3-edge.1" dependencies = [ "async-trait", "axum", @@ -4582,7 +4582,7 @@ dependencies = [ [[package]] name = "iggy-mcp" -version = "0.2.2-edge.1" +version = "0.2.3-edge.1" dependencies = [ "axum", "axum-server", @@ -4614,7 +4614,7 @@ dependencies = [ [[package]] name = "iggy_binary_protocol" -version = "0.8.2-edge.2" +version = "0.8.3-edge.1" dependencies = [ "anyhow", "async-broadcast", @@ -4635,7 +4635,7 @@ dependencies = [ [[package]] name = "iggy_common" -version = "0.8.2-edge.2" +version = "0.8.3-edge.1" dependencies = [ "aes-gcm", "ahash 0.8.12", @@ -4676,7 +4676,7 @@ dependencies = [ [[package]] name = "iggy_connector_elasticsearch_sink" -version = "0.2.1-edge.1" +version = "0.2.2-edge.1" dependencies = [ "async-trait", "base64 0.22.1", @@ -4694,7 +4694,7 @@ dependencies = [ [[package]] name = "iggy_connector_elasticsearch_source" -version = "0.2.1-edge.1" +version = "0.2.2-edge.1" dependencies = [ "async-trait", "chrono", @@ -4712,7 +4712,7 @@ dependencies = [ [[package]] name = "iggy_connector_iceberg_sink" -version = "0.2.1-edge.1" +version = "0.2.2-edge.1" dependencies = [ "arrow-json", "async-trait", @@ -4731,7 +4731,7 @@ dependencies = [ [[package]] name = "iggy_connector_postgres_sink" -version = "0.2.1-edge.1" +version = "0.2.2-edge.1" dependencies = [ "async-trait", "chrono", @@ -4750,7 +4750,7 @@ dependencies = [ [[package]] name = "iggy_connector_postgres_source" -version = "0.2.1-edge.1" +version = "0.2.2-edge.1" dependencies = [ "async-trait", "base64 0.22.1", @@ -4771,7 +4771,7 @@ dependencies = [ [[package]] name = "iggy_connector_quickwit_sink" -version = "0.2.1-edge.1" +version = "0.2.2-edge.1" dependencies = [ "async-trait", "dashmap", @@ -4786,7 +4786,7 @@ dependencies = [ [[package]] name = "iggy_connector_random_source" -version = "0.2.1-edge.1" +version = "0.2.2-edge.1" dependencies = [ "async-trait", "dashmap", @@ -4803,7 +4803,7 @@ dependencies = [ [[package]] name = "iggy_connector_sdk" -version = "0.1.2-edge.1" +version = "0.1.3-edge.1" dependencies = [ "async-trait", "base64 0.22.1", @@ -4831,7 +4831,7 @@ dependencies = [ [[package]] name = "iggy_connector_stdout_sink" -version = "0.2.1-edge.1" +version = "0.2.2-edge.1" dependencies = [ "async-trait", "dashmap", @@ -8243,7 +8243,7 @@ dependencies = [ [[package]] name = "server" -version = "0.6.2-edge.1" +version = "0.6.3-edge.1" dependencies = [ "ahash 0.8.12", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index 0be7d8a9cc..ef364eb18b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -160,10 +160,10 @@ humantime = "2.3.0" hwlocality = "1.0.0-alpha.11" iceberg = "0.8.0" iceberg-catalog-rest = "0.8.0" -iggy = { path = "core/sdk", version = "0.8.2-edge.2" } -iggy_binary_protocol = { path = "core/binary_protocol", version = "0.8.2-edge.2" } -iggy_common = { path = "core/common", version = "0.8.2-edge.2" } -iggy_connector_sdk = { path = "core/connectors/sdk", version = "0.1.2-edge.1" } +iggy = { path = "core/sdk", version = "0.8.3-edge.1" } +iggy_binary_protocol = { path = "core/binary_protocol", version = "0.8.3-edge.1" } +iggy_common = { path = "core/common", version = "0.8.3-edge.1" } +iggy_connector_sdk = { path = "core/connectors/sdk", version = "0.1.3-edge.1" } integration = { path = "core/integration" } journal = { path = "core/journal" } js-sys = "0.3" diff --git a/DEPENDENCIES.md b/DEPENDENCIES.md index a7fd8c256e..e77b152458 100644 --- a/DEPENDENCIES.md +++ b/DEPENDENCIES.md @@ -384,23 +384,23 @@ icu_provider: 2.1.1, "Unicode-3.0", ident_case: 1.0.1, "Apache-2.0 OR MIT", idna: 1.1.0, "Apache-2.0 OR MIT", idna_adapter: 1.2.1, "Apache-2.0 OR MIT", -iggy: 0.8.2-edge.2, "Apache-2.0", -iggy-bench: 0.3.2-edge.1, "Apache-2.0", +iggy: 0.8.3-edge.1, "Apache-2.0", +iggy-bench: 0.3.3-edge.1, "Apache-2.0", iggy-bench-dashboard-server: 0.5.1-edge.1, "Apache-2.0", -iggy-cli: 0.10.2-edge.1, "Apache-2.0", -iggy-connectors: 0.2.2-edge.1, "Apache-2.0", -iggy-mcp: 0.2.2-edge.1, "Apache-2.0", -iggy_binary_protocol: 0.8.2-edge.2, "Apache-2.0", -iggy_common: 0.8.2-edge.2, "Apache-2.0", -iggy_connector_elasticsearch_sink: 0.2.1-edge.1, "Apache-2.0", -iggy_connector_elasticsearch_source: 0.2.1-edge.1, "Apache-2.0", -iggy_connector_iceberg_sink: 0.2.1-edge.1, "Apache-2.0", -iggy_connector_postgres_sink: 0.2.1-edge.1, "Apache-2.0", -iggy_connector_postgres_source: 0.2.1-edge.1, "Apache-2.0", -iggy_connector_quickwit_sink: 0.2.1-edge.1, "Apache-2.0", -iggy_connector_random_source: 0.2.1-edge.1, "Apache-2.0", -iggy_connector_sdk: 0.1.2-edge.1, "Apache-2.0", -iggy_connector_stdout_sink: 0.2.1-edge.1, "Apache-2.0", +iggy-cli: 0.10.3-edge.1, "Apache-2.0", +iggy-connectors: 0.2.3-edge.1, "Apache-2.0", +iggy-mcp: 0.2.3-edge.1, "Apache-2.0", +iggy_binary_protocol: 0.8.3-edge.1, "Apache-2.0", +iggy_common: 0.8.3-edge.1, "Apache-2.0", +iggy_connector_elasticsearch_sink: 0.2.2-edge.1, "Apache-2.0", +iggy_connector_elasticsearch_source: 0.2.2-edge.1, "Apache-2.0", +iggy_connector_iceberg_sink: 0.2.2-edge.1, "Apache-2.0", +iggy_connector_postgres_sink: 0.2.2-edge.1, "Apache-2.0", +iggy_connector_postgres_source: 0.2.2-edge.1, "Apache-2.0", +iggy_connector_quickwit_sink: 0.2.2-edge.1, "Apache-2.0", +iggy_connector_random_source: 0.2.2-edge.1, "Apache-2.0", +iggy_connector_sdk: 0.1.3-edge.1, "Apache-2.0", +iggy_connector_stdout_sink: 0.2.2-edge.1, "Apache-2.0", iggy_examples: 0.0.6, "Apache-2.0", ignore: 0.4.25, "MIT OR Unlicense", impl-more: 0.1.9, "Apache-2.0 OR MIT", @@ -717,7 +717,7 @@ serde_with_macros: 3.16.1, "Apache-2.0 OR MIT", serde_yaml_ng: 0.10.0, "MIT", serial_test: 3.3.1, "MIT", serial_test_derive: 3.3.1, "MIT", -server: 0.6.2-edge.1, "Apache-2.0", +server: 0.6.3-edge.1, "Apache-2.0", sha1: 0.10.6, "Apache-2.0 OR MIT", sha2: 0.10.9, "Apache-2.0 OR MIT", sha3: 0.10.8, "Apache-2.0 OR MIT", diff --git a/core/ai/mcp/Cargo.toml b/core/ai/mcp/Cargo.toml index ac05978a54..9dcfc45cbb 100644 --- a/core/ai/mcp/Cargo.toml +++ b/core/ai/mcp/Cargo.toml @@ -17,7 +17,7 @@ [package] name = "iggy-mcp" -version = "0.2.2-edge.1" +version = "0.2.3-edge.1" description = "MCP Server for Iggy message streaming platform" edition = "2024" license = "Apache-2.0" diff --git a/core/bench/Cargo.toml b/core/bench/Cargo.toml index 459ed102f2..294a47dd70 100644 --- a/core/bench/Cargo.toml +++ b/core/bench/Cargo.toml @@ -17,7 +17,7 @@ [package] name = "iggy-bench" -version = "0.3.2-edge.1" +version = "0.3.3-edge.1" edition = "2024" license = "Apache-2.0" repository = "https://github.com/apache/iggy" diff --git a/core/binary_protocol/Cargo.toml b/core/binary_protocol/Cargo.toml index a5553ff510..be1171ce3f 100644 --- a/core/binary_protocol/Cargo.toml +++ b/core/binary_protocol/Cargo.toml @@ -17,7 +17,7 @@ [package] name = "iggy_binary_protocol" -version = "0.8.2-edge.2" +version = "0.8.3-edge.1" description = "Iggy is the persistent message streaming platform written in Rust, supporting QUIC, TCP and HTTP transport protocols, capable of processing millions of messages per second." edition = "2024" license = "Apache-2.0" diff --git a/core/cli/Cargo.toml b/core/cli/Cargo.toml index 7a669b8fc0..71232bc5af 100644 --- a/core/cli/Cargo.toml +++ b/core/cli/Cargo.toml @@ -17,7 +17,7 @@ [package] name = "iggy-cli" -version = "0.10.2-edge.1" +version = "0.10.3-edge.1" edition = "2024" authors = ["bartosz.ciesla@gmail.com"] repository = "https://github.com/apache/iggy" diff --git a/core/common/Cargo.toml b/core/common/Cargo.toml index 74f1b27a03..783a6aa23c 100644 --- a/core/common/Cargo.toml +++ b/core/common/Cargo.toml @@ -16,7 +16,7 @@ # under the License. [package] name = "iggy_common" -version = "0.8.2-edge.2" +version = "0.8.3-edge.1" description = "Iggy is the persistent message streaming platform written in Rust, supporting QUIC, TCP and HTTP transport protocols, capable of processing millions of messages per second." edition = "2024" license = "Apache-2.0" diff --git a/core/common/src/types/message/iggy_message.rs b/core/common/src/types/message/iggy_message.rs index 49fe0b89be..12a2c1afc3 100644 --- a/core/common/src/types/message/iggy_message.rs +++ b/core/common/src/types/message/iggy_message.rs @@ -190,6 +190,7 @@ impl IggyMessage { origin_timestamp: IggyTimestamp::now().as_micros(), user_headers_length, payload_length: payload.len() as u32, + reserved: 0, }; let user_headers = user_headers.map(|h| h.to_bytes()); diff --git a/core/common/src/types/message/message_header.rs b/core/common/src/types/message/message_header.rs index 120f779e61..c2b788eba1 100644 --- a/core/common/src/types/message/message_header.rs +++ b/core/common/src/types/message/message_header.rs @@ -21,7 +21,7 @@ use bytes::{BufMut, Bytes, BytesMut}; use serde::{Deserialize, Serialize}; use std::ops::Range; -pub const IGGY_MESSAGE_HEADER_SIZE: usize = 8 + 16 + 8 + 8 + 8 + 4 + 4; +pub const IGGY_MESSAGE_HEADER_SIZE: usize = 8 + 16 + 8 + 8 + 8 + 4 + 4 + 8; pub const IGGY_MESSAGE_HEADER_RANGE: Range = 0..IGGY_MESSAGE_HEADER_SIZE; pub const IGGY_MESSAGE_CHECKSUM_OFFSET_RANGE: Range = 0..8; @@ -31,6 +31,7 @@ pub const IGGY_MESSAGE_TIMESTAMP_OFFSET_RANGE: Range = 32..40; pub const IGGY_MESSAGE_ORIGIN_TIMESTAMP_OFFSET_RANGE: Range = 40..48; pub const IGGY_MESSAGE_HEADERS_LENGTH_OFFSET_RANGE: Range = 48..52; pub const IGGY_MESSAGE_PAYLOAD_LENGTH_OFFSET_RANGE: Range = 52..56; +pub const IGGY_MESSAGE_RESERVED_OFFSET_RANGE: Range = 56..64; #[derive(Debug, Serialize, Deserialize, PartialEq, Default)] pub struct IggyMessageHeader { @@ -41,6 +42,8 @@ pub struct IggyMessageHeader { pub origin_timestamp: u64, pub user_headers_length: u32, pub payload_length: u32, + // Reserved for future use + pub reserved: u64, } impl Sizeable for IggyMessageHeader { @@ -91,6 +94,11 @@ impl IggyMessageHeader { .try_into() .map_err(|_| IggyError::InvalidNumberEncoding)?, ), + reserved: u64::from_le_bytes( + bytes[IGGY_MESSAGE_RESERVED_OFFSET_RANGE] + .try_into() + .map_err(|_| IggyError::InvalidNumberEncoding)?, + ), }) } } @@ -105,6 +113,7 @@ impl BytesSerializable for IggyMessageHeader { bytes.put_u64_le(self.origin_timestamp); bytes.put_u32_le(self.user_headers_length); bytes.put_u32_le(self.payload_length); + bytes.put_u64_le(self.reserved); bytes.freeze() } @@ -155,6 +164,12 @@ impl BytesSerializable for IggyMessageHeader { .map_err(|_| IggyError::InvalidNumberEncoding)?, ); + let _reserved = u64::from_le_bytes( + bytes[IGGY_MESSAGE_RESERVED_OFFSET_RANGE] + .try_into() + .map_err(|_| IggyError::InvalidNumberEncoding)?, + ); + Ok(IggyMessageHeader { checksum, id, @@ -163,6 +178,71 @@ impl BytesSerializable for IggyMessageHeader { origin_timestamp, user_headers_length: headers_length, payload_length, + reserved: _reserved, }) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn should_serialize_and_deserialize_header() { + let header = IggyMessageHeader { + checksum: 123456789, + id: 987654321, + offset: 100, + timestamp: 1000000, + origin_timestamp: 999999, + user_headers_length: 50, + payload_length: 200, + reserved: 0, + }; + + let bytes = header.to_bytes(); + assert_eq!(bytes.len(), IGGY_MESSAGE_HEADER_SIZE); + + let deserialized = IggyMessageHeader::from_bytes(bytes).unwrap(); + assert_eq!(header, deserialized); + } + + #[test] + fn should_serialize_header_to_correct_size() { + let header = IggyMessageHeader::default(); + let bytes = header.to_bytes(); + assert_eq!(bytes.len(), IGGY_MESSAGE_HEADER_SIZE); + assert_eq!(bytes.len(), 64); + } + + #[test] + fn should_fail_to_deserialize_invalid_size() { + let bytes = Bytes::from(vec![0u8; 56]); + let result = IggyMessageHeader::from_bytes(bytes); + assert!(result.is_err()); + } + + #[test] + fn should_deserialize_from_raw_bytes() { + let header = IggyMessageHeader { + checksum: 111, + id: 222, + offset: 333, + timestamp: 444, + origin_timestamp: 555, + user_headers_length: 66, + payload_length: 77, + reserved: 0, + }; + + let bytes = header.to_bytes(); + let deserialized = IggyMessageHeader::from_raw_bytes(&bytes).unwrap(); + assert_eq!(header.checksum, deserialized.checksum); + assert_eq!(header.id, deserialized.id); + assert_eq!(header.offset, deserialized.offset); + assert_eq!(header.timestamp, deserialized.timestamp); + assert_eq!(header.origin_timestamp, deserialized.origin_timestamp); + assert_eq!(header.user_headers_length, deserialized.user_headers_length); + assert_eq!(header.payload_length, deserialized.payload_length); + } +} diff --git a/core/common/src/types/message/message_header_view.rs b/core/common/src/types/message/message_header_view.rs index 94a8a690ab..2d8b45c342 100644 --- a/core/common/src/types/message/message_header_view.rs +++ b/core/common/src/types/message/message_header_view.rs @@ -24,6 +24,7 @@ use crate::{ IGGY_MESSAGE_OFFSET_OFFSET_RANGE, IGGY_MESSAGE_ORIGIN_TIMESTAMP_OFFSET_RANGE, IGGY_MESSAGE_PAYLOAD_LENGTH_OFFSET_RANGE, IGGY_MESSAGE_TIMESTAMP_OFFSET_RANGE, IggyMessageHeader, error::IggyError, + types::message::message_header::IGGY_MESSAGE_RESERVED_OFFSET_RANGE, }; /// A read-only, typed view into a message header in a raw buffer. @@ -87,6 +88,12 @@ impl<'a> IggyMessageHeaderView<'a> { u32::from_le_bytes(bytes.try_into().unwrap()) as usize } + /// The reserved field (8 bytes) + pub fn reserved(&self) -> u64 { + let bytes = &self.data[IGGY_MESSAGE_RESERVED_OFFSET_RANGE]; + u64::from_le_bytes(bytes.try_into().unwrap()) + } + /// Convert this view to a full IggyMessageHeader struct pub fn to_header(&self) -> IggyMessageHeader { IggyMessageHeader { @@ -97,6 +104,7 @@ impl<'a> IggyMessageHeaderView<'a> { origin_timestamp: self.origin_timestamp(), user_headers_length: self.user_headers_length() as u32, payload_length: self.payload_length() as u32, + reserved: self.reserved(), } } } diff --git a/core/connectors/runtime/Cargo.toml b/core/connectors/runtime/Cargo.toml index 270471abe4..41e7a38085 100644 --- a/core/connectors/runtime/Cargo.toml +++ b/core/connectors/runtime/Cargo.toml @@ -17,7 +17,7 @@ [package] name = "iggy-connectors" -version = "0.2.2-edge.1" +version = "0.2.3-edge.1" description = "Connectors runtime for Iggy message streaming platform" edition = "2024" license = "Apache-2.0" diff --git a/core/connectors/sdk/Cargo.toml b/core/connectors/sdk/Cargo.toml index 4d03859c46..b429093865 100644 --- a/core/connectors/sdk/Cargo.toml +++ b/core/connectors/sdk/Cargo.toml @@ -17,7 +17,7 @@ [package] name = "iggy_connector_sdk" -version = "0.1.2-edge.1" +version = "0.1.3-edge.1" description = "Iggy is the persistent message streaming platform written in Rust, supporting QUIC, TCP and HTTP transport protocols, capable of processing millions of messages per second." edition = "2024" license = "Apache-2.0" diff --git a/core/connectors/sinks/elasticsearch_sink/Cargo.toml b/core/connectors/sinks/elasticsearch_sink/Cargo.toml index 7ede4457af..6201be03db 100644 --- a/core/connectors/sinks/elasticsearch_sink/Cargo.toml +++ b/core/connectors/sinks/elasticsearch_sink/Cargo.toml @@ -17,7 +17,7 @@ [package] name = "iggy_connector_elasticsearch_sink" -version = "0.2.1-edge.1" +version = "0.2.2-edge.1" description = "Iggy Elasticsearch sink connector" edition = "2024" license = "Apache-2.0" diff --git a/core/connectors/sinks/iceberg_sink/Cargo.toml b/core/connectors/sinks/iceberg_sink/Cargo.toml index 4b63979de2..d175ac70d4 100644 --- a/core/connectors/sinks/iceberg_sink/Cargo.toml +++ b/core/connectors/sinks/iceberg_sink/Cargo.toml @@ -17,7 +17,7 @@ [package] name = "iggy_connector_iceberg_sink" -version = "0.2.1-edge.1" +version = "0.2.2-edge.1" edition = "2024" license = "Apache-2.0" keywords = ["iggy", "messaging", "streaming"] diff --git a/core/connectors/sinks/postgres_sink/Cargo.toml b/core/connectors/sinks/postgres_sink/Cargo.toml index bfc5ead2c6..a24a68cf38 100644 --- a/core/connectors/sinks/postgres_sink/Cargo.toml +++ b/core/connectors/sinks/postgres_sink/Cargo.toml @@ -17,7 +17,7 @@ [package] name = "iggy_connector_postgres_sink" -version = "0.2.1-edge.1" +version = "0.2.2-edge.1" description = "Iggy PostgreSQL sink connector for storing stream messages into PostgreSQL database" edition = "2024" license = "Apache-2.0" diff --git a/core/connectors/sinks/quickwit_sink/Cargo.toml b/core/connectors/sinks/quickwit_sink/Cargo.toml index 51fa78f100..360d9f919a 100644 --- a/core/connectors/sinks/quickwit_sink/Cargo.toml +++ b/core/connectors/sinks/quickwit_sink/Cargo.toml @@ -17,7 +17,7 @@ [package] name = "iggy_connector_quickwit_sink" -version = "0.2.1-edge.1" +version = "0.2.2-edge.1" description = "Iggy is the persistent message streaming platform written in Rust, supporting QUIC, TCP and HTTP transport protocols, capable of processing millions of messages per second." edition = "2024" license = "Apache-2.0" diff --git a/core/connectors/sinks/stdout_sink/Cargo.toml b/core/connectors/sinks/stdout_sink/Cargo.toml index bdceb6297e..56a36028b1 100644 --- a/core/connectors/sinks/stdout_sink/Cargo.toml +++ b/core/connectors/sinks/stdout_sink/Cargo.toml @@ -17,7 +17,7 @@ [package] name = "iggy_connector_stdout_sink" -version = "0.2.1-edge.1" +version = "0.2.2-edge.1" description = "Iggy is the persistent message streaming platform written in Rust, supporting QUIC, TCP and HTTP transport protocols, capable of processing millions of messages per second." edition = "2024" license = "Apache-2.0" diff --git a/core/connectors/sources/elasticsearch_source/Cargo.toml b/core/connectors/sources/elasticsearch_source/Cargo.toml index 206a9ee67a..6b19b6bc49 100644 --- a/core/connectors/sources/elasticsearch_source/Cargo.toml +++ b/core/connectors/sources/elasticsearch_source/Cargo.toml @@ -17,7 +17,7 @@ [package] name = "iggy_connector_elasticsearch_source" -version = "0.2.1-edge.1" +version = "0.2.2-edge.1" description = "Iggy Elasticsearch source connector" edition = "2024" license = "Apache-2.0" diff --git a/core/connectors/sources/postgres_source/Cargo.toml b/core/connectors/sources/postgres_source/Cargo.toml index 4c5ed6bcc7..0ce9b49680 100644 --- a/core/connectors/sources/postgres_source/Cargo.toml +++ b/core/connectors/sources/postgres_source/Cargo.toml @@ -17,7 +17,7 @@ [package] name = "iggy_connector_postgres_source" -version = "0.2.1-edge.1" +version = "0.2.2-edge.1" description = "Iggy PostgreSQL source connector supporting CDC and table polling for message streaming platform" edition = "2024" license = "Apache-2.0" diff --git a/core/connectors/sources/random_source/Cargo.toml b/core/connectors/sources/random_source/Cargo.toml index 11b4d4a6ea..092c31cbb9 100644 --- a/core/connectors/sources/random_source/Cargo.toml +++ b/core/connectors/sources/random_source/Cargo.toml @@ -17,7 +17,7 @@ [package] name = "iggy_connector_random_source" -version = "0.2.1-edge.1" +version = "0.2.2-edge.1" description = "Iggy is the persistent message streaming platform written in Rust, supporting QUIC, TCP and HTTP transport protocols, capable of processing millions of messages per second." edition = "2024" license = "Apache-2.0" diff --git a/core/integration/tests/server/scenarios/system_scenario.rs b/core/integration/tests/server/scenarios/system_scenario.rs index 61163cded5..7efeba1f18 100644 --- a/core/integration/tests/server/scenarios/system_scenario.rs +++ b/core/integration/tests/server/scenarios/system_scenario.rs @@ -262,7 +262,7 @@ pub async fn run(client_factory: &dyn ClientFactory) { assert_eq!(topic.name, TOPIC_NAME); assert_eq!(topic.partitions_count, PARTITIONS_COUNT); assert_eq!(topic.partitions.len(), PARTITIONS_COUNT as usize); - assert_eq!(topic.size, 89806); + assert_eq!(topic.size, 100502); assert_eq!(topic.messages_count, MESSAGES_COUNT as u64); let topic_partition = topic.partitions.get((PARTITION_ID) as usize).unwrap(); assert_eq!(topic_partition.id, PARTITION_ID); diff --git a/core/sdk/Cargo.toml b/core/sdk/Cargo.toml index 5479fdf7a7..deb6f4568d 100644 --- a/core/sdk/Cargo.toml +++ b/core/sdk/Cargo.toml @@ -17,7 +17,7 @@ [package] name = "iggy" -version = "0.8.2-edge.2" +version = "0.8.3-edge.1" description = "Iggy is the persistent message streaming platform written in Rust, supporting QUIC, TCP and HTTP transport protocols, capable of processing millions of messages per second." edition = "2024" license = "Apache-2.0" diff --git a/core/server/Cargo.toml b/core/server/Cargo.toml index 6789e6cb0c..d0740fb5ca 100644 --- a/core/server/Cargo.toml +++ b/core/server/Cargo.toml @@ -17,7 +17,7 @@ [package] name = "server" -version = "0.6.2-edge.1" +version = "0.6.3-edge.1" edition = "2024" license = "Apache-2.0" diff --git a/examples/java/src/main/java/org/apache/iggy/examples/messageenvelope/producer/MessageEnvelopeProducer.java b/examples/java/src/main/java/org/apache/iggy/examples/messageenvelope/producer/MessageEnvelopeProducer.java index 936c03a676..d4df7e1daa 100644 --- a/examples/java/src/main/java/org/apache/iggy/examples/messageenvelope/producer/MessageEnvelopeProducer.java +++ b/examples/java/src/main/java/org/apache/iggy/examples/messageenvelope/producer/MessageEnvelopeProducer.java @@ -42,6 +42,7 @@ import java.util.Optional; public final class MessageEnvelopeProducer { + private static final String STREAM_NAME = "envelope-stream"; private static final StreamId STREAM_ID = StreamId.of(STREAM_NAME); @@ -126,7 +127,8 @@ public static void produceMessages(IggyTcpClient client) { BigInteger.ZERO, BigInteger.ZERO, 0L, - (long) payload.length); + (long) payload.length, + BigInteger.ZERO); Message message = new Message(header, payload, new HashMap<>()); messages.add(message); serializableMessages.add(serializableMessage); diff --git a/examples/node/package-lock.json b/examples/node/package-lock.json index 210e1dec81..26c9b4c9c1 100644 --- a/examples/node/package-lock.json +++ b/examples/node/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "Apache-2.0", "dependencies": { - "apache-iggy": "0.6.0-edge.2", + "apache-iggy": "file:../../foreign/node", "debug": "^4.3.7" }, "devDependencies": { @@ -21,10 +21,43 @@ "typescript-eslint": "^8.47.0" } }, + "../../foreign/node": { + "name": "apache-iggy", + "version": "0.6.3-edge.1", + "license": "Apache-2.0", + "dependencies": { + "debug": "4.4.3", + "generic-pool": "3.9.0", + "uuidv7": "1.0.2" + }, + "devDependencies": { + "@commitlint/cli": "20.1.0", + "@commitlint/config-conventional": "20.0.0", + "@cucumber/cucumber": "12.2.0", + "@swc-node/register": "1.11.1", + "@types/debug": "4.1.12", + "@types/node": "24.10.1", + "husky": "9.1.7", + "typescript": "5.9.3", + "typescript-eslint": "^8.47.0" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "^1.15.3", + "@swc/core-darwin-x64": "^1.15.3", + "@swc/core-linux-arm-gnueabihf": "^1.15.3", + "@swc/core-linux-arm64-gnu": "^1.15.3", + "@swc/core-linux-arm64-musl": "^1.15.3", + "@swc/core-linux-x64-gnu": "^1.15.3", + "@swc/core-linux-x64-musl": "^1.15.3", + "@swc/core-win32-arm64-msvc": "^1.15.3", + "@swc/core-win32-ia32-msvc": "^1.15.3", + "@swc/core-win32-x64-msvc": "^1.15.3" + } + }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", - "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", "cpu": [ "ppc64" ], @@ -39,9 +72,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", - "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", "cpu": [ "arm" ], @@ -56,9 +89,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", - "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", "cpu": [ "arm64" ], @@ -73,9 +106,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", - "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", "cpu": [ "x64" ], @@ -90,9 +123,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", - "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", "cpu": [ "arm64" ], @@ -107,9 +140,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", - "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", "cpu": [ "x64" ], @@ -124,9 +157,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", - "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", "cpu": [ "arm64" ], @@ -141,9 +174,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", - "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", "cpu": [ "x64" ], @@ -158,9 +191,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", - "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", "cpu": [ "arm" ], @@ -175,9 +208,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", - "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", "cpu": [ "arm64" ], @@ -192,9 +225,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", - "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", "cpu": [ "ia32" ], @@ -209,9 +242,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", - "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", "cpu": [ "loong64" ], @@ -226,9 +259,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", - "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", "cpu": [ "mips64el" ], @@ -243,9 +276,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", - "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", "cpu": [ "ppc64" ], @@ -260,9 +293,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", - "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", "cpu": [ "riscv64" ], @@ -277,9 +310,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", - "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", "cpu": [ "s390x" ], @@ -294,9 +327,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", - "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", "cpu": [ "x64" ], @@ -311,9 +344,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", - "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", "cpu": [ "arm64" ], @@ -328,9 +361,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", - "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", "cpu": [ "x64" ], @@ -345,9 +378,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", - "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", "cpu": [ "arm64" ], @@ -362,9 +395,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", - "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", "cpu": [ "x64" ], @@ -379,9 +412,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", - "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", "cpu": [ "arm64" ], @@ -396,9 +429,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", - "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", "cpu": [ "x64" ], @@ -413,9 +446,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", - "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", "cpu": [ "arm64" ], @@ -430,9 +463,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", - "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", "cpu": [ "ia32" ], @@ -447,9 +480,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", - "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", "cpu": [ "x64" ], @@ -464,9 +497,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", - "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "dev": true, "license": "MIT", "dependencies": { @@ -547,9 +580,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", - "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", "dev": true, "license": "MIT", "dependencies": { @@ -559,7 +592,7 @@ "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", + "js-yaml": "^4.1.1", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, @@ -570,23 +603,10 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/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/@eslint/js": { - "version": "9.39.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", - "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", "dev": true, "license": "MIT", "engines": { @@ -672,44 +692,6 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -742,9 +724,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.18.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.1.tgz", - "integrity": "sha512-rzSDyhn4cYznVG+PCzGe1lwuMYJrcBS1fc3JqSa2PvtABwWo+dZ1ij5OVok3tqfpEBCBoaR4d7upFJk73HRJDw==", + "version": "22.19.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.7.tgz", + "integrity": "sha512-MciR4AKGHWl7xwxkBa6xUGxQJ4VBOmPTF7sL+iGzuahOFaO0jHCsuEfS80pan1ef4gWId1oWOweIhrDEYLuaOw==", "dev": true, "license": "MIT", "dependencies": { @@ -752,21 +734,20 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.47.0.tgz", - "integrity": "sha512-fe0rz9WJQ5t2iaLfdbDc9T80GJy0AeO453q8C3YCilnGozvOyCG5t+EZtg7j7D88+c3FipfP/x+wzGnh1xp8ZA==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.54.0.tgz", + "integrity": "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.47.0", - "@typescript-eslint/type-utils": "8.47.0", - "@typescript-eslint/utils": "8.47.0", - "@typescript-eslint/visitor-keys": "8.47.0", - "graphemer": "^1.4.0", - "ignore": "^7.0.0", + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.54.0", + "@typescript-eslint/type-utils": "8.54.0", + "@typescript-eslint/utils": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0", + "ignore": "^7.0.5", "natural-compare": "^1.4.0", - "ts-api-utils": "^2.1.0" + "ts-api-utils": "^2.4.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -776,7 +757,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.47.0", + "@typescript-eslint/parser": "^8.54.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } @@ -792,18 +773,17 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.47.0.tgz", - "integrity": "sha512-lJi3PfxVmo0AkEY93ecfN+r8SofEqZNGByvHAI3GBLrvt1Cw6H5k1IM02nSzu0RfUafr2EvFSw0wAsZgubNplQ==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.54.0.tgz", + "integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.47.0", - "@typescript-eslint/types": "8.47.0", - "@typescript-eslint/typescript-estree": "8.47.0", - "@typescript-eslint/visitor-keys": "8.47.0", - "debug": "^4.3.4" + "@typescript-eslint/scope-manager": "8.54.0", + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0", + "debug": "^4.4.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -818,15 +798,15 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.47.0.tgz", - "integrity": "sha512-2X4BX8hUeB5JcA1TQJ7GjcgulXQ+5UkNb0DL8gHsHUHdFoiCTJoYLTpib3LtSDPZsRET5ygN4qqIWrHyYIKERA==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.54.0.tgz", + "integrity": "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.47.0", - "@typescript-eslint/types": "^8.47.0", - "debug": "^4.3.4" + "@typescript-eslint/tsconfig-utils": "^8.54.0", + "@typescript-eslint/types": "^8.54.0", + "debug": "^4.4.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -840,14 +820,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.47.0.tgz", - "integrity": "sha512-a0TTJk4HXMkfpFkL9/WaGTNuv7JWfFTQFJd6zS9dVAjKsojmv9HT55xzbEpnZoY+VUb+YXLMp+ihMLz/UlZfDg==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.54.0.tgz", + "integrity": "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.47.0", - "@typescript-eslint/visitor-keys": "8.47.0" + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -858,9 +838,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.47.0.tgz", - "integrity": "sha512-ybUAvjy4ZCL11uryalkKxuT3w3sXJAuWhOoGS3T/Wu+iUu1tGJmk5ytSY8gbdACNARmcYEB0COksD2j6hfGK2g==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.54.0.tgz", + "integrity": "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==", "dev": true, "license": "MIT", "engines": { @@ -875,17 +855,17 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.47.0.tgz", - "integrity": "sha512-QC9RiCmZ2HmIdCEvhd1aJELBlD93ErziOXXlHEZyuBo3tBiAZieya0HLIxp+DoDWlsQqDawyKuNEhORyku+P8A==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.54.0.tgz", + "integrity": "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.47.0", - "@typescript-eslint/typescript-estree": "8.47.0", - "@typescript-eslint/utils": "8.47.0", - "debug": "^4.3.4", - "ts-api-utils": "^2.1.0" + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0", + "@typescript-eslint/utils": "8.54.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -900,9 +880,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.47.0.tgz", - "integrity": "sha512-nHAE6bMKsizhA2uuYZbEbmp5z2UpffNrPEqiKIeN7VsV6UY/roxanWfoRrf6x/k9+Obf+GQdkm0nPU+vnMXo9A==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz", + "integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==", "dev": true, "license": "MIT", "engines": { @@ -914,22 +894,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.47.0.tgz", - "integrity": "sha512-k6ti9UepJf5NpzCjH31hQNLHQWupTRPhZ+KFF8WtTuTpy7uHPfeg2NM7cP27aCGajoEplxJDFVCEm9TGPYyiVg==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.54.0.tgz", + "integrity": "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.47.0", - "@typescript-eslint/tsconfig-utils": "8.47.0", - "@typescript-eslint/types": "8.47.0", - "@typescript-eslint/visitor-keys": "8.47.0", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^2.1.0" + "@typescript-eslint/project-service": "8.54.0", + "@typescript-eslint/tsconfig-utils": "8.54.0", + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/visitor-keys": "8.54.0", + "debug": "^4.4.3", + "minimatch": "^9.0.5", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -969,16 +948,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.47.0.tgz", - "integrity": "sha512-g7XrNf25iL4TJOiPqatNuaChyqt49a/onq5YsJ9+hXeugK+41LVg7AxikMfM02PC6jbNtZLCJj6AUcQXJS/jGQ==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.54.0.tgz", + "integrity": "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.47.0", - "@typescript-eslint/types": "8.47.0", - "@typescript-eslint/typescript-estree": "8.47.0" + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.54.0", + "@typescript-eslint/types": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -993,13 +972,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.47.0.tgz", - "integrity": "sha512-SIV3/6eftCy1bNzCQoPmbWsRLujS8t5iDIZ4spZOBHqrM+yfX2ogg8Tt3PDTAVKw3sSCiUgg30uOAvK2r9zGjQ==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.54.0.tgz", + "integrity": "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.47.0", + "@typescript-eslint/types": "8.54.0", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -1016,7 +995,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1068,32 +1046,8 @@ } }, "node_modules/apache-iggy": { - "version": "0.6.0-edge.2", - "resolved": "https://registry.npmjs.org/apache-iggy/-/apache-iggy-0.6.0-edge.2.tgz", - "integrity": "sha512-8K1t7zQXZSQpGA98a/Sc/8qtmFZFvu1kinhMNgeta/6VWJn6OcmfvjML25kcb4TrfMN+P0ozuDGnO3qB3LfK/g==", - "license": "Apache-2.0", - "dependencies": { - "debug": "4.3.7", - "generic-pool": "3.9.0", - "uuidv7": "1.0.2" - } - }, - "node_modules/apache-iggy/node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } + "resolved": "../../foreign/node", + "link": true }, "node_modules/argparse": { "version": "2.0.1", @@ -1120,19 +1074,6 @@ "concat-map": "0.0.1" } }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1203,9 +1144,9 @@ } }, "node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -1227,9 +1168,9 @@ "license": "MIT" }, "node_modules/esbuild": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", - "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1240,32 +1181,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.9", - "@esbuild/android-arm": "0.25.9", - "@esbuild/android-arm64": "0.25.9", - "@esbuild/android-x64": "0.25.9", - "@esbuild/darwin-arm64": "0.25.9", - "@esbuild/darwin-x64": "0.25.9", - "@esbuild/freebsd-arm64": "0.25.9", - "@esbuild/freebsd-x64": "0.25.9", - "@esbuild/linux-arm": "0.25.9", - "@esbuild/linux-arm64": "0.25.9", - "@esbuild/linux-ia32": "0.25.9", - "@esbuild/linux-loong64": "0.25.9", - "@esbuild/linux-mips64el": "0.25.9", - "@esbuild/linux-ppc64": "0.25.9", - "@esbuild/linux-riscv64": "0.25.9", - "@esbuild/linux-s390x": "0.25.9", - "@esbuild/linux-x64": "0.25.9", - "@esbuild/netbsd-arm64": "0.25.9", - "@esbuild/netbsd-x64": "0.25.9", - "@esbuild/openbsd-arm64": "0.25.9", - "@esbuild/openbsd-x64": "0.25.9", - "@esbuild/openharmony-arm64": "0.25.9", - "@esbuild/sunos-x64": "0.25.9", - "@esbuild/win32-arm64": "0.25.9", - "@esbuild/win32-ia32": "0.25.9", - "@esbuild/win32-x64": "0.25.9" + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" } }, "node_modules/escape-string-regexp": { @@ -1282,12 +1223,11 @@ } }, "node_modules/eslint": { - "version": "9.39.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", - "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz", + "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -1295,7 +1235,7 @@ "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.1", + "@eslint/js": "9.39.2", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", @@ -1391,9 +1331,9 @@ } }, "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -1443,36 +1383,6 @@ "dev": true, "license": "MIT" }, - "node_modules/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -1487,14 +1397,22 @@ "dev": true, "license": "MIT" }, - "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, "node_modules/file-entry-cache": { @@ -1510,19 +1428,6 @@ "node": ">=16.0.0" } }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -1576,19 +1481,10 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/generic-pool": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", - "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, "node_modules/get-tsconfig": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", - "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.1.tgz", + "integrity": "sha512-EoY1N2xCn44xU6750Sx7OjOIT59FkmstNc3X6y5xpz7D5cBtZRe/3pSlTkDJgqsOk3WwZPkWfonhhUJfttQo3w==", "dev": true, "license": "MIT", "dependencies": { @@ -1611,12 +1507,18 @@ "node": ">=10.13.0" } }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/has-flag": { "version": "4.0.0", @@ -1688,16 +1590,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -1711,7 +1603,6 @@ "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "jiti": "lib/jiti-cli.mjs" } @@ -1797,30 +1688,6 @@ "dev": true, "license": "MIT" }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -1931,13 +1798,13 @@ } }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" @@ -1963,27 +1830,6 @@ "node": ">=6" } }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -2004,41 +1850,6 @@ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, "node_modules/semver": { "version": "7.7.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", @@ -2101,23 +1912,27 @@ "node": ">=8" } }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "dev": true, "license": "MIT", "dependencies": { - "is-number": "^7.0.0" + "fdir": "^6.5.0", + "picomatch": "^4.0.3" }, "engines": { - "node": ">=8.0" + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, "node_modules/ts-api-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", - "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", "dev": true, "license": "MIT", "engines": { @@ -2128,13 +1943,13 @@ } }, "node_modules/tsx": { - "version": "4.20.5", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.5.tgz", - "integrity": "sha512-+wKjMNU9w/EaQayHXb7WA7ZaHY6hN8WgfvHNQ3t1PnU91/7O8TcTnIhCDYTZwnt8JsO9IBqZ30Ln1r7pPF52Aw==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "~0.25.0", + "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" }, "bin": { @@ -2176,16 +1991,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.47.0.tgz", - "integrity": "sha512-Lwe8i2XQ3WoMjua/r1PHrCTpkubPYJCAfOurtn+mtTzqB6jNd+14n9UN1bJ4s3F49x9ixAm0FLflB/JzQ57M8Q==", + "version": "8.54.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.54.0.tgz", + "integrity": "sha512-CKsJ+g53QpsNPqbzUsfKVgd3Lny4yKZ1pP4qN3jdMOg/sisIDLGyDMezycquXLE5JsEU0wp3dGNdzig0/fmSVQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.47.0", - "@typescript-eslint/parser": "8.47.0", - "@typescript-eslint/typescript-estree": "8.47.0", - "@typescript-eslint/utils": "8.47.0" + "@typescript-eslint/eslint-plugin": "8.54.0", + "@typescript-eslint/parser": "8.54.0", + "@typescript-eslint/typescript-estree": "8.54.0", + "@typescript-eslint/utils": "8.54.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2216,15 +2031,6 @@ "punycode": "^2.1.0" } }, - "node_modules/uuidv7": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uuidv7/-/uuidv7-1.0.2.tgz", - "integrity": "sha512-8JQkH4ooXnm1JCIhqTMbtmdnYEn6oKukBxHn1Ic9878jMkL7daTI7anTExfY18VRCX7tcdn5quzvCb6EWrR8PA==", - "license": "Apache-2.0", - "bin": { - "uuidv7": "cli.js" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/examples/node/package.json b/examples/node/package.json index 003748e41f..3d6b2b5505 100644 --- a/examples/node/package.json +++ b/examples/node/package.json @@ -31,7 +31,7 @@ "author": "Apache Iggy", "license": "Apache-2.0", "dependencies": { - "apache-iggy": "0.6.0-edge.2", + "apache-iggy": "file:../../foreign/node", "debug": "^4.3.7" }, "devDependencies": { diff --git a/examples/node/src/basic/producer.ts b/examples/node/src/basic/producer.ts index 4c097ab322..d2d21e396b 100644 --- a/examples/node/src/basic/producer.ts +++ b/examples/node/src/basic/producer.ts @@ -17,46 +17,55 @@ * under the License. */ -import { Client, Partitioning } from 'apache-iggy'; -import crypto from 'crypto'; -import debug from 'debug'; -import { PARTITION_COUNT, BATCHES_LIMIT, MESSAGES_PER_BATCH, initSystem } from '../utils'; - -const log = debug('iggy:examples:basic-producer'); +import { Client, Partitioning } from "apache-iggy"; +import crypto from "crypto"; +import debug from "debug"; +import { + PARTITION_COUNT, + BATCHES_LIMIT, + MESSAGES_PER_BATCH, + initSystem, +} from "../utils"; + +const log = debug("iggy:examples:basic-producer"); function parseArgs() { - console.log = (...args) => process.stdout.write(args.join(' ') + '\n'); + console.log = (...args) => process.stdout.write(args.join(" ") + "\n"); const args = process.argv.slice(2); - const connectionString = args[ 0 ] || 'iggy+tcp://iggy:iggy@127.0.0.1:8090'; + const connectionString = args[0] || "iggy+tcp://iggy:iggy@127.0.0.1:8090"; - if (args.length > 0 && (args[ 0 ] === '-h' || args[ 0 ] === '--help')) { - log('Usage: node producer.js [connection_string]'); - log('Example: node producer.js iggy+tcp://iggy:iggy@127.0.0.1:8090'); + if (args.length > 0 && (args[0] === "-h" || args[0] === "--help")) { + log("Usage: node producer.js [connection_string]"); + log("Example: node producer.js iggy+tcp://iggy:iggy@127.0.0.1:8090"); process.exit(0); } return { connectionString }; } -async function produceMessages(client: Client, stream: Awaited>[ 'stream' ], topic: Awaited>[ 'topic' ]) { +async function produceMessages( + client: Client, + stream: Awaited>["stream"], + topic: Awaited>["topic"], +) { const interval = 500; // 500 milliseconds log( - 'Messages will be sent to stream: %d, topic: %d, partition: %d with interval %d ms.', - interval + "Messages will be sent to stream: %d, topic: %d, partition: %d with interval %d ms.", + interval, ); let currentId = 0; let sentBatches = 0; - for (; sentBatches < BATCHES_LIMIT;) { + for (; sentBatches < BATCHES_LIMIT; ) { const messages = Array.from({ length: MESSAGES_PER_BATCH }).map(() => { currentId++; return { //optional message id can be used for deduplication id: currentId, //optional headers can be used to store metadata - headers: {}, - payload: `message-${currentId}` + headers: [], + payload: `message-${currentId}`, }; }); @@ -65,57 +74,70 @@ async function produceMessages(client: Client, stream: Awaited setTimeout(resolve, interval)); + log("Sent messages: %o", messages); + await new Promise((resolve) => setTimeout(resolve, interval)); } } - log('Sent %d batches of messages, exiting.', sentBatches); + log("Sent %d batches of messages, exiting.", sentBatches); } -async function cleanup(client: Client, streamId: number | string, topicId: number | string) { - log('Cleaning up: deleting topic ID %d and stream ID %d...', topicId, streamId); +async function cleanup( + client: Client, + streamId: number | string, + topicId: number | string, +) { + log( + "Cleaning up: deleting topic ID %d and stream ID %d...", + topicId, + streamId, + ); try { await client.topic.delete({ streamId: streamId, topicId: topicId, - partitionsCount: PARTITION_COUNT + partitionsCount: PARTITION_COUNT, }); - log('Topic deleted successfully.'); + log("Topic deleted successfully."); } catch (error) { - log('Error deleting topic: %o', error); + log("Error deleting topic: %o", error); } try { await client.stream.delete({ streamId }); - log('Stream deleted successfully.'); + log("Stream deleted successfully."); } catch (error) { - log('Error deleting stream: %o', error); + log("Error deleting stream: %o", error); } } async function main() { const args = parseArgs(); - log('Using connection string: %s', args.connectionString); + log("Using connection string: %s", args.connectionString); // Parse connection string (simplified parsing for this example) - const url = new URL(args.connectionString.replace('iggy+tcp://', 'http://')); + const url = new URL(args.connectionString.replace("iggy+tcp://", "http://")); const host = url.hostname; const port = parseInt(url.port) || 8090; - const username = url.username || 'iggy'; - const password = url.password || 'iggy'; + const username = url.username || "iggy"; + const password = url.password || "iggy"; const client = new Client({ - transport: 'TCP', + transport: "TCP", options: { port, host, @@ -124,19 +146,19 @@ async function main() { reconnect: { enabled: true, interval: 5000, - maxRetries: 5 + maxRetries: 5, }, heartbeatInterval: 5000, - credentials: { username, password } + credentials: { username, password }, }); let streamId = null; // iggy will create topic with id 0 by default let topicId = 0; try { - log('Basic producer has started, selected transport: TCP'); - log('Connecting to Iggy server...'); + log("Basic producer has started, selected transport: TCP"); + log("Connecting to Iggy server..."); // Client connects automatically when first command is called - log('Connected successfully.'); + log("Connected successfully."); // Login will be handled automatically by the client on first command const { stream, topic } = await initSystem(client); @@ -145,28 +167,25 @@ async function main() { //ping before producing messages const pong = await client.system.ping(); - log('Ping successful.', pong); + log("Ping successful.", pong); const stats = await client.system.getStats(); - log('System stats: %o', stats); + log("System stats: %o", stats); - - log('Stream ID: %s, Topic ID: %s', streamId, topicId); + log("Stream ID: %s, Topic ID: %s", streamId, topicId); await produceMessages(client, stream, topic); } catch (error) { - log('Error in main: %o', error); + log("Error in main: %o", error); await client.destroy(); - log('Disconnected from server.'); + log("Disconnected from server."); process.exitCode = 1; } finally { if (streamId) { await cleanup(client, streamId, topicId); } await client.destroy(); - log('Disconnected from server.'); + log("Disconnected from server."); } } - - await main(); diff --git a/examples/node/src/getting-started/producer.ts b/examples/node/src/getting-started/producer.ts index 4a97718637..ce472e4b51 100644 --- a/examples/node/src/getting-started/producer.ts +++ b/examples/node/src/getting-started/producer.ts @@ -17,29 +17,41 @@ * under the License. */ -import { Client, Partitioning } from 'apache-iggy'; -import debug from 'debug'; -import { BATCHES_LIMIT, cleanup, initSystem, log, MESSAGES_PER_BATCH, parseArgs, sleep } from '../utils'; - -async function produceMessages(client: Client, stream: Awaited>[ 'stream' ], topic: Awaited>[ 'topic' ]) { +import { Client, Partitioning } from "apache-iggy"; +import debug from "debug"; +import { + BATCHES_LIMIT, + cleanup, + initSystem, + log, + MESSAGES_PER_BATCH, + parseArgs, + sleep, +} from "../utils"; + +async function produceMessages( + client: Client, + stream: Awaited>["stream"], + topic: Awaited>["topic"], +) { const interval = 500; // 500 milliseconds log( - 'Messages will be sent to stream: %d, topic: %d, partition: %d with interval %d ms.', - interval + "Messages will be sent to stream: %d, topic: %d, partition: %d with interval %d ms.", + interval, ); let currentId = 0; let sentBatches = 0; - for (; sentBatches < BATCHES_LIMIT;) { + for (; sentBatches < BATCHES_LIMIT; ) { const messages = Array.from({ length: MESSAGES_PER_BATCH }).map(() => { currentId++; return { //optional message id can be used for deduplication id: currentId, //optional headers can be used to store metadata - headers: {}, - payload: `message-${currentId}` + headers: [], + payload: `message-${currentId}`, }; }); @@ -48,38 +60,42 @@ async function produceMessages(client: Client, stream: Awaited ORDER_REJECTED_TYPE, @@ -91,20 +97,18 @@ class MessagesGenerator { } } - - async function produceMessages( client: Client, - stream: Awaited>['stream'], - topic: Awaited>['topic'] + stream: Awaited>["stream"], + topic: Awaited>["topic"], ) { const interval = 500; // 500 milliseconds log( - 'Messages will be sent to stream: %d, topic: %d, partition: %d with interval %d ms.', + "Messages will be sent to stream: %d, topic: %d, partition: %d with interval %d ms.", stream.id, topic.id, topic.partitions[0].id, - interval + interval, ); const messageGenerator = new MessagesGenerator(); @@ -125,51 +129,54 @@ async function produceMessages( return { payload, - headers: {}, + headers: [], }; }); try { - log('Sending messages count: %d', messages.length); + log("Sending messages count: %d", messages.length); await client.message.send({ streamId: stream.id, topicId: topic.id, messages, partition: Partitioning.PartitionId( - topic.partitions[Math.floor(Math.random() * topic.partitions.length)].id + topic.partitions[Math.floor(Math.random() * topic.partitions.length)] + .id, ), }); sentBatches++; - log('Sent %d message(s).', messages.length); + log("Sent %d message(s).", messages.length); } catch (error) { - log('Error sending messages: %o', error); + log("Error sending messages: %o", error); + log( + "This might be due to server version compatibility. The stream and topic creation worked successfully.", + ); log( - 'This might be due to server version compatibility. The stream and topic creation worked successfully.' + "Please check the Iggy server version and ensure it supports the SendMessages command.", ); - log('Please check the Iggy server version and ensure it supports the SendMessages command.'); sentBatches++; } - await new Promise(resolve => setTimeout(resolve, interval)); + await new Promise((resolve) => setTimeout(resolve, interval)); } - log('Sent %d batches of messages, exiting.', sentBatches); + log("Sent %d batches of messages, exiting.", sentBatches); } async function main() { const args = parseArgs(); - log('Using connection string: %s', args.connectionString); + log("Using connection string: %s", args.connectionString); // Parse connection string (simplified parsing for this example) - const url = new URL(args.connectionString.replace('iggy+tcp://', 'http://')); + const url = new URL(args.connectionString.replace("iggy+tcp://", "http://")); const host = url.hostname; const port = parseInt(url.port) || 8090; - const username = url.username || 'iggy'; - const password = url.password || 'iggy'; + const username = url.username || "iggy"; + const password = url.password || "iggy"; const client = new Client({ - transport: 'TCP', + transport: "TCP", options: { port, host, @@ -188,10 +195,10 @@ async function main() { let topicId = 0; try { - log('Message headers producer has started, selected transport: TCP'); - log('Connecting to Iggy server...'); + log("Message headers producer has started, selected transport: TCP"); + log("Connecting to Iggy server..."); // Client connects automatically when first command is called - log('Connected successfully.'); + log("Connected successfully."); // Login will be handled automatically by the client on first command const { stream, topic } = await initSystem(client); @@ -199,19 +206,19 @@ async function main() { topicId = topic.id; await produceMessages(client, stream, topic); } catch (error) { - log('Error in main: %o', error); + log("Error in main: %o", error); process.exitCode = 1; } finally { if (streamId !== null && topicId !== null) { await cleanup(client, streamId, topicId); } await client.destroy(); - log('Disconnected from server.'); + log("Disconnected from server."); } } -process.on('unhandledRejection', (reason, promise) => { - log('Unhandled Rejection at: %o, reason: %o', promise, reason); +process.on("unhandledRejection", (reason, promise) => { + log("Unhandled Rejection at: %o, reason: %o", promise, reason); process.exitCode = 1; }); diff --git a/foreign/csharp/Iggy_SDK.Tests.Integration/StreamsTests.cs b/foreign/csharp/Iggy_SDK.Tests.Integration/StreamsTests.cs index a14b45ed0c..32c9b26ed6 100644 --- a/foreign/csharp/Iggy_SDK.Tests.Integration/StreamsTests.cs +++ b/foreign/csharp/Iggy_SDK.Tests.Integration/StreamsTests.cs @@ -151,7 +151,7 @@ await Fixture.Clients[protocol].SendMessagesAsync(Identifier.String(Name.GetWith response.ShouldNotBeNull(); response.Id.ShouldBeGreaterThanOrEqualTo(0u); response.Name.ShouldBe(Name.GetWithProtocol(protocol)); - response.Size.ShouldBe(490u); + response.Size.ShouldBe(546u); response.CreatedAt.UtcDateTime.ShouldBe(DateTimeOffset.UtcNow.UtcDateTime, TimeSpan.FromMinutes(1)); response.MessagesCount.ShouldBe(7u); response.TopicsCount.ShouldBe(2); @@ -163,7 +163,7 @@ await Fixture.Clients[protocol].SendMessagesAsync(Identifier.String(Name.GetWith topic.CompressionAlgorithm.ShouldBe(topicRequest1.CompressionAlgorithm); topic.Partitions.ShouldBeNull(); topic.MessageExpiry.ShouldBe(topicRequest1.MessageExpiry); - topic.Size.ShouldBe(210u); + topic.Size.ShouldBe(234u); topic.PartitionsCount.ShouldBe(topicRequest1.PartitionsCount); topic.ReplicationFactor.ShouldBe(topicRequest1.ReplicationFactor); topic.MaxTopicSize.ShouldBeGreaterThan(0u); diff --git a/foreign/csharp/Iggy_SDK.Tests.Integration/TopicsTests.cs b/foreign/csharp/Iggy_SDK.Tests.Integration/TopicsTests.cs index e6b8ffd632..4bb55b42de 100644 --- a/foreign/csharp/Iggy_SDK.Tests.Integration/TopicsTests.cs +++ b/foreign/csharp/Iggy_SDK.Tests.Integration/TopicsTests.cs @@ -193,7 +193,7 @@ await Fixture.Clients[protocol] response.CompressionAlgorithm.ShouldBe(TopicRequest.CompressionAlgorithm); response.Partitions!.Count().ShouldBe(3); response.MessageExpiry.ShouldBe(TopicRequest.MessageExpiry); - response.Size.ShouldBe(630u); + response.Size.ShouldBe(702u); response.PartitionsCount.ShouldBe(3u); response.ReplicationFactor.ShouldBe(TopicRequest.ReplicationFactor); response.MaxTopicSize.ShouldBe(TopicRequest.MaxTopicSize); diff --git a/foreign/csharp/Iggy_SDK/Contracts/Tcp/TcpContracts.cs b/foreign/csharp/Iggy_SDK/Contracts/Tcp/TcpContracts.cs index f2753e51ca..1a0da05f20 100644 --- a/foreign/csharp/Iggy_SDK/Contracts/Tcp/TcpContracts.cs +++ b/foreign/csharp/Iggy_SDK/Contracts/Tcp/TcpContracts.cs @@ -420,17 +420,18 @@ internal static void CreateMessage(Span bytes, Identifier streamId, Identi message.Header.OriginTimestamp); BinaryPrimitives.WriteInt32LittleEndian(bytes[(position + 48)..(position + 52)], headersBytes.Length); BinaryPrimitives.WriteInt32LittleEndian(bytes[(position + 52)..(position + 56)], message.Payload.Length); + BinaryPrimitives.WriteUInt64LittleEndian(bytes[(position + 56)..(position + 64)], message.Header.Reserved); - message.Payload.CopyTo(bytes[(position + 56)..(position + 56 + message.Header.PayloadLength)]); + message.Payload.CopyTo(bytes[(position + 64)..(position + 64 + message.Header.PayloadLength)]); if (headersBytes.Length > 0) { headersBytes .CopyTo(bytes[ - (position + 56 + message.Header.PayloadLength)..(position + 56 + message.Header.PayloadLength + + (position + 64 + message.Header.PayloadLength)..(position + 64 + message.Header.PayloadLength + headersBytes.Length)]); } - position += 56 + message.Header.PayloadLength + headersBytes.Length; + position += 64 + message.Header.PayloadLength + headersBytes.Length; msgSize += message.GetSize() + headersBytes.Length; diff --git a/foreign/csharp/Iggy_SDK/Iggy_SDK.csproj b/foreign/csharp/Iggy_SDK/Iggy_SDK.csproj index cf7adcb5fe..634855ae12 100644 --- a/foreign/csharp/Iggy_SDK/Iggy_SDK.csproj +++ b/foreign/csharp/Iggy_SDK/Iggy_SDK.csproj @@ -7,7 +7,7 @@ net8.0;net10.0 Apache.Iggy Apache.Iggy - 0.6.2-edge.1 + 0.6.3-edge.1 true diff --git a/foreign/csharp/Iggy_SDK/Mappers/BinaryMapper.cs b/foreign/csharp/Iggy_SDK/Mappers/BinaryMapper.cs index 63b8376a93..576204e4e7 100644 --- a/foreign/csharp/Iggy_SDK/Mappers/BinaryMapper.cs +++ b/foreign/csharp/Iggy_SDK/Mappers/BinaryMapper.cs @@ -29,7 +29,7 @@ namespace Apache.Iggy.Mappers; internal static class BinaryMapper { - private const int PropertiesSize = 56; + private const int PropertiesSize = 64; internal static RawPersonalAccessToken MapRawPersonalAccessToken(ReadOnlySpan payload) { @@ -359,17 +359,18 @@ internal static PolledMessages MapMessages(ReadOnlySpan payload, var originTimestamp = BinaryPrimitives.ReadUInt64LittleEndian(payload[(position + 40)..(position + 48)]); var headersLength = BinaryPrimitives.ReadInt32LittleEndian(payload[(position + 48)..(position + 52)]); var payloadLength = BinaryPrimitives.ReadInt32LittleEndian(payload[(position + 52)..(position + 56)]); + var reserved = BinaryPrimitives.ReadUInt64LittleEndian(payload[(position + 56)..(position + 64)]); Dictionary? headers = headersLength switch { 0 => null, > 0 => MapHeaders( - payload[(position + 56 + payloadLength)..(position + 56 + payloadLength + headersLength)]), + payload[(position + 64 + payloadLength)..(position + 64 + payloadLength + headersLength)]), < 0 => throw new ArgumentOutOfRangeException() }; - var payloadRangeStart = position + 56; - var payloadRangeEnd = position + 56 + payloadLength; + var payloadRangeStart = position + 64; + var payloadRangeEnd = position + 64 + payloadLength; if (payloadRangeStart > length || payloadRangeEnd > length) { break; @@ -393,7 +394,8 @@ internal static PolledMessages MapMessages(ReadOnlySpan payload, OriginTimestamp = originTimestamp, PayloadLength = payloadLength, Timestamp = DateTimeOffsetUtils.FromUnixTimeMicroSeconds(timestamp), - UserHeadersLength = headersLength + UserHeadersLength = headersLength, + Reserved = reserved }, UserHeaders = headers, Payload = decryptor is not null @@ -406,7 +408,7 @@ internal static PolledMessages MapMessages(ReadOnlySpan payload, ArrayPool.Shared.Return(messagePayload); } - position += 56 + payloadLength + headersLength; + position += 64 + payloadLength + headersLength; if (position + PropertiesSize >= length) { break; diff --git a/foreign/csharp/Iggy_SDK/Messages/Message.cs b/foreign/csharp/Iggy_SDK/Messages/Message.cs index 3ae23d7e35..1a0e7e697a 100644 --- a/foreign/csharp/Iggy_SDK/Messages/Message.cs +++ b/foreign/csharp/Iggy_SDK/Messages/Message.cs @@ -96,8 +96,8 @@ public Message(UInt128 id, byte[] payload, Dictionary? u /// public int GetSize() { - //return 56 + Payload.Length + (UserHeaders?.Count ?? 0); - return 56 + Payload.Length; + //return 64 + Payload.Length + (UserHeaders?.Count ?? 0); + return 64 + Payload.Length; } private ulong CalculateChecksum(byte[] bytes) diff --git a/foreign/csharp/Iggy_SDK/Messages/MessageHeader.cs b/foreign/csharp/Iggy_SDK/Messages/MessageHeader.cs index 32ed5e1cfb..d20e288d8d 100644 --- a/foreign/csharp/Iggy_SDK/Messages/MessageHeader.cs +++ b/foreign/csharp/Iggy_SDK/Messages/MessageHeader.cs @@ -60,4 +60,9 @@ public class MessageHeader /// Length of the payload. /// public int PayloadLength { get; set; } + + /// + /// Reserved for future use. + /// + public ulong Reserved { get; set; } } diff --git a/foreign/csharp/Iggy_SDK/Utils/TcpMessageStreamHelpers.cs b/foreign/csharp/Iggy_SDK/Utils/TcpMessageStreamHelpers.cs index 22445d37d6..c99337b4db 100644 --- a/foreign/csharp/Iggy_SDK/Utils/TcpMessageStreamHelpers.cs +++ b/foreign/csharp/Iggy_SDK/Utils/TcpMessageStreamHelpers.cs @@ -48,7 +48,7 @@ internal static int CalculateMessageBytesCount(IList messages) var bytesCount = 0; foreach (var message in messages) { - bytesCount += 16 + 56 + message.Payload.Length; + bytesCount += 16 + 64 + message.Payload.Length; if (message.UserHeaders is null) { continue; diff --git a/foreign/csharp/Iggy_SDK_Tests/Utils/BinaryFactory.cs b/foreign/csharp/Iggy_SDK_Tests/Utils/BinaryFactory.cs index daa7875525..78e5c595e6 100644 --- a/foreign/csharp/Iggy_SDK_Tests/Utils/BinaryFactory.cs +++ b/foreign/csharp/Iggy_SDK_Tests/Utils/BinaryFactory.cs @@ -46,7 +46,7 @@ internal static byte[] CreateMessagePayload(ulong offset, ulong timestamp, int h Guid guid, ReadOnlySpan payload) { var messageLength = payload.Length; - var totalSize = 56 + payload.Length; + var totalSize = 64 + payload.Length; Span payloadBuffer = new byte[totalSize].AsSpan(); BinaryPrimitives.WriteUInt64LittleEndian(payloadBuffer[..8], checkSum); @@ -56,8 +56,9 @@ internal static byte[] CreateMessagePayload(ulong offset, ulong timestamp, int h BinaryPrimitives.WriteUInt64LittleEndian(payloadBuffer[40..48], timestamp); BinaryPrimitives.WriteInt32LittleEndian(payloadBuffer[48..52], headersLength); BinaryPrimitives.WriteInt32LittleEndian(payloadBuffer[52..56], payload.Length); + BinaryPrimitives.WriteUInt64LittleEndian(payloadBuffer[56..64], 0); // reserved - payload.CopyTo(payloadBuffer[56..(56 + messageLength)]); + payload.CopyTo(payloadBuffer[64..(64 + messageLength)]); return payloadBuffer.ToArray(); } diff --git a/foreign/go/binary_serialization/send_messages_request_serializer_test.go b/foreign/go/binary_serialization/send_messages_request_serializer_test.go index 985c4b4ebf..c319e11ae3 100644 --- a/foreign/go/binary_serialization/send_messages_request_serializer_test.go +++ b/foreign/go/binary_serialization/send_messages_request_serializer_test.go @@ -54,7 +54,7 @@ func TestSerialize_SendMessagesRequest(t *testing.T) { 0x04, // Partitioning Length 0x01, 0x00, 0x00, 0x00, // PartitionId (123) 0x01, 0x0, 0x0, 0x0, // MessageCount - 0, 0, 0, 0, 112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Index (16*1) bytes + 0, 0, 0, 0, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Index (16*1) bytes } expected = append(expected, message1.Header.ToBytes()...) expected = append(expected, message1.Payload...) diff --git a/foreign/go/contracts/message_header.go b/foreign/go/contracts/message_header.go index 88afa0c998..7167f18d8b 100644 --- a/foreign/go/contracts/message_header.go +++ b/foreign/go/contracts/message_header.go @@ -23,7 +23,7 @@ import ( "time" ) -const MessageHeaderSize = 8 + 16 + 8 + 8 + 8 + 4 + 4 +const MessageHeaderSize = 8 + 16 + 8 + 8 + 8 + 4 + 4 + 8 type MessageID [16]byte @@ -35,6 +35,7 @@ type MessageHeader struct { OriginTimestamp uint64 `json:"origin_timestamp"` UserHeaderLength uint32 `json:"user_header_length"` PayloadLength uint32 `json:"payload_length"` + Reserved uint64 `json:"reserved"` } func NewMessageHeader(id MessageID, payloadLength uint32, userHeaderLength uint32) MessageHeader { @@ -49,7 +50,7 @@ func NewMessageHeader(id MessageID, payloadLength uint32, userHeaderLength uint3 func MessageHeaderFromBytes(data []byte) (*MessageHeader, error) { if len(data) != MessageHeaderSize { - return nil, errors.New("data has incorrect size, must be 56") + return nil, errors.New("data has incorrect size, must be 64") } checksum := binary.LittleEndian.Uint64(data[0:8]) id := data[8:24] @@ -58,6 +59,7 @@ func MessageHeaderFromBytes(data []byte) (*MessageHeader, error) { originTimestamp := binary.LittleEndian.Uint64(data[40:48]) userHeaderLength := binary.LittleEndian.Uint32(data[48:52]) payloadLength := binary.LittleEndian.Uint32(data[52:56]) + reserved := binary.LittleEndian.Uint64(data[56:64]) return &MessageHeader{ Checksum: checksum, @@ -67,6 +69,7 @@ func MessageHeaderFromBytes(data []byte) (*MessageHeader, error) { OriginTimestamp: originTimestamp, UserHeaderLength: userHeaderLength, PayloadLength: payloadLength, + Reserved: reserved, }, nil } @@ -81,6 +84,7 @@ func (mh *MessageHeader) ToBytes() []byte { bytes = binary.LittleEndian.AppendUint64(bytes, mh.OriginTimestamp) bytes = binary.LittleEndian.AppendUint32(bytes, mh.UserHeaderLength) bytes = binary.LittleEndian.AppendUint32(bytes, mh.PayloadLength) + bytes = binary.LittleEndian.AppendUint64(bytes, mh.Reserved) return bytes } diff --git a/foreign/java/external-processors/iggy-connector-flink/iggy-connector-library/src/main/java/org/apache/iggy/connector/flink/sink/IggySinkWriter.java b/foreign/java/external-processors/iggy-connector-flink/iggy-connector-library/src/main/java/org/apache/iggy/connector/flink/sink/IggySinkWriter.java index 70458a1e3f..244750b17c 100644 --- a/foreign/java/external-processors/iggy-connector-flink/iggy-connector-library/src/main/java/org/apache/iggy/connector/flink/sink/IggySinkWriter.java +++ b/foreign/java/external-processors/iggy-connector-flink/iggy-connector-library/src/main/java/org/apache/iggy/connector/flink/sink/IggySinkWriter.java @@ -67,7 +67,7 @@ public class IggySinkWriter implements SinkWriter { public enum PartitioningStrategy { BALANCED, PARTITION_ID, - MESSAGE_KEY + MESSAGE_KEY, } /** @@ -89,7 +89,6 @@ public IggySinkWriter( int batchSize, Duration flushInterval, PartitioningStrategy partitioningStrategy) { - if (httpClient == null) { throw new IllegalArgumentException("httpClient cannot be null"); } @@ -172,7 +171,6 @@ public void flush(boolean endOfInput) throws IOException { // Clear buffer and update flush time buffer.clear(); lastFlushTime = System.currentTimeMillis(); - } catch (RuntimeException e) { log.error("IggySinkWriter.flush() - ERROR: {}", e.getMessage(), e); throw new ConnectorException( @@ -206,7 +204,6 @@ private Partitioning determinePartitioning() { switch (partitioningStrategy) { case BALANCED: return Partitioning.balanced(); - case PARTITION_ID: // Use first element's partition key if available if (!buffer.isEmpty()) { @@ -216,7 +213,6 @@ private Partitioning determinePartitioning() { } } return Partitioning.balanced(); - case MESSAGE_KEY: // Use first element's partition key as message key if (!buffer.isEmpty()) { @@ -226,7 +222,6 @@ private Partitioning determinePartitioning() { } } return Partitioning.balanced(); - default: return Partitioning.balanced(); } @@ -287,7 +282,9 @@ private Message createMessage(byte[] payload) { BigInteger.ZERO, // timestamp BigInteger.ZERO, // originTimestamp 0L, // userHeadersLength - (long) payload.length); // payloadLength + (long) payload.length, // payloadLength + BigInteger.ZERO // reserved + ); return new Message(header, payload, Collections.emptyMap()); } diff --git a/foreign/java/gradle.properties b/foreign/java/gradle.properties index 2942656f95..cbbe7abd4d 100644 --- a/foreign/java/gradle.properties +++ b/foreign/java/gradle.properties @@ -17,5 +17,5 @@ # under the License. # -version=0.6.2-SNAPSHOT +version=0.6.3-SNAPSHOT group=org.apache.iggy diff --git a/foreign/java/java-sdk/src/main/java/org/apache/iggy/message/Message.java b/foreign/java/java-sdk/src/main/java/org/apache/iggy/message/Message.java index 144103d102..d781105aba 100644 --- a/foreign/java/java-sdk/src/main/java/org/apache/iggy/message/Message.java +++ b/foreign/java/java-sdk/src/main/java/org/apache/iggy/message/Message.java @@ -68,7 +68,8 @@ public static Message of(String payload, Map userHeaders BigInteger.ZERO, BigInteger.ZERO, userHeadersLength, - (long) payloadBytes.length); + (long) payloadBytes.length, + BigInteger.ZERO); return new Message(msgHeader, payloadBytes, userHeaders); } @@ -82,7 +83,8 @@ public Message withUserHeaders(Map userHeaders) { header.timestamp(), header.originTimestamp(), userHeadersLength, - (long) payload.length); + (long) payload.length, + header.reserved()); return new Message(updatedHeader, payload, mergedHeaders); } diff --git a/foreign/java/java-sdk/src/main/java/org/apache/iggy/message/MessageHeader.java b/foreign/java/java-sdk/src/main/java/org/apache/iggy/message/MessageHeader.java index a0867988f3..85f5868f15 100644 --- a/foreign/java/java-sdk/src/main/java/org/apache/iggy/message/MessageHeader.java +++ b/foreign/java/java-sdk/src/main/java/org/apache/iggy/message/MessageHeader.java @@ -28,7 +28,7 @@ public record MessageHeader( BigInteger timestamp, BigInteger originTimestamp, Long userHeadersLength, - Long payloadLength) { - - public static final int SIZE = 8 + 16 + 8 + 8 + 8 + 4 + 4; + Long payloadLength, + BigInteger reserved) { + public static final int SIZE = 8 + 16 + 8 + 8 + 8 + 4 + 4 + 8; } diff --git a/foreign/java/java-sdk/src/main/java/org/apache/iggy/serde/BytesDeserializer.java b/foreign/java/java-sdk/src/main/java/org/apache/iggy/serde/BytesDeserializer.java index fcd16ca55e..3fb1c843f7 100644 --- a/foreign/java/java-sdk/src/main/java/org/apache/iggy/serde/BytesDeserializer.java +++ b/foreign/java/java-sdk/src/main/java/org/apache/iggy/serde/BytesDeserializer.java @@ -193,8 +193,9 @@ public static Message readPolledMessage(ByteBuf response) { var originTimestamp = readU64AsBigInteger(response); var userHeadersLength = response.readUnsignedIntLE(); var payloadLength = response.readUnsignedIntLE(); - var header = - new MessageHeader(checksum, id, offset, timestamp, originTimestamp, userHeadersLength, payloadLength); + var reserved = readU64AsBigInteger(response); + var header = new MessageHeader( + checksum, id, offset, timestamp, originTimestamp, userHeadersLength, payloadLength, reserved); var payload = newByteArray(payloadLength); response.readBytes(payload); Map userHeaders = new HashMap<>(); diff --git a/foreign/java/java-sdk/src/main/java/org/apache/iggy/serde/BytesSerializer.java b/foreign/java/java-sdk/src/main/java/org/apache/iggy/serde/BytesSerializer.java index 20301ecdbd..c9c3171895 100644 --- a/foreign/java/java-sdk/src/main/java/org/apache/iggy/serde/BytesSerializer.java +++ b/foreign/java/java-sdk/src/main/java/org/apache/iggy/serde/BytesSerializer.java @@ -99,6 +99,7 @@ public static ByteBuf toBytes(MessageHeader header) { buffer.writeBytes(toBytesAsU64(header.originTimestamp())); buffer.writeIntLE(header.userHeadersLength().intValue()); buffer.writeIntLE(header.payloadLength().intValue()); + buffer.writeBytes(toBytesAsU64(header.reserved())); return buffer; } diff --git a/foreign/java/java-sdk/src/test/java/org/apache/iggy/client/blocking/tcp/BytesSerializerTest.java b/foreign/java/java-sdk/src/test/java/org/apache/iggy/client/blocking/tcp/BytesSerializerTest.java index 3453f18631..13893f040e 100644 --- a/foreign/java/java-sdk/src/test/java/org/apache/iggy/client/blocking/tcp/BytesSerializerTest.java +++ b/foreign/java/java-sdk/src/test/java/org/apache/iggy/client/blocking/tcp/BytesSerializerTest.java @@ -505,7 +505,8 @@ void shouldSerializeMessageWithoutUserHeaders() { BigInteger.valueOf(1000), // timestamp BigInteger.valueOf(1000), // originTimestamp 0L, // userHeadersLength - 5L // payloadLength + 5L, // payloadLength + BigInteger.ZERO // reserved ); byte[] payload = "hello".getBytes(); var message = new Message(header, payload, new HashMap<>()); @@ -535,7 +536,8 @@ void shouldSerializeMessageWithUserHeaders() { BigInteger.valueOf(1000), BigInteger.valueOf(1000), (long) userHeadersLength, - 3L // "abc".length() + 3L, // "abc".length() + BigInteger.ZERO // reserved ); byte[] payload = "abc".getBytes(); var message = new Message(header, payload, userHeaders); @@ -562,7 +564,8 @@ void shouldSerializeMessageHeader() { BigInteger.valueOf(2000), // timestamp BigInteger.valueOf(1999), // originTimestamp 10L, // userHeadersLength - 100L // payloadLength + 100L, // payloadLength + BigInteger.ZERO // reserved ); // when diff --git a/foreign/java/java-sdk/src/test/java/org/apache/iggy/serde/BytesDeserializerTest.java b/foreign/java/java-sdk/src/test/java/org/apache/iggy/serde/BytesDeserializerTest.java index 36a6d5ea36..c9b570ac09 100644 --- a/foreign/java/java-sdk/src/test/java/org/apache/iggy/serde/BytesDeserializerTest.java +++ b/foreign/java/java-sdk/src/test/java/org/apache/iggy/serde/BytesDeserializerTest.java @@ -341,6 +341,7 @@ void shouldDeserializePolledMessageWithoutUserHeaders() { writeU64(buffer, BigInteger.valueOf(1000)); // origin timestamp buffer.writeIntLE(0); // user headers length buffer.writeIntLE(5); // payload length + writeU64(buffer, BigInteger.ZERO); // reserved buffer.writeBytes("hello".getBytes()); // payload // when @@ -374,6 +375,7 @@ void shouldDeserializePolledMessageWithUserHeaders() { buffer.writeIntLE(headersBuffer.readableBytes()); // user headers length buffer.writeIntLE(3); // payload length + writeU64(buffer, BigInteger.ZERO); // reserved buffer.writeBytes("abc".getBytes()); // payload buffer.writeBytes(headersBuffer); // user headers @@ -401,6 +403,7 @@ void shouldDeserializePolledMessages() { writeU64(buffer, BigInteger.valueOf(1000)); buffer.writeIntLE(0); buffer.writeIntLE(2); + writeU64(buffer, BigInteger.ZERO); // reserved buffer.writeBytes("hi".getBytes()); // when @@ -775,7 +778,8 @@ void shouldDeserializePolledMessagesWithEmptyUserHeaders() throws Exception { "timestamp": 0, "origin_timestamp": 1000, "user_headers_length": 0, - "payload_length": 4 + "payload_length": 4, + "reserved": 0 }, "payload": "dGVzdA==", "user_headers": [] @@ -807,7 +811,8 @@ void shouldDeserializePolledMessagesWithUserHeaders() throws Exception { "timestamp": 0, "origin_timestamp": 1000, "user_headers_length": 62, - "payload_length": 4 + "payload_length": 4, + "reserved": 0 }, "payload": "dGVzdA==", "user_headers": [ diff --git a/foreign/node/package-lock.json b/foreign/node/package-lock.json index a8b396898c..6ca584d629 100644 --- a/foreign/node/package-lock.json +++ b/foreign/node/package-lock.json @@ -1,12 +1,12 @@ { "name": "apache-iggy", - "version": "0.6.1-edge.1", + "version": "0.6.3-edge.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "apache-iggy", - "version": "0.6.1-edge.1", + "version": "0.6.3-edge.1", "license": "Apache-2.0", "dependencies": { "debug": "4.4.3", diff --git a/foreign/node/package.json b/foreign/node/package.json index e04752b5ae..f339c42250 100644 --- a/foreign/node/package.json +++ b/foreign/node/package.json @@ -1,7 +1,7 @@ { "name": "apache-iggy", "type": "module", - "version": "0.6.2-edge.1", + "version": "0.6.3-edge.1", "description": "Official Apache Iggy NodeJS SDK", "keywords": [ "iggy", diff --git a/foreign/node/src/wire/message/iggy-header.utils.ts b/foreign/node/src/wire/message/iggy-header.utils.ts index d26ef4decb..b6bd0bf548 100644 --- a/foreign/node/src/wire/message/iggy-header.utils.ts +++ b/foreign/node/src/wire/message/iggy-header.utils.ts @@ -20,32 +20,33 @@ import { toDate } from "../serialize.utils.js"; import { u128LEBufToBigint } from "../number.utils.js"; - /** * Iggy message header containing metadata for each message. */ export type IggyMessageHeader = { /** Message checksum for integrity verification */ - checksum: bigint, + checksum: bigint; /** Unique message identifier (UUID or numeric) */ - id: string | bigint, + id: string | bigint; /** Message offset within the partition */ - offset: bigint, + offset: bigint; /** Server-assigned timestamp */ - timestamp: Date, + timestamp: Date; /** Client-provided origin timestamp */ - originTimestamp: Date, + originTimestamp: Date; /** Length of user-defined headers in bytes */ - userHeadersLength: number, + userHeadersLength: number; /** Length of message payload in bytes */ - payloadLength: number + payloadLength: number; + /** Reserved for future use */ + reserved: bigint; }; /** * Size of the Iggy message header in bytes. - * Layout: u64 (checksum) + u128 (id) + u64 (offset) + u64 (timestamp) + u64 (originTimestamp) + u32 (userHeadersLength) + u32 (payloadLength) + * Layout: u64 (checksum) + u128 (id) + u64 (offset) + u64 (timestamp) + u64 (originTimestamp) + u32 (userHeadersLength) + u32 (payloadLength) + u64 (reserved) */ -export const IGGY_MESSAGE_HEADER_SIZE = 8 + 16 + 8 + 8 + 8 + 4 + 4; +export const IGGY_MESSAGE_HEADER_SIZE = 8 + 16 + 8 + 8 + 8 + 4 + 4 + 8; /** * Serializes an Iggy message header to wire format. @@ -59,7 +60,7 @@ export const IGGY_MESSAGE_HEADER_SIZE = 8 + 16 + 8 + 8 + 8 + 4 + 4; export const serializeIggyMessageHeader = ( id: Buffer, payload: Buffer, - userHeaders: Buffer + userHeaders: Buffer, ) => { const b = Buffer.allocUnsafe(IGGY_MESSAGE_HEADER_SIZE); b.writeBigUInt64LE(0n, 0); // checksum u64 @@ -68,7 +69,8 @@ export const serializeIggyMessageHeader = ( b.writeBigUInt64LE(0n, 32); // timestamp u64 b.writeBigUint64LE(BigInt(new Date().getTime()), 40); // originTimestamp u64 b.writeUInt32LE(userHeaders.length, 48); // userHeaders len u32 - b.writeUInt32LE(payload.length, 52) // payload len u32 + b.writeUInt32LE(payload.length, 52); // payload len u32 + b.writeBigUInt64LE(0n, 56); // reserved u64 return b; }; @@ -88,10 +90,10 @@ export const deserialiseMessageId = (b: Buffer) => u128LEBufToBigint(b); * @throws Error if buffer length doesn't match expected header size */ export const deserializeIggyMessageHeaders = (b: Buffer) => { - if(b.length !== IGGY_MESSAGE_HEADER_SIZE) + if (b.length !== IGGY_MESSAGE_HEADER_SIZE) throw new Error( `deserialize message headers error, length = ${b.length} ` + - `expected ${IGGY_MESSAGE_HEADER_SIZE}` + `expected ${IGGY_MESSAGE_HEADER_SIZE}`, ); const headers: IggyMessageHeader = { checksum: b.readBigUInt64LE(0), @@ -100,7 +102,8 @@ export const deserializeIggyMessageHeaders = (b: Buffer) => { timestamp: toDate(b.readBigUInt64LE(32)), originTimestamp: toDate(b.readBigUInt64LE(40)), userHeadersLength: b.readUInt32LE(48), - payloadLength: b.readUInt32LE(52) - } + payloadLength: b.readUInt32LE(52), + reserved: b.readBigUInt64LE(56), + }; return headers; }; diff --git a/foreign/node/src/wire/message/send-messages.command.test.ts b/foreign/node/src/wire/message/send-messages.command.test.ts index 5538858faa..9caf2ce1e8 100644 --- a/foreign/node/src/wire/message/send-messages.command.test.ts +++ b/foreign/node/src/wire/message/send-messages.command.test.ts @@ -40,7 +40,7 @@ describe("SendMessages", () => { }; it("serialize SendMessages into a buffer", () => { - assert.deepEqual(SEND_MESSAGES.serialize(t1).length, 533); + assert.deepEqual(SEND_MESSAGES.serialize(t1).length, 589); }); it("serialize all kinds of messageId", () => { diff --git a/foreign/python/Cargo.toml b/foreign/python/Cargo.toml index dc398e1d4f..ee1094cda9 100644 --- a/foreign/python/Cargo.toml +++ b/foreign/python/Cargo.toml @@ -17,7 +17,7 @@ [package] name = "apache-iggy" -version = "0.6.2-dev1" +version = "0.6.3-dev1" edition = "2021" authors = [ "Dario Lencina Talarico ", @@ -31,7 +31,7 @@ repository = "https://github.com/apache/iggy" [dependencies] bytes = "1.11.0" futures = "0.3.31" -iggy = { path = "../../core/sdk", version = "0.8.2-edge.2" } +iggy = { path = "../../core/sdk", version = "0.8.3-edge.1" } pyo3 = "0.27.2" pyo3-async-runtimes = { version = "0.27.0", features = [ "attributes", diff --git a/foreign/python/src/send_message.rs b/foreign/python/src/send_message.rs index 0dd9fb5ab9..3f3729626e 100644 --- a/foreign/python/src/send_message.rs +++ b/foreign/python/src/send_message.rs @@ -47,6 +47,7 @@ impl Clone for SendMessage { origin_timestamp: self.inner.header.origin_timestamp, user_headers_length: self.inner.header.user_headers_length, payload_length: self.inner.header.payload_length, + reserved: self.inner.header.reserved, }, payload: self.inner.payload.clone(), user_headers: self.inner.user_headers.clone(), From 6ee5a178ce3f5fc387d40b7f6ec7911446e3ee9c Mon Sep 17 00:00:00 2001 From: Maciej Modzelewski Date: Mon, 2 Feb 2026 12:33:35 +0100 Subject: [PATCH 2/3] update java tests --- .../blocking/http/ObjectMapperTest.java | 9 ++- .../iggy/serde/BytesDeserializerTest.java | 78 ------------------- 2 files changed, 6 insertions(+), 81 deletions(-) diff --git a/foreign/java/java-sdk/src/test/java/org/apache/iggy/client/blocking/http/ObjectMapperTest.java b/foreign/java/java-sdk/src/test/java/org/apache/iggy/client/blocking/http/ObjectMapperTest.java index eefda1659d..53c8f58bcd 100644 --- a/foreign/java/java-sdk/src/test/java/org/apache/iggy/client/blocking/http/ObjectMapperTest.java +++ b/foreign/java/java-sdk/src/test/java/org/apache/iggy/client/blocking/http/ObjectMapperTest.java @@ -59,7 +59,8 @@ void shouldDeserializePolledMessagesWithEmptyUserHeaders() { "timestamp": 0, "origin_timestamp": 1000, "user_headers_length": 0, - "payload_length": 4 + "payload_length": 4, + "reserved": 0 }, "payload": "dGVzdA==", "user_headers": [] @@ -94,7 +95,8 @@ void shouldDeserializePolledMessagesWithUserHeaders() { "timestamp": 0, "origin_timestamp": 1000, "user_headers_length": 62, - "payload_length": 4 + "payload_length": 4, + "reserved": 0 }, "payload": "dGVzdA==", "user_headers": [ @@ -186,7 +188,8 @@ private String createMessageJson(String base64Payload) { "timestamp": 0, "origin_timestamp": 0, "user_headers_length": 0, - "payload_length": 4 + "payload_length": 4, + "reserved": 0 }, "payload": "%s", "user_headers": [] diff --git a/foreign/java/java-sdk/src/test/java/org/apache/iggy/serde/BytesDeserializerTest.java b/foreign/java/java-sdk/src/test/java/org/apache/iggy/serde/BytesDeserializerTest.java index c9b570ac09..22ce77a75d 100644 --- a/foreign/java/java-sdk/src/test/java/org/apache/iggy/serde/BytesDeserializerTest.java +++ b/foreign/java/java-sdk/src/test/java/org/apache/iggy/serde/BytesDeserializerTest.java @@ -755,82 +755,4 @@ void shouldDeserializePersonalAccessTokenInfoWithoutExpiry() { assertThat(tokenInfo.expiryAt()).isEmpty(); } } - - @Nested - class JsonDeserialization { - - private static final tools.jackson.databind.ObjectMapper MAPPER = - org.apache.iggy.client.blocking.http.ObjectMapperFactory.getInstance(); - - @Test - void shouldDeserializePolledMessagesWithEmptyUserHeaders() throws Exception { - String json = """ - { - "partition_id": 1, - "current_offset": 10, - "count": 1, - "messages": [ - { - "header": { - "checksum": 0, - "id": 42, - "offset": 0, - "timestamp": 0, - "origin_timestamp": 1000, - "user_headers_length": 0, - "payload_length": 4, - "reserved": 0 - }, - "payload": "dGVzdA==", - "user_headers": [] - } - ] - } - """; - - var polledMessages = MAPPER.readValue(json, org.apache.iggy.message.PolledMessages.class); - - assertThat(polledMessages).isNotNull(); - assertThat(polledMessages.messages()).hasSize(1); - assertThat(polledMessages.messages().get(0).userHeaders()).isEmpty(); - } - - @Test - void shouldDeserializePolledMessagesWithUserHeaders() throws Exception { - String json = """ - { - "partition_id": 1, - "current_offset": 10, - "count": 1, - "messages": [ - { - "header": { - "checksum": 0, - "id": 42, - "offset": 0, - "timestamp": 0, - "origin_timestamp": 1000, - "user_headers_length": 62, - "payload_length": 4, - "reserved": 0 - }, - "payload": "dGVzdA==", - "user_headers": [ - { - "key": {"kind": "string", "value": "Y29udGVudC10eXBl"}, - "value": {"kind": "string", "value": "dGV4dC9wbGFpbg=="} - } - ] - } - ] - } - """; - - var polledMessages = MAPPER.readValue(json, org.apache.iggy.message.PolledMessages.class); - - assertThat(polledMessages).isNotNull(); - assertThat(polledMessages.messages()).hasSize(1); - assertThat(polledMessages.messages().get(0).userHeaders()).hasSize(1); - } - } } From 03146ebade904550ade6ca403f1369d8360911c4 Mon Sep 17 00:00:00 2001 From: spetz Date: Tue, 3 Feb 2026 10:33:51 +0100 Subject: [PATCH 3/3] Validate reserved field must be set to 0 --- core/common/src/error/iggy_error.rs | 2 + .../src/types/message/message_header.rs | 74 +++++++++++++++++-- 2 files changed, 69 insertions(+), 7 deletions(-) diff --git a/core/common/src/error/iggy_error.rs b/core/common/src/error/iggy_error.rs index 0e5bd23e2d..18d759c795 100644 --- a/core/common/src/error/iggy_error.rs +++ b/core/common/src/error/iggy_error.rs @@ -407,6 +407,8 @@ pub enum IggyError { ProducerClosed = 4057, #[error("Invalid offset: {0}")] InvalidOffset(u64) = 4100, + #[error("Invalid reserved field value: {0}, expected: 0")] + InvalidReservedField(u64) = 4101, #[error("Consumer group with ID: {0} for topic with ID: {1} was not found.")] ConsumerGroupIdNotFound(Identifier, Identifier) = 5000, #[error("Invalid consumer group ID")] diff --git a/core/common/src/types/message/message_header.rs b/core/common/src/types/message/message_header.rs index c2b788eba1..0fc1121c35 100644 --- a/core/common/src/types/message/message_header.rs +++ b/core/common/src/types/message/message_header.rs @@ -94,11 +94,17 @@ impl IggyMessageHeader { .try_into() .map_err(|_| IggyError::InvalidNumberEncoding)?, ), - reserved: u64::from_le_bytes( - bytes[IGGY_MESSAGE_RESERVED_OFFSET_RANGE] - .try_into() - .map_err(|_| IggyError::InvalidNumberEncoding)?, - ), + reserved: { + let reserved = u64::from_le_bytes( + bytes[IGGY_MESSAGE_RESERVED_OFFSET_RANGE] + .try_into() + .map_err(|_| IggyError::InvalidNumberEncoding)?, + ); + if reserved != 0 { + return Err(IggyError::InvalidReservedField(reserved)); + } + reserved + }, }) } } @@ -164,12 +170,16 @@ impl BytesSerializable for IggyMessageHeader { .map_err(|_| IggyError::InvalidNumberEncoding)?, ); - let _reserved = u64::from_le_bytes( + let reserved = u64::from_le_bytes( bytes[IGGY_MESSAGE_RESERVED_OFFSET_RANGE] .try_into() .map_err(|_| IggyError::InvalidNumberEncoding)?, ); + if reserved != 0 { + return Err(IggyError::InvalidReservedField(reserved)); + } + Ok(IggyMessageHeader { checksum, id, @@ -178,7 +188,7 @@ impl BytesSerializable for IggyMessageHeader { origin_timestamp, user_headers_length: headers_length, payload_length, - reserved: _reserved, + reserved, }) } } @@ -245,4 +255,54 @@ mod tests { assert_eq!(header.user_headers_length, deserialized.user_headers_length); assert_eq!(header.payload_length, deserialized.payload_length); } + + #[test] + fn should_reject_non_zero_reserved_field_from_bytes() { + let header = IggyMessageHeader { + checksum: 123456789, + id: 987654321, + offset: 100, + timestamp: 1000000, + origin_timestamp: 999999, + user_headers_length: 50, + payload_length: 200, + reserved: 0, + }; + + let mut bytes = header.to_bytes().to_vec(); + let non_zero_reserved: u64 = 42; + bytes[IGGY_MESSAGE_RESERVED_OFFSET_RANGE].copy_from_slice(&non_zero_reserved.to_le_bytes()); + + let result = IggyMessageHeader::from_bytes(Bytes::from(bytes)); + assert!(result.is_err()); + assert_eq!( + result.unwrap_err(), + IggyError::InvalidReservedField(non_zero_reserved) + ); + } + + #[test] + fn should_reject_non_zero_reserved_field_from_raw_bytes() { + let header = IggyMessageHeader { + checksum: 111, + id: 222, + offset: 333, + timestamp: 444, + origin_timestamp: 555, + user_headers_length: 66, + payload_length: 77, + reserved: 0, + }; + + let mut bytes = header.to_bytes().to_vec(); + let non_zero_reserved: u64 = 123456789; + bytes[IGGY_MESSAGE_RESERVED_OFFSET_RANGE].copy_from_slice(&non_zero_reserved.to_le_bytes()); + + let result = IggyMessageHeader::from_raw_bytes(&bytes); + assert!(result.is_err()); + assert_eq!( + result.unwrap_err(), + IggyError::InvalidReservedField(non_zero_reserved) + ); + } }