Package

Akadenia Azure Storage

A wrapper around Azure Storage SDK to make it easier to use

View on:

GithubNPM
Akadenia

@akadenia/azure-storage

npm versionLicense: MITTypeScript

A TypeScript library that wraps Azure Blob, Table, and Queue Storage with a clean, consistent API. Supports both connection strings and Managed Identity — so it works the same in local dev and production Azure environments.

Documentation · GitHub · Issues

Features

  • Blob Storage: Upload, download, list, and manage blobs with SAS URL support
  • Table Storage: Complete CRUD operations for Azure Table Storage
  • Queue Storage: Send, receive, and manage queue messages
  • Managed Identity Support: Passwordless authentication using Azure Managed Identity (system-assigned and user-assigned)
  • SAS URL Support: Generate Shared Access Signature URLs — User Delegation SAS with Managed Identity, Service SAS with connection strings
  • TypeScript Support: Full type definitions included
  • Error Handling: Built-in error handling and validation

Table of Contents

  • Installation
  • Quick Start
  • Blob Storage
  • Table Storage
  • Queue Storage
  • Configuration
  • Error Handling
  • Best Practices
  • API Reference
  • Contributing
  • License

Installation

npm install @akadenia/azure-storage --save

Quick Start

Prerequisites

You can authenticate using either:

  • Connection String: Get this from the Azure Portal under your storage account's "Access keys" section
  • Managed Identity: For applications running in Azure (recommended for production)

Option 1: Connection string

import { BlobStorage, TableStorage, QueueStorage } from '@akadenia/azure-storage';

const connectionString = "DefaultEndpointsProtocol=https;AccountName=yourstorageaccount;AccountKey=yourkey;EndpointSuffix=core.windows.net";

const blobStorage  = new BlobStorage(connectionString);
const tableStorage = new TableStorage(connectionString, 'tableName');
const queueStorage = new QueueStorage(connectionString);

Option 2: Managed Identity (recommended for production)

import { BlobStorage, TableStorage, QueueStorage } from '@akadenia/azure-storage';

const blobStorage  = new BlobStorage({ accountName: 'yourstorageaccount' });
const tableStorage = new TableStorage({ accountName: 'yourstorageaccount', tableName: 'tableName' });
const queueStorage = new QueueStorage({ accountName: 'yourstorageaccount' });

Blob Storage

The BlobStorage class provides methods to interact with Azure Blob Storage.

Basic Setup

import { BlobStorage } from '@akadenia/azure-storage';

const blobStorage = new BlobStorage(connectionString);

Container Operations

// Create a container
const containerCreated = await blobStorage.createContainer('my-container');
console.log('Container created:', containerCreated);

// Delete a container
const containerDeleted = await blobStorage.deleteContainer('my-container');
console.log('Container deleted:', containerDeleted);

Upload Operations

// Upload data from Buffer
const data = Buffer.from('Hello, Azure Blob Storage!');
const uploaded = await blobStorage.uploadData('my-container', 'my-blob.txt', data, {
  blobContentType: 'text/plain'
});

// Upload from stream
import { Readable } from 'stream';
const stream = Readable.from(['Stream data content']);
await blobStorage.uploadStream('my-container', 'stream-blob.txt', stream, {
  blobContentType: 'text/plain'
});

// Upload with additional headers
await blobStorage.uploadData('my-container', 'document.pdf', pdfBuffer, {
  blobContentType: 'application/pdf',
  blobCacheControl: 'max-age=3600',
  blobContentEncoding: 'gzip'
});

// Legacy upload method
await blobStorage.upload('my-container', 'file.pdf', buffer, buffer.length, 'application/pdf');

Download Operations

// Download blob as Buffer
const blobData = await blobStorage.downloadBlob('my-container', 'my-blob.txt');
console.log('Downloaded content:', blobData.toString());

// Check if blob exists before downloading
const exists = await blobStorage.blobExists('my-container', 'my-blob.txt');
if (exists) {
  const data = await blobStorage.downloadBlob('my-container', 'my-blob.txt');
}

