@sen-use/web3
Version:
The library for Sentre
85 lines (78 loc) • 2.43 kB
text/typescript
import { File, Web3Storage } from 'web3.storage'
import { CID } from 'multiformats/cid'
import { DataLoader } from './dataloader'
export class IPFS<
MapTypes extends Record<string, any>,
T extends Array<keyof MapTypes>,
> {
private provider: Web3Storage
constructor(
private key: string,
private IDL: T,
private endpoint = 'https://api.web3.storage',
) {
this.provider = new Web3Storage({
endpoint: new URL(this.endpoint),
token: this.key,
})
}
decodeCID = (digest: string | Buffer | Uint8Array | number[]) => {
if (typeof digest === 'string') return digest
const v0Prefix = new Uint8Array([18, 32])
const v0Digest = new Uint8Array(v0Prefix.length + digest?.length)
v0Digest.set(v0Prefix) // multicodec + length
v0Digest.set(digest, v0Prefix.length)
const cid = CID.decode(v0Digest)
return cid.toString()
}
get methods() {
const methods: {
[x in T[number]]: {
get: (
digest: string | Buffer | Uint8Array | number[],
) => Promise<MapTypes[x]>
set: (data: MapTypes[x]) => Promise<{ cid: string; digest: Uint8Array }>
}
} = {} as any
for (const elm of this.IDL) {
methods[elm] = {
set: (data) => this.set(data),
get: (digest) => this.get(digest),
}
}
return methods
}
private async set(data: any): Promise<any> {
const file = new File([JSON.stringify(data)], 'file', {
type: 'application/json',
})
const cid = await this.provider.put([file])
const {
multihash: { digest },
} = CID.parse(cid)
return { cid, digest }
}
private async get(
digest: string | Buffer | Uint8Array | number[],
): Promise<any> {
const cid = this.decodeCID(digest)
return DataLoader.load(`ipfs:${cid}`, async () => {
const re = await this.provider.get(cid)
const file = ((await re?.files()) || [])[0]
const reader = new FileReader()
return new Promise((resolve, reject) => {
try {
if (!file) throw new Error('Cannot read empty file')
reader.onload = () => {
const contents = reader.result?.toString()
if (!contents) throw new Error('Cannot read empty file')
return resolve(JSON.parse(contents))
}
reader.readAsText(file)
} catch (er: any) {
return reject(er.message)
}
})
})
}
}