Skip to main content

Overview

VK-IO provides strongly-typed attachment classes for all VK media types. Each attachment type has its own class with specific properties and methods.

Base Attachment Class

All attachments extend the base Attachment class which provides common functionality:
import { Attachment } from 'vk-io';

// Properties available on all attachments
attachment.id          // Attachment ID
attachment.ownerId     // Owner ID
attachment.accessKey   // Access key (if present)
attachment.type        // Attachment type
attachment.isFilled    // Whether full data is loaded

// Methods
attachment.toString()               // Returns "type{ownerId}_{id}_{accessKey}"
attachment.equals(otherAttachment)  // Compare attachments
attachment.toJSON()                 // Serialize to JSON

Parsing Attachments

// Parse from string
const attachment = Attachment.fromString('photo-1_456239099', vk.api);

console.log(attachment.type);     // "photo"
console.log(attachment.ownerId);  // -1
console.log(attachment.id);       // 456239099

Attachment Types

VK-IO supports all VK attachment types with dedicated classes:

PhotoAttachment

Photos with multiple sizes and metadata.
import { PhotoAttachment } from 'vk-io';

// From message
context.attachments.forEach(attachment => {
  if (attachment instanceof PhotoAttachment) {
    console.log('Photo ID:', attachment.id);
    console.log('Album ID:', attachment.albumId);
    console.log('Text:', attachment.text);
    console.log('Dimensions:', attachment.width, 'x', attachment.height);
    
    // Get photo URLs
    console.log('Small:', attachment.smallSizeUrl);
    console.log('Medium:', attachment.mediumSizeUrl);
    console.log('Large:', attachment.largeSizeUrl);
    
    // Access all sizes
    attachment.sizes?.forEach(size => {
      console.log(`Size ${size.type}: ${size.url} (${size.width}x${size.height})`);
    });
  }
});
Properties:
  • userId - User who uploaded the photo
  • albumId - Album ID
  • text - Photo caption
  • createdAt - Upload timestamp
  • width / height - Dimensions
  • sizes - Array of all available sizes
  • smallSizeUrl - URL for small size (130 or 75px)
  • mediumSizeUrl - URL for medium size (807, 604px or less)
  • largeSizeUrl - URL for large size (2560, 1280px or less)
Methods:
  • getSizes(sizeTypes: string[]) - Get specific sizes by type
  • loadAttachmentPayload() - Load full data from API

More Attachment Types

WallAttachment

Wall posts with full metadata.
import { WallAttachment } from 'vk-io';

context.attachments.forEach(attachment => {
  if (attachment instanceof WallAttachment) {
    console.log('Post text:', attachment.text);
    console.log('Author ID:', attachment.authorId);
    console.log('Created:', new Date(attachment.createdAt! * 1000));
    
    // Statistics
    console.log('Likes:', attachment.likesCount);
    console.log('Comments:', attachment.commentsCount);
    console.log('Reposts:', attachment.repostsCount);
    console.log('Views:', attachment.viewsCount);
    
    // Nested attachments
    console.log('Attachments:', attachment.attachments.length);
    
    // Repost chain
    if (attachment.copyHistory) {
      console.log('Repost chain length:', attachment.copyHistory.length);
    }
    
    // Permissions
    if (attachment.isCanEdit) {
      console.log('You can edit this post');
    }
  }
});
Properties:
  • text - Post text
  • authorId / signerId - Author information
  • createdAt - Timestamp
  • postType - Post type
  • Statistics: likesCount, commentsCount, repostsCount, viewsCount
  • attachments - Nested attachments array
  • copyHistory - Repost chain
  • Permissions: isCanEdit, isCanDelete, isCanPin, isCanCommented
  • Status: isPinned, hasAds, isFavorited

Working with Attachments

Loading Full Data

Most attachments have partial data initially. Load full data when needed:
const photo = context.attachments[0] as PhotoAttachment;

if (!photo.isFilled) {
  await photo.loadAttachmentPayload();
}

// Now all data is available
console.log('Album ID:', photo.albumId);
console.log('Upload date:', photo.createdAt);

Type Checking

import { 
  PhotoAttachment, 
  VideoAttachment, 
  DocumentAttachment,
  AttachmentType 
} from 'vk-io';