List Operations

// List all blobs with a prefix
const blobs = await blobStorage.listBlobs('my-container', 'documents/');
blobs.forEach(blob => {
  console.log(`Blob: ${blob.name}, Size: ${blob.properties.contentLength}`);
});

Delete Operations

const deleted = await blobStorage.deleteBlob('my-container', 'my-blob.txt');
console.log('Blob deleted:', deleted);

SAS URL Generation

generateSASUrl supports two SAS token types automatically:

  • User Delegation SAS — used with Managed Identity (more secure, no account keys)
  • Service SAS — used with connection string authentication
import { BlobPermissions } from '@akadenia/azure-storage';

// Read-only SAS, 1 hour expiry
const sasUrl = await blobStorage.generateSASUrl('my-container', 'my-blob.txt', {
  startsOn: new Date(),
  expiresOn: new Date(Date.now() + 3600 * 1000),
  permissions: [BlobPermissions.READ]
});
console.log('SAS URL:', sasUrl.fullUrlWithSAS);

// Write-enabled container-level SAS
const containerSas = await blobStorage.generateSASUrl('my-container', undefined, {
  permissions: [BlobPermissions.ADD, BlobPermissions.WRITE],
  expiresOn: new Date(Date.now() + 24 * 3600 * 1000)
});

SAS Permissions

import { BlobPermissions } from '@akadenia/azure-storage';

BlobPermissions.READ    // "r"
BlobPermissions.WRITE   // "w"
BlobPermissions.CREATE  // "c"
BlobPermissions.DELETE  // "d"
BlobPermissions.ADD     // "a"

Table Storage

The TableStorage class provides methods to interact with Azure Table Storage.

Basic Setup

import { TableStorage, ITableEntity } from '@akadenia/azure-storage';

const tableStorage = new TableStorage(connectionString, 'MyTable');

Table Management

const tableCreated = await tableStorage.createTable();
const tableDeleted = await tableStorage.deleteTable();

Entity Operations

interface UserEntity extends ITableEntity {
  partitionKey: string;
  rowKey: string;
  name: string;
  email: string;
  age: number;
  isActive: boolean;
}

// Insert
const user: UserEntity = {
  partitionKey: 'users',
  rowKey: 'user-123',
  name: 'John Doe',
  email: 'john@example.com',
  age: 30,
  isActive: true
};
await tableStorage.insert(user);

// Get
const retrievedUser = await tableStorage.get('users', 'user-123');

// Update
user.age = 31;
await tableStorage.update(user);

// Upsert (insert or update)
await tableStorage.upsert(newUser);

// Delete
await tableStorage.delete('users', 'user-123');

List Operations

// List all entities
const allUsers = await tableStorage.list<UserEntity>();

// List with filter
const activeUsers = await tableStorage.list<UserEntity>({
  queryOptions: { filter: "isActive eq true and age gt 25" }
});

// Access underlying TableClient for advanced operations
const tableClient = tableStorage.getTableClient();

Queue Storage

The QueueStorage class provides methods to interact with Azure Queue Storage.

Basic Setup

import { QueueStorage } from '@akadenia/azure-storage';

const queueStorage = new QueueStorage(connectionString);
// or with Managed Identity:
const queueStorage = new QueueStorage({ accountName: 'yourstorageaccount' });

Message Operations

// Send a string message (base64 encoded by default)
await queueStorage.sendMessage('my-queue', 'Hello, Queue!');

// Send an object (auto JSON stringified + base64 encoded)
await queueStorage.sendMessage('my-queue', { orderNumber: '12345', action: 'process' });

// Send without base64 encoding
await queueStorage.sendMessage('my-queue', 'plain text', false);

// Receive messages
const { receivedMessageItems } = await queueStorage.receiveMessages('my-queue', 5, 30);

// Process and delete
for (const message of receivedMessageItems) {
  const decoded = Buffer.from(message.messageText, 'base64').toString('utf-8');
  const data = JSON.parse(decoded);
  // ... process data ...
  await queueStorage.deleteMessage('my-queue', message.messageId, message.popReceipt);
}

