@janbox/contentful-marketplace-sdk 2.0.1 → 3.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @janbox/contentful-marketplace-sdk
2
2
 
3
- TypeScript SDK for querying iChiba marketplace content from Contentful GraphQL.
3
+ TypeScript SDK for querying iChiba marketplace content from the internal headless CMS Delivery API (REST, Contentful CDA style).
4
4
 
5
5
  ## Features
6
6
 
@@ -31,9 +31,9 @@ import {
31
31
  } from "@janbox/contentful-marketplace-sdk";
32
32
 
33
33
  ContentfulSDK.configure({
34
- url: `https://graphql.contentful.com/content/v1/spaces/${process.env.CONTENTFUL_SPACE_ID}/environments/master`,
34
+ url: "https://headless-cms.ichiba.net/delivery/janbox",
35
35
  headers: {
36
- Authorization: `Bearer ${process.env.CONTENTFUL_ACCESS_TOKEN}`,
36
+ Authorization: `Bearer ${process.env.CMS_DELIVERY_TOKEN}`,
37
37
  },
38
38
  });
39
39
 
@@ -57,24 +57,32 @@ Configure the SDK once before calling entry methods.
57
57
 
58
58
  | Parameter | Type | Required | Description |
59
59
  |-----------|--------------------------|----------|-------------------------------------------|
60
- | `url` | `string` | ✅ | GraphQL endpoint URL |
61
- | `method` | `string` | — | HTTP method (defaults to `"POST"`) |
62
- | `headers` | `Record<string, string>` | — | Custom headers (e.g. `Authorization`) |
60
+ | `url` | `string` | ✅ | Delivery API base URL, e.g. `https://headless-cms.ichiba.net/delivery/janbox` |
61
+ | `method` | `string` | — | Deprecated and ignored: requests are always `GET` |
62
+ | `headers` | `Record<string, string>` | — | Custom headers, usually `Authorization: Bearer cdel_...` |
63
63
 
64
64
  ```ts
65
65
  ContentfulSDK.configure({
66
- url: "https://graphql.contentful.com/content/v1/spaces/your-space-id/environments/master",
66
+ url: "https://test-headless-cms.ichiba.net/delivery/janbox", // QC
67
67
  headers: {
68
- Authorization: "Bearer your-delivery-access-token",
68
+ Authorization: "Bearer cdel_your-delivery-key",
69
69
  },
70
70
  });
71
71
  ```
72
72
 
73
73
  Notes:
74
74
 
75
- - The SDK always sends `Content-Type: application/json`. Custom headers are merged on top.
75
+ - The SDK sends `GET {url}/entries?...` with `Accept: application/json`. Custom headers are merged on top.
76
+ - Keep the delivery key server-side: call the SDK from your server (route handler, BFF), never from browser JavaScript.
76
77
  - Runtime requires `fetch` (Node.js 18+ recommended).
77
78
 
79
+ ## Breaking changes in 3.0.0
80
+
81
+ 1. `url` is now the Delivery API base URL of the internal CMS, and `headers` carries the delivery key (`Authorization: Bearer cdel_...`). `method` is still accepted but ignored.
82
+ 2. The delivery key must stay on the server, so the SDK must be called server-side.
83
+ 3. Types built on the `contentful` package are removed: `TypeXxxSkeleton`, the generic `TypeXxx<Modifiers, Locales>` types, and the `DocArticleEntry`, `DocCategoryEntry` and `HyperlinkEntry` aliases. `TypeXxxFields` are kept as plain interfaces.
84
+ 4. Entry ids are the new CMS ids (GUIDs). Old Contentful ids must be migrated by the apps: the CMS rejects them with `400 InvalidQuery`, which the SDK throws as `Error("Request failed: 400 ...")`.
85
+
78
86
  ## API Methods
79
87
 
80
88
  Collection methods return `{ page, total, size, items }`.
@@ -247,8 +255,8 @@ This supports global fallback content.
247
255
  The package exports:
248
256
 
249
257
  - client and entry functions from `src/client` and `src/entries`
250
- - Contentful schema types from `src/types`
251
- - entry aliases such as `BlogPostEntry`, `DocArticleEntry`, and `DocCategoryEntry`
258
+ - content model field types (`TypeXxxFields`) and CMS response types (`CmsEntry`, `CmsAsset`, `CmsLink`, `CmsCollection`) from `src/types`
259
+ - response item types such as `BlogPostGraphQLItem` and `DocArticleGraphQLItem` (names kept from 2.x)
252
260
 
