@metalevel/snapix-sdk-core
v1.0.0
Published
TypeScript SDK for the Snapix REST API - image upload, conversion, resizing, gallery management, and AI generation
Maintainers
Readme
@metalevel/snapix-sdk-core
Typed TypeScript SDK for the Snapix REST API - image upload, on-the-fly conversion, resizing, gallery management, and AI generation. Three client classes cover every runtime: a full-featured Node.js server client, a browser-safe client for any JS runtime, and an abstract base you can extend directly.
- Full TypeScript types for all requests and responses
- Zero runtime dependencies - uses native
fetchandFormData - Three client classes -
SnapixClientServer(Node.js, full CRUD),SnapixClientBrowser(any JS runtime, read + convert),SnapixClientBasic(abstract base) - Auto-configuration from environment variables
Installation
npm install @metalevel/snapix-sdk-coreor
pnpm add @metalevel/snapix-sdk-coreQuick Start
SnapixClientServer
Upload an image from your Node.js server using SNAPIX_API_KEY:
export SNAPIX_API_KEY=your_api_key_hereimport { SnapixClientServer } from "@metalevel/snapix-sdk-core";
const client = new SnapixClientServer(); // reads SNAPIX_API_KEY from env
const result = await client.uploadImage({
imageUrl: "https://example.com/photo.jpg",
name: "my-photo",
formatOptions: [{ format: "webp" }],
});
console.log(result.simpleData.variants);
// { webp: "https://cdn.snapix.space/..." }SnapixClientBrowser
Read images and galleries safely in any JS runtime using NEXT_PUBLIC_SNAPIX_API_KEY. A read-only API key is sufficient and recommended:
export NEXT_PUBLIC_SNAPIX_API_KEY=your_read_only_api_key_hereimport { SnapixClientBrowser } from "@metalevel/snapix-sdk-core/browser";
const client = new SnapixClientBrowser(); // reads NEXT_PUBLIC_SNAPIX_API_KEY from env
// List galleries
const { galleries } = await client.listGalleries();
// List images with pagination
const { data: images, simpleData } = await client.listImages({ page: 1, limit: 10 });
// Get a single image
const { data: image } = await client.getImage({ imageId: "image-uuid" });
console.log(image.urlBase, image.metadata);Class Hierarchy
SnapixClientBasic (abstract - shared read methods, zero Node.js deps)
├── SnapixClientServer (full CRUD + Node.js file I/O, uses SNAPIX_* env vars)
└── SnapixClientBrowser (read + convert, browser-safe, uses NEXT_PUBLIC_SNAPIX_* env vars)SnapixClientBasic is the abstract base - you do not instantiate it directly. Use SnapixClientServer in Node.js environments for full access to upload, generate, and gallery write operations. Use SnapixClientBrowser in browsers, edge runtimes, or any environment where you only need read access and on-the-fly image conversion with a restricted API key.
Package Exports
The SDK ships three dedicated entry points. Use the subpath that matches your runtime — importing from the wrong one will cause build errors in browser-targeting bundlers (Turbopack, Webpack, Vite, etc.).
Why three entry points?
SnapixClientServer uses node:fs/promises for file I/O. Browser bundlers statically resolve every import in a module's graph, even code you never call at runtime. When a barrel file re-exports both SnapixClientServer and SnapixClientBrowser together, the bundler tries to include node:fs/promises in the browser chunk and fails with:
the chunking context does not support external modules (request: node:fs/promises)Dedicated subpath exports ensure each entry point only pulls in what its target runtime supports.
Subpath exports
| Import path | Class | Use in |
| --- | --- | --- |
| @metalevel/snapix-sdk-core | SnapixClientServer | Node.js server, MCP server, Next.js server actions, API routes |
| @metalevel/snapix-sdk-core/browser | SnapixClientBrowser | Browser, Next.js client components, edge runtimes |
| @metalevel/snapix-sdk-core/basic | SnapixClientBasic | Custom subclasses only |
| @metalevel/snapix-sdk-core/server | SnapixClientServer | Alias for root — identical to "." |
All subpaths export the error classes (SnapixApiError, SnapixConfigError) and all TypeScript types relevant to that client.
SnapixClientBasic
The abstract base class shared by both subclasses. It holds all read methods and requires zero Node.js dependencies. Use it only if you are extending the SDK with a custom subclass; otherwise use SnapixClientServer or SnapixClientBrowser directly.
Configuration
Pass options directly to the constructor:
// When subclassing SnapixClientBasic directly:
super({
apiKey: "your_api_key",
baseUrl: "https://www.snapix.space", // optional
bucketKey: "my-bucket", // optional
logLevel: "debug", // optional
});Logging
The logLevel option (or the corresponding env var on each subclass) controls log verbosity:
| Level | Description |
| --- | --- |
| debug | All requests logged with method + URL |
| info | Informational messages (e.g., file written) |
| warn | Rate limit hits (HTTP 429) |
| error | API errors, quota exceeded |
| silent | No output |
Read Methods
All read methods are inherited by both SnapixClientServer and SnapixClientBrowser:
// List images with optional pagination and filters
await client.listImages(params?: ListImagesParams): Promise<ListImagesResponse>
// params: { page?, limit?, sort?: "asc" | "desc", bucketKey? }
// response includes: data, simpleData, accountStatistics, pagination
// Get a single image by ID
await client.getImage(params: GetImageParams): Promise<GetImageResponse>
// params: { imageId }
// List all galleries
await client.listGalleries(): Promise<ListGalleriesResponse>
// Get a single gallery with its images
await client.getGallery(params: GetGalleryParams): Promise<GetGalleryResponse>
// params: { galleryId }
// Get images not assigned to any gallery
await client.getImagesWithoutGallery(params?: GetImagesWithoutGalleryParams): Promise<GetGalleryResponse>
// params: { bucketKey? }
// Fetch a documentation page as Markdown
await client.getDocs(params: GetDocsParams): Promise<string>
// params: { docType: "sdk" | "api" | "mcp" | "about" }Error Handling
Both SnapixApiError and SnapixConfigError are thrown by all three client classes. Import them from the same subpath as your client:
// Server / Node.js
import { SnapixClientServer, SnapixApiError, SnapixConfigError } from "@metalevel/snapix-sdk-core";
// Browser / client components
// import { SnapixClientBrowser, SnapixApiError, SnapixConfigError } from "@metalevel/snapix-sdk-core/browser";
try {
const client = new SnapixClientServer();
await client.uploadImage({ imageUrl: "https://example.com/photo.jpg" });
} catch (err) {
if (err instanceof SnapixConfigError) {
// Missing SNAPIX_API_KEY or invalid configuration
console.error("Config error:", err.message);
} else if (err instanceof SnapixApiError) {
console.error("API error:", err.status, err.message);
if (err.isRetryable) { /* HTTP 429 - retry after backoff */ }
if (err.isReadOnly) { /* HTTP 403 - key lacks required permission */ }
}
}SnapixClientBrowser
Designed for any JavaScript runtime - browsers, Next.js client components, edge runtimes. Zero Node.js dependencies. Reads NEXT_PUBLIC_SNAPIX_* environment variables by default (standard in Next.js), but accepts explicit config options in any environment.
Security: When used client-side, your API key is exposed in the browser bundle. Use a dedicated API key with restricted read-only permissions - see API Key Permissions.
Environment Variables
| Variable | Required | Default | Description |
| --- | --- | --- | --- |
| NEXT_PUBLIC_SNAPIX_API_KEY | Yes | - | Your Snapix API key |
| NEXT_PUBLIC_SNAPIX_BASE_URL | No | https://www.snapix.space | Override API base URL |
| NEXT_PUBLIC_SNAPIX_BUCKET_KEY | No | primary bucket | Default storage bucket key |
| NEXT_PUBLIC_SNAPIX_LOG_LEVEL | No | warn | debug | info | warn | error | silent |
Manual Configuration
import { SnapixClientBrowser } from "@metalevel/snapix-sdk-core/browser";
const client = new SnapixClientBrowser({
apiKey: "your_api_key",
baseUrl: "https://www.snapix.space", // optional
bucketKey: "my-bucket", // optional
logLevel: "debug", // optional
});Read Methods
SnapixClientBrowser inherits all read methods from SnapixClientBasic - see Read Methods above.
Convert Methods
On-the-fly conversion - results are not stored in cloud storage. imageFilePath is not supported (no filesystem access in browser environments); use SnapixClientServer for that. imageBlob accepts a File from <input type="file"> directly - no base64 encoding needed.
Write methods (uploadImage, updateImage, deleteImage, generateImage, and all gallery write methods) are only available on SnapixClientServer.
convertImage - raw binary + MIME type
await client.convertImage(params: ConvertImageParams): Promise<ConvertImageBrowserResult>
// ConvertImageBrowserResult: { buffer: Uint8Array, type: string }
// `type` is the MIME type from the API response Content-Type headerconst file = inputElement.files[0];
const result = await client.convertImage({
imageBlob: file,
formatOptions: { format: "webp" },
resizeOptions: { width: 800 },
});
// result.buffer - Uint8Array of the converted image
// result.type - e.g. "image/webp"convertImageToBlob - returns a Blob
await client.convertImageToBlob(params: ConvertImageToBlobParams): Promise<Blob>
// params extends ConvertImageParams with { mimeType?: string }
// mimeType overrides the API-returned Content-Type; defaults to result.typeconst blob = await client.convertImageToBlob({
imageBlob: file,
formatOptions: { format: "webp" },
});convertImageToObjectUrl - returns a blob: URL
await client.convertImageToObjectUrl(params: ConvertImageToObjectUrlParams): Promise<string>
// params extends ConvertImageParams with { mimeType?: string }
// Returns a temporary blob: URL - caller must call URL.revokeObjectURL() when doneconst objectUrl = await client.convertImageToObjectUrl({
imageBlob: file,
formatOptions: { format: "webp" },
});
imgElement.src = objectUrl;
// Later, when no longer needed:
URL.revokeObjectURL(objectUrl);convertImageAndDownload - triggers a download dialog
await client.convertImageAndDownload(params: ConvertImageAndDownloadParams): Promise<void>
// params extends ConvertImageParams with { filename: string, mimeType?: string }
// Browser-only - throws if called outside a browser environment (SSR, Node.js, Workers)
// URL.revokeObjectURL() is called automatically after the download is triggeredawait client.convertImageAndDownload({
imageBlob: file,
formatOptions: { format: "avif" },
filename: "converted.avif",
});SnapixClientServer
The full-featured server client for Node.js ≥ 18. Provides all read methods inherited from SnapixClientBasic, plus image upload, update, delete, AI generation, on-the-fly conversion to Buffer, and gallery management.
Environment Variables
| Variable | Required | Default | Description |
| --- | --- | --- | --- |
| SNAPIX_API_KEY | Yes | - | Your Snapix API key |
| SNAPIX_BASE_URL | No | https://www.snapix.space | Override API base URL |
| SNAPIX_BUCKET_KEY | No | primary bucket | Default storage bucket key |
| SNAPIX_LOG_LEVEL | No | warn | debug | info | warn | error | silent |
Manual Configuration
import { SnapixClientServer } from "@metalevel/snapix-sdk-core";
const client = new SnapixClientServer({
apiKey: "your_api_key",
baseUrl: "https://www.snapix.space", // optional
bucketKey: "my-bucket", // optional
logLevel: "debug", // optional
});Read Methods
SnapixClientServer inherits all read methods from SnapixClientBasic - see Read Methods above.
Image Methods
// Upload from URL, file path, base64, or Blob/File
await client.uploadImage(params: UploadImageParams): Promise<UploadImageResponse>
// Update metadata and/or replace image content
await client.updateImage(params: UpdateImageParams): Promise<UpdateImageResponse>
// params: { imageId, name?, description?, galleries?, formatOptions?, resizeOptions?, imageUrl?, ... }
// Delete an image
await client.deleteImage(params: DeleteImageParams): Promise<{ success: true }>
// params: { imageId }Upload example - format + resize combinations, assign to gallery:
const result = await client.uploadImage({
imageUrl: "https://example.com/photo.jpg",
name: "my-photo",
description: "A landscape photo",
formatOptions: [{ format: "webp" }, { format: "avif" }],
resizeOptions: [{ width: 1280 }, { width: 640 }],
galleries: ["gallery-uuid"],
});
// Costs 4 credits (2 formats × 2 resizes)
console.log(result.simpleData); // [{ id, originalName, variants, info }, ...]Update example - metadata only, or replace the image file:
// Metadata-only update
await client.updateImage({
imageId: "image-uuid",
name: "new-name",
description: "Updated description",
galleries: ["gallery-uuid"],
});
// Replace image content
await client.updateImage({
imageId: "image-uuid",
imageFilePath: "/tmp/new-version.png",
formatOptions: [{ format: "webp" }],
});Convert Methods
On-the-fly conversion - results are not stored in cloud storage. Accepts imageFilePath, imageBlob, imageBase64, or imageUrl. Costs 1 credit per call.
// Returns binary data as a Buffer
await client.convertImage(params: ConvertImageParams): Promise<Buffer>
// Converts and writes directly to disk
await client.convertImageToFile(params: ConvertImageToFileParams): Promise<void>
// params extends ConvertImageParams with { outputPath: string }// From URL
const buffer = await client.convertImage({
imageUrl: "https://example.com/photo.jpg",
formatOptions: { format: "webp" },
resizeOptions: { width: 400 },
});
// From file path
const buffer = await client.convertImage({
imageFilePath: "/tmp/source.png",
formatOptions: { format: "avif" },
});
// Write directly to disk
await client.convertImageToFile({
imageFilePath: "/tmp/source.png",
formatOptions: { format: "avif" },
outputPath: "/tmp/output.avif",
});Generate Method (AI)
Generate an image from a text prompt using AI. Requires a paid subscription.
await client.generateImage(params: GenerateImageParams): Promise<GenerateImageResponse>// From text prompt only
const result = await client.generateImage({
promptText: "A serene mountain lake at sunset",
name: "mountain-lake",
formatOptions: [{ format: "webp" }],
});
// Costs 40+ credits
// From text prompt + image template (image-to-image)
const result = await client.generateImage({
promptText: "Transform into an oil painting style",
imageUrl: "https://example.com/source-photo.jpg",
name: "oil-painting",
formatOptions: [{ format: "webp" }],
});
// Also accepts imageFilePath, imageBase64, or imageBlob as the template sourceGallery Methods
// Create a gallery (server-only)
await client.createGallery(params: CreateGalleryParams): Promise<CreateGalleryResponse>
// Update gallery name or visibility (server-only)
await client.updateGallery(params: UpdateGalleryParams): Promise<GalleryType>
// params: { galleryId, name?, isPublic? }
// Delete a gallery; pass deleteImages: true to also delete all its images (server-only)
await client.deleteGallery(params: DeleteGalleryParams): Promise<{ success: boolean }>
// params: { galleryId, deleteImages? }
// Inherited read methods from SnapixClientBasic:
await client.listGalleries(): Promise<ListGalleriesResponse>
await client.getGallery(params: GetGalleryParams): Promise<GetGalleryResponse>
await client.getImagesWithoutGallery(params?: GetImagesWithoutGalleryParams): Promise<GetGalleryResponse>// Create
const { gallery } = await client.createGallery({ name: "My Portfolio", isPublic: true });
// Update
await client.updateGallery({ galleryId: gallery.id, isPublic: false });
// Delete gallery only (keep images)
await client.deleteGallery({ galleryId: gallery.id });
// Delete gallery and all its images
await client.deleteGallery({ galleryId: gallery.id, deleteImages: true });Next.js Integration
Use SnapixClientServer in server actions or API routes - never in client components:
// app/actions/upload.ts
"use server";
import { SnapixClientServer } from "@metalevel/snapix-sdk-core";
const client = new SnapixClientServer(); // reads SNAPIX_API_KEY from env
export async function uploadProfileImage(formData: FormData) {
const file = formData.get("image") as File;
const base64 = Buffer.from(await file.arrayBuffer()).toString("base64");
const result = await client.uploadImage({
imageBase64: base64,
imageContentType: file.type,
name: "profile-image",
formatOptions: [{ format: "webp" }],
resizeOptions: [{ width: 256, height: 256 }],
});
return result.simpleData[0].variants["webp"];
}Constants Reference
Some runtime constants are exported from every subpath alongside types. Import them from the same entry point as your client:
export {
NEXT_PUBLIC_SNAPIX_BASE_URL as nextPublicSnapixBaseUrl,
SNAPIX_BASE_URL as snapixBaseUrl,
APP_SERVER_GALLERY_URI as snapixGalleryUri,
} from "./constants.js";SNAPIX_BASE_URL and NEXT_PUBLIC_SNAPIX_BASE_URL are particularly useful when constructing image URLs or links to the {{ appName }} app without hard-coding the domain:
import { snapixBaseUrl, snapixGalleryUri } from "@metalevel/snapix-sdk-core";
const galleryPageUrl = `${snapixBaseUrl}${snapixGalleryUri}/${galleryId}`;Links
- Full SDK Documentation
- REST API Reference
- MCP Server
- SDK Preview App - interactive Next.js test app for this SDK
- Get API Key
- API Key Permissions - granular permissions reference
License
MIT
