CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-pouchdb-adapter-http

PouchDB adapter using HTTP for remote CouchDB connections and database operations

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

attachment-operations.mddocs/

Attachment Operations

File attachment management with support for binary data, proper content types, and efficient streaming for documents stored in remote CouchDB databases.

Capabilities

Attachment Retrieval

Retrieves a document attachment by its ID and returns the binary data.

/**
 * Get a document attachment by ID
 * @param docId - Document ID containing the attachment
 * @param attachmentId - Attachment ID within the document
 * @param opts - Retrieval options including revision
 * @param callback - Callback function receiving attachment data
 */
api.getAttachment(docId, attachmentId, opts, callback): void;

Usage Examples:

// Get attachment from latest document revision
db.getAttachment('user:john', 'profile-photo.jpg', (err, blob) => {
  if (err) {
    console.error('Attachment not found:', err);
    return;
  }
  
  console.log('Attachment size:', blob.size);
  console.log('Content type:', blob.type);
  
  // In browser - create download link
  if (typeof window !== 'undefined') {
    const url = URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url;
    link.download = 'profile-photo.jpg';
    link.click();
  }
  
  // In Node.js - save to file
  if (typeof process !== 'undefined' && !process.browser) {
    const fs = require('fs');
    fs.writeFileSync('downloaded-photo.jpg', blob);
  }
});

// Get attachment from specific revision
db.getAttachment('user:john', 'profile-photo.jpg', {
  rev: '2-abc123'
}, (err, blob) => {
  if (err) {
    console.error('Attachment not found in revision:', err);
    return;
  }
  
  console.log('Retrieved attachment from specific revision');
});

Attachment Creation/Update

Adds a new attachment to a document or updates an existing attachment.

/**
 * Add or update a document attachment
 * @param docId - Document ID to attach to
 * @param attachmentId - Attachment ID within the document
 * @param rev - Document revision (optional for new attachments)
 * @param blob - Attachment data (Blob, Buffer, or base64 string)
 * @param type - MIME content type
 * @param callback - Callback function receiving save result
 */
api.putAttachment(docId, attachmentId, rev, blob, type, callback): void;

Usage Examples:

// Add attachment to existing document
db.get('user:john', (err, doc) => {
  if (err) {
    console.error('Document not found:', err);
    return;
  }
  
  // In browser - from file input
  const fileInput = document.getElementById('photoInput');
  const file = fileInput.files[0];
  
  db.putAttachment('user:john', 'profile-photo.jpg', doc._rev, file, file.type, (err, result) => {
    if (err) {
      console.error('Attachment upload failed:', err);
      return;
    }
    
    console.log('Attachment saved, new revision:', result.rev);
  });
});

// Add attachment from base64 string
const base64Image = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==';

db.get('user:jane', (err, doc) => {
  if (err) {
    console.error('Document not found:', err);
    return;
  }
  
  db.putAttachment('user:jane', 'avatar.png', doc._rev, base64Image, 'image/png', (err, result) => {
    if (err) {
      console.error('Attachment upload failed:', err);
      return;
    }
    
    console.log('Base64 attachment saved:', result.rev);
  });
});

// Add attachment to new document (without revision)
const textData = new Blob(['Hello, world!'], { type: 'text/plain' });

db.putAttachment('note:greeting', 'content.txt', textData, 'text/plain', (err, result) => {
  if (err) {
    console.error('Attachment upload failed:', err);
    return;
  }
  
  console.log('Attachment saved to new document:', result.rev);
});

Attachment Deletion

Removes an attachment from a document.

/**
 * Remove an attachment from a document
 * @param docId - Document ID containing the attachment
 * @param attachmentId - Attachment ID to remove
 * @param rev - Current document revision
 * @param callback - Callback function receiving deletion result
 */
api.removeAttachment(docId, attachmentId, rev, callback): void;

Usage Examples:

// Remove attachment
db.get('user:john', (err, doc) => {
  if (err) {
    console.error('Document not found:', err);
    return;
  }
  
  // Check if attachment exists
  if (!doc._attachments || !doc._attachments['profile-photo.jpg']) {
    console.log('Attachment not found in document');
    return;
  }
  
  db.removeAttachment('user:john', 'profile-photo.jpg', doc._rev, (err, result) => {
    if (err) {
      console.error('Attachment removal failed:', err);
      return;
    }
    
    console.log('Attachment removed, new revision:', result.rev);
  });
});

