|
|
import { PinataSDK } from 'pinata'; |
|
|
|
|
|
export class IpfsService { |
|
|
private pinata: PinataSDK | null; |
|
|
private gatewayUrl: string; |
|
|
|
|
|
constructor() { |
|
|
const pinataJwt = process.env.PINATA_JWT || ''; |
|
|
const gatewayUrl = process.env.GATEWAY_URL || ''; |
|
|
|
|
|
if (!pinataJwt) { |
|
|
console.warn('PINATA_JWT not set - IPFS features will be disabled'); |
|
|
this.pinata = null; |
|
|
this.gatewayUrl = ''; |
|
|
} else { |
|
|
const gatewayDomain = gatewayUrl |
|
|
? gatewayUrl.replace(/^https?:\/\//, '').replace(/\/ipfs\/?$/, '') |
|
|
: 'gateway.pinata.cloud'; |
|
|
|
|
|
this.gatewayUrl = `https://${gatewayDomain}/ipfs/`; |
|
|
|
|
|
if (!gatewayUrl) { |
|
|
console.warn('GATEWAY_URL not set - using default Pinata gateway'); |
|
|
} |
|
|
|
|
|
this.pinata = new PinataSDK({ |
|
|
pinataJwt: pinataJwt, |
|
|
pinataGateway: gatewayDomain, |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
async uploadMetadata(metadata: { |
|
|
name: string; |
|
|
description: string; |
|
|
endpoint: string; |
|
|
price: number; |
|
|
creatorId: string; |
|
|
category?: string; |
|
|
capabilities?: string[]; |
|
|
metadata?: Record<string, any>; |
|
|
}): Promise<string> { |
|
|
if (!this.pinata) { |
|
|
throw new Error('Pinata JWT not configured'); |
|
|
} |
|
|
|
|
|
try { |
|
|
|
|
|
const jsonString = JSON.stringify(metadata); |
|
|
const file = new File( |
|
|
[jsonString], |
|
|
`agent-${metadata.name}-${Date.now()}.json`, |
|
|
{ type: 'application/json' } |
|
|
); |
|
|
|
|
|
const upload = await this.pinata.upload.public.file(file); |
|
|
|
|
|
|
|
|
return upload.cid; |
|
|
} catch (error) { |
|
|
console.error('IPFS upload error:', error); |
|
|
throw new Error('Failed to upload metadata to IPFS'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async getMetadata(cid: string): Promise<any> { |
|
|
if (!this.pinata) { |
|
|
throw new Error('Pinata JWT not configured'); |
|
|
} |
|
|
|
|
|
try { |
|
|
const data = await this.pinata.gateways.public.get(cid); |
|
|
return data; |
|
|
} catch (error) { |
|
|
console.error('IPFS fetch error:', error); |
|
|
throw new Error('Failed to fetch metadata from IPFS'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async uploadFile(file: File): Promise<{ cid: string; size: number }> { |
|
|
if (!this.pinata) { |
|
|
throw new Error('Pinata JWT not configured'); |
|
|
} |
|
|
|
|
|
try { |
|
|
const upload = await this.pinata.upload.public.file(file); |
|
|
return { |
|
|
cid: upload.cid, |
|
|
size: upload.size || file.size, |
|
|
}; |
|
|
} catch (error) { |
|
|
console.error('IPFS file upload error:', error); |
|
|
throw new Error('Failed to upload file to IPFS'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
getGatewayUrl(cid: string): string { |
|
|
if (this.gatewayUrl) { |
|
|
|
|
|
const base = this.gatewayUrl.endsWith('/') |
|
|
? this.gatewayUrl.slice(0, -1) |
|
|
: this.gatewayUrl; |
|
|
return `${base}/${cid}`; |
|
|
} |
|
|
|
|
|
return `https://gateway.pinata.cloud/ipfs/${cid}`; |
|
|
} |
|
|
} |
|
|
|