npm package: @janbox/contentful-marketplace-sdk
Description: TypeScript SDK for querying iChiba marketplace content from Contentful GraphQL.
Latest version: 1.0.6

# @janbox/contentful-marketplace-sdk

TypeScript SDK for querying iChiba marketplace content from Contentful GraphQL.

## Features

- Typed API for marketplace content entries.
- Built-in market/language filtering in query builders.
- Single-entry methods with 404 handling.
- Works in both ESM and CJS builds.

## Installation

`contentful` is a peer dependency and must be installed in your app.

```bash
# pnpm
pnpm add @janbox/contentful-marketplace-sdk contentful

# npm
npm install @janbox/contentful-marketplace-sdk contentful

# yarn
yarn add @janbox/contentful-marketplace-sdk contentful
```

## Quick Start

```ts
import {
  ContentfulSDK,
  getBannerCollections,
} from "@janbox/contentful-marketplace-sdk";
import type { CreateClientParams } from "contentful";

const clientOptions: CreateClientParams = {
  space: process.env.CONTENTFUL_SPACE_ID!,
  accessToken: process.env.CONTENTFUL_ACCESS_TOKEN!,
  environment: "master", // optional, defaults to "master"
};

ContentfulSDK.configure(clientOptions);

const result = await getBannerCollections({
  slot: "home_hero",
  marketCode: "vn",
  language: "en",
  platform: "WEB",
  page: 1,
  size: 10,
});

console.log(result.items);
```

## Configuration

### `ContentfulSDK.configure(params)`

Configure the SDK once before calling entry methods.

```ts
ContentfulSDK.configure({
  space: "your-space-id",
  accessToken: "your-delivery-access-token",
  environment: "master",
});
```

Notes:

- `environment` defaults to `"master"` if omitted.
- The SDK sends requests to `https://graphql.contentful.com/content/v1/...`.
- Runtime requires `fetch` (Node.js 18+ recommended).

## API Methods

Collection methods return `{ page, total, size, items }`.
Detail methods return the entry object directly.

### Banner Collection

- `getBannerCollections(options)`

```ts
await getBannerCollections({
  slot: "home_hero",
  page: 1,
  size: 20,
  platform: "WEB",
  marketCode: "vn",
  language: "en",
});
```

### Blog

- `getBlogPosts(options?)`
- `getBlogPostDetail({ id } | { slug })`

```ts
const posts = await getBlogPosts({
  marketCode: "vn",
  language: "en",
  page: 1,
  size: 10,
});
// paging response shape: { page, total, size, items }

const post = await getBlogPostDetail({
  slug: "how-to-shop-online",
  marketCode: "vn",
  language: "en",
});

const postById = await getBlogPostDetail({
  id: "1a2b3c4d5e",
  marketCode: "vn",
  language: "en",
});
```

### Documentation

- `getDocCategories(options?)`
- `getDocCategoryDetail({ id } | { slug })`
- `getDocArticles(options?)`
- `getDocArticleDetail({ id } | { slug })`

```ts
const categories = await getDocCategories({
  marketCode: "vn",
  language: "en",
  page: 1,
  size: 10,
});
// paging response shape: { page, total, size, items }

const category = await getDocCategoryDetail({
  slug: "getting-started",
  marketCode: "vn",
  language: "en",
});

const categoryById = await getDocCategoryDetail({
  id: "1a2b3c4d5e",
  marketCode: "vn",
  language: "en",
});

const articles = await getDocArticles({
  categorySlug: "getting-started",
  marketCode: "vn",
  language: "en",
  page: 1,
  size: 10,
});
// getDocArticles returns summary fields only (no content, no seo)

const article = await getDocArticleDetail({
  slug: "payment-methods",
  marketCode: "vn",
  language: "en",
});

const articleById = await getDocArticleDetail({
  id: "1a2b3c4d5e",
  marketCode: "vn",
  language: "en",
});
```

### Brand / Hyperlink / Keyword Collections

- `getBrandCollections(options?)`
- `getHyperlinkCollections(options?)`
- `getKeywordCollections(options?)`

```ts
const brands = await getBrandCollections({
  marketCode: "vn",
  language: "en",
  page: 1,
  size: 20,
});

const links = await getHyperlinkCollections({
  page: 1,
  size: 20,
  marketCode: "vn",
  language: "en",
});

const keywords = await getKeywordCollections({
  marketCode: "vn",
  language: "en",
  page: 1,
  size: 20,
});
```

## Error Handling

`getBlogPostDetail`, `getDocCategoryDetail`, and `getDocArticleDetail` throw:

- `Error("Either id or slug is required.")` if neither `id` nor `slug` is provided.
- `Response` with status `404` when no entry is found.

```ts
try {
  await getDocArticleDetail({ slug: "unknown-slug" });
} catch (error) {
  if (error instanceof Response && error.status === 404) {
    console.log("Entry not found");
  }
}
```

## Market/Language Filtering Behavior

When `marketCode` or `language` is provided, queries include both:

- entries matching the given code
- entries where that field is not set

This supports global fallback content.

## Exported Types

The package exports:

- client and entry functions from `src/client` and `src/entries`
- Contentful schema types from `src/types`
- entry aliases such as `BlogPostEntry`, `DocArticleEntry`, and `DocCategoryEntry`

## Development

From repository root:

```bash
pnpm install
pnpm --filter @janbox/contentful-marketplace-sdk build
pnpm --filter @janbox/contentful-marketplace-sdk test
```