253
261
  ## Development
254
262
 
@@ -259,3 +267,10 @@ pnpm install
259
267
  pnpm --filter @janbox/contentful-marketplace-sdk build
260
268
  pnpm --filter @janbox/contentful-marketplace-sdk test
261
269
  ```
270
+
271
+ Unit tests (`*.unit.test.ts`) mock `fetch` and always run. Integration tests (`*.test.ts`) call a real Delivery API and are skipped unless these variables are set (e.g. in `packages/marketplace-sdk/.env`):
272
+
273
+ ```bash
274
+ VITE_CMS_DELIVERY_URL=https://test-headless-cms.ichiba.net/delivery/janbox
275
+ VITE_CMS_DELIVERY_TOKEN=cdel_your-delivery-key
276
+ ```
@@ -1,5 +1,8 @@
1
+ import { CmsCollection, CmsEntry } from '../types';
2
+ import { QueryParams } from '../utils/query';
1
3
  export interface ContentfulSDKConfig {
2
4
  url: string;
5
+ /** @deprecated Ignored: requests are always GET. Kept so existing configs still type-check. */
3
6
  method?: string;
4
7
  headers?: Record<string, string>;
5
8
  }
@@ -7,5 +10,5 @@ export declare class ContentfulSDK {
7
10
  private static _config;
8
11
  static get config(): ContentfulSDKConfig;
9
12
  static configure(params: ContentfulSDKConfig): void;
10
- static graphqlQuery<T extends object>(query: string, variables?: Record<string, any>): Promise<T>;
13
+ static getEntries<T = CmsEntry>(params: QueryParams): Promise<CmsCollection<T>>;
11
14
  }
@@ -1,28 +1,26 @@
1
1
  import { PaginatedResponse } from '../utils';
2
- import { GraphQLAsset, TypeBannerCollectionSkeleton } from '../types';
3
- import { Entry, EntrySys } from 'contentful';
4
- import { HyperlinkEntry } from './hyperlink';
5
- type BannerCollectionEntry = Entry<TypeBannerCollectionSkeleton, "WITHOUT_UNRESOLVABLE_LINKS", string>;
6
- type GraphQLEntrySys = Pick<EntrySys, "id">;
2
+ import { GraphQLAsset, TypeBannerCollectionFields } from '../types';
3
+ import { HyperlinkGraphQLItem } from './hyperlink';
4
+ type GraphQLEntrySys = {
5
+ id: string;
6
+ };
7
7
  export type BannerCollectionGraphQLItem = {
8
8
  sys: GraphQLEntrySys;
9
9
  bannersCollection: {
10
10
  items: Array<{
11
11
  sys: GraphQLEntrySys;
12
- hyperlink: ({
13
- sys: GraphQLEntrySys;
14
- } & Pick<HyperlinkEntry["fields"], "label" | "url" | "target" | "marketHandling">) | null;
12
+ hyperlink: HyperlinkGraphQLItem | null;
15
13
  media: GraphQLAsset;
16
14
  name: string;
17
15
  }>;
18
16
  };
19
- } & Pick<BannerCollectionEntry["fields"], "name" | "slot" | "platform">;
17
+ } & Pick<TypeBannerCollectionFields, "name" | "slot" | "platform">;
20
18
  export type GetBannerCollectionsResponse = PaginatedResponse<BannerCollectionGraphQLItem>;
21
19
  export declare const getBannerCollections: ({ slot, page, size, platform, marketCode, locale, }: {
22
- slot: BannerCollectionEntry["fields"]["slot"];
20
+ slot: TypeBannerCollectionFields["slot"];
23
21
  page?: number;
24
22
  size?: number;
25
- platform?: BannerCollectionEntry["fields"]["platform"][number];
23
+ platform?: TypeBannerCollectionFields["platform"][number];
26
24
  marketCode?: string;
27
25
  locale?: string;
28
26
  }) => Promise<GetBannerCollectionsResponse>;
@@ -1,14 +1,12 @@
1
1
  import { PaginatedResponse } from '../utils';
2
- import { GraphQLAsset, TypeBlogCategorySkeleton } from '../types';
2
+ import { GraphQLAsset, TypeBlogCategoryFields } from '../types';
3
3
  import { GraphQLSeo } from './seo';
4
- import { Entry } from 'contentful';
5
- type BlogCategoryEntry = Entry<TypeBlogCategorySkeleton, "WITHOUT_UNRESOLVABLE_LINKS", string>;
6
4
  export type BlogCategoryGraphQLItem = {
7
5
  sys: {
8
6
  id: string;
9
7
  };
10
8
  featuredImage: GraphQLAsset | null;
11
- } & Pick<BlogCategoryEntry["fields"], "title" | "slug">;
9
+ } & Pick<TypeBlogCategoryFields, "title" | "slug">;
12
10
  export interface BlogCategoryDetailGraphQLItem extends BlogCategoryGraphQLItem {
13
11
  description: string | null;
14
12
  seo: GraphQLSeo | null;
@@ -27,4 +25,3 @@ export declare const getBlogCategoryDetail: ({ id, slug, marketCode, locale, }:
27
25
  marketCode?: string;
28
26
  locale?: string;
29
27
  }) => Promise<GetBlogCategoryDetailResponse>;
30
- export {};
@@ -1,7 +1,5 @@
1
- import { TypeBlogCollectionSkeleton, GraphQLAsset } from '../types';
1
+ import { GraphQLAsset, TypeBlogCollectionFields } from '../types';
2
2
  import { PaginatedResponse } from '../utils';
3
- import { Entry } from 'contentful';
4
- type BlogCollectionEntry = Entry<TypeBlogCollectionSkeleton, "WITHOUT_UNRESOLVABLE_LINKS", string>;
5
3
  type BlogCollectionCategoryGraphQLItem = {
6
4
  sys: {
7
5
  id: string;
@@ -17,7 +15,7 @@ export type BlogCollectionGraphQLItem = {
17
15
  featuredImage: GraphQLAsset | null;
18
16
  categoryId: string | null;
19
17
  collectionId: string | null;
20
- } & Pick<BlogCollectionEntry["fields"], "name" | "type" | "order">;
18
+ } & Pick<TypeBlogCollectionFields, "name" | "type" | "order">;
21
19
  export type GetBlogCollectionsResponse = PaginatedResponse<BlogCollectionGraphQLItem>;
22
20
  export declare const getBlogCollections: ({ marketCode, locale, page, size, }?: {
23
21
  marketCode?: string;
@@ -1,9 +1,11 @@
1
- import { GraphQLAsset, GraphQLAssetLink, TypeBlogPostSkeleton } from '../types';
1
+ import { GraphQLAsset, GraphQLAssetLink, TypeBlogPostFields } from '../types';
2
2
  import { PaginatedResponse } from '../utils';
3
- import { Entry, EntrySys } from 'contentful';
4
3
  import { GraphQLSeo } from './seo';
5
- type BlogPostEntry = Entry<TypeBlogPostSkeleton, "WITHOUT_UNRESOLVABLE_LINKS", string>;
6
- type GraphQLEntrySys = Pick<EntrySys, "id" | "createdAt" | "updatedAt">;
4
+ type GraphQLEntrySys = {
5
+ id: string;
6
+ createdAt: string;
7
+ updatedAt: string;
8
+ };
7
9
  type BlogPostCategoryGraphQLItem = {
8
10
  sys: Pick<GraphQLEntrySys, "id">;
9
11
  title: string;
@@ -15,14 +17,14 @@ export type BlogPostGraphQLItem = {
15
17
  categoriesCollection: {
16
18
  items: BlogPostCategoryGraphQLItem[];
17
19
  } | null;
18
- } & Pick<BlogPostEntry["fields"], "title" | "shortDescription" | "slug">;
20
+ } & Pick<TypeBlogPostFields, "title" | "shortDescription" | "slug">;
19
21
  export interface BlogPostDetailGraphQLItem extends BlogPostGraphQLItem {
20
22
  author: {
21
23
  name: string;
22
24
  avatar: GraphQLAsset | null;
23
25
  } | null;
24
26
  content: {
25
- json: BlogPostEntry["fields"]["content"];
27
+ json: TypeBlogPostFields["content"];
26
28
  links: {
27
29
  assets: {
28
30
  block: GraphQLAssetLink[];
@@ -1,10 +1,8 @@
1
1
  import { PaginatedResponse } from '../utils';
2
- import { GraphQLAsset, TypeBrandCollectionSkeleton, TypeBrandSkeleton } from '../types';
3
- import { Entry, EntrySys } from 'contentful';
4
- import { HyperlinkEntry } from './hyperlink';
5
- type BrandEntry = Entry<TypeBrandSkeleton, "WITHOUT_UNRESOLVABLE_LINKS", string>;
6
- type BrandCollectionEntry = Entry<TypeBrandCollectionSkeleton, "WITHOUT_UNRESOLVABLE_LINKS", string>;
7
- type GraphQLEntrySys = Pick<EntrySys, "id">;
2
+ import { GraphQLAsset, TypeBrandCollectionFields, TypeBrandFields, TypeHyperlinkFields } from '../types';
3
+ type GraphQLEntrySys = {
4
+ id: string;
5
+ };
8
6
  export type BrandCollectionGraphQLItem = {
9
7
  sys: GraphQLEntrySys;
10
8
  brandsCollection: {
@@ -13,10 +11,10 @@ export type BrandCollectionGraphQLItem = {
13
11
  logo: GraphQLAsset | null;
14
12
  hyperlink: ({
15
13
  sys: GraphQLEntrySys;
16
- } & Pick<HyperlinkEntry["fields"], "label" | "url" | "target" | "marketHandling">) | null;
17
- } & Pick<BrandEntry["fields"], "name">>;
14
+ } & Pick<TypeHyperlinkFields, "label" | "url" | "target" | "marketHandling">) | null;
15
+ } & Pick<TypeBrandFields, "name">>;
18
16
  };
19
- } & Pick<BrandCollectionEntry["fields"], "name" | "slot">;
17
+ } & Pick<TypeBrandCollectionFields, "name" | "slot">;
20
18
  export type GetBrandCollectionsResponse = PaginatedResponse<BrandCollectionGraphQLItem>;
21
19
  export declare const getBrandCollections: ({ page, size, marketCode, locale, }?: {
22
20
  page?: number;
@@ -1,15 +1,16 @@
1
- import { GraphQLAsset, GraphQLAssetLink, TypeDocumentationArticleSkeleton, TypeDocumentationCategorySkeleton } from '../types';
1
+ import { GraphQLAsset, GraphQLAssetLink, TypeDocumentationArticleFields, TypeDocumentationCategoryFields } from '../types';
2
2
  import { PaginatedResponse } from '../utils';
3
- import { Entry, EntrySys } from 'contentful';
4
3
  import { GraphQLSeo } from './seo';
5
- export type DocCategoryEntry = Entry<TypeDocumentationCategorySkeleton, "WITHOUT_UNRESOLVABLE_LINKS", string>;
6
- export type DocArticleEntry = Entry<TypeDocumentationArticleSkeleton, "WITHOUT_UNRESOLVABLE_LINKS", string>;
7
- type GraphQLEntrySys = Pick<EntrySys, "id" | "createdAt" | "updatedAt">;
4
+ type GraphQLEntrySys = {
5
+ id: string;
6
+ createdAt: string;
7
+ updatedAt: string;
8
+ };
8
9
  export type DocCategoryGraphQLItem = {
9
10
  sys: GraphQLEntrySys;
10
11
  seo: GraphQLSeo | null;
11
- } & Pick<DocCategoryEntry["fields"], "title" | "slug" | "description" | "order">;
12
- type DocArticleCategoryGraphQLItem = Pick<DocCategoryEntry["fields"], "title" | "slug" | "description" | "order">;
12
+ } & Pick<TypeDocumentationCategoryFields, "title" | "slug" | "description" | "order">;
13
+ type DocArticleCategoryGraphQLItem = Pick<TypeDocumentationCategoryFields, "title" | "slug" | "description" | "order">;
13
14
  export type DocArticleGraphQLItem = {
14
15
  sys: GraphQLEntrySys;
15
16
  category: DocArticleCategoryGraphQLItem;
@@ -17,10 +18,10 @@ export type DocArticleGraphQLItem = {
17
18
  name: string;
18
19
  avatar: GraphQLAsset | null;
19
20
  } | null;
20
- } & Pick<DocArticleEntry["fields"], "title" | "slug">;
21
+ } & Pick<TypeDocumentationArticleFields, "title" | "slug">;
21
22
  export interface DocArticleDetailGraphQLItem extends DocArticleGraphQLItem {
22
23
  content: {
23
- json: DocArticleEntry["fields"]["content"];
24
+ json: TypeDocumentationArticleFields["content"];
24
25
  links: {
25
26
  assets: {
26
27
  block: GraphQLAssetLink[];
@@ -1,17 +1,16 @@
1
1
  import { PaginatedResponse } from '../utils';
2
- import { TypeHyperlinkCollectionSkeleton } from '../types';
3
- import { Entry, EntrySys } from 'contentful';
4
- import { HyperlinkEntry } from './hyperlink';
5
- type HyperlinkCollectionEntry = Entry<TypeHyperlinkCollectionSkeleton, "WITHOUT_UNRESOLVABLE_LINKS", string>;
6
- type GraphQLEntrySys = Pick<EntrySys, "id">;
2
+ import { TypeHyperlinkCollectionFields, TypeHyperlinkFields } from '../types';
3
+ type GraphQLEntrySys = {
4
+ id: string;
5
+ };
7
6
  export type HyperlinkCollectionGraphQLItem = {
8
7
  sys: GraphQLEntrySys;
9
8
  linksCollection: {
10
9
  items: Array<{
11
10
  sys: GraphQLEntrySys;
12
- } & Pick<HyperlinkEntry["fields"], "label" | "url" | "target" | 'marketHandling'>>;
11
+ } & Pick<TypeHyperlinkFields, "label" | "url" | "target" | 'marketHandling'>>;
13
12
  };
14
- } & Pick<HyperlinkCollectionEntry["fields"], "name" | "slot" | "order">;
13
+ } & Pick<TypeHyperlinkCollectionFields, "name" | "slot" | "order">;
15
14
  export type GetHyperlinkCollectionsResponse = PaginatedResponse<HyperlinkCollectionGraphQLItem>;
16
15
  export declare const getHyperlinkCollections: ({ page, size, marketCode, locale, }?: {
17
16
  page?: number;
@@ -1,3 +1,6 @@
1
- import { TypeHyperlinkSkeleton } from '../types';
2
- import { Entry } from 'contentful';
3
- export type HyperlinkEntry = Entry<TypeHyperlinkSkeleton, "WITHOUT_UNRESOLVABLE_LINKS", string>;
1
+ import { TypeHyperlinkFields } from '../types';
2
+ export type HyperlinkGraphQLItem = {
3
+ sys: {
4
+ id: string;
5
+ };
6
+ } & Pick<TypeHyperlinkFields, "label" | "url" | "target" | "marketHandling">;
@@ -1,11 +1,11 @@
1
1
  import { PaginatedResponse } from '../utils';
2
- import { TypeKeywordCollectionSkeleton } from '../types';
3
- import { Entry, EntrySys } from 'contentful';
4
- type KeywordCollectionEntry = Entry<TypeKeywordCollectionSkeleton, "WITHOUT_UNRESOLVABLE_LINKS", string>;
5
- type GraphQLEntrySys = Pick<EntrySys, "id">;
2
+ import { TypeKeywordCollectionFields } from '../types';
3
+ type GraphQLEntrySys = {
4
+ id: string;
5
+ };
6
6
  export type KeywordCollectionGraphQLItem = {
7
7
  sys: GraphQLEntrySys;
8
- } & Pick<KeywordCollectionEntry["fields"], "name" | "slot" | "keywords">;
8
+ } & Pick<TypeKeywordCollectionFields, "name" | "slot" | "keywords">;
9
9
  export type GetKeywordCollectionsResponse = PaginatedResponse<KeywordCollectionGraphQLItem>;
10
10
  export declare const getKeywordCollections: ({ page, size, marketCode, locale, }?: {
11
11
  page?: number;
@@ -1,18 +1,18 @@
1
- import { GraphQLAssetLink, TypePolicyAndTermsSkeleton } from '../types';
2
- import { Entry, EntrySys } from 'contentful';
3
- type PolicyAndTermsEntry = Entry<TypePolicyAndTermsSkeleton, "WITHOUT_UNRESOLVABLE_LINKS", string>;
4
- type GraphQLEntrySys = Pick<EntrySys, "id">;
1
+ import { GraphQLAssetLink, TypePolicyAndTermsFields } from '../types';
2
+ type GraphQLEntrySys = {
3
+ id: string;
4
+ };
5
5
  export type PolicyAndTermsGraphQLItem = {
6
6
  sys: GraphQLEntrySys;
7
7
  content: {
8
- json: PolicyAndTermsEntry["fields"]["content"];
8
+ json: TypePolicyAndTermsFields["content"];
9
9
  links: {
10
10
  assets: {
11
11
  block: GraphQLAssetLink[];
12
12
  };
13
13
  };
14
14
  } | null;
15
- } & Pick<PolicyAndTermsEntry["fields"], "title" | "locale">;
15
+ } & Pick<TypePolicyAndTermsFields, "title" | "locale">;
16
16
  export declare const getPolicyAndTerms: ({ marketCode, locale, }?: {
17
17
  marketCode?: string;
18
18
  locale?: string;