@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.
@@ -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.47";
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.43",
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 (!regionId) {
458
+ if (!facet) {
289
459
  return null;
290
460
  }
291
461
 
292
462
  return {
293
463
  key: REGION_KEY,
294
- value: regionId
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 skuIds => {
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);