for (const attachment of context.attachments) {
  // Using instanceof
  if (attachment instanceof PhotoAttachment) {
    console.log('Photo:', attachment.largeSizeUrl);
  }
  
  // Using type property
  if (attachment.type === AttachmentType.VIDEO) {
    const video = attachment as VideoAttachment;
    console.log('Video:', video.player);
  }
  
  // Type guards
  switch (attachment.type) {
    case 'photo':
      handlePhoto(attachment as PhotoAttachment);
      break;
    case 'video':
      handleVideo(attachment as VideoAttachment);
      break;
    case 'doc':
      handleDocument(attachment as DocumentAttachment);
      break;
  }
}

Filtering Attachments

// Get only photos
const photos = context.attachments.filter(
  (a): a is PhotoAttachment => a instanceof PhotoAttachment
);

// Get only videos and documents
const media = context.attachments.filter(a => 
  a instanceof VideoAttachment || a instanceof DocumentAttachment
);

// Get first photo
const firstPhoto = context.attachments.find(
  (a): a is PhotoAttachment => a instanceof PhotoAttachment
);

Sending Attachments

// Forward attachments
await context.send({
  message: 'Check this out!',
  attachment: context.attachments
});

// Send specific attachments
const photos = context.attachments.filter(
  (a): a is PhotoAttachment => a instanceof PhotoAttachment
);
await context.send({
  message: 'Photos only',
  attachment: photos
});

// Mix attachments from different sources
await context.send({
  message: 'Mixed content',
  attachment: [
    context.attachments[0],
    'photo-1_456239099',
    await vk.upload.messagePhoto({
      source: './image.jpg'
    })
  ]
});

Transform Attachments

Convert raw API data to attachment objects:
import { transformAttachments } from 'vk-io';

const rawAttachments = [
  { type: 'photo', photo: { id: 1, owner_id: -1, ... } },
  { type: 'video', video: { id: 2, owner_id: -1, ... } }
];

const attachments = transformAttachments(rawAttachments, vk.api);

attachments.forEach(attachment => {
  console.log(`${attachment.type}: ${attachment.toString()}`);
});

Advanced Patterns

Download All Photos

import { PhotoAttachment } from 'vk-io';
import { writeFile } from 'fs/promises';
import fetch from 'node-fetch';

async function downloadPhotos(attachments: Attachment[]) {
  const photos = attachments.filter(
    (a): a is PhotoAttachment => a instanceof PhotoAttachment
  );
  
  for (const photo of photos) {
    const url = photo.largeSizeUrl || photo.mediumSizeUrl;
    if (!url) continue;
    
    const response = await fetch(url);
    const buffer = await response.buffer();
    await writeFile(`photo_${photo.id}.jpg`, buffer);
    
    console.log(`Downloaded: photo_${photo.id}.jpg`);
  }
}

await downloadPhotos(context.attachments);

Process Documents by Type

import { DocumentAttachment } from 'vk-io';

function processDocuments(attachments: Attachment[]) {
  const docs = attachments.filter(
    (a): a is DocumentAttachment => a instanceof DocumentAttachment
  );
  
  for (const doc of docs) {
    if (doc.isGif) {
      console.log(`GIF: ${doc.url}`);
    } else if (doc.isVoice) {
      const duration = doc.preview?.audio_message?.duration;
      console.log(`Voice message: ${duration}s`);
    } else if (doc.isImage) {
      console.log(`Image: ${doc.title} (${doc.size} bytes)`);
    } else {
      console.log(`File: ${doc.title}.${doc.extension}`);
    }
  }
}
Some attachment types (like audio) may have restricted access depending on VK API permissions and privacy settings.
Attachment classes are implemented in:
  • /packages/vk-io/src/structures/attachments/attachment.ts:27 - Base Attachment class
  • /packages/vk-io/src/structures/attachments/photo.ts:34 - PhotoAttachment
  • /packages/vk-io/src/structures/attachments/video.ts:32 - VideoAttachment
  • /packages/vk-io/src/structures/attachments/audio.ts:25 - AudioAttachment
  • /packages/vk-io/src/structures/attachments/document.ts:37 - DocumentAttachment
  • And more in the same directory

Build docs developers (and LLMs) love