// Remove multiple attachments
db.get('document:with-attachments', (err, doc) => {
  if (err) {
    console.error('Document not found:', err);
    return;
  }
  
  const attachmentIds = Object.keys(doc._attachments || {});
  
  // Remove attachments sequentially
  let currentRev = doc._rev;
  
  const removeNext = (index) => {
    if (index >= attachmentIds.length) {
      console.log('All attachments removed');
      return;
    }
    
    db.removeAttachment(doc._id, attachmentIds[index], currentRev, (err, result) => {
      if (err) {
        console.error(`Failed to remove ${attachmentIds[index]}:`, err);
        return;
      }
      
      currentRev = result.rev;
      console.log(`Removed ${attachmentIds[index]}`);
      removeNext(index + 1);
    });
  };
  
  removeNext(0);
});

Working with Different Data Types

Browser File Handling

// Handle file input in browsers
function handleFileUpload(event) {
  const file = event.target.files[0];
  if (!file) return;
  
  const docId = 'upload:' + Date.now();
  
  db.putAttachment(docId, file.name, file, file.type, (err, result) => {
    if (err) {
      console.error('Upload failed:', err);
      return;
    }
    
    console.log('File uploaded successfully:', result.rev);
  });
}

// Create download link for attachment
function downloadAttachment(docId, attachmentId) {
  db.getAttachment(docId, attachmentId, (err, blob) => {
    if (err) {
      console.error('Download failed:', err);
      return;
    }
    
    const url = URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url;
    link.download = attachmentId;
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    URL.revokeObjectURL(url);
  });
}

Node.js File Handling

const fs = require('fs');
const path = require('path');

// Upload file from filesystem
function uploadFile(filePath, docId) {
  const fileName = path.basename(filePath);
  const fileBuffer = fs.readFileSync(filePath);
  
  // Determine content type based on extension
  const ext = path.extname(fileName).toLowerCase();
  const contentType = {
    '.jpg': 'image/jpeg',
    '.jpeg': 'image/jpeg',
    '.png': 'image/png',
    '.pdf': 'application/pdf',
    '.txt': 'text/plain'
  }[ext] || 'application/octet-stream';
  
  db.putAttachment(docId, fileName, fileBuffer, contentType, (err, result) => {
    if (err) {
      console.error('File upload failed:', err);
      return;
    }
    
    console.log('File uploaded:', result.rev);
  });
}

// Save attachment to filesystem
function saveAttachment(docId, attachmentId, outputPath) {
  db.getAttachment(docId, attachmentId, (err, buffer) => {
    if (err) {
      console.error('Download failed:', err);
      return;
    }
    
    fs.writeFileSync(outputPath, buffer);
    console.log('Attachment saved to:', outputPath);
  });
}

Types

// Attachment data types
type AttachmentData = Blob | Buffer | string;

// Get attachment options
interface GetAttachmentOptions {
  rev?: string;
}

// Attachment info in document
interface AttachmentInfo {
  content_type: string;
  revpos: number;
  digest: string;
  length: number;
  stub: boolean;
  data?: string; // base64 data when fetched
}

// Document with attachments
interface DocumentWithAttachments extends PouchDoc {
  _attachments?: {
    [attachmentId: string]: AttachmentInfo;
  };
}

// Attachment operation result
interface AttachmentResult {
  ok: boolean;
  id: string;
  rev: string;
}

// Content type constants
type ContentType = 
  | 'image/jpeg'
  | 'image/png'
  | 'image/gif'
  | 'image/webp'
  | 'application/pdf'
  | 'text/plain'
  | 'text/html'
  | 'application/json'
  | 'application/octet-stream'
  | string;

Install with Tessl CLI

npx tessl i tessl/npm-pouchdb-adapter-http

docs

attachment-operations.md

changes-feed.md

database-operations.md

document-operations.md

http-utilities.md

index.md

tile.json