or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

attachment-operations.mdchanges-feed.mddatabase-operations.mddocument-operations.mdhttp-utilities.mdindex.md

attachment-operations.mddocs/

0

# Attachment Operations

1

2

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

3

4

## Capabilities

5

6

### Attachment Retrieval

7

8

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

9

10

```javascript { .api }

11

/**

12

* Get a document attachment by ID

13

* @param docId - Document ID containing the attachment

14

* @param attachmentId - Attachment ID within the document

15

* @param opts - Retrieval options including revision

16

* @param callback - Callback function receiving attachment data

17

*/

18

api.getAttachment(docId, attachmentId, opts, callback): void;

19

```

20

21

**Usage Examples:**

22

23

```javascript

24

// Get attachment from latest document revision

25

db.getAttachment('user:john', 'profile-photo.jpg', (err, blob) => {

26

if (err) {

27

console.error('Attachment not found:', err);

28

return;

29

}

30

31

console.log('Attachment size:', blob.size);

32

console.log('Content type:', blob.type);

33

34

// In browser - create download link

35

if (typeof window !== 'undefined') {

36

const url = URL.createObjectURL(blob);

37

const link = document.createElement('a');

38

link.href = url;

39

link.download = 'profile-photo.jpg';

40

link.click();

41

}

42

43

// In Node.js - save to file

44

if (typeof process !== 'undefined' && !process.browser) {

45

const fs = require('fs');

46

fs.writeFileSync('downloaded-photo.jpg', blob);

47

}

48

});

49

50

// Get attachment from specific revision

51

db.getAttachment('user:john', 'profile-photo.jpg', {

52

rev: '2-abc123'

53

}, (err, blob) => {

54

if (err) {

55

console.error('Attachment not found in revision:', err);

56

return;

57

}

58

59

console.log('Retrieved attachment from specific revision');

60

});

61

```

62

63

### Attachment Creation/Update

64

65

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

66

67

```javascript { .api }

68

/**

69

* Add or update a document attachment

70

* @param docId - Document ID to attach to

71

* @param attachmentId - Attachment ID within the document

72

* @param rev - Document revision (optional for new attachments)

73

* @param blob - Attachment data (Blob, Buffer, or base64 string)

74

* @param type - MIME content type

75

* @param callback - Callback function receiving save result

76

*/

77

api.putAttachment(docId, attachmentId, rev, blob, type, callback): void;

78

```

79

80

**Usage Examples:**

81

82

```javascript

83

// Add attachment to existing document

84

db.get('user:john', (err, doc) => {

85

if (err) {

86

console.error('Document not found:', err);

87

return;

88

}

89

90

// In browser - from file input

91

const fileInput = document.getElementById('photoInput');

92

const file = fileInput.files[0];

93

94

db.putAttachment('user:john', 'profile-photo.jpg', doc._rev, file, file.type, (err, result) => {

95

if (err) {

96

console.error('Attachment upload failed:', err);

97

return;

98

}

99

100

console.log('Attachment saved, new revision:', result.rev);

101

});

102

});

103

104

// Add attachment from base64 string

105

const base64Image = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==';

106

107

db.get('user:jane', (err, doc) => {

108

if (err) {

109

console.error('Document not found:', err);

110

return;

111

}

112

113

db.putAttachment('user:jane', 'avatar.png', doc._rev, base64Image, 'image/png', (err, result) => {

114

if (err) {

115

console.error('Attachment upload failed:', err);

116

return;

117

}

118

119

console.log('Base64 attachment saved:', result.rev);

120

});

121

});

122

123

// Add attachment to new document (without revision)

124

const textData = new Blob(['Hello, world!'], { type: 'text/plain' });

125

126

db.putAttachment('note:greeting', 'content.txt', textData, 'text/plain', (err, result) => {

127

if (err) {

128

console.error('Attachment upload failed:', err);

129

return;

130

}

131

132

console.log('Attachment saved to new document:', result.rev);

133

});

134

```

135

136

### Attachment Deletion

137

138

Removes an attachment from a document.

139

140

```javascript { .api }

141

/**

142

* Remove an attachment from a document

143

* @param docId - Document ID containing the attachment

144

* @param attachmentId - Attachment ID to remove

145

* @param rev - Current document revision

146

* @param callback - Callback function receiving deletion result

147

*/

148

api.removeAttachment(docId, attachmentId, rev, callback): void;

149

```

150

151

**Usage Examples:**

152

153

