diff --git a/Cargo.lock b/Cargo.lock index 0f1dddc1b..ae965687d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3169,6 +3169,7 @@ dependencies = [ name = "nub-phantom-scan" version = "0.7.5" dependencies = [ + "node-semver", "nub-phantom-core", "serde", "serde_json", diff --git a/crates/nub-cli/src/pm_engine/mod.rs b/crates/nub-cli/src/pm_engine/mod.rs index 3cd4ca956..2b9134bca 100644 --- a/crates/nub-cli/src/pm_engine/mod.rs +++ b/crates/nub-cli/src/pm_engine/mod.rs @@ -1279,6 +1279,22 @@ fn apply_config_scope( c.embedder_overrides = Some(effective); c.trusted_dependencies_honored = trusted; c.embedder_package_extensions = Some(effective_pe); + // Bundled ecosystem defaults (Yarn ∪ pnpm ∪ nub-phantom), applied as + // the lowest-precedence packageExtensions layer. Role-gated to the + // identities that apply packageExtensions at all - nub identity and + // pnpm compat - so npm/yarn-classic/bun compat installs mirror the + // incumbent (which applies no curated extension list) instead of gaining + // resolve edges it would not. (Yarn Berry applies @yarnpkg/extensions + // by default via @yarnpkg/plugin-compat; the Yarn role doesn't + // currently split classic vs Berry, so Berry compat is a follow-up.) + // Kept out of the checksum by reading them through + // the separate `bundled_package_extensions` seam. + c.bundled_package_extensions = + if matches!(role, config_scope::Role::Nub | config_scope::Role::Pnpm) { + Some(bundled_package_extensions_defaults()) + } else { + None + }; }); if noise == ConfigScopeNoise::Warn { @@ -1306,6 +1322,29 @@ fn apply_config_scope( Ok(()) } +/// Bundled ecosystem `packageExtensions` defaults (Yarn ∪ pnpm ∪ +/// nub-phantom), vendored at `vendor/package-extensions/unified.json` and +/// kept fresh by `scripts/sync-package-extensions.ts`. Applied as the +/// lowest-precedence layer in aube's `resolve_dependency_policy` (user +/// extensions win per-key via `extend_missing`'s first-write-wins), and +/// deliberately excluded from the lockfile `packageExtensionsChecksum` by +/// flowing through the separate `bundled_package_extensions` seam. +/// +/// A parse failure is non-fatal: the bundled file is committed and +/// compile-time-`include_str!`'d, so corruption would be a bad commit, not +/// a runtime input — warn and install with no bundled defaults rather than +/// abort an install over data the user never authored. +fn bundled_package_extensions_defaults() -> std::collections::BTreeMap { + const BUNDLED: &str = include_str!("../../../../vendor/package-extensions/unified.json"); + match serde_json::from_str(BUNDLED) { + Ok(map) => map, + Err(err) => { + tracing::warn!("ignoring unparseable bundled package-extensions defaults: {err}"); + std::collections::BTreeMap::new() + } + } +} + /// Does the active PM honor `catalog:` specifiers? pnpm@9+, bun@1.2+, and /// yarn-berry (v2+) implement catalogs; npm and yarn-classic (v1) do not. nub /// identity honors catalogs (an un-branded cross-tool field, like @@ -5104,4 +5143,160 @@ mod tests { install state never saw" ); } + + // The bundled ecosystem defaults (Yarn ∪ pnpm ∪ nub-phantom) must load + // from the vendored `vendor/package-extensions/unified.json` and parse + // into the selector -> body map aube consumes. This guards the + // `include_str!` path and the data's correctness: the map is non-empty, + // carries the pnpm-specific `@angular/build@*` entry, and carries the + // Yarn `gatsby-core-utils@<2.14.0-next.1` entry with BOTH `got` and + // `@babel/runtime` — the latter checks the sync script's deep-merge of + // @yarnpkg/extensions' one duplicate selector (last-wins would drop + // `@babel/runtime`). + #[test] + fn bundled_package_extensions_defaults_load() { + let map = bundled_package_extensions_defaults(); + assert!( + map.len() > 100, + "bundled defaults should carry 100+ entries, got {}", + map.len() + ); + // pnpm-specific entry not in Yarn. + let angular = map + .get("@angular/build@*") + .expect("@angular/build@* present"); + let tslib = angular + .get("dependencies") + .and_then(|d| d.get("tslib")) + .and_then(|v| v.as_str()); + assert_eq!( + tslib, + Some("^2.3.0"), + "@angular/build@* -> dependencies.tslib" + ); + + // Yarn entry whose selector is duplicated in the source array; the + // two bodies (got, @babel/runtime) must both survive the deep-merge. + let gatsby = map + .get("gatsby-core-utils@<2.14.0-next.1") + .expect("gatsby-core-utils entry present"); + let deps = gatsby + .get("dependencies") + .expect("gatsby-core-utils entry has dependencies"); + assert_eq!( + deps.get("got").and_then(|v| v.as_str()), + Some("8.3.2"), + "gatsby-core-utils -> dependencies.got" + ); + assert_eq!( + deps.get("@babel/runtime").and_then(|v| v.as_str()), + Some("^7.14.8"), + "gatsby-core-utils -> dependencies.@babel/runtime (survives dup-selector merge)" + ); + } + + // The bundled ecosystem `packageExtensions` defaults are role-gated in + // `apply_config_scope`: applied only under nub identity and pnpm compat + // (`Role::Nub | Role::Pnpm`), and dropped under npm/yarn/bun compat — + // whose incumbents apply no curated extension list, so nub mirrors them + // instead of grafting resolve edges the incumbent would not. This is the + // NEGATIVE-case guard for that gate (the positive case — the bundled set + // shaping the graph under nub identity — is covered by the network + // `bundled_default_shapes_graph_and_stays_out_of_checksum` install test in + // `tests/package_extensions.rs`). It drives `apply_config_scope` with a + // `DetectedLockfile` of each kind and reads the + // `bundled_package_extensions` seam back off the process-global + // `EngineContext` — no install, no network: the gate is a pure function of + // the resolved role, so exercising the role -> field mapping is sufficient. + #[test] + fn bundled_package_extensions_gate_blocks_compat_roles() { + use aube_util::{EngineContext, engine_context, set_engine_context}; + + // Takes `ENGINE_GLOBAL_LOCK` for the whole test and restores the + // process-global `EngineContext` on DROP (not a tail statement, so a + // panicking assert still restores it) — the same shape as + // `install_report.rs`'s `EngineGuard`. Without the lock this test's + // 8 `set_engine_context(EngineContext::default())` writes race any + // other test in this binary that reads or writes the same global. + struct EngineGuard { + context: EngineContext, + _lock: std::sync::MutexGuard<'static, ()>, + } + impl EngineGuard { + fn take() -> Self { + let lock = crate::pm_engine::ENGINE_GLOBAL_LOCK + .lock() + .unwrap_or_else(|error| error.into_inner()); + Self { + _lock: lock, + context: engine_context(), + } + } + } + impl Drop for EngineGuard { + fn drop(&mut self) { + set_engine_context(self.context.clone()); + } + } + let _guard = EngineGuard::take(); + + // A manifest carrying a dependency the bundled set WOULD extend + // (`gatsby-core-utils@2.13.0` satisfies the bundled + // `gatsby-core-utils@<2.14.0-next.1` selector injecting `got`). The + // body is irrelevant to the gate — only the resolved role matters — + // but mirroring the real affected package keeps the intent legible. + let manifest = + r#"{"name":"gate","version":"1.0.0","dependencies":{"gatsby-core-utils":"2.13.0"}}"#; + + // Reset the process-global EngineContext to a clean default before each + // role so a prior test's residue can't mask the gate. `apply_config_scope` + // is the single writer of `bundled_package_extensions` here. Safe under + // the guard above: this test now holds `ENGINE_GLOBAL_LOCK` for its + // full duration, and the guard restores the pre-test context on drop. + let bundled_for_kind = |kind: Option| -> Option { + let dir = tempfile::tempdir().unwrap(); + std::fs::write(dir.path().join("package.json"), manifest).unwrap(); + let detected = kind.map(|k| DetectedLockfile { + kind: k, + dir: dir.path().to_path_buf(), + fresh: false, + }); + set_engine_context(EngineContext::default()); + apply_config_scope(detected.as_ref(), dir.path(), ConfigScopeNoise::Silent) + .expect("Silent scoping never hard-errors on a bare manifest"); + engine_context() + .bundled_package_extensions + .as_ref() + .map(std::collections::BTreeMap::len) + }; + + // Compat roles whose incumbents apply no curated extension list: the + // gate must block the bundled set, so the seam stays `None`. + for kind in [ + LockfileKind::Npm, + LockfileKind::NpmShrinkwrap, + LockfileKind::Yarn, + LockfileKind::YarnBerry, + LockfileKind::Bun, + ] { + assert_eq!( + bundled_for_kind(Some(kind)), + None, + "{kind:?} compat must NOT receive the bundled packageExtensions set \ + (the gate blocks npm/yarn/bun); the seam should be None" + ); + } + + // Positive side of the same gate: nub identity (no lockfile → role + // defaults to Nub) and pnpm compat must receive the bundled set, and it + // must be the non-empty defaults map — not a vacuous `Some(empty)`. + for kind in [None, Some(LockfileKind::Aube), Some(LockfileKind::Pnpm)] { + let len = + bundled_for_kind(kind).expect("nub identity / pnpm must receive the bundled set"); + assert!( + len > 100, + "nub/pnpm bundled set must carry the 100+ vendored defaults, got {len}" + ); + } + } } diff --git a/crates/nub-cli/tests/package_extensions.rs b/crates/nub-cli/tests/package_extensions.rs index 8fe106bef..d7b112b2b 100644 --- a/crates/nub-cli/tests/package_extensions.rs +++ b/crates/nub-cli/tests/package_extensions.rs @@ -77,6 +77,17 @@ fn store_has(dir: &Path, name: &str) -> bool { .any(|n| n.starts_with(&prefix)) } +/// Whether the virtual store holds the exact `name@version` entry. +fn store_has_version(dir: &Path, name: &str, version: &str) -> bool { + let target = format!("{name}@{version}"); + std::fs::read_dir(dir.join("node_modules/.store")) + .into_iter() + .flatten() + .flatten() + .filter_map(|e| e.file_name().into_string().ok()) + .any(|n| n == target) +} + /// A top-level `packageExtensions` entry injecting a dependency into a resolved /// package must shape the graph under Nub identity, and editing it after an /// install must invalidate the fast path so the injected dep lands. @@ -130,3 +141,131 @@ fn top_level_package_extensions_shapes_resolution_and_invalidates_freshness() { the edit must invalidate the install fast path so it re-resolves: {err2}" ); } + +/// Read the `packageExtensionsChecksum` aube stamps onto `nub.lock` (pnpm-v9 +/// YAML format), or `None` when the lockfile carries no checksum. +fn lockfile_checksum(dir: &Path) -> Option { + let lock = std::fs::read_to_string(dir.join("nub.lock")).ok()?; + for line in lock.lines() { + if let Some(rest) = line.trim_start().strip_prefix("packageExtensionsChecksum:") { + let v = rest.trim().trim_matches('"'); + if !v.is_empty() { + return Some(v.to_string()); + } + } + } + None +} + +/// A bundled ecosystem default (Yarn ∪ pnpm ∪ nub-phantom, vendored at +/// `vendor/package-extensions/unified.json`) must shape the resolved graph +/// with NO user `packageExtensions` — and must NOT leak into the lockfile +/// `packageExtensionsChecksum` (routing it there would drift every existing +/// lockfile on each bundled-list bump and abort `--frozen-lockfile`). +/// +/// `gatsby-core-utils@2.13.0` declares neither `got` nor `@babel/runtime`, +/// and `2.13.0` satisfies the bundled selector +/// `gatsby-core-utils@<2.14.0-next.1`, so the bundled extension injecting +/// `got` is observable: without it, `got` is absent from the graph. +/// +/// The checksum guard has two cases: (1) empty user `packageExtensions` → +/// aube writes NO `packageExtensionsChecksum` field (the checksum fn returns +/// `None` for an empty map), so a bundled-list bump cannot drift the +/// lockfile — there is nothing to mismatch; (2) non-empty user +/// `packageExtensions` with the bundled default ALSO shaping the graph → the +/// checksum must equal `package_extensions_checksum(&user_pe_only)`, proving +/// the bundled map is not folded into the checksum input. +#[test] +#[ignore = "network: resolves gatsby-core-utils@2.13.0 + the bundled got from the npm registry"] +fn bundled_default_shapes_graph_and_stays_out_of_checksum() { + use aube_lockfile::pnpm::package_extensions_checksum; + if !registry_reachable() { + eprintln!("skipping: registry.npmjs.org unreachable"); + return; + } + let store = pm_tmpdir("store"); + let cache = pm_tmpdir("cache"); + + // (1) No user packageExtensions: the bundled default must still apply, + // and the lockfile must carry NO checksum (empty user PE → None → a + // bundled-list bump cannot drift this lockfile). + let dir_a = pm_tmpdir("bundled-a"); + let pkg_a = + r#"{"name":"bundled-a","version":"1.0.0","dependencies":{"gatsby-core-utils":"2.13.0"}}"#; + std::fs::write(dir_a.join("package.json"), pkg_a).unwrap(); + let (err_a, code_a) = run_install_in_store(&dir_a, &store, &cache, &["install"]); + assert_eq!(code_a, 0, "bundled-default install A failed: {err_a}"); + assert!( + store_has(&dir_a, "got"), + "the bundled `gatsby-core-utils@<2.14.0-next.1` extension must inject `got` \ + (undeclared by 2.13.0) into the graph with no user packageExtensions: {err_a}" + ); + assert!( + dir_a.join("nub.lock").is_file(), + "A: nub-identity install writes nub.lock: {err_a}" + ); + assert_eq!( + lockfile_checksum(&dir_a), + None, + "empty user packageExtensions must produce NO packageExtensionsChecksum \ + (the checksum fn returns None for an empty map), so a bundled-list bump \ + cannot drift the lockfile: {err_a}" + ); + + // (2) Non-empty user packageExtensions, with the bundled default ALSO + // shaping the graph: the checksum must reflect ONLY the user's + // packageExtensions, not the bundled map. Compare against + // `package_extensions_checksum` computed on the user-PE-only map. + let dir_b = pm_tmpdir("bundled-b"); + let user_pe = r#"{"is-positive@3.1.0":{"dependencies":{"is-number":"7.0.0"}}}"#; + let pkg_b = format!( + r#"{{"name":"bundled-b","version":"1.0.0","dependencies":{{"gatsby-core-utils":"2.13.0","is-positive":"3.1.0"}},"packageExtensions":{user_pe}}}"# + ); + std::fs::write(dir_b.join("package.json"), pkg_b).unwrap(); + let (err_b, code_b) = run_install_in_store(&dir_b, &store, &cache, &["install"]); + assert_eq!(code_b, 0, "bundled-default install B failed: {err_b}"); + assert!( + store_has(&dir_b, "got"), + "B: bundled default still applies alongside user packageExtensions: {err_b}" + ); + let user_pe_map: std::collections::BTreeMap = + serde_json::from_str(user_pe).unwrap(); + let expected = + package_extensions_checksum(&user_pe_map).expect("non-empty user PE yields a checksum"); + assert_eq!( + lockfile_checksum(&dir_b).as_deref(), + Some(expected.as_str()), + "the lockfile packageExtensionsChecksum must equal the hash of the \ + USER packageExtensions only — the bundled map (actively shaping this \ + graph via `got`) must not be folded into the checksum input, or every \ + bundled-list bump drifts existing lockfiles and aborts \ + --frozen-lockfile: {err_b}" + ); + + // (3) User packageExtensions OVERRIDE the bundled default on a matching + // selector + dependency key. The bundled `gatsby-core-utils@<2.14.0-next.1` + // injects `got: 8.3.2`; a user entry for the SAME selector injecting + // `got: 8.3.0` must win (user-first Vec ordering + `extend_missing` + // first-write-wins), so the resolved `got` is the user's 8.3.0, not the + // bundled 8.3.2. This guards the precedence construction in + // `resolve_dependency_policy`, which the existing aube `extend_missing` + // unit tests do not cover. + let dir_c = pm_tmpdir("bundled-c"); + let user_pe_c = r#"{"gatsby-core-utils@<2.14.0-next.1":{"dependencies":{"got":"8.3.0"}}}"#; + let pkg_c = format!( + r#"{{"name":"bundled-c","version":"1.0.0","dependencies":{{"gatsby-core-utils":"2.13.0"}},"packageExtensions":{user_pe_c}}}"# + ); + std::fs::write(dir_c.join("package.json"), pkg_c).unwrap(); + let (err_c, code_c) = run_install_in_store(&dir_c, &store, &cache, &["install"]); + assert_eq!(code_c, 0, "bundled-default install C failed: {err_c}"); + assert!( + store_has_version(&dir_c, "got", "8.3.0"), + "user packageExtensions must override the bundled `got: 8.3.2` with the \ + user's `got: 8.3.0` on the same selector: {err_c}" + ); + assert!( + !store_has_version(&dir_c, "got", "8.3.2"), + "the bundled `got: 8.3.2` must NOT be resolved when the user overrides \ + the same selector+key with 8.3.0: {err_c}" + ); +} diff --git a/crates/nub-phantom-scan/Cargo.toml b/crates/nub-phantom-scan/Cargo.toml index e52579d06..8a704ded7 100644 --- a/crates/nub-phantom-scan/Cargo.toml +++ b/crates/nub-phantom-scan/Cargo.toml @@ -24,6 +24,9 @@ path = "src/lib.rs" nub-phantom-core = { path = "../nub-phantom-core" } serde = { version = "1", features = ["derive"] } serde_json = "1" +# Used by the `emit-extensions` bin's dedup matcher (selector → name+range +# against a scanned version), mirroring aube-resolver's `package_selector_matches`. +node-semver = "2" [lints] workspace = true diff --git a/crates/nub-phantom-scan/src/bin/emit-extensions.rs b/crates/nub-phantom-scan/src/bin/emit-extensions.rs new file mode 100644 index 000000000..bbd209118 --- /dev/null +++ b/crates/nub-phantom-scan/src/bin/emit-extensions.rs @@ -0,0 +1,183 @@ +//! emit-extensions — convert a `nub-phantom scan --json` report into +//! `packageExtensions`-shaped entries for the vendored +//! `vendor/package-extensions/nub-phantom-extensions.json` member of the +//! unified bundled-defaults set. +//! +//! The scanner records the phantom target *name* (the extension key) but not +//! the importer range, the bucket, or the value, so this emitter applies the +//! policy documented in the unified-extensions plan: +//! - selector: `pkg@*` — the scanner samples `latest`, so a phantom present +//! there means the fix hasn't shipped; `*` matches Yarn's "always needs" +//! class and is safe under `extend_missing` (declared deps win). +//! - bucket: a subpath-adapter phantom (hard, reachable only from a non-`.` +//! `exports` subpath) → `peerDependenciesMeta..optional = true` ONLY +//! (no required `peerDependencies` entry, which would warn for consumers +//! not using that subpath). A main-graph hard phantom → `dependencies.`. +//! - value: `"*"` — the scanner has no version signal for the target. +//! - dedup: skip a finding when a bundled (Yarn ∪ pnpm) selector already +//! matches `(offender, version)` AND its body declares the same dep in the +//! same bucket — the curated lists cover it. +//! +//! `Finding` in `nub-phantom-scan` is `Serialize`-only with `pub(crate)` +//! fields, and the scan JSON is emitted by the separate `nub-phantom` eval CLI, +//! so this binary deserializes minimal local mirror structs (with `default` on +//! the fields it doesn't read). +//! +//! Usage: +//! emit-extensions > nub-phantom-extensions.json + +use std::collections::BTreeMap; + +// --- Mirror of the eval CLI's `ScanReport`/`Offender`/`Finding` (Serialize-only +// in the scan crate), trimmed to the fields this emitter reads. --- +#[derive(serde::Deserialize)] +struct ScanReport { + offenders: Vec, +} + +#[derive(serde::Deserialize)] +struct Offender { + package: String, + version: String, + hard_phantoms: Vec, +} + +#[derive(serde::Deserialize)] +struct FindingMirror { + package: String, + verdict: String, + #[serde(default)] + from_main: bool, + #[serde(default)] + from_subpath: bool, +} + +impl FindingMirror { + /// Mirror of `nub_phantom_scan::Finding::is_subpath_adapter`. + fn is_subpath_adapter(&self) -> bool { + self.verdict == "hard-phantom" && self.from_subpath && !self.from_main + } +} + +/// Reimplementation of aube-resolver's `pub(crate) package_selector_matches` +/// (this crate doesn't depend on aube-resolver). A name-only selector matches +/// every version; a `*`/empty range matches any version (even non-semver); +/// otherwise the version must satisfy the range. +fn selector_matches(selector: &str, name: &str, version: &str) -> bool { + let selector = selector.trim(); + if selector == name { + return true; + } + // Split `name@range`, honoring a leading scope `@`. Mirrors aube's + // `split_package_selector` (rfind('@'), skip the scope @ at index 0). + let at = match selector.rfind('@') { + Some(0) => return false, + Some(i) => i, + None => return false, // no @ and not a bare-name match above + }; + let (sel_name, range) = (&selector[..at], &selector[at + 1..]); + if sel_name != name || range.is_empty() { + return sel_name == name && range.is_empty(); + } + let range = range.trim(); + if range == "*" { + return true; + } + let Ok(r) = node_semver::Range::parse(range) else { + return false; + }; + let Ok(v) = node_semver::Version::parse(version) else { + return false; + }; + r.satisfies(&v) +} + +/// Does `body` already declare `dep` in the bucket this emitter would write? +fn body_covers(body: &serde_json::Value, dep: &str, as_optional_peer: bool) -> bool { + let Some(obj) = body.as_object() else { + return false; + }; + if as_optional_peer { + obj.get("peerDependenciesMeta") + .and_then(|v| v.as_object()) + .is_some_and(|m| m.contains_key(dep)) + } else { + obj.get("dependencies") + .and_then(|v| v.as_object()) + .is_some_and(|m| m.contains_key(dep)) + } +} + +fn main() { + let mut args = std::env::args().skip(1); + let scan_path = args + .next() + .expect("usage: emit-extensions "); + let union_path = args + .next() + .expect("usage: emit-extensions "); + + let scan_raw = std::fs::read_to_string(&scan_path) + .unwrap_or_else(|e| panic!("read scan report {scan_path}: {e}")); + let report: ScanReport = serde_json::from_str(&scan_raw) + .unwrap_or_else(|e| panic!("parse scan report {scan_path}: {e}")); + let union_raw = std::fs::read_to_string(&union_path) + .unwrap_or_else(|e| panic!("read bundled union {union_path}: {e}")); + let bundled: BTreeMap = serde_json::from_str(&union_raw) + .unwrap_or_else(|e| panic!("parse bundled union {union_path}: {e}")); + + // selector -> body, accumulating multiple phantoms per offender into one body. + let mut out: BTreeMap = BTreeMap::new(); + let mut emitted = 0usize; + let mut deduped = 0usize; + + for offender in &report.offenders { + for finding in &offender.hard_phantoms { + if finding.verdict != "hard-phantom" { + continue; + } + let dep = &finding.package; + let as_optional_peer = finding.is_subpath_adapter(); + + // Dedup: a bundled (Yarn ∪ pnpm) selector that already matches this + // offender+version AND declares the same dep in the same bucket. + let covered = bundled.iter().any(|(sel, body)| { + selector_matches(sel, &offender.package, &offender.version) + && body_covers(body, dep, as_optional_peer) + }); + if covered { + deduped += 1; + continue; + } + + let selector = format!("{}@*", offender.package); + let body = out.entry(selector).or_insert_with(|| serde_json::json!({})); + let obj = body.as_object_mut().expect("bodies are objects"); + if as_optional_peer { + let pmd = obj + .entry("peerDependenciesMeta".to_string()) + .or_insert_with(|| serde_json::json!({})) + .as_object_mut() + .expect("peerDependenciesMeta is an object"); + pmd.entry(dep.clone()) + .or_insert_with(|| serde_json::json!({"optional": true})); + } else { + let deps = obj + .entry("dependencies".to_string()) + .or_insert_with(|| serde_json::json!({})) + .as_object_mut() + .expect("dependencies is an object"); + deps.entry(dep.clone()) + .or_insert_with(|| serde_json::json!("*")); + } + emitted += 1; + } + } + + let serialized = serde_json::to_string_pretty(&out).expect("serialize output"); + println!("{serialized}"); + eprintln!( + "emit-extensions: {emitted} emitted, {deduped} deduped (covered by Yarn ∪ pnpm), {} selectors", + out.len() + ); +} diff --git a/scripts/sync-package-extensions.ts b/scripts/sync-package-extensions.ts new file mode 100644 index 000000000..889fffca8 --- /dev/null +++ b/scripts/sync-package-extensions.ts @@ -0,0 +1,184 @@ +#!/usr/bin/env node +// sync-package-extensions — regenerate the vendored unified package-extensions +// defaults under vendor/package-extensions/ from the live ecosystem sources. +// +// Runs under BOTH plain Node (type-stripping) and nub: +// node scripts/sync-package-extensions.ts +// nub scripts/sync-package-extensions.ts +// +// Erasable TypeScript only (no enums/namespaces/parameter-properties) so plain +// modern `node` runs it with no build step — same constraint as the other scripts/*.ts. +// +// Sources: +// - Yarn: `@yarnpkg/extensions` (npm-published, BSD-2-Clause). `npm pack`, then +// read lib/index.js for the `packageExtensions` array. +// - pnpm: not published standalone. Fetch pnpm/pnpm's +// pnpm_compat_package_extensions.json (pnpm-specific entries not in Yarn yet). +// compat_package_extensions.json is a stale copy of Yarn and is NOT merged. +// - nub-phantom: vendor/package-extensions/nub-phantom-extensions.json, generated +// separately by crates/nub-phantom-scan/src/bin/emit-extensions.rs. This script +// preserves it as-is (does not regenerate the scan). +// +// The exported @yarnpkg/extensions list is an ARRAY of [selector, body] pairs and +// carries one duplicate selector (gatsby-core-utils@<2.14.0-next.1) with two +// different bodies. We deep-merge bodies on selector collision so the +// selector-keyed map representation is lossless (last-wins would drop a dep). +// +// Output is a selector -> body map (body fields: dependencies, optionalDependencies, +// peerDependencies, peerDependenciesMeta) — the same shape aube's +// `embedder_package_extensions` / `parse_package_extensions` consume. +// +// Idempotent: a second run with unchanged upstreams produces byte-identical output. + +import { execSync } from 'node:child_process' +import { mkdtempSync, mkdirSync, readFileSync, writeFileSync, rmSync, existsSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join, resolve } from 'node:path' +import { createRequire } from 'node:module' + +const require = createRequire(import.meta.url) + +const ROOT = resolve(import.meta.dirname ?? __dirname, '..') +const DIR = join(ROOT, 'vendor/package-extensions') +const PNPM_RAW = (sha: string, p: string) => + `https://raw.githubusercontent.com/pnpm/pnpm/${sha}/${p}` + +type Body = Record> +type ExtMap = Record + +// Deep-merge `from` into `into`: for each field, union the inner map's keys +// (first-write-wins per key, matching aube's `extend_missing` semantics). +function mergeBody(into: Body, from: Body): void { + for (const field of Object.keys(from)) { + into[field] = into[field] ?? {} + for (const [k, v] of Object.entries(from[field])) { + if (!(k in into[field])) into[field][k] = v + } + } +} + +function sh(cmd: string): string { + return execSync(cmd, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'inherit'] }).trim() +} + +async function fetchText(url: string): Promise { + const res = await fetch(url) + if (!res.ok) throw new Error(`GET ${url} -> ${res.status} ${res.statusText}`) + return res.text() +} + +function writeJson(file: string, obj: unknown): void { + writeFileSync(file, JSON.stringify(obj, null, 2) + '\n') +} + +// --- Yarn: npm pack @yarnpkg/extensions, require lib/index.js, deep-merge dup selectors --- +function fetchYarn(): { version: string; map: ExtMap } { + const version = sh('npm view @yarnpkg/extensions version') + const tmp = mkdtempSync(join(tmpdir(), 'yarnpkg-ext-')) + try { + sh(`npm pack @yarnpkg/extensions --pack-destination ${JSON.stringify(tmp)}`) + const tarball = join(tmp, `yarnpkg-extensions-${version}.tgz`) + sh(`tar -xzf ${JSON.stringify(tarball)} -C ${JSON.stringify(tmp)}`) + // require() the CJS build to get the curated array verbatim. + // eslint-disable-next-line @typescript-eslint/no-require-imports + const mod = require(join(tmp, 'package/lib/index.js')) as { packageExtensions?: [string, Body][]; default?: { packageExtensions?: [string, Body][] } } + const arr: [string, Body][] = mod.packageExtensions ?? mod.default?.packageExtensions + const map: ExtMap = {} + for (const [sel, body] of arr) { + if (map[sel]) mergeBody(map[sel], body) + else map[sel] = JSON.parse(JSON.stringify(body)) + } + return { version, map } + } finally { + rmSync(tmp, { recursive: true, force: true }) + } +} + +// --- pnpm: the pnpm-specific entries not in Yarn yet --- +async function fetchPnpm(): Promise<{ sha: string; map: ExtMap }> { + const sha = sh('git ls-remote https://github.com/pnpm/pnpm HEAD').split(/\s+/)[0] + const specUrl = PNPM_RAW(sha, 'pnpm/crates/package-manager/src/pnpm_compat_package_extensions.json') + const spec: [string, Body][] = JSON.parse(await fetchText(specUrl)) + const map: ExtMap = {} + for (const e of spec) { + const sel = e[0] + const body = e[1] + map[sel] = JSON.parse(JSON.stringify(body)) + } + return { sha, map } +} + +async function main(): Promise { + mkdirSync(DIR, { recursive: true }) + + const yarn = fetchYarn() + writeJson(join(DIR, 'yarnpkg-extensions.json'), yarn.map) + + const pnpm = await fetchPnpm() + writeJson(join(DIR, 'pnpm-extensions.json'), pnpm.map) + + // nub-phantom: preserve an existing generated file, else seed empty. + const phantomPath = join(DIR, 'nub-phantom-extensions.json') + const phantom: ExtMap = existsSync(phantomPath) + ? JSON.parse(readFileSync(phantomPath, 'utf8')) + : {} + if (!existsSync(phantomPath)) writeJson(phantomPath, {}) + + // unified: yarn ∪ pnpm-unique ∪ nub-phantom, deep-merging on selector collision. + const unified: ExtMap = {} + for (const [sel, body] of Object.entries(yarn.map)) unified[sel] = JSON.parse(JSON.stringify(body)) + for (const [sel, body] of Object.entries(pnpm.map)) { + if (unified[sel]) mergeBody(unified[sel], body) + else unified[sel] = JSON.parse(JSON.stringify(body)) + } + for (const [sel, body] of Object.entries(phantom)) { + if (unified[sel]) mergeBody(unified[sel], body) + else unified[sel] = JSON.parse(JSON.stringify(body)) + } + writeJson(join(DIR, 'unified.json'), unified) + + writeFileSync( + join(DIR, 'UPSTREAM'), + `# Which upstream revisions this vendored package-extensions data derives from. +# +# Regenerate with: nub scripts/sync-package-extensions.ts +# (or: node scripts/sync-package-extensions.ts) +# +# The bundled defaults are binary-version ecosystem data, deliberately excluded +# from the lockfile packageExtensionsChecksum (see crates/nub-cli/src/pm_engine/mod.rs +# bundled_package_extensions_defaults). Bumping this data does NOT drift existing +# lockfiles. +# +# UPDATE THIS IN THE SAME COMMIT that changes the vendored data. + +yarn_package = @yarnpkg/extensions +yarn_version = ${yarn.version} +yarn_source = https://github.com/yarnpkg/berry (packages/yarnpkg-extensions) +yarn_license = BSD-2-Clause (Copyright (c) 2016-present, Yarn Contributors) + +pnpm_repo = pnpm/pnpm +pnpm_commit = ${sha(pnpm.sha, 10)} +pnpm_paths = pnpm/crates/package-manager/src/compat_package_extensions.json + pnpm/crates/package-manager/src/pnpm_compat_package_extensions.json +pnpm_note = compat_package_extensions.json is a copy of @yarnpkg/extensions (BSD-2-Clause); + only pnpm_compat_package_extensions.json (pnpm-specific entries not in Yarn yet) + is merged into unified.json. + +nub_phantom = generated by crates/nub-phantom-scan/src/bin/emit-extensions.rs + from \`nub-phantom scan --top N --json\` output (npm-high-impact corpus). +` + ) + + const n = Object.keys(unified).length + console.log(`synced package-extensions: yarn ${Object.keys(yarn.map).length} + pnpm ${Object.keys(pnpm.map).length} + nub-phantom ${Object.keys(phantom).length} -> unified ${n}`) +} + +// `sha` helper: truncate a commit sha for the UPSTREAM marker. +function sha(s: string, len: number): string { + return s.slice(0, len) +} + +main().catch((err) => { + console.error(err) + process.exit(1) +}) diff --git a/site/content/docs/install/virtual-store.mdx b/site/content/docs/install/virtual-store.mdx index cdd67a773..b16f4b539 100644 --- a/site/content/docs/install/virtual-store.mdx +++ b/site/content/docs/install/virtual-store.mdx @@ -40,6 +40,8 @@ As each tarball is imported into the store, Nub parses that version's published At link time, a flagged package is **ejected**: hardlinked into the project as real files instead of symlinked into the store, so its resolution walk passes through the project again — and the undeclared target is linked where that walk finds it. Everything that transitively imports the flagged package is ejected with it; ejecting the offender alone would leave its store-resident importers loading the shared copy — two real paths, two module instances. The ejected closure measures 0.3–2.1% of real large trees, and the symlinked majority keeps the one-link-per-package relink. +Ejection is the fallback. The first line of defense fixes the manifests themselves: Nub bundles a curated set of **package extensions** - declarations added to a dependency's `package.json` at resolve time so an import the package does not declare resolves normally in the store and needs no ejection. The set is the union of [`@yarnpkg/extensions`](https://github.com/yarnpkg/berry/tree/master/packages/yarnpkg-extensions) (the shared Yarn database) and pnpm's companion entries. It is applied as the lowest-precedence layer: a `packageExtensions` entry you author in your `package.json` wins on a matching selector, and a dependency's own declared fields are never overwritten. Bundled extensions are ecosystem data, not project config, so they are kept out of the lockfile `packageExtensionsChecksum` - bumping the bundled set does not drift existing lockfiles or break `--frozen-lockfile`. The bundled set applies under the nub and pnpm identities: a compat install under an npm, yarn, or bun incumbent does not receive it, and ejection covers those trees instead. + Detection and ejection are on for every install, with no configuration. Two toolchains whose resolvers cannot follow symlinks out of the project — Next.js, whose Turbopack canonicalizes paths and confines the module graph to a single project root, and bare React Native, whose Metro config crawls by real path — automatically get a **project-local** store instead: the same isolated layout, with every link staying inside `node_modules`. See [shared vs per-project store](/docs/install#shared-vs-per-project-store). ## Performance diff --git a/vendor/aube/crates/aube-util/src/engine_context.rs b/vendor/aube/crates/aube-util/src/engine_context.rs index 8f0744e3a..764b4b527 100644 --- a/vendor/aube/crates/aube-util/src/engine_context.rs +++ b/vendor/aube/crates/aube-util/src/engine_context.rs @@ -397,6 +397,25 @@ pub struct EngineContext { /// [`embedder_overrides`]: Self::embedder_overrides pub embedder_package_extensions: Option>, + /// Bundled ecosystem `packageExtensions` defaults (Yarn ∪ pnpm ∪ + /// nub-phantom), applied as the LOWEST-precedence layer on top of the + /// user/project extensions. Additive only — `apply_package_extensions` + /// uses `extend_missing`, so a dependency a package already declares is + /// never overwritten, and user extensions (parsed first in + /// `resolve_dependency_policy`) win per-key over bundled ones. + /// + /// Deliberately SEPARATE from [`embedder_package_extensions`]: that seam + /// is a *replacement* source that also feeds the lockfile + /// `packageExtensionsChecksum` (via `effective_package_extensions`). Routing + /// bundled defaults through it would make every bundled-list bump change + /// the checksum, drift every existing lockfile, and abort + /// `--frozen-lockfile` under `enforce_package_extensions_checksum`. This + /// field is read ONLY by `resolve_dependency_policy`, never by the + /// checksum path — so a bundled-list update is a no-op for existing + /// lockfiles (it only affects freshly-resolved packages). Same shape as + /// the replacement seam (`selector -> body`, npm/yarn camelCase bodies). + pub bundled_package_extensions: Option>, + /// Whether the embedder treats `packageExtensions` as a checksummed, /// drift-enforced config like pnpm does. `false` (default) preserves /// upstream behavior: aube stamps `packageExtensionsChecksum` only onto @@ -444,6 +463,7 @@ impl Default for EngineContext { npm_save_prefix_on_bare_exact: false, named_registries_enabled: false, embedder_package_extensions: None, + bundled_package_extensions: None, enforce_package_extensions_checksum: false, } } diff --git a/vendor/aube/crates/aube/src/commands/install/settings.rs b/vendor/aube/crates/aube/src/commands/install/settings.rs index d1ecfffac..4a81821e9 100644 --- a/vendor/aube/crates/aube/src/commands/install/settings.rs +++ b/vendor/aube/crates/aube/src/commands/install/settings.rs @@ -488,7 +488,24 @@ pub(crate) fn resolve_dependency_policy( let mut policy = aube_resolver::DependencyPolicy::default(); let package_extensions = effective_package_extensions(manifest, ctx); - policy.package_extensions = parse_package_extensions(package_extensions); + // User/project extensions first, then bundled ecosystem defaults + // (Yarn ∪ pnpm ∪ nub-phantom) appended LAST. `apply_package_extensions` + // iterates this Vec in order and `extend_missing` is first-write-wins per + // dependency key, so this ordering gives user extensions precedence over + // bundled ones for free. The bundled map is read from the + // `bundled_package_extensions` embedder seam — NEVER from + // `effective_package_extensions`, which feeds the lockfile + // `packageExtensionsChecksum`: routing bundled defaults through the + // checksum would drift every existing lockfile on each bundled-list bump + // and abort `--frozen-lockfile` under `enforce_package_extensions_checksum`. + let mut extensions = parse_package_extensions(package_extensions); + if let Some(bundled) = aube_util::engine_context() + .bundled_package_extensions + .as_ref() + { + extensions.extend(parse_package_extensions(bundled.clone())); + } + policy.package_extensions = extensions; let mut allowed_deprecated = manifest.allowed_deprecated_versions(); merge_string_map_setting(ctx, "allowedDeprecatedVersions", &mut allowed_deprecated); diff --git a/vendor/package-extensions/LICENSE b/vendor/package-extensions/LICENSE new file mode 100644 index 000000000..a177ac683 --- /dev/null +++ b/vendor/package-extensions/LICENSE @@ -0,0 +1,61 @@ +BSD 2-Clause License + +Copyright (c) 2016-present, Yarn Contributors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +--- + +The vendored package-extensions data in this directory derives from +`@yarnpkg/extensions` (https://github.com/yarnpkg/berry, packages/yarnpkg- +extensions), which is distributed under the BSD-2-Clause license above. + +The 3 pnpm-specific entries derive from `pnpm/pnpm` and are MIT-licensed, not +BSD-2-Clause — pnpm's compat copy of Yarn's list is a separate, stale subset of +Yarn's and is NOT merged or vendored here. The full MIT notice covering those +entries is reproduced below (and is also kept at +vendor/aube/licenses/pnpm-LICENSE). + +--- + +The MIT License (MIT) + +Copyright (c) 2015-2016 Rico Sta. Cruz and other contributors +Copyright (c) 2016-2026 Zoltan Kochan and other contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/package-extensions/UPSTREAM b/vendor/package-extensions/UPSTREAM new file mode 100644 index 000000000..23fbfd55c --- /dev/null +++ b/vendor/package-extensions/UPSTREAM @@ -0,0 +1,27 @@ +# Which upstream revisions this vendored package-extensions data derives from. +# +# Regenerate with: nub scripts/sync-package-extensions.ts +# (or: node scripts/sync-package-extensions.ts) +# +# The bundled defaults are binary-version ecosystem data, deliberately excluded +# from the lockfile packageExtensionsChecksum (see crates/nub-cli/src/pm_engine/mod.rs +# bundled_package_extensions_defaults). Bumping this data does NOT drift existing +# lockfiles. +# +# UPDATE THIS IN THE SAME COMMIT that changes the vendored data. + +yarn_package = @yarnpkg/extensions +yarn_version = 2.0.7 +yarn_source = https://github.com/yarnpkg/berry (packages/yarnpkg-extensions) +yarn_license = BSD-2-Clause (Copyright (c) 2016-present, Yarn Contributors) + +pnpm_repo = pnpm/pnpm +pnpm_commit = b40d2624e0 +pnpm_paths = pnpm/crates/package-manager/src/compat_package_extensions.json + pnpm/crates/package-manager/src/pnpm_compat_package_extensions.json +pnpm_note = compat_package_extensions.json is a copy of @yarnpkg/extensions (BSD-2-Clause); + only pnpm_compat_package_extensions.json (pnpm-specific entries not in Yarn yet) + is merged into unified.json. + +nub_phantom = generated by crates/nub-phantom-scan/src/bin/emit-extensions.rs + from `nub-phantom scan --top N --json` output (npm-high-impact corpus). diff --git a/vendor/package-extensions/nub-phantom-extensions.json b/vendor/package-extensions/nub-phantom-extensions.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/vendor/package-extensions/nub-phantom-extensions.json @@ -0,0 +1 @@ +{} diff --git a/vendor/package-extensions/pnpm-extensions.json b/vendor/package-extensions/pnpm-extensions.json new file mode 100644 index 000000000..9549d42ba --- /dev/null +++ b/vendor/package-extensions/pnpm-extensions.json @@ -0,0 +1,17 @@ +{ + "@angular/build@*": { + "dependencies": { + "tslib": "^2.3.0" + } + }, + "@nuxt/vite-builder@>=4.0.0 <4.5.0": { + "dependencies": { + "unplugin": "^2.3.5" + } + }, + "@nuxt/vite-builder@>=4.5.0": { + "dependencies": { + "unplugin": "^3.3.0" + } + } +} diff --git a/vendor/package-extensions/unified.json b/vendor/package-extensions/unified.json new file mode 100644 index 000000000..1fd0fa4f7 --- /dev/null +++ b/vendor/package-extensions/unified.json @@ -0,0 +1,1232 @@ +{ + "@tailwindcss/aspect-ratio@<0.2.1": { + "peerDependencies": { + "tailwindcss": "^2.0.2" + } + }, + "@tailwindcss/line-clamp@<0.2.1": { + "peerDependencies": { + "tailwindcss": "^2.0.2" + } + }, + "@fullhuman/postcss-purgecss@3.1.3 || 3.1.3-alpha.0": { + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "@samverschueren/stream-to-observable@<0.3.1": { + "peerDependenciesMeta": { + "rxjs": { + "optional": true + }, + "zenObservable": { + "optional": true + } + } + }, + "any-observable@<0.5.1": { + "peerDependenciesMeta": { + "rxjs": { + "optional": true + }, + "zenObservable": { + "optional": true + } + } + }, + "@pm2/agent@<1.0.4": { + "dependencies": { + "debug": "*" + } + }, + "debug@<4.2.0": { + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "got@<11": { + "dependencies": { + "@types/responselike": "^1.0.0", + "@types/keyv": "^3.1.1" + } + }, + "cacheable-lookup@<4.1.2": { + "dependencies": { + "@types/keyv": "^3.1.1" + } + }, + "http-link-dataloader@*": { + "peerDependencies": { + "graphql": "^0.13.1 || ^14.0.0" + } + }, + "typescript-language-server@*": { + "dependencies": { + "vscode-jsonrpc": "^5.0.1", + "vscode-languageserver-protocol": "^3.15.0" + } + }, + "postcss-syntax@*": { + "peerDependenciesMeta": { + "postcss-html": { + "optional": true + }, + "postcss-jsx": { + "optional": true + }, + "postcss-less": { + "optional": true + }, + "postcss-markdown": { + "optional": true + }, + "postcss-scss": { + "optional": true + } + } + }, + "jss-plugin-rule-value-function@<=10.1.1": { + "dependencies": { + "tiny-warning": "^1.0.2" + } + }, + "ink-select-input@<4.1.0": { + "peerDependencies": { + "react": "^16.8.2" + } + }, + "license-webpack-plugin@<2.3.18": { + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "snowpack@>=3.3.0": { + "dependencies": { + "node-gyp": "^7.1.0" + } + }, + "promise-inflight@*": { + "peerDependenciesMeta": { + "bluebird": { + "optional": true + } + } + }, + "reactcss@*": { + "peerDependencies": { + "react": "*" + } + }, + "react-color@<=2.19.0": { + "peerDependencies": { + "react": "*" + } + }, + "gatsby-plugin-i18n@*": { + "dependencies": { + "ramda": "^0.24.1" + } + }, + "useragent@^2.0.0": { + "dependencies": { + "request": "^2.88.0", + "yamlparser": "0.0.x", + "semver": "5.5.x" + } + }, + "@apollographql/apollo-tools@<=0.5.2": { + "peerDependencies": { + "graphql": "^14.2.1 || ^15.0.0" + } + }, + "material-table@^2.0.0": { + "dependencies": { + "@babel/runtime": "^7.11.2" + } + }, + "@babel/parser@*": { + "dependencies": { + "@babel/types": "^7.8.3" + } + }, + "fork-ts-checker-webpack-plugin@<=6.3.4": { + "peerDependencies": { + "eslint": ">= 6", + "typescript": ">= 2.7", + "webpack": ">= 4", + "vue-template-compiler": "*" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + } + } + }, + "rc-animate@<=3.1.1": { + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "react-bootstrap-table2-paginator@*": { + "dependencies": { + "classnames": "^2.2.6" + } + }, + "react-draggable@<=4.4.3": { + "peerDependencies": { + "react": ">= 16.3.0", + "react-dom": ">= 16.3.0" + } + }, + "apollo-upload-client@<14": { + "peerDependencies": { + "graphql": "14 - 15" + } + }, + "react-instantsearch-core@<=6.7.0": { + "peerDependencies": { + "algoliasearch": ">= 3.1 < 5" + } + }, + "react-instantsearch-dom@<=6.7.0": { + "dependencies": { + "react-fast-compare": "^3.0.0" + } + }, + "ws@<7.2.1": { + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "react-portal@<4.2.2": { + "peerDependencies": { + "react-dom": "^15.0.0-0 || ^16.0.0-0 || ^17.0.0-0" + } + }, + "react-scripts@<=4.0.1": { + "peerDependencies": { + "react": "*" + } + }, + "testcafe@<=1.10.1": { + "dependencies": { + "@babel/plugin-transform-for-of": "^7.12.1", + "@babel/runtime": "^7.12.5" + } + }, + "testcafe-legacy-api@<=4.2.0": { + "dependencies": { + "testcafe-hammerhead": "^17.0.1", + "read-file-relative": "^1.2.0" + } + }, + "@google-cloud/firestore@<=4.9.3": { + "dependencies": { + "protobufjs": "^6.8.6" + } + }, + "gatsby-source-apiserver@*": { + "dependencies": { + "babel-polyfill": "^6.26.0" + } + }, + "@webpack-cli/package-utils@<=1.0.1-alpha.4": { + "dependencies": { + "cross-spawn": "^7.0.3" + } + }, + "gatsby-remark-prismjs@<3.3.28": { + "dependencies": { + "lodash": "^4" + } + }, + "gatsby-plugin-favicon@*": { + "peerDependencies": { + "webpack": "*" + } + }, + "gatsby-plugin-sharp@<=4.6.0-next.3": { + "dependencies": { + "debug": "^4.3.1" + } + }, + "gatsby-react-router-scroll@<=5.6.0-next.0": { + "dependencies": { + "prop-types": "^15.7.2" + } + }, + "@rebass/forms@*": { + "dependencies": { + "@styled-system/should-forward-prop": "^5.0.0" + }, + "peerDependencies": { + "react": "^16.8.6" + } + }, + "rebass@*": { + "peerDependencies": { + "react": "^16.8.6" + } + }, + "@ant-design/react-slick@<=0.28.3": { + "peerDependencies": { + "react": ">=16.0.0" + } + }, + "mqtt@<4.2.7": { + "dependencies": { + "duplexify": "^4.1.1" + } + }, + "vue-cli-plugin-vuetify@<=2.0.3": { + "dependencies": { + "semver": "^6.3.0" + }, + "peerDependenciesMeta": { + "sass-loader": { + "optional": true + }, + "vuetify-loader": { + "optional": true + } + } + }, + "vue-cli-plugin-vuetify@<=2.0.4": { + "dependencies": { + "null-loader": "^3.0.0" + } + }, + "vue-cli-plugin-vuetify@>=2.4.3": { + "peerDependencies": { + "vue": "*" + } + }, + "@vuetify/cli-plugin-utils@<=0.0.4": { + "dependencies": { + "semver": "^6.3.0" + }, + "peerDependenciesMeta": { + "sass-loader": { + "optional": true + } + } + }, + "@vue/cli-plugin-typescript@<=5.0.0-alpha.0": { + "dependencies": { + "babel-loader": "^8.1.0" + } + }, + "@vue/cli-plugin-typescript@<=5.0.0-beta.0": { + "dependencies": { + "@babel/core": "^7.12.16" + }, + "peerDependencies": { + "vue-template-compiler": "^2.0.0" + }, + "peerDependenciesMeta": { + "vue-template-compiler": { + "optional": true + } + } + }, + "cordova-ios@<=6.3.0": { + "dependencies": { + "underscore": "^1.9.2" + } + }, + "cordova-lib@<=10.0.1": { + "dependencies": { + "underscore": "^1.9.2" + } + }, + "git-node-fs@*": { + "peerDependencies": { + "js-git": "^0.7.8" + }, + "peerDependenciesMeta": { + "js-git": { + "optional": true + } + } + }, + "consolidate@<0.16.0": { + "peerDependencies": { + "mustache": "^3.0.0" + }, + "peerDependenciesMeta": { + "mustache": { + "optional": true + } + } + }, + "consolidate@<=0.16.0": { + "peerDependencies": { + "velocityjs": "^2.0.1", + "tinyliquid": "^0.2.34", + "liquid-node": "^3.0.1", + "jade": "^1.11.0", + "then-jade": "*", + "dust": "^0.3.0", + "dustjs-helpers": "^1.7.4", + "dustjs-linkedin": "^2.7.5", + "swig": "^1.4.2", + "swig-templates": "^2.0.3", + "razor-tmpl": "^1.3.1", + "atpl": ">=0.7.6", + "liquor": "^0.0.5", + "twig": "^1.15.2", + "ejs": "^3.1.5", + "eco": "^1.1.0-rc-3", + "jazz": "^0.0.18", + "jqtpl": "~1.1.0", + "hamljs": "^0.6.2", + "hamlet": "^0.3.3", + "whiskers": "^0.4.0", + "haml-coffee": "^1.14.1", + "hogan.js": "^3.0.2", + "templayed": ">=0.2.3", + "handlebars": "^4.7.6", + "underscore": "^1.11.0", + "lodash": "^4.17.20", + "pug": "^3.0.0", + "then-pug": "*", + "qejs": "^3.0.5", + "walrus": "^0.10.1", + "mustache": "^4.0.1", + "just": "^0.1.8", + "ect": "^0.5.9", + "mote": "^0.2.0", + "toffee": "^0.3.6", + "dot": "^1.1.3", + "bracket-template": "^1.1.5", + "ractive": "^1.3.12", + "nunjucks": "^3.2.2", + "htmling": "^0.0.8", + "babel-core": "^6.26.3", + "plates": "~0.4.11", + "react-dom": "^16.13.1", + "react": "^16.13.1", + "arc-templates": "^0.5.3", + "vash": "^0.13.0", + "slm": "^2.0.0", + "marko": "^3.14.4", + "teacup": "^2.0.0", + "coffee-script": "^1.12.7", + "squirrelly": "^5.1.0", + "twing": "^5.0.2" + }, + "peerDependenciesMeta": { + "velocityjs": { + "optional": true + }, + "tinyliquid": { + "optional": true + }, + "liquid-node": { + "optional": true + }, + "jade": { + "optional": true + }, + "then-jade": { + "optional": true + }, + "dust": { + "optional": true + }, + "dustjs-helpers": { + "optional": true + }, + "dustjs-linkedin": { + "optional": true + }, + "swig": { + "optional": true + }, + "swig-templates": { + "optional": true + }, + "razor-tmpl": { + "optional": true + }, + "atpl": { + "optional": true + }, + "liquor": { + "optional": true + }, + "twig": { + "optional": true + }, + "ejs": { + "optional": true + }, + "eco": { + "optional": true + }, + "jazz": { + "optional": true + }, + "jqtpl": { + "optional": true + }, + "hamljs": { + "optional": true + }, + "hamlet": { + "optional": true + }, + "whiskers": { + "optional": true + }, + "haml-coffee": { + "optional": true + }, + "hogan.js": { + "optional": true + }, + "templayed": { + "optional": true + }, + "handlebars": { + "optional": true + }, + "underscore": { + "optional": true + }, + "lodash": { + "optional": true + }, + "pug": { + "optional": true + }, + "then-pug": { + "optional": true + }, + "qejs": { + "optional": true + }, + "walrus": { + "optional": true + }, + "mustache": { + "optional": true + }, + "just": { + "optional": true + }, + "ect": { + "optional": true + }, + "mote": { + "optional": true + }, + "toffee": { + "optional": true + }, + "dot": { + "optional": true + }, + "bracket-template": { + "optional": true + }, + "ractive": { + "optional": true + }, + "nunjucks": { + "optional": true + }, + "htmling": { + "optional": true + }, + "babel-core": { + "optional": true + }, + "plates": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react": { + "optional": true + }, + "arc-templates": { + "optional": true + }, + "vash": { + "optional": true + }, + "slm": { + "optional": true + }, + "marko": { + "optional": true + }, + "teacup": { + "optional": true + }, + "coffee-script": { + "optional": true + }, + "squirrelly": { + "optional": true + }, + "twing": { + "optional": true + } + } + }, + "vue-loader@<=16.3.3": { + "peerDependencies": { + "@vue/compiler-sfc": "^3.0.8", + "webpack": "^4.1.0 || ^5.0.0-0" + }, + "peerDependenciesMeta": { + "@vue/compiler-sfc": { + "optional": true + } + } + }, + "vue-loader@^16.7.0": { + "peerDependencies": { + "@vue/compiler-sfc": "^3.0.8", + "vue": "^3.2.13" + }, + "peerDependenciesMeta": { + "@vue/compiler-sfc": { + "optional": true + }, + "vue": { + "optional": true + } + } + }, + "scss-parser@<=1.0.5": { + "dependencies": { + "lodash": "^4.17.21" + } + }, + "query-ast@<1.0.5": { + "dependencies": { + "lodash": "^4.17.21" + } + }, + "redux-thunk@<=2.3.0": { + "peerDependencies": { + "redux": "^4.0.0" + } + }, + "skypack@<=0.3.2": { + "dependencies": { + "tar": "^6.1.0" + } + }, + "@npmcli/metavuln-calculator@<2.0.0": { + "dependencies": { + "json-parse-even-better-errors": "^2.3.1" + } + }, + "bin-links@<2.3.0": { + "dependencies": { + "mkdirp-infer-owner": "^1.0.2" + } + }, + "rollup-plugin-polyfill-node@<=0.8.0": { + "peerDependencies": { + "rollup": "^1.20.0 || ^2.0.0" + } + }, + "snowpack@<3.8.6": { + "dependencies": { + "magic-string": "^0.25.7" + } + }, + "elm-webpack-loader@*": { + "dependencies": { + "temp": "^0.9.4" + } + }, + "winston-transport@<=4.4.0": { + "dependencies": { + "logform": "^2.2.0" + } + }, + "jest-vue-preprocessor@*": { + "dependencies": { + "@babel/core": "7.8.7", + "@babel/template": "7.8.6" + }, + "peerDependencies": { + "pug": "^2.0.4" + }, + "peerDependenciesMeta": { + "pug": { + "optional": true + } + } + }, + "redux-persist@*": { + "peerDependencies": { + "react": ">=16" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } + } + }, + "sodium@>=3": { + "dependencies": { + "node-gyp": "^3.8.0" + } + }, + "babel-plugin-graphql-tag@<=3.1.0": { + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0" + } + }, + "@playwright/test@<=1.14.1": { + "dependencies": { + "jest-matcher-utils": "^26.4.2" + } + }, + "babel-plugin-remove-graphql-queries@<3.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "babel-preset-gatsby-package@<1.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "create-gatsby@<1.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-admin@<0.24.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-cli@<3.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-core-utils@<2.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8", + "got": "8.3.2" + } + }, + "gatsby-design-tokens@<3.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-legacy-polyfills@<1.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-benchmark-reporting@<1.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-graphql-config@<0.23.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-image@<1.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-mdx@<2.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-netlify-cms@<5.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-no-sourcemaps@<3.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-page-creator@<3.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-preact@<5.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-preload-fonts@<2.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-schema-snapshot@<2.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-styletron@<6.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-subfont@<3.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-utils@<1.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-recipes@<0.25.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-source-shopify@<5.6.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-source-wikipedia@<3.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-transformer-screenshot@<3.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-worker@<0.5.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-gatsby-cloud@<=3.1.0-next.0": { + "dependencies": { + "gatsby-core-utils": "^2.13.0-next.0" + } + }, + "gatsby-plugin-gatsby-cloud@<=3.2.0-next.1": { + "peerDependencies": { + "webpack": "*" + } + }, + "babel-plugin-remove-graphql-queries@<=3.14.0-next.1": { + "dependencies": { + "gatsby-core-utils": "^2.8.0-next.1" + } + }, + "gatsby-plugin-netlify@3.13.0-next.1": { + "dependencies": { + "gatsby-core-utils": "^2.13.0-next.0" + } + }, + "clipanion-v3-codemod@<=0.2.0": { + "peerDependencies": { + "jscodeshift": "^0.11.0" + } + }, + "react-live@*": { + "peerDependencies": { + "react-dom": "*", + "react": "*" + } + }, + "webpack@<4.44.1": { + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + }, + "webpack-command": { + "optional": true + } + } + }, + "webpack@<5.0.0-beta.23": { + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "webpack-dev-server@<3.10.2": { + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "@docusaurus/responsive-loader@<1.5.0": { + "peerDependenciesMeta": { + "sharp": { + "optional": true + }, + "jimp": { + "optional": true + } + } + }, + "eslint-module-utils@*": { + "peerDependenciesMeta": { + "eslint-import-resolver-node": { + "optional": true + }, + "eslint-import-resolver-typescript": { + "optional": true + }, + "eslint-import-resolver-webpack": { + "optional": true + }, + "@typescript-eslint/parser": { + "optional": true + } + } + }, + "eslint-plugin-import@*": { + "peerDependenciesMeta": { + "@typescript-eslint/parser": { + "optional": true + } + } + }, + "critters-webpack-plugin@<3.0.2": { + "peerDependenciesMeta": { + "html-webpack-plugin": { + "optional": true + } + } + }, + "terser@<=5.10.0": { + "dependencies": { + "acorn": "^8.5.0" + } + }, + "babel-preset-react-app@10.0.x <10.0.2": { + "dependencies": { + "@babel/plugin-proposal-private-property-in-object": "^7.16.7" + } + }, + "eslint-config-react-app@*": { + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "@vue/eslint-config-typescript@<11.0.0": { + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "unplugin-vue2-script-setup@<0.9.1": { + "peerDependencies": { + "@vue/composition-api": "^1.4.3", + "@vue/runtime-dom": "^3.2.26" + } + }, + "@cypress/snapshot@*": { + "dependencies": { + "debug": "^3.2.7" + } + }, + "auto-relay@<=0.14.0": { + "peerDependencies": { + "reflect-metadata": "^0.1.13" + } + }, + "vue-template-babel-compiler@<1.2.0": { + "peerDependencies": { + "vue-template-compiler": "^2.6.0" + } + }, + "@parcel/transformer-image@<2.5.0": { + "peerDependencies": { + "@parcel/core": "*" + } + }, + "@parcel/transformer-js@<2.5.0": { + "peerDependencies": { + "@parcel/core": "*" + } + }, + "parcel@*": { + "peerDependenciesMeta": { + "@parcel/core": { + "optional": true + } + } + }, + "react-scripts@*": { + "peerDependencies": { + "eslint": "*" + } + }, + "focus-trap-react@^8.0.0": { + "dependencies": { + "tabbable": "^5.3.2" + } + }, + "react-rnd@<10.3.7": { + "peerDependencies": { + "react": ">=16.3.0", + "react-dom": ">=16.3.0" + } + }, + "connect-mongo@<5.0.0": { + "peerDependencies": { + "express-session": "^1.17.1" + } + }, + "vue-i18n@<9": { + "peerDependencies": { + "vue": "^2" + } + }, + "vue-router@<4": { + "peerDependencies": { + "vue": "^2" + } + }, + "unified@<10": { + "dependencies": { + "@types/unist": "^2.0.0" + } + }, + "react-github-btn@<=1.3.0": { + "peerDependencies": { + "react": ">=16.3.0" + } + }, + "react-dev-utils@*": { + "peerDependencies": { + "typescript": ">=2.7", + "webpack": ">=4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "@asyncapi/react-component@<=1.0.0-next.39": { + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "xo@*": { + "peerDependencies": { + "webpack": ">=1.11.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "babel-plugin-remove-graphql-queries@<=4.20.0-next.0": { + "dependencies": { + "@babel/types": "^7.15.4" + } + }, + "gatsby-plugin-page-creator@<=4.20.0-next.1": { + "dependencies": { + "fs-extra": "^10.1.0" + } + }, + "gatsby-plugin-utils@<=3.14.0-next.1": { + "dependencies": { + "fastq": "^1.13.0" + }, + "peerDependencies": { + "graphql": "^15.0.0" + } + }, + "gatsby-plugin-mdx@<3.1.0-next.1": { + "dependencies": { + "mkdirp": "^1.0.4" + } + }, + "gatsby-plugin-mdx@^2": { + "peerDependencies": { + "gatsby": "^3.0.0-next" + } + }, + "fdir@<=5.2.0": { + "peerDependencies": { + "picomatch": "2.x" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "babel-plugin-transform-typescript-metadata@<=0.3.2": { + "peerDependencies": { + "@babel/core": "^7", + "@babel/traverse": "^7" + }, + "peerDependenciesMeta": { + "@babel/traverse": { + "optional": true + } + } + }, + "graphql-compose@>=9.0.10": { + "peerDependencies": { + "graphql": "^14.2.0 || ^15.0.0 || ^16.0.0" + } + }, + "vite-plugin-vuetify@<=1.0.2": { + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "webpack-plugin-vuetify@<=2.0.1": { + "peerDependencies": { + "vue": "^3.2.6" + } + }, + "eslint-import-resolver-vite@<2.0.1": { + "dependencies": { + "debug": "^4.3.4", + "resolve": "^1.22.8" + } + }, + "notistack@^3.0.0": { + "dependencies": { + "csstype": "^3.0.10" + } + }, + "@fastify/type-provider-typebox@^5.0.0": { + "peerDependencies": { + "fastify": "^5.0.0" + } + }, + "@fastify/type-provider-typebox@^4.0.0": { + "peerDependencies": { + "fastify": "^4.0.0" + } + }, + "vite-plugin-vue-devtools@>=7.4.3": { + "peerDependencies": { + "vue": "*" + } + }, + "@parcel/resolver-default@>=2": { + "peerDependencies": { + "@parcel/core": "*" + } + }, + "@parcel/node-resolver-core@>=2": { + "peerDependencies": { + "@parcel/core": "*" + } + }, + "@volar/typescript@*": { + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "@volar/language-server@*": { + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "@volar/language-service@*": { + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "volar-service-typescript@*": { + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "volar-service-typescript-twoslash-queries@*": { + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "@angular/build@*": { + "dependencies": { + "tslib": "^2.3.0" + } + }, + "@nuxt/vite-builder@>=4.0.0 <4.5.0": { + "dependencies": { + "unplugin": "^2.3.5" + } + }, + "@nuxt/vite-builder@>=4.5.0": { + "dependencies": { + "unplugin": "^3.3.0" + } + } +} diff --git a/vendor/package-extensions/yarnpkg-extensions.json b/vendor/package-extensions/yarnpkg-extensions.json new file mode 100644 index 000000000..e8e85a343 --- /dev/null +++ b/vendor/package-extensions/yarnpkg-extensions.json @@ -0,0 +1,1217 @@ +{ + "@tailwindcss/aspect-ratio@<0.2.1": { + "peerDependencies": { + "tailwindcss": "^2.0.2" + } + }, + "@tailwindcss/line-clamp@<0.2.1": { + "peerDependencies": { + "tailwindcss": "^2.0.2" + } + }, + "@fullhuman/postcss-purgecss@3.1.3 || 3.1.3-alpha.0": { + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "@samverschueren/stream-to-observable@<0.3.1": { + "peerDependenciesMeta": { + "rxjs": { + "optional": true + }, + "zenObservable": { + "optional": true + } + } + }, + "any-observable@<0.5.1": { + "peerDependenciesMeta": { + "rxjs": { + "optional": true + }, + "zenObservable": { + "optional": true + } + } + }, + "@pm2/agent@<1.0.4": { + "dependencies": { + "debug": "*" + } + }, + "debug@<4.2.0": { + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "got@<11": { + "dependencies": { + "@types/responselike": "^1.0.0", + "@types/keyv": "^3.1.1" + } + }, + "cacheable-lookup@<4.1.2": { + "dependencies": { + "@types/keyv": "^3.1.1" + } + }, + "http-link-dataloader@*": { + "peerDependencies": { + "graphql": "^0.13.1 || ^14.0.0" + } + }, + "typescript-language-server@*": { + "dependencies": { + "vscode-jsonrpc": "^5.0.1", + "vscode-languageserver-protocol": "^3.15.0" + } + }, + "postcss-syntax@*": { + "peerDependenciesMeta": { + "postcss-html": { + "optional": true + }, + "postcss-jsx": { + "optional": true + }, + "postcss-less": { + "optional": true + }, + "postcss-markdown": { + "optional": true + }, + "postcss-scss": { + "optional": true + } + } + }, + "jss-plugin-rule-value-function@<=10.1.1": { + "dependencies": { + "tiny-warning": "^1.0.2" + } + }, + "ink-select-input@<4.1.0": { + "peerDependencies": { + "react": "^16.8.2" + } + }, + "license-webpack-plugin@<2.3.18": { + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "snowpack@>=3.3.0": { + "dependencies": { + "node-gyp": "^7.1.0" + } + }, + "promise-inflight@*": { + "peerDependenciesMeta": { + "bluebird": { + "optional": true + } + } + }, + "reactcss@*": { + "peerDependencies": { + "react": "*" + } + }, + "react-color@<=2.19.0": { + "peerDependencies": { + "react": "*" + } + }, + "gatsby-plugin-i18n@*": { + "dependencies": { + "ramda": "^0.24.1" + } + }, + "useragent@^2.0.0": { + "dependencies": { + "request": "^2.88.0", + "yamlparser": "0.0.x", + "semver": "5.5.x" + } + }, + "@apollographql/apollo-tools@<=0.5.2": { + "peerDependencies": { + "graphql": "^14.2.1 || ^15.0.0" + } + }, + "material-table@^2.0.0": { + "dependencies": { + "@babel/runtime": "^7.11.2" + } + }, + "@babel/parser@*": { + "dependencies": { + "@babel/types": "^7.8.3" + } + }, + "fork-ts-checker-webpack-plugin@<=6.3.4": { + "peerDependencies": { + "eslint": ">= 6", + "typescript": ">= 2.7", + "webpack": ">= 4", + "vue-template-compiler": "*" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + } + } + }, + "rc-animate@<=3.1.1": { + "peerDependencies": { + "react": ">=16.9.0", + "react-dom": ">=16.9.0" + } + }, + "react-bootstrap-table2-paginator@*": { + "dependencies": { + "classnames": "^2.2.6" + } + }, + "react-draggable@<=4.4.3": { + "peerDependencies": { + "react": ">= 16.3.0", + "react-dom": ">= 16.3.0" + } + }, + "apollo-upload-client@<14": { + "peerDependencies": { + "graphql": "14 - 15" + } + }, + "react-instantsearch-core@<=6.7.0": { + "peerDependencies": { + "algoliasearch": ">= 3.1 < 5" + } + }, + "react-instantsearch-dom@<=6.7.0": { + "dependencies": { + "react-fast-compare": "^3.0.0" + } + }, + "ws@<7.2.1": { + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "react-portal@<4.2.2": { + "peerDependencies": { + "react-dom": "^15.0.0-0 || ^16.0.0-0 || ^17.0.0-0" + } + }, + "react-scripts@<=4.0.1": { + "peerDependencies": { + "react": "*" + } + }, + "testcafe@<=1.10.1": { + "dependencies": { + "@babel/plugin-transform-for-of": "^7.12.1", + "@babel/runtime": "^7.12.5" + } + }, + "testcafe-legacy-api@<=4.2.0": { + "dependencies": { + "testcafe-hammerhead": "^17.0.1", + "read-file-relative": "^1.2.0" + } + }, + "@google-cloud/firestore@<=4.9.3": { + "dependencies": { + "protobufjs": "^6.8.6" + } + }, + "gatsby-source-apiserver@*": { + "dependencies": { + "babel-polyfill": "^6.26.0" + } + }, + "@webpack-cli/package-utils@<=1.0.1-alpha.4": { + "dependencies": { + "cross-spawn": "^7.0.3" + } + }, + "gatsby-remark-prismjs@<3.3.28": { + "dependencies": { + "lodash": "^4" + } + }, + "gatsby-plugin-favicon@*": { + "peerDependencies": { + "webpack": "*" + } + }, + "gatsby-plugin-sharp@<=4.6.0-next.3": { + "dependencies": { + "debug": "^4.3.1" + } + }, + "gatsby-react-router-scroll@<=5.6.0-next.0": { + "dependencies": { + "prop-types": "^15.7.2" + } + }, + "@rebass/forms@*": { + "dependencies": { + "@styled-system/should-forward-prop": "^5.0.0" + }, + "peerDependencies": { + "react": "^16.8.6" + } + }, + "rebass@*": { + "peerDependencies": { + "react": "^16.8.6" + } + }, + "@ant-design/react-slick@<=0.28.3": { + "peerDependencies": { + "react": ">=16.0.0" + } + }, + "mqtt@<4.2.7": { + "dependencies": { + "duplexify": "^4.1.1" + } + }, + "vue-cli-plugin-vuetify@<=2.0.3": { + "dependencies": { + "semver": "^6.3.0" + }, + "peerDependenciesMeta": { + "sass-loader": { + "optional": true + }, + "vuetify-loader": { + "optional": true + } + } + }, + "vue-cli-plugin-vuetify@<=2.0.4": { + "dependencies": { + "null-loader": "^3.0.0" + } + }, + "vue-cli-plugin-vuetify@>=2.4.3": { + "peerDependencies": { + "vue": "*" + } + }, + "@vuetify/cli-plugin-utils@<=0.0.4": { + "dependencies": { + "semver": "^6.3.0" + }, + "peerDependenciesMeta": { + "sass-loader": { + "optional": true + } + } + }, + "@vue/cli-plugin-typescript@<=5.0.0-alpha.0": { + "dependencies": { + "babel-loader": "^8.1.0" + } + }, + "@vue/cli-plugin-typescript@<=5.0.0-beta.0": { + "dependencies": { + "@babel/core": "^7.12.16" + }, + "peerDependencies": { + "vue-template-compiler": "^2.0.0" + }, + "peerDependenciesMeta": { + "vue-template-compiler": { + "optional": true + } + } + }, + "cordova-ios@<=6.3.0": { + "dependencies": { + "underscore": "^1.9.2" + } + }, + "cordova-lib@<=10.0.1": { + "dependencies": { + "underscore": "^1.9.2" + } + }, + "git-node-fs@*": { + "peerDependencies": { + "js-git": "^0.7.8" + }, + "peerDependenciesMeta": { + "js-git": { + "optional": true + } + } + }, + "consolidate@<0.16.0": { + "peerDependencies": { + "mustache": "^3.0.0" + }, + "peerDependenciesMeta": { + "mustache": { + "optional": true + } + } + }, + "consolidate@<=0.16.0": { + "peerDependencies": { + "velocityjs": "^2.0.1", + "tinyliquid": "^0.2.34", + "liquid-node": "^3.0.1", + "jade": "^1.11.0", + "then-jade": "*", + "dust": "^0.3.0", + "dustjs-helpers": "^1.7.4", + "dustjs-linkedin": "^2.7.5", + "swig": "^1.4.2", + "swig-templates": "^2.0.3", + "razor-tmpl": "^1.3.1", + "atpl": ">=0.7.6", + "liquor": "^0.0.5", + "twig": "^1.15.2", + "ejs": "^3.1.5", + "eco": "^1.1.0-rc-3", + "jazz": "^0.0.18", + "jqtpl": "~1.1.0", + "hamljs": "^0.6.2", + "hamlet": "^0.3.3", + "whiskers": "^0.4.0", + "haml-coffee": "^1.14.1", + "hogan.js": "^3.0.2", + "templayed": ">=0.2.3", + "handlebars": "^4.7.6", + "underscore": "^1.11.0", + "lodash": "^4.17.20", + "pug": "^3.0.0", + "then-pug": "*", + "qejs": "^3.0.5", + "walrus": "^0.10.1", + "mustache": "^4.0.1", + "just": "^0.1.8", + "ect": "^0.5.9", + "mote": "^0.2.0", + "toffee": "^0.3.6", + "dot": "^1.1.3", + "bracket-template": "^1.1.5", + "ractive": "^1.3.12", + "nunjucks": "^3.2.2", + "htmling": "^0.0.8", + "babel-core": "^6.26.3", + "plates": "~0.4.11", + "react-dom": "^16.13.1", + "react": "^16.13.1", + "arc-templates": "^0.5.3", + "vash": "^0.13.0", + "slm": "^2.0.0", + "marko": "^3.14.4", + "teacup": "^2.0.0", + "coffee-script": "^1.12.7", + "squirrelly": "^5.1.0", + "twing": "^5.0.2" + }, + "peerDependenciesMeta": { + "velocityjs": { + "optional": true + }, + "tinyliquid": { + "optional": true + }, + "liquid-node": { + "optional": true + }, + "jade": { + "optional": true + }, + "then-jade": { + "optional": true + }, + "dust": { + "optional": true + }, + "dustjs-helpers": { + "optional": true + }, + "dustjs-linkedin": { + "optional": true + }, + "swig": { + "optional": true + }, + "swig-templates": { + "optional": true + }, + "razor-tmpl": { + "optional": true + }, + "atpl": { + "optional": true + }, + "liquor": { + "optional": true + }, + "twig": { + "optional": true + }, + "ejs": { + "optional": true + }, + "eco": { + "optional": true + }, + "jazz": { + "optional": true + }, + "jqtpl": { + "optional": true + }, + "hamljs": { + "optional": true + }, + "hamlet": { + "optional": true + }, + "whiskers": { + "optional": true + }, + "haml-coffee": { + "optional": true + }, + "hogan.js": { + "optional": true + }, + "templayed": { + "optional": true + }, + "handlebars": { + "optional": true + }, + "underscore": { + "optional": true + }, + "lodash": { + "optional": true + }, + "pug": { + "optional": true + }, + "then-pug": { + "optional": true + }, + "qejs": { + "optional": true + }, + "walrus": { + "optional": true + }, + "mustache": { + "optional": true + }, + "just": { + "optional": true + }, + "ect": { + "optional": true + }, + "mote": { + "optional": true + }, + "toffee": { + "optional": true + }, + "dot": { + "optional": true + }, + "bracket-template": { + "optional": true + }, + "ractive": { + "optional": true + }, + "nunjucks": { + "optional": true + }, + "htmling": { + "optional": true + }, + "babel-core": { + "optional": true + }, + "plates": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "react": { + "optional": true + }, + "arc-templates": { + "optional": true + }, + "vash": { + "optional": true + }, + "slm": { + "optional": true + }, + "marko": { + "optional": true + }, + "teacup": { + "optional": true + }, + "coffee-script": { + "optional": true + }, + "squirrelly": { + "optional": true + }, + "twing": { + "optional": true + } + } + }, + "vue-loader@<=16.3.3": { + "peerDependencies": { + "@vue/compiler-sfc": "^3.0.8", + "webpack": "^4.1.0 || ^5.0.0-0" + }, + "peerDependenciesMeta": { + "@vue/compiler-sfc": { + "optional": true + } + } + }, + "vue-loader@^16.7.0": { + "peerDependencies": { + "@vue/compiler-sfc": "^3.0.8", + "vue": "^3.2.13" + }, + "peerDependenciesMeta": { + "@vue/compiler-sfc": { + "optional": true + }, + "vue": { + "optional": true + } + } + }, + "scss-parser@<=1.0.5": { + "dependencies": { + "lodash": "^4.17.21" + } + }, + "query-ast@<1.0.5": { + "dependencies": { + "lodash": "^4.17.21" + } + }, + "redux-thunk@<=2.3.0": { + "peerDependencies": { + "redux": "^4.0.0" + } + }, + "skypack@<=0.3.2": { + "dependencies": { + "tar": "^6.1.0" + } + }, + "@npmcli/metavuln-calculator@<2.0.0": { + "dependencies": { + "json-parse-even-better-errors": "^2.3.1" + } + }, + "bin-links@<2.3.0": { + "dependencies": { + "mkdirp-infer-owner": "^1.0.2" + } + }, + "rollup-plugin-polyfill-node@<=0.8.0": { + "peerDependencies": { + "rollup": "^1.20.0 || ^2.0.0" + } + }, + "snowpack@<3.8.6": { + "dependencies": { + "magic-string": "^0.25.7" + } + }, + "elm-webpack-loader@*": { + "dependencies": { + "temp": "^0.9.4" + } + }, + "winston-transport@<=4.4.0": { + "dependencies": { + "logform": "^2.2.0" + } + }, + "jest-vue-preprocessor@*": { + "dependencies": { + "@babel/core": "7.8.7", + "@babel/template": "7.8.6" + }, + "peerDependencies": { + "pug": "^2.0.4" + }, + "peerDependenciesMeta": { + "pug": { + "optional": true + } + } + }, + "redux-persist@*": { + "peerDependencies": { + "react": ">=16" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + } + } + }, + "sodium@>=3": { + "dependencies": { + "node-gyp": "^3.8.0" + } + }, + "babel-plugin-graphql-tag@<=3.1.0": { + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0" + } + }, + "@playwright/test@<=1.14.1": { + "dependencies": { + "jest-matcher-utils": "^26.4.2" + } + }, + "babel-plugin-remove-graphql-queries@<3.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "babel-preset-gatsby-package@<1.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "create-gatsby@<1.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-admin@<0.24.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-cli@<3.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-core-utils@<2.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8", + "got": "8.3.2" + } + }, + "gatsby-design-tokens@<3.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-legacy-polyfills@<1.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-benchmark-reporting@<1.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-graphql-config@<0.23.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-image@<1.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-mdx@<2.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-netlify-cms@<5.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-no-sourcemaps@<3.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-page-creator@<3.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-preact@<5.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-preload-fonts@<2.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-schema-snapshot@<2.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-styletron@<6.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-subfont@<3.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-utils@<1.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-recipes@<0.25.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-source-shopify@<5.6.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-source-wikipedia@<3.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-transformer-screenshot@<3.14.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-worker@<0.5.0-next.1": { + "dependencies": { + "@babel/runtime": "^7.14.8" + } + }, + "gatsby-plugin-gatsby-cloud@<=3.1.0-next.0": { + "dependencies": { + "gatsby-core-utils": "^2.13.0-next.0" + } + }, + "gatsby-plugin-gatsby-cloud@<=3.2.0-next.1": { + "peerDependencies": { + "webpack": "*" + } + }, + "babel-plugin-remove-graphql-queries@<=3.14.0-next.1": { + "dependencies": { + "gatsby-core-utils": "^2.8.0-next.1" + } + }, + "gatsby-plugin-netlify@3.13.0-next.1": { + "dependencies": { + "gatsby-core-utils": "^2.13.0-next.0" + } + }, + "clipanion-v3-codemod@<=0.2.0": { + "peerDependencies": { + "jscodeshift": "^0.11.0" + } + }, + "react-live@*": { + "peerDependencies": { + "react-dom": "*", + "react": "*" + } + }, + "webpack@<4.44.1": { + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + }, + "webpack-command": { + "optional": true + } + } + }, + "webpack@<5.0.0-beta.23": { + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "webpack-dev-server@<3.10.2": { + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "@docusaurus/responsive-loader@<1.5.0": { + "peerDependenciesMeta": { + "sharp": { + "optional": true + }, + "jimp": { + "optional": true + } + } + }, + "eslint-module-utils@*": { + "peerDependenciesMeta": { + "eslint-import-resolver-node": { + "optional": true + }, + "eslint-import-resolver-typescript": { + "optional": true + }, + "eslint-import-resolver-webpack": { + "optional": true + }, + "@typescript-eslint/parser": { + "optional": true + } + } + }, + "eslint-plugin-import@*": { + "peerDependenciesMeta": { + "@typescript-eslint/parser": { + "optional": true + } + } + }, + "critters-webpack-plugin@<3.0.2": { + "peerDependenciesMeta": { + "html-webpack-plugin": { + "optional": true + } + } + }, + "terser@<=5.10.0": { + "dependencies": { + "acorn": "^8.5.0" + } + }, + "babel-preset-react-app@10.0.x <10.0.2": { + "dependencies": { + "@babel/plugin-proposal-private-property-in-object": "^7.16.7" + } + }, + "eslint-config-react-app@*": { + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "@vue/eslint-config-typescript@<11.0.0": { + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "unplugin-vue2-script-setup@<0.9.1": { + "peerDependencies": { + "@vue/composition-api": "^1.4.3", + "@vue/runtime-dom": "^3.2.26" + } + }, + "@cypress/snapshot@*": { + "dependencies": { + "debug": "^3.2.7" + } + }, + "auto-relay@<=0.14.0": { + "peerDependencies": { + "reflect-metadata": "^0.1.13" + } + }, + "vue-template-babel-compiler@<1.2.0": { + "peerDependencies": { + "vue-template-compiler": "^2.6.0" + } + }, + "@parcel/transformer-image@<2.5.0": { + "peerDependencies": { + "@parcel/core": "*" + } + }, + "@parcel/transformer-js@<2.5.0": { + "peerDependencies": { + "@parcel/core": "*" + } + }, + "parcel@*": { + "peerDependenciesMeta": { + "@parcel/core": { + "optional": true + } + } + }, + "react-scripts@*": { + "peerDependencies": { + "eslint": "*" + } + }, + "focus-trap-react@^8.0.0": { + "dependencies": { + "tabbable": "^5.3.2" + } + }, + "react-rnd@<10.3.7": { + "peerDependencies": { + "react": ">=16.3.0", + "react-dom": ">=16.3.0" + } + }, + "connect-mongo@<5.0.0": { + "peerDependencies": { + "express-session": "^1.17.1" + } + }, + "vue-i18n@<9": { + "peerDependencies": { + "vue": "^2" + } + }, + "vue-router@<4": { + "peerDependencies": { + "vue": "^2" + } + }, + "unified@<10": { + "dependencies": { + "@types/unist": "^2.0.0" + } + }, + "react-github-btn@<=1.3.0": { + "peerDependencies": { + "react": ">=16.3.0" + } + }, + "react-dev-utils@*": { + "peerDependencies": { + "typescript": ">=2.7", + "webpack": ">=4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "@asyncapi/react-component@<=1.0.0-next.39": { + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "xo@*": { + "peerDependencies": { + "webpack": ">=1.11.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "babel-plugin-remove-graphql-queries@<=4.20.0-next.0": { + "dependencies": { + "@babel/types": "^7.15.4" + } + }, + "gatsby-plugin-page-creator@<=4.20.0-next.1": { + "dependencies": { + "fs-extra": "^10.1.0" + } + }, + "gatsby-plugin-utils@<=3.14.0-next.1": { + "dependencies": { + "fastq": "^1.13.0" + }, + "peerDependencies": { + "graphql": "^15.0.0" + } + }, + "gatsby-plugin-mdx@<3.1.0-next.1": { + "dependencies": { + "mkdirp": "^1.0.4" + } + }, + "gatsby-plugin-mdx@^2": { + "peerDependencies": { + "gatsby": "^3.0.0-next" + } + }, + "fdir@<=5.2.0": { + "peerDependencies": { + "picomatch": "2.x" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "babel-plugin-transform-typescript-metadata@<=0.3.2": { + "peerDependencies": { + "@babel/core": "^7", + "@babel/traverse": "^7" + }, + "peerDependenciesMeta": { + "@babel/traverse": { + "optional": true + } + } + }, + "graphql-compose@>=9.0.10": { + "peerDependencies": { + "graphql": "^14.2.0 || ^15.0.0 || ^16.0.0" + } + }, + "vite-plugin-vuetify@<=1.0.2": { + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "webpack-plugin-vuetify@<=2.0.1": { + "peerDependencies": { + "vue": "^3.2.6" + } + }, + "eslint-import-resolver-vite@<2.0.1": { + "dependencies": { + "debug": "^4.3.4", + "resolve": "^1.22.8" + } + }, + "notistack@^3.0.0": { + "dependencies": { + "csstype": "^3.0.10" + } + }, + "@fastify/type-provider-typebox@^5.0.0": { + "peerDependencies": { + "fastify": "^5.0.0" + } + }, + "@fastify/type-provider-typebox@^4.0.0": { + "peerDependencies": { + "fastify": "^4.0.0" + } + }, + "vite-plugin-vue-devtools@>=7.4.3": { + "peerDependencies": { + "vue": "*" + } + }, + "@parcel/resolver-default@>=2": { + "peerDependencies": { + "@parcel/core": "*" + } + }, + "@parcel/node-resolver-core@>=2": { + "peerDependencies": { + "@parcel/core": "*" + } + }, + "@volar/typescript@*": { + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "@volar/language-server@*": { + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "@volar/language-service@*": { + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "volar-service-typescript@*": { + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "volar-service-typescript-twoslash-queries@*": { + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + } +}