@autonomys/auto-files 1.4.34
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.
- package/README.md +1 -0
- package/package.json +22 -0
- package/src/api.ts +106 -0
- package/src/index.ts +1 -0
- package/src/utils.ts +18 -0
- package/tsconfig.json +11 -0
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# auto-files
|
package/package.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@autonomys/auto-files",
|
|
3
|
+
"version": "1.4.34",
|
|
4
|
+
"packageManager": "yarn@4.7.0",
|
|
5
|
+
"private": false,
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc"
|
|
8
|
+
},
|
|
9
|
+
"devDependencies": {
|
|
10
|
+
"typescript": "^5.5.4"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"require": "./dist/index.js",
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.d.ts"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@autonomys/auto-drive": "^1.4.34"
|
|
21
|
+
}
|
|
22
|
+
}
|
package/src/api.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { CompressionOptions, EncryptionOptions } from '@autonomys/auto-drive'
|
|
2
|
+
import { Readable } from 'stream'
|
|
3
|
+
import { withRetries } from './utils'
|
|
4
|
+
|
|
5
|
+
interface FetchedFile {
|
|
6
|
+
length: bigint
|
|
7
|
+
compression: CompressionOptions | undefined
|
|
8
|
+
encryption: EncryptionOptions | undefined
|
|
9
|
+
data: Readable
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Creates an API client for interacting with the Auto Files service
|
|
14
|
+
* @param baseUrl - The base URL of the Auto Files API
|
|
15
|
+
* @param apiSecret - The API secret key for authentication
|
|
16
|
+
* @returns An object containing methods to interact with the API
|
|
17
|
+
*/
|
|
18
|
+
export const createAutoFilesApi = (baseUrl: string, apiSecret: string) => {
|
|
19
|
+
/**
|
|
20
|
+
* Makes an authenticated fetch request to the API
|
|
21
|
+
* @param url - The URL to fetch from
|
|
22
|
+
* @param options - Optional fetch request options
|
|
23
|
+
* @returns A Promise that resolves to the fetch Response
|
|
24
|
+
*/
|
|
25
|
+
const authFetch = (url: string, options: RequestInit = {}) => {
|
|
26
|
+
const urlObj = new URL(url)
|
|
27
|
+
return fetch(urlObj.toString(), {
|
|
28
|
+
...options,
|
|
29
|
+
headers: { ...options.headers, Authorization: `Bearer ${apiSecret}` },
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Fetches a specific chunk of a file from the API
|
|
35
|
+
* @param cid - The content identifier of the file
|
|
36
|
+
* @param chunk - The chunk number to fetch
|
|
37
|
+
* @returns A Promise that resolves to the chunk data as ArrayBuffer, or null if chunk doesn't exist
|
|
38
|
+
* @throws Error if the chunk fetch fails
|
|
39
|
+
*/
|
|
40
|
+
const getChunk = async (cid: string, chunk: number): Promise<ArrayBuffer | null> => {
|
|
41
|
+
const response = await authFetch(`${baseUrl}/files/${cid}/partial?chunk=${chunk}`)
|
|
42
|
+
if (!response.ok) {
|
|
43
|
+
throw new Error('Error fetching chunk')
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (response.status === 204) {
|
|
47
|
+
return null
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const buffer = await response.arrayBuffer()
|
|
51
|
+
console.log('Chunk download finished:', buffer.byteLength)
|
|
52
|
+
return buffer
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Fetches a complete file from the API with support for progress tracking and retries
|
|
57
|
+
* @param cid - The content identifier of the file to fetch
|
|
58
|
+
* @param options - Optional configuration for the fetch operation
|
|
59
|
+
* @param options.retriesPerFetch - Number of retry attempts for failed requests (default: 3)
|
|
60
|
+
* @param options.onProgress - Optional callback function to track download progress (0-1)
|
|
61
|
+
* @returns A Promise that resolves to a FetchedFile object containing the file data and metadata
|
|
62
|
+
* @throws Error if the file metadata fetch fails
|
|
63
|
+
*/
|
|
64
|
+
const getFile = async (
|
|
65
|
+
cid: string,
|
|
66
|
+
{
|
|
67
|
+
retriesPerFetch = 3,
|
|
68
|
+
onProgress,
|
|
69
|
+
}: { retriesPerFetch?: number; onProgress?: (progress: number) => void } = {},
|
|
70
|
+
): Promise<FetchedFile> => {
|
|
71
|
+
const response = await withRetries(
|
|
72
|
+
() => authFetch(`${baseUrl}/files/${cid}/metadata`),
|
|
73
|
+
retriesPerFetch,
|
|
74
|
+
)
|
|
75
|
+
if (!response.ok) {
|
|
76
|
+
throw new Error('Error fetching file header')
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const metadata = await response.json()
|
|
80
|
+
|
|
81
|
+
// Parse size from string to bigint
|
|
82
|
+
const length = BigInt(metadata.size ?? 0)
|
|
83
|
+
|
|
84
|
+
const compression = metadata.uploadOptions?.compression
|
|
85
|
+
const encryption = metadata.uploadOptions?.encryption
|
|
86
|
+
|
|
87
|
+
let i = 0
|
|
88
|
+
let totalDownloaded = BigInt(0)
|
|
89
|
+
const precision = 10 ** 4
|
|
90
|
+
return {
|
|
91
|
+
data: new Readable({
|
|
92
|
+
async read() {
|
|
93
|
+
const chunk = await withRetries(() => getChunk(cid, i++), retriesPerFetch)
|
|
94
|
+
this.push(chunk ? Buffer.from(chunk) : null)
|
|
95
|
+
totalDownloaded += BigInt(chunk?.byteLength ?? 0)
|
|
96
|
+
onProgress?.(Number((BigInt(precision) * totalDownloaded) / length) / precision)
|
|
97
|
+
},
|
|
98
|
+
}),
|
|
99
|
+
length,
|
|
100
|
+
compression,
|
|
101
|
+
encryption,
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return { getFile }
|
|
106
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './api'
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const withRetries = <T>(fn: () => Promise<T>, retries: number, delay: number = 1000) => {
|
|
2
|
+
return new Promise<T>((resolve, reject) => {
|
|
3
|
+
const attempt = async () => {
|
|
4
|
+
try {
|
|
5
|
+
const result = await fn()
|
|
6
|
+
resolve(result)
|
|
7
|
+
} catch (error) {
|
|
8
|
+
if (retries > 0) {
|
|
9
|
+
await new Promise((resolve) => setTimeout(resolve, delay))
|
|
10
|
+
attempt()
|
|
11
|
+
} else {
|
|
12
|
+
reject(error)
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
attempt()
|
|
17
|
+
})
|
|
18
|
+
}
|