bitview: reorg part 6

This commit is contained in:
nym21
2025-09-27 19:52:11 +02:00
parent dfe5148f17
commit 9d03fdf31d
95 changed files with 4395 additions and 441 deletions
Generated
+76 -74
View File
@@ -4,9 +4,9 @@ version = 4
[[package]]
name = "addr2line"
version = "0.24.2"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b"
dependencies = [
"gimli",
]
@@ -182,9 +182,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]]
name = "async-compression"
version = "0.4.31"
version = "0.4.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9611ec0b6acea03372540509035db2f7f1e9f04da5d27728436fa994033c00a0"
checksum = "5a89bce6054c720275ac2432fbba080a66a2106a44a1b804553930ca6909f4e0"
dependencies = [
"compression-codecs",
"compression-core",
@@ -283,9 +283,9 @@ dependencies = [
[[package]]
name = "backtrace"
version = "0.3.75"
version = "0.3.76"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6"
dependencies = [
"addr2line",
"cfg-if",
@@ -293,7 +293,7 @@ dependencies = [
"miniz_oxide",
"object",
"rustc-demangle",
"windows-targets 0.52.6",
"windows-link",
]
[[package]]
@@ -515,6 +515,14 @@ dependencies = [
"brk_structs",
]
[[package]]
name = "brk_bridge"
version = "0.0.109"
dependencies = [
"brk_interface",
"brk_structs",
]
[[package]]
name = "brk_bundler"
version = "0.0.109"
@@ -531,6 +539,7 @@ name = "brk_cli"
version = "0.0.109"
dependencies = [
"bitcoincore-rpc",
"brk_bridge",
"brk_bundler",
"brk_computer",
"brk_fetcher",
@@ -1070,7 +1079,7 @@ dependencies = [
"quick_cache",
"serde",
"serde_json",
"sonic-rs 0.5.4",
"sonic-rs 0.5.5",
"tokio",
"tower-http",
"tracing",
@@ -1183,9 +1192,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.2.38"
version = "1.2.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9"
checksum = "e1354349954c6fc9cb0deab020f27f783cf0b604e8bb754dc4658ecf0d29c35f"
dependencies = [
"find-msvc-tools",
"jobserver",
@@ -1227,7 +1236,7 @@ dependencies = [
"num-traits",
"serde",
"wasm-bindgen",
"windows-link 0.2.0",
"windows-link",
]
[[package]]
@@ -1335,9 +1344,9 @@ checksum = "ea0095f6103c2a8b44acd6fd15960c801dafebf02e21940360833e0673f48ba7"
[[package]]
name = "compression-codecs"
version = "0.4.30"
version = "0.4.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "485abf41ac0c8047c07c87c72c8fb3eb5197f6e9d7ded615dfd1a00ae00a0f64"
checksum = "ef8a506ec4b81c460798f572caead636d57d3d7e940f998160f52bd254bf2d23"
dependencies = [
"brotli",
"compression-core",
@@ -1507,7 +1516,7 @@ checksum = "881c5d0a13b2f1498e2306e82cbada78390e152d4b1378fb28a84f4dcd0dc4f3"
dependencies = [
"dispatch",
"nix",
"windows-sys 0.61.0",
"windows-sys 0.61.1",
]
[[package]]
@@ -1640,7 +1649,7 @@ dependencies = [
"libc",
"option-ext",
"redox_users",
"windows-sys 0.61.0",
"windows-sys 0.61.1",
]
[[package]]
@@ -1750,7 +1759,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.61.0",
"windows-sys 0.61.1",
]
[[package]]
@@ -2016,9 +2025,9 @@ dependencies = [
[[package]]
name = "gimli"
version = "0.31.1"
version = "0.32.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7"
[[package]]
name = "guardian"
@@ -2632,9 +2641,9 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
[[package]]
name = "memchr"
version = "2.7.5"
version = "2.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
[[package]]
name = "memmap2"
@@ -2855,9 +2864,9 @@ dependencies = [
[[package]]
name = "object"
version = "0.36.7"
version = "0.37.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe"
dependencies = [
"memchr",
]
@@ -2918,9 +2927,9 @@ dependencies = [
[[package]]
name = "oxc-browserslist"
version = "2.1.1"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37c5bf598bf7f55955c737d580cdadaeeda80e0e6430834f6165aef21220e3a2"
checksum = "7612127f5fa1ef0f3e98905ddfc10a7fa1df98944b75d774bb3cb4b530663616"
dependencies = [
"bincode",
"flate2",
@@ -3248,9 +3257,9 @@ dependencies = [
[[package]]
name = "oxc_sourcemap"
version = "4.1.5"
version = "4.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6194c58467a15d9dcb5cb852fcad312af57fd46fabd419fae87fcf801f83702"
checksum = "05ff280f25901ac054ad8552395ecd6a455e4b9352a94debbc34c433760586ef"
dependencies = [
"base64-simd",
"json-escape-simd",
@@ -3855,9 +3864,9 @@ dependencies = [
[[package]]
name = "regex"
version = "1.11.2"
version = "1.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912"
checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c"
dependencies = [
"aho-corasick",
"memchr",
@@ -3867,9 +3876,9 @@ dependencies = [
[[package]]
name = "regex-automata"
version = "0.4.10"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6"
checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad"
dependencies = [
"aho-corasick",
"memchr",
@@ -3983,7 +3992,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.61.0",
"windows-sys 0.61.1",
]
[[package]]
@@ -4111,7 +4120,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b55fb86dfd3a2f5f76ea78310a88f96c4ea21a3031f8d212443d56123fd0521"
dependencies = [
"libc",
"windows-sys 0.61.0",
"windows-sys 0.61.1",
]
[[package]]
@@ -4144,9 +4153,9 @@ dependencies = [
[[package]]
name = "serde"
version = "1.0.226"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
"serde_derive",
@@ -4164,18 +4173,18 @@ dependencies = [
[[package]]
name = "serde_core"
version = "1.0.226"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.226"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
@@ -4374,9 +4383,9 @@ dependencies = [
[[package]]
name = "sonic-rs"
version = "0.5.4"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0e0c5c1c429b500b4583e860ed48f9e34968cb1ba49dd16c1e2743678e3fd18"
checksum = "22540d56ba14521e4878ad436d498518c59698c39a89d5905c694932f0bf7134"
dependencies = [
"ahash",
"bumpalo",
@@ -4521,7 +4530,7 @@ dependencies = [
"getrandom 0.3.3",
"once_cell",
"rustix",
"windows-sys 0.61.0",
"windows-sys 0.61.1",
]
[[package]]
@@ -5227,7 +5236,7 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
"windows-sys 0.61.0",
"windows-sys 0.61.1",
]
[[package]]
@@ -5238,55 +5247,54 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows"
version = "0.62.0"
version = "0.62.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9579d0e6970fd5250aa29aba5994052385ff55cf7b28a059e484bb79ea842e42"
checksum = "49e6c4a1f363c8210c6f77ba24f645c61c6fb941eccf013da691f7e09515b8ac"
dependencies = [
"windows-collections",
"windows-core",
"windows-future",
"windows-link 0.2.0",
"windows-numerics",
]
[[package]]
name = "windows-collections"
version = "0.3.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a90dd7a7b86859ec4cdf864658b311545ef19dbcf17a672b52ab7cefe80c336f"
checksum = "123e712f464a8a60ce1a13f4c446d2d43ab06464cb5842ff68f5c71b6fb7852e"
dependencies = [
"windows-core",
]
[[package]]
name = "windows-core"
version = "0.62.0"
version = "0.62.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c"
checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9"
dependencies = [
"windows-implement",
"windows-interface",
"windows-link 0.2.0",
"windows-link",
"windows-result",
"windows-strings",
]
[[package]]
name = "windows-future"
version = "0.3.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2194dee901458cb79e1148a4e9aac2b164cc95fa431891e7b296ff0b2f1d8a6"
checksum = "68f3db6b24b120200d649cd4811b4947188ed3a8d2626f7075146c5d178a9a4a"
dependencies = [
"windows-core",
"windows-link 0.2.0",
"windows-link",
"windows-threading",
]
[[package]]
name = "windows-implement"
version = "0.60.0"
version = "0.60.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
checksum = "edb307e42a74fb6de9bf3a02d9712678b22399c87e6fa869d6dfcd8c1b7754e0"
dependencies = [
"proc-macro2",
"quote",
@@ -5295,21 +5303,15 @@ dependencies = [
[[package]]
name = "windows-interface"
version = "0.59.1"
version = "0.59.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
checksum = "c0abd1ddbc6964ac14db11c7213d6532ef34bd9aa042c2e5935f59d7908b46a5"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.106",
]
[[package]]
name = "windows-link"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
[[package]]
name = "windows-link"
version = "0.2.0"
@@ -5323,7 +5325,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ce3498fe0aba81e62e477408383196b4b0363db5e0c27646f932676283b43d8"
dependencies = [
"windows-core",
"windows-link 0.2.0",
"windows-link",
]
[[package]]
@@ -5332,7 +5334,7 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f"
dependencies = [
"windows-link 0.2.0",
"windows-link",
]
[[package]]
@@ -5341,7 +5343,7 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda"
dependencies = [
"windows-link 0.2.0",
"windows-link",
]
[[package]]
@@ -5368,16 +5370,16 @@ version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
"windows-targets 0.53.3",
"windows-targets 0.53.4",
]
[[package]]
name = "windows-sys"
version = "0.61.0"
version = "0.61.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa"
checksum = "6f109e41dd4a3c848907eb83d5a42ea98b3769495597450cf6d153507b166f0f"
dependencies = [
"windows-link 0.2.0",
"windows-link",
]
[[package]]
@@ -5398,11 +5400,11 @@ dependencies = [
[[package]]
name = "windows-targets"
version = "0.53.3"
version = "0.53.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b"
dependencies = [
"windows-link 0.1.3",
"windows-link",
"windows_aarch64_gnullvm 0.53.0",
"windows_aarch64_msvc 0.53.0",
"windows_i686_gnu 0.53.0",
@@ -5419,7 +5421,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab47f085ad6932defa48855254c758cdd0e2f2d48e62a34118a268d8f345e118"
dependencies = [
"windows-link 0.2.0",
"windows-link",
]
[[package]]
+4 -3
View File
@@ -45,6 +45,7 @@ allocative = { version = "0.3.4", features = ["parking_lot"] }
axum = "0.8.4"
bitcoin = { version = "0.32.7", features = ["serde"] }
bitcoincore-rpc = "0.19.0"
brk_bridge = { version = "0.0.109", path = "crates/brk_bridge" }
brk_bundler = { version = "0.0.109", path = "crates/brk_bundler" }
brk_cli = { version = "0.0.109", path = "crates/brk_cli" }
brk_computer = { version = "0.0.109", path = "crates/brk_computer" }
@@ -67,11 +68,11 @@ minreq = { version = "2.14.1", features = ["https", "serde_json"] }
parking_lot = "0.12.4"
quick_cache = "0.6.16"
rayon = "1.11.0"
serde = "1.0.226"
serde = "1.0.228"
serde_bytes = "0.11.19"
serde_derive = "1.0.226"
serde_derive = "1.0.228"
serde_json = { version = "1.0.145", features = ["float_roundtrip"] }
sonic-rs = "0.5.4"
sonic-rs = "0.5.5"
tokio = { version = "1.47.1", features = ["rt-multi-thread"] }
# vecdb = { path = "../seqdb/crates/vecdb", features = ["derive"]}
vecdb = { version = "0.2.16", features = ["derive"]}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 340 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 263 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 386 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 496 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 564 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 592 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 453 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 526 KiB

+14
View File
@@ -0,0 +1,14 @@
[package]
name = "brk_bridge"
description = "A generator of bridge files for other languages"
version.workspace = true
edition.workspace = true
license.workspace = true
homepage.workspace = true
repository.workspace = true
rust-version.workspace = true
build = "build.rs"
[dependencies]
brk_interface = { workspace = true }
brk_structs = { workspace = true }
+1
View File
@@ -0,0 +1 @@
# brk_bridge
+8
View File
@@ -0,0 +1,8 @@
fn main() {
let profile = std::env::var("PROFILE").unwrap_or_default();
if profile == "release" {
println!("cargo:rustc-flag=-C");
println!("cargo:rustc-flag=target-cpu=native");
}
}
+291
View File
@@ -0,0 +1,291 @@
use std::{
collections::{BTreeMap, HashMap},
fs, io,
path::Path,
};
use brk_interface::{Index, Interface};
use brk_structs::pools;
use super::VERSION;
const AUTO_GENERATED_DISCLAIMER: &str = "//
// File auto-generated, any modifications will be overwritten
//";
#[allow(clippy::upper_case_acronyms)]
pub trait Bridge {
fn generate_js_files(&self, packages_path: &Path) -> io::Result<()>;
}
impl Bridge for Interface<'static> {
fn generate_js_files(&self, packages_path: &Path) -> io::Result<()> {
let path = packages_path.join("brk");
if !fs::exists(&path)? {
return Ok(());
}
let path = packages_path.join("generated");
fs::create_dir_all(&path)?;
generate_version_file(&path)?;
generate_metrics_file(self, &path)?;
generate_pools_file(&path)
}
}
fn generate_version_file(parent: &Path) -> io::Result<()> {
let path = parent.join(Path::new("metrics.js"));
let contents = format!(
"{AUTO_GENERATED_DISCLAIMER}
export const VERSION = \"v{VERSION}\";
"
);
fs::write(path, contents)
}
fn generate_pools_file(parent: &Path) -> io::Result<()> {
let path = parent.join(Path::new("pools.js"));
let pools = pools();
let mut contents = format!("{AUTO_GENERATED_DISCLAIMER}\n");
contents += "
/**
* @typedef {typeof POOL_ID_TO_POOL_NAME} PoolIdToPoolName
* @typedef {keyof PoolIdToPoolName} PoolId
*/
export const POOL_ID_TO_POOL_NAME = /** @type {const} */ ({
";
let mut sorted_pools: Vec<_> = pools.iter().collect();
sorted_pools.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase()));
contents += &sorted_pools
.iter()
.map(|pool| {
let id = pool.serialized_id();
format!(" {id}: \"{}\",", pool.name)
})
.collect::<Vec<_>>()
.join("\n");
contents += "\n});\n";
fs::write(path, contents)
}
fn generate_metrics_file(interface: &Interface<'static>, parent: &Path) -> io::Result<()> {
let path = parent.join(Path::new("metrics.js"));
let indexes = Index::all();
let mut contents = format!(
"{AUTO_GENERATED_DISCLAIMER}
/**
"
);
contents += &indexes
.iter()
.map(|i| format!(" * @typedef {{\"{}\"}} {i}", i.serialize_long()))
.collect::<Vec<_>>()
.join("\n");
contents += &format!(
"
* @typedef {{{}}} Index",
indexes
.iter()
.map(|i| i.to_string())
.collect::<Vec<_>>()
.join(" | ")
);
let mut unique_index_groups = BTreeMap::new();
contents += "
*
* @typedef {typeof COMPRESSED_METRIC_TO_INDEXES} MetricToIndexes
* @typedef {string} Metric
*/
";
let mut word_to_freq: BTreeMap<_, usize> = BTreeMap::new();
interface
.metric_to_index_to_vec()
.keys()
.for_each(|metric| {
metric.split("_").for_each(|word| {
*word_to_freq.entry(word).or_default() += 1;
});
});
let mut word_to_freq = word_to_freq.into_iter().collect::<Vec<_>>();
word_to_freq.sort_unstable_by(|a, b| b.1.cmp(&a.1).then(a.0.cmp(b.0)));
let words = word_to_freq
.into_iter()
.map(|(str, _)| str)
.collect::<Vec<_>>();
contents += &format!(
"const INDEX_TO_WORD = [
{}
];
",
words
.iter()
.map(|w| format!("\"{w}\""))
.collect::<Vec<_>>()
.join(",\n ")
);
contents += "
const WORD_TO_INDEX = {};
INDEX_TO_WORD.forEach((word, index) => {
WORD_TO_INDEX[word] = index;
});
function lettersToIndex(s) {
let result = 0;
for (let i = 0; i < s.length; i++) {
const value = charToIndex(s.charCodeAt(i));
result = result * 52 + value + 1;
}
return result - 1;
}
function charToIndex(c) {
const A = 65, Z = 90, a = 97, z = 122;
if (c >= A && c <= Z) {
return c - A;
} else if (c >= a && c <= z) {
return c - a + 26;
} else {
return 255; // Invalid
}
}
function compressMetric(metric) {
return metric
.split('_')
.map((word) => {
const index = WORD_TO_INDEX[word];
if (index === undefined) throw \"bad word\";
return indexToLetters(index);
})
.join('_');
}
function decompressMetric(compressedMetric) {
return compressedMetric
.split('_')
.map((code) => {
const index = lettersToIndex(code);
return WORDS[index] || code; // Fallback to original if not found
})
.join('_');
}
";
let word_to_base62 = words
.into_iter()
.enumerate()
.map(|(i, w)| (w, index_to_letters(i)))
.collect::<HashMap<_, _>>();
let mut ser_metric_to_indexes = "
/** @type {Record<string, Index[]>} */
const COMPRESSED_METRIC_TO_INDEXES = {
"
.to_string();
interface
.metric_to_index_to_vec()
.iter()
.for_each(|(metric, index_to_vec)| {
let indexes = index_to_vec
.keys()
.map(|i| format!("\"{}\"", i.serialize_long()))
.collect::<Vec<_>>()
.join(", ");
let indexes = format!("[{indexes}]");
let unique = unique_index_groups.len();
let index = index_to_letters(*unique_index_groups.entry(indexes).or_insert(unique));
let compressed_metric = metric.split('_').fold(String::new(), |mut acc, w| {
if !acc.is_empty() {
acc.push('_');
}
acc.push_str(&word_to_base62[w]);
acc
});
ser_metric_to_indexes += &format!(" {compressed_metric}: {index},\n");
});
ser_metric_to_indexes += "};
";
let mut sorted_groups: Vec<_> = unique_index_groups.into_iter().collect();
sorted_groups.sort_by_key(|(_, index)| *index);
sorted_groups.into_iter().for_each(|(group, index)| {
let index = index_to_letters(index);
contents += &format!("/** @type {{Index[]}} */\nconst {index} = {group};\n");
});
contents += &ser_metric_to_indexes;
fs::write(path, contents)
}
fn index_to_letters(mut index: usize) -> String {
if index < 52 {
return (index_to_char(index) as char).to_string();
}
let mut result = [0u8; 8];
let mut pos = 8;
loop {
pos -= 1;
result[pos] = index_to_char(index % 52);
index /= 52;
if index == 0 {
break;
}
index -= 1;
}
unsafe { String::from_utf8_unchecked(result[pos..].to_vec()) }
}
fn index_to_char(index: usize) -> u8 {
match index {
0..=25 => b'A' + index as u8,
26..=51 => b'a' + (index - 26) as u8,
_ => unreachable!(),
}
}
// fn letters_to_index(s: &str) -> usize {
// let mut result = 0;
// for byte in s.bytes() {
// let value = char_to_index(byte) as usize;
// result = result * 52 + value + 1;
// }
// result - 1
// }
// fn char_to_index(byte: u8) -> u8 {
// match byte {
// b'A'..=b'Z' => byte - b'A',
// b'a'..=b'z' => byte - b'a' + 26,
// _ => 255, // Invalid
// }
// }
+5
View File
@@ -0,0 +1,5 @@
mod js;
pub use js::Bridge;
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
+1
View File
@@ -0,0 +1 @@
// TODO ?
+1
View File
@@ -11,6 +11,7 @@ build = "build.rs"
[dependencies]
bitcoincore-rpc = { workspace = true }
brk_bridge = { workspace = true }
brk_bundler = { workspace = true }
brk_computer = { workspace = true }
brk_fetcher = { workspace = true }
-154
View File
@@ -1,154 +0,0 @@
use std::{fs, io, path::Path};
use brk_interface::{Index, Interface};
use brk_server::VERSION;
use brk_structs::pools;
use crate::website::Website;
const BRIDGE_PATH: &str = "scripts/bridge";
#[allow(clippy::upper_case_acronyms)]
pub trait Bridge {
fn generate_bridge_files(&self, website: Website, websites_path: &Path) -> io::Result<()>;
}
impl Bridge for Interface<'static> {
fn generate_bridge_files(&self, website: Website, websites_path: &Path) -> io::Result<()> {
if website.is_none() {
return Ok(());
}
let path = websites_path.join(website.to_folder_name());
if !fs::exists(&path)? {
return Ok(());
}
let path = path.join(BRIDGE_PATH);
fs::create_dir_all(&path)?;
generate_metrics_file(self, &path)?;
generate_pools_file(&path)
}
}
fn generate_pools_file(parent: &Path) -> io::Result<()> {
let path = parent.join(Path::new("pools.js"));
let pools = pools();
let mut contents = "//
// File auto-generated, any modifications will be overwritten
//
"
.to_string();
contents += "
/** @typedef {ReturnType<typeof createPools>} Pools */
/** @typedef {keyof Pools} Pool */
export function createPools() {
return /** @type {const} */ ({
";
let mut sorted_pools: Vec<_> = pools.iter().collect();
sorted_pools.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase()));
contents += &sorted_pools
.iter()
.map(|pool| {
let id = pool.serialized_id();
format!(" {id}: \"{}\",", pool.name)
})
.collect::<Vec<_>>()
.join("\n");
contents += "\n });\n}\n";
fs::write(path, contents)
}
fn generate_metrics_file(interface: &Interface<'static>, parent: &Path) -> io::Result<()> {
let path = parent.join(Path::new("metrics.js"));
let indexes = Index::all();
let mut contents = format!(
"//
// File auto-generated, any modifications will be overwritten
//
export const VERSION = \"v{VERSION}\";
"
);
contents += &indexes
.iter()
.enumerate()
.map(|(i_of_i, i)| {
// let lowered = i.to_string().to_lowercase();
format!("/** @typedef {{{i_of_i}}} {i} */",)
})
.collect::<Vec<_>>()
.join("\n");
contents += &format!(
"\n\n/** @typedef {{{}}} Index */\n",
indexes
.iter()
.map(|i| i.to_string())
.collect::<Vec<_>>()
.join(" | ")
);
contents += "
/** @typedef {ReturnType<typeof createIndexes>} Indexes */
export function createIndexes() {
return {
";
contents += &indexes
.iter()
.enumerate()
.map(|(i_of_i, i)| {
let lowered = i.to_string().to_lowercase();
format!(" {lowered}: /** @satisfies {{{i}}} */ ({i_of_i}),",)
})
.collect::<Vec<_>>()
.join("\n");
contents += " };\n}\n";
contents += "
/** @typedef {ReturnType<typeof createMetricToIndexes>} MetricToIndexes
/** @typedef {keyof MetricToIndexes} Metric */
/**
* @returns {Record<any, number[]>}
*/
export function createMetricToIndexes() {
return {
";
interface
.id_to_index_to_vec()
.iter()
.for_each(|(id, index_to_vec)| {
let indexes = index_to_vec
.keys()
.map(|i| (*i as u8).to_string())
// .map(|i| i.to_string())
.collect::<Vec<_>>()
.join(", ");
contents += &format!(" \"{id}\": [{indexes}],\n");
});
contents += " };\n}\n";
fs::write(path, contents)
}
+95 -85
View File
@@ -9,6 +9,7 @@ use std::{
};
use bitcoincore_rpc::{self, RpcApi};
use brk_bridge::Bridge;
use brk_bundler::bundle;
use brk_computer::Computer;
use brk_indexer::Indexer;
@@ -18,12 +19,11 @@ use brk_server::{Server, VERSION};
use log::info;
use vecdb::Exit;
mod bridge;
mod config;
mod paths;
mod website;
use crate::{bridge::Bridge, config::Config, paths::*};
use crate::{config::Config, paths::*};
pub fn main() -> color_eyre::Result<()> {
color_eyre::install()?;
@@ -51,97 +51,107 @@ pub fn run() -> color_eyre::Result<()> {
let mut indexer = Indexer::forced_import(&config.brkdir())?;
let wait_for_synced_node = |rpc_client: &bitcoincore_rpc::Client| -> color_eyre::Result<()> {
let is_synced = || -> color_eyre::Result<bool> {
let info = rpc_client.get_blockchain_info()?;
Ok(info.headers == info.blocks)
let mut computer = Computer::forced_import(&config.brkdir(), &indexer, config.fetcher())?;
let interface = Interface::build(&parser, &indexer, &computer);
let website = config.website();
let downloads_path = config.downloads_dir();
let future = async {
let bundle_path = if website.is_some() {
let websites_dev_path = Path::new("../../websites");
let packages_dev_path = Path::new("../../packages");
let websites_path;
let packages_path;
if fs::exists(websites_dev_path)? {
websites_path = websites_dev_path.to_path_buf();
packages_path = packages_dev_path.to_path_buf();
} else {
let downloaded_brk_path = downloads_path.join(format!("brk-{VERSION}"));
let downloaded_websites_path = downloaded_brk_path.join("websites");
let downloaded_packages_path = downloaded_brk_path.join("packages");
if !fs::exists(&downloaded_websites_path)? {
info!("Downloading source from Github...");
let url = format!(
"https://github.com/bitcoinresearchkit/brk/archive/refs/tags/v{VERSION}.zip",
);
let response = minreq::get(url).send()?;
let bytes = response.as_bytes();
let cursor = Cursor::new(bytes);
let mut zip = zip::ZipArchive::new(cursor).unwrap();
zip.extract(downloads_path).unwrap();
}
websites_path = downloaded_websites_path;
packages_path = downloaded_packages_path;
}
interface.generate_js_files(&packages_path)?;
Some(bundle(&websites_path, website.to_folder_name(), true).await?)
} else {
None
};
if !is_synced()? {
info!("Waiting for node to be synced...");
while !is_synced()? {
let server = Server::new(interface, bundle_path);
tokio::spawn(async move {
server.serve(true).await.unwrap();
});
sleep(Duration::from_secs(1));
loop {
wait_for_synced_node(rpc)?;
let block_count = rpc.get_block_count()?;
info!("{} blocks found.", block_count + 1);
let starting_indexes = indexer
.index(&parser, rpc, &exit, config.check_collisions())
.unwrap();
computer
.compute(&indexer, starting_indexes, &parser, &exit)
.unwrap();
info!("Waiting for new blocks...");
while block_count == rpc.get_block_count()? {
sleep(Duration::from_secs(1))
}
}
Ok(())
};
let mut computer = Computer::forced_import(&config.brkdir(), &indexer, config.fetcher())?;
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()?
.block_on(async {
let interface = Interface::build(&parser, &indexer, &computer);
let website = config.website();
let downloads_path = config.downloads_dir();
let bundle_path = if website.is_some() {
let websites_dev_path = Path::new("../../websites");
let websites_path = if fs::exists(websites_dev_path)? {
websites_dev_path.to_path_buf()
} else {
let downloaded_websites_path =
downloads_path.join(format!("brk-{VERSION}")).join("websites");
if !fs::exists(&downloaded_websites_path)? {
info!("Downloading websites from Github...");
let url = format!(
"https://github.com/bitcoinresearchkit/brk/archive/refs/tags/v{VERSION}.zip",
);
let response = minreq::get(url).send()?;
let bytes = response.as_bytes();
let cursor = Cursor::new(bytes);
let mut zip = zip::ZipArchive::new(cursor).unwrap();
zip.extract(downloads_path).unwrap();
}
downloaded_websites_path
};
interface.generate_bridge_files(website, websites_path.as_path())?;
Some(bundle(&websites_path, website.to_folder_name(), true).await?)
} else {
None
};
let server = Server::new(
interface,
bundle_path,
);
tokio::spawn(async move {
server.serve(true).await.unwrap();
});
sleep(Duration::from_secs(1));
loop {
wait_for_synced_node(rpc)?;
let block_count = rpc.get_block_count()?;
info!("{} blocks found.", block_count + 1);
let starting_indexes =
indexer.index(&parser, rpc, &exit, config.check_collisions()).unwrap();
computer.compute(&indexer, starting_indexes, &parser, &exit).unwrap();
info!("Waiting for new blocks...");
while block_count == rpc.get_block_count()? {
sleep(Duration::from_secs(1))
}
}
})
.block_on(future)
}
fn wait_for_synced_node(rpc_client: &bitcoincore_rpc::Client) -> color_eyre::Result<()> {
let is_synced = || -> color_eyre::Result<bool> {
let info = rpc_client.get_blockchain_info()?;
Ok(info.headers == info.blocks)
};
if !is_synced()? {
info!("Waiting for node to be synced...");
while !is_synced()? {
sleep(Duration::from_secs(1))
}
}
Ok(())
}
+11 -11
View File
@@ -30,7 +30,7 @@ pub use pagination::{PaginatedIndexParam, PaginationParam};
pub use params::{IdParam, Params, ParamsOpt};
use vecs::Vecs;
use crate::vecs::{IdToVec, IndexToVec};
use crate::vecs::{IndexToVec, MetricToVec};
pub fn cached_errors() -> &'static Cache<String, String> {
static CACHE: OnceLock<Cache<String, String>> = OnceLock::new();
@@ -70,7 +70,7 @@ impl<'a> Interface<'a> {
let ids_to_vec = self
.vecs
.index_to_id_to_vec
.index_to_metric_to_vec
.get(&index)
.ok_or(Error::String(format!(
"Index \"{}\" isn't a valid index",
@@ -111,7 +111,7 @@ impl<'a> Interface<'a> {
&format!("\nMaybe you meant one of the following: {matches:#?} ?\n");
}
if let Some(index_to_vec) = self.id_to_index_to_vec().get(id.as_str()) {
if let Some(index_to_vec) = self.metric_to_index_to_vec().get(id.as_str()) {
message += &format!("\nBut there is a vec named {id} which supports the following indexes: {:#?}\n", index_to_vec.keys());
}
@@ -214,16 +214,16 @@ impl<'a> Interface<'a> {
self.format(self.search(&params)?, &params.rest)
}
pub fn id_to_index_to_vec(&self) -> &BTreeMap<&str, IndexToVec<'_>> {
&self.vecs.id_to_index_to_vec
pub fn metric_to_index_to_vec(&self) -> &BTreeMap<&str, IndexToVec<'_>> {
&self.vecs.metric_to_index_to_vec
}
pub fn index_to_id_to_vec(&self) -> &BTreeMap<Index, IdToVec<'_>> {
&self.vecs.index_to_id_to_vec
pub fn index_to_metric_to_vec(&self) -> &BTreeMap<Index, MetricToVec<'_>> {
&self.vecs.index_to_metric_to_vec
}
pub fn get_vecid_count(&self) -> usize {
self.vecs.id_count
pub fn get_metric_count(&self) -> usize {
self.vecs.metric_count
}
pub fn get_index_count(&self) -> usize {
@@ -242,8 +242,8 @@ impl<'a> Interface<'a> {
&self.vecs.accepted_indexes
}
pub fn get_vecids(&self, pagination: PaginationParam) -> &[&str] {
self.vecs.ids(pagination)
pub fn get_metrics(&self, pagination: PaginationParam) -> &[&str] {
self.vecs.metrics(pagination)
}
pub fn get_index_to_vecids(&self, paginated_index: PaginatedIndexParam) -> Vec<&str> {
+30 -26
View File
@@ -11,16 +11,16 @@ use super::index::Index;
#[derive(Default)]
pub struct Vecs<'a> {
pub id_to_index_to_vec: BTreeMap<&'a str, IndexToVec<'a>>,
pub index_to_id_to_vec: BTreeMap<Index, IdToVec<'a>>,
pub ids: Vec<&'a str>,
pub metric_to_index_to_vec: BTreeMap<&'a str, IndexToVec<'a>>,
pub index_to_metric_to_vec: BTreeMap<Index, MetricToVec<'a>>,
pub metrics: Vec<&'a str>,
pub indexes: Vec<&'static str>,
pub accepted_indexes: BTreeMap<&'static str, &'static [&'static str]>,
pub index_count: usize,
pub id_count: usize,
pub metric_count: usize,
pub vec_count: usize,
id_to_indexes: BTreeMap<&'a str, Vec<&'static str>>,
indexes_to_ids: BTreeMap<Index, Vec<&'a str>>,
metric_to_indexes: BTreeMap<&'a str, Vec<&'static str>>,
index_to_metrics: BTreeMap<Index, Vec<&'a str>>,
}
impl<'a> Vecs<'a> {
@@ -33,7 +33,11 @@ impl<'a> Vecs<'a> {
.iter_any_collectable()
.for_each(|vec| this.insert(vec));
let mut ids = this.id_to_index_to_vec.keys().cloned().collect::<Vec<_>>();
let mut ids = this
.metric_to_index_to_vec
.keys()
.cloned()
.collect::<Vec<_>>();
let sort_ids = |ids: &mut Vec<&str>| {
ids.sort_unstable_by(|a, b| {
@@ -48,26 +52,26 @@ impl<'a> Vecs<'a> {
sort_ids(&mut ids);
this.ids = ids;
this.id_count = this.id_to_index_to_vec.keys().count();
this.index_count = this.index_to_id_to_vec.keys().count();
this.metrics = ids;
this.metric_count = this.metric_to_index_to_vec.keys().count();
this.index_count = this.index_to_metric_to_vec.keys().count();
this.vec_count = this
.index_to_id_to_vec
.index_to_metric_to_vec
.values()
.map(|tree| tree.len())
.sum::<usize>();
this.indexes = this
.index_to_id_to_vec
.index_to_metric_to_vec
.keys()
.map(|i| i.serialize_long())
.collect::<Vec<_>>();
this.accepted_indexes = this
.index_to_id_to_vec
.index_to_metric_to_vec
.keys()
.map(|i| (i.serialize_long(), i.possible_values()))
.collect::<BTreeMap<_, _>>();
this.id_to_indexes = this
.id_to_index_to_vec
this.metric_to_indexes = this
.metric_to_index_to_vec
.iter()
.map(|(id, index_to_vec)| {
(
@@ -79,12 +83,12 @@ impl<'a> Vecs<'a> {
)
})
.collect();
this.indexes_to_ids = this
.index_to_id_to_vec
this.index_to_metrics = this
.index_to_metric_to_vec
.iter()
.map(|(index, id_to_vec)| (*index, id_to_vec.keys().cloned().collect::<Vec<_>>()))
.collect();
this.indexes_to_ids
this.index_to_metrics
.values_mut()
.for_each(|ids| sort_ids(ids));
@@ -101,7 +105,7 @@ impl<'a> Vecs<'a> {
})
.unwrap();
let prev = self
.id_to_index_to_vec
.metric_to_index_to_vec
.entry(name)
.or_default()
.insert(index, vec);
@@ -110,7 +114,7 @@ impl<'a> Vecs<'a> {
panic!()
}
let prev = self
.index_to_id_to_vec
.index_to_metric_to_vec
.entry(index)
.or_default()
.insert(name, vec);
@@ -120,22 +124,22 @@ impl<'a> Vecs<'a> {
}
}
pub fn ids(&self, pagination: PaginationParam) -> &[&'_ str] {
let len = self.ids.len();
pub fn metrics(&self, pagination: PaginationParam) -> &[&'_ str] {
let len = self.metrics.len();
let start = pagination.start(len);
let end = pagination.end(len);
&self.ids[start..end]
&self.metrics[start..end]
}
pub fn id_to_indexes(&self, id: String) -> Option<&Vec<&'static str>> {
self.id_to_indexes.get(id.as_str())
self.metric_to_indexes.get(id.as_str())
}
pub fn index_to_ids(
&self,
PaginatedIndexParam { index, pagination }: PaginatedIndexParam,
) -> Vec<&'a str> {
let vec = self.indexes_to_ids.get(&index).unwrap();
let vec = self.index_to_metrics.get(&index).unwrap();
let len = vec.len();
let start = pagination.start(len);
@@ -149,4 +153,4 @@ impl<'a> Vecs<'a> {
pub struct IndexToVec<'a>(BTreeMap<Index, &'a dyn AnyCollectableVec>);
#[derive(Default, Deref, DerefMut)]
pub struct IdToVec<'a>(BTreeMap<&'a str, &'a dyn AnyCollectableVec>);
pub struct MetricToVec<'a>(BTreeMap<&'a str, &'a dyn AnyCollectableVec>);
+6 -6
View File
@@ -40,12 +40,12 @@ Get the count of all existing indexes.
}
#[tool(description = "
Get the count of all existing vec ids.
Get the count of all existing metrics.
")]
async fn get_vecid_count(&self) -> Result<CallToolResult, McpError> {
info!("mcp: get_vecid_count");
async fn get_metric_count(&self) -> Result<CallToolResult, McpError> {
info!("mcp: get_metric_count");
Ok(CallToolResult::success(vec![
Content::json(self.interface.get_vecid_count()).unwrap(),
Content::json(self.interface.get_metric_count()).unwrap(),
]))
}
@@ -89,9 +89,9 @@ If the `page` param is omitted, it will default to the first page.
&self,
Parameters(pagination): Parameters<PaginationParam>,
) -> Result<CallToolResult, McpError> {
info!("mcp: get_vecids");
info!("mcp: get_metrics");
Ok(CallToolResult::success(vec![
Content::json(self.interface.get_vecids(pagination)).unwrap(),
Content::json(self.interface.get_metrics(pagination)).unwrap(),
]))
}
+5 -5
View File
@@ -229,9 +229,9 @@ impl ApiRoutes for Router<AppState> {
}),
)
.route(
"/api/vecs/id-count",
"/api/vecs/metric-count",
get(async |State(app_state): State<AppState>| -> Response {
Json(app_state.interface.get_vecid_count()).into_response()
Json(app_state.interface.get_metric_count()).into_response()
}),
)
.route(
@@ -253,17 +253,17 @@ impl ApiRoutes for Router<AppState> {
}),
)
.route(
"/api/vecs/ids",
"/api/vecs/metrics",
get(
async |State(app_state): State<AppState>,
Query(pagination): Query<PaginationParam>|
-> Response {
Json(app_state.interface.get_vecids(pagination)).into_response()
Json(app_state.interface.get_metrics(pagination)).into_response()
},
),
)
.route(
"/api/vecs/index-to-ids",
"/api/vecs/index-to-metrics",
get(
async |State(app_state): State<AppState>,
Query(paginated_index): Query<PaginatedIndexParam>|
+3
View File
@@ -93,6 +93,8 @@
- _STORE_
- save height and version in one file
- _STRUCTS_
- _GLOBAL_
- https://davidlattimore.github.io/posts/2025/09/02/rustforge-wild-performance-tricks.html
- __DOCS__
- _README_
- add a comparison table with alternatives
@@ -145,6 +147,7 @@
- https://fonts.google.com/specimen/Space+Mono
- keep as many files as possible [under 14kb](https://endtimes.dev/why-your-website-should-be-under-14kb-in-size/)
- [No classes](https://news.ycombinator.com/item?id=45287155)
- [Organic animations](https://courses.joshwcomeau.com/playground/magic-wand-final)
- __GLOBAL__
- check `TODO`s in codebase
- rename `output` to `txout` or `vout`, `input` to `txin` or `vin`
+1
View File
@@ -0,0 +1 @@
generated
View File
View File
+7
View File
@@ -0,0 +1,7 @@
/**
* @import { Signal, Signals, Accessor } from "../solidjs-signals/index";
*
* @import { Index } from "./metrics"
*
* @typedef {[number, number, number, number]} OHLCTuple
*/
@@ -6,5 +6,5 @@
"module": "ESNext",
"skipLibCheck": true
},
"exclude": ["scripts/packages", "scripts/bridge", "spmething"]
"exclude": ["dist"]
}
+656
View File
@@ -0,0 +1,656 @@
declare module 'lean-qr' {
interface ImageDataLike {
readonly data: Uint8ClampedArray;
}
interface Context2DLike<DataT extends ImageDataLike> {
createImageData(width: number, height: number): DataT;
putImageData(data: DataT, x: number, y: number): void;
}
interface CanvasLike<DataT extends ImageDataLike> {
width: number;
height: number;
getContext(type: '2d'): Context2DLike<DataT> | null;
}
/**
* A colour in `[red, green, blue, alpha]` format (all values from 0 to 255).
* If alpha is omitted, it is assumed to be 255 (opaque).
*/
export type RGBA = readonly [number, number, number, number?];
export interface Bitmap1D {
/**
* Appends a sequence of bits.
*
* @param value an integer containing the bits to append (big endian).
* @param bits the number of bits to read from `value`. Must be between 1 and 24.
*/
push(value: number, bits: number): void;
}
export interface StringOptions {
/** the text to use for modules which are 'on' (typically black) */
on?: string;
/** the text to use for modules which are 'off' (typically white) */
off?: string;
/** the text to use for linefeeds between rows */
lf?: string;
/** the padding to apply around the output (populated with 'off' modules) */
pad?: number;
/**
* the padding to apply on the left and right of the output (populated with 'off' modules)
* @deprecated use `pad` instead
*/
padX?: number;
/**
* the padding to apply on the top and bottom of the output (populated with 'off' modules)
* @deprecated use `pad` instead
*/
padY?: number;
}
export interface ImageDataOptions {
/** the colour to use for modules which are 'on' (typically black) */
on?: RGBA;
/** the colour to use for modules which are 'off' (typically white) */
off?: RGBA;
/** the padding to apply around the output (filled with 'off') */
pad?: number;
/**
* the padding to apply on the left and right of the output (filled with 'off')
* @deprecated use `pad` instead
*/
padX?: number;
/**
* the padding to apply on the top and bottom of the output (filled with 'off')
* @deprecated use `pad` instead
*/
padY?: number;
}
export interface Bitmap2D {
/** the width / height of the QR code in modules (excluding any padding) */
readonly size: number;
/**
* Read the state of a module from the QR code.
*
* @param x the x coordinate to read. Can be negative / out of bounds.
* @param y the y coordinate to read. Can be negative / out of bounds.
* @returns true if the requested module is set (i.e. typically black)
*/
get(x: number, y: number): boolean;
/**
* Generate a string containing the QR code, suitable for displaying in a
* terminal environment. Generally, you should customise on and off to use
* the ANSI escapes of your target terminal for better rendering.
*
* @param options optional configuration for the display.
*/
toString(options?: Readonly<StringOptions>): string;
/**
* Generate image data containing the QR code, at a scale of 1 pixel per
* module. Use this if you need more control than toCanvas allows.
*
* @param context a context to use for creating the image data.
* @param options optional configuration for the display.
*/
toImageData<DataT extends ImageDataLike>(
context: Context2DLike<DataT>,
options?: Readonly<ImageDataOptions>,
): DataT;
/**
* Generate a `data:image/*` URL for the QR code.
*
* @param options optional configuration for the output.
* @returns a string suitable for use as the `src` of an `img` tag.
*/
toDataURL(
options?: Readonly<
ImageDataOptions & {
type?: `image/${string}`;
scale?: number;
}
>,
): string;
/**
* Populate a given canvas with the QR code, at a scale of 1 pixel per
* module. Set image-rendering: pixelated and scale the canvas using CSS
* for a large image. Automatically resizes the canvas to fit the QR code
* if necessary.
*
* @param canvas the canvas to populate.
* @param options optional configuration for the display.
*/
toCanvas(
canvas: CanvasLike<ImageDataLike>,
options?: Readonly<ImageDataOptions>,
): void;
}
export type Mask = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
export type Mode = (data: Bitmap1D, version: number) => void;
export interface ModeFactory {
(value: string): Mode;
/** a function which returns true when given a character which the current mode can represent */
test(string: string): boolean;
/** a function which returns an estimate of the number of bits required to encode a given value */
est(value: string, version: number): number;
/** an optional ECI which must be active for this mode to be interpreted correctly by a reader */
eci?: number;
}
interface ModeAutoOptions {
/** a list of modes which can be considered when encoding a message */
modes?: ReadonlyArray<ModeFactory>;
}
export const mode: Readonly<{
/** automatically picks the most optimal combination of modes for the requested message */
auto(value: string, options?: Readonly<ModeAutoOptions>): Mode;
/** concatenates multiple modes together */
multi(...modes: ReadonlyArray<Mode>): Mode;
/** sets the Extended Channel Interpretation for the message from this point onwards */
eci(id: number): Mode;
/** supports `0-9` and stores 3 characters per 10 bits */
numeric: ModeFactory;
/** supports `0-9A-Z $%*+-./:` and stores 2 characters per 11 bits */
alphaNumeric: ModeFactory;
/** arbitrary byte data, typically combined with `eci` */
bytes(data: Uint8Array | ReadonlyArray<number>): Mode;
/** supports 7-bit ASCII and stores 1 character per 8 bits with no ECI */
ascii: ModeFactory;
/** supports 8-bit ISO-8859-1 and stores 1 character per 8 bits with ECI 3 */
iso8859_1: ModeFactory;
/** supports double-byte Shift-JIS characters stores 1 character per 13 bits */
shift_jis: ModeFactory;
/** supports variable length UTF-8 with ECI 26 */
utf8: ModeFactory;
}>;
export type Correction = number & { readonly _: unique symbol };
export const correction: Readonly<{
/**
* minimum possible correction level (same as L)
* @deprecated use correction.L
*/
min: Correction;
/** ~7.5% error tolerance, ~25% data overhead */
L: Correction;
/** ~15% error tolerance, ~60% data overhead */
M: Correction;
/** ~22.5% error tolerance, ~120% data overhead */
Q: Correction;
/** ~30% error tolerance, ~190% data overhead */
H: Correction;
/**
* maximum possible correction level (same as H)
* @deprecated use correction.H
*/
max: Correction;
}>;
export interface GenerateOptions extends ModeAutoOptions {
/** the minimum correction level to use (higher levels may still be used if the chosen version has space) */
minCorrectionLevel?: Correction;
/** the maximum correction level to use */
maxCorrectionLevel?: Correction;
/** the minimum version (size) of code to generate (must be between 1 and 40) */
minVersion?: number;
/** the maximum version (size) of code to generate (must be between 1 and 40) */
maxVersion?: number;
/** a mask to use on the QR code (should be left as `null` for ISO compliance but may be changed for artistic effect) */
mask?: null | Mask;
/** padding bits to use for extra space in the QR code (should be left as the default for ISO compliance but may be changed for artistic effect) */
trailer?: number;
}
/**
* Generate a QR code.
*
* @param data either a string, or a pre-encoded mode.
* @param options optional configuration for the QR code.
* @returns the requested QR code.
*/
export type GenerateFn = (
data: Mode | string,
options?: Readonly<GenerateOptions>,
) => Bitmap2D;
interface Generate extends GenerateFn {
/**
* Creates a scoped `generate` function which considers additional modes
* when using auto encoding.
*
* @param modes the modes to add.
* @returns a `generate` function which will additionally consider the
* given modes when using auto encoding.
*
* @deprecated this will be removed in version 3. Prefer passing an explicit list of modes when calling `generate`.
*/
with(...modes: ReadonlyArray<ModeFactory>): GenerateFn;
}
export const generate: Generate;
}
declare module 'lean-qr/nano' {
import type {
Correction,
Bitmap2D as FullBitmap2D,
GenerateOptions as FullGenerateOptions,
} from 'lean-qr';
import { correction as fullCorrection } from 'lean-qr';
export type { Correction };
export const correction: Pick<typeof fullCorrection, 'L' | 'M' | 'Q' | 'H'>;
export type Bitmap2D = Pick<FullBitmap2D, 'size' | 'get' | 'toCanvas'>;
export type GenerateOptions = Pick<
FullGenerateOptions,
'minCorrectionLevel' | 'minVersion'
>;
/**
* Generate a QR code.
*
* @param data either a string, or a pre-encoded mode.
* @param options optional configuration for the QR code.
* @returns the requested QR code.
*/
export function generate(
data: string,
options?: Readonly<GenerateOptions>,
): Bitmap2D;
}
declare module 'lean-qr/extras/svg' {
import type { Bitmap2D as FullBitmap2D } from 'lean-qr';
type Bitmap2D = Pick<FullBitmap2D, 'size' | 'get'>;
export interface SVGOptions {
/** the colour to use for modules which are 'on' (typically black) */
on?: string;
/** the colour to use for modules which are 'off' (typically white) */
off?: string;
/** the padding to apply around the output (filled with 'off') */
pad?: number;
/**
* the padding to apply on the left and right of the output (filled with 'off')
* @deprecated use `pad` instead
*/
padX?: number;
/**
* the padding to apply on the top and bottom of the output (filled with 'off')
* @deprecated use `pad` instead
*/
padY?: number;
/** a width to apply to the resulting image (overrides `scale`) */
width?: number | null;
/** a height to apply to the resulting image (overrides `scale`) */
height?: number | null;
/** a scale to apply to the resulting image (`scale` pixels = 1 module) */
scale?: number;
}
/**
* Generate the raw outline of the QR code for use in an existing SVG.
*
* @param code the QR code to convert.
* @returns a string suitable for passing to the `d` attribute of a `path`.
*/
export function toSvgPath(code: Bitmap2D): string;
/**
* Generate an SVG element which can be added to the DOM.
*
* @param code the QR code to convert.
* @param options optional configuration for the display.
* @returns an SVG element.
*/
export function toSvg(
code: Bitmap2D,
target: Document | SVGElement,
options?: Readonly<SVGOptions>,
): SVGElement;
/**
* Generate an SVG document which can be exported to a file or served from a
* web server.
*
* @param code the QR code to convert.
* @param options optional configuration for the display.
* @returns an SVG document.
*/
export function toSvgSource(
code: Bitmap2D,
options?: Readonly<
SVGOptions & {
/** `true` to include an XML declaration at the start of the source (for standalone documents which will not be embedded inside another document) */
xmlDeclaration?: boolean;
}
>,
): string;
/**
* Generate a `data:image/svg+xml` URL.
*
* @param code the QR code to convert.
* @param options optional configuration for the display.
* @returns a string suitable for use as the `src` of an `img` tag.
*/
export function toSvgDataURL(
code: Bitmap2D,
options?: Readonly<SVGOptions>,
): string;
}
declare module 'lean-qr/extras/node_export' {
import type { RGBA, Bitmap2D as FullBitmap2D } from 'lean-qr';
type Bitmap2D = Pick<FullBitmap2D, 'size' | 'get'>;
export interface PNGOptions {
/** the colour to use for modules which are 'on' (typically black) */
on?: RGBA;
/** the colour to use for modules which are 'off' (typically white) */
off?: RGBA;
/** the padding to apply around the output (filled with 'off') */
pad?: number;
/**
* the padding to apply on the left and right of the output (filled with 'off')
* @deprecated use `pad` instead
*/
padX?: number;
/**
* the padding to apply on the top and bottom of the output (filled with 'off')
* @deprecated use `pad` instead
*/
padY?: number;
/** a scale to apply to the resulting image (`scale` pixels = 1 module) */
scale?: number;
}
/**
* Generate a PNG document which can be exported to a file or served from a
* web server.
*
* @param code the QR code to convert.
* @param options optional configuration for the display.
* @returns a PNG document.
*/
export function toPngBuffer(
code: Bitmap2D,
options?: Readonly<PNGOptions>,
): Uint8Array;
/**
* Generate a `data:image/png` URL.
*
* @param code the QR code to convert.
* @param options optional configuration for the display.
* @returns a string suitable for use as the `src` of an `img` tag.
*/
export function toPngDataURL(
code: Bitmap2D,
options?: Readonly<PNGOptions>,
): string;
}
declare module 'lean-qr/extras/react' {
import type {
Bitmap2D as FullBitmap2D,
GenerateOptions,
ImageDataOptions,
} from 'lean-qr';
import type {
SVGOptions,
toSvgDataURL as toSvgDataURLFn,
} from 'lean-qr/extras/svg';
export interface AsyncFramework<T> {
createElement: (
type: 'canvas',
props: {
ref: any;
style: { imageRendering: 'pixelated' };
className: string;
},
) => T;
useRef<T>(initialValue: T | null): { readonly current: T | null };
useEffect(fn: () => void | (() => void), deps: unknown[]): void;
}
interface QRComponentProps {
content: string;
className?: string;
}
export interface AsyncQRComponentProps
extends ImageDataOptions,
GenerateOptions,
QRComponentProps {}
export type AsyncQRComponent<T> = (
props: Readonly<AsyncQRComponentProps>,
) => T;
/**
* Generate an asynchronous QR component (rendering to a `canvas`).
* You should call this just once, in the global scope.
*
* ```js
* import * as React from 'react';
* import { generate } from 'lean-qr';
* import { makeAsyncComponent } from 'lean-qr/extras/react';
* const QR = makeAsyncComponent(React, generate);
* ```
*
* This is not suitable for server-side rendering (use `makeSyncComponent`
* instead).
*
* @param framework the framework to use (e.g. `React`).
* @param generate the `generate` function to use
* (from `lean-qr` or `lean-qr/nano`).
* @param defaultProps optional default properties to apply when the
* component is used (overridden by properties set on use).
* @returns a component which can be rendered elsewhere.
*/
export function makeAsyncComponent<T>(
framework: Readonly<AsyncFramework<T>>,
generate: (
data: string,
options?: Readonly<GenerateOptions>,
) => Pick<FullBitmap2D, 'toCanvas'>,
defaultProps?: Readonly<Partial<AsyncQRComponentProps>>,
): AsyncQRComponent<T>;
export interface SyncFramework<T> {
createElement: (
type: 'img',
props: {
src: string;
style: { imageRendering: 'pixelated' };
className: string;
},
) => T;
useMemo<T>(fn: () => T, deps: unknown[]): T;
}
export interface SyncQRComponentProps
extends SVGOptions,
GenerateOptions,
QRComponentProps {}
export type SyncQRComponent<T> = (props: Readonly<SyncQRComponentProps>) => T;
/**
* Generate a synchronous QR component (rendering to an SVG).
* You should call this just once, in the global scope.
*
* ```js
* import * as React from 'react';
* import { generate } from 'lean-qr';
* import { toSvgDataURL } from 'lean-qr/extras/svg';
* import { makeSyncComponent } from 'lean-qr/extras/react';
* const QR = makeSyncComponent(React, generate, toSvgDataURL);
* ```
*
* This is best suited for server-side rendering (prefer
* `makeAsyncComponent` if you only need client-side rendering).
*
* @param framework the framework to use (e.g. `React`).
* @param generate the `generate` function to use
* (from `lean-qr` or `lean-qr/nano`).
* @param toSvgDataURL the `toSvgDataURL` function to use
* (from `lean-qr/extras/svg`).
* @param defaultProps optional default properties to apply when the
* component is used (overridden by properties set on use).
* @returns a component which can be rendered elsewhere.
*/
export function makeSyncComponent<T>(
framework: Readonly<SyncFramework<T>>,
generate: (
data: string,
options?: Readonly<GenerateOptions>,
) => Pick<FullBitmap2D, 'size' | 'get'>,
toSvgDataURL: typeof toSvgDataURLFn,
defaultProps?: Readonly<Partial<SyncQRComponentProps>>,
): SyncQRComponent<T>;
}
declare module 'lean-qr/extras/vue' {
import type {
Bitmap2D as FullBitmap2D,
GenerateOptions,
ImageDataOptions,
} from 'lean-qr';
import type {
SVGOptions,
toSvgDataURL as toSvgDataURLFn,
} from 'lean-qr/extras/svg';
export interface Framework<T> {
h:
| ((type: 'canvas', props: { ref: string; style: string }) => T)
| ((type: 'img', props: { src: string; style: string }) => T);
}
interface QRComponentProps {
content: string;
}
export interface VueCanvasComponentProps
extends ImageDataOptions,
GenerateOptions,
QRComponentProps {}
type VueComponentDefinition<Props, Node> = {
props: {
[k in keyof Props]: {
type: {
(): Props[k];
required: undefined extends Props[k] ? false : true;
};
};
};
render: () => Node;
} & ThisType<unknown>;
/**
* Generate a QR component which renders to a `canvas`.
* You should call this just once, in the global scope.
*
* ```js
* import { h, defineComponent } from 'vue';
* import { generate } from 'lean-qr';
* import { makeVueCanvasComponent } from 'lean-qr/extras/vue';
* export const QR = defineComponent(makeVueCanvasComponent({ h }, generate));
* ```
*
* This is not suitable for server-side rendering (use `makeSyncComponent`
* instead).
*
* @param framework the framework to use (e.g. `{ h }`).
* @param generate the `generate` function to use
* (from `lean-qr` or `lean-qr/nano`).
* @param defaultProps optional default properties to apply when the
* component is used (overridden by properties set on use).
* @returns a component which can be rendered elsewhere.
*/
export function makeVueCanvasComponent<T>(
framework: Readonly<Framework<T>>,
generate: (
data: string,
options?: Readonly<GenerateOptions>,
) => Pick<FullBitmap2D, 'toCanvas'>,
defaultProps?: Readonly<Partial<VueCanvasComponentProps>>,
): VueComponentDefinition<Partial<VueCanvasComponentProps>, T>;
export interface VueSVGComponentProps
extends SVGOptions,
GenerateOptions,
QRComponentProps {}
/**
* Generate a QR component which renders to an SVG.
* You should call this just once, in the global scope:
*
* ```js
* import { h, defineComponent } from 'vue';
* import { generate } from 'lean-qr';
* import { toSvgDataURL } from 'lean-qr/extras/svg';
* import { makeVueSvgComponent } from 'lean-qr/extras/vue';
* export const QR = defineComponent(makeVueSvgComponent({ h }, generate, toSvgDataURL));
* ```
*
* This is best suited for server-side rendering (prefer
* `makeAsyncComponent` if you only need client-side rendering).
*
* @param framework the framework to use (e.g. `{ h }`).
* @param generate the `generate` function to use
* (from `lean-qr` or `lean-qr/nano`).
* @param toSvgDataURL the `toSvgDataURL` function to use
* (from `lean-qr/extras/svg`).
* @param defaultProps optional default properties to apply when the
* component is used (overridden by properties set on use).
* @returns a component which can be rendered elsewhere.
*/
export function makeVueSvgComponent<T>(
framework: Readonly<Framework<T>>,
generate: (
data: string,
options?: Readonly<GenerateOptions>,
) => Pick<FullBitmap2D, 'size' | 'get'>,
toSvgDataURL: typeof toSvgDataURLFn,
defaultProps?: Readonly<Partial<VueSVGComponentProps>>,
): VueComponentDefinition<Partial<VueSVGComponentProps>, T>;
}
declare module 'lean-qr/extras/errors' {
/**
* Convert an error into a human-readable message. This is intended for use
* with Lean QR errors, but will return somewhat meaningful messages for
* other errors too.
*
* @param error the error to convert.
* @returns a human-readable message explaining the error.
*/
export function readError(error: unknown): string;
}
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,22 @@
import { Computation, Queue } from "./core/index.js";
import type { Effect } from "./core/index.js";
export declare class CollectionQueue extends Queue {
_collectionType: number;
_nodes: Set<Effect>;
_disabled: Computation<boolean>;
constructor(type: number);
run(type: number): void;
notify(node: Effect, type: number, flags: number): any;
merge(queue: CollectionQueue): void;
}
export declare enum BoundaryMode {
VISIBLE = "visible",
HIDDEN = "hidden"
}
export declare function createBoundary<T>(fn: () => T, condition: () => BoundaryMode): () => T | undefined;
export declare function createSuspense(fn: () => any, fallback: () => any): () => any;
export declare function createErrorBoundary<U>(fn: () => any, fallback: (error: unknown, reset: () => void) => U): () => any;
export declare function flatten(children: any, options?: {
skipNonRendered?: boolean;
doNotUnwrap?: boolean;
}): any;
@@ -0,0 +1,14 @@
/**
* See https://dev.to/modderme123/super-charging-fine-grained-reactive-performance-47ph
* State clean corresponds to a node where all the sources are fully up to date
* State check corresponds to a node where some sources (including grandparents) may have changed
* State dirty corresponds to a node where the direct parents of a node has changed
*/
export declare const STATE_CLEAN = 0;
export declare const STATE_CHECK = 1;
export declare const STATE_DIRTY = 2;
export declare const STATE_DISPOSED = 3;
export declare const EFFECT_PURE = 0;
export declare const EFFECT_RENDER = 1;
export declare const EFFECT_USER = 2;
export declare const SUPPORTS_PROXY: boolean;
+162
View File
@@ -0,0 +1,162 @@
/**
* Nodes for constructing a graph of reactive values and reactive computations.
*
* - The graph is acyclic.
* - The user inputs new values into the graph by calling .write() on one more computation nodes.
* - The user retrieves computed results from the graph by calling .read() on one or more computation nodes.
* - The library is responsible for running any necessary computations so that .read() is up to date
* with all prior .write() calls anywhere in the graph.
* - We call the input nodes 'roots' and the output nodes 'leaves' of the graph here.
* - Changes flow from roots to leaves. It would be effective but inefficient to immediately
* propagate all changes from a root through the graph to descendant leaves. Instead, we defer
* change most change propagation computation until a leaf is accessed. This allows us to
* coalesce computations and skip altogether recalculating unused sections of the graph.
* - Each computation node tracks its sources and its observers (observers are other
* elements that have this node as a source). Source and observer links are updated automatically
* as observer computations re-evaluate and call get() on their sources.
* - Each node stores a cache state (clean/check/dirty) to support the change propagation algorithm:
*
* In general, execution proceeds in three passes:
*
* 1. write() propagates changes down the graph to the leaves
* direct children are marked as dirty and their deeper descendants marked as check
* (no computations are evaluated)
* 2. read() requests that parent nodes updateIfNecessary(), which proceeds recursively up the tree
* to decide whether the node is clean (parents unchanged) or dirty (parents changed)
* 3. updateIfNecessary() evaluates the computation if the node is dirty (the computations are
* executed in root to leaf order)
*/
import { type Flags } from "./flags.js";
import { Owner } from "./owner.js";
import { type Transition } from "./scheduler.js";
export interface SignalOptions<T> {
id?: string;
name?: string;
equals?: ((prev: T, next: T) => boolean) | false;
pureWrite?: boolean;
unobserved?: () => void;
}
export interface SourceType {
_observers: ObserverType[] | null;
_unobserved?: () => void;
_updateIfNecessary: () => void;
_stateFlags: Flags;
_time: number;
_transition?: Transition;
_cloned?: Computation;
}
export interface ObserverType {
_sources: SourceType[] | null;
_notify: (state: number, skipQueue?: boolean) => void;
_handlerMask: Flags;
_notifyFlags: (mask: Flags, newFlags: Flags) => void;
_time: number;
_cloned?: Computation;
}
/**
* Returns the current observer.
*/
export declare function getObserver(): Computation | null;
export declare const UNCHANGED: unique symbol;
export type UNCHANGED = typeof UNCHANGED;
export declare class Computation<T = any> extends Owner implements SourceType, ObserverType {
_sources: SourceType[] | null;
_observers: ObserverType[] | null;
_value: T | undefined;
_error: unknown;
_compute: null | ((p?: T) => T);
_name: string | undefined;
_equals: false | ((a: T, b: T) => boolean);
_unobserved: (() => void) | undefined;
_pureWrite: boolean;
/** Whether the computation is an error or has ancestors that are unresolved */
_stateFlags: number;
/** Which flags raised by sources are handled, vs. being passed through. */
_handlerMask: number;
_time: number;
_forceNotify: boolean;
_transition?: Transition | undefined;
_cloned?: Computation;
constructor(initialValue: T | undefined, compute: null | ((p?: T) => T), options?: SignalOptions<T>);
_read(): T;
/**
* Return the current value of this computation
* Automatically re-executes the surrounding computation when the value changes
*/
read(): T;
/**
* Return the current value of this computation
* Automatically re-executes the surrounding computation when the value changes
*
* If the computation has any unresolved ancestors, this function waits for the value to resolve
* before continuing
*/
wait(): T;
/** Update the computation with a new value. */
write(value: T | ((currentValue: T) => T) | UNCHANGED, flags?: number, raw?: boolean): T;
/**
* Set the current node's state, and recursively mark all of this node's observers as STATE_CHECK
*/
_notify(state: number, skipQueue?: boolean): void;
/**
* Notify the computation that one of its sources has changed flags.
*
* @param mask A bitmask for which flag(s) were changed.
* @param newFlags The source's new flags, masked to just the changed ones.
*/
_notifyFlags(mask: Flags, newFlags: Flags): void;
_setError(error: unknown): void;
/**
* This is the core part of the reactivity system, which makes sure that the values are updated
* before they are read. We've also adapted it to return the loading state of the computation,
* so that we can propagate that to the computation's observers.
*
* This function will ensure that the value and states we read from the computation are up to date
*/
_updateIfNecessary(): void;
/**
* Remove ourselves from the owner graph and the computation graph
*/
_disposeNode(): void;
}
/**
* Reruns a computation's _compute function, producing a new value and keeping track of dependencies.
*
* It handles the updating of sources and observers, disposal of previous executions,
* and error handling if the _compute function throws. It also sets the node as loading
* if it reads any parents that are currently loading.
*/
export declare function update<T>(node: Computation<T>): void;
export declare function isEqual<T>(a: T, b: T): boolean;
/**
* Returns the current value stored inside the given compute function without triggering any
* dependencies. Use `untrack` if you want to also disable owner tracking.
*/
export declare function untrack<T>(fn: () => T): T;
/**
* Returns true if the given functinon contains signals that have been updated since the last time
* the parent computation was run.
*/
export declare function hasUpdated(fn: () => any): boolean;
/**
* Returns an accessor that is true if the given function contains async signals that are out of date.
*/
export declare function isPending(fn: () => any): boolean;
export declare function isPending(fn: () => any, loadingValue: boolean): boolean;
/**
* Attempts to resolve value of expression synchronously returning the last resolved value for any async computation.
*/
export declare function latest<T>(fn: () => T): T;
export declare function latest<T, U>(fn: () => T, fallback: U): T | U;
/**
* Runs the given function in the given observer.
*
* Warning: Usually there are simpler ways of modeling a problem that avoid using this function
*/
export declare function runWithObserver<T>(observer: Computation, run: () => T): T | undefined;
/**
* A convenient wrapper that calls `compute` with the `owner` and `observer` and is guaranteed
* to reset the global context after the computation is finished even if an error is thrown.
*/
export declare function compute<T>(owner: Owner | null, fn: (val: T) => T, observer: Computation<T>): T;
export declare function compute<T>(owner: Owner | null, fn: (val: undefined) => T, observer: null): T;
@@ -0,0 +1,39 @@
import { EFFECT_RENDER, EFFECT_USER } from "./constants.js";
import { Computation, type SignalOptions } from "./core.js";
import { type Flags } from "./flags.js";
/**
* Effects are the leaf nodes of our reactive graph. When their sources change, they are
* automatically added to the queue of effects to re-execute, which will cause them to fetch their
* sources and recompute
*/
export declare class Effect<T = any> extends Computation<T> {
_effect: (val: T, prev: T | undefined) => void | (() => void);
_onerror: ((err: unknown, cleanup: () => void) => void) | undefined;
_cleanup: (() => void) | undefined;
_modified: boolean;
_prevValue: T | undefined;
_type: typeof EFFECT_RENDER | typeof EFFECT_USER;
constructor(initialValue: T, compute: (val?: T) => T, effect: (val: T, prev: T | undefined) => void | (() => void), error?: (err: unknown) => void | (() => void), options?: SignalOptions<T> & {
render?: boolean;
defer?: boolean;
});
write(value: T, flags?: number): T;
_notify(state: number, skipQueue?: boolean): void;
_notifyFlags(mask: Flags, newFlags: Flags): void;
_setError(error: unknown): void;
_disposeNode(): void;
_run(type: number): void;
}
export declare class EagerComputation<T = any> extends Computation<T> {
constructor(initialValue: T, compute: () => T, options?: SignalOptions<T> & {
defer?: boolean;
});
_notify(state: number, skipQueue?: boolean): void;
_run(): void;
}
export declare class FirewallComputation extends Computation {
firewall: boolean;
constructor(compute: () => void);
_notify(state: number, skipQueue?: boolean): void;
_run(): void;
}
@@ -0,0 +1,8 @@
export declare class NotReadyError extends Error {
}
export declare class NoOwnerError extends Error {
constructor();
}
export declare class ContextNotFoundError extends Error {
constructor();
}
@@ -0,0 +1,11 @@
export type Flags = number;
export declare const ERROR_OFFSET = 0;
export declare const ERROR_BIT: number;
export declare const ERROR: unique symbol;
export declare const LOADING_OFFSET = 1;
export declare const LOADING_BIT: number;
export declare const LOADING: unique symbol;
export declare const UNINITIALIZED_OFFSET = 2;
export declare const UNINITIALIZED_BIT: number;
export declare const UNINITIALIZED: unique symbol;
export declare const DEFAULT_FLAGS: number;
@@ -0,0 +1,7 @@
export { ContextNotFoundError, NoOwnerError, NotReadyError } from "./error.js";
export { Owner, createContext, getContext, setContext, hasContext, getOwner, onCleanup, type Context, type ContextRecord, type Disposable } from "./owner.js";
export { Computation, getObserver, isEqual, untrack, hasUpdated, isPending, latest, UNCHANGED, compute, runWithObserver, type SignalOptions } from "./core.js";
export { Effect, EagerComputation } from "./effect.js";
export { flush, Queue, incrementClock, transition, ActiveTransition, type IQueue } from "./scheduler.js";
export * from "./constants.js";
export * from "./flags.js";
@@ -0,0 +1,95 @@
/**
* Owner tracking is used to enable nested tracking scopes with automatic cleanup.
* We also use owners to also keep track of which error handling context we are in.
*
* If you write the following
*
* const a = createOwner(() => {
* const b = createOwner(() => {});
*
* const c = createOwner(() => {
* const d = createOwner(() => {});
* });
*
* const e = createOwner(() => {});
* });
*
* The owner tree will look like this:
*
* a
* /|\
* b-c-e
* |
* d
*
* Following the _nextSibling pointers of each owner will first give you its children, and then its siblings (in reverse).
* a -> e -> c -> d -> b
*
* Note that the owner tree is largely orthogonal to the reactivity tree, and is much closer to the component tree.
*/
import { type IQueue } from "./scheduler.js";
export type ContextRecord = Record<string | symbol, unknown>;
export interface Disposable {
(): void;
}
/**
* Returns the currently executing parent owner.
*/
export declare function getOwner(): Owner | null;
export declare function setOwner(owner: Owner | null): Owner | null;
export declare class Owner {
_parent: Owner | null;
_nextSibling: Owner | null;
_prevSibling: Owner | null;
_state: number;
_disposal: Disposable | Disposable[] | null;
_context: ContextRecord;
_queue: IQueue;
_childCount: number;
id: string | null;
constructor(id?: string | null, skipAppend?: boolean);
append(child: Owner): void;
dispose(this: Owner, self?: boolean): void;
_disposeNode(): void;
emptyDisposal(): void;
getNextChildId(): string;
}
export interface Context<T> {
readonly id: symbol;
readonly defaultValue: T | undefined;
}
/**
* Context provides a form of dependency injection. It is used to save from needing to pass
* data as props through intermediate components. This function creates a new context object
* that can be used with `getContext` and `setContext`.
*
* A default value can be provided here which will be used when a specific value is not provided
* via a `setContext` call.
*/
export declare function createContext<T>(defaultValue?: T, description?: string): Context<T>;
/**
* Attempts to get a context value for the given key.
*
* @throws `NoOwnerError` if there's no owner at the time of call.
* @throws `ContextNotFoundError` if a context value has not been set yet.
*/
export declare function getContext<T>(context: Context<T>, owner?: Owner | null): T;
/**
* Attempts to set a context value on the parent scope with the given key.
*
* @throws `NoOwnerError` if there's no owner at the time of call.
*/
export declare function setContext<T>(context: Context<T>, value?: T, owner?: Owner | null): void;
/**
* Whether the given context is currently defined.
*/
export declare function hasContext(context: Context<any>, owner?: Owner | null): boolean;
/**
* Runs an effect once before the reactive scope is disposed
* @param fn an effect that should run only once on cleanup
*
* @returns the same {@link fn} function that was passed in
*
* @description https://docs.solidjs.com/reference/lifecycle/on-cleanup
*/
export declare function onCleanup(fn: Disposable): Disposable;
@@ -0,0 +1,86 @@
import type { Computation, ObserverType, SourceType } from "./core.js";
import type { Effect } from "./effect.js";
export declare let clock: number;
export declare function incrementClock(): void;
export declare let ActiveTransition: Transition | null;
export declare let Unobserved: SourceType[];
export type QueueCallback = (type: number) => void;
export interface IQueue {
enqueue(type: number, fn: QueueCallback): void;
run(type: number): boolean | void;
flush(): void;
addChild(child: IQueue): void;
removeChild(child: IQueue): void;
created: number;
notify(...args: any[]): boolean;
merge(queue: IQueue): void;
_parent: IQueue | null;
_cloned?: IQueue | undefined;
}
export declare class Queue implements IQueue {
_parent: IQueue | null;
_running: boolean;
_queues: [QueueCallback[], QueueCallback[]];
_children: IQueue[];
created: number;
enqueue(type: number, fn: QueueCallback): void;
run(type: number): void;
flush(): void;
addChild(child: IQueue): any;
removeChild(child: IQueue): any;
notify(...args: any[]): boolean;
merge(queue: Queue): void;
}
export declare const globalQueue: Queue;
/**
* By default, changes are batched on the microtask queue which is an async process. You can flush
* the queue synchronously to get the latest updates by calling `flush()`.
*/
export declare function flush(): void;
export declare function removeSourceObservers(node: ObserverType, index: number): void;
export declare class Transition implements IQueue {
_sources: Map<Computation, Computation>;
_pendingNodes: Set<Effect>;
_promises: Set<Promise<any>>;
_optimistic: Set<(() => void) & {
_transition?: Transition;
}>;
_done: Transition | boolean;
_queues: [QueueCallback[], QueueCallback[]];
_clonedQueues: Map<Queue, Queue>;
_pureQueue: QueueCallback[];
_children: IQueue[];
_parent: IQueue | null;
_running: boolean;
_scheduled: boolean;
_cloned: Queue;
created: number;
constructor();
enqueue(type: number, fn: QueueCallback): void;
run(type: number): void;
flush(): void;
addChild(child: IQueue): void;
removeChild(child: IQueue): void;
notify(node: Effect, type: number, flags: number): boolean;
merge(queue: Transition): void;
schedule(): void;
runTransition(fn: () => any | Promise<any>, force?: boolean): void;
addOptimistic(fn: (() => void) & {
_transition?: Transition;
}): void;
}
/**
* Runs the given function in a transition scope, allowing for batch updates and optimizations.
* This is useful for grouping multiple state updates together to avoid unnecessary re-renders.
*
* @param fn A function that receives a resume function to continue the transition.
* The resume function can be called with another function to continue the transition.
*
* @description https://docs.solidjs.com/reference/advanced-reactivity/transition
*/
export declare function transition(fn: (resume: (fn: () => any | Promise<any>) => void) => any | Promise<any> | Iterable<any>): void;
export declare function cloneGraph(node: Computation): Computation;
export declare function getOGSource<T extends Computation>(input: T): T;
export declare function getTransitionSource<T extends Computation>(input: T): T;
export declare function getQueue(node: Computation): IQueue;
export declare function initialDispose(node: any): void;
+6
View File
@@ -0,0 +1,6 @@
export { Computation, ContextNotFoundError, NoOwnerError, NotReadyError, Owner, Queue, createContext, flush, getContext, setContext, hasContext, getOwner, onCleanup, getObserver, isEqual, untrack, hasUpdated, isPending, latest, runWithObserver, transition, SUPPORTS_PROXY } from "./core/index.js";
export type { SignalOptions, Context, ContextRecord, Disposable, IQueue } from "./core/index.js";
export { mapArray, repeat, type Maybe } from "./map.js";
export * from "./signals.js";
export * from "./store/index.js";
export { createSuspense, createErrorBoundary, createBoundary, flatten, type BoundaryMode } from "./boundaries.js";
+22
View File
@@ -0,0 +1,22 @@
import type { Accessor } from "./signals.js";
export type Maybe<T> = T | void | null | undefined | false;
/**
* Reactively transforms an array with a callback function - underlying helper for the `<For>` control flow
*
* similar to `Array.prototype.map`, but gets the value and index as accessors, transforms only values that changed and returns an accessor and reactively tracks changes to the list.
*
* @description https://docs.solidjs.com/reference/reactive-utilities/map-array
*/
export declare function mapArray<Item, MappedItem>(list: Accessor<Maybe<readonly Item[]>>, map: (value: Accessor<Item>, index: Accessor<number>) => MappedItem, options?: {
keyed?: boolean | ((item: Item) => any);
fallback?: Accessor<any>;
}): Accessor<MappedItem[]>;
/**
* Reactively repeats a callback function the count provided - underlying helper for the `<Repeat>` control flow
*
* @description https://docs.solidjs.com/reference/reactive-utilities/repeat
*/
export declare function repeat(count: Accessor<number>, map: (index: number) => any, options?: {
from?: Accessor<number | undefined>;
fallback?: Accessor<any>;
}): Accessor<any[]>;
+180
View File
@@ -0,0 +1,180 @@
import type { SignalOptions } from "./core/index.js";
import { Owner } from "./core/index.js";
import { type Store, type StoreSetter } from "./store/index.js";
export type Accessor<T> = () => T;
export type Setter<in out T> = {
<U extends T>(...args: undefined extends T ? [] : [value: Exclude<U, Function> | ((prev: T) => U)]): undefined extends T ? undefined : U;
<U extends T>(value: (prev: T) => U): U;
<U extends T>(value: Exclude<U, Function>): U;
<U extends T>(value: Exclude<U, Function> | ((prev: T) => U)): U;
};
export type Signal<T> = [get: Accessor<T>, set: Setter<T>];
export type ComputeFunction<Prev, Next extends Prev = Prev> = (v: Prev) => Next;
export type EffectFunction<Prev, Next extends Prev = Prev> = (v: Next, p?: Prev) => (() => void) | void;
export type EffectBundle<Prev, Next extends Prev = Prev> = {
effect: EffectFunction<Prev, Next>;
error: (err: unknown, cleanup: () => void) => void;
};
export interface EffectOptions {
name?: string;
defer?: boolean;
}
export interface MemoOptions<T> {
name?: string;
equals?: false | ((prev: T, next: T) => boolean);
}
export type NoInfer<T extends any> = [T][T extends any ? 0 : never];
/**
* Creates a simple reactive state with a getter and setter
* ```typescript
* const [state: Accessor<T>, setState: Setter<T>] = createSignal<T>(
* value: T,
* options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) }
* )
* ```
* @param value initial value of the state; if empty, the state's type will automatically extended with undefined; otherwise you need to extend the type manually if you want setting to undefined not be an error
* @param options optional object with a name for debugging purposes and equals, a comparator function for the previous and next value to allow fine-grained control over the reactivity
*
* @returns ```typescript
* [state: Accessor<T>, setState: Setter<T>]
* ```
* * the Accessor is a function that returns the current value and registers each call to the reactive root
* * the Setter is a function that allows directly setting or mutating the value:
* ```typescript
* const [count, setCount] = createSignal(0);
* setCount(count => count + 1);
* ```
*
* @description https://docs.solidjs.com/reference/basic-reactivity/create-signal
*/
export declare function createSignal<T>(): Signal<T | undefined>;
export declare function createSignal<T>(value: Exclude<T, Function>, options?: SignalOptions<T>): Signal<T>;
export declare function createSignal<T>(fn: ComputeFunction<T>, initialValue?: T, options?: SignalOptions<T>): Signal<T>;
/**
* Creates a readonly derived reactive memoized signal
* ```typescript
* export function createMemo<T>(
* compute: (v: T) => T,
* value?: T,
* options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) }
* ): () => T;
* ```
* @param compute a function that receives its previous or the initial value, if set, and returns a new value used to react on a computation
* @param value an optional initial value for the computation; if set, fn will never receive undefined as first argument
* @param options allows to set a name in dev mode for debugging purposes and use a custom comparison function in equals
*
* @description https://docs.solidjs.com/reference/basic-reactivity/create-memo
*/
export declare function createMemo<Next extends Prev, Prev = Next>(compute: ComputeFunction<undefined | NoInfer<Prev>, Next>): Accessor<Next>;
export declare function createMemo<Next extends Prev, Init = Next, Prev = Next>(compute: ComputeFunction<Init | Prev, Next>, value: Init, options?: MemoOptions<Next>): Accessor<Next>;
/**
* Creates a readonly derived async reactive memoized signal
* ```typescript
* export function createAsync<T>(
* compute: (v: T) => Promise<T> | T,
* value?: T,
* options?: { name?: string, equals?: false | ((prev: T, next: T) => boolean) }
* ): () => T;
* ```
* @param compute a function that receives its previous or the initial value, if set, and returns a new value used to react on a computation
* @param value an optional initial value for the computation; if set, fn will never receive undefined as first argument
* @param options allows to set a name in dev mode for debugging purposes and use a custom comparison function in equals
*
* @description https://docs.solidjs.com/reference/basic-reactivity/create-async
*/
export declare function createAsync<T>(compute: (prev: T | undefined, refreshing: boolean) => Promise<T> | AsyncIterable<T> | T, value?: T, options?: MemoOptions<T>): Accessor<T> & {
refresh: () => void;
};
/**
* Creates a reactive effect that runs after the render phase
* ```typescript
* export function createEffect<T>(
* compute: (prev: T) => T,
* effect: (v: T, prev: T) => (() => void) | void,
* value?: T,
* options?: { name?: string }
* ): void;
* ```
* @param compute a function that receives its previous or the initial value, if set, and returns a new value used to react on a computation
* @param effect a function that receives the new value and is used to perform side effects, return a cleanup function to run on disposal
* @param error an optional function that receives an error if thrown during the computation
* @param value an optional initial value for the computation; if set, fn will never receive undefined as first argument
* @param options allows to set a name in dev mode for debugging purposes
*
* @description https://docs.solidjs.com/reference/basic-reactivity/create-effect
*/
export declare function createEffect<Next>(compute: ComputeFunction<undefined | NoInfer<Next>, Next>, effect: EffectFunction<NoInfer<Next>, Next> | EffectBundle<NoInfer<Next>, Next>): void;
export declare function createEffect<Next, Init = Next>(compute: ComputeFunction<Init | Next, Next>, effect: EffectFunction<Next, Next> | EffectBundle<Next, Next>, value: Init, options?: EffectOptions): void;
/**
* Creates a reactive computation that runs during the render phase as DOM elements are created and updated but not necessarily connected
* ```typescript
* export function createRenderEffect<T>(
* compute: (prev: T) => T,
* effect: (v: T, prev: T) => (() => void) | void,
* value?: T,
* options?: { name?: string }
* ): void;
* ```
* @param compute a function that receives its previous or the initial value, if set, and returns a new value used to react on a computation
* @param effect a function that receives the new value and is used to perform side effects
* @param value an optional initial value for the computation; if set, fn will never receive undefined as first argument
* @param options allows to set a name in dev mode for debugging purposes
*
* @description https://docs.solidjs.com/reference/secondary-primitives/create-render-effect
*/
export declare function createRenderEffect<Next>(compute: ComputeFunction<undefined | NoInfer<Next>, Next>, effect: EffectFunction<NoInfer<Next>, Next>): void;
export declare function createRenderEffect<Next, Init = Next>(compute: ComputeFunction<Init | Next, Next>, effect: EffectFunction<Next, Next>, value: Init, options?: EffectOptions): void;
/**
* Creates a new non-tracked reactive context with manual disposal
*
* @param fn a function in which the reactive state is scoped
* @returns the output of `fn`.
*
* @description https://docs.solidjs.com/reference/reactive-utilities/create-root
*/
export declare function createRoot<T>(init: ((dispose: () => void) => T) | (() => T), options?: {
id: string;
}): T;
/**
* Runs the given function in the given owner to move ownership of nested primitives and cleanups.
* This method untracks the current scope.
*
* Warning: Usually there are simpler ways of modeling a problem that avoid using this function
*/
export declare function runWithOwner<T>(owner: Owner | null, run: () => T): T;
/**
* Returns a promise of the resolved value of a reactive expression
* @param fn a reactive expression to resolve
*/
export declare function resolve<T>(fn: () => T): Promise<T>;
/** Allows the user to mark a state change as non-urgent.
*
* @see {@link https://docs.solidjs.com/reference/advanced-reactivity/transition}
*
* @returns A tuple containing an accessor for the pending state and a function to start a transition.
*/
export declare function useTransition(): [
get: Accessor<boolean>,
start: (fn: (resume: (fn: () => any | Promise<any>) => void) => any | Promise<any> | Iterable<any>) => void
];
/**
* Creates an optimistic store that can be used to optimistically update a value
* and then revert it back to the previous value at end of transition.
* ```typescript
* export function createOptimistic<T>(
* fn: (store: T) => void,
* initial: T,
* options?: { key?: string | ((item: NonNullable<any>) => any); all?: boolean }
* ): [get: Store<T>, set: StoreSetter<T>];
* ```
* @param fn a function that receives the current store and can be used to mutate it directly inside a transition
* @param initial The initial value of the signal.
* @param options Optional signal options.
*
* @returns A tuple containing an accessor for the current value and a setter function to apply changes.
*/
export declare function createOptimistic<T extends object = {}>(initial: T | Store<T>): [get: Store<T>, set: StoreSetter<T>];
export declare function createOptimistic<T extends object = {}>(fn: (store: T) => void, initial: T | Store<T>, options?: {
key?: string | ((item: NonNullable<any>) => any);
all?: boolean;
}): [get: Store<T>, set: StoreSetter<T>];
@@ -0,0 +1,6 @@
export type { Store, StoreSetter, StoreNode, NotWrappable, SolidStore } from "./store.js";
export type { Merge, Omit } from "./utils.js";
export { isWrappable, createStore, deep, $TRACK, $PROXY, $TARGET } from "./store.js";
export { createProjection } from "./projection.js";
export { reconcile } from "./reconcile.js";
export { snapshot, merge, omit } from "./utils.js";
@@ -0,0 +1,7 @@
import { type Store, type StoreOptions } from "./store.js";
/**
* Creates a mutable derived value
*
* @see {@link https://github.com/solidjs/x-reactivity#createprojection}
*/
export declare function createProjection<T extends Object>(fn: (draft: T) => void | T, initialValue?: T, options?: StoreOptions): Store<T>;
@@ -0,0 +1 @@
export declare function reconcile<T extends U, U>(value: T, key: string | ((item: NonNullable<any>) => any), all?: boolean): (state: U) => void;
@@ -0,0 +1,37 @@
import { Computation } from "../core/index.js";
export type Store<T> = Readonly<T>;
export type StoreSetter<T> = (fn: (state: T) => T | void) => void;
export type StoreOptions = {
key?: string | ((item: NonNullable<any>) => any);
all?: boolean;
};
type DataNode = Computation<any>;
type DataNodes = Record<PropertyKey, DataNode>;
export declare const $TRACK: unique symbol, $DEEP: unique symbol, $TARGET: unique symbol, $PROXY: unique symbol, $DELETED: unique symbol;
export declare const STORE_VALUE = "v", STORE_OVERRIDE = "o", STORE_NODE = "n", STORE_HAS = "h", STORE_WRAP = "w", STORE_LOOKUP = "l";
export type StoreNode = {
[$PROXY]: any;
[STORE_VALUE]: Record<PropertyKey, any>;
[STORE_OVERRIDE]?: Record<PropertyKey, any>;
[STORE_NODE]?: DataNodes;
[STORE_HAS]?: DataNodes;
[STORE_WRAP]?: (value: any, target?: StoreNode) => any;
[STORE_LOOKUP]?: WeakMap<any, any>;
};
export declare namespace SolidStore {
interface Unwrappable {
}
}
export type NotWrappable = string | number | bigint | symbol | boolean | Function | null | undefined | SolidStore.Unwrappable[keyof SolidStore.Unwrappable];
export declare function createStoreProxy<T extends object>(value: T, traps?: ProxyHandler<StoreNode>, extend?: Record<PropertyKey, any>): any;
export declare const storeLookup: WeakMap<object, any>;
export declare function wrap<T extends Record<PropertyKey, any>>(value: T, target?: StoreNode): T;
export declare function isWrappable<T>(obj: T | NotWrappable): obj is T;
export declare function getKeys(source: Record<PropertyKey, any>, override: Record<PropertyKey, any> | undefined, enumerable?: boolean): PropertyKey[];
export declare function getPropertyDescriptor(source: Record<PropertyKey, any>, override: Record<PropertyKey, any> | undefined, property: PropertyKey): PropertyDescriptor | undefined;
export declare const storeTraps: ProxyHandler<StoreNode>;
export declare function storeSetter<T extends object>(store: Store<T>, fn: (draft: T) => T | void): void;
export declare function createStore<T extends object = {}>(store: T | Store<T>): [get: Store<T>, set: StoreSetter<T>];
export declare function createStore<T extends object = {}>(fn: (store: T) => void, store: T | Store<T>, options?: StoreOptions): [get: Store<T>, set: StoreSetter<T>];
export declare function deep<T extends object>(store: Store<T>): Store<T>;
export {};
@@ -0,0 +1,36 @@
/**
* Returns a non reactive copy of the store object.
* It will attempt to preserver the original reference unless the value has been modified.
* @param item store proxy object
*/
export declare function snapshot<T>(item: T): T;
export declare function snapshot<T>(item: T, map?: Map<unknown, unknown>, lookup?: WeakMap<any, any>): T;
type DistributeOverride<T, F> = T extends undefined ? F : T;
type Override<T, U> = T extends any ? U extends any ? {
[K in keyof T]: K extends keyof U ? DistributeOverride<U[K], T[K]> : T[K];
} & {
[K in keyof U]: K extends keyof T ? DistributeOverride<U[K], T[K]> : U[K];
} : T & U : T & U;
type OverrideSpread<T, U> = T extends any ? {
[K in keyof ({
[K in keyof T]: any;
} & {
[K in keyof U]?: any;
} & {
[K in U extends any ? keyof U : keyof U]?: any;
})]: K extends keyof T ? Exclude<U extends any ? U[K & keyof U] : never, undefined> | T[K] : U extends any ? U[K & keyof U] : never;
} : T & U;
type Simplify<T> = T extends any ? {
[K in keyof T]: T[K];
} : T;
type _Merge<T extends unknown[], Curr = {}> = T extends [
infer Next | (() => infer Next),
...infer Rest
] ? _Merge<Rest, Override<Curr, Next>> : T extends [...infer Rest, infer Next | (() => infer Next)] ? Override<_Merge<Rest, Curr>, Next> : T extends [] ? Curr : T extends (infer I | (() => infer I))[] ? OverrideSpread<Curr, I> : Curr;
export type Merge<T extends unknown[]> = Simplify<_Merge<T>>;
export declare function merge<T extends unknown[]>(...sources: T): Merge<T>;
export type Omit<T, K extends readonly (keyof T)[]> = {
[P in keyof T as Exclude<P, K[number]>]: T[P];
};
export declare function omit<T extends Record<any, any>, K extends readonly (keyof T)[]>(props: T, ...keys: K): Omit<T, K>;
export {};
@@ -9,5 +9,5 @@
"lib": ["DOM", "DOM.Iterable", "ESNext", "WebWorker"],
"skipLibCheck": true
},
"exclude": ["scripts/packages", "scripts/bridge"]
"exclude": ["dist"]
}
-2
View File
@@ -1,2 +0,0 @@
pools.js
metrics.js
-64
View File
@@ -1,64 +0,0 @@
// Should be generated by server
export const serdeIndex = {
/**
* @param {Index} v
*/
serialize(v) {
switch (v) {
case /** @satisfies {DateIndex} */ (0):
return "dateindex";
case /** @satisfies {DecadeIndex} */ (1):
return "decadeindex";
case /** @satisfies {DifficultyEpoch} */ (2):
return "difficultyepoch";
case /** @satisfies {EmptyOutputIndex} */ (3):
return "emptyoutputindex";
case /** @satisfies {HalvingEpoch} */ (4):
return "halvingepoch";
case /** @satisfies {Height} */ (5):
return "height";
case /** @satisfies {InputIndex} */ (6):
return "inputindex";
case /** @satisfies {MonthIndex} */ (7):
return "monthindex";
case /** @satisfies {OpReturnIndex} */ (8):
return "opreturnindex";
case /** @satisfies {OutputIndex} */ (9):
return "outputindex";
case /** @satisfies {P2AAddressIndex} */ (10):
return "p2aaddressindex";
case /** @satisfies {P2MSOutputIndex} */ (11):
return "p2msoutputindex";
case /** @satisfies {P2PK33AddressIndex} */ (12):
return "p2pk33addressindex";
case /** @satisfies {P2PK65AddressIndex} */ (13):
return "p2pk65addressindex";
case /** @satisfies {P2PKHAddressIndex} */ (14):
return "p2pkhaddressindex";
case /** @satisfies {P2SHAddressIndex} */ (15):
return "p2shaddressindex";
case /** @satisfies {P2TRAddressIndex} */ (16):
return "p2traddressindex";
case /** @satisfies {P2WPKHAddressIndex} */ (17):
return "p2wpkhaddressindex";
case /** @satisfies {P2WSHAddressIndex} */ (18):
return "p2wshaddressindex";
case /** @satisfies {QuarterIndex} */ (19):
return "quarterindex";
case /** @satisfies {SemesterIndex} */ (20):
return "semesterindex";
case /** @satisfies {TxIndex} */ (21):
return "txindex";
case /** @satisfies {UnknownOutputIndex} */ (22):
return "unknownoutputindex";
case /** @satisfies {WeekIndex} */ (23):
return "weekindex";
case /** @satisfies {YearIndex} */ (24):
return "yearindex";
case /** @satisfies {LoadedAddressIndex} */ (25):
return "loadedaddressindex";
case /** @satisfies {EmptyAddressIndex} */ (26):
return "emptyaddressindex";
}
},
};
-9
View File
@@ -1,9 +0,0 @@
/**
* @import { Signal, Signals, Accessor } from "../solidjs-signals/index";
*
* @import { DateIndex, DecadeIndex, DifficultyEpoch, Index, HalvingEpoch, Height, MonthIndex, P2PK33AddressIndex, P2PK65AddressIndex, P2PKHAddressIndex, P2SHAddressIndex, P2MSOutputIndex, P2AAddressIndex, P2TRAddressIndex, P2WPKHAddressIndex, P2WSHAddressIndex, TxIndex, InputIndex, OutputIndex, WeekIndex, SemesterIndex, YearIndex, MetricToIndexes, QuarterIndex, EmptyOutputIndex, OpReturnIndex, UnknownOutputIndex, EmptyAddressIndex, LoadedAddressIndex } from "./metrics"
*
* @typedef {[number, number, number, number]} OHLCTuple
*
* @typedef {any} Metric
*/