@bsv/sdk 1.9.2 → 1.9.4

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 (93) hide show
  1. package/dist/cjs/package.json +1 -1
  2. package/dist/cjs/src/kvstore/GlobalKVStore.js +116 -98
  3. package/dist/cjs/src/kvstore/GlobalKVStore.js.map +1 -1
  4. package/dist/cjs/src/kvstore/types.js.map +1 -1
  5. package/dist/cjs/src/overlay-tools/index.js +1 -0
  6. package/dist/cjs/src/overlay-tools/index.js.map +1 -1
  7. package/dist/cjs/src/overlay-tools/withDoubleSpendRetry.js +55 -0
  8. package/dist/cjs/src/overlay-tools/withDoubleSpendRetry.js.map +1 -0
  9. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  10. package/dist/esm/src/kvstore/GlobalKVStore.js +117 -99
  11. package/dist/esm/src/kvstore/GlobalKVStore.js.map +1 -1
  12. package/dist/esm/src/kvstore/types.js.map +1 -1
  13. package/dist/esm/src/overlay-tools/index.js +1 -0
  14. package/dist/esm/src/overlay-tools/index.js.map +1 -1
  15. package/dist/esm/src/overlay-tools/withDoubleSpendRetry.js +48 -0
  16. package/dist/esm/src/overlay-tools/withDoubleSpendRetry.js.map +1 -0
  17. package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
  18. package/dist/types/src/kvstore/GlobalKVStore.d.ts.map +1 -1
  19. package/dist/types/src/kvstore/types.d.ts +2 -0
  20. package/dist/types/src/kvstore/types.d.ts.map +1 -1
  21. package/dist/types/src/overlay-tools/index.d.ts +1 -0
  22. package/dist/types/src/overlay-tools/index.d.ts.map +1 -1
  23. package/dist/types/src/overlay-tools/withDoubleSpendRetry.d.ts +14 -0
  24. package/dist/types/src/overlay-tools/withDoubleSpendRetry.d.ts.map +1 -0
  25. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  26. package/dist/umd/bundle.js +2 -2
  27. package/dist/umd/bundle.js.map +1 -1
  28. package/docs/fast-docs.png +0 -0
  29. package/docs/index.md +49 -44
  30. package/docs/reference/kvstore.md +9 -0
  31. package/docs/reference/overlay-tools.md +32 -0
  32. package/docs/swagger.png +0 -0
  33. package/package.json +1 -1
  34. package/src/kvstore/GlobalKVStore.ts +134 -114
  35. package/src/kvstore/__tests/GlobalKVStore.test.ts +11 -1
  36. package/src/kvstore/types.ts +2 -0
  37. package/src/overlay-tools/index.ts +1 -0
  38. package/src/overlay-tools/withDoubleSpendRetry.ts +71 -0
  39. package/docs/MARKDOWN_VALIDATION_GUIDE.md +0 -175
  40. package/docs/concepts/beef.md +0 -92
  41. package/docs/concepts/chain-tracking.md +0 -134
  42. package/docs/concepts/decentralized-identity.md +0 -221
  43. package/docs/concepts/fees.md +0 -249
  44. package/docs/concepts/identity-certificates.md +0 -307
  45. package/docs/concepts/index.md +0 -77
  46. package/docs/concepts/key-management.md +0 -185
  47. package/docs/concepts/script-templates.md +0 -176
  48. package/docs/concepts/sdk-philosophy.md +0 -80
  49. package/docs/concepts/signatures.md +0 -194
  50. package/docs/concepts/spv-verification.md +0 -118
  51. package/docs/concepts/transaction-encoding.md +0 -167
  52. package/docs/concepts/transaction-structure.md +0 -67
  53. package/docs/concepts/trust-model.md +0 -139
  54. package/docs/concepts/verification.md +0 -250
  55. package/docs/concepts/wallet-integration.md +0 -101
  56. package/docs/guides/development-wallet-setup.md +0 -374
  57. package/docs/guides/direct-transaction-creation.md +0 -147
  58. package/docs/guides/http-client-configuration.md +0 -488
  59. package/docs/guides/index.md +0 -138
  60. package/docs/guides/large-transactions.md +0 -448
  61. package/docs/guides/multisig-transactions.md +0 -792
  62. package/docs/guides/security-best-practices.md +0 -494
  63. package/docs/guides/transaction-batching.md +0 -132
  64. package/docs/guides/transaction-signing-methods.md +0 -419
  65. package/docs/reference/arc-config.md +0 -698
  66. package/docs/reference/brc-100.md +0 -33
  67. package/docs/reference/configuration.md +0 -835
  68. package/docs/reference/debugging.md +0 -705
  69. package/docs/reference/errors.md +0 -597
  70. package/docs/reference/index.md +0 -111
  71. package/docs/reference/network-config.md +0 -914
  72. package/docs/reference/op-codes.md +0 -325
  73. package/docs/reference/transaction-signatures.md +0 -95
  74. package/docs/tutorials/advanced-transaction.md +0 -572
  75. package/docs/tutorials/aes-encryption.md +0 -949
  76. package/docs/tutorials/authfetch-tutorial.md +0 -986
  77. package/docs/tutorials/ecdh-key-exchange.md +0 -549
  78. package/docs/tutorials/elliptic-curve-fundamentals.md +0 -606
  79. package/docs/tutorials/error-handling.md +0 -1216
  80. package/docs/tutorials/first-transaction-low-level.md +0 -205
  81. package/docs/tutorials/first-transaction.md +0 -275
  82. package/docs/tutorials/hashes-and-hmacs.md +0 -788
  83. package/docs/tutorials/identity-management.md +0 -729
  84. package/docs/tutorials/index.md +0 -219
  85. package/docs/tutorials/key-management.md +0 -538
  86. package/docs/tutorials/protowallet-development.md +0 -743
  87. package/docs/tutorials/script-construction.md +0 -690
  88. package/docs/tutorials/spv-merkle-proofs.md +0 -685
  89. package/docs/tutorials/testnet-transactions-low-level.md +0 -359
  90. package/docs/tutorials/transaction-broadcasting.md +0 -538
  91. package/docs/tutorials/transaction-types.md +0 -420
  92. package/docs/tutorials/type-42.md +0 -568
  93. package/docs/tutorials/uhrp-storage.md +0 -599