// Peek without consuming
const { peekedMessageItems } = await queueStorage.peekMessages('my-queue', 5);

Queue Management

await queueStorage.createQueue('my-new-queue');

const exists = await queueStorage.queueExists('my-queue');
const count  = await queueStorage.getMessageCount('my-queue');

await queueStorage.clearMessages('my-queue');
await queueStorage.deleteQueue('old-queue');

// Access underlying QueueClient for advanced options
const queueClient = queueStorage.getQueueClient('my-queue');
await queueClient.sendMessage('Custom', {
  visibilityTimeoutInSeconds: 30,
  timeToLiveInSeconds: 3600
});

Integration Example: Order Processing Pipeline

class OrderProcessor {
  private queueStorage: QueueStorage;

  constructor(connectionString: string) {
    this.queueStorage = new QueueStorage(connectionString);
  }

  async queueOrder(orderNumber: string): Promise<void> {
    await this.queueStorage.sendMessage('orders-to-process', { orderNumber, timestamp: Date.now() });
  }

  async processOrders(): Promise<void> {
    const { receivedMessageItems } = await this.queueStorage.receiveMessages('orders-to-process', 10);

    for (const message of receivedMessageItems) {
      try {
        const decoded = Buffer.from(message.messageText, 'base64').toString('utf-8');
        const order = JSON.parse(decoded);
        console.log(`Processing order ${order.orderNumber}`);
        await this.queueStorage.deleteMessage('orders-to-process', message.messageId, message.popReceipt);
      } catch (error) {
        console.error('Failed to process message:', error);
        // Message will become visible again after visibility timeout
      }
    }
  }
}

Configuration

Environment Variables

const connectionString = process.env.AZURE_STORAGE_CONNECTION_STRING;
if (!connectionString) throw new Error('AZURE_STORAGE_CONNECTION_STRING is required');

Local Development with Azurite

const blobStorage  = new BlobStorage("UseDevelopmentStorage=true");
const tableStorage = new TableStorage("UseDevelopmentStorage=true", 'MyTable');
const queueStorage = new QueueStorage("UseDevelopmentStorage=true");

Managed Identity Authentication

System-Assigned (Most Common)

Automatically created when you enable managed identity on your Azure resource — no client ID needed.

const blobStorage  = new BlobStorage({ accountName: 'yourstorageaccount' });
const tableStorage = new TableStorage({ accountName: 'yourstorageaccount', tableName: 'MyTable' });
const queueStorage = new QueueStorage({ accountName: 'yourstorageaccount' });

User-Assigned

A standalone identity shared across multiple Azure resources. Requires the client ID.

const blobStorage = new BlobStorage({
  accountName: 'yourstorageaccount',
  managedIdentityClientId: 'your-client-id'
});

Environment-Based Configuration

const blobStorage = process.env.NODE_ENV === 'production'
  ? new BlobStorage({ accountName: process.env.AZURE_STORAGE_ACCOUNT_NAME! })
  : new BlobStorage(process.env.AZURE_STORAGE_CONNECTION_STRING!);

Note: When using Managed Identity, ensure your Azure resource has the appropriate role assignments:

  • Storage Blob Data Contributor for Blob Storage
  • Storage Table Data Contributor for Table Storage
  • Storage Queue Data Contributor for Queue Storage

Error Handling

try {
  const blobData = await blobStorage.downloadBlob('container', 'non-existent.txt');
} catch (error) {
  if (error.statusCode === 404) {
    console.log('Blob not found');
  } else {
    console.error('Error downloading blob:', error);
  }
}

Best Practices

1. Use Managed Identity in Production

const blobStorage = process.env.NODE_ENV === 'production'
  ? new BlobStorage({ accountName: process.env.AZURE_STORAGE_ACCOUNT_NAME! })
  : new BlobStorage(process.env.AZURE_STORAGE_CONNECTION_STRING!);

