@janbox/contentful-marketplace-sdk 1.0.1 → 1.0.3
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 +73 -34
- package/dist/entries/banner-collection.d.ts +9 -5
- package/dist/entries/blog.d.ts +30 -29
- package/dist/entries/brand-collection.d.ts +9 -5
- package/dist/entries/documentation.d.ts +35 -33
- package/dist/entries/hyperlink-collection.d.ts +9 -4
- package/dist/entries/keyword-collection.d.ts +9 -5
- package/dist/index.cjs +87 -121
- package/dist/index.js +512 -492
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ TypeScript SDK for querying iChiba marketplace content from Contentful GraphQL.
|
|
|
6
6
|
|
|
7
7
|
- Typed API for marketplace content entries.
|
|
8
8
|
- Built-in market/language filtering in query builders.
|
|
9
|
-
-
|
|
9
|
+
- Single-entry methods with 404 handling.
|
|
10
10
|
- Works in both ESM and CJS builds.
|
|
11
11
|
|
|
12
12
|
## Installation
|
|
@@ -29,7 +29,7 @@ yarn add @janbox/contentful-marketplace-sdk contentful
|
|
|
29
29
|
```ts
|
|
30
30
|
import {
|
|
31
31
|
ContentfulSDK,
|
|
32
|
-
|
|
32
|
+
listBannerCollections,
|
|
33
33
|
} from "@janbox/contentful-marketplace-sdk";
|
|
34
34
|
import type { CreateClientParams } from "contentful";
|
|
35
35
|
|
|
@@ -41,15 +41,16 @@ const clientOptions: CreateClientParams = {
|
|
|
41
41
|
|
|
42
42
|
ContentfulSDK.configure(clientOptions);
|
|
43
43
|
|
|
44
|
-
const result = await
|
|
44
|
+
const result = await listBannerCollections({
|
|
45
45
|
slot: "home_hero",
|
|
46
46
|
marketCode: "vn",
|
|
47
47
|
language: "en",
|
|
48
48
|
platform: "WEB",
|
|
49
|
-
|
|
49
|
+
page: 1,
|
|
50
|
+
size: 10,
|
|
50
51
|
});
|
|
51
52
|
|
|
52
|
-
console.log(result.
|
|
53
|
+
console.log(result.items);
|
|
53
54
|
```
|
|
54
55
|
|
|
55
56
|
## Configuration
|
|
@@ -74,16 +75,18 @@ Notes:
|
|
|
74
75
|
|
|
75
76
|
## API Methods
|
|
76
77
|
|
|
77
|
-
|
|
78
|
+
List methods return `{ page, total, size, items }`.
|
|
79
|
+
Detail methods return the entry object directly.
|
|
78
80
|
|
|
79
81
|
### Banner Collection
|
|
80
82
|
|
|
81
|
-
- `
|
|
83
|
+
- `listBannerCollections(options)`
|
|
82
84
|
|
|
83
85
|
```ts
|
|
84
|
-
await
|
|
86
|
+
await listBannerCollections({
|
|
85
87
|
slot: "home_hero",
|
|
86
|
-
|
|
88
|
+
page: 1,
|
|
89
|
+
size: 20,
|
|
87
90
|
platform: "WEB",
|
|
88
91
|
marketCode: "vn",
|
|
89
92
|
language: "en",
|
|
@@ -92,84 +95,120 @@ await listBannerCollectionEntries({
|
|
|
92
95
|
|
|
93
96
|
### Blog
|
|
94
97
|
|
|
95
|
-
- `
|
|
96
|
-
- `
|
|
98
|
+
- `listBlogPosts(options?)`
|
|
99
|
+
- `getBlogPostDetail({ id } | { slug })`
|
|
97
100
|
|
|
98
101
|
```ts
|
|
99
|
-
const posts = await
|
|
102
|
+
const posts = await listBlogPosts({
|
|
100
103
|
marketCode: "vn",
|
|
101
104
|
language: "en",
|
|
102
|
-
|
|
103
|
-
|
|
105
|
+
page: 1,
|
|
106
|
+
size: 10,
|
|
104
107
|
});
|
|
108
|
+
// paging response shape: { page, total, size, items }
|
|
105
109
|
|
|
106
|
-
const post = await
|
|
110
|
+
const post = await getBlogPostDetail({
|
|
107
111
|
slug: "how-to-shop-online",
|
|
108
112
|
marketCode: "vn",
|
|
109
113
|
language: "en",
|
|
110
114
|
});
|
|
115
|
+
|
|
116
|
+
const postById = await getBlogPostDetail({
|
|
117
|
+
id: "1a2b3c4d5e",
|
|
118
|
+
marketCode: "vn",
|
|
119
|
+
language: "en",
|
|
120
|
+
});
|
|
111
121
|
```
|
|
112
122
|
|
|
113
123
|
### Documentation
|
|
114
124
|
|
|
115
|
-
- `
|
|
116
|
-
- `
|
|
117
|
-
- `
|
|
118
|
-
- `
|
|
125
|
+
- `listDocCategories(options?)`
|
|
126
|
+
- `getDocCategoryDetail({ id } | { slug })`
|
|
127
|
+
- `listDocArticles(options?)`
|
|
128
|
+
- `getDocArticleDetail({ id } | { slug })`
|
|
119
129
|
|
|
120
130
|
```ts
|
|
121
|
-
const categories = await
|
|
131
|
+
const categories = await listDocCategories({
|
|
122
132
|
marketCode: "vn",
|
|
123
133
|
language: "en",
|
|
124
|
-
|
|
134
|
+
page: 1,
|
|
135
|
+
size: 10,
|
|
125
136
|
});
|
|
137
|
+
// paging response shape: { page, total, size, items }
|
|
126
138
|
|
|
127
|
-
const
|
|
139
|
+
const category = await getDocCategoryDetail({
|
|
140
|
+
slug: "getting-started",
|
|
141
|
+
marketCode: "vn",
|
|
142
|
+
language: "en",
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
const categoryById = await getDocCategoryDetail({
|
|
146
|
+
id: "1a2b3c4d5e",
|
|
147
|
+
marketCode: "vn",
|
|
148
|
+
language: "en",
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const articles = await listDocArticles({
|
|
128
152
|
categorySlug: "getting-started",
|
|
129
153
|
marketCode: "vn",
|
|
130
154
|
language: "en",
|
|
131
|
-
|
|
155
|
+
page: 1,
|
|
156
|
+
size: 10,
|
|
132
157
|
});
|
|
158
|
+
// listDocArticles returns summary fields only (no content, no seo)
|
|
133
159
|
|
|
134
|
-
const article = await
|
|
160
|
+
const article = await getDocArticleDetail({
|
|
135
161
|
slug: "payment-methods",
|
|
136
162
|
marketCode: "vn",
|
|
137
163
|
language: "en",
|
|
138
164
|
});
|
|
165
|
+
|
|
166
|
+
const articleById = await getDocArticleDetail({
|
|
167
|
+
id: "1a2b3c4d5e",
|
|
168
|
+
marketCode: "vn",
|
|
169
|
+
language: "en",
|
|
170
|
+
});
|
|
139
171
|
```
|
|
140
172
|
|
|
141
173
|
### Brand / Hyperlink / Keyword Collections
|
|
142
174
|
|
|
143
|
-
- `
|
|
144
|
-
- `
|
|
145
|
-
- `
|
|
175
|
+
- `listBrandCollections(options?)`
|
|
176
|
+
- `listHyperlinkCollections(options?)`
|
|
177
|
+
- `listKeywordCollections(options?)`
|
|
146
178
|
|
|
147
179
|
```ts
|
|
148
|
-
const brands = await
|
|
180
|
+
const brands = await listBrandCollections({
|
|
149
181
|
marketCode: "vn",
|
|
150
182
|
language: "en",
|
|
151
|
-
|
|
183
|
+
page: 1,
|
|
184
|
+
size: 20,
|
|
152
185
|
});
|
|
153
186
|
|
|
154
|
-
const links = await
|
|
187
|
+
const links = await listHyperlinkCollections({
|
|
188
|
+
page: 1,
|
|
189
|
+
size: 20,
|
|
155
190
|
marketCode: "vn",
|
|
156
191
|
language: "en",
|
|
157
192
|
});
|
|
158
193
|
|
|
159
|
-
const keywords = await
|
|
194
|
+
const keywords = await listKeywordCollections({
|
|
160
195
|
marketCode: "vn",
|
|
161
196
|
language: "en",
|
|
162
|
-
|
|
197
|
+
page: 1,
|
|
198
|
+
size: 20,
|
|
163
199
|
});
|
|
164
200
|
```
|
|
165
201
|
|
|
166
202
|
## Error Handling
|
|
167
203
|
|
|
168
|
-
`
|
|
204
|
+
`getBlogPostDetail`, `getDocCategoryDetail`, and `getDocArticleDetail` throw:
|
|
205
|
+
|
|
206
|
+
- `Error("Either id or slug is required.")` if neither `id` nor `slug` is provided.
|
|
207
|
+
- `Response` with status `404` when no entry is found.
|
|
169
208
|
|
|
170
209
|
```ts
|
|
171
210
|
try {
|
|
172
|
-
await
|
|
211
|
+
await getDocArticleDetail({ slug: "unknown-slug" });
|
|
173
212
|
} catch (error) {
|
|
174
213
|
if (error instanceof Response && error.status === 404) {
|
|
175
214
|
console.log("Entry not found");
|
|
@@ -21,14 +21,18 @@ export type BannerCollectionGraphQLItem = {
|
|
|
21
21
|
}>;
|
|
22
22
|
};
|
|
23
23
|
} & Pick<BannerCollectionEntry["fields"], "name" | "slot" | "platform">;
|
|
24
|
-
export type
|
|
25
|
-
|
|
24
|
+
export type ListBannerCollectionsResponse = {
|
|
25
|
+
page: number;
|
|
26
|
+
total: number;
|
|
27
|
+
size: number;
|
|
28
|
+
items: BannerCollectionGraphQLItem[];
|
|
26
29
|
};
|
|
27
|
-
export declare const
|
|
30
|
+
export declare const listBannerCollections: ({ slot, page, size, platform, marketCode, language, }: {
|
|
28
31
|
slot: BannerCollectionEntry["fields"]["slot"];
|
|
29
|
-
|
|
32
|
+
page?: number;
|
|
33
|
+
size?: number;
|
|
30
34
|
platform?: BannerCollectionEntry["fields"]["platform"][number];
|
|
31
35
|
marketCode?: string;
|
|
32
36
|
language?: string;
|
|
33
|
-
}) => Promise<
|
|
37
|
+
}) => Promise<ListBannerCollectionsResponse>;
|
|
34
38
|
export {};
|
package/dist/entries/blog.d.ts
CHANGED
|
@@ -1,54 +1,55 @@
|
|
|
1
1
|
import { TypeBlogPostSkeleton } from '../types';
|
|
2
2
|
import { Entry, EntrySys } from 'contentful';
|
|
3
3
|
type BlogPostEntry = Entry<TypeBlogPostSkeleton, "WITHOUT_UNRESOLVABLE_LINKS", string>;
|
|
4
|
-
type GraphQLEntrySys = Pick<EntrySys, "id">;
|
|
4
|
+
type GraphQLEntrySys = Pick<EntrySys, "id" | "createdAt" | "updatedAt">;
|
|
5
5
|
type GraphQLAsset = {
|
|
6
6
|
url: string;
|
|
7
7
|
width: number | null;
|
|
8
8
|
height: number | null;
|
|
9
9
|
contentType: string;
|
|
10
10
|
};
|
|
11
|
+
type GraphQLSeo = {
|
|
12
|
+
metaTitle: string;
|
|
13
|
+
metaDescription: string | null;
|
|
14
|
+
metaKeywords: string[] | null;
|
|
15
|
+
metaRobots: string[] | null;
|
|
16
|
+
};
|
|
17
|
+
type BlogPostCategoryGraphQLItem = {
|
|
18
|
+
title: string;
|
|
19
|
+
slug: string;
|
|
20
|
+
};
|
|
11
21
|
export type BlogPostGraphQLItem = {
|
|
12
22
|
sys: GraphQLEntrySys;
|
|
13
|
-
category:
|
|
14
|
-
sys: GraphQLEntrySys;
|
|
15
|
-
title: string;
|
|
16
|
-
slug: string;
|
|
17
|
-
} | null;
|
|
23
|
+
category: BlogPostCategoryGraphQLItem | null;
|
|
18
24
|
featuredImage: GraphQLAsset | null;
|
|
19
25
|
} & Pick<BlogPostEntry["fields"], "title" | "shortDescription" | "slug">;
|
|
20
|
-
export
|
|
26
|
+
export interface BlogPostDetailGraphQLItem extends BlogPostGraphQLItem {
|
|
21
27
|
author: {
|
|
22
|
-
sys: GraphQLEntrySys;
|
|
23
28
|
name: string;
|
|
24
29
|
avatar: GraphQLAsset | null;
|
|
25
30
|
} | null;
|
|
26
31
|
content: {
|
|
27
32
|
json: BlogPostEntry["fields"]["content"];
|
|
28
|
-
}
|
|
29
|
-
seo:
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
};
|
|
37
|
-
export type ListBlogPostEntriesResponse = {
|
|
38
|
-
data: BlogPostGraphQLItem[];
|
|
33
|
+
};
|
|
34
|
+
seo: GraphQLSeo | null;
|
|
35
|
+
}
|
|
36
|
+
export type ListBlogPostsResponse = {
|
|
37
|
+
page: number;
|
|
38
|
+
total: number;
|
|
39
|
+
size: number;
|
|
40
|
+
items: BlogPostGraphQLItem[];
|
|
39
41
|
};
|
|
40
|
-
export type
|
|
41
|
-
|
|
42
|
-
};
|
|
43
|
-
export declare const listBlogPostEntries: ({ marketCode, language, limit, skip, }?: {
|
|
42
|
+
export type GetBlogPostDetailResponse = BlogPostDetailGraphQLItem;
|
|
43
|
+
export declare const listBlogPosts: ({ marketCode, language, page, size, }?: {
|
|
44
44
|
marketCode?: string;
|
|
45
45
|
language?: string;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}) => Promise<
|
|
49
|
-
export declare const
|
|
50
|
-
|
|
46
|
+
page?: number;
|
|
47
|
+
size?: number;
|
|
48
|
+
}) => Promise<ListBlogPostsResponse>;
|
|
49
|
+
export declare const getBlogPostDetail: ({ id, slug, marketCode, language, }: {
|
|
50
|
+
id?: string;
|
|
51
|
+
slug?: string;
|
|
51
52
|
marketCode?: string;
|
|
52
53
|
language?: string;
|
|
53
|
-
}) => Promise<
|
|
54
|
+
}) => Promise<GetBlogPostDetailResponse>;
|
|
54
55
|
export {};
|
|
@@ -11,12 +11,16 @@ export type BrandCollectionGraphQLItem = {
|
|
|
11
11
|
} & Pick<BrandEntry["fields"], "name" | "slug">>;
|
|
12
12
|
};
|
|
13
13
|
} & Pick<BrandCollectionEntry["fields"], "name" | "slot">;
|
|
14
|
-
export type
|
|
15
|
-
|
|
14
|
+
export type ListBrandCollectionsResponse = {
|
|
15
|
+
page: number;
|
|
16
|
+
total: number;
|
|
17
|
+
size: number;
|
|
18
|
+
items: BrandCollectionGraphQLItem[];
|
|
16
19
|
};
|
|
17
|
-
export declare const
|
|
18
|
-
|
|
20
|
+
export declare const listBrandCollections: ({ page, size, marketCode, language, }?: {
|
|
21
|
+
page?: number;
|
|
22
|
+
size?: number;
|
|
19
23
|
marketCode?: string;
|
|
20
24
|
language?: string;
|
|
21
|
-
}) => Promise<
|
|
25
|
+
}) => Promise<ListBrandCollectionsResponse>;
|
|
22
26
|
export {};
|
|
@@ -2,7 +2,7 @@ import { TypeDocumentationArticleSkeleton, TypeDocumentationCategorySkeleton } f
|
|
|
2
2
|
import { Entry, EntrySys } from 'contentful';
|
|
3
3
|
export type DocCategoryEntry = Entry<TypeDocumentationCategorySkeleton, "WITHOUT_UNRESOLVABLE_LINKS", string>;
|
|
4
4
|
export type DocArticleEntry = Entry<TypeDocumentationArticleSkeleton, "WITHOUT_UNRESOLVABLE_LINKS", string>;
|
|
5
|
-
type GraphQLEntrySys = Pick<EntrySys, "id">;
|
|
5
|
+
type GraphQLEntrySys = Pick<EntrySys, "id" | "createdAt" | "updatedAt">;
|
|
6
6
|
type GraphQLAsset = {
|
|
7
7
|
url: string | null;
|
|
8
8
|
width: number | null;
|
|
@@ -10,7 +10,6 @@ type GraphQLAsset = {
|
|
|
10
10
|
contentType: string | null;
|
|
11
11
|
};
|
|
12
12
|
type GraphQLSeo = {
|
|
13
|
-
sys: GraphQLEntrySys;
|
|
14
13
|
metaTitle: string;
|
|
15
14
|
metaDescription: string | null;
|
|
16
15
|
metaKeywords: string[] | null;
|
|
@@ -20,55 +19,58 @@ export type DocCategoryGraphQLItem = {
|
|
|
20
19
|
sys: GraphQLEntrySys;
|
|
21
20
|
seo: GraphQLSeo | null;
|
|
22
21
|
} & Pick<DocCategoryEntry["fields"], "title" | "slug" | "description" | "order">;
|
|
22
|
+
type DocArticleCategoryGraphQLItem = Pick<DocCategoryEntry["fields"], "title" | "slug" | "description" | "order">;
|
|
23
23
|
export type DocArticleGraphQLItem = {
|
|
24
24
|
sys: GraphQLEntrySys;
|
|
25
|
-
category:
|
|
26
|
-
sys: GraphQLEntrySys;
|
|
27
|
-
seo: GraphQLSeo | null;
|
|
28
|
-
} & Pick<DocCategoryEntry["fields"], "title" | "slug" | "description" | "order">) | null;
|
|
25
|
+
category: DocArticleCategoryGraphQLItem;
|
|
29
26
|
author: {
|
|
30
|
-
sys: GraphQLEntrySys;
|
|
31
27
|
name: string;
|
|
32
28
|
avatar: GraphQLAsset | null;
|
|
33
29
|
} | null;
|
|
30
|
+
} & Pick<DocArticleEntry["fields"], "title" | "slug">;
|
|
31
|
+
export interface DocArticleDetailGraphQLItem extends DocArticleGraphQLItem {
|
|
34
32
|
content: {
|
|
35
33
|
json: DocArticleEntry["fields"]["content"];
|
|
36
|
-
}
|
|
34
|
+
};
|
|
37
35
|
seo: GraphQLSeo | null;
|
|
38
|
-
}
|
|
39
|
-
export type
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
};
|
|
45
|
-
export type ListDocArticleEntriesResponse = {
|
|
46
|
-
data: DocArticleGraphQLItem[];
|
|
36
|
+
}
|
|
37
|
+
export type ListDocCategoriesResponse = {
|
|
38
|
+
page: number;
|
|
39
|
+
total: number;
|
|
40
|
+
size: number;
|
|
41
|
+
items: DocCategoryGraphQLItem[];
|
|
47
42
|
};
|
|
48
|
-
export type
|
|
49
|
-
|
|
43
|
+
export type GetDocCategoryDetailResponse = DocCategoryGraphQLItem;
|
|
44
|
+
export type ListDocArticlesResponse = {
|
|
45
|
+
page: number;
|
|
46
|
+
total: number;
|
|
47
|
+
size: number;
|
|
48
|
+
items: DocArticleGraphQLItem[];
|
|
50
49
|
};
|
|
51
|
-
export
|
|
50
|
+
export type GetDocArticleDetailResponse = DocArticleDetailGraphQLItem;
|
|
51
|
+
export declare const listDocCategories: ({ marketCode, language, page, size, }?: {
|
|
52
52
|
marketCode?: string;
|
|
53
53
|
language?: string;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}) => Promise<
|
|
57
|
-
export declare const
|
|
58
|
-
|
|
54
|
+
page?: number;
|
|
55
|
+
size?: number;
|
|
56
|
+
}) => Promise<ListDocCategoriesResponse>;
|
|
57
|
+
export declare const getDocCategoryDetail: ({ id, slug, marketCode, language, }: {
|
|
58
|
+
id?: string;
|
|
59
|
+
slug?: string;
|
|
59
60
|
marketCode?: string;
|
|
60
61
|
language?: string;
|
|
61
|
-
}) => Promise<
|
|
62
|
-
export declare const
|
|
62
|
+
}) => Promise<GetDocCategoryDetailResponse>;
|
|
63
|
+
export declare const listDocArticles: ({ marketCode, language, categorySlug, page, size, }?: {
|
|
63
64
|
marketCode?: string;
|
|
64
65
|
language?: string;
|
|
65
66
|
categorySlug?: string;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}) => Promise<
|
|
69
|
-
export declare const
|
|
70
|
-
|
|
67
|
+
page?: number;
|
|
68
|
+
size?: number;
|
|
69
|
+
}) => Promise<ListDocArticlesResponse>;
|
|
70
|
+
export declare const getDocArticleDetail: ({ id, slug, marketCode, language, }: {
|
|
71
|
+
id?: string;
|
|
72
|
+
slug?: string;
|
|
71
73
|
marketCode?: string;
|
|
72
74
|
language?: string;
|
|
73
|
-
}) => Promise<
|
|
75
|
+
}) => Promise<GetDocArticleDetailResponse>;
|
|
74
76
|
export {};
|
|
@@ -11,11 +11,16 @@ export type HyperlinkCollectionGraphQLItem = {
|
|
|
11
11
|
} & Pick<HyperlinkEntry["fields"], "label" | "url" | "target" | "includesMarketCode">>;
|
|
12
12
|
};
|
|
13
13
|
} & Pick<HyperlinkCollectionEntry["fields"], "name" | "slot" | "order">;
|
|
14
|
-
export type
|
|
15
|
-
|
|
14
|
+
export type ListHyperlinkCollectionsResponse = {
|
|
15
|
+
page: number;
|
|
16
|
+
total: number;
|
|
17
|
+
size: number;
|
|
18
|
+
items: HyperlinkCollectionGraphQLItem[];
|
|
16
19
|
};
|
|
17
|
-
export declare const
|
|
20
|
+
export declare const listHyperlinkCollections: ({ page, size, marketCode, language, }?: {
|
|
21
|
+
page?: number;
|
|
22
|
+
size?: number;
|
|
18
23
|
marketCode?: string;
|
|
19
24
|
language?: string;
|
|
20
|
-
}) => Promise<
|
|
25
|
+
}) => Promise<ListHyperlinkCollectionsResponse>;
|
|
21
26
|
export {};
|
|
@@ -5,12 +5,16 @@ type GraphQLEntrySys = Pick<EntrySys, "id">;
|
|
|
5
5
|
export type KeywordCollectionGraphQLItem = {
|
|
6
6
|
sys: GraphQLEntrySys;
|
|
7
7
|
} & Pick<KeywordCollectionEntry["fields"], "name" | "slot" | "keywords">;
|
|
8
|
-
export type
|
|
9
|
-
|
|
8
|
+
export type ListKeywordCollectionsResponse = {
|
|
9
|
+
page: number;
|
|
10
|
+
total: number;
|
|
11
|
+
size: number;
|
|
12
|
+
items: KeywordCollectionGraphQLItem[];
|
|
10
13
|
};
|
|
11
|
-
export declare const
|
|
12
|
-
|
|
14
|
+
export declare const listKeywordCollections: ({ page, size, marketCode, language, }?: {
|
|
15
|
+
page?: number;
|
|
16
|
+
size?: number;
|
|
13
17
|
marketCode?: string;
|
|
14
18
|
language?: string;
|
|
15
|
-
}) => Promise<
|
|
19
|
+
}) => Promise<ListKeywordCollectionsResponse>;
|
|
16
20
|
export {};
|