diff --git a/API.md b/API.md new file mode 100644 index 0000000..8285f71 --- /dev/null +++ b/API.md @@ -0,0 +1,16 @@ +# Tesla API Matrix + +List of all known Tesla APIs, and if this crate supports it, and which of the Tesla enpoints support them. + +### Legend + +- Blank - Unknown +- โœ… Supported by this crate +- ๐ŸŸข Supported by specified API +- ๐Ÿ”ด Not supported by specified API + +Currently only the Owner API is partially supported by this crate. + +| API | Owner API | Fleet API | Command Mode | +|-----------| --- | --- | --- | +| honk_horn | โœ… | | | diff --git a/scrape_fleet_api/Cargo.lock b/scrape_fleet_api/Cargo.lock deleted file mode 100644 index dc8baaa..0000000 --- a/scrape_fleet_api/Cargo.lock +++ /dev/null @@ -1,1755 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "ahash" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" -dependencies = [ - "cfg-if", - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "anstream" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" - -[[package]] -name = "anstyle-parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" -dependencies = [ - "anstyle", - "windows-sys", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "backtrace" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base64" -version = "0.21.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" - -[[package]] -name = "bumpalo" -version = "3.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" - -[[package]] -name = "cc" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clap" -version = "4.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "clap_lex" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" - -[[package]] -name = "colorchoice" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" - -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" - -[[package]] -name = "cssparser" -version = "0.31.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b3df4f93e5fbbe73ec01ec8d3f68bba73107993a5b1e7519273c32db9b0d5be" -dependencies = [ - "cssparser-macros", - "dtoa-short", - "itoa", - "phf 0.11.2", - "smallvec", -] - -[[package]] -name = "cssparser-macros" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" -dependencies = [ - "quote", - "syn 2.0.38", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "dtoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" - -[[package]] -name = "dtoa-short" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbaceec3c6e4211c79e7b1800fb9680527106beb2f9c51904a3210c03a448c74" -dependencies = [ - "dtoa", -] - -[[package]] -name = "ego-tree" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a68a4904193147e0a8dec3314640e6db742afd5f6e634f428a6af230d9b3591" - -[[package]] -name = "encoding_rs" -version = "0.8.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "errno" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "fastrand" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" -dependencies = [ - "mac", - "new_debug_unreachable", -] - -[[package]] -name = "futures-channel" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" -dependencies = [ - "futures-core", -] - -[[package]] -name = "futures-core" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" - -[[package]] -name = "futures-sink" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" - -[[package]] -name = "futures-task" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" - -[[package]] -name = "futures-util" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" -dependencies = [ - "futures-core", - "futures-task", - "pin-project-lite", - "pin-utils", -] - -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "getopts" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "getrandom" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "gimli" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" - -[[package]] -name = "h2" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hermit-abi" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" - -[[package]] -name = "html5ever" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" -dependencies = [ - "log", - "mac", - "markup5ever", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "http" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2 0.4.10", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] - -[[package]] -name = "idna" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "ipnet" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" - -[[package]] -name = "itoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" - -[[package]] -name = "js-sys" -version = "0.3.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.149" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" - -[[package]] -name = "linux-raw-sys" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" - -[[package]] -name = "lock_api" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "mac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" - -[[package]] -name = "markup5ever" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" -dependencies = [ - "log", - "phf 0.10.1", - "phf_codegen", - "string_cache", - "string_cache_codegen", - "tendril", -] - -[[package]] -name = "memchr" -version = "2.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" -dependencies = [ - "libc", - "wasi", - "windows-sys", -] - -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "new_debug_unreachable" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.32.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "openssl" -version = "0.10.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" -dependencies = [ - "bitflags 2.4.1", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.4.1", - "smallvec", - "windows-targets", -] - -[[package]] -name = "percent-encoding" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" - -[[package]] -name = "phf" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" -dependencies = [ - "phf_shared 0.10.0", -] - -[[package]] -name = "phf" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" -dependencies = [ - "phf_macros", - "phf_shared 0.11.2", -] - -[[package]] -name = "phf_codegen" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", -] - -[[package]] -name = "phf_generator" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" -dependencies = [ - "phf_shared 0.10.0", - "rand", -] - -[[package]] -name = "phf_generator" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" -dependencies = [ - "phf_shared 0.11.2", - "rand", -] - -[[package]] -name = "phf_macros" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" -dependencies = [ - "phf_generator 0.11.2", - "phf_shared 0.11.2", - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher", -] - -[[package]] -name = "phf_shared" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "proc-macro2" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "reqwest" -version = "0.11.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" -dependencies = [ - "base64", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-tls", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "serde", - "serde_json", - "serde_urlencoded", - "system-configuration", - "tokio", - "tokio-native-tls", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "winreg", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - -[[package]] -name = "rustix" -version = "0.38.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ce50cb2e16c2903e30d1cbccfd8387a74b9d4c938b6a4c5ec6cc7556f7a8a0" -dependencies = [ - "bitflags 2.4.1", - "errno", - "libc", - "linux-raw-sys", - "windows-sys", -] - -[[package]] -name = "rustversion" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" - -[[package]] -name = "ryu" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" - -[[package]] -name = "schannel" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "scrape_fleet_api" -version = "0.1.0" -dependencies = [ - "clap", - "reqwest", - "scraper", - "strum", - "tokio", - "tracing-subscriber", -] - -[[package]] -name = "scraper" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c95a930e03325234c18c7071fd2b60118307e025d6fff3e12745ffbf63a3d29c" -dependencies = [ - "ahash", - "cssparser", - "ego-tree", - "getopts", - "html5ever", - "once_cell", - "selectors", - "smallvec", - "tendril", -] - -[[package]] -name = "security-framework" -version = "2.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "selectors" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb30575f3638fc8f6815f448d50cb1a2e255b0897985c8c59f4d37b72a07b06" -dependencies = [ - "bitflags 2.4.1", - "cssparser", - "derive_more", - "fxhash", - "log", - "new_debug_unreachable", - "phf 0.10.1", - "phf_codegen", - "precomputed-hash", - "servo_arc", - "smallvec", -] - -[[package]] -name = "serde" -version = "1.0.189" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.189" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "serde_json" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "servo_arc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d036d71a959e00c77a63538b90a6c2390969f9772b096ea837205c6bd0491a44" -dependencies = [ - "stable_deref_trait", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" -dependencies = [ - "libc", -] - -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" - -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "socket2" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "string_cache" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot", - "phf_shared 0.10.0", - "precomputed-hash", - "serde", -] - -[[package]] -name = "string_cache_codegen" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", - "proc-macro2", - "quote", -] - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "strum" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.25.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.38", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "tempfile" -version = "3.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" -dependencies = [ - "cfg-if", - "fastrand", - "redox_syscall 0.3.5", - "rustix", - "windows-sys", -] - -[[package]] -name = "tendril" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" -dependencies = [ - "futf", - "mac", - "utf-8", -] - -[[package]] -name = "thread_local" -version = "1.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "num_cpus", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2 0.5.5", - "tokio-macros", - "windows-sys", -] - -[[package]] -name = "tokio-macros" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922" -dependencies = [ - "lazy_static", - "log", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" -dependencies = [ - "nu-ansi-term", - "sharded-slab", - "smallvec", - "thread_local", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "try-lock" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" - -[[package]] -name = "unicode-bidi" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-width" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" - -[[package]] -name = "url" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.38", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" - -[[package]] -name = "web-sys" -version = "0.3.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys", -] diff --git a/scrape_fleet_api/src/main.rs b/scrape_fleet_api/src/main.rs deleted file mode 100644 index bc26987..0000000 --- a/scrape_fleet_api/src/main.rs +++ /dev/null @@ -1,425 +0,0 @@ -use clap::{Command, Parser}; -use scraper::{Element, ElementRef, Html, Selector}; -use std::collections::HashMap; -use std::path::{Path, PathBuf}; -use std::str::FromStr; - -#[derive(Parser, Debug)] -#[clap(author, version)] -struct Cli { - /// Only use the cached html to avoid making a request. - #[clap(short, long)] - cache: bool, -} - -#[tokio::main] -async fn main() { - tracing_subscriber::fmt::init(); - let args = Cli::parse(); - - let html = get_and_save_html(&args).await; - - let fleet_api = parse(&html); -} - -async fn get_and_save_html(args: &Cli) -> String { - // Write to where this project root is, not in the parent project. - let mut path = PathBuf::new(); - path.push(env!("CARGO_MANIFEST_DIR")); - path.push("fleet.html"); - - if args.cache { - return std::fs::read_to_string(path).unwrap(); - } - - let response = reqwest::get("https://developer.tesla.com/docs/fleet-api") - .await - .unwrap(); - - let html = response.text().await.unwrap(); - - std::fs::write(path, &html).unwrap(); - - html -} - -struct FleetApiSpec { - calls: HashMap, -} - -// e.g. serialize to similar: vehicle-endpoints -#[derive(Debug, strum::EnumString)] -#[strum(serialize_all = "kebab-case")] -enum Category { - ChargingEndpoints, - PartnerEndpoints, - UserEndpoints, - VehicleCommands, - VehicleEndpoints, -} - -/* -Profile Information user_data Contact information, home address, profile picture, and referral information -Vehicle Information vehicle_device_data Vehicle live data, location, eligible upgrades, nearby superchargers, ownership, and service scheduling data -Vehicle Commands vehicle_cmds Commands like add/remove driver, access Live Camera, unlock, wake up, remote start, and schedule software updates -Vehicle Charging Management vehicle_charging_cmds Vehicle charging history, billed amount, charging location, commands to schedule, and start/stop charging -Energy Product Information energy_device_data Energy flow history, saving forecast, tariff rates, grid import, calendar, site status, time of use, and ownership -Energy Product Commands energy_cmds Commands like update storm mode - */ - -#[derive(Debug, strum::EnumString)] -#[strum(serialize_all = "snake_case")] -enum Scope { - /// Profile Information - /// - /// Contact information, home address, profile picture, and referral information. - UserData, - - /// Vehicle Information - /// - /// Vehicle live data, location, eligible upgrades, nearby superchargers, ownership, and service scheduling data. - VehicleDeviceData, - - /// Vehicle Commands - /// - /// Commands like add/remove driver, access Live Camera, unlock, wake up, remote start, and schedule software updates. - VehicleCmds, - - /// Vehicle Charging Management - /// - /// Vehicle charging history, billed amount, charging location, commands to schedule, and start/stop charging. - VehicleChargingCmds, - - /// Energy Product Information - /// - /// Energy flow history, saving forecast, tariff rates, grid import, calendar, site status, time of use, and ownership. - EnergyDeviceData, - - /// Energy Product Commands - /// - /// Commands like update storm mode. - EnergyCmds, -} - -/* -Name In Type Required Description -vin query string No VIN -startTime query string No StartTime -endTime query string No EndTime - */ - -enum InRequestData { - Query, - Body, -} - -struct Parameter { - name: String, - request: InRequestData, - var_type: String, - required: bool, - description: String, -} - -struct Call { - name: String, - method: reqwest::Method, - url_definition: String, - description: String, - category: Category, - scopes: Vec, - parameters: Vec, - request_example: String, - response_example: String, -} - -/* -Example HTML docs for two calls: - - -

Vehicle Commands

actuate_trunk

-

POST /api/1/vehicles/{id}/command/actuate_trunk

- -

scopes: vehicle_cmds

-
curl --header 'Content-Type: application/json' \
-  --header "Authorization: Bearer $TESLA_API_TOKEN" \
-  --data '{"which_trunk":"string"}' \
-  'https://fleet-api.prd.na.vn.cloud.tesla.com/api/1/vehicles/{id}/command/actuate_trunk'
-
const myHeaders = new Headers();
-myHeaders.append("Content-Type", "application/json");
-myHeaders.append("Authorization", `Bearer ${process.env.TESLA_API_TOKEN}`);
-
-const body = JSON.stringify({
-   "which_trunk": "string"
-});
-
-const requestOptions = {
-   method: 'POST',
-   headers: myHeaders,
-   body,
-   redirect: 'follow'
-};
-
-fetch("https://fleet-api.prd.na.vn.cloud.tesla.com/api/1/vehicles/{id}/command/actuate_trunk", requestOptions)
-   .then(response => response.json())
-   .then(result => console.log(result))
-   .catch(error => console.log('error', error));
-
require "uri"
-require "json"
-require "net/http"
-
-url = URI("https://fleet-api.prd.na.vn.cloud.tesla.com/api/1/vehicles/{id}/command/actuate_trunk")
-
-https = Net::HTTP.new(url.host, url.port)
-https.use_ssl = true
-
-request = Net::HTTP::Post.new(url)
-request["Content-Type"] = "application/json"
-request["Authorization"] = "Bearer ENV_TESLA_API_TOKEN"
-request.body = JSON.dump({
-   "which_trunk": "string"
-})
-
-response = https.request(request)
-puts response.read_body
-
-
import os
-import http.client
-import json
-
-conn = http.client.HTTPSConnection("fleet-api.prd.na.vn.cloud.tesla.com")
-payload = json.dumps({
-   "which_trunk": "string"
-})
-headers = {
-   'Content-Type': 'application/json',
-   'Authorization': 'Bearer ENV_TESLA_API_TOKEN'
-}
-conn.request("POST", "/api/1/vehicles/{id}/command/actuate_trunk", payload, headers)
-res = conn.getresponse()
-data = res.read()
-print(data.decode("utf-8"))
-
-

Controls the front (which_trunk: "front") or rear (which_trunk: "rear") trunk.

-

Parameters

- - - - - - - - - - - - - - - - - - - - - - - -
NameInTypeRequiredDescription
idpathintegerYesvehicle id
which_trunkbodystringYes
-
Click to view successful response{ - "result": true, - "reason": "" -} -
- -

adjust_volume

-

POST /api/1/vehicles/{id}/command/adjust_volume

- -

scopes: vehicle_cmds

-
curl --header 'Content-Type: application/json' \
-  --header "Authorization: Bearer $TESLA_API_TOKEN" \
-  --data '{"volume":"integer"}' \
-  'https://fleet-api.prd.na.vn.cloud.tesla.com/api/1/vehicles/{id}/command/adjust_volume'
-
const myHeaders = new Headers();
-myHeaders.append("Content-Type", "application/json");
-myHeaders.append("Authorization", `Bearer ${process.env.TESLA_API_TOKEN}`);
-
-const body = JSON.stringify({
-   "volume": "integer"
-});
-
-const requestOptions = {
-   method: 'POST',
-   headers: myHeaders,
-   body,
-   redirect: 'follow'
-};
-
-fetch("https://fleet-api.prd.na.vn.cloud.tesla.com/api/1/vehicles/{id}/command/adjust_volume", requestOptions)
-   .then(response => response.json())
-   .then(result => console.log(result))
-   .catch(error => console.log('error', error));
-
require "uri"
-require "json"
-require "net/http"
-
-url = URI("https://fleet-api.prd.na.vn.cloud.tesla.com/api/1/vehicles/{id}/command/adjust_volume")
-
-https = Net::HTTP.new(url.host, url.port)
-https.use_ssl = true
-
-request = Net::HTTP::Post.new(url)
-request["Content-Type"] = "application/json"
-request["Authorization"] = "Bearer ENV_TESLA_API_TOKEN"
-request.body = JSON.dump({
-   "volume": "integer"
-})
-
-response = https.request(request)
-puts response.read_body
-
-
import os
-import http.client
-import json
-
-conn = http.client.HTTPSConnection("fleet-api.prd.na.vn.cloud.tesla.com")
-payload = json.dumps({
-   "volume": "integer"
-})
-headers = {
-   'Content-Type': 'application/json',
-   'Authorization': 'Bearer ENV_TESLA_API_TOKEN'
-}
-conn.request("POST", "/api/1/vehicles/{id}/command/adjust_volume", payload, headers)
-res = conn.getresponse()
-data = res.read()
-print(data.decode("utf-8"))
-
-

Adjusts vehicle media playback volume.

-

Parameters

