Compare commits

..

9 Commits

Author SHA1 Message Date
nym21 30affc884b release: v0.0.95 2025-08-28 12:43:49 +02:00
nym21 745717ea49 global: added unrealized relative datasets 2025-08-28 12:43:28 +02:00
nym21 4efd98b758 release: v0.0.94 2025-08-28 00:31:36 +02:00
nym21 36640e3710 global: added datasets 2025-08-28 00:31:14 +02:00
nym21 311c4fd29d website: rename default to bitview 2025-08-27 11:52:22 +02:00
nym21 f50374f983 release: v0.0.93 2025-08-26 23:34:57 +02:00
nym21 82ceb7f021 cargo: update 2025-08-26 23:34:38 +02:00
nym21 0aba3bc1d8 release: v0.0.92 2025-08-26 22:27:16 +02:00
nym21 f6c984ff3c website: add screenshot feature 2025-08-26 22:26:55 +02:00
112 changed files with 3036 additions and 6483 deletions
Generated
+29 -26
View File
@@ -487,7 +487,7 @@ dependencies = [
[[package]]
name = "brk"
version = "0.0.91"
version = "0.0.95"
dependencies = [
"brk_bundler",
"brk_cli",
@@ -506,7 +506,7 @@ dependencies = [
[[package]]
name = "brk_bundler"
version = "0.0.91"
version = "0.0.95"
dependencies = [
"brk_rolldown",
"log",
@@ -517,7 +517,7 @@ dependencies = [
[[package]]
name = "brk_cli"
version = "0.0.91"
version = "0.0.95"
dependencies = [
"bitcoincore-rpc",
"brk_bundler",
@@ -542,7 +542,7 @@ dependencies = [
[[package]]
name = "brk_computer"
version = "0.0.91"
version = "0.0.95"
dependencies = [
"bitcoin",
"bitcoincore-rpc",
@@ -564,7 +564,7 @@ dependencies = [
[[package]]
name = "brk_error"
version = "0.0.91"
version = "0.0.95"
dependencies = [
"bitcoincore-rpc",
"fjall",
@@ -577,7 +577,7 @@ dependencies = [
[[package]]
name = "brk_fetcher"
version = "0.0.91"
version = "0.0.95"
dependencies = [
"brk_error",
"brk_logger",
@@ -589,7 +589,7 @@ dependencies = [
[[package]]
name = "brk_indexer"
version = "0.0.91"
version = "0.0.95"
dependencies = [
"bitcoin",
"bitcoincore-rpc",
@@ -606,7 +606,7 @@ dependencies = [
[[package]]
name = "brk_interface"
version = "0.0.91"
version = "0.0.95"
dependencies = [
"brk_computer",
"brk_error",
@@ -623,7 +623,7 @@ dependencies = [
[[package]]
name = "brk_logger"
version = "0.0.91"
version = "0.0.95"
dependencies = [
"env_logger",
"jiff",
@@ -633,7 +633,7 @@ dependencies = [
[[package]]
name = "brk_mcp"
version = "0.0.91"
version = "0.0.95"
dependencies = [
"axum",
"brk_interface",
@@ -643,7 +643,7 @@ dependencies = [
[[package]]
name = "brk_parser"
version = "0.0.91"
version = "0.0.95"
dependencies = [
"bitcoin",
"bitcoincore-rpc",
@@ -1021,7 +1021,7 @@ dependencies = [
[[package]]
name = "brk_server"
version = "0.0.91"
version = "0.0.95"
dependencies = [
"axum",
"bitcoincore-rpc",
@@ -1045,7 +1045,7 @@ dependencies = [
[[package]]
name = "brk_store"
version = "0.0.91"
version = "0.0.95"
dependencies = [
"brk_error",
"brk_structs",
@@ -1068,7 +1068,7 @@ dependencies = [
[[package]]
name = "brk_structs"
version = "0.0.91"
version = "0.0.95"
dependencies = [
"bitcoin",
"bitcoincore-rpc",
@@ -1198,18 +1198,18 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.45"
version = "4.5.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fc0e74a703892159f5ae7d3aac52c8e6c392f5ae5f359c70b5881d60aaac318"
checksum = "2c5e4fcf9c21d2e544ca1ee9d8552de13019a42aa7dbf32747fa7aaf1df76e57"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
version = "4.5.44"
version = "4.5.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3e7f4214277f3c7aa526a59dd3fbe306a370daee1f8b7b8c987069cd8e888a8"
checksum = "fecb53a0e6fcfb055f686001bc2e2592fa527efaf38dbe81a6a9563562e57d41"
dependencies = [
"anstream",
"anstyle",
@@ -1735,9 +1735,9 @@ dependencies = [
[[package]]
name = "fancy-regex"
version = "0.14.0"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e24cb5a94bcae1e5408b0effca5cd7172ea3c5755049c5f3af4cd283a165298"
checksum = "bf04c5ec15464ace8355a7b440a33aece288993475556d461154d7a62ad9947c"
dependencies = [
"bit-set",
"regex-automata",
@@ -3054,9 +3054,9 @@ dependencies = [
[[package]]
name = "oxc_resolver"
version = "11.6.2"
version = "11.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d84cdcd778d15db5b21cc61baf79ac55cee97e7feb725b2664453979ba3cd76"
checksum = "0784392356fa78dd4c9047fce7c9046c141f8990736792d00310bf40935b1870"
dependencies = [
"cfg-if",
"indexmap 2.11.0",
@@ -3407,9 +3407,9 @@ checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
[[package]]
name = "pnp"
version = "0.12.1"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab3167cbab15e437e9c7db8a4cf613eb4a77583d4327a8964d50fedd6cf364bd"
checksum = "e001eb06e9523653f2a88adb94e286ef5d7acfe64158b21bf57a6f6bc3ba65ca"
dependencies = [
"byteorder",
"clean-path",
@@ -3602,9 +3602,12 @@ dependencies = [
[[package]]
name = "rapidhash"
version = "3.1.0"
version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "efee4b7317469c6c6e7fdeee3d094313af846a97678d6ed971d83a852d730083"
checksum = "9d126f24bc587b080d7823a831d0fe832090a606fd3fd244ecbe23c561104ab8"
dependencies = [
"rustversion",
]
[[package]]
name = "rayon"
+14 -14
View File
@@ -4,7 +4,7 @@ members = ["crates/*"]
package.description = "The Bitcoin Research Kit is a suite of tools designed to extract, compute and display data stored on a Bitcoin Core node"
package.license = "MIT"
package.edition = "2024"
package.version = "0.0.91"
package.version = "0.0.95"
package.homepage = "https://bitcoinresearchkit.org"
package.repository = "https://github.com/bitcoinresearchkit/brk"
package.readme = "README.md"
@@ -26,19 +26,19 @@ inherits = "release"
axum = "0.8.4"
bitcoin = { version = "0.32.7", features = ["serde"] }
bitcoincore-rpc = "0.19.0"
brk_bundler = { version = "0.0.91", path = "crates/brk_bundler" }
brk_cli = { version = "0.0.91", path = "crates/brk_cli" }
brk_computer = { version = "0.0.91", path = "crates/brk_computer" }
brk_error = { version = "0.0.91", path = "crates/brk_error" }
brk_fetcher = { version = "0.0.91", path = "crates/brk_fetcher" }
brk_indexer = { version = "0.0.91", path = "crates/brk_indexer" }
brk_interface = { version = "0.0.91", path = "crates/brk_interface" }
brk_logger = { version = "0.0.91", path = "crates/brk_logger" }
brk_mcp = { version = "0.0.91", path = "crates/brk_mcp" }
brk_parser = { version = "0.0.91", path = "crates/brk_parser" }
brk_server = { version = "0.0.91", path = "crates/brk_server" }
brk_store = { version = "0.0.91", path = "crates/brk_store" }
brk_structs = { version = "0.0.91", path = "crates/brk_structs" }
brk_bundler = { version = "0.0.95", path = "crates/brk_bundler" }
brk_cli = { version = "0.0.95", path = "crates/brk_cli" }
brk_computer = { version = "0.0.95", path = "crates/brk_computer" }
brk_error = { version = "0.0.95", path = "crates/brk_error" }
brk_fetcher = { version = "0.0.95", path = "crates/brk_fetcher" }
brk_indexer = { version = "0.0.95", path = "crates/brk_indexer" }
brk_interface = { version = "0.0.95", path = "crates/brk_interface" }
brk_logger = { version = "0.0.95", path = "crates/brk_logger" }
brk_mcp = { version = "0.0.95", path = "crates/brk_mcp" }
brk_parser = { version = "0.0.95", path = "crates/brk_parser" }
brk_server = { version = "0.0.95", path = "crates/brk_server" }
brk_store = { version = "0.0.95", path = "crates/brk_store" }
brk_structs = { version = "0.0.95", path = "crates/brk_structs" }
byteview = "=0.6.1"
derive_deref = "1.1.1"
fjall = "2.11.2"
+3 -4
View File
@@ -31,10 +31,9 @@ In other words it's an alternative to [Glassnode](https://glassnode.com), [mempo
The toolkit can be used in various ways to accommodate as many needs as possible:
- **[Website](https://bitcoinresearchkit.org)** \
- **[Website](https://bitview.space)** \
Everyone is welcome to visit the official instance and showcase of the suite's capabilities. \
It has a wide range of functionalities including charts, tables and simulations which you can visit for free and without the need for an account. \
Also available at: [brekit.org](https://brekit.org) // [kibo.money](https://kibo.money) // [satonomics.xyz](https://satonomics.xyz)
It has a wide range of functionalities including charts, tables and simulations which you can visit for free and without the need for an account.
- **[API](https://github.com/bitcoinresearchkit/brk/tree/main/crates/brk_server#brk-server)** \
Researchers and developers are free to use BRK's public API with ![Datasets variant count](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fbitcoinresearchkit.org%2Fapi%2Fvecs%2Fvec-count&query=%24&style=flat&label=%20&color=white) dataset variants at their disposal. \
Just like the website, it's entirely free, with no authentication or rate-limiting.
@@ -62,7 +61,7 @@ If you'd like to have your own instance hosted for you please contact [hosting@b
- Updates delivered at your convenience
- Direct communication for feature requests and support
- Bitcoin Core or Knots with desired version
- Optional subdomains: `*.bitcoinresearchkit.org`, `*.brekit.org`, `*.kibo.money` and `*.satonomics.xyz`
- Optional subdomains
- Logo featured in the Readme if desired
Pricing: `0.01 BTC / month` *or* `0.1 BTC / year`
-11
View File
@@ -10,30 +10,19 @@
- pull latest version and notify is out of date
- _computer_
- **add rollback of states (in stateful)**
- remove configurable format (raw/compressed) and chose sane ones instead
- linear reads: compressed (height/date/... + txindex_to_height + txindex_to_version + ...)
- random reads: raw (outputindex_to_value + ...)
- add costs basis by percentile (percentile cost basis) back
- add support for per index computation
- fix min feerate which is always ZERO due to coinbase transaction
- before computing multiple sources check their length, panic if not equal
- add oracle price dataset (https://utxo.live/oracle/UTXOracle.py)
- add address counts relative to all datasets
- make decade, quarter, year datasets `computed` instead of `eager`
- add 6 months (semester) interval datasets to builder
- some datasets in `indexes` can probably be removed
- add revived/sent supply datasets
- add `in-sats` version of all price datasets (average and co)
- add `p2pk` group (sum of `p2pk33` and `p2pk65`)
- add chopiness datasets
- add utxo count, address count, supply data for by reused addresses in groups by address type
- add more date ranges (3-6 months and more)
- add puell multiple dataset
- add pi cycle dataset
- add emas of price
- add 7d and 30d ema to sell side risk ratio and sopr
- don't compute everything for all cohorts as some datasets combinations are irrelevant
- addresses/utxos by amount don't need mvrvz for example
- add all possible charts from:
- https://mainnet.observer
- https://glassnode.com
+1 -1
View File
@@ -20,7 +20,7 @@ brk_logger = { workspace = true }
brk_parser = { workspace = true }
brk_server = { workspace = true }
vecdb = { workspace = true }
clap = { version = "4.5.45", features = ["string"] }
clap = { version = "4.5.46", features = ["string"] }
clap_derive = "4.5.45"
color-eyre = "0.6.5"
log = { workspace = true }
+1 -1
View File
@@ -284,7 +284,7 @@ Finally, you can run the program with '-h' for help."
}
pub fn website(&self) -> Website {
self.website.unwrap_or(Website::Default)
self.website.unwrap_or(Website::Bitview)
}
pub fn fetch(&self) -> bool {
+2 -2
View File
@@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize, ValueEnum)]
pub enum Website {
None,
Default,
Bitview,
Custom,
}
@@ -20,7 +20,7 @@ impl Website {
pub fn to_folder_name(self) -> &'static str {
match self {
Self::Custom => "custom",
Self::Default => "default",
Self::Bitview => "bitview",
Self::None => unreachable!(),
}
}
+19 -4
View File
@@ -78,15 +78,25 @@ impl Vecs {
Source::None,
version + VERSION + Version::ZERO,
indexes,
VecBuilderOptions::default().add_sum().add_cumulative(),
VecBuilderOptions::default()
.add_sum()
.add_minmax()
.add_average()
.add_percentiles()
.add_cumulative(),
)?,
indexes_to_block_size: ComputedVecsFromHeight::forced_import(
&db,
"block_size",
Source::None,
Source::Compute,
version + VERSION + Version::ZERO,
indexes,
VecBuilderOptions::default().add_sum().add_cumulative(),
VecBuilderOptions::default()
.add_sum()
.add_minmax()
.add_average()
.add_percentiles()
.add_cumulative(),
)?,
height_to_vbytes: EagerVec::forced_import_compressed(
&db,
@@ -99,7 +109,12 @@ impl Vecs {
Source::None,
version + VERSION + Version::ZERO,
indexes,
VecBuilderOptions::default().add_sum().add_cumulative(),
VecBuilderOptions::default()
.add_sum()
.add_minmax()
.add_average()
.add_percentiles()
.add_cumulative(),
)?,
difficultyepoch_to_timestamp: EagerVec::forced_import_compressed(
&db,
@@ -79,8 +79,8 @@ impl Vecs {
version,
indexes,
price,
compute_relative_to_all,
false,
compute_relative_to_all,
false,
)?,
})
File diff suppressed because it is too large Load Diff
@@ -32,8 +32,8 @@ impl Vecs {
indexes: &indexes::Vecs,
price: Option<&price::Vecs>,
states_path: Option<&Path>,
extended: bool,
compute_relative_to_all: bool,
ratio_extended: bool,
compute_adjusted: bool,
) -> Result<Self> {
let compute_dollars = price.is_some();
@@ -56,8 +56,8 @@ impl Vecs {
version,
indexes,
price,
extended,
compute_relative_to_all,
ratio_extended,
compute_adjusted,
)?,
})
@@ -42,8 +42,8 @@ impl Vecs {
indexes,
price,
None,
false,
true,
false,
true,
)?,
term: ByTerm {
@@ -143,8 +143,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
p2pk33: utxo_cohort::Vecs::forced_import(
@@ -155,8 +155,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
p2pkh: utxo_cohort::Vecs::forced_import(
@@ -167,8 +167,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
p2sh: utxo_cohort::Vecs::forced_import(
@@ -179,8 +179,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
p2wpkh: utxo_cohort::Vecs::forced_import(
@@ -191,8 +191,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
p2wsh: utxo_cohort::Vecs::forced_import(
@@ -203,8 +203,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
p2tr: utxo_cohort::Vecs::forced_import(
@@ -215,8 +215,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
p2a: utxo_cohort::Vecs::forced_import(
@@ -227,8 +227,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
p2ms: utxo_cohort::Vecs::forced_import(
@@ -239,8 +239,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
empty: utxo_cohort::Vecs::forced_import(
@@ -251,8 +251,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
unknown: utxo_cohort::Vecs::forced_import(
@@ -263,8 +263,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
},
@@ -955,8 +955,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_1sat_to_10sats: utxo_cohort::Vecs::forced_import(
@@ -967,8 +967,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_10sats_to_100sats: utxo_cohort::Vecs::forced_import(
@@ -979,8 +979,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_100sats_to_1k_sats: utxo_cohort::Vecs::forced_import(
@@ -991,8 +991,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_1k_sats_to_10k_sats: utxo_cohort::Vecs::forced_import(
@@ -1003,8 +1003,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_10k_sats_to_100k_sats: utxo_cohort::Vecs::forced_import(
@@ -1015,8 +1015,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_100k_sats_to_1m_sats: utxo_cohort::Vecs::forced_import(
@@ -1027,8 +1027,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_1m_sats_to_10m_sats: utxo_cohort::Vecs::forced_import(
@@ -1039,8 +1039,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_10m_sats_to_1btc: utxo_cohort::Vecs::forced_import(
@@ -1051,8 +1051,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_1btc_to_10btc: utxo_cohort::Vecs::forced_import(
@@ -1063,8 +1063,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_10btc_to_100btc: utxo_cohort::Vecs::forced_import(
@@ -1075,8 +1075,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_100btc_to_1k_btc: utxo_cohort::Vecs::forced_import(
@@ -1087,8 +1087,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_1k_btc_to_10k_btc: utxo_cohort::Vecs::forced_import(
@@ -1099,8 +1099,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_10k_btc_to_100k_btc: utxo_cohort::Vecs::forced_import(
@@ -1111,8 +1111,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
_100k_btc_or_more: utxo_cohort::Vecs::forced_import(
@@ -1123,8 +1123,8 @@ impl Vecs {
indexes,
price,
Some(states_path),
true,
false,
true,
false,
)?,
},
@@ -1137,8 +1137,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_100sats: utxo_cohort::Vecs::forced_import(
@@ -1149,8 +1149,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_1k_sats: utxo_cohort::Vecs::forced_import(
@@ -1161,8 +1161,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_10k_sats: utxo_cohort::Vecs::forced_import(
@@ -1173,8 +1173,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_100k_sats: utxo_cohort::Vecs::forced_import(
@@ -1185,8 +1185,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_1m_sats: utxo_cohort::Vecs::forced_import(
@@ -1197,8 +1197,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_10m_sats: utxo_cohort::Vecs::forced_import(
@@ -1209,8 +1209,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_1btc: utxo_cohort::Vecs::forced_import(
@@ -1221,8 +1221,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_10btc: utxo_cohort::Vecs::forced_import(
@@ -1233,8 +1233,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_100btc: utxo_cohort::Vecs::forced_import(
@@ -1245,8 +1245,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_1k_btc: utxo_cohort::Vecs::forced_import(
@@ -1257,8 +1257,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_10k_btc: utxo_cohort::Vecs::forced_import(
@@ -1269,8 +1269,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_100k_btc: utxo_cohort::Vecs::forced_import(
@@ -1281,8 +1281,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
},
@@ -1295,8 +1295,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_10sats: utxo_cohort::Vecs::forced_import(
@@ -1307,8 +1307,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_100sats: utxo_cohort::Vecs::forced_import(
@@ -1319,8 +1319,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_1k_sats: utxo_cohort::Vecs::forced_import(
@@ -1331,8 +1331,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_10k_sats: utxo_cohort::Vecs::forced_import(
@@ -1343,8 +1343,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_100k_sats: utxo_cohort::Vecs::forced_import(
@@ -1355,8 +1355,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_1m_sats: utxo_cohort::Vecs::forced_import(
@@ -1367,8 +1367,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_10m_sats: utxo_cohort::Vecs::forced_import(
@@ -1379,8 +1379,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_1btc: utxo_cohort::Vecs::forced_import(
@@ -1391,8 +1391,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_10btc: utxo_cohort::Vecs::forced_import(
@@ -1403,8 +1403,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_100btc: utxo_cohort::Vecs::forced_import(
@@ -1415,8 +1415,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_1k_btc: utxo_cohort::Vecs::forced_import(
@@ -1427,8 +1427,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
_10k_btc: utxo_cohort::Vecs::forced_import(
@@ -1439,8 +1439,8 @@ impl Vecs {
indexes,
price,
None,
true,
false,
true,
false,
)?,
},
+1 -1
View File
@@ -17,7 +17,7 @@ vecdb = {workspace = true}
byteview = { workspace = true }
derive_deref = { workspace = true }
jiff = { workspace = true }
rapidhash = "3.1.0"
rapidhash = "4.0.0"
serde = { workspace = true }
serde_bytes = { workspace = true }
zerocopy = { workspace = true }

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Before

Width:  |  Height:  |  Size: 511 B

After

Width:  |  Height:  |  Size: 511 B

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

Before

Width:  |  Height:  |  Size: 594 B

After

Width:  |  Height:  |  Size: 594 B

Before

Width:  |  Height:  |  Size: 562 B

After

Width:  |  Height:  |  Size: 562 B

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

@@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="description" content="Bitcoin with X-ray vision" />
<meta name="description" content="Bitcoin transparency, amplified" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
@@ -449,7 +449,7 @@
text-transform: uppercase;
font-size: var(--font-size-xl);
line-height: var(--line-height-xl);
font-weight: 325;
font-weight: 350;
}
h3 {
@@ -556,6 +556,10 @@
&:has(input:checked) {
color: var(--color);
}
[data-screenshot="true"] &:has(input:not(:checked)) {
display: none;
}
}
main {
@@ -971,7 +975,6 @@
flex-shrink: 0;
display: flex;
align-items: center;
gap: 1.5rem;
margin: -0.5rem var(--negative-main-padding);
padding: 0.75rem var(--main-padding);
overflow-x: auto;
@@ -989,13 +992,33 @@
margin-top: 2rem;
margin-bottom: 1rem;
button#screenshot {
width: 100%;
text-align: left;
padding-left: 1rem;
height: 100%;
font-size: var(--font-size-sm);
line-height: var(--line-height-sm);
[data-screenshot="true"] & {
display: none;
}
}
> legend {
gap: 1.5rem;
&:empty {
display: none;
}
> div {
[data-screenshot="true"] &:has(input:not(:checked)) {
display: none;
}
flex: 0;
height: 100%;
display: flex;
align-items: center;
@@ -1033,6 +1056,11 @@
padding-right: 0.375rem;
margin-left: -0.375rem;
margin-right: -0.375rem;
[data-screenshot="true"] & {
width: 0;
opacity: 0;
}
}
}
}
@@ -1118,6 +1146,16 @@
width: 100%;
min-height: 0;
padding: var(--main-padding);
background-color: var(--background-color);
p#domain {
position: absolute;
left: 2rem;
top: 0.75rem;
color: var(--gray);
font-size: var(--font-size-sm);
line-height: var(--line-height-sm);
}
header {
flex-shrink: 0;
@@ -1141,6 +1179,17 @@
flex: 1;
}
#interval {
> span {
display: none;
[data-screenshot="true"] & {
color: var(--gray);
display: inline-block;
}
}
}
> .chart > legend,
> fieldset {
z-index: 20;
@@ -1696,7 +1745,9 @@
<div class="shadow-bottom"></div>
<div id="resize-bar"></div>
<nav id="nav" hidden></nav>
<nav id="nav" hidden>
<!-- <h4>bitview</h4> -->
</nav>
<search id="search" hidden>
<header>
@@ -1,7 +1,7 @@
{
"name": "Bitcoin Research Kit",
"short_name": "₿RK",
"description": "A better, FOSS, Bitcoin-only, self-hostable Glassnode",
"name": "bitview",
"short_name": "bitview",
"description": "Bitcoin transparency, amplified",
"categories": [
"bitcoin",
"on-chain",
@@ -1,7 +1,7 @@
LICENSE
*.json
*webcomponent*
README.md
README*.md
cli*
extras/
*.cjs
@@ -9,3 +9,7 @@ dev.js
*.development*
*.iife.*
nano.*
worker.*
*.ts
*.mts
*.cts
@@ -4,7 +4,7 @@
*
* uFuzzy.js (μFuzzy)
* A tiny, efficient fuzzy matcher that doesn't suck
* https://github.com/leeoniya/uFuzzy (v1.0.18)
* https://github.com/leeoniya/uFuzzy (v1.0.19)
*/
const cmp = (a, b) => a > b ? 1 : a < b ? -1 : 0;
@@ -925,40 +925,50 @@ function uFuzzy(opts) {
const latinize = (() => {
let accents = {
A: 'ÁÀÃÂÄĄ',
a: 'áàãâäą',
E: 'ÉÈÊËĖ',
e: 'éèêëę',
I: 'ÍÌÎÏĮ',
i: 'íìîïį',
A: 'ÁÀÃÂÄĄĂÅ',
a: 'áàãâäąăå',
E: 'ÉÈÊËĖĚ',
e: 'éèêëęě',
I: 'ÍÌÎÏĮİ',
i: 'íìîïįı',
O: 'ÓÒÔÕÖ',
o: 'óòôõö',
U: 'ÚÙÛÜŪŲ',
u: 'úùûüūų',
U: 'ÚÙÛÜŪŲŮŰ',
u: 'úùûüūųůű',
C: 'ÇČĆ',
c: 'çčć',
D: 'Ď',
d: 'ď',
G: 'Ğ',
g: 'ğ',
L: 'Ł',
l: 'ł',
N: 'ÑŃ',
n: 'ñń',
S: 'ŠŚ',
s: 'šś',
Z: 'ŻŹ',
z: 'żź'
N: 'ÑŃŇ',
n: 'ñńň',
S: 'ŠŚȘŞ',
s: 'šśșş',
T: 'ŢȚŤ',
t: 'ţțť',
Y: 'Ý',
y: 'ý',
Z: 'ŻŹŽ',
z: 'żźž'
};
let accentsMap = new Map();
// str.normalize("NFD").replace(/\p{Diacritic}/gu, "")
let accentsMap = {};
let accentsTpl = '';
for (let r in accents) {
accents[r].split('').forEach(a => {
accentsTpl += a;
accentsMap.set(a, r);
accentsMap[a] = r;
});
}
let accentsRe = new RegExp(`[${accentsTpl}]`, 'g');
let replacer = m => accentsMap.get(m);
let replacer = m => accentsMap[m];
return strings => {
if (typeof strings == 'string')
@@ -0,0 +1 @@
*.js
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,13 @@
import { domToBlob } from "./4.6.6/dist/index.mjs";
/**
* @param {Element} element
*/
export async function screenshot(element) {
const blob = await domToBlob(element, {
scale: 2,
});
const url = URL.createObjectURL(blob);
window.open(url, "_blank");
setTimeout(() => URL.revokeObjectURL(url), 100);
}
@@ -386,10 +386,10 @@ main() {
# Check if the directory already exists and has content
if [[ -d "$output_dir" ]] && [[ -n "$(ls -A "$output_dir" 2>/dev/null)" ]]; then
print_error "Directory already exists and is not empty: $output_dir"
print_error "Package $package_name@$resolved_version appears to already be downloaded."
print_error "Remove the directory or choose a different output location to proceed."
exit 1
print_warning "Directory already exists and is not empty: $output_dir"
print_warning "Package $package_name@$resolved_version appears to already be downloaded."
print_warning "Remove the directory or choose a different output location to proceed."
return
fi
# Create the base output directory
@@ -409,3 +409,4 @@ main "@solidjs/signals"
main "@leeoniya/ufuzzy"
main "lean-qr"
main "lightweight-charts"
main "modern-screenshot"
@@ -21,6 +21,7 @@ const CANDLE = "candle";
* @param {Elements} args.elements
* @param {VecsResources} args.vecsResources
* @param {VecIdToIndexes} args.vecIdToIndexes
* @param {Packages} args.packages
*/
export function init({
colors,
@@ -32,6 +33,7 @@ export function init({
webSockets,
vecsResources,
vecIdToIndexes,
packages,
}) {
elements.charts.append(utils.dom.createShadow("left"));
elements.charts.append(utils.dom.createShadow("right"));
@@ -95,6 +97,35 @@ export function init({
},
});
const chartBottomRightCanvas = Array.from(
chart.inner.chartElement().getElementsByTagName("tr"),
).at(-1)?.lastChild?.firstChild?.firstChild;
if (chartBottomRightCanvas) {
const charts = elements.charts;
const domain = window.document.createElement("p");
domain.innerText = `${window.location.host}`;
domain.id = "domain";
const screenshotButton = window.document.createElement("button");
screenshotButton.id = "screenshot";
const camera = "[ ◉¯]";
screenshotButton.innerHTML = camera;
screenshotButton.title = "Screenshot";
chartBottomRightCanvas.replaceWith(screenshotButton);
screenshotButton.addEventListener("click", () => {
packages.modernScreenshot().then(async ({ screenshot }) => {
charts.dataset.screenshot = "true";
charts.append(domain);
seriesTypeField.hidden = true;
try {
await screenshot(charts);
} catch {}
charts.removeChild(domain);
seriesTypeField.hidden = false;
charts.dataset.screenshot = "false";
});
});
}
chart.inner.timeScale().subscribeVisibleLogicalRangeChange(
utils.debounce((t) => {
if (t) {
@@ -525,6 +556,12 @@ function createIndexSelector({ option, vecIdToIndexes, signals, utils }) {
});
const fieldset = window.document.createElement("fieldset");
fieldset.id = "interval";
const screenshotSpan = window.document.createElement("span");
screenshotSpan.innerText = "interval:";
fieldset.append(screenshotSpan);
fieldset.append(field);
fieldset.dataset.size = "sm";
@@ -3,7 +3,7 @@
/**
* @import { Option, PartialChartOption, ChartOption, AnyPartialOption, ProcessedOptionAddons, OptionsTree, SimulationOption, AnySeriesBlueprint, SeriesType } from "./options"
* @import { Valued, SingleValueData, CandlestickData, OHLCTuple, Series, ISeries, HistogramData, LineData, BaselineData, LineSeriesPartialOptions, BaselineSeriesPartialOptions, HistogramSeriesPartialOptions, CandlestickSeriesPartialOptions } from "../packages/lightweight-charts/wrapper"
* @import * as _ from "../packages/leeoniya-ufuzzy/1.0.18/dist/uFuzzy.d.ts"
* @import * as _ from "../packages/leeoniya-ufuzzy/1.0.19/dist/uFuzzy.d.ts"
* @import { SerializedChartableIndex } from "./chart";
* @import { Signal, Signals, Accessor } from "../packages/solidjs-signals/wrapper";
* @import { DateIndex, DecadeIndex, DifficultyEpoch, Index, HalvingEpoch, Height, MonthIndex, P2PK33AddressIndex, P2PK65AddressIndex, P2PKHAddressIndex, P2SHAddressIndex, P2MSOutputIndex, P2AAddressIndex, P2TRAddressIndex, P2WPKHAddressIndex, P2WSHAddressIndex, TxIndex, InputIndex, OutputIndex, VecId, WeekIndex, SemesterIndex, YearIndex, VecIdToIndexes, QuarterIndex, EmptyOutputIndex, OpReturnIndex, UnknownOutputIndex } from "./vecid-to-indexes"
@@ -24,7 +24,6 @@
* "Gigabytes" |
* "Hash" |
* "Index" |
* "mb" |
* "percentage" |
* "Ratio" |
* "Sats" |
@@ -39,6 +38,8 @@
* "Bool" |
* "Days" |
* "%mcap" |
* "%cmcap" |
* "%cp+l" |
* "%rcap" |
* "%self" |
* "%all" |
@@ -78,10 +79,13 @@ function initPackages() {
return import("../packages/lean-qr/2.5.0/index.mjs").then((d) => d);
},
async ufuzzy() {
return import("../packages/leeoniya-ufuzzy/1.0.18/dist/uFuzzy.mjs").then(
return import("../packages/leeoniya-ufuzzy/1.0.19/dist/uFuzzy.mjs").then(
({ default: d }) => d,
);
},
async modernScreenshot() {
return import("../packages/modern-screenshot/wrapper.js").then((d) => d);
},
};
/**
@@ -106,6 +110,7 @@ function initPackages() {
lightweightCharts: importPackage("lightweightCharts"),
leanQr: importPackage("leanQr"),
ufuzzy: importPackage("ufuzzy"),
modernScreenshot: importPackage("modernScreenshot"),
};
}
/**
@@ -850,7 +855,11 @@ function createUtils() {
}
if (
(!unit || thoroughUnitCheck) &&
(id === "txid" || (id.endsWith("bytes") && !id.endsWith("vbytes")))
(id === "txid" ||
(id.endsWith("bytes") && !id.endsWith("vbytes")) ||
id.endsWith("base_size") ||
id.endsWith("total_size") ||
id.includes("block_size"))
) {
if (unit) throw Error(`Unit "${unit}" already assigned "${id}"`);
unit = "Bytes";
@@ -859,15 +868,6 @@ function createUtils() {
if (unit) throw Error(`Unit "${unit}" already assigned "${id}"`);
unit = "sd";
}
if (
(!unit || thoroughUnitCheck) &&
(id.endsWith("_size") ||
id.endsWith("_size_sum") ||
id.endsWith("_size_cumulative"))
) {
if (unit) throw Error(`Unit "${unit}" already assigned "${id}"`);
unit = "mb";
}
if (
(!unit || thoroughUnitCheck) &&
(id.includes("vsize") || id.includes("vbytes"))
@@ -921,6 +921,20 @@ function createUtils() {
if (unit) throw Error(`Unit "${unit}" already assigned "${id}"`);
unit = "%mcap";
}
if (
(!unit || thoroughUnitCheck) &&
id.endsWith("relative_to_own_market_cap")
) {
if (unit) throw Error(`Unit "${unit}" already assigned "${id}"`);
unit = "%cmcap";
}
if (
(!unit || thoroughUnitCheck) &&
id.endsWith("relative_to_own_unrealized_profit_plus_loss")
) {
if (unit) throw Error(`Unit "${unit}" already assigned "${id}"`);
unit = "%cp+l";
}
if (
(!unit || thoroughUnitCheck) &&
id.endsWith("relative_to_realized_cap")
@@ -2282,6 +2296,7 @@ function main() {
webSockets,
vecsResources,
vecIdToIndexes,
packages,
}),
),
),
@@ -1068,17 +1068,26 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) {
* @param {number} [args.number]
* @param {string} [args.name]
* @param {boolean} [args.defaultActive]
* @param {number} [args.lineStyle]
* @param {Color} [args.color]
* @param {Unit} args.unit
*/
function createPriceLine({ number = 0, unit, defaultActive, name }) {
function createPriceLine({
number = 0,
unit,
defaultActive,
color,
name,
lineStyle,
}) {
return /** @satisfies {FetchedLineSeriesBlueprint} */ ({
key: `constant_${number >= 0 ? number : `minus_${Math.abs(number)}`}`,
title: name ?? `${number}`,
unit,
defaultActive,
color: colors.gray,
color: color ?? colors.gray,
options: {
lineStyle: 4,
lineStyle: lineStyle ?? 4,
lastValueVisible: false,
crosshairMarkerVisible: false,
},
@@ -1183,7 +1192,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) {
*/
function createSumSeries({ key, title = "", color }) {
return /** @satisfies {AnyFetchedSeriesBlueprint} */ ({
key,
key: key in vecIdToIndexes ? key : `${key}_sum`,
title: `Sum ${title}`,
color: color ?? colors.orange,
});
@@ -1256,14 +1265,23 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) {
]);
}
/**
* @param {VecIdAverageBase & CumulativeVecIdBase & VecIdMinBase & VecIdMaxBase & VecId90pBase & VecId75pBase & VecIdMedianBase & VecId25pBase & VecId10pBase} key
*/
function createSumCumulativeMinMaxPercentilesSeries(key) {
return [
...createSumCumulativeSeries({ concat: key }),
...createMinMaxPercentilesSeries({ concat: key }),
];
}
/**
* @param {VecIdAverageBase & CumulativeVecIdBase & VecIdMinBase & VecIdMaxBase & VecId90pBase & VecId75pBase & VecIdMedianBase & VecId25pBase & VecId10pBase} key
*/
function createAverageSumCumulativeMinMaxPercentilesSeries(key) {
return [
createAverageSeries({ concat: key }),
...createSumCumulativeSeries({ concat: key }),
...createMinMaxPercentilesSeries({ concat: key }),
...createSumCumulativeMinMaxPercentilesSeries(key),
];
}
@@ -1824,6 +1842,16 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) {
name: "Even",
color: colors.yellow,
}),
createPriceLine({
unit: "%self",
number: 100,
lineStyle: 0,
color: colors.default,
}),
createPriceLine({
unit: "%self",
number: 50,
}),
]);
}),
}
@@ -2279,6 +2307,22 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) {
},
},
}),
...(asoprKey in vecIdToIndexes
? [
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: asoprKey,
title: "adjusted",
colors: [colors.yellow, colors.fuchsia],
defaultActive: false,
options: {
baseValue: {
price: 1,
},
},
}),
]
: []),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `${soprKey}_7d_ema`,
@@ -2295,9 +2339,9 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) {
? [
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: asoprKey,
title: "adjusted",
colors: [colors.avocado, colors.pink],
key: `${asoprKey}_7d_ema`,
title: "adj. 7d ema",
colors: [colors.amber, colors.purple],
defaultActive: false,
options: {
baseValue: {
@@ -2305,11 +2349,27 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) {
},
},
}),
]
: []),
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `${soprKey}_30d_ema`,
title: "30d ema",
colors: [colors.avocado, colors.pink],
defaultActive: false,
options: {
baseValue: {
price: 1,
},
},
}),
...(asoprKey in vecIdToIndexes
? [
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `${asoprKey}_7d_ema`,
title: "adj. 7d ema",
colors: [colors.yellow, colors.fuchsia],
key: `${asoprKey}_30d_ema`,
title: "adj. 30d ema",
colors: [colors.orange, colors.violet],
defaultActive: false,
options: {
baseValue: {
@@ -2577,6 +2637,12 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) {
color: colors.red,
defaultActive: false,
}),
createBaseSeries({
key: `${fixKey(key)}sell_side_risk_ratio_30d_ema`,
name: "30d ema",
color: colors.rose,
defaultActive: false,
}),
])
: list.flatMap(({ color, name, key }) => [
createBaseSeries({
@@ -2597,6 +2663,11 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) {
name: "pnl",
title: `Unrealized Profit And Loss ${title}`,
bottom: [
createBaseSeries({
key: `${fixKey(args.key)}unrealized_profit_plus_loss`,
name: "profit+loss",
color: colors.default,
}),
createBaseSeries({
key: `${fixKey(args.key)}unrealized_profit`,
name: "Profit",
@@ -2613,10 +2684,86 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) {
name: "Negative Loss",
color: colors.red,
}),
createBaseSeries({
key: `${fixKey(args.key)}unrealized_profit_relative_to_market_cap`,
name: "Profit",
color: colors.green,
}),
createBaseSeries({
key: `${fixKey(args.key)}unrealized_loss_relative_to_market_cap`,
name: "Loss",
color: colors.red,
defaultActive: false,
}),
createBaseSeries({
key: `${fixKey(args.key)}negative_unrealized_loss_relative_to_market_cap`,
name: "Negative Loss",
color: colors.red,
}),
...(`${fixKey(args.key)}unrealized_profit_relative_to_own_market_cap` in
vecIdToIndexes
? [
createBaseSeries({
key: `${fixKey(args.key)}unrealized_profit_relative_to_own_market_cap`,
name: "Profit",
color: colors.green,
}),
createBaseSeries({
key: `${fixKey(args.key)}unrealized_loss_relative_to_own_market_cap`,
name: "Loss",
color: colors.red,
defaultActive: false,
}),
createBaseSeries({
key: `${fixKey(args.key)}negative_unrealized_loss_relative_to_own_market_cap`,
name: "Negative Loss",
color: colors.red,
}),
createPriceLine({
unit: "%cmcap",
number: 100,
}),
createPriceLine({
unit: "%cmcap",
}),
]
: []),
...(`${fixKey(args.key)}unrealized_profit_relative_to_own_unrealized_profit_plus_loss` in
vecIdToIndexes
? [
createBaseSeries({
key: `${fixKey(args.key)}unrealized_profit_relative_to_own_unrealized_profit_plus_loss`,
name: "Profit",
color: colors.green,
}),
createBaseSeries({
key: `${fixKey(args.key)}unrealized_loss_relative_to_own_unrealized_profit_plus_loss`,
name: "Loss",
color: colors.red,
defaultActive: false,
}),
createBaseSeries({
key: `${fixKey(args.key)}negative_unrealized_loss_relative_to_own_unrealized_profit_plus_loss`,
name: "Negative Loss",
color: colors.red,
}),
createPriceLine({
unit: "%cp+l",
number: 100,
}),
createPriceLine({
unit: "%cp+l",
}),
]
: []),
createPriceLine({
unit: "USD",
defaultActive: false,
}),
createPriceLine({
unit: "%mcap",
defaultActive: false,
}),
],
},
]
@@ -2669,6 +2816,38 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) {
title: useGroupName ? name : "Net",
color: useGroupName ? color : undefined,
}),
...(`${fixKey(key)}net_unrealized_profit_and_loss_relative_to_own_market_cap` in
vecIdToIndexes
? [
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `${fixKey(
key,
)}net_unrealized_profit_and_loss_relative_to_own_market_cap`,
title: useGroupName ? name : "Net",
color: useGroupName ? color : undefined,
}),
createPriceLine({
unit: "%cmcap",
}),
]
: []),
...(`${fixKey(key)}net_unrealized_profit_and_loss_relative_to_own_unrealized_profit_plus_loss` in
vecIdToIndexes
? [
/** @satisfies {FetchedBaselineSeriesBlueprint} */ ({
type: "Baseline",
key: `${fixKey(
key,
)}net_unrealized_profit_and_loss_relative_to_own_unrealized_profit_plus_loss`,
title: useGroupName ? name : "Net",
color: useGroupName ? color : undefined,
}),
createPriceLine({
unit: "%cp+l",
}),
]
: []),
]),
createPriceLine({
unit: "USD",
@@ -3270,33 +3449,29 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) {
bottom: [
createBaseSeries({
key: "total_size",
name: "Size",
}),
...createSumCumulativeSeries({
concat: "block_size",
}),
],
},
{
name: "Bytes",
title: "Block Bytes",
bottom: [
createBaseSeries({
key: "weight",
name: "Weight",
}),
...createSumCumulativeSeries({
concat: "block_weight",
common: "weight",
name: "raw",
}),
createBaseSeries({
key: "vbytes",
name: "Vbytes",
name: "raw",
}),
...createSumCumulativeSeries({
concat: "block_vbytes",
common: "Vbytes",
createBaseSeries({
key: "weight",
name: "raw",
}),
// createBaseSeries({
// key: "weight",
// name: "Weight",
// }),
...createAverageSumCumulativeMinMaxPercentilesSeries(
"block_size",
),
...createAverageSumCumulativeMinMaxPercentilesSeries(
"block_weight",
),
...createAverageSumCumulativeMinMaxPercentilesSeries(
"block_vbytes",
),
],
},
],
@@ -3313,8 +3488,8 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) {
}),
},
{
name: "Bytes",
title: "Transaction Bytes",
name: "Size",
title: "Transaction Size",
bottom: [
createAverageSeries({ concat: "tx_weight", title: "Weight" }),
...createMinMaxPercentilesSeries({
@@ -3824,7 +3999,7 @@ function createPartialOptions({ env, colors, vecIdToIndexes }) {
tree: [
{
name: "Status",
url: () => "https://status.bitcoinresearchkit.org/",
url: () => "https://status.bitview.space/",
},
{
name: "Self",
+5 -7
View File
@@ -35,13 +35,13 @@
chartOptions,
);
const baseURL = "https://bitview.space/api";
const minDate = "2022-11-09";
// const minDate = "2023-11-09";
let dates = await (
await fetch(
"https://next.bitray.xyz/api/vecs/dateindex-to-date?from=-10000",
)
await fetch(`${baseURL}/vecs/dateindex-to-date?from=-10000`)
).json();
let i = 0;
console.log(
@@ -54,9 +54,7 @@
const from = dates.length;
const ohlcs = await (
await fetch(
`https://next.bitray.xyz/api/vecs/dateindex-to-ohlc?from=-${from}`,
)
await fetch(`${baseURL}/vecs/dateindex-to-ohlc?from=-${from}`)
).json();
chart.addSeries(lc.CandlestickSeries, {}, 0).setData(
@@ -74,7 +72,7 @@
const sopr = (
await (
await fetch(
`https://next.bitray.xyz/api/vecs/dateindex-to-utxos-up-to-${cohort}-old-spent-output-profit-ratio?from=-${from}`,
`${baseURL}/vecs/dateindex-to-utxos-up-to-${cohort}-old-spent-output-profit-ratio?from=-${from}`,
)
).json()
).map((v) => v - 1);
-491
View File
@@ -1,491 +0,0 @@
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 on the left and right of the output (populated with 'off' modules) */
padX?: number;
/** the padding to apply on the top and bottom of the output (populated with 'off' modules) */
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 on the left and right of the output (filled with 'off') */
padX?: number;
/** the padding to apply on the top and bottom of the output (filled with 'off') */
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) */
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) */
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.
*/
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 on the left and right of the output (filled with 'off') */
padX?: number;
/** the padding to apply on the top and bottom of the output (filled with 'off') */
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 on the left and right of the output (filled with 'off') */
padX?: number;
/** the padding to apply on the top and bottom of the output (filled with 'off') */
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.
*
* 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.
*
* 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/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;
}
@@ -1,215 +0,0 @@
declare class uFuzzy {
constructor(opts?: uFuzzy.Options);
/** search API composed of filter/info/sort, with a info/ranking threshold (1e3) and fast outOfOrder impl */
search(
haystack: string[],
needle: string,
/** limit how many terms will be permuted, default = 0; 5 will result in up to 5! (120) search iterations. be careful with this! */
outOfOrder?: number,
/** default = 1e3 */
infoThresh?: number,
preFiltered?: uFuzzy.HaystackIdxs | null,
): uFuzzy.SearchResult;
/** initial haystack filter, can accept idxs from previous prefix/typeahead match as optimization */
filter(
haystack: string[],
needle: string,
idxs?: uFuzzy.HaystackIdxs,
): uFuzzy.HaystackIdxs | null;
/** collects stats about pre-filtered matches, does additional filtering based on term boundary settings, finds highlight ranges */
info(
idxs: uFuzzy.HaystackIdxs,
haystack: string[],
needle: string,
): uFuzzy.Info;
/** performs final result sorting via Array.sort(), relying on Info */
sort(
info: uFuzzy.Info,
haystack: string[],
needle: string,
): uFuzzy.InfoIdxOrder;
/** utility for splitting needle into terms following defined interSplit/intraSplit opts. useful for out-of-order permutes */
split(needle: string, keepCase?: boolean): uFuzzy.Terms;
/** util for creating out-of-order permutations of a needle terms array */
static permute(arr: unknown[]): unknown[][];
/** util for replacing common diacritics/accents */
static latinize<T extends string[] | string>(strings: T): T;
/** util for highlighting matched substr parts of a result */
static highlight<TAccum = string, TMarkedPart = string>(
match: string,
ranges: number[],
mark?: (part: string, matched: boolean) => TMarkedPart,
accum?: TAccum,
append?: (accum: TAccum, part: TMarkedPart) => TAccum | undefined,
): TAccum;
}
export = uFuzzy;
declare namespace uFuzzy {
/** needle's terms */
export type Terms = string[];
/** subset of idxs of a haystack array */
export type HaystackIdxs = number[];
/** sorted order in which info facets should be iterated */
export type InfoIdxOrder = number[];
export type AbortedResult = [null, null, null];
export type FilteredResult = [uFuzzy.HaystackIdxs, null, null];
export type RankedResult = [
uFuzzy.HaystackIdxs,
uFuzzy.Info,
uFuzzy.InfoIdxOrder,
];
export type SearchResult = FilteredResult | RankedResult | AbortedResult;
/** partial RegExp */
type PartialRegExp = string;
/** what should be considered acceptable term bounds */
export const enum BoundMode {
/** will match 'man' substr anywhere. e.g. tasmania */
Any = 0,
/** will match 'man' at whitespace, punct, case-change, and alpha-num boundaries. e.g. mantis, SuperMan, fooManBar, 0007man */
Loose = 1,
/** will match 'man' at whitespace, punct boundaries only. e.g. mega man, walk_man, man-made, foo.man.bar */
Strict = 2,
}
export const enum IntraMode {
/** allows any number of extra char insertions within a term, but all term chars must be present for a match */
MultiInsert = 0,
/** allows for a single-char substitution, transposition, insertion, or deletion within terms (excluding first and last chars) */
SingleError = 1,
}
export type IntraSliceIdxs = [from: number, to: number];
type CompareFn = (a: string, b: string) => number;
export interface Options {
// whether regexps use a /u unicode flag
unicode?: boolean; // false
/** @deprecated renamed to opts.alpha */
letters?: PartialRegExp | null; // a-z
// regexp character class [] of chars which should be treated as letters (case insensitive)
alpha?: PartialRegExp | null; // a-z
/** term segmentation & punct/whitespace merging */
interSplit?: PartialRegExp; // '[^A-Za-z\\d']+'
intraSplit?: PartialRegExp | null; // '[a-z][A-Z]'
/** inter bounds that will be used to increase lft2/rgt2 info counters */
interBound?: PartialRegExp | null; // '[^A-Za-z\\d]'
/** intra bounds that will be used to increase lft1/rgt1 info counters */
intraBound?: PartialRegExp | null; // '[A-Za-z][0-9]|[0-9][A-Za-z]|[a-z][A-Z]'
/** inter-term modes, during .info() can discard matches when bounds conditions are not met */
interLft?: BoundMode; // 0
interRgt?: BoundMode; // 0
/** allowance between terms */
interChars?: PartialRegExp; // '.'
interIns?: number; // Infinity
/** allowance between chars within terms */
intraChars?: PartialRegExp; // '[a-z\\d]'
intraIns?: number; // 0
/** contractions detection */
intraContr?: PartialRegExp; // "'[a-z]{1,2}\\b"
/** error tolerance mode within terms. will clamp intraIns to 1 when set to SingleError */
intraMode?: IntraMode; // 0
/** which part of each term should tolerate errors (when intraMode: 1) */
intraSlice?: IntraSliceIdxs; // [1, Infinity]
/** max substitutions (when intraMode: 1) */
intraSub?: 0 | 1; // 0
/** max transpositions (when intraMode: 1) */
intraTrn?: 0 | 1; // 0
/** max omissions/deletions (when intraMode: 1) */
intraDel?: 0 | 1; // 0
/** can dynamically adjust error tolerance rules per term in needle (when intraMode: 1) */
intraRules?: (term: string) => {
intraSlice?: IntraSliceIdxs;
intraIns: 0 | 1;
intraSub: 0 | 1;
intraTrn: 0 | 1;
intraDel: 0 | 1;
};
/** post-filters matches during .info() based on cmp of term in needle vs partial match */
intraFilt?: (term: string, match: string, index: number) => boolean; // should this also accept WIP info?
/** default: toLocaleUpperCase() */
toUpper?: (str: string) => string;
/** default: toLocaleLowerCase() */
toLower?: (str: string) => string;
/** final sorting cmp when all other match metrics are equal */
compare?: CompareFn;
sort?: (
info: Info,
haystack: string[],
needle: string,
compare?: CompareFn,
) => InfoIdxOrder;
}
export interface Info {
/** matched idxs from haystack */
idx: HaystackIdxs;
/** match offsets */
start: number[];
/** number of left BoundMode.Strict term boundaries found */
interLft2: number[];
/** number of right BoundMode.Strict term boundaries found */
interRgt2: number[];
/** number of left BoundMode.Loose term boundaries found */
interLft1: number[];
/** number of right BoundMode.Loose term boundaries found */
interRgt1: number[];
/** total number of extra chars matched within all terms. higher = matched terms have more fuzz in them */
intraIns: number[];
/** total number of chars found in between matched terms. higher = terms are more sparse, have more fuzz in between them */
interIns: number[];
/** total number of matched contiguous chars (substrs but not necessarily full terms) */
chars: number[];
/** number of exactly-matched terms (intra = 0) where both lft and rgt landed on a BoundMode.Loose or BoundMode.Strict boundary */
terms: number[];
/** number of needle terms with case-sensitive partial matches */
cases: number[];
/** offset ranges within match for highlighting: [startIdx0, endIdx0, startIdx1, endIdx1,...] */
ranges: number[][];
}
}
export as namespace uFuzzy;
File diff suppressed because it is too large Load Diff
@@ -1,21 +0,0 @@
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): boolean;
}
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;
@@ -1,14 +0,0 @@
/**
* 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;
@@ -1,157 +0,0 @@
/**
* 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";
export interface SignalOptions<T> {
id?: string;
name?: string;
equals?: ((prev: T, next: T) => boolean) | false;
pureWrite?: boolean;
unobserved?: () => void;
}
interface SourceType {
_observers: ObserverType[] | null;
_unobserved?: () => void;
_updateIfNecessary: () => void;
_stateFlags: Flags;
_time: number;
}
interface ObserverType {
_sources: SourceType[] | null;
_notify: (state: number, skipQueue?: boolean) => void;
_handlerMask: Flags;
_notifyFlags: (mask: Flags, newFlags: Flags) => void;
_time: number;
}
/**
* 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;
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;
export {};
@@ -1,37 +0,0 @@
import { EFFECT_RENDER, EFFECT_USER } from "./constants.js";
import { Computation, type SignalOptions } from "./core.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;
_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;
}
@@ -1,8 +0,0 @@
export declare class NotReadyError extends Error {
}
export declare class NoOwnerError extends Error {
constructor();
}
export declare class ContextNotFoundError extends Error {
constructor();
}

Some files were not shown because too many files have changed in this diff Show More