From 3278d3db43e2b70135f8c8e3c872d32ae60d0647 Mon Sep 17 00:00:00 2001 From: Nicolas Moutschen Date: Mon, 13 Jan 2025 16:05:35 +0100 Subject: [PATCH 01/11] fix(fleet_detector): use SizeHint for subgraph request when possible --- apollo-router/src/plugins/fleet_detector.rs | 108 +++++++++++++++++++- 1 file changed, 106 insertions(+), 2 deletions(-) diff --git a/apollo-router/src/plugins/fleet_detector.rs b/apollo-router/src/plugins/fleet_detector.rs index 27b01e1527..d3e8af6d94 100644 --- a/apollo-router/src/plugins/fleet_detector.rs +++ b/apollo-router/src/plugins/fleet_detector.rs @@ -7,6 +7,7 @@ use std::time::Duration; use std::time::Instant; use futures::StreamExt; +use http_body::Body; use opentelemetry::metrics::MeterProvider; use opentelemetry_api::metrics::ObservableGauge; use opentelemetry_api::metrics::Unit; @@ -299,6 +300,27 @@ impl PluginPrivate for FleetDetector { HttpRequest { http_request: req.http_request.map(move |body| { let sn = sn.clone(); + let size_hint = body.size_hint(); + + // Short-circuit for complete bodies + // + // If the `SizeHint` gives us an exact value, where the upper and lower + // bounds are equal, we can use this for the metric and return without + // wrapping the request Body. + if let Some(upper) = size_hint.upper() { + if upper == size_hint.lower() { + let sn = sn.clone(); + u64_counter!( + "apollo.router.operations.fetch.request_size", + "Total number of request bytes for subgraph fetches", + upper as u64, + subgraph.name = sn.to_string() + ); + return body; + } + } + + // For streaming bodies, we need to wrap the stream and count bytes as we go RouterBody::wrap_stream(body.inspect(move |res| { if let Ok(bytes) = res { let sn = sn.clone(); @@ -473,6 +495,8 @@ register_private_plugin!("apollo", "fleet_detector", FleetDetector); #[cfg(test)] mod tests { + use std::convert::Infallible; + use http::StatusCode; use tower::Service as _; @@ -660,7 +684,7 @@ mod tests { } #[tokio::test] - async fn test_enabled_http_client_service() { + async fn test_enabled_http_client_service_full() { async { // WHEN the plugin is enabled let plugin = FleetDetector { @@ -668,7 +692,7 @@ mod tests { ..Default::default() }; - // GIVEN an http client service request + // GIVEN an http client service request with a complete body let mut mock_bad_request_service = MockHttpClientService::new(); mock_bad_request_service.expect_call().times(1).returning( |req: http::Request| { @@ -736,4 +760,84 @@ mod tests { .with_metrics() .await; } + + #[tokio::test] + async fn test_enabled_http_client_service_stream() { + async { + // WHEN the plugin is enabled + let plugin = FleetDetector { + enabled: true, + ..Default::default() + }; + + // GIVEN an http client service request with a streaming body + let mut mock_bad_request_service = MockHttpClientService::new(); + mock_bad_request_service.expect_call().times(1).returning( + |req: http::Request| { + Box::pin(async { + let data = hyper::body::to_bytes(req.into_body()).await?; + Ok(http::Response::builder() + .status(StatusCode::BAD_REQUEST) + .header("content-type", "application/json") + // making sure the request body is consumed + .body(Body::from(data)) + .unwrap()) + }) + }, + ); + let mut bad_request_http_client_service = plugin.http_client_service( + "subgraph", + mock_bad_request_service + .map_request(|req: HttpRequest| req.http_request.map(|body| body.into_inner())) + .map_response(|res: http::Response| HttpResponse { + http_response: res.map(RouterBody::from), + context: Default::default(), + }) + .boxed(), + ); + let http_client_req = HttpRequest { + http_request: http::Request::builder() + .body(RouterBody::wrap_stream(futures::stream::once(async { + Ok::<_, Infallible>("request") + }))) + .unwrap(), + context: Default::default(), + }; + let http_client_response = bad_request_http_client_service + .ready() + .await + .unwrap() + .call(http_client_req) + .await + .unwrap(); + + // making sure the response body is consumed + let _data = hyper::body::to_bytes(http_client_response.http_response.into_body()) + .await + .unwrap(); + + // THEN fetch metrics should exist + assert_counter!( + "apollo.router.operations.fetch", + 1, + &[ + KeyValue::new("subgraph.name", "subgraph"), + KeyValue::new("http.response.status_code", 400), + KeyValue::new("client_error", false) + ] + ); + assert_counter!( + "apollo.router.operations.fetch.request_size", + 7, + &[KeyValue::new("subgraph.name", "subgraph"),] + ); + assert_counter!( + "apollo.router.operations.fetch.response_size", + 7, + &[KeyValue::new("subgraph.name", "subgraph"),] + ); + } + .with_metrics() + .await; + } } From 61a4a38e14e402ceccab0254c99bdb2805c3c653 Mon Sep 17 00:00:00 2001 From: Nicolas Moutschen Date: Mon, 13 Jan 2025 16:09:58 +0100 Subject: [PATCH 02/11] chore: add changeset --- .changesets/fix_junior_granddad_salami_dye.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changesets/fix_junior_granddad_salami_dye.md diff --git a/.changesets/fix_junior_granddad_salami_dye.md b/.changesets/fix_junior_granddad_salami_dye.md new file mode 100644 index 0000000000..9c1604cd3a --- /dev/null +++ b/.changesets/fix_junior_granddad_salami_dye.md @@ -0,0 +1,7 @@ +### Fix missing Content-Length header in subgraph requests ([Issue #6503](https://github.com/apollographql/router/issues/6503)) + +A new telemetry feature introduced in the Router version 1.59.0 would convert all request bodies to subgraphs into stream to infer the total body sizes. This would cause requests to subgraphs to no longer have a `Content-Length` header, which could cause issues with some GraphQL servers. + +This solves this issue by using `SizeHint` when possible to infer the body size instead. + +By [@nmoutschen](https://github.com/nmoutschen) in https://github.com/apollographql/router/pull/6538 From 6cef7ee60141c56b8637b356bb8d684b855f5903 Mon Sep 17 00:00:00 2001 From: Nicolas Moutschen Date: Mon, 13 Jan 2025 17:43:58 +0100 Subject: [PATCH 03/11] fix: clippy fix --- apollo-router/src/plugins/fleet_detector.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apollo-router/src/plugins/fleet_detector.rs b/apollo-router/src/plugins/fleet_detector.rs index d3e8af6d94..ac0b1b77cd 100644 --- a/apollo-router/src/plugins/fleet_detector.rs +++ b/apollo-router/src/plugins/fleet_detector.rs @@ -313,7 +313,7 @@ impl PluginPrivate for FleetDetector { u64_counter!( "apollo.router.operations.fetch.request_size", "Total number of request bytes for subgraph fetches", - upper as u64, + upper, subgraph.name = sn.to_string() ); return body; From 4fc63d55104c81c77e6e0a3cca615eac28e39dc3 Mon Sep 17 00:00:00 2001 From: Jesse Rosenberger Date: Tue, 14 Jan 2025 16:27:07 +0200 Subject: [PATCH 04/11] chore(deps): Update dev dependencies with `npm audit fix` (#6544) --- .../datadog-subgraph/package-lock.json | 142 ++-- .../tracing/jaeger-subgraph/package-lock.json | 254 ++---- .../tracing/zipkin-subgraph/package-lock.json | 254 ++---- .../package-lock.json | 721 +++++++++++------- 4 files changed, 657 insertions(+), 714 deletions(-) diff --git a/dockerfiles/tracing/datadog-subgraph/package-lock.json b/dockerfiles/tracing/datadog-subgraph/package-lock.json index b2e4649c45..5c002080a1 100644 --- a/dockerfiles/tracing/datadog-subgraph/package-lock.json +++ b/dockerfiles/tracing/datadog-subgraph/package-lock.json @@ -793,21 +793,6 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/body-parser/node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -871,9 +856,9 @@ } }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "engines": { "node": ">= 0.6" } @@ -1033,9 +1018,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "engines": { "node": ">= 0.8" } @@ -1080,37 +1065,36 @@ "integrity": "sha512-8qz9nOz5VeD2z96elrEKD2U433+L3DWdUdDkOINLGOJvx1GsMBbMn0aCeu28y8/e85A6mCigBiFlYMnTBEGlSw==" }, "node_modules/express": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.20.0.tgz", - "integrity": "sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==", - "license": "MIT", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", - "serve-static": "1.16.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -1119,63 +1103,19 @@ }, "engines": { "node": ">= 0.10.0" - } - }, - "node_modules/express/node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/express/node_modules/send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/express/node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "license": "MIT", - "engines": { - "node": ">= 0.8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -1656,10 +1596,9 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", - "license": "MIT" + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, "node_modules/pprof-format": { "version": "2.1.0", @@ -1716,11 +1655,11 @@ } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -1798,9 +1737,9 @@ } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -1820,21 +1759,28 @@ "node": ">= 0.8.0" } }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/serve-static": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.0.tgz", - "integrity": "sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==", - "license": "MIT", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" diff --git a/dockerfiles/tracing/jaeger-subgraph/package-lock.json b/dockerfiles/tracing/jaeger-subgraph/package-lock.json index 6918784db6..054c033351 100644 --- a/dockerfiles/tracing/jaeger-subgraph/package-lock.json +++ b/dockerfiles/tracing/jaeger-subgraph/package-lock.json @@ -632,20 +632,6 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/body-parser/node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/bufrw": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/bufrw/-/bufrw-1.3.0.tgz", @@ -717,9 +703,9 @@ } }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "engines": { "node": ">= 0.6" } @@ -796,9 +782,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "engines": { "node": ">= 0.8" } @@ -845,36 +831,36 @@ } }, "node_modules/express": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.20.0.tgz", - "integrity": "sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", - "serve-static": "1.16.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -883,59 +869,19 @@ }, "engines": { "node": ">= 0.10.0" - } - }, - "node_modules/express/node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/express/node_modules/send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/express/node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "engines": { - "node": ">= 0.8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -1338,9 +1284,9 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, "node_modules/process": { "version": "0.10.1", @@ -1363,11 +1309,11 @@ } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -1431,9 +1377,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -1453,20 +1399,28 @@ "node": ">= 0.8.0" } }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/serve-static": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.0.tgz", - "integrity": "sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" @@ -2166,16 +2120,6 @@ "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" - }, - "dependencies": { - "qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "requires": { - "side-channel": "^1.0.6" - } - } } }, "bufrw": { @@ -2228,9 +2172,9 @@ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" }, "cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==" + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==" }, "cookie-signature": { "version": "1.0.6", @@ -2285,9 +2229,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" }, "error": { "version": "7.0.2", @@ -2322,89 +2266,50 @@ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" }, "express": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.20.0.tgz", - "integrity": "sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", - "serve-static": "1.16.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" - }, - "dependencies": { - "encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "dependencies": { - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" - } - } - } } }, "finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "requires": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -2672,9 +2577,9 @@ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, "path-to-regexp": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, "process": { "version": "0.10.1", @@ -2691,11 +2596,11 @@ } }, "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "requires": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" } }, "range-parser": { @@ -2730,9 +2635,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "requires": { "debug": "2.6.9", "depd": "2.0.0", @@ -2749,6 +2654,11 @@ "statuses": "2.0.1" }, "dependencies": { + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -2757,14 +2667,14 @@ } }, "serve-static": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.0.tgz", - "integrity": "sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "requires": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" } }, "set-function-length": { diff --git a/dockerfiles/tracing/zipkin-subgraph/package-lock.json b/dockerfiles/tracing/zipkin-subgraph/package-lock.json index cba9a4fb28..4feef23b59 100644 --- a/dockerfiles/tracing/zipkin-subgraph/package-lock.json +++ b/dockerfiles/tracing/zipkin-subgraph/package-lock.json @@ -653,20 +653,6 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/body-parser/node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/bufrw": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/bufrw/-/bufrw-1.3.0.tgz", @@ -738,9 +724,9 @@ } }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "engines": { "node": ">= 0.6" } @@ -817,9 +803,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "engines": { "node": ">= 0.8" } @@ -866,36 +852,36 @@ } }, "node_modules/express": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.20.0.tgz", - "integrity": "sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", - "serve-static": "1.16.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -904,59 +890,19 @@ }, "engines": { "node": ">= 0.10.0" - } - }, - "node_modules/express/node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/express/node_modules/send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/express/node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "engines": { - "node": ">= 0.8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -1365,9 +1311,9 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, "node_modules/process": { "version": "0.10.1", @@ -1390,11 +1336,11 @@ } }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -1458,9 +1404,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -1480,20 +1426,28 @@ "node": ">= 0.8.0" } }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/serve-static": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.0.tgz", - "integrity": "sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" @@ -2231,16 +2185,6 @@ "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" - }, - "dependencies": { - "qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "requires": { - "side-channel": "^1.0.6" - } - } } }, "bufrw": { @@ -2293,9 +2237,9 @@ "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" }, "cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==" + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==" }, "cookie-signature": { "version": "1.0.6", @@ -2350,9 +2294,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" }, "error": { "version": "7.0.2", @@ -2387,89 +2331,50 @@ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" }, "express": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.20.0.tgz", - "integrity": "sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", - "serve-static": "1.16.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" - }, - "dependencies": { - "encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "dependencies": { - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" - } - } - } } }, "finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "requires": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -2743,9 +2648,9 @@ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, "path-to-regexp": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, "process": { "version": "0.10.1", @@ -2762,11 +2667,11 @@ } }, "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "requires": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" } }, "range-parser": { @@ -2801,9 +2706,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "requires": { "debug": "2.6.9", "depd": "2.0.0", @@ -2820,6 +2725,11 @@ "statuses": "2.0.1" }, "dependencies": { + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -2828,14 +2738,14 @@ } }, "serve-static": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.0.tgz", - "integrity": "sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "requires": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" } }, "set-function-length": { diff --git a/examples/coprocessor-override-launchdarkly/package-lock.json b/examples/coprocessor-override-launchdarkly/package-lock.json index 8201944392..7906fd5fd3 100644 --- a/examples/coprocessor-override-launchdarkly/package-lock.json +++ b/examples/coprocessor-override-launchdarkly/package-lock.json @@ -317,21 +317,21 @@ } }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", + "qs": "6.13.0", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -351,12 +351,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -371,15 +371,30 @@ "node": ">= 0.8" } }, - "node_modules/call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "node_modules/call-bind-apply-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", + "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", "dev": true, "dependencies": { - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", + "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -440,9 +455,9 @@ } }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "dev": true, "engines": { "node": ">= 0.6" @@ -469,20 +484,6 @@ "ms": "2.0.0" } }, - "node_modules/define-data-property": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", - "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -522,6 +523,20 @@ "url": "https://github.com/motdotla/dotenv?sponsor=1" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -529,14 +544,44 @@ "dev": true }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, "engines": { "node": ">= 0.8" } }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.1.tgz", + "integrity": "sha512-BPOBuyUF9QIVhuNLhbToCLHP6+0MHwZ7xLBkPPCZqK4JmpJgGnv10035STzzQwFpqdzNFMB3irvDI63IagvDwA==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -553,37 +598,37 @@ } }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dev": true, "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -592,12 +637,16 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -607,13 +656,13 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -666,20 +715,42 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", + "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", "dev": true, "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.0", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -693,12 +764,12 @@ } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -713,34 +784,10 @@ "node": ">=4" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, "engines": { "node": ">= 0.4" @@ -750,9 +797,9 @@ } }, "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, "dependencies": { "function-bind": "^1.1.2" @@ -910,6 +957,15 @@ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -920,10 +976,13 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/methods": { "version": "1.1.2", @@ -1070,10 +1129,13 @@ } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", "dev": true, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -1100,9 +1162,9 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", "dev": true }, "node_modules/picomatch": { @@ -1137,12 +1199,12 @@ "dev": true }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -1161,9 +1223,9 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, "dependencies": { "bytes": "3.1.2", @@ -1228,9 +1290,9 @@ } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, "dependencies": { "debug": "2.6.9", @@ -1251,6 +1313,15 @@ "node": ">= 0.8.0" } }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -1258,51 +1329,93 @@ "dev": true }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" } }, - "node_modules/set-function-length": { + "node_modules/setprototypeof": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz", - "integrity": "sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "dev": true, "dependencies": { - "define-data-property": "^1.1.1", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.2", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.1" + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "dev": true, "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1766,21 +1879,21 @@ "dev": true }, "body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, "requires": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", + "qs": "6.13.0", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" } @@ -1796,12 +1909,12 @@ } }, "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "requires": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" } }, "bytes": { @@ -1810,15 +1923,24 @@ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true }, - "call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "call-bind-apply-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", + "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", "dev": true, "requires": { - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + } + }, + "call-bound": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", + "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "dev": true, + "requires": { + "call-bind-apply-helpers": "^1.0.1", + "get-intrinsic": "^1.2.6" } }, "chokidar": { @@ -1859,9 +1981,9 @@ "dev": true }, "cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "dev": true }, "cookie-signature": { @@ -1885,17 +2007,6 @@ "ms": "2.0.0" } }, - "define-data-property": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", - "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", - "dev": true, - "requires": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" - } - }, "depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -1919,6 +2030,17 @@ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.2.tgz", "integrity": "sha512-HTlk5nmhkm8F6JcdXvHIzaorzCoziNQT9mGxLPVXW8wJF1TiGSL60ZGB4gHWabHOaMmWmhvk2/lPHfnBiT78AQ==" }, + "dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "requires": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -1926,11 +2048,32 @@ "dev": true }, "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true + }, + "es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true }, + "es-object-atoms": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.1.tgz", + "integrity": "sha512-BPOBuyUF9QIVhuNLhbToCLHP6+0MHwZ7xLBkPPCZqK4JmpJgGnv10035STzzQwFpqdzNFMB3irvDI63IagvDwA==", + "dev": true, + "requires": { + "es-errors": "^1.3.0" + } + }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1944,37 +2087,37 @@ "dev": true }, "express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dev": true, "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -1983,22 +2126,22 @@ } }, "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "requires": { "to-regex-range": "^5.0.1" } }, "finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, "requires": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -2032,15 +2175,31 @@ "dev": true }, "get-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", + "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", "dev": true, "requires": { + "call-bind-apply-helpers": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.0", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + } + }, + "get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "requires": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" } }, "glob-parent": { @@ -2053,13 +2212,10 @@ } }, "gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.3" - } + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true }, "has-flag": { "version": "3.0.0", @@ -2067,31 +2223,16 @@ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true }, - "has-property-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", - "dev": true, - "requires": { - "get-intrinsic": "^1.2.2" - } - }, - "has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true - }, "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true }, "hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, "requires": { "function-bind": "^1.1.2" @@ -2210,6 +2351,12 @@ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, + "math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -2217,9 +2364,9 @@ "dev": true }, "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", "dev": true }, "methods": { @@ -2321,9 +2468,9 @@ "dev": true }, "object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", "dev": true }, "on-finished": { @@ -2342,9 +2489,9 @@ "dev": true }, "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", "dev": true }, "picomatch": { @@ -2370,12 +2517,12 @@ "dev": true }, "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, "requires": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" } }, "range-parser": { @@ -2385,9 +2532,9 @@ "dev": true }, "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, "requires": { "bytes": "3.1.2", @@ -2426,9 +2573,9 @@ } }, "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, "requires": { "debug": "2.6.9", @@ -2446,6 +2593,12 @@ "statuses": "2.0.1" }, "dependencies": { + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true + }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -2455,28 +2608,15 @@ } }, "serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, "requires": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" - } - }, - "set-function-length": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz", - "integrity": "sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==", - "dev": true, - "requires": { - "define-data-property": "^1.1.1", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.2", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.1" + "send": "0.19.0" } }, "setprototypeof": { @@ -2486,14 +2626,51 @@ "dev": true }, "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "requires": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + } + }, + "side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "requires": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + } + }, + "side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "requires": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + } + }, + "side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "dev": true, "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" } }, "simple-update-notifier": { From 5d7eec51b4919986a0bcb8fe11935f800c81b524 Mon Sep 17 00:00:00 2001 From: Taylor Ninesling Date: Wed, 15 Jan 2025 09:11:59 -0600 Subject: [PATCH 05/11] Demand control lookup optimizations (#6450) Co-authored-by: Bryn Cooke --- .../fix_tninesling_demand_control_perf.md | 9 + .../demand_control/cost_calculator/schema.rs | 292 ++++++++++-------- .../cost_calculator/static_cost.rs | 212 ++++++------- 3 files changed, 282 insertions(+), 231 deletions(-) create mode 100644 .changesets/fix_tninesling_demand_control_perf.md diff --git a/.changesets/fix_tninesling_demand_control_perf.md b/.changesets/fix_tninesling_demand_control_perf.md new file mode 100644 index 0000000000..e892390f87 --- /dev/null +++ b/.changesets/fix_tninesling_demand_control_perf.md @@ -0,0 +1,9 @@ +### Demand control lookup optimizations ([PR #6450](https://github.com/apollographql/router/pull/6450)) + +Demand Control can reduce router throughput due to the extra processing required for scoring. This change shifts more data to be computed at plugin initialization and consolidates lookup queries. + +- Cost directives for arguments are now stored in a map alongside those for field definitions +- All precomputed directives are bundled into a struct for each field, along with that field's extended schema type. This reduces 5 individual lookups to a single lookup. +- Response scoring was looking up each field's definition twice. This is now reduced to a single lookup. + +By [@tninesling](https://github.com/tninesling) in https://github.com/apollographql/router/pull/6450 diff --git a/apollo-router/src/plugins/demand_control/cost_calculator/schema.rs b/apollo-router/src/plugins/demand_control/cost_calculator/schema.rs index d59243f4d5..b5e620609a 100644 --- a/apollo-router/src/plugins/demand_control/cost_calculator/schema.rs +++ b/apollo-router/src/plugins/demand_control/cost_calculator/schema.rs @@ -13,112 +13,186 @@ use apollo_federation::link::cost_spec_definition::CostSpecDefinition; use apollo_federation::link::cost_spec_definition::ListSizeDirective; use apollo_federation::schema::ValidFederationSchema; -use super::directives::RequiresDirective; +use crate::plugins::demand_control::cost_calculator::directives::RequiresDirective; use crate::plugins::demand_control::DemandControlError; +pub(in crate::plugins::demand_control) struct InputDefinition { + name: Name, + ty: ExtendedType, + cost_directive: Option, +} + +impl InputDefinition { + fn new( + schema: &ValidFederationSchema, + field_definition: &InputValueDefinition, + ) -> Result { + let field_type = schema + .schema() + .types + .get(field_definition.ty.inner_named_type()) + .ok_or_else(|| { + DemandControlError::QueryParseFailure(format!( + "Field {} was found in query, but its type is missing from the schema.", + field_definition.name + )) + })?; + let processed_inputs = InputDefinition { + name: field_definition.name.clone(), + ty: field_type.clone(), + cost_directive: CostSpecDefinition::cost_directive_from_argument( + schema, + field_definition, + field_type, + )?, + }; + + Ok(processed_inputs) + } + + pub(in crate::plugins::demand_control) fn name(&self) -> &Name { + &self.name + } + + pub(in crate::plugins::demand_control) fn ty(&self) -> &ExtendedType { + &self.ty + } + + pub(in crate::plugins::demand_control) fn cost_directive(&self) -> Option<&CostDirective> { + self.cost_directive.as_ref() + } +} + +pub(in crate::plugins::demand_control) struct FieldDefinition { + ty: ExtendedType, + cost_directive: Option, + list_size_directive: Option, + requires_directive: Option, + arguments: HashMap, +} + +impl FieldDefinition { + fn new( + schema: &ValidFederationSchema, + parent_type_name: &Name, + field_definition: &apollo_compiler::ast::FieldDefinition, + ) -> Result { + let field_type = schema + .schema() + .types + .get(field_definition.ty.inner_named_type()) + .ok_or_else(|| { + DemandControlError::QueryParseFailure(format!( + "Field {} was found in query, but its type is missing from the schema.", + field_definition.name, + )) + })?; + let mut processed_field_definition = Self { + ty: field_type.clone(), + cost_directive: None, + list_size_directive: None, + requires_directive: None, + arguments: HashMap::new(), + }; + + processed_field_definition.cost_directive = + CostSpecDefinition::cost_directive_from_field(schema, field_definition, field_type)?; + processed_field_definition.list_size_directive = + CostSpecDefinition::list_size_directive_from_field_definition( + schema, + field_definition, + )?; + processed_field_definition.requires_directive = RequiresDirective::from_field_definition( + field_definition, + parent_type_name, + schema.schema(), + )?; + + for argument in &field_definition.arguments { + processed_field_definition.arguments.insert( + argument.name.clone(), + InputDefinition::new(schema, argument)?, + ); + } + + Ok(processed_field_definition) + } + + pub(in crate::plugins::demand_control) fn ty(&self) -> &ExtendedType { + &self.ty + } + + pub(in crate::plugins::demand_control) fn cost_directive(&self) -> Option<&CostDirective> { + self.cost_directive.as_ref() + } + + pub(in crate::plugins::demand_control) fn list_size_directive( + &self, + ) -> Option<&ListSizeDirective> { + self.list_size_directive.as_ref() + } + + pub(in crate::plugins::demand_control) fn requires_directive( + &self, + ) -> Option<&RequiresDirective> { + self.requires_directive.as_ref() + } + + pub(in crate::plugins::demand_control) fn argument_by_name( + &self, + argument_name: &str, + ) -> Option<&InputDefinition> { + self.arguments.get(argument_name) + } +} + pub(crate) struct DemandControlledSchema { inner: ValidFederationSchema, - type_field_cost_directives: HashMap>, - type_field_list_size_directives: HashMap>, - type_field_requires_directives: HashMap>, + input_field_definitions: HashMap>, + output_field_definitions: HashMap>, } impl DemandControlledSchema { pub(crate) fn new(schema: Arc>) -> Result { let fed_schema = ValidFederationSchema::new((*schema).clone())?; - let mut type_field_cost_directives: HashMap> = + let mut input_field_definitions: HashMap> = HashMap::new(); - let mut type_field_list_size_directives: HashMap> = - HashMap::new(); - let mut type_field_requires_directives: HashMap> = + let mut output_field_definitions: HashMap> = HashMap::new(); for (type_name, type_) in &schema.types { - let field_cost_directives = type_field_cost_directives - .entry(type_name.clone()) - .or_default(); - let field_list_size_directives = type_field_list_size_directives - .entry(type_name.clone()) - .or_default(); - let field_requires_directives = type_field_requires_directives - .entry(type_name.clone()) - .or_default(); - match type_ { ExtendedType::Interface(ty) => { - for field_name in ty.fields.keys() { - let field_definition = schema.type_field(type_name, field_name)?; - let field_type = schema.types.get(field_definition.ty.inner_named_type()).ok_or_else(|| { - DemandControlError::QueryParseFailure(format!( - "Field {} was found in query, but its type is missing from the schema.", - field_name - )) - })?; - - if let Some(cost_directive) = CostSpecDefinition::cost_directive_from_field( - &fed_schema, - field_definition, - field_type, - )? { - field_cost_directives.insert(field_name.clone(), cost_directive); - } - - if let Some(list_size_directive) = - CostSpecDefinition::list_size_directive_from_field_definition( - &fed_schema, - field_definition, - )? - { - field_list_size_directives - .insert(field_name.clone(), list_size_directive); - } - - if let Some(requires_directive) = RequiresDirective::from_field_definition( - field_definition, - type_name, - &schema, - )? { - field_requires_directives - .insert(field_name.clone(), requires_directive); - } + let type_fields = output_field_definitions + .entry(type_name.clone()) + .or_default(); + for (field_name, field_definition) in &ty.fields { + type_fields.insert( + field_name.clone(), + FieldDefinition::new(&fed_schema, type_name, field_definition)?, + ); } } ExtendedType::Object(ty) => { - for field_name in ty.fields.keys() { - let field_definition = schema.type_field(type_name, field_name)?; - let field_type = schema.types.get(field_definition.ty.inner_named_type()).ok_or_else(|| { - DemandControlError::QueryParseFailure(format!( - "Field {} was found in query, but its type is missing from the schema.", - field_name - )) - })?; - - if let Some(cost_directive) = CostSpecDefinition::cost_directive_from_field( - &fed_schema, - field_definition, - field_type, - )? { - field_cost_directives.insert(field_name.clone(), cost_directive); - } - - if let Some(list_size_directive) = - CostSpecDefinition::list_size_directive_from_field_definition( - &fed_schema, - field_definition, - )? - { - field_list_size_directives - .insert(field_name.clone(), list_size_directive); - } - - if let Some(requires_directive) = RequiresDirective::from_field_definition( - field_definition, - type_name, - &schema, - )? { - field_requires_directives - .insert(field_name.clone(), requires_directive); - } + let type_fields = output_field_definitions + .entry(type_name.clone()) + .or_default(); + for (field_name, field_definition) in &ty.fields { + type_fields.insert( + field_name.clone(), + FieldDefinition::new(&fed_schema, type_name, field_definition)?, + ); + } + } + ExtendedType::InputObject(ty) => { + let type_fields = input_field_definitions + .entry(type_name.clone()) + .or_default(); + for (field_name, field_definition) in &ty.fields { + type_fields.insert( + field_name.clone(), + InputDefinition::new(&fed_schema, field_definition)?, + ); } } _ => { @@ -129,54 +203,28 @@ impl DemandControlledSchema { Ok(Self { inner: fed_schema, - type_field_cost_directives, - type_field_list_size_directives, - type_field_requires_directives, + input_field_definitions, + output_field_definitions, }) } - pub(in crate::plugins::demand_control) fn type_field_cost_directive( + pub(in crate::plugins::demand_control) fn input_field_definition( &self, type_name: &str, field_name: &str, - ) -> Option<&CostDirective> { - self.type_field_cost_directives - .get(type_name)? - .get(field_name) + ) -> Option<&InputDefinition> { + self.input_field_definitions.get(type_name)?.get(field_name) } - pub(in crate::plugins::demand_control) fn type_field_list_size_directive( + pub(in crate::plugins::demand_control) fn output_field_definition( &self, type_name: &str, field_name: &str, - ) -> Option<&ListSizeDirective> { - self.type_field_list_size_directives - .get(type_name)? - .get(field_name) - } - - pub(in crate::plugins::demand_control) fn type_field_requires_directive( - &self, - type_name: &str, - field_name: &str, - ) -> Option<&RequiresDirective> { - self.type_field_requires_directives + ) -> Option<&FieldDefinition> { + self.output_field_definitions .get(type_name)? .get(field_name) } - - pub(in crate::plugins::demand_control) fn argument_cost_directive( - &self, - definition: &InputValueDefinition, - ty: &ExtendedType, - ) -> Option { - // For now, we ignore FederationError and return None because this should not block the whole scoring - // process at runtime. Later, this should be pushed into the constructor and propagate any federation - // errors encountered when parsing. - CostSpecDefinition::cost_directive_from_argument(&self.inner, definition, ty) - .ok() - .flatten() - } } impl AsRef> for DemandControlledSchema { diff --git a/apollo-router/src/plugins/demand_control/cost_calculator/static_cost.rs b/apollo-router/src/plugins/demand_control/cost_calculator/static_cost.rs index d8887e86a9..7881b5abf8 100644 --- a/apollo-router/src/plugins/demand_control/cost_calculator/static_cost.rs +++ b/apollo-router/src/plugins/demand_control/cost_calculator/static_cost.rs @@ -2,7 +2,6 @@ use std::sync::Arc; use ahash::HashMap; use apollo_compiler::ast; -use apollo_compiler::ast::InputValueDefinition; use apollo_compiler::ast::NamedType; use apollo_compiler::executable::ExecutableDocument; use apollo_compiler::executable::Field; @@ -12,12 +11,12 @@ use apollo_compiler::executable::Operation; use apollo_compiler::executable::Selection; use apollo_compiler::executable::SelectionSet; use apollo_compiler::schema::ExtendedType; -use apollo_compiler::Node; use serde_json_bytes::Value; use super::directives::IncludeDirective; use super::directives::SkipDirective; use super::schema::DemandControlledSchema; +use super::schema::InputDefinition; use super::DemandControlError; use crate::graphql::Response; use crate::graphql::ResponseVisitor; @@ -28,6 +27,7 @@ use crate::query_planner::DeferredNode; use crate::query_planner::PlanNode; use crate::query_planner::Primary; use crate::query_planner::QueryPlan; +use crate::spec::TYPENAME; pub(crate) struct StaticCostCalculator { list_size: u32, @@ -44,49 +44,37 @@ struct ScoringContext<'a> { fn score_argument( argument: &apollo_compiler::ast::Value, - argument_definition: &Node, + argument_definition: &InputDefinition, schema: &DemandControlledSchema, variables: &Object, ) -> Result { - let ty = schema - .types - .get(argument_definition.ty.inner_named_type()) - .ok_or_else(|| { - DemandControlError::QueryParseFailure(format!( - "Argument {} was found in query, but its type ({}) was not found in the schema", - argument_definition.name, - argument_definition.ty.inner_named_type() - )) - })?; - let cost_directive = schema.argument_cost_directive(argument_definition, ty); - - match (argument, ty) { + match (argument, argument_definition.ty()) { (_, ExtendedType::Interface(_)) | (_, ExtendedType::Object(_)) | (_, ExtendedType::Union(_)) => Err(DemandControlError::QueryParseFailure( format!( "Argument {} has type {}, but objects, interfaces, and unions are disallowed in this position", - argument_definition.name, - argument_definition.ty.inner_named_type() + argument_definition.name(), + argument_definition.ty().name() ) )), - (ast::Value::Object(inner_args), ExtendedType::InputObject(inner_arg_defs)) => { - let mut cost = cost_directive.map_or(1.0, |cost| cost.weight()); + (ast::Value::Object(inner_args), ExtendedType::InputObject(_)) => { + let mut cost = argument_definition.cost_directive().map_or(1.0, |cost| cost.weight()); for (arg_name, arg_val) in inner_args { - let arg_def = inner_arg_defs.fields.get(arg_name).ok_or_else(|| { + let arg_def = schema.input_field_definition(argument_definition.ty().name(), arg_name).ok_or_else(|| { DemandControlError::QueryParseFailure(format!( "Argument {} was found in query, but its type ({}) was not found in the schema", - argument_definition.name, - argument_definition.ty.inner_named_type() + arg_name, + argument_definition.ty().name() )) })?; - cost += score_argument(arg_val, arg_def, schema, variables,)?; + cost += score_argument(arg_val, arg_def, schema, variables)?; } Ok(cost) } (ast::Value::List(inner_args), _) => { - let mut cost = cost_directive.map_or(0.0, |cost| cost.weight()); + let mut cost = argument_definition.cost_directive().map_or(0.0, |cost| cost.weight()); for arg_val in inner_args { cost += score_argument(arg_val, argument_definition, schema, variables)?; } @@ -102,46 +90,34 @@ fn score_argument( } } (ast::Value::Null, _) => Ok(0.0), - _ => Ok(cost_directive.map_or(0.0, |cost| cost.weight())) + _ => Ok(argument_definition.cost_directive().map_or(0.0, |cost| cost.weight())) } } fn score_variable( variable: &Value, - argument_definition: &Node, + argument_definition: &InputDefinition, schema: &DemandControlledSchema, ) -> Result { - let ty = schema - .types - .get(argument_definition.ty.inner_named_type()) - .ok_or_else(|| { - DemandControlError::QueryParseFailure(format!( - "Argument {} was found in query, but its type ({}) was not found in the schema", - argument_definition.name, - argument_definition.ty.inner_named_type() - )) - })?; - let cost_directive = schema.argument_cost_directive(argument_definition, ty); - - match (variable, ty) { + match (variable, argument_definition.ty()) { (_, ExtendedType::Interface(_)) | (_, ExtendedType::Object(_)) | (_, ExtendedType::Union(_)) => Err(DemandControlError::QueryParseFailure( format!( "Argument {} has type {}, but objects, interfaces, and unions are disallowed in this position", - argument_definition.name, - argument_definition.ty.inner_named_type() + argument_definition.name(), + argument_definition.ty().name() ) )), - (Value::Object(inner_args), ExtendedType::InputObject(inner_arg_defs)) => { - let mut cost = cost_directive.map_or(1.0, |cost| cost.weight()); + (Value::Object(inner_args), ExtendedType::InputObject(_)) => { + let mut cost = argument_definition.cost_directive().map_or(1.0, |cost| cost.weight()); for (arg_name, arg_val) in inner_args { - let arg_def = inner_arg_defs.fields.get(arg_name.as_str()).ok_or_else(|| { + let arg_def = schema.input_field_definition(argument_definition.ty().name(), arg_name.as_str()).ok_or_else(|| { DemandControlError::QueryParseFailure(format!( "Argument {} was found in query, but its type ({}) was not found in the schema", - argument_definition.name, - argument_definition.ty.inner_named_type() + argument_definition.name(), + argument_definition.ty().name() )) })?; cost += score_variable(arg_val, arg_def, schema)?; @@ -149,14 +125,14 @@ fn score_variable( Ok(cost) } (Value::Array(inner_args), _) => { - let mut cost = cost_directive.map_or(0.0, |cost| cost.weight()); + let mut cost = argument_definition.cost_directive().map_or(0.0, |cost| cost.weight()); for arg_val in inner_args { cost += score_variable(arg_val, argument_definition, schema)?; } Ok(cost) } (Value::Null, _) => Ok(0.0), - _ => Ok(cost_directive.map_or(0.0, |cost| cost.weight())) + _ => Ok(argument_definition.cost_directive().map_or(0.0, |cost| cost.weight())) } } @@ -198,24 +174,23 @@ impl StaticCostCalculator { parent_type: &NamedType, list_size_from_upstream: Option, ) -> Result { + if field.name == TYPENAME { + return Ok(0.0); + } if StaticCostCalculator::skipped_by_directives(field) { return Ok(0.0); } - // We need to look up the `FieldDefinition` from the supergraph schema instead of using `field.definition` - // because `field.definition` was generated from the API schema, which strips off the directives we need. - let definition = ctx.schema.type_field(parent_type, &field.name)?; - let ty = field.inner_type_def(ctx.schema).ok_or_else(|| { - DemandControlError::QueryParseFailure(format!( - "Field {} was found in query, but its type is missing from the schema.", - field.name - )) - })?; - - let list_size_directive = match ctx + let definition = ctx .schema - .type_field_list_size_directive(parent_type, &field.name) - { + .output_field_definition(parent_type, &field.name) + .ok_or_else(|| { + DemandControlError::QueryParseFailure(format!( + "Field {} was found in query, but its type is missing from the schema.", + field.name + )) + })?; + let list_size_directive = match definition.list_size_directive() { Some(dir) => ListSizeDirective::new(dir, field, ctx.variables).map(Some), None => Ok(None), }?; @@ -235,12 +210,12 @@ impl StaticCostCalculator { // Determine the cost for this particular field. Scalars are free, non-scalars are not. // For fields with selections, add in the cost of the selections as well. - let mut type_cost = if let Some(cost_directive) = ctx - .schema - .type_field_cost_directive(parent_type, &field.name) - { + let mut type_cost = if let Some(cost_directive) = definition.cost_directive() { cost_directive.weight() - } else if ty.is_interface() || ty.is_object() || ty.is_union() { + } else if definition.ty().is_interface() + || definition.ty().is_object() + || definition.ty().is_union() + { 1.0 } else { 0.0 @@ -274,10 +249,7 @@ impl StaticCostCalculator { // If the field is marked with `@requires`, the required selection may not be included // in the query's selection. Adding that requirement's cost to the field ensures it's // accounted for. - let requirements = ctx - .schema - .type_field_requires_directive(parent_type, &field.name) - .map(|d| &d.fields); + let requirements = definition.requires_directive().map(|d| &d.fields); if let Some(selection_set) = requirements { requirements_cost = self.score_selection_set( ctx, @@ -559,39 +531,78 @@ impl<'schema> ResponseCostCalculator<'schema> { pub(crate) fn new(schema: &'schema DemandControlledSchema) -> Self { Self { cost: 0.0, schema } } -} -impl ResponseVisitor for ResponseCostCalculator<'_> { - fn visit_field( + fn score_response_field( &mut self, request: &ExecutableDocument, variables: &Object, parent_ty: &NamedType, field: &Field, value: &Value, + include_argument_score: bool, ) { - self.visit_list_item(request, variables, parent_ty, field, value); + if let Some(definition) = self.schema.output_field_definition(parent_ty, &field.name) { + match value { + Value::Null | Value::Bool(_) | Value::Number(_) | Value::String(_) => { + self.cost += definition + .cost_directive() + .map_or(0.0, |cost| cost.weight()); + } + Value::Array(items) => { + for item in items { + self.visit_list_item(request, variables, parent_ty, field, item); + } + } + Value::Object(children) => { + self.cost += definition + .cost_directive() + .map_or(1.0, |cost| cost.weight()); + self.visit_selections(request, variables, &field.selection_set, children); + } + } - let definition = self.schema.type_field(parent_ty, &field.name); - for argument in &field.arguments { - if let Ok(Some(argument_definition)) = definition - .as_ref() - .map(|def| def.argument_by_name(&argument.name)) - { - if let Ok(score) = - score_argument(&argument.value, argument_definition, self.schema, variables) - { - self.cost += score; + if include_argument_score { + for argument in &field.arguments { + if let Some(argument_definition) = definition.argument_by_name(&argument.name) { + if let Ok(score) = score_argument( + &argument.value, + argument_definition, + self.schema, + variables, + ) { + self.cost += score; + } + } else { + tracing::warn!( + "Failed to get schema definition for argument {}.{}({}:). The resulting response cost will be a partial result.", + parent_ty, + field.name, + argument.name, + ) + } } - } else { - tracing::warn!( - "Failed to get schema definition for argument {} of field {}. The resulting actual cost will be a partial result.", - argument.name, - field.name - ) } + } else { + tracing::warn!( + "Failed to get schema definition for field {}.{}. The resulting response cost will be a partial result.", + parent_ty, + field.name, + ) } } +} + +impl ResponseVisitor for ResponseCostCalculator<'_> { + fn visit_field( + &mut self, + request: &ExecutableDocument, + variables: &Object, + parent_ty: &NamedType, + field: &Field, + value: &Value, + ) { + self.score_response_field(request, variables, parent_ty, field, value, true); + } fn visit_list_item( &mut self, @@ -601,24 +612,7 @@ impl ResponseVisitor for ResponseCostCalculator<'_> { field: &apollo_compiler::executable::Field, value: &Value, ) { - let cost_directive = self - .schema - .type_field_cost_directive(parent_ty, &field.name); - - match value { - Value::Null | Value::Bool(_) | Value::Number(_) | Value::String(_) => { - self.cost += cost_directive.map_or(0.0, |cost| cost.weight()); - } - Value::Array(items) => { - for item in items { - self.visit_list_item(request, variables, parent_ty, field, item); - } - } - Value::Object(children) => { - self.cost += cost_directive.map_or(1.0, |cost| cost.weight()); - self.visit_selections(request, variables, &field.selection_set, children); - } - } + self.score_response_field(request, variables, parent_ty, field, value, false); } } From f52bab84301cee3a32254b48562d8cb13998447b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9e?= Date: Thu, 16 Jan 2025 08:58:19 +0000 Subject: [PATCH 06/11] fix(router, only 1.x): fix the `apollo_router_session_count_total` metric (#6539) --- .../maint_renee_migrate_metrics_histograms.md | 5 - .../maint_renee_migrate_metrics_values.md | 6 +- apollo-router/src/axum_factory/listeners.rs | 36 ++++--- apollo-router/src/axum_factory/tests.rs | 93 +++++++++++++++++++ 4 files changed, 118 insertions(+), 22 deletions(-) delete mode 100644 .changesets/maint_renee_migrate_metrics_histograms.md diff --git a/.changesets/maint_renee_migrate_metrics_histograms.md b/.changesets/maint_renee_migrate_metrics_histograms.md deleted file mode 100644 index b78b99d872..0000000000 --- a/.changesets/maint_renee_migrate_metrics_histograms.md +++ /dev/null @@ -1,5 +0,0 @@ -### Migrate histogram metrics to `{f,u}64_histogram!` ([PR #6356](https://github.com/apollographql/router/pull/6356)) - -Updates histogram metrics using the legacy `tracing::info!(histogram.*)` syntax to the new metrics macros. - -By [@goto-bus-stop](https://github.com/goto-bus-stop) in https://github.com/apollographql/router/pull/6356 \ No newline at end of file diff --git a/.changesets/maint_renee_migrate_metrics_values.md b/.changesets/maint_renee_migrate_metrics_values.md index 2bb0ee2e23..19ab1e9815 100644 --- a/.changesets/maint_renee_migrate_metrics_values.md +++ b/.changesets/maint_renee_migrate_metrics_values.md @@ -1,5 +1,5 @@ -### Migrate gauge metrics to OTel instruments ([PR #6476](https://github.com/apollographql/router/pull/6476)) +### Migrate various metrics to OTel instruments ([PR #6476](https://github.com/apollographql/router/pull/6476), [PR #6356](https://github.com/apollographql/router/pull/6356), [PR #6539](https://github.com/apollographql/router/pull/6539)) -Updates gauge metrics using the legacy `tracing::info!(value.*)` syntax to OTel instruments. +Various metrics using our legacy mechanism based on the `tracing` crate are migrated to OTel instruments. -By [@goto-bus-stop](https://github.com/goto-bus-stop) in https://github.com/apollographql/router/pull/6476 \ No newline at end of file +By [@goto-bus-stop](https://github.com/goto-bus-stop) in https://github.com/apollographql/router/pull/6476, https://github.com/apollographql/router/pull/6356, https://github.com/apollographql/router/pull/6539 diff --git a/apollo-router/src/axum_factory/listeners.rs b/apollo-router/src/axum_factory/listeners.rs index 17881d47bb..d691d84c85 100644 --- a/apollo-router/src/axum_factory/listeners.rs +++ b/apollo-router/src/axum_factory/listeners.rs @@ -224,6 +224,19 @@ pub(super) fn serve_router_on_listen_addr( all_connections_stopped_sender: mpsc::Sender<()>, ) -> (impl Future, oneshot::Sender<()>) { let (shutdown_sender, shutdown_receiver) = oneshot::channel::<()>(); + + let meter = meter_provider().meter("apollo/router"); + let total_session_count_instrument = meter + .u64_observable_gauge("apollo_router_session_count_total") + .with_description("Number of currently connected clients") + .with_callback(move |gauge| { + gauge.observe( + TOTAL_SESSION_COUNT.load(Ordering::Relaxed), + &[KeyValue::new("listener", address.to_string())], + ); + }) + .init(); + // this server reproduces most of hyper::server::Server's behaviour // we select over the stop_listen_receiver channel and the listener's // accept future. If the channel received something or the sender @@ -232,18 +245,6 @@ pub(super) fn serve_router_on_listen_addr( let server = async move { tokio::pin!(shutdown_receiver); - let _total_session_count_instrument = meter_provider() - .meter("apollo/router") - .u64_observable_gauge("apollo_router_session_count_total") - .with_description("Number of currently connected clients") - .with_callback(move |gauge| { - gauge.observe( - TOTAL_SESSION_COUNT.load(Ordering::Relaxed), - &[KeyValue::new("listener", address.to_string())], - ); - }) - .init(); - let connection_shutdown = Arc::new(Notify::new()); loop { @@ -263,13 +264,20 @@ pub(super) fn serve_router_on_listen_addr( MAX_FILE_HANDLES_WARN.store(false, Ordering::SeqCst); } - // We only want to recognise sessions if we are the main graphql port. - let _guard = main_graphql_port.then(TotalSessionCountGuard::start); + // The session count instrument must be kept alive as long as any + // request is in flight. So its lifetime is not related to the server + // itself. The simplest way to do this is to hold onto a reference for + // the duration of every request. + let session_count_instrument = total_session_count_instrument.clone(); + // We only want to count sessions if we are the main graphql port. + let session_count_guard = main_graphql_port.then(TotalSessionCountGuard::start); let mut http_config = http_config.clone(); tokio::task::spawn(async move { // this sender must be moved into the session to track that it is still running let _connection_stop_signal = connection_stop_signal; + let _session_count_instrument = session_count_instrument; + let _session_count_guard = session_count_guard; match res { NetworkStream::Tcp(stream) => { diff --git a/apollo-router/src/axum_factory/tests.rs b/apollo-router/src/axum_factory/tests.rs index 7c9c585663..9fe6f489cb 100644 --- a/apollo-router/src/axum_factory/tests.rs +++ b/apollo-router/src/axum_factory/tests.rs @@ -61,6 +61,7 @@ use crate::graphql; use crate::http_server_factory::HttpServerFactory; use crate::http_server_factory::HttpServerHandle; use crate::json_ext::Path; +use crate::metrics::FutureMetricsExt as _; use crate::plugin::test::MockSubgraph; use crate::query_planner::QueryPlannerService; use crate::router_factory::create_plugins; @@ -2351,3 +2352,95 @@ async fn test_supergraph_timeout() { }) ); } + +/// There are two session count gauges: +/// - apollo_router_session_count_total, the number of open client connections +/// - apollo_router_session_count_active, the number of in-flight HTTP requests +/// +/// To test them, we use two hyper clients. Each client has its own connection pool, so by manually +/// sending requests and completing responses, and creating and dropping clients, we can control +/// the amount of open connections and the amount of in-flight requests. +/// +/// XXX(@goto-bus-stop): this only tests the `session_count_total` metric right now. The +/// `session_count_active` metric is reported from inside an axum router, so its lifetime is +/// actually a little shorter than the full request/response cycle, in a way that is not easy to +/// test from the outside. To test it we could use a custom inner service (passed to +/// `init_with_config`) where we can control the progress the inner service makes. +/// For now, I've tested the `session_count_active` metric manually and confirmed its value makes +/// sense... +#[tokio::test] +async fn it_reports_session_count_metric() { + let configuration = Configuration::fake_builder().build().unwrap(); + + async { + let (server, _client) = init_with_config( + router::service::empty().await, + Arc::new(configuration), + MultiMap::new(), + ) + .await + .unwrap(); + + let url = server + .graphql_listen_address() + .as_ref() + .unwrap() + .to_string(); + + let make_request = || { + http::Request::builder() + .uri(&url) + .body(hyper::Body::from(r#"{ "query": "{ me }" }"#)) + .unwrap() + }; + + let client = hyper::Client::new(); + // Create a second client that does not reuse the same connection pool. + let second_client = hyper::Client::new(); + + let first_response = client.request(make_request()).await.unwrap(); + + assert_gauge!( + "apollo_router_session_count_total", + 1, + "listener" = url.clone() + ); + + let second_response = second_client.request(make_request()).await.unwrap(); + + // Both requests are in-flight + assert_gauge!( + "apollo_router_session_count_total", + 2, + "listener" = url.clone() + ); + + _ = hyper::body::to_bytes(first_response.into_body()).await; + + // Connection is still open in the pool even though the request is complete. + assert_gauge!( + "apollo_router_session_count_total", + 2, + "listener" = url.clone() + ); + + _ = hyper::body::to_bytes(second_response.into_body()).await; + + drop(client); + drop(second_client); + + // XXX(@goto-bus-stop): Not ideal, but we would probably have to drop down to very + // low-level hyper primitives to control the shutdown of connections to the required + // extent. 100ms is a long time so I hope it's not flaky. + tokio::time::sleep(Duration::from_millis(100)).await; + + // All connections are closed + assert_gauge!( + "apollo_router_session_count_total", + 0, + "listener" = url.clone() + ); + } + .with_metrics() + .await; +} From 5cf45f7180ee8e4f8c97fbfc397f37774ecf00fd Mon Sep 17 00:00:00 2001 From: Nicolas Moutschen Date: Thu, 16 Jan 2025 12:10:46 +0100 Subject: [PATCH 07/11] chore: address PR review --- .changesets/fix_junior_granddad_salami_dye.md | 4 +-- apollo-router/src/plugins/fleet_detector.rs | 25 ++++++++----------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/.changesets/fix_junior_granddad_salami_dye.md b/.changesets/fix_junior_granddad_salami_dye.md index 9c1604cd3a..5c810c6a6e 100644 --- a/.changesets/fix_junior_granddad_salami_dye.md +++ b/.changesets/fix_junior_granddad_salami_dye.md @@ -1,7 +1,7 @@ ### Fix missing Content-Length header in subgraph requests ([Issue #6503](https://github.com/apollographql/router/issues/6503)) -A new telemetry feature introduced in the Router version 1.59.0 would convert all request bodies to subgraphs into stream to infer the total body sizes. This would cause requests to subgraphs to no longer have a `Content-Length` header, which could cause issues with some GraphQL servers. +A change in `1.59.0` caused the Router to send requests to subgraphs without a `Content-Length` header, which would cause issues with some GraphQL servers that depend on that header. -This solves this issue by using `SizeHint` when possible to infer the body size instead. +This solves the underlying bug and reintroduces the `Content-Length` header. By [@nmoutschen](https://github.com/nmoutschen) in https://github.com/apollographql/router/pull/6538 diff --git a/apollo-router/src/plugins/fleet_detector.rs b/apollo-router/src/plugins/fleet_detector.rs index ac0b1b77cd..97e6524865 100644 --- a/apollo-router/src/plugins/fleet_detector.rs +++ b/apollo-router/src/plugins/fleet_detector.rs @@ -304,20 +304,17 @@ impl PluginPrivate for FleetDetector { // Short-circuit for complete bodies // - // If the `SizeHint` gives us an exact value, where the upper and lower - // bounds are equal, we can use this for the metric and return without - // wrapping the request Body. - if let Some(upper) = size_hint.upper() { - if upper == size_hint.lower() { - let sn = sn.clone(); - u64_counter!( - "apollo.router.operations.fetch.request_size", - "Total number of request bytes for subgraph fetches", - upper, - subgraph.name = sn.to_string() - ); - return body; - } + // If the `SizeHint` gives us an exact value, we can use this for the + // metric and return without wrapping the request Body into a stream. + if let Some(size) = size_hint.exact() { + let sn = sn.clone(); + u64_counter!( + "apollo.router.operations.fetch.request_size", + "Total number of request bytes for subgraph fetches", + size, + subgraph.name = sn.to_string() + ); + return body; } // For streaming bodies, we need to wrap the stream and count bytes as we go From fab42145a0e44a2ed71d8c4b83beda6d54b41564 Mon Sep 17 00:00:00 2001 From: Edward Huang Date: Thu, 16 Jan 2025 13:10:44 -0800 Subject: [PATCH 08/11] docs: add docker compose config example (#6554) Co-authored-by: Maria Elisabeth Schreiber --- .../self-hosted/containerization/docker.mdx | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/source/routing/self-hosted/containerization/docker.mdx b/docs/source/routing/self-hosted/containerization/docker.mdx index 605b8723c1..28a69e5b3b 100644 --- a/docs/source/routing/self-hosted/containerization/docker.mdx +++ b/docs/source/routing/self-hosted/containerization/docker.mdx @@ -24,7 +24,9 @@ The exact image version to use depends on which release you wish to use. In the To run the router, your Docker container must have the [`APOLLO_GRAPH_REF`](/router/configuration/overview#apollo_graph_ref) and [`APOLLO_KEY`](/router/configuration/overview#apollo_key) environment variables set to your graph ref and API key, respectively. -Here's a basic example of running a router image in Docker. Make sure to replace `` with whichever version you want to use, such as `v1.32.0`. +Below is a basic example of running a router image with Docker, either with `docker run` or `docker compose`. It downloads your supergraph schema from Apollo and uses a default configuration that listens for connections on port `4000`. + +You can use `docker run` with the following example command: ```bash title="Docker" docker run -p 4000:4000 \ @@ -34,7 +36,20 @@ docker run -p 4000:4000 \ ghcr.io/apollographql/router: ``` -This command downloads your supergraph schema from Apollo and uses a default configuration that listens for connections on port `4000`. +You can also use `docker compose` with the following example `compose.yaml`: + +```yaml title="compose.yaml" +services: + apollo-router: + image: ghcr.io/apollographql/router: + ports: + - "4000:4000" + environment: + APOLLO_GRAPH_REF: "" + APOLLO_KEY: "" +``` + +Whether you use `docker run` or `docker compose`, make sure to replace `` with whichever version you want to use, such as `v1.58.0`, and `` and `` with your graph reference and API key, respectively. For more complex configurations, such as overriding subgraph URLs or propagating headers, see [Router Configuration](/router/configuration/overview/). From 817e8780571945934559d113f1bf13201109cba2 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 17 Jan 2025 10:01:38 +0100 Subject: [PATCH 09/11] Update to apollo-compiler 1.25.0 stable release (#6556) --- Cargo.lock | 30 +++++++------------ Cargo.toml | 6 ++-- apollo-federation/src/operation/tests/mod.rs | 6 ++-- .../src/query_graph/path_tree.rs | 7 +++-- apollo-federation/src/subgraph/mod.rs | 4 +-- apollo-router/src/error.rs | 4 +-- apollo-router/src/graphql/mod.rs | 8 ++--- apollo-router/src/graphql/response.rs | 23 ++++---------- apollo-router/src/introspection.rs | 19 +++++++----- ...supergraph__tests__invalid_input_enum.snap | 2 +- apollo-router/src/spec/query/transform.rs | 11 +++---- examples/supergraph-sdl/rust/Cargo.toml | 2 +- 12 files changed, 52 insertions(+), 70 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e55d81f838..b8e7a7a518 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -174,9 +174,9 @@ checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "apollo-compiler" -version = "1.0.0-beta.24" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71153ad85c85f7aa63f0e0a5868912c220bb48e4c764556f5841d37fc17b0103" +checksum = "2d810db7b42773a4082426bcd58658cb9b311c5b74febd255130a9dcfc13109d" dependencies = [ "ahash", "apollo-parser", @@ -245,9 +245,9 @@ dependencies = [ [[package]] name = "apollo-parser" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b64257011a999f2e22275cf7a118f651e58dc9170e11b775d435de768fad0387" +checksum = "c8f05cbc7da3c2e3bb2f86e985aad5f72571d2e2cd26faf8caa7782131576f84" dependencies = [ "memchr", "rowan", @@ -470,9 +470,9 @@ dependencies = [ [[package]] name = "apollo-smith" -version = "0.14.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89479524886fdbe62b124d3825879778680e0147304d1a6d32164418f8089a2" +checksum = "95a04f64d4d4f0048201967b8064257de212ab240fd74e2b153691b39b0e8721" dependencies = [ "apollo-compiler", "apollo-parser", @@ -499,9 +499,9 @@ checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" [[package]] name = "ariadne" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44055e597c674aef7cb903b2b9f6e4cba1277ed0d2d61dae7cd52d7ffa81f8e2" +checksum = "31beedec3ce83ae6da3a79592b3d8d7afd146a5b15bb9bb940279aced60faa89" dependencies = [ "concolor", "unicode-width", @@ -4041,15 +4041,6 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -[[package]] -name = "memoffset" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" -dependencies = [ - "autocfg", -] - [[package]] name = "memory-stats" version = "1.2.0" @@ -5584,13 +5575,12 @@ dependencies = [ [[package]] name = "rowan" -version = "0.15.15" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a58fa8a7ccff2aec4f39cc45bf5f985cec7125ab271cf681c279fd00192b49" +checksum = "417a3a9f582e349834051b8a10c8d71ca88da4211e4093528e36b9845f6b5f21" dependencies = [ "countme", "hashbrown 0.14.5", - "memoffset", "rustc-hash", "text-size", ] diff --git a/Cargo.toml b/Cargo.toml index c492b05480..25fd043d7c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,9 +49,9 @@ debug = 1 # Dependencies used in more than one place are specified here in order to keep versions in sync: # https://doc.rust-lang.org/cargo/reference/workspaces.html#the-dependencies-table [workspace.dependencies] -apollo-compiler = "=1.0.0-beta.24" -apollo-parser = "0.8.3" -apollo-smith = "0.14.0" +apollo-compiler = "1.25.0" +apollo-parser = "0.8.4" +apollo-smith = "0.15.0" async-trait = "0.1.77" hex = { version = "0.4.3", features = ["serde"] } http = "0.2.11" diff --git a/apollo-federation/src/operation/tests/mod.rs b/apollo-federation/src/operation/tests/mod.rs index dd90422494..8dfbf599d4 100644 --- a/apollo-federation/src/operation/tests/mod.rs +++ b/apollo-federation/src/operation/tests/mod.rs @@ -1,5 +1,6 @@ use apollo_compiler::collections::IndexSet; use apollo_compiler::name; +use apollo_compiler::parser::Parser; use apollo_compiler::schema::Schema; use apollo_compiler::ExecutableDocument; @@ -29,8 +30,9 @@ macro_rules! assert_normalized { pub(super) fn parse_schema_and_operation( schema_and_operation: &str, ) -> (ValidFederationSchema, ExecutableDocument) { - let (schema, executable_document) = - apollo_compiler::parse_mixed_validate(schema_and_operation, "document.graphql").unwrap(); + let (schema, executable_document) = Parser::new() + .parse_mixed_validate(schema_and_operation, "document.graphql") + .unwrap(); let executable_document = executable_document.into_inner(); let schema = ValidFederationSchema::new(schema).unwrap(); (schema, executable_document) diff --git a/apollo-federation/src/query_graph/path_tree.rs b/apollo-federation/src/query_graph/path_tree.rs index b8564f90ed..b8f59ef2c2 100644 --- a/apollo-federation/src/query_graph/path_tree.rs +++ b/apollo-federation/src/query_graph/path_tree.rs @@ -563,6 +563,7 @@ where mod tests { use std::sync::Arc; + use apollo_compiler::parser::Parser; use apollo_compiler::ExecutableDocument; use petgraph::stable_graph::NodeIndex; use petgraph::visit::EdgeRef; @@ -585,9 +586,9 @@ mod tests { fn parse_schema_and_operation( schema_and_operation: &str, ) -> (ValidFederationSchema, ExecutableDocument) { - let (schema, executable_document) = - apollo_compiler::parse_mixed_validate(schema_and_operation, "document.graphql") - .unwrap(); + let (schema, executable_document) = Parser::new() + .parse_mixed_validate(schema_and_operation, "document.graphql") + .unwrap(); let executable_document = executable_document.into_inner(); let schema = ValidFederationSchema::new(schema).unwrap(); (schema, executable_document) diff --git a/apollo-federation/src/subgraph/mod.rs b/apollo-federation/src/subgraph/mod.rs index d36382e73d..3a79de9aba 100644 --- a/apollo-federation/src/subgraph/mod.rs +++ b/apollo-federation/src/subgraph/mod.rs @@ -119,7 +119,7 @@ impl Subgraph { .schema_definition .make_mut() .directives - .push(defaults.applied_link_directive().into()); + .push(defaults.applied_link_directive()); defaults } }; @@ -136,7 +136,7 @@ impl Subgraph { .schema_definition .make_mut() .directives - .push(defaults.applied_link_directive().into()); + .push(defaults.applied_link_directive()); defaults } }; diff --git a/apollo-router/src/error.rs b/apollo-router/src/error.rs index d20f35cc39..d8000b99cf 100644 --- a/apollo-router/src/error.rs +++ b/apollo-router/src/error.rs @@ -343,7 +343,7 @@ impl IntoGraphQLErrors for FederationErrorBridge { } } -impl IntoGraphQLErrors for Vec { +impl IntoGraphQLErrors for Vec { fn into_graphql_errors(self) -> Result, Self> { Ok(self .into_iter() @@ -550,7 +550,7 @@ impl IntoGraphQLErrors for ParseErrors { /// Collection of schema validation errors. #[derive(Debug, Clone, Serialize, Deserialize)] pub(crate) struct ValidationErrors { - pub(crate) errors: Vec, + pub(crate) errors: Vec, } impl ValidationErrors { diff --git a/apollo-router/src/graphql/mod.rs b/apollo-router/src/graphql/mod.rs index 0ac60d3f69..939a3eb338 100644 --- a/apollo-router/src/graphql/mod.rs +++ b/apollo-router/src/graphql/mod.rs @@ -7,8 +7,8 @@ mod visitor; use std::fmt; use std::pin::Pin; -use apollo_compiler::execution::GraphQLError as CompilerExecutionError; -use apollo_compiler::execution::ResponseDataPathElement; +use apollo_compiler::response::GraphQLError as CompilerExecutionError; +use apollo_compiler::response::ResponseDataPathSegment; use futures::Stream; use heck::ToShoutySnakeCase; pub use request::Request; @@ -233,10 +233,10 @@ impl From for Error { let elements = path .into_iter() .map(|element| match element { - ResponseDataPathElement::Field(name) => { + ResponseDataPathSegment::Field(name) => { JsonPathElement::Key(name.as_str().to_owned(), None) } - ResponseDataPathElement::ListIndex(i) => JsonPathElement::Index(i), + ResponseDataPathSegment::ListIndex(i) => JsonPathElement::Index(i), }) .collect(); Some(Path(elements)) diff --git a/apollo-router/src/graphql/response.rs b/apollo-router/src/graphql/response.rs index 1f710e7add..4c153f694b 100644 --- a/apollo-router/src/graphql/response.rs +++ b/apollo-router/src/graphql/response.rs @@ -1,6 +1,7 @@ #![allow(missing_docs)] // FIXME use std::time::Instant; +use apollo_compiler::response::ExecutionResponse; use bytes::Bytes; use serde::Deserialize; use serde::Serialize; @@ -245,25 +246,13 @@ impl IncrementalResponse { } } -impl From for Response { - fn from(response: apollo_compiler::execution::Response) -> Response { - let apollo_compiler::execution::Response { - errors, - data, - extensions, - } = response; +impl From for Response { + fn from(response: ExecutionResponse) -> Response { + let ExecutionResponse { errors, data } = response; Self { errors: errors.into_graphql_errors().unwrap(), - data: match data { - apollo_compiler::execution::ResponseData::Object(map) => { - Some(serde_json_bytes::Value::Object(map)) - } - apollo_compiler::execution::ResponseData::Null => { - Some(serde_json_bytes::Value::Null) - } - apollo_compiler::execution::ResponseData::Absent => None, - }, - extensions, + data: data.map(serde_json_bytes::Value::Object), + extensions: Default::default(), label: None, path: None, has_next: None, diff --git a/apollo-router/src/introspection.rs b/apollo-router/src/introspection.rs index 20098af96b..29870d9741 100644 --- a/apollo-router/src/introspection.rs +++ b/apollo-router/src/introspection.rs @@ -147,23 +147,26 @@ impl IntrospectionCache { } fn execute_introspection(schema: &spec::Schema, doc: &ParsedDocument) -> graphql::Response { - let schema = schema.api_schema(); + let api_schema = schema.api_schema(); let operation = &doc.operation; let variable_values = Default::default(); - match apollo_compiler::execution::coerce_variable_values( - schema, + match apollo_compiler::request::coerce_variable_values( + api_schema, operation, &variable_values, - ) { - Ok(variable_values) => apollo_compiler::execution::execute_introspection_only_query( - schema, + ) + .and_then(|variable_values| { + apollo_compiler::introspection::partial_execute( + api_schema, + &schema.implementers_map, &doc.executable, operation, &variable_values, ) - .into(), + }) { + Ok(response) => response.into(), Err(e) => { - let error = e.into_graphql_error(&doc.executable.sources); + let error = e.to_graphql_error(&doc.executable.sources); graphql::Response::builder().error(error).build() } } diff --git a/apollo-router/src/services/supergraph/snapshots/apollo_router__services__supergraph__tests__invalid_input_enum.snap b/apollo-router/src/services/supergraph/snapshots/apollo_router__services__supergraph__tests__invalid_input_enum.snap index 0e2dd5d122..d0c6e66d41 100644 --- a/apollo-router/src/services/supergraph/snapshots/apollo_router__services__supergraph__tests__invalid_input_enum.snap +++ b/apollo-router/src/services/supergraph/snapshots/apollo_router__services__supergraph__tests__invalid_input_enum.snap @@ -5,7 +5,7 @@ expression: response { "errors": [ { - "message": "Value \"C does not exist in \"InputEnum\" enum.", + "message": "Value \"C\" does not exist in \"InputEnum\" enum.", "locations": [ { "line": 1, diff --git a/apollo-router/src/spec/query/transform.rs b/apollo-router/src/spec/query/transform.rs index 47b93c75e3..d9da27dde0 100644 --- a/apollo-router/src/spec/query/transform.rs +++ b/apollo-router/src/spec/query/transform.rs @@ -569,13 +569,10 @@ mod tests { def: &ast::Field, ) -> Result, BoxError> { Ok(field(self, field_def, def)?.map(|mut new| { - new.directives.push( - ast::Directive { - name: apollo_compiler::name!("added"), - arguments: Vec::new(), - } - .into(), - ); + new.directives.push(ast::Directive { + name: apollo_compiler::name!("added"), + arguments: Vec::new(), + }); new })) } diff --git a/examples/supergraph-sdl/rust/Cargo.toml b/examples/supergraph-sdl/rust/Cargo.toml index 827e44ed5d..49157427b5 100644 --- a/examples/supergraph-sdl/rust/Cargo.toml +++ b/examples/supergraph-sdl/rust/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] anyhow = "1" -apollo-compiler = "=1.0.0-beta.24" +apollo-compiler = "1.25.0" apollo-router = { path = "../../../apollo-router" } async-trait = "0.1" tower = { version = "0.4", features = ["full"] } From e9f746d45b4e6d8d416b152b72d6ce622a038b6e Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Fri, 17 Jan 2025 17:21:37 +0100 Subject: [PATCH 10/11] Revert "fix(router, only 1.x): fix the `apollo_router_session_count_total` metric (#6539)" This reverts commit f52bab84301cee3a32254b48562d8cb13998447b for the purpose of merging into Router 2.0, as it is only intended for 1.x. --- .../maint_renee_migrate_metrics_histograms.md | 5 + .../maint_renee_migrate_metrics_values.md | 6 +- apollo-router/src/axum_factory/listeners.rs | 36 +++---- apollo-router/src/axum_factory/tests.rs | 93 ------------------- 4 files changed, 22 insertions(+), 118 deletions(-) create mode 100644 .changesets/maint_renee_migrate_metrics_histograms.md diff --git a/.changesets/maint_renee_migrate_metrics_histograms.md b/.changesets/maint_renee_migrate_metrics_histograms.md new file mode 100644 index 0000000000..b78b99d872 --- /dev/null +++ b/.changesets/maint_renee_migrate_metrics_histograms.md @@ -0,0 +1,5 @@ +### Migrate histogram metrics to `{f,u}64_histogram!` ([PR #6356](https://github.com/apollographql/router/pull/6356)) + +Updates histogram metrics using the legacy `tracing::info!(histogram.*)` syntax to the new metrics macros. + +By [@goto-bus-stop](https://github.com/goto-bus-stop) in https://github.com/apollographql/router/pull/6356 \ No newline at end of file diff --git a/.changesets/maint_renee_migrate_metrics_values.md b/.changesets/maint_renee_migrate_metrics_values.md index 19ab1e9815..2bb0ee2e23 100644 --- a/.changesets/maint_renee_migrate_metrics_values.md +++ b/.changesets/maint_renee_migrate_metrics_values.md @@ -1,5 +1,5 @@ -### Migrate various metrics to OTel instruments ([PR #6476](https://github.com/apollographql/router/pull/6476), [PR #6356](https://github.com/apollographql/router/pull/6356), [PR #6539](https://github.com/apollographql/router/pull/6539)) +### Migrate gauge metrics to OTel instruments ([PR #6476](https://github.com/apollographql/router/pull/6476)) -Various metrics using our legacy mechanism based on the `tracing` crate are migrated to OTel instruments. +Updates gauge metrics using the legacy `tracing::info!(value.*)` syntax to OTel instruments. -By [@goto-bus-stop](https://github.com/goto-bus-stop) in https://github.com/apollographql/router/pull/6476, https://github.com/apollographql/router/pull/6356, https://github.com/apollographql/router/pull/6539 +By [@goto-bus-stop](https://github.com/goto-bus-stop) in https://github.com/apollographql/router/pull/6476 \ No newline at end of file diff --git a/apollo-router/src/axum_factory/listeners.rs b/apollo-router/src/axum_factory/listeners.rs index d691d84c85..17881d47bb 100644 --- a/apollo-router/src/axum_factory/listeners.rs +++ b/apollo-router/src/axum_factory/listeners.rs @@ -224,19 +224,6 @@ pub(super) fn serve_router_on_listen_addr( all_connections_stopped_sender: mpsc::Sender<()>, ) -> (impl Future, oneshot::Sender<()>) { let (shutdown_sender, shutdown_receiver) = oneshot::channel::<()>(); - - let meter = meter_provider().meter("apollo/router"); - let total_session_count_instrument = meter - .u64_observable_gauge("apollo_router_session_count_total") - .with_description("Number of currently connected clients") - .with_callback(move |gauge| { - gauge.observe( - TOTAL_SESSION_COUNT.load(Ordering::Relaxed), - &[KeyValue::new("listener", address.to_string())], - ); - }) - .init(); - // this server reproduces most of hyper::server::Server's behaviour // we select over the stop_listen_receiver channel and the listener's // accept future. If the channel received something or the sender @@ -245,6 +232,18 @@ pub(super) fn serve_router_on_listen_addr( let server = async move { tokio::pin!(shutdown_receiver); + let _total_session_count_instrument = meter_provider() + .meter("apollo/router") + .u64_observable_gauge("apollo_router_session_count_total") + .with_description("Number of currently connected clients") + .with_callback(move |gauge| { + gauge.observe( + TOTAL_SESSION_COUNT.load(Ordering::Relaxed), + &[KeyValue::new("listener", address.to_string())], + ); + }) + .init(); + let connection_shutdown = Arc::new(Notify::new()); loop { @@ -264,20 +263,13 @@ pub(super) fn serve_router_on_listen_addr( MAX_FILE_HANDLES_WARN.store(false, Ordering::SeqCst); } - // The session count instrument must be kept alive as long as any - // request is in flight. So its lifetime is not related to the server - // itself. The simplest way to do this is to hold onto a reference for - // the duration of every request. - let session_count_instrument = total_session_count_instrument.clone(); - // We only want to count sessions if we are the main graphql port. - let session_count_guard = main_graphql_port.then(TotalSessionCountGuard::start); + // We only want to recognise sessions if we are the main graphql port. + let _guard = main_graphql_port.then(TotalSessionCountGuard::start); let mut http_config = http_config.clone(); tokio::task::spawn(async move { // this sender must be moved into the session to track that it is still running let _connection_stop_signal = connection_stop_signal; - let _session_count_instrument = session_count_instrument; - let _session_count_guard = session_count_guard; match res { NetworkStream::Tcp(stream) => { diff --git a/apollo-router/src/axum_factory/tests.rs b/apollo-router/src/axum_factory/tests.rs index 9fe6f489cb..7c9c585663 100644 --- a/apollo-router/src/axum_factory/tests.rs +++ b/apollo-router/src/axum_factory/tests.rs @@ -61,7 +61,6 @@ use crate::graphql; use crate::http_server_factory::HttpServerFactory; use crate::http_server_factory::HttpServerHandle; use crate::json_ext::Path; -use crate::metrics::FutureMetricsExt as _; use crate::plugin::test::MockSubgraph; use crate::query_planner::QueryPlannerService; use crate::router_factory::create_plugins; @@ -2352,95 +2351,3 @@ async fn test_supergraph_timeout() { }) ); } - -/// There are two session count gauges: -/// - apollo_router_session_count_total, the number of open client connections -/// - apollo_router_session_count_active, the number of in-flight HTTP requests -/// -/// To test them, we use two hyper clients. Each client has its own connection pool, so by manually -/// sending requests and completing responses, and creating and dropping clients, we can control -/// the amount of open connections and the amount of in-flight requests. -/// -/// XXX(@goto-bus-stop): this only tests the `session_count_total` metric right now. The -/// `session_count_active` metric is reported from inside an axum router, so its lifetime is -/// actually a little shorter than the full request/response cycle, in a way that is not easy to -/// test from the outside. To test it we could use a custom inner service (passed to -/// `init_with_config`) where we can control the progress the inner service makes. -/// For now, I've tested the `session_count_active` metric manually and confirmed its value makes -/// sense... -#[tokio::test] -async fn it_reports_session_count_metric() { - let configuration = Configuration::fake_builder().build().unwrap(); - - async { - let (server, _client) = init_with_config( - router::service::empty().await, - Arc::new(configuration), - MultiMap::new(), - ) - .await - .unwrap(); - - let url = server - .graphql_listen_address() - .as_ref() - .unwrap() - .to_string(); - - let make_request = || { - http::Request::builder() - .uri(&url) - .body(hyper::Body::from(r#"{ "query": "{ me }" }"#)) - .unwrap() - }; - - let client = hyper::Client::new(); - // Create a second client that does not reuse the same connection pool. - let second_client = hyper::Client::new(); - - let first_response = client.request(make_request()).await.unwrap(); - - assert_gauge!( - "apollo_router_session_count_total", - 1, - "listener" = url.clone() - ); - - let second_response = second_client.request(make_request()).await.unwrap(); - - // Both requests are in-flight - assert_gauge!( - "apollo_router_session_count_total", - 2, - "listener" = url.clone() - ); - - _ = hyper::body::to_bytes(first_response.into_body()).await; - - // Connection is still open in the pool even though the request is complete. - assert_gauge!( - "apollo_router_session_count_total", - 2, - "listener" = url.clone() - ); - - _ = hyper::body::to_bytes(second_response.into_body()).await; - - drop(client); - drop(second_client); - - // XXX(@goto-bus-stop): Not ideal, but we would probably have to drop down to very - // low-level hyper primitives to control the shutdown of connections to the required - // extent. 100ms is a long time so I hope it's not flaky. - tokio::time::sleep(Duration::from_millis(100)).await; - - // All connections are closed - assert_gauge!( - "apollo_router_session_count_total", - 0, - "listener" = url.clone() - ); - } - .with_metrics() - .await; -} From ba8b138342aacd6c7c986f9da8aba5f7b5f1d78e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9e=20Kooi?= Date: Mon, 20 Jan 2025 09:15:34 +0100 Subject: [PATCH 11/11] fix(deps): update apollo-compiler JsonMap import --- apollo-router/src/plugins/connectors/tests/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apollo-router/src/plugins/connectors/tests/mod.rs b/apollo-router/src/plugins/connectors/tests/mod.rs index e5c723ff8f..a6fa81ed8c 100644 --- a/apollo-router/src/plugins/connectors/tests/mod.rs +++ b/apollo-router/src/plugins/connectors/tests/mod.rs @@ -1,7 +1,7 @@ use std::str::FromStr; use std::sync::Arc; -use apollo_compiler::execution::JsonMap; +use apollo_compiler::response::JsonMap; use http::header::CONTENT_TYPE; use itertools::EitherOrBoth; use itertools::Itertools;