/** * meta.json format for authenticated torrent metadata * * Provides cryptographic proof of authorship using Ed25519 signatures. * Supports extensible metadata for audio, video, image, and document files. */ import { CryptoAdapter, KeyPair } from './crypto/adapter.js'; /** * Root meta.json structure */ export interface TorrentMeta { version: string; infohash?: string; created: number; title: string; description?: string; files: MetaFile[]; authors: MetaAuthor[]; extensions?: MetaExtensions; } /** * File entry with optional per-file metadata */ export interface MetaFile { path: string; size: number; type?: string; sha256?: string; role?: FileRole; meta?: FileMetaExtensions; } /** * Special file roles for cover art, thumbnails, etc. */ export type FileRole = 'cover' | 'thumbnail' | 'preview' | 'lyrics' | 'subtitles'; /** * Author entry with signature */ export interface MetaAuthor { publicKey: string; role?: AuthorRole; signedAt: number; signature: string; } /** * Author roles */ export type AuthorRole = 'creator' | 'co-author' | 'endorser'; /** * Torrent-level metadata extensions */ export interface MetaExtensions { audio?: AudioMeta; video?: VideoMeta; image?: ImageMeta; document?: DocumentMeta; } /** * Per-file metadata extensions */ export interface FileMetaExtensions { audio?: AudioFileMeta; video?: VideoMeta; image?: ImageMeta; document?: DocumentMeta; } /** * Audio metadata (torrent-level, e.g., album info) */ export interface AudioMeta { artist?: string; album?: string; genre?: string; year?: number; totalTracks?: number; } /** * Audio metadata (file-level, e.g., track info) */ export interface AudioFileMeta { title?: string; track?: number; duration?: number; artist?: string; bpm?: number; } /** * Video metadata */ export interface VideoMeta { duration?: number; width?: number; height?: number; codec?: string; framerate?: number; bitrate?: number; } /** * Image metadata */ export interface ImageMeta { width?: number; height?: number; format?: string; camera?: string; takenAt?: number; gps?: { lat: number; lon: number; }; } /** * Document metadata */ export interface DocumentMeta { pages?: number; author?: string; language?: string; format?: string; } /** * The canonical payload that gets signed * Includes author public keys to prevent fake co-author additions * Note: infohash is optional because we may not know it before signing * (torrent infohash includes meta.json, creating a chicken-egg problem) * Content authenticity is ensured by sha256 hashes in the files array */ export interface SigningPayload { created: number; title: string; files: MetaFile[]; authors: string[]; signedAt: number; } /** * Canonicalize an object to JSON with sorted keys (deterministic) * This ensures the same object always produces the same string for signing */ export declare function canonicalize(obj: unknown): string; /** * Build the signing payload from meta.json data */ export declare function buildSigningPayload(meta: Pick, authorPublicKeys: string[], signedAt: number): SigningPayload; /** * Sign a torrent meta.json * * @param crypto - Crypto adapter for signing * @param keyPair - The signer's key pair * @param meta - The meta.json data (without this author's signature) * @param authorPublicKeys - All author public keys (including this signer) * @param role - This author's role * @returns MetaAuthor entry with signature */ export declare function signMeta(crypto: CryptoAdapter, keyPair: KeyPair, meta: Pick, authorPublicKeys: string[], role?: AuthorRole): Promise; /** * Verify a single author's signature * * @param crypto - Crypto adapter for verification * @param meta - The meta.json data * @param author - The author entry to verify * @returns True if signature is valid */ export declare function verifyAuthorSignature(crypto: CryptoAdapter, meta: Pick, author: MetaAuthor): Promise; /** * Verify all author signatures in a meta.json * * @param crypto - Crypto adapter for verification * @param meta - The complete meta.json * @returns Object with verification results per author */ export declare function verifyMeta(crypto: CryptoAdapter, meta: TorrentMeta): Promise<{ valid: boolean; results: Map; }>; /** * Create a complete meta.json with signatures from all authors * * @param crypto - Crypto adapter for signing * @param options - Meta creation options * @returns Complete TorrentMeta with all signatures */ export declare function createMeta(crypto: CryptoAdapter, options: { title: string; description?: string; files: MetaFile[]; authors: Array<{ keyPair: KeyPair; role?: AuthorRole; }>; extensions?: MetaExtensions; infohash?: string; }): Promise; /** * Parse and validate a meta.json string * Does NOT verify signatures - use verifyMeta for that * * @param json - JSON string to parse * @returns Parsed TorrentMeta or null if invalid */ export declare function parseMeta(json: string): TorrentMeta | null; /** * Find a file with a specific role (e.g., cover art) */ export declare function findFileByRole(meta: TorrentMeta, role: FileRole): MetaFile | undefined; /** * Get the cover art file if present */ export declare function getCoverFile(meta: TorrentMeta): MetaFile | undefined; /** * Compute SHA256 hash of a file (browser-compatible) */ export declare function computeFileSha256(file: File | Blob | ArrayBuffer): Promise; /** * Build MetaFile entries from File objects with SHA256 hashes */ export declare function buildMetaFiles(files: File[]): Promise; /** * Set the infohash on a TorrentMeta after torrent creation * Note: This does NOT re-sign - infohash is informational only */ export declare function setInfohash(meta: TorrentMeta, infohash: string): TorrentMeta;