import { blob as blobFromStream } from 'stream/consumers'; import { IPFSAddAll, IPFSRefsOptions, RefsReturnType, IPFSAdd, CreateIPFS } from './types'; import path from 'path'; import { ReadStream } from 'fs'; export const createIPFS: CreateIPFS = (ipfsOptions) => { console.log("Creating IPFS Client..."); const addAll: IPFSAddAll = async (values, options = {}) => { const formData = new FormData(); const queryParams = { 'chunker': options.chunker || 'rabin-131072-262144-524288', 'cid-version': String(options.cidVersion || 0), ...options.wrapWithDirectory && { 'wrap-with-directory': 'true' }, ...options.onlyHash && { 'only-hash': 'true' }, ...options.hash && { 'hash': options.hash }, ...options.pin && { 'pin': String(options.pin) }, }; const url = constructURL(ipfsOptions.url, 'api/v0/add', queryParams); for (const item of values) { const blob = await blobFromStream(item.content); formData.append('file', blob, item.path); } return await fetchAndParseJson(url, { keepalive: false, method: 'POST', body: formData, }); } const add: IPFSAdd = async (content: ReadStream, options) => { const data = await addAll([{ path: path.basename(String(content.path)), content, }], options); if (data.length !== 0) return data[data.length - 1]; throw new Error("No data returned from IPFS."); } const refs = async (ipfsPath: string, options: IPFSRefsOptions): Promise => { const queryParams = { 'arg': ipfsPath, ...options.recursive && { 'recursive': 'true' }, }; const url = constructURL(ipfsOptions.url, 'api/v0/refs', queryParams); return await fetchAndParseJson(url, { keepalive: false, method: 'POST', }); } return { addAll, add, refs } }; // Utility function to construct URL with search parameters function constructURL(baseUrl: string, path: string, queryParams: Record) { const url = new URL(`${baseUrl}/${path}`); url.search = new URLSearchParams( Object.entries(queryParams).reduce>((acc, [key, value]) => { if (value !== undefined) acc[key] = value; return acc; }, {}) ).toString(); return url; } // Utility function to handle HTTP requests and parse JSON responses async function fetchAndParseJson(url: URL | string, init?: RequestInit): Promise { const response = await fetch(url, init); if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); response.headers.forEach((value, key) => { console.log({ value, key }) }); const text = await response.text(); return text.trim().split('\n').filter(line => line).map(line => JSON.parse(line)); }