2. Short-Lived SAS URLs

const sasUrl = await blobStorage.generateSASUrl('container', 'blob', {
  permissions: [BlobPermissions.READ],
  expiresOn: new Date(Date.now() + 3600 * 1000) // 1 hour max
});

3. Always Handle Errors

async function safeUpload(container: string, name: string, data: Buffer) {
  try {
    return await blobStorage.uploadData(container, name, data);
  } catch (error) {
    console.error('Upload failed:', error);
    throw error;
  }
}

4. Clean Up Temporary Resources

async function cleanup() {
  try {
    await blobStorage.deleteContainer('temp-container');
    await tableStorage.deleteTable();
  } catch (error) {
    console.error('Cleanup failed:', error);
  }
}

API Reference

BlobStorage

MethodDescriptionReturns
createContainer(containerName)Creates a container if it doesn't existPromise<boolean>
deleteContainer(containerName)Deletes a containerPromise<boolean>
upload(container, blob, buffer, length, contentType)Uploads a buffer (legacy)Promise<boolean>
uploadData(container, blob, data, headers?)Uploads a Buffer with optional headersPromise<boolean>
uploadStream(container, blob, stream, headers?)Uploads a readable streamPromise<boolean>
downloadBlob(container, blob)Downloads a blob as BufferPromise<Buffer>
blobExists(container, blob)Checks if a blob existsPromise<boolean>
listBlobs(container, prefix)Lists blobs with a prefixPromise<BlobItem[]>
deleteBlob(container, blob)Deletes a blobPromise<boolean>
generateSASUrl(container, blob?, options?)Generates a SAS URLPromise<SASUrlComponents>

TableStorage

MethodDescriptionReturns
createTable()Creates the tablePromise<boolean>
deleteTable()Deletes the tablePromise<boolean>
insert(entity)Inserts an entityPromise<boolean>
update(entity)Updates an entityPromise<boolean>
upsert(entity)Inserts or updates an entityPromise<boolean>
get(partitionKey, rowKey)Gets an entityPromise<GetTableEntityResponse>
delete(partitionKey, rowKey)Deletes an entityPromise<boolean>
list(options?)Lists entities with optional filterPromise<T[]>
getTableClient()Returns the underlying TableClientTableClient

QueueStorage

MethodDescriptionReturns
getQueueClient(queueName)Gets a QueueClientQueueClient
sendMessage(queue, message, base64Encode?)Sends a messagePromise<QueueSendMessageResponse>
receiveMessages(queue, maxMessages?, visibilityTimeout?)Receives messagesPromise<any>
deleteMessage(queue, messageId, popReceipt)Deletes a messagePromise<void>
peekMessages(queue, maxMessages?)Peeks messages without consumingPromise<any>
clearMessages(queue)Clears all messagesPromise<void>
createQueue(queue)Creates a queuePromise<void>
deleteQueue(queue)Deletes a queuePromise<void>
queueExists(queue)Checks if a queue existsPromise<boolean>
getMessageCount(queue)Gets approximate message countPromise<number>

Contributing

We welcome contributions! Please feel free to submit a Pull Request.

Development Setup

git clone https://github.com/akadenia/AkadeniaAzureStorage.git
cd AkadeniaAzureStorage
npm install
npm run build
npm run test:with-azurite  # requires Azurite running locally

Commit Message Guidelines

We follow Conventional Commits. Scope is required.
type(scope): description

Common scopes: blob · table · queue · docs · deps · test · build · ci

Types: feat · fix · docs · style · refactor · test · chore

Requirements

  • Node.js >= 20
  • Azure Storage account (or Azurite for local development)

License

MIT

Support

For support, please open an issue on GitHub.

More

Akadenia API

Akadenia API is an opinionated Axios wrapper simplifying HTTP requests with intuitive methods, enhanced error handling, retries, and consistent API responses.

Akadenia Helpers

Akadenia Helpers is a library with modular utilities like DateHelpers, MapHelpers, and more, simplifying coding tasks across various use cases with ease