import Unixfs from 'ipfs-unixfs';
import { DAGNode, util as DAGUtil } from 'ipld-dag-pb';
export function isValidCID(input: string): boolean {
// Basic CID validation - checks if it matches common CID patterns
const cidPattern = /^(Qm[1-9A-HJ-NP-Za-km-z]{44}|baf[a-z0-9]{56}|ba[a-z0-9]{57}|b[a-z2-7]{58})$/;
return cidPattern.test(input);
}
export const getIpfsHash = (string: string): Promise<string> =>
new Promise((resolve, reject) => {
const unixFsFile = new Unixfs('file', Buffer.from(string));
const buffer = unixFsFile.marshal();
DAGNode.create(buffer, (err: any, dagNode: any) => {
if (err) {
reject(new Error('Cannot create ipfs DAGNode'));
}
DAGUtil.cid(dagNode, (error: any, cid: any) => {
if (error) {
reject(error);
} else {
resolve(cid.toBaseEncodedString());
}
});
});
});
export async function fetchFromGateway(gateway: string, cid: string): Promise<string> {
const url = `${gateway}/ipfs/${cid}`;
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Failed to fetch from gateway: ${response.status} ${response.statusText}`);
}
return await response.text();
}
export async function fetchContentFromGateway(gateway: string, cid: string): Promise<{
content: string;
mimeType: string;
isImage: boolean;
}> {
const url = `${gateway}/ipfs/${cid}`;
const response = await fetch(url);
if (!response.ok) {
throw new Error(`Failed to fetch from gateway: ${response.status} ${response.statusText}`);
}
const contentType = response.headers.get('content-type') || '';
const isImage = contentType.startsWith('image/');
if (isImage) {
// For images, return base64 encoded data
const arrayBuffer = await response.arrayBuffer();
const base64 = Buffer.from(arrayBuffer).toString('base64');
return {
content: base64,
mimeType: contentType,
isImage: true,
};
} else {
// For text content, return as string
const text = await response.text();
return {
content: text,
mimeType: contentType || 'text/plain',
isImage: false,
};
}
}
export function detectImageMimeFromContent(content: Buffer): string | null {
// Check for common image file signatures
if (content.length < 4) return null;
// PNG signature
if (content[0] === 0x89 && content[1] === 0x50 && content[2] === 0x4E && content[3] === 0x47) {
return 'image/png';
}
// JPEG signature
if (content[0] === 0xFF && content[1] === 0xD8 && content[2] === 0xFF) {
return 'image/jpeg';
}
// GIF signature
if (content[0] === 0x47 && content[1] === 0x49 && content[2] === 0x46) {
return 'image/gif';
}
// WebP signature
if (content.length >= 12 &&
content[0] === 0x52 && content[1] === 0x49 && content[2] === 0x46 && content[3] === 0x46 &&
content[8] === 0x57 && content[9] === 0x45 && content[10] === 0x42 && content[11] === 0x50) {
return 'image/webp';
}
// SVG signature (check for '<svg' or '<?xml' followed by 'svg')
const textStart = content.toString('utf8', 0, Math.min(100, content.length)).toLowerCase();
if (textStart.includes('<svg') || (textStart.includes('<?xml') && textStart.includes('svg'))) {
return 'image/svg+xml';
}
return null;
}