create-sia-app 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +179 -0
  3. package/package.json +29 -0
  4. package/template/CLAUDE.md +160 -0
  5. package/template/README.md +102 -0
  6. package/template/_gitignore +5 -0
  7. package/template/biome.json +40 -0
  8. package/template/index.html +13 -0
  9. package/template/package.json +30 -0
  10. package/template/rust/README.md +16 -0
  11. package/template/rust/sia-sdk-rs/.changeset/added_cancel_function_to_cancel_inflight_packed_uploads.md +6 -0
  12. package/template/rust/sia-sdk-rs/.changeset/check_if_we_have_enough_hosts_prior_to_encoding_in_upload_slabs.md +16 -0
  13. package/template/rust/sia-sdk-rs/.changeset/fix_slab_length_in_packed_object.md +5 -0
  14. package/template/rust/sia-sdk-rs/.changeset/fix_upload_racing_race_conditon.md +13 -0
  15. package/template/rust/sia-sdk-rs/.changeset/improved_parallelism_of_packed_uploads.md +5 -0
  16. package/template/rust/sia-sdk-rs/.changeset/progress_callback_will_now_be_called_as_expected_for_packed_uploads.md +5 -0
  17. package/template/rust/sia-sdk-rs/.github/dependabot.yml +10 -0
  18. package/template/rust/sia-sdk-rs/.github/workflows/main.yml +36 -0
  19. package/template/rust/sia-sdk-rs/.github/workflows/prepare-release.yml +34 -0
  20. package/template/rust/sia-sdk-rs/.github/workflows/release.yml +30 -0
  21. package/template/rust/sia-sdk-rs/.rustfmt.toml +4 -0
  22. package/template/rust/sia-sdk-rs/Cargo.lock +4127 -0
  23. package/template/rust/sia-sdk-rs/Cargo.toml +3 -0
  24. package/template/rust/sia-sdk-rs/LICENSE +21 -0
  25. package/template/rust/sia-sdk-rs/README.md +30 -0
  26. package/template/rust/sia-sdk-rs/indexd/CHANGELOG.md +79 -0
  27. package/template/rust/sia-sdk-rs/indexd/Cargo.toml +79 -0
  28. package/template/rust/sia-sdk-rs/indexd/benches/upload.rs +258 -0
  29. package/template/rust/sia-sdk-rs/indexd/src/app_client.rs +1710 -0
  30. package/template/rust/sia-sdk-rs/indexd/src/builder.rs +354 -0
  31. package/template/rust/sia-sdk-rs/indexd/src/download.rs +379 -0
  32. package/template/rust/sia-sdk-rs/indexd/src/hosts.rs +659 -0
  33. package/template/rust/sia-sdk-rs/indexd/src/lib.rs +827 -0
  34. package/template/rust/sia-sdk-rs/indexd/src/mock.rs +162 -0
  35. package/template/rust/sia-sdk-rs/indexd/src/object_encryption.rs +125 -0
  36. package/template/rust/sia-sdk-rs/indexd/src/quic.rs +575 -0
  37. package/template/rust/sia-sdk-rs/indexd/src/rhp4.rs +52 -0
  38. package/template/rust/sia-sdk-rs/indexd/src/slabs.rs +497 -0
  39. package/template/rust/sia-sdk-rs/indexd/src/upload.rs +629 -0
  40. package/template/rust/sia-sdk-rs/indexd/src/wasm_time.rs +41 -0
  41. package/template/rust/sia-sdk-rs/indexd/src/web_transport.rs +398 -0
  42. package/template/rust/sia-sdk-rs/indexd_ffi/CHANGELOG.md +76 -0
  43. package/template/rust/sia-sdk-rs/indexd_ffi/Cargo.toml +47 -0
  44. package/template/rust/sia-sdk-rs/indexd_ffi/examples/python/README.md +10 -0
  45. package/template/rust/sia-sdk-rs/indexd_ffi/examples/python/example.py +130 -0
  46. package/template/rust/sia-sdk-rs/indexd_ffi/src/bin/uniffi-bindgen.rs +3 -0
  47. package/template/rust/sia-sdk-rs/indexd_ffi/src/builder.rs +377 -0
  48. package/template/rust/sia-sdk-rs/indexd_ffi/src/io.rs +155 -0
  49. package/template/rust/sia-sdk-rs/indexd_ffi/src/lib.rs +1039 -0
  50. package/template/rust/sia-sdk-rs/indexd_ffi/src/logging.rs +58 -0
  51. package/template/rust/sia-sdk-rs/indexd_ffi/src/tls.rs +23 -0
  52. package/template/rust/sia-sdk-rs/indexd_wasm/Cargo.toml +33 -0
  53. package/template/rust/sia-sdk-rs/indexd_wasm/src/lib.rs +818 -0
  54. package/template/rust/sia-sdk-rs/knope.toml +54 -0
  55. package/template/rust/sia-sdk-rs/sia_derive/CHANGELOG.md +38 -0
  56. package/template/rust/sia-sdk-rs/sia_derive/Cargo.toml +19 -0
  57. package/template/rust/sia-sdk-rs/sia_derive/src/lib.rs +278 -0
  58. package/template/rust/sia-sdk-rs/sia_sdk/CHANGELOG.md +91 -0
  59. package/template/rust/sia-sdk-rs/sia_sdk/Cargo.toml +59 -0
  60. package/template/rust/sia-sdk-rs/sia_sdk/benches/merkle_root.rs +12 -0
  61. package/template/rust/sia-sdk-rs/sia_sdk/src/blake2.rs +22 -0
  62. package/template/rust/sia-sdk-rs/sia_sdk/src/consensus.rs +767 -0
  63. package/template/rust/sia-sdk-rs/sia_sdk/src/encoding/v1.rs +257 -0
  64. package/template/rust/sia-sdk-rs/sia_sdk/src/encoding/v2.rs +291 -0
  65. package/template/rust/sia-sdk-rs/sia_sdk/src/encoding.rs +26 -0
  66. package/template/rust/sia-sdk-rs/sia_sdk/src/encoding_async/v2.rs +367 -0
  67. package/template/rust/sia-sdk-rs/sia_sdk/src/encoding_async.rs +6 -0
  68. package/template/rust/sia-sdk-rs/sia_sdk/src/encryption.rs +303 -0
  69. package/template/rust/sia-sdk-rs/sia_sdk/src/erasure_coding.rs +347 -0
  70. package/template/rust/sia-sdk-rs/sia_sdk/src/lib.rs +15 -0
  71. package/template/rust/sia-sdk-rs/sia_sdk/src/macros.rs +435 -0
  72. package/template/rust/sia-sdk-rs/sia_sdk/src/merkle.rs +112 -0
  73. package/template/rust/sia-sdk-rs/sia_sdk/src/rhp/merkle.rs +357 -0
  74. package/template/rust/sia-sdk-rs/sia_sdk/src/rhp/rpc.rs +1507 -0
  75. package/template/rust/sia-sdk-rs/sia_sdk/src/rhp/types.rs +146 -0
  76. package/template/rust/sia-sdk-rs/sia_sdk/src/rhp.rs +7 -0
  77. package/template/rust/sia-sdk-rs/sia_sdk/src/seed.rs +278 -0
  78. package/template/rust/sia-sdk-rs/sia_sdk/src/signing.rs +236 -0
  79. package/template/rust/sia-sdk-rs/sia_sdk/src/types/common.rs +677 -0
  80. package/template/rust/sia-sdk-rs/sia_sdk/src/types/currency.rs +450 -0
  81. package/template/rust/sia-sdk-rs/sia_sdk/src/types/specifier.rs +110 -0
  82. package/template/rust/sia-sdk-rs/sia_sdk/src/types/spendpolicy.rs +778 -0
  83. package/template/rust/sia-sdk-rs/sia_sdk/src/types/utils.rs +117 -0
  84. package/template/rust/sia-sdk-rs/sia_sdk/src/types/v1.rs +1737 -0
  85. package/template/rust/sia-sdk-rs/sia_sdk/src/types/v2.rs +1726 -0
  86. package/template/rust/sia-sdk-rs/sia_sdk/src/types/work.rs +59 -0
  87. package/template/rust/sia-sdk-rs/sia_sdk/src/types.rs +16 -0
  88. package/template/scripts/setup-rust.js +29 -0
  89. package/template/src/App.tsx +13 -0
  90. package/template/src/components/DevNote.tsx +21 -0
  91. package/template/src/components/auth/ApproveScreen.tsx +84 -0
  92. package/template/src/components/auth/AuthFlow.tsx +77 -0
  93. package/template/src/components/auth/ConnectScreen.tsx +214 -0
  94. package/template/src/components/auth/LoadingScreen.tsx +8 -0
  95. package/template/src/components/auth/RecoveryScreen.tsx +182 -0
  96. package/template/src/components/upload/UploadZone.tsx +314 -0
  97. package/template/src/index.css +9 -0
  98. package/template/src/lib/constants.ts +8 -0
  99. package/template/src/lib/format.ts +35 -0
  100. package/template/src/lib/hex.ts +13 -0
  101. package/template/src/lib/sdk.ts +25 -0
  102. package/template/src/lib/wasm-env.ts +5 -0
  103. package/template/src/main.tsx +12 -0
  104. package/template/src/stores/auth.ts +86 -0
  105. package/template/tsconfig.app.json +31 -0
  106. package/template/tsconfig.json +7 -0
  107. package/template/tsconfig.node.json +26 -0
  108. package/template/vite.config.ts +18 -0
  109. package/template/wasm/indexd_wasm/indexd_wasm.d.ts +309 -0
  110. package/template/wasm/indexd_wasm/indexd_wasm.js +1507 -0
  111. package/template/wasm/indexd_wasm/indexd_wasm_bg.wasm +0 -0
  112. package/template/wasm/indexd_wasm/package.json +31 -0
