npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@headless-commerce/sdk

v0.2.0

Published

TypeScript SDK for Headless Commerce API

Downloads

32

Readme

@headless-commerce/sdk

Headless Commerce API를 위한 공식 TypeScript SDK입니다.

Features

  • Type-safe: 모든 API 요청/응답에 대한 완전한 TypeScript 타입
  • Zero dependencies: fetch API만 사용 (Node.js 18+, Deno, Bun, 브라우저)
  • Dual format: ESM + CJS 동시 지원
  • Auto-pagination: for await 기반 자동 페이지네이션
  • Retry & Timeout: 429/5xx 자동 재시도 + 요청 타임아웃
  • Stripe-like DX: client.products.list() 패턴의 직관적인 API
  • Idempotency: 중복 요청 방지를 위한 Idempotency-Key 지원
  • Debug logging: 요청/응답 디버깅 로그 + 커스텀 로거
  • Webhook verification: HMAC-SHA256 기반 웹훅 서명 검증

Installation

npm install @headless-commerce/sdk
# or
pnpm add @headless-commerce/sdk
# or
yarn add @headless-commerce/sdk

Setup

API Keys

Headless Commerce는 두 종류의 API 키를 사용합니다:

| 키 종류 | Prefix | 용도 | |---------|--------|------| | Publishable Key | pk_ | 프론트엔드 (Storefront) — 브라우저에 노출 가능 | | Secret Key | sk_ | 백엔드 (Admin) — 서버에서만 사용. 절대 프론트엔드에 노출하지 마세요 |

Base URL

// 프로덕션 (기본값)
const client = new HeadlessCommerce({ apiKey: 'pk_xxx' });
// → https://api.headlesscommerce.io/v1

// 로컬 개발
const client = new HeadlessCommerce({
  apiKey: 'pk_test_xxx',
  baseUrl: 'http://localhost:3000/v1',
});

Quick Start

Storefront (프론트엔드) — 타입 안전 팩토리

import { createStorefrontClient } from '@headless-commerce/sdk';

// StorefrontClient 타입 — admin 메서드가 autocomplete에 노출되지 않음
const client = createStorefrontClient({
  apiKey: 'pk_test_xxx',           // Publishable key
  baseUrl: 'http://localhost:3000/v1',
});

// 상품 목록 조회
const products = await client.products.list({ limit: 10 });
console.log(products.data);

// 장바구니 생성 → 상품 추가
const cart = await client.carts.create();
await client.carts.addItem(cart.id, {
  variant_id: 'var_xxx',
  quantity: 2,
});

// 체크아웃
const order = await client.checkout.create(cart.id, {
  email: '[email protected]',
  shipping_address: {
    name: 'Hong Gildong',
    line1: '123 Main St',
    city: 'Seoul',
    postal_code: '06000',
    country: 'KR',
  },
});

Admin (백엔드) — 풀 액세스

import { createAdminClient } from '@headless-commerce/sdk';

const admin = createAdminClient({
  apiKey: 'sk_test_xxx',           // Secret key
});

// 상품 생성
const product = await admin.products.adminCreate({
  name: 'New T-Shirt',
  slug: 'new-t-shirt',
  type: 'physical',
  status: 'active',
});

// 주문 관리
const orders = await admin.orders.adminList({ status: 'pending' });
await admin.orders.adminConfirm('ord_xxx');

Customer Authentication

서버에서 고객 토큰을 발급하고 클라이언트에서 사용합니다.

// Server: 토큰 발급
const admin = new HeadlessCommerce({ apiKey: 'sk_test_xxx' });
const { token } = await admin.customers.adminCreateToken('cus_xxx');

// Client: 토큰 설정
const client = new HeadlessCommerce({ apiKey: 'pk_test_xxx' });
client.setCustomerToken(token);

// 인증된 요청
const me = await client.customers.me();
const addresses = await client.customers.listAddresses();

Auto-Pagination