@@ -1,599 +0,0 @@
1
- # Decentralized File Storage with UHRP
2
-
3
- **Duration**: 75 minutes
4
- **Prerequisites**: Node.js, basic TypeScript knowledge, understanding of decentralized storage and `WalletClient` usage
5
- **Learning Goals**:
6
-
7
- - Understand UHRP (Universal Hash Resource Protocol)
8
- - Upload and download files using StorageUploader/StorageDownloader
9
- - Implement decentralized file management systems
10
- - Handle file integrity verification and expiration
11
-
12
- ## Introduction
13
-
14
- UHRP (Universal Hash Resource Protocol) is a decentralized file storage system that uses content hashing for addressing and retrieval. The BSV SDK provides `StorageUploader` and `StorageDownloader` classes for seamless integration with UHRP storage networks.
15
-
16
- ## Prerequisites
17
-
18
- ### For Upload Operations
19
-
20
- - **BRC-100 compliant wallet** (such as MetaNet Desktop Wallet) must be installed and running
21
- - **Wallet connection** accessible via JSON API (typically <http://localhost:3321>)
22
- - **Sufficient wallet balance** for transaction fees and storage costs
23
- - **UHRP storage service** - This tutorial uses `https://nanostore.babbage.systems`
24
-
25
- ### For Download Operations Only
26
-
27
- - **No wallet connection required** - downloads work independently
28
- - **Network access** to resolve UHRP URLs via lookup services
29
-
30
- ### Service Availability
31
-
32
- **Important Note**: This tutorial uses `https://nanostore.babbage.systems`, which is a working UHRP storage service. The examples demonstrate correct SDK usage patterns and will work with:
33
-
34
- - A running BRC-100 compliant wallet (such as MetaNet Desktop Wallet)
35
- - Sufficient wallet balance for storage fees
36
-
37
- **Performance Note**: UHRP storage operations may take time to complete as they involve blockchain transactions and network propagation. Upload operations can take 10-30 seconds or more depending on network conditions.
38
-
39
- **Network Propagation**: After uploading, files typically take 30-60 seconds to propagate across the UHRP network before they become available for download. This is normal behavior for decentralized storage systems and ensures content integrity verification.
40
-
41
- ## Key Features
42
-
43
- - **Content-Addressed Storage**: Files identified by their hash
44
- - **Decentralized Retrieval**: Multiple storage providers
45
- - **Integrity Verification**: Automatic hash validation
46
- - **Expiration Management**: Time-based file retention
47
- - **Authenticated Upload**: Wallet-based authentication
48
-
49
- ## What You'll Build
50
-
51
- - File upload system with UHRP
52
- - Decentralized file retrieval
53
- - File management dashboard
54
- - Integrity verification system
55
-
56
- ## Setting Up UHRP Storage
57
-
58
- ### Basic File Upload
59
-
60
- ```typescript
61
- import { StorageUploader, WalletClient } from '@bsv/sdk'
62
-
63
- async function basicFileUpload() {
64
- const wallet = new WalletClient('auto', 'localhost')
65
-
66
- const uploader = new StorageUploader({
67
- storageURL: 'https://nanostore.babbage.systems',
68
- wallet
69
- })
70
-
71
- // Create sample file
72
- const fileData = new TextEncoder().encode('Hello, UHRP storage!')
73
- const file = {
74
- data: fileData,
75
- type: 'text/plain'
76
- }
77
-
78
- try {
79
- const result = await uploader.publishFile({
80
- file,
81
- retentionPeriod: 60 * 24 * 7 // 7 days in minutes
82
- })
83
-
84
- console.log('File uploaded successfully!')
85
- console.log('UHRP URL:', result.uhrpURL)
86
- console.log('Published:', result.published)
87
-
88
- return result
89
- } catch (error) {
90
- console.error('Upload failed:', error)
91
- throw error
92
- }
93
- }
94
-
95
- basicFileUpload().catch(console.error)
96
- ```
97
-
98
- ### File Download and Verification
99
-
100
- ```typescript
101
- import { StorageDownloader } from '@bsv/sdk'
102
-
103
- async function basicFileDownload(uhrpUrl: string) {
104
- const downloader = new StorageDownloader({
105
- networkPreset: 'mainnet'
106
- })
107
-
108
- try {
109
- console.log('Downloading file:', uhrpUrl)
110
-
111
- const result = await downloader.download(uhrpUrl)
112
-
113
- console.log('File downloaded successfully!')
114
- console.log('MIME Type:', result.mimeType)
115
- console.log('Content length:', result.data.length, 'bytes')
116
-
117
- // Convert to string if text file
118
- if (result.mimeType?.startsWith('text/')) {
119
- const content = new TextDecoder().decode(result.data)
120
- console.log('Content:', content)
121
- }
122
-
123
- return result
124
- } catch (error) {
125
- console.error('Download failed:', error)
126
- throw error
127
- }
128
- }
129
-
130
- // Example usage (replace with actual UHRP URL)
131
- // basicFileDownload('uhrp://abc123...').catch(console.error)
132
- ```
133
-
134
- ## Complete File Management System
135
-
136
- ### File Manager Class
137
-
138
- ```typescript
139
- import { StorageUploader, StorageDownloader, WalletClient } from '@bsv/sdk'
140
-
141
- interface FileMetadata {
142
- uhrpUrl: string
143
- originalName: string
144
- mimeType: string
145
- size: number
146
- uploadDate: Date
147
- expiryDate: Date
148
- tags: string[]
149
- }
150
-
151
- class UHRPFileManager {
152
- private uploader: StorageUploader
153
- private downloader: StorageDownloader
154
- private fileRegistry: Map<string, FileMetadata> = new Map()
155
-
156
- constructor(storageURL: string, wallet?: WalletClient) {
157
- this.uploader = new StorageUploader({
158
- storageURL,
159
- wallet: wallet || new WalletClient('auto', 'localhost')
160
- })
161
-
162
- this.downloader = new StorageDownloader({
163
- networkPreset: 'mainnet'
164
- })
165
- }
166
-
167
- async uploadFile(
168
- fileData: Uint8Array,
169
- fileName: string,
170
- mimeType: string,
171
- retentionDays: number = 30,
172
- tags: string[] = []
173
- ): Promise<FileMetadata> {
174
- const file = {
175
- data: fileData,
176
- type: mimeType
177
- }
178
-
179
- const retentionMinutes = retentionDays * 24 * 60
180
-
181
- try {
182
- const result = await this.uploader.publishFile({
183
- file,
184
- retentionPeriod: retentionMinutes
185
- })
186
-
187
- const metadata: FileMetadata = {
188
- uhrpUrl: result.uhrpURL,
189
- originalName: fileName,
190
- mimeType,
191
- size: fileData.length,
192
- uploadDate: new Date(),
193
- expiryDate: new Date(Date.now() + retentionDays * 24 * 60 * 60 * 1000),
194
- tags
195
- }
196
-
197
- this.fileRegistry.set(result.uhrpURL, metadata)
198
-
199
- console.log(`File "${fileName}" uploaded successfully`)
200
- console.log('UHRP URL:', result.uhrpURL)
201
-
202
- return metadata
203
- } catch (error) {
204
- console.error(`Failed to upload "${fileName}":`, error)
205
- throw error
206
- }
207
- }
208
-
209
- async downloadFile(uhrpUrl: string): Promise<{
210
- data: Uint8Array
211
- metadata: FileMetadata | null
212
- }> {
213
- try {
214
- const result = await this.downloader.download(uhrpUrl)
215
- const metadata = this.fileRegistry.get(uhrpUrl) || null
216
-
217
- console.log('File downloaded:', uhrpUrl)
218
-
219
- return {
220
- data: result.data,
221
- metadata
222
- }
223
- } catch (error) {
224
- console.error('Download failed:', error)
225
- throw error
226
- }
227
- }
228
-
229
- async getFileInfo(uhrpUrl: string): Promise<any> {
230
- try {
231
- return await this.uploader.findFile(uhrpUrl)
232
- } catch (error) {
233
- console.error('Failed to get file info:', error)
234
- throw error
235
- }
236
- }
237
-
238
- async renewFile(uhrpUrl: string, additionalDays: number): Promise<any> {
239
- const additionalMinutes = additionalDays * 24 * 60
240
-
241
- try {
242
- const result = await this.uploader.renewFile(uhrpUrl, additionalMinutes)
243
-
244
- // Update local metadata if exists
245
- const metadata = this.fileRegistry.get(uhrpUrl)
246
- if (metadata) {
247
- metadata.expiryDate = new Date(Date.now() + additionalDays * 24 * 60 * 60 * 1000)
248
- this.fileRegistry.set(uhrpUrl, metadata)
249
- }
250
-
251
- console.log(`File renewed for ${additionalDays} days`)
252
- return result
253
- } catch (error) {
254
- console.error('Failed to renew file:', error)
255
- throw error
256
- }
257
- }
258
-
259
- listFiles(tag?: string): FileMetadata[] {
260
- const files = Array.from(this.fileRegistry.values())
261
-
262
- if (tag) {
263
- return files.filter(file => file.tags.includes(tag))
264
- }
265
-
266
- return files
267
- }
268
-
269
- getExpiringFiles(daysAhead: number = 7): FileMetadata[] {
270
- const cutoffDate = new Date(Date.now() + daysAhead * 24 * 60 * 60 * 1000)
271
-
272
- return Array.from(this.fileRegistry.values())
273
- .filter(file => file.expiryDate <= cutoffDate)
274
- .sort((a, b) => a.expiryDate.getTime() - b.expiryDate.getTime())
275
- }
276
- }
277
-
278
- async function demonstrateFileManager() {
279
- const fileManager = new UHRPFileManager('https://nanostore.babbage.systems')
280
-
281
- console.log('=== UHRP File Manager Demo ===')
282
-
283
- // Upload different types of files
284
- const textData = new TextEncoder().encode('This is a text document for UHRP storage.')
285
- const jsonData = new TextEncoder().encode(JSON.stringify({
286
- message: 'Hello from UHRP',
287
- timestamp: new Date().toISOString(),
288
- data: [1, 2, 3, 4, 5]
289
- }))
290
-
291
- try {
292
- // Upload text file
293
- const textFile = await fileManager.uploadFile(
294
- textData,
295
- 'document.txt',
296
- 'text/plain',
297
- 30,
298
- ['document', 'text']
299
- )
300
-
301
- // Upload JSON file
302
- const jsonFile = await fileManager.uploadFile(
303
- jsonData,
304
- 'data.json',
305
- 'application/json',
306
- 60,
307
- ['data', 'json']
308
- )
309
-
310
- console.log('\n=== File Registry ===')
311
- const allFiles = fileManager.listFiles()
312
- allFiles.forEach(file => {
313
- console.log(`${file.originalName}: ${file.uhrpUrl}`)
314
- })
315
-
316
- // Test download
317
- console.log('\n=== Testing Download ===')
318
- const downloadResult = await fileManager.downloadFile(textFile.uhrpUrl)
319
- const content = new TextDecoder().decode(downloadResult.data)
320
- console.log('Downloaded content:', content)
321
-
322
- // Check expiring files
323
- console.log('\n=== Expiring Files ===')
324
- const expiringFiles = fileManager.getExpiringFiles(365) // Next year
325
- expiringFiles.forEach(file => {
326
- console.log(`${file.originalName} expires: ${file.expiryDate.toISOString()}`)
327
- })
328
-
329
- return { textFile, jsonFile, allFiles }
330
- } catch (error) {
331
- console.error('Demo failed:', error)
332
- }
333
- }
334
-
335
- demonstrateFileManager().catch(console.error)
336
- ```
337
-
338
- ## Advanced Features
339
-
340
- ### Batch Operations
341
-
342
- ```typescript
343
- import { StorageUploader, StorageDownloader, WalletClient } from '@bsv/sdk'
344
-
345
- class BatchFileOperations {
346
- private uploader: StorageUploader
347
- private downloader: StorageDownloader
348
-
349
- constructor(storageURL: string, wallet?: WalletClient) {
350
- this.uploader = new StorageUploader({
351
- storageURL,
352
- wallet: wallet || new WalletClient('auto', 'localhost')
353
- })
354
-
355
- this.downloader = new StorageDownloader()
356
- }
357
-
358
- async batchUpload(files: Array<{
359
- data: Uint8Array
360
- name: string
361
- type: string
362
- retention?: number
363
- }>): Promise<Array<{
364
- success: boolean
365
- file: string
366
- uhrpUrl?: string
367
- error?: string
368
- }>> {
369
- console.log(`Starting batch upload of ${files.length} files...`)
370
-
371
- const results = await Promise.allSettled(
372
- files.map(async (file) => {
373
- const fileObj = {
374
- data: file.data,
375
- type: file.type
376
- }
377
-
378
- const result = await this.uploader.publishFile({
379
- file: fileObj,
380
- retentionPeriod: (file.retention || 30) * 24 * 60
381
- })
382
-
383
- return { file: file.name, result }
384
- })
385
- )
386
-
387
- return results.map((result, index) => {
388
- const fileName = files[index].name
389
-
390
- if (result.status === 'fulfilled') {
391
- return {
392
- success: true,
393
- file: fileName,
394
- uhrpUrl: result.value.result.uhrpURL
395
- }
396
- } else {
397
- return {
398
- success: false,
399
- file: fileName,
400
- error: result.reason.message
401
- }
402
- }
403
- })
404
- }
405
-
406
- async batchDownload(uhrpUrls: string[]): Promise<Array<{
407
- success: boolean
408
- url: string
409
- data?: Uint8Array
410
- error?: string
411
- }>> {
412
- console.log(`Starting batch download of ${uhrpUrls.length} files...`)
413
-
414
- const results = await Promise.allSettled(
415
- uhrpUrls.map(url => this.downloader.download(url))
416
- )
417
-
418
- return results.map((result, index) => {
419
- const url = uhrpUrls[index]
420
-
421
- if (result.status === 'fulfilled') {
422
- return {
423
- success: true,
424
- url,
425
- data: result.value.data
426
- }
427
- } else {
428
- return {
429
- success: false,
430
- url,
431
- error: result.reason.message
432
- }
433
- }
434
- })
435
- }
436
- }
437
-
438
- async function demonstrateBatchOperations() {
439
- const batchOps = new BatchFileOperations('https://nanostore.babbage.systems')
440
-
441
- // Prepare test files
442
- const testFiles = [
443
- {
444
- data: new TextEncoder().encode('File 1 content'),
445
- name: 'file1.txt',
446
- type: 'text/plain'
447
- },
448
- {
449
- data: new TextEncoder().encode('File 2 content'),
450
- name: 'file2.txt',
451
- type: 'text/plain'
452
- },
453
- {
454
- data: new TextEncoder().encode(JSON.stringify({ test: 'data' })),
455
- name: 'data.json',
456
- type: 'application/json'
457
- }
458
- ]
459
-
460
- console.log('=== Batch Upload Demo ===')
461
- const uploadResults = await batchOps.batchUpload(testFiles)
462
-
463
- uploadResults.forEach(result => {
464
- if (result.success) {
465
- console.log(`✅ ${result.file}: ${result.uhrpUrl}`)
466
- } else {
467
- console.log(`❌ ${result.file}: ${result.error}`)
468
- }
469
- })
470
-
471
- // Extract successful URLs for download test
472
- const successfulUrls = uploadResults
473
- .filter(r => r.success && r.uhrpUrl)
474
- .map(r => r.uhrpUrl!)
475
-
476
- if (successfulUrls.length > 0) {
477
- console.log('\n=== Batch Download Demo ===')
478
- const downloadResults = await batchOps.batchDownload(successfulUrls)
479
-
480
- downloadResults.forEach(result => {
481
- if (result.success) {
482
- console.log(`✅ Downloaded: ${result.url} (${result.data?.length} bytes)`)
483
- } else {
484
- console.log(`❌ Failed: ${result.url} - ${result.error}`)
485
- }
486
- })
487
- }
488
-
489
- return { uploadResults, downloadResults: [] }
490
- }
491
-
492
- demonstrateBatchOperations().catch(console.error)
493
- ```
494
-
495
- ## Troubleshooting
496
-
497
- ### Common Issues and Solutions
498
-
499
- #### "No wallet available" Error
500
-
501
- **Problem**: StorageUploader fails with "No wallet available over any communication substrate"
502
- **Solution**:
503
-
504
- - Install and run a BRC-100 compliant wallet (e.g., MetaNet Desktop Wallet)
505
- - Ensure wallet is accessible at <http://localhost:3321>
506
- - Verify wallet is fully synced and has sufficient balance
507
-
508
- #### "401 Unauthorized" Error
509
-
510
- **Problem**: Upload operations fail with HTTP 401 errors
511
- **Solution**:
512
-
513
- - Verify your wallet is properly authenticated
514
- - Check that the UHRP storage service is available
515
- - Ensure your wallet has sufficient balance for storage fees
516
-
517
- #### "Invalid parameter UHRP url" Error
518
-
519
- **Problem**: Download operations fail with invalid URL error
520
- **Solution**:
521
-
522
- - Verify the UHRP URL format (should start with `uhrp://`)
523
- - Check that the file hasn’t expired
524
- - Ensure network connectivity for UHRP lookup services
525
-
526
- #### Download Works but Upload Fails
527
-
528
- **Problem**: StorageDownloader works but StorageUploader fails
529
- **Solution**: This is expected behavior without a wallet connection. StorageDownloader works independently, while StorageUploader requires wallet authentication.
530
-
531
- #### Service Unavailable
532
-
533
- **Problem**: UHRP storage service returns errors or is unreachable
534
- **Solution**:
535
-
536
- - Try alternative UHRP storage services
537
- - Check service status and availability
538
- - Consider setting up your own UHRP storage infrastructure
539
-
540
- ## Best Practices
541
-
542
- ### 1. File Management
543
-
544
- - Use meaningful file names and metadata
545
- - Implement proper retention policies
546
- - Tag files for easy organization and retrieval
547
-
548
- ### 2. Error Handling
549
-
550
- - Always validate file integrity after download
551
- - Implement retry logic for network failures
552
- - Handle storage quota and payment requirements
553
-
554
- ### 3. Performance
555
-
556
- - Use batch operations for multiple files
557
- - Implement caching for frequently accessed files
558
- - Monitor file expiration and renewal needs
559
-
560
- ### 4. Security
561
-
562
- - Encrypt sensitive files before upload
563
- - Use authenticated storage endpoints
564
- - Validate file types and sizes
565
-
566
- ## Summary
567
-
568
- In this tutorial, you learned how to:
569
-
570
- ✅ **Upload files to UHRP storage** with StorageUploader
571
- ✅ **Download and verify files** with StorageDownloader
572
- ✅ **Build file management systems** with metadata tracking
573
- ✅ **Implement batch operations** for multiple files
574
- ✅ **Handle file expiration** and renewal
575
-
576
- UHRP provides a robust foundation for decentralized file storage with content addressing and integrity verification.
577
-
578
- ## Next Steps
579
-
580
- - Learn about [Identity Management and Certificates](./identity-management.md)
581
- - Explore [AuthFetch for Authenticated HTTP Requests](./authfetch-tutorial.md)
582
- - Review [Security Best Practices](../guides/security-best-practices.md)
583
-
584
- UHRP provides a robust foundation for decentralized file storage with content addressing and integrity verification.
585
-
586
- The `WalletClient` provides the authentication and payment capabilities needed for UHRP operations.
587
-
588
- ## Setting Up UHRP with `WalletClient`
589
-
590
- The `WalletClient` handles authentication automatically when you create `StorageUploader` and `StorageDownloader` instances.
591
-
592
- ### How `WalletClient` Enables UHRP
593
-
594
- When you use UHRP with `WalletClient`:
595
-
596
- - You can upload files to decentralized storage networks.
597
- - You can download files from decentralized storage networks.
598
- - You can manage file metadata and track file expiration.
599
- - You can implement batch operations for multiple files.