@atzentis/storage-sdk
v0.2.0
Published
Atzentis Storage SDK — TypeScript client for api.atzentis.cloud
Maintainers
Readme
@atzentis/storage-sdk
TypeScript client for the Atzentis Storage Cloud API (api.atzentis.cloud).
The core SDK ships a single StorageClient class that wraps the platform's
HTTP surface with API key authentication, tenant injection, automatic retry
on transient failures, timeout enforcement, typed error classes, and cursor
pagination helpers. Domain services in later phases (files, folders,
search, annotations, processing, usage) extend BaseService to share
this transport.
Installation
pnpm add @atzentis/storage-sdk zodzod is an optional peer dependency, used for runtime config validation.
Quick start
import { StorageClient } from "@atzentis/storage-sdk";
const storage = new StorageClient({
apiKey: process.env.ATZ_STORAGE_API_KEY!,
tenantId: process.env.ATZ_TENANT_ID!,
});
// Upload a file
const file = await storage.files.upload(blob);
// Search (hybrid)
const results = await storage.search.query({ q: "quarterly report" });
// Annotate
const annotation = await storage.annotations.create({
fileId: file.id,
type: "highlight",
position: { page: 1, x: 10, y: 20, width: 100, height: 30 },
});
// Run OCR and wait
const job = await storage.processing.ocr(file.id);
const completed = await job.completed();Domain services
| Accessor | Surface |
|---|---|
| client.files | upload, getUploadUrl, confirmUpload, getDownloadUrl, list, autoPaginate, get, update, delete (single + batch) |
| client.folders | create, get, list, autoPaginate, update, move, delete, getTree |
| client.search | query, fulltext, autoPaginateQuery, autoPaginateFulltext |
| client.annotations | create, get, listByFile, autoPaginateByFile, update, delete, reply, listReplies, autoPaginateReplies, deleteReply |
| client.processing | ocr, getOcrStatus, generateEmbedding, getEmbeddingStatus, generateThumbnail, getThumbnailStatus, getThumbnailUrl — every enqueue returns AwaitableJob<T> with a completed() poll helper |
| client.usage | getQuota, getUsage, getUsageHistory |
Configuration
| Option | Required | Default | Description |
| -------------- | -------- | ----------------------------- | ------------------------------------------------------ |
| apiKey | yes | — | API key — sent as Authorization: Bearer {apiKey} |
| tenantId | yes | — | Tenant identifier — sent as X-Tenant-ID: {tenantId} |
| baseUrl | no | https://api.atzentis.cloud | Override for sandbox / preview / self-hosted |
| timeoutMs | no | 30000 | Per-request timeout (ms) |
| maxRetries | no | 3 | Maximum retries on transient failures |
| retryDelayMs | no | 200 | Initial backoff delay (ms) |
| fetch | no | globalThis.fetch | Custom transport (e.g. undici, MSW, test mocks) |
Missing apiKey or tenantId throws StorageConfigError synchronously.
Errors
All errors extend BaseError and carry code + statusCode:
| Class | HTTP | Retryable |
| ---------------------- | ---- | --------- |
| ValidationError | 400 | no |
| AuthenticationError | 401 | no |
| PermissionError | 403 | no |
| NotFoundError | 404 | no |
| ConflictError | 409 | no |
| RateLimitError | 429 | yes |
| ServerError | 5xx | yes |
| ApiError | other| no |
| NetworkError | — | yes |
| TimeoutError | — | yes |
| StorageConfigError | — | no |
RateLimitError.retryAfter honors the server's Retry-After header.
Retry behavior
maxRetries + 1 total attempts. Backoff is exponential with full jitter,
capped at 8s. Only retryable errors trigger another attempt; validation and
permission errors fail fast.
// Disable retry for a single request
await storage.get("/files", undefined, { retry: false });Cursor pagination
import { paginate } from "@atzentis/storage-sdk";
for await (const file of paginate((p) => storage.get("/files", p))) {
console.log(file);
}paginate returns an AsyncIterable<T> and stops when the server reports
hasNextPage: false. Use collectAll for small result sets.
Extending: BaseService
import { BaseService } from "@atzentis/storage-sdk";
import type { PaginatedResult } from "@atzentis/storage-sdk";
class FilesService extends BaseService {
protected basePath = "/files";
list(params?: { limit?: number }): Promise<PaginatedResult<File>> {
return this._list<File>(params);
}
get(id: string): Promise<File> {
return this._get<File>(this._buildPath(id));
}
}License
MIT — © Atzentis
