95 lines
2.8 KiB
TypeScript
95 lines
2.8 KiB
TypeScript
/**
|
|
* Shared Blob Storage utilities.
|
|
*
|
|
* Delegates to @bytelyst/storage for provider-agnostic blob operations.
|
|
* Keeps the same exported API surface for backward compatibility.
|
|
*
|
|
* Expected env vars:
|
|
* STORAGE_PROVIDER — 'azure' (default) | 'memory'
|
|
* AZURE_BLOB_CONNECTION_STRING — full connection string (preferred, when provider=azure)
|
|
* — OR —
|
|
* AZURE_BLOB_ACCOUNT_NAME + AZURE_BLOB_ACCOUNT_KEY
|
|
*/
|
|
|
|
import {
|
|
getStorage,
|
|
_resetStorage,
|
|
type StorageProvider,
|
|
type StorageBucket,
|
|
} from '@bytelyst/storage';
|
|
|
|
/**
|
|
* Known blob containers and their purposes.
|
|
*
|
|
* Note: This is a convenience list (not enforced). Products can add their own
|
|
* containers as needed.
|
|
*/
|
|
export const BLOB_CONTAINERS = {
|
|
audio: 'audio', // Dictation audio recordings
|
|
transcripts: 'transcripts', // Exported transcript files (PDF, DOCX, TXT)
|
|
attachments: 'attachments', // Tracker item attachments (screenshots, docs)
|
|
avatars: 'avatars', // User profile images
|
|
releases: 'releases', // Desktop app update binaries
|
|
backups: 'backups', // Cosmos DB JSON backups
|
|
feedbackScreenshots: 'feedback-screenshots', // User feedback screenshot attachments
|
|
} as const;
|
|
|
|
export type BlobContainerName = (typeof BLOB_CONTAINERS)[keyof typeof BLOB_CONTAINERS];
|
|
|
|
/**
|
|
* Get the storage provider singleton.
|
|
*/
|
|
export async function getStorageProvider(): Promise<StorageProvider> {
|
|
return getStorage();
|
|
}
|
|
|
|
/**
|
|
* Get a bucket (container) by name.
|
|
*/
|
|
export async function getBucket(containerName: string): Promise<StorageBucket> {
|
|
const storage = await getStorage();
|
|
return storage.getBucket(containerName);
|
|
}
|
|
|
|
/**
|
|
* Generate a signed URL for direct browser upload (or download).
|
|
*
|
|
* @param containerName - Target container
|
|
* @param blobName - Full blob path (e.g., "product/user123/audio/recording.wav")
|
|
* @param permissions - SAS permissions (default: read)
|
|
* @param expiresInMinutes - Token lifetime (default: 60)
|
|
* @returns Full signed URL for the blob
|
|
*/
|
|
export async function generateSasUrl(
|
|
containerName: string,
|
|
blobName: string,
|
|
permissions: 'r' | 'w' | 'rw' | 'rwc' | 'rwd' = 'r',
|
|
expiresInMinutes = 60
|
|
): Promise<string> {
|
|
const bucket = await getBucket(containerName);
|
|
const perm = permissions.includes('w') ? ('write' as const) : ('read' as const);
|
|
return bucket.getSignedUrl(blobName, {
|
|
permissions: perm,
|
|
expiresIn: expiresInMinutes * 60,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Check if blob storage is configured.
|
|
*/
|
|
export function isBlobStorageConfigured(): boolean {
|
|
const provider = process.env.STORAGE_PROVIDER || 'azure';
|
|
if (provider === 'memory') return true;
|
|
return !!(
|
|
process.env.AZURE_BLOB_CONNECTION_STRING ||
|
|
(process.env.AZURE_BLOB_ACCOUNT_NAME && process.env.AZURE_BLOB_ACCOUNT_KEY)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Test helper: reset module singletons/caches.
|
|
*/
|
|
export function _resetBlobClient(): void {
|
|
_resetStorage();
|
|
}
|