@faststore/api 1.12.48 → 1.12.51
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/dist/api.cjs.development.js +203 -16
- 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 +203 -16
- package/dist/api.esm.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/platforms/vtex/clients/fetch.d.ts +5 -1
- package/dist/platforms/vtex/clients/index.d.ts +3 -3
- package/dist/platforms/vtex/clients/search/index.d.ts +2 -0
- package/dist/platforms/vtex/index.d.ts +7 -2
- package/dist/platforms/vtex/resolvers/query.d.ts +1 -1
- package/dist/platforms/vtex/utils/cookies.d.ts +52 -0
- package/dist/platforms/vtex/utils/facets.d.ts +1 -0
- package/package.json +2 -2
- package/src/platforms/vtex/clients/commerce/index.ts +47 -4
- package/src/platforms/vtex/clients/fetch.ts +13 -1
- package/src/platforms/vtex/clients/search/index.ts +15 -6
- package/src/platforms/vtex/index.ts +6 -0
- package/src/platforms/vtex/loaders/sku.ts +5 -1
- package/src/platforms/vtex/resolvers/query.ts +3 -0
- package/src/platforms/vtex/resolvers/validateCart.ts +1 -1
- package/src/platforms/vtex/utils/cookies.ts +157 -0
- package/src/platforms/vtex/utils/facets.ts +3 -0
package/dist/api.esm.js
CHANGED
|
@@ -18,7 +18,7 @@ import { trace, context, SpanKind } from '@opentelemetry/api';
|
|
|
18
18
|
import { SeverityNumber } from '@opentelemetry/api-logs';
|
|
19
19
|
|
|
20
20
|
var name = "@faststore/api";
|
|
21
|
-
var version = "1.12.
|
|
21
|
+
var version = "1.12.50";
|
|
22
22
|
var license = "MIT";
|
|
23
23
|
var main = "dist/index.js";
|
|
24
24
|
var typings = "dist/index.d.ts";
|
|
@@ -54,7 +54,7 @@ var dependencies = {
|
|
|
54
54
|
};
|
|
55
55
|
var devDependencies = {
|
|
56
56
|
"@envelop/core": "^2.6.0",
|
|
57
|
-
"@faststore/shared": "^1.12.
|
|
57
|
+
"@faststore/shared": "^1.12.48",
|
|
58
58
|
"@graphql-codegen/cli": "2.2.0",
|
|
59
59
|
"@graphql-codegen/typescript": "2.2.2",
|
|
60
60
|
concurrently: "^6.2.1",
|
|
@@ -88,7 +88,7 @@ var packageJson = {
|
|
|
88
88
|
};
|
|
89
89
|
|
|
90
90
|
const USER_AGENT = `${packageJson.name}@${packageJson.version}`;
|
|
91
|
-
const fetchAPI = async (info, init) => {
|
|
91
|
+
const fetchAPI = async (info, init, options) => {
|
|
92
92
|
const response = await fetch(info, { ...init,
|
|
93
93
|
headers: { ...(init == null ? void 0 : init.headers),
|
|
94
94
|
'User-Agent': USER_AGENT
|
|
@@ -96,6 +96,10 @@ const fetchAPI = async (info, init) => {
|
|
|
96
96
|
});
|
|
97
97
|
|
|
98
98
|
if (response.ok) {
|
|
99
|
+
if (options != null && options.storeCookies) {
|
|
100
|
+
options.storeCookies(response.headers);
|
|
101
|
+
}
|
|
102
|
+
|
|
99
103
|
return response.status !== 204 ? response.json() : undefined;
|
|
100
104
|
}
|
|
101
105
|
|
|
@@ -104,17 +108,169 @@ const fetchAPI = async (info, init) => {
|
|
|
104
108
|
throw new Error(text);
|
|
105
109
|
};
|
|
106
110
|
|
|
111
|
+
const MATCH_FIRST_SET_COOKIE_KEY_VALUE = /^([^=]+)=([^;]*)/;
|
|
112
|
+
/**
|
|
113
|
+
* Splits a combined `set-cookie` header value (cookies joined by `, `) into
|
|
114
|
+
* individual cookies. Commas inside `expires=...` dates are kept.
|
|
115
|
+
*/
|
|
116
|
+
|
|
117
|
+
const splitSetCookieHeader = value => value.split(/,(?=\s*[^;,=\s]+=)/).map(setCookie => setCookie.trim());
|
|
118
|
+
/**
|
|
119
|
+
* Returns every `set-cookie` value of a fetch response.
|
|
120
|
+
*
|
|
121
|
+
* `Headers.getSetCookie()` only exists on Node >= 18.14 (undici). FastStore v1
|
|
122
|
+
* stores may still run on Node 16, where isomorphic-unfetch falls back to
|
|
123
|
+
* node-fetch v2, which exposes repeated headers through `raw()` instead.
|
|
124
|
+
*/
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
const getSetCookies = headers => {
|
|
128
|
+
const maybeHeaders = headers;
|
|
129
|
+
|
|
130
|
+
if (typeof maybeHeaders.getSetCookie === 'function') {
|
|
131
|
+
return maybeHeaders.getSetCookie();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (typeof maybeHeaders.raw === 'function') {
|
|
135
|
+
var _maybeHeaders$raw$set;
|
|
136
|
+
|
|
137
|
+
return (_maybeHeaders$raw$set = maybeHeaders.raw()['set-cookie']) != null ? _maybeHeaders$raw$set : [];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const setCookie = headers.get('set-cookie');
|
|
141
|
+
return setCookie ? splitSetCookieHeader(setCookie) : [];
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* This function updates the ctx.storage.cookies, that is used in each request.
|
|
145
|
+
*
|
|
146
|
+
* ctx.storage.cookies is a Map<string[1], Record<string, string>[2]> where,
|
|
147
|
+
* [1] cookie key
|
|
148
|
+
* [2] {
|
|
149
|
+
* value: cookie value,
|
|
150
|
+
* setCookie: setCookie used in browser response
|
|
151
|
+
* }
|
|
152
|
+
*/
|
|
153
|
+
|
|
154
|
+
const updatesContextStorageCookies = (ctx, setCookieValue) => {
|
|
155
|
+
const matchCookie = setCookieValue.match(MATCH_FIRST_SET_COOKIE_KEY_VALUE);
|
|
156
|
+
|
|
157
|
+
if (matchCookie) {
|
|
158
|
+
const cookieKey = matchCookie[1];
|
|
159
|
+
const cookieValue = matchCookie[2];
|
|
160
|
+
ctx.storage.cookies.set(cookieKey, {
|
|
161
|
+
value: cookieValue,
|
|
162
|
+
setCookie: setCookieValue
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
const setCookie = (ctx, headers) => {
|
|
167
|
+
getSetCookies(headers).forEach(setCookieValue => updatesContextStorageCookies(ctx, setCookieValue));
|
|
168
|
+
};
|
|
169
|
+
const getStoreCookie = ctx => headers => setCookie(ctx, headers);
|
|
170
|
+
/**
|
|
171
|
+
* This function returns a modified copy of the original cookie header (ctx.headers.cookie from the first request)
|
|
172
|
+
* with the cookie values that comes in each request (ctx.storage.cookies).
|
|
173
|
+
* If there is no cookies in storage, the ctx.headers?.cookie is used
|
|
174
|
+
*
|
|
175
|
+
* ctx.storage.cookies is a Map<string[1], Record<string, string>[2]> where,
|
|
176
|
+
* [1] cookie key
|
|
177
|
+
* [2] {
|
|
178
|
+
* value: cookie value,
|
|
179
|
+
* setCookie: setCookie used in browser response
|
|
180
|
+
* }
|
|
181
|
+
*/
|
|
182
|
+
|
|
183
|
+
const getUpdatedCookie = ctx => {
|
|
184
|
+
var _ctx$headers;
|
|
185
|
+
|
|
186
|
+
if (!((_ctx$headers = ctx.headers) != null && _ctx$headers.cookie)) {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const contextStorageCookies = Array.from(ctx.storage.cookies.entries());
|
|
191
|
+
|
|
192
|
+
if (contextStorageCookies.length === 0) {
|
|
193
|
+
return ctx.headers.cookie;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return contextStorageCookies.reduce((existingCookies, [storageCookieKey, {
|
|
197
|
+
value: storageCookieValue
|
|
198
|
+
}]) => updatesCookieValueByKey(existingCookies, storageCookieKey, storageCookieValue), ctx.headers.cookie);
|
|
199
|
+
};
|
|
200
|
+
const getWithCookie = ctx => function withCookie(headers) {
|
|
201
|
+
const updatedCookie = getUpdatedCookie(ctx);
|
|
202
|
+
|
|
203
|
+
if (!updatedCookie) {
|
|
204
|
+
return headers;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return { ...headers,
|
|
208
|
+
cookie: updatedCookie
|
|
209
|
+
};
|
|
210
|
+
};
|
|
211
|
+
/**
|
|
212
|
+
* This function updates the cookie value based on its key
|
|
213
|
+
*
|
|
214
|
+
* const existingCookies = 'key=value1; key2=; key3=value3';
|
|
215
|
+
* const storageCookieKey = 'key2';
|
|
216
|
+
* const storageCookieValue = 'value2'
|
|
217
|
+
*
|
|
218
|
+
* updatesCookieValueByKey(existingCookies, storageCookieKey, storageCookieValue) returns 'key=value1; key2=value2; key3=value3';
|
|
219
|
+
*/
|
|
220
|
+
|
|
221
|
+
const updatesCookieValueByKey = (existingCookies, storageCookieKey, storageCookieValue) => {
|
|
222
|
+
const MATCH_COOKIE_KEY_VALUE = new RegExp(`(${storageCookieKey})=([^;]*)`);
|
|
223
|
+
const cookieParts = existingCookies.match(MATCH_COOKIE_KEY_VALUE); // replaces original cookie with the one coming from storage
|
|
224
|
+
|
|
225
|
+
if (cookieParts) {
|
|
226
|
+
return existingCookies.replace(cookieParts[0], `${cookieParts[1]}=${storageCookieValue}`);
|
|
227
|
+
} // add new storage cookie to the original list of cookies
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
return `${existingCookies};${storageCookieKey}=${storageCookieValue}`;
|
|
231
|
+
};
|
|
232
|
+
|
|
107
233
|
const BASE_INIT = {
|
|
108
234
|
method: 'POST',
|
|
109
235
|
headers: {
|
|
110
236
|
'content-type': 'application/json'
|
|
111
237
|
}
|
|
112
238
|
};
|
|
239
|
+
|
|
240
|
+
const getHeader = (headers, name) => {
|
|
241
|
+
const value = headers == null ? void 0 : headers[name];
|
|
242
|
+
return Array.isArray(value) ? value[0] : value;
|
|
243
|
+
};
|
|
244
|
+
/**
|
|
245
|
+
* Host the Checkout API uses as the domain of the cookies it sets. Checkout
|
|
246
|
+
* only honors it for hosts registered in the account, so a forged value is
|
|
247
|
+
* ignored there.
|
|
248
|
+
*/
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
const getForwardedHost = headers => {
|
|
252
|
+
var _getHeader;
|
|
253
|
+
|
|
254
|
+
// Proxies may append values: "client, proxy". Only the first one is the store host.
|
|
255
|
+
const host = ((_getHeader = getHeader(headers, 'x-forwarded-host')) == null ? void 0 : _getHeader.split(',')[0].trim()) || getHeader(headers, 'host') || '';
|
|
256
|
+
return host.trim().replace(/^www\./, '');
|
|
257
|
+
};
|
|
258
|
+
|
|
113
259
|
const VtexCommerce = ({
|
|
114
260
|
account,
|
|
115
261
|
environment
|
|
116
262
|
}, ctx) => {
|
|
117
263
|
const base = `https://${account}.${environment}.com.br`;
|
|
264
|
+
const storeCookies = getStoreCookie(ctx);
|
|
265
|
+
const withCookie = getWithCookie(ctx);
|
|
266
|
+
const forwardedHost = getForwardedHost(ctx.headers); // Checkout calls forward the shopper cookies and keep the cookies Checkout
|
|
267
|
+
// sets (e.g. CheckoutOrderFormOwnership) so they can reach the browser.
|
|
268
|
+
|
|
269
|
+
const checkoutHeaders = () => withCookie({
|
|
270
|
+
'content-type': 'application/json',
|
|
271
|
+
'X-FORWARDED-HOST': forwardedHost
|
|
272
|
+
});
|
|
273
|
+
|
|
118
274
|
return {
|
|
119
275
|
catalog: {
|
|
120
276
|
salesChannel: sc => fetchAPI(`${base}/api/catalog_system/pub/saleschannel/${sc}`),
|
|
@@ -165,7 +321,10 @@ const VtexCommerce = ({
|
|
|
165
321
|
}
|
|
166
322
|
|
|
167
323
|
return fetchAPI(`${base}/api/checkout/pub/orderForm/${id}/attachments/shippingData`, { ...BASE_INIT,
|
|
324
|
+
headers: checkoutHeaders(),
|
|
168
325
|
body: JSON.stringify(body)
|
|
326
|
+
}, {
|
|
327
|
+
storeCookies
|
|
169
328
|
});
|
|
170
329
|
},
|
|
171
330
|
orderForm: ({
|
|
@@ -180,7 +339,11 @@ const VtexCommerce = ({
|
|
|
180
339
|
refreshOutdatedData: refreshOutdatedData.toString(),
|
|
181
340
|
sc: salesChannel
|
|
182
341
|
});
|
|
183
|
-
return fetchAPI(`${base}/api/checkout/pub/orderForm/${id}?${params.toString()}`, BASE_INIT
|
|
342
|
+
return fetchAPI(`${base}/api/checkout/pub/orderForm/${id}?${params.toString()}`, { ...BASE_INIT,
|
|
343
|
+
headers: checkoutHeaders()
|
|
344
|
+
}, {
|
|
345
|
+
storeCookies
|
|
346
|
+
});
|
|
184
347
|
},
|
|
185
348
|
updateOrderFormItems: ({
|
|
186
349
|
id,
|
|
@@ -194,11 +357,14 @@ const VtexCommerce = ({
|
|
|
194
357
|
sc: salesChannel
|
|
195
358
|
});
|
|
196
359
|
return fetchAPI(`${base}/api/checkout/pub/orderForm/${id}/items?${params}`, { ...BASE_INIT,
|
|
360
|
+
headers: checkoutHeaders(),
|
|
197
361
|
body: JSON.stringify({
|
|
198
362
|
orderItems,
|
|
199
363
|
noSplitItem: !shouldSplitItem
|
|
200
364
|
}),
|
|
201
365
|
method: 'PATCH'
|
|
366
|
+
}, {
|
|
367
|
+
storeCookies
|
|
202
368
|
});
|
|
203
369
|
},
|
|
204
370
|
setCustomData: ({
|
|
@@ -208,10 +374,13 @@ const VtexCommerce = ({
|
|
|
208
374
|
value
|
|
209
375
|
}) => {
|
|
210
376
|
return fetchAPI(`${base}/api/checkout/pub/orderForm/${id}/customData/${appId}/${key}`, { ...BASE_INIT,
|
|
377
|
+
headers: checkoutHeaders(),
|
|
211
378
|
body: JSON.stringify({
|
|
212
379
|
value
|
|
213
380
|
}),
|
|
214
381
|
method: 'PUT'
|
|
382
|
+
}, {
|
|
383
|
+
storeCookies
|
|
215
384
|
});
|
|
216
385
|
},
|
|
217
386
|
region: async ({
|
|
@@ -276,22 +445,23 @@ const IntelligentSearch = ({
|
|
|
276
445
|
};
|
|
277
446
|
};
|
|
278
447
|
|
|
279
|
-
const getRegionFacet =
|
|
448
|
+
const getRegionFacet = regionIdFromQuery => {
|
|
280
449
|
const {
|
|
281
450
|
regionId
|
|
282
451
|
} = ctx.storage.channel;
|
|
452
|
+
const facet = regionIdFromQuery != null ? regionIdFromQuery : regionId;
|
|
283
453
|
|
|
284
|
-
if (!
|
|
454
|
+
if (!facet) {
|
|
285
455
|
return null;
|
|
286
456
|
}
|
|
287
457
|
|
|
288
458
|
return {
|
|
289
459
|
key: REGION_KEY,
|
|
290
|
-
value:
|
|
460
|
+
value: facet
|
|
291
461
|
};
|
|
292
462
|
};
|
|
293
463
|
|
|
294
|
-
const addDefaultFacets = facets => {
|
|
464
|
+
const addDefaultFacets = (facets, regionIdFromQuery) => {
|
|
295
465
|
var _facets$find, _facets$find2;
|
|
296
466
|
|
|
297
467
|
const withDefaltFacets = facets.filter(({
|
|
@@ -302,7 +472,7 @@ const IntelligentSearch = ({
|
|
|
302
472
|
}) => key === POLICY_KEY)) != null ? _facets$find : getPolicyFacet();
|
|
303
473
|
const regionFacet = (_facets$find2 = facets.find(({
|
|
304
474
|
key
|
|
305
|
-
}) => key === REGION_KEY)) != null ? _facets$find2 : getRegionFacet();
|
|
475
|
+
}) => key === REGION_KEY)) != null ? _facets$find2 : getRegionFacet(regionIdFromQuery);
|
|
306
476
|
|
|
307
477
|
if (policyFacet !== null) {
|
|
308
478
|
withDefaltFacets.push(policyFacet);
|
|
@@ -322,7 +492,9 @@ const IntelligentSearch = ({
|
|
|
322
492
|
sort = '',
|
|
323
493
|
selectedFacets = [],
|
|
324
494
|
type,
|
|
325
|
-
fuzzy = 'auto'
|
|
495
|
+
fuzzy = 'auto',
|
|
496
|
+
showInvisibleItems,
|
|
497
|
+
regionId
|
|
326
498
|
}) => {
|
|
327
499
|
const params = new URLSearchParams({
|
|
328
500
|
page: (page + 1).toString(),
|
|
@@ -333,11 +505,15 @@ const IntelligentSearch = ({
|
|
|
333
505
|
locale: ctx.storage.locale
|
|
334
506
|
});
|
|
335
507
|
|
|
508
|
+
if (showInvisibleItems) {
|
|
509
|
+
params.append('show-invisible-items', 'true');
|
|
510
|
+
}
|
|
511
|
+
|
|
336
512
|
if (hideUnavailableItems !== undefined) {
|
|
337
513
|
params.append('hideUnavailableItems', hideUnavailableItems.toString());
|
|
338
514
|
}
|
|
339
515
|
|
|
340
|
-
const pathname = addDefaultFacets(selectedFacets).map(({
|
|
516
|
+
const pathname = addDefaultFacets(selectedFacets, regionId).map(({
|
|
341
517
|
key,
|
|
342
518
|
value
|
|
343
519
|
}) => `${key}/${value}`).join('/');
|
|
@@ -530,13 +706,16 @@ const isBadRequestError = error => {
|
|
|
530
706
|
};
|
|
531
707
|
|
|
532
708
|
const getSkuLoader = (_, clients) => {
|
|
533
|
-
const loader = async
|
|
709
|
+
const loader = async keys => {
|
|
710
|
+
const skuIds = keys.map(key => key.split('-')[0]);
|
|
711
|
+
const showInvisibleItems = keys.some(key => key.split('-')[1] === 'invisibleItems');
|
|
534
712
|
const {
|
|
535
713
|
products
|
|
536
714
|
} = await clients.search.products({
|
|
537
715
|
query: `sku:${skuIds.join(';')}`,
|
|
538
716
|
page: 0,
|
|
539
|
-
count: skuIds.length
|
|
717
|
+
count: skuIds.length,
|
|
718
|
+
showInvisibleItems
|
|
540
719
|
});
|
|
541
720
|
const skuBySkuId = products.reduce((acc, product) => {
|
|
542
721
|
for (const sku of product.items) {
|
|
@@ -916,6 +1095,11 @@ const findChannel = facets => {
|
|
|
916
1095
|
|
|
917
1096
|
return (_facets$find$value4 = facets == null ? void 0 : (_facets$find4 = facets.find(facet => facet.key === 'channel')) == null ? void 0 : _facets$find4.value) != null ? _facets$find$value4 : null;
|
|
918
1097
|
};
|
|
1098
|
+
const findRegionId = facets => {
|
|
1099
|
+
var _facets$find$value5, _facets$find5;
|
|
1100
|
+
|
|
1101
|
+
return (_facets$find$value5 = facets == null ? void 0 : (_facets$find5 = facets.find(facet => facet.key === 'regionId')) == null ? void 0 : _facets$find5.value) != null ? _facets$find$value5 : undefined;
|
|
1102
|
+
};
|
|
919
1103
|
|
|
920
1104
|
/**
|
|
921
1105
|
* More info at: https://en.wikipedia.org/wiki/Order_statistic
|
|
@@ -1154,7 +1338,7 @@ const orderFormToCart = async (form, skuLoader) => {
|
|
|
1154
1338
|
order: {
|
|
1155
1339
|
orderNumber: form.orderFormId,
|
|
1156
1340
|
acceptedOffer: form.items.map(async item => ({ ...item,
|
|
1157
|
-
product: await skuLoader.load(item.id)
|
|
1341
|
+
product: await skuLoader.load(`${item.id}-invisibleItems`)
|
|
1158
1342
|
}))
|
|
1159
1343
|
},
|
|
1160
1344
|
messages: form.messages.map(({
|
|
@@ -1793,6 +1977,7 @@ const Query = {
|
|
|
1793
1977
|
// Insert channel in context for later usage
|
|
1794
1978
|
const channel = findChannel(locator);
|
|
1795
1979
|
const locale = findLocale(locator);
|
|
1980
|
+
const regionId = findRegionId(locator);
|
|
1796
1981
|
const id = findSkuId(locator);
|
|
1797
1982
|
const slug = findSlug(locator);
|
|
1798
1983
|
|
|
@@ -1853,7 +2038,8 @@ const Query = {
|
|
|
1853
2038
|
} = await search.products({
|
|
1854
2039
|
page: 0,
|
|
1855
2040
|
count: 1,
|
|
1856
|
-
query: `product:${route.id}
|
|
2041
|
+
query: `product:${route.id}`,
|
|
2042
|
+
regionId
|
|
1857
2043
|
});
|
|
1858
2044
|
|
|
1859
2045
|
if (!product) {
|
|
@@ -2447,7 +2633,8 @@ const getContextFactory = options => ctx => {
|
|
|
2447
2633
|
ctx.storage = {
|
|
2448
2634
|
channel: ChannelMarshal.parse(options.channel),
|
|
2449
2635
|
flags: (_options$flags = options.flags) != null ? _options$flags : {},
|
|
2450
|
-
locale: options.locale
|
|
2636
|
+
locale: options.locale,
|
|
2637
|
+
cookies: new Map()
|
|
2451
2638
|
};
|
|
2452
2639
|
ctx.clients = getClients(options, ctx);
|
|
2453
2640
|
ctx.loaders = getLoaders(options, ctx);
|