@@ -0,0 +1,162 @@
1
+ use std::collections::{HashMap, HashSet};
2
+ use std::sync::{Arc, RwLock};
3
+ use std::time::Duration;
4
+
5
+ use bytes::Bytes;
6
+ use chrono::Utc;
7
+ use sia::rhp::{self, HostPrices};
8
+ use sia::signing::{PrivateKey, PublicKey, Signature};
9
+ use sia::types::{Currency, Hash256};
10
+ use tokio::io::{AsyncReadExt, AsyncWriteExt};
11
+ use tokio::time::sleep;
12
+
13
+ use crate::rhp4::{self, RHP4Client};
14
+ use crate::{
15
+ DownloadError, DownloadOptions, Downloader, Hosts, Object, PackedUpload, UploadError,
16
+ UploadOptions, Uploader,
17
+ };
18
+
19
+ pub struct MockRHP4Client {
20
+ sectors: RwLock<HashMap<PublicKey, HashMap<Hash256, Bytes>>>,
21
+ slow_hosts: RwLock<HashSet<PublicKey>>,
22
+ slow_delay: RwLock<Duration>,
23
+ }
24
+
25
+ impl MockRHP4Client {
26
+ pub fn new() -> Self {
27
+ Self {
28
+ sectors: RwLock::new(HashMap::new()),
29
+ slow_hosts: RwLock::new(HashSet::new()),
30
+ slow_delay: RwLock::new(Duration::ZERO),
31
+ }
32
+ }
33
+
34
+ pub fn clear(&self) {
35
+ self.sectors.write().unwrap().clear();
36
+ }
37
+
38
+ /// Sets the given hosts as "slow" - they will sleep for the specified duration
39
+ /// before completing any write_sector or read_sector operation.
40
+ pub fn set_slow_hosts(&self, hosts: impl IntoIterator<Item = PublicKey>, delay: Duration) {
41
+ let mut slow = self.slow_hosts.write().unwrap();
42
+ slow.clear();
43
+ slow.extend(hosts);
44
+ *self.slow_delay.write().unwrap() = delay;
45
+ }
46
+
47
+ /// Clears all slow host settings.
48
+ pub fn reset_slow_hosts(&self) {
49
+ self.slow_hosts.write().unwrap().clear();
50
+ *self.slow_delay.write().unwrap() = Duration::ZERO;
51
+ }
52
+ }
53
+
54
+ impl RHP4Client for Arc<MockRHP4Client> {
55
+ async fn host_prices(&self, _: PublicKey, _: bool) -> Result<HostPrices, rhp4::Error> {
56
+ Ok(HostPrices {
57
+ contract_price: Currency::zero(),
58
+ collateral: Currency::zero(),
59
+ ingress_price: Currency::zero(),
60
+ egress_price: Currency::zero(),
61
+ storage_price: Currency::zero(),
62
+ free_sector_price: Currency::zero(),
63
+ tip_height: 0,
64
+ signature: Signature::default(),
65
+ valid_until: Utc::now() + chrono::Duration::days(1),
66
+ })
67
+ }
68
+
69
+ async fn write_sector(
70
+ &self,
71
+ host_key: PublicKey,
72
+ _: &PrivateKey,
73
+ sector: Bytes,
74
+ ) -> Result<Hash256, rhp4::Error> {
75
+ // Check if this host is configured as slow
76
+ let slow_delay = {
77
+ let slow_hosts = self.slow_hosts.read().unwrap();
78
+ if slow_hosts.contains(&host_key) {
79
+ Some(*self.slow_delay.read().unwrap())
80
+ } else {
81
+ None
82
+ }
83
+ };
84
+ if let Some(delay) = slow_delay {
85
+ sleep(delay).await;
86
+ }
87
+
88
+ sleep(Duration::from_millis(3)).await; // simulate network latency ~ 10Gbps
89
+ let sector_root = rhp::sector_root(&sector);
90
+ let mut sectors = self.sectors.write().unwrap();
91
+ let host_sectors = sectors.entry(host_key).or_default();
92
+ host_sectors.insert(sector_root, sector);
93
+ Ok(sector_root)
94
+ }
95
+
96
+ async fn read_sector(
97
+ &self,
98
+ host_key: PublicKey,
99
+ _: &PrivateKey,
100
+ root: Hash256,
101
+ offset: usize,
102
+ length: usize,
103
+ ) -> Result<Bytes, rhp4::Error> {
104
+ let sector = {
105
+ let sectors = self.sectors.read().unwrap();
106
+ let host_sectors = sectors
107
+ .get(&host_key)
108
+ .ok_or_else(|| rhp4::Error::Transport("host not found".to_string()))?;
109
+ let sector = host_sectors
110
+ .get(&root)
111
+ .ok_or_else(|| rhp4::Error::Transport("sector not found".to_string()))?;
112
+ sector.slice(offset..offset + length)
113
+ };
114
+ sleep(Duration::from_nanos(sector.len() as u64 * 8 / 10)).await; // simulate network latency ~ 10Gbps
115
+ Ok(sector)
116
+ }
117
+ }
118
+
119
+ pub struct MockUploader {
120
+ uploader: Uploader<Arc<MockRHP4Client>>,
121
+ }
122
+
123
+ impl MockUploader {
124
+ pub fn new(hosts: Hosts, client: Arc<MockRHP4Client>, app_key: Arc<PrivateKey>) -> Self {
125
+ Self {
126
+ uploader: Uploader::new(hosts, client.clone(), app_key),
127
+ }
128
+ }
129
+
130
+ pub async fn upload<R: AsyncReadExt + Send + Sync + Unpin + 'static>(
131
+ &self,
132
+ r: R,
133
+ options: UploadOptions,
134
+ ) -> Result<Object, UploadError> {
135
+ self.uploader.upload(r, options).await
136
+ }
137
+
138
+ pub fn upload_packed(&self, options: UploadOptions) -> PackedUpload {
139
+ self.uploader.upload_packed(options)
140
+ }
141
+ }
142
+
143
+ pub struct MockDownloader {
144
+ downloader: Downloader<Arc<MockRHP4Client>>,
145
+ }
146
+
147
+ impl MockDownloader {
148
+ pub fn new(hosts: Hosts, client: Arc<MockRHP4Client>, app_key: Arc<PrivateKey>) -> Self {
149
+ Self {
150
+ downloader: Downloader::new(hosts, client.clone(), app_key),
151
+ }
152
+ }
153
+
154
+ pub async fn download<W: AsyncWriteExt + Send + Sync + Unpin>(
155
+ &self,
156
+ w: &mut W,
157
+ object: &Object,
158
+ options: DownloadOptions,
159
+ ) -> Result<(), DownloadError> {
160
+ self.downloader.download(w, object, options).await
161
+ }
162
+ }
@@ -0,0 +1,125 @@
1
+ use chacha20poly1305::aead::{Aead, OsRng};
2
+ use chacha20poly1305::{AeadCore, KeyInit, XChaCha20Poly1305};
3
+ use sia::blake2::Blake2b256;
4
+ use sia::encryption::EncryptionKey;
5
+ use sia::signing::PrivateKey;
6
+ use sia::types::Hash256;
7
+ use thiserror::Error;
8
+
9
+ const NONCE_SIZE: usize = 24;
10
+
11
+ #[derive(Error, Debug)]
12
+ pub enum DecryptError {
13
+ #[error("decryption error")]
14
+ Decryption,
15
+ #[error("invalid encryption key length")]
16
+ KeyLength,
17
+ }
18
+
19
+ pub(crate) fn derive(key: &[u8], salt: &[u8], domain: &[u8], okm: &mut [u8]) {
20
+ let hkdf = hkdf::SimpleHkdf::<Blake2b256>::new(Some(salt), key);
21
+ hkdf.expand(domain, okm).unwrap();
22
+ }
23
+
24
+ pub(crate) fn derive_encryption_key(key: &[u8], salt: &[u8], domain: &[u8]) -> EncryptionKey {
25
+ let hkdf = hkdf::SimpleHkdf::<Blake2b256>::new(Some(salt), key);
26
+ let mut okm = [0u8; 32];
27
+ hkdf.expand(domain, &mut okm).unwrap();
28
+ okm.into()
29
+ }
30
+
31
+ pub(crate) fn seal_data_key(
32
+ app_key: &PrivateKey,
33
+ object_id: &Hash256,
34
+ encryption_key: &EncryptionKey,
35
+ ) -> Vec<u8> {
36
+ let data_encryption_key =
37
+ derive_encryption_key(app_key.as_ref(), object_id.as_ref(), b"dataKey");
38
+ let encryption_key_cipher = XChaCha20Poly1305::new(data_encryption_key.as_ref().into());
39
+ let nonce = XChaCha20Poly1305::generate_nonce(&mut OsRng);
40
+ let encrypted_data_key = encryption_key_cipher
41
+ .encrypt(&nonce, encryption_key.as_ref().as_ref())
42
+ .expect("encryption failed");
43
+ [nonce.to_vec(), encrypted_data_key].concat()
44
+ }
45
+
46
+ pub(crate) fn seal_metadata_key(
47
+ app_key: &PrivateKey,
48
+ object_id: &Hash256,
49
+ encryption_key: &EncryptionKey,
50
+ ) -> Vec<u8> {
51
+ let meta_encryption_key =
52
+ derive_encryption_key(app_key.as_ref(), object_id.as_ref(), b"metadataKey");
53
+ let encryption_key_cipher = XChaCha20Poly1305::new(meta_encryption_key.as_ref().into());
54
+ let nonce = XChaCha20Poly1305::generate_nonce(&mut OsRng);
55
+ let encrypted_meta_key = encryption_key_cipher
56
+ .encrypt(&nonce, encryption_key.as_ref().as_ref())
57
+ .expect("encryption failed");
58
+ [nonce.to_vec(), encrypted_meta_key].concat()
59
+ }
60
+
61
+ pub(crate) fn open_data_key(
62
+ app_key: &PrivateKey,
63
+ object_id: &Hash256,
64
+ encrypted_data_key: &[u8],
65
+ ) -> Result<EncryptionKey, DecryptError> {
66
+ if encrypted_data_key.len() < NONCE_SIZE {
67
+ return Err(DecryptError::Decryption);
68
+ }
69
+ let data_encryption_key =
70
+ derive_encryption_key(app_key.as_ref(), object_id.as_ref(), b"dataKey");
71
+ let encryption_key_cipher = XChaCha20Poly1305::new(data_encryption_key.as_ref().into());
72
+ let (nonce_bytes, ciphertext) = encrypted_data_key.split_at(NONCE_SIZE);
73
+ let nonce_bytes: [u8; 24] = nonce_bytes.try_into().unwrap(); // safe due to length check above
74
+ let nonce = chacha20poly1305::XNonce::from(nonce_bytes);
75
+ let decrypted_data_key = encryption_key_cipher
76
+ .decrypt(&nonce, ciphertext)
77
+ .map_err(|_| DecryptError::Decryption)?;
78
+ EncryptionKey::try_from(decrypted_data_key.as_ref()).map_err(|_| DecryptError::KeyLength)
79
+ }
80
+
81
+ pub(crate) fn open_metadata_key(
82
+ app_key: &PrivateKey,
83
+ object_id: &Hash256,
84
+ encrypted_meta_key: &[u8],
85
+ ) -> Result<EncryptionKey, DecryptError> {
86
+ if encrypted_meta_key.len() < NONCE_SIZE {
87
+ return Err(DecryptError::Decryption);
88
+ }
89
+ let meta_encryption_key =
90
+ derive_encryption_key(app_key.as_ref(), object_id.as_ref(), b"metadataKey");
91
+ let encryption_key_cipher = XChaCha20Poly1305::new(meta_encryption_key.as_ref().into());
92
+ let (nonce_bytes, ciphertext) = encrypted_meta_key.split_at(NONCE_SIZE);
93
+ let nonce_bytes: [u8; 24] = nonce_bytes.try_into().unwrap(); // safe due to length check above
94
+ let nonce = chacha20poly1305::XNonce::from(nonce_bytes);
95
+ let decrypted_meta_key = encryption_key_cipher
96
+ .decrypt(&nonce, ciphertext)
97
+ .map_err(|_| DecryptError::Decryption)?;
98
+ EncryptionKey::try_from(decrypted_meta_key.as_ref()).map_err(|_| DecryptError::KeyLength)
99
+ }
100
+
101
+ pub(crate) fn seal_metadata(meta_key: &EncryptionKey, metadata: &[u8]) -> Vec<u8> {
102
+ let metadata_cipher = XChaCha20Poly1305::new(meta_key.as_ref().into());
103
+ let nonce = XChaCha20Poly1305::generate_nonce(&mut OsRng);
104
+ let encrypted_metadata = metadata_cipher
105
+ .encrypt(&nonce, metadata)
106
+ .expect("encryption failed");
107
+ [nonce.to_vec(), encrypted_metadata].concat()
108
+ }
109
+
110
+ pub(crate) fn open_metadata(
111
+ meta_key: &EncryptionKey,
112
+ encrypted_metadata: &[u8],
113
+ ) -> Result<Vec<u8>, DecryptError> {
114
+ if encrypted_metadata.len() < NONCE_SIZE {
115
+ return Err(DecryptError::Decryption);
116
+ }
117
+ let metadata_cipher = XChaCha20Poly1305::new(meta_key.as_ref().into());
118
+ let (nonce_bytes, ciphertext) = encrypted_metadata.split_at(NONCE_SIZE);
119
+ let nonce_bytes: [u8; 24] = nonce_bytes.try_into().unwrap(); // safe due to length check above
120
+ let nonce = chacha20poly1305::XNonce::from(nonce_bytes);
121
+ let decrypted_metadata = metadata_cipher
122
+ .decrypt(&nonce, ciphertext)
123
+ .map_err(|_| DecryptError::Decryption)?;
124
+ Ok(decrypted_metadata)
125
+ }