@asstio-dev/storefront 0.3.0 → 0.6.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 +67 -2
- package/dist/filters.d.ts +12 -0
- package/dist/filters.js +39 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +6 -3
- package/dist/schema.d.ts +287 -1
- package/package.json +2 -2
- package/src/schema.d.ts +287 -1
package/README.md
CHANGED
|
@@ -75,6 +75,60 @@ for (const file of product?.files ?? []) console.log(file.filename, fileUrl(site
|
|
|
75
75
|
// A variant with hasOwnImages: false inherits: variant.hasOwnImages ? variant.images : product.images
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
+
`videoSources` returns `[]` for anything that is not a video, while `mediaUrl`/`pictureSources`/`fileUrl`/`posterUrl`
|
|
79
|
+
throw `MediaUrlError` when the descriptor cannot produce that URL — branch on `kind` before calling.
|
|
80
|
+
|
|
81
|
+
### Product content
|
|
82
|
+
|
|
83
|
+
`description` is **already sanitized** on the server: render `description.html` as-is — do not sanitize, escape or
|
|
84
|
+
re-parse it — and use `description.text` wherever you need plain text (a meta description, a snippet, an
|
|
85
|
+
`aria-label`). `shortDescription` is plain text. `brand.facet` is set when the brand shares a facet's source, so it
|
|
86
|
+
can link straight to a filtered listing; when it is `null`, render `brand.label` as plain text and never guess a
|
|
87
|
+
filter.
|
|
88
|
+
|
|
89
|
+
`attributes[]` arrives ordered and labelled for display. Branch on `type` (`text` | `html` | `number` | `bool` |
|
|
90
|
+
`list`): a list fills `values`, everything else fills `value`, and `html` fills `html` too — sanitized exactly like
|
|
91
|
+
`description.html`.
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
if (product.description) render(product.description.html); // as-is: sanitized server-side
|
|
95
|
+
for (const a of product.attributes) {
|
|
96
|
+
if (a.type === "html") render(a.html!); // sanitized like description.html
|
|
97
|
+
else if (a.values) render(a.values.join(", ")); // type: "list"
|
|
98
|
+
else render(a.value!); // text | number | bool
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
`facetKey` and `valueKeys` turn an attribute's values into filter links — `filter[facetKey]=valueKeys[i]`, aligned
|
|
103
|
+
index-for-index with `values` (or carrying the single `value`'s key). `valueKeys` is absent entirely when any one
|
|
104
|
+
value has no key of its own: a list is either fully linkable or not linkable at all.
|
|
105
|
+
|
|
106
|
+
`related[]` holds groups of cards already resolved for this market, and `bundle.components[]` the cards a bundle is
|
|
107
|
+
made of; both leave out anything that no longer exists or is not sold here.
|
|
108
|
+
|
|
109
|
+
### Search-as-you-type and search-in-facet
|
|
110
|
+
|
|
111
|
+
`/v1/search/suggest` answers three short lists for what the shopper has typed so far: up to 5 product cards
|
|
112
|
+
(matched on the product name), 5 categories (each with the `path` to show above it) and 10 values from the facets
|
|
113
|
+
whose panel is searchable. `q` is required and 1–100 characters — blank, missing or longer is a 400
|
|
114
|
+
(`INVALID_QUERY`), not a truncation the way a listing's `q` is.
|
|
115
|
+
|
|
116
|
+
`/v1/products/facets/{key}` is the search box inside one facet panel: the facet's values with the counts they have
|
|
117
|
+
in the same `filter[…]` context the listing is showing, so a count is what selecting that value would leave. Send
|
|
118
|
+
the panel's own filters with it, and omit `q` for the values as they are.
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
const { data: suggestions } = await storefront.GET("/v1/search/suggest", { params: { query: { q: typed } } });
|
|
122
|
+
const { data: brands } = await storefront.GET("/v1/products/facets/{key}", {
|
|
123
|
+
params: { path: { key: "varumarke" }, query: { q: typed, filter: filterQuery({ kon: ["dam"] }) } },
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
The endpoint reads the facet's **1000 most common values** and matches `q` against those — label contains,
|
|
128
|
+
case-insensitively, or key prefix — returning at most 50. A facet with more distinct values than that is searched
|
|
129
|
+
over its top 1000; no regular expression ever reaches the search index. `key` has to be a `list` or `swatch` facet:
|
|
130
|
+
an unknown key is `FACET_NOT_FOUND` (404), and a range or toggle facet is `FACET_NOT_SEARCHABLE` (400).
|
|
131
|
+
|
|
78
132
|
## Headers
|
|
79
133
|
|
|
80
134
|
Every call the client makes carries these; you never set them by hand.
|
|
@@ -115,7 +169,8 @@ Every operation documents `400`, `401`, `403`, `404`, `429` and `503`; the entit
|
|
|
115
169
|
Codes you will meet: `SITE_KEY_MISSING`, `SITE_KEY_INVALID`, `SITE_INACTIVE`, `SECRET_KEY_FROM_BROWSER`,
|
|
116
170
|
`SITE_REGISTRY_WARMING`, `MARKET_UNKNOWN`, `RATE_LIMITED` (with `retryAfterSeconds`, plus a `Retry-After`
|
|
117
171
|
header), `PRODUCT_NOT_FOUND`, `COLLECTION_NOT_FOUND`, `INVALID_PAGE`, `INVALID_SINCE`, `INVALID_TYPE`,
|
|
118
|
-
`INDEX_UNAVAILABLE` (retry — a preview index is being rebuilt), `NOT_FOUND
|
|
172
|
+
`INDEX_UNAVAILABLE` (retry — a preview index is being rebuilt), `NOT_FOUND`, `INVALID_QUERY`,
|
|
173
|
+
`FACET_NOT_FOUND`, `FACET_NOT_SEARCHABLE`.
|
|
119
174
|
|
|
120
175
|
`SITE_REGISTRY_WARMING` and `INDEX_UNAVAILABLE` are retries, not bugs in your call.
|
|
121
176
|
|
|
@@ -135,11 +190,21 @@ goes blank because of a bad query string:
|
|
|
135
190
|
|
|
136
191
|
`q`, `page`, `pageSize`, `sort` and `filter` are all in the contract, so they are typed and autocompleted.
|
|
137
192
|
`filter` is a `deepObject`: `{ brand: "dior,chanel" }` goes out as `filter[brand]=dior,chanel`, which is the
|
|
138
|
-
form the API reads.
|
|
193
|
+
form the API reads. In a list, swatch or hierarchy filter `,` separates values, `\,` is a comma inside a value and
|
|
194
|
+
`\\` a backslash — value keys are raw values, and an option such as `14,2` is the key `14,2`. Never join or split a
|
|
195
|
+
filter parameter yourself: `encodeFilterValues(values)` builds one and `decodeFilterValues(param)` reads one (for
|
|
196
|
+
the selected state of a URL you parse), for every facet alike. `filterQuery()` uses `encodeFilterValues` for
|
|
197
|
+
multi-select arrays, passes a single string (a range `100-500`, a toggle `true`) as given and drops `undefined` ones.
|
|
198
|
+
A range is `min-max`: either bound may be left out and either may be negative — `-10--2`, `-10-2`, `-10-` (at least
|
|
199
|
+
−10), `--2` (at most −2) — and a leading dash with nothing before it keeps its meaning, `-500` is "at most 500". A
|
|
200
|
+
range whose lower bound is above its upper bound is ignored with a warning.
|
|
139
201
|
|
|
140
202
|
`/v1/sitemap` takes `type` (`product` | `collection`), `since` (ISO-8601, inclusive), `page` and `pageSize`
|
|
141
203
|
(max 1000, default 500).
|
|
142
204
|
|
|
205
|
+
`/v1/search/suggest` takes `q` only, and `/v1/products/facets/{key}` takes `q` plus the same `filter` object as a
|
|
206
|
+
listing — both are described under [Search-as-you-type and search-in-facet](#search-as-you-type-and-search-in-facet).
|
|
207
|
+
|
|
143
208
|
## Caching
|
|
144
209
|
|
|
145
210
|
Read responses carry an `ETag` and `Vary: X-Site-Key, X-Market, Accept-Language` — the answer depends on
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The list grammar of a `filter[<key>]` parameter (list, swatch and hierarchy facets): `,` separates values, `\,` is a
|
|
3
|
+
* comma inside a value and `\\` a backslash. A value key is the raw value — an option such as "14,2" is the key "14,2" —
|
|
4
|
+
* so a frontend never joins or splits a filter parameter by hand: it builds and toggles filter URLs with these two, for
|
|
5
|
+
* every facet alike. Range (`min-max`) and toggle (`true`) parameters are single strings and need neither.
|
|
6
|
+
*/
|
|
7
|
+
export declare function encodeFilterValues(values: readonly string[]): string;
|
|
8
|
+
/**
|
|
9
|
+
* The values a `filter[<key>]` parameter selects, read the way the API reads it: `\,` and `\\` unescaped, a backslash
|
|
10
|
+
* before anything else (or at the end) kept as it is, values trimmed, empty ones and repeats dropped.
|
|
11
|
+
*/
|
|
12
|
+
export declare function decodeFilterValues(param: string): string[];
|
package/dist/filters.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The list grammar of a `filter[<key>]` parameter (list, swatch and hierarchy facets): `,` separates values, `\,` is a
|
|
3
|
+
* comma inside a value and `\\` a backslash. A value key is the raw value — an option such as "14,2" is the key "14,2" —
|
|
4
|
+
* so a frontend never joins or splits a filter parameter by hand: it builds and toggles filter URLs with these two, for
|
|
5
|
+
* every facet alike. Range (`min-max`) and toggle (`true`) parameters are single strings and need neither.
|
|
6
|
+
*/
|
|
7
|
+
export function encodeFilterValues(values) {
|
|
8
|
+
return values.map((v) => v.replace(/\\/g, "\\\\").replace(/,/g, "\\,")).join(",");
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The values a `filter[<key>]` parameter selects, read the way the API reads it: `\,` and `\\` unescaped, a backslash
|
|
12
|
+
* before anything else (or at the end) kept as it is, values trimmed, empty ones and repeats dropped.
|
|
13
|
+
*/
|
|
14
|
+
export function decodeFilterValues(param) {
|
|
15
|
+
const values = [];
|
|
16
|
+
let current = "";
|
|
17
|
+
const push = () => {
|
|
18
|
+
const value = current.trim();
|
|
19
|
+
current = "";
|
|
20
|
+
if (value.length > 0 && !values.includes(value))
|
|
21
|
+
values.push(value);
|
|
22
|
+
};
|
|
23
|
+
for (let i = 0; i < param.length; i++) {
|
|
24
|
+
const c = param[i];
|
|
25
|
+
const next = param[i + 1];
|
|
26
|
+
if (c === "\\" && (next === "," || next === "\\")) {
|
|
27
|
+
current += next;
|
|
28
|
+
i++;
|
|
29
|
+
}
|
|
30
|
+
else if (c === ",") {
|
|
31
|
+
push();
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
current += c;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
push();
|
|
38
|
+
return values;
|
|
39
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -38,10 +38,12 @@ export declare function createStorefrontClient(opts: StorefrontClientOptions): C
|
|
|
38
38
|
/** The `filter` query parameter of a listing call: one facet key to one value, as the generated types spell it. */
|
|
39
39
|
export type FilterSelection = NonNullable<NonNullable<paths["/v1/products"]["get"]["parameters"]["query"]>["filter"]>;
|
|
40
40
|
/**
|
|
41
|
-
* Collapse a facet selection into the typed `filter` object: several values for one facet are
|
|
42
|
-
*
|
|
41
|
+
* Collapse a facet selection into the typed `filter` object: several values for one facet are encoded with
|
|
42
|
+
* `encodeFilterValues` (so a value containing a comma or a backslash survives), a single string is sent as given (a
|
|
43
|
+
* range "100-500", a toggle "true"), and `undefined` facets drop out — an unchecked checkbox needs no special case.
|
|
43
44
|
* `{ brand: ["dior", "chanel"], price: "100-500", size: undefined }` → `{ brand: "dior,chanel", price: "100-500" }`.
|
|
44
45
|
* The client sends it as `filter[brand]=dior,chanel` (deepObject), which is what the API reads.
|
|
45
46
|
*/
|
|
46
47
|
export declare function filterQuery(selection: Record<string, string | string[] | undefined>): FilterSelection;
|
|
48
|
+
export { decodeFilterValues, encodeFilterValues } from "./filters.js";
|
|
47
49
|
export { fileUrl, mediaHash, mediaUrl, MediaUrlError, pickWidth, pictureSources, posterUrl, srcSet, videoSources, type MediaConfig, type MediaDescriptor, type PictureSources, type VideoSource, } from "./media.js";
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import createClient from "openapi-fetch";
|
|
2
|
+
import { encodeFilterValues } from "./filters.js";
|
|
2
3
|
/** Thin typed client: every call carries X-Site-Key / X-Market / Accept-Language. Works in browsers and on the server. */
|
|
3
4
|
export function createStorefrontClient(opts) {
|
|
4
5
|
const client = createClient({ baseUrl: opts.baseUrl.replace(/\/$/, ""), fetch: opts.fetch });
|
|
@@ -18,8 +19,9 @@ export function createStorefrontClient(opts) {
|
|
|
18
19
|
return client;
|
|
19
20
|
}
|
|
20
21
|
/**
|
|
21
|
-
* Collapse a facet selection into the typed `filter` object: several values for one facet are
|
|
22
|
-
*
|
|
22
|
+
* Collapse a facet selection into the typed `filter` object: several values for one facet are encoded with
|
|
23
|
+
* `encodeFilterValues` (so a value containing a comma or a backslash survives), a single string is sent as given (a
|
|
24
|
+
* range "100-500", a toggle "true"), and `undefined` facets drop out — an unchecked checkbox needs no special case.
|
|
23
25
|
* `{ brand: ["dior", "chanel"], price: "100-500", size: undefined }` → `{ brand: "dior,chanel", price: "100-500" }`.
|
|
24
26
|
* The client sends it as `filter[brand]=dior,chanel` (deepObject), which is what the API reads.
|
|
25
27
|
*/
|
|
@@ -28,8 +30,9 @@ export function filterQuery(selection) {
|
|
|
28
30
|
for (const [key, value] of Object.entries(selection)) {
|
|
29
31
|
if (value === undefined)
|
|
30
32
|
continue;
|
|
31
|
-
out[key] = Array.isArray(value) ? value
|
|
33
|
+
out[key] = Array.isArray(value) ? encodeFilterValues(value) : value;
|
|
32
34
|
}
|
|
33
35
|
return out;
|
|
34
36
|
}
|
|
37
|
+
export { decodeFilterValues, encodeFilterValues } from "./filters.js";
|
|
35
38
|
export { fileUrl, mediaHash, mediaUrl, MediaUrlError, pickWidth, pictureSources, posterUrl, srcSet, videoSources, } from "./media.js";
|
package/dist/schema.d.ts
CHANGED
|
@@ -153,6 +153,23 @@ export interface paths {
|
|
|
153
153
|
patch?: never;
|
|
154
154
|
trace?: never;
|
|
155
155
|
};
|
|
156
|
+
"/v1/products/facets/{key}": {
|
|
157
|
+
parameters: {
|
|
158
|
+
query?: never;
|
|
159
|
+
header?: never;
|
|
160
|
+
path?: never;
|
|
161
|
+
cookie?: never;
|
|
162
|
+
};
|
|
163
|
+
/** Search within a facet: values whose label matches q, counted in this request's filter[...] context (spelled as on /products). Free text and collections are not applied. */
|
|
164
|
+
get: operations["SearchFacetValues"];
|
|
165
|
+
put?: never;
|
|
166
|
+
post?: never;
|
|
167
|
+
delete?: never;
|
|
168
|
+
options?: never;
|
|
169
|
+
head?: never;
|
|
170
|
+
patch?: never;
|
|
171
|
+
trace?: never;
|
|
172
|
+
};
|
|
156
173
|
"/v1/products/{slugOrId}": {
|
|
157
174
|
parameters: {
|
|
158
175
|
query?: never;
|
|
@@ -187,6 +204,23 @@ export interface paths {
|
|
|
187
204
|
patch?: never;
|
|
188
205
|
trace?: never;
|
|
189
206
|
};
|
|
207
|
+
"/v1/search/suggest": {
|
|
208
|
+
parameters: {
|
|
209
|
+
query?: never;
|
|
210
|
+
header?: never;
|
|
211
|
+
path?: never;
|
|
212
|
+
cookie?: never;
|
|
213
|
+
};
|
|
214
|
+
/** Search-as-you-type: products by name prefix, categories and facet values whose label starts with q. Market, assortment and language as /products. */
|
|
215
|
+
get: operations["Suggest"];
|
|
216
|
+
put?: never;
|
|
217
|
+
post?: never;
|
|
218
|
+
delete?: never;
|
|
219
|
+
options?: never;
|
|
220
|
+
head?: never;
|
|
221
|
+
patch?: never;
|
|
222
|
+
trace?: never;
|
|
223
|
+
};
|
|
190
224
|
"/v1/site": {
|
|
191
225
|
parameters: {
|
|
192
226
|
query?: never;
|
|
@@ -235,6 +269,27 @@ export interface components {
|
|
|
235
269
|
label: string;
|
|
236
270
|
value: string;
|
|
237
271
|
};
|
|
272
|
+
AttributeDto: {
|
|
273
|
+
facetKey: null | string;
|
|
274
|
+
html: null | string;
|
|
275
|
+
key: string;
|
|
276
|
+
label: string;
|
|
277
|
+
type: string;
|
|
278
|
+
value: null | string;
|
|
279
|
+
valueKeys: string[] | null;
|
|
280
|
+
values: string[] | null;
|
|
281
|
+
};
|
|
282
|
+
BrandDto: {
|
|
283
|
+
facet: null | components["schemas"]["FacetLinkDto"];
|
|
284
|
+
label: string;
|
|
285
|
+
};
|
|
286
|
+
BundleComponentDto: {
|
|
287
|
+
product: components["schemas"]["ProductCardDto"];
|
|
288
|
+
quantity: string;
|
|
289
|
+
};
|
|
290
|
+
BundleDto: {
|
|
291
|
+
components: components["schemas"]["BundleComponentDto"][];
|
|
292
|
+
};
|
|
238
293
|
CartDto: {
|
|
239
294
|
currency: string;
|
|
240
295
|
grandTotalInc: string;
|
|
@@ -251,10 +306,22 @@ export interface components {
|
|
|
251
306
|
id: string;
|
|
252
307
|
image: null | components["schemas"]["MediaDescriptorDto"];
|
|
253
308
|
price: components["schemas"]["PriceDto"];
|
|
254
|
-
|
|
309
|
+
product: components["schemas"]["CartLineProductDto"];
|
|
255
310
|
/** Format: int32 */
|
|
256
311
|
quantity: number | string;
|
|
257
312
|
sku: string;
|
|
313
|
+
variant: components["schemas"]["CartLineVariantDto"];
|
|
314
|
+
};
|
|
315
|
+
CartLineProductDto: {
|
|
316
|
+
id: string;
|
|
317
|
+
name: string;
|
|
318
|
+
slug: string;
|
|
319
|
+
};
|
|
320
|
+
CartLineVariantDto: {
|
|
321
|
+
id: string;
|
|
322
|
+
selectedOptions: {
|
|
323
|
+
[key: string]: string;
|
|
324
|
+
};
|
|
258
325
|
};
|
|
259
326
|
CategoryNodeDto: {
|
|
260
327
|
children: components["schemas"]["CategoryNodeDto"][];
|
|
@@ -298,7 +365,13 @@ export interface components {
|
|
|
298
365
|
slug: string;
|
|
299
366
|
url: string;
|
|
300
367
|
};
|
|
368
|
+
DescriptionDto: {
|
|
369
|
+
html: string;
|
|
370
|
+
text: string;
|
|
371
|
+
};
|
|
301
372
|
FacetDto: {
|
|
373
|
+
collapsed: boolean;
|
|
374
|
+
help: null | string;
|
|
302
375
|
key: string;
|
|
303
376
|
label: string;
|
|
304
377
|
match: string;
|
|
@@ -308,16 +381,25 @@ export interface components {
|
|
|
308
381
|
type: string;
|
|
309
382
|
values: components["schemas"]["FacetValueDto"][];
|
|
310
383
|
};
|
|
384
|
+
FacetLinkDto: {
|
|
385
|
+
key: string;
|
|
386
|
+
valueKey: string;
|
|
387
|
+
};
|
|
311
388
|
FacetValueDto: {
|
|
312
389
|
children: components["schemas"]["FacetValueDto"][] | null;
|
|
313
390
|
/** Format: int64 */
|
|
314
391
|
count: number | string;
|
|
392
|
+
help: null | string;
|
|
315
393
|
key: string;
|
|
316
394
|
label: string;
|
|
317
395
|
pinned: boolean;
|
|
318
396
|
selected: boolean;
|
|
319
397
|
swatch: null | components["schemas"]["SwatchDto"];
|
|
320
398
|
};
|
|
399
|
+
FacetValuesResponse: {
|
|
400
|
+
facet: string;
|
|
401
|
+
values: components["schemas"]["FacetValueDto"][];
|
|
402
|
+
};
|
|
321
403
|
ListingResponse: {
|
|
322
404
|
appliedFilters: components["schemas"]["AppliedFilterDto"][];
|
|
323
405
|
facets: components["schemas"]["FacetDto"][];
|
|
@@ -414,6 +496,7 @@ export interface components {
|
|
|
414
496
|
vatRate: string;
|
|
415
497
|
};
|
|
416
498
|
ProductCardDto: {
|
|
499
|
+
brand: null | components["schemas"]["BrandDto"];
|
|
417
500
|
collections: string[];
|
|
418
501
|
id: string;
|
|
419
502
|
image: null | components["schemas"]["MediaDescriptorDto"];
|
|
@@ -421,6 +504,7 @@ export interface components {
|
|
|
421
504
|
name: string;
|
|
422
505
|
price: null | components["schemas"]["PriceDto"];
|
|
423
506
|
priceVaries: boolean;
|
|
507
|
+
shortDescription: null | string;
|
|
424
508
|
sku: string;
|
|
425
509
|
slug: string;
|
|
426
510
|
/** Format: date-time */
|
|
@@ -431,8 +515,12 @@ export interface components {
|
|
|
431
515
|
alternateUrls: {
|
|
432
516
|
[key: string]: string;
|
|
433
517
|
};
|
|
518
|
+
attributes: components["schemas"]["AttributeDto"][];
|
|
519
|
+
brand: null | components["schemas"]["BrandDto"];
|
|
520
|
+
bundle: null | components["schemas"]["BundleDto"];
|
|
434
521
|
categories: components["schemas"]["CategoryRefDto"][];
|
|
435
522
|
collections: components["schemas"]["CollectionRefDto"][];
|
|
523
|
+
description: null | components["schemas"]["DescriptionDto"];
|
|
436
524
|
files: components["schemas"]["MediaDescriptorDto"][];
|
|
437
525
|
id: string;
|
|
438
526
|
image: null | components["schemas"]["MediaDescriptorDto"];
|
|
@@ -441,7 +529,9 @@ export interface components {
|
|
|
441
529
|
name: string;
|
|
442
530
|
options: components["schemas"]["OptionDto"][];
|
|
443
531
|
redirectTo: null | string;
|
|
532
|
+
related: components["schemas"]["RelatedGroupDto"][];
|
|
444
533
|
seo: components["schemas"]["SeoDto"];
|
|
534
|
+
shortDescription: null | string;
|
|
445
535
|
sku: string;
|
|
446
536
|
slug: string;
|
|
447
537
|
/** Format: date-time */
|
|
@@ -457,12 +547,18 @@ export interface components {
|
|
|
457
547
|
min: string;
|
|
458
548
|
mode: string;
|
|
459
549
|
selected: null | components["schemas"]["RangeSelectionDto"];
|
|
550
|
+
step: null | string;
|
|
460
551
|
unit: null | string;
|
|
461
552
|
};
|
|
462
553
|
RangeSelectionDto: {
|
|
463
554
|
max: null | string;
|
|
464
555
|
min: null | string;
|
|
465
556
|
};
|
|
557
|
+
RelatedGroupDto: {
|
|
558
|
+
key: string;
|
|
559
|
+
label: string;
|
|
560
|
+
products: components["schemas"]["ProductCardDto"][];
|
|
561
|
+
};
|
|
466
562
|
SeoDto: {
|
|
467
563
|
description: null | string;
|
|
468
564
|
title: string;
|
|
@@ -532,6 +628,22 @@ export interface components {
|
|
|
532
628
|
/** @description Link to this code's documentation. */
|
|
533
629
|
type?: string;
|
|
534
630
|
};
|
|
631
|
+
SuggestCategoryDto: {
|
|
632
|
+
id: string;
|
|
633
|
+
name: string;
|
|
634
|
+
path: string[];
|
|
635
|
+
};
|
|
636
|
+
SuggestFacetValueDto: {
|
|
637
|
+
facet: string;
|
|
638
|
+
key: string;
|
|
639
|
+
label: string;
|
|
640
|
+
};
|
|
641
|
+
SuggestResponse: {
|
|
642
|
+
categories: components["schemas"]["SuggestCategoryDto"][];
|
|
643
|
+
facetValues: components["schemas"]["SuggestFacetValueDto"][];
|
|
644
|
+
products: components["schemas"]["ProductCardDto"][];
|
|
645
|
+
query: string;
|
|
646
|
+
};
|
|
535
647
|
SwatchDto: {
|
|
536
648
|
color: null | string;
|
|
537
649
|
image: null | components["schemas"]["MediaDescriptorDto"];
|
|
@@ -1630,6 +1742,96 @@ export interface operations {
|
|
|
1630
1742
|
};
|
|
1631
1743
|
};
|
|
1632
1744
|
};
|
|
1745
|
+
SearchFacetValues: {
|
|
1746
|
+
parameters: {
|
|
1747
|
+
query?: {
|
|
1748
|
+
/** @description Narrows to the values whose label contains q (case-insensitively) or whose key starts with it. Omit for the facet's values as they are. Matched against the 1000 most common values of the facet, in this API — at most 50 are returned. Present but blank is a 400 (INVALID_QUERY). */
|
|
1749
|
+
q?: string;
|
|
1750
|
+
/** @description The filter context the values are counted in, sent as filter[key]=value exactly as on /products: a count is what selecting that value would leave. This facet's own selection does not narrow it (the counts are disjunctive), and a key this site has no facet for is dropped silently. */
|
|
1751
|
+
filter?: {
|
|
1752
|
+
[key: string]: string;
|
|
1753
|
+
};
|
|
1754
|
+
};
|
|
1755
|
+
header: {
|
|
1756
|
+
/** @description Publishable, preview or secret site key. Required on every request; secret keys are server-side only. */
|
|
1757
|
+
"X-Site-Key": string;
|
|
1758
|
+
/** @description Market code (e.g. "se"). Omit for the site's default market. */
|
|
1759
|
+
"X-Market"?: string;
|
|
1760
|
+
/** @description BCP-47 language tag. Omit to use the market's language. */
|
|
1761
|
+
"Accept-Language"?: string;
|
|
1762
|
+
};
|
|
1763
|
+
path: {
|
|
1764
|
+
key: string;
|
|
1765
|
+
};
|
|
1766
|
+
cookie?: never;
|
|
1767
|
+
};
|
|
1768
|
+
requestBody?: never;
|
|
1769
|
+
responses: {
|
|
1770
|
+
/** @description OK */
|
|
1771
|
+
200: {
|
|
1772
|
+
headers: {
|
|
1773
|
+
[name: string]: unknown;
|
|
1774
|
+
};
|
|
1775
|
+
content: {
|
|
1776
|
+
"application/json": components["schemas"]["FacetValuesResponse"];
|
|
1777
|
+
};
|
|
1778
|
+
};
|
|
1779
|
+
/** @description problem+json. MARKET_UNKNOWN (no such market on this site), INVALID_PAGE, or INVALID_QUERY (q present but blank, or longer than 100 characters), or FACET_NOT_SEARCHABLE (the facet exists but has no list of values to search in: a range, a toggle or a tree). */
|
|
1780
|
+
400: {
|
|
1781
|
+
headers: {
|
|
1782
|
+
[name: string]: unknown;
|
|
1783
|
+
};
|
|
1784
|
+
content: {
|
|
1785
|
+
"application/problem+json": components["schemas"]["StorefrontProblem"];
|
|
1786
|
+
};
|
|
1787
|
+
};
|
|
1788
|
+
/** @description problem+json. SITE_KEY_MISSING or SITE_KEY_INVALID. */
|
|
1789
|
+
401: {
|
|
1790
|
+
headers: {
|
|
1791
|
+
[name: string]: unknown;
|
|
1792
|
+
};
|
|
1793
|
+
content: {
|
|
1794
|
+
"application/problem+json": components["schemas"]["StorefrontProblem"];
|
|
1795
|
+
};
|
|
1796
|
+
};
|
|
1797
|
+
/** @description problem+json. SECRET_KEY_FROM_BROWSER: a secret key was sent from a browser. */
|
|
1798
|
+
403: {
|
|
1799
|
+
headers: {
|
|
1800
|
+
[name: string]: unknown;
|
|
1801
|
+
};
|
|
1802
|
+
content: {
|
|
1803
|
+
"application/problem+json": components["schemas"]["StorefrontProblem"];
|
|
1804
|
+
};
|
|
1805
|
+
};
|
|
1806
|
+
/** @description problem+json. FACET_NOT_FOUND, or SITE_INACTIVE when the site itself is not live. */
|
|
1807
|
+
404: {
|
|
1808
|
+
headers: {
|
|
1809
|
+
[name: string]: unknown;
|
|
1810
|
+
};
|
|
1811
|
+
content: {
|
|
1812
|
+
"application/problem+json": components["schemas"]["StorefrontProblem"];
|
|
1813
|
+
};
|
|
1814
|
+
};
|
|
1815
|
+
/** @description problem+json. RATE_LIMITED; retryAfterSeconds and the Retry-After header say how long to wait. */
|
|
1816
|
+
429: {
|
|
1817
|
+
headers: {
|
|
1818
|
+
[name: string]: unknown;
|
|
1819
|
+
};
|
|
1820
|
+
content: {
|
|
1821
|
+
"application/problem+json": components["schemas"]["StorefrontProblem"];
|
|
1822
|
+
};
|
|
1823
|
+
};
|
|
1824
|
+
/** @description problem+json. SITE_REGISTRY_WARMING or INDEX_UNAVAILABLE — retry, the request was not wrong. */
|
|
1825
|
+
503: {
|
|
1826
|
+
headers: {
|
|
1827
|
+
[name: string]: unknown;
|
|
1828
|
+
};
|
|
1829
|
+
content: {
|
|
1830
|
+
"application/problem+json": components["schemas"]["StorefrontProblem"];
|
|
1831
|
+
};
|
|
1832
|
+
};
|
|
1833
|
+
};
|
|
1834
|
+
};
|
|
1633
1835
|
GetProduct: {
|
|
1634
1836
|
parameters: {
|
|
1635
1837
|
query?: never;
|
|
@@ -1805,6 +2007,90 @@ export interface operations {
|
|
|
1805
2007
|
};
|
|
1806
2008
|
};
|
|
1807
2009
|
};
|
|
2010
|
+
Suggest: {
|
|
2011
|
+
parameters: {
|
|
2012
|
+
query: {
|
|
2013
|
+
/** @description What the shopper has typed so far, 1–100 characters. Blank, missing or longer is a 400 (INVALID_QUERY) — unlike a listing's q, which is truncated. */
|
|
2014
|
+
q: string;
|
|
2015
|
+
};
|
|
2016
|
+
header: {
|
|
2017
|
+
/** @description Publishable, preview or secret site key. Required on every request; secret keys are server-side only. */
|
|
2018
|
+
"X-Site-Key": string;
|
|
2019
|
+
/** @description Market code (e.g. "se"). Omit for the site's default market. */
|
|
2020
|
+
"X-Market"?: string;
|
|
2021
|
+
/** @description BCP-47 language tag. Omit to use the market's language. */
|
|
2022
|
+
"Accept-Language"?: string;
|
|
2023
|
+
};
|
|
2024
|
+
path?: never;
|
|
2025
|
+
cookie?: never;
|
|
2026
|
+
};
|
|
2027
|
+
requestBody?: never;
|
|
2028
|
+
responses: {
|
|
2029
|
+
/** @description OK */
|
|
2030
|
+
200: {
|
|
2031
|
+
headers: {
|
|
2032
|
+
[name: string]: unknown;
|
|
2033
|
+
};
|
|
2034
|
+
content: {
|
|
2035
|
+
"application/json": components["schemas"]["SuggestResponse"];
|
|
2036
|
+
};
|
|
2037
|
+
};
|
|
2038
|
+
/** @description problem+json. MARKET_UNKNOWN (no such market on this site), INVALID_PAGE, or INVALID_QUERY (q missing, blank or longer than 100 characters). */
|
|
2039
|
+
400: {
|
|
2040
|
+
headers: {
|
|
2041
|
+
[name: string]: unknown;
|
|
2042
|
+
};
|
|
2043
|
+
content: {
|
|
2044
|
+
"application/problem+json": components["schemas"]["StorefrontProblem"];
|
|
2045
|
+
};
|
|
2046
|
+
};
|
|
2047
|
+
/** @description problem+json. SITE_KEY_MISSING or SITE_KEY_INVALID. */
|
|
2048
|
+
401: {
|
|
2049
|
+
headers: {
|
|
2050
|
+
[name: string]: unknown;
|
|
2051
|
+
};
|
|
2052
|
+
content: {
|
|
2053
|
+
"application/problem+json": components["schemas"]["StorefrontProblem"];
|
|
2054
|
+
};
|
|
2055
|
+
};
|
|
2056
|
+
/** @description problem+json. SECRET_KEY_FROM_BROWSER: a secret key was sent from a browser. */
|
|
2057
|
+
403: {
|
|
2058
|
+
headers: {
|
|
2059
|
+
[name: string]: unknown;
|
|
2060
|
+
};
|
|
2061
|
+
content: {
|
|
2062
|
+
"application/problem+json": components["schemas"]["StorefrontProblem"];
|
|
2063
|
+
};
|
|
2064
|
+
};
|
|
2065
|
+
/** @description problem+json. SITE_INACTIVE, or NOT_FOUND for an unrouted path. */
|
|
2066
|
+
404: {
|
|
2067
|
+
headers: {
|
|
2068
|
+
[name: string]: unknown;
|
|
2069
|
+
};
|
|
2070
|
+
content: {
|
|
2071
|
+
"application/problem+json": components["schemas"]["StorefrontProblem"];
|
|
2072
|
+
};
|
|
2073
|
+
};
|
|
2074
|
+
/** @description problem+json. RATE_LIMITED; retryAfterSeconds and the Retry-After header say how long to wait. */
|
|
2075
|
+
429: {
|
|
2076
|
+
headers: {
|
|
2077
|
+
[name: string]: unknown;
|
|
2078
|
+
};
|
|
2079
|
+
content: {
|
|
2080
|
+
"application/problem+json": components["schemas"]["StorefrontProblem"];
|
|
2081
|
+
};
|
|
2082
|
+
};
|
|
2083
|
+
/** @description problem+json. SITE_REGISTRY_WARMING or INDEX_UNAVAILABLE — retry, the request was not wrong. */
|
|
2084
|
+
503: {
|
|
2085
|
+
headers: {
|
|
2086
|
+
[name: string]: unknown;
|
|
2087
|
+
};
|
|
2088
|
+
content: {
|
|
2089
|
+
"application/problem+json": components["schemas"]["StorefrontProblem"];
|
|
2090
|
+
};
|
|
2091
|
+
};
|
|
2092
|
+
};
|
|
2093
|
+
};
|
|
1808
2094
|
GetSite: {
|
|
1809
2095
|
parameters: {
|
|
1810
2096
|
query?: never;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@asstio-dev/storefront",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Typed client for the Asstio Storefront API (generated from OpenAPI).",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"build": "npm run generate && tsc -p tsconfig.json && node -e \"require('node:fs').copyFileSync('src/schema.d.ts','dist/schema.d.ts')\" && npm run typecheck-examples && npm run smoke",
|
|
21
21
|
"test": "vitest run",
|
|
22
22
|
"check": "npm run generate && npm run typecheck-examples && npm test && git diff --exit-code -- src/schema.d.ts && test -z \"$(git status --porcelain -- src/schema.d.ts)\"",
|
|
23
|
-
"smoke": "node --input-type=module -e \"import(\\\"./dist/index.js\\\").then(m => { for (const f of [\\\"createStorefrontClient\\\", \\\"filterQuery\\\", \\\"pictureSources\\\", \\\"mediaUrl\\\"]) if (typeof m[f] !== \\\"function\\\") throw new Error(\\\"missing export \\\" + f) })\""
|
|
23
|
+
"smoke": "node --input-type=module -e \"import(\\\"./dist/index.js\\\").then(m => { for (const f of [\\\"createStorefrontClient\\\", \\\"filterQuery\\\", \\\"encodeFilterValues\\\", \\\"decodeFilterValues\\\", \\\"pictureSources\\\", \\\"mediaUrl\\\"]) if (typeof m[f] !== \\\"function\\\") throw new Error(\\\"missing export \\\" + f) })\""
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"openapi-fetch": "0.17.0"
|
package/src/schema.d.ts
CHANGED
|
@@ -153,6 +153,23 @@ export interface paths {
|
|
|
153
153
|
patch?: never;
|
|
154
154
|
trace?: never;
|
|
155
155
|
};
|
|
156
|
+
"/v1/products/facets/{key}": {
|
|
157
|
+
parameters: {
|
|
158
|
+
query?: never;
|
|
159
|
+
header?: never;
|
|
160
|
+
path?: never;
|
|
161
|
+
cookie?: never;
|
|
162
|
+
};
|
|
163
|
+
/** Search within a facet: values whose label matches q, counted in this request's filter[...] context (spelled as on /products). Free text and collections are not applied. */
|
|
164
|
+
get: operations["SearchFacetValues"];
|
|
165
|
+
put?: never;
|
|
166
|
+
post?: never;
|
|
167
|
+
delete?: never;
|
|
168
|
+
options?: never;
|
|
169
|
+
head?: never;
|
|
170
|
+
patch?: never;
|
|
171
|
+
trace?: never;
|
|
172
|
+
};
|
|
156
173
|
"/v1/products/{slugOrId}": {
|
|
157
174
|
parameters: {
|
|
158
175
|
query?: never;
|
|
@@ -187,6 +204,23 @@ export interface paths {
|
|
|
187
204
|
patch?: never;
|
|
188
205
|
trace?: never;
|
|
189
206
|
};
|
|
207
|
+
"/v1/search/suggest": {
|
|
208
|
+
parameters: {
|
|
209
|
+
query?: never;
|
|
210
|
+
header?: never;
|
|
211
|
+
path?: never;
|
|
212
|
+
cookie?: never;
|
|
213
|
+
};
|
|
214
|
+
/** Search-as-you-type: products by name prefix, categories and facet values whose label starts with q. Market, assortment and language as /products. */
|
|
215
|
+
get: operations["Suggest"];
|
|
216
|
+
put?: never;
|
|
217
|
+
post?: never;
|
|
218
|
+
delete?: never;
|
|
219
|
+
options?: never;
|
|
220
|
+
head?: never;
|
|
221
|
+
patch?: never;
|
|
222
|
+
trace?: never;
|
|
223
|
+
};
|
|
190
224
|
"/v1/site": {
|
|
191
225
|
parameters: {
|
|
192
226
|
query?: never;
|
|
@@ -235,6 +269,27 @@ export interface components {
|
|
|
235
269
|
label: string;
|
|
236
270
|
value: string;
|
|
237
271
|
};
|
|
272
|
+
AttributeDto: {
|
|
273
|
+
facetKey: null | string;
|
|
274
|
+
html: null | string;
|
|
275
|
+
key: string;
|
|
276
|
+
label: string;
|
|
277
|
+
type: string;
|
|
278
|
+
value: null | string;
|
|
279
|
+
valueKeys: string[] | null;
|
|
280
|
+
values: string[] | null;
|
|
281
|
+
};
|
|
282
|
+
BrandDto: {
|
|
283
|
+
facet: null | components["schemas"]["FacetLinkDto"];
|
|
284
|
+
label: string;
|
|
285
|
+
};
|
|
286
|
+
BundleComponentDto: {
|
|
287
|
+
product: components["schemas"]["ProductCardDto"];
|
|
288
|
+
quantity: string;
|
|
289
|
+
};
|
|
290
|
+
BundleDto: {
|
|
291
|
+
components: components["schemas"]["BundleComponentDto"][];
|
|
292
|
+
};
|
|
238
293
|
CartDto: {
|
|
239
294
|
currency: string;
|
|
240
295
|
grandTotalInc: string;
|
|
@@ -251,10 +306,22 @@ export interface components {
|
|
|
251
306
|
id: string;
|
|
252
307
|
image: null | components["schemas"]["MediaDescriptorDto"];
|
|
253
308
|
price: components["schemas"]["PriceDto"];
|
|
254
|
-
|
|
309
|
+
product: components["schemas"]["CartLineProductDto"];
|
|
255
310
|
/** Format: int32 */
|
|
256
311
|
quantity: number | string;
|
|
257
312
|
sku: string;
|
|
313
|
+
variant: components["schemas"]["CartLineVariantDto"];
|
|
314
|
+
};
|
|
315
|
+
CartLineProductDto: {
|
|
316
|
+
id: string;
|
|
317
|
+
name: string;
|
|
318
|
+
slug: string;
|
|
319
|
+
};
|
|
320
|
+
CartLineVariantDto: {
|
|
321
|
+
id: string;
|
|
322
|
+
selectedOptions: {
|
|
323
|
+
[key: string]: string;
|
|
324
|
+
};
|
|
258
325
|
};
|
|
259
326
|
CategoryNodeDto: {
|
|
260
327
|
children: components["schemas"]["CategoryNodeDto"][];
|
|
@@ -298,7 +365,13 @@ export interface components {
|
|
|
298
365
|
slug: string;
|
|
299
366
|
url: string;
|
|
300
367
|
};
|
|
368
|
+
DescriptionDto: {
|
|
369
|
+
html: string;
|
|
370
|
+
text: string;
|
|
371
|
+
};
|
|
301
372
|
FacetDto: {
|
|
373
|
+
collapsed: boolean;
|
|
374
|
+
help: null | string;
|
|
302
375
|
key: string;
|
|
303
376
|
label: string;
|
|
304
377
|
match: string;
|
|
@@ -308,16 +381,25 @@ export interface components {
|
|
|
308
381
|
type: string;
|
|
309
382
|
values: components["schemas"]["FacetValueDto"][];
|
|
310
383
|
};
|
|
384
|
+
FacetLinkDto: {
|
|
385
|
+
key: string;
|
|
386
|
+
valueKey: string;
|
|
387
|
+
};
|
|
311
388
|
FacetValueDto: {
|
|
312
389
|
children: components["schemas"]["FacetValueDto"][] | null;
|
|
313
390
|
/** Format: int64 */
|
|
314
391
|
count: number | string;
|
|
392
|
+
help: null | string;
|
|
315
393
|
key: string;
|
|
316
394
|
label: string;
|
|
317
395
|
pinned: boolean;
|
|
318
396
|
selected: boolean;
|
|
319
397
|
swatch: null | components["schemas"]["SwatchDto"];
|
|
320
398
|
};
|
|
399
|
+
FacetValuesResponse: {
|
|
400
|
+
facet: string;
|
|
401
|
+
values: components["schemas"]["FacetValueDto"][];
|
|
402
|
+
};
|
|
321
403
|
ListingResponse: {
|
|
322
404
|
appliedFilters: components["schemas"]["AppliedFilterDto"][];
|
|
323
405
|
facets: components["schemas"]["FacetDto"][];
|
|
@@ -414,6 +496,7 @@ export interface components {
|
|
|
414
496
|
vatRate: string;
|
|
415
497
|
};
|
|
416
498
|
ProductCardDto: {
|
|
499
|
+
brand: null | components["schemas"]["BrandDto"];
|
|
417
500
|
collections: string[];
|
|
418
501
|
id: string;
|
|
419
502
|
image: null | components["schemas"]["MediaDescriptorDto"];
|
|
@@ -421,6 +504,7 @@ export interface components {
|
|
|
421
504
|
name: string;
|
|
422
505
|
price: null | components["schemas"]["PriceDto"];
|
|
423
506
|
priceVaries: boolean;
|
|
507
|
+
shortDescription: null | string;
|
|
424
508
|
sku: string;
|
|
425
509
|
slug: string;
|
|
426
510
|
/** Format: date-time */
|
|
@@ -431,8 +515,12 @@ export interface components {
|
|
|
431
515
|
alternateUrls: {
|
|
432
516
|
[key: string]: string;
|
|
433
517
|
};
|
|
518
|
+
attributes: components["schemas"]["AttributeDto"][];
|
|
519
|
+
brand: null | components["schemas"]["BrandDto"];
|
|
520
|
+
bundle: null | components["schemas"]["BundleDto"];
|
|
434
521
|
categories: components["schemas"]["CategoryRefDto"][];
|
|
435
522
|
collections: components["schemas"]["CollectionRefDto"][];
|
|
523
|
+
description: null | components["schemas"]["DescriptionDto"];
|
|
436
524
|
files: components["schemas"]["MediaDescriptorDto"][];
|
|
437
525
|
id: string;
|
|
438
526
|
image: null | components["schemas"]["MediaDescriptorDto"];
|
|
@@ -441,7 +529,9 @@ export interface components {
|
|
|
441
529
|
name: string;
|
|
442
530
|
options: components["schemas"]["OptionDto"][];
|
|
443
531
|
redirectTo: null | string;
|
|
532
|
+
related: components["schemas"]["RelatedGroupDto"][];
|
|
444
533
|
seo: components["schemas"]["SeoDto"];
|
|
534
|
+
shortDescription: null | string;
|
|
445
535
|
sku: string;
|
|
446
536
|
slug: string;
|
|
447
537
|
/** Format: date-time */
|
|
@@ -457,12 +547,18 @@ export interface components {
|
|
|
457
547
|
min: string;
|
|
458
548
|
mode: string;
|
|
459
549
|
selected: null | components["schemas"]["RangeSelectionDto"];
|
|
550
|
+
step: null | string;
|
|
460
551
|
unit: null | string;
|
|
461
552
|
};
|
|
462
553
|
RangeSelectionDto: {
|
|
463
554
|
max: null | string;
|
|
464
555
|
min: null | string;
|
|
465
556
|
};
|
|
557
|
+
RelatedGroupDto: {
|
|
558
|
+
key: string;
|
|
559
|
+
label: string;
|
|
560
|
+
products: components["schemas"]["ProductCardDto"][];
|
|
561
|
+
};
|
|
466
562
|
SeoDto: {
|
|
467
563
|
description: null | string;
|
|
468
564
|
title: string;
|
|
@@ -532,6 +628,22 @@ export interface components {
|
|
|
532
628
|
/** @description Link to this code's documentation. */
|
|
533
629
|
type?: string;
|
|
534
630
|
};
|
|
631
|
+
SuggestCategoryDto: {
|
|
632
|
+
id: string;
|
|
633
|
+
name: string;
|
|
634
|
+
path: string[];
|
|
635
|
+
};
|
|
636
|
+
SuggestFacetValueDto: {
|
|
637
|
+
facet: string;
|
|
638
|
+
key: string;
|
|
639
|
+
label: string;
|
|
640
|
+
};
|
|
641
|
+
SuggestResponse: {
|
|
642
|
+
categories: components["schemas"]["SuggestCategoryDto"][];
|
|
643
|
+
facetValues: components["schemas"]["SuggestFacetValueDto"][];
|
|
644
|
+
products: components["schemas"]["ProductCardDto"][];
|
|
645
|
+
query: string;
|
|
646
|
+
};
|
|
535
647
|
SwatchDto: {
|
|
536
648
|
color: null | string;
|
|
537
649
|
image: null | components["schemas"]["MediaDescriptorDto"];
|
|
@@ -1630,6 +1742,96 @@ export interface operations {
|
|
|
1630
1742
|
};
|
|
1631
1743
|
};
|
|
1632
1744
|
};
|
|
1745
|
+
SearchFacetValues: {
|
|
1746
|
+
parameters: {
|
|
1747
|
+
query?: {
|
|
1748
|
+
/** @description Narrows to the values whose label contains q (case-insensitively) or whose key starts with it. Omit for the facet's values as they are. Matched against the 1000 most common values of the facet, in this API — at most 50 are returned. Present but blank is a 400 (INVALID_QUERY). */
|
|
1749
|
+
q?: string;
|
|
1750
|
+
/** @description The filter context the values are counted in, sent as filter[key]=value exactly as on /products: a count is what selecting that value would leave. This facet's own selection does not narrow it (the counts are disjunctive), and a key this site has no facet for is dropped silently. */
|
|
1751
|
+
filter?: {
|
|
1752
|
+
[key: string]: string;
|
|
1753
|
+
};
|
|
1754
|
+
};
|
|
1755
|
+
header: {
|
|
1756
|
+
/** @description Publishable, preview or secret site key. Required on every request; secret keys are server-side only. */
|
|
1757
|
+
"X-Site-Key": string;
|
|
1758
|
+
/** @description Market code (e.g. "se"). Omit for the site's default market. */
|
|
1759
|
+
"X-Market"?: string;
|
|
1760
|
+
/** @description BCP-47 language tag. Omit to use the market's language. */
|
|
1761
|
+
"Accept-Language"?: string;
|
|
1762
|
+
};
|
|
1763
|
+
path: {
|
|
1764
|
+
key: string;
|
|
1765
|
+
};
|
|
1766
|
+
cookie?: never;
|
|
1767
|
+
};
|
|
1768
|
+
requestBody?: never;
|
|
1769
|
+
responses: {
|
|
1770
|
+
/** @description OK */
|
|
1771
|
+
200: {
|
|
1772
|
+
headers: {
|
|
1773
|
+
[name: string]: unknown;
|
|
1774
|
+
};
|
|
1775
|
+
content: {
|
|
1776
|
+
"application/json": components["schemas"]["FacetValuesResponse"];
|
|
1777
|
+
};
|
|
1778
|
+
};
|
|
1779
|
+
/** @description problem+json. MARKET_UNKNOWN (no such market on this site), INVALID_PAGE, or INVALID_QUERY (q present but blank, or longer than 100 characters), or FACET_NOT_SEARCHABLE (the facet exists but has no list of values to search in: a range, a toggle or a tree). */
|
|
1780
|
+
400: {
|
|
1781
|
+
headers: {
|
|
1782
|
+
[name: string]: unknown;
|
|
1783
|
+
};
|
|
1784
|
+
content: {
|
|
1785
|
+
"application/problem+json": components["schemas"]["StorefrontProblem"];
|
|
1786
|
+
};
|
|
1787
|
+
};
|
|
1788
|
+
/** @description problem+json. SITE_KEY_MISSING or SITE_KEY_INVALID. */
|
|
1789
|
+
401: {
|
|
1790
|
+
headers: {
|
|
1791
|
+
[name: string]: unknown;
|
|
1792
|
+
};
|
|
1793
|
+
content: {
|
|
1794
|
+
"application/problem+json": components["schemas"]["StorefrontProblem"];
|
|
1795
|
+
};
|
|
1796
|
+
};
|
|
1797
|
+
/** @description problem+json. SECRET_KEY_FROM_BROWSER: a secret key was sent from a browser. */
|
|
1798
|
+
403: {
|
|
1799
|
+
headers: {
|
|
1800
|
+
[name: string]: unknown;
|
|
1801
|
+
};
|
|
1802
|
+
content: {
|
|
1803
|
+
"application/problem+json": components["schemas"]["StorefrontProblem"];
|
|
1804
|
+
};
|
|
1805
|
+
};
|
|
1806
|
+
/** @description problem+json. FACET_NOT_FOUND, or SITE_INACTIVE when the site itself is not live. */
|
|
1807
|
+
404: {
|
|
1808
|
+
headers: {
|
|
1809
|
+
[name: string]: unknown;
|
|
1810
|
+
};
|
|
1811
|
+
content: {
|
|
1812
|
+
"application/problem+json": components["schemas"]["StorefrontProblem"];
|
|
1813
|
+
};
|
|
1814
|
+
};
|
|
1815
|
+
/** @description problem+json. RATE_LIMITED; retryAfterSeconds and the Retry-After header say how long to wait. */
|
|
1816
|
+
429: {
|
|
1817
|
+
headers: {
|
|
1818
|
+
[name: string]: unknown;
|
|
1819
|
+
};
|
|
1820
|
+
content: {
|
|
1821
|
+
"application/problem+json": components["schemas"]["StorefrontProblem"];
|
|
1822
|
+
};
|
|
1823
|
+
};
|
|
1824
|
+
/** @description problem+json. SITE_REGISTRY_WARMING or INDEX_UNAVAILABLE — retry, the request was not wrong. */
|
|
1825
|
+
503: {
|
|
1826
|
+
headers: {
|
|
1827
|
+
[name: string]: unknown;
|
|
1828
|
+
};
|
|
1829
|
+
content: {
|
|
1830
|
+
"application/problem+json": components["schemas"]["StorefrontProblem"];
|
|
1831
|
+
};
|
|
1832
|
+
};
|
|
1833
|
+
};
|
|
1834
|
+
};
|
|
1633
1835
|
GetProduct: {
|
|
1634
1836
|
parameters: {
|
|
1635
1837
|
query?: never;
|
|
@@ -1805,6 +2007,90 @@ export interface operations {
|
|
|
1805
2007
|
};
|
|
1806
2008
|
};
|
|
1807
2009
|
};
|
|
2010
|
+
Suggest: {
|
|
2011
|
+
parameters: {
|
|
2012
|
+
query: {
|
|
2013
|
+
/** @description What the shopper has typed so far, 1–100 characters. Blank, missing or longer is a 400 (INVALID_QUERY) — unlike a listing's q, which is truncated. */
|
|
2014
|
+
q: string;
|
|
2015
|
+
};
|
|
2016
|
+
header: {
|
|
2017
|
+
/** @description Publishable, preview or secret site key. Required on every request; secret keys are server-side only. */
|
|
2018
|
+
"X-Site-Key": string;
|
|
2019
|
+
/** @description Market code (e.g. "se"). Omit for the site's default market. */
|
|
2020
|
+
"X-Market"?: string;
|
|
2021
|
+
/** @description BCP-47 language tag. Omit to use the market's language. */
|
|
2022
|
+
"Accept-Language"?: string;
|
|
2023
|
+
};
|
|
2024
|
+
path?: never;
|
|
2025
|
+
cookie?: never;
|
|
2026
|
+
};
|
|
2027
|
+
requestBody?: never;
|
|
2028
|
+
responses: {
|
|
2029
|
+
/** @description OK */
|
|
2030
|
+
200: {
|
|
2031
|
+
headers: {
|
|
2032
|
+
[name: string]: unknown;
|
|
2033
|
+
};
|
|
2034
|
+
content: {
|
|
2035
|
+
"application/json": components["schemas"]["SuggestResponse"];
|
|
2036
|
+
};
|
|
2037
|
+
};
|
|
2038
|
+
/** @description problem+json. MARKET_UNKNOWN (no such market on this site), INVALID_PAGE, or INVALID_QUERY (q missing, blank or longer than 100 characters). */
|
|
2039
|
+
400: {
|
|
2040
|
+
headers: {
|
|
2041
|
+
[name: string]: unknown;
|
|
2042
|
+
};
|
|
2043
|
+
content: {
|
|
2044
|
+
"application/problem+json": components["schemas"]["StorefrontProblem"];
|
|
2045
|
+
};
|
|
2046
|
+
};
|
|
2047
|
+
/** @description problem+json. SITE_KEY_MISSING or SITE_KEY_INVALID. */
|
|
2048
|
+
401: {
|
|
2049
|
+
headers: {
|
|
2050
|
+
[name: string]: unknown;
|
|
2051
|
+
};
|
|
2052
|
+
content: {
|
|
2053
|
+
"application/problem+json": components["schemas"]["StorefrontProblem"];
|
|
2054
|
+
};
|
|
2055
|
+
};
|
|
2056
|
+
/** @description problem+json. SECRET_KEY_FROM_BROWSER: a secret key was sent from a browser. */
|
|
2057
|
+
403: {
|
|
2058
|
+
headers: {
|
|
2059
|
+
[name: string]: unknown;
|
|
2060
|
+
};
|
|
2061
|
+
content: {
|
|
2062
|
+
"application/problem+json": components["schemas"]["StorefrontProblem"];
|
|
2063
|
+
};
|
|
2064
|
+
};
|
|
2065
|
+
/** @description problem+json. SITE_INACTIVE, or NOT_FOUND for an unrouted path. */
|
|
2066
|
+
404: {
|
|
2067
|
+
headers: {
|
|
2068
|
+
[name: string]: unknown;
|
|
2069
|
+
};
|
|
2070
|
+
content: {
|
|
2071
|
+
"application/problem+json": components["schemas"]["StorefrontProblem"];
|
|
2072
|
+
};
|
|
2073
|
+
};
|
|
2074
|
+
/** @description problem+json. RATE_LIMITED; retryAfterSeconds and the Retry-After header say how long to wait. */
|
|
2075
|
+
429: {
|
|
2076
|
+
headers: {
|
|
2077
|
+
[name: string]: unknown;
|
|
2078
|
+
};
|
|
2079
|
+
content: {
|
|
2080
|
+
"application/problem+json": components["schemas"]["StorefrontProblem"];
|
|
2081
|
+
};
|
|
2082
|
+
};
|
|
2083
|
+
/** @description problem+json. SITE_REGISTRY_WARMING or INDEX_UNAVAILABLE — retry, the request was not wrong. */
|
|
2084
|
+
503: {
|
|
2085
|
+
headers: {
|
|
2086
|
+
[name: string]: unknown;
|
|
2087
|
+
};
|
|
2088
|
+
content: {
|
|
2089
|
+
"application/problem+json": components["schemas"]["StorefrontProblem"];
|
|
2090
|
+
};
|
|
2091
|
+
};
|
|
2092
|
+
};
|
|
2093
|
+
};
|
|
1808
2094
|
GetSite: {
|
|
1809
2095
|
parameters: {
|
|
1810
2096
|
query?: never;
|