@faststore/api 1.12.50 → 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 +174 -4
- 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 +174 -4
- package/dist/api.esm.js.map +1 -1
- package/dist/platforms/vtex/clients/fetch.d.ts +5 -1
- package/dist/platforms/vtex/index.d.ts +5 -0
- package/dist/platforms/vtex/utils/cookies.d.ts +52 -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/index.ts +6 -0
- package/src/platforms/vtex/utils/cookies.ts +157 -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";
|
|
@@ -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 ({
|
|
@@ -2468,7 +2637,8 @@ const getContextFactory = options => ctx => {
|
|
|
2468
2637
|
ctx.storage = {
|
|
2469
2638
|
channel: ChannelMarshal.parse(options.channel),
|
|
2470
2639
|
flags: (_options$flags = options.flags) != null ? _options$flags : {},
|
|
2471
|
-
locale: options.locale
|
|
2640
|
+
locale: options.locale,
|
|
2641
|
+
cookies: new Map()
|
|
2472
2642
|
};
|
|
2473
2643
|
ctx.clients = getClients(options, ctx);
|
|
2474
2644
|
ctx.loaders = getLoaders(options, ctx);
|