@vjeko.com/azure-blob
v1.0.0
Published
Helper for accessing Azure Storage BLOB functionality from Node.js applications (primarily concerned with Azure Functions)
Downloads
207
Readme
@vjeko.com/azure-blob
A TypeScript wrapper for Azure Blob Storage that simplifies blob operations through an intuitive object-based API. Instead of dealing with low-level Azure SDK calls, clients, streams, and configuration, you work with simple objects that handle all the complexity for you.
Table of Contents
Features
- Simple API – Read and write blobs with single method calls
- Type-Safe – Full TypeScript support with generics
- Multiple Content Types – JSON, string, and binary blob support
- Container Management – Create, list, and delete containers and blobs
- Concurrent Access – Built-in optimistic locking with automatic retries
- Secondary Indexes – Optional indexing for fast lookups
- Extensible – Easy to create custom blob types
Prerequisites
- Node.js 22 or higher
- An Azure Storage account
- TypeScript 5.0+ (if using TypeScript)
Why Use This Library?
Working directly with the Azure Storage Blob SDK requires managing service clients, container clients, block blob clients, streams, buffers, upload options, and error handling. This library abstracts all of that away:
// Before: Azure SDK directly
const serviceClient = BlobServiceClient.fromConnectionString(connectionString);
const containerClient = serviceClient.getContainerClient("users");
const blobClient = containerClient.getBlockBlobClient("john-doe.json");
const downloadResponse = await blobClient.download();
const content = await streamToBuffer(downloadResponse.readableStreamBody);
const user = JSON.parse(content.toString());
// After: This library
const blob = new Blob<User>("users://john-doe");
const user = await blob.read();Installation
npm install @vjeko.com/azure-blobConfiguration
Set the Azure Storage connection string as an environment variable:
AZURE_STORAGE_CONNECTION_STRING=<your-connection-string>Basic Usage
import { Blob } from "@vjeko.com/azure-blob";
interface User {
name: string;
email: string;
}
// Create a blob reference using "container://path" format
const userBlob = new Blob<User>("users://john-doe");
// Check existence
const exists = await userBlob.exists();
// Write data
await userBlob.write({ name: "John", email: "[email protected]" });
// Read data
const user = await userBlob.read();
// Read with default value if blob doesn't exist
const userOrDefault = await userBlob.read({ name: "Unknown", email: "" });
// Delete
await userBlob.delete();
// Copy to another location
await userBlob.copyTo("archive://users/john-doe");Blob Types
The library provides specialized blob classes for different content types:
Blob<T> – JSON Data
The primary class for storing typed objects with automatic JSON serialization.
import { Blob } from "@vjeko.com/azure-blob";
const configBlob = new Blob<AppConfig>("settings://app-config");
await configBlob.write({ theme: "dark", language: "en" });StringBlob – Plain Text
Stores raw string content without JSON serialization.
import { StringBlob } from "@vjeko.com/azure-blob";
const logBlob = new StringBlob("logs://2024-01-15.txt");
await logBlob.write("Application started at 10:00");BinaryBlob – Binary Data
Stores binary Buffer data directly for files, images, or other binary content.
import { BinaryBlob } from "@vjeko.com/azure-blob";
const imageBlob = new BinaryBlob("images://photo.png");
await imageBlob.write(imageBuffer);Container Operations
The BlobContainer class provides container-level operations:
import { BlobContainer } from "@vjeko.com/azure-blob";
const container = new BlobContainer("my-container");
// Create container
await container.createIfNotExists();
// Check existence
const exists = await container.exists();
// List blobs
for await (const blob of container.listBlobPaths("folder/")) {
console.log(blob.name);
}
// Delete a blob by path
await container.deleteBlobAtPath("folder/file.json");
// Delete the container
await container.delete();Concurrent Updates
For scenarios where multiple processes may update the same blob, the library provides safe update methods with automatic retry logic:
// Update a blob safely, even with concurrent access
await blob.optimisticUpdate(
(current) => ({ ...current, counter: current.counter + 1 }),
{ counter: 0 } // default value if blob doesn't exist
);
// Update only if the blob already exists
await blob.optimisticUpdateIfExists(
(current) => ({ ...current, lastAccess: new Date().toISOString() })
);Indexed Blobs
For advanced scenarios requiring fast lookups across multiple blobs, IndexedBlob maintains secondary indexes that are automatically updated on writes:
import { IndexedBlob } from "@vjeko.com/azure-blob";
const productBlob = new IndexedBlob<Product>(
"products://items",
"sku-12345",
[["category"], ["category", "inStock"]]
);
await productBlob.write({ name: "Widget", category: "electronics", inStock: true });
const index = await productBlob.readIndex("category");Extending
Create custom blob types by extending the base Blob<T> class:
import { Blob } from "@vjeko.com/azure-blob";
class EncryptedBlob<T> extends Blob<T> {
protected override serializeBeforeWrite(data: T): Buffer {
return encrypt(JSON.stringify(data));
}
protected override deserializeAfterRead(content: Buffer): T {
return JSON.parse(decrypt(content));
}
protected override readContent(buffer: Buffer): Buffer {
return buffer;
}
}API Reference
Blob<T>
| Method | Description |
|--------|-------------|
| exists() | Check if the blob exists |
| read(defaultValue?) | Read blob content, optionally with a default value |
| readBlob() | Read content along with ETag metadata |
| write(data, etag?, overwrite?) | Write data to the blob |
| delete(etag?) | Delete the blob |
| optimisticUpdate(update, default, timeout?, maxAttempts?) | Safe concurrent update with retries |
| optimisticUpdateIfExists(update, timeout?, maxAttempts?) | Update only if blob exists |
| copyTo(destination) | Copy blob to a new path |
BlobContainer
| Method | Description |
|--------|-------------|
| exists() | Check if the container exists |
| create(isPublic?) | Create the container |
| createIfNotExists(isPublic?) | Create if it doesn't exist |
| delete() | Delete the container |
| listBlobPaths(prefix) | List blobs matching a prefix |
| deleteBlobAtPath(path) | Delete a specific blob |
Contributing
Contributions are welcome! Here's how you can help:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Please make sure to:
- Update tests as appropriate
- Follow the existing code style
- Update documentation for any new features
Issues
Found a bug or have a feature request? Please open an issue with a clear description.
License
This project is licensed under the MIT License - see the LICENSE file for details.
