File - Object Storage

Scalable object storage powered by Google Cloud Storage for files, media, documents, and model artifacts.

Overview

File provides managed object storage optimized for:

  • Document and file storage
  • Media assets (images, videos, audio)
  • ML model artifacts
  • Backup and archival
  • Static asset hosting

Quick Start

import { Tenzro } from 'tenzro';
const tenzro = new Tenzro({ apiKey: 'your-api-key' });
// Create a file bucket
const bucket = await tenzro.file.create({
projectId: 'project-id',
bucket_name: 'my-files',
storageClass: 'STANDARD',
});
// Get signed upload URL
const { uploadUrl, fileId } = await tenzro.file.getUploadUrl(bucket.bucket_id, {
fileName: 'document.pdf',
contentType: 'application/pdf',
folderPath: 'documents/',
});
// Upload file directly to signed URL (client-side)
await fetch(uploadUrl, {
method: 'PUT',
body: fileData,
headers: { 'Content-Type': 'application/pdf' },
});
// Get signed download URL
const { url } = await tenzro.file.getSignedUrl(bucket.bucket_id, fileId, {
action: 'read',
expiresIn: 3600, // 1 hour
});
console.log(url); // Time-limited download URL

SDK Reference

Bucket Management

Create Bucket

const bucket = await tenzro.file.create({
projectId: string,
bucket_name: string,
description?: string,
storageClass?: 'STANDARD' | 'NEARLINE' | 'COLDLINE' | 'ARCHIVE',
});

List Buckets

const { data, count } = await tenzro.file.list(projectId);

Get Statistics

const stats = await tenzro.file.getStats(bucketId);
// Returns: { fileCount, totalSize, folderCount }

Folder Operations

Create Folder

const folder = await tenzro.file.createFolder(
bucketId,
'documents/reports/2024/',
'Annual reports'
);

List Folders

const { data } = await tenzro.file.listFolders(bucketId, 'documents/');

Delete Folder

await tenzro.file.deleteFolder(bucketId, 'old-folder/');
// Deletes folder and all contents

File Operations

Get Upload URL

const { uploadUrl, fileId, expiresAt } = await tenzro.file.getUploadUrl(
bucketId,
{
fileName: string, // Required
contentType: string, // Required: MIME type
folderPath?: string, // Optional: folder path
expiresIn?: number, // Seconds until URL expires (default: 3600)
}
);

Get Signed URL

const { url, expiresIn } = await tenzro.file.getSignedUrl(
bucketId,
fileId,
{
action?: 'read' | 'write', // Default: 'read'
expiresIn?: number, // Seconds (default: 3600)
contentType?: string, // Required for 'write'
}
);

List Files

const { data, count } = await tenzro.file.listFiles(bucketId, {
prefix?: string, // Filter by path prefix
maxResults?: number, // Default: 100
});

Get File Metadata

const file = await tenzro.file.getFileMetadata(bucketId, fileId);
// Returns: { fileId, fileName, contentType, size, createdAt, ... }

Copy File

const copiedFile = await tenzro.file.copyFile(bucketId, fileId, {
destBucketId?: string, // Default: same bucket
destFileName?: string, // Default: same name
destFolderPath?: string, // Destination folder
});

Move File

const movedFile = await tenzro.file.moveFile(bucketId, fileId, {
destBucketId?: string,
destFileName?: string,
destFolderPath?: string,
});

Delete File

await tenzro.file.deleteFile(bucketId, fileId);

Storage Classes

ClassAccess PatternMin DurationUse Case
STANDARDFrequentNoneActive data, frequently accessed
NEARLINEMonthly30 daysBackups, accessed monthly
COLDLINEQuarterly90 daysArchives, accessed quarterly
ARCHIVEYearly365 daysLong-term archives

Use Cases

Document Upload (Browser)

// React component example
async function uploadDocument(file: File) {
// 1. Get signed upload URL from your backend
const { uploadUrl, fileId } = await fetch('/api/upload-url', {
method: 'POST',
body: JSON.stringify({
fileName: file.name,
contentType: file.type,
}),
}).then(r => r.json());
// 2. Upload directly to GCS
await fetch(uploadUrl, {
method: 'PUT',
body: file,
headers: {
'Content-Type': file.type,
},
});
return fileId;
}
// Backend API route
async function handleUploadUrl(req: Request) {
const { fileName, contentType } = await req.json();
const result = await tenzro.file.getUploadUrl(bucketId, {
fileName,
contentType,
folderPath: 'uploads/',
});
return Response.json(result);
}

Model Artifact Storage

// Store ML model
async function saveModel(modelName: string, modelData: ArrayBuffer) {
const { uploadUrl, fileId } = await tenzro.file.getUploadUrl(bucketId, {
fileName: `${modelName}.onnx`,
contentType: 'application/octet-stream',
folderPath: 'models/',
});
await fetch(uploadUrl, {
method: 'PUT',
body: modelData,
headers: { 'Content-Type': 'application/octet-stream' },
});
return fileId;
}
// Load model
async function loadModel(fileId: string) {
const { url } = await tenzro.file.getSignedUrl(bucketId, fileId, {
expiresIn: 3600,
});
const response = await fetch(url);
return response.arrayBuffer();
}

Image Gallery

// List images with thumbnails
async function getGalleryImages(folder = 'images/') {
const { data: files } = await tenzro.file.listFiles(bucketId, {
prefix: folder,
maxResults: 50,
});
// Generate temporary URLs for each image
const images = await Promise.all(
files
.filter(f => f.contentType?.startsWith('image/'))
.map(async (file) => {
const { url } = await tenzro.file.getSignedUrl(bucketId, file.file_id, {
expiresIn: 3600,
});
return {
id: file.file_id,
name: file.file_name,
url,
size: file.size,
};
})
);
return images;
}

CORS Configuration

For browser uploads, ensure CORS is configured. Contact support to configure CORS for your bucket.

{
"cors": [
{
"origin": ["https://your-app.com"],
"method": ["GET", "PUT", "POST"],
"responseHeader": ["Content-Type"],
"maxAgeSeconds": 3600
}
]
}

Best Practices

  • Use signed URLs: Never expose bucket credentials to clients
  • Set appropriate TTL: Use short expiration times for signed URLs
  • Organize with folders: Use folder paths for logical organization
  • Choose storage class wisely: Match storage class to access patterns
  • Set content types: Always specify correct MIME types
  • Use unique file names: Include timestamps or UUIDs in file names

Limits

ResourceLimit
Max file size5 TB
Max buckets per project100
Signed URL expiration7 days max
Max file name length1024 bytes
Max folder depthUnlimited