create-sia-app 0.1.7 → 0.1.9

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 (114) hide show
  1. package/package.json +2 -6
  2. package/template/AGENTS.md +143 -0
  3. package/template/CLAUDE.md +25 -46
  4. package/template/README.md +6 -12
  5. package/template/_gitignore +0 -1
  6. package/template/dist/assets/index-BEylY2j7.css +1 -0
  7. package/template/dist/assets/index-CnYqArKN.js +8741 -0
  8. package/template/dist/assets/sia_bg-BTOHUC1A.wasm +0 -0
  9. package/template/dist/assets/slab-download-worker-DhW6ZBJs.js +2 -0
  10. package/template/dist/assets/slab-upload-worker-B2uSB2iY.js +2 -0
  11. package/template/dist/index.html +13 -0
  12. package/template/e2e/smoke.spec.ts +20 -0
  13. package/template/index.html +0 -1
  14. package/template/package.json +2 -2
  15. package/template/playwright.config.ts +13 -0
  16. package/template/src/components/Navbar.tsx +3 -3
  17. package/template/src/components/auth/ApproveScreen.tsx +10 -13
  18. package/template/src/components/auth/AuthFlow.tsx +13 -10
  19. package/template/src/components/auth/ConnectScreen.tsx +2 -3
  20. package/template/src/components/auth/RecoveryScreen.tsx +7 -7
  21. package/template/src/components/upload/UploadZone.tsx +192 -74
  22. package/template/src/index.css +14 -4
  23. package/template/src/stores/auth.ts +6 -12
  24. package/template/test-results/.last-run.json +4 -0
  25. package/template/tsconfig.app.json +1 -1
  26. package/template/tsconfig.node.json +0 -1
  27. package/template/vite.config.ts +2 -3
  28. package/template/rust/README.md +0 -16
  29. package/template/rust/sia-sdk-rs/.changeset/added_cancel_function_to_cancel_inflight_packed_uploads.md +0 -6
  30. package/template/rust/sia-sdk-rs/.changeset/check_if_we_have_enough_hosts_prior_to_encoding_in_upload_slabs.md +0 -16
  31. package/template/rust/sia-sdk-rs/.changeset/fix_slab_length_in_packed_object.md +0 -5
  32. package/template/rust/sia-sdk-rs/.changeset/fix_upload_racing_race_conditon.md +0 -13
  33. package/template/rust/sia-sdk-rs/.changeset/improved_parallelism_of_packed_uploads.md +0 -5
  34. package/template/rust/sia-sdk-rs/.changeset/progress_callback_will_now_be_called_as_expected_for_packed_uploads.md +0 -5
  35. package/template/rust/sia-sdk-rs/.github/dependabot.yml +0 -10
  36. package/template/rust/sia-sdk-rs/.github/workflows/main.yml +0 -36
  37. package/template/rust/sia-sdk-rs/.github/workflows/prepare-release.yml +0 -34
  38. package/template/rust/sia-sdk-rs/.github/workflows/release.yml +0 -30
  39. package/template/rust/sia-sdk-rs/.rustfmt.toml +0 -4
  40. package/template/rust/sia-sdk-rs/Cargo.lock +0 -4127
  41. package/template/rust/sia-sdk-rs/Cargo.toml +0 -3
  42. package/template/rust/sia-sdk-rs/LICENSE +0 -21
  43. package/template/rust/sia-sdk-rs/README.md +0 -30
  44. package/template/rust/sia-sdk-rs/indexd/CHANGELOG.md +0 -79
  45. package/template/rust/sia-sdk-rs/indexd/Cargo.toml +0 -79
  46. package/template/rust/sia-sdk-rs/indexd/benches/upload.rs +0 -258
  47. package/template/rust/sia-sdk-rs/indexd/src/app_client.rs +0 -1710
  48. package/template/rust/sia-sdk-rs/indexd/src/builder.rs +0 -354
  49. package/template/rust/sia-sdk-rs/indexd/src/download.rs +0 -379
  50. package/template/rust/sia-sdk-rs/indexd/src/hosts.rs +0 -659
  51. package/template/rust/sia-sdk-rs/indexd/src/lib.rs +0 -827
  52. package/template/rust/sia-sdk-rs/indexd/src/mock.rs +0 -162
  53. package/template/rust/sia-sdk-rs/indexd/src/object_encryption.rs +0 -125
  54. package/template/rust/sia-sdk-rs/indexd/src/quic.rs +0 -575
  55. package/template/rust/sia-sdk-rs/indexd/src/rhp4.rs +0 -52
  56. package/template/rust/sia-sdk-rs/indexd/src/slabs.rs +0 -497
  57. package/template/rust/sia-sdk-rs/indexd/src/upload.rs +0 -629
  58. package/template/rust/sia-sdk-rs/indexd/src/wasm_time.rs +0 -41
  59. package/template/rust/sia-sdk-rs/indexd/src/web_transport.rs +0 -398
  60. package/template/rust/sia-sdk-rs/indexd_ffi/CHANGELOG.md +0 -76
  61. package/template/rust/sia-sdk-rs/indexd_ffi/Cargo.toml +0 -47
  62. package/template/rust/sia-sdk-rs/indexd_ffi/examples/python/README.md +0 -10
  63. package/template/rust/sia-sdk-rs/indexd_ffi/examples/python/example.py +0 -130
  64. package/template/rust/sia-sdk-rs/indexd_ffi/src/bin/uniffi-bindgen.rs +0 -3
  65. package/template/rust/sia-sdk-rs/indexd_ffi/src/builder.rs +0 -377
  66. package/template/rust/sia-sdk-rs/indexd_ffi/src/io.rs +0 -155
  67. package/template/rust/sia-sdk-rs/indexd_ffi/src/lib.rs +0 -1039
  68. package/template/rust/sia-sdk-rs/indexd_ffi/src/logging.rs +0 -58
  69. package/template/rust/sia-sdk-rs/indexd_ffi/src/tls.rs +0 -23
  70. package/template/rust/sia-sdk-rs/indexd_wasm/Cargo.toml +0 -33
  71. package/template/rust/sia-sdk-rs/indexd_wasm/src/lib.rs +0 -818
  72. package/template/rust/sia-sdk-rs/knope.toml +0 -54
  73. package/template/rust/sia-sdk-rs/sia_derive/CHANGELOG.md +0 -38
  74. package/template/rust/sia-sdk-rs/sia_derive/Cargo.toml +0 -19
  75. package/template/rust/sia-sdk-rs/sia_derive/src/lib.rs +0 -278
  76. package/template/rust/sia-sdk-rs/sia_sdk/CHANGELOG.md +0 -91
  77. package/template/rust/sia-sdk-rs/sia_sdk/Cargo.toml +0 -59
  78. package/template/rust/sia-sdk-rs/sia_sdk/benches/merkle_root.rs +0 -12
  79. package/template/rust/sia-sdk-rs/sia_sdk/src/blake2.rs +0 -22
  80. package/template/rust/sia-sdk-rs/sia_sdk/src/consensus.rs +0 -767
  81. package/template/rust/sia-sdk-rs/sia_sdk/src/encoding/v1.rs +0 -257
  82. package/template/rust/sia-sdk-rs/sia_sdk/src/encoding/v2.rs +0 -291
  83. package/template/rust/sia-sdk-rs/sia_sdk/src/encoding.rs +0 -26
  84. package/template/rust/sia-sdk-rs/sia_sdk/src/encoding_async/v2.rs +0 -367
  85. package/template/rust/sia-sdk-rs/sia_sdk/src/encoding_async.rs +0 -6
  86. package/template/rust/sia-sdk-rs/sia_sdk/src/encryption.rs +0 -303
  87. package/template/rust/sia-sdk-rs/sia_sdk/src/erasure_coding.rs +0 -347
  88. package/template/rust/sia-sdk-rs/sia_sdk/src/lib.rs +0 -15
  89. package/template/rust/sia-sdk-rs/sia_sdk/src/macros.rs +0 -435
  90. package/template/rust/sia-sdk-rs/sia_sdk/src/merkle.rs +0 -112
  91. package/template/rust/sia-sdk-rs/sia_sdk/src/rhp/merkle.rs +0 -357
  92. package/template/rust/sia-sdk-rs/sia_sdk/src/rhp/rpc.rs +0 -1507
  93. package/template/rust/sia-sdk-rs/sia_sdk/src/rhp/types.rs +0 -146
  94. package/template/rust/sia-sdk-rs/sia_sdk/src/rhp.rs +0 -7
  95. package/template/rust/sia-sdk-rs/sia_sdk/src/seed.rs +0 -278
  96. package/template/rust/sia-sdk-rs/sia_sdk/src/signing.rs +0 -236
  97. package/template/rust/sia-sdk-rs/sia_sdk/src/types/common.rs +0 -677
  98. package/template/rust/sia-sdk-rs/sia_sdk/src/types/currency.rs +0 -450
  99. package/template/rust/sia-sdk-rs/sia_sdk/src/types/specifier.rs +0 -110
  100. package/template/rust/sia-sdk-rs/sia_sdk/src/types/spendpolicy.rs +0 -778
  101. package/template/rust/sia-sdk-rs/sia_sdk/src/types/utils.rs +0 -117
  102. package/template/rust/sia-sdk-rs/sia_sdk/src/types/v1.rs +0 -1737
  103. package/template/rust/sia-sdk-rs/sia_sdk/src/types/v2.rs +0 -1726
  104. package/template/rust/sia-sdk-rs/sia_sdk/src/types/work.rs +0 -59
  105. package/template/rust/sia-sdk-rs/sia_sdk/src/types.rs +0 -16
  106. package/template/scripts/setup-rust.js +0 -29
  107. package/template/src/lib/format.ts +0 -35
  108. package/template/src/lib/hex.ts +0 -13
  109. package/template/src/lib/sdk.ts +0 -25
  110. package/template/src/lib/wasm-env.ts +0 -5
  111. package/template/wasm/indexd_wasm/indexd_wasm.d.ts +0 -309
  112. package/template/wasm/indexd_wasm/indexd_wasm.js +0 -1507
  113. package/template/wasm/indexd_wasm/indexd_wasm_bg.wasm +0 -0
  114. package/template/wasm/indexd_wasm/package.json +0 -31