```javascript

154

// Remove attachment

155

db.get('user:john', (err, doc) => {

156

if (err) {

157

console.error('Document not found:', err);

158

return;

159

}

160

161

// Check if attachment exists

162

if (!doc._attachments || !doc._attachments['profile-photo.jpg']) {

163

console.log('Attachment not found in document');

164

return;

165

}

166

167

db.removeAttachment('user:john', 'profile-photo.jpg', doc._rev, (err, result) => {

168

if (err) {

169

console.error('Attachment removal failed:', err);

170

return;

171

}

172

173

console.log('Attachment removed, new revision:', result.rev);

174

});

175

});

176

177

// Remove multiple attachments

178

db.get('document:with-attachments', (err, doc) => {

179

if (err) {

180

console.error('Document not found:', err);

181

return;

182

}

183

184

const attachmentIds = Object.keys(doc._attachments || {});

185

186

// Remove attachments sequentially

187

let currentRev = doc._rev;

188

189

const removeNext = (index) => {

190

if (index >= attachmentIds.length) {

191

console.log('All attachments removed');

192

return;

193

}

194

195

db.removeAttachment(doc._id, attachmentIds[index], currentRev, (err, result) => {

196

if (err) {

197

console.error(`Failed to remove ${attachmentIds[index]}:`, err);

198

return;

199

}

200

201

currentRev = result.rev;

202

console.log(`Removed ${attachmentIds[index]}`);

203

removeNext(index + 1);

204

});

205

};

206

207

removeNext(0);

208

});

209

```

210

211

## Working with Different Data Types

212

213

### Browser File Handling

214

215

```javascript

216

// Handle file input in browsers

217

function handleFileUpload(event) {

218

const file = event.target.files[0];

219

if (!file) return;

220

221

const docId = 'upload:' + Date.now();

222

223

db.putAttachment(docId, file.name, file, file.type, (err, result) => {

224

if (err) {

225

console.error('Upload failed:', err);

226

return;

227

}

228

229

console.log('File uploaded successfully:', result.rev);

230

});

231

}

232

233

// Create download link for attachment

234

function downloadAttachment(docId, attachmentId) {

235

db.getAttachment(docId, attachmentId, (err, blob) => {

236

if (err) {

237

console.error('Download failed:', err);

238

return;

239

}

240

241

const url = URL.createObjectURL(blob);

242

const link = document.createElement('a');

243

link.href = url;

244

link.download = attachmentId;

245

document.body.appendChild(link);

246

link.click();

247

document.body.removeChild(link);

248

URL.revokeObjectURL(url);

249

});

250

}

251

```

252

253

### Node.js File Handling

254

255

```javascript

256

const fs = require('fs');

257

const path = require('path');

258

259

// Upload file from filesystem

260

function uploadFile(filePath, docId) {

261

const fileName = path.basename(filePath);

262

const fileBuffer = fs.readFileSync(filePath);

263

264

// Determine content type based on extension

265

const ext = path.extname(fileName).toLowerCase();

266

const contentType = {

267

'.jpg': 'image/jpeg',

268

'.jpeg': 'image/jpeg',

269

'.png': 'image/png',

270

'.pdf': 'application/pdf',

271

'.txt': 'text/plain'

272

}[ext] || 'application/octet-stream';

273

274

db.putAttachment(docId, fileName, fileBuffer, contentType, (err, result) => {

275

if (err) {

276

console.error('File upload failed:', err);

277

return;

278

}

279

280

console.log('File uploaded:', result.rev);

281

});

282

}

283

284

// Save attachment to filesystem

285

function saveAttachment(docId, attachmentId, outputPath) {

286

db.getAttachment(docId, attachmentId, (err, buffer) => {

287

if (err) {

288

console.error('Download failed:', err);

289

return;

290

}

291

292

fs.writeFileSync(outputPath, buffer);

293

console.log('Attachment saved to:', outputPath);

294

});

295

}

296

```

297

298

## Types

299

300

```javascript { .api }

301

// Attachment data types

302

type AttachmentData = Blob | Buffer | string;

303

304

// Get attachment options

305

interface GetAttachmentOptions {

306

rev?: string;

307

}

308

309

// Attachment info in document

310

interface AttachmentInfo {

311

content_type: string;

312

revpos: number;

313

digest: string;

314

length: number;

315

stub: boolean;

316

data?: string; // base64 data when fetched

317

}

318

319

// Document with attachments

320

interface DocumentWithAttachments extends PouchDoc {

321

_attachments?: {

322

[attachmentId: string]: AttachmentInfo;

323

};

324

}

325

326

// Attachment operation result

327

interface AttachmentResult {

328

ok: boolean;

329

id: string;

330

rev: string;

331

}

332

333

// Content type constants

334

type ContentType =

335

| 'image/jpeg'

336

| 'image/png'

337

| 'image/gif'

338

| 'image/webp'

339

| 'application/pdf'

340

| 'text/plain'

341

| 'text/html'

342

| 'application/json'

343

| 'application/octet-stream'

344

| string;

345

```