@metalevel/snapix-sdk-core is a typed TypeScript SDK that lets you integrate SnapiX into your applications - image upload, conversion, resizing, gallery management, and AI generation - with full type safety and zero runtime dependencies. 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.
fetch and FormDataSnapixClientServer (Node.js, full CRUD), SnapixClientBrowser (any JS runtime, read + convert), SnapixClientBasic (abstract base)npm install @metalevel/snapix-sdk-core
or
pnpm add @metalevel/snapix-sdk-core
If you have the SnapiX MCP server configured in your AI client, you can install and configure Snapix SDK Core automatically using the built-in snapix_setup_sdk_core prompt - no manual steps required.
In VS Code Copilot, type / in chat and select snapix_setup_sdk_core. The agent will read the live SDK documentation, install @metalevel/snapix-sdk-core using your project's package manager, and append the required SNAPIX_* environment variables to your .env file.
See the MCP setup guide to configure the MCP server if you haven't already.
Upload an image from your Node.js server using SNAPIX_API_KEY (get one at API Keys):
export SNAPIX_API_KEY="sk_snapix_apiKey-a1b2c3-placeholder"
import { SnapixClientServer } from "@metalevel/snapix-sdk-core";
// Auto-loads config from environment variables
const client = new SnapixClientServer();
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.example.com/my-photo.webp" }
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="sk_snapix_apiKey-a1b2c3-placeholder"
import { SnapixClientBrowser } from "@metalevel/snapix-sdk-core/browser";
// Auto-loads config from NEXT_PUBLIC_SNAPIX_* environment variables
const client = new SnapixClientBrowser();
// 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);
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.
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.).
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 an error like:
the chunking context does not support external modules (request: node:fs/promises)
The solution is to provide subpath exports so that each entry point only pulls in what its target runtime supports.
| 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 also export the error classes (SnapixApiError, SnapixConfigError) and all TypeScript types relevant to that client.
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.
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
});
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 |
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" }
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(); // throws SnapixConfigError if SNAPIX_API_KEY is missing
const result = await client.uploadImage({ imageUrl: "https://..." });
} catch (err) {
if (err instanceof SnapixConfigError) {
// Missing API key or invalid configuration
console.error("Configuration error:", err.message);
// e.g. "SNAPIX_API_KEY environment variable is required but not set."
} else if (err instanceof SnapixApiError) {
console.error("API error:", err.message, "status:", err.status);
if (err.isRetryable) {
// HTTP 429 - rate limit hit, retry after backoff
}
if (err.status === 402) {
// Quota exceeded - check your plan
}
if (err.isReadOnly) {
// HTTP 403 - key lacks required permission for this operation; check key permissions
}
}
}
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.
| 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 |
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
});
SnapixClientBrowser inherits all read methods from SnapixClientBasic - see Read Methods above.
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 typeawait client.convertImage(params: ConvertImageParams): Promise<ConvertImageBrowserResult>
// ConvertImageBrowserResult: { buffer: Uint8Array, type: string }
// `type` is the MIME type from the API response Content-Type header
const 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 Blobawait client.convertImageToBlob(params: ConvertImageToBlobParams): Promise<Blob>
// params extends ConvertImageParams with { mimeType?: string }
// mimeType overrides the API-returned Content-Type; defaults to result.type
const blob = await client.convertImageToBlob({
imageBlob: file,
formatOptions: { format: "webp" },
});
convertImageToObjectUrl - returns a blob: URLawait client.convertImageToObjectUrl(params: ConvertImageToObjectUrlParams): Promise<string>
// params extends ConvertImageParams with { mimeType?: string }
// Returns a temporary blob: URL - caller must call URL.revokeObjectURL() when done
const objectUrl = await client.convertImageToObjectUrl({
imageBlob: file,
formatOptions: { format: "webp" },
});
imgElement.src = objectUrl;
// Later, when no longer needed:
URL.revokeObjectURL(objectUrl);
convertImageAndDownload - triggers a download dialogawait 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 triggered
await client.convertImageAndDownload({
imageBlob: file,
formatOptions: { format: "avif" },
filename: "converted.avif",
});
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.
| 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 |
Log verbosity (see Logging) |
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
});
SnapixClientServer inherits all read methods from SnapixClientBasic - see Read Methods above.
// 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" }],
});
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 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 source
// 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 });
Use SnapixClientServer in server actions or API routes - never in client components. Client components must use SnapixClientBrowser imported from @metalevel/snapix-sdk-core/browser:
// app/actions/upload.ts - server action
"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"];
}
// components/gallery.tsx - client component
"use client";
import { SnapixClientBrowser } from "@metalevel/snapix-sdk-core/browser";
// Instantiate once outside the component to avoid re-creating on every render.
// NEXT_PUBLIC_SNAPIX_API_KEY must be a read-only key - it will be visible in the browser bundle.
const client = new SnapixClientBrowser();
export function Gallery() {
// ...
const { galleries } = await client.listGalleries();
// ...
}
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 SnapiX app without hard-coding the domain:
import { snapixBaseUrl, snapixGalleryUri } from "@metalevel/snapix-sdk-core";
const galleryPageUrl = `${snapixBaseUrl}${snapixGalleryUri}/${galleryId}`;
All types are exported from every subpath. Import them from the same entry point as your client to avoid mixing server and browser module graphs:
// Server / Node.js - import from root
import type {
UploadImageParams,
UpdateImageParams,
DeleteImageParams,
ConvertImageToFileParams,
GenerateImageParams,
CreateGalleryParams,
UpdateGalleryParams,
DeleteGalleryParams,
ImageSourceParams,
UploadImageResponse,
UpdateImageResponse,
GenerateImageResponse,
// ... plus all shared types below
} from "@metalevel/snapix-sdk-core";
// Browser / client components - import from /browser
import type {
ConvertImageParams,
ConvertImageBrowserResult,
ConvertImageToBlobParams,
ConvertImageToObjectUrlParams,
ConvertImageAndDownloadParams,
// ... plus all shared types below
} from "@metalevel/snapix-sdk-core/browser";
// Shared types - available from all subpaths
import type {
// Request params (read)
ListImagesParams,
GetImageParams,
GetGalleryParams,
GetImagesWithoutGalleryParams,
GetDocsParams,
// Response types
ListImagesResponse,
GetImageResponse,
GetGalleryResponse,
ListGalleriesResponse,
CreateGalleryResponse,
// Entity types
ImageType,
ImageMetadata,
ImageInfo,
ImageGalleryRef,
ImageDataSimplified,
GalleryType,
GalleryWithImagesType,
GalleryImageEntry,
AccountStatistics,
Pagination,
StorageUsed,
// Config
GetDocsDocType,
SnapixClientOptions,
LogLevel,
} from "@metalevel/snapix-sdk-core"; // or /browser or /basic
The snapix-sdk-preview repository contains a private Next.js + shadcn/ui application used to interactively test and preview SDK packages against the live SnapiX API. It covers @metalevel/snapix-sdk-core and will be extended as new SDK variants (e.g. sdk-react) are introduced.