@@ -1,19 +1,41 @@
1
+ import {
2
+ type DownloadProgress,
3
+ decodeMetadata,
4
+ type PinnedObject,
5
+ toHex,
6
+ type UploadProgress,
7
+ } from '@siafoundation/sia'
1
8
  import { useCallback, useEffect, useRef, useState } from 'react'
2
9
  import { APP_KEY } from '../../lib/constants'
3
- import { type FileMetadata, formatBytes } from '../../lib/format'
4
- import { toHex } from '../../lib/hex'
5
10
  import { useAuthStore } from '../../stores/auth'
6
11
  import { DevNote } from '../DevNote'
7
12
 
13
+ type FileMetadata = {
14
+ name: string
15
+ type: string
16
+ size: number
17
+ hash: string
18
+ createdAt?: number
19
+ updatedAt?: number
20
+ }
21
+
22
+ function formatBytes(bytes: number): string {
23
+ if (bytes === 0) return '0 B'
24
+ const k = 1024
25
+ const sizes = ['B', 'KB', 'MB', 'GB', 'TB']
26
+ const i = Math.floor(Math.log(bytes) / Math.log(k))
27
+ return `${parseFloat((bytes / k ** i).toFixed(1))} ${sizes[i]}`
28
+ }
29
+
8
30
  type UploadedFile = {
9
31
  id: string
10
32
  metadata: FileMetadata
33
+ object: PinnedObject
11
34
  }
