Compare commits

...

5 Commits

Author SHA1 Message Date
bb53821aef Update gw proto & refactor Mesh Heartbeat event.
This refactors the gateway protobuf payloads, such that the
Concentratord can publish an Event message, containing one of the
possible events published by the Concentratord (uplink, stats or mesh
event). It also combines the possible Concentratord commands into a
single Command message. This simplifies the ZMQ interface as it is no
longer needed to match the payload type by string.

This also refactors the MeshHeartbeat message into a Mesh message, which
can contain multiple events, of which the Heartbeat is one of the
possible events.

The future goal is to make it possible to send different types of events
from the Gateway Mesh Relay gateways (e.g. battery status, ...) and to
make it possible to also send proprietary event types.
2025-05-08 14:29:15 +01:00
d002f5c97b ui: Format code. 2025-04-28 10:18:44 +01:00
9cf12a187c ui: Clear tenant id after delete.
Fixes #635.
2025-04-28 10:18:05 +01:00
1b5e5972f4 ui: Fix JSON enqueue issue / code-editor render issue.
This fixes two issues:

- An error logged to the console when enqueueing a JSON downlink payload
(Q.Va is not a function).
- The codemirror editor has been replaced by ace, to solve a potential
rendering issue within ReactJS / Antd.

Closes #658.
2025-04-28 10:09:52 +01:00
330f5dcae0 Bump version to 4.12.0 2025-04-22 09:01:31 +01:00
27 changed files with 342 additions and 167 deletions

12
Cargo.lock generated
View File

