npm.io
0.18.1 • Published 6d ago

@snowcone-app/sdk

Licence
MIT
Version
0.18.1
Deps
1
Size
797 kB
Vulns
0
Weekly
1.1K

@snowcone-app/sdk

Building with an AI agent? Read the complete agent-facing docs in one fetch — https://developers.snowcone.app/llms-full.txt — before integrating. It's the source of truth; grep it before assuming a field or behavior is undocumented.

JavaScript/TypeScript SDK for product mockups and print-on-demand

A small, isomorphic SDK for fetching product data and building real-time merchandise mockup URLs. Use it to visualize artwork on t-shirts, posters, mugs, and more — in the browser or on the server.

Full documentation: developers.snowcone.app/sdk

Installation

npm install @snowcone-app/sdk
# or
yarn add @snowcone-app/sdk
# or
pnpm add @snowcone-app/sdk

Quick Start

import { getProduct, listProducts, getMockupUrl } from '@snowcone-app/sdk';

// 1. Find a product (public catalog read — no key needed)
const products = await listProducts({ limit: 10 });
const product = await getProduct('BEEB77'); // by id or slug

// 2. Build a mockup URL. A mockup is a PUBLIC image URL — getMockupUrl is a
//    pure, synchronous builder (no await, no fetch, no secret). The result
//    drops straight into an <img>. Code-first: productCode, then options.
const url = getMockupUrl('hoodie-black', {
  shop: shop.id,                       // your Shop ID (publishable, = shop.id)
  asset: 'https://example.com/art.png' // your artwork
});
// <img src={url} />