12
35
 
13
- type UploadProgress = {
36
+ type ActiveUpload = {
14
37
  fileName: string
15
- current: number
16
- total: number
38
+ progress: UploadProgress
17
39
  }
18
40
 
19
41
  // Detect unconfigured template placeholder. The string is split so the
@@ -21,61 +43,65 @@ type UploadProgress = {
21
43
  const isPlaceholderKey = APP_KEY.startsWith('{' + '{')
22
44
 
23
45
  export function UploadZone() {
24
- const sdk = useAuthStore((s) => s.sdk)
46
+ const client = useAuthStore((s) => s.client)
25
47
  const [files, setFiles] = useState<UploadedFile[]>([])
26
48
  const [uploading, setUploading] = useState(false)
27
- const [progress, setProgress] = useState<UploadProgress | null>(null)
49
+ const [activeUpload, setActiveUpload] = useState<ActiveUpload | null>(null)
28
50
  const [dragOver, setDragOver] = useState(false)
29
51
  const [error, setError] = useState<string | null>(null)
52
+ const [downloading, setDownloading] = useState<string | null>(null)
53
+ const [downloadProgress, setDownloadProgress] =
54
+ useState<DownloadProgress | null>(null)
30
55
  const fileInputRef = useRef<HTMLInputElement>(null)
31
56
 
32
57
  const loadFiles = useCallback(async () => {
33
- if (!sdk) return
58
+ if (!client) return
34
59
  try {
35
- const events = await sdk.objectEvents(null, 100)
60
+ const events = await client.objectEvents(null, 100)
36
61
  const loaded: UploadedFile[] = []
37
62
  for (const event of events) {
38
63
  if (event.deleted || !event.object) continue
39
- try {
40
- const metaBytes = event.object.metadata()
41
- const meta = JSON.parse(
42
- new TextDecoder().decode(metaBytes),
43
- ) as FileMetadata
44
- loaded.push({ id: event.id, metadata: meta })
45
- } catch {
46
- // skip objects with invalid metadata
64
+ const meta = decodeMetadata(event.object.metadata()) as FileMetadata
65
+ if (meta.name) {
66
+ loaded.push({ id: event.id, metadata: meta, object: event.object })
47
67
  }
48
68
  }
49
69
  setFiles(loaded)
50
70
  } catch (e) {
51
71
  console.error('Failed to load files:', e)
52
72
  }
53
- }, [sdk])
73
+ }, [client])
54
74
 
55
75
  useEffect(() => {
56
76
  loadFiles()
57
77
  }, [loadFiles])
58
78
 
59
79
  async function uploadFile(file: File) {
60
- if (!sdk) return
80
+ if (!client) return
61
81
  setUploading(true)
62
82
  setError(null)
63
- setProgress({ fileName: file.name, current: 0, total: 0 })
83
+ setActiveUpload({
84
+ fileName: file.name,
85
+ progress: {
86
+ phase: 'connecting',
87
+ slabsComplete: 0,
88
+ slabsTotal: 0,
89
+ shardsComplete: 0,
90
+ shardsTotal: 0,
91
+ },
92
+ })
64
93
 
65
94
  try {
66
- const arrayBuffer = await file.arrayBuffer()
67
- const data = new Uint8Array(arrayBuffer)
68
-
69
95
  // Compute SHA-256 hash for metadata
70
- const hashBuffer = await crypto.subtle.digest('SHA-256', data)
96
+ const hashBuffer = await crypto.subtle.digest(
97
+ 'SHA-256',
98
+ await file.arrayBuffer(),
99
+ )
71
100
  const hash = toHex(new Uint8Array(hashBuffer))
72
101
 
73
- const pinnedObject = await sdk.uploadWithProgress(
74
- data,
75
- (current: number, total: number) => {
76
- setProgress({ fileName: file.name, current, total })
77
- },
78
- )
102
+ const pinnedObject = await client.upload(file, (p) => {
103
+ setActiveUpload({ fileName: file.name, progress: p })
104
+ })
79
105
 
80
106
  const metadata: FileMetadata = {
81
107
  name: file.name,
@@ -88,15 +114,41 @@ export function UploadZone() {
88
114
  pinnedObject.updateMetadata(
89
115
  new TextEncoder().encode(JSON.stringify(metadata)),
90
116
  )
91
- await sdk.pinObject(pinnedObject)
92
- await sdk.updateObjectMetadata(pinnedObject)
117
+ await client.pinObject(pinnedObject)
118
+ await client.updateObjectMetadata(pinnedObject)
93
119
 
94
- setFiles((prev) => [{ id: pinnedObject.id(), metadata }, ...prev])
120
+ setFiles((prev) => [
121
+ { id: pinnedObject.id(), metadata, object: pinnedObject },
122
+ ...prev,
123
+ ])
95
124
  } catch (e) {
96
125
  setError(e instanceof Error ? e.message : 'Upload failed')
97
126
  } finally {
98
127
  setUploading(false)
99
- setProgress(null)
128
+ setActiveUpload(null)
129
+ }
130
+ }
131
+
132
+ async function downloadFile(file: UploadedFile) {
133
+ if (!client) return
134
+ setDownloading(file.id)
135
+ setDownloadProgress(null)
136
+ try {
137
+ const data = await client.download(file.object, (p) => {
138
+ setDownloadProgress(p)
139
+ })
140
+ const blob = new Blob([data as BlobPart], { type: file.metadata.type })
141
+ const url = URL.createObjectURL(blob)
142
+ const a = document.createElement('a')
143
+ a.href = url
144
+ a.download = file.metadata.name
145
+ a.click()
146
+ URL.revokeObjectURL(url)
147
+ } catch (e) {
148
+ setError(e instanceof Error ? e.message : 'Download failed')
149
+ } finally {
150
+ setDownloading(null)
151
+ setDownloadProgress(null)
100
152
  }
101
153
  }
102
154
 
@@ -114,12 +166,31 @@ export function UploadZone() {
114
166
  }
115
167
  }
116
168
 
117
- const isIndeterminate = progress && progress.total === 0
169
+ const progress = activeUpload?.progress
170
+ const isIndeterminate =
171
+ progress &&
172
+ (progress.phase === 'connecting' ||
173
+ progress.phase === 'assembling' ||
174
+ progress.phase === 'pinning')
118
175
  const progressPercent =
119
- progress && progress.total > 0
120
- ? Math.round((progress.current / progress.total) * 100)
176
+ progress && progress.slabsTotal > 0
177
+ ? Math.round((progress.slabsComplete / progress.slabsTotal) * 100)
121
178
  : 0
122
179
 
180
+ function progressLabel(): string {
181
+ if (!progress) return ''
182
+ switch (progress.phase) {
183
+ case 'connecting':
184
+ return 'Connecting to hosts...'
185
+ case 'uploading':
186
+ return `${progress.slabsComplete}/${progress.slabsTotal} slabs \u00B7 ${progressPercent}%`
187
+ case 'assembling':
188
+ return 'Assembling object...'
189
+ case 'pinning':
190
+ return 'Pinning object...'
191
+ }
192
+ }
193
+
123
194
  return (
124
195
  <div className="flex-1 p-6 space-y-5 max-w-5xl mx-auto w-full">
125
196
  {/* Dev notes — remove these when shipping */}
@@ -134,16 +205,17 @@ export function UploadZone() {
134
205
  </DevNote>
135
206
  )}
136
207
 
137
- <DevNote title="Upload Flow">
208
+ <DevNote title="Upload & Download">
138
209
  <p>
139
- <code className="text-amber-300">sdk.uploadWithProgress()</code>{' '}
140
- encrypts, erasure-codes, and uploads directly to Sia hosts. Metadata
141
- is attached via{' '}
142
210
  <code className="text-amber-300">
143
- pinnedObject.updateMetadata()
211
+ client.upload(file, onProgress)
144
212
  </code>{' '}
145
- then pinned with{' '}
146
- <code className="text-amber-300">sdk.pinObject()</code>.
213
+ encrypts, erasure-codes, and uploads to Sia hosts using parallel Web
214
+ Workers.{' '}
215
+ <code className="text-amber-300">
216
+ client.download(object, onProgress)
217
+ </code>{' '}
218
+ retrieves and decrypts files the same way.
147
219
  </p>
148
220
  </DevNote>
149
221
 
@@ -191,18 +263,18 @@ export function UploadZone() {
191
263
  }}
192
264
  />
193
265
 
194
- {progress ? (
266
+ {activeUpload ? (
195
267
  <div className="space-y-4">
196
268
  <p className="text-neutral-300 text-sm">
197
- {isIndeterminate ? (
269
+ {progress?.phase === 'connecting' ? (
198
270
  <>
199
271
  Preparing upload for{' '}
200
- <span className="text-white">{progress.fileName}</span>
272
+ <span className="text-white">{activeUpload.fileName}</span>
201
273
  </>
202
274
  ) : (
203
275
  <>
204
276
  Uploading{' '}
205
- <span className="text-white">{progress.fileName}</span>
277
+ <span className="text-white">{activeUpload.fileName}</span>
206
278
  </>
207
279
  )}
208
280
  </p>
@@ -217,9 +289,7 @@ export function UploadZone() {
217
289
  )}
218
290
  </div>
219
291
  <p className="text-neutral-600 text-xs font-mono">
220
- {isIndeterminate
221
- ? 'Preparing upload...'
222
- : `${progress.current}/${progress.total} shards \u00B7 ${progressPercent}%`}
292
+ {progressLabel()}
223
293
  </p>
224
294
  </div>
225
295
  ) : (
@@ -252,30 +322,78 @@ export function UploadZone() {
252
322
  {files.length} file{files.length !== 1 ? 's' : ''}
253
323
  </h2>
254
324
  <div className="divide-y divide-neutral-800/60">
255
- {files.map((file) => (
256
- <div
257
- key={file.id}
258
- className="flex items-center justify-between py-3 group"
259
- >
260
- <div className="flex-1 min-w-0 mr-4">
261
- <p className="text-sm text-neutral-200 truncate">
262
- {file.metadata.name}
263
- </p>
264
- <p className="text-xs text-neutral-600 mt-0.5">
265
- {formatBytes(file.metadata.size)}
266
- {file.metadata.type !== 'application/octet-stream' && (
267
- <span> &middot; {file.metadata.type}</span>
268
- )}
269
- </p>
270
- </div>
271
- <span
272
- className="text-[11px] text-neutral-700 font-mono shrink-0 group-hover:text-neutral-500 transition-colors"
273
- title={file.metadata.hash}
325
+ {files.map((file) => {
326
+ const isDownloading = downloading === file.id
327
+ return (
328
+ <div
329
+ key={file.id}
330
+ className="flex items-center justify-between py-3 group"
274
331
  >
275
- {file.metadata.hash.slice(0, 8)}...
276
- </span>
277
- </div>
278
- ))}
332
+ <div className="flex-1 min-w-0 mr-4">
333
+ <p className="text-sm text-neutral-200 truncate">
334
+ {file.metadata.name}
335
+ </p>
336
+ <p className="text-xs text-neutral-600 mt-0.5">
337
+ {formatBytes(file.metadata.size)}
338
+ {file.metadata.type !== 'application/octet-stream' && (
339
+ <span> &middot; {file.metadata.type}</span>
340
+ )}
341
+ {isDownloading && downloadProgress && (
342
+ <span>
343
+ {' &middot; '}
344
+ {downloadProgress.phase === 'downloading'
345
+ ? `${downloadProgress.slabsComplete}/${downloadProgress.slabsTotal} slabs`
346
+ : downloadProgress.phase === 'connecting'
347
+ ? 'Connecting...'
348
+ : 'Assembling...'}
349
+ </span>
350
+ )}
351
+ </p>
352
+ </div>
353
+ <div className="flex items-center gap-3 shrink-0">
354
+ <button
355
+ type="button"
356
+ onClick={() => downloadFile(file)}
357
+ disabled={downloading !== null}
358
+ className="text-xs text-neutral-600 hover:text-neutral-300 disabled:opacity-30 disabled:cursor-default transition-colors"
359
+ title="Download"
360
+ >
361
+ {isDownloading ? (
362
+ <svg
363
+ className="w-4 h-4 animate-spin"
364
+ viewBox="0 0 24 24"
365
+ fill="none"
366
+ stroke="currentColor"
367
+ strokeWidth="2"
368
+ aria-hidden="true"
369
+ >
370
+ <circle cx="12" cy="12" r="10" strokeOpacity="0.25" />
371
+ <path d="M12 2a10 10 0 019.17 6" />
372
+ </svg>
373
+ ) : (
374
+ <svg
375
+ className="w-4 h-4"
376
+ viewBox="0 0 24 24"
377
+ fill="none"
378
+ stroke="currentColor"
379
+ strokeWidth="1.5"
380
+ aria-hidden="true"
381
+ >
382
+ <path d="M12 4v12m0 0l-4-4m4 4l4-4" />
383
+ <path d="M20 16v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2" />
384
+ </svg>
385
+ )}
386
+ </button>
387
+ <span
388
+ className="text-[11px] text-neutral-700 font-mono group-hover:text-neutral-500 transition-colors"
389
+ title={file.metadata.hash}
390
+ >
391
+ {file.metadata.hash.slice(0, 8)}...
392
+ </span>
393
+ </div>
394
+ </div>
395
+ )
396
+ })}
279
397
  </div>
280
398
  </div>
281
399
  )}
@@ -9,13 +9,23 @@ body {
9
9
  }
10
10
 
11
11
  @keyframes fade-in {
12
- from { opacity: 0; transform: translateY(8px); }
13
- to { opacity: 1; transform: translateY(0); }
12
+ from {
13
+ opacity: 0;
14
+ transform: translateY(8px);
15
+ }
16
+ to {
17
+ opacity: 1;
18
+ transform: translateY(0);
19
+ }
14
20
  }
15
21
 
16
22
  @keyframes indeterminate {
17
- 0% { transform: translateX(-100%); }
18
- 100% { transform: translateX(400%); }
23
+ 0% {
24
+ transform: translateX(-100%);
25
+ }
26
+ 100% {
27
+ transform: translateX(400%);
28
+ }
19
29
  }
20
30
 
21
31
  .animate-fade-in {
@@ -1,6 +1,6 @@
1
+ import type { SiaClient } from '@siafoundation/sia'
1
2
  import { create } from 'zustand'
2
3
  import { persist } from 'zustand/middleware'
3
- import type { Builder, SDK } from '../lib/sdk'
4
4
 
5
5
  export type AuthStep =
6
6
  | 'loading'
@@ -9,20 +9,14 @@ export type AuthStep =
9
9
  | 'recovery'
10
10
  | 'connected'
11
11
 
12
- export function applyBalancedPreset(builder: Builder) {
13
- builder.withMaxPriceFetches(5)
14
- builder.withMaxDownloads(10)
15
- builder.withMaxUploads(8)
16
- }
17
-
18
12
  type AuthState = {
19
- sdk: SDK | null
13
+ client: SiaClient | null
20
14
  storedKeyHex: string | null
21
15
  indexerUrl: string
22
16
  step: AuthStep
23
17
  error: string | null
24
18
  approvalUrl: string | null
25
- setSdk: (sdk: SDK) => void
19
+ setClient: (client: SiaClient) => void
26
20
  setStep: (step: AuthStep) => void
27
21
  setError: (error: string | null) => void
28
22
  setStoredKeyHex: (hex: string) => void
@@ -34,13 +28,13 @@ type AuthState = {
34
28
  export const useAuthStore = create<AuthState>()(
35
29
  persist(
36
30
  (set) => ({
37
- sdk: null,
31
+ client: null,
38
32
  storedKeyHex: null,
39
33
  indexerUrl: '',
40
34
  step: 'loading',
41
35
  error: null,
42
36
  approvalUrl: null,
43
- setSdk: (sdk) => set({ sdk, step: 'connected', error: null }),
37
+ setClient: (client) => set({ client, step: 'connected', error: null }),
44
38
  setStep: (step) => set({ step, error: null }),
45
39
  setError: (error) => set({ error }),
46
40
  setStoredKeyHex: (hex) => set({ storedKeyHex: hex }),
@@ -48,7 +42,7 @@ export const useAuthStore = create<AuthState>()(
48
42
  setApprovalUrl: (url) => set({ approvalUrl: url }),
49
43
  reset: () =>
50
44
  set({
51
- sdk: null,
45
+ client: null,
52
46
  storedKeyHex: null,
53
47
  step: 'loading',
54
48
  error: null,
@@ -0,0 +1,4 @@
1
+ {
2
+ "status": "passed",
3
+ "failedTests": []
4
+ }
@@ -16,7 +16,7 @@
16
16
  "noEmit": true,
17
17
  "jsx": "react-jsx",
18
18
  "paths": {
19
- "indexd_wasm": ["./wasm/indexd_wasm/indexd_wasm.d.ts"]
19
+ "sia-wasm": ["./node_modules/@siafoundation/sia/wasm/sia.d.ts"]
20
20
  },
21
21
 
22
22
  /* Linting */
@@ -4,7 +4,6 @@
4
4
  "target": "ES2023",
5
5
  "lib": ["ES2023"],
6
6
  "module": "ESNext",
7
- "types": ["node"],
8
7
  "skipLibCheck": true,
9
8
 
10
9
  /* Bundler mode */
@@ -7,12 +7,11 @@ import wasm from 'vite-plugin-wasm'
7
7
  export default defineConfig({
8
8
  plugins: [react(), tailwindcss(), wasm(), topLevelAwait()],
9
9
  optimizeDeps: {
10
- exclude: ['indexd_wasm'],
10
+ exclude: ['@siafoundation/sia', 'sia-wasm'],
11
11
  },
12
12
  resolve: {
13
13
  alias: {
14
- indexd_wasm: '/wasm/indexd_wasm/indexd_wasm.js',
15
- env: '/src/lib/wasm-env.ts',
14
+ 'sia-wasm': '@siafoundation/sia/wasm',
16
15
  },
17
16
  },
18
17
  })
@@ -1,16 +0,0 @@
1
- # Rust SDK Source
2
-
3
- The Rust SDK source (`sia-sdk-rs/`) is cloned automatically on `bun install` from [alexfreska/sia-sdk-rs](https://github.com/alexfreska/sia-sdk-rs) (branch `alex/wasm-experimental`).
4
-
5
- The pre-built WASM in `../wasm/` is what the app actually uses at runtime. The Rust source is only needed if you want to rebuild the WASM module.
6
-
7
- ## Rebuilding WASM
8
-
9
- ```bash
10
- cd sia-sdk-rs
11
- cargo install wasm-pack
12
- wasm-pack build indexd_wasm --target web --out-dir pkg
13
- cp indexd_wasm/pkg/indexd_wasm_bg.wasm ../../wasm/indexd_wasm/
14
- cp indexd_wasm/pkg/indexd_wasm.js ../../wasm/indexd_wasm/
15
- cp indexd_wasm/pkg/indexd_wasm.d.ts ../../wasm/indexd_wasm/
16
- ```
@@ -1,6 +0,0 @@
1
- ---
2
- indexd: patch
3
- indexd_ffi: patch
4
- ---
5
-
6
- # Added cancel function to cancel inflight packed uploads.
@@ -1,16 +0,0 @@
1
- ---
2
- sia_sdk: patch
3
- indexd: patch
4
- indexd_ffi: patch
5
- sia_sdk_derive: patch
6
- ---
7
-
8
- # Check if we have enough hosts prior to encoding in upload_slabs
9
-
10
- #261 by @Alrighttt
11
-
12
- Fixes https://github.com/SiaFoundation/sia-sdk-rs/issues/251
13
-
14
- - Added an `available_for_upload` method that returns the amount of known hosts marked `good_for_upload`.
15
- - Added a check in `upload_slabs` that verifies we have enough good hosts prior to encoding any data.
16
- - Adds a variant to `QueueError` for `upload_slabs`'s new failure case. This enables testing for this new case specifically.
@@ -1,5 +0,0 @@
1
- ---
2
- indexd_ffi: patch
3
- ---
4
-
5
- # Fix slab length in packed object
@@ -1,13 +0,0 @@
1
- ---
2
- indexd: patch
3
- ---
4
-
5
- # Fix upload racing race conditon
6
-
7
- #258 by @Alrighttt
8
-
9
- This fixes a race condition in the upload logic that could happen when the amount of healthy hosts is nearly the same as the amount of shards. This could happen when the racing mechanism was triggered prior to all of the initial shards being assigned a host. The slow hosts would be consumed from the HostQueue without completing the upload. This would cause a latter shard to hit a QueueError::NoMoreHosts error.
10
-
11
- This changes the upload behavior so that each shard has a host assigned before any upload begins.
12
-
13
- A `set_slow_hosts` method was added to the `MockRHP4Client` to allow easily testing these conditions. This mimics a similar mechanism from the Go SDK.
@@ -1,5 +0,0 @@
1
- ---
2
- indexd_ffi: patch
3
- ---
4
-
5
- # Improved parallelism of packed uploads.
@@ -1,5 +0,0 @@
1
- ---
2
- indexd_ffi: patch
3
- ---
4
-
5
- # Progress callback will now be called as expected for packed uploads.
@@ -1,10 +0,0 @@
1
- version: 2
2
- updates:
3
- - package-ecosystem: cargo
4
- directory: "/"
5
- schedule:
6
- interval: weekly
7
- groups:
8
- all-dependencies:
9
- patterns:
10
- - "*"
@@ -1,36 +0,0 @@
1
- name: Main
2
-
3
- on:
4
- push:
5
- branches:
6
- - master
7
- pull_request:
8
-
9
- jobs:
10
- test:
11
- runs-on: tenki-standard-autoscale
12
- steps:
13
- - uses: actions/checkout@v4
14
- - name: Setup Environment
15
- run: |
16
- rustup update stable
17
- rustup toolchain install nightly
18
- rustup target add wasm32-unknown-unknown
19
- rustup component add rustfmt --toolchain nightly
20
- - name: Build for wasm
21
- # Check if the library target compiles. This will still allow for using
22
- # non-wasm functionality in tests and benchmarks but guarantees that
23
- # consumers of the library can use it to generate wasm bindings.
24
- run: cargo check --target wasm32-unknown-unknown --lib --package sia_sdk
25
- - name: Rustfmt
26
- run: cargo +nightly fmt --all -- --check
27
- - name: Clippy
28
- run: cargo clippy -- -D warnings
29
- - name: Build docs
30
- run: cargo doc --all-features --no-deps
31
- env:
32
- RUSTDOCFLAGS: "-D warnings"
33
- - name: Build benches
34
- run: cargo build --benches --features=mock
35
- - name: Test
36
- run: cargo test
@@ -1,34 +0,0 @@
1
- name: Prepare Release
2
-
3
- on:
4
- workflow_dispatch:
5
- push:
6
- branches:
7
- - master
8
-
9
- permissions:
10
- contents: write
11
- pull-requests: write
12
-
13
- jobs:
14
- prepare-release:
15
- if: "!contains(github.event.head_commit.message, 'chore: prepare releases')" # Skip merges from releases
16
- runs-on: tenki-standard-autoscale
17
- steps:
18
- - uses: actions/checkout@v4
19
- with:
20
- fetch-depth: 0
21
- - name: Setup Knope
22
- uses: knope-dev/action@407e9ef7c272d2dd53a4e71e39a7839e29933c48
23
- - name: Prepare Release
24
- run: knope prepare-release --verbose
25
- - name: Create Pull Request
26
- uses: peter-evans/create-pull-request@v7
27
- with:
28
- delete-branch: true
29
- commit-message: "chore: prepare releases"
30
- title: Release Versions
31
- base: master
32
- branch: release
33
- body: |
34
- This PR was automatically created to prepare the release versions. Close the PR when you are ready to release. See the changelog for more details.