@ -629,7 +629,7 @@ dependencies = [
[[package]] [[package]]
name = "backend" name = "backend"
version = "4.12.0-test.4" version = "4.12.0"
dependencies = [ dependencies = [
"aes-kw", "aes-kw",
"anyhow", "anyhow",
@ -831,7 +831,7 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]] [[package]]
name = "chirpstack" name = "chirpstack"
version = "4.12.0-test.4" version = "4.12.0"
dependencies = [ dependencies = [
"aes", "aes",
"anyhow", "anyhow",
@ -923,7 +923,7 @@ dependencies = [
[[package]] [[package]]
name = "chirpstack_api" name = "chirpstack_api"
version = "4.12.0-test.4" version = "4.12.0"
dependencies = [ dependencies = [
"hex", "hex",
"pbjson", "pbjson",
@ -940,7 +940,7 @@ dependencies = [
[[package]] [[package]]
name = "chirpstack_integration" name = "chirpstack_integration"
version = "4.12.0-test.4" version = "4.12.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -2776,7 +2776,7 @@ dependencies = [
[[package]] [[package]]
name = "lrwn" name = "lrwn"
version = "4.12.0-test.4" version = "4.12.0"
dependencies = [ dependencies = [
"aes", "aes",
"anyhow", "anyhow",
@ -2789,7 +2789,7 @@ dependencies = [
[[package]] [[package]]
name = "lrwn_filters" name = "lrwn_filters"
version = "4.12.0-test.4" version = "4.12.0"
dependencies = [ dependencies = [
"hex", "hex",
"lrwn", "lrwn",

View File

@ -1,16 +1,16 @@
{ {
"name": "@chirpstack/chirpstack-api-grpc-web", "name": "@chirpstack/chirpstack-api-grpc-web",
"version": "4.12.0-test.4", "version": "4.12.0",
"description": "Chirpstack gRPC-web API", "description": "Chirpstack gRPC-web API",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"grpc-tools": "^1.12.4", "grpc-tools": "^1.13.0",
"ts-protoc-gen": "^0.15.0", "ts-protoc-gen": "^0.15.0",
"typescript": "^5.1.6" "typescript": "^5.8.3"
}, },
"dependencies": { "dependencies": {
"@types/google-protobuf": "^3.15.12", "@types/google-protobuf": "^3.15.12",
"google-protobuf": "^3.21.2", "google-protobuf": "^3.21.4",
"grpc-web": "^1.5.0" "grpc-web": "^1.5.0"
} }
} }

View File

@ -146,15 +146,20 @@ glob@^7.1.3:
once "^1.3.0" once "^1.3.0"
path-is-absolute "^1.0.0" path-is-absolute "^1.0.0"
google-protobuf@^3.15.5, google-protobuf@^3.21.2: google-protobuf@^3.15.5:
version "3.21.2" version "3.21.2"
resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.21.2.tgz#4580a2bea8bbb291ee579d1fefb14d6fa3070ea4" resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.21.2.tgz#4580a2bea8bbb291ee579d1fefb14d6fa3070ea4"
integrity sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA== integrity sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==
grpc-tools@^1.12.4: google-protobuf@^3.21.4:
version "1.12.4" version "3.21.4"
resolved "https://registry.yarnpkg.com/grpc-tools/-/grpc-tools-1.12.4.tgz#a044c9e8157941033ea7a5f144c2dc9dc4501de4" resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.21.4.tgz#2f933e8b6e5e9f8edde66b7be0024b68f77da6c9"
integrity sha512-5+mLAJJma3BjnW/KQp6JBjUMgvu7Mu3dBvBPd1dcbNIb+qiR0817zDpgPjS7gRb+l/8EVNIa3cB02xI9JLToKg== integrity sha512-MnG7N936zcKTco4Jd2PX2U96Kf9PxygAPKBug+74LHzmHXmceN16MmRcdgZv+DGef/S9YvQAfRsNCn4cjf9yyQ==
grpc-tools@^1.13.0:
version "1.13.0"
resolved "https://registry.yarnpkg.com/grpc-tools/-/grpc-tools-1.13.0.tgz#a4fea8eebce51fb9fec00055a3e52016dfd5af89"
integrity sha512-7CbkJ1yWPfX0nHjbYG58BQThNhbICXBZynzCUxCb3LzX5X9B3hQbRY2STiRgIEiLILlK9fgl0z0QVGwPCdXf5g==
dependencies: dependencies:
"@mapbox/node-pre-gyp" "^1.0.5" "@mapbox/node-pre-gyp" "^1.0.5"
@ -376,10 +381,10 @@ ts-protoc-gen@^0.15.0:
dependencies: dependencies:
google-protobuf "^3.15.5" google-protobuf "^3.15.5"
typescript@^5.1.6: typescript@^5.8.3:
version "5.4.3" version "5.8.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.3.tgz#5c6fedd4c87bee01cd7a528a30145521f8e0feff" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e"
integrity sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg== integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==
util-deprecate@^1.0.1: util-deprecate@^1.0.1:
version "1.0.2" version "1.0.2"

View File

@ -8,7 +8,7 @@ plugins {
} }
group = "io.chirpstack" group = "io.chirpstack"
version = "4.12.0-test.4" version = "4.12.0"
repositories { repositories {
mavenCentral() mavenCentral()

12
api/js/package.json vendored
View File

@ -1,17 +1,17 @@
{ {
"name": "@chirpstack/chirpstack-api", "name": "@chirpstack/chirpstack-api",
"version": "4.12.0-test.4", "version": "4.12.0",
"description": "Chirpstack JS and TS API", "description": "Chirpstack JS and TS API",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"grpc-tools": "^1.12.4", "grpc-tools": "^1.13.0",
"ts-protoc-gen": "^0.15.0", "ts-protoc-gen": "^0.15.0",
"typescript": "^5.1.6" "typescript": "^5.8.3"
}, },
"dependencies": { "dependencies": {
"@grpc/grpc-js": "^1.10.4", "@grpc/grpc-js": "^1.13.3",
"@mapbox/node-pre-gyp": "^1.0.11", "@mapbox/node-pre-gyp": "^1.0.11",
"@types/google-protobuf": "^3.15.6", "@types/google-protobuf": "^3.15.12",
"google-protobuf": "^3.21.2" "google-protobuf": "^3.21.4"
} }
} }

39
api/js/yarn.lock vendored
View File

@ -2,10 +2,10 @@
# yarn lockfile v1 # yarn lockfile v1
"@grpc/grpc-js@^1.10.4": "@grpc/grpc-js@^1.13.3":
version "1.10.9" version "1.13.3"
resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.10.9.tgz#468cc1549a3fe37b760a16745fb7685d91f4f10c" resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.13.3.tgz#6ad08d186c2a8651697085f790c5c68eaca45904"
integrity sha512-5tcgUctCG0qoNyfChZifz2tJqbRbXVO9J7X6duFcOjY3HUNCxg5D0ZCK7EP9vIcZ0zRpLU9bWkyCqVCLZ46IbQ== integrity sha512-FTXHdOoPbZrBjlVLHuKbDZnsTxXv2BlHF57xw6LuThXacXvtkahEPED0CKMk6obZDf65Hv4k3z62eyPNpvinIg==
dependencies: dependencies:
"@grpc/proto-loader" "^0.7.13" "@grpc/proto-loader" "^0.7.13"
"@js-sdsl/ordered-map" "^4.4.2" "@js-sdsl/ordered-map" "^4.4.2"
@ -93,10 +93,10 @@
resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570"
integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==
"@types/google-protobuf@^3.15.6": "@types/google-protobuf@^3.15.12":
version "3.15.6" version "3.15.12"
resolved "https://registry.yarnpkg.com/@types/google-protobuf/-/google-protobuf-3.15.6.tgz#674a69493ef2c849b95eafe69167ea59079eb504" resolved "https://registry.yarnpkg.com/@types/google-protobuf/-/google-protobuf-3.15.12.tgz#eb2ba0eddd65712211a2b455dc6071d665ccf49b"
integrity sha512-pYVNNJ+winC4aek+lZp93sIKxnXt5qMkuKmaqS3WGuTq0Bw1ZDYNBgzG5kkdtwcv+GmYJGo3yEg6z2cKKAiEdw== integrity sha512-40um9QqwHjRS92qnOaDpL7RmDK15NuZYo9HihiJRbYkMQZlWnuH8AdvbMy8/o6lgLmKbDUKa+OALCltHdbOTpQ==
"@types/node@>=13.7.0": "@types/node@>=13.7.0":
version "20.4.8" version "20.4.8"
@ -265,15 +265,20 @@ glob@^7.1.3:
once "^1.3.0" once "^1.3.0"
path-is-absolute "^1.0.0" path-is-absolute "^1.0.0"
google-protobuf@^3.15.5, google-protobuf@^3.21.2: google-protobuf@^3.15.5:
version "3.21.2" version "3.21.2"
resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.21.2.tgz#4580a2bea8bbb291ee579d1fefb14d6fa3070ea4" resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.21.2.tgz#4580a2bea8bbb291ee579d1fefb14d6fa3070ea4"
integrity sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA== integrity sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==
grpc-tools@^1.12.4: google-protobuf@^3.21.4:
version "1.12.4" version "3.21.4"
resolved "https://registry.yarnpkg.com/grpc-tools/-/grpc-tools-1.12.4.tgz#a044c9e8157941033ea7a5f144c2dc9dc4501de4" resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.21.4.tgz#2f933e8b6e5e9f8edde66b7be0024b68f77da6c9"
integrity sha512-5+mLAJJma3BjnW/KQp6JBjUMgvu7Mu3dBvBPd1dcbNIb+qiR0817zDpgPjS7gRb+l/8EVNIa3cB02xI9JLToKg== integrity sha512-MnG7N936zcKTco4Jd2PX2U96Kf9PxygAPKBug+74LHzmHXmceN16MmRcdgZv+DGef/S9YvQAfRsNCn4cjf9yyQ==
grpc-tools@^1.13.0:
version "1.13.0"
resolved "https://registry.yarnpkg.com/grpc-tools/-/grpc-tools-1.13.0.tgz#a4fea8eebce51fb9fec00055a3e52016dfd5af89"
integrity sha512-7CbkJ1yWPfX0nHjbYG58BQThNhbICXBZynzCUxCb3LzX5X9B3hQbRY2STiRgIEiLILlK9fgl0z0QVGwPCdXf5g==
dependencies: dependencies:
"@mapbox/node-pre-gyp" "^1.0.5" "@mapbox/node-pre-gyp" "^1.0.5"
@ -523,10 +528,10 @@ ts-protoc-gen@^0.15.0:
dependencies: dependencies:
google-protobuf "^3.15.5" google-protobuf "^3.15.5"
typescript@^5.1.6: typescript@^5.8.3:
version "5.1.6" version "5.8.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e"
integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA== integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==
util-deprecate@^1.0.1: util-deprecate@^1.0.1:
version "1.0.2" version "1.0.2"

View File

@ -9,7 +9,7 @@ plugins {
} }
group = "io.chirpstack" group = "io.chirpstack"
version = "4.12.0-test.4" version = "4.12.0"
repositories { repositories {
mavenCentral() mavenCentral()

View File

@ -3,7 +3,7 @@
"description": "Chirpstack PHP API", "description": "Chirpstack PHP API",
"license": "MIT", "license": "MIT",
"type": "library", "type": "library",
"version": "4.12.0-test.4", "version": "4.12.0",
"require": { "require": {
"php": ">=7.0.0", "php": ">=7.0.0",
"grpc/grpc": "^v1.57.0", "grpc/grpc": "^v1.57.0",

95
api/proto/gw/gw.proto vendored
View File

@ -104,6 +104,61 @@ enum TxAckStatus {
DUTY_CYCLE_OVERFLOW = 11; DUTY_CYCLE_OVERFLOW = 11;
} }
// Gateway events as reported by the ChirpStack Concentratord ZMQ interface.
message Event {
oneof event {
// Uplink frame.
UplinkFrame uplink_frame = 1;
// Gateway stats.
GatewayStats gateway_stats = 2;
// Gateway Mesh Event.
Mesh mesh = 3;
}
}
// Commands that can be sent to the ChirpStack Concentratord ZMQ interface.
message Command {
oneof command {
// Downlink frame.
DownlinkFrame send_downlink_frame = 1;
// Gateway configuration.
GatewayConfiguration set_gateway_configuration = 2;
// Get Gateway ID.
GetGatewayIdRequest get_gateway_id = 3;
// Get location.
GetLocationRequest get_location = 4;
}
}
message Mesh {
// Gateway ID (of the Border Gateway).
string gateway_id = 1;
// Relay ID.
string relay_id = 2;
// Timestamp (second precision).
google.protobuf.Timestamp time = 3;
// Mesh events.
repeated MeshEvent events = 4;
}
message MeshEvent {
oneof event {
// Proprietary Mesh event.
MeshEventProprietary proprietary = 1;
// Mesh heartbeat.
MeshEventHeartbeat heartbeat = 2;
}
}
message Modulation { message Modulation {
oneof parameters { oneof parameters {
// LoRa modulation information. // LoRa modulation information.
@ -611,6 +666,23 @@ message GatewayConfiguration {
google.protobuf.Duration stats_interval = 4; google.protobuf.Duration stats_interval = 4;
} }
message GetGatewayIdRequest {}
message GetGatewayIdResponse {
// Gateway ID.
string gateway_id = 1;
}
message GetLocationRequest {}
message GetLocationResponse {
// Location.
common.Location location = 1;
// Last updated at.
google.protobuf.Timestamp updated_at = 2;
}
message ChannelConfiguration { message ChannelConfiguration {
// Frequency (Hz). // Frequency (Hz).
uint32 frequency = 1; uint32 frequency = 1;
@ -751,21 +823,13 @@ message ConnState {
} }
// Gateway Mesh heartbeat (sent periodically by the Relay Gateways). // Gateway Mesh heartbeat (sent periodically by the Relay Gateways).
message MeshHeartbeat { message MeshEventHeartbeat {
// Gateway ID (of the Border Gateway).
string gateway_id = 1;
// Relay ID.
string relay_id = 2;
// Timestamp (second precision).
google.protobuf.Timestamp time = 3;
// Relay path. // Relay path.
repeated MeshHeartbeatRelayPath relay_path = 4; repeated MeshEventHeartbeatRelayPath relay_path = 4;
} }
message MeshHeartbeatRelayPath { message MeshEventHeartbeatRelayPath {
// Relay ID. // Relay ID.
string relay_id = 1; string relay_id = 1;
@ -775,3 +839,12 @@ message MeshHeartbeatRelayPath {
// SNR. // SNR.
int32 snr = 3; int32 snr = 3;
} }
// Proprietary mesh event.
message MeshEventProprietary {
// Event type.
uint32 event_type = 1;
// Payload.
bytes payload = 2;
}

View File

@ -18,7 +18,7 @@ CLASSIFIERS = [
setup( setup(
name='chirpstack-api', name='chirpstack-api',
version = "4.12.0-test.4", version = "4.12.0",
url='https://github.com/brocaar/chirpstack-api', url='https://github.com/brocaar/chirpstack-api',
author='Orne Brocaar', author='Orne Brocaar',
author_email='info@brocaar.com', author_email='info@brocaar.com',

2
api/rust/Cargo.toml vendored
View File

@ -1,7 +1,7 @@
[package] [package]
name = "chirpstack_api" name = "chirpstack_api"
description = "ChirpStack Protobuf / gRPC API definitions." description = "ChirpStack Protobuf / gRPC API definitions."
version = "4.12.0-test.4" version = "4.12.0"
authors = ["Orne Brocaar <info@brocaar.com>"] authors = ["Orne Brocaar <info@brocaar.com>"]
license = "MIT" license = "MIT"
homepage = "https://www.chirpstack.io" homepage = "https://www.chirpstack.io"

View File

@ -104,6 +104,61 @@ enum TxAckStatus {
DUTY_CYCLE_OVERFLOW = 11; DUTY_CYCLE_OVERFLOW = 11;
} }
// Gateway events as reported by the ChirpStack Concentratord ZMQ interface.
message Event {
oneof event {
// Uplink frame.
UplinkFrame uplink_frame = 1;
// Gateway stats.
GatewayStats gateway_stats = 2;
// Gateway Mesh Event.
Mesh mesh = 3;
}
}
// Commands that can be sent to the ChirpStack Concentratord ZMQ interface.
message Command {
oneof command {
// Downlink frame.
DownlinkFrame send_downlink_frame = 1;
// Gateway configuration.
GatewayConfiguration set_gateway_configuration = 2;
// Get Gateway ID.
GetGatewayIdRequest get_gateway_id = 3;
// Get location.
GetLocationRequest get_location = 4;
}
}
message Mesh {
// Gateway ID (of the Border Gateway).
string gateway_id = 1;
// Relay ID.
string relay_id = 2;
// Timestamp (second precision).
google.protobuf.Timestamp time = 3;
// Mesh events.
repeated MeshEvent events = 4;
}
message MeshEvent {
oneof event {
// Proprietary Mesh event.
MeshEventProprietary proprietary = 1;
// Mesh heartbeat.
MeshEventHeartbeat heartbeat = 2;
}
}
message Modulation { message Modulation {
oneof parameters { oneof parameters {
// LoRa modulation information. // LoRa modulation information.
@ -611,6 +666,23 @@ message GatewayConfiguration {
google.protobuf.Duration stats_interval = 4; google.protobuf.Duration stats_interval = 4;
} }
message GetGatewayIdRequest {}
message GetGatewayIdResponse {
// Gateway ID.
string gateway_id = 1;
}
message GetLocationRequest {}
message GetLocationResponse {
// Location.
common.Location location = 1;
// Last updated at.
google.protobuf.Timestamp updated_at = 2;
}
message ChannelConfiguration { message ChannelConfiguration {
// Frequency (Hz). // Frequency (Hz).
uint32 frequency = 1; uint32 frequency = 1;
@ -751,21 +823,13 @@ message ConnState {
} }
// Gateway Mesh heartbeat (sent periodically by the Relay Gateways). // Gateway Mesh heartbeat (sent periodically by the Relay Gateways).
message MeshHeartbeat { message MeshEventHeartbeat {
// Gateway ID (of the Border Gateway).
string gateway_id = 1;
// Relay ID.
string relay_id = 2;
// Timestamp (second precision).
google.protobuf.Timestamp time = 3;
// Relay path. // Relay path.
repeated MeshHeartbeatRelayPath relay_path = 4; repeated MeshEventHeartbeatRelayPath relay_path = 4;
} }
message MeshHeartbeatRelayPath { message MeshEventHeartbeatRelayPath {
// Relay ID. // Relay ID.
string relay_id = 1; string relay_id = 1;
@ -775,3 +839,12 @@ message MeshHeartbeatRelayPath {
// SNR. // SNR.
int32 snr = 3; int32 snr = 3;
} }
// Proprietary mesh event.
message MeshEventProprietary {
// Event type.
uint32 event_type = 1;
// Payload.
bytes payload = 2;
}

9
api/rust/src/lib.rs vendored
View File

@ -1,14 +1,17 @@
pub use prost;
pub use prost_types;
#[cfg(feature = "json")] #[cfg(feature = "json")]
pub use pbjson_types; pub use pbjson_types;
pub use prost;
#[cfg(feature = "api")] #[cfg(feature = "api")]
pub use tonic; pub use tonic;
#[cfg(feature = "api")] #[cfg(feature = "api")]
pub mod api; pub mod api;
#[cfg(feature = "internal")]
pub mod internal;
pub mod common; pub mod common;
pub mod gw; pub mod gw;
pub mod integration; pub mod integration;
#[cfg(feature = "internal")]
pub mod internal;
pub mod stream; pub mod stream;

View File

@ -1,6 +1,6 @@
[package] [package]
name = "backend" name = "backend"
version = "4.12.0-test.4" version = "4.12.0"
authors = ["Orne Brocaar <info@brocaar.com>"] authors = ["Orne Brocaar <info@brocaar.com>"]
edition = "2018" edition = "2018"
publish = false publish = false

View File

@ -3,13 +3,13 @@
description = "Library for building external ChirpStack integrations" description = "Library for building external ChirpStack integrations"
homepage = "https://www.chirpstack.io/" homepage = "https://www.chirpstack.io/"
license = "MIT" license = "MIT"
version = "4.12.0-test.4" version = "4.12.0"
authors = ["Orne Brocaar <info@brocaar.com>"] authors = ["Orne Brocaar <info@brocaar.com>"]
edition = "2021" edition = "2021"
repository = "https://github.com/chirpstack/chirpstack" repository = "https://github.com/chirpstack/chirpstack"
[dependencies] [dependencies]
chirpstack_api = { path = "../api/rust", version = "4.12.0-test.4" } chirpstack_api = { path = "../api/rust", version = "4.12.0" }
redis = { version = "0.29", features = [ redis = { version = "0.29", features = [
"cluster-async", "cluster-async",
"tokio-rustls-comp", "tokio-rustls-comp",

View File

@ -3,7 +3,7 @@
description = "ChirpStack is an open-source LoRaWAN(TM) Network Server" description = "ChirpStack is an open-source LoRaWAN(TM) Network Server"
repository = "https://github.com/chirpstack/chirpstack" repository = "https://github.com/chirpstack/chirpstack"
homepage = "https://www.chirpstack.io/" homepage = "https://www.chirpstack.io/"
version = "4.12.0-test.4" version = "4.12.0"
authors = ["Orne Brocaar <info@brocaar.com>"] authors = ["Orne Brocaar <info@brocaar.com>"]
edition = "2021" edition = "2021"
publish = false publish = false

View File

@ -1,5 +1,4 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::io::Cursor;
use std::sync::{LazyLock, RwLock}; use std::sync::{LazyLock, RwLock};
use std::time::Duration; use std::time::Duration;
@ -352,7 +351,7 @@ async fn message_callback(
.inc(); .inc();
let mut event = match json { let mut event = match json {
true => serde_json::from_slice(&p.payload)?, true => serde_json::from_slice(&p.payload)?,
false => chirpstack_api::gw::UplinkFrame::decode(&mut Cursor::new(&p.payload))?, false => chirpstack_api::gw::UplinkFrame::decode(p.payload.as_ref())?,
}; };
if v4_migrate { if v4_migrate {
@ -377,7 +376,7 @@ async fn message_callback(
.inc(); .inc();
let mut event = match json { let mut event = match json {
true => serde_json::from_slice(&p.payload)?, true => serde_json::from_slice(&p.payload)?,
false => chirpstack_api::gw::GatewayStats::decode(&mut Cursor::new(&p.payload))?, false => chirpstack_api::gw::GatewayStats::decode(p.payload.as_ref())?,
}; };
if v4_migrate { if v4_migrate {
@ -401,7 +400,7 @@ async fn message_callback(
.inc(); .inc();
let mut event = match json { let mut event = match json {
true => serde_json::from_slice(&p.payload)?, true => serde_json::from_slice(&p.payload)?,
false => chirpstack_api::gw::DownlinkTxAck::decode(&mut Cursor::new(&p.payload))?, false => chirpstack_api::gw::DownlinkTxAck::decode(p.payload.as_ref())?,
}; };
if v4_migrate { if v4_migrate {
@ -410,18 +409,18 @@ async fn message_callback(
set_gateway_json(&event.gateway_id, json); set_gateway_json(&event.gateway_id, json);
tokio::spawn(downlink::tx_ack::TxAck::handle(event)); tokio::spawn(downlink::tx_ack::TxAck::handle(event));
} else if topic.ends_with("/mesh-heartbeat") { } else if topic.ends_with("/mesh") {
EVENT_COUNTER EVENT_COUNTER
.get_or_create(&EventLabels { .get_or_create(&EventLabels {
event: "mesh-heartbeat".to_string(), event: "mesh".to_string(),
}) })
.inc(); .inc();
let event = match json { let event = match json {
true => serde_json::from_slice(&p.payload)?, true => serde_json::from_slice(&p.payload)?,
false => chirpstack_api::gw::MeshHeartbeat::decode(&mut Cursor::new(&p.payload))?, false => chirpstack_api::gw::Mesh::decode(p.payload.as_ref())?,
}; };
tokio::spawn(uplink::mesh::MeshHeartbeat::handle(event)); tokio::spawn(uplink::mesh::Mesh::handle(event));
} else { } else {
return Err(anyhow!("Unknown event type")); return Err(anyhow!("Unknown event type"));
} }

View File

@ -14,14 +14,15 @@ use crate::storage::{
}; };
use lrwn::EUI64; use lrwn::EUI64;
pub struct MeshHeartbeat { pub struct Mesh {
gateway_id: EUI64, gateway_id: EUI64,
relay_id: RelayId, relay_id: RelayId,
mesh_stats: gw::MeshHeartbeat, time: DateTime<Utc>,
mesh_event: gw::Mesh,
} }
impl MeshHeartbeat { impl Mesh {
pub async fn handle(s: gw::MeshHeartbeat) { pub async fn handle(s: gw::Mesh) {
let gateway_id = match EUI64::from_str(&s.gateway_id) { let gateway_id = match EUI64::from_str(&s.gateway_id) {
Ok(v) => v, Ok(v) => v,
Err(e) => { Err(e) => {
@ -38,9 +39,9 @@ impl MeshHeartbeat {
} }
}; };
let span = span!(Level::INFO, "mesh_stats", gateway_id = %gateway_id, relay_id = %relay_id); let span = span!(Level::INFO, "mesh", gateway_id = %gateway_id, relay_id = %relay_id);
if let Err(e) = MeshHeartbeat::_handle(gateway_id, relay_id, s) if let Err(e) = Mesh::_handle(gateway_id, relay_id, s)
.instrument(span) .instrument(span)
.await .await
{ {
@ -48,52 +49,61 @@ impl MeshHeartbeat {
Some(Error::NotFound(_)) => { Some(Error::NotFound(_)) => {
let conf = config::get(); let conf = config::get();
if !conf.gateway.allow_unknown_gateways { if !conf.gateway.allow_unknown_gateways {
error!(error = %e.full(), "Handle mesh-stats error"); error!(error = %e.full(), "Handle mesh error");
} }
} }
Some(_) | None => { Some(_) | None => {
error!(error = %e.full(), "Handle mesh-stats error"); error!(error = %e.full(), "Handle mesh error");
} }
} }
} }
} }
async fn _handle(gateway_id: EUI64, relay_id: RelayId, s: gw::MeshHeartbeat) -> Result<()> { async fn _handle(gateway_id: EUI64, relay_id: RelayId, s: gw::Mesh) -> Result<()> {
let mut ctx = MeshHeartbeat { let ctx = Mesh {
gateway_id, gateway_id,
relay_id, relay_id,
mesh_stats: s, time: s
.time
.ok_or_else(|| anyhow!("Time field is empty"))?
.try_into()
.map_err(|e| anyhow!("Covert time error: {}", e))?,
mesh_event: s,
}; };
ctx.update_or_create_relay_gateway().await?; ctx.handle_events().await?;
Ok(()) Ok(())
} }
async fn update_or_create_relay_gateway(&mut self) -> Result<()> { async fn handle_events(&self) -> Result<()> {
trace!("Getting Border Gateway"); trace!("Handling mesh events");
let border_gw = gateway::get(&self.gateway_id).await?;
let ts: DateTime<Utc> = match &self.mesh_stats.time { for event in &self.mesh_event.events {
Some(v) => (*v) match &event.event {
.try_into() Some(gw::mesh_event::Event::Proprietary(_)) | None => continue,
.map_err(|e| anyhow!("Convert time error: {}", e))?, Some(gw::mesh_event::Event::Heartbeat(v)) => self._handle_heartbeat(v).await?,
None => {
warn!("Stats message does not have time field set");
return Ok(());
} }
}; }
Ok(())
}
async fn _handle_heartbeat(&self, _pl: &gw::MeshEventHeartbeat) -> Result<()> {
trace!("Handling heartbeat event");
let border_gw = gateway::get(&self.gateway_id).await?;
match gateway::get_relay_gateway(border_gw.tenant_id.into(), self.relay_id).await { match gateway::get_relay_gateway(border_gw.tenant_id.into(), self.relay_id).await {
Ok(mut v) => { Ok(mut v) => {
if let Some(last_seen_at) = v.last_seen_at { if let Some(last_seen_at) = v.last_seen_at {
if last_seen_at > ts { if last_seen_at > self.time {
warn!("Time is less than last seen timestamp, ignoring stats"); warn!("Time is less than last seen timestamp, ignoring heartbeat");
return Ok(()); return Ok(());
} }
} }
v.last_seen_at = Some(ts); v.last_seen_at = Some(self.time);
v.region_config_id = border_gw v.region_config_id = border_gw
.properties .properties
.get("region_config_id") .get("region_config_id")
@ -106,7 +116,7 @@ impl MeshHeartbeat {
tenant_id: border_gw.tenant_id, tenant_id: border_gw.tenant_id,
relay_id: self.relay_id, relay_id: self.relay_id,
name: self.relay_id.to_string(), name: self.relay_id.to_string(),
last_seen_at: Some(ts), last_seen_at: Some(self.time),
..Default::default() ..Default::default()
}) })
.await?; .await?;

View File

@ -3,7 +3,7 @@
description = "Library for filtering LoRaWAN payloads on DevAddr and JoinEUIs prefixes" description = "Library for filtering LoRaWAN payloads on DevAddr and JoinEUIs prefixes"
homepage = "https://www.chirpstack.io/" homepage = "https://www.chirpstack.io/"
license = "MIT" license = "MIT"
version = "4.12.0-test.4" version = "4.12.0"
authors = ["Orne Brocaar <info@brocaar.com>"] authors = ["Orne Brocaar <info@brocaar.com>"]
edition = "2021" edition = "2021"
repository = "https://github.com/chirpstack/chirpstack" repository = "https://github.com/chirpstack/chirpstack"

View File

@ -3,7 +3,7 @@
description = "Library for encoding / decoding LoRaWAN frames." description = "Library for encoding / decoding LoRaWAN frames."
homepage = "https://www.chirpstack.io" homepage = "https://www.chirpstack.io"
license = "MIT" license = "MIT"
version = "4.12.0-test.4" version = "4.12.0"
authors = ["Orne Brocaar <info@brocaar.com>"] authors = ["Orne Brocaar <info@brocaar.com>"]
edition = "2018" edition = "2018"
repository = "https://github.com/chirpstack/chirpstack" repository = "https://github.com/chirpstack/chirpstack"

View File

@ -1,6 +1,6 @@
{ {
"name": "chirpstack-ui", "name": "chirpstack-ui",
"version": "4.12.0-test.4", "version": "4.12.0",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
@ -18,12 +18,12 @@
"@fortawesome/fontawesome-svg-core": "^6.7.2", "@fortawesome/fontawesome-svg-core": "^6.7.2",
"@fortawesome/free-solid-svg-icons": "^6.7.2", "@fortawesome/free-solid-svg-icons": "^6.7.2",
"@fortawesome/react-fontawesome": "^0.2.2", "@fortawesome/react-fontawesome": "^0.2.2",
"ace-builds": "^1.36.4",
"antd": "^5.23.3", "antd": "^5.23.3",
"buffer": "^6.0.3", "buffer": "^6.0.3",
"chart.js": "^4.4.7", "chart.js": "^4.4.7",
"chartjs-adapter-date-fns": "^3.0.0", "chartjs-adapter-date-fns": "^3.0.0",
"chartjs-chart-matrix": "^2.0.1", "chartjs-chart-matrix": "^2.0.1",
"codemirror": "^5.65.16",
"date-fns": "^3.6.0", "date-fns": "^3.6.0",
"events": "^3.3.0", "events": "^3.3.0",
"google-palette": "^1.1.1", "google-palette": "^1.1.1",
@ -32,8 +32,8 @@
"leaflet": "^1.9.4", "leaflet": "^1.9.4",
"leaflet.awesome-markers": "^2.0.5", "leaflet.awesome-markers": "^2.0.5",
"react": "^18.3.1", "react": "^18.3.1",
"react-ace": "^13.0.0",
"react-chartjs-2": "^5.2.0", "react-chartjs-2": "^5.2.0",
"react-codemirror2": "^8.0.0",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-json-tree": "^0.19.0", "react-json-tree": "^0.19.0",
"react-leaflet": "^4.2.1", "react-leaflet": "^4.2.1",
@ -43,7 +43,6 @@
}, },
"devDependencies": { "devDependencies": {
"@testing-library/jest-dom": "^6.4.6", "@testing-library/jest-dom": "^6.4.6",
"@types/codemirror": "^5.60.15",
"@types/events": "^3.0.3", "@types/events": "^3.0.3",
"@types/leaflet": "^1.9.12", "@types/leaflet": "^1.9.12",
"@types/leaflet.awesome-markers": "^2.0.28", "@types/leaflet.awesome-markers": "^2.0.28",
@ -56,7 +55,7 @@
"eslint-plugin-react-hooks": "^4.6.2", "eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-react-refresh": "^0.4.7", "eslint-plugin-react-refresh": "^0.4.7",
"prettier": "^3.3.2", "prettier": "^3.3.2",
"typescript": "^5.2.2", "typescript": "^5.8.3",
"vite": "^6.2.6" "vite": "^6.2.6"
} }
} }

View File

@ -1,10 +1,11 @@
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { Controlled as CodeMirror } from "react-codemirror2";
import type { Editor, EditorChange } from "codemirror";
import { Form } from "antd"; import { Form } from "antd";
import AceEditor from "react-ace";
import "codemirror/mode/javascript/javascript"; import "ace-builds/src-noconflict/mode-javascript";
import "ace-builds/src-noconflict/mode-json";
import "ace-builds/src-noconflict/theme-github";
interface IProps { interface IProps {
label?: string; label?: string;
@ -12,6 +13,7 @@ interface IProps {
required?: boolean; required?: boolean;
disabled?: boolean; disabled?: boolean;
tooltip?: string; tooltip?: string;
mode?: string;
} }
function CodeEditor(props: IProps) { function CodeEditor(props: IProps) {
@ -24,28 +26,25 @@ function CodeEditor(props: IProps) {
setReloadKey(k => k + 1); setReloadKey(k => k + 1);
}, [form, props]); }, [form, props]);
const handleChange = (editor: Editor, data: EditorChange, newCode: string) => { const onChange = (newValue: string) => {
setValue(newCode); setValue(newValue);
form.setFieldsValue({ form.setFieldsValue({
[props.name]: newCode, [props.name]: newValue,
}); });
}; };
const codeMirrorOptions = {
lineNumbers: true,
mode: "javascript",
theme: "base16-light",
readOnly: props.disabled,
};
return ( return (
<Form.Item label={props.label} name={props.name} tooltip={props.tooltip}> <Form.Item label={props.label} name={props.name} tooltip={props.tooltip}>
<div style={{ border: "1px solid #cccccc" }}> <div style={{ border: "1px solid #cccccc" }}>
<CodeMirror <AceEditor
key={`code-editor-refresh-${reloadKey}`} mode={props.mode || "javascript"}
theme="github"
onChange={onChange}
value={value} value={value}
options={codeMirrorOptions} name={`code-editor-refresh-${reloadKey}`}
onBeforeChange={handleChange} width="100%"
height="600px"
editorProps={{ $blockScrolling: true }}
/> />
</div> </div>
</Form.Item> </Form.Item>

View File

@ -12,8 +12,6 @@ import "antd/dist/reset.css";
import "leaflet/dist/leaflet.css"; import "leaflet/dist/leaflet.css";
import "leaflet.awesome-markers/dist/leaflet.awesome-markers.css"; import "leaflet.awesome-markers/dist/leaflet.awesome-markers.css";
import "@fortawesome/fontawesome-free/css/all.css"; import "@fortawesome/fontawesome-free/css/all.css";
import "codemirror/lib/codemirror.css";
import "codemirror/theme/base16-light.css";
import "./index.css"; import "./index.css";
Chart.register(MatrixController, MatrixElement, ...registerables); Chart.register(MatrixController, MatrixElement, ...registerables);

View File

@ -268,7 +268,7 @@ function DeviceQueue(props: IProps) {
</Form.Item> </Form.Item>
</Tabs.TabPane> </Tabs.TabPane>
<Tabs.TabPane tab="JSON" key="3"> <Tabs.TabPane tab="JSON" key="3">
<CodeEditor name="json" /> <CodeEditor name="json" mode="json" />
</Tabs.TabPane> </Tabs.TabPane>
</Tabs> </Tabs>
<Button type="primary" htmlType="submit"> <Button type="primary" htmlType="submit">

View File

@ -168,7 +168,9 @@ function FuotaDeploymentLayout(props: IProps) {
description="Are you sure you want to start the deploymen? Once started, you will not be able to make changes." description="Are you sure you want to start the deploymen? Once started, you will not be able to make changes."
onConfirm={startFuotaDeployment} onConfirm={startFuotaDeployment}
> >
<Button type="primary" disabled={getFuotaDeploymentResponse.getStartedAt() !== undefined}>Start deployment</Button> <Button type="primary" disabled={getFuotaDeploymentResponse.getStartedAt() !== undefined}>
Start deployment
</Button>
</Popconfirm> </Popconfirm>
<DeleteConfirm typ="FUOTA deployment" confirm={d.getName()} onConfirm={deleteFuotaDeployment}> <DeleteConfirm typ="FUOTA deployment" confirm={d.getName()} onConfirm={deleteFuotaDeployment}>
<Button danger type="primary"> <Button danger type="primary">

View File

@ -8,6 +8,7 @@ import { DeleteTenantRequest } from "@chirpstack/chirpstack-api-grpc-web/api/ten
import TenantStore from "../../stores/TenantStore"; import TenantStore from "../../stores/TenantStore";
import DeleteConfirm from "../../components/DeleteConfirm"; import DeleteConfirm from "../../components/DeleteConfirm";
import SessionStore from "../../stores/SessionStore";
import Admin from "../../components/Admin"; import Admin from "../../components/Admin";
import EditTenant from "./EditTenant"; import EditTenant from "./EditTenant";
import TenantDashboard from "./TenantDashboard"; import TenantDashboard from "./TenantDashboard";
@ -23,6 +24,7 @@ function TenantLayout({ tenant }: { tenant: Tenant }) {
req.setId(tenant.getId()); req.setId(tenant.getId());
TenantStore.delete(req, () => { TenantStore.delete(req, () => {
SessionStore.setTenantId("");
navigate("/tenants"); navigate("/tenants");
}); });
}; };

View File

@ -127,10 +127,10 @@
regenerator-runtime "^0.14.0" regenerator-runtime "^0.14.0"
"@chirpstack/chirpstack-api-grpc-web@file:../api/grpc-web": "@chirpstack/chirpstack-api-grpc-web@file:../api/grpc-web":
version "4.12.0-test.3" version "4.12.0"
dependencies: dependencies:
"@types/google-protobuf" "^3.15.12" "@types/google-protobuf" "^3.15.12"
google-protobuf "^3.21.2" google-protobuf "^3.21.4"
grpc-web "^1.5.0" grpc-web "^1.5.0"
"@ctrl/tinycolor@^3.4.0": "@ctrl/tinycolor@^3.4.0":
@ -667,13 +667,6 @@
lodash "^4.17.21" lodash "^4.17.21"
redent "^3.0.0" redent "^3.0.0"
"@types/codemirror@^5.60.15":
version "5.60.15"
resolved "https://registry.yarnpkg.com/@types/codemirror/-/codemirror-5.60.15.tgz#0f82be6f4126d1e59cf4c4830e56dcd49d3c3e8a"
integrity sha512-dTOvwEQ+ouKJ/rE9LT1Ue2hmP6H1mZv5+CCnNWu2qtiOe2LQa9lCprEY20HxiDmV/Bxh+dXjywmy5aKvoGjULA==
dependencies:
"@types/tern" "*"
"@types/debug@^4.0.0": "@types/debug@^4.0.0":
version "4.1.12" version "4.1.12"
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917" resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917"
@ -764,13 +757,6 @@
"@types/prop-types" "*" "@types/prop-types" "*"
csstype "^3.0.2" csstype "^3.0.2"
"@types/tern@*":
version "0.23.9"
resolved "https://registry.yarnpkg.com/@types/tern/-/tern-0.23.9.tgz#6f6093a4a9af3e6bb8dde528e024924d196b367c"
integrity sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==
dependencies:
"@types/estree" "*"
"@types/unist@*", "@types/unist@^3.0.0": "@types/unist@*", "@types/unist@^3.0.0":
version "3.0.3" version "3.0.3"
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.3.tgz#acaab0f919ce69cce629c2d4ed2eb4adc1b6c20c" resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.3.tgz#acaab0f919ce69cce629c2d4ed2eb4adc1b6c20c"
@ -884,6 +870,11 @@
dependencies: dependencies:
"@swc/core" "^1.11.21" "@swc/core" "^1.11.21"
ace-builds@^1.36.3, ace-builds@^1.36.4:
version "1.40.1"
resolved "https://registry.yarnpkg.com/ace-builds/-/ace-builds-1.40.1.tgz#68421283088f0e075f3375cb3d46bb86ad6ddc6e"
integrity sha512-32uwJNwmhqpnYtr6oq8RoO1D6F6tnxisv5f9w2XPX3vi4QruuHNikadHUiHvnxLAV1n5Azv4LFtpItQ5dD1eRw==
acorn-jsx@^5.3.2: acorn-jsx@^5.3.2:
version "5.3.2" version "5.3.2"
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
@ -1099,11 +1090,6 @@ classnames@2.x, classnames@^2.2.1, classnames@^2.2.3, classnames@^2.2.5, classna
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b"
integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==
codemirror@^5.65.16:
version "5.65.19"
resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.65.19.tgz#71016c701d6a4b6e1982b0f6e7186be65e49653d"
integrity sha512-+aFkvqhaAVr1gferNMuN8vkTSrWIFvzlMV9I2KBLCWS2WpZ2+UAkZjlMZmEuT+gcXTi6RrGQCkWq1/bDtGqhIA==
color-convert@^2.0.1: color-convert@^2.0.1:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
@ -1214,6 +1200,11 @@ devlop@^1.0.0, devlop@^1.1.0:
dependencies: dependencies:
dequal "^2.0.0" dequal "^2.0.0"
diff-match-patch@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.5.tgz#abb584d5f10cd1196dfc55aa03701592ae3f7b37"
integrity sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==
dir-glob@^3.0.1: dir-glob@^3.0.1:
version "3.0.1" version "3.0.1"
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
@ -1513,7 +1504,7 @@ google-palette@^1.1.1:
resolved "https://registry.yarnpkg.com/google-palette/-/google-palette-1.1.1.tgz#671b3b932c8393271b67da908ccd7f2c48e84cc7" resolved "https://registry.yarnpkg.com/google-palette/-/google-palette-1.1.1.tgz#671b3b932c8393271b67da908ccd7f2c48e84cc7"
integrity sha512-yZiM5oLl8lCZzf06IMOGdDkxqvCMd9HNFcCiOMqWgGGiGzC22vWBVhKJNvykXXbeC0NAElNH97jA/y0bq6TCrA== integrity sha512-yZiM5oLl8lCZzf06IMOGdDkxqvCMd9HNFcCiOMqWgGGiGzC22vWBVhKJNvykXXbeC0NAElNH97jA/y0bq6TCrA==
google-protobuf@^3.21.2: google-protobuf@^3.21.4:
version "3.21.4" version "3.21.4"
resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.21.4.tgz#2f933e8b6e5e9f8edde66b7be0024b68f77da6c9" resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.21.4.tgz#2f933e8b6e5e9f8edde66b7be0024b68f77da6c9"
integrity sha512-MnG7N936zcKTco4Jd2PX2U96Kf9PxygAPKBug+74LHzmHXmceN16MmRcdgZv+DGef/S9YvQAfRsNCn4cjf9yyQ== integrity sha512-MnG7N936zcKTco4Jd2PX2U96Kf9PxygAPKBug+74LHzmHXmceN16MmRcdgZv+DGef/S9YvQAfRsNCn4cjf9yyQ==
@ -1755,6 +1746,16 @@ lodash-es@^4.17.21:
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
lodash.get@^4.4.2:
version "4.4.2"
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==
lodash.isequal@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==
lodash.merge@^4.6.2: lodash.merge@^4.6.2:
version "4.6.2" version "4.6.2"
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
@ -2610,6 +2611,17 @@ rc-virtual-list@^3.14.2, rc-virtual-list@^3.5.1, rc-virtual-list@^3.5.2:
rc-resize-observer "^1.0.0" rc-resize-observer "^1.0.0"
rc-util "^5.36.0" rc-util "^5.36.0"
react-ace@^13.0.0:
version "13.0.0"
resolved "https://registry.yarnpkg.com/react-ace/-/react-ace-13.0.0.tgz#e69c2aa4ccf1a81c758adba9ba2b4b3e3d929a69"
integrity sha512-PPk2O/ArHzDtbnK82QImfHYXwuiitRgHJf5AxwMQh9zciojbWsPmKJm1tMgWOYLCtGEz8/Dh3MxRxrXe7QcstQ==
dependencies:
ace-builds "^1.36.3"
diff-match-patch "^1.0.5"
lodash.get "^4.4.2"
lodash.isequal "^4.5.0"
prop-types "^15.8.1"
react-base16-styling@^0.10.0: react-base16-styling@^0.10.0:
version "0.10.0" version "0.10.0"
resolved "https://registry.yarnpkg.com/react-base16-styling/-/react-base16-styling-0.10.0.tgz#5d5f019bd4dc5870c3e92fd9d5410533a0bbb0c6" resolved "https://registry.yarnpkg.com/react-base16-styling/-/react-base16-styling-0.10.0.tgz#5d5f019bd4dc5870c3e92fd9d5410533a0bbb0c6"
@ -2625,11 +2637,6 @@ react-chartjs-2@^5.2.0:
resolved "https://registry.yarnpkg.com/react-chartjs-2/-/react-chartjs-2-5.3.0.tgz#2d3286339a742bc7f77b5829c33ebab215f714cc" resolved "https://registry.yarnpkg.com/react-chartjs-2/-/react-chartjs-2-5.3.0.tgz#2d3286339a742bc7f77b5829c33ebab215f714cc"
integrity sha512-UfZZFnDsERI3c3CZGxzvNJd02SHjaSJ8kgW1djn65H1KK8rehwTjyrRKOG3VTMG8wtHZ5rgAO5oTHtHi9GCCmw== integrity sha512-UfZZFnDsERI3c3CZGxzvNJd02SHjaSJ8kgW1djn65H1KK8rehwTjyrRKOG3VTMG8wtHZ5rgAO5oTHtHi9GCCmw==
react-codemirror2@^8.0.0:
version "8.0.1"
resolved "https://registry.yarnpkg.com/react-codemirror2/-/react-codemirror2-8.0.1.tgz#a229c9dda2a6ee9ea18bdb8a4c33a1b2df823613"
integrity sha512-ZALowE5sGK1t66i0Fm1hoJLWT/iZHNjaAmcjwgYl9gyl2v1sqWwxzWHLmgq6K9KCk7p5+I+U3jMF1vsLaIkrmA==
react-dom@^18.3.1: react-dom@^18.3.1:
version "18.3.1" version "18.3.1"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4"
@ -2967,7 +2974,7 @@ type-fest@^0.20.2:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
typescript@^5.2.2: typescript@^5.8.3:
version "5.8.3" version "5.8.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e"
integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==