JK
JustKalm
v2.0.0Stable

TypeScript SDK

Full TypeScript support for Node.js and browsers. Includes React hooks, streaming support, and first-class Next.js integration.

Node.js 18+
Modern Browsers
React Native

Installation

npmbash
npm install @justkalm/sdk
pnpmbash
pnpm add @justkalm/sdk

TypeScript Built-in

The SDK is written in TypeScript and includes full type definitions. No need to install @types packages.

Quick Start

quickstart.tstypescript
import { JustKalm } from '@justkalm/sdk';

// Initialize the client
const client = new JustKalm({
  apiKey: process.env.JUSTKALM_API_KEY!,
  environment: 'production', // or 'sandbox'
});

// Create a product
const product = await client.products.create({
  name: 'Organic Cotton T-Shirt',
  brand: 'EcoWear',
  category: 'apparel',
  materials: {
    organic_cotton: 0.95,
    elastane: 0.05,
  },
  certifications: ['GOTS', 'Fair Trade'],
});

console.log(`Created product: ${product.id}`);

// Get valuation with health scoring
const valuation = await client.valuations.create(product.id, {
  includeHealth: true,
  includeSustainability: true,
});

console.log(`Health Score: ${valuation.healthScore}/100`);
console.log(`Value: $${valuation.adjustedValue.toFixed(2)}`);

React Hooks

The SDK includes React hooks for seamless frontend integration with built-in loading states, error handling, and caching.

Setup Provider

// app/providers.tsx
'use client';

import { JustKalmProvider } from '@justkalm/sdk/react';

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <JustKalmProvider
      apiKey={process.env.NEXT_PUBLIC_JUSTKALM_API_KEY!}
      options={{
        refetchOnWindowFocus: true,
        staleTime: 5 * 60 * 1000, // 5 minutes
      }}
    >
      {children}
    </JustKalmProvider>
  );
}

useProduct Hook

import { useProduct, useValuation } from '@justkalm/sdk/react';

function ProductCard({ productId }: { productId: string }) {
  const { 
    data: product, 
    isLoading, 
    error 
  } = useProduct(productId);
  
  const { 
    data: valuation 
  } = useValuation(productId, {
    includeHealth: true,
  });

  if (isLoading) return <Skeleton />;
  if (error) return <Error message={error.message} />;

  return (
    <div className="p-4 border rounded-lg">
      <h2>{product.name}</h2>
      <p>Brand: {product.brand}</p>
      {valuation && (
        <>
          <HealthScore score={valuation.healthScore} />
          <Price value={valuation.adjustedValue} />
        </>
      )}
    </div>
  );
}

Mutations

import { useCreateProduct } from '@justkalm/sdk/react';

function CreateProductForm() {
  const { 
    mutate: createProduct, 
    isPending,
    error 
  } = useCreateProduct();

  const handleSubmit = async (data: FormData) => {
    createProduct({
      name: data.get('name') as string,
      brand: data.get('brand') as string,
      category: 'apparel',
    }, {
      onSuccess: (product) => {
        toast.success(`Created ${product.name}`);
        router.push(`/products/${product.id}`);
      },
      onError: (error) => {
        toast.error(error.message);
      },
    });
  };

  return (
    <form onSubmit={handleSubmit}>
      {/* form fields */}
      <button type="submit" disabled={isPending}>
        {isPending ? 'Creating...' : 'Create Product'}
      </button>
    </form>
  );
}

Products API

// Create a product
const product = await client.products.create({
  name: 'Premium Leather Handbag',
  brand: 'LuxuryBrand',
  category: 'accessories',
  materials: {
    full_grain_leather: 0.85,
    brass: 0.10,
    cotton_lining: 0.05,
  },
  condition: 'excellent',
  originalPrice: 1200,
  metadata: {
    color: 'cognac',
    year: 2023,
  },
});

// List products with filtering
const { data: products, pagination } = await client.products.list({
  limit: 50,
  category: 'apparel',
  brand: 'EcoWear',
  minHealthScore: 70,
});

// Iterate with pagination
for await (const product of client.products.iterate()) {
  console.log(product.name);
}

// Get, update, delete
const product = await client.products.get('prod_abc123');
const updated = await client.products.update('prod_abc123', { 
  condition: 'good' 
});
await client.products.delete('prod_abc123');

Streaming

Stream real-time updates for long-running operations like batch processing or AI insights.

// Stream valuation generation
const stream = await client.valuations.createStream(productId, {
  includeHealth: true,
  includeInsights: true,
});

for await (const chunk of stream) {
  switch (chunk.type) {
    case 'health_score':
      console.log(`Health: ${chunk.data.score}/100`);
      updateUI({ healthScore: chunk.data.score });
      break;
    case 'sustainability_score':
      console.log(`Sustainability: ${chunk.data.score}/100`);
      break;
    case 'insight':
      console.log(`Insight: ${chunk.data.text}`);
      break;
    case 'complete':
      console.log('Valuation complete');
      break;
  }
}

// React hook for streaming
function ValuationStream({ productId }: { productId: string }) {
  const { 
    chunks, 
    isStreaming, 
    error 
  } = useValuationStream(productId);

  return (
    <div>
      {chunks.map((chunk, i) => (
        <StreamChunk key={i} chunk={chunk} />
      ))}
      {isStreaming && <Spinner />}
    </div>
  );
}

Error Handling

import { 
  JustKalmError,
  AuthenticationError,
  RateLimitError,
  ValidationError,
  NotFoundError,
  isJustKalmError,
} from '@justkalm/sdk';

try {
  const product = await client.products.get('prod_invalid');
} catch (error) {
  if (error instanceof NotFoundError) {
    console.log(`Not found: ${error.message}`);
  } else if (error instanceof RateLimitError) {
    console.log(`Rate limited. Retry after: ${error.retryAfter}s`);
  } else if (error instanceof ValidationError) {
    console.log(`Validation failed:`);
    error.errors.forEach(e => {
      console.log(`  ${e.field}: ${e.message}`);
    });
  } else if (error instanceof AuthenticationError) {
    console.log(`Auth error: ${error.message}`);
  } else if (isJustKalmError(error)) {
    // Any SDK error
    console.log(`SDK Error: ${error.message}`);
  } else {
    // Unknown error
    throw error;
  }
}

// Type-safe error checking
function handleError(error: unknown) {
  if (isJustKalmError(error)) {
    // TypeScript knows this is JustKalmError
    console.log(error.code, error.message);
  }
}

Next.js Integration

// app/products/[id]/page.tsx
import { getJustKalmClient } from '@justkalm/sdk/server';

export default async function ProductPage({ 
  params 
}: { 
  params: { id: string } 
}) {
  const client = getJustKalmClient();
  
  const [product, valuation] = await Promise.all([
    client.products.get(params.id),
    client.valuations.get(params.id),
  ]);

  return (
    <div>
      <h1>{product.name}</h1>
      <HealthScoreBadge score={valuation.healthScore} />
      <ValuationDetails valuation={valuation} />
    </div>
  );
}

// With caching
export const revalidate = 60; // Revalidate every 60 seconds