@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
|
@@ -22,7 +22,7 @@ var api = require('@opentelemetry/api');
|
|
|
22
22
|
var apiLogs = require('@opentelemetry/api-logs');
|
|
23
23
|
|
|
24
24
|
var name = "@faststore/api";
|
|
25
|
-
var version = "1.12.
|
|
25
|
+
var version = "1.12.50";
|
|
26
26
|
var license = "MIT";
|
|
27
27
|
var main = "dist/index.js";
|
|
28
28
|
var typings = "dist/index.d.ts";
|
|
@@ -58,7 +58,7 @@ var dependencies = {
|
|
|
58
58
|
};
|
|
59
59
|
var devDependencies = {
|
|
60
60
|
"@envelop/core": "^2.6.0",
|
|
61
|
-
"@faststore/shared": "^1.12.
|
|
61
|
+
"@faststore/shared": "^1.12.48",
|
|
62
62
|
"@graphql-codegen/cli": "2.2.0",
|
|
63
63
|
"@graphql-codegen/typescript": "2.2.2",
|
|
64
64
|
concurrently: "^6.2.1",
|
|
@@ -92,7 +92,7 @@ var packageJson = {
|
|
|
92
92
|
};
|
|
93
93
|
|
|
94
94
|
const USER_AGENT = `${packageJson.name}@${packageJson.version}`;
|
|
95
|
-
const fetchAPI = async (info, init) => {
|
|
95
|
+
const fetchAPI = async (info, init, options) => {
|
|
96
96
|
const response = await fetch(info, { ...init,
|
|
97
97
|
headers: { ...(init == null ? void 0 : init.headers),
|
|
98
98
|
'User-Agent': USER_AGENT
|
|
@@ -100,6 +100,10 @@ const fetchAPI = async (info, init) => {
|
|
|
100
100
|
});
|
|
101
101
|
|
|
102
102
|
if (response.ok) {
|
|
103
|
+
if (options != null && options.storeCookies) {
|
|
104
|
+
options.storeCookies(response.headers);
|
|
105
|
+
}
|
|
106
|
+
|
|
103
107
|
return response.status !== 204 ? response.json() : undefined;
|
|
104
108
|
}
|
|
105
109
|
|
|
@@ -108,17 +112,169 @@ const fetchAPI = async (info, init) => {
|
|
|
108
112
|
throw new Error(text);
|
|
109
113
|
};
|
|
110
114
|
|
|
115
|
+
const MATCH_FIRST_SET_COOKIE_KEY_VALUE = /^([^=]+)=([^;]*)/;
|
|
116
|
+
/**
|
|
117
|
+
* Splits a combined `set-cookie` header value (cookies joined by `, `) into
|
|
118
|
+
* individual cookies. Commas inside `expires=...` dates are kept.
|
|
119
|
+
*/
|
|
120
|
+
|
|
121
|
+
const splitSetCookieHeader = value => value.split(/,(?=\s*[^;,=\s]+=)/).map(setCookie => setCookie.trim());
|
|
122
|
+
/**
|
|
123
|
+
* Returns every `set-cookie` value of a fetch response.
|
|
124
|
+
*
|
|
125
|
+
* `Headers.getSetCookie()` only exists on Node >= 18.14 (undici). FastStore v1
|
|
126
|
+
* stores may still run on Node 16, where isomorphic-unfetch falls back to
|
|
127
|
+
* node-fetch v2, which exposes repeated headers through `raw()` instead.
|
|
128
|
+
*/
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
const getSetCookies = headers => {
|
|
132
|
+
const maybeHeaders = headers;
|
|
133
|
+
|
|
134
|
+
if (typeof maybeHeaders.getSetCookie === 'function') {
|
|
135
|
+
return maybeHeaders.getSetCookie();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (typeof maybeHeaders.raw === 'function') {
|
|
139
|
+
var _maybeHeaders$raw$set;
|
|
140
|
+
|
|
141
|
+
return (_maybeHeaders$raw$set = maybeHeaders.raw()['set-cookie']) != null ? _maybeHeaders$raw$set : [];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const setCookie = headers.get('set-cookie');
|
|
145
|
+
return setCookie ? splitSetCookieHeader(setCookie) : [];
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* This function updates the ctx.storage.cookies, that is used in each request.
|
|
149
|
+
*
|
|
150
|
+
* ctx.storage.cookies is a Map<string[1], Record<string, string>[2]> where,
|
|
151
|
+
* [1] cookie key
|
|
152
|
+
* [2] {
|
|
153
|
+
* value: cookie value,
|
|
154
|
+
* setCookie: setCookie used in browser response
|
|
155
|
+
* }
|
|
156
|
+
*/
|
|
157
|
+
|
|
158
|
+
const updatesContextStorageCookies = (ctx, setCookieValue) => {
|
|
159
|
+
const matchCookie = setCookieValue.match(MATCH_FIRST_SET_COOKIE_KEY_VALUE);
|
|
160
|
+
|
|
161
|
+
if (matchCookie) {
|
|
162
|
+
const cookieKey = matchCookie[1];
|
|
163
|
+
const cookieValue = matchCookie[2];
|
|
164
|
+
ctx.storage.cookies.set(cookieKey, {
|
|
165
|
+
value: cookieValue,
|
|
166
|
+
setCookie: setCookieValue
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
const setCookie = (ctx, headers) => {
|
|
171
|
+
getSetCookies(headers).forEach(setCookieValue => updatesContextStorageCookies(ctx, setCookieValue));
|
|
172
|
+
};
|
|
173
|
+
const getStoreCookie = ctx => headers => setCookie(ctx, headers);
|
|
174
|
+
/**
|
|
175
|
+
* This function returns a modified copy of the original cookie header (ctx.headers.cookie from the first request)
|
|
176
|
+
* with the cookie values that comes in each request (ctx.storage.cookies).
|
|
177
|
+
* If there is no cookies in storage, the ctx.headers?.cookie is used
|
|
178
|
+
*
|
|
179
|
+
* ctx.storage.cookies is a Map<string[1], Record<string, string>[2]> where,
|
|
180
|
+
* [1] cookie key
|
|
181
|
+
* [2] {
|
|
182
|
+
* value: cookie value,
|
|
183
|
+
* setCookie: setCookie used in browser response
|
|
184
|
+
* }
|
|
185
|
+
*/
|
|
186
|
+
|
|
187
|
+
const getUpdatedCookie = ctx => {
|
|
188
|
+
var _ctx$headers;
|
|
189
|
+
|
|
190
|
+
if (!((_ctx$headers = ctx.headers) != null && _ctx$headers.cookie)) {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const contextStorageCookies = Array.from(ctx.storage.cookies.entries());
|
|
195
|
+
|
|
196
|
+
if (contextStorageCookies.length === 0) {
|
|
197
|
+
return ctx.headers.cookie;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return contextStorageCookies.reduce((existingCookies, [storageCookieKey, {
|
|
201
|
+
value: storageCookieValue
|
|
202
|
+
}]) => updatesCookieValueByKey(existingCookies, storageCookieKey, storageCookieValue), ctx.headers.cookie);
|
|
203
|
+
};
|
|
204
|
+
const getWithCookie = ctx => function withCookie(headers) {
|
|
205
|
+
const updatedCookie = getUpdatedCookie(ctx);
|
|
206
|
+
|
|
207
|
+
if (!updatedCookie) {
|
|
208
|
+
return headers;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return { ...headers,
|
|
212
|
+
cookie: updatedCookie
|
|
213
|
+
};
|
|
214
|
+
};
|
|
215
|
+
/**
|
|
216
|
+
* This function updates the cookie value based on its key
|
|
217
|
+
*
|
|
218
|
+
* const existingCookies = 'key=value1; key2=; key3=value3';
|
|
219
|
+
* const storageCookieKey = 'key2';
|
|
220
|
+
* const storageCookieValue = 'value2'
|
|
221
|
+
*
|
|
222
|
+
* updatesCookieValueByKey(existingCookies, storageCookieKey, storageCookieValue) returns 'key=value1; key2=value2; key3=value3';
|
|
223
|
+
*/
|
|
224
|
+
|
|
225
|
+
const updatesCookieValueByKey = (existingCookies, storageCookieKey, storageCookieValue) => {
|
|
226
|
+
const MATCH_COOKIE_KEY_VALUE = new RegExp(`(${storageCookieKey})=([^;]*)`);
|
|
227
|
+
const cookieParts = existingCookies.match(MATCH_COOKIE_KEY_VALUE); // replaces original cookie with the one coming from storage
|
|
228
|
+
|
|
229
|
+
if (cookieParts) {
|
|
230
|
+
return existingCookies.replace(cookieParts[0], `${cookieParts[1]}=${storageCookieValue}`);
|
|
231
|
+
} // add new storage cookie to the original list of cookies
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
return `${existingCookies};${storageCookieKey}=${storageCookieValue}`;
|
|
235
|
+
};
|
|
236
|
+
|
|
111
237
|
const BASE_INIT = {
|
|
112
238
|
method: 'POST',
|
|
113
239
|
headers: {
|
|
114
240
|
'content-type': 'application/json'
|
|
115
241
|
}
|
|
116
242
|
};
|
|
243
|
+
|
|
244
|
+
const getHeader = (headers, name) => {
|
|
245
|
+
const value = headers == null ? void 0 : headers[name];
|
|
246
|
+
return Array.isArray(value) ? value[0] : value;
|
|
247
|
+
};
|
|
248
|
+
/**
|
|
249
|
+
* Host the Checkout API uses as the domain of the cookies it sets. Checkout
|
|
250
|
+
* only honors it for hosts registered in the account, so a forged value is
|
|
251
|
+
* ignored there.
|
|
252
|
+
*/
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
const getForwardedHost = headers => {
|
|
256
|
+
var _getHeader;
|
|
257
|
+
|
|
258
|
+
// Proxies may append values: "client, proxy". Only the first one is the store host.
|
|
259
|
+
const host = ((_getHeader = getHeader(headers, 'x-forwarded-host')) == null ? void 0 : _getHeader.split(',')[0].trim()) || getHeader(headers, 'host') || '';
|
|
260
|
+
return host.trim().replace(/^www\./, '');
|
|
261
|
+
};
|
|
262
|
+
|
|
117
263
|
const VtexCommerce = ({
|
|
118
264
|
account,
|
|
119
265
|
environment
|
|
120
266
|
}, ctx) => {
|
|
121
267
|
const base = `https://${account}.${environment}.com.br`;
|
|
268
|
+
const storeCookies = getStoreCookie(ctx);
|
|
269
|
+
const withCookie = getWithCookie(ctx);
|
|
270
|
+
const forwardedHost = getForwardedHost(ctx.headers); // Checkout calls forward the shopper cookies and keep the cookies Checkout
|
|
271
|
+
// sets (e.g. CheckoutOrderFormOwnership) so they can reach the browser.
|
|
272
|
+
|
|
273
|
+
const checkoutHeaders = () => withCookie({
|
|
274
|
+
'content-type': 'application/json',
|
|
275
|
+
'X-FORWARDED-HOST': forwardedHost
|
|
276
|
+
});
|
|
277
|
+
|
|
122
278
|
return {
|
|
123
279
|
catalog: {
|
|
124
280
|
salesChannel: sc => fetchAPI(`${base}/api/catalog_system/pub/saleschannel/${sc}`),
|
|
@@ -169,7 +325,10 @@ const VtexCommerce = ({
|
|
|
169
325
|
}
|
|
170
326
|
|
|
171
327
|
return fetchAPI(`${base}/api/checkout/pub/orderForm/${id}/attachments/shippingData`, { ...BASE_INIT,
|
|
328
|
+
headers: checkoutHeaders(),
|
|
172
329
|
body: JSON.stringify(body)
|
|
330
|
+
}, {
|
|
331
|
+
storeCookies
|
|
173
332
|
});
|
|
174
333
|
},
|
|
175
334
|
orderForm: ({
|
|
@@ -184,7 +343,11 @@ const VtexCommerce = ({
|
|
|
184
343
|
refreshOutdatedData: refreshOutdatedData.toString(),
|
|
185
344
|
sc: salesChannel
|
|
186
345
|
});
|
|
187
|
-
return fetchAPI(`${base}/api/checkout/pub/orderForm/${id}?${params.toString()}`, BASE_INIT
|
|
346
|
+
return fetchAPI(`${base}/api/checkout/pub/orderForm/${id}?${params.toString()}`, { ...BASE_INIT,
|
|
347
|
+
headers: checkoutHeaders()
|
|
348
|
+
}, {
|
|
349
|
+
storeCookies
|
|
350
|
+
});
|
|
188
351
|
},
|
|
189
352
|
updateOrderFormItems: ({
|
|
190
353
|
id,
|
|
@@ -198,11 +361,14 @@ const VtexCommerce = ({
|
|
|
198
361
|
sc: salesChannel
|
|
199
362
|
});
|
|
200
363
|
return fetchAPI(`${base}/api/checkout/pub/orderForm/${id}/items?${params}`, { ...BASE_INIT,
|
|
364
|
+
headers: checkoutHeaders(),
|
|
201
365
|
body: JSON.stringify({
|
|
202
366
|
orderItems,
|
|
203
367
|
noSplitItem: !shouldSplitItem
|
|
204
368
|
}),
|
|
205
369
|
method: 'PATCH'
|
|
370
|
+
}, {
|
|
371
|
+
storeCookies
|
|
206
372
|
});
|
|
207
373
|
},
|
|
208
374
|
setCustomData: ({
|
|
@@ -212,10 +378,13 @@ const VtexCommerce = ({
|
|
|
212
378
|
value
|
|
213
379
|
}) => {
|
|
214
380
|
return fetchAPI(`${base}/api/checkout/pub/orderForm/${id}/customData/${appId}/${key}`, { ...BASE_INIT,
|
|
381
|
+
headers: checkoutHeaders(),
|
|
215
382
|
body: JSON.stringify({
|
|
216
383
|
value
|
|
217
384
|
}),
|
|
218
385
|
method: 'PUT'
|
|
386
|
+
}, {
|
|
387
|
+
storeCookies
|
|
219
388
|
});
|
|
220
389
|
},
|
|
221
390
|
region: async ({
|
|
@@ -280,22 +449,23 @@ const IntelligentSearch = ({
|
|
|
280
449
|
};
|
|
281
450
|
};
|
|
282
451
|
|
|
283
|
-
const getRegionFacet =
|
|
452
|
+
const getRegionFacet = regionIdFromQuery => {
|
|
284
453
|
const {
|
|
285
454
|
regionId
|
|
286
455
|
} = ctx.storage.channel;
|
|
456
|
+
const facet = regionIdFromQuery != null ? regionIdFromQuery : regionId;
|
|
287
457
|
|
|
288
|
-
if (!
|
|
458
|
+
if (!facet) {
|
|
289
459
|
return null;
|
|
290
460
|
}
|
|
291
461
|
|
|
292
462
|
return {
|
|
293
463
|
key: REGION_KEY,
|
|
294
|
-
value:
|
|
464
|
+
value: facet
|
|
295
465
|
};
|
|
296
466
|
};
|
|
297
467
|
|
|
298
|
-
const addDefaultFacets = facets => {
|
|
468
|
+
const addDefaultFacets = (facets, regionIdFromQuery) => {
|
|
299
469
|
var _facets$find, _facets$find2;
|
|
300
470
|
|
|
301
471
|
const withDefaltFacets = facets.filter(({
|
|
@@ -306,7 +476,7 @@ const IntelligentSearch = ({
|
|
|
306
476
|
}) => key === POLICY_KEY)) != null ? _facets$find : getPolicyFacet();
|
|
307
477
|
const regionFacet = (_facets$find2 = facets.find(({
|
|
308
478
|
key
|
|
309
|
-
}) => key === REGION_KEY)) != null ? _facets$find2 : getRegionFacet();
|
|
479
|
+
}) => key === REGION_KEY)) != null ? _facets$find2 : getRegionFacet(regionIdFromQuery);
|
|
310
480
|
|
|
311
481
|
if (policyFacet !== null) {
|
|
312
482
|
withDefaltFacets.push(policyFacet);
|
|
@@ -326,7 +496,9 @@ const IntelligentSearch = ({
|
|
|
326
496
|
sort = '',
|
|
327
497
|
selectedFacets = [],
|
|
328
498
|
type,
|
|
329
|
-
fuzzy = 'auto'
|
|
499
|
+
fuzzy = 'auto',
|
|
500
|
+
showInvisibleItems,
|
|
501
|
+
regionId
|
|
330
502
|
}) => {
|
|
331
503
|
const params = new URLSearchParams({
|
|
332
504
|
page: (page + 1).toString(),
|
|
@@ -337,11 +509,15 @@ const IntelligentSearch = ({
|
|
|
337
509
|
locale: ctx.storage.locale
|
|
338
510
|
});
|
|
339
511
|
|
|
512
|
+
if (showInvisibleItems) {
|
|
513
|
+
params.append('show-invisible-items', 'true');
|
|
514
|
+
}
|
|
515
|
+
|
|
340
516
|
if (hideUnavailableItems !== undefined) {
|
|
341
517
|
params.append('hideUnavailableItems', hideUnavailableItems.toString());
|
|
342
518
|
}
|
|
343
519
|
|
|
344
|
-
const pathname = addDefaultFacets(selectedFacets).map(({
|
|
520
|
+
const pathname = addDefaultFacets(selectedFacets, regionId).map(({
|
|
345
521
|
key,
|
|
346
522
|
value
|
|
347
523
|
}) => `${key}/${value}`).join('/');
|
|
@@ -534,13 +710,16 @@ const isBadRequestError = error => {
|
|
|
534
710
|
};
|
|
535
711
|
|
|
536
712
|
const getSkuLoader = (_, clients) => {
|
|
537
|
-
const loader = async
|
|
713
|
+
const loader = async keys => {
|
|
714
|
+
const skuIds = keys.map(key => key.split('-')[0]);
|
|
715
|
+
const showInvisibleItems = keys.some(key => key.split('-')[1] === 'invisibleItems');
|
|
538
716
|
const {
|
|
539
717
|
products
|
|
540
718
|
} = await clients.search.products({
|
|
541
719
|
query: `sku:${skuIds.join(';')}`,
|
|
542
720
|
page: 0,
|
|
543
|
-
count: skuIds.length
|
|
721
|
+
count: skuIds.length,
|
|
722
|
+
showInvisibleItems
|
|
544
723
|
});
|
|
545
724
|
const skuBySkuId = products.reduce((acc, product) => {
|
|
546
725
|
for (const sku of product.items) {
|
|
@@ -920,6 +1099,11 @@ const findChannel = facets => {
|
|
|
920
1099
|
|
|
921
1100
|
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;
|
|
922
1101
|
};
|
|
1102
|
+
const findRegionId = facets => {
|
|
1103
|
+
var _facets$find$value5, _facets$find5;
|
|
1104
|
+
|
|
1105
|
+
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;
|
|
1106
|
+
};
|
|
923
1107
|
|
|
924
1108
|
/**
|
|
925
1109
|
* More info at: https://en.wikipedia.org/wiki/Order_statistic
|
|
@@ -1158,7 +1342,7 @@ const orderFormToCart = async (form, skuLoader) => {
|
|
|
1158
1342
|
order: {
|
|
1159
1343
|
orderNumber: form.orderFormId,
|
|
1160
1344
|
acceptedOffer: form.items.map(async item => ({ ...item,
|
|
1161
|
-
product: await skuLoader.load(item.id)
|
|
1345
|
+
product: await skuLoader.load(`${item.id}-invisibleItems`)
|
|
1162
1346
|
}))
|
|
1163
1347
|
},
|
|
1164
1348
|
messages: form.messages.map(({
|
|
@@ -1797,6 +1981,7 @@ const Query = {
|
|
|
1797
1981
|
// Insert channel in context for later usage
|
|
1798
1982
|
const channel = findChannel(locator);
|
|
1799
1983
|
const locale = findLocale(locator);
|
|
1984
|
+
const regionId = findRegionId(locator);
|
|
1800
1985
|
const id = findSkuId(locator);
|
|
1801
1986
|
const slug = findSlug(locator);
|
|
1802
1987
|
|
|
@@ -1857,7 +2042,8 @@ const Query = {
|
|
|
1857
2042
|
} = await search.products({
|
|
1858
2043
|
page: 0,
|
|
1859
2044
|
count: 1,
|
|
1860
|
-
query: `product:${route.id}
|
|
2045
|
+
query: `product:${route.id}`,
|
|
2046
|
+
regionId
|
|
1861
2047
|
});
|
|
1862
2048
|
|
|
1863
2049
|
if (!product) {
|
|
@@ -2451,7 +2637,8 @@ const getContextFactory = options => ctx => {
|
|
|
2451
2637
|
ctx.storage = {
|
|
2452
2638
|
channel: ChannelMarshal.parse(options.channel),
|
|
2453
2639
|
flags: (_options$flags = options.flags) != null ? _options$flags : {},
|
|
2454
|
-
locale: options.locale
|
|
2640
|
+
locale: options.locale,
|
|
2641
|
+
cookies: new Map()
|
|
2455
2642
|
};
|
|
2456
2643
|
ctx.clients = getClients(options, ctx);
|
|
2457
2644
|
ctx.loaders = getLoaders(options, ctx);
|