The shop ID is your publishable token — public and safe to expose (like Cloudinary's cloud name). It defaults to your shop.id. See Public or signed below if you want to lock things down.

Core Functions

Product Data
// Get a single product
const product = await getProduct(productId: string, options?: {
  endpoint?: string;
  mode?: 'mock' | 'live' | 'meilisearch';
});

// List products
const products = await listProducts(options?: {
  limit?: number;
  offset?: number;
  endpoint?: string;
  mode?: 'mock' | 'live' | 'meilisearch';
});

Product Object Structure:

{
  id: string;              // Product ID (e.g., "BEEB77")
  name: string;            // Product name
  description?: string;    // Product description
  basePrice: number;       // Base price in cents
  variants: Variant[];     // Color/size variants
  placements: Placement[]; // Print areas (Front, Back, etc.)
  mockup: {
    blankUrl: string;      // Blank product image URL
  };
}
Mockup URLs

A mockup is a public image URL on img.snowcone.app:

https://img.snowcone.app/{productCode}?asset={assetUrl}&shop={shopId}

You can hand-write it, or use getMockupUrl — a pure, synchronous, isomorphic builder (browser + server, no await). It never hand-rolls the query string; it delegates to @snowcone-app/mockup-url's buildPublicMockupUrl (the single source of truth shared byte-for-byte with the edge resolver).

import { getMockupUrl } from '@snowcone-app/sdk';

// Code-first form: productCode, then options.
const url = getMockupUrl(productCode: string, opts: {
  shop: string;           // Required: your Shop ID (publishable, = shop.id)
  asset?: string;         // Single default-placement image (get-started shorthand)
  design?: Design;        // Multi-placement: { [placementKey]: Fill } — takes precedence over `asset`
  options?: Record<string, string>; // Variant picks: { size: "m" } → opt.size=m
  secret?: string;        // Optional: per-shop secret → appends a signed &signature (server only)
  base?: string;          // Optional: override the host (default img.snowcone.app)
  width?: number;         // Optional: display width
  view?: string;          // Optional: camera view / mockup scene (alias: `mockup`)
  variant?: string;       // Optional: specific resolved variant (gvid)
  placement?: string;     // Optional: specific print area (single-asset only)
  aspect?: '16:9' | '2:3';// Optional: canvas aspect ratio
}): string;

Fill (re-exported from the SDK) is what fills one placement:

type Fill =
  | string                                       // image URL (shorthand for { src })
  | { src: string; align?: ImageAlignment; tile?: 0.25 | 0.5 | 1 | 2 | 4 }
  | { color: string };                           // a color placement (e.g. a cap's Crown)
type Design = Record<string, Fill>;              // placement key → fill
Multi-placement + variant options
// A front + back tee, size M.
const url = getMockupUrl('KMYKUK', {
  shop: shop.id,
  options: { size: 'm' },
  design: {
    front: 'https://cdn.example.com/front.png',
    back: { src: 'https://cdn.example.com/back.png', tile: 2, align: 'top' },
  },
});
// → …/KMYKUK?shop=…&asset.back=…&tile.back=2&align.back=top&asset.front=…&opt.size=m

// A cap with a printed front + chosen Crown/Strap colors (color placements).
const cap = getMockupUrl('RQNU68', {
  shop: shop.id,
  design: { front: 'https://cdn.example.com/logo.png', crown: { color: '#001f3f' } },
});
// → …/RQNU68?shop=…&color.crown=%23001f3f&asset.front=…

A legacy positional form getMockupUrl(assetUrl, productCode, opts) is also accepted (it builds the same URL as getMockupUrl(productCode, { asset, … })). Prefer the code-first form above for new code.

Public or signed

The default is open and frictionless. There's one decision to make up front:

  • Public — the Shop ID alone, safe to expose. Lock it to your asset origins so a stolen ID can only re-render your own catalog.
  • Signed — your server appends an &signature (HMAC of a per-shop secret), so only you can mint valid URLs. The secret stays server-side.

To sign, pass secret (server-side only) and getMockupUrl appends the verified &signature:

// On your server/BFF — the secret never ships to the browser.
const url = getMockupUrl('hoodie-black', {
  shop: shop.id,
  asset: assetUrl,
  secret: process.env.SNOWCONE_SHOP_SECRET,
});

See Public or signed for the full picture.

Realtime: render a saved canvas, no pixel upload

getMockupUrl composites one artwork onto a product. For a full multi-layer design — the kind the Snowcone canvas editor produces — use a RenderSession: the browser sends a ~1 KB description of the canvas (or just a saved design's id) over a WebSocket, and the server renders the mockup and fetches the referenced assets itself. No per-placement PNG is ever uploaded, so it's fast on thin/mobile clients. This is exactly how the Snowcone PDP renders mockups.

Authorize the session with a short-lived grant. Mint it server-side with a secret API key (sk_…, scope mockups:realtime) so the key never reaches the browser. Create the key — and find your publishable shop.id — on the API keys page:

// YOUR backend route, e.g. POST /api/realtime/grant
import { mintRealtimeGrant } from '@snowcone-app/sdk';

export async function POST(req: Request) {
  const { shop } = await req.json();
  const grant = await mintRealtimeGrant({
    apiKey: process.env.SNOWCONE_API_KEY!, // secret — server only
    shop,                                  // = shop.id (publishable)
  });
  return Response.json(grant); // { token, expiresAt }
}

In the browser, point a RenderSession at that proxy and render. Render a saved design by id (no canvas JSON needed) or a live serializeStateForServer(...) state:

import { RenderSession } from '@snowcone-app/sdk';

const session = new RenderSession({
  shop: 'YOUR_SHOP_ID',            // publishable, like Stripe pk_
  grantUrl: '/api/realtime/grant', // your proxy above
  // mockupIds are catalog SCENE CODES (product.mockups[].id) — not placement
  // names. variantId is required for products with a color/size option.
  product: { productId: 'BEEB77', mockupIds: ['FV1qjO'], variantId: 'Pv1sLC' },
});

session.onMockups((results) => { img.src = results[0].imageUrl; });

// (a) render a SAVED canvas by id — ideal for fulfillment / agents
await session.renderSavedState('Front', 'design-state-id');

// (b) or render a live canvas state from @snowcone-app/canvas
// import { serializeStateForServer } from '@snowcone-app/canvas';
// await session.renderState('Front', serializeStateForServer(canvasState));

React apps can use the lower-level useRealtimeMockup({ getToken }) hook from @snowcone-app/sdk/react instead. Full walkthrough: Realtime server-side render.

TypeScript Support

Full TypeScript definitions are included. Import types:

import type {
  CatalogProduct,
  Variant,
  Placement,
  ImageAlignment
} from '@snowcone-app/sdk';

API Reference

See full API documentation at: https://developers.snowcone.app/sdk

React Components

For pre-built React components, install @snowcone-app/ui:

npm install @snowcone-app/ui

See: @snowcone-app/ui on npm

Examples

Support

License

MIT Snowcone


Built for developers. Optimized for LLMs.

This SDK is designed to work seamlessly with AI coding assistants like Claude, GitHub Copilot, and Cursor. Clear types, explicit examples, and predictable patterns make it easy for LLMs to generate correct code.

Keywords