diff --git a/crates/turborepo-api-client/src/error.rs b/crates/turborepo-api-client/src/error.rs index cf796d2ade757..aabf7a398a0f5 100644 --- a/crates/turborepo-api-client/src/error.rs +++ b/crates/turborepo-api-client/src/error.rs @@ -15,6 +15,8 @@ pub enum Error { TooManyFailures(#[from] Box), #[error("Unable to set up TLS.")] TlsError(#[source] reqwest::Error), + #[error("HTTP client initialization was cancelled (runtime shutting down)")] + HttpClientCancelled, #[error("Error parsing header: {0}")] InvalidHeader(#[from] ToStrError), #[error("Error parsing '{url}' as URL: {err}")] diff --git a/crates/turborepo-api-client/src/telemetry.rs b/crates/turborepo-api-client/src/telemetry.rs index 066ee0b4b7c30..19916eae208c4 100644 --- a/crates/turborepo-api-client/src/telemetry.rs +++ b/crates/turborepo-api-client/src/telemetry.rs @@ -1,9 +1,10 @@ -use std::future::Future; +use std::{future::Future, sync::Arc}; use reqwest::Method; +use tokio::sync::OnceCell; use turborepo_vercel_api::telemetry::TelemetryEvent; -use crate::{AnonAPIClient, Error, retry}; +use crate::{APIClient, AnonAPIClient, Error, build_user_agent, retry}; const TELEMETRY_ENDPOINT: &str = "/api/turborepo/v1/events"; @@ -41,3 +42,69 @@ impl TelemetryClient for AnonAPIClient { Ok(()) } } + +/// A telemetry client backed by an HTTP client that initializes on a +/// background thread. TLS initialization (~100ms) starts as early as +/// possible via `spawn_blocking`; this client shares the `OnceCell` that +/// the background task writes to. By the time telemetry flushes its +/// first batch, TLS init has almost certainly already completed. +#[derive(Clone)] +pub struct DeferredTelemetryClient { + http_client: Arc>, + base_url: String, + user_agent: String, +} + +impl DeferredTelemetryClient { + pub fn new( + http_client: Arc>, + base_url: impl Into, + version: &str, + ) -> Self { + Self { + http_client, + base_url: base_url.into(), + user_agent: build_user_agent(version), + } + } +} + +impl TelemetryClient for DeferredTelemetryClient { + async fn record_telemetry( + &self, + events: Vec, + telemetry_id: &str, + session_id: &str, + ) -> Result<(), Error> { + // Fast path: background TLS init already completed. + // Slow path: initialize inline, but if the runtime is shutting down + // the spawn_blocking task will be cancelled — return an error instead + // of panicking. Telemetry is never worth crashing over. + let maybe_client; + let client = match self.http_client.get() { + Some(client) => client, + None => { + maybe_client = tokio::task::spawn_blocking(|| APIClient::build_http_client(None)) + .await + .map_err(|_| Error::HttpClientCancelled)??; + &maybe_client + } + }; + + let url = format!("{}{}", self.base_url, TELEMETRY_ENDPOINT); + let telemetry_request = client + .request(Method::POST, url) + .header("User-Agent", self.user_agent.clone()) + .header("Content-Type", "application/json") + .header("x-turbo-telemetry-id", telemetry_id) + .header("x-turbo-session-id", session_id) + .json(&events); + + retry::make_retryable_request(telemetry_request, retry::RetryStrategy::Timeout) + .await? + .into_response() + .error_for_status()?; + + Ok(()) + } +} diff --git a/crates/turborepo-lib/src/cli/error.rs b/crates/turborepo-lib/src/cli/error.rs index bf97c8dd645be..555390ad26e86 100644 --- a/crates/turborepo-lib/src/cli/error.rs +++ b/crates/turborepo-lib/src/cli/error.rs @@ -92,7 +92,7 @@ pub async fn print_potential_tasks( let color_config = base.color_config; let run_builder = RunBuilder::new(base, None)?; - let run = run_builder.build(&handler, telemetry).await?; + let (run, _analytics) = run_builder.build(&handler, telemetry).await?; let potential_tasks = run.get_potential_tasks()?; println!("No tasks provided, here are some potential ones\n",); diff --git a/crates/turborepo-lib/src/cli/mod.rs b/crates/turborepo-lib/src/cli/mod.rs index 4ac5c01dd92a7..c4556aeddc529 100644 --- a/crates/turborepo-lib/src/cli/mod.rs +++ b/crates/turborepo-lib/src/cli/mod.rs @@ -1158,6 +1158,25 @@ fn initialize_telemetry_client( } } +fn initialize_deferred_telemetry_client( + http_client_cell: std::sync::Arc>, + color_config: ColorConfig, + version: &str, +) -> Option { + let deferred_client = turborepo_api_client::telemetry::DeferredTelemetryClient::new( + http_client_cell, + "https://telemetry.vercel.com", + version, + ); + match init_telemetry(deferred_client, color_config) { + Ok(h) => Some(h), + Err(error) => { + debug!("failed to start telemetry: {:?}", error); + None + } + } +} + #[derive(PartialEq)] enum PrintVersionState { Enabled, @@ -1300,21 +1319,38 @@ pub async fn run( ) -> Result { let _cli_run_span = tracing::info_span!("cli_run").entered(); + // Spawn TLS initialization on a background thread immediately. + // This takes ~100ms (loading root certificates, TLS backend init) + // and runs fully in the background. Neither telemetry nor the run + // path block on it — the HTTP client is resolved lazily when the + // first network request is actually needed. + let http_client_cell = std::sync::Arc::new(tokio::sync::OnceCell::::new()); + { + let cell = http_client_cell.clone(); + tokio::task::spawn(async move { + if let Ok(Ok(client)) = tokio::task::spawn_blocking(|| { + let _span = tracing::info_span!("http_client_init").entered(); + APIClient::build_http_client(None) + }) + .await + { + cell.set(client).ok(); + } + }); + } + let mut cli_args = { let _span = tracing::info_span!("cli_arg_parsing").entered(); Args::new(env::args_os().collect()) }; let version = get_version(); - let http_client = { - let _span = tracing::info_span!("http_client_init").entered(); - APIClient::build_http_client(None) - .expect("Failed to create HTTP client: TLS initialization failed") - }; - + // Initialize telemetry immediately with a deferred HTTP client. + // Events are queued to a channel from the start; the actual HTTP + // client is only resolved when the worker flushes its first batch. let telemetry_handle = { let _span = tracing::info_span!("telemetry_init").entered(); - initialize_telemetry_client(&http_client, color_config, version) + initialize_deferred_telemetry_client(http_client_cell.clone(), color_config, version) }; if should_print_version() { @@ -1326,9 +1362,6 @@ pub async fn run( // Set some run flags if we have the data and are executing a Run set_run_flags(&mut command, &repo_state, &cli_args)?; - // TODO: make better use of RepoState, here and below. We've already inferred - // the repo root, we don't need to calculate it again, along with package - // manager inference. let cwd = repo_state .as_ref() .map(|state| state.root.as_path()) @@ -1611,11 +1644,13 @@ pub async fn run( } run_args.track(&event); - let exit_code = run::run(base, event, &http_client).await.inspect(|code| { - if *code != 0 { - error!("run failed: command exited ({code})"); - } - })?; + let exit_code = run::run(base, event, http_client_cell) + .await + .inspect(|code| { + if *code != 0 { + error!("run failed: command exited ({code})"); + } + })?; // Chrome tracing is enabled early in shim::run(). Here we just // flush and generate the markdown summary. diff --git a/crates/turborepo-lib/src/commands/boundaries.rs b/crates/turborepo-lib/src/commands/boundaries.rs index f66cb784e62a1..fb7c472af9a9c 100644 --- a/crates/turborepo-lib/src/commands/boundaries.rs +++ b/crates/turborepo-lib/src/commands/boundaries.rs @@ -18,7 +18,7 @@ pub async fn run( let signal = get_signal()?; let handler = SignalHandler::new(signal); - let run = RunBuilder::new(base, None)? + let (run, _analytics) = RunBuilder::new(base, None)? .do_not_validate_engine() .build(&handler, telemetry) .await?; diff --git a/crates/turborepo-lib/src/commands/ls.rs b/crates/turborepo-lib/src/commands/ls.rs index bfe2f7a35216c..385209c5523fe 100644 --- a/crates/turborepo-lib/src/commands/ls.rs +++ b/crates/turborepo-lib/src/commands/ls.rs @@ -125,7 +125,7 @@ pub async fn run( let handler = SignalHandler::new(signal); let run_builder = RunBuilder::new(base, None)?; - let run = run_builder.build(&handler, telemetry).await?; + let (run, _analytics) = run_builder.build(&handler, telemetry).await?; if packages.is_empty() { RepositoryDetails::new(&run).print(output)?; diff --git a/crates/turborepo-lib/src/commands/query.rs b/crates/turborepo-lib/src/commands/query.rs index 8dcdf18c6a5b8..a8398a01560ac 100644 --- a/crates/turborepo-lib/src/commands/query.rs +++ b/crates/turborepo-lib/src/commands/query.rs @@ -167,7 +167,7 @@ pub async fn run( let run_builder = RunBuilder::new(base, None)? .add_all_tasks() .do_not_validate_engine(); - let run = run_builder.build(&handler, telemetry).await?; + let (run, _analytics) = run_builder.build(&handler, telemetry).await?; let query = query.as_deref().or(include_schema.then_some(SCHEMA_QUERY)); if let Some(query) = query { let trimmed_query = query.trim(); diff --git a/crates/turborepo-lib/src/commands/run.rs b/crates/turborepo-lib/src/commands/run.rs index cd823e11a36e1..6635c2db05d1c 100644 --- a/crates/turborepo-lib/src/commands/run.rs +++ b/crates/turborepo-lib/src/commands/run.rs @@ -11,24 +11,21 @@ use crate::{commands::CommandBase, run, run::builder::RunBuilder}; pub async fn run( base: CommandBase, telemetry: CommandEventBuilder, - http_client: &reqwest::Client, + http_client_cell: Arc>, ) -> Result { let signal = get_signal()?; let handler = SignalHandler::new(signal); let run_builder = { let _span = tracing::info_span!("run_builder_new").entered(); - RunBuilder::new(base, Some(http_client))? + RunBuilder::new(base, Some(http_client_cell))? }; let run_fut = async { - let (analytics_sender, analytics_handle) = run_builder.start_analytics(); - let run = Arc::new( - run_builder - .with_analytics_sender(analytics_sender) - .build(&handler, telemetry) - .await?, - ); + let (run, analytics_handle) = { + let (run, analytics_handle) = run_builder.build(&handler, telemetry).await?; + (Arc::new(run), analytics_handle) + }; let (sender, handle) = { let _span = tracing::info_span!("start_ui").entered(); diff --git a/crates/turborepo-lib/src/run/builder.rs b/crates/turborepo-lib/src/run/builder.rs index 6a58569b0889b..28aaba4f95db9 100644 --- a/crates/turborepo-lib/src/run/builder.rs +++ b/crates/turborepo-lib/src/run/builder.rs @@ -6,9 +6,9 @@ use std::{ }; use chrono::Local; -use tracing::{debug, Instrument}; +use tracing::Instrument; use turbopath::{AbsoluteSystemPath, AbsoluteSystemPathBuf}; -use turborepo_analytics::{start_analytics, AnalyticsHandle, AnalyticsSender}; +use turborepo_analytics::{start_analytics, AnalyticsHandle}; use turborepo_api_client::{APIAuth, APIClient}; use turborepo_cache::AsyncCache; use turborepo_env::EnvironmentVariableMap; @@ -49,8 +49,7 @@ pub struct RunBuilder { repo_root: AbsoluteSystemPathBuf, color_config: ColorConfig, version: &'static str, - api_client: APIClient, - analytics_sender: Option, + http_client_cell: Arc>, // In watch mode, we can have a changed package that we want to serve as an entrypoint. // We will then prune away any tasks that do not depend on tasks inside // this package. @@ -64,12 +63,12 @@ pub struct RunBuilder { impl RunBuilder { #[tracing::instrument(skip_all)] - pub fn new(base: CommandBase, http_client: Option<&reqwest::Client>) -> Result { - let api_client = match http_client { - Some(client) => base.api_client_with_http(client), - None => base.api_client()?, - }; - + pub fn new( + base: CommandBase, + http_client_cell: Option>>, + ) -> Result { + let http_client_cell = + http_client_cell.unwrap_or_else(|| Arc::new(tokio::sync::OnceCell::new())); let opts = base.opts(); let api_auth = base.api_auth()?; @@ -92,12 +91,11 @@ impl RunBuilder { Ok(Self { processes, opts, - api_client, + http_client_cell, repo_root, color_config: ui, version, api_auth, - analytics_sender: None, entrypoint_packages: None, should_print_prelude_override: None, should_validate_engine: true, @@ -129,11 +127,6 @@ impl RunBuilder { self.opts.run_opts.dry_run.is_none() && self.opts.run_opts.graph.is_none() } - pub fn with_analytics_sender(mut self, analytics_sender: Option) -> Self { - self.analytics_sender = analytics_sender; - self - } - pub fn calculate_filtered_packages( repo_root: &AbsoluteSystemPath, opts: &Opts, @@ -172,25 +165,12 @@ impl RunBuilder { Ok(filtered_pkgs) } - // Starts analytics and returns handle. This is not included in the main `build` - // function because we don't want the handle stored in the `Run` struct. - pub fn start_analytics(&self) -> (Option, Option) { - // If there's no API auth, we don't want to record analytics - let Some(api_auth) = self.api_auth.clone() else { - return (None, None); - }; - api_auth - .is_linked() - .then(|| start_analytics(api_auth, self.api_client.clone())) - .unzip() - } - #[tracing::instrument(skip(self, signal_handler))] pub async fn build( - mut self, + self, signal_handler: &SignalHandler, telemetry: CommandEventBuilder, - ) -> Result { + ) -> Result<(Run, Option), Error> { tracing::trace!( platform = %TurboState::platform_name(), start_time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).expect("system time after epoch").as_micros(), @@ -229,7 +209,7 @@ impl RunBuilder { // we only track the remote cache if we're linked because this defaults to // Vercel if is_linked { - run_telemetry.track_remote_cache(self.api_client.base_url()); + run_telemetry.track_remote_cache(&self.opts.api_client_opts.api_url); } let _is_structured_output = self.opts.run_opts.graph.is_some() || matches!(self.opts.run_opts.dry_run, Some(DryRunMode::Json)); @@ -293,22 +273,56 @@ impl RunBuilder { .await .expect("detecting scm panicked"); let repo_index = Arc::new(repo_index); - debug!( - "RunBuilder creating AsyncCache with cache_dir={}, repo_root={}", - self.opts.cache_opts.cache_dir, self.repo_root - ); + + // Resolve the HTTP client. TLS initialization has been running in the + // background since cli::run started, overlapping with arg parsing, + // config loading, package graph construction, and SCM indexing. + let api_client = { + let _span = tracing::info_span!("resolve_api_client").entered(); + let http_client = match self.http_client_cell.get() { + Some(client) => client.clone(), + None => tokio::task::spawn_blocking(|| APIClient::build_http_client(None)) + .await + .map_err(|_| turborepo_api_client::Error::HttpClientCancelled)??, + }; + let timeout = self.opts.api_client_opts.timeout; + let upload_timeout = self.opts.api_client_opts.upload_timeout; + APIClient::new_with_client( + http_client.clone(), + &self.opts.api_client_opts.api_url, + if timeout > 0 { + Some(std::time::Duration::from_secs(timeout)) + } else { + None + }, + if upload_timeout > 0 { + Some(std::time::Duration::from_secs(upload_timeout)) + } else { + None + }, + self.version, + self.opts.api_client_opts.preflight, + ) + }; + + let (analytics_sender, analytics_handle) = self + .api_auth + .as_ref() + .filter(|auth| auth.is_linked()) + .map(|auth| start_analytics(auth.clone(), api_client.clone())) + .unzip(); + let async_cache = { let _span = tracing::info_span!("async_cache_new").entered(); AsyncCache::new( &self.opts.cache_opts, &self.repo_root, - self.api_client.clone(), + api_client.clone(), self.api_auth.clone(), - self.analytics_sender.take(), + analytics_sender, )? }; - // restore config from task access trace if it's enabled let task_access = TaskAccess::new(self.repo_root.clone(), async_cache.clone(), &scm); task_access.restore_config().await; @@ -407,30 +421,33 @@ impl RunBuilder { .should_print_prelude_override .unwrap_or_else(|| self.will_execute_tasks()); - Ok(Run { - version: self.version, - color_config: self.color_config, - start_at, - processes: self.processes, - run_telemetry, - task_access, - repo_root: self.repo_root, - opts: Arc::new(self.opts), - api_client: self.api_client, - api_auth: self.api_auth, - env_at_execution_start, - filtered_pkgs: filtered_pkgs.keys().cloned().collect(), - pkg_dep_graph: Arc::new(pkg_dep_graph), - turbo_json_loader, - root_turbo_json, - scm, - engine: Arc::new(engine), - run_cache, - signal_handler: signal_handler.clone(), - should_print_prelude, - micro_frontend_configs, - repo_index, - }) + Ok(( + Run { + version: self.version, + color_config: self.color_config, + start_at, + processes: self.processes, + run_telemetry, + task_access, + repo_root: self.repo_root, + opts: Arc::new(self.opts), + api_client, + api_auth: self.api_auth, + env_at_execution_start, + filtered_pkgs: filtered_pkgs.keys().cloned().collect(), + pkg_dep_graph: Arc::new(pkg_dep_graph), + turbo_json_loader, + root_turbo_json, + scm, + engine: Arc::new(engine), + run_cache, + signal_handler: signal_handler.clone(), + should_print_prelude, + micro_frontend_configs, + repo_index, + }, + analytics_handle, + )) } #[tracing::instrument(skip_all)] diff --git a/crates/turborepo-lib/src/run/error.rs b/crates/turborepo-lib/src/run/error.rs index 19f0f91832a9d..0dcc63f3643d2 100644 --- a/crates/turborepo-lib/src/run/error.rs +++ b/crates/turborepo-lib/src/run/error.rs @@ -59,4 +59,6 @@ pub enum Error { MicroFrontends(#[from] turborepo_microfrontends::Error), #[error("Microfrontends proxy error: {0}")] Proxy(String), + #[error(transparent)] + ApiClient(#[from] turborepo_api_client::Error), } diff --git a/crates/turborepo-lib/src/run/task_access.rs b/crates/turborepo-lib/src/run/task_access.rs index f131478a8e06b..18846be866b1a 100644 --- a/crates/turborepo-lib/src/run/task_access.rs +++ b/crates/turborepo-lib/src/run/task_access.rs @@ -188,6 +188,13 @@ impl TaskAccess { self.enabled } + /// Check if task access tracing is enabled without constructing the + /// full TaskAccess (which requires a cache). Used early in the build + /// pipeline before the HTTP client is available. + pub fn check_enabled(repo_root: &AbsoluteSystemPathBuf) -> bool { + task_access_trace_enabled(repo_root).unwrap_or(false) + } + pub async fn restore_config(&self) { match (self.enabled, &self.config_cache) { (true, Some(config_cache)) => match config_cache.restore().await { diff --git a/crates/turborepo-lib/src/run/watch.rs b/crates/turborepo-lib/src/run/watch.rs index 77a54a896e77f..b64cc302bf04e 100644 --- a/crates/turborepo-lib/src/run/watch.rs +++ b/crates/turborepo-lib/src/run/watch.rs @@ -122,11 +122,10 @@ impl WatchClient { let standard_config_path = resolve_turbo_config_path(&base.repo_root)?; let new_base = base.clone(); - let run = Arc::new( - RunBuilder::new(new_base, None)? - .build(&handler, telemetry.clone()) - .await?, - ); + let (run, _analytics) = RunBuilder::new(new_base, None)? + .build(&handler, telemetry.clone()) + .await?; + let run = Arc::new(run); let watched_packages = run.get_relevant_packages(); @@ -355,7 +354,7 @@ impl WatchClient { let signal_handler = self.handler.clone(); let telemetry = self.telemetry.clone(); - let run = RunBuilder::new(new_base, None)? + let (run, _analytics) = RunBuilder::new(new_base, None)? .with_entrypoint_packages(packages) .hide_prelude() .build(&signal_handler, telemetry) @@ -389,11 +388,11 @@ impl WatchClient { ); // rebuild run struct - self.run = RunBuilder::new(base.clone(), None)? + let (run, _analytics) = RunBuilder::new(base.clone(), None)? .hide_prelude() .build(&self.handler, self.telemetry.clone()) - .await? - .into(); + .await?; + self.run = run.into(); self.watched_packages = self.run.get_relevant_packages(); diff --git a/examples/basic/apps/docs/tsconfig.json b/examples/basic/apps/docs/tsconfig.json index efd817de77baa..c0346be081be2 100644 --- a/examples/basic/apps/docs/tsconfig.json +++ b/examples/basic/apps/docs/tsconfig.json @@ -15,7 +15,5 @@ "next.config.js", ".next/types/**/*.ts" ], - "exclude": [ - "node_modules" - ] + "exclude": ["node_modules"] } diff --git a/examples/basic/apps/web/tsconfig.json b/examples/basic/apps/web/tsconfig.json index efd817de77baa..c0346be081be2 100644 --- a/examples/basic/apps/web/tsconfig.json +++ b/examples/basic/apps/web/tsconfig.json @@ -15,7 +15,5 @@ "next.config.js", ".next/types/**/*.ts" ], - "exclude": [ - "node_modules" - ] + "exclude": ["node_modules"] } diff --git a/examples/design-system/apps/docs/tsconfig.json b/examples/design-system/apps/docs/tsconfig.json index cf07022ad29f3..08848e3d6389c 100644 --- a/examples/design-system/apps/docs/tsconfig.json +++ b/examples/design-system/apps/docs/tsconfig.json @@ -1,11 +1,7 @@ { "extends": "@repo/typescript-config/react-app.json", "include": ["."], - "exclude": [ - "dist", - "build", - "node_modules" - ], + "exclude": ["dist", "build", "node_modules"], "compilerOptions": { "strictNullChecks": true } diff --git a/examples/design-system/packages/ui/tsconfig.json b/examples/design-system/packages/ui/tsconfig.json index 82301fe47b4db..2d8a4f4624b04 100644 --- a/examples/design-system/packages/ui/tsconfig.json +++ b/examples/design-system/packages/ui/tsconfig.json @@ -1,11 +1,7 @@ { "extends": "@repo/typescript-config/react-library.json", "include": ["."], - "exclude": [ - "dist", - "build", - "node_modules" - ], + "exclude": ["dist", "build", "node_modules"], "compilerOptions": { "strictNullChecks": true } diff --git a/examples/kitchen-sink/packages/logger/tsconfig.json b/examples/kitchen-sink/packages/logger/tsconfig.json index fa1f75ada7108..6c527e52573c4 100644 --- a/examples/kitchen-sink/packages/logger/tsconfig.json +++ b/examples/kitchen-sink/packages/logger/tsconfig.json @@ -3,12 +3,9 @@ "compilerOptions": { "lib": ["ES2015"], "outDir": "./dist", - "types": [ - "jest", - "node" - ], + "types": ["jest", "node"], "strictNullChecks": true }, "include": ["."], - "exclude": ["node_modules", "dist"], + "exclude": ["node_modules", "dist"] } diff --git a/examples/kitchen-sink/packages/ui/tsconfig.json b/examples/kitchen-sink/packages/ui/tsconfig.json index 8a15b2df4fc06..2b26763ece677 100644 --- a/examples/kitchen-sink/packages/ui/tsconfig.json +++ b/examples/kitchen-sink/packages/ui/tsconfig.json @@ -3,10 +3,7 @@ "compilerOptions": { "lib": ["dom", "ES2015"], "sourceMap": true, - "types": [ - "jest", - "node" - ], + "types": ["jest", "node"], "strictNullChecks": true }, "include": ["."], diff --git a/examples/with-angular/apps/docs/tsconfig.app.json b/examples/with-angular/apps/docs/tsconfig.app.json index ddb3575139e0e..7ee0c959f3dc6 100644 --- a/examples/with-angular/apps/docs/tsconfig.app.json +++ b/examples/with-angular/apps/docs/tsconfig.app.json @@ -6,10 +6,6 @@ "types": [], "strictNullChecks": true }, - "files": [ - "src/main.ts" - ], - "include": [ - "src/**/*.d.ts" - ] + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"] } diff --git a/examples/with-angular/apps/docs/tsconfig.spec.json b/examples/with-angular/apps/docs/tsconfig.spec.json index b55354cdcb1f0..872c79ce8a608 100644 --- a/examples/with-angular/apps/docs/tsconfig.spec.json +++ b/examples/with-angular/apps/docs/tsconfig.spec.json @@ -3,13 +3,8 @@ "extends": "./tsconfig.json", "compilerOptions": { "outDir": "./out-tsc/spec", - "types": [ - "jasmine" - ], + "types": ["jasmine"], "strictNullChecks": true }, - "include": [ - "src/**/*.spec.ts", - "src/**/*.d.ts" - ] + "include": ["src/**/*.spec.ts", "src/**/*.d.ts"] } diff --git a/examples/with-angular/apps/web/tsconfig.app.json b/examples/with-angular/apps/web/tsconfig.app.json index ddb3575139e0e..7ee0c959f3dc6 100644 --- a/examples/with-angular/apps/web/tsconfig.app.json +++ b/examples/with-angular/apps/web/tsconfig.app.json @@ -6,10 +6,6 @@ "types": [], "strictNullChecks": true }, - "files": [ - "src/main.ts" - ], - "include": [ - "src/**/*.d.ts" - ] + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"] } diff --git a/examples/with-angular/apps/web/tsconfig.spec.json b/examples/with-angular/apps/web/tsconfig.spec.json index b55354cdcb1f0..872c79ce8a608 100644 --- a/examples/with-angular/apps/web/tsconfig.spec.json +++ b/examples/with-angular/apps/web/tsconfig.spec.json @@ -3,13 +3,8 @@ "extends": "./tsconfig.json", "compilerOptions": { "outDir": "./out-tsc/spec", - "types": [ - "jasmine" - ], + "types": ["jasmine"], "strictNullChecks": true }, - "include": [ - "src/**/*.spec.ts", - "src/**/*.d.ts" - ] + "include": ["src/**/*.spec.ts", "src/**/*.d.ts"] } diff --git a/examples/with-angular/packages/ui/projects/ui/tsconfig.spec.json b/examples/with-angular/packages/ui/projects/ui/tsconfig.spec.json index 029f6e00a8cb7..fe3b7da6feb45 100644 --- a/examples/with-angular/packages/ui/projects/ui/tsconfig.spec.json +++ b/examples/with-angular/packages/ui/projects/ui/tsconfig.spec.json @@ -3,13 +3,8 @@ "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "../../out-tsc/spec", - "types": [ - "jasmine" - ], + "types": ["jasmine"], "strictNullChecks": true }, - "include": [ - "**/*.spec.ts", - "**/*.d.ts" - ] + "include": ["**/*.spec.ts", "**/*.d.ts"] } diff --git a/examples/with-berry/packages/ui/tsconfig.json b/examples/with-berry/packages/ui/tsconfig.json index 82301fe47b4db..2d8a4f4624b04 100644 --- a/examples/with-berry/packages/ui/tsconfig.json +++ b/examples/with-berry/packages/ui/tsconfig.json @@ -1,11 +1,7 @@ { "extends": "@repo/typescript-config/react-library.json", "include": ["."], - "exclude": [ - "dist", - "build", - "node_modules" - ], + "exclude": ["dist", "build", "node_modules"], "compilerOptions": { "strictNullChecks": true } diff --git a/examples/with-biome/apps/docs/tsconfig.json b/examples/with-biome/apps/docs/tsconfig.json index 6d598a6a2163b..c0346be081be2 100644 --- a/examples/with-biome/apps/docs/tsconfig.json +++ b/examples/with-biome/apps/docs/tsconfig.json @@ -1,19 +1,19 @@ { - "extends": "@repo/typescript-config/nextjs.json", - "compilerOptions": { - "plugins": [ - { - "name": "next" - } + "extends": "@repo/typescript-config/nextjs.json", + "compilerOptions": { + "plugins": [ + { + "name": "next" + } ], "strictNullChecks": true - }, - "include": [ - "**/*.ts", - "**/*.tsx", - "next-env.d.ts", - "next.config.js", - ".next/types/**/*.ts" - ], - "exclude": ["node_modules"] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + "next-env.d.ts", + "next.config.js", + ".next/types/**/*.ts" + ], + "exclude": ["node_modules"] } diff --git a/examples/with-biome/apps/web/tsconfig.json b/examples/with-biome/apps/web/tsconfig.json index 6d598a6a2163b..c0346be081be2 100644 --- a/examples/with-biome/apps/web/tsconfig.json +++ b/examples/with-biome/apps/web/tsconfig.json @@ -1,19 +1,19 @@ { - "extends": "@repo/typescript-config/nextjs.json", - "compilerOptions": { - "plugins": [ - { - "name": "next" - } + "extends": "@repo/typescript-config/nextjs.json", + "compilerOptions": { + "plugins": [ + { + "name": "next" + } ], "strictNullChecks": true - }, - "include": [ - "**/*.ts", - "**/*.tsx", - "next-env.d.ts", - "next.config.js", - ".next/types/**/*.ts" - ], - "exclude": ["node_modules"] + }, + "include": [ + "**/*.ts", + "**/*.tsx", + "next-env.d.ts", + "next.config.js", + ".next/types/**/*.ts" + ], + "exclude": ["node_modules"] } diff --git a/examples/with-biome/packages/ui/tsconfig.json b/examples/with-biome/packages/ui/tsconfig.json index 5793262545022..ed023ce414ae3 100644 --- a/examples/with-biome/packages/ui/tsconfig.json +++ b/examples/with-biome/packages/ui/tsconfig.json @@ -1,9 +1,9 @@ { - "extends": "@repo/typescript-config/react-library.json", - "compilerOptions": { + "extends": "@repo/typescript-config/react-library.json", + "compilerOptions": { "outDir": "dist", "strictNullChecks": true - }, - "include": ["src"], - "exclude": ["node_modules", "dist"] + }, + "include": ["src"], + "exclude": ["node_modules", "dist"] } diff --git a/examples/with-changesets/packages/acme-core/tsconfig.json b/examples/with-changesets/packages/acme-core/tsconfig.json index bbc6d43ee8701..32260d5a42351 100644 --- a/examples/with-changesets/packages/acme-core/tsconfig.json +++ b/examples/with-changesets/packages/acme-core/tsconfig.json @@ -1,11 +1,7 @@ { "extends": "@acme/tsconfig/react-library.json", "include": ["."], - "exclude": [ - "dist", - "build", - "node_modules" - ], + "exclude": ["dist", "build", "node_modules"], "compilerOptions": { "strictNullChecks": true } diff --git a/examples/with-changesets/packages/acme-utils/tsconfig.json b/examples/with-changesets/packages/acme-utils/tsconfig.json index bbc6d43ee8701..32260d5a42351 100644 --- a/examples/with-changesets/packages/acme-utils/tsconfig.json +++ b/examples/with-changesets/packages/acme-utils/tsconfig.json @@ -1,11 +1,7 @@ { "extends": "@acme/tsconfig/react-library.json", "include": ["."], - "exclude": [ - "dist", - "build", - "node_modules" - ], + "exclude": ["dist", "build", "node_modules"], "compilerOptions": { "strictNullChecks": true } diff --git a/examples/with-docker/apps/web/tsconfig.json b/examples/with-docker/apps/web/tsconfig.json index b5fd6f7072d4c..36efe2bb5ac87 100644 --- a/examples/with-docker/apps/web/tsconfig.json +++ b/examples/with-docker/apps/web/tsconfig.json @@ -8,6 +8,12 @@ ], "strictNullChecks": true }, - "include": ["next-env.d.ts", "next.config.js", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "include": [ + "next-env.d.ts", + "next.config.js", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts" + ], "exclude": ["node_modules"] } diff --git a/examples/with-docker/packages/logger/tsconfig.json b/examples/with-docker/packages/logger/tsconfig.json index 7a773f67154da..af40419b0cb6c 100644 --- a/examples/with-docker/packages/logger/tsconfig.json +++ b/examples/with-docker/packages/logger/tsconfig.json @@ -4,10 +4,7 @@ "lib": ["ES2015", "DOM"], "outDir": "./dist", "rootDir": "./src", - "types": [ - "jest", - "node" - ], + "types": ["jest", "node"], "strictNullChecks": true }, "include": ["src"], diff --git a/examples/with-docker/packages/ui/tsconfig.json b/examples/with-docker/packages/ui/tsconfig.json index 82301fe47b4db..2d8a4f4624b04 100644 --- a/examples/with-docker/packages/ui/tsconfig.json +++ b/examples/with-docker/packages/ui/tsconfig.json @@ -1,11 +1,7 @@ { "extends": "@repo/typescript-config/react-library.json", "include": ["."], - "exclude": [ - "dist", - "build", - "node_modules" - ], + "exclude": ["dist", "build", "node_modules"], "compilerOptions": { "strictNullChecks": true } diff --git a/examples/with-gatsby/apps/docs/tsconfig.json b/examples/with-gatsby/apps/docs/tsconfig.json index b854fd78856f3..f2a2d85687bdf 100644 --- a/examples/with-gatsby/apps/docs/tsconfig.json +++ b/examples/with-gatsby/apps/docs/tsconfig.json @@ -1,9 +1,7 @@ { "extends": "@repo/typescript-config/nextjs.json", "include": ["next-env.d.ts", "next.config.js", "**/*.ts", "**/*.tsx"], - "exclude": [ - "node_modules" - ], + "exclude": ["node_modules"], "compilerOptions": { "strictNullChecks": true } diff --git a/examples/with-gatsby/apps/web/tsconfig.json b/examples/with-gatsby/apps/web/tsconfig.json index 68aef3d9b4b63..5eb9d0afecc65 100644 --- a/examples/with-gatsby/apps/web/tsconfig.json +++ b/examples/with-gatsby/apps/web/tsconfig.json @@ -1,9 +1,7 @@ { "extends": "@repo/typescript-config/gatsby.json", "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], - "exclude": [ - "node_modules" - ], + "exclude": ["node_modules"], "compilerOptions": { "strictNullChecks": true } diff --git a/examples/with-gatsby/packages/ui/tsconfig.json b/examples/with-gatsby/packages/ui/tsconfig.json index 82301fe47b4db..2d8a4f4624b04 100644 --- a/examples/with-gatsby/packages/ui/tsconfig.json +++ b/examples/with-gatsby/packages/ui/tsconfig.json @@ -1,11 +1,7 @@ { "extends": "@repo/typescript-config/react-library.json", "include": ["."], - "exclude": [ - "dist", - "build", - "node_modules" - ], + "exclude": ["dist", "build", "node_modules"], "compilerOptions": { "strictNullChecks": true } diff --git a/examples/with-microfrontends/apps/docs/tsconfig.json b/examples/with-microfrontends/apps/docs/tsconfig.json index efd817de77baa..c0346be081be2 100644 --- a/examples/with-microfrontends/apps/docs/tsconfig.json +++ b/examples/with-microfrontends/apps/docs/tsconfig.json @@ -15,7 +15,5 @@ "next.config.js", ".next/types/**/*.ts" ], - "exclude": [ - "node_modules" - ] + "exclude": ["node_modules"] } diff --git a/examples/with-microfrontends/apps/web/tsconfig.json b/examples/with-microfrontends/apps/web/tsconfig.json index efd817de77baa..c0346be081be2 100644 --- a/examples/with-microfrontends/apps/web/tsconfig.json +++ b/examples/with-microfrontends/apps/web/tsconfig.json @@ -15,7 +15,5 @@ "next.config.js", ".next/types/**/*.ts" ], - "exclude": [ - "node_modules" - ] + "exclude": ["node_modules"] } diff --git a/examples/with-nestjs/apps/web/tsconfig.json b/examples/with-nestjs/apps/web/tsconfig.json index efd817de77baa..c0346be081be2 100644 --- a/examples/with-nestjs/apps/web/tsconfig.json +++ b/examples/with-nestjs/apps/web/tsconfig.json @@ -15,7 +15,5 @@ "next.config.js", ".next/types/**/*.ts" ], - "exclude": [ - "node_modules" - ] + "exclude": ["node_modules"] } diff --git a/examples/with-nestjs/packages/api/tsconfig.json b/examples/with-nestjs/packages/api/tsconfig.json index 480b23eaf5556..2564ddf296459 100644 --- a/examples/with-nestjs/packages/api/tsconfig.json +++ b/examples/with-nestjs/packages/api/tsconfig.json @@ -6,9 +6,7 @@ "esModuleInterop": true, "incremental": false, "outDir": "dist", - "types": [ - "node" - ], + "types": ["node"], "strictNullChecks": true }, "include": ["src"], diff --git a/examples/with-prisma/packages/database/tsconfig.json b/examples/with-prisma/packages/database/tsconfig.json index 1e719c3b07d4a..6d3462f795b1f 100644 --- a/examples/with-prisma/packages/database/tsconfig.json +++ b/examples/with-prisma/packages/database/tsconfig.json @@ -1,9 +1,7 @@ { "extends": "@repo/typescript-config/base.json", "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "tsup.config.ts"], - "exclude": [ - "node_modules" - ], + "exclude": ["node_modules"], "compilerOptions": { "strictNullChecks": true } diff --git a/examples/with-rollup/packages/ui/tsconfig.json b/examples/with-rollup/packages/ui/tsconfig.json index 82301fe47b4db..2d8a4f4624b04 100644 --- a/examples/with-rollup/packages/ui/tsconfig.json +++ b/examples/with-rollup/packages/ui/tsconfig.json @@ -1,11 +1,7 @@ { "extends": "@repo/typescript-config/react-library.json", "include": ["."], - "exclude": [ - "dist", - "build", - "node_modules" - ], + "exclude": ["dist", "build", "node_modules"], "compilerOptions": { "strictNullChecks": true } diff --git a/examples/with-svelte/packages/ui/tsconfig.json b/examples/with-svelte/packages/ui/tsconfig.json index 762895acee90e..b8756b735debf 100644 --- a/examples/with-svelte/packages/ui/tsconfig.json +++ b/examples/with-svelte/packages/ui/tsconfig.json @@ -1,5 +1,8 @@ { - "extends": ["@repo/typescript-config/svelte.json", "./.svelte-kit/tsconfig.json"], + "extends": [ + "@repo/typescript-config/svelte.json", + "./.svelte-kit/tsconfig.json" + ], "compilerOptions": { "declaration": true, "declarationMap": true, diff --git a/examples/with-vite-react/apps/web/tsconfig.json b/examples/with-vite-react/apps/web/tsconfig.json index 0fcc7fec7bc9a..a822a843b37f2 100644 --- a/examples/with-vite-react/apps/web/tsconfig.json +++ b/examples/with-vite-react/apps/web/tsconfig.json @@ -5,4 +5,4 @@ "jsx": "react-jsx", "strictNullChecks": true } -} \ No newline at end of file +} diff --git a/examples/with-vite-react/packages/ui/tsconfig.json b/examples/with-vite-react/packages/ui/tsconfig.json index 646d66dc025f9..8d9e87630b843 100644 --- a/examples/with-vite-react/packages/ui/tsconfig.json +++ b/examples/with-vite-react/packages/ui/tsconfig.json @@ -1,9 +1,7 @@ { "extends": "@repo/typescript-config/react-library.json", "include": ["."], - "exclude": [ - "node_modules" - ], + "exclude": ["node_modules"], "compilerOptions": { "strictNullChecks": true } diff --git a/examples/with-vite/apps/docs/tsconfig.json b/examples/with-vite/apps/docs/tsconfig.json index 64ec97e51a190..da0e2eb8cc3fd 100644 --- a/examples/with-vite/apps/docs/tsconfig.json +++ b/examples/with-vite/apps/docs/tsconfig.json @@ -1,8 +1,6 @@ { "extends": "@repo/typescript-config/vite.json", - "include": [ - "src" - ], + "include": ["src"], "compilerOptions": { "strictNullChecks": true } diff --git a/examples/with-vite/apps/web/tsconfig.json b/examples/with-vite/apps/web/tsconfig.json index 64ec97e51a190..da0e2eb8cc3fd 100644 --- a/examples/with-vite/apps/web/tsconfig.json +++ b/examples/with-vite/apps/web/tsconfig.json @@ -1,8 +1,6 @@ { "extends": "@repo/typescript-config/vite.json", - "include": [ - "src" - ], + "include": ["src"], "compilerOptions": { "strictNullChecks": true } diff --git a/examples/with-vite/packages/ui/tsconfig.json b/examples/with-vite/packages/ui/tsconfig.json index 1b2c9012501d7..bd457909e2f3d 100644 --- a/examples/with-vite/packages/ui/tsconfig.json +++ b/examples/with-vite/packages/ui/tsconfig.json @@ -1,9 +1,7 @@ { "extends": "@repo/typescript-config/base.json", "include": ["."], - "exclude": [ - "node_modules" - ], + "exclude": ["node_modules"], "compilerOptions": { "strictNullChecks": true } diff --git a/examples/with-vitest/apps/docs/tsconfig.json b/examples/with-vitest/apps/docs/tsconfig.json index efd817de77baa..c0346be081be2 100644 --- a/examples/with-vitest/apps/docs/tsconfig.json +++ b/examples/with-vitest/apps/docs/tsconfig.json @@ -15,7 +15,5 @@ "next.config.js", ".next/types/**/*.ts" ], - "exclude": [ - "node_modules" - ] + "exclude": ["node_modules"] } diff --git a/examples/with-vitest/apps/web/tsconfig.json b/examples/with-vitest/apps/web/tsconfig.json index efd817de77baa..c0346be081be2 100644 --- a/examples/with-vitest/apps/web/tsconfig.json +++ b/examples/with-vitest/apps/web/tsconfig.json @@ -15,7 +15,5 @@ "next.config.js", ".next/types/**/*.ts" ], - "exclude": [ - "node_modules" - ] + "exclude": ["node_modules"] } diff --git a/examples/with-vue-nuxt/apps/web/tsconfig.node.json b/examples/with-vue-nuxt/apps/web/tsconfig.node.json index e761336ed5e85..358fcecd4ccf1 100644 --- a/examples/with-vue-nuxt/apps/web/tsconfig.node.json +++ b/examples/with-vue-nuxt/apps/web/tsconfig.node.json @@ -11,9 +11,7 @@ "composite": true, "module": "ESNext", "moduleResolution": "Bundler", - "types": [ - "node" - ], + "types": ["node"], "strictNullChecks": true } } diff --git a/examples/with-vue-nuxt/packages/ui/tsconfig.json b/examples/with-vue-nuxt/packages/ui/tsconfig.json index cd4939c345376..2aa3bac97a40a 100644 --- a/examples/with-vue-nuxt/packages/ui/tsconfig.json +++ b/examples/with-vue-nuxt/packages/ui/tsconfig.json @@ -1,11 +1,7 @@ { "extends": "tsconfig/vue.json", "include": ["."], - "exclude": [ - "dist", - "build", - "node_modules" - ], + "exclude": ["dist", "build", "node_modules"], "compilerOptions": { "strictNullChecks": true } diff --git a/packages/turbo-repository/js/package.json b/packages/turbo-repository/js/package.json index c1496d369c565..d3a76e49a9e15 100644 --- a/packages/turbo-repository/js/package.json +++ b/packages/turbo-repository/js/package.json @@ -6,8 +6,8 @@ "bugs": "https://github.com/vercel/turborepo/issues", "license": "MIT", "files": [ - "dist/index.js", - "dist/index.d.ts" + "dist/index.d.ts", + "dist/index.js" ], "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/turbo-types/package.json b/packages/turbo-types/package.json index 2325374a66bee..ab9dfeb7cda44 100644 --- a/packages/turbo-types/package.json +++ b/packages/turbo-types/package.json @@ -13,8 +13,8 @@ "directory": "packages/turbo-types" }, "files": [ - "src", - "schemas" + "schemas", + "src" ], "type": "commonjs", "main": "src/index.ts", diff --git a/turborepo-tests/integration/fixtures/boundaries/apps/my-app/tsconfig.json b/turborepo-tests/integration/fixtures/boundaries/apps/my-app/tsconfig.json index b835cde1e71e8..9dd4108995141 100644 --- a/turborepo-tests/integration/fixtures/boundaries/apps/my-app/tsconfig.json +++ b/turborepo-tests/integration/fixtures/boundaries/apps/my-app/tsconfig.json @@ -1,11 +1,9 @@ { "compilerOptions": { "paths": { - "@/*": [ - "./*" - ], + "@/*": ["./*"], "!": ["../../packages/another/index.jsx"] }, "strictNullChecks": true } -} \ No newline at end of file +} diff --git a/turborepo-tests/integration/fixtures/turbo_trace/tsconfig.json b/turborepo-tests/integration/fixtures/turbo_trace/tsconfig.json index 687c92b33af6e..ab8c8afa4b84f 100644 --- a/turborepo-tests/integration/fixtures/turbo_trace/tsconfig.json +++ b/turborepo-tests/integration/fixtures/turbo_trace/tsconfig.json @@ -1,10 +1,8 @@ { "compilerOptions": { "paths": { - "@*": [ - ".*" - ] + "@*": [".*"] }, "strictNullChecks": true } -} \ No newline at end of file +} diff --git a/turborepo-tests/integration/fixtures/turbo_trace_monorepo/apps/my-app/tsconfig.json b/turborepo-tests/integration/fixtures/turbo_trace_monorepo/apps/my-app/tsconfig.json index 1d261b3a47884..40a4afb18ce78 100644 --- a/turborepo-tests/integration/fixtures/turbo_trace_monorepo/apps/my-app/tsconfig.json +++ b/turborepo-tests/integration/fixtures/turbo_trace_monorepo/apps/my-app/tsconfig.json @@ -1,10 +1,8 @@ { "compilerOptions": { "paths": { - "@/*": [ - "./*" - ] + "@/*": ["./*"] }, "strictNullChecks": true } -} \ No newline at end of file +}