- - - - - - - - - - - - - - - - - - - - - - - -
NameInTypeRequiredDescription
idpathintegerYesvehicle id
volumebodyintegerYes
-
Click to view successful response{ - "result": true, - "reason": "" -} -
- - */ - -fn parse(html: &str) -> FleetApiSpec { - let document = Html::parse_document(html); - let content_selector = selector(".content h1"); - let mut element = document.select(&content_selector).next().unwrap(); - let mut category = None; - - // Iterate over all the elements in the content section until we see a h1 or h2. - loop { - match element.value().name() { - "h1" => { - let category_name = element.value().id().unwrap(); - category = Category::from_str(&category_name).ok(); - } - "h2" => { - if category.is_some() { - let name = element.inner_html(); - println!("{category:?} {name:?}"); - // let call = parse_call(element); - } - } - _ => {} - } - - let Some(next_element) = element.next_sibling_element() else { - println!("exiting..."); - break; - }; - element = next_element; - } - - todo!() -} - -/// Return None if this is not an endpoint. -/// -/// Will panic if it looks like an endpoint and has trouble parsing. -fn parse_call(element: ElementRef) -> Option { - let name = element.value().id().unwrap(); - - //

POST /api/1/vehicles/{id}/command/auto_conditioning_start

- // This section determines if this is an endpoint or not. - let (fragment, element) = next(element); - let url = fragment.select(&selector("code")).next()?.inner_html(); - if !url.starts_with("GET ") && !url.starts_with("POST ") { - return None; - } - - let (method, url) = url.split_once(' ').unwrap(); - println!("{} {}", method, url); - - //

scopes: vehicle_cmds

- let (fragment, element) = next(element); - let scopes = fragment - .select(&selector("em")) - .map(|e| e.inner_html()) - .map(|e| Scope::from_str(&e)) - .collect::>(); - - // 4
nodes containing example requests in different languages. - // TODO: Skip for now - let mut count = 0; - let mut element = element; - loop { - let (fragment, new_element) = next(element); - element = new_element; - if fragment - .select(&selector(r#"div[class="highlight"]"#)) - .next() - .is_none() - { - break; - } - - count += 1; - if count == 10 { - panic!("Too many examples"); - } - } - if count == 0 && name != "api-status" { - panic!("No examples for {}", name); - } - - None -} - -fn next(element: ElementRef) -> (Html, ElementRef) { - let element = element.next_sibling_element().unwrap(); - let html = Html::parse_fragment(&element.html()); - (html, element) -} - -fn selector(s: &str) -> Selector { - Selector::parse(s).unwrap() -} diff --git a/scrape_fleet_api/.gitignore b/tesla_api_coverage/.gitignore similarity index 100% rename from scrape_fleet_api/.gitignore rename to tesla_api_coverage/.gitignore diff --git a/scrape_fleet_api/Cargo.toml b/tesla_api_coverage/Cargo.toml similarity index 61% rename from scrape_fleet_api/Cargo.toml rename to tesla_api_coverage/Cargo.toml index 3ade292..62486a3 100644 --- a/scrape_fleet_api/Cargo.toml +++ b/tesla_api_coverage/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "scrape_fleet_api" +name = "tesla_api_coverage" version = "0.1.0" edition = "2021" @@ -7,6 +7,10 @@ edition = "2021" reqwest = "0.11.22" tokio = { version = "1.33.0", features = ["full"] } clap = { version = "4.4.6", features = ["derive"] } -tracing-subscriber = "0.3.17" scraper = "0.17.1" -strum = { version = "0.25.0", features = ["derive"] } \ No newline at end of file +strum = { version = "0.25.0", features = ["derive"] } +tracing-subscriber = "0.3.17" +tracing = "0.1.40" +log = "0.4.20" +nom = "7.1.3" +anyhow = "1.0.75" \ No newline at end of file diff --git a/tesla_api_coverage/README.md b/tesla_api_coverage/README.md new file mode 100644 index 0000000..101b2fb --- /dev/null +++ b/tesla_api_coverage/README.md @@ -0,0 +1,42 @@ +# API Coverage + +A tool designed to compare the API calls between `teslatte` and the publicly documented Tesla APIs. + +**Note:** This tool is bespoke to the build of `teslatte` and is not intended for publishing on crates.io. + +This project does (or will do) the following: + +* Scrape the teslatte project for what has been implemented. +* Scrape the Fleet API for its list of endpoints. +* Scrape the Command Mode SDK sources for its list of endpoints: https://github.com/teslamotors/vehicle-command/blob/main/cmd/tesla-control/commands.go +* Scrape timdorr/tesla-api's endpoints file: https://github.com/timdorr/tesla-api/blob/master/ownerapi_endpoints.json +* Combine the results into a single list of endpoints. + * Has a configuration on how to merge the endpoints, e.g. if an endpoint name is different, how to resolve it. +* Output a table of endpoints that are implemented or not, maybe in Markdown. + + +### Brainstorm + +Combined format idea: + +```json +{ + "honk_horn": { + + // If owner-api vs fleet-api methods are different, they should have different entries, + // otherwise call it "rest": + "rest": { + "method": "POST", + "endpoint": "/vehicles/{vehicle_id}/command/honk_horn" + }, + "vehicle-command": { + "endpoint": "honk" + } + + "timdorr-endpoints-file": true, + "teslatte": true, + "owners-api": true, + "fleet-api": true, + } +} +``` \ No newline at end of file diff --git a/scrape_fleet_api/fleet.html b/tesla_api_coverage/cached/fleet.html similarity index 99% rename from scrape_fleet_api/fleet.html rename to tesla_api_coverage/cached/fleet.html index 36fc986..2ce9f8d 100644 --- a/scrape_fleet_api/fleet.html +++ b/tesla_api_coverage/cached/fleet.html @@ -2248,9 +2248,7 @@ The response body is typically JSON-encoded with details in the "error" --header "Authorization: Bearer $TESLA_API_TOKEN" \ --data '{}' \ 'https://fleet-api.prd.na.vn.cloud.tesla.com/api/1/vehicles/{id}/command/auto_conditioning_start' -
- -
const myHeaders = new Headers();
+
const myHeaders = new Headers();
 myHeaders.append("Content-Type", "application/json");
 myHeaders.append("Authorization", `Bearer ${process.env.TESLA_API_TOKEN}`);
 
@@ -2267,9 +2265,7 @@ The response body is typically JSON-encoded with details in the "error"
    .then(response => response.json())
    .then(result => console.log(result))
    .catch(error => console.log('error', error));
-
- -
require "uri"
+
require "uri"
 require "json"
 require "net/http"
 
@@ -2301,7 +2297,6 @@ The response body is typically JSON-encoded with details in the "error"
 data = res.read()
 print(data.decode("utf-8"))
 
-

Starts climate preconditioning.

Parameters

diff --git a/tesla_api_coverage/cached/timdorr.json b/tesla_api_coverage/cached/timdorr.json new file mode 100644 index 0000000..f24ed7e --- /dev/null +++ b/tesla_api_coverage/cached/timdorr.json @@ -0,0 +1,2761 @@ +{ + "ADD_KEY": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/add_key", + "AUTH": true + }, + "STATUS": { + "TYPE": "GET", + "URI": "status", + "AUTH": false + }, + "PRODUCT_LIST": { + "TYPE": "GET", + "URI": "api/1/products", + "AUTH": true + }, + "VEHICLE_LIST": { + "TYPE": "GET", + "URI": "api/1/vehicles", + "AUTH": true + }, + "VEHICLE_ORDER_LIST": { + "TYPE": "GET", + "URI": "api/1/users/orders", + "AUTH": true + }, + "VEHICLE_SUMMARY": { + "TYPE": "GET", + "URI": "api/1/vehicles/{vehicle_id}", + "AUTH": true + }, + "VEHICLE_DATA": { + "TYPE": "GET", + "URI": "api/1/vehicles/{vehicle_id}/vehicle_data", + "AUTH": true + }, + "VEHICLE_SERVICE_DATA": { + "TYPE": "GET", + "URI": "api/1/vehicles/{vehicle_id}/service_data", + "AUTH": true + }, + "NEARBY_CHARGING_SITES": { + "TYPE": "GET", + "URI": "api/1/vehicles/{vehicle_id}/nearby_charging_sites", + "AUTH": true + }, + "WAKE_UP": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/wake_up", + "AUTH": true + }, + "UNLOCK": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/door_unlock", + "AUTH": true + }, + "LOCK": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/door_lock", + "AUTH": true + }, + "HONK_HORN": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/honk_horn", + "AUTH": true + }, + "FLASH_LIGHTS": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/flash_lights", + "AUTH": true + }, + "REMOTE_BOOMBOX": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/remote_boombox", + "AUTH": true + }, + "CLIMATE_ON": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/auto_conditioning_start", + "AUTH": true + }, + "CLIMATE_OFF": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/auto_conditioning_stop", + "AUTH": true + }, + "MAX_DEFROST": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/set_preconditioning_max", + "AUTH": true + }, + "CHANGE_CLIMATE_TEMPERATURE_SETTING": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/set_temps", + "AUTH": true + }, + "SET_CLIMATE_KEEPER_MODE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/set_climate_keeper_mode", + "AUTH": true + }, + "HVAC_BIOWEAPON_MODE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/set_bioweapon_mode", + "AUTH": true + }, + "SCHEDULED_DEPARTURE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/set_scheduled_departure", + "AUTH": true + }, + "SCHEDULED_CHARGING": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/set_scheduled_charging", + "AUTH": true + }, + "CHARGING_AMPS": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/set_charging_amps", + "AUTH": true + }, + "NAVIGATION_ROUTE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/get_active_route", + "AUTH": true + }, + "SET_CABIN_OVERHEAT_PROTECTION": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/set_cabin_overheat_protection", + "AUTH": true + }, + "CHANGE_CHARGE_LIMIT": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/set_charge_limit", + "AUTH": true + }, + "CHANGE_SUNROOF_STATE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/sun_roof_control", + "AUTH": true + }, + "WINDOW_CONTROL": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/window_control", + "AUTH": true + }, + "ACTUATE_TRUNK": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/actuate_trunk", + "AUTH": true + }, + "REMOTE_START": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/remote_start_drive", + "AUTH": true + }, + "TRIGGER_HOMELINK": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/trigger_homelink", + "AUTH": true + }, + "CHARGE_PORT_DOOR_OPEN": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/charge_port_door_open", + "AUTH": true + }, + "CHARGE_PORT_DOOR_CLOSE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/charge_port_door_close", + "AUTH": true + }, + "START_CHARGE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/charge_start", + "AUTH": true + }, + "STOP_CHARGE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/charge_stop", + "AUTH": true + }, + "SET_COP_TEMP": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/set_cop_temp", + "AUTH": true + }, + "MEDIA_TOGGLE_PLAYBACK": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/media_toggle_playback", + "AUTH": true + }, + "MEDIA_NEXT_TRACK": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/media_next_track", + "AUTH": true + }, + "MEDIA_PREVIOUS_TRACK": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/media_prev_track", + "AUTH": true + }, + "MEDIA_NEXT_FAVORITE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/media_next_fav", + "AUTH": true + }, + "MEDIA_PREVIOUS_FAVORITE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/media_prev_fav", + "AUTH": true + }, + "MEDIA_VOLUME_UP": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/media_volume_up", + "AUTH": true + }, + "MEDIA_VOLUME_DOWN": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/media_volume_down", + "AUTH": true + }, + "ADJUST_VOLUME": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/adjust_volume", + "AUTH": true + }, + "GET_MANAGED_CHARGING_SITES": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/get_managed_charging_sites", + "AUTH": true + }, + "ADD_MANAGED_CHARGING_SITE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/add_managed_charging_site", + "AUTH": true + }, + "REMOVE_MANAGED_CHARGING_SITE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/remove_managed_charging_site", + "AUTH": true + }, + "UPDATE_CHARGE_ON_SOLAR_FEATURE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/update_charge_on_solar_feature", + "AUTH": true + }, + "GET_CHARGE_ON_SOLAR_FEATURE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/get_charge_on_solar_feature", + "AUTH": true + }, + "SPLUNK_TELEMETRY": { + "TYPE": "POST", + "URI": "api/1/logs", + "AUTH": true + }, + "APP_FEEDBACK_ENTITLEMENTS": { + "TYPE": "GET", + "URI": "api/1/diagnostics", + "AUTH": true + }, + "APP_FEEDBACK_LOGS": { + "TYPE": "POST", + "URI": "api/1/reports", + "AUTH": true + }, + "APP_FEEDBACK_METADATA": { + "TYPE": "POST", + "URI": "api/1/diagnostics", + "AUTH": true + }, + "RETRIEVE_NOTIFICATION_PREFERENCES": { + "TYPE": "GET", + "URI": "api/1/notification_preferences", + "AUTH": true + }, + "SEND_NOTIFICATION_PREFERENCES": { + "TYPE": "POST", + "URI": "api/1/notification_preferences", + "AUTH": true + }, + "RETRIEVE_NOTIFICATION_SUBSCRIPTIONS": { + "TYPE": "GET", + "URI": "api/1/subscriptions", + "AUTH": true + }, + "SEND_NOTIFICATION_SUBSCRIPTIONS": { + "TYPE": "POST", + "URI": "api/1/subscriptions", + "AUTH": true + }, + "DEACTIVATE_DEVICE_TOKEN": { + "TYPE": "POST", + "URI": "api/1/device/{device_token}/deactivate", + "AUTH": true + }, + "CALENDAR_SYNC": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/upcoming_calendar_entries", + "AUTH": true + }, + "SET_VALET_MODE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/set_valet_mode", + "AUTH": true + }, + "RESET_VALET_PIN": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/reset_valet_pin", + "AUTH": true + }, + "SPEED_LIMIT_ACTIVATE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/speed_limit_activate", + "AUTH": true + }, + "SPEED_LIMIT_DEACTIVATE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/speed_limit_deactivate", + "AUTH": true + }, + "SPEED_LIMIT_SET_LIMIT": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/speed_limit_set_limit", + "AUTH": true + }, + "SPEED_LIMIT_CLEAR_PIN": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/speed_limit_clear_pin", + "AUTH": true + }, + "SCHEDULE_SOFTWARE_UPDATE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/schedule_software_update", + "AUTH": true + }, + "CANCEL_SOFTWARE_UPDATE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/cancel_software_update", + "AUTH": true + }, + "SET_SENTRY_MODE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/set_sentry_mode", + "AUTH": true + }, + "TAKE_DRIVENOTE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/take_drivenote", + "AUTH": true + }, + "POWERWALL_ORDER_SESSION_DATA": { + "TYPE": "GET", + "URI": "api/1/users/powerwall_order_entry_data", + "AUTH": true + }, + "POWERWALL_ORDER_PAGE": { + "TYPE": "GET", + "URI": "powerwall_order_page", + "AUTH": true, + "CONTENT": "HTML" + }, + "ONBOARDING_EXPERIENCE": { + "TYPE": "GET", + "URI": "api/1/users/onboarding_data", + "AUTH": true + }, + "ONBOARDING_EXPERIENCE_PAGE": { + "TYPE": "GET", + "URI": "onboarding_page", + "AUTH": true, + "CONTENT": "HTML" + }, + "GET_UPCOMING_SERVICE_VISIT_DATA": { + "TYPE": "GET", + "URI": "api/1/users/service_scheduling_data", + "AUTH": true + }, + "GET_OWNERSHIP_XP_CONFIG": { + "TYPE": "GET", + "URI": "api/1/users/app_config", + "AUTH": true + }, + "REFERRAL_DATA": { + "TYPE": "GET", + "URI": "api/1/users/referral_data", + "AUTH": true + }, + "REFERRAL_PAGE": { + "TYPE": "GET", + "URI": "referral_page", + "AUTH": true, + "CONTENT": "HTML" + }, + "ROADSIDE_ASSISTANCE_DATA": { + "TYPE": "GET", + "URI": "api/1/users/roadside_assistance_data", + "AUTH": true + }, + "ROADSIDE_ASSISTANCE_PAGE": { + "TYPE": "GET", + "URI": "roadside_assistance_page", + "AUTH": true, + "CONTENT": "HTML" + }, + "MESSAGE_CENTER_MESSAGE_COUNT": { + "TYPE": "GET", + "URI": "api/1/messages/count", + "AUTH": true + }, + "MESSAGE_CENTER_MESSAGE_LIST": { + "TYPE": "GET", + "URI": "api/1/messages", + "AUTH": true + }, + "MESSAGE_CENTER_MESSAGE": { + "TYPE": "GET", + "URI": "api/1/messages/{message_id}", + "AUTH": true + }, + "MESSAGE_CENTER_MESSAGE_ACTION_UPDATE": { + "TYPE": "POST", + "URI": "api/1/messages/{message_id}/actions", + "AUTH": true + }, + "SEND_DEVICE_KEY": { + "TYPE": "POST", + "URI": "api/1/users/keys", + "AUTH": true + }, + "SITE_DATA": { + "TYPE": "GET", + "URI": "api/1/energy_sites/{site_id}/live_status", + "AUTH": true + }, + "SITE_CONFIG": { + "TYPE": "GET", + "URI": "api/1/energy_sites/{site_id}/site_info", + "AUTH": true + }, + "SITE_ADDRESS": { + "TYPE": "POST", + "URI": "api/1/energy_sites/{site_id}/site_address", + "AUTH": true + }, + "RATE_TARIFFS": { + "TYPE": "GET", + "URI": "api/1/energy_sites/rate_tariffs", + "AUTH": true + }, + "SITE_TARIFF": { + "TYPE": "GET", + "URI": "api/1/energy_sites/{site_id}/tariff_rate", + "AUTH": true + }, + "CALENDAR_HISTORY_DATA": { + "TYPE": "GET", + "URI": "api/1/energy_sites/{site_id}/calendar_history", + "AUTH": true + }, + "SOLAR_SAVINGS_FORECAST": { + "TYPE": "GET", + "URI": "api/1/energy_sites/{site_id}/savings_forecast", + "AUTH": true + }, + "ENERGY_REGISTER_PRODUCT": { + "TYPE": "POST", + "URI": "api/1/users/register_product", + "AUTH": true + }, + "ENERGY_SITE_BACKUP_TIME_REMAINING": { + "TYPE": "GET", + "URI": "api/1/energy_sites/{site_id}/backup_time_remaining", + "AUTH": true + }, + "ENERGY_SITE_PROGRAMS": { + "TYPE": "GET", + "URI": "api/1/energy_sites/{site_id}/programs", + "AUTH": true + }, + "ENERGY_SITE_TELEMETRY_HISTORY": { + "TYPE": "GET", + "URI": "api/1/energy_sites/{site_id}/telemetry_history", + "AUTH": true + }, + "BACKUP_RESERVE": { + "TYPE": "POST", + "URI": "api/1/energy_sites/{site_id}/backup", + "AUTH": true + }, + "OFF_GRID_VEHICLE_CHARGING_RESERVE": { + "TYPE": "POST", + "URI": "api/1/energy_sites/{site_id}/off_grid_vehicle_charging_reserve", + "AUTH": true + }, + "SITE_NAME": { + "TYPE": "POST", + "URI": "api/1/energy_sites/{site_id}/site_name", + "AUTH": true + }, + "OPERATION_MODE": { + "TYPE": "POST", + "URI": "api/1/energy_sites/{site_id}/operation", + "AUTH": true + }, + "ENERGY_SITE_IMPORT_EXPORT_CONFIG": { + "TYPE": "POST", + "URI": "api/1/energy_sites/{site_id}/grid_import_export", + "AUTH": true + }, + "TIME_OF_USE_SETTINGS": { + "TYPE": "POST", + "URI": "api/1/energy_sites/{site_id}/time_of_use_settings", + "AUTH": true + }, + "STORM_MODE_SETTINGS": { + "TYPE": "POST", + "URI": "api/1/energy_sites/{site_id}/storm_mode", + "AUTH": true + }, + "ENERGY_SITE_USER_SETTINGS": { + "TYPE": "POST", + "URI": "api/1/energy_sites/{site_id}/user_settings", + "AUTH": true + }, + "ENERGY_SITE_COMMAND": { + "TYPE": "POST", + "URI": "api/1/energy_sites/{site_id}/command", + "AUTH": true + }, + "ENERGY_SITE_ENROLL_PROGRAM": { + "TYPE": "POST", + "URI": "api/1/energy_sites/{site_id}/program", + "AUTH": true + }, + "ENERGY_SITE_OPT_EVENT": { + "TYPE": "POST", + "URI": "api/1/energy_sites/{site_id}/event", + "AUTH": true + }, + "ENERGY_SITE_PREFERENCE": { + "TYPE": "POST", + "URI": "api/1/energy_sites/{site_id}/preference", + "AUTH": true + }, + "CHECK_ENERGY_PRODUCT_REGISTRATION": { + "TYPE": "GET", + "URI": "api/1/energy_sites/registered", + "AUTH": true + }, + "ENERGY_EVENT": { + "TYPE": "POST", + "URI": "api/1/energy_sites/energy_event", + "AUTH": true + }, + "VEHICLE_CHARGE_HISTORY": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/charge_history", + "AUTH": true + }, + "VEHICLE_ENERGY_SITES": { + "TYPE": "GET", + "URI": "api/1/vehicles/{vehicle_id}/energy_sites", + "AUTH": true + }, + "ENERGY_SITE_PROGRAM_DETAILS": { + "TYPE": "GET", + "URI": "api/1/energy_sites/{site_id}/program", + "AUTH": true + }, + "ENERGY_SITE_ONBOARDING_TIPS": { + "TYPE": "GET", + "URI": "api/1/energy_sites/{site_id}/onboarding", + "AUTH": true + }, + "ENERGY_WALL_CONNECTOR_FIRMWARE_DOWNLOAD_URL": { + "TYPE": "GET", + "URI": "api/1/wall_connectors/firmware", + "AUTH": true + }, + "SEND_NOTIFICATION_CONFIRMATION": { + "TYPE": "POST", + "URI": "api/1/notification_confirmations", + "AUTH": true + }, + "SEND_TO_VEHICLE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/share", + "AUTH": true + }, + "SEND_SC_TO_VEHICLE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/navigation_sc_request", + "AUTH": true + }, + "SEND_GPS_TO_VEHICLE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/navigation_gps_request", + "AUTH": true + }, + "REMOTE_SEAT_HEATER_REQUEST": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/remote_seat_heater_request", + "AUTH": true + }, + "REMOTE_AUTO_SEAT_CLIMATE_REQUEST": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/remote_auto_seat_climate_request", + "AUTH": true + }, + "REMOTE_SEAT_COOLING_REQUEST": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/remote_seat_cooler_request", + "AUTH": true + }, + "REMOTE_STEERING_WHEEL_HEATER_REQUEST": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/remote_steering_wheel_heater_request", + "AUTH": true + }, + "REMOTE_AUTO_STEERING_WHEEL_HEAT_CLIMATE_REQUEST": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/remote_auto_steering_wheel_heat_climate_request", + "AUTH": true + }, + "REMOTE_STEERING_WHEEL_HEAT_LEVEL_REQUEST": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/remote_steering_wheel_heat_level_request", + "AUTH": true + }, + "TRIGGER_VEHICLE_SCREENSHOT": { + "TYPE": "GET", + "URI": "api/1/vehicles/{vehicle_id}/screenshot", + "AUTH": true + }, + "HERMES_AUTHORIZATION": { + "TYPE": "POST", + "URI": "api/1/users/jwt/hermes", + "AUTH": true + }, + "HERMES_VEHICLE_AUTHORIZATION": { + "TYPE": "POST", + "URI": "api/1/vehicles/{id}/jwt/hermes", + "AUTH": true + }, + "RELEASE_NOTES": { + "TYPE": "GET", + "URI": "api/1/vehicles/{vehicle_id}/release_notes", + "AUTH": true + }, + "STATIC_SUPERCHARGER_FILE": { + "TYPE": "GET", + "URI": "static/superchargers/{file_path}", + "AUTH": true + }, + "STATIC_CHARGER_FILE": { + "TYPE": "GET", + "URI": "static/chargers/{file_path}", + "AUTH": true + }, + "PLACE_SUGGESTIONS": { + "TYPE": "POST", + "URI": "api/1/vehicles/place_suggestions", + "AUTH": true + }, + "DRIVING_PLAN": { + "TYPE": "POST", + "URI": "api/1/vehicles/driving_plan", + "AUTH": true + }, + "PLAN_TRIP": { + "TYPE": "POST", + "URI": "trip-planner/api/v1/tripplan", + "AUTH": true + }, + "REVERSE_GEOCODING": { + "TYPE": "GET", + "URI": "maps/reverse_geocoding/v3/", + "AUTH": true + }, + "USER": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/user", + "AUTH": true + }, + "OWNERSHIP_TRANSLATIONS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/static/protected/translations/{path}", + "AUTH": true + }, + "ROADSIDE_INCIDENTS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/roadside/incidents", + "AUTH": true + }, + "ROADSIDE_CREATE_INCIDENT": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/roadside/incidents", + "AUTH": true + }, + "ROADSIDE_CANCEL_INCIDENT": { + "TYPE": "PUT", + "URI": "bff/v2/mobile-app/roadside/incidents/{incidentsId}", + "AUTH": true + }, + "ROADSIDE_WARRANTY": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/roadside/warranty", + "AUTH": true + }, + "ROADSIDE_WARRANTY_QUALIFICATION": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/roadside/warranty/qualify", + "AUTH": true + }, + "ROADSIDE_LOCATIONS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/roadside/locations", + "AUTH": true + }, + "ROADSIDE_MOBILE_TIRE_SLOTS": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/roadside/tire/slots", + "AUTH": true + }, + "ROADSIDE_CREATE_MOBILE_TIRE_VISIT": { + "TYPE": "POST", + "URI": "mobile-app/roadside/visit", + "AUTH": true + }, + "ROADSIDE_UPDATE_MOBILE_TIRE_VISIT": { + "TYPE": "PATCH", + "URI": "mobile-app/roadside/visit/{serviceVisitID}", + "AUTH": true + }, + "ROADSIDE_STATIC_CONTENT": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/roadside/static-content", + "AUTH": true + }, + "ROADSIDE_COUNTRIES": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/roadside/countries", + "AUTH": true + }, + "SERVICE_GET_SERVICE_VISITS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/appointments", + "AUTH": true + }, + "SERVICE_GET_SERVICE_VISIT_AMOUNT_DUE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/payment/amount-due/{serviceVisitID}", + "AUTH": true + }, + "SERVICE_UPDATE_APPOINTMENT": { + "TYPE": "PUT", + "URI": "bff/v2/mobile-app/service/appointments/{serviceVisitId}", + "AUTH": true + }, + "SERVICE_CANCEL_APPOINTMENT": { + "TYPE": "PATCH", + "URI": "mobile-app/service/appointments/{serviceVisitId}", + "AUTH": true + }, + "SERVICE_CREATE_ACTIVITIES": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/service/activities/{serviceVisitId}", + "AUTH": true + }, + "SERVICE_UPDATE_ACTIVITIES": { + "TYPE": "PUT", + "URI": "bff/v2/mobile-app/service/activities/{serviceVisitId}", + "AUTH": true + }, + "SERVICE_DELETE_ACTIVITIES": { + "TYPE": "PATCH", + "URI": "bff/v2/mobile-app/service/activities/{serviceVisitId}", + "AUTH": true + }, + "SERVICE_IPOS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/ipos/{serviceVisitId}", + "AUTH": true + }, + "SERVICE_GET_SERVICE_APPOINTMENTS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/service-appointments", + "AUTH": true + }, + "SERVICE_CREATE_SERVICE_VISIT": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/service/appointments", + "AUTH": true + }, + "SERVICE_TRACKER_DETAILS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/tracker/{serviceVisitID}", + "AUTH": true + }, + "SERVICE_MOBILE_NEAREST_LOCATIONS": { + "TYPE": "GET", + "URI": "mobile-app/service/locations/mobile/nearest", + "AUTH": true + }, + "SERVICE_MOBILE_OPEN_SLOTS": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/service/locations/mobile/slots", + "AUTH": true + }, + "SERVICE_CENTER_OPEN_SLOTS": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/service/locations/center/slots", + "AUTH": true + }, + "SERVICE_NEAREST_LOCATIONS": { + "TYPE": "POST", + "URI": "bff/mobile-app/service/locations/nearest", + "AUTH": true + }, + "SERVICE_SLOTS_BY_TRTID": { + "TYPE": "POST", + "URI": "bff/mobile-app/service/locations/slots-by-trtid", + "AUTH": true + }, + "SERVICE_CENTER_FETCH_PREFERRED_CENTER": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/locations/preferred-service-center", + "AUTH": true + }, + "SERVICE_CENTER_UPDATE_PREFERRED_CENTER": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/service/locations/preferred-service-center", + "AUTH": true + }, + "SERVICE_SAVE_CENTER_APPOINTMENT": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/service/center", + "AUTH": true + }, + "SERVICE_CREATE_MOBILE_APPOINTMENT": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/service/mobile", + "AUTH": true + }, + "SERVICE_UPDATE_MOBILE_APPOINTMENT": { + "TYPE": "PATCH", + "URI": "bff/v2/mobile-app/service/mobile/{appointmentId}", + "AUTH": true + }, + "SERVICE_SWITCH_TO_CENTER_APPOINTMENT": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/service/mobile/{appointmentId}/convert-to-center", + "AUTH": true + }, + "SERVICE_SWITCH_TO_MOBILE_APPOINTMENT": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/service/center/{appointmentId}/convert-to-mobile", + "AUTH": true + }, + "SERVICE_MOBILE_APPOINTMENT_DETAILS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/mobile/{appointmentId}", + "AUTH": true + }, + "SERVICE_CENTER_APPOINTMENT_DETAILS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/center/{appointmentId}", + "AUTH": true + }, + "SERVICE_HISTORY": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/history", + "AUTH": true + }, + "SERVICE_SURVEY_ELIGIBILITY": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/surveys", + "AUTH": true + }, + "SERVICE_SURVEY_QUESTIONS": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/service/surveys", + "AUTH": true + }, + "SERVICE_SURVEY_ANSWER_QUESTIONS": { + "TYPE": "PUT", + "URI": "bff/v2/mobile-app/service/surveys", + "AUTH": true + }, + "SERVICE_LOCATIONS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/center/locations", + "AUTH": true + }, + "SERVICE_LOCATIONS_BY_TRT_ID": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/center/locations-by-trtid", + "AUTH": true + }, + "SERVICE_MOBILE_ISSUES": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/feature-flag/mobile-service-issues", + "AUTH": true + }, + "SERVICE_FEATURE_FLAG_SERVICE_TRACKER": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/feature-flag/mobile-app-service-tracker", + "AUTH": true + }, + "SERVICE_FEATURE_FLAG_ALLOW_FILE_UPLOAD": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/feature-flag/service-scheduling-allow-file-upload", + "AUTH": true + }, + "SERVICE_FEATURE_FLAG_MOBILE_SERVICE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/feature-flag/show-mobile-service", + "AUTH": true + }, + "SERVICE_FEATURE_FLAG_MACGYVER": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/feature-flag/tao-4109-use-macgyver-mobile-app", + "AUTH": true + }, + "SERVICE_FEATURE_FLAG_SCHEDULING_FALLBACK": { + "TYPE": "GET", + "URI": "mobile-app/feature-flag/TAO-13782-no-estimate-schedule-fallback", + "AUTH": true + }, + "SERVICE_UPLOAD_FILE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/files", + "AUTH": true + }, + "SERVICE_UPLOAD_FILE_STREAM": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/files/stream", + "AUTH": true + }, + "SERVICE_DELETE_UPLOADED_FILE": { + "TYPE": "PUT", + "URI": "bff/v2/mobile-app/files/{uuid}", + "AUTH": true + }, + "SERVICE_UPDATE_FILE_METADATA": { + "TYPE": "PATCH", + "URI": "bff/v2/mobile-app/files/{uuid}/metadata", + "AUTH": true + }, + "SERVICE_GET_FILE_LIST": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/files/metadata", + "AUTH": true + }, + "SERVICE_GET_FILE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/files/{uuid}", + "AUTH": true + }, + "SERVICE_GET_APPOINTMENT_INVOICES": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/tracker/{serviceVisitID}/invoices", + "AUTH": true + }, + "SERVICE_GET_ESTIMATE_APPROVAL_STATUS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/tracker/{serviceVisitID}/estimate-status", + "AUTH": true + }, + "SERVICE_GET_ESTIMATE_COST_DETAILS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/tracker/invoices/{invoiceId}", + "AUTH": true + }, + "SERVICE_APPROVE_ESTIMATE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/service/tracker/{serviceVisitID}/estimate-status", + "AUTH": true + }, + "SERVICE_APPROVE_DOC": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/service/tracker/{serviceVisitID}/doc-status", + "AUTH": true + }, + "SERVICE_GET_FINAL_INVOICE_AMOUNT_DUE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/tracker/{serviceVisitID}/amount-due", + "AUTH": true + }, + "SERVICE_MACGYVER_ALERTS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/macgyver/alerts", + "AUTH": true + }, + "SERVICE_MACGYVER_OUTSTANDING_WORK": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/macgyver/categories", + "AUTH": true + }, + "SERVICE_ACTIVITY_INFO": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/macgyver/activity-info/{serviceVisitID}", + "AUTH": true + }, + "SERVICE_MACGYVER_POST_CUSTOMER_ANSWERS": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/macgyver/customer-answers", + "AUTH": true + }, + "SERVICE_MACGYVER_DISMISS_CUSTOMER_ANSWERS": { + "TYPE": "PUT", + "URI": "bff/v2/mobile-app/macgyver/customer-answers", + "AUTH": true + }, + "SERVICE_MACGYVER_SERVICE_TYPE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/macgyver/service-type", + "AUTH": true + }, + "TESLA_ELECTRIC_VEHICLES": { + "TYPE": "GET", + "URI": "mobile-app/tesla-electric/vehicles", + "AUTH": true + }, + "TESLA_ELECTRIC_SCHEDULE": { + "TYPE": "GET", + "URI": "mobile-app/tesla-electric/unlimited-charging-schedule", + "AUTH": true + }, + "TESLA_ELECTRIC_PRICING_DETAILS": { + "TYPE": "GET", + "URI": "mobile-app/tesla-electric/pricing-details", + "AUTH": true + }, + "SERVICE_MACGYVER_DIAGNOSTIC": { + "TYPE": "POST", + "URI": "mobile-app/macgyver/diagnostic", + "AUTH": true + }, + "SERVICE_MACGYVER_DIAGNOSTIC_RESULT": { + "TYPE": "GET", + "URI": "mobile-app/macgyver/urgent-autodiag-result", + "AUTH": true + }, + "SERVICE_MACGYVER_CLASSIFY_COLLISION_IMAGES": { + "TYPE": "POST", + "URI": "mobile-app/macgyver/classify-collision-images", + "AUTH": true + }, + "SERVICE_ACCEPT_LOANER_AGREEMENT": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/service/loaner/{serviceVisitId}", + "AUTH": true + }, + "SERVICE_CREATE_OFFLINE_ORDER": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/service/payment/create-offline-order", + "AUTH": true + }, + "SERVICE_COMPLETE_OFFLINE_ORDER": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/service/payment/complete-offline-order", + "AUTH": true + }, + "SERVICE_EXTERNAL_COLLISION_CENTER_LIST": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/locations/external-collision-center-list", + "AUTH": true + }, + "SERVICE_FETCH_RECALLS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/campaign/recall-detail", + "AUTH": true + }, + "SERVICE_FETCH_ENTITY_CODE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/appointments/get-trt/{trtId}", + "AUTH": true + }, + "SERVICE_FETCH_VEHICLE_VOLUME_REMAINING": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/volume/remaining", + "AUTH": true + }, + "SERVICE_CREATE_INVOICE": { + "TYPE": "POST", + "URI": "mobile-app/service/estimate/{serviceVisitId}", + "AUTH": true + }, + "SERVICE_ESTIMATE_DETAILS": { + "TYPE": "GET", + "URI": "mobile-app/service/estimate/{serviceVisitID}", + "AUTH": true + }, + "SERVICE_RESCHEDULE_DISCLAIMER": { + "TYPE": "GET", + "URI": "mobile-app/service/reschedule-disclaimer", + "AUTH": true + }, + "SERVICE_GET_RANGE_ANALYSIS_STATIC_CONTENT": { + "TYPE": "GET", + "URI": "mobile-app/macgyver/range-static-content", + "AUTH": true + }, + "SERVICE_LOG": { + "TYPE": "POST", + "URI": "mobile-app/service/log/{issue-name}", + "AUTH": true + }, + "SERVICE_TCC_CREATE_CASE": { + "TYPE": "POST", + "URI": "bff/mobile-app/support/case", + "AUTH": true + }, + "SERVICE_ACTIVITY_PROGRESS": { + "TYPE": "GET", + "URI": "bff/mobile-app/service/activities/{serviceVisitID}/progress", + "AUTH": true + }, + "SERVICE_ACTIVITY_FINAL_SUMMARY": { + "TYPE": "GET", + "URI": "bff/mobile-app/service/activities/{serviceVisitID}/final-summary", + "AUTH": true + }, + "SERVICE_BILLING_ADDRESS": { + "TYPE": "GET", + "URI": "bff/mobile-app/service/billing-address", + "AUTH": true + }, + "SERVICE_VISIT_BILLING_ADDRESS": { + "TYPE": "GET", + "URI": "bff/mobile-app/service/billing-address/service-visit/{serviceVisitID}", + "AUTH": true + }, + "SERVICE_UPDATE_BILLING_ADDRESS": { + "TYPE": "POST", + "URI": "mobile-app/service/billing-address", + "AUTH": true + }, + "SERVICE_VISIT_UPDATE_BILLING_ADDRESS": { + "TYPE": "POST", + "URI": "bff/mobile-app/service/billing-address/service-visit/{serviceVisitID}", + "AUTH": true + }, + "SERVICE_STEPS": { + "TYPE": "GET", + "URI": "bff/mobile-app/service/steps/{serviceVisitID}", + "AUTH": true + }, + "SERVICE_SAVE_LOCATION": { + "TYPE": "POST", + "URI": "mobile-app/service/appointments/{serviceVisitID}/save-address", + "AUTH": true + }, + "ENERGY_OWNERSHIP_GET_TOGGLES": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/energy/feature-flags", + "AUTH": true + }, + "ENERGY_OWNERSHIP_GET_BILLING_DETAILS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/energy/billing-information", + "AUTH": true + }, + "ENERGY_SERVICE_UPLOAD_FILE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/energy/files", + "AUTH": true + }, + "ENERGY_SITE_PROGRAM_CREATE_OR_EDIT_BILLING_ADDRESS": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/energy-site-program/billing-address", + "AUTH": true + }, + "ENERGY_SITE_PROGRAM_GET_BILLING_ADDRESS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/energy-site-program/billing-address", + "AUTH": true + }, + "ENERGY_SITE_PROGRAM_GET_BALANCE_DETAILS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/energy-site-program/balance", + "AUTH": true + }, + "ENERGY_SITE_PROGRAM_GET_STATEMENTS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/energy-site-program/statements", + "AUTH": true + }, + "ENERGY_SITE_PROGRAM_GET_STATEMENT": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/energy-site-program/statements/{statementId}", + "AUTH": true + }, + "ENERGY_SITE_PROGRAM_GET_PAYMENT_HISTORY": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/energy-site-program/payments", + "AUTH": true + }, + "ENERGY_SITE_PROGRAM_INITIATE_PAYMENT": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/energy-site-program/payments/initiate", + "AUTH": true + }, + "ENERGY_SITE_PROGRAM_COMPLETE_PAYMENT": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/energy-site-program/payments/complete", + "AUTH": true + }, + "ENERGY_SERVICE_GET_SITE_INFORMATION": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/energy-support/site-information", + "AUTH": true + }, + "ENERGY_SERVICE_GET_INSTALLER_INFORMATION": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/energy-support/installer-information", + "AUTH": true + }, + "ENERGY_SERVICE_GET_SUPPORT_CASES": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/energy-support/support-cases", + "AUTH": true + }, + "ENERGY_SERVICE_POST_GRID_SERVICE_CASE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/energy-support/appointments", + "AUTH": true + }, + "ENERGY_SERVICE_POST_SUPPORT_CASE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/energy-support/support-cases", + "AUTH": true + }, + "ENERGY_SERVICE_GET_APPOINTMENT_SUGGESTIONS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/energy-support/appointment-suggestions", + "AUTH": true + }, + "ENERGY_SERVICE_CANCEL_GRID_SERVICE_CASE": { + "TYPE": "PUT", + "URI": "bff/v2/mobile-app/energy-support/service-case", + "AUTH": true + }, + "ENERGY_SERVICE_CANCEL_SUPPORT_CASE": { + "TYPE": "PUT", + "URI": "bff/v2/mobile-app/energy-support/support-cases", + "AUTH": true + }, + "ENERGY_SERVICE_CANCEL_APPOINTMENT": { + "TYPE": "PUT", + "URI": "bff/v2/mobile-app/energy-support/appointments", + "AUTH": true + }, + "ENERGY_SERVICE_CONFIRM_APPOINTMENT": { + "TYPE": "PUT", + "URI": "bff/v2/mobile-app/energy-support/confirm-appointment", + "AUTH": true + }, + "ENERGY_DOCUMENTS_GET_DOCUMENTS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/energy-documents/documents", + "AUTH": true + }, + "ENERGY_DOCUMENTS_DOWNLOAD_DOCUMENT": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/energy-documents/documents/{documentId}", + "AUTH": true + }, + "ENERGY_GET_TROUBLESHOOTING_GUIDE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/energy-support/troubleshooting/{troubleshootingFlow}?version=3", + "AUTH": true + }, + "ENERGY_SERVICE_GET_POWERWALL_WARRANTY_DETAILS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/energy-support/warranty-details", + "AUTH": true + }, + "ENERGY_SERVICE_GET_CHAT_AVAILABILITY": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/energy-support/chat-availability", + "AUTH": true + }, + "ENERGY_SERVICE_GET_POWERWALL_REBATE_DETAILS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/energy-support/powerwall-rebate", + "AUTH": true + }, + "ENERGY_SERVICE_POST_POWERWALL_REBATE_DETAILS": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/energy-support/powerwall-rebate", + "AUTH": true + }, + "LOOTBOX_USER_INFO": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/referrals", + "AUTH": true + }, + "LOOTBOX_GET_ONBOARDING_COPY": { + "TYPE": "GET", + "URI": "mobile-app/referrals/getOnboardingConfigurations", + "AUTH": true + }, + "LOOTBOX_GET_TERMS": { + "TYPE": "GET", + "URI": "mobile-app/referrals/terms", + "AUTH": true + }, + "LOOTBOX_PAST_REFERRAL_DATA": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/referrals/past-referrals", + "AUTH": true + }, + "LOOTBOX_GET_VOTE_HISTORY": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/referrals/vote/history", + "AUTH": true + }, + "LOOTBOX_SUBMIT_VOTES": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/referrals/vote/record", + "AUTH": true + }, + "LOOTBOX_GET_FILE_LIST_BY_METADATA": { + "TYPE": "GET", + "URI": "mobile-app/files/lootbox/files-by-metadata", + "AUTH": true + }, + "LOOTBOX_UPLOAD_FILE": { + "TYPE": "POST", + "URI": "mobile-app/files/lootbox", + "AUTH": true + }, + "LOOTBOX_GET_FILE": { + "TYPE": "GET", + "URI": "mobile-app/files/lootbox/{uuid}", + "AUTH": true + }, + "GET_FILE_LIST_BY_METADATA": { + "TYPE": "GET", + "URI": "bff/mobile-app/files/product-files/files-by-metadata", + "AUTH": true + }, + "REFERRAL_GET_USER_INFO": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/referrals/user-info", + "AUTH": true + }, + "REFERRAL_GET_REFERRAL_SUMMARY": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/referrals/referral-summary", + "AUTH": true + }, + "REFERRAL_GET_PRODUCT_INFO": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/referrals/product-info", + "AUTH": true + }, + "REFERRAL_GET_PRODUCT_DATA": { + "TYPE": "GET", + "URI": "mobile-app/referrals/product-data", + "AUTH": true + }, + "REFERRAL_GET_CONTACT_LIST": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/referrals/contact-list", + "AUTH": true + }, + "REFERRAL_POST_CONTACT_LIST": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/referrals/contact-list", + "AUTH": true + }, + "REFERRAL_GET_CREDIT_HISTORY": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/referrals/credit-history", + "AUTH": true + }, + "REFERRAL_GET_PAST_HISTORY": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/referrals/past-referral-history", + "AUTH": true + }, + "REFERRAL_GET_PAST_HISTORY_COUNT": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/referrals/past-referral-history/count", + "AUTH": true + }, + "REFERRAL_GET_FEATURE_FLAG": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/feature-flag/tao-69420-treasure", + "AUTH": true + }, + "REFERRAL_GET_TERMS_AND_CONDITIONS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/referrals/terms-conditions", + "AUTH": true + }, + "UPGRADES_GET_ELIGIBLE_UPGRADES": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/upgrades/eligible/v2", + "AUTH": true + }, + "UPGRADES_GET_PURCHASED_UPGRADES_V2": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/upgrades/purchased/v2", + "AUTH": true + }, + "UPGRADES_SUBMIT_REFUND": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/upgrades/refunds/v2", + "AUTH": true + }, + "UPGRADES_V3_CONFIG": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/upgrades/v3/config", + "AUTH": true + }, + "UPGRADES_V3_ELIGIBLE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/upgrades/v3/eligible", + "AUTH": true + }, + "UPGRADES_V3_CART": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/upgrades/v3/cart", + "AUTH": true + }, + "UPGRADES_V3_PAYMENT_CREATE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/upgrades/v3/payment/create", + "AUTH": true + }, + "UPGRADES_V3_PAYMENT_COMPLETE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/upgrades/v3/payment/complete", + "AUTH": true + }, + "USER_ACCOUNT_GET_DETAILS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/account/details", + "AUTH": true + }, + "USER_ACCOUNT_PUT_DETAILS": { + "TYPE": "PUT", + "URI": "bff/v2/mobile-app/account/details", + "AUTH": true + }, + "USER_ACCOUNT_UPLOAD_PROFILE_PICTURE": { + "TYPE": "POST", + "URI": "images/upload", + "AUTH": true + }, + "USER_ACCOUNT_DOWNLOAD_PROFILE_PICTURE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/account/profile-pic", + "AUTH": true + }, + "USER_ACCOUNT_FETCH_LICENSE_PLATES": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/account/license-plate", + "AUTH": true + }, + "USER_ACCOUNT_UPDATE_LICENSE_PLATE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/account/license-plate", + "AUTH": true + }, + "USER_ACCOUNT_DELETE_LICENSE_PLATE": { + "TYPE": "PATCH", + "URI": "bff/v2/mobile-app/account/license-plate", + "AUTH": true + }, + "UPGRADES_CREATE_OFFLINE_ORDER": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/upgrades/payment/offline-order", + "AUTH": true + }, + "UPGRADES_COMPLETE_OFFLINE_ORDER": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/upgrades/payment/offline-purchase-complete/v2", + "AUTH": true + }, + "SUBSCRIPTIONS_GET_ELIGIBLE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/subscriptions", + "AUTH": true + }, + "SUBSCRIPTIONS_GET_PURCHASED_SUBSCRIPTIONS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/subscriptions/purchased/v2", + "AUTH": true + }, + "SUBSCRIPTIONS_CREATE_OFFLINE_ORDER": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/subscriptions/offline-order", + "AUTH": true + }, + "SUBSCRIPTIONS_POST_CREATE_OFFLINE_ORDER": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/subscriptions/offline-order", + "AUTH": true + }, + "SUBSCRIPTIONS_PURCHASE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/subscriptions", + "AUTH": true + }, + "MANAGE_GET_SUBSCRIPTION_INVOICES": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/subscriptions/invoices", + "AUTH": true + }, + "MANAGE_PATCH_AUTO_RENEW_SUBSCRIPTIONS": { + "TYPE": "PATCH", + "URI": "bff/v2/mobile-app/subscriptions/v2", + "AUTH": true + }, + "MANAGE_GET_BILL_ME_LATER_LIST": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/bill-me-later/pending-orders", + "AUTH": true + }, + "MANAGE_COMPLETE_BILL_ME_LATER_ORDER": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/bill-me-later/purchase-complete", + "AUTH": true + }, + "MANAGE_CANCEL_BILL_ME_LATER_ORDER": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/bill-me-later/cancel", + "AUTH": true + }, + "MANAGE_UPGRADE_BILL_ME_LATER_GET_OFFLINE_TOKEN": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/bill-me-later/token", + "AUTH": true + }, + "MANAGE_GET_BILL_ME_LATER_TOGGLE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/bill-me-later/security-toggle", + "AUTH": true + }, + "MANAGE_POST_BILL_ME_LATER_TOGGLE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/bill-me-later/security-toggle", + "AUTH": true + }, + "MANAGE_UPGRADES_GET_ITEMS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/manage-upgrades/v1/purchased/items", + "AUTH": true + }, + "MANAGE_UPGRADES_GET_UPGRADE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/manage-upgrades/v1/purchased/upgrade", + "AUTH": true + }, + "MANAGE_UPGRADES_GET_ESA": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/manage-upgrades/v1/purchased/esa", + "AUTH": true + }, + "MANAGE_UPGRADES_POST_REFUND": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/manage-upgrades/v1/refund/upgrade", + "AUTH": true + }, + "BILLING_ADDRESS_FORM_FEATURE_FLAG": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/billing-address/feature-flag/tao-8202-ownership-mobile-app-billing-address", + "AUTH": true + }, + "VIDEO_GUIDES_GET_VIDEO_LIST": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/video-guides", + "AUTH": true + }, + "PAYMENTS_GET_SIGNED_USER_TOKEN": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/payments/signed-user-token", + "AUTH": true + }, + "PAYMENTS_GET_SIGNED_USER_TOKEN_V4": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/payments/v4/signed-user-token", + "AUTH": true + }, + "PAYMENTS_POST_SIGNED_USER_TOKEN": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/payments/signed-user-token", + "AUTH": true + }, + "PAYMENTS_GET_INSTRUMENT": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/payments/instrument", + "AUTH": true + }, + "PAYMENTS_GET_BILLING_ADDRESS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/billing-address", + "AUTH": true + }, + "PAYMENTS_UPDATE_BILLING_ADDRESS": { + "TYPE": "PUT", + "URI": "bff/v2/mobile-app/billing-address", + "AUTH": true + }, + "PAYMENTS_FETCH_CN_ENTITY": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/payments/entity", + "AUTH": true + }, + "DOCUMENTS_DOWNLOAD_INVOICE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/documents/invoices/{invoiceId}", + "AUTH": true + }, + "DOCUMENTS_DOWNLOAD_INSPECTION": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/documents/inspection/{serviceVisitID}", + "AUTH": true + }, + "DOCUMENTS_DOWNLOAD_FAPIAO": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/documents/fapiao/{fapiaoId}", + "AUTH": true + }, + "SERVICE_MESSAGES": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/messages/{serviceVisitID}", + "AUTH": true + }, + "SERVICE_SEND_MESSAGE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/service/messages/{serviceVisitID}", + "AUTH": true + }, + "SERVICE_MESSAGES_MARK_READ": { + "TYPE": "PATCH", + "URI": "bff/v2/mobile-app/service/messages/{serviceVisitID}", + "AUTH": true + }, + "SERVICE_MESSAGES_USER_LIST": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/service/messages/users", + "AUTH": true + }, + "COMMERCE_EVENTS_CONTENTS": { + "TYPE": "GET", + "URI": "commerce-api/events/contents/v1", + "AUTH": true + }, + "COMMERCE_EVENTS_CONTENTS_POST": { + "TYPE": "POST", + "URI": "commerce-api/events/contents/v1", + "AUTH": true + }, + "COMMERCE_CATEGORIES": { + "TYPE": "GET", + "URI": "commerce-api/categories/v1{locale}", + "AUTH": true + }, + "COMMERCE_RECOMMENDATIONS_CATEGORIES": { + "TYPE": "POST", + "URI": "commerce-api/recommendations/categories/v1{locale}", + "AUTH": true + }, + "COMMERCE_CROSS_SELL_ASSOCIATIONS": { + "TYPE": "POST", + "URI": "commerce-api/recommendations/associations/v1", + "AUTH": true + }, + "COMMERCE_GET_ADDRESS": { + "TYPE": "GET", + "URI": "commerce-api/addresses/v1{locale}", + "AUTH": true + }, + "COMMERCE_ADDRESS": { + "TYPE": "POST", + "URI": "commerce-api/addresses/v1{locale}", + "AUTH": true + }, + "COMMERCE_CAPTURE": { + "TYPE": "POST", + "URI": "commerce-api/purchases/v1{locale}", + "AUTH": true + }, + "COMMERCE_PROCESSPAYMENT": { + "TYPE": "POST", + "URI": "commerce-api/purchases/{purchaseNumber}/processpayment/v1{locale}", + "AUTH": true + }, + "COMMERCE_CART_UPDATE": { + "TYPE": "PUT", + "URI": "commerce-api/carts/{cartId}/items/{lineitemId}/v1{locale}", + "AUTH": true + }, + "COMMERCE_CART_DELETE": { + "TYPE": "DELETE", + "URI": "commerce-api/carts/{cartId}/items/{lineitemId}/v1{locale}", + "AUTH": true + }, + "COMMERCE_ADD_CART": { + "TYPE": "POST", + "URI": "commerce-api/carts/items/v1{locale}", + "AUTH": true + }, + "COMMERCE_CLEAR_CART": { + "TYPE": "DELETE", + "URI": "commerce-api/carts/v1{locale}", + "AUTH": true + }, + "COMMERCE_GET_CART": { + "TYPE": "GET", + "URI": "commerce-api/carts/v1{locale}", + "AUTH": true + }, + "COMMERCE_BATCH_CART": { + "TYPE": "POST", + "URI": "commerce-api/batchcarts/v1{locale}", + "AUTH": true + }, + "COMMERCE_INVENTORY": { + "TYPE": "POST", + "URI": "commerce-api/inventory/v2{locale}", + "AUTH": true + }, + "COMMERCE_ITEM": { + "TYPE": "POST", + "URI": "commerce-api/items/v1{locale}", + "AUTH": true + }, + "COMMERCE_TOKEN": { + "TYPE": "POST", + "URI": "commerce-api/tokens/v1{locale}", + "AUTH": true + }, + "COMMERCE_ADDRESS_VALIDATION": { + "TYPE": "POST", + "URI": "commerce-api/addresses/validations/v1{locale}", + "AUTH": true + }, + "COMMERCE_GEOGRAPHIES": { + "TYPE": "GET", + "URI": "commerce-api/geographies/v1{locale}", + "AUTH": true + }, + "COMMERCE_GET_STORE_INFO": { + "TYPE": "GET", + "URI": "commerce-api/storeconfigurations/v1{locale}", + "AUTH": true + }, + "COMMERCE_GET_ITEMS_ELIGIBILITY": { + "TYPE": "POST", + "URI": "commerce-api/items/eligibility/v1{locale}", + "AUTH": true + }, + "COMMERCE_PURCHASE_HISTORY": { + "TYPE": "GET", + "URI": "commerce-api/purchases/v1{locale}", + "AUTH": true + }, + "COMMERCE_PURCHASE_BY_ORDERNUMBER": { + "TYPE": "GET", + "URI": "commerce-api/purchases/{orderNumber}/v1{locale}", + "AUTH": true + }, + "COMMERCE_GET_VEHICLES": { + "TYPE": "GET", + "URI": "commerce-api/vehicles/v1{locale}", + "AUTH": true + }, + "COMMERCE_POST_VEHICLES": { + "TYPE": "POST", + "URI": "commerce-api/vehicles/v1{locale}", + "AUTH": true + }, + "COMMERCE_GET_SERVICECENTERS": { + "TYPE": "GET", + "URI": "commerce-api/servicecenters/v1{locale}", + "AUTH": true + }, + "COMMERCE_POST_SERVICECENTERS": { + "TYPE": "POST", + "URI": "commerce-api/servicecenters/v1{locale}", + "AUTH": true + }, + "COMMERCE_POST_CANCELORDER": { + "TYPE": "POST", + "URI": "commerce-api/cancellation/v1{locale}", + "AUTH": true + }, + "COMMERCE_POST_RETURNORDER": { + "TYPE": "POST", + "URI": "commerce-api/returns/v1{locale}", + "AUTH": true + }, + "COMMERCE_GET_INSTALLERS": { + "TYPE": "GET", + "URI": "commerce-api/installers/v1{locale}", + "AUTH": true + }, + "COMMERCE_POST_INSTALLER_VENDOR": { + "TYPE": "POST", + "URI": "commerce-api/checkout/auditrecords/v1{locale}", + "AUTH": true + }, + "COMMERCE_CONTENT": { + "TYPE": "GET", + "URI": "commerce-api/content/v2?file={fileName}", + "AUTH": true + }, + "COMMERCE_CREATE_ENERGY_ORDER": { + "TYPE": "POST", + "URI": "commerce-api/energy/orders/v1{locale}", + "AUTH": true + }, + "COMMERCE_STOCK_NOTIFICATION": { + "TYPE": "POST", + "URI": "commerce-api/stocknotifications/v1{locale}", + "AUTH": true + }, + "COMMERCE_APPLY_COUPON_CODE": { + "TYPE": "POST", + "URI": "commerce-api/promotion/v1{locale}", + "AUTH": true + }, + "COMMERCE_REMOVE_COUPON_CODE": { + "TYPE": "DELETE", + "URI": "commerce-api/promotion/v1{locale}", + "AUTH": true + }, + "COMMERCE_VIN_ELIGIBILITY": { + "TYPE": "POST", + "URI": "commerce-api/eligibility/v1{locale}", + "AUTH": true + }, + "INSURANCE_CN_SUBMIT_CLAIMS": { + "TYPE": "POST", + "URI": "mobile-app/insurance-cn/report-claim", + "AUTH": true + }, + "MATTERMOST": { + "TYPE": "POST", + "URI": "Just a placeholder", + "AUTH": true + }, + "SAFETY_RATING_GET_ELIGIBLE_FOR_TELEMATICS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/insurance/eligible-for-telematics", + "AUTH": true + }, + "SAFETY_RATING_GET_DAILY_BREAKDOWN": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/insurance/daily-breakdown", + "AUTH": true + }, + "SAFETY_RATING_GET_TRIPS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/insurance/trips", + "AUTH": true + }, + "SAFETY_RATING_GET_ESTIMATED_SAFETY_SCORE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/insurance/calculate-safety-rating", + "AUTH": true + }, + "SEND_DOCUMENTS_EMAIL": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/insurance-cn/send-mail", + "AUTH": true + }, + "COMMERCE_POST_INVOICE": { + "TYPE": "POST", + "URI": "commerce-api/purchases/invoices/v1{locale}", + "AUTH": true + }, + "COMMERCE_POST_CHECKOUT_INVOICE": { + "TYPE": "POST", + "URI": "commerce-api/checkout/invoices/v1{locale}", + "AUTH": true + }, + "CHARGING_BALANCE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/charging/balance", + "AUTH": true + }, + "CHARGING_BALANCE_CREATE_OFFLINE_ORDER": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/charging/payment", + "AUTH": true + }, + "CHARGING_BALANCE_PAYMENT": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/charging/payment/complete", + "AUTH": true + }, + "CHARGING_BALANCE_ZERO_DOLLAR_TX": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/charging/signed-token", + "AUTH": true + }, + "CHARGING_BALANCE_GET_IS_BLOCKED": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/charging-cn/supercharger-status", + "AUTH": true + }, + "CHARGING_BALANCE_GET_CTA": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/charging-cn/supercharger-balance-cta", + "AUTH": true + }, + "CHARGING_HISTORY": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/charging/history", + "AUTH": true + }, + "CHARGING_HISTORY_VEHICLES": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/charging/vehicles", + "AUTH": true + }, + "CHARGING_HISTORY_VEHICLE_IMAGES": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/charging/vehicle-images", + "AUTH": true + }, + "DOWNLOAD_CHARGING_INVOICE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/charging/invoice/{uuid}", + "AUTH": true + }, + "DOWNLOAD_CHARGING_SUBSCRIPTION_INVOICE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/charging/subscription/invoice/{invoiceId}", + "AUTH": true + }, + "CHARGING_DOWNLOAD_CSV": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/charging/export", + "AUTH": true + }, + "CHARGING_GET_SITES_BOUNDING_BOX": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/charging/sites", + "AUTH": true + }, + "CHARGING_GET_SITE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/charging/site/{id}", + "AUTH": true + }, + "CHARGING_STOP_SESSION": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/charging/session/stop/{id}", + "AUTH": true + }, + "FINANCING_IS_ENABLED": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/is-captive", + "AUTH": true + }, + "FINANCING_FETCH_DETAILS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/details", + "AUTH": true + }, + "FINANCING_FETCH_DOCUMENT_LIST": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/document-list", + "AUTH": true + }, + "FINANCING_DOWNLOAD_DOCUMENT": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/document", + "AUTH": true + }, + "FINANCING_GET_SIGNED_TOKEN": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/signed-token", + "AUTH": true + }, + "FINANCING_GET_STATIC_ASSETS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/static-assets", + "AUTH": true + }, + "FINANCING_GET_AMORTIZATION": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/amortization-info-v2", + "AUTH": true + }, + "FINANCING_GET_AGREEMENT_DOCS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/agreement-docs", + "AUTH": true + }, + "FINANCING_BUYOUT_ELIGIBLE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/buyout-eligible", + "AUTH": true + }, + "FINANCING_BUYOUT_QUOTE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/buyout-quote", + "AUTH": true + }, + "FINANCING_BUYOUT_NEW_QUOTE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/financing/new-buyout-quote", + "AUTH": true + }, + "FINANCING_BUYOUT_ESIGN_STATUS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/buyout-esign-status", + "AUTH": true + }, + "FINANCING_BUYOUT_APPLY_ESIGN": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/financing/buyout-apply-esign", + "AUTH": true + }, + "FINANCING_GET_PAYMENT_PROFILE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/payment-profile", + "AUTH": true + }, + "FINANCING_GET_COMMERCIAL_SIGNED_TOKEN": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/commercial-signed-token", + "AUTH": true + }, + "FINANCING_GET_BILLING_ADDRESS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/billing-address", + "AUTH": true + }, + "FINANCING_GET_FINAL_PAYMENT_INFO": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/final-payment-info", + "AUTH": true + }, + "FINANCING_GET_WIRE_TRANSFER_INFO": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/wire-transfer-info", + "AUTH": true + }, + "FINANCING_UPDATE_BILLING_ADDRESS": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/financing/billing-address", + "AUTH": true + }, + "FINANCING_PAYMENT_SIGNED_TOKEN": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/financing/payment-signed-token", + "AUTH": true + }, + "FINANCING_UPDATE_PAYMENT_STATUS": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/financing/update-payment-status", + "AUTH": true + }, + "FINANCING_UPDATE_ENROLLMENT_SETTINGS": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/financing/update-enrollment-settings", + "AUTH": true + }, + "FINANCING_LOOKUP_WALLET": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/lookup-wallet", + "AUTH": true + }, + "FINANCING_GET_FEATURE_FLAGS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/feature-flags", + "AUTH": true + }, + "FINANCING_GET_E_SIGN_DOCUMENTS_STATUS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/documents-status", + "AUTH": true + }, + "FINANCING_SUBMIT_FINANCING_ACTION": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/financing/manage-financing-action", + "AUTH": true + }, + "FINANCING_GET_EXTENSION_QUOTE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/extension-quote", + "AUTH": true + }, + "FINANCING_GET_CAR_DETAILS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/car-details", + "AUTH": true + }, + "FINANCING_GET_E_SIGN_SUMMARY": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/esign-summary", + "AUTH": true + }, + "FINANCING_GET_E_SIGN_DOCUMENT": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/esign-document", + "AUTH": true + }, + "FINANCING_GET_ACQUISITION_FILE_LIST": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/acquisition/files", + "AUTH": true + }, + "FINANCING_GET_ACQUISITION_FILE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/acquisition/file", + "AUTH": true + }, + "FINANCING_UPLOAD_ACQUISITION_FILE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/financing/acquisition/file", + "AUTH": true + }, + "FINANCING_VALIDATE_E_SIGN_DETAILS": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/financing/esign-validate-details", + "AUTH": true + }, + "FINANCING_GET_ACQUISITION_DETAILS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/acquisition/details", + "AUTH": true + }, + "FINANCING_GET_APPOINTMENT_DETAILS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/appointment/details", + "AUTH": true + }, + "FINANCING_GET_APPOINTMENT_LOCATION": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/appointment/location", + "AUTH": true + }, + "FINANCING_GET_SETTLEMENT_QUOTE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/settlement-quote", + "AUTH": true + }, + "FINANCING_GENERATE_QUOTE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/quote", + "AUTH": true + }, + "FINANCING_GENERATE_BUYOUT_QUOTE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/buyout-quote", + "AUTH": true + }, + "FINANCING_GET_ODOMETER_INFO": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/odometer-info", + "AUTH": true + }, + "FINANCING_REMOVE_ACQUISITION_FILE": { + "TYPE": "PUT", + "URI": "bff/v2/mobile-app/financing/acquisition/file", + "AUTH": true + }, + "FINANCING_SUBMIT_ACQUISITION": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/financing/acquisition/submit", + "AUTH": true + }, + "FINANCING_STATUS_UPDATE_ACQUISITION": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/financing/acquisition/status-update", + "AUTH": true + }, + "FINANCING_SAVE_INSPECTION": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/financing/acquisition/save-inspection", + "AUTH": true + }, + "FINANCING_SAVE_INSPECTION_ELIGIBILITY": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/financing/acquisition/inspection-eligibility", + "AUTH": true + }, + "FINANCING_GET_ELIGIBLE_DELIVERY_LINKS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/eligible-delivery-links", + "AUTH": true + }, + "FINANCING_GET_ELIGIBLE_LEASE_LINKS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/eligible-lease-links", + "AUTH": true + }, + "FINANCING_GET_DELIVERY_LINK": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/delivery-link", + "AUTH": true + }, + "FINANCING_GET_NEW_MODEL_RATES": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/new-model-rates", + "AUTH": true + }, + "FINANCING_SAVE_DELIVERY_LINK_INTENT": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/financing/delivery-link-intent", + "AUTH": true + }, + "FINANCING_SUBMIT_APPOINTMENT": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/financing/appointment/save", + "AUTH": true + }, + "FINANCING_CANCEL_APPOINTMENT": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/financing/appointment/cancel", + "AUTH": true + }, + "FINANCING_GET_NEAREST_LOCATIONS": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/financing/appointment/nearest-locations", + "AUTH": true + }, + "FINANCING_GET_OPEN_SLOTS": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/financing/appointment/open-slots", + "AUTH": true + }, + "FINANCING_GET_OPTION_CODES": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/option-codes", + "AUTH": true + }, + "FINANCING_GET_TRANSLATIONS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/translations", + "AUTH": true + }, + "FINANCING_REQUEST_INSPECTION_APPOINTMENT": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/financing/appointment/inspection-request", + "AUTH": true + }, + "FINANCING_GET_REGISTRATION_ADDRESS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/registration-address", + "AUTH": true + }, + "FINANCING_GET_LOAN_PRINCIPAL_BALANCE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/financing/loan-principal-balance", + "AUTH": true + }, + "DASHCAM_SAVE_CLIP": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/command/dashcam_save_clip", + "AUTH": true + }, + "NON_OWNER_SUPPORTED_PRODUCTS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/user/supported-products", + "AUTH": true + }, + "FEATURE_CONFIG": { + "TYPE": "GET", + "URI": "api/1/users/feature_config", + "AUTH": true + }, + "SITE_LOCK_GET_SITES": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/charging-cn/get-locks", + "AUTH": true + }, + "SITE_LOCK_SEND_UNLOCK_REQUEST": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/charging-cn/open-lock", + "AUTH": true + }, + "SITE_LOCK_GET_STATUS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/charging-cn/get-lock-status", + "AUTH": true + }, + "FETCH_VEHICLE_SHARED_DRIVERS": { + "TYPE": "GET", + "URI": "api/1/vehicles/{vehicle_id}/drivers", + "AUTH": true + }, + "CREATE_VEHICLE_SHARE_INVITE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/invitations", + "AUTH": true + }, + "FETCH_VEHICLE_SHARE_INVITES": { + "TYPE": "GET", + "URI": "api/1/vehicles/{vehicle_id}/invitations", + "AUTH": true + }, + "REVOKE_VEHICLE_SHARE_INVITE": { + "TYPE": "POST", + "URI": "api/1/vehicles/{vehicle_id}/invitations/{invite_id}/revoke", + "AUTH": true + }, + "REMOVE_VEHICLE_SHARE_DRIVER": { + "TYPE": "DELETE", + "URI": "api/1/vehicles/{vehicle_id}/drivers/{share_user_id}", + "AUTH": true + }, + "REDEEM_VEHICLE_SHARE_INVITE": { + "TYPE": "POST", + "URI": "api/1/invitations/redeem", + "AUTH": true + }, + "FETCH_ENERGY_SITE_SHARED_USERS": { + "TYPE": "GET", + "URI": "api/1/energy_sites/{site_id}/users", + "AUTH": true + }, + "CREATE_ENERGY_SITE_SHARE_INVITE": { + "TYPE": "POST", + "URI": "api/1/energy_sites/{site_id}/invitations", + "AUTH": true + }, + "FETCH_ENERGY_SITE_SHARE_INVITES": { + "TYPE": "GET", + "URI": "api/1/energy_sites/{site_id}/invitations", + "AUTH": true + }, + "REVOKE_ENERGY_SITE_SHARE_INVITE": { + "TYPE": "POST", + "URI": "api/1/energy_sites/{site_id}/invitations/{invite_id}/revoke", + "AUTH": true + }, + "REMOVE_ENERGY_SITE_SHARE_USER": { + "TYPE": "DELETE", + "URI": "api/1/energy_sites/{site_id}/users/{user_id}", + "AUTH": true + }, + "REDEEM_ENERGY_SITE_SHARE_INVITE": { + "TYPE": "POST", + "URI": "api/1/invitations/redeem", + "AUTH": true + }, + "AUTH_GENERATE_INSTANT_LOGIN": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/auth/generate-instant-login", + "AUTH": true + }, + "GET_MANAGE_DRIVER_FLAG": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/feature-flag/TAO-14025-add-driver-flow", + "AUTH": true + }, + "CHARGING_FEATURE_FLAG_PDF_HISTORY_EXPORT": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/feature-flag/tao-22345-enable-charging-history-pdf-export", + "AUTH": true + }, + "CONTACT_US_CLASSIFICATION": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/contact-us/classify-narrative", + "AUTH": true + }, + "CONTACT_US_CONTENT_CATALOG": { + "TYPE": "GET", + "URI": "mobile-app/contact-us/content-catalog", + "AUTH": true + }, + "VEHICLE_PSEUDONYM_DIRECTIVES": { + "TYPE": "POST", + "URI": "api/1/directives/products", + "AUTH": true + }, + "VEHICLE_UPLOAD_PSEUDONYM_DIRECTIVE": { + "TYPE": "POST", + "URI": "api/1/directives/discover", + "AUTH": true + }, + "VEHICLE_COMPLETE_PSEUDONYM_DIRECTIVE": { + "TYPE": "POST", + "URI": "api/1/directives/products/complete", + "AUTH": true + }, + "OWNERSHIP_VEHICLE_SPECS_REQUEST": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/ownership/vehicle-details", + "AUTH": true + }, + "OWNERSHIP_RESERVATION_DETAILS_REQUEST": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/ownership/reservation-details/{rn}", + "AUTH": true + }, + "OWNERSHIP_WARRANTY_DETAILS_REQUEST": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/ownership/warranty-details", + "AUTH": true + }, + "COMMERCE_FEATURE_FLAG": { + "TYPE": "GET", + "URI": "mobile-app/commerce/feature-flags", + "AUTH": true + }, + "COMMERCE_SEARCH_PRODUCTS": { + "TYPE": "POST", + "URI": "commerce-api/searches/v1{locale}", + "AUTH": true + }, + "VEHICLE_DOWNLOAD_VAULT": { + "TYPE": "GET", + "URI": "api/1/users/vault_profile", + "AUTH": true + }, + "VEHICLE_UPLOAD_VAULT": { + "TYPE": "POST", + "URI": "api/1/users/vault_profile", + "AUTH": true + }, + "USER_RESET_VAULT": { + "TYPE": "DELETE", + "URI": "api/1/users/vault_profile", + "AUTH": true + }, + "USER_INFO": { + "TYPE": "GET", + "URI": "api/1/users/me", + "AUTH": true + }, + "OWNERSHIP_TRANSFER_TOOL_ASSETS_REQUEST": { + "TYPE": "GET", + "URI": "bff/mobile-app/transfer/assets", + "AUTH": true + }, + "OWNERSHIP_TRANSFER_TOOL_REMOVAL_ELIGIBILITY": { + "TYPE": "GET", + "URI": "bff/mobile-app/transfer/remove-car-eligibility-v2", + "AUTH": true + }, + "OWNERSHIP_TRANSFER_TOOL_ADD_INITIATE": { + "TYPE": "POST", + "URI": "bff/mobile-app/transfer/add-initiate", + "AUTH": true + }, + "OWNERSHIP_TRANSFER_TOOL_VALIDATE_CAR_NAME": { + "TYPE": "POST", + "URI": "bff/mobile-app/transfer/check-name", + "AUTH": true + }, + "OWNERSHIP_TRANSFER_TOOL_REMOVE_INITIATE": { + "TYPE": "POST", + "URI": "bff/mobile-app/transfer/remove-car", + "AUTH": true + }, + "OWNERSHIP_TRANSFER_TOOL_SECURITY_CODE": { + "TYPE": "POST", + "URI": "bff/mobile-app/transfer/security-code", + "AUTH": true + }, + "OWNERSHIP_TRANSFER_TOOL_UPLOAD_DOCUMENT": { + "TYPE": "POST", + "URI": "bff/mobile-app/transfer/upload-document", + "AUTH": true + }, + "OWNERSHIP_TRANSFER_TOOL_ADD_PROCESS": { + "TYPE": "POST", + "URI": "bff/mobile-app/transfer/add-process", + "AUTH": true + }, + "OWNERSHIP_TRANSFER_TOOL_USER_SIGNED_TOKEN": { + "TYPE": "GET", + "URI": "bff/mobile-app/transfer/user-signed-token", + "AUTH": true + }, + "OWNERSHIP_TRANSFER_TOOL_SIGNED_TOKEN": { + "TYPE": "POST", + "URI": "bff/mobile-app/transfer/signed-token", + "AUTH": true + }, + "OWNERSHIP_TRANSFER_VIEW_REQUEST": { + "TYPE": "GET", + "URI": "bff/mobile-app/transfer/view-transfer-request", + "AUTH": true + }, + "OWNERSHIP_TRANSFER_REQUEST_INITIATE": { + "TYPE": "POST", + "URI": "bff/mobile-app/transfer/transfer-request-initiate", + "AUTH": true + }, + "OWNERSHIP_TRANSFER_REQUEST_APPROVE": { + "TYPE": "POST", + "URI": "bff/mobile-app/transfer/transfer-request-approve", + "AUTH": true + }, + "OWNERSHIP_TRANSFER_REQUEST_REJECT": { + "TYPE": "POST", + "URI": "bff/mobile-app/transfer/transfer-request-reject", + "AUTH": true + }, + "SECURITY_AND_PRIVACY_ASSETS_REQUEST": { + "TYPE": "GET", + "URI": "bff/mobile-app/security-privacy/assets", + "AUTH": true + }, + "CONTACT_INFO_ASSETS_REQUEST": { + "TYPE": "GET", + "URI": "bff/mobile-app/account/contact-info-assets", + "AUTH": true + }, + "ESA_FETCH_ELIGIBLE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/esa/eligible", + "AUTH": true + }, + "ESA_CREATE_OFFLINE_ORDER": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/esa/payment/offline-order", + "AUTH": true + }, + "ESA_OFFLINE_ORDER_COMPLETE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/esa/payment/offline-purchase-complete", + "AUTH": true + }, + "ESA_FETCH_PURCHASED": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/esa/purchased", + "AUTH": true + }, + "ESA_DOWNLOAD_AGREEMENT": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/esa-documents/agreement", + "AUTH": true + }, + "ESA_V2_FETCH_ELIGIBLE": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/esa/v2/eligible", + "AUTH": true + }, + "ESA_V2_CREATE_OFFLINE_ORDER": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/esa/v2/payment/offline-order", + "AUTH": true + }, + "ESA_V2_OFFLINE_ORDER_COMPLETE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/esa/v2/payment/offline-purchase-complete", + "AUTH": true + }, + "ESA_V2_FETCH_PURCHASED": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/esa/v2/purchased", + "AUTH": true + }, + "ESA_V3_CONFIG": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/esa/v3/config", + "AUTH": true + }, + "ESA_V3_ELIGIBLE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/esa/v3/eligible", + "AUTH": true + }, + "ESA_V3_CART": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/esa/v3/cart", + "AUTH": true + }, + "ESA_V3_PAYMENT_CREATE": { + "TYPE": "POST", + "URI": "mobile-app/esa/v3/payment/create", + "AUTH": true + }, + "ESA_V3_PAYMENT_COMPLETE": { + "TYPE": "POST", + "URI": "mobile-app/esa/v3/payment/complete", + "AUTH": true + }, + "VEHICLE_DETAILS_ASSETS_REQUEST_V2": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/ownership/vehicle-details-assets/v2", + "AUTH": true + }, + "NOTIFICATIONS_GET_NEWS_AND_EVENTS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/notifications/news-and-events", + "AUTH": true + }, + "NOTIFICATIONS_UPDATE_NEWS_AND_EVENTS": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/notifications/news-and-events", + "AUTH": true + }, + "SPLASH_FEATURE_FLAG": { + "TYPE": "GET", + "URI": "bff/mobile-app/splash-feature-flag", + "AUTH": false + }, + "SPLASH_VIDEO": { + "TYPE": "GET", + "URI": "bff/mobile-app/splash-assets", + "AUTH": false + }, + "INBOX_UPLOAD_FILE": { + "TYPE": "POST", + "URI": "bff/mobile-app/files/product-files", + "AUTH": true + }, + "GET_PRODUCT_FILE": { + "TYPE": "GET", + "URI": "bff/mobile-app/files/product-files/{uuid}", + "AUTH": true + }, + "FAPIAO_FETCH_MENUS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/fapiao/menus", + "AUTH": true + }, + "FAPIAO_FETCH_ORDERS": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/fapiao/orders", + "AUTH": true + }, + "FAPIAO_POST_ORDERS": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/fapiao", + "AUTH": true + }, + "FAPIAO_FETCH_HISTORIES": { + "TYPE": "GET", + "URI": "mobile-app/fapiao/history", + "AUTH": true + }, + "FAPIAO_FETCH_DETAILS": { + "TYPE": "GET", + "URI": "mobile-app/fapiao/{id}/details", + "AUTH": true + }, + "OWNERSHIP_VERIFY_ID": { + "TYPE": "GET", + "URI": "mobile-app/financing/validate-identity-card", + "AUTH": true + }, + "INSURANCE_CN_GET_SELF_INSURANCE_INFO": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/insurance-cn/self-insurance/get-insurance", + "AUTH": true + }, + "INSURANCE_CN_GET_INSURANCE_STATUS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/insurance-cn/status", + "AUTH": true + }, + "INSURANCE_CN_DISMISS_EXPIRE_MESSAGE": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/insurance-cn/expiry-status-dismiss", + "AUTH": true + }, + "INSURANCE_CN_GET_INSURER_LIST": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/insurance-cn/insurers", + "AUTH": true + }, + "INSURANCE_CN_GET_CLAIMS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/insurance-cn/claims", + "AUTH": true + }, + "INSURANCE_CN_SAVE_SELF_INSURANCE_INFO": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/insurance-cn/self-insurance/save", + "AUTH": true + }, + "INSURANCE_CN_DELETE_SELF_INSURANCE_INFO": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/insurance-cn/self-insurance/delete", + "AUTH": true + }, + "INSURANCE_CN_GET_CLAIM_PHOTOS": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/insurance-cn/claim-photos", + "AUTH": true + }, + "INSURANCE_CN_SAVE_CLAIM_PHOTOS": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/insurance-cn/claim-photos", + "AUTH": true + }, + "INSURANCE_CN_GET_CLAIM_SERVICE_INFO": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/insurance-cn/claim-service-info", + "AUTH": true + }, + "INSURANCE_CN_SAVE_CLAIM_GET_PHOTO": { + "TYPE": "GET", + "URI": "bff/v2/mobile-app/insurance-cn/claim-photo/{uuid}", + "AUTH": true + }, + "INSURANCE_CN_SAVE_CLAIM_UPLOAD_PHOTO": { + "TYPE": "POST", + "URI": "bff/v2/mobile-app/insurance-cn/upload-claim-photo", + "AUTH": true + }, + "SERVICE_GET_TESLA_INSURANCE_OPEN_CLAIMS": { + "TYPE": "GET", + "URI": "mobile-app/service/insurance/claims", + "AUTH": true + }, + "GUEST_MODE_CARDS": { + "TYPE": "GET", + "URI": "mobile-app/guest/cards", + "AUTH": false + }, + "TEST_DRIVE_LIST": { + "TYPE": "GET", + "URI": "mobile-app/drive/appointments", + "AUTH": true + }, + "TEST_DRIVE_AGREEMENT": { + "TYPE": "GET", + "URI": "mobile-app/drive/waiver", + "AUTH": true + }, + "TEST_DRIVE_SUBMIT_FILES": { + "TYPE": "POST", + "URI": "mobile-app/drive/approve-agreement/{guid}", + "AUTH": true + }, + "TEST_DRIVE_UPLOAD_FILES": { + "TYPE": "POST", + "URI": "mobile-app/drive/files", + "AUTH": true + }, + "TEST_DRIVE_GET_SLOTS": { + "TYPE": "POST", + "URI": "mobile-app/drive/slots", + "AUTH": true + }, + "TEST_DRIVE_CANCEL_APPOINTMENT": { + "TYPE": "PUT", + "URI": "mobile-app/drive/appointments/{guid}", + "AUTH": true + }, + "TEST_DRIVE_UPDATE_APPOINTMENT": { + "TYPE": "PATCH", + "URI": "mobile-app/drive/appointments/{guid}", + "AUTH": true + }, + "TEST_DRIVE_GET_SUPPORT_MODELS": { + "TYPE": "GET", + "URI": "mobile-app/drive/models", + "AUTH": true + } +} diff --git a/tesla_api_coverage/cached/vehicle_command.go b/tesla_api_coverage/cached/vehicle_command.go new file mode 100644 index 0000000..25e2bb5 --- /dev/null +++ b/tesla_api_coverage/cached/vehicle_command.go @@ -0,0 +1,695 @@ +package main + +import ( + "context" + "errors" + "fmt" + "io" + "os" + "strconv" + "strings" + "time" + + "github.com/teslamotors/vehicle-command/pkg/account" + "github.com/teslamotors/vehicle-command/pkg/cli" + "github.com/teslamotors/vehicle-command/pkg/protocol" + "github.com/teslamotors/vehicle-command/pkg/protocol/protobuf/vcsec" + "github.com/teslamotors/vehicle-command/pkg/vehicle" +) + +var ErrCommandLineArgs = errors.New("invalid command line arguments") + +type Argument struct { + name string + help string +} + +type Handler func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error + +type Command struct { + help string + requiresAuth bool // True if command requires client-to-vehicle authentication (private key) + requiresFleetAPI bool // True if command requires client-to-server authentication (OAuth token) + args []Argument + optional []Argument + handler Handler +} + +// configureAndVerifyFlags verifies that c contains all the information required to execute a command. +func configureFlags(c *cli.Config, commandName string, forceBLE bool) error { + info, ok := commands[commandName] + if !ok { + return ErrUnknownCommand + } + c.Flags = cli.FlagBLE + if info.requiresAuth { + c.Flags |= cli.FlagPrivateKey | cli.FlagVIN + } + if !info.requiresFleetAPI { + c.Flags |= cli.FlagVIN + } + if forceBLE { + if info.requiresFleetAPI { + return ErrRequiresOAuth + } + } else { + c.Flags |= cli.FlagOAuth + } + + // Verify all required parameters are present. + havePrivateKey := !(c.KeyringKeyName == "" && c.KeyFilename == "") + haveOAuth := !(c.KeyringTokenName == "" && c.TokenFilename == "") + haveVIN := c.VIN != "" + _, err := checkReadiness(commandName, havePrivateKey, haveOAuth, haveVIN) + return err +} + +var ( + ErrRequiresOAuth = errors.New("command requires a FleetAPI OAuth token") + ErrRequiresVIN = errors.New("command requires a VIN") + ErrRequiresPrivateKey = errors.New("command requires a private key") + ErrUnknownCommand = errors.New("unrecognized command") +) + +func checkReadiness(commandName string, havePrivateKey, haveOAuth, haveVIN bool) (*Command, error) { + info, ok := commands[commandName] + if !ok { + return nil, ErrUnknownCommand + } + if info.requiresFleetAPI { + if !haveOAuth { + return nil, ErrRequiresOAuth + } + } else { + // Currently, commands supported by this application either target the account (and + // therefore require FleetAPI credentials but not a VIN) or target a vehicle (and therefore + // require a VIN but not FleetAPI credentials). + if !haveVIN { + return nil, ErrRequiresVIN + } + } + if info.requiresAuth && !havePrivateKey { + return nil, ErrRequiresPrivateKey + } + return info, nil +} + +func execute(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args []string) error { + if len(args) == 0 { + return errors.New("missing COMMAND") + } + + info, err := checkReadiness(args[0], car != nil && car.PrivateKeyAvailable(), acct != nil, car != nil) + if err != nil { + return err + } + + if len(args)-1 < len(info.args) || len(args)-1 > len(info.args)+len(info.optional) { + writeErr("Invalid number of command line arguments: %d (%d required, %d optional).", len(args), len(info.args), len(info.optional)) + err = ErrCommandLineArgs + } else { + keywords := make(map[string]string) + for i, argInfo := range info.args { + keywords[argInfo.name] = args[i+1] + } + index := len(info.args) + 1 + for _, argInfo := range info.optional { + if index >= len(args) { + break + } + keywords[argInfo.name] = args[index] + index++ + } + err = info.handler(ctx, acct, car, keywords) + } + + // Print command-specific help + if errors.Is(err, ErrCommandLineArgs) { + info.Usage(args[0]) + } + return err +} + +func (c *Command) Usage(name string) { + fmt.Printf("Usage: %s", name) + maxLength := 0 + for _, arg := range c.args { + fmt.Printf(" %s", arg.name) + if len(arg.name) > maxLength { + maxLength = len(arg.name) + } + } + if len(c.optional) > 0 { + fmt.Printf(" [") + } + for _, arg := range c.optional { + fmt.Printf(" %s", arg.name) + if len(arg.name) > maxLength { + maxLength = len(arg.name) + } + } + if len(c.optional) > 0 { + fmt.Printf(" ]") + } + fmt.Printf("\n%s\n", c.help) + maxLength++ + for _, arg := range c.args { + fmt.Printf(" %s:%s%s\n", arg.name, strings.Repeat(" ", maxLength-len(arg.name)), arg.help) + } + for _, arg := range c.optional { + fmt.Printf(" %s:%s%s\n", arg.name, strings.Repeat(" ", maxLength-len(arg.name)), arg.help) + } +} + +var commands = map[string]*Command{ + "unlock": &Command{ + help: "Unlock vehicle", + requiresAuth: true, + requiresFleetAPI: false, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + return car.Unlock(ctx) + }, + }, + "lock": &Command{ + help: "Lock vehicle", + requiresAuth: true, + requiresFleetAPI: false, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + return car.Lock(ctx) + }, + }, + "drive": &Command{ + help: "Remote start vehicle", + requiresAuth: true, + requiresFleetAPI: false, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + return car.RemoteDrive(ctx) + }, + }, + "climate-on": &Command{ + help: "Turn on climate control", + requiresAuth: true, + requiresFleetAPI: false, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + return car.ClimateOn(ctx) + }, + }, + "climate-off": &Command{ + help: "Turn off climate control", + requiresAuth: true, + requiresFleetAPI: false, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + return car.ClimateOff(ctx) + }, + }, + "climate-set-temp": &Command{ + help: "Set temperature (Celsius)", + requiresAuth: true, + requiresFleetAPI: false, + args: []Argument{ + Argument{name: "TEMP", help: "Desired temperature (e.g., 70f or 21c; defaults to Celsius)"}, + }, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + var degrees float32 + var unit string + if _, err := fmt.Sscanf(args["TEMP"], "%f%s", °rees, &unit); err != nil { + return fmt.Errorf("failed to parse temperature: format as 22C or 72F") + } + if unit == "F" || unit == "f" { + degrees = (5.0 * degrees / 9.0) + 32.0 + } else if unit != "C" && unit != "c" { + return fmt.Errorf("temperature units must be C or F") + } + return car.ChangeClimateTemp(ctx, degrees, degrees) + }, + }, + "add-key": &Command{ + help: "Add PUBLIC_KEY to vehicle whitelist with ROLE and FORM_FACTOR", + requiresAuth: true, + requiresFleetAPI: false, + args: []Argument{ + Argument{name: "PUBLIC_KEY", help: "file containing public key (or corresponding private key)"}, + Argument{name: "ROLE", help: "One of: owner, driver"}, + Argument{name: "FORM_FACTOR", help: "One of: nfc_card, ios_device, android_device, cloud_key"}, + }, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + role := strings.ToUpper(args["ROLE"]) + if role != "OWNER" && role != "DRIVER" { + return fmt.Errorf("%w: invalid ROLE", ErrCommandLineArgs) + } + formFactor, ok := vcsec.KeyFormFactor_value["KEY_FORM_FACTOR_"+strings.ToUpper(args["FORM_FACTOR"])] + if !ok { + return fmt.Errorf("%w: unrecognized FORM_FACTOR", ErrCommandLineArgs) + } + publicKey, err := protocol.LoadPublicKey(args["PUBLIC_KEY"]) + if err != nil { + return fmt.Errorf("invalid public key: %s", err) + } + return car.AddKey(ctx, publicKey, role == "OWNER", vcsec.KeyFormFactor(formFactor)) + }, + }, + "add-key-request": &Command{ + help: "Requset NFC-card approval for a enrolling PUBLIC_KEY with ROLE and FORM_FACTOR", + requiresAuth: false, + requiresFleetAPI: false, + args: []Argument{ + Argument{name: "PUBLIC_KEY", help: "file containing public key (or corresponding private key)"}, + Argument{name: "ROLE", help: "One of: owner, driver"}, + Argument{name: "FORM_FACTOR", help: "One of: nfc_card, ios_device, android_device, cloud_key"}, + }, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + role := strings.ToUpper(args["ROLE"]) + if role != "OWNER" && role != "DRIVER" { + return fmt.Errorf("%w: invalid ROLE", ErrCommandLineArgs) + } + formFactor, ok := vcsec.KeyFormFactor_value["KEY_FORM_FACTOR_"+strings.ToUpper(args["FORM_FACTOR"])] + if !ok { + return fmt.Errorf("%w: unrecognized FORM_FACTOR", ErrCommandLineArgs) + } + publicKey, err := protocol.LoadPublicKey(args["PUBLIC_KEY"]) + if err != nil { + return fmt.Errorf("invalid public key: %s", err) + } + if err := car.SendAddKeyRequest(ctx, publicKey, role == "OWNER", vcsec.KeyFormFactor(formFactor)); err != nil { + return err + } + fmt.Printf("Sent add-key request to %s. Confirm by tapping NFC card on center console.\n", car.VIN()) + return nil + }, + }, + "remove-key": &Command{ + help: "Remove PUBLIC_KEY from vehicle whitelist", + requiresAuth: true, + requiresFleetAPI: false, + args: []Argument{ + Argument{name: "PUBLIC_KEY", help: "file containing public key (or corresponding private key)"}, + }, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + publicKey, err := protocol.LoadPublicKey(args["PUBLIC_KEY"]) + if err != nil { + return fmt.Errorf("invalid public key: %s", err) + } + return car.RemoveKey(ctx, publicKey) + }, + }, + "rename-key": &Command{ + help: "Change the human-readable metadata of PUBLIC_KEY to NAME, MODEL, KIND", + requiresAuth: false, + requiresFleetAPI: true, + args: []Argument{ + Argument{name: "PUBLIC_KEY", help: "file containing public key (or corresponding private key)"}, + Argument{name: "NAME", help: "New human-readable name for the public key (e.g., Dave's Phone)"}, + }, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + publicKey, err := protocol.LoadPublicKey(args["PUBLIC_KEY"]) + if err != nil { + return fmt.Errorf("invalid public key: %s", err) + } + return acct.UpdateKey(ctx, publicKey, args["NAME"]) + }, + }, + "get": &Command{ + help: "GET an owner API http ENDPOINT. Hostname will be taken from -config.", + requiresAuth: false, + requiresFleetAPI: true, + args: []Argument{ + Argument{name: "ENDPOINT", help: "Fleet API endpoint"}, + }, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + reply, err := acct.Get(ctx, args["ENDPOINT"]) + if err != nil { + return err + } + fmt.Println(string(reply)) + return nil + }, + }, + "post": &Command{ + help: "POST to ENDPOINT the contents of FILE. Hostname will be taken from -config.", + requiresAuth: false, + requiresFleetAPI: true, + args: []Argument{ + Argument{name: "ENDPOINT", help: "Fleet API endpoint"}, + }, + optional: []Argument{ + Argument{name: "FILE", help: "JSON file to POST"}, + }, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + var jsonBytes []byte + var err error + if filename, ok := args["FILE"]; ok { + jsonBytes, err = os.ReadFile(filename) + } else { + jsonBytes, err = io.ReadAll(os.Stdin) + } + if err != nil { + return err + } + reply, err := acct.Post(ctx, args["ENDPOINT"], jsonBytes) + // reply can be set where there's an error; typically a JSON blob providing details + if reply != nil { + fmt.Println(string(reply)) + } + if err != nil { + return err + } + return nil + }, + }, + "list-keys": &Command{ + help: "List public keys enrolled on vehicle", + requiresAuth: false, + requiresFleetAPI: false, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + summary, err := car.KeySummary(ctx) + if err != nil { + return err + } + slot := uint32(0) + var details *vcsec.WhitelistEntryInfo + for mask := summary.GetSlotMask(); mask > 0; mask >>= 1 { + if mask&1 == 1 { + details, err = car.KeyInfoBySlot(ctx, slot) + if err != nil { + writeErr("Error fetching slot %d: %s", slot, err) + if errors.Is(err, context.DeadlineExceeded) { + return err + } + } + if details != nil { + fmt.Printf("%02x\t%s\t%s\n", details.GetPublicKey().GetPublicKeyRaw(), details.GetKeyRole(), details.GetMetadataForKey().GetKeyFormFactor()) + } + } + slot++ + } + return nil + }, + }, + "honk": &Command{ + help: "Honk horn", + requiresAuth: true, + requiresFleetAPI: false, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + return car.HonkHorn(ctx) + }, + }, + "ping": &Command{ + help: "Ping vehicle", + requiresAuth: true, + requiresFleetAPI: false, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + return car.Ping(ctx) + }, + }, + "flash-lights": &Command{ + help: "Flash lights", + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + return car.FlashLights(ctx) + }, + }, + "charging-set-limit": &Command{ + help: "Set charge limit to PERCENT", + requiresAuth: true, + requiresFleetAPI: false, + args: []Argument{ + Argument{name: "PERCENT", help: "Charging limit"}, + }, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + limit, err := strconv.Atoi(args["PERCENT"]) + if err != nil { + return fmt.Errorf("error parsing PERCENT") + } + return car.ChangeChargeLimit(ctx, int32(limit)) + }, + }, + "charging-start": &Command{ + help: "Start charging", + requiresAuth: true, + requiresFleetAPI: false, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + return car.ChargeStart(ctx) + }, + }, + "charging-stop": &Command{ + help: "Stop charging", + requiresAuth: true, + requiresFleetAPI: false, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + return car.ChargeStop(ctx) + }, + }, + "media-set-volume": &Command{ + help: "Set volume", + requiresAuth: true, + requiresFleetAPI: false, + args: []Argument{ + Argument{name: "VOLUME", help: "Set volume (0.0-10.0"}, + }, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + volume, err := strconv.ParseFloat(args["VOLUME"], 32) + if err != nil { + return fmt.Errorf("failed to parse volume") + } + return car.SetVolume(ctx, float32(volume)) + }, + }, + "software-update-start": &Command{ + help: "Start software update after DELAY", + requiresAuth: true, + requiresFleetAPI: false, + args: []Argument{ + Argument{ + name: "DELAY", + help: "Time to wait before starting update. Examples: 2h, 10m.", + }, + }, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + delay, err := time.ParseDuration(args["DELAY"]) + if err != nil { + return fmt.Errorf("error parsing DELAY. Valid times are , where is a number (decimals are allowed) and is 's, 'm', or 'h'") + // ...or 'ns'/'ยตs' if that's your cup of tea. + } + return car.ScheduleSoftwareUpdate(ctx, delay) + }, + }, + "software-update-cancel": &Command{ + help: "Cancel a pending software update", + requiresAuth: true, + requiresFleetAPI: false, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + return car.CancelSoftwareUpdate(ctx) + }, + }, + "sentry-mode": &Command{ + help: "Set sentry mode to STATE ('on' or 'off')", + requiresAuth: true, + requiresFleetAPI: false, + args: []Argument{ + Argument{name: "STATE", help: "'on' or 'off'"}, + }, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + var state bool + switch args["STATE"] { + case "on": + state = true + case "off": + state = false + default: + return fmt.Errorf("sentry mode state must be 'on' or 'off'") + } + return car.SetSentryMode(ctx, state) + }, + }, + "wake": &Command{ + help: "Wake up vehicle", + requiresAuth: false, + requiresFleetAPI: false, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + return car.Wakeup(ctx) + }, + }, + "trunk-open": &Command{ + help: "Open vehicle trunk. Note that trunk-close only works on certain vehicle types.", + requiresAuth: true, + requiresFleetAPI: false, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + return car.OpenTrunk(ctx) + }, + }, + "trunk-move": &Command{ + help: "Toggle trunk open/closed. Closing is only available on certain vehicle types.", + requiresAuth: true, + requiresFleetAPI: false, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + return car.ActuateTrunk(ctx) + }, + }, + "trunk-close": &Command{ + help: "Closes vehicle trunk. Only available on certain vehicle types.", + requiresAuth: true, + requiresFleetAPI: false, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + return car.CloseTrunk(ctx) + }, + }, + "frunk-open": &Command{ + help: "Open vehicle frunk. Note that there's no frunk-close command!", + requiresAuth: true, + requiresFleetAPI: false, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + return car.OpenFrunk(ctx) + }, + }, + "charge-port-open": &Command{ + help: "Open charge port", + requiresAuth: true, + requiresFleetAPI: false, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + return car.OpenChargePort(ctx) + }, + }, + "charge-port-close": &Command{ + help: "Close charge port", + requiresAuth: true, + requiresFleetAPI: false, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + return car.CloseChargePort(ctx) + }, + }, + "autosecure-modelx": &Command{ + help: "Close falcon-wing doors and lock vehicle. Model X only.", + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + return car.AutoSecureVehicle(ctx) + }, + }, + "session-info": &Command{ + help: "Retrieve session info for PUBLIC_KEY from DOMAIN", + requiresAuth: true, + requiresFleetAPI: false, + args: []Argument{ + Argument{name: "PUBLIC_KEY", help: "file containing public key (or corresponding private key)"}, + Argument{name: "DOMAIN", help: "'vcsec' or 'infotainment'"}, + }, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + // See SeatPosition definition for controlling backrest heaters (limited models). + domains := map[string]protocol.Domain{ + "vcsec": protocol.DomainVCSEC, + "infotainment": protocol.DomainInfotainment, + } + domain, ok := domains[args["DOMAIN"]] + if !ok { + return fmt.Errorf("invalid domain %s", args["DOMAIN"]) + } + publicKey, err := protocol.LoadPublicKey(args["PUBLIC_KEY"]) + if err != nil { + return fmt.Errorf("invalid public key: %s", err) + } + info, err := car.SessionInfo(ctx, publicKey, domain) + if err != nil { + return err + } + fmt.Printf("%s\n", info) + return nil + }, + }, + "seat-heater": &Command{ + help: "Set seat heater at POSITION to LEVEL", + requiresAuth: true, + requiresFleetAPI: false, + args: []Argument{ + Argument{name: "SEAT", help: "- (e.g., 2nd-row-left)"}, + Argument{name: "LEVEL", help: "off, low, medium, or high"}, + }, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + // See SeatPosition definition for controlling backrest heaters (limited models). + seats := map[string]vehicle.SeatPosition{ + "front-left": vehicle.SeatFrontLeft, + "front-right": vehicle.SeatFrontRight, + "2nd-row-left": vehicle.SeatSecondRowLeft, + "2nd-row-center": vehicle.SeatSecondRowCenter, + "2nd-row-right": vehicle.SeatSecondRowRight, + "3rd-row-left": vehicle.SeatThirdRowLeft, + "3rd-row-right": vehicle.SeatThirdRowRight, + } + position, ok := seats[args["SEAT"]] + if !ok { + return fmt.Errorf("invalid seat position") + } + levels := map[string]vehicle.Level{ + "off": vehicle.LevelOff, + "low": vehicle.LevelLow, + "medium": vehicle.LevelMed, + "high": vehicle.LevelHigh, + } + level, ok := levels[args["LEVEL"]] + if !ok { + return fmt.Errorf("invalid seat heater level") + } + spec := map[vehicle.SeatPosition]vehicle.Level{ + position: level, + } + return car.SetSeatHeater(ctx, spec) + }, + }, + "steering-wheel-heater": &Command{ + help: "Set steering wheel mode to STATE ('on' or 'off')", + requiresAuth: true, + requiresFleetAPI: false, + args: []Argument{ + Argument{name: "STATE", help: "'on' or 'off'"}, + }, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + var state bool + switch args["STATE"] { + case "on": + state = true + case "off": + state = false + default: + return fmt.Errorf("steering wheel state must be 'on' or 'off'") + } + return car.SetSteeringWheelHeater(ctx, state) + }, + }, + "product-info": &Command{ + help: "Print JSON product info", + requiresAuth: false, + requiresFleetAPI: true, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + productsJSON, err := acct.Get(ctx, "api/1/products") + if err != nil { + return err + } + fmt.Println(string(productsJSON)) + return nil + }, + }, + "auto-seat-and-climate": &Command{ + help: "Turn on automatic seat heating and HVAC", + requiresAuth: true, + requiresFleetAPI: false, + args: []Argument{ + Argument{name: "POSITIONS", help: "'L' (left), 'R' (right), or 'LR'"}, + }, + optional: []Argument{ + Argument{name: "STATE", help: "'on' (default) or 'off'"}, + }, + handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + var positions []vehicle.SeatPosition + if strings.Contains(args["POSITIONS"], "L") { + positions = append(positions, vehicle.SeatFrontLeft) + } + if strings.Contains(args["POSITIONS"], "R") { + positions = append(positions, vehicle.SeatFrontRight) + } + if len(positions) != len(args["POSITIONS"]) { + return fmt.Errorf("invalid seat position") + } + enabled := true + if state, ok := args["STATE"]; ok && strings.ToUpper(state) == "OFF" { + enabled = false + } + return car.AutoSeatAndClimate(ctx, positions, enabled) + }, + }, +} diff --git a/tesla_api_coverage/src/fleet.rs b/tesla_api_coverage/src/fleet.rs new file mode 100644 index 0000000..3b26270 --- /dev/null +++ b/tesla_api_coverage/src/fleet.rs @@ -0,0 +1,170 @@ +use scraper::{Element, ElementRef, Html, Selector}; +use std::collections::HashMap; +use std::str::FromStr; + +struct FleetApiSpec { + calls: HashMap, +} + +// e.g. serialize to similar: vehicle-endpoints +#[derive(Debug, strum::EnumString)] +#[strum(serialize_all = "kebab-case")] +enum Category { + ChargingEndpoints, + PartnerEndpoints, + UserEndpoints, + VehicleCommands, + VehicleEndpoints, +} + +#[derive(Debug, strum::EnumString)] +#[strum(serialize_all = "snake_case")] +enum Scope { + /// Profile Information + /// + /// Contact information, home address, profile picture, and referral information. + UserData, + + /// Vehicle Information + /// + /// Vehicle live data, location, eligible upgrades, nearby superchargers, ownership, and service scheduling data. + VehicleDeviceData, + + /// Vehicle Commands + /// + /// Commands like add/remove driver, access Live Camera, unlock, wake up, remote start, and schedule software updates. + VehicleCmds, + + /// Vehicle Charging Management + /// + /// Vehicle charging history, billed amount, charging location, commands to schedule, and start/stop charging. + VehicleChargingCmds, + + /// Energy Product Information + /// + /// Energy flow history, saving forecast, tariff rates, grid import, calendar, site status, time of use, and ownership. + EnergyDeviceData, + + /// Energy Product Commands + /// + /// Commands like update storm mode. + EnergyCmds, +} + +enum InRequestData { + Query, + Body, +} + +struct Parameter { + name: String, + request: InRequestData, + var_type: String, + required: bool, + description: String, +} + +struct Call { + name: String, + method: reqwest::Method, + url_definition: String, + description: String, + category: Category, + scopes: Vec, + parameters: Vec, + request_example: String, + response_example: String, +} + +pub fn parse(html: &str) -> () { + let document = Html::parse_document(html); + let content_selector = selector(".content h1"); + let mut element = document.select(&content_selector).next().unwrap(); + let mut category = None; + + // Iterate over all the elements in the content section until we see a h1 or h2. + loop { + match element.value().name() { + "h1" => { + let category_name = element.value().id().unwrap(); + category = Category::from_str(&category_name).ok(); + } + "h2" => { + if category.is_some() { + let name = element.inner_html(); + println!("{category:?} {name:?}"); + // let call = parse_call(element); + } + } + _ => {} + } + + let Some(next_element) = element.next_sibling_element() else { + println!("exiting..."); + break; + }; + element = next_element; + } +} + +/// Return None if this is not an endpoint. +/// +/// Will panic if it looks like an endpoint and has trouble parsing. +fn parse_call(element: ElementRef) -> Option { + let name = element.value().id().unwrap(); + + //

POST /api/1/vehicles/{id}/command/auto_conditioning_start

+ // This section determines if this is an endpoint or not. + let (fragment, element) = next(element); + let url = fragment.select(&selector("code")).next()?.inner_html(); + if !url.starts_with("GET ") && !url.starts_with("POST ") { + return None; + } + + let (method, url) = url.split_once(' ').unwrap(); + println!("{} {}", method, url); + + //

scopes: vehicle_cmds

+ let (fragment, element) = next(element); + let scopes = fragment + .select(&selector("em")) + .map(|e| e.inner_html()) + .map(|e| Scope::from_str(&e)) + .collect::>(); + + // 4
nodes containing example requests in different languages. + // TODO: Skip for now + let mut count = 0; + let mut element = element; + loop { + let (fragment, new_element) = next(element); + element = new_element; + if fragment + .select(&selector(r#"div[class="highlight"]"#)) + .next() + .is_none() + { + break; + } + + count += 1; + if count == 10 { + panic!("Too many examples"); + } + } + if count == 0 && name != "api-status" { + panic!("No examples for {}", name); + } + + None +} + +fn next(element: ElementRef) -> (Html, ElementRef) { + let element = element.next_sibling_element().unwrap(); + let html = Html::parse_fragment(&element.html()); + (html, element) +} + +fn selector(s: &str) -> Selector { + Selector::parse(s).unwrap() +} diff --git a/tesla_api_coverage/src/main.rs b/tesla_api_coverage/src/main.rs new file mode 100644 index 0000000..188da41 --- /dev/null +++ b/tesla_api_coverage/src/main.rs @@ -0,0 +1,93 @@ +mod fleet; +mod vehicle_command; + +use clap::Parser; +use scraper::Element; +use std::path::PathBuf; +use std::str::FromStr; +use tracing::info; + +const TIMDORR_URL: &str = + "https://raw.githubusercontent.com/timdorr/tesla-api/master/ownerapi_endpoints.json"; +const TIMDORR_FILE: &str = "timdorr.json"; +const VEHICLE_COMMAND_URL: &str = "https://raw.githubusercontent.com/teslamotors/vehicle-command/main/cmd/tesla-control/commands.go"; +const VEHICLE_COMMAND_FILE: &str = "vehicle_command.go"; +const FLEET_API_URL: &str = "https://developer.tesla.com/docs/fleet-api"; +const FLEET_API_FILE: &str = "fleet.html"; + +#[derive(Parser, Debug)] +#[clap(author, version)] +struct Cli { + /// Use the cached html if exists, to avoid making requests. + #[clap(short, long)] + cached: bool, + + #[clap(short = 'v', long)] + only_vehicle_command: bool, +} + +#[tokio::main] +async fn main() { + tracing_subscriber::fmt::init(); + let args = Cli::parse(); + + // let timorr = cache_fetch(TIMDORR_URL, TIMDORR_FILE, args.cache).await; + // + // let fleet_html = cache_fetch( + // FLEET_API_URL, + // FLEET_API_FILE, + // args.cache, + // ) + // .await; + // + // let command_golang = cache_fetch( + // VEHICLE_COMMAND_URL, + // VEHICLE_COMMAND_FILE, + // args.cache, + // ).await; + + let (timorr, fleet_html, command_golang) = tokio::join!( + cache_fetch(TIMDORR_URL, TIMDORR_FILE, args.cached), + cache_fetch(FLEET_API_URL, FLEET_API_FILE, args.cached), + cache_fetch(VEHICLE_COMMAND_URL, VEHICLE_COMMAND_FILE, args.cached) + ); + + let mut vehicle_command = true; + let mut fleet_api = true; + let mut timdorr = true; + + if args.only_vehicle_command { + fleet_api = false; + timdorr = false; + } + + if fleet_api { + fleet::parse(&fleet_html); + } + + if vehicle_command { + vehicle_command::parse(&command_golang); + } +} + +async fn cache_fetch(url: &str, filename: &str, cache: bool) -> String { + // Write to where this project root is, not in the parent project. + let mut path = PathBuf::new(); + path.push(env!("CARGO_MANIFEST_DIR")); + path.push("cached"); + path.push(filename); + + if cache && path.exists() { + info!("Using cache: {path:?}"); + return std::fs::read_to_string(path).unwrap(); + } + + info!("Fetching {url} -> {path:?}"); + let response = reqwest::get(url).await.unwrap(); + + let html = response.text().await.unwrap(); + + std::fs::write(path, &html).unwrap(); + + html +} diff --git a/tesla_api_coverage/src/vehicle_command.rs b/tesla_api_coverage/src/vehicle_command.rs new file mode 100644 index 0000000..4a62516 --- /dev/null +++ b/tesla_api_coverage/src/vehicle_command.rs @@ -0,0 +1,209 @@ +use nom::branch::alt; +use nom::bytes::complete::{tag, take_until, take_while}; +use nom::character::complete::{char, line_ending, space0, space1, tab}; +use nom::combinator::opt; +use nom::multi::{many0, many1}; +use nom::IResult; +use tracing::{trace, warn}; + +pub fn parse(s: &str) -> () { + // Seek all the way to: var commands = map[string]*Command{\n + // Afterwards has the first map entry. + let commands_start = "var commands = map[string]*Command{\n"; + let offset = s.find(commands_start).unwrap(); + let s = &s[offset + commands_start.len()..]; + + let (go, entries) = many1(map_entry)(s).unwrap(); + + dbg!(&entries); + + warn!("todo: parse") +} + +#[derive(Debug)] +struct MapEntry { + endpoint: String, + help: String, + // requires_auth: bool, + // requires_fleet: bool, +} + +fn map_entry(s: &str) -> IResult<&str, MapEntry> { + // "unlock": &Command{ + // help: "Unlock vehicle", + // requiresAuth: true, + // requiresFleetAPI: false, + // args: []Argument{ + // Argument{name: "TEMP", help: "Desired temperature (e.g., 70f or 21c; defaults to Celsius)"}, + // Argument{name: "ROLE", help: "One of: owner, driver"}, + // }, + // handler: func(ctx context.Context, acct *account.Account, car *vehicle.Vehicle, args map[string]string) error { + // return car.Unlock(ctx) + // }, + // }, + + short_trace("--- map entry ---", s); + + // endpoint + short_trace("endpoint", s); + let (s, _) = ignore_whitespace(s)?; + let (s, endpoint) = quoted_string(s)?; + let (s, _) = until_eol(s)?; + + // help + short_trace("help", s); + let (s, _) = ignore_whitespace(s)?; + let (s, _) = tag("help:")(s)?; + let (s, _) = ignore_whitespace(s)?; + let (s, help) = quoted_string(s)?; + let (s, _) = tag(",")(s)?; + + // requiresAuth + short_trace("requiresAuth", s); + let (s, requires_auth) = bool_field_or_false(s, "requiresAuth:")?; + + // requiresFleetAPI + short_trace("requiresFleetAPI", s); + let (s, requires_fleet) = bool_field_or_false(s, "requiresFleetAPI:")?; + + // required args + short_trace("required args", s); + let (s, required_args) = args(s, "args: []Argument{")?; + + // optional args + short_trace("optional args", s); + let (s, optional_args) = args(s, "optional: []Argument{")?; + + // check and ignore the handler, as there's not really much data we can take out of it. + let (s, _) = ignore_whitespace(s)?; + + let (s, _) = take_until("},")(s)?; + let (s, _) = tag("},")(s)?; + + // And the end of the record... + let (s, _) = take_until("},")(s)?; + let (s, _) = tag("},")(s)?; + + dbg!(endpoint, help, requires_auth, requires_fleet); + + Ok(( + s, + MapEntry { + endpoint: endpoint.to_string(), + help: help.to_string(), + }, + )) +} + +/// Ignore the quotes and return the inner string. +/// e.g. "unlock" +fn quoted_string(s: &str) -> IResult<&str, &str> { + short_trace("quoted string", s); + let (s, _) = char('"')(s)?; + let (s, string) = take_until("\"")(s)?; + let (s, _) = char('"')(s)?; + Ok((s, string)) +} + +fn ignore_whitespace(s: &str) -> IResult<&str, ()> { + short_trace("ignore whitespace", s); + let (s, ws) = many0(alt((tag("\t"), space1, line_ending)))(s)?; + short_trace("ignore whitespace afterwards", s); + Ok((s, ())) +} + +fn until_eol(s: &str) -> IResult<&str, &str> { + short_trace("eol", s); + let (s, line) = take_until("\n")(s)?; + let (s, _) = line_ending(s)?; + short_trace("eol afterwards", s); + Ok((s, line)) +} + +fn str_to_bool(s: &str) -> IResult<&str, bool> { + short_trace("bool", s); + let (s, bool_str) = alt((tag("true"), tag("false")))(s)?; + let bool = match bool_str { + "true" => true, + "false" => false, + _ => unreachable!(), + }; + short_trace("bool afterwards", s); + Ok((s, bool)) +} + +/// If the field isn't there, assume false. +fn bool_field<'a>(field_tag: &str) -> impl Fn(&'a str) -> IResult<&'a str, bool> + '_ { + return move |s: &str| -> IResult<&'a str, bool> { + let (s, _) = ignore_whitespace(s)?; + let (s, _) = tag(field_tag)(s)?; + let (s, _) = ignore_whitespace(s)?; + let (s, value) = str_to_bool(s)?; + let (s, _) = tag(",")(s)?; + + Ok((s, value)) + }; +} + +fn bool_field_or_false<'a>(s: &'a str, field_tag: &str) -> IResult<&'a str, bool> { + let (s, value) = opt(bool_field(field_tag))(s)?; + return Ok((s, value.unwrap_or(false))); +} + +struct Arg { + name: String, + help: String, +} + +fn args<'a>(s: &'a str, field_tag: &str) -> IResult<&'a str, Vec> { + short_trace("args", s); + + let (s, _) = ignore_whitespace(s)?; + let (s, maybe_field) = opt(tag(field_tag))(s)?; + if maybe_field.is_none() { + trace!("no arg record"); + return Ok((s, vec![])); + } + + let (s, _) = ignore_whitespace(s)?; + let (s, args) = many1(arg)(s)?; + let (s, _) = ignore_whitespace(s)?; + let (s, _) = tag("},")(s)?; + short_trace("args afterwards", s); + Ok((s, args)) +} + +fn arg(s: &str) -> IResult<&str, Arg> { + short_trace("arg", s); + let (s, _) = ignore_whitespace(s)?; + let (s, _) = tag("Argument{")(s)?; + let (s, _) = ignore_whitespace(s)?; + let (s, _) = tag("name:")(s)?; + let (s, _) = ignore_whitespace(s)?; + let (s, name) = quoted_string(s)?; + let (s, _) = ignore_whitespace(s)?; + let (s, _) = tag(",")(s)?; + let (s, _) = ignore_whitespace(s)?; + let (s, _) = tag("help:")(s)?; + let (s, _) = ignore_whitespace(s)?; + let (s, help) = quoted_string(s)?; + let (s, _) = opt(tag(","))(s)?; + let (s, _) = ignore_whitespace(s)?; + let (s, _) = tag("},")(s)?; + short_trace("arg afterwards", s); + Ok(( + s, + Arg { + name: name.to_string(), + help: help.to_string(), + }, + )) +} + +fn short_trace(prefix: &str, s: &str) { + let mut max_len_left = 20; + if s.len() < max_len_left { + max_len_left = s.len(); + } + trace!("{}: {:?}...", prefix, &s[0..max_len_left]) +}