diff --git a/go.mod b/go.mod index 655837a..c2db032 100644 --- a/go.mod +++ b/go.mod @@ -6,23 +6,23 @@ toolchain go1.26.4 require ( github.com/99designs/gqlgen v0.17.89 - github.com/DIMO-Network/cloudevent v0.2.13 + github.com/DIMO-Network/cloudevent v1.1.0 + github.com/DIMO-Network/dauth v0.0.1 github.com/DIMO-Network/model-garage v1.0.11 - github.com/DIMO-Network/server-garage v0.1.1 - github.com/DIMO-Network/shared v1.1.7 - github.com/DIMO-Network/token-exchange-api v0.4.0 + github.com/DIMO-Network/server-garage v0.4.0 + github.com/DIMO-Network/shared v1.1.9 github.com/auth0/go-jwt-middleware/v2 v2.3.0 github.com/aws/aws-sdk-go-v2 v1.41.5 github.com/aws/aws-sdk-go-v2/credentials v1.19.14 github.com/aws/aws-sdk-go-v2/service/s3 v1.99.0 github.com/aws/smithy-go v1.24.2 github.com/duckdb/duckdb-go/v2 v2.10504.0 - github.com/ethereum/go-ethereum v1.17.1 - github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 + github.com/ethereum/go-ethereum v1.17.3 + github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 github.com/modelcontextprotocol/go-sdk v1.4.1 github.com/parquet-go/parquet-go v0.30.1 github.com/prometheus/client_golang v1.23.2 - github.com/rs/zerolog v1.34.0 + github.com/rs/zerolog v1.35.1 github.com/stretchr/testify v1.11.1 github.com/uber/h3-go/v4 v4.3.0 github.com/vektah/gqlparser/v2 v2.5.32 @@ -95,7 +95,7 @@ require ( github.com/sosodev/duration v1.4.0 // indirect github.com/spf13/cast v1.10.0 // indirect github.com/teslamotors/fleet-telemetry v0.9.0 // indirect - github.com/tidwall/gjson v1.18.0 // indirect + github.com/tidwall/gjson v1.19.0 // indirect github.com/tidwall/match v1.2.0 // indirect github.com/tidwall/pretty v1.2.1 // indirect github.com/twpayne/go-geom v1.6.1 // indirect diff --git a/go.sum b/go.sum index f8bf4d3..26c3735 100644 --- a/go.sum +++ b/go.sum @@ -4,16 +4,16 @@ github.com/99designs/gqlgen v0.17.89 h1:KzEcxPiMgQoMw3m/E85atUEHyZyt0PbAflMia5Kw github.com/99designs/gqlgen v0.17.89/go.mod h1:GFqruTVGB7ZTdrf1uzOagpXbY7DrEt1pIxnTdhIbWvQ= github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= -github.com/DIMO-Network/cloudevent v0.2.13 h1:Lyf3gq7/SR29dzDGkJvJniulKgb+nhKJcG37dYrwR0o= -github.com/DIMO-Network/cloudevent v0.2.13/go.mod h1:I/9NcpMozV5Fw194WimhbkAsJtKVZf5UKYJ9hgc8Cdg= +github.com/DIMO-Network/cloudevent v1.1.0 h1:pDJxwO3/Zom/U8BOZqKtMQ05Ye6Pgn6LAh/Dlr8VwWA= +github.com/DIMO-Network/cloudevent v1.1.0/go.mod h1:I/9NcpMozV5Fw194WimhbkAsJtKVZf5UKYJ9hgc8Cdg= +github.com/DIMO-Network/dauth v0.0.1 h1:ZDPNOfCRci1+RhpgMz/2LXUywXjYdSeXRDl+J3M+/5A= +github.com/DIMO-Network/dauth v0.0.1/go.mod h1:RWy1bbPI0KWJ/Q5eS5teKo7jP6sNPWLomK0SXKkhdoo= github.com/DIMO-Network/model-garage v1.0.11 h1:aLvIyeo58p9pVgz+d3DnU5k5Fxvxh6mq/jE2s3LxXoc= github.com/DIMO-Network/model-garage v1.0.11/go.mod h1:oi7EGKQVxFVpXRsu2H+YbizbKcx06aQg2N1Yu4GqOp8= -github.com/DIMO-Network/server-garage v0.1.1 h1:EYmyy+Fgi2BNW0Bufn04BViDtb8BCWaN7C7BbEuoI5s= -github.com/DIMO-Network/server-garage v0.1.1/go.mod h1:Z3A1KDUsXey+XhrPhmw/wyCidfrQvmEdWp7nShno7ZM= -github.com/DIMO-Network/shared v1.1.7 h1:5Ex8bZ6BpOjcLj4u7n5Kih1Ho6b9BVJsKpKn4iU2EaM= -github.com/DIMO-Network/shared v1.1.7/go.mod h1:lDHUKwwT2LW6Zvd42Nb33dXklRNTmfyOlbUNx2dQfGY= -github.com/DIMO-Network/token-exchange-api v0.4.0 h1:EayDrw9VdyAfc6rbpdnDxFhlN3lMhbonUJoouKZu35g= -github.com/DIMO-Network/token-exchange-api v0.4.0/go.mod h1:cldgAyDGLMNk3YIf2mr6vGohcO0ANlZ88fCbI+v/wEY= +github.com/DIMO-Network/server-garage v0.4.0 h1:3ukXvtldIhLldn9AtbtQBooBjT2gicvB3WphrsjNQho= +github.com/DIMO-Network/server-garage v0.4.0/go.mod h1:Z3A1KDUsXey+XhrPhmw/wyCidfrQvmEdWp7nShno7ZM= +github.com/DIMO-Network/shared v1.1.9 h1:vwTPHZ3m1PjyKQpOA/zxB/IkySqhl0SpSxILwwxDRvo= +github.com/DIMO-Network/shared v1.1.9/go.mod h1:dVum9AzLJejZyKrQqknoKkRVZV2Zm4fCOLkBjy1w/pA= github.com/DIMO-Network/yaml v0.1.0 h1:KQ3oKHUZETchR6Pxbmmol3e4ewrPv/q8cEwqxfwyZbU= github.com/DIMO-Network/yaml v0.1.0/go.mod h1:KkiehcbkVzH8Pf8f9dja8B2aW81gYYZSqfwzSj9yN68= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= @@ -74,7 +74,6 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54 h1:SG7nF6SRlWhcT7cNTs5R6Hk4V2lcmLz2NsG2VnInyNo= @@ -93,8 +92,8 @@ github.com/duckdb/duckdb-go-bindings/lib/windows-amd64 v0.10504.0 h1:8O774uudYee github.com/duckdb/duckdb-go-bindings/lib/windows-amd64 v0.10504.0/go.mod h1:K25pJL26ARblGDeuAkrdblFvUen92+CwksLtPEHRqqQ= github.com/duckdb/duckdb-go/v2 v2.10504.0 h1:bnkcNQpz3EaJmMmfOhFRFJ3ELVDHW4u3PDhZ78ZTCMY= github.com/duckdb/duckdb-go/v2 v2.10504.0/go.mod h1:DQ8TxrUb0RGyTTFTwPNlpQ9FFx+ocJjoZGDkuOktYp8= -github.com/ethereum/go-ethereum v1.17.1 h1:IjlQDjgxg2uL+GzPRkygGULPMLzcYWncEI7wbaizvho= -github.com/ethereum/go-ethereum v1.17.1/go.mod h1:7UWOVHL7K3b8RfVRea022btnzLCaanwHtBuH1jUCH/I= +github.com/ethereum/go-ethereum v1.17.3 h1:Ev/sQHH+UdKZHWjuVzhu2pxhi/sXaPZl23Q+Q5LDd4Q= +github.com/ethereum/go-ethereum v1.17.3/go.mod h1:f2EhRwqewIZkGoQekywI2Y2RZAMTSavLNkD9qItFy1A= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= @@ -107,7 +106,6 @@ github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofiber/fiber/v2 v2.52.13 h1:TOKP64iqC9b5P49VrBW5tHhUOvDyrtJ0xePEfzJbCbk= github.com/gofiber/fiber/v2 v2.52.13/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= @@ -126,8 +124,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 h1:sGm2vDRFUrQJO/Veii4h4zG2vvqG6uWNkBHSTqXOZk0= -github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2/go.mod h1:wd1YpapPLivG6nQgbf7ZkG1hhSOXDhhn4MLTknx2aAc= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3 h1:B+8ClL/kCQkRiU82d9xajRPKYMrB7E0MbtzWVi1K4ns= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3/go.mod h1:NbCUVmiS4foBGBHOYlCT25+YmGpJ32dZPi75pGEUpj4= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= @@ -148,11 +146,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.21 h1:jJKAZiQH+2mIinzCJIaIG9Be1+0NR+5sz/lYEEjdM8w= @@ -191,9 +186,8 @@ github.com/prometheus/procfs v0.20.1 h1:XwbrGOIplXW/AU3YhIhLODXMJYyC1isLFfYCsTEy github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= -github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= -github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= -github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= +github.com/rs/zerolog v1.35.1 h1:m7xQeoiLIiV0BCEY4Hs+j2NG4Gp2o2KPKmhnnLiazKI= +github.com/rs/zerolog v1.35.1/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw= github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0= github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/segmentio/encoding v0.5.4 h1:OW1VRern8Nw6ITAtwSZ7Idrl3MXCFwXHPgqESYfvNt0= @@ -212,12 +206,10 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/teslamotors/fleet-telemetry v0.9.0 h1:3qz6JAaMF15+HdUzq5eH+LPelH6qiUf+6x5pHG9uzbg= github.com/teslamotors/fleet-telemetry v0.9.0/go.mod h1:0pr+vwxzHPxJjB2LNhwCuG+FvIgpoM70GICHJB3MMlk= -github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= -github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/gjson v1.19.0 h1:xwxm7n691Uf3u5OFjzngavjGTh55KX5q/9w9xHW88JU= +github.com/tidwall/gjson v1.19.0/go.mod h1:V37/opeE/JbLUOfH0QTXiNez2l0RUjYUhpT4szFQAfc= github.com/tidwall/match v1.2.0 h1:0pt8FlkOwjN2fPt4bIl4BoNxb98gGHN2ObFEDkrfZnM= github.com/tidwall/match v1.2.0/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/twpayne/go-geom v1.6.1 h1:iLE+Opv0Ihm/ABIcvQFGIiFBXd76oBIar9drAwHFhR4= @@ -270,9 +262,7 @@ golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ= golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/telemetry v0.0.0-20260409153401-be6f6cb8b1fa h1:efT73AJZfAAUV7SOip6pWGkwJDzIGiKBZGVzHYa+ve4= diff --git a/gqlgen.yml b/gqlgen.yml index fdeca41..4faba72 100644 --- a/gqlgen.yml +++ b/gqlgen.yml @@ -38,19 +38,19 @@ models: model: github.com/99designs/gqlgen/graphql.String enum_values: VEHICLE_NON_LOCATION_DATA: - value: github.com/DIMO-Network/token-exchange-api/pkg/tokenclaims.PermissionGetNonLocationHistory + value: github.com/DIMO-Network/dauth/pkg/tokenclaims.PermissionGetNonLocationHistory VEHICLE_COMMANDS: - value: github.com/DIMO-Network/token-exchange-api/pkg/tokenclaims.PermissionExecuteCommands + value: github.com/DIMO-Network/dauth/pkg/tokenclaims.PermissionExecuteCommands VEHICLE_CURRENT_LOCATION: - value: github.com/DIMO-Network/token-exchange-api/pkg/tokenclaims.PermissionGetCurrentLocation + value: github.com/DIMO-Network/dauth/pkg/tokenclaims.PermissionGetCurrentLocation VEHICLE_ALL_TIME_LOCATION: - value: github.com/DIMO-Network/token-exchange-api/pkg/tokenclaims.PermissionGetLocationHistory + value: github.com/DIMO-Network/dauth/pkg/tokenclaims.PermissionGetLocationHistory VEHICLE_VIN_CREDENTIAL: - value: github.com/DIMO-Network/token-exchange-api/pkg/tokenclaims.PermissionGetVINCredential + value: github.com/DIMO-Network/dauth/pkg/tokenclaims.PermissionGetVINCredential VEHICLE_APPROXIMATE_LOCATION: - value: github.com/DIMO-Network/token-exchange-api/pkg/tokenclaims.PermissionGetApproximateLocation + value: github.com/DIMO-Network/dauth/pkg/tokenclaims.PermissionGetApproximateLocation VEHICLE_RAW_DATA: - value: github.com/DIMO-Network/token-exchange-api/pkg/tokenclaims.PermissionGetRawData + value: github.com/DIMO-Network/dauth/pkg/tokenclaims.PermissionGetRawData Time: model: - github.com/99designs/gqlgen/graphql.Time diff --git a/internal/auth/claim.go b/internal/auth/claim.go index 82dbee2..629a04f 100644 --- a/internal/auth/claim.go +++ b/internal/auth/claim.go @@ -4,7 +4,7 @@ package auth import ( "context" - "github.com/DIMO-Network/token-exchange-api/pkg/tokenclaims" + "github.com/DIMO-Network/dauth/pkg/tokenclaims" jwtmiddleware "github.com/auth0/go-jwt-middleware/v2" ) diff --git a/internal/auth/grpc.go b/internal/auth/grpc.go index 0564516..72be67c 100644 --- a/internal/auth/grpc.go +++ b/internal/auth/grpc.go @@ -5,7 +5,7 @@ import ( "slices" "strings" - "github.com/DIMO-Network/token-exchange-api/pkg/tokenclaims" + "github.com/DIMO-Network/dauth/pkg/tokenclaims" "github.com/auth0/go-jwt-middleware/v2/validator" "github.com/rs/zerolog" "google.golang.org/grpc" diff --git a/internal/auth/grpc_test.go b/internal/auth/grpc_test.go index 877eb08..9b062e1 100644 --- a/internal/auth/grpc_test.go +++ b/internal/auth/grpc_test.go @@ -4,7 +4,7 @@ import ( "context" "testing" - "github.com/DIMO-Network/token-exchange-api/pkg/tokenclaims" + "github.com/DIMO-Network/dauth/pkg/tokenclaims" "github.com/stretchr/testify/assert" "google.golang.org/grpc/metadata" ) diff --git a/internal/auth/jwt.go b/internal/auth/jwt.go index e95f8c7..52add35 100644 --- a/internal/auth/jwt.go +++ b/internal/auth/jwt.go @@ -14,7 +14,7 @@ import ( "github.com/rs/zerolog" ) -// newValidator builds the token-exchange JWT validator (RS256, dimo.zone +// newValidator builds the dauth JWT validator (RS256, dimo.zone // audience, *DQClaim custom claims) shared by the HTTP middleware and the gRPC // fetch interceptor so both enforce identical token semantics. func newValidator(issuer, jwksURI string) (*validator.Validator, error) { @@ -43,7 +43,7 @@ func newValidator(issuer, jwksURI string) (*validator.Validator, error) { ) } -// NewJWTMiddleware creates JWT middleware with the given token-exchange issuer and JWKS URI. +// NewJWTMiddleware creates JWT middleware with the given dauth issuer and JWKS URI. func NewJWTMiddleware(issuer, jwksURI string) (*jwtmiddleware.JWTMiddleware, error) { jwtValidator, err := newValidator(issuer, jwksURI) if err != nil { diff --git a/internal/fetch/rpc/authz_test.go b/internal/fetch/rpc/authz_test.go index f6f35eb..309ad52 100644 --- a/internal/fetch/rpc/authz_test.go +++ b/internal/fetch/rpc/authz_test.go @@ -7,7 +7,7 @@ import ( "github.com/DIMO-Network/dq/internal/auth" "github.com/DIMO-Network/dq/pkg/grpc" - "github.com/DIMO-Network/token-exchange-api/pkg/tokenclaims" + "github.com/DIMO-Network/dauth/pkg/tokenclaims" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc/codes" diff --git a/internal/graph/auth_helpers.go b/internal/graph/auth_helpers.go index a1056c1..1f8449a 100644 --- a/internal/graph/auth_helpers.go +++ b/internal/graph/auth_helpers.go @@ -8,7 +8,7 @@ import ( "github.com/DIMO-Network/cloudevent" "github.com/DIMO-Network/dq/internal/graph/model" "github.com/DIMO-Network/dq/pkg/grpc" - "github.com/DIMO-Network/token-exchange-api/pkg/tokenclaims" + "github.com/DIMO-Network/dauth/pkg/tokenclaims" ) const ( diff --git a/internal/graph/base.resolvers.go b/internal/graph/base.resolvers.go index e27e290..8530d9a 100644 --- a/internal/graph/base.resolvers.go +++ b/internal/graph/base.resolvers.go @@ -12,7 +12,6 @@ import ( "github.com/99designs/gqlgen/graphql" "github.com/DIMO-Network/dq/internal/graph/model" "github.com/DIMO-Network/dq/internal/repositories" - "github.com/DIMO-Network/token-exchange-api/pkg/tokenclaims" ) // Signals is the resolver for the signals field. @@ -33,14 +32,6 @@ func (r *queryResolver) SignalsLatest(ctx context.Context, subject string, filte return r.SignalRepo.GetSignalLatest(ctx, latestArgs) } -// permissionsFromCtx returns the caller's token permissions, or nil when unauthenticated. -func permissionsFromCtx(ctx context.Context) []string { - if tok, _ := ctx.Value(ClaimsContextKey{}).(*tokenclaims.Token); tok != nil { - return tok.Permissions - } - return nil -} - // AvailableSignals is the resolver for the availableSignals field. func (r *queryResolver) AvailableSignals(ctx context.Context, subject string, filter *model.SignalFilter) ([]string, error) { names, err := r.SignalRepo.GetAvailableSignals(ctx, subject, filter) diff --git a/internal/graph/base_resolvers_test.go b/internal/graph/base_resolvers_test.go index 3d68999..12977dc 100644 --- a/internal/graph/base_resolvers_test.go +++ b/internal/graph/base_resolvers_test.go @@ -5,7 +5,7 @@ import ( "github.com/DIMO-Network/dq/internal/graph/model" "github.com/DIMO-Network/dq/internal/repositories" - "github.com/DIMO-Network/token-exchange-api/pkg/tokenclaims" + "github.com/DIMO-Network/dauth/pkg/tokenclaims" ) func TestHasPrivilegesForSignal(t *testing.T) { diff --git a/internal/graph/generated.go b/internal/graph/generated.go index 5c6bbb1..18f66d0 100644 --- a/internal/graph/generated.go +++ b/internal/graph/generated.go @@ -14,8 +14,8 @@ import ( "github.com/99designs/gqlgen/graphql" "github.com/99designs/gqlgen/graphql/introspection" "github.com/DIMO-Network/cloudevent" + "github.com/DIMO-Network/dauth/pkg/tokenclaims" "github.com/DIMO-Network/dq/internal/graph/model" - "github.com/DIMO-Network/token-exchange-api/pkg/tokenclaims" gqlparser "github.com/vektah/gqlparser/v2" "github.com/vektah/gqlparser/v2/ast" ) diff --git a/internal/graph/mcp_tools_gen.go b/internal/graph/mcp_tools_gen.go index 392cc68..a2e6890 100644 --- a/internal/graph/mcp_tools_gen.go +++ b/internal/graph/mcp_tools_gen.go @@ -195,4 +195,4 @@ var MCPTools = []mcpserver.ToolDefinition{ }, } -var CondensedSchema = "scalar Address # A 20-byte Ethereum address, encoded as a checksummed hex string with 0x prefix.\nscalar JSON # Arbitrary JSON value; serialized as raw JSON (object/array), not an escaped string.\nscalar Map\nscalar Time # A point in time, encoded per RFC-3999.\nscalar Uint64 # A 64-bit unsigned integer.\n\n# ═══ SIGNAL FIELDS (117 total) ═══\n# All signals below exist on every signal type. Calling convention per type:\n# SignalAggregations:\n# fieldName(agg: LocationAggregation!): Location\n# fieldName(agg: FloatAggregation!, filter: SignalFloatFilter): Float\n# fieldName(agg: LocationAggregation!, filter: SignalLocationFilter): Location\n# fieldName(agg: StringAggregation!): String\n# SignalCollection:\n# fieldName(): SignalLocation\n# fieldName(): SignalFloat\n# fieldName(): SignalString\n# Float is the default type. Location: currentLocationApproximateCoordinates, currentLocationCoordinates. String: obdDTCList, obdFuelTypeName, powertrainCombustionEngineEngineOilLevel, powertrainFuelSystemSupportedFuelTypes, powertrainTransmissionRetarderTorqueMode, powertrainType.\n# | Signal | Unit | Description |\n# |--------|------|-------------|\n# Shared descriptions (blank rows below use these):\n# - Is item open or closed? True = Fully or partially open\n# - Is the belt engaged\n# - Measured Load on axle row 3\n# ── CURRENT (privilege: VEHICLE_ALL_TIME_LOCATION) ──\n# | currentLocationApproximateCoordinates | | Approximate location of the vehicle in WGS 84 coordinates (privilege: VEHICLE_APPROXIMATE_LOCATION VEHICLE_ALL_TIME_LOCATION) |\n# | currentLocationAltitude | m | Current altitude relative to WGS 84 reference ellipsoid, as measured at the position of GNSS receiver antenna |\n# | currentLocationCoordinates | | Current location of the vehicle in WGS 84 coordinates |\n# | currentLocationHeading | degrees | Current heading relative to geographic north |\n# ── OTHER (privilege: VEHICLE_NON_LOCATION_DATA) ──\n# | angularVelocityYaw | degrees/s | Vehicle rotation rate along Z (vertical) |\n# | connectivityCellularIsJammingDetected | | Indicates whether cellular radio signal jamming or interference is detected that prevents normal communication |\n# | exteriorAirTemperature | celsius | Air temperature outside the vehicle |\n# | isIgnitionOn | | Vehicle ignition status |\n# | lowVoltageBatteryCurrentVoltage | V | |\n# | speed | km/h | |\n# ── BODY (privilege: VEHICLE_NON_LOCATION_DATA) ──\n# | bodyLightsIsAirbagWarningOn | | Indicates whether the airbag/SRS warning telltale is active |\n# | bodyLockIsLocked | | Indicates whether the vehicle is locked via the central locking system |\n# | bodyTrunkFrontIsOpen | | |\n# | bodyTrunkRearIsOpen | | |\n# ── CABIN (privilege: VEHICLE_NON_LOCATION_DATA) ──\n# | cabinDoorRow1DriverSideIsOpen | | |\n# | cabinDoorRow1DriverSideWindowIsOpen | | |\n# | cabinDoorRow1PassengerSideIsOpen | | |\n# | cabinDoorRow1PassengerSideWindowIsOpen | | |\n# | cabinDoorRow2DriverSideIsOpen | | |\n# | cabinDoorRow2DriverSideWindowIsOpen | | |\n# | cabinDoorRow2PassengerSideIsOpen | | |\n# | cabinDoorRow2PassengerSideWindowIsOpen | | |\n# | cabinSeatRow1DriverSideIsBelted | | |\n# | cabinSeatRow1PassengerSideIsBelted | | |\n# | cabinSeatRow2DriverSideIsBelted | | |\n# | cabinSeatRow2MiddleIsBelted | | |\n# | cabinSeatRow2PassengerSideIsBelted | | |\n# | cabinSeatRow3DriverSideIsBelted | | |\n# | cabinSeatRow3PassengerSideIsBelted | | |\n# ── CHASSIS (privilege: VEHICLE_NON_LOCATION_DATA) ──\n# shared: Rotational speed of a vehicle's wheel\n# shared: Pneumatic pressure in the service brake circuit or reservoir\n# | chassisAxleRow1WheelLeftSpeed | km/h | |\n# | chassisAxleRow1WheelLeftTirePressure | kPa | |\n# | chassisAxleRow1WheelRightSpeed | km/h | |\n# | chassisAxleRow1WheelRightTirePressure | kPa | |\n# | chassisAxleRow2WheelLeftTirePressure | kPa | |\n# | chassisAxleRow2WheelRightTirePressure | kPa | |\n# | chassisAxleRow3Weight | kg | |\n# | chassisAxleRow4Weight | kg | |\n# | chassisAxleRow5Weight | kg | |\n# | chassisBrakeABSIsWarningOn | | Indicates whether the ABS warning telltale is active (any non-off state) |\n# | chassisBrakeCircuit1PressurePrimary | kPa | |\n# | chassisBrakeCircuit2PressurePrimary | kPa | |\n# | chassisBrakeIsPedalPressed | | Indicates whether the brake pedal is pressed |\n# | chassisBrakePedalPosition | percent | Brake pedal position as percent |\n# | chassisParkingBrakeIsEngaged | | |\n# | chassisTireSystemIsWarningOn | | Indicates whether the tire system warning telltale is active |\n# ── OBD (privilege: VEHICLE_NON_LOCATION_DATA) ──\n# shared: PID 2x (byte CD) - Voltage for wide range/band oxygen sensor\n# | obdBarometricPressure | kPa | PID 33 - Barometric pressure |\n# | obdCommandedEGR | percent | PID 2C - Commanded exhaust gas recirculation (EGR) |\n# | obdCommandedEVAP | percent | PID 2E - Commanded evaporative purge (EVAP) valve |\n# | obdDTCList | | List of currently active DTCs formatted according OBD II (SAE-J2012DA_201812) standard ([P|C|B|U]XXXXX ) |\n# | obdDistanceSinceDTCClear | km | PID 31 - Distance traveled since codes cleared |\n# | obdDistanceWithMIL | km | PID 21 - Distance traveled with MIL on |\n# | obdEngineLoad | percent | PID 04 - Engine load in percent - 0 = no load, 100 = full load |\n# | obdEthanolPercent | percent | PID 52 - Percentage of ethanol in the fuel |\n# | obdFuelPressure | kPa | PID 0A - Fuel pressure |\n# | obdFuelRailPressure | kPa | |\n# | obdFuelRate | l/h | PID 5E - Engine fuel rate |\n# | obdFuelTypeName | | Fuel type names decoded from PID 51 |\n# | obdIntakeTemp | celsius | PID 0F - Intake temperature |\n# | obdIsEngineBlocked | | Engine block status, 0 = engine unblocked, 1 = engine blocked |\n# | obdIsPTOActive | | PID 1E - Auxiliary input status (power take off) |\n# | obdIsPluggedIn | | Aftermarket device plugged in status |\n# | obdLongTermFuelTrim1 | percent | PID 07 - Long Term (learned) Fuel Trim - Bank 1 - negative percent leaner, positive percent richer |\n# | obdLongTermFuelTrim2 | percent | PID 09 - Long Term (learned) Fuel Trim - Bank 2 - negative percent leaner, positive percent richer |\n# | obdMAP | kPa | PID 0B - Intake manifold pressure |\n# | obdMaxMAF | g/s | PID 50 - Maximum flow for mass air flow sensor |\n# | obdO2WRSensor1Voltage | V | |\n# | obdO2WRSensor2Voltage | V | |\n# | obdOilTemperature | celsius | PID 5C - Engine oil temperature |\n# | obdRunTime | s | PID 1F - Engine run time |\n# | obdShortTermFuelTrim1 | percent | PID 06 - Short Term (immediate) Fuel Trim - Bank 1 - negative percent leaner, positive percent richer |\n# | obdStatusDTCCount | | Number of Diagnostic Trouble Codes (DTC) |\n# | obdThrottlePosition | percent | PID 11 - Throttle position - 0 = closed throttle, 100 = open throttle |\n# | obdWarmupsSinceDTCClear | | PID 30 - Number of warm-ups since codes cleared |\n# ── POWERTRAIN (privilege: VEHICLE_NON_LOCATION_DATA) ──\n# | powertrainCombustionEngineDieselExhaustFluidCapacity | l | Capacity in liters of the Diesel Exhaust Fluid Tank |\n# | powertrainCombustionEngineDieselExhaustFluidLevel | percent | Level of the Diesel Exhaust Fluid tank as percent of capacity |\n# | powertrainCombustionEngineECT | celsius | Engine coolant temperature |\n# | powertrainCombustionEngineEOP | kPa | Engine oil pressure |\n# | powertrainCombustionEngineEOT | celsius | Engine oil temperature |\n# | powertrainCombustionEngineEngineOilLevel | | |\n# | powertrainCombustionEngineEngineOilRelativeLevel | percent | Engine oil level as a percentage |\n# | powertrainCombustionEngineMAF | g/s | Grams of air drawn into engine per second |\n# | powertrainCombustionEngineSpeed | rpm | Engine speed measured as rotations per minute |\n# | powertrainCombustionEngineTPS | percent | Current throttle position |\n# | powertrainCombustionEngineTorque | Nm | |\n# | powertrainCombustionEngineTorquePercent | percent | Actual engine output torque as a percentage of reference engine torque (FMS / J1939 parameter SPN 513) |\n# | powertrainFuelSystemAbsoluteLevel | l | Current available fuel in the fuel tank expressed in liters |\n# | powertrainFuelSystemAccumulatedConsumption | l | Accumulated fuel consumption (totalized) reported by the vehicle (FMS SPN 250) |\n# | powertrainFuelSystemRelativeLevel | percent | Level in fuel tank as percent of capacity |\n# | powertrainFuelSystemSupportedFuelTypes | | High level information of fuel types supported |\n# | powertrainRange | km | Remaining range in kilometers using all energy sources available in the vehicle |\n# | powertrainTractionBatteryChargingAddedEnergy | kWh | Amount of charge added to the high voltage battery during the current charging session, expressed in kilowatt-hours |\n# | powertrainTractionBatteryChargingChargeCurrentAC | A | Current AC charging current (rms) at inlet |\n# | powertrainTractionBatteryChargingChargeLimit | percent | Target charge limit (state of charge) for battery |\n# | powertrainTractionBatteryChargingChargeVoltageUnknownType | V | Current charging voltage at inlet |\n# | powertrainTractionBatteryChargingIsCharging | | True if charging is ongoing |\n# | powertrainTractionBatteryChargingIsChargingCableConnected | | Indicates if a charging cable is physically connected to the vehicle or not |\n# | powertrainTractionBatteryChargingPower | kW | Instantaneous charging power recorded during a charging event |\n# | powertrainTractionBatteryCurrentPower | W | Current electrical energy flowing in/out of battery |\n# | powertrainTractionBatteryCurrentVoltage | V | |\n# | powertrainTractionBatteryGrossCapacity | kWh | |\n# | powertrainTractionBatteryRange | km | Remaining range in kilometers using only battery |\n# | powertrainTractionBatteryStateOfChargeCurrent | percent | Physical state of charge of the high voltage battery, relative to net capacity |\n# | powertrainTractionBatteryStateOfChargeCurrentEnergy | kWh | Physical state of charge of high voltage battery expressed in kWh |\n# | powertrainTractionBatteryStateOfHealth | percent | Calculated battery state of health at standard conditions |\n# | powertrainTractionBatteryTemperatureAverage | celsius | Current average temperature of the battery cells |\n# | powertrainTransmissionActualGear | | Actual transmission gear currently engaged |\n# | powertrainTransmissionActualGearRatio | | |\n# | powertrainTransmissionCurrentGear | | |\n# | powertrainTransmissionIsClutchSwitchOperated | | Indicates if the Clutch switch is operated, so engine and transmission are partially or fully decoupled |\n# | powertrainTransmissionRetarderActualTorque | percent | Actual retarder torque as a percentage (FMS / J1939 SPN 520) |\n# | powertrainTransmissionRetarderTorqueMode | | Active engine torque mode |\n# | powertrainTransmissionSelectedGear | | |\n# | powertrainTransmissionTemperature | celsius | The current gearbox temperature |\n# | powertrainTransmissionTravelledDistance | km | Odometer reading, total distance travelled during the lifetime of the transmission |\n# | powertrainType | | Defines the powertrain type of the vehicle |\n# ── SERVICE (privilege: VEHICLE_NON_LOCATION_DATA) ──\n# | serviceDistanceToService | km | Remaining distance to service (of any kind) |\n# | serviceTimeToService | s | Remaining time to service (of any kind) |\n\ntype Query {\n \"signals returns a collection of signals for a given vehicle DID in a given time range.\"\n signals(\n subject: String!\n \"\"\"\n interval is a time span that used for aggregatting the data with. A duration\n string is a sequence of decimal numbers, each with optional fraction and a unit\n suffix, such as \"300ms\" or \"2h45m\". Valid time units are \"ms\", \"s\", \"m\", \"h\"\n \"\"\"\n interval: String!\n from: Time!\n to: Time!\n filter: SignalFilter\n ): [SignalAggregations!]\n # Example - Hourly average speed over a time range:\n # query TimeSeries($subject:String!,$from:Time!,$to:Time!) { signals(subject:$subject,interval:\"1h\",from:$from,to:$to) { timestamp speed(agg:AVG) } }\n\n \"SignalsLatest returns the latest signals for a given vehicle DID.\"\n signalsLatest(subject: String!, filter: SignalFilter): SignalCollection\n # Example - Latest speed and battery charge:\n # query Latest($subject:String!) { signalsLatest(subject:$subject) { lastSeen speed{timestamp value} powertrainTractionBatteryStateOfChargeCurrent{timestamp value} } }\n\n \"availableSignals returns a list of queryable signal names that have stored data for a given vehicle DID.\"\n availableSignals(subject: String!, filter: SignalFilter): [String!]\n\n \"data summary of all signals for a given vehicle DID\"\n dataSummary(subject: String!, filter: SignalFilter): DataSummary\n\n \"signalsSnapshot returns the latest value of every available signal for a vehicle, along with when any signal was last seen.\"\n signalsSnapshot(subject: String!, filter: SignalFilter): SignalsSnapshotResponse\n # Example - Full snapshot of all signals for a vehicle:\n # query Snapshot($subject:String!) { signalsSnapshot(subject:$subject) { lastSeen signals { name timestamp valueNumber valueString valueLocation { latitude longitude hdop } } } }\n\n \"Latest full cloud event matching the given subject DID and optional filter.\"\n latestCloudEvent(subject: String!, filter: CloudEventFilter): CloudEvent!\n\n cloudEvents(subject: String!, limit: Int = 10, filter: CloudEventFilter): [CloudEvent!]!\n availableCloudEventTypes(subject: String!, filter: CloudEventFilter): [CloudEventTypeSummary!]!\n \"events returns a list of events for a given vehicle DID in a given time range.\"\n events(\n \"subject is the vehicle DID to get events for.\"\n subject: String!\n \"from is the start time of the event.\"\n from: Time!\n \"to is the end time of the event.\"\n to: Time!\n \"filter is the filter to apply to the events.\"\n filter: EventFilter\n ): [Event!]\n\n \"\"\"\n Returns vehicle usage segments detected using the specified mechanism. Maximum\n date range: 31 days.\n Detection mechanisms:\n - IGNITION_DETECTION: Uses 'isIgnitionOn' signal with configurable debouncing\n - FREQUENCY_ANALYSIS: Analyzes signal update frequency to detect activity\n periods\n - CHANGE_POINT_DETECTION: CUSUM-based regime change detection\n - IDLING: Idling segments (engine rpm idle)\n - REFUEL: Refueling segments (fuel level increased)\n - RECHARGE: Charging segments (battery SoC increased)\n Segment IDs are stable and consistent across queries as long as the segment\n start is captured in the underlying data source.\n Each segment includes summary: signals, start/end location, and (when requested)\n eventCounts. A default set of signal requests is always applied (e.g. speed,\n odometer; for refuel/recharge also the level signal at start and end). When\n signalRequests is provided, those requests are added on top of the default set;\n duplicates (same name and agg) are omitted.\n \"\"\"\n segments(\n subject: String!\n from: Time!\n to: Time!\n mechanism: DetectionMechanism!\n config: SegmentConfig\n signalRequests: [SegmentSignalRequest!]\n eventRequests: [SegmentEventRequest!]\n \"Maximum number of segments to return. Default 100, max 200.\"\n limit: Int = 100\n after: Time\n ): [Segment!]!\n # Example - Trip segments with start/end locations and signal aggregates:\n # query Trips($subject:String!,$from:Time!,$to:Time!) { segments(subject:$subject,from:$from,to:$to,mechanism:FREQUENCY_ANALYSIS) { start{timestamp value{latitude longitude}} end{timestamp value{latitude longitude}} duration isOngoing signals{name agg value} eventCounts{name count} } }\n\n \"\"\"\n Returns one record per calendar day in the date range. Mechanism must be\n IGNITION_DETECTION, FREQUENCY_ANALYSIS, or CHANGE_POINT_DETECTION (IDLING,\n REFUEL, and RECHARGE not allowed). Maximum date range: 31 days.\n \"\"\"\n dailyActivity(subject: String!, from: Time!, to: Time!, mechanism: DetectionMechanism!, config: SegmentConfig, signalRequests: [SegmentSignalRequest!], eventRequests: [SegmentEventRequest!], timezone: String): [DailyActivity!]!\n # Example - Daily activity summaries:\n # query Daily($subject:String!,$from:Time!,$to:Time!) { dailyActivity(subject:$subject,from:$from,to:$to,mechanism:FREQUENCY_ANALYSIS) { segmentCount duration signals{name agg value} eventCounts{name count} } }\n}\n\ntype CloudEvent { header: CloudEventHeader!, data: JSON, dataBase64: String, dataUrl: String }\n\ninput CloudEventFilter { id: String, type: String, types: [String!], dataversion: String, source: String, producer: String, before: Time, after: Time }\n\ntype CloudEventHeader { specversion: String!, type: String!, source: String!, subject: String!, id: String!, time: Time!, datacontenttype: String, dataschema: String, dataversion: String, producer: String!, signature: String, raweventid: String, tags: [String!]! }\n\ntype CloudEventTypeSummary { type: String!, count: Int!, firstSeen: Time!, lastSeen: Time! }\n\ntype DailyActivity { start: SignalLocation, end: SignalLocation, segmentCount: Int!, duration: Int!, signals: [SignalAggregationValue!]!, eventCounts: [EventCount!]! }\n\ntype DataSummary { numberOfSignals: Uint64!, availableSignals: [String!]!, firstSeen: Time!, lastSeen: Time!, signalDataSummary: [SignalDataSummary!]!, eventDataSummary: [EventDataSummary!]! }\n\nenum DetectionMechanism {\n \"Ignition-based detection: Segments are identified by isIgnitionOn state transitions. Most reliable for vehicles with proper ignition signal support.\"\n IGNITION_DETECTION\n \"Frequency analysis: Segments are detected by analyzing signal update patterns. Uses pre-computed materialized view for optimal performance. Ideal for real-time APIs and bulk queries.\"\n FREQUENCY_ANALYSIS\n \"\"\"\n Change point detection: Uses CUSUM algorithm to detect statistical regime\n changes. Monitors cumulative deviation in signal frequency via materialized\n view. Excellent noise resistance with 100% accuracy match to ignition baseline.\n Best alternative when ignition signal is unavailable - same accuracy, same speed\n as frequency analysis.\n \"\"\"\n CHANGE_POINT_DETECTION\n \"Idling: Segments are contiguous periods where engine RPM remains in idle range.\"\n IDLING\n \"Refuel: Detects where fuel level rises significantly.\"\n REFUEL\n \"Recharge: Hybrid detection. Uses charging signals and state of charge for detection.\"\n RECHARGE\n}\n\ntype Event { timestamp: Time!, name: String!, source: String!, durationNs: Int!, metadata: String }\n\ntype EventCount { name: String!, count: Int! }\n\ntype EventDataSummary { name: String!, numberOfEvents: Uint64!, firstSeen: Time!, lastSeen: Time! }\n\ninput EventFilter {\n name: StringValueFilter\n \"source is the name of the source connection that created the event.\"\n source: StringValueFilter\n tags: StringArrayFilter\n}\n\ninput FilterLocation {\n \"Latitude in the range [-90, 90].\"\n latitude: Float!\n \"Longitude in the range [-180, 180].\"\n longitude: Float!\n}\n\nenum FloatAggregation { AVG, MED, MAX, MIN, RAND, FIRST, LAST }\n\ninput InCircleFilter {\n center: FilterLocation!\n \"Radius of the circle around the center, in kilometers (km).\"\n radius: Float!\n}\n\ntype LatestSignal { name: String!, timestamp: Time!, valueNumber: Float, valueString: String, valueLocation: Location }\n\ntype Location { latitude: Float!, longitude: Float!, hdop: Float! }\n\nenum LocationAggregation { AVG, RAND, FIRST, LAST }\n\nenum Privilege { VEHICLE_NON_LOCATION_DATA, VEHICLE_COMMANDS, VEHICLE_CURRENT_LOCATION, VEHICLE_ALL_TIME_LOCATION, VEHICLE_VIN_CREDENTIAL, VEHICLE_APPROXIMATE_LOCATION, VEHICLE_RAW_DATA }\n\ntype Segment { start: SignalLocation!, end: SignalLocation, duration: Int!, isOngoing: Boolean!, startedBeforeRange: Boolean!, signals: [SignalAggregationValue!], eventCounts: [EventCount!] }\n\ninput SegmentConfig {\n \"\"\"\n Maximum gap (seconds) between data points before a segment is split. For\n IGNITION_DETECTION: filters noise from brief ignition OFF events. For\n FREQUENCY_ANALYSIS: maximum gap between active windows to merge. Default: 300 (5\n minutes), Min: 60, Max: 3600\n \"\"\"\n maxGapSeconds: Int = 300\n \"Minimum segment duration (seconds) to include in results. Filters very short segments (testing, engine cycling). Default: 240 (4 minutes), Min: 60, Max: 3600\"\n minSegmentDurationSeconds: Int = 240\n \"\"\"\n [FREQUENCY_ANALYSIS] Minimum signal count per window for activity detection.\n [IDLING] Minimum samples per window to consider it idle (same semantics). Higher\n values = more conservative. Lower values = more sensitive. Default: 10, Min: 1,\n Max: 3600\n \"\"\"\n signalCountThreshold: Int = 10\n \"[IDLING only] Upper bound for idle RPM. Windows with max(RPM) <= this are considered idle. Default: 1000, Min: 300, Max: 3000\"\n maxIdleRpm: Int = 1000\n \"[REFUEL and RECHARGE only] Minimum percent increase within a window to consider it a level-increase window.\"\n minIncreasePercent: Int = 15\n}\n\ninput SegmentEventRequest { name: String! }\n\ninput SegmentSignalRequest { name: String!, agg: FloatAggregation! }\n\ntype SignalAggregationValue { name: String!, agg: String!, value: Float! }\n\ntype SignalAggregations {\n \"Timestamp of the aggregated data.\"\n timestamp: Time!\n # + 117 signal fields (see SIGNAL FIELDS table above)\n}\n\ntype SignalCollection {\n \"The last time any signal was seen matching the filter.\"\n lastSeen: Time\n # + 117 signal fields (see SIGNAL FIELDS table above)\n}\n\ntype SignalDataSummary { name: String!, numberOfSignals: Uint64!, firstSeen: Time!, lastSeen: Time! }\n\ninput SignalFilter {\n \"\"\"\n Filter signals by source using an ethr DID. Example:\n \"did:ethr:137:0xcd445F4c6bDAD32b68a2939b912150Fe3C88803E\"\n \"\"\"\n source: String\n}\n\ntype SignalFloat { timestamp: Time!, value: Float! }\n\ninput SignalFloatFilter { eq: Float, neq: Float, gt: Float, lt: Float, gte: Float, lte: Float, notIn: [Float!], in: [Float!], or: [SignalFloatFilter!] }\n\ntype SignalLocation { timestamp: Time!, value: Location! }\n\ninput SignalLocationFilter {\n \"Filter for locations within a polygon. The vertices should be ordered clockwise or counterclockwise, and there must be at least 3. May produce inaccurate results around the poles and the antimeridian.\"\n inPolygon: [FilterLocation!]\n \"Filter for locations within a given distance of a given point. Distances are computed using WGS 84, and points that are exactly a distance `radius` from the `center` will be included.\"\n inCircle: InCircleFilter\n}\n\ntype SignalString { timestamp: Time!, value: String! }\n\ntype SignalsSnapshotResponse { lastSeen: Time, signals: [LatestSignal!]! }\n\nenum StringAggregation {\n \"Randomly select a value from the group.\"\n RAND\n \"Select the most frequently occurring value in the group.\"\n TOP\n \"Return a list of unique values in the group.\"\n UNIQUE\n \"Return value in group associated with the minimum time value.\"\n FIRST\n \"Return value in group associated with the maximum time value.\"\n LAST\n}\n\ninput StringArrayFilter {\n containsAny: [String!]\n containsAll: [String!]\n \"notContainsAny array of strings does not contain any of the strings in the array\"\n notContainsAny: [String!]\n \"notContainsAll array of strings does not contain all of the strings in the array\"\n notContainsAll: [String!]\n or: [StringArrayFilter!]\n}\n\ninput StringValueFilter {\n eq: String\n neq: String\n notIn: [String!]\n in: [String!]\n \"startsWith matches strings that begin with the given prefix.\"\n startsWith: String\n or: [StringValueFilter!]\n}\n" +var CondensedSchema = "scalar JSON # Arbitrary JSON value; serialized as raw JSON (object/array), not an escaped string.\nscalar Map\nscalar Time # A point in time, encoded per RFC-3999.\nscalar Uint64 # A 64-bit unsigned integer.\n\n# ═══ SIGNAL FIELDS (117 total) ═══\n# All signals below exist on every signal type. Calling convention per type:\n# SignalAggregations:\n# fieldName(agg: LocationAggregation!): Location\n# fieldName(agg: FloatAggregation!, filter: SignalFloatFilter): Float\n# fieldName(agg: LocationAggregation!, filter: SignalLocationFilter): Location\n# fieldName(agg: StringAggregation!): String\n# SignalCollection:\n# fieldName(): SignalLocation\n# fieldName(): SignalFloat\n# fieldName(): SignalString\n# Float is the default type. Location: currentLocationApproximateCoordinates, currentLocationCoordinates. String: obdDTCList, obdFuelTypeName, powertrainCombustionEngineEngineOilLevel, powertrainFuelSystemSupportedFuelTypes, powertrainTransmissionRetarderTorqueMode, powertrainType.\n# | Signal | Unit | Description |\n# |--------|------|-------------|\n# Shared descriptions (blank rows below use these):\n# - Is item open or closed? True = Fully or partially open\n# - Is the belt engaged\n# - Measured Load on axle row 3\n# ── CURRENT (privilege: VEHICLE_ALL_TIME_LOCATION) ──\n# | currentLocationApproximateCoordinates | | Approximate location of the vehicle in WGS 84 coordinates (privilege: VEHICLE_APPROXIMATE_LOCATION VEHICLE_ALL_TIME_LOCATION) |\n# | currentLocationAltitude | m | Current altitude relative to WGS 84 reference ellipsoid, as measured at the position of GNSS receiver antenna |\n# | currentLocationCoordinates | | Current location of the vehicle in WGS 84 coordinates |\n# | currentLocationHeading | degrees | Current heading relative to geographic north |\n# ── OTHER (privilege: VEHICLE_NON_LOCATION_DATA) ──\n# | angularVelocityYaw | degrees/s | Vehicle rotation rate along Z (vertical) |\n# | connectivityCellularIsJammingDetected | | Indicates whether cellular radio signal jamming or interference is detected that prevents normal communication |\n# | exteriorAirTemperature | celsius | Air temperature outside the vehicle |\n# | isIgnitionOn | | Vehicle ignition status |\n# | lowVoltageBatteryCurrentVoltage | V | |\n# | speed | km/h | |\n# ── BODY (privilege: VEHICLE_NON_LOCATION_DATA) ──\n# | bodyLightsIsAirbagWarningOn | | Indicates whether the airbag/SRS warning telltale is active |\n# | bodyLockIsLocked | | Indicates whether the vehicle is locked via the central locking system |\n# | bodyTrunkFrontIsOpen | | |\n# | bodyTrunkRearIsOpen | | |\n# ── CABIN (privilege: VEHICLE_NON_LOCATION_DATA) ──\n# | cabinDoorRow1DriverSideIsOpen | | |\n# | cabinDoorRow1DriverSideWindowIsOpen | | |\n# | cabinDoorRow1PassengerSideIsOpen | | |\n# | cabinDoorRow1PassengerSideWindowIsOpen | | |\n# | cabinDoorRow2DriverSideIsOpen | | |\n# | cabinDoorRow2DriverSideWindowIsOpen | | |\n# | cabinDoorRow2PassengerSideIsOpen | | |\n# | cabinDoorRow2PassengerSideWindowIsOpen | | |\n# | cabinSeatRow1DriverSideIsBelted | | |\n# | cabinSeatRow1PassengerSideIsBelted | | |\n# | cabinSeatRow2DriverSideIsBelted | | |\n# | cabinSeatRow2MiddleIsBelted | | |\n# | cabinSeatRow2PassengerSideIsBelted | | |\n# | cabinSeatRow3DriverSideIsBelted | | |\n# | cabinSeatRow3PassengerSideIsBelted | | |\n# ── CHASSIS (privilege: VEHICLE_NON_LOCATION_DATA) ──\n# shared: Rotational speed of a vehicle's wheel\n# shared: Pneumatic pressure in the service brake circuit or reservoir\n# | chassisAxleRow1WheelLeftSpeed | km/h | |\n# | chassisAxleRow1WheelLeftTirePressure | kPa | |\n# | chassisAxleRow1WheelRightSpeed | km/h | |\n# | chassisAxleRow1WheelRightTirePressure | kPa | |\n# | chassisAxleRow2WheelLeftTirePressure | kPa | |\n# | chassisAxleRow2WheelRightTirePressure | kPa | |\n# | chassisAxleRow3Weight | kg | |\n# | chassisAxleRow4Weight | kg | |\n# | chassisAxleRow5Weight | kg | |\n# | chassisBrakeABSIsWarningOn | | Indicates whether the ABS warning telltale is active (any non-off state) |\n# | chassisBrakeCircuit1PressurePrimary | kPa | |\n# | chassisBrakeCircuit2PressurePrimary | kPa | |\n# | chassisBrakeIsPedalPressed | | Indicates whether the brake pedal is pressed |\n# | chassisBrakePedalPosition | percent | Brake pedal position as percent |\n# | chassisParkingBrakeIsEngaged | | |\n# | chassisTireSystemIsWarningOn | | Indicates whether the tire system warning telltale is active |\n# ── OBD (privilege: VEHICLE_NON_LOCATION_DATA) ──\n# shared: PID 2x (byte CD) - Voltage for wide range/band oxygen sensor\n# | obdBarometricPressure | kPa | PID 33 - Barometric pressure |\n# | obdCommandedEGR | percent | PID 2C - Commanded exhaust gas recirculation (EGR) |\n# | obdCommandedEVAP | percent | PID 2E - Commanded evaporative purge (EVAP) valve |\n# | obdDTCList | | List of currently active DTCs formatted according OBD II (SAE-J2012DA_201812) standard ([P|C|B|U]XXXXX ) |\n# | obdDistanceSinceDTCClear | km | PID 31 - Distance traveled since codes cleared |\n# | obdDistanceWithMIL | km | PID 21 - Distance traveled with MIL on |\n# | obdEngineLoad | percent | PID 04 - Engine load in percent - 0 = no load, 100 = full load |\n# | obdEthanolPercent | percent | PID 52 - Percentage of ethanol in the fuel |\n# | obdFuelPressure | kPa | PID 0A - Fuel pressure |\n# | obdFuelRailPressure | kPa | |\n# | obdFuelRate | l/h | PID 5E - Engine fuel rate |\n# | obdFuelTypeName | | Fuel type names decoded from PID 51 |\n# | obdIntakeTemp | celsius | PID 0F - Intake temperature |\n# | obdIsEngineBlocked | | Engine block status, 0 = engine unblocked, 1 = engine blocked |\n# | obdIsPTOActive | | PID 1E - Auxiliary input status (power take off) |\n# | obdIsPluggedIn | | Aftermarket device plugged in status |\n# | obdLongTermFuelTrim1 | percent | PID 07 - Long Term (learned) Fuel Trim - Bank 1 - negative percent leaner, positive percent richer |\n# | obdLongTermFuelTrim2 | percent | PID 09 - Long Term (learned) Fuel Trim - Bank 2 - negative percent leaner, positive percent richer |\n# | obdMAP | kPa | PID 0B - Intake manifold pressure |\n# | obdMaxMAF | g/s | PID 50 - Maximum flow for mass air flow sensor |\n# | obdO2WRSensor1Voltage | V | |\n# | obdO2WRSensor2Voltage | V | |\n# | obdOilTemperature | celsius | PID 5C - Engine oil temperature |\n# | obdRunTime | s | PID 1F - Engine run time |\n# | obdShortTermFuelTrim1 | percent | PID 06 - Short Term (immediate) Fuel Trim - Bank 1 - negative percent leaner, positive percent richer |\n# | obdStatusDTCCount | | Number of Diagnostic Trouble Codes (DTC) |\n# | obdThrottlePosition | percent | PID 11 - Throttle position - 0 = closed throttle, 100 = open throttle |\n# | obdWarmupsSinceDTCClear | | PID 30 - Number of warm-ups since codes cleared |\n# ── POWERTRAIN (privilege: VEHICLE_NON_LOCATION_DATA) ──\n# | powertrainCombustionEngineDieselExhaustFluidCapacity | l | Capacity in liters of the Diesel Exhaust Fluid Tank |\n# | powertrainCombustionEngineDieselExhaustFluidLevel | percent | Level of the Diesel Exhaust Fluid tank as percent of capacity |\n# | powertrainCombustionEngineECT | celsius | Engine coolant temperature |\n# | powertrainCombustionEngineEOP | kPa | Engine oil pressure |\n# | powertrainCombustionEngineEOT | celsius | Engine oil temperature |\n# | powertrainCombustionEngineEngineOilLevel | | |\n# | powertrainCombustionEngineEngineOilRelativeLevel | percent | Engine oil level as a percentage |\n# | powertrainCombustionEngineMAF | g/s | Grams of air drawn into engine per second |\n# | powertrainCombustionEngineSpeed | rpm | Engine speed measured as rotations per minute |\n# | powertrainCombustionEngineTPS | percent | Current throttle position |\n# | powertrainCombustionEngineTorque | Nm | |\n# | powertrainCombustionEngineTorquePercent | percent | Actual engine output torque as a percentage of reference engine torque (FMS / J1939 parameter SPN 513) |\n# | powertrainFuelSystemAbsoluteLevel | l | Current available fuel in the fuel tank expressed in liters |\n# | powertrainFuelSystemAccumulatedConsumption | l | Accumulated fuel consumption (totalized) reported by the vehicle (FMS SPN 250) |\n# | powertrainFuelSystemRelativeLevel | percent | Level in fuel tank as percent of capacity |\n# | powertrainFuelSystemSupportedFuelTypes | | High level information of fuel types supported |\n# | powertrainRange | km | Remaining range in kilometers using all energy sources available in the vehicle |\n# | powertrainTractionBatteryChargingAddedEnergy | kWh | Amount of charge added to the high voltage battery during the current charging session, expressed in kilowatt-hours |\n# | powertrainTractionBatteryChargingChargeCurrentAC | A | Current AC charging current (rms) at inlet |\n# | powertrainTractionBatteryChargingChargeLimit | percent | Target charge limit (state of charge) for battery |\n# | powertrainTractionBatteryChargingChargeVoltageUnknownType | V | Current charging voltage at inlet |\n# | powertrainTractionBatteryChargingIsCharging | | True if charging is ongoing |\n# | powertrainTractionBatteryChargingIsChargingCableConnected | | Indicates if a charging cable is physically connected to the vehicle or not |\n# | powertrainTractionBatteryChargingPower | kW | Instantaneous charging power recorded during a charging event |\n# | powertrainTractionBatteryCurrentPower | W | Current electrical energy flowing in/out of battery |\n# | powertrainTractionBatteryCurrentVoltage | V | |\n# | powertrainTractionBatteryGrossCapacity | kWh | |\n# | powertrainTractionBatteryRange | km | Remaining range in kilometers using only battery |\n# | powertrainTractionBatteryStateOfChargeCurrent | percent | Physical state of charge of the high voltage battery, relative to net capacity |\n# | powertrainTractionBatteryStateOfChargeCurrentEnergy | kWh | Physical state of charge of high voltage battery expressed in kWh |\n# | powertrainTractionBatteryStateOfHealth | percent | Calculated battery state of health at standard conditions |\n# | powertrainTractionBatteryTemperatureAverage | celsius | Current average temperature of the battery cells |\n# | powertrainTransmissionActualGear | | Actual transmission gear currently engaged |\n# | powertrainTransmissionActualGearRatio | | |\n# | powertrainTransmissionCurrentGear | | |\n# | powertrainTransmissionIsClutchSwitchOperated | | Indicates if the Clutch switch is operated, so engine and transmission are partially or fully decoupled |\n# | powertrainTransmissionRetarderActualTorque | percent | Actual retarder torque as a percentage (FMS / J1939 SPN 520) |\n# | powertrainTransmissionRetarderTorqueMode | | Active engine torque mode |\n# | powertrainTransmissionSelectedGear | | |\n# | powertrainTransmissionTemperature | celsius | The current gearbox temperature |\n# | powertrainTransmissionTravelledDistance | km | Odometer reading, total distance travelled during the lifetime of the transmission |\n# | powertrainType | | Defines the powertrain type of the vehicle |\n# ── SERVICE (privilege: VEHICLE_NON_LOCATION_DATA) ──\n# | serviceDistanceToService | km | Remaining distance to service (of any kind) |\n# | serviceTimeToService | s | Remaining time to service (of any kind) |\n\ntype Query {\n \"signals returns a collection of signals for a given vehicle DID in a given time range.\"\n signals(\n subject: String!\n \"\"\"\n interval is a time span that used for aggregatting the data with. A duration\n string is a sequence of decimal numbers, each with optional fraction and a unit\n suffix, such as \"300ms\" or \"2h45m\". Valid time units are \"ms\", \"s\", \"m\", \"h\"\n \"\"\"\n interval: String!\n from: Time!\n to: Time!\n filter: SignalFilter\n ): [SignalAggregations!]\n # Example - Hourly average speed over a time range:\n # query TimeSeries($subject:String!,$from:Time!,$to:Time!) { signals(subject:$subject,interval:\"1h\",from:$from,to:$to) { timestamp speed(agg:AVG) } }\n\n \"SignalsLatest returns the latest signals for a given vehicle DID.\"\n signalsLatest(subject: String!, filter: SignalFilter): SignalCollection\n # Example - Latest speed and battery charge:\n # query Latest($subject:String!) { signalsLatest(subject:$subject) { lastSeen speed{timestamp value} powertrainTractionBatteryStateOfChargeCurrent{timestamp value} } }\n\n \"availableSignals returns a list of queryable signal names that have stored data for a given vehicle DID.\"\n availableSignals(subject: String!, filter: SignalFilter): [String!]\n\n \"data summary of all signals for a given vehicle DID\"\n dataSummary(subject: String!, filter: SignalFilter): DataSummary\n\n \"signalsSnapshot returns the latest value of every available signal for a vehicle, along with when any signal was last seen.\"\n signalsSnapshot(subject: String!, filter: SignalFilter): SignalsSnapshotResponse\n # Example - Full snapshot of all signals for a vehicle:\n # query Snapshot($subject:String!) { signalsSnapshot(subject:$subject) { lastSeen signals { name timestamp valueNumber valueString valueLocation { latitude longitude hdop } } } }\n\n \"Latest full cloud event matching the given subject DID and optional filter.\"\n latestCloudEvent(subject: String!, filter: CloudEventFilter): CloudEvent!\n\n cloudEvents(subject: String!, limit: Int = 10, filter: CloudEventFilter): [CloudEvent!]!\n availableCloudEventTypes(subject: String!, filter: CloudEventFilter): [CloudEventTypeSummary!]!\n \"events returns a list of events for a given vehicle DID in a given time range.\"\n events(\n \"subject is the vehicle DID to get events for.\"\n subject: String!\n \"from is the start time of the event.\"\n from: Time!\n \"to is the end time of the event.\"\n to: Time!\n \"filter is the filter to apply to the events.\"\n filter: EventFilter\n ): [Event!]\n\n \"\"\"\n Returns vehicle usage segments detected using the specified mechanism. Maximum\n date range: 31 days.\n Detection mechanisms:\n - IGNITION_DETECTION: Uses 'isIgnitionOn' signal with configurable debouncing\n - FREQUENCY_ANALYSIS: Analyzes signal update frequency to detect activity\n periods\n - CHANGE_POINT_DETECTION: CUSUM-based regime change detection\n - IDLING: Idling segments (engine rpm idle)\n - REFUEL: Refueling segments (fuel level increased)\n - RECHARGE: Charging segments (battery SoC increased)\n Segment IDs are stable and consistent across queries as long as the segment\n start is captured in the underlying data source.\n Each segment includes summary: signals, start/end location, and (when requested)\n eventCounts. A default set of signal requests is always applied (e.g. speed,\n odometer; for refuel/recharge also the level signal at start and end). When\n signalRequests is provided, those requests are added on top of the default set;\n duplicates (same name and agg) are omitted.\n \"\"\"\n segments(\n subject: String!\n from: Time!\n to: Time!\n mechanism: DetectionMechanism!\n config: SegmentConfig\n signalRequests: [SegmentSignalRequest!]\n eventRequests: [SegmentEventRequest!]\n \"Maximum number of segments to return. Default 100, max 200.\"\n limit: Int = 100\n after: Time\n ): [Segment!]!\n # Example - Trip segments with start/end locations and signal aggregates:\n # query Trips($subject:String!,$from:Time!,$to:Time!) { segments(subject:$subject,from:$from,to:$to,mechanism:FREQUENCY_ANALYSIS) { start{timestamp value{latitude longitude}} end{timestamp value{latitude longitude}} duration isOngoing signals{name agg value} eventCounts{name count} } }\n\n \"\"\"\n Returns one record per calendar day in the date range. Mechanism must be\n IGNITION_DETECTION, FREQUENCY_ANALYSIS, or CHANGE_POINT_DETECTION (IDLING,\n REFUEL, and RECHARGE not allowed). Maximum date range: 31 days.\n \"\"\"\n dailyActivity(subject: String!, from: Time!, to: Time!, mechanism: DetectionMechanism!, config: SegmentConfig, signalRequests: [SegmentSignalRequest!], eventRequests: [SegmentEventRequest!], timezone: String): [DailyActivity!]!\n # Example - Daily activity summaries:\n # query Daily($subject:String!,$from:Time!,$to:Time!) { dailyActivity(subject:$subject,from:$from,to:$to,mechanism:FREQUENCY_ANALYSIS) { segmentCount duration signals{name agg value} eventCounts{name count} } }\n}\n\ntype CloudEvent { header: CloudEventHeader!, data: JSON, dataBase64: String, dataUrl: String }\n\ninput CloudEventFilter { id: String, type: String, types: [String!], dataversion: String, source: String, producer: String, before: Time, after: Time }\n\ntype CloudEventHeader { specversion: String!, type: String!, source: String!, subject: String!, id: String!, time: Time!, datacontenttype: String, dataschema: String, dataversion: String, producer: String!, signature: String, raweventid: String, tags: [String!]! }\n\ntype CloudEventTypeSummary { type: String!, count: Int!, firstSeen: Time!, lastSeen: Time! }\n\ntype DailyActivity { start: SignalLocation, end: SignalLocation, segmentCount: Int!, duration: Int!, signals: [SignalAggregationValue!]!, eventCounts: [EventCount!]! }\n\ntype DataSummary { numberOfSignals: Uint64!, availableSignals: [String!]!, firstSeen: Time!, lastSeen: Time!, signalDataSummary: [SignalDataSummary!]!, eventDataSummary: [EventDataSummary!]! }\n\nenum DetectionMechanism {\n \"Ignition-based detection: Segments are identified by isIgnitionOn state transitions. Most reliable for vehicles with proper ignition signal support.\"\n IGNITION_DETECTION\n \"Frequency analysis: Segments are detected by analyzing signal update patterns. Uses pre-computed materialized view for optimal performance. Ideal for real-time APIs and bulk queries.\"\n FREQUENCY_ANALYSIS\n \"\"\"\n Change point detection: Uses CUSUM algorithm to detect statistical regime\n changes. Monitors cumulative deviation in signal frequency via materialized\n view. Excellent noise resistance with 100% accuracy match to ignition baseline.\n Best alternative when ignition signal is unavailable - same accuracy, same speed\n as frequency analysis.\n \"\"\"\n CHANGE_POINT_DETECTION\n \"Idling: Segments are contiguous periods where engine RPM remains in idle range.\"\n IDLING\n \"Refuel: Detects where fuel level rises significantly.\"\n REFUEL\n \"Recharge: Hybrid detection. Uses charging signals and state of charge for detection.\"\n RECHARGE\n}\n\ntype Event { timestamp: Time!, name: String!, source: String!, durationNs: Int!, metadata: String }\n\ntype EventCount { name: String!, count: Int! }\n\ntype EventDataSummary { name: String!, numberOfEvents: Uint64!, firstSeen: Time!, lastSeen: Time! }\n\ninput EventFilter {\n name: StringValueFilter\n \"source is the name of the source connection that created the event.\"\n source: StringValueFilter\n tags: StringArrayFilter\n}\n\ninput FilterLocation {\n \"Latitude in the range [-90, 90].\"\n latitude: Float!\n \"Longitude in the range [-180, 180].\"\n longitude: Float!\n}\n\nenum FloatAggregation { AVG, MED, MAX, MIN, RAND, FIRST, LAST }\n\ninput InCircleFilter {\n center: FilterLocation!\n \"Radius of the circle around the center, in kilometers (km).\"\n radius: Float!\n}\n\ntype LatestSignal { name: String!, timestamp: Time!, valueNumber: Float, valueString: String, valueLocation: Location }\n\ntype Location { latitude: Float!, longitude: Float!, hdop: Float! }\n\nenum LocationAggregation { AVG, RAND, FIRST, LAST }\n\nenum Privilege { VEHICLE_NON_LOCATION_DATA, VEHICLE_COMMANDS, VEHICLE_CURRENT_LOCATION, VEHICLE_ALL_TIME_LOCATION, VEHICLE_VIN_CREDENTIAL, VEHICLE_APPROXIMATE_LOCATION, VEHICLE_RAW_DATA }\n\ntype Segment { start: SignalLocation!, end: SignalLocation, duration: Int!, isOngoing: Boolean!, startedBeforeRange: Boolean!, signals: [SignalAggregationValue!], eventCounts: [EventCount!] }\n\ninput SegmentConfig {\n \"\"\"\n Maximum gap (seconds) between data points before a segment is split. For\n IGNITION_DETECTION: filters noise from brief ignition OFF events. For\n FREQUENCY_ANALYSIS: maximum gap between active windows to merge. Default: 300 (5\n minutes), Min: 60, Max: 3600\n \"\"\"\n maxGapSeconds: Int = 300\n \"Minimum segment duration (seconds) to include in results. Filters very short segments (testing, engine cycling). Default: 240 (4 minutes), Min: 60, Max: 3600\"\n minSegmentDurationSeconds: Int = 240\n \"\"\"\n [FREQUENCY_ANALYSIS] Minimum signal count per window for activity detection.\n [IDLING] Minimum samples per window to consider it idle (same semantics). Higher\n values = more conservative. Lower values = more sensitive. Default: 10, Min: 1,\n Max: 3600\n \"\"\"\n signalCountThreshold: Int = 10\n \"[IDLING only] Upper bound for idle RPM. Windows with max(RPM) <= this are considered idle. Default: 1000, Min: 300, Max: 3000\"\n maxIdleRpm: Int = 1000\n \"[REFUEL and RECHARGE only] Minimum percent increase within a window to consider it a level-increase window.\"\n minIncreasePercent: Int = 15\n}\n\ninput SegmentEventRequest { name: String! }\n\ninput SegmentSignalRequest { name: String!, agg: FloatAggregation! }\n\ntype SignalAggregationValue { name: String!, agg: String!, value: Float! }\n\ntype SignalAggregations {\n \"Timestamp of the aggregated data.\"\n timestamp: Time!\n # + 117 signal fields (see SIGNAL FIELDS table above)\n}\n\ntype SignalCollection {\n \"The last time any signal was seen matching the filter.\"\n lastSeen: Time\n # + 117 signal fields (see SIGNAL FIELDS table above)\n}\n\ntype SignalDataSummary { name: String!, numberOfSignals: Uint64!, firstSeen: Time!, lastSeen: Time! }\n\ninput SignalFilter {\n \"\"\"\n Filter signals by source using an ethr DID. Example:\n \"did:ethr:137:0xcd445F4c6bDAD32b68a2939b912150Fe3C88803E\"\n \"\"\"\n source: String\n}\n\ntype SignalFloat { timestamp: Time!, value: Float! }\n\ninput SignalFloatFilter { eq: Float, neq: Float, gt: Float, lt: Float, gte: Float, lte: Float, notIn: [Float!], in: [Float!], or: [SignalFloatFilter!] }\n\ntype SignalLocation { timestamp: Time!, value: Location! }\n\ninput SignalLocationFilter {\n \"Filter for locations within a polygon. The vertices should be ordered clockwise or counterclockwise, and there must be at least 3. May produce inaccurate results around the poles and the antimeridian.\"\n inPolygon: [FilterLocation!]\n \"Filter for locations within a given distance of a given point. Distances are computed using WGS 84, and points that are exactly a distance `radius` from the `center` will be included.\"\n inCircle: InCircleFilter\n}\n\ntype SignalString { timestamp: Time!, value: String! }\n\ntype SignalsSnapshotResponse { lastSeen: Time, signals: [LatestSignal!]! }\n\nenum StringAggregation {\n \"Randomly select a value from the group.\"\n RAND\n \"Select the most frequently occurring value in the group.\"\n TOP\n \"Return a list of unique values in the group.\"\n UNIQUE\n \"Return value in group associated with the minimum time value.\"\n FIRST\n \"Return value in group associated with the maximum time value.\"\n LAST\n}\n\ninput StringArrayFilter {\n containsAny: [String!]\n containsAll: [String!]\n \"notContainsAny array of strings does not contain any of the strings in the array\"\n notContainsAny: [String!]\n \"notContainsAll array of strings does not contain all of the strings in the array\"\n notContainsAll: [String!]\n or: [StringArrayFilter!]\n}\n\ninput StringValueFilter {\n eq: String\n neq: String\n notIn: [String!]\n in: [String!]\n \"startsWith matches strings that begin with the given prefix.\"\n startsWith: String\n or: [StringValueFilter!]\n}\n" diff --git a/internal/graph/privilege_filter.go b/internal/graph/privilege_filter.go index b852077..4a00b57 100644 --- a/internal/graph/privilege_filter.go +++ b/internal/graph/privilege_filter.go @@ -1,11 +1,12 @@ package graph import ( + "context" "slices" + "github.com/DIMO-Network/dauth/pkg/tokenclaims" "github.com/DIMO-Network/dq/internal/graph/model" "github.com/DIMO-Network/dq/internal/repositories" - "github.com/DIMO-Network/token-exchange-api/pkg/tokenclaims" ) // privilegeEnumToPermission maps GraphQL Privilege enum values (as they appear @@ -42,3 +43,11 @@ func hasPrivilegesForSignal(repo *repositories.Repository, name string, permissi } return true } + +// permissionsFromCtx returns the caller's token permissions, or nil when unauthenticated. +func permissionsFromCtx(ctx context.Context) []string { + if tok, _ := ctx.Value(ClaimsContextKey{}).(*tokenclaims.Token); tok != nil { + return tok.Permissions + } + return nil +} diff --git a/tests/local_e2e_186612_fetch_test.go b/tests/local_e2e_186612_fetch_test.go index 4800536..8afea87 100644 --- a/tests/local_e2e_186612_fetch_test.go +++ b/tests/local_e2e_186612_fetch_test.go @@ -23,7 +23,7 @@ import ( "github.com/99designs/gqlgen/graphql/handler/transport" "github.com/DIMO-Network/dq/internal/graph" "github.com/DIMO-Network/dq/internal/service/duck" - "github.com/DIMO-Network/token-exchange-api/pkg/tokenclaims" + "github.com/DIMO-Network/dauth/pkg/tokenclaims" "github.com/stretchr/testify/require" )