File size: 3,132 Bytes
b5e5eac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
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 {
      // Convert metadata object to JSON string for upload
      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 the CID (IPFS hash)
      return upload.cid;
    } catch (error) {
      console.error('IPFS upload error:', error);
      throw new Error('Failed to upload metadata to IPFS');
    }
  }

  /**
   * Get metadata from IPFS hash (CID)
   */
  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');
    }
  }

  /**
   * Upload file to 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');
    }
  }

  /**
   * Get gateway URL for IPFS hash (CID)
   * Uses the configured gateway to construct the URL
   */
  getGatewayUrl(cid: string): string {
    if (this.gatewayUrl) {
      // Remove trailing slash if present, add CID
      const base = this.gatewayUrl.endsWith('/')
        ? this.gatewayUrl.slice(0, -1)
        : this.gatewayUrl;
      return `${base}/${cid}`;
    }
    // Fallback to default gateway
    return `https://gateway.pinata.cloud/ipfs/${cid}`;
  }
}