for await로 전체 데이터를 자동 순회합니다.

// 리소스에 내장된 자동 페이지네이션
for await (const product of client.products.listAutoPaginate({ limit: 50 })) {
  console.log(product.name);
}

// 또는 autoPaginate 헬퍼 직접 사용
import { autoPaginate } from '@headless-commerce/sdk';

for await (const order of autoPaginate(
  (params) => client.orders.list(params),
  { limit: 20 },
)) {
  console.log(order.number);
}

Retry & Timeout

const client = new HeadlessCommerce({
  apiKey: 'pk_test_xxx',
  maxRetries: 3,    // 429, 5xx 에러 시 최대 3회 재시도 (기본값: 2)
  timeout: 30000,   // 요청 타임아웃 30초 (기본값: 없음)
});

재시도는 지수 백오프(exponential backoff)를 사용하며, 429 Too Many Requests5xx 서버 에러에 대해서만 재시도합니다.

Idempotency

결제, 주문 생성 등 중복 방지가 필요한 요청에 idempotencyKey를 전달합니다.

await client.checkout.create(cart.id, checkoutInput, {
  idempotencyKey: 'unique-checkout-key-123',
});

await admin.orders.adminCreate(orderInput, {
  idempotencyKey: `order-${Date.now()}`,
});

Debug Logging

// 기본 콘솔 로깅
const client = new HeadlessCommerce({
  apiKey: 'pk_test_xxx',
  debug: true,
});
// 출력: [HeadlessCommerce] GET https://.../ 200 45ms

// 커스텀 로거 (Datadog, Sentry 등 연동)
const client = new HeadlessCommerce({
  apiKey: 'pk_test_xxx',
  logger: (entry) => {
    myLogger.info('api_request', {
      method: entry.method,
      url: entry.url,
      status: entry.status,
      duration: entry.duration,
    });
  },
});

Webhook Verification

웹훅 수신 시 서명을 검증하여 요청의 진위를 확인합니다.

import { verifyWebhookSignature } from '@headless-commerce/sdk';

app.post('/webhooks', async (req, res) => {
  const signature = req.headers['x-webhook-signature'] as string;
  const isValid = await verifyWebhookSignature(
    req.body,       // raw body string
    signature,
    WEBHOOK_SECRET,
  );

  if (!isValid) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  const event = JSON.parse(req.body);
  // event.type: 'order.created', 'payment.completed', ...
});

Error Handling

import { HeadlessCommerce, HeadlessCommerceError } from '@headless-commerce/sdk';

try {
  await client.products.get('invalid_id');
} catch (err) {
  if (err instanceof HeadlessCommerceError) {
    console.error(err.message);   // "Product not found"
    console.error(err.code);      // "RESOURCE_NOT_FOUND"
    console.error(err.status);    // 404
    console.error(err.details);   // { resource: "Product", id: "invalid_id" }

    // Boolean helpers로 에러 유형 분기
    if (err.isNotFound) {
      // 404 — 리소스 없음
    } else if (err.isValidationError) {
      // 400/422 — 입력값 오류
    } else if (err.isAuthError) {
      // 401 — 인증 실패
    } else if (err.isRateLimitError) {
      // 429 — 속도 제한
    }

    // 네트워크/타임아웃 에러는 .cause로 원인 추적
    if (err.code === 'NETWORK_ERROR' || err.code === 'TIMEOUT') {
      console.error('Original error:', err.cause);
    }
  }
}

Error Codes

API Error Codes

