TypeScript SDK
Official TypeScript SDK for TruthMark invisible watermarking with full type safety.
Installation
npm
npm install @truthmark/sdk-typescriptyarn
yarn add @truthmark/sdk-typescriptQuick Example
import { TruthMarkClient, EncodeResult, DecodeResult } from '@truthmark/sdk-typescript';
const client = new TruthMarkClient({
apiKey: 'tm_live_your_key',
baseUrl: 'https://truthmark-api.onrender.com'
});
// Encode watermark
const result: EncodeResult = await client.encode(
'./image.png',
'My secret message'
);
console.log(`Download: ${result.downloadUrl}`);
console.log(`PSNR: ${result.metadata.psnr} dB`);
// Decode watermark
const decoded: DecodeResult = await client.decode('./watermarked.png');
if (decoded.found) {
console.log(`Message: ${decoded.message}`);
console.log(`Confidence: ${(decoded.confidence * 100).toFixed(1)}%`);
}API Reference
new TruthMarkClient(config?)
Create a new typed client instance.
interface TruthMarkConfig {
apiKey?: string;
baseUrl?: string; // defaults to production
timeout?: number; // request timeout in ms
}
const client = new TruthMarkClient({
apiKey: process.env.TRUTHMARK_API_KEY!,
});encode(imagePath, message)
Embed an invisible watermark into an image.
interface EncodeResult {
status: string;
metadata: {
psnr: number;
bits_embedded: number;
};
download_url: string;
filename: string;
}decode(imagePath)
Extract watermark from an image.
interface DecodeResult {
found: boolean;
message: string | null;
confidence: number;
}Error Handling
import { TruthMarkError } from '@truthmark/sdk-typescript';
try {
const result = await client.encode(file, message);
} catch (error) {
if (error instanceof TruthMarkError) {
switch (error.status) {
case 401: console.error('Invalid API key'); break;
case 429: console.error(`Rate limited. Retry after ${error.retryAfter}s`); break;
case 413: console.error('Image too large (max 20MB)'); break;
default: console.error(`API error: ${error.message}`);
}
}
}Advanced Examples
Generic Wrapper Function
async function watermarkImage(
imagePath: string,
metadata: Record<string, string>
): Promise<EncodeResult> {
const message = JSON.stringify({
...metadata,
timestamp: new Date().toISOString(),
version: '1.0',
});
return client.encode(imagePath, message);
}
// Usage
const result = await watermarkImage('./photo.jpg', {
author: 'Jane Doe',
license: 'CC-BY-4.0',
aiModel: 'DALL-E-3',
});Next.js Server Action
'use server';
import { TruthMarkClient } from '@truthmark/sdk-typescript';
const client = new TruthMarkClient({
apiKey: process.env.TRUTHMARK_API_KEY!,
});
export async function watermarkAction(formData: FormData) {
const file = formData.get('file') as File;
const message = formData.get('message') as string;
if (!file || !message) {
return { error: 'Missing file or message' };
}
const result = await client.encode(file, message);
return { url: result.download_url, psnr: result.metadata.psnr };
}Batch Processing with Concurrency
import { readdir } from 'fs/promises';
import { join } from 'path';
async function batchWatermark(dir: string, message: string) {
const files = (await readdir(dir))
.filter(f => /\.(png|jpg|jpeg)$/i.test(f));
const CONCURRENCY = 5;
const results: EncodeResult[] = [];
for (let i = 0; i < files.length; i += CONCURRENCY) {
const batch = files.slice(i, i + CONCURRENCY);
const batchResults = await Promise.all(
batch.map(f => client.encode(join(dir, f), message))
);
results.push(...batchResults);
console.log(`Processed ${results.length}/${files.length}`);
}
return results;
}Best Practices
Use strict TypeScript config
Enable strict: true for full type safety with the SDK.
Always type your results
Use EncodeResult and DecodeResult type imports for better IDE support.
Don't expose API keys in client bundles
Use server-side routes or server actions to keep keys secure.