@faststore/api 1.9.5 → 1.9.8
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/CHANGELOG.md +33 -0
- package/dist/__generated__/schema.d.ts +49 -33
- package/dist/api.cjs.development.js +169 -61
- package/dist/api.cjs.development.js.map +1 -1
- package/dist/api.cjs.production.min.js +1 -1
- package/dist/api.cjs.production.min.js.map +1 -1
- package/dist/api.esm.js +165 -62
- package/dist/api.esm.js.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/platforms/errors.d.ts +19 -0
- package/dist/platforms/vtex/clients/commerce/types/Portal.d.ts +1 -1
- package/dist/platforms/vtex/index.d.ts +5 -4
- package/dist/platforms/vtex/loaders/index.d.ts +1 -1
- package/dist/platforms/vtex/loaders/sku.d.ts +1 -2
- package/dist/platforms/vtex/resolvers/mutation.d.ts +3 -3
- package/dist/platforms/vtex/resolvers/offer.d.ts +1 -1
- package/dist/platforms/vtex/resolvers/seo.d.ts +1 -0
- package/dist/platforms/vtex/resolvers/validateCart.d.ts +3 -3
- package/dist/platforms/vtex/utils/canonical.d.ts +2 -0
- package/dist/platforms/vtex/utils/facets.d.ts +2 -0
- package/dist/platforms/vtex/utils/orderStatistics.d.ts +4 -0
- package/dist/platforms/vtex/utils/sku.d.ts +8 -0
- package/package.json +3 -2
- package/src/__generated__/schema.ts +49 -33
- package/src/index.ts +1 -0
- package/src/platforms/errors.ts +34 -0
- package/src/platforms/vtex/clients/commerce/index.ts +1 -1
- package/src/platforms/vtex/clients/commerce/types/Portal.ts +1 -1
- package/src/platforms/vtex/loaders/collection.ts +1 -1
- package/src/platforms/vtex/loaders/sku.ts +6 -19
- package/src/platforms/vtex/resolvers/offer.ts +6 -3
- package/src/platforms/vtex/resolvers/product.ts +6 -4
- package/src/platforms/vtex/resolvers/query.ts +44 -1
- package/src/platforms/vtex/resolvers/seo.ts +2 -2
- package/src/platforms/vtex/resolvers/validateCart.ts +3 -3
- package/src/platforms/vtex/utils/canonical.ts +3 -0
- package/src/platforms/vtex/utils/facets.ts +6 -0
- package/src/platforms/vtex/utils/orderStatistics.ts +16 -0
- package/src/platforms/vtex/utils/sku.ts +26 -0
- package/src/typeDefs/cart.graphql +1 -1
- package/src/typeDefs/collection.graphql +12 -0
- package/src/typeDefs/mutation.graphql +2 -2
- package/src/typeDefs/order.graphql +1 -1
- package/src/typeDefs/pageInfo.graphql +5 -5
- package/src/typeDefs/query.graphql +59 -23
- package/src/typeDefs/session.graphql +4 -4
- package/src/typeDefs/status.graphql +1 -1
- package/dist/platforms/vtex/utils/errors.d.ts +0 -6
- package/src/platforms/vtex/utils/errors.ts +0 -13
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import { NotFoundError, BadRequestError } from '../../errors'
|
|
1
2
|
import { mutateChannelContext, mutateLocaleContext } from '../utils/contex'
|
|
2
3
|
import { enhanceSku } from '../utils/enhanceSku'
|
|
3
4
|
import {
|
|
4
5
|
findChannel,
|
|
5
6
|
findLocale,
|
|
7
|
+
findSkuId,
|
|
8
|
+
findSlug,
|
|
6
9
|
transformSelectedFacet,
|
|
7
10
|
} from '../utils/facets'
|
|
8
11
|
import { SORT_MAP } from '../utils/sort'
|
|
@@ -16,12 +19,15 @@ import type {
|
|
|
16
19
|
} from '../../../__generated__/schema'
|
|
17
20
|
import type { CategoryTree } from '../clients/commerce/types/CategoryTree'
|
|
18
21
|
import type { Context } from '../index'
|
|
22
|
+
import { isValidSkuId, pickBestSku } from '../utils/sku'
|
|
19
23
|
|
|
20
24
|
export const Query = {
|
|
21
25
|
product: async (_: unknown, { locator }: QueryProductArgs, ctx: Context) => {
|
|
22
26
|
// Insert channel in context for later usage
|
|
23
27
|
const channel = findChannel(locator)
|
|
24
28
|
const locale = findLocale(locator)
|
|
29
|
+
const id = findSkuId(locator)
|
|
30
|
+
const slug = findSlug(locator)
|
|
25
31
|
|
|
26
32
|
if (channel) {
|
|
27
33
|
mutateChannelContext(ctx, channel)
|
|
@@ -33,9 +39,46 @@ export const Query = {
|
|
|
33
39
|
|
|
34
40
|
const {
|
|
35
41
|
loaders: { skuLoader },
|
|
42
|
+
clients: { commerce, search },
|
|
36
43
|
} = ctx
|
|
37
44
|
|
|
38
|
-
|
|
45
|
+
try {
|
|
46
|
+
const skuId = id ?? slug?.split('-').pop() ?? ''
|
|
47
|
+
|
|
48
|
+
if (!isValidSkuId(skuId)) {
|
|
49
|
+
throw new Error('Invalid SkuId')
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const sku = await skuLoader.load(skuId)
|
|
53
|
+
|
|
54
|
+
return sku
|
|
55
|
+
} catch (err) {
|
|
56
|
+
if (slug == null) {
|
|
57
|
+
throw new BadRequestError('Missing slug or id')
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const route = await commerce.catalog.portal.pagetype(`${slug}/p`)
|
|
61
|
+
|
|
62
|
+
if (route.pageType !== 'Product' || !route.id) {
|
|
63
|
+
throw new NotFoundError(`No product found for slug ${slug}`)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const {
|
|
67
|
+
products: [product],
|
|
68
|
+
} = await search.products({
|
|
69
|
+
page: 0,
|
|
70
|
+
count: 1,
|
|
71
|
+
query: `product:${route.id}`,
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
if (!product) {
|
|
75
|
+
throw new NotFoundError(`No product found for id ${route.id}`)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const sku = pickBestSku(product.items)
|
|
79
|
+
|
|
80
|
+
return enhanceSku(sku, product)
|
|
81
|
+
}
|
|
39
82
|
},
|
|
40
83
|
collection: (_: unknown, { slug }: QueryCollectionArgs, ctx: Context) => {
|
|
41
84
|
const {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { Resolver } from '..'
|
|
2
2
|
|
|
3
|
-
type Root = { title?: string; description?: string }
|
|
3
|
+
type Root = { title?: string; description?: string; canonical?: string }
|
|
4
4
|
|
|
5
5
|
export const StoreSeo: Record<string, Resolver<Root>> = {
|
|
6
6
|
title: ({ title }) => title ?? '',
|
|
7
7
|
description: ({ description }) => description ?? '',
|
|
8
|
+
canonical: ({ canonical }) => canonical ?? '',
|
|
8
9
|
titleTemplate: () => '',
|
|
9
|
-
canonical: () => '',
|
|
10
10
|
}
|
|
@@ -96,16 +96,16 @@ const equals = (storeOrder: IStoreOrder, orderForm: OrderForm) => {
|
|
|
96
96
|
return isSameOrder && orderItemsAreSync
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
const orderFormToCart = (
|
|
99
|
+
const orderFormToCart = async (
|
|
100
100
|
form: OrderForm,
|
|
101
101
|
skuLoader: Context['loaders']['skuLoader']
|
|
102
102
|
) => {
|
|
103
103
|
return {
|
|
104
104
|
order: {
|
|
105
105
|
orderNumber: form.orderFormId,
|
|
106
|
-
acceptedOffer: form.items.map((item) => ({
|
|
106
|
+
acceptedOffer: form.items.map(async (item) => ({
|
|
107
107
|
...item,
|
|
108
|
-
product: skuLoader.load(
|
|
108
|
+
product: await skuLoader.load(item.id), // TODO: add channel
|
|
109
109
|
})),
|
|
110
110
|
},
|
|
111
111
|
messages: form.messages.map(({ text, status }) => ({
|
|
@@ -34,6 +34,12 @@ export const transformSelectedFacet = ({ key, value }: SelectedFacet) => {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
export const findSlug = (facets?: Maybe<SelectedFacet[]>) =>
|
|
38
|
+
facets?.find((x) => x.key === 'slug')?.value ?? null
|
|
39
|
+
|
|
40
|
+
export const findSkuId = (facets?: Maybe<SelectedFacet[]>) =>
|
|
41
|
+
facets?.find((x) => x.key === 'id')?.value ?? null
|
|
42
|
+
|
|
37
43
|
export const findLocale = (facets?: Maybe<SelectedFacet[]>) =>
|
|
38
44
|
facets?.find((x) => x.key === 'locale')?.value ?? null
|
|
39
45
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* More info at: https://en.wikipedia.org/wiki/Order_statistic
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// O(n) search to find the max of an array
|
|
6
|
+
export const min = <T>(array: T[], cmp: (a: T, b: T) => number) => {
|
|
7
|
+
let best = 0
|
|
8
|
+
|
|
9
|
+
for (let curr = 1; curr < array.length; curr++) {
|
|
10
|
+
if (cmp(array[best], array[curr]) > 0) {
|
|
11
|
+
best = curr
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return array[best]
|
|
16
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { min } from './orderStatistics'
|
|
2
|
+
import { bestOfferFirst } from './productStock'
|
|
3
|
+
import type { Item } from '../clients/search/types/ProductSearchResult'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* This function implements Portal heuristics for returning the best sku for a product.
|
|
7
|
+
*
|
|
8
|
+
* The best sku is the one with the best (cheapest available) offer
|
|
9
|
+
* */
|
|
10
|
+
export const pickBestSku = (skus: Item[]) => {
|
|
11
|
+
const offersBySku = skus.flatMap((sku) =>
|
|
12
|
+
sku.sellers.map((seller) => ({
|
|
13
|
+
offer: seller.commertialOffer,
|
|
14
|
+
sku,
|
|
15
|
+
}))
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
const best = min(offersBySku, ({ offer: o1 }, { offer: o2 }) =>
|
|
19
|
+
bestOfferFirst(o1, o2)
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
return best.sku
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const isValidSkuId = (skuId: string) =>
|
|
26
|
+
skuId !== '' && !Number.isNaN(Number(skuId))
|
|
@@ -2,9 +2,21 @@
|
|
|
2
2
|
Product collection type. Possible values are `Department`, `Category`, `Brand` or `Cluster`.
|
|
3
3
|
"""
|
|
4
4
|
enum StoreCollectionType {
|
|
5
|
+
"""
|
|
6
|
+
First level of product categorization.
|
|
7
|
+
"""
|
|
5
8
|
Department
|
|
9
|
+
"""
|
|
10
|
+
Second level of product categorization.
|
|
11
|
+
"""
|
|
6
12
|
Category
|
|
13
|
+
"""
|
|
14
|
+
Product brand.
|
|
15
|
+
"""
|
|
7
16
|
Brand
|
|
17
|
+
"""
|
|
18
|
+
Product cluster.
|
|
19
|
+
"""
|
|
8
20
|
Cluster
|
|
9
21
|
}
|
|
10
22
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
type Mutation {
|
|
2
2
|
"""
|
|
3
|
-
|
|
3
|
+
Checks for changes between the cart presented in the UI and the cart stored in the ecommerce platform. If changes are detected, it returns the cart stored on the platform. Otherwise, it returns `null`.
|
|
4
4
|
"""
|
|
5
5
|
validateCart(cart: IStoreCart!): StoreCart
|
|
6
6
|
"""
|
|
7
|
-
|
|
7
|
+
Updates a web session with the specified values.
|
|
8
8
|
"""
|
|
9
9
|
validateSession(session: IStoreSession!, search: String!): StoreSession
|
|
10
10
|
}
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
Whenever you make a query that allows for pagination, such as `allProducts` or `allCollections`, you can check `StorePageInfo` to learn more about the complete set of items and use it to paginate your queries.
|
|
3
3
|
"""
|
|
4
4
|
type StorePageInfo {
|
|
5
5
|
"""
|
|
6
|
-
Indicates whether
|
|
6
|
+
Indicates whether there is at least one more page with items after the ones returned in the current query.
|
|
7
7
|
"""
|
|
8
8
|
hasNextPage: Boolean!
|
|
9
9
|
"""
|
|
10
|
-
Indicates whether
|
|
10
|
+
Indicates whether there is at least one more page with items before the ones returned in the current query.
|
|
11
11
|
"""
|
|
12
12
|
hasPreviousPage: Boolean!
|
|
13
13
|
"""
|
|
14
|
-
|
|
14
|
+
Cursor corresponding to the first possible item.
|
|
15
15
|
"""
|
|
16
16
|
startCursor: String!
|
|
17
17
|
"""
|
|
18
|
-
|
|
18
|
+
Cursor corresponding to the last possible item.
|
|
19
19
|
"""
|
|
20
20
|
endCursor: String!
|
|
21
21
|
"""
|
|
@@ -1,78 +1,108 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
Each product edge contains a `node`, with product information, and a `cursor`, that can be used as a reference for pagination.
|
|
3
3
|
"""
|
|
4
4
|
type StoreProductEdge {
|
|
5
5
|
"""
|
|
6
|
-
|
|
6
|
+
Each product node contains the information of a product returned by the query.
|
|
7
7
|
"""
|
|
8
8
|
node: StoreProduct!
|
|
9
9
|
"""
|
|
10
|
-
Product pagination
|
|
10
|
+
Product cursor. Used as pagination reference.
|
|
11
11
|
"""
|
|
12
12
|
cursor: String!
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
"""
|
|
16
|
-
Product
|
|
16
|
+
Product connections, including pagination information and products returned by the query.
|
|
17
17
|
"""
|
|
18
18
|
type StoreProductConnection {
|
|
19
19
|
"""
|
|
20
|
-
Product
|
|
20
|
+
Product pagination information.
|
|
21
21
|
"""
|
|
22
22
|
pageInfo: StorePageInfo!
|
|
23
23
|
"""
|
|
24
|
-
Array with product connection
|
|
24
|
+
Array with product connection edges, each containing a product and a corresponding cursor.
|
|
25
25
|
"""
|
|
26
26
|
edges: [StoreProductEdge!]!
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
"""
|
|
30
|
-
|
|
30
|
+
Each collection edge contains a `node`, with product collection information, and a `cursor`, that can be used as a reference for pagination.
|
|
31
31
|
"""
|
|
32
32
|
type StoreCollectionEdge {
|
|
33
33
|
"""
|
|
34
|
-
|
|
34
|
+
Each collection node contains the information of a product collection returned by the query.
|
|
35
35
|
"""
|
|
36
36
|
node: StoreCollection!
|
|
37
37
|
"""
|
|
38
|
-
Collection pagination
|
|
38
|
+
Collection cursor. Used as pagination reference.
|
|
39
39
|
"""
|
|
40
40
|
cursor: String!
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
"""
|
|
44
|
-
Collection
|
|
44
|
+
Collection connections, including pagination information and collections returned by the query.
|
|
45
45
|
"""
|
|
46
46
|
type StoreCollectionConnection {
|
|
47
47
|
"""
|
|
48
|
-
Collection
|
|
48
|
+
Collection pagination information.
|
|
49
49
|
"""
|
|
50
50
|
pageInfo: StorePageInfo!
|
|
51
51
|
"""
|
|
52
|
-
Array with collection connection page edges
|
|
52
|
+
Array with collection connection page edges, each containing a collection and a corresponding cursor..
|
|
53
53
|
"""
|
|
54
54
|
edges: [StoreCollectionEdge!]!
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
"""
|
|
58
|
-
Product sorting options
|
|
58
|
+
Product search results sorting options.
|
|
59
59
|
"""
|
|
60
60
|
enum StoreSort {
|
|
61
|
+
"""
|
|
62
|
+
Sort by price, from highest to lowest.
|
|
63
|
+
"""
|
|
61
64
|
price_desc
|
|
65
|
+
"""
|
|
66
|
+
Sort by price, from lowest to highest.
|
|
67
|
+
"""
|
|
62
68
|
price_asc
|
|
69
|
+
"""
|
|
70
|
+
Sort by orders, from highest to lowest.
|
|
71
|
+
"""
|
|
63
72
|
orders_desc
|
|
73
|
+
"""
|
|
74
|
+
Sort by name, in reverse alphabetical order.
|
|
75
|
+
"""
|
|
64
76
|
name_desc
|
|
77
|
+
"""
|
|
78
|
+
Sort by name, in alphabetical order.
|
|
79
|
+
"""
|
|
65
80
|
name_asc
|
|
81
|
+
"""
|
|
82
|
+
Sort by release date, from highest to lowest.
|
|
83
|
+
"""
|
|
66
84
|
release_desc
|
|
85
|
+
"""
|
|
86
|
+
Sort by discount value, from highest to lowest.
|
|
87
|
+
"""
|
|
67
88
|
discount_desc
|
|
89
|
+
"""
|
|
90
|
+
Sort by product score, from highest to lowest.
|
|
91
|
+
"""
|
|
68
92
|
score_desc
|
|
69
93
|
}
|
|
70
94
|
|
|
71
95
|
"""
|
|
72
|
-
Selected facet input.
|
|
96
|
+
Selected search facet input.
|
|
73
97
|
"""
|
|
74
98
|
input IStoreSelectedFacet {
|
|
99
|
+
"""
|
|
100
|
+
Selected search facet key.
|
|
101
|
+
"""
|
|
75
102
|
key: String!
|
|
103
|
+
"""
|
|
104
|
+
Selected search facet value.
|
|
105
|
+
"""
|
|
76
106
|
value: String!
|
|
77
107
|
}
|
|
78
108
|
|
|
@@ -80,7 +110,13 @@ input IStoreSelectedFacet {
|
|
|
80
110
|
Search facet type.
|
|
81
111
|
"""
|
|
82
112
|
enum StoreFacetType {
|
|
113
|
+
"""
|
|
114
|
+
Indicates boolean search facet.
|
|
115
|
+
"""
|
|
83
116
|
BOOLEAN
|
|
117
|
+
"""
|
|
118
|
+
Indicates range type search facet.
|
|
119
|
+
"""
|
|
84
120
|
RANGE
|
|
85
121
|
}
|
|
86
122
|
|
|
@@ -132,17 +168,17 @@ type StoreSearchResult {
|
|
|
132
168
|
|
|
133
169
|
type Query {
|
|
134
170
|
"""
|
|
135
|
-
|
|
171
|
+
Returns the details of a product based on the specified locator.
|
|
136
172
|
"""
|
|
137
173
|
product(
|
|
138
174
|
"""
|
|
139
|
-
|
|
175
|
+
An array of selected search facets.
|
|
140
176
|
"""
|
|
141
177
|
locator: [IStoreSelectedFacet!]!
|
|
142
178
|
): StoreProduct!
|
|
143
179
|
|
|
144
180
|
"""
|
|
145
|
-
|
|
181
|
+
Returns the details of a collection based on the collection slug.
|
|
146
182
|
"""
|
|
147
183
|
collection(
|
|
148
184
|
"""
|
|
@@ -152,7 +188,7 @@ type Query {
|
|
|
152
188
|
): StoreCollection!
|
|
153
189
|
|
|
154
190
|
"""
|
|
155
|
-
|
|
191
|
+
Returns the result of a product, facet, or suggestion search.
|
|
156
192
|
"""
|
|
157
193
|
search(
|
|
158
194
|
"""
|
|
@@ -160,7 +196,7 @@ type Query {
|
|
|
160
196
|
"""
|
|
161
197
|
first: Int!
|
|
162
198
|
"""
|
|
163
|
-
Search pagination argument, indicating the item after which the results should be fetched.
|
|
199
|
+
Search pagination argument, indicating the cursor corresponding with the item after which the results should be fetched.
|
|
164
200
|
"""
|
|
165
201
|
after: String
|
|
166
202
|
"""
|
|
@@ -178,7 +214,7 @@ type Query {
|
|
|
178
214
|
): StoreSearchResult!
|
|
179
215
|
|
|
180
216
|
"""
|
|
181
|
-
|
|
217
|
+
Returns information about all products.
|
|
182
218
|
"""
|
|
183
219
|
allProducts(
|
|
184
220
|
"""
|
|
@@ -186,13 +222,13 @@ type Query {
|
|
|
186
222
|
"""
|
|
187
223
|
first: Int!,
|
|
188
224
|
"""
|
|
189
|
-
Product pagination argument, indicating the item after which the items should be fetched.
|
|
225
|
+
Product pagination argument, indicating the cursor corresponding with the item after which the items should be fetched.
|
|
190
226
|
"""
|
|
191
227
|
after: String
|
|
192
228
|
): StoreProductConnection!
|
|
193
229
|
|
|
194
230
|
"""
|
|
195
|
-
|
|
231
|
+
Returns information about all collections.
|
|
196
232
|
"""
|
|
197
233
|
allCollections(
|
|
198
234
|
"""
|
|
@@ -200,7 +236,7 @@ type Query {
|
|
|
200
236
|
"""
|
|
201
237
|
first: Int!,
|
|
202
238
|
"""
|
|
203
|
-
Collection pagination argument, indicating the item after which the items should be fetched.
|
|
239
|
+
Collection pagination argument, indicating the cursor corresponding with the item after which the items should be fetched.
|
|
204
240
|
"""
|
|
205
241
|
after: String
|
|
206
242
|
): StoreCollectionConnection!
|
|
@@ -3,22 +3,22 @@ Currency information.
|
|
|
3
3
|
"""
|
|
4
4
|
type StoreCurrency {
|
|
5
5
|
"""
|
|
6
|
-
Currency code
|
|
6
|
+
Currency code (e.g: USD).
|
|
7
7
|
"""
|
|
8
8
|
code: String!
|
|
9
9
|
"""
|
|
10
|
-
Currency symbol
|
|
10
|
+
Currency symbol (e.g: $).
|
|
11
11
|
"""
|
|
12
12
|
symbol: String!
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
input IStoreCurrency {
|
|
16
16
|
"""
|
|
17
|
-
Currency code
|
|
17
|
+
Currency code (e.g: USD).
|
|
18
18
|
"""
|
|
19
19
|
code: String!
|
|
20
20
|
"""
|
|
21
|
-
Currency symbol
|
|
21
|
+
Currency symbol (e.g: $).
|
|
22
22
|
"""
|
|
23
23
|
symbol: String!
|
|
24
24
|
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export class BadRequestError extends Error {
|
|
2
|
-
constructor(message: string) {
|
|
3
|
-
super(message)
|
|
4
|
-
this.name = 'BadRequestError'
|
|
5
|
-
}
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export class NotFoundError extends Error {
|
|
9
|
-
constructor(message: string) {
|
|
10
|
-
super(message)
|
|
11
|
-
this.name = 'NotFoundError'
|
|
12
|
-
}
|
|
13
|
-
}
|