| Code | HTTP | 설명 | |------|------|------| | MISSING_API_KEY | 401 | API 키 누락 | | INVALID_API_KEY | 401 | 유효하지 않은 API 키 | | INVALID_CUSTOMER_TOKEN | 401 | 유효하지 않은 고객 토큰 | | VALIDATION_ERROR | 400 | 요청 데이터 검증 실패 | | INVALID_CURRENCY | 400 | 지원하지 않는 통화 코드 | | RESOURCE_NOT_FOUND | 404 | 리소스를 찾을 수 없음 | | INSUFFICIENT_STOCK | 409 | 재고 부족 | | INVALID_STATE_TRANSITION | 409 | 유효하지 않은 상태 전환 (예: cancelled → confirmed) | | CART_NOT_ACTIVE | 409 | 비활성 장바구니에 대한 조작 시도 | | DISCOUNT_EXPIRED | 409 | 만료된 할인 코드 | | RATE_LIMIT_EXCEEDED | 429 | 요청 속도 제한 초과 | | INTERNAL_ERROR | 500 | 서버 내부 오류 |

SDK Error Codes

| Code | 설명 | |------|------| | NETWORK_ERROR | 네트워크 연결 실패 (.cause에 원본 에러 포함) | | TIMEOUT | 요청 타임아웃 초과 (.cause에 AbortError 포함) | | UNKNOWN | 서버에서 JSON이 아닌 응답을 반환한 경우 |

API Reference

Storefront Resources

| Resource | Methods | |----------|---------| | client.products | list(), get(), getBySlug(), listAutoPaginate() | | client.categories | list(), getBySlug() | | client.collections | list(), get(), getBySlug(), listAutoPaginate() | | client.carts | create(), get(), getBySession(), update(), addItem(), updateItem(), removeItem(), applyDiscount(), removeDiscount(), merge() | | client.checkout | create() | | client.orders | list(), get(), lookup(), listAutoPaginate() | | client.customers | me(), updateMe(), listAddresses(), createAddress(), updateAddress(), deleteAddress() | | client.shipping | list() |

Admin Resources

| Resource | Methods | |----------|---------| | client.products | adminList(), adminGet(), adminCreate(), adminUpdate(), adminDelete(), adminAddImage(), adminRemoveImage(), adminListBundleItems(), adminAddBundleItem(), adminRemoveBundleItem(), adminListAutoPaginate() | | client.categories | adminList(), adminCreate(), adminUpdate(), adminDelete() | | client.collections | adminList(), adminCreate(), adminUpdate(), adminDelete(), adminListAutoPaginate() | | client.orders | adminList(), adminGet(), adminCreate(), adminUpdate(), adminConfirm(), adminProcess(), adminComplete(), adminCancel(), adminListAutoPaginate() | | client.customers | adminList(), adminGet(), adminCreate(), adminUpdate(), adminDelete(), adminCreateToken(), adminListAutoPaginate() | | client.variants | adminList(), adminCreate(), adminUpdate(), adminDelete() | | client.inventory | adminList(), adminGet(), adminUpdateSettings(), adminAdjust(), adminListAutoPaginate() | | client.payments | adminCreate(), adminComplete() | | client.fulfillments | adminCreate(), adminUpdate(), adminShip(), adminDeliver() | | client.discounts | adminList(), adminGet(), adminCreate(), adminUpdate(), adminDelete(), adminListAutoPaginate() | | client.shippingMethods | adminList(), adminGet(), adminCreate(), adminUpdate(), adminDelete() | | client.apiKeys | adminList(), adminCreate(), adminDelete(), adminRotate() | | client.organization | adminGet(), adminUpdate(), adminListMembers(), adminAddMember(), adminUpdateMember(), adminRemoveMember() | | client.store | adminGet(), adminUpdate() | | client.webhooks | adminList(), adminGet(), adminCreate(), adminUpdate(), adminDelete(), adminTest() |

Type Exports

모든 타입을 re-export합니다.

import type {
  Product, Variant, Category, Collection,
  Cart, CartItem, Order, OrderLine,
  Customer, CustomerAddress,
  ShippingMethod, Discount,
  PaginatedResponse, Money,
} from '@headless-commerce/sdk';

Requirements

  • Node.js 18+ (native fetch 필요)
  • TypeScript 5.0+